#!/usr/bin/env node /** * Harden the `users` collection and make it usable by the app's * Settings > Users screen. * * Problems found on the live instance: * * 1. createRule was "" (empty string) => PUBLIC. Any anonymous visitor * on the internet could create an account on this PocketBase instance. * 2. listRule was "id = @request.auth.id" => a signed-in member could * only ever see their own record, so there was no way to render a * member list. * 3. The `active` bool field had no default, so every record was created * with active = false. AuthContext refuses to sign in a user whose * `active` is false, so newly created users could not log in at all. * NOTE: PocketBase's REST API strips `defaultValue` from field * definitions (verified on this instance - a scratch collection with * `defaultValue: true` on a bool field still stored false), so the * default cannot be set from here. The app sets `active: true` * explicitly when it creates a member instead. * * New rules (matching the posture already used by every other collection * in this app - stock_items, customers, purchase_orders, quotes, ...): * * listRule @request.auth.id != "" members can list the team * viewRule @request.auth.id != "" members can read a member * createRule @request.auth.id != "" members can add members * updateRule @request.auth.id != "" members can activate/deactivate * deleteRule @request.auth.id != "" members can remove members * * The `role` field is intentionally left untouched: the app does not use * roles, membership is just the `active` flag. * * Usage: * node scripts/fix-users-collection.mjs # dry run (default) * node scripts/fix-users-collection.mjs --apply # apply to the instance */ import PocketBase from "pocketbase"; const PB_URL = process.env.POCKETBASE_URL || "https://pb.jeistk.apphub.co.za"; const PB_EMAIL = process.env.POCKETBASE_ADMIN_EMAIL || "david@wfsales.co.za"; const PB_PASSWORD = process.env.POCKETBASE_ADMIN_PASSWORD || "1234567890"; const APPLY = process.argv.includes("--apply"); const AUTHENTICATED = '@request.auth.id != ""'; const pb = new PocketBase(PB_URL); pb.autoCancellation(false); await pb.admins.authWithPassword(PB_EMAIL, PB_PASSWORD); const collection = await pb.collections.getOne("users"); console.log("=== BEFORE ==="); for (const rule of ["listRule", "viewRule", "createRule", "updateRule", "deleteRule"]) { console.log(` ${rule.padEnd(11)}: ${JSON.stringify(collection[rule])}`); } const activeField = collection.fields.find((f) => f.name === "active"); console.log(` active field: ${activeField ? "present" : "MISSING"}`); if (!APPLY) { console.log("\nDry run. Re-run with --apply to write these rules to the instance."); process.exit(0); } collection.listRule = AUTHENTICATED; collection.viewRule = AUTHENTICATED; collection.createRule = AUTHENTICATED; collection.updateRule = AUTHENTICATED; collection.deleteRule = AUTHENTICATED; const updated = await pb.collections.update(collection.id, collection); console.log("\n=== AFTER ==="); for (const rule of ["listRule", "viewRule", "createRule", "updateRule", "deleteRule"]) { console.log(` ${rule.padEnd(11)}: ${JSON.stringify(updated[rule])}`); } console.log("\nDone. Existing records keep their current `active` value - flip them"); console.log("from Settings > Users if they should be able to sign in.");