feat(rbac): implement full admin management, dynamic roles, permissions matrix, and workspace access control
- Add Workspace, Role, Permission, RolePermission, AdminRoleAssignment, and AdminWorkspaceAssignment models to Prisma schema\n- Create database migration and RBAC seed script\n- Implement PermissionsGuard, @RequirePermission decorator, and real-time permission resolution in JwtAdminStrategy\n- Implement AdminManagementModule with endpoints for managers CRUD, roles matrix, permissions catalog, and workspaces\n- Secure all sensitive admin controllers with granular permission requirements\n- Add useAuthStore helpers (can, canAny, fetchMe) and v-permission directive\n- Implement Desktop views: AdminListView, AdminFormDrawer (RTL right-side), RoleMatrixView, WorkspaceListView, and ForbiddenView\n- Implement Mobile views: MAdminListView, MAdminFormView (stepped mobile form), MRoleMatrixView, MWorkspaceListView, and MForbiddenView\n- Fix sticky header behavior across desktop and mobile shells\n- Update route guards and device detection logic for mobile prefixing
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "AccessScopeType" AS ENUM ('ALL', 'CUSTOM_CAMPAIGNS');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "admins" ADD COLUMN "is_super_admin" BOOLEAN NOT NULL DEFAULT false,
|
||||
ADD COLUMN "last_login_at" TIMESTAMP(3);
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "campaigns" ADD COLUMN "workspace_id" TEXT;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "workspaces" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"status" TEXT NOT NULL DEFAULT 'ACTIVE',
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "workspaces_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "roles" (
|
||||
"id" TEXT NOT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"is_system" BOOLEAN NOT NULL DEFAULT false,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "roles_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "permissions" (
|
||||
"id" TEXT NOT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"module" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
|
||||
CONSTRAINT "permissions_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "role_permissions" (
|
||||
"role_id" TEXT NOT NULL,
|
||||
"permission_id" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "role_permissions_pkey" PRIMARY KEY ("role_id","permission_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "admin_role_assignments" (
|
||||
"id" TEXT NOT NULL,
|
||||
"admin_id" TEXT NOT NULL,
|
||||
"role_id" TEXT NOT NULL,
|
||||
"assigned_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "admin_role_assignments_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "admin_workspace_assignments" (
|
||||
"id" TEXT NOT NULL,
|
||||
"admin_id" TEXT NOT NULL,
|
||||
"workspace_id" TEXT NOT NULL,
|
||||
"scope_type" "AccessScopeType" NOT NULL DEFAULT 'ALL',
|
||||
"specific_campaign_ids" JSONB,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "admin_workspace_assignments_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "workspaces_slug_key" ON "workspaces"("slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "roles_code_key" ON "roles"("code");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "permissions_code_key" ON "permissions"("code");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "permissions_module_idx" ON "permissions"("module");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "admin_role_assignments_admin_id_role_id_key" ON "admin_role_assignments"("admin_id", "role_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "admin_workspace_assignments_admin_id_workspace_id_key" ON "admin_workspace_assignments"("admin_id", "workspace_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "campaigns_workspace_id_idx" ON "campaigns"("workspace_id");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "campaigns" ADD CONSTRAINT "campaigns_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "workspaces"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "role_permissions" ADD CONSTRAINT "role_permissions_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "roles"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "role_permissions" ADD CONSTRAINT "role_permissions_permission_id_fkey" FOREIGN KEY ("permission_id") REFERENCES "permissions"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "admin_role_assignments" ADD CONSTRAINT "admin_role_assignments_admin_id_fkey" FOREIGN KEY ("admin_id") REFERENCES "admins"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "admin_role_assignments" ADD CONSTRAINT "admin_role_assignments_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "roles"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "admin_workspace_assignments" ADD CONSTRAINT "admin_workspace_assignments_admin_id_fkey" FOREIGN KEY ("admin_id") REFERENCES "admins"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "admin_workspace_assignments" ADD CONSTRAINT "admin_workspace_assignments_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "workspaces"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -21,6 +21,11 @@ enum AdminRole {
|
||||
SUPPORT
|
||||
}
|
||||
|
||||
enum AccessScopeType {
|
||||
ALL
|
||||
CUSTOM_CAMPAIGNS
|
||||
}
|
||||
|
||||
enum UserStatus {
|
||||
ACTIVE
|
||||
BLOCKED
|
||||
@@ -111,11 +116,15 @@ model Admin {
|
||||
passwordHash String @map("password_hash")
|
||||
role AdminRole @default(OPERATOR)
|
||||
status AdminStatus @default(ACTIVE)
|
||||
isSuperAdmin Boolean @default(false) @map("is_super_admin")
|
||||
lastLoginAt DateTime? @map("last_login_at")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
auditLogs AdminLog[]
|
||||
chanceTxns ChanceTransaction[] @relation("AdminCreatedTxn")
|
||||
auditLogs AdminLog[]
|
||||
chanceTxns ChanceTransaction[] @relation("AdminCreatedTxn")
|
||||
roles AdminRoleAssignment[]
|
||||
workspaceAssignments AdminWorkspaceAssignment[]
|
||||
|
||||
@@map("admins")
|
||||
}
|
||||
@@ -171,6 +180,8 @@ model Campaign {
|
||||
ctaText String? @map("cta_text")
|
||||
wheelDesign WheelDesign @default(CLASSIC_CASINO) @map("wheel_design")
|
||||
settings Json? // primaryColor, secondaryColor, headerText, buttonText, headerImage, celebrationEffect...
|
||||
workspaceId String? @map("workspace_id")
|
||||
workspace Workspace? @relation(fields: [workspaceId], references: [id])
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
@@ -181,6 +192,7 @@ model Campaign {
|
||||
userPrizes UserPrize[]
|
||||
|
||||
@@index([status, startAt, endAt])
|
||||
@@index([workspaceId])
|
||||
@@map("campaigns")
|
||||
}
|
||||
|
||||
@@ -317,3 +329,84 @@ model AdminLog {
|
||||
@@index([entityType, entityId])
|
||||
@@map("admin_logs")
|
||||
}
|
||||
|
||||
// ==================== WORKSPACE & RBAC MODELS ====================
|
||||
|
||||
model Workspace {
|
||||
id String @id @default(uuid())
|
||||
name String
|
||||
slug String @unique
|
||||
description String?
|
||||
status String @default("ACTIVE")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
campaigns Campaign[]
|
||||
adminAssignments AdminWorkspaceAssignment[]
|
||||
|
||||
@@map("workspaces")
|
||||
}
|
||||
|
||||
model Role {
|
||||
id String @id @default(uuid())
|
||||
code String @unique // e.g. "SUPER_ADMIN", "OPERATOR", "SUPPORT"
|
||||
name String // نام فارسی
|
||||
description String?
|
||||
isSystem Boolean @default(false) @map("is_system")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
permissions RolePermission[]
|
||||
admins AdminRoleAssignment[]
|
||||
|
||||
@@map("roles")
|
||||
}
|
||||
|
||||
model Permission {
|
||||
id String @id @default(uuid())
|
||||
code String @unique // e.g. "campaigns:read", "campaigns:create"
|
||||
module String // e.g. "campaigns", "users", "prizes", "reports", "admins"
|
||||
name String // نام فارسی
|
||||
description String?
|
||||
|
||||
roles RolePermission[]
|
||||
|
||||
@@index([module])
|
||||
@@map("permissions")
|
||||
}
|
||||
|
||||
model RolePermission {
|
||||
roleId String @map("role_id")
|
||||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
||||
permissionId String @map("permission_id")
|
||||
permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@id([roleId, permissionId])
|
||||
@@map("role_permissions")
|
||||
}
|
||||
|
||||
model AdminRoleAssignment {
|
||||
id String @id @default(uuid())
|
||||
adminId String @map("admin_id")
|
||||
admin Admin @relation(fields: [adminId], references: [id], onDelete: Cascade)
|
||||
roleId String @map("role_id")
|
||||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
||||
assignedAt DateTime @default(now()) @map("assigned_at")
|
||||
|
||||
@@unique([adminId, roleId])
|
||||
@@map("admin_role_assignments")
|
||||
}
|
||||
|
||||
model AdminWorkspaceAssignment {
|
||||
id String @id @default(uuid())
|
||||
adminId String @map("admin_id")
|
||||
admin Admin @relation(fields: [adminId], references: [id], onDelete: Cascade)
|
||||
workspaceId String @map("workspace_id")
|
||||
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
||||
scopeType AccessScopeType @default(ALL) @map("scope_type")
|
||||
specificCampaignIds Json? @map("specific_campaign_ids")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
@@unique([adminId, workspaceId])
|
||||
@@map("admin_workspace_assignments")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
import { AccessScopeType, PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
const PERMISSIONS = [
|
||||
// Campaigns
|
||||
{ code: 'campaigns:read', module: 'campaigns', name: 'مشاهده کمپینها', description: 'مشاهده لیست و جزئیات کمپینها' },
|
||||
{ code: 'campaigns:create', module: 'campaigns', name: 'ایجاد کمپین', description: 'ثبت کمپین جدید' },
|
||||
{ code: 'campaigns:update', module: 'campaigns', name: 'ویرایش کمپین', description: 'تغییر تنظیمات و وضعیت کمپین' },
|
||||
{ code: 'campaigns:delete', module: 'campaigns', name: 'حذف کمپین', description: 'حذف کمپین از سامانه' },
|
||||
|
||||
// Prizes
|
||||
{ code: 'prizes:read', module: 'prizes', name: 'مشاهده جوایز', description: 'مشاهده لیست جوایز کمپینها' },
|
||||
{ code: 'prizes:manage', module: 'prizes', name: 'مدیریت جوایز', description: 'افزودن، ویرایش و تنظیم ظرفیت جوایز' },
|
||||
|
||||
// Users & Chances
|
||||
{ code: 'users:read', module: 'users', name: 'مشاهده کاربران', description: 'مشاهده لیست کاربران شرکتکننده و پروفایل' },
|
||||
{ code: 'users:block', module: 'users', name: 'مسدودسازی کاربران', description: 'بلاک یا آنبلاک کردن کاربران' },
|
||||
{ code: 'chances:adjust', module: 'chances', name: 'تنظیم دستی شانس', description: 'افزایش یا کاهش شانس با ثبت لاگ' },
|
||||
|
||||
// Winners & Spins
|
||||
{ code: 'spins:read', module: 'spins', name: 'مشاهده لاگ چرخشها', description: 'بررسی تاریخچه اسپینهای کاربران' },
|
||||
{ code: 'winners:read', module: 'winners', name: 'مشاهده برندگان', description: 'مشاهده لیست برندگان و کدهای هدیه' },
|
||||
{ code: 'winners:manage', module: 'winners', name: 'مدیریت وضعیت جوایز', description: 'تغییر وضعیت کدهای جایزه به تحویلشده و...' },
|
||||
|
||||
// SMS & Logs
|
||||
{ code: 'sms:read', module: 'sms', name: 'مشاهده لاگ پیامک', description: 'مشاهده پیامکهای ارسالی OTP و برندگان' },
|
||||
{ code: 'sms:resend', module: 'sms', name: 'ارسال مجدد پیامک', description: 'ارسال دوباره پیامکهای ناموفق' },
|
||||
{ code: 'audit:read', module: 'audit', name: 'مشاهده لاگ بازرسی', description: 'مشاهده ردپای عملیات و تغییرات مدیران' },
|
||||
|
||||
// Reports
|
||||
{ code: 'reports:read', module: 'reports', name: 'مشاهده گزارشها و آمار', description: 'مشاهده نمودارها، آمار زنده و داشبورد' },
|
||||
{ code: 'reports:export', module: 'reports', name: 'خروجی دادهها', description: 'دریافت خروجی اکسل و CSV گزارشها' },
|
||||
|
||||
// Access Control & Admins
|
||||
{ code: 'admins:read', module: 'admins', name: 'مشاهده مدیران', description: 'مشاهده لیست مدیران و همکاران' },
|
||||
{ code: 'admins:manage', module: 'admins', name: 'مدیریت مدیران', description: 'ایجاد، ویرایش، تغییر رمز و غیرفعالسازی مدیران' },
|
||||
{ code: 'roles:manage', module: 'roles', name: 'مدیریت نقشها و مجوزها', description: 'تعریف نقش جدید و تخصیص مجوزها' },
|
||||
{ code: 'workspaces:manage', module: 'workspaces', name: 'مدیریت فضاهای کاری', description: 'تعریف و مدیریت فضاهای کاری سازمانی' },
|
||||
];
|
||||
|
||||
async function main() {
|
||||
console.log('Seeding RBAC and Workspaces...');
|
||||
|
||||
// 1. Ensure Default Workspace exists
|
||||
let defaultWorkspace = await prisma.workspace.findUnique({
|
||||
where: { slug: 'default-workspace' },
|
||||
});
|
||||
|
||||
if (!defaultWorkspace) {
|
||||
defaultWorkspace = await prisma.workspace.create({
|
||||
data: {
|
||||
name: 'فضای کاری اصلی',
|
||||
slug: 'default-workspace',
|
||||
description: 'فضای کاری پیشفرض و سراسری سیستم گردونه شانس',
|
||||
status: 'ACTIVE',
|
||||
},
|
||||
});
|
||||
console.log('Created default workspace:', defaultWorkspace.id);
|
||||
}
|
||||
|
||||
// Link any unassigned campaigns to default workspace
|
||||
await prisma.campaign.updateMany({
|
||||
where: { workspaceId: null },
|
||||
data: { workspaceId: defaultWorkspace.id },
|
||||
});
|
||||
|
||||
// 2. Seed Permissions
|
||||
const permissionMap = new Map<string, string>();
|
||||
for (const perm of PERMISSIONS) {
|
||||
const p = await prisma.permission.upsert({
|
||||
where: { code: perm.code },
|
||||
update: {
|
||||
module: perm.module,
|
||||
name: perm.name,
|
||||
description: perm.description,
|
||||
},
|
||||
create: {
|
||||
code: perm.code,
|
||||
module: perm.module,
|
||||
name: perm.name,
|
||||
description: perm.description,
|
||||
},
|
||||
});
|
||||
permissionMap.set(p.code, p.id);
|
||||
}
|
||||
console.log(`Seeded ${permissionMap.size} permissions.`);
|
||||
|
||||
// 3. Seed Roles
|
||||
// SUPER_ADMIN (All permissions)
|
||||
const superAdminRole = await prisma.role.upsert({
|
||||
where: { code: 'SUPER_ADMIN' },
|
||||
update: {
|
||||
name: 'مدیر ارشد سامانه',
|
||||
description: 'دسترسی کامل و بدون محدودیت به تمامی بخشها و تنظیمات سامانه',
|
||||
isSystem: true,
|
||||
},
|
||||
create: {
|
||||
code: 'SUPER_ADMIN',
|
||||
name: 'مدیر ارشد سامانه',
|
||||
description: 'دسترسی کامل و بدون محدودیت به تمامی بخشها و تنظیمات سامانه',
|
||||
isSystem: true,
|
||||
},
|
||||
});
|
||||
|
||||
// OPERATOR (Operational permissions)
|
||||
const operatorRole = await prisma.role.upsert({
|
||||
where: { code: 'OPERATOR' },
|
||||
update: {
|
||||
name: 'اپراتور سامانه',
|
||||
description: 'مدیریت کمپینها، جوایز، شانسها، برندگان و کاربران بدون دسترسی به مدیریت ادمینها',
|
||||
isSystem: true,
|
||||
},
|
||||
create: {
|
||||
code: 'OPERATOR',
|
||||
name: 'اپراتور سامانه',
|
||||
description: 'مدیریت کمپینها، جوایز، شانسها، برندگان و کاربران بدون دسترسی به مدیریت ادمینها',
|
||||
isSystem: true,
|
||||
},
|
||||
});
|
||||
|
||||
// SUPPORT (Read-only + winner management)
|
||||
const supportRole = await prisma.role.upsert({
|
||||
where: { code: 'SUPPORT' },
|
||||
update: {
|
||||
name: 'کارشناس پشتیبانی',
|
||||
description: 'مشاهده کاربران، برندگان، پیامکها و تغییر وضعیت تحویل جوایز',
|
||||
isSystem: true,
|
||||
},
|
||||
create: {
|
||||
code: 'SUPPORT',
|
||||
name: 'کارشناس پشتیبانی',
|
||||
description: 'مشاهده کاربران، برندگان، پیامکها و تغییر وضعیت تحویل جوایز',
|
||||
isSystem: true,
|
||||
},
|
||||
});
|
||||
|
||||
// 4. Assign permissions to roles
|
||||
// SUPER_ADMIN gets all permissions
|
||||
for (const permId of permissionMap.values()) {
|
||||
await prisma.rolePermission.upsert({
|
||||
where: {
|
||||
roleId_permissionId: {
|
||||
roleId: superAdminRole.id,
|
||||
permissionId: permId,
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
create: {
|
||||
roleId: superAdminRole.id,
|
||||
permissionId: permId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// OPERATOR permissions
|
||||
const operatorPermCodes = [
|
||||
'campaigns:read', 'campaigns:create', 'campaigns:update', 'campaigns:delete',
|
||||
'prizes:read', 'prizes:manage',
|
||||
'users:read', 'users:block', 'chances:adjust',
|
||||
'spins:read', 'winners:read', 'winners:manage',
|
||||
'sms:read', 'sms:resend',
|
||||
'reports:read', 'reports:export',
|
||||
'audit:read',
|
||||
];
|
||||
for (const code of operatorPermCodes) {
|
||||
const permId = permissionMap.get(code);
|
||||
if (permId) {
|
||||
await prisma.rolePermission.upsert({
|
||||
where: {
|
||||
roleId_permissionId: {
|
||||
roleId: operatorRole.id,
|
||||
permissionId: permId,
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
create: {
|
||||
roleId: operatorRole.id,
|
||||
permissionId: permId,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// SUPPORT permissions
|
||||
const supportPermCodes = [
|
||||
'campaigns:read',
|
||||
'prizes:read',
|
||||
'users:read',
|
||||
'spins:read',
|
||||
'winners:read', 'winners:manage',
|
||||
'sms:read',
|
||||
];
|
||||
for (const code of supportPermCodes) {
|
||||
const permId = permissionMap.get(code);
|
||||
if (permId) {
|
||||
await prisma.rolePermission.upsert({
|
||||
where: {
|
||||
roleId_permissionId: {
|
||||
roleId: supportRole.id,
|
||||
permissionId: permId,
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
create: {
|
||||
roleId: supportRole.id,
|
||||
permissionId: permId,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Backfill existing admins
|
||||
const admins = await prisma.admin.findMany();
|
||||
for (const admin of admins) {
|
||||
const isSuper = admin.role === 'SUPER_ADMIN';
|
||||
|
||||
await prisma.admin.update({
|
||||
where: { id: admin.id },
|
||||
data: {
|
||||
isSuperAdmin: isSuper,
|
||||
},
|
||||
});
|
||||
|
||||
const targetRoleId = isSuper
|
||||
? superAdminRole.id
|
||||
: admin.role === 'OPERATOR'
|
||||
? operatorRole.id
|
||||
: supportRole.id;
|
||||
|
||||
await prisma.adminRoleAssignment.upsert({
|
||||
where: {
|
||||
adminId_roleId: {
|
||||
adminId: admin.id,
|
||||
roleId: targetRoleId,
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
create: {
|
||||
adminId: admin.id,
|
||||
roleId: targetRoleId,
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.adminWorkspaceAssignment.upsert({
|
||||
where: {
|
||||
adminId_workspaceId: {
|
||||
adminId: admin.id,
|
||||
workspaceId: defaultWorkspace.id,
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
create: {
|
||||
adminId: admin.id,
|
||||
workspaceId: defaultWorkspace.id,
|
||||
scopeType: AccessScopeType.ALL,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`Backfilled ${admins.length} existing admins with roles and workspace assignments.`);
|
||||
console.log('RBAC seed completed successfully.');
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
Reference in New Issue
Block a user