From 2aed75fd4e8b2ccdb3ffebdeab85e2950583c068 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Sun, 30 Aug 2026 16:19:59 +0200 Subject: [PATCH 1/2] Implemented GetMilestoneEndpoint --- ...yIdEndpoint.cs => GetIndicatorEndpoint.cs} | 4 +-- .../Evidence/GetMilestoneEndpoint.cs | 33 +++++++++++++++++++ .../Services/Evidence/EvidenceService.cs | 24 ++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) rename PostFundManagement.Api/Endpoints/Evidence/{GetIndicatorByIdEndpoint.cs => GetIndicatorEndpoint.cs} (90%) create mode 100644 PostFundManagement.Api/Endpoints/Evidence/GetMilestoneEndpoint.cs diff --git a/PostFundManagement.Api/Endpoints/Evidence/GetIndicatorByIdEndpoint.cs b/PostFundManagement.Api/Endpoints/Evidence/GetIndicatorEndpoint.cs similarity index 90% rename from PostFundManagement.Api/Endpoints/Evidence/GetIndicatorByIdEndpoint.cs rename to PostFundManagement.Api/Endpoints/Evidence/GetIndicatorEndpoint.cs index 2e34ac3..6b93962 100644 --- a/PostFundManagement.Api/Endpoints/Evidence/GetIndicatorByIdEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Evidence/GetIndicatorEndpoint.cs @@ -8,7 +8,7 @@ using PostFundManagement.Domain.Security; namespace PostFundManagement.Api.Endpoints.Evidence; [ApiVersionTarget(1)] -public sealed class GetIndicatorByIdEndpoint : IEndpoint +public sealed class GetIndicatorEndpoint : IEndpoint { public void Map(IEndpointRouteBuilder builder) { @@ -22,7 +22,7 @@ public sealed class GetIndicatorByIdEndpoint : IEndpoint : Results.NotFound(); }) .WithDescription("Get a specific indicator.") - .WithName(typeof(GetIndicatorByIdEndpoint).ToEndpointName()) + .WithName(typeof(GetIndicatorEndpoint).ToEndpointName()) .MapToApiVersion(new ApiVersion(1)) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status404NotFound) diff --git a/PostFundManagement.Api/Endpoints/Evidence/GetMilestoneEndpoint.cs b/PostFundManagement.Api/Endpoints/Evidence/GetMilestoneEndpoint.cs new file mode 100644 index 0000000..c1cdcd3 --- /dev/null +++ b/PostFundManagement.Api/Endpoints/Evidence/GetMilestoneEndpoint.cs @@ -0,0 +1,33 @@ +using PostFundManagement.Application.Extensions; +using PostFundManagement.Application.Services.Evidence; +using PostFundManagement.Domain.Abstractions; +using PostFundManagement.Domain.Extensions; +using PostFundManagement.Domain.Models; +using PostFundManagement.Domain.Security; + +namespace PostFundManagement.Api.Endpoints.Evidence; + +[ApiVersionTarget(1)] +public class GetMilestoneEndpoint : IEndpoint +{ + public void Map(IEndpointRouteBuilder builder) + { + builder.MapGet("api/evidence/milestones/{milestoneId}", async (string milestoneId, EvidenceService service, + CancellationToken cancellationToken = default) => + { + var result = await service.GetMilestoneAsync(milestoneId, cancellationToken); + + return result.IsSuccess + ? Results.Ok(result.Value) + : Results.NotFound(); + }) + .WithDescription("Gets a specific milestone") + .WithName(typeof(GetMilestoneEndpoint).ToEndpointName()) + .MapToApiVersion(new ApiVersion(1)) + .Produces(StatusCodes.Status200OK) + .Produces(StatusCodes.Status404NotFound) + .Produces(StatusCodes.Status401Unauthorized) + .WithTags(EndpointTags.Evidence) + .CacheOutput(); + } +} diff --git a/PostFundManagement.Application/Services/Evidence/EvidenceService.cs b/PostFundManagement.Application/Services/Evidence/EvidenceService.cs index fffe880..99bb851 100644 --- a/PostFundManagement.Application/Services/Evidence/EvidenceService.cs +++ b/PostFundManagement.Application/Services/Evidence/EvidenceService.cs @@ -253,4 +253,28 @@ public sealed class EvidenceService(IDbContextFactory cont return Result.Fail(new Error(ex.Message).CausedBy(ex)); } } + + public async Task> GetMilestoneAsync(string milestoneId, CancellationToken cancellationToken) + { + try + { + var decodeResult = hashService.DecodeLongIdHash(milestoneId); + + if (decodeResult.IsFailed) + return Result.Fail(decodeResult.Errors); + + using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + + var milestone = await context.Milestones.AsNoTracking().FirstOrDefaultAsync(m => m.Id == decodeResult.Value, cancellationToken); + + return milestone is not null + ? Result.Ok(milestone.Map()) + : Result.Fail("Failed to get specific milestone"); + + } + catch (Exception ex) + { + return Result.Fail(new Error(ex.Message).CausedBy(ex)); + } + } } From 5caa8066000797d608f102dc40f0d67502ebedab Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Sun, 30 Aug 2026 16:27:13 +0200 Subject: [PATCH 2/2] Implemented GetEvidenceEndpoint --- .../Endpoints/Evidence/GetEvidenceEndpoint.cs | 33 +++++++++++++++++++ .../Services/Evidence/EvidenceService.cs | 23 +++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 PostFundManagement.Api/Endpoints/Evidence/GetEvidenceEndpoint.cs diff --git a/PostFundManagement.Api/Endpoints/Evidence/GetEvidenceEndpoint.cs b/PostFundManagement.Api/Endpoints/Evidence/GetEvidenceEndpoint.cs new file mode 100644 index 0000000..39b74e3 --- /dev/null +++ b/PostFundManagement.Api/Endpoints/Evidence/GetEvidenceEndpoint.cs @@ -0,0 +1,33 @@ +using PostFundManagement.Application.Extensions; +using PostFundManagement.Application.Services.Evidence; +using PostFundManagement.Domain.Abstractions; +using PostFundManagement.Domain.Extensions; +using PostFundManagement.Domain.Security; + +namespace PostFundManagement.Api.Endpoints.Evidence; + +[ApiVersionTarget(1)] +public sealed class GetEvidenceEndpoint : IEndpoint +{ + public void Map(IEndpointRouteBuilder builder) + { + builder.MapGet("api/evidence/{evidenceId}", async (string evidenceId, EvidenceService service, + CancellationToken cancellationToken = default) => + { + var result = await service.GetEvidenceAsync(evidenceId, cancellationToken); + + return result.IsSuccess + ? Results.Ok(result.Value) + : Results.NotFound(); + + }) + .WithDescription("Get a specific evidence record and assiciated file URLs") + .WithName(typeof(GetEvidenceEndpoint).ToEndpointName()) + .MapToApiVersion(new ApiVersion(1)) + .Produces(StatusCodes.Status200OK) + .Produces(StatusCodes.Status404NotFound) + .Produces(StatusCodes.Status401Unauthorized) + .WithTags(EndpointTags.Evidence) + .CacheOutput(); + } +} diff --git a/PostFundManagement.Application/Services/Evidence/EvidenceService.cs b/PostFundManagement.Application/Services/Evidence/EvidenceService.cs index 99bb851..a070297 100644 --- a/PostFundManagement.Application/Services/Evidence/EvidenceService.cs +++ b/PostFundManagement.Application/Services/Evidence/EvidenceService.cs @@ -277,4 +277,27 @@ public sealed class EvidenceService(IDbContextFactory cont return Result.Fail(new Error(ex.Message).CausedBy(ex)); } } + + public async ValueTask> GetEvidenceAsync(string evidenceId, CancellationToken cancellationToken = default) + { + try + { + var decodeResult = hashService.DecodeLongIdHash(evidenceId); + + if (decodeResult.IsFailed) + return Result.Fail(decodeResult.Errors); + + using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + + var evidence = await context.Evidences.AsNoTracking().FirstOrDefaultAsync(e => e.Id == decodeResult.Value, cancellationToken); + + return evidence is not null + ? Result.Ok(evidence.Map()) + : Result.Fail("Failed to get a specific evidence record."); + } + catch (Exception ex) + { + return Result.Fail(new Error(ex.Message).CausedBy(ex)); + } + } }