@@ -126,7 +126,12 @@ const service = {
126126 . modify ( 'filterActive' , params . active )
127127 . modify ( 'filterTenantId' , userInfo . tenantId ) ;
128128
129- const userGroups = await tenantService . getUserTenantGroupsAndRoles ( { currentUser : userInfo , headers } , userInfo . tenantId ) ;
129+ let userGroups = [ ] ;
130+ try {
131+ userGroups = await tenantService . getUserTenantGroupsAndRoles ( { currentUser : userInfo , headers } , userInfo . tenantId ) ;
132+ } catch ( err ) {
133+ log . error ( `Failed to fetch tenant groups/roles for tenant ${ userInfo . tenantId } ` , err ) ;
134+ }
130135 const allRoles = await Role . query ( ) . withGraphFetched ( 'permissions' ) ;
131136
132137 for ( const item of items ) {
@@ -137,19 +142,31 @@ const service = {
137142 } else {
138143 // if user has an id, then we fetch whatever forms match the query params
139144 items = await UserFormAccess . query ( ) . modify ( 'filterUserId' , userInfo . id ) . modify ( 'filterFormId' , params . formId ) . modify ( 'filterActive' , params . active ) ;
140- const userGroupsByTenant = new Map ( ) ;
141- const allRoles = await Role . query ( ) . withGraphFetched ( 'permissions' ) ;
142- for ( const item of items ) {
143- if ( item && item . tenantId && Array . isArray ( item . idps ) && item . idps . length === 0 ) {
144- // Group-only tenanted forms need tenant context to look up roles; skip if no headers
145- if ( ! headers ) continue ;
146145
147- if ( ! userGroupsByTenant . has ( item . tenantId ) ) {
148- const userGroups = await tenantService . getUserTenantGroupsAndRoles ( { currentUser : userInfo , headers } , item . tenantId ) ;
149- userGroupsByTenant . set ( item . tenantId , userGroups ) ;
146+ // For single-form permission checks (params.formId set, e.g. hasFormPermissions
147+ // middleware on /form/submit, /user/draft, /user/view), resolve group-based roles
148+ // using the form's own tenantId from form_tenant — not from the request header,
149+ // since those routes never send x-tenant-id by design. This lets legitimate group
150+ // members access the form regardless of which tenant is currently selected in the UI.
151+ //
152+ // For list-all calls (no formId, e.g. "My Forms"), skip resolution: group-only
153+ // forms must only appear when that tenant is actively selected (branch above).
154+ if ( params . formId && headers ) {
155+ const userGroupsByTenant = new Map ( ) ;
156+ const allRoles = await Role . query ( ) . withGraphFetched ( 'permissions' ) ;
157+ for ( const item of items ) {
158+ if ( item && item . tenantId && Array . isArray ( item . idps ) && item . idps . length === 0 ) {
159+ if ( ! userGroupsByTenant . has ( item . tenantId ) ) {
160+ let userGroups = [ ] ;
161+ try {
162+ userGroups = await tenantService . getUserTenantGroupsAndRoles ( { currentUser : userInfo , headers } , item . tenantId ) ;
163+ } catch ( err ) {
164+ log . error ( `Failed to fetch tenant groups/roles for form ${ item . formId } (tenant ${ item . tenantId } )` , err ) ;
165+ }
166+ userGroupsByTenant . set ( item . tenantId , userGroups ) ;
167+ }
168+ await service . populateItemWithTenantRoles ( item , userGroupsByTenant . get ( item . tenantId ) , allRoles ) ;
150169 }
151-
152- await service . populateItemWithTenantRoles ( item , userGroupsByTenant . get ( item . tenantId ) , allRoles ) ;
153170 }
154171 }
155172
0 commit comments