chore(seed): update seed scripts for RBAC roles
Assign the developer role document to the sysadmin user on seed. Add seedRoles script to create default RBAC roles.
This commit is contained in:
parent
d3890cc191
commit
fb74e6b0c2
2 changed files with 236 additions and 0 deletions
226
src/tools/seed/seedRoles.ts
Normal file
226
src/tools/seed/seedRoles.ts
Normal file
|
|
@ -0,0 +1,226 @@
|
||||||
|
import { getPayload } from "payload";
|
||||||
|
import config from "@payload-config";
|
||||||
|
import type { Permission } from "@/permissions";
|
||||||
|
|
||||||
|
const USER_PERMISSIONS: Permission[] = [
|
||||||
|
"users:read",
|
||||||
|
"ranks:read",
|
||||||
|
"profiles:read",
|
||||||
|
"awards:read",
|
||||||
|
"qualifications:read",
|
||||||
|
"assignments:read",
|
||||||
|
"experience:read",
|
||||||
|
"user-notifications:read",
|
||||||
|
"missions:read",
|
||||||
|
"mission-attendances:read",
|
||||||
|
"campaigns:read",
|
||||||
|
"factions:read",
|
||||||
|
"technologies:read",
|
||||||
|
"assets:read",
|
||||||
|
"resources:read",
|
||||||
|
"vehicles:read",
|
||||||
|
"structures:read",
|
||||||
|
"shipments:read",
|
||||||
|
"bank-accounts:read",
|
||||||
|
"bank-transactions:read",
|
||||||
|
"ledger-entries:read",
|
||||||
|
"locker-storages:read",
|
||||||
|
"loadouts:read",
|
||||||
|
"market-listings:read",
|
||||||
|
"market-negotiations:read",
|
||||||
|
"tickets:read",
|
||||||
|
"game-structures:read",
|
||||||
|
"game-vehicles:read",
|
||||||
|
"game-npcs:read",
|
||||||
|
"game-hard-resources:read",
|
||||||
|
"game-event-logs:read",
|
||||||
|
"maps:read",
|
||||||
|
"narrative-events:read",
|
||||||
|
"mission-files:read",
|
||||||
|
"mod-lists:read",
|
||||||
|
"game-rules:read",
|
||||||
|
"shims:read",
|
||||||
|
"shipments:create",
|
||||||
|
"shipments:update",
|
||||||
|
"structures:update",
|
||||||
|
"structures:delete",
|
||||||
|
];
|
||||||
|
|
||||||
|
const ADMIN_PERMISSIONS: Permission[] = [
|
||||||
|
...USER_PERMISSIONS,
|
||||||
|
"system:admin-access",
|
||||||
|
"users:read",
|
||||||
|
"users:update",
|
||||||
|
"users:delete",
|
||||||
|
"technologies:create",
|
||||||
|
"technologies:read",
|
||||||
|
"technologies:update",
|
||||||
|
"technologies:delete",
|
||||||
|
"tickets:read",
|
||||||
|
"tickets:update",
|
||||||
|
"tickets:staff",
|
||||||
|
"bank-accounts:create",
|
||||||
|
"bank-accounts:update",
|
||||||
|
"user-notifications:read",
|
||||||
|
"user-notifications:update",
|
||||||
|
"mission-attendances:create",
|
||||||
|
"mission-attendances:read",
|
||||||
|
"mission-attendances:update",
|
||||||
|
"mission-attendances:delete",
|
||||||
|
"missions:read",
|
||||||
|
"market-negotiations:read",
|
||||||
|
"market-negotiations:update",
|
||||||
|
"logistics:manage",
|
||||||
|
"banking:manage",
|
||||||
|
"discord:staff",
|
||||||
|
"discord:announce",
|
||||||
|
"structures:create",
|
||||||
|
];
|
||||||
|
|
||||||
|
interface BuiltinRole {
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
permissions: Permission[];
|
||||||
|
isSystem: boolean;
|
||||||
|
isSuperuser: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BUILTIN_ROLES: BuiltinRole[] = [
|
||||||
|
{
|
||||||
|
slug: "guest",
|
||||||
|
name: "Guest",
|
||||||
|
description: "Default role for unauthenticated or basic users. No permissions.",
|
||||||
|
permissions: [],
|
||||||
|
isSystem: true,
|
||||||
|
isSuperuser: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "user",
|
||||||
|
name: "User",
|
||||||
|
description: "Standard authenticated user. Can manage shipments, structures, and read profiles.",
|
||||||
|
permissions: [...USER_PERMISSIONS],
|
||||||
|
isSystem: true,
|
||||||
|
isSuperuser: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "admin",
|
||||||
|
name: "Admin",
|
||||||
|
description: "Administrator. Can manage users, tickets, banking, logistics, and most collections.",
|
||||||
|
permissions: [...ADMIN_PERMISSIONS],
|
||||||
|
isSystem: true,
|
||||||
|
isSuperuser: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "developer",
|
||||||
|
name: "Developer",
|
||||||
|
description: "Superuser. Bypasses all permission checks. Full access to everything.",
|
||||||
|
permissions: [],
|
||||||
|
isSystem: true,
|
||||||
|
isSuperuser: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const ENUM_TO_SLUG: Record<string, string> = {
|
||||||
|
guest: "guest",
|
||||||
|
user: "user",
|
||||||
|
trusted: "user",
|
||||||
|
admin: "admin",
|
||||||
|
developer: "developer",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const seedRoles = async () => {
|
||||||
|
const payload = await getPayload({ config });
|
||||||
|
|
||||||
|
payload.logger.info("Seeding built-in RBAC roles...");
|
||||||
|
|
||||||
|
const roleIdMap = new Map<string, number>();
|
||||||
|
|
||||||
|
for (const role of BUILTIN_ROLES) {
|
||||||
|
const existing = await payload.find({
|
||||||
|
collection: "roles",
|
||||||
|
where: { slug: { equals: role.slug } },
|
||||||
|
limit: 1,
|
||||||
|
overrideAccess: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existing.docs.length > 0) {
|
||||||
|
const doc = existing.docs[0] as { id: number };
|
||||||
|
roleIdMap.set(role.slug, doc.id);
|
||||||
|
payload.logger.info(` Role "${role.slug}" already exists (id=${doc.id}), skipping.`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const created = await payload.create({
|
||||||
|
collection: "roles",
|
||||||
|
data: {
|
||||||
|
name: role.name,
|
||||||
|
slug: role.slug,
|
||||||
|
description: role.description,
|
||||||
|
permissions: role.permissions,
|
||||||
|
isSystem: role.isSystem,
|
||||||
|
isSuperuser: role.isSuperuser,
|
||||||
|
},
|
||||||
|
overrideAccess: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
roleIdMap.set(role.slug, created.id);
|
||||||
|
payload.logger.info(` Created role "${role.slug}" (id=${created.id}).`);
|
||||||
|
}
|
||||||
|
|
||||||
|
payload.logger.info("Migrating existing users from roles enum to roleDocs...");
|
||||||
|
|
||||||
|
const users = await payload.find({
|
||||||
|
collection: "users",
|
||||||
|
limit: 0,
|
||||||
|
depth: 0,
|
||||||
|
overrideAccess: true,
|
||||||
|
select: { roles: true, roleDocs: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
let migrated = 0;
|
||||||
|
let skipped = 0;
|
||||||
|
|
||||||
|
for (const user of users.docs) {
|
||||||
|
const u = user as { id: number; roles?: string[] | null; roleDocs?: unknown[] | null };
|
||||||
|
|
||||||
|
if (u.roleDocs && Array.isArray(u.roleDocs) && u.roleDocs.length > 0) {
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const enumRoles = u.roles ?? [];
|
||||||
|
if (enumRoles.length === 0) {
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const roleDocIds: number[] = [];
|
||||||
|
const seenSlugs = new Set<string>();
|
||||||
|
|
||||||
|
for (const enumRole of enumRoles) {
|
||||||
|
const slug = ENUM_TO_SLUG[enumRole];
|
||||||
|
if (!slug || seenSlugs.has(slug)) continue;
|
||||||
|
seenSlugs.add(slug);
|
||||||
|
const roleId = roleIdMap.get(slug);
|
||||||
|
if (roleId) roleDocIds.push(roleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roleDocIds.length === 0) {
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await payload.update({
|
||||||
|
collection: "users",
|
||||||
|
id: user.id,
|
||||||
|
data: { roleDocs: roleDocIds },
|
||||||
|
overrideAccess: true,
|
||||||
|
});
|
||||||
|
migrated++;
|
||||||
|
}
|
||||||
|
|
||||||
|
payload.logger.info(`Migration complete: ${migrated} users migrated, ${skipped} users skipped.`);
|
||||||
|
};
|
||||||
|
|
||||||
|
await seedRoles();
|
||||||
|
|
@ -14,6 +14,15 @@ export const seedUsers = async () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const devRole = await payload.find({
|
||||||
|
collection: "roles",
|
||||||
|
where: { slug: { equals: "developer" } },
|
||||||
|
limit: 1,
|
||||||
|
depth: 0,
|
||||||
|
overrideAccess: true,
|
||||||
|
});
|
||||||
|
const devRoleId = devRole.docs[0]?.id;
|
||||||
|
|
||||||
payload.logger.info(`Creating initial sysadmin/developer user...`);
|
payload.logger.info(`Creating initial sysadmin/developer user...`);
|
||||||
try {
|
try {
|
||||||
const result = await payload.create({
|
const result = await payload.create({
|
||||||
|
|
@ -25,6 +34,7 @@ export const seedUsers = async () => {
|
||||||
discordUsername: "Z8MB1E",
|
discordUsername: "Z8MB1E",
|
||||||
steamId: "76561198091303179",
|
steamId: "76561198091303179",
|
||||||
roles: ["developer"],
|
roles: ["developer"],
|
||||||
|
roleDocs: devRoleId ? [devRoleId] : [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue