Skip to content

NMS-20106: versioned user management API and PrimeVue Manage Users page - #8713

Open
joseanesONMS wants to merge 6 commits into
developfrom
jira/NMS-20106-manage-users-primevue
Open

NMS-20106: versioned user management API and PrimeVue Manage Users page#8713
joseanesONMS wants to merge 6 commits into
developfrom
jira/NMS-20106-manage-users-primevue

Conversation

@joseanesONMS

Copy link
Copy Markdown

NMS-20106: a versioned user management API (/api/v2/users) so users can be provisioned by external tooling, and a PrimeVue Manage Users page that is a straight visualization of it. users.xml stays the system of record via the existing UserManager; fields the API does not expose (XMPP among them, deliberately hidden in the UI) and the password survive updates untouched.

  • Endpoints: list/get/create/update/set-password/rename/delete plus available-roles, admin-only via new Spring Security rules and in-code checks.
  • Responses never contain the password hash in any form (the v1 API returns it to admins).
  • The admin/rtc delete and rename protections and the admin ROLE_ADMIN-retention guard are enforced server-side; the legacy page only hid the buttons.
  • Requests are validated up front (ids, roles, time zones, duty schedule grammar, comments markup) and applied to a detached copy, so a rejected request leaves no partial state, while hand-edited values are grandfathered so files never become uneditable.
  • The page validates fields inline against the same rules and shows API rejections inside the dialogs.
  • 22 integration tests (mock managers, users.xml never touched) plus Vitest store/dialog tests; verified end to end against a local instance including byte-level users.xml restoration.

Adds /api/v2/users (interface + impl following the v2 conventions):
list/get/create/update, dedicated password and rename endpoints, delete,
and available-roles — all admin-only via new Spring Security rules plus
in-code checks. users.xml stays the system of record: updates apply only
the exposed fields, so contact types the API does not carry (XMPP among
them) and the password survive untouched, and passwords are stored
salted via the existing UserManager hashing. Unlike the legacy JSPs,
which only hid the buttons, the admin/rtc delete and rename protections
are enforced server-side; responses never include the password hash
(the v1 API returns it to admins).

The new Manage Users page (ui/#/admin/users) is a straight visualization
of that API: users table without the XMPP column, add/edit dialog with
role assignment, password and rename dialogs, and delete disabled for
the protected system accounts. The Manage Users menu entry now points at
the new page.
Fixes from self-review. The list fields of UserDto now default to null
so a request that omits them genuinely preserves roles and duty
schedules (empty-list defaults made the preservation guards dead code
and a partial update wiped both). Mutations validate the whole request
first and then apply it to a detached copy of the stored user, so a
rejected request can no longer leave partial changes in UserManager's
shared in-memory state; a failed create rolls the phantom map entry
back, and a service-level lock closes the check-then-act races. Duty
schedule validation accepts overnight ranges (legacy wrote MoTu2000-800
and hand-edited files contain them — rejecting those made such users
uneditable), user ids reject characters that cannot appear in a URL
path segment, a body/path user-id mismatch is rejected instead of
ignored, and HEAD joins the admin-only security rules. The UI keeps the
previous user list when a refresh fails instead of blanking the table.

The IT grows to 14 tests including regressions for omitted-field
preservation, rejected-update atomicity, and overnight schedules.
Follow-up from the group-management review, applying the same findings
here. Duty schedules with begin after end are rejected for new entries
(DutySchedule.isInSchedule compares within one calendar day, so an
overnight range never matches); strings already stored on the record
keep round-tripping so hand-edited files never make a user uneditable.
Dot-segment user ids are rejected. Emptied form fields now clear the
value instead of silently preserving it. The service serializes on the
same shared monitor as the groups API because user mutations cascade
into GroupManager. Adds a collapsed "?" help panel explaining what user
accounts are for and how to use the page.
…dialogs

The dialogs previously reported failures only through a toast that renders
behind the modal overlay, so a rejected save looked like nothing happened.
Mutating service calls now return the server's error message, which the
dialogs display inside the form while staying open; new client-side checks
(shared lib/adminValidation.ts) mirror the server rules for user-ids and
flag malformed email addresses before submitting. Users whose ids contain
/ \ or % (possible in hand-edited users.xml) get their row actions replaced
with a file-managed note, since the security filter rejects those characters
in URL paths. Error toasts now use the error styling.
The markup regexes used full-string matches that a newline anywhere
bypassed; they now scan for the characters directly. The admin account can
no longer have ROLE_ADMIN removed (it would lock every administrator out).
applyDto treats omitted scalar fields as preserve, matching the documented
contract and the sibling APIs, so a roles-only PUT no longer wipes names,
comments and contacts. User comments now reject markup like group comments
do, with unchanged hand-edited values grandfathered. Deleting a user who
supervises an on-call role is rejected, since GroupManager leaves the
supervisor attribute dangling. The client email check accepts display-name
and comma-separated recipient forms and, like the comments check, only
fires on changed input so hand-edited values never block the editor.
@joseanesONMS

Copy link
Copy Markdown
Author

@marshallmassengill could you take a review pass when you get a chance?

@joseanesONMS
joseanesONMS requested a review from synqotik July 30, 2026 20:51
…HeaderIT

The menu entry now lands on the Vue page, so the smoke test waits for its
page title instead of the legacy JSP breadcrumb.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant