Context
The Angular Roles and Tools portlet (FE task #36930) needs to update existing roles — including changing the parent (drag-to-reparent in the roles tree, and the Parent field in the Edit Role dialog). The current REST surface only offers POST /v1/roles for creating roles. The only path to update an existing role today is DWR RoleAjax#updateRole (dotCMS/src/main/java/com/dotmarketing/business/ajax/RoleAjax.java, ~line 411), which the Angular portlet is dropping.
Add a PUT /v1/roles/{roleId} endpoint that mirrors the existing POST /v1/roles body shape (RoleForm), so the Angular Edit Role dialog and drag-to-reparent can go through v1 REST end-to-end.
Endpoint Spec
| Field |
Value |
| HTTP |
PUT |
| Path |
/v1/roles/{roleId} |
| Class#method |
com.dotcms.rest.api.v1.system.role.RoleResource#updateRole (new) |
| Path param |
roleId — existing role ID |
| Request body |
RoleForm — roleName*, roleKey, parentRoleId, canEditUsers, canEditPermissions, canEditLayouts, description |
| Response |
RoleResponseEntityView (role.toMap()) — same shape POST already returns |
| Auth gates |
requiredBackendUser=true, requiredPortlet("roles"), admin check via roleAPI.doesUserHaveRole(user, cmsAdminRole) |
| OpenAPI |
@Operation annotation required; swagger-maven-plugin regenerated openapi.yaml committed |
Behavior
- Load the role by
roleId; 404 if not found
- Update fields from the form
- Handle
parentRoleId:
- Non-null → validate parent exists (
roleAPI.loadRoleById(parentRoleId)), reject with 400 if parent is a descendant of the role being edited (would create a cycle), then role.setParent(parentRole.getId())
- Null →
role.setParent(role.getId()) (root)
- Persist via
roleAPI.save(role)
- Surface these existing exceptions as structured errors:
DuplicateRoleKeyException → 409 with field-level error on roleKey
DuplicateRoleException / RoleNameException → 409 with field-level error on roleName
- Do not touch
system or locked flags — system roles rejected with 403
Acceptance Criteria
References
Context
The Angular Roles and Tools portlet (FE task #36930) needs to update existing roles — including changing the parent (drag-to-reparent in the roles tree, and the Parent field in the Edit Role dialog). The current REST surface only offers
POST /v1/rolesfor creating roles. The only path to update an existing role today is DWRRoleAjax#updateRole(dotCMS/src/main/java/com/dotmarketing/business/ajax/RoleAjax.java, ~line 411), which the Angular portlet is dropping.Add a
PUT /v1/roles/{roleId}endpoint that mirrors the existingPOST /v1/rolesbody shape (RoleForm), so the Angular Edit Role dialog and drag-to-reparent can go through v1 REST end-to-end.Endpoint Spec
PUT/v1/roles/{roleId}com.dotcms.rest.api.v1.system.role.RoleResource#updateRole(new)roleId— existing role IDRoleForm—roleName*,roleKey,parentRoleId,canEditUsers,canEditPermissions,canEditLayouts,descriptionRoleResponseEntityView(role.toMap()) — same shape POST already returnsrequiredBackendUser=true,requiredPortlet("roles"), admin check viaroleAPI.doesUserHaveRole(user, cmsAdminRole)@Operationannotation required;swagger-maven-pluginregeneratedopenapi.yamlcommittedBehavior
roleId; 404 if not foundparentRoleId:roleAPI.loadRoleById(parentRoleId)), reject with 400 if parent is a descendant of the role being edited (would create a cycle), thenrole.setParent(parentRole.getId())role.setParent(role.getId())(root)roleAPI.save(role)DuplicateRoleKeyException→ 409 with field-level error onroleKeyDuplicateRoleException/RoleNameException→ 409 with field-level error onroleNamesystemorlockedflags — system roles rejected with 403Acceptance Criteria
PUT /v1/roles/{roleId}implemented with the spec above@OperationOpenAPI doc added on the new methodswagger-maven-pluginregenerateddotCMS/src/main/webapp/WEB-INF/openapi/openapi.yamlcommitteddotcms-integration/src/test/.../RoleResourceIntegrationTest.java(or nearest existing) covering: happy-path update, reparent to a different parent, reparent to root (null), attempt to create a cycle (→ 400), attempt to edit a system role (→ 403), duplicate key (→ 409), duplicate name (→ 409), missing role (→ 404), non-admin caller (→ 403), missing portlet gate (→ 403)POST /v1/rolesand DWRupdateRoleremain functional (no breaking changes)References
RoleAjax#updateRoleindotCMS/src/main/java/com/dotmarketing/business/ajax/RoleAjax.javacom.dotcms.rest.api.v1.system.role.RoleResource#addNewRole(POST — sameRoleFormshape, same auth pattern)