Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for bulk processing new login device requests #4064

Draft
wants to merge 10 commits into
base: ac/addison/ac-2301/service-bulk-device-approval-endpoint-api
Choose a base branch
from

Conversation

addisonbeck
Copy link
Contributor

@addisonbeck addisonbeck commented May 7, 2024

Type of change

- [ ] Bug fix
- [x] New feature development
- [ ] Tech debt (refactoring, code cleanup, dependency upgrades, etc)
- [ ] Build/deploy pipeline (DevOps)
- [ ] Other

Objective

To facilitate a new bulk device login request in the admin console server
logic needs to be written that can bulk approve and deny new device login
requests safely. This logic will need to accept a list of ids, keys, and
approval states and process those requests to apply the keys and approval
states.

Code changes

See the commits tab

References

  • AC-2301 is the Jira ticket for this work.
  • This PR builds on #4053, which implements the repository and
    database functionality needed to bulk update AuthRequest table records.
  • This PR is extended by #4077, which exposes an API endpoint that calls through to the UpdateManyAsync command written here.

Copy link

codecov bot commented May 7, 2024

Codecov Report

Attention: Patch coverage is 92.26190% with 13 lines in your changes are missing coverage. Please review.

Project coverage is 38.50%. Comparing base (9d5b27e) to head (603cc6d).
Report is 16 commits behind head on ac/addison/ac-2301/service-bulk-device-approval-endpoint-api.

Current head 603cc6d differs from pull request most recent head b03ea39

Please upload reports for the commit b03ea39 to get more accurate results.

Files Patch % Lines
...zationAuth/UpdateOrganizationAuthRequestCommand.cs 92.12% 4 Missing and 9 partials ⚠️
Additional details and impacted files
@@                                       Coverage Diff                                        @@
##           ac/addison/ac-2301/service-bulk-device-approval-endpoint-api    #4064      +/-   ##
================================================================================================
+ Coverage                                                         38.35%   38.50%   +0.15%     
================================================================================================
  Files                                                              1210     1211       +1     
  Lines                                                             58712    58879     +167     
  Branches                                                           5586     5608      +22     
================================================================================================
+ Hits                                                              22518    22674     +156     
- Misses                                                            35152    35154       +2     
- Partials                                                           1042     1051       +9     

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

Copy link
Contributor

github-actions bot commented May 7, 2024

Logo
Checkmarx One – Scan Summary & Detailsa418c774-dbb9-4dd0-b3e0-47033a68920a

New Issues

Severity Issue Source File / Package Checkmarx Insight
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 190 Attack Vector
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 331 Attack Vector
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 331 Attack Vector
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 752 Attack Vector
MEDIUM CSRF /src/Api/AdminConsole/Controllers/ProviderOrganizationsController.cs: 52 Attack Vector
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 111 Attack Vector
MEDIUM CSRF /src/Api/AdminConsole/Controllers/GroupsController.cs: 118 Attack Vector
MEDIUM CSRF /src/Api/AdminConsole/Controllers/GroupsController.cs: 81 Attack Vector
MEDIUM CSRF /src/Admin/AdminConsole/Controllers/OrganizationsController.cs: 308 Attack Vector
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 563 Attack Vector
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 560 Attack Vector
MEDIUM CSRF /src/Api/AdminConsole/Controllers/GroupsController.cs: 93 Attack Vector
MEDIUM Privacy_Violation /src/Core/Services/Implementations/UserService.cs: 873 Attack Vector

Fixed Issues

Severity Issue Source File / Package
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 607
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 607
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 607
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 607
MEDIUM CSRF /src/Api/AdminConsole/Controllers/GroupsController.cs: 132
MEDIUM CSRF /src/Api/AdminConsole/Controllers/ProvidersController.cs: 141
MEDIUM CSRF /src/Api/SecretsManager/Controllers/AccessPoliciesController.cs: 229
MEDIUM CSRF /src/Admin/AdminConsole/Controllers/ProvidersController.cs: 320
MEDIUM CSRF /src/Api/AdminConsole/Controllers/GroupsController.cs: 163
MEDIUM CSRF /src/Api/AdminConsole/Controllers/GroupsController.cs: 163
MEDIUM CSRF /src/Api/Billing/Controllers/ProviderClientsController.cs: 30
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 190
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 333
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 333
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 645
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 669
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationsController.cs: 535
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 711
MEDIUM CSRF /src/Api/Vault/Controllers/FoldersController.cs: 45
MEDIUM CSRF /src/Api/Controllers/SelfHosted/SelfHostedOrganizationLicensesController.cs: 51
MEDIUM CSRF /src/Api/Controllers/UsersController.cs: 22
MEDIUM CSRF /src/Api/Controllers/DevicesController.cs: 70
MEDIUM CSRF /src/Api/Controllers/DevicesController.cs: 57
MEDIUM CSRF /src/Api/AdminConsole/Public/Controllers/PoliciesController.cs: 69
MEDIUM CSRF /src/Api/AdminConsole/Public/Controllers/PoliciesController.cs: 49
MEDIUM CSRF /src/Api/AdminConsole/Public/Controllers/OrganizationController.cs: 42
MEDIUM CSRF /src/Api/AdminConsole/Public/Controllers/GroupsController.cs: 92
MEDIUM CSRF /src/Api/AdminConsole/Public/Controllers/GroupsController.cs: 49
MEDIUM CSRF /src/Api/AdminConsole/Controllers/ProviderUsersController.cs: 142
MEDIUM CSRF /src/Api/AdminConsole/Controllers/PoliciesController.cs: 148
MEDIUM CSRF /src/Api/AdminConsole/Controllers/PoliciesController.cs: 78
MEDIUM CSRF /src/Api/AdminConsole/Controllers/PoliciesController.cs: 61
MEDIUM CSRF /bitwarden_license/src/Sso/Controllers/AccountController.cs: 163
MEDIUM CSRF /bitwarden_license/src/Sso/Controllers/AccountController.cs: 96
MEDIUM CSRF /bitwarden_license/src/Scim/Controllers/v2/UsersController.cs: 50
MEDIUM CSRF /src/Api/AdminConsole/Public/Controllers/GroupsController.cs: 161
MEDIUM CSRF /src/Api/Auth/Controllers/EmergencyAccessController.cs: 159
MEDIUM CSRF /bitwarden_license/src/Scim/Controllers/v2/GroupsController.cs: 98
MEDIUM CSRF /bitwarden_license/src/Scim/Controllers/v2/GroupsController.cs: 88
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 627
MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 303
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationsController.cs: 283
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 174
MEDIUM CSRF /src/Api/Auth/Controllers/TwoFactorController.cs: 403
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 926
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 583
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 583
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 287
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 786
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 407
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1100
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 432
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1066
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1066
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1017
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1017
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 811
MEDIUM CSRF /src/Api/AdminConsole/Public/Controllers/GroupsController.cs: 133
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 530
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 449
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 545
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 193
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 222
MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 303
MEDIUM CSRF /src/Admin/AdminConsole/Controllers/OrganizationsController.cs: 308
MEDIUM CSRF /src/Admin/AdminConsole/Controllers/ProvidersController.cs: 243
MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 375
MEDIUM CSRF /src/Api/AdminConsole/Controllers/GroupsController.cs: 81
MEDIUM CSRF /src/Api/AdminConsole/Controllers/GroupsController.cs: 118
MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 411
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 144
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 246
MEDIUM CSRF /src/Api/AdminConsole/Controllers/GroupsController.cs: 277
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 361
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationsController.cs: 117
MEDIUM CSRF /src/Api/AdminConsole/Controllers/ProviderUsersController.cs: 175
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 867
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationsController.cs: 283
MEDIUM CSRF /src/Api/AdminConsole/Public/Controllers/MembersController.cs: 187
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 86
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 222
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 218
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 300
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 318
MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 323
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 286
MEDIUM CSRF /src/Api/AdminConsole/Public/Controllers/MembersController.cs: 150
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 570
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1120
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 774
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 748
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 246
MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 411
MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 375
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 931
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 286
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 193
MEDIUM CSRF /src/Api/Controllers/SettingsController.cs: 36
MEDIUM CSRF /src/Api/AdminConsole/Controllers/GroupsController.cs: 260
MEDIUM CSRF /src/Api/AdminConsole/Controllers/ProviderUsersController.cs: 188
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 722
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 159
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 627
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 519
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 312
MEDIUM CSRF /src/Identity/Controllers/AccountsController.cs: 72
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 570
MEDIUM CSRF /src/Identity/Controllers/AccountsController.cs: 50
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1043
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 962
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 125
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 111
MEDIUM CSRF /src/Api/Tools/Controllers/ImportCiphersController.cs: 66
MEDIUM CSRF /src/Api/Tools/Controllers/ImportCiphersController.cs: 50
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1043
MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 156
MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 187
MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 196
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 898
MEDIUM CSRF /src/Api/Public/Controllers/CollectionsController.cs: 64
MEDIUM CSRF /src/Api/AdminConsole/Public/Controllers/MembersController.cs: 150
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 572
MEDIUM CSRF /src/Api/AdminConsole/Controllers/ProviderOrganizationsController.cs: 53
MEDIUM CSRF /src/Api/AdminConsole/Public/Controllers/OrganizationController.cs: 42
MEDIUM CSRF /src/Api/AdminConsole/Public/Controllers/OrganizationController.cs: 42
MEDIUM CSRF /src/Api/AdminConsole/Public/Controllers/OrganizationController.cs: 42
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 221
MEDIUM CSRF

More results are available on AST platform

In order to facilitate a command method that can update many auth
requests at one time a new model must be defined that accepts valid
input for the command's needs. To achieve this a new file has been
created at
`Core/AdminConsole/OrganizationAuth/Models/OrganizationAuthRequestUpdateCommandModel.cs`
that contains a class of the same name. It's properties match those that
need to come from any calling API request models to fulfill the request.
@addisonbeck addisonbeck force-pushed the ac/addison/ac-2301/bulk-device-approval-service branch 2 times, most recently from 7f4b13b to f952e19 Compare May 7, 2024 23:15
Calling API functions of the `UpdateOrganizationAuthRequestCommand` need
a function that can accept many auth request response objects and
process them as approved or denied. To achieve this a new function has
been added to `IUpdateOrganizationAuthRequestCommand` called
`UpdateManyAsync()` that accepts an
`IEnumberable<OrganizationAuthRequest>` and returns a `Task`.
Implementations of this interface method will be used to bulk process
auth requests as approved or denied.
To facilitate a bulk device login request approval workflow in the admin
console `UpdateOrganizationAuthRequestCommand` needs to be updated to
include an `UpdateMany()` method. It should accept a list of
`OrganizationAuthRequestUpdateCommandModel` objects, perform some simple
data validation checks, and then pass those along to
`AuthRequestRepository` for updating in the database.

This commit stubs out this method for the purpose of writing unit tests.
At this stage the method throws a `NotImplementedException()`. It will
be expand after writing assertions.
The updates to `UpdateOrganizationAuthRequestCommand` require a new
direct dependency on `IAuthRequestRepository`. This commit simply
registers this dependency in the `UpdateOrganizationAuthRequest`
constructor for use in unit tests and the `UpdateManyAsync()`
implementation.
@addisonbeck addisonbeck force-pushed the ac/addison/ac-2301/bulk-device-approval-service branch 5 times, most recently from 640de72 to a1777e5 Compare May 9, 2024 11:45
@addisonbeck addisonbeck changed the base branch from main to ac/addison/ac-2301/service-bulk-device-approval-endpoint-api May 9, 2024 11:46
@addisonbeck addisonbeck force-pushed the ac/addison/ac-2301/bulk-device-approval-service branch 15 times, most recently from 896e8b5 to 3a17788 Compare May 10, 2024 19:58
@addisonbeck addisonbeck force-pushed the ac/addison/ac-2301/bulk-device-approval-service branch 8 times, most recently from 8b8099c to 1a754f5 Compare May 13, 2024 00:35
@addisonbeck addisonbeck force-pushed the ac/addison/ac-2301/bulk-device-approval-service branch from 1a754f5 to 603cc6d Compare May 13, 2024 02:48
Copy link
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.

Looking good! Some early feedback...

Comment on lines 7 to 8
Task UpdateAsync(Guid requestId, Guid userId, bool requestApproved, string encryptedUserKey);
Task UpdateManyAsync(Guid organizationId, IEnumerable<OrganizationAuthRequestUpdateCommandModel> authRequestUpdates);
Copy link
Member

Choose a reason for hiding this comment

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

Suggestion: this could be an overload of UpdateAsync. Avoid the naming problems altogether 😁

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed to UpdateAsync as suggested on 188af1f

@@ -0,0 +1,8 @@
namespace Bit.Core.AdminConsole.OrganizationAuth.Models;

public class OrganizationAuthRequestUpdateCommandModel
Copy link
Member

@eliykat eliykat May 13, 2024

Choose a reason for hiding this comment

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

I don't think there's any need to repeat Command in this class name. Usually request, response, and data models have suffixes, domain models don't. e.g. OrganizationAuthRequestUpdateModel.

EDIT: in fact, I'm not even sure we use the Model suffix, except in the public api. OrganizationAuthRequestUpdate?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed to OrganizationAuthRequestUpdate as suggested on 0a0216f

Comment on lines 110 to 114
var processedAuthRequests = new List<T>();
authRequestsToProcess = FilterOutSpentAuthRequests(authRequestsToProcess);
authRequestsToProcess = FilterOutExpiredAuthRequests(authRequestsToProcess);
authRequestsToProcess = FilterOutAuthRequestsWithNoUpdates(authRequestsToProcess, updates);
authRequestsToProcess = FilterOutAuthRequestsThatDoNotMatchOrganizationId(authRequestsToProcess, organizationId);
Copy link
Member

Choose a reason for hiding this comment

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

This loses the nice chained linq syntax, and in general I think it's better to encapsulate the single rather than the many. I suggest encapsulating the callback only, e.g.

var processedAuthRequests = authRequestsToProcess
  .Where(notExpired)
  .Where(notSpent)  // is there a more descriptive term than spent?
  .Where(matchesOrganizationId(orgId))
// etc

although then that suggests to me that maybe these belong on the model, because most of them are just about validating model state. eg. authRequestsToProcess.Where(a => !a.expired)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I liked this feedback, but felt like I had to go in a slightly more complicated direction than just using the UpdateAuthRequest model. That model is meant to just be an input model, and adding a bunch of logic to it that is also dependent on the unprocessed and processed auth request seemed out of scope for its intended purpose.

BUT I did make a new model, or really two. AuthRequestUpdateProcessor, and BatchAuthRequestUpdateProcesssor. These take in everything needed to process the auth request and handle approving it, denying it, running validation checks, and declaring what a processed auth request is capable of doing like saving itself and sending notifications. They have no direct dependencies on other services, and just consume and manipulate data and the occasional callback function.

These leaves the Command as a buffer between the external dependencies of processing an auth request (all the other repos and services that are used) and what processing an auth request means to it's data (the processors). It also features some sick method chaining.

Implemented on ac451cb

Comment on lines 128 to 144
public T ApproveAuthRequest<T>(T authRequestToApprove, string Key) where T : AuthRequest
{
if (string.IsNullOrWhiteSpace(Key))
{
_logger.LogError($"An auth request with id {authRequestToApprove.Id} was approved, but no key was provided. This auth request can not be approved.");
return authRequestToApprove;
}
authRequestToApprove.Key = Key;
authRequestToApprove.Approved = true;
authRequestToApprove.ResponseDate = DateTime.UtcNow;
return authRequestToApprove;
}

public T DenyAuthRequest<T>(T authRequestToDeny) where T : AuthRequest
{
authRequestToDeny.Approved = false;
authRequestToDeny.ResponseDate = DateTime.UtcNow;
return authRequestToDeny;
}
Copy link
Member

Choose a reason for hiding this comment

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

These are just about updating model state, they could be moved to the model. e.g. request.Approve(key) / request.Deny().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See #4064 (comment) as a reference for all "put-this-in-a-model" talk.


public TimeSpan FetchRequestExpirationTimespan()
{
return _globalSettings.PasswordlessAuth.AdminRequestExpiration;
Copy link
Member

Choose a reason for hiding this comment

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

I suggest this could be a property rather than a method.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was removed on ac451cb and just called directly.

return await _userRepository.GetByIdAsync(userId);
}

public async Task<bool> PushManyTrustedDeviceEmails<T>(IEnumerable<T> authRequests) where T : AuthRequest
Copy link
Member

Choose a reason for hiding this comment

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

Unused return value? Only seems to be used in tests, but in that case it's better to assert the call to the mailService dependency.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed on ac451cb, but to explain: this was unused, except for in tests. I was having trouble asserting the mail service was called. I also sort of converting voids into things that return status codes.

Comment on lines 217 to 220
return authRequest.RequestDeviceType.GetType()
.GetMember(authRequest.RequestDeviceType.ToString())
.FirstOrDefault()?
// This unknown case can't be unit tested without adding an enum
// with no display attribute. Faith and trust are required!
.GetCustomAttribute<DisplayAttribute>()?.Name ?? "Unknown Device Type";
Copy link
Member

Choose a reason for hiding this comment

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

Probably sounding like a broken record here. But this could be moved the model 😅 it's only concerned with parsing the RequestDeviceType property.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See #4064 (comment) as a reference for all "put-this-in-a-model" talk.

{
return null;
}
return await _organizationUserRepository.GetByOrganizationAsync(authRequest.OrganizationId.Value, authRequest.UserId);
Copy link
Member

Choose a reason for hiding this comment

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

There's a bulk method you can use - GetManyAsync(authRequests.Select(r => r.OrganizationUserId).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Implemented on b03ea39. I also added some post release work for creating these sorts of bulk methods for the other auth request events (emails and push notifications). Those are still done one at a time in a loop for now.

_logger.LogError($"An organization user was not found while processing auth request {authRequest.Id}. Event logs can not be posted for this request.");
return;
}
await _eventService.LogOrganizationUserEventAsync(organizationUser, CalculateOrganizationAuthRequestProcessingEventLogType(authRequest));
Copy link
Member

Choose a reason for hiding this comment

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

There's also a bulk overload for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Implemented on b03ea39

Copy link
Member

@eliykat eliykat May 13, 2024

Choose a reason for hiding this comment

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

I see you're still working on tests, so this might be premature, but: I think these tests are too granular. I think the biggest risk here is that the tests would not stand up to refactoring; they express how the command is implemented, not what it does. So any internal refactor would immediately break them, reducing their usefulness in guarding against regressions.

Different devs do take different approaches here, I am pretty strongly on the "only test public interfaces" side of things, but I know not everyone is. So I won't hold it up over that. But I would like to see at least some tests that test the public interface only, and assert all the expected behavior resulting from that call.

Copy link
Contributor

Choose a reason for hiding this comment

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

All these new methods are only used once so I'd prefer if their logic would be inside UpdateManyAsync, that would make it easier to read. Just add a comment for each section.

@addisonbeck addisonbeck force-pushed the ac/addison/ac-2301/service-bulk-device-approval-endpoint-api branch 5 times, most recently from fab5fde to cea0589 Compare May 13, 2024 19:22
@addisonbeck addisonbeck force-pushed the ac/addison/ac-2301/bulk-device-approval-service branch 7 times, most recently from 5942db0 to e8887a6 Compare May 17, 2024 22:42
@addisonbeck addisonbeck force-pushed the ac/addison/ac-2301/bulk-device-approval-service branch from e8887a6 to b03ea39 Compare May 20, 2024 17:34
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.

None yet

3 participants