@@ -560,8 +560,8 @@ describe('Auth', () => {
560560 } ,
561561 } )
562562
563- expect ( result . docs [ 0 ] . value . property ) . toStrictEqual ( 'updated' )
564- expect ( result . docs [ 0 ] . value . property2 ) . toStrictEqual ( 'updated' )
563+ expect ( ( result . docs [ 0 ] ? .value as any ) ? .property ) . toStrictEqual ( 'updated' )
564+ expect ( ( result . docs [ 0 ] ? .value as any ) ? .property2 ) . toStrictEqual ( 'updated' )
565565
566566 expect ( result . docs ) . toHaveLength ( 1 )
567567 } )
@@ -600,6 +600,105 @@ describe('Auth', () => {
600600 } )
601601 } )
602602
603+ describe ( 'Cross-Collection Preference Isolation' , ( ) => {
604+ const adminKey = 'cross-collection-admin'
605+ const publicKey = 'cross-collection-public'
606+ let publicUserToken : string
607+ let publicUserId : number | string
608+ const createdIDs : ( number | string ) [ ] = [ ]
609+
610+ beforeAll ( async ( ) => {
611+ // Admin creates preference
612+ const adminPref = await restClient . POST ( `/payload-preferences/${ adminKey } ` , {
613+ body : JSON . stringify ( { value : { data : 'admin-sensitive' } } ) ,
614+ headers : { Authorization : `JWT ${ token } ` } ,
615+ } )
616+ createdIDs . push ( ( ( await adminPref . json ( ) ) as any ) . doc . id )
617+
618+ // Create and verify public user
619+ const userRes = await restClient . POST ( `/${ publicUsersSlug } ` , {
620+ body : JSON . stringify ( { email : 'crosscollection@test.com' , password : 'test123!' } ) ,
621+ headers : { Authorization : `JWT ${ token } ` } ,
622+ } )
623+ publicUserId = ( ( await userRes . json ( ) ) as any ) . doc . id
624+
625+ const user = await payload . findByID ( {
626+ collection : publicUsersSlug ,
627+ id : publicUserId ,
628+ showHiddenFields : true ,
629+ } )
630+ await restClient . POST ( `/${ publicUsersSlug } /verify/${ ( user as any ) . _verificationToken } ` )
631+
632+ // Login as public user
633+ const login = await restClient . POST ( `/${ publicUsersSlug } /login` , {
634+ body : JSON . stringify ( { email : 'crosscollection@test.com' , password : 'test123!' } ) ,
635+ } )
636+ publicUserToken = ( ( await login . json ( ) ) as any ) . token
637+
638+ // Public user creates preference
639+ const publicPref = await restClient . POST ( `/payload-preferences/${ publicKey } ` , {
640+ body : JSON . stringify ( { value : { data : 'public-data' } } ) ,
641+ headers : { Authorization : `JWT ${ publicUserToken } ` } ,
642+ } )
643+ createdIDs . push ( ( ( await publicPref . json ( ) ) as any ) . doc . id )
644+ } )
645+
646+ afterAll ( async ( ) => {
647+ await Promise . all (
648+ createdIDs . map ( ( id ) =>
649+ payload . delete ( { collection : 'payload-preferences' , id } ) . catch ( ( ) => { } ) ,
650+ ) ,
651+ )
652+ if ( publicUserId ) {
653+ await payload . delete ( { collection : publicUsersSlug , id : publicUserId } ) . catch ( ( ) => { } )
654+ }
655+ } )
656+
657+ it ( 'should only return own preferences via REST find' , async ( ) => {
658+ const res = await restClient . GET ( '/payload-preferences' , {
659+ headers : { Authorization : `JWT ${ publicUserToken } ` } ,
660+ } )
661+ const data : any = await res . json ( )
662+
663+ expect ( data . docs ) . toHaveLength ( 1 )
664+ expect ( data . docs [ 0 ] . user . relationTo ) . toBe ( publicUsersSlug )
665+ expect ( data . docs . some ( ( doc : any ) => doc . user . relationTo === 'users' ) ) . toBe ( false )
666+ } )
667+
668+ it ( 'should not delete other collection preferences via REST' , async ( ) => {
669+ const before = await payload . find ( {
670+ collection : 'payload-preferences' ,
671+ where : { 'user.relationTo' : { equals : 'users' } } ,
672+ } )
673+ expect ( before . docs ) . toHaveLength ( 1 )
674+
675+ await restClient . DELETE ( `/payload-preferences?where[key][equals]=${ adminKey } ` , {
676+ headers : { Authorization : `JWT ${ publicUserToken } ` } ,
677+ } )
678+
679+ const after = await payload . find ( {
680+ collection : 'payload-preferences' ,
681+ where : { 'user.relationTo' : { equals : 'users' } } ,
682+ } )
683+ expect ( after . docs ) . toHaveLength ( 1 )
684+ expect ( ( after . docs [ 0 ] ?. value as any ) ?. data ) . toBe ( 'admin-sensitive' )
685+ } )
686+
687+ it ( 'should isolate preferences by user ID and collection' , async ( ) => {
688+ const publicPrefs = await payload . find ( {
689+ collection : 'payload-preferences' ,
690+ where : { 'user.relationTo' : { equals : publicUsersSlug } } ,
691+ } )
692+ expect ( publicPrefs . docs ) . toHaveLength ( 1 )
693+
694+ const adminPrefs = await payload . find ( {
695+ collection : 'payload-preferences' ,
696+ where : { 'user.relationTo' : { equals : 'users' } } ,
697+ } )
698+ expect ( adminPrefs . docs ) . toHaveLength ( 1 )
699+ } )
700+ } )
701+
603702 describe ( 'Account Locking' , ( ) => {
604703 const userEmail = 'lock@me.com'
605704
0 commit comments