@@ -23,7 +23,10 @@ import {
2323 userStats ,
2424 workspace ,
2525} from '@sim/db/schema'
26+ import { assertDisposableTestDatabaseUrl } from '@sim/db/testing/test-infrastructure'
2627import { generateId } from '@sim/utils/id'
28+ import { generateRandomHex } from '@sim/utils/random'
29+ import { normalizeEmail } from '@sim/utils/string'
2730import { hashPassword } from 'better-auth/crypto'
2831import { inArray } from 'drizzle-orm'
2932import { getCredentialGroupProviderAdapter } from '@/lib/credential-groups/provider-registry'
@@ -65,11 +68,7 @@ import {
6568 * Seeds the organization `test-org-redesign-e2e.ts` runs against. Ids are stable and a rerun starts
6669 * over, so a failed run can be repeated against the same database.
6770 */
68- const databaseUrl = process . env . DATABASE_URL
69- if ( ! databaseUrl ) throw new Error ( 'DATABASE_URL must be set' )
70- if ( ! / t e s t / i. test ( new URL ( databaseUrl ) . pathname ) ) {
71- throw new Error ( 'Seed only a dedicated test database' )
72- }
71+ assertDisposableTestDatabaseUrl ( process . env . DATABASE_URL ?? '' )
7372
7473const CREDENTIAL_GROUP_ID = 'org-redesign-credential-group'
7574const allUserIds = EVERYONE . map ( ( { userId } ) => userId )
@@ -78,43 +77,23 @@ const passwordHash = await hashPassword(PASSWORD)
7877
7978/** Workspace access per viewer: admins hold all of it, members only what they were given. */
8079function workspacePermissions ( ) {
81- const rows : {
82- id : string
83- userId : string
84- entityType : 'workspace'
85- entityId : string
80+ const rows = (
81+ viewers : readonly ( typeof MEMBER | typeof ADMIN | typeof OWNER ) [ ] ,
82+ entityId : string ,
8683 permissionType : 'admin' | 'write'
87- } [ ] = [ ]
88- for ( const { id : entityId } of WORKSPACES ) {
89- for ( const viewer of [ OWNER , ADMIN ] ) {
90- rows . push ( {
91- id : `${ entityId } -${ viewer . key } ` ,
92- userId : viewer . userId ,
93- entityType : 'workspace' ,
94- entityId,
95- permissionType : 'admin' ,
96- } )
97- }
98- }
99- for ( const viewer of [ MEMBER , CONNECTED ] ) {
100- rows . push (
101- {
102- id : `${ MEMBER_ADMIN_WORKSPACE . id } -${ viewer . key } ` ,
103- userId : viewer . userId ,
104- entityType : 'workspace' ,
105- entityId : MEMBER_ADMIN_WORKSPACE . id ,
106- permissionType : 'admin' ,
107- } ,
108- {
109- id : `${ MEMBER_WRITE_WORKSPACE . id } -${ viewer . key } ` ,
110- userId : viewer . userId ,
111- entityType : 'workspace' ,
112- entityId : MEMBER_WRITE_WORKSPACE . id ,
113- permissionType : 'write' ,
114- }
115- )
116- }
117- return rows
84+ ) =>
85+ viewers . map ( ( { key, userId } ) => ( {
86+ id : `${ entityId } -${ key } ` ,
87+ userId,
88+ entityType : 'workspace' as const ,
89+ entityId,
90+ permissionType,
91+ } ) )
92+ return [
93+ ...WORKSPACES . flatMap ( ( { id } ) => rows ( [ OWNER , ADMIN ] , id , 'admin' ) ) ,
94+ ...rows ( [ MEMBER , CONNECTED ] , MEMBER_ADMIN_WORKSPACE . id , 'admin' ) ,
95+ ...rows ( [ MEMBER , CONNECTED ] , MEMBER_WRITE_WORKSPACE . id , 'write' ) ,
96+ ]
11897}
11998
12099/** The numbered rows sort after the named ones, and creators and activity vary across them. */
@@ -164,7 +143,7 @@ await db.transaction(async (tx) => {
164143 id : userId ,
165144 email,
166145 name,
167- normalizedEmail : email . toLowerCase ( ) ,
146+ normalizedEmail : normalizeEmail ( email ) ,
168147 emailVerified : true ,
169148 createdAt : now ,
170149 updatedAt : now ,
@@ -268,26 +247,22 @@ await db.transaction(async (tx) => {
268247 membershipMode : 'explicit' ,
269248 } ,
270249 ] )
271- await tx . insert ( permissionGroupMember ) . values ( [
272- ...[ MEMBER , CONNECTED , ...FILLERS ] . map ( ( { key, userId } ) => ( {
273- id : `org-redesign-group-member-${ key } ` ,
274- permissionGroupId : STANDARD_GROUP_ID ,
275- organizationId : ORGANIZATION_ID ,
276- userId,
277- } ) ) ,
278- {
279- id : `org-redesign-group-member-${ NARROW . key } ` ,
280- permissionGroupId : NARROW_GROUP_ID ,
281- organizationId : ORGANIZATION_ID ,
282- userId : NARROW . userId ,
283- } ,
284- ...[ OWNER , ADMIN ] . map ( ( { key, userId } ) => ( {
285- id : `org-redesign-group-member-${ key } ` ,
286- permissionGroupId : FULL_GROUP_ID ,
287- organizationId : ORGANIZATION_ID ,
288- userId,
289- } ) ) ,
290- ] )
250+ await tx . insert ( permissionGroupMember ) . values (
251+ (
252+ [
253+ [ STANDARD_GROUP_ID , [ MEMBER , CONNECTED , ...FILLERS ] ] ,
254+ [ NARROW_GROUP_ID , [ NARROW ] ] ,
255+ [ FULL_GROUP_ID , [ OWNER , ADMIN ] ] ,
256+ ] as const
257+ ) . flatMap ( ( [ permissionGroupId , people ] ) =>
258+ people . map ( ( { key, userId } ) => ( {
259+ id : `org-redesign-group-member-${ key } ` ,
260+ permissionGroupId,
261+ organizationId : ORGANIZATION_ID ,
262+ userId,
263+ } ) )
264+ )
265+ )
291266
292267 for ( const { id, name } of WORKSPACES ) {
293268 await tx . insert ( project ) . values ( {
@@ -413,7 +388,7 @@ await db.transaction(async (tx) => {
413388 credentialGroupId : CREDENTIAL_GROUP_ID ,
414389 email : CONNECTED . email ,
415390 status : 'completed' ,
416- invitationTokenHash : generateId ( ) . replaceAll ( '-' , '' ) . repeat ( 2 ) ,
391+ invitationTokenHash : generateRandomHex ( 64 ) ,
417392 invitationExpiresAt : new Date ( now . getTime ( ) + 86_400_000 ) ,
418393 invitedAt : now ,
419394 } )
0 commit comments