diff --git a/src/ServiceDefaults/ServiceDefaults.csproj b/src/ServiceDefaults/ServiceDefaults.csproj index 19a3a614..42f6e61d 100644 --- a/src/ServiceDefaults/ServiceDefaults.csproj +++ b/src/ServiceDefaults/ServiceDefaults.csproj @@ -11,11 +11,11 @@ - - - - - + + + + + diff --git a/src/Web/Features/UserManagement/UserManagementHandler.cs b/src/Web/Features/UserManagement/UserManagementHandler.cs index 73183c1b..ef1c5f15 100644 --- a/src/Web/Features/UserManagement/UserManagementHandler.cs +++ b/src/Web/Features/UserManagement/UserManagementHandler.cs @@ -8,115 +8,130 @@ //======================================================= using Auth0.ManagementApi; -using Auth0.ManagementApi.Models; -using Auth0.ManagementApi.Paging; +using Auth0.ManagementApi.Users; namespace MyBlog.Web.Features.UserManagement; public sealed class UserManagementHandler( - IConfiguration configuration, - IHttpClientFactory httpClientFactory) - : IRequestHandler>>, - IRequestHandler, - IRequestHandler, - IRequestHandler>> -{ - public async Task>> Handle( - GetUsersWithRolesQuery request, CancellationToken ct) - { - try - { - var client = await GetManagementClientAsync(ct); - var users = await client.Users.GetAllAsync(new GetUsersRequest(), new PaginationInfo(), ct); - var result = new List(); - foreach (var user in users) - { - var roles = await client.Users.GetRolesAsync(user.UserId, new PaginationInfo(), ct); - result.Add(new UserWithRolesDto( - user.UserId, - user.Email ?? string.Empty, - user.FullName ?? user.Email ?? string.Empty, - roles.Select(r => r.Name ?? string.Empty).ToList())); - } - return Result.Ok>(result); - } - catch (Exception ex) - { - return Result.Fail>(ex.Message); - } - } +IConfiguration configuration, +IHttpClientFactory httpClientFactory) +: IRequestHandler>>, +IRequestHandler, +IRequestHandler, +IRequestHandler>> +{ +public async Task>> Handle( +GetUsersWithRolesQuery request, CancellationToken ct) +{ +try +{ +var client = await GetManagementClientAsync(ct); +var usersPager = await client.Users.ListAsync(new ListUsersRequestParameters(), cancellationToken: ct); +var result = new List(); +await foreach (var user in usersPager) +{ +var rolesPager = await client.Users.Roles.ListAsync( +user.UserId ?? string.Empty, new ListUserRolesRequestParameters(), cancellationToken: ct); +var roles = new List(); +await foreach (var role in rolesPager) +{ +roles.Add(role.Name ?? string.Empty); +} +result.Add(new UserWithRolesDto( +user.UserId ?? string.Empty, +user.Email ?? string.Empty, +user.Name ?? user.Email ?? string.Empty, +roles)); +} +return Result.Ok>(result); +} +catch (Exception ex) +{ +return Result.Fail>(ex.Message); +} +} - public async Task Handle(AssignRoleCommand request, CancellationToken ct) - { - try - { - var client = await GetManagementClientAsync(ct); - await client.Users.AssignRolesAsync(request.UserId, - new AssignRolesRequest { Roles = [request.RoleId] }, ct); - return Result.Ok(); - } - catch (Exception ex) - { - return Result.Fail(ex.Message); - } - } +public async Task Handle(AssignRoleCommand request, CancellationToken ct) +{ +try +{ +var client = await GetManagementClientAsync(ct); +await client.Users.Roles.AssignAsync( +request.UserId, +new AssignUserRolesRequestContent { Roles = [request.RoleId] }, +cancellationToken: ct); +return Result.Ok(); +} +catch (Exception ex) +{ +return Result.Fail(ex.Message); +} +} - public async Task Handle(RemoveRoleCommand request, CancellationToken ct) - { - try - { - var client = await GetManagementClientAsync(ct); - await client.Users.RemoveRolesAsync(request.UserId, - new AssignRolesRequest { Roles = [request.RoleId] }, ct); - return Result.Ok(); - } - catch (Exception ex) - { - return Result.Fail(ex.Message); - } - } +public async Task Handle(RemoveRoleCommand request, CancellationToken ct) +{ +try +{ +var client = await GetManagementClientAsync(ct); +await client.Users.Roles.DeleteAsync( +request.UserId, +new DeleteUserRolesRequestContent { Roles = [request.RoleId] }, +cancellationToken: ct); +return Result.Ok(); +} +catch (Exception ex) +{ +return Result.Fail(ex.Message); +} +} - public async Task>> Handle(GetAvailableRolesQuery request, CancellationToken ct) - { - try - { - var client = await GetManagementClientAsync(ct); - var roles = await client.Roles.GetAllAsync(new GetRolesRequest(), new PaginationInfo(), ct); - return Result.Ok>( - roles.Select(r => new RoleDto(r.Id ?? string.Empty, r.Name ?? string.Empty)).ToList()); - } - catch (Exception ex) - { - return Result.Fail>(ex.Message); - } - } +public async Task>> Handle(GetAvailableRolesQuery request, CancellationToken ct) +{ +try +{ +var client = await GetManagementClientAsync(ct); +var rolesPager = await client.Roles.ListAsync(new ListRolesRequestParameters(), cancellationToken: ct); +var roles = new List(); +await foreach (var role in rolesPager) +{ +roles.Add(new RoleDto(role.Id ?? string.Empty, role.Name ?? string.Empty)); +} +return Result.Ok>(roles); +} +catch (Exception ex) +{ +return Result.Fail>(ex.Message); +} +} - private async Task GetManagementClientAsync(CancellationToken ct) - { - var domain = configuration["Auth0:ManagementApiDomain"] - ?? throw new InvalidOperationException("Auth0:ManagementApiDomain not configured."); - var clientId = configuration["Auth0:ManagementApiClientId"] - ?? throw new InvalidOperationException("Auth0:ManagementApiClientId not configured."); - var clientSecret = configuration["Auth0:ManagementApiClientSecret"] - ?? throw new InvalidOperationException("Auth0:ManagementApiClientSecret not configured."); +private async Task GetManagementClientAsync(CancellationToken ct) +{ +var domain = configuration["Auth0:ManagementApiDomain"] +?? throw new InvalidOperationException("Auth0:ManagementApiDomain not configured."); +var clientId = configuration["Auth0:ManagementApiClientId"] +?? throw new InvalidOperationException("Auth0:ManagementApiClientId not configured."); +var clientSecret = configuration["Auth0:ManagementApiClientSecret"] +?? throw new InvalidOperationException("Auth0:ManagementApiClientSecret not configured."); - var httpClient = httpClientFactory.CreateClient(); - var tokenResponse = await httpClient.PostAsJsonAsync( - $"https://{domain}/oauth/token", - new - { - client_id = clientId, - client_secret = clientSecret, - audience = $"https://{domain}/api/v2/", - grant_type = "client_credentials" - }, ct); - tokenResponse.EnsureSuccessStatusCode(); - var tokenData = await tokenResponse.Content.ReadFromJsonAsync(ct); - return new ManagementApiClient(tokenData!.AccessToken, domain); - } +var httpClient = httpClientFactory.CreateClient(); +var tokenResponse = await httpClient.PostAsJsonAsync( +$"https://{domain}/oauth/token", +new +{ +client_id = clientId, +client_secret = clientSecret, +audience = $"https://{domain}/api/v2/", +grant_type = "client_credentials" +}, ct); +tokenResponse.EnsureSuccessStatusCode(); +var tokenData = await tokenResponse.Content.ReadFromJsonAsync(ct); +return new ManagementApiClient( +token: tokenData!.AccessToken, +clientOptions: new ClientOptions { BaseUrl = $"https://{domain}/api/v2" }); +} - private sealed class TokenResponse - { - public string AccessToken { get; init; } = string.Empty; - } +private sealed class TokenResponse +{ +public string AccessToken { get; init; } = string.Empty; +} } diff --git a/src/Web/Web.csproj b/src/Web/Web.csproj index b798d3df..c81835dc 100644 --- a/src/Web/Web.csproj +++ b/src/Web/Web.csproj @@ -9,8 +9,9 @@ - + + diff --git a/tests/Architecture.Tests/Architecture.Tests.csproj b/tests/Architecture.Tests/Architecture.Tests.csproj index df12ee9a..cbad7d9e 100644 --- a/tests/Architecture.Tests/Architecture.Tests.csproj +++ b/tests/Architecture.Tests/Architecture.Tests.csproj @@ -9,12 +9,12 @@ - + - + - + diff --git a/tests/Integration.Tests/Integration.Tests.csproj b/tests/Integration.Tests/Integration.Tests.csproj index 71054000..ec7602f4 100644 --- a/tests/Integration.Tests/Integration.Tests.csproj +++ b/tests/Integration.Tests/Integration.Tests.csproj @@ -11,13 +11,13 @@ - + - + - + diff --git a/tests/Unit.Tests/Unit.Tests.csproj b/tests/Unit.Tests/Unit.Tests.csproj index a929434e..b1f08bbe 100644 --- a/tests/Unit.Tests/Unit.Tests.csproj +++ b/tests/Unit.Tests/Unit.Tests.csproj @@ -16,16 +16,16 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + - +