import { MigrationInterface, QueryRunner } from "typeorm"; type CrudResource = { old: string; group: string; titles: { create: string; read: string; update: string; delete: string }; }; const CRUD_RESOURCES: CrudResource[] = [ { old: "services", group: "services", titles: { create: "ایجاد سرویس‌ها", read: "مشاهده سرویس‌ها", update: "ویرایش سرویس‌ها", delete: "حذف سرویس‌ها" }, }, { old: "customers", group: "customers", titles: { create: "ایجاد مشتریان", read: "مشاهده مشتریان", update: "ویرایش مشتریان", delete: "حذف مشتریان" }, }, { old: "agents", group: "representatives", titles: { create: "ایجاد نمایندگان", read: "مشاهده نمایندگان", update: "ویرایش نمایندگان", delete: "حذف نمایندگان" }, }, { old: "developers", group: "users", titles: { create: "ایجاد توسعه‌دهندگان", read: "مشاهده توسعه‌دهندگان", update: "ویرایش توسعه‌دهندگان", delete: "حذف توسعه‌دهندگان", }, }, { old: "invoices", group: "financial", titles: { create: "ایجاد صورتحساب‌ها", read: "مشاهده صورتحساب‌ها", update: "ویرایش صورتحساب‌ها", delete: "حذف صورتحساب‌ها" }, }, { old: "transactions", group: "financial", titles: { create: "ایجاد تراکنش‌ها", read: "مشاهده تراکنش‌ها", update: "ویرایش تراکنش‌ها", delete: "حذف تراکنش‌ها" }, }, { old: "discounts", group: "financial", titles: { create: "ایجاد تخفیف‌ها", read: "مشاهده تخفیف‌ها", update: "ویرایش تخفیف‌ها", delete: "حذف تخفیف‌ها" }, }, { old: "admins", group: "users", titles: { create: "ایجاد ادمین‌ها", read: "مشاهده ادمین‌ها", update: "ویرایش ادمین‌ها", delete: "حذف ادمین‌ها" }, }, { old: "tickets", group: "support", titles: { create: "ایجاد تیکت‌ها", read: "مشاهده تیکت‌ها", update: "ویرایش تیکت‌ها", delete: "حذف تیکت‌ها" }, }, { old: "criticisms", group: "other", titles: { create: "ایجاد انتقادات", read: "مشاهده انتقادات", update: "ویرایش انتقادات", delete: "حذف انتقادات" }, }, { old: "contacts_us", group: "other", titles: { create: "ایجاد تماس با ما", read: "مشاهده تماس با ما", update: "ویرایش تماس با ما", delete: "حذف تماس با ما" }, }, { old: "advertisements", group: "content", titles: { create: "ایجاد تبلیغات", read: "مشاهده تبلیغات", update: "ویرایش تبلیغات", delete: "حذف تبلیغات" }, }, { old: "announcements", group: "content", titles: { create: "ایجاد اطلاعیه‌ها", read: "مشاهده اطلاعیه‌ها", update: "ویرایش اطلاعیه‌ها", delete: "حذف اطلاعیه‌ها" }, }, { old: "blogs", group: "content", titles: { create: "ایجاد بلاگ‌ها", read: "مشاهده بلاگ‌ها", update: "ویرایش بلاگ‌ها", delete: "حذف بلاگ‌ها" }, }, { old: "learnings", group: "content", titles: { create: "ایجاد آموزش‌ها", read: "مشاهده آموزش‌ها", update: "ویرایش آموزش‌ها", delete: "حذف آموزش‌ها" }, }, { old: "settings", group: "other", titles: { create: "ایجاد تنظیمات", read: "مشاهده تنظیمات", update: "ویرایش تنظیمات", delete: "حذف تنظیمات" }, }, { old: "bank_accounts", group: "financial", titles: { create: "ایجاد حساب‌های بانکی", read: "مشاهده حساب‌های بانکی", update: "ویرایش حساب‌های بانکی", delete: "حذف حساب‌های بانکی", }, }, { old: "payments", group: "financial", titles: { create: "ایجاد پرداخت‌ها", read: "مشاهده پرداخت‌ها", update: "ویرایش پرداخت‌ها", delete: "حذف پرداخت‌ها" }, }, { old: "support_plan", group: "support", titles: { create: "ایجاد پلن پشتیبانی", read: "مشاهده پلن پشتیبانی", update: "ویرایش پلن پشتیبانی", delete: "حذف پلن پشتیبانی", }, }, { old: "reseller", group: "representatives", titles: { create: "ایجاد نمایندگی فروش", read: "مشاهده نمایندگی فروش", update: "ویرایش نمایندگی فروش", delete: "حذف نمایندگی فروش", }, }, { old: "workspace", group: "task_manager", titles: { create: "ایجاد فضای کار", read: "مشاهده فضای کار", update: "ویرایش فضای کار", delete: "حذف فضای کار" }, }, { old: "project", group: "task_manager", titles: { create: "ایجاد پروژه", read: "مشاهده پروژه", update: "ویرایش پروژه", delete: "حذف پروژه" }, }, { old: "task", group: "task_manager", titles: { create: "ایجاد وظیفه", read: "مشاهده وظیفه", update: "ویرایش وظیفه", delete: "حذف وظیفه" }, }, { old: "task_phase", group: "task_manager", titles: { create: "ایجاد فاز وظیفه", read: "مشاهده فاز وظیفه", update: "ویرایش فاز وظیفه", delete: "حذف فاز وظیفه" }, }, ]; const SINGLE_PERMISSIONS: { name: string; group: string; title: string }[] = [ { name: "logs", group: "other", title: "لاگ‌ها" }, { name: "manage_sso_clients", group: "other", title: "مدیریت کلاینت‌های SSO" }, { name: "dmenu", group: "products", title: "دی‌منو" }, { name: "dkala", group: "products", title: "دی‌کالا" }, { name: "dpage", group: "products", title: "دی‌پیج" }, { name: "dmail", group: "products", title: "دی‌میل" }, { name: "view_all_workspaces", group: "task_manager", title: "مشاهده همه فضاهای کار" }, { name: "view_all_projects", group: "task_manager", title: "مشاهده همه پروژه‌ها" }, ]; const NEW_ENUM_VALUES = [ ...CRUD_RESOURCES.flatMap((r) => [`${r.old}_create`, `${r.old}_read`, `${r.old}_update`, `${r.old}_delete`]), ...SINGLE_PERMISSIONS.map((p) => p.name), ]; const OLD_ENUM_VALUES = [ "services", "customers", "agents", "developers", "invoices", "transactions", "discounts", "admins", "tickets", "criticisms", "contacts_us", "advertisements", "announcements", "blogs", "learnings", "logs", "settings", "bank_accounts", "payments", "manage_sso_clients", "support_plan", "dmenu", "dkala", "dpage", "dmail", "reseller", "workspace", "view_all_workspaces", "project", "view_all_projects", "task", "task_phase", ]; export class RefactorPermissionsToCrudAndGroup1784500000000 implements MigrationInterface { name = "RefactorPermissionsToCrudAndGroup1784500000000"; public async up(queryRunner: QueryRunner): Promise { await queryRunner.query( `CREATE TYPE "public"."permission_group_enum" AS ENUM('services', 'customers', 'users', 'financial', 'content', 'support', 'other', 'products', 'representatives', 'task_manager')`, ); await queryRunner.query(`ALTER TABLE "permission" ADD "group" "public"."permission_group_enum"`); await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "name" TYPE text USING "name"::text`); await queryRunner.query(`DROP TYPE "public"."permission_name_enum"`); for (const resource of CRUD_RESOURCES) { const oldPerm = await queryRunner.query(`SELECT id FROM "permission" WHERE "name" = $1`, [resource.old]); if (!oldPerm.length) continue; const oldId = oldPerm[0].id as string; const actions = ["create", "read", "update", "delete"] as const; for (const action of actions) { const newName = `${resource.old}_${action}`; const title = resource.titles[action]; const inserted = await queryRunner.query( `INSERT INTO "permission" ("id", "name", "title", "group", "createdAt", "updatedAt") VALUES (uuid_generate_v4(), $1, $2, $3, NOW(), NOW()) RETURNING id`, [newName, title, resource.group], ); const newId = inserted[0].id as string; await queryRunner.query( `INSERT INTO "role_permission_relation" ("roleId", "permissionId") SELECT "roleId", $1 FROM "role_permission_relation" WHERE "permissionId" = $2 ON CONFLICT ("roleId", "permissionId") DO NOTHING`, [newId, oldId], ); } await queryRunner.query(`DELETE FROM "role_permission_relation" WHERE "permissionId" = $1`, [oldId]); await queryRunner.query(`DELETE FROM "permission" WHERE "id" = $1`, [oldId]); } for (const perm of SINGLE_PERMISSIONS) { await queryRunner.query(`UPDATE "permission" SET "group" = $1, "title" = COALESCE(NULLIF("title", ''), $2) WHERE "name" = $3`, [ perm.group, perm.title, perm.name, ]); } await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "group" SET NOT NULL`); const enumList = NEW_ENUM_VALUES.map((v) => `'${v}'`).join(", "); await queryRunner.query(`CREATE TYPE "public"."permission_name_enum" AS ENUM(${enumList})`); await queryRunner.query( `ALTER TABLE "permission" ALTER COLUMN "name" TYPE "public"."permission_name_enum" USING "name"::"public"."permission_name_enum"`, ); } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "name" TYPE text USING "name"::text`); await queryRunner.query(`DROP TYPE "public"."permission_name_enum"`); for (const resource of CRUD_RESOURCES) { // const actions = ["create", "read", "update", "delete"]; const crudRows = await queryRunner.query(`SELECT id, name FROM "permission" WHERE "name" LIKE $1`, [`${resource.old}_%`]); if (!crudRows.length) continue; const inserted = await queryRunner.query( `INSERT INTO "permission" ("id", "name", "title", "group", "createdAt", "updatedAt") VALUES (uuid_generate_v4(), $1, $2, $3, NOW(), NOW()) RETURNING id`, [resource.old, resource.old, resource.group], ); const oldId = inserted[0].id as string; for (const row of crudRows) { await queryRunner.query( `INSERT INTO "role_permission_relation" ("roleId", "permissionId") SELECT "roleId", $1 FROM "role_permission_relation" WHERE "permissionId" = $2 ON CONFLICT ("roleId", "permissionId") DO NOTHING`, [oldId, row.id], ); await queryRunner.query(`DELETE FROM "role_permission_relation" WHERE "permissionId" = $1`, [row.id]); await queryRunner.query(`DELETE FROM "permission" WHERE "id" = $1`, [row.id]); } } const oldEnumList = OLD_ENUM_VALUES.map((v) => `'${v}'`).join(", "); await queryRunner.query(`CREATE TYPE "public"."permission_name_enum" AS ENUM(${oldEnumList})`); await queryRunner.query( `ALTER TABLE "permission" ALTER COLUMN "name" TYPE "public"."permission_name_enum" USING "name"::"public"."permission_name_enum"`, ); await queryRunner.query(`ALTER TABLE "permission" DROP COLUMN "group"`); await queryRunner.query(`DROP TYPE "public"."permission_group_enum"`); } }