200 lines
10 KiB
C#
200 lines
10 KiB
C#
using PostFundManagement.Domain.Abstractions;
|
|
using PostFundManagement.Domain.Errors;
|
|
using PostFundManagement.Domain.Models.Security;
|
|
|
|
namespace PostFundManagement.Infrastructure.Security;
|
|
|
|
public class SkorubaUserService(IHttpClientFactory httpClientFactory) : ISkorubaUserService
|
|
{
|
|
public async Task<Result<string>> CreateUserAsync(CreateUserRequest request, CancellationToken cancellationToken = default) =>
|
|
await Result.Try((Func<Task<Result<string>>>)(async () =>
|
|
{
|
|
var httpClient = httpClientFactory.CreateClient(SkorubaHttpClient);
|
|
var response = await httpClient.PostAsJsonAsync("api/users", request, cancellationToken);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
return Result.Fail(CreateError.Create(response.ReasonPhrase!));
|
|
|
|
var created = await response.Content.ReadFromJsonAsync<UserResponse>(cancellationToken: cancellationToken);
|
|
|
|
return Result.FailIf(created is null, CreateError.Create("User ID missing from creation response."))
|
|
.ToResult(created?.Id!);
|
|
}));
|
|
|
|
public async Task<Result<UserResponse>> GetUserAsync(Guid userId, CancellationToken cancellationToken = default) =>
|
|
await Result.Try((Func<Task<Result<UserResponse>>>)(async () =>
|
|
{
|
|
var httpClient = httpClientFactory.CreateClient(SkorubaHttpClient);
|
|
var result = await httpClient.GetFromJsonAsync<UserResponse>($"api/users/{userId}", cancellationToken);
|
|
|
|
return Result.FailIf(result is null, NotFoundError.Create($"User {userId} not found."))
|
|
.ToResult(result!);
|
|
}));
|
|
|
|
public async Task<Result> UpdateUserAsync(UpdateUserRequest request, CancellationToken cancellationToken = default) =>
|
|
await Result.Try((Func<Task<Result>>)(async () =>
|
|
{
|
|
var httpClient = httpClientFactory.CreateClient(SkorubaHttpClient);
|
|
var response = await httpClient.PutAsJsonAsync("api/users", request, cancellationToken);
|
|
|
|
return Result.OkIf(response.IsSuccessStatusCode, UpdateError.Create("Failed to update user."));
|
|
}));
|
|
|
|
public async Task<Result> SetUserLockoutAsync(Guid userId, bool disabled, CancellationToken cancellationToken = default) =>
|
|
await Result.Try((Func<Task<Result>>)(async () =>
|
|
{
|
|
var httpClient = httpClientFactory.CreateClient(SkorubaHttpClient);
|
|
var user = await httpClient.GetFromJsonAsync<UpdateUserRequest>($"api/users/{userId}", cancellationToken);
|
|
|
|
if (user is null)
|
|
return Result.Fail(NotFoundError.Create($"User {userId} not found."));
|
|
|
|
var updated = new UserLockOutRequest
|
|
{
|
|
UserId = userId.ToString(),
|
|
UserName = user.UserName,
|
|
Email = user.Email,
|
|
EmailConfirmed = user.EmailConfirmed,
|
|
PhoneNumber = user.PhoneNumber,
|
|
PhoneNumberConfirmed = user.PhoneNumberConfirmed,
|
|
LockoutEnabled = true,
|
|
TwoFactorEnabled = user.TwoFactorEnabled,
|
|
AccessFailedCount = user.AccessFailedCount,
|
|
LockoutEnd = disabled ? DateTimeOffset.UtcNow.AddYears(100) : null
|
|
};
|
|
|
|
var response = await httpClient.PutAsJsonAsync("api/users", updated, cancellationToken);
|
|
|
|
return Result.OkIf(response.IsSuccessStatusCode, UpdateError.Create("Failed to update user lockout status."));
|
|
}));
|
|
|
|
public async Task<Result> AddClaimAsync(Guid userId, string claimType, string claimValue, CancellationToken cancellationToken = default) =>
|
|
await Result.Try((Func<Task<Result>>)(async () =>
|
|
{
|
|
var httpClient = httpClientFactory.CreateClient(SkorubaHttpClient);
|
|
var payload = new { userId = userId, claimType = claimType, claimValue = claimValue };
|
|
|
|
var response = await httpClient.PostAsJsonAsync($"api/users/claims", payload, cancellationToken);
|
|
|
|
return Result.OkIf(response.IsSuccessStatusCode, CreateError.Create("Failed to add user claim."));
|
|
}));
|
|
|
|
public async Task<Result> RemoveClaimAsync(Guid userId, int claimId, CancellationToken cancellationToken = default) =>
|
|
await Result.Try((Func<Task<Result>>)(async () =>
|
|
{
|
|
var httpClient = httpClientFactory.CreateClient(SkorubaHttpClient);
|
|
var response = await httpClient.DeleteAsync($"api/users/{userId}/Claims?claimId={claimId}", cancellationToken);
|
|
|
|
if(response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
return Result.Fail(NotFoundError.Create($"Claim {claimId} for user {userId} not found."));
|
|
|
|
return Result.OkIf(response.IsSuccessStatusCode, ValidationError.Create("Failed to remove user claim."));
|
|
}));
|
|
|
|
public async Task<Result<Claim[]>> GetUserClaimsAsync(Guid userId, int page = 1, int pageSize = 50, CancellationToken cancellationToken = default) =>
|
|
await Result.Try((Func<Task<Result<Claim[]>>>)(async () =>
|
|
{
|
|
var httpClient = httpClientFactory.CreateClient(SkorubaHttpClient);
|
|
|
|
var result = await httpClient.GetFromJsonAsync<ClaimsResponse>($"api/users/{userId}/claims?page={page}&pageSize={pageSize}", cancellationToken);
|
|
|
|
return Result.FailIf(result is null, NotFoundError.Create($"Claims for user {userId} could not be retrieved."))
|
|
.ToResult(result?.Claims.ToArray() ?? []);
|
|
}));
|
|
|
|
public async Task<Result> AddRoleAsync(Guid userId, Guid roleId, CancellationToken cancellationToken = default) =>
|
|
await Result.Try((Func<Task<Result>>)(async () =>
|
|
{
|
|
var httpClient = httpClientFactory.CreateClient(SkorubaHttpClient);
|
|
var payload = new { userId = userId, roleId = roleId };
|
|
|
|
var response = await httpClient.PostAsJsonAsync($"api/users/roles", payload, cancellationToken);
|
|
|
|
return Result.OkIf(response.IsSuccessStatusCode, CreateError.Create("Failed to add user role."));
|
|
}));
|
|
|
|
public async Task<Result> RemoveRoleAsync(Guid userId, Guid roleId, CancellationToken cancellationToken = default) =>
|
|
await Result.Try((Func<Task<Result>>)(async () =>
|
|
{
|
|
var httpClient = httpClientFactory.CreateClient(SkorubaHttpClient);
|
|
|
|
var request = new HttpRequestMessage(HttpMethod.Delete, "api/Users/Roles")
|
|
{
|
|
Content = JsonContent.Create(new
|
|
{
|
|
userId = userId.ToString(),
|
|
roleId = roleId.ToString()
|
|
})
|
|
};
|
|
|
|
var response = await httpClient.SendAsync(request, cancellationToken);
|
|
|
|
return Result.OkIf(response.IsSuccessStatusCode, CreateError.Create("Failed to remove user role."));
|
|
}));
|
|
|
|
public async Task<Result<Role[]>> GetUserRolesAsync(Guid userId, int page = 1, int pageSize = 50, CancellationToken cancellationToken = default) =>
|
|
await Result.Try((Func<Task<Result<Role[]>>>)(async () =>
|
|
{
|
|
var httpClient = httpClientFactory.CreateClient(SkorubaHttpClient);
|
|
|
|
var result = await httpClient.GetFromJsonAsync<RolesResponse>($"api/Users/{userId}/Roles?page={page}&pageSize={pageSize}", cancellationToken);
|
|
|
|
return Result.FailIf(result is null, NotFoundError.Create($"Roles for user {userId} could not be retrieved."))
|
|
.ToResult(result?.Roles?.ToArray() ?? []);
|
|
}));
|
|
|
|
public async Task<Result<Claim[]>> GetRoleClaimsAsync(Guid roleId, CancellationToken cancellationToken = default) =>
|
|
await Result.Try((Func<Task<Result<Claim[]>>>)(async () =>
|
|
{
|
|
var httpClient = httpClientFactory.CreateClient(SkorubaHttpClient);
|
|
|
|
var page = 1;
|
|
var pageSize = 100;
|
|
|
|
var result = await httpClient.GetFromJsonAsync<ClaimsResponse>($"api/roles/{roleId}/claims?page={page}&pageSize={pageSize}", cancellationToken);
|
|
|
|
return Result.FailIf(result is null, NotFoundError.Create($"Claims for role {roleId} could not be retrieved."))
|
|
.ToResult(result?.Claims.ToArray() ?? []);
|
|
}));
|
|
|
|
public async Task<Result> InvalidateUserSessionAsync(Guid userId, CancellationToken cancellationToken = default) =>
|
|
await Result.Try((Func<Task<Result>>)(async () =>
|
|
{
|
|
var httpClient = httpClientFactory.CreateClient(SkorubaHttpClient);
|
|
var user = await httpClient.GetFromJsonAsync<UserResponse>($"api/users/{userId}", cancellationToken);
|
|
|
|
if (user is null)
|
|
return Result.Fail(NotFoundError.Create($"User {userId} not found."));
|
|
|
|
var response = await httpClient.PutAsJsonAsync("api/users", user, cancellationToken);
|
|
|
|
return Result.OkIf(response.IsSuccessStatusCode, UpdateError.Create("Failed to invalidate user session."));
|
|
}));
|
|
|
|
public async Task<Result<Role[]>> GetAvailableRolesAsync(string? searchText = null, int page = 1, int pageSize = 50, CancellationToken cancellationToken = default) =>
|
|
await Result.Try((Func<Task<Result<Role[]>>>)(async () =>
|
|
{
|
|
var httpClient = httpClientFactory.CreateClient(SkorubaHttpClient);
|
|
|
|
var query = $"api/roles?page={page}&pageSize={pageSize}";
|
|
|
|
if (!string.IsNullOrWhiteSpace(searchText))
|
|
query += $"&searchText={Uri.EscapeDataString(searchText)}";
|
|
|
|
var result = await httpClient.GetFromJsonAsync<RolesResponse>(query, cancellationToken);
|
|
|
|
return Result.FailIf(result is null, NotFoundError.Create("Available roles could not be retrieved."))
|
|
.ToResult(result?.Roles?.ToArray() ?? []);
|
|
}));
|
|
|
|
public async Task<Result> RemoveUserAsync(Guid userId, CancellationToken cancellationToken = default) =>
|
|
await Result.Try((Func<Task<Result>>)(async () =>
|
|
{
|
|
var httpClient = httpClientFactory.CreateClient(SkorubaHttpClient);
|
|
var result = await httpClient.DeleteAsync($"api/users/{userId}", cancellationToken);
|
|
|
|
return result.StatusCode == System.Net.HttpStatusCode.NotFound
|
|
? Result.Fail(NotFoundError.Create($"User {userId} not found."))
|
|
: Result.OkIf(result.IsSuccessStatusCode, UpdateError.Create("Failed to remove user."));
|
|
}));
|
|
} |