Skip to content

[PM-33951] feat(admin-console): Add bulk confirmation and pending auto-confirmation#7661

Open
JaredScar wants to merge 5 commits into
mainfrom
ac/pm-33919-db-changes
Open

[PM-33951] feat(admin-console): Add bulk confirmation and pending auto-confirmation#7661
JaredScar wants to merge 5 commits into
mainfrom
ac/pm-33919-db-changes

Conversation

@JaredScar
Copy link
Copy Markdown
Contributor

@JaredScar JaredScar commented May 18, 2026

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-33951

📔 Objective

This PR contains the database changes needed for #7527, split to their own PR to manage PR size.

…ion methods for organization users

- Implemented ConfirmManyOrganizationUsersAsync to confirm multiple users in a single operation.
- Added GetManyPendingAutoConfirmAsync to retrieve users pending automatic confirmation.
- Created stored procedures for bulk confirmation and fetching pending users.
- Updated relevant repository interfaces and implementations across Dapper and Entity Framework.
@JaredScar JaredScar requested review from a team as code owners May 18, 2026 16:05
@JaredScar JaredScar added the ai-review Request a Claude code review label May 18, 2026
@JaredScar JaredScar requested a review from r-tome May 18, 2026 16:05
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 18, 2026

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

This PR adds the database layer for bulk organization user confirmation and pending auto-confirm reads, split from PR #7527 to keep change size manageable. It introduces two stored procedures (OrganizationUser_ConfirmByIds, OrganizationUser_ReadByPendingAutoConfirm), matching Dapper and EF repository methods, migration scripts, and integration tests. All prior review feedback on the PR has been addressed across the commit history.

Code Review Details

No findings. The implementation follows established patterns in this codebase:

  • The new bulk SQL sproc uses the same atomic UPDATE ... WHERE Status = 1 pattern as the existing OrganizationUser_ConfirmById, with OUTPUT INTO for idempotency tracking.
  • The JSON parameter pattern (OPENJSON with NVARCHAR(MAX)) is consistent with other multi-row Dapper sprocs in the repo.
  • The OrganizationUser_ReadByPendingAutoConfirm filters (OrganizationId, Status = Accepted, Type = User, UserId IS NOT NULL) match the EF query exactly, preserving dual-ORM parity.
  • Test coverage includes mixed-batch filtering, idempotency on re-runs, and the full set of negative cases (already-confirmed, wrong type, null UserId, other organization).
  • Migration filenames (2026-05-14_01_*, 2026-05-14_02_*) follow the established sequence numbering with no collisions.

@JaredScar JaredScar changed the title [PM-33919] feat(admin-console): Add bulk confirmation and pending auto-confirmation [PM-33951] feat(admin-console): Add bulk confirmation and pending auto-confirmation May 18, 2026
Comment thread src/Sql/dbo/Stored Procedures/OrganizationUser_ReadByOrganizationIdStatus.sql Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented May 18, 2026

Codecov Report

❌ Patch coverage is 0% with 61 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.39%. Comparing base (7180015) to head (e742d6a).

Files with missing lines Patch % Lines
...Console/Repositories/OrganizationUserRepository.cs 0.00% 36 Missing ⚠️
...Console/Repositories/OrganizationUserRepository.cs 0.00% 25 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7661      +/-   ##
==========================================
- Coverage   60.43%   60.39%   -0.04%     
==========================================
  Files        2140     2140              
  Lines       94622    94683      +61     
  Branches     8443     8446       +3     
==========================================
  Hits        57188    57188              
- Misses      35429    35490      +61     
  Partials     2005     2005              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

@r-tome r-tome left a comment

Choose a reason for hiding this comment

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

Claude pointed out a few things to fix. Let me know when to review this again

@mkincaid-bw
Copy link
Copy Markdown
Contributor

There are similar database changes in PR 7527, as well as this one. Do both PR's need a review from dbops or only this one?

@JaredScar
Copy link
Copy Markdown
Contributor Author

JaredScar commented May 19, 2026

There are similar database changes in PR 7527, as well as this one. Do both PR's need a review from dbops or only this one?

Valid question! @mkincaid-bw -- Sorry for the confusion. @eliykat suggested we split up that PR into smaller PRs like this one that we merge first, then that original PR will be smaller and easier to review since that big chunk of code are broken into pieces. Theoretically speaking, this should be the only one DB ops needs to worry about 😄

…ationUsersAsync to IReadOnlyCollection

- Updated the ConfirmManyOrganizationUsersAsync method signature in the IOrganizationUserRepository and its implementations to use IReadOnlyCollection instead of IEnumerable for better performance and clarity.
- Adjusted related repository methods in both Dapper and Entity Framework implementations to reflect this change.
- Added unit tests to ensure the new implementation behaves as expected, including scenarios for mixed batches and idempotency.
@JaredScar JaredScar requested a review from r-tome May 19, 2026 19:50
@eliykat eliykat self-requested a review May 21, 2026 04:53
Copy link
Copy Markdown
Member

@eliykat eliykat left a comment

Choose a reason for hiding this comment

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

Thanks @JaredScar for splitting this to a separate PR - I cannot tell you how much easier it is to review smaller PRs.

Aside from my comments below, please check the CI runs:

  • db integration test is failing - potentially faulty prod or test logic
  • db validation is failing - this ensures that the migration scripts match the src/Sql files
  • validate new migration naming and order - this is failing because later migrations have overtaken you and you need to bump the dates on your script

More info available in each of the runs, or hit me up on Slack if you have questions.

EDIT: please also add more info to your PR description, e.g.

This PR contains the database changes needed for #7527, split to their own PR to manage PR size.

The PR link is particularly useful to understand what's going on.

Comment thread src/Sql/dbo/Stored Procedures/OrganizationUser_ReadByOrganizationIdStatus.sql Outdated
JaredScar and others added 3 commits May 21, 2026 11:48
…dingAutoConfirm methods

- Introduced ConfirmManyOrganizationUsersTests to validate the confirmation of multiple organization users, ensuring only accepted users are confirmed and idempotency is maintained.
- Added GetManyPendingAutoConfirmTests to verify retrieval of pending auto-confirm users, ensuring only eligible users are returned based on specific criteria.
- Removed duplicate test implementations from OrganizationUserRepositoryTests to maintain clarity and organization in the test suite.
@JaredScar JaredScar requested a review from eliykat May 21, 2026 16:03
@sonarqubecloud
Copy link
Copy Markdown

@@ -0,0 +1,43 @@
CREATE PROCEDURE [dbo].[OrganizationUser_ConfirmByIds]
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 stored proc name does not follow our naming standards (I realize we have OrganizationUser_ConfirmById as well, which I previously approved but should not have). It should start with OrganizationUser_Update..., and perhaps be named something like OrganizationUser_UpdateStatusKey, or something to that effect.

WHERE
[OrganizationId] = @OrganizationId
AND [Status] = 1 -- Accepted
AND [Type] = 0 -- User
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.

❓According to src/Core/AdminConsole/Enums/OrganizationUserType.cs, Type 0 is Owner and Type 2 is User. Is the value for Type supposed to be User or Owner?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good catch! This is also the cause of the test failure, so good to know our tests are working :D

Copy link
Copy Markdown
Member

@eliykat eliykat left a comment

Choose a reason for hiding this comment

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

My changes have been addressed, I can approve once @mkincaid-bw is happy and CI checks are passing.

public class ConfirmManyOrganizationUsersTests
{
[Theory, DatabaseData]
public async Task ConfirmManyOrganizationUsersAsync_MixedBatch_ReturnsOnlyAcceptedIds(
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.

Also assert that RevisionDate is updated. The simplest way is to capture var before = DateTime.UtcNow before the call and assert updated.RevisionDate >= before afterwards.

A more thorough alternative (which I'd lean toward but not a blocker!) is to pass RevisionDate in as a parameter to the repository method, as we do for example in GroupRepository.DeleteUserAsync. This lets the caller (the command/service) generate the timestamp via TimeProvider, the repository becomes a pure persistence layer, and the test can assert exact equality. Example:

Assert.Equal(expectedRevisionDate, actualGroup.RevisionDate, TimeSpan.FromMilliseconds(10));

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.

Bump the date on the migration file names

WHERE
OU.[Status] = 1 -- Accepted

EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationUserIds] @UpdatedIds
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 singular update sproc checks if any rows are updated before calling this. Might be worth it to be consistent and add that here too.

Suggested change
EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationUserIds] @UpdatedIds
SET @RowCount = @@ROWCOUNT;
IF @RowCount > 0
BEGIN
EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationUserIds] @UpdatedIds
END

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

Labels

ai-review Request a Claude code review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants