Skip to content

Add office-scoped user-list API and management UI - #1734

Merged
krowvin merged 18 commits into
developfrom
1733-user-lists
Aug 5, 2026
Merged

Add office-scoped user-list API and management UI#1734
krowvin merged 18 commits into
developfrom
1733-user-lists

Conversation

@krowvin

@krowvin krowvin commented May 15, 2026

Copy link
Copy Markdown
Collaborator

Refs #1733.

Summary

Adds the complete, authenticated CDA user-list feature for office-scoped recipient groups:

  • office-scoped user-list metadata CRUD
  • list membership read and management endpoints
  • candidate-member lookup
  • owner and office authorization behavior
  • schema/feature gating for installations without the database objects
  • Groundwork-styled CDA UI for creating, editing, and deleting lists and managing members
  • ADR documenting the CDA user-list context, ownership, office scope, API, and UI decisions

Related Issue

Closes #1733

Database foundation: HydrologicEngineeringCenter/cwms-database#160. Two follow-up database commits for office scoping and CDA grants remain local for review before a separate database PR.

Validation

  • latest origin/develop fetched and merged: already up to date
  • :cwms-data-api:integrationTests --tests cwms.cda.api.users.UserListControllerTestIT: 5 passed
  • :cwms-data-api:test --tests cwms.cda.features.CdaFeatureManagerProviderTest: 6 passed with the local runtime feature override isolated
  • CDA UI npm run lint: passed
  • CDA UI source Prettier check: passed
  • CDA UI npm run build: passed
  • broad Gradle build completed compilation, WAR packaging, and the bundled UI build; its unit-test phase still reports unrelated existing Windows/JDK 21 fixture and Mockito failures

Screenshots

image image image image

Checklist

  • AI tools used

@krowvin krowvin linked an issue May 15, 2026 that may be closed by this pull request
@krowvin

krowvin commented May 15, 2026

Copy link
Copy Markdown
Collaborator Author

Drafting until DB changes are in. Did one endpoint to start so i can check performance of the endpoints as I go.

@MikeNeilson MikeNeilson left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a reasonable start.

crud("/users/{user-name}", new UsersController(metrics), adminRoles);
get("/roles", new GetRolesController(metrics), adminRoles);
get("/user/profile", new UserProfileController(metrics), userRoles);
get("/user/list/{user-list-id}/members", new UserListMembersController(metrics), adminRoles);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

long term, I'd probably group these by "/user/list" rather that method -> "/user/..."

But that's just me.

@krowvin

krowvin commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator Author

Added the next user-list GET endpoint under /user/list:

GET /user/list/{user-list-id}?office={office}

Returns metadata for a single office-scoped user list

Separate from the existing members endpoint.

EDIT: Going to resolve conflicts at the end when it's ready for merge (not draft)

@krowvin
krowvin requested a review from MikeNeilson June 2, 2026 21:48
@krowvin

krowvin commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator Author

Spoke with Mike N on 07/24/2026

Needs to be behind a feature flag (togglez) to make sure the DB has it. This will make it not show it in swagger. and a proper unsupported response. Minimum schema version enum.

Also to go ahead and PR this to have all the GET/POST/DELETE/etc for one larger review.

All the user stuff should have add user handlers/function for grouping so things are more clear.

@krowvin krowvin changed the title Add initial user-lists API endpoint Add office-scoped user-list API and management UI Jul 27, 2026
@krowvin

krowvin commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator Author
  • Added office scoped list CRUD and member management endpoints
  • Added owner/office authorization and candidate member lookup
  • Added the requested togglz/schema version gate, including unsupported schema handling and hiding unavailable endpoints from openapi
  • Added the authenticated CDA UI for creating, editing, deleting, and managing list members using Groundwork styling
  • Added an ADR covering ownership, office scope, API behavior, and UI decisions
  • Updated the branch onto current develop

krowvin added 2 commits July 31, 2026 16:23
Signed-off-by: Charles Graham, SWT <charles.r.graham@usace.army.mil>
Signed-off-by: Charles Graham, SWT <charles.r.graham@usace.army.mil>

# Conflicts:
#	cwms-data-api/src/main/java/cwms/cda/helpers/DatabaseHelpers.java
@krowvin

krowvin commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator Author

Related Batch Events follow-up: USACE-WaterManagement/cwms-batch-events#186

This draft consumes PR 1734's office-scoped CDA user-list API/UI so script administrators can select maintained recipient lists for failed-job email alerts. Batch Events resolves current membership at failure time instead of duplicating users locally.

@krowvin
krowvin marked this pull request as ready for review August 4, 2026 21:39

@MikeNeilson MikeNeilson left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise looks good.

while i would like to see pages/user-lits/index.jsx broken down into smaller components, i wouldn't consider it super critical right now. but open an issue to track that work.

The test changes should be done, there already exists an annotation to do what you're doing with the schema version check.

Comment thread cda-gui/src/pages/user-lists/index.jsx Outdated
let detail = `${response.status} ${response.statusText}`.trim();
try {
const payload = await response.json();
detail = payload.message ?? payload.detail ?? detail;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what didn't return JSON? if it's the API itself something is wrong.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or is this just a bit of paranoid just in case... which yeah, probably a good idea.

@krowvin krowvin Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bit of paranoid just in case

The gateway won't return a valid JSON if the API is down. It's a guard to make sure something can always render. I'm trying to be better at not assuming the API will always return valid...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be broken up into smaller components, overall everything does seem fine, but it's difficult to follow the logical structure of what's rendering by code alone (err, harder than it should be.)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that was much easier to follow.

public final class UserListDao {

private final DSLContext dsl;
private final Table<?> avUserListMembers = table(name("CWMS_20", "AV_USER_LIST_MEMBERS")).as("ulm");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The table and field definition can be static.

Additionally, as they are reused in different places they should be declared in their own classes. I would follow a style at least similar to the JOOQ auto generated output so that transitioning to the next code gen will be a bit easier.


@BeforeAll
static void ensureUserListSchema() throws SQLException {
if (!schemaSupportsUserLists()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the @MinimumSchema annotation on the class level

@AuthType(user = TestAccounts.KeyUser.SPK_NORMAL2)
void test_user_lists_are_unsupported_on_older_schemas(String authType,
TestAccounts.KeyUser user, RequestSpecification authSpec) {
assumeTrue(getSchemaVersion() < V2026_07_16.numeric());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use @MinimumSchema annotation at the class level.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh wait, for this we would need a maximum schema. this particular one is fine for the moment.

krowvin added 3 commits August 5, 2026 09:36
Signed-off-by: Charles Graham, SWT <charles.r.graham@usace.army.mil>
Signed-off-by: Charles Graham, SWT <charles.r.graham@usace.army.mil>
Signed-off-by: Charles Graham, SWT <charles.r.graham@usace.army.mil>
@krowvin
krowvin requested a review from MikeNeilson August 5, 2026 15:18
@krowvin

krowvin commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

I put a TODO in there for the maximum comment. Do we have a pending issue to add that feature?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that was much easier to follow.


public static int getSchemaVersion() {
if (cwmsDb == null) {
// Class-level execution conditions run before the database container starts.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... I keep forgetting about that. But the fix for that is definitely beyond the scope of this PR.

@MikeNeilson

Copy link
Copy Markdown
Contributor

I put a TODO in there for the maximum comment. Do we have a pending issue to add that feature?

We don't, I only just realized we needed it looking at your code.

@krowvin
krowvin merged commit 934bcad into develop Aug 5, 2026
7 of 11 checks passed
@krowvin
krowvin deleted the 1733-user-lists branch August 5, 2026 16:33
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.

Add API support for managing and retrieving user lists

2 participants