Skip to content

#36939: feat(roles): add DELETE /v1/roles/{roleId} for role deletion - #37042

Open
hassandotcms wants to merge 4 commits into
mainfrom
36939-roles-api-delete-role
Open

#36939: feat(roles): add DELETE /v1/roles/{roleId} for role deletion#37042
hassandotcms wants to merge 4 commits into
mainfrom
36939-roles-api-delete-role

Conversation

@hassandotcms

@hassandotcms hassandotcms commented Aug 13, 2026

Copy link
Copy Markdown
Member

Adds DELETE /v1/roles/{roleId}, replacing DWR RoleAjax#deleteRole for the Angular portlet rewrite (#36909).

Delete cascades, same as legacy RoleAPIImpl.delete: role removed from all users, permissions deleted, layouts detached. Cascading (rather than the 409-on-users the issue suggested) keeps legacy behavior intact; the blast radius is returned as usersAffected (direct assignments) so the FE can warn before calling (#36930). Returns {deleted, roleId, usersAffected}.

Blocks: children → 409, workflow-action Assign To reference → 409 (pre-checked; inside delete() it degrades to a generic error), system/locked → 403. Auth: backend user + roles portlet + CMS admin (legacy gated on users-portlet only; tightened since this is destructive and token-scriptable — DWR path untouched until Dojo removal).

Testing

10 new ITs in RoleResourceIntegrationTest, 26/26 green: happy path, cascade pinned (user/permission/layout rows verified gone), both 409s, 403 system/locked, 404, 401, both auth 403s.

resolved #36939

…eparent

* New v1 REST endpoint replacing DWR RoleAjax#updateRole for the Angular
  Roles & Tools portlet (epic #36909): updates name, key, description,
  can-grant flags and parent; null parentRoleId reparents to root (DWR parity)
* Guards: 404 missing role/parent, 403 system/locked roles, 400 invalid name
  and reparent cycles (net-new corruption guard), 409 duplicate key/name
* Auth: backend user + roles portlet + CMS admin, shared gate extracted and
  reused by POST /v1/roles (behavior unchanged, regression-tested)
* RoleHelper promoted to @ApplicationScoped CDI with the update logic under
  @WrapInTransaction; response reuses RoleView/ResponseEntityRoleDetailView
  (same shape as GET /v1/roles/{roleid})
* 15 integration tests (TDD red->green), registered in MainSuite3a
* Regenerated openapi.yaml
…th a test

* OpenAPI description now spells out that PUT overwrites every field:
  omitted booleans reset to false, omitted roleKey/description are cleared,
  omitted parentRoleId reparents to root (DWR parity)
* New IT testUpdateRole_fullReplace_omittedFieldsAreReset pins the contract
  so drift to merge/PATCH semantics is a deliberate, test-breaking change
* Addresses claude[bot] review finding on PR #37012
Cascading delete (legacy RoleAPIImpl.delete parity): removes the role from
all users, strips its permissions, detaches its layouts. Blocks only where
legacy blocks: children (409), workflow-action Assign To references (409,
pre-checked because delete() re-wraps the check into a generic failure),
system/locked roles (403). Response reports usersAffected as the cascade
blast radius via a new typed RoleDeletionView.
@github-actions github-actions Bot added the Area : Backend PR changes Java/Maven backend code label Aug 13, 2026
@claude

claude Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Claude finished @hassandotcms's task in 2m 38s —— View job


Code Review — DELETE /v1/roles/{roleId}

Reviewed the delete path end-to-end: RoleHelper.deleteRole, the pre-flight checks, the RoleResource endpoint, the immutable view, and the 10 new ITs against legacy RoleAPIImpl.delete.

This is a clean, well-tested change. Cascade parity is correctly preserved, the auth gate is appropriately tightened, exception→HTTP mapping is all in place (DotConflictExceptionMapper → 409, DoesNotExistException → 404, DotSecurityException → 403), and the audit lines correctly carry name/key/blast-radius since the row is gone post-delete. A couple of non-blocking notes below.

New Issues

  • 🟡 Medium: RoleHelper.java:200 & :235 — the workflow-dependency scan runs twice on every successful delete. checkNoDependentWorkflowActions walks all schemes × actions as a pre-flight, then roleAPI.delete()findDependentWorkflowActions (RoleAPIImpl.java:194) walks them again inside the transaction. For instances with many schemes/actions this doubles that work on the delete path. It's a deliberate trade for the structured 409 (the note at RoleHelper.java:167-169 explains why the inner one can't be relied on), so acceptable — just flagging the cost.

  • 🟡 Medium: RoleHelper.java:193-198 — the children pre-check runs outside roleAPI.delete()'s transaction, and delete() re-validates system/locked (throws DotStateException) but does not re-check for children. Assumption: a child role could be created under this role between the pre-flight read and the delete commit. What to verify: whether roleFactory.delete() has an FK/child guard that would fail such a delete — if not, a concurrently-added child would be orphaned pointing at a deleted parent. Low probability and matches legacy behavior, so non-blocking. Fix this →

Notes (non-issues, for confirmation)

  • usersAffected uses findUserIdsForRole(role) (direct assignments only), which matches both the AbstractRoleDeletionView doc and the removal set delete() acts on. Test testDeleteRole_withUsersAssigned_cascades pins == 1. ✅
  • Endpoint returns ResponseEntityRoleDeletionView directly (not Response.ok(...)), consistent with updateRole; the payload is the standard {entity: {...}} envelope, not a bare {deleted, roleId, usersAffected} as the PR description implies — worth confirming the FE ([Task] Roles and Tools: Angular implementation + backend wiring #36930) expects the envelope. ✅
  • New workflow lambda role.getId().equals(action.getNextAssign()) is null-safe, unlike legacy's action.getNextAssign().equals(role.getId()). ✅

No blocking issues. The two Medium items are worth a look but do not block merge.

36939-roles-api-delete-role

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI: Safe To Rollback Area : Backend PR changes Java/Maven backend code

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

[Task] Roles API: add DELETE /v1/roles/{roleId} for role deletion

1 participant