|
| 1 | +import { randomUUID } from 'crypto'; |
| 2 | +import type { Sql } from 'postgres'; |
| 3 | +import { expect } from 'vitest'; |
| 4 | + |
| 5 | +export const preMigration = async (sql: Sql) => { |
| 6 | + const projectId = `test-${randomUUID()}`; |
| 7 | + const tenancyId = randomUUID(); |
| 8 | + const unrestricted = randomUUID(); |
| 9 | + const restrictedWithReason = randomUUID(); |
| 10 | + const restrictedNoReason = randomUUID(); |
| 11 | + |
| 12 | + await sql`INSERT INTO "Project" ("id", "createdAt", "updatedAt", "displayName", "description", "isProductionMode") VALUES (${projectId}, NOW(), NOW(), 'Test', '', false)`; |
| 13 | + await sql`INSERT INTO "Tenancy" ("id", "createdAt", "updatedAt", "projectId", "branchId", "hasNoOrganization") VALUES (${tenancyId}::uuid, NOW(), NOW(), ${projectId}, 'main', 'TRUE'::"BooleanTrue")`; |
| 14 | + |
| 15 | + // Unrestricted user (valid: false + null reason) |
| 16 | + await sql`INSERT INTO "ProjectUser" ("projectUserId", "tenancyId", "mirroredProjectId", "mirroredBranchId", "createdAt", "updatedAt", "lastActiveAt") VALUES (${unrestricted}::uuid, ${tenancyId}::uuid, ${projectId}, 'main', NOW(), NOW(), NOW())`; |
| 17 | + |
| 18 | + // Restricted with reason |
| 19 | + await sql`INSERT INTO "ProjectUser" ("projectUserId", "tenancyId", "mirroredProjectId", "mirroredBranchId", "createdAt", "updatedAt", "lastActiveAt", "restrictedByAdmin", "restrictedByAdminReason") VALUES (${restrictedWithReason}::uuid, ${tenancyId}::uuid, ${projectId}, 'main', NOW(), NOW(), NOW(), true, 'spam')`; |
| 20 | + |
| 21 | + // Restricted without reason |
| 22 | + await sql`INSERT INTO "ProjectUser" ("projectUserId", "tenancyId", "mirroredProjectId", "mirroredBranchId", "createdAt", "updatedAt", "lastActiveAt", "restrictedByAdmin") VALUES (${restrictedNoReason}::uuid, ${tenancyId}::uuid, ${projectId}, 'main', NOW(), NOW(), NOW(), true)`; |
| 23 | + |
| 24 | + return { projectId, tenancyId, unrestricted, restrictedWithReason, restrictedNoReason }; |
| 25 | +}; |
| 26 | + |
| 27 | +export const postMigration = async (sql: Sql, ctx: Awaited<ReturnType<typeof preMigration>>) => { |
| 28 | + // Existing valid rows should still be there |
| 29 | + const rows = await sql` |
| 30 | + SELECT "projectUserId", "restrictedByAdmin", "restrictedByAdminReason", "restrictedByAdminPrivateDetails" |
| 31 | + FROM "ProjectUser" |
| 32 | + WHERE "mirroredProjectId" = ${ctx.projectId} |
| 33 | + ORDER BY "projectUserId" |
| 34 | + `; |
| 35 | + expect(rows).toHaveLength(3); |
| 36 | + |
| 37 | + for (const row of rows) { |
| 38 | + expect(row.restrictedByAdminPrivateDetails).toBeNull(); |
| 39 | + } |
| 40 | + |
| 41 | + // Restricted user can have private details set |
| 42 | + await sql`UPDATE "ProjectUser" SET "restrictedByAdminPrivateDetails" = 'internal notes' WHERE "projectUserId" = ${ctx.restrictedWithReason}::uuid`; |
| 43 | + |
| 44 | + // INVALID: unrestricted user with a reason should fail |
| 45 | + await expect(sql` |
| 46 | + UPDATE "ProjectUser" SET "restrictedByAdminReason" = 'should fail' WHERE "projectUserId" = ${ctx.unrestricted}::uuid |
| 47 | + `).rejects.toThrow(/ProjectUser_restricted_by_admin_consistency/); |
| 48 | + |
| 49 | + // INVALID: unrestricted user with private details should fail |
| 50 | + await expect(sql` |
| 51 | + UPDATE "ProjectUser" SET "restrictedByAdminPrivateDetails" = 'should fail' WHERE "projectUserId" = ${ctx.unrestricted}::uuid |
| 52 | + `).rejects.toThrow(/ProjectUser_restricted_by_admin_consistency/); |
| 53 | + |
| 54 | + // VALID: new restricted user with all fields |
| 55 | + const newUser = randomUUID(); |
| 56 | + await sql`INSERT INTO "ProjectUser" ("projectUserId", "tenancyId", "mirroredProjectId", "mirroredBranchId", "createdAt", "updatedAt", "lastActiveAt", "restrictedByAdmin", "restrictedByAdminReason", "restrictedByAdminPrivateDetails") VALUES (${newUser}::uuid, ${ctx.tenancyId}::uuid, ${ctx.projectId}, 'main', NOW(), NOW(), NOW(), true, 'test', 'details')`; |
| 57 | + |
| 58 | + // VALID: un-restricting clears reason and details |
| 59 | + await sql`UPDATE "ProjectUser" SET "restrictedByAdmin" = false, "restrictedByAdminReason" = NULL, "restrictedByAdminPrivateDetails" = NULL WHERE "projectUserId" = ${newUser}::uuid`; |
| 60 | +}; |
0 commit comments