| | | 1 | | using ArturRios.Data.Relational.Core.Interfaces; |
| | | 2 | | using ArturRios.Heimdall.Domain.Entities; |
| | | 3 | | using ArturRios.Heimdall.Query.Input; |
| | | 4 | | using ArturRios.Heimdall.Query.Output; |
| | | 5 | | using ArturRios.Heimdall.Shared.Messages; |
| | | 6 | | using ArturRios.Heimdall.Shared.Services; |
| | | 7 | | using ArturRios.Mediator.Query.Interfaces; |
| | | 8 | | using ArturRios.Output; |
| | | 9 | | using Microsoft.EntityFrameworkCore; |
| | | 10 | | using Application = ArturRios.Heimdall.Domain.Entities.Application; |
| | | 11 | | |
| | | 12 | | namespace ArturRios.Heimdall.Query.Handlers; |
| | | 13 | | |
| | | 14 | | /// <summary>Handles <see cref="ListApplicationCredentialsQuery" /> (UC-54, FR-AP-12).</summary> |
| | 10 | 15 | | public class ListApplicationCredentialsQueryHandler( |
| | 10 | 16 | | IAsyncReadOnlyRepository<Application, long> applicationReader, |
| | 10 | 17 | | IAsyncReadOnlyRepository<ApplicationCredential, long> credentialReader) |
| | | 18 | | : IQueryHandlerAsync<ListApplicationCredentialsQuery, ApplicationCredentialListOutput> |
| | | 19 | | { |
| | | 20 | | public async Task<DataOutput<ApplicationCredentialListOutput?>> HandleAsync( |
| | | 21 | | ListApplicationCredentialsQuery query, CancellationToken cancellationToken = default) |
| | | 22 | | { |
| | 10 | 23 | | var output = DataOutput<ApplicationCredentialListOutput?>.New; |
| | | 24 | | |
| | | 25 | | // AF-54a, then AF-54b. |
| | 10 | 26 | | var access = await ApplicationManagementAccess.ResolveAsync( |
| | 10 | 27 | | applicationReader.Query(), query.ScopeId, query.Id, query.ActingRole, query.ActingPersonId); |
| | | 28 | | |
| | 10 | 29 | | switch (access.Access) |
| | | 30 | | { |
| | | 31 | | case ApplicationAccess.NotFound: |
| | 2 | 32 | | return output.WithError(ApplicationMessages.ApplicationNotFound); |
| | | 33 | | case ApplicationAccess.Forbidden: |
| | 2 | 34 | | return output.WithError(ApplicationCredentialMessages.NotAuthorizedToManageCredentials); |
| | | 35 | | } |
| | | 36 | | |
| | 6 | 37 | | var applicationId = access.Application!.Id; |
| | 6 | 38 | | var credentials = await credentialReader.Query() |
| | 6 | 39 | | .Where(x => x.ApplicationId == applicationId) |
| | 6 | 40 | | .OrderByDescending(x => x.CreatedAt) |
| | 6 | 41 | | .ThenByDescending(x => x.Id) |
| | 6 | 42 | | .ToListAsync(cancellationToken); |
| | | 43 | | |
| | | 44 | | // Liveness is judged once, in memory, so every row is measured against the same instant. |
| | 6 | 45 | | var now = DateTime.UtcNow; |
| | | 46 | | |
| | 6 | 47 | | return output |
| | 6 | 48 | | .WithData(new ApplicationCredentialListOutput |
| | 6 | 49 | | { |
| | 8 | 50 | | Credentials = credentials.Select(x => new ApplicationCredentialOutput |
| | 8 | 51 | | { |
| | 8 | 52 | | Id = x.PublicId, |
| | 8 | 53 | | CreatedAt = x.CreatedAt, |
| | 8 | 54 | | ExpiresAt = x.ExpiresAt, |
| | 8 | 55 | | RevokedAt = x.RevokedAt, |
| | 8 | 56 | | LastUsedAt = x.LastUsedAt, |
| | 8 | 57 | | Live = x.IsLiveAt(now) |
| | 8 | 58 | | }).ToList() |
| | 6 | 59 | | }) |
| | 6 | 60 | | .WithMessage(ApplicationCredentialMessages.CredentialsRetrieved); |
| | 10 | 61 | | } |
| | | 62 | | } |