[Task] Users API: `GET /v1/users/filter` should be able to return each user's direct roles
@hassandotcms is already working on this.
Since Aug 26, 2026.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Context
The Angular Users portlet list (#36930 arc) shows each user's roles beyond the default access roles in a column. GET /api/v1/users/filter returns no role data — items are user.toMap() plus an optional requestPassword flag (UserPaginator#addRequestPasswordAttr).
The FE therefore fans out one GET /api/v1/roles/users/{userId} per row after every list load (dot-users-list.store.ts:107-124): 40 extra requests per page at the default per_page=40, each paying REST auth init. That endpoint also returns explicit and implicit roles (loadRolesForUser(userId) defaults includeImplicitRoles=true), so the FE filters access roles and the personal role out client-side.
Legacy reference: the Dojo Users portlet list grid had no roles column; its Roles tab listed direct memberships only (UserAjax#getUserRoles → loadRolesForUser(userId, false)).
Requirements
- A single
GET /api/v1/users/filterrequest can return, per user, the user's directly assigned roles — inherited/implicit roles excluded (legacy parity with the Roles tab, and consistent with the direct-membership semantics of the/v1/roles/{roleid}/users*endpoints from #37077 and #37070; inherited roles cannot be removed from a user, so listing them alongside a Remove action would mislead) - Each role entry must carry at least
id,name, androleKey.idis required because roles created in the Roles portlet may have no key (#37209) - The behavior is opt-in: callers that do not ask for roles get a byte-identical response to today.
UserPaginatoris shared; no extra payload or DB work for callers that don't need roles - All existing
filterparameters (query,roleKey, paging, sorting,includeAnonymous,includeDefault,assetInode/permission) keep working unchanged in combination - No change to authorization of the endpoint
- OpenAPI documents the new option and the per-item role shape; regenerated
openapi.yamlcommitted
Acceptance Criteria
- Roles returned per user when requested; absent when not requested (existing payload unchanged)
- Only direct memberships are listed; a role held via inheritance (child of a held role, or the implicit CMS Anonymous role) is not
- Keyless roles appear with
idandname,roleKeynull/absent - Integration tests: opt-in on/off, direct-vs-inherited, keyless role, combined with
roleKeyfilter and paging - Existing
UserResourceIntegrationTestand PostmanUserResourcecollection still green - OpenAPI updated and regenerated
Out of scope
- Changing
GET /v1/roles/users/{userIdOrEmail} - Inherited/implicit role expansion in the list (could be a later opt-in if a use case appears)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.