< Summary - Heimdall API

Information
Class: ArturRios.Heimdall.Query.Handlers.ListApplicationCredentialsQueryHandler
Assembly: ArturRios.Heimdall.Query
File(s): /home/runner/work/heimdall-api/heimdall-api/src/Application/ArturRios.Heimdall.Query/Handlers/ListApplicationCredentialsQueryHandler.cs
Line coverage
100%
Covered lines: 31
Uncovered lines: 0
Coverable lines: 31
Total lines: 62
Line coverage: 100%
Branch coverage
100%
Covered branches: 4
Total branches: 4
Branch coverage: 100%
Method coverage
100%
Covered methods: 2
Fully covered methods: 2
Total methods: 2
Method coverage: 100%
Full method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
HandleAsync()100%44100%

File(s)

/home/runner/work/heimdall-api/heimdall-api/src/Application/ArturRios.Heimdall.Query/Handlers/ListApplicationCredentialsQueryHandler.cs

#LineLine coverage
 1using ArturRios.Data.Relational.Core.Interfaces;
 2using ArturRios.Heimdall.Domain.Entities;
 3using ArturRios.Heimdall.Query.Input;
 4using ArturRios.Heimdall.Query.Output;
 5using ArturRios.Heimdall.Shared.Messages;
 6using ArturRios.Heimdall.Shared.Services;
 7using ArturRios.Mediator.Query.Interfaces;
 8using ArturRios.Output;
 9using Microsoft.EntityFrameworkCore;
 10using Application = ArturRios.Heimdall.Domain.Entities.Application;
 11
 12namespace ArturRios.Heimdall.Query.Handlers;
 13
 14/// <summary>Handles <see cref="ListApplicationCredentialsQuery" /> (UC-54, FR-AP-12).</summary>
 1015public class ListApplicationCredentialsQueryHandler(
 1016    IAsyncReadOnlyRepository<Application, long> applicationReader,
 1017    IAsyncReadOnlyRepository<ApplicationCredential, long> credentialReader)
 18    : IQueryHandlerAsync<ListApplicationCredentialsQuery, ApplicationCredentialListOutput>
 19{
 20    public async Task<DataOutput<ApplicationCredentialListOutput?>> HandleAsync(
 21        ListApplicationCredentialsQuery query, CancellationToken cancellationToken = default)
 22    {
 1023        var output = DataOutput<ApplicationCredentialListOutput?>.New;
 24
 25        // AF-54a, then AF-54b.
 1026        var access = await ApplicationManagementAccess.ResolveAsync(
 1027            applicationReader.Query(), query.ScopeId, query.Id, query.ActingRole, query.ActingPersonId);
 28
 1029        switch (access.Access)
 30        {
 31            case ApplicationAccess.NotFound:
 232                return output.WithError(ApplicationMessages.ApplicationNotFound);
 33            case ApplicationAccess.Forbidden:
 234                return output.WithError(ApplicationCredentialMessages.NotAuthorizedToManageCredentials);
 35        }
 36
 637        var applicationId = access.Application!.Id;
 638        var credentials = await credentialReader.Query()
 639            .Where(x => x.ApplicationId == applicationId)
 640            .OrderByDescending(x => x.CreatedAt)
 641            .ThenByDescending(x => x.Id)
 642            .ToListAsync(cancellationToken);
 43
 44        // Liveness is judged once, in memory, so every row is measured against the same instant.
 645        var now = DateTime.UtcNow;
 46
 647        return output
 648            .WithData(new ApplicationCredentialListOutput
 649            {
 850                Credentials = credentials.Select(x => new ApplicationCredentialOutput
 851                {
 852                    Id = x.PublicId,
 853                    CreatedAt = x.CreatedAt,
 854                    ExpiresAt = x.ExpiresAt,
 855                    RevokedAt = x.RevokedAt,
 856                    LastUsedAt = x.LastUsedAt,
 857                    Live = x.IsLiveAt(now)
 858                }).ToList()
 659            })
 660            .WithMessage(ApplicationCredentialMessages.CredentialsRetrieved);
 1061    }
 62}