Added consolidated applicant data retrieval endpoint
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Models;
|
||||
|
||||
namespace PostFundManagement.Api.Endpoints.Communications;
|
||||
|
||||
[ApiVersionTarget(1)]
|
||||
public sealed class GetIApplicantDataEndpoint : IEndpoint
|
||||
{
|
||||
public void Map(IEndpointRouteBuilder builder)
|
||||
{
|
||||
builder.MapGet("api/communications/applicants/{applicantUserId:Guid}/all", async (Guid applicantUserId,
|
||||
ICommunicationsService service, CancellationToken cancellationtToken = default ) =>
|
||||
await service.GetApplicantDataAsync(applicantUserId, cancellationtToken) switch
|
||||
{
|
||||
{ IsSuccess: true, Value: var applicantData } => Results.Ok(applicantData),
|
||||
var r when r.HasError<NotFoundError>() => Results.NotFound(r.Errors.ToProblems()),
|
||||
var r when r.HasError<ValidationError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||
var r => Results.InternalServerError(r.Errors.ToProblems()),
|
||||
})
|
||||
.WithDescription("Gets an applicant's data")
|
||||
.RequireAuthorization(Constants.MainScope)
|
||||
.WithName(typeof(GetIApplicantDataEndpoint).ToEndpointName())
|
||||
.MapToApiVersion(new ApiVersion(1))
|
||||
.Produces<Invite>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status401Unauthorized)
|
||||
.Produces<Problems>(StatusCodes.Status404NotFound)
|
||||
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||
.WithTags(EndpointTags.Communications)
|
||||
.CacheOutput();
|
||||
}
|
||||
}
|
||||
@@ -33,4 +33,7 @@ public interface ICommunicationsService
|
||||
|
||||
[Log]
|
||||
Task<Result<Notification>> GetNotificationAsync(string notificationIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
[Log]
|
||||
Task<Result<ApplicantData[]>> GetApplicantDataAsync(Guid applicantUserId, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,28 @@ public sealed class CommunicationsCacheService(CommunicationsService service, ID
|
||||
public async Task<Result> CreateNotificationAsync(CreateNotificationRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||
await service.CreateNotificationAsync(request, userId, cancellationToken);
|
||||
|
||||
public async Task<Result<ApplicantData[]>> GetApplicantDataAsync(Guid applicantUserId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<ApplicantData[]>>>)(async () =>
|
||||
{
|
||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||
return await service.GetApplicantDataAsync(applicantUserId, cancellationToken);
|
||||
|
||||
var cacheKey = HashService.ToMd5Hash($"getapplicantdata-{applicantUserId}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetApplicantDataAsync(applicantUserId, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
|
||||
}
|
||||
|
||||
return Result.Ok(cached!.FromJson<ApplicantData[]>());
|
||||
}));
|
||||
|
||||
public async Task<Result<Invite>> GetApplicantInviteAsync(Guid applicantUserId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Invite>>>)(async () =>
|
||||
{
|
||||
|
||||
@@ -164,4 +164,59 @@ public sealed class CommunicationsService(IDbContextFactory<ApplicationDbContext
|
||||
return Result.FailIf(notification is null, NotFoundError.Create("Notification not found"))
|
||||
.ToResult(notification?.Map()!);
|
||||
}));
|
||||
|
||||
public async Task<Result<ApplicantData[]>> GetApplicantDataAsync(Guid applicantUserId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<ApplicantData[]>>>)(async () =>
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var invites = await context.Invites.AsNoTracking()
|
||||
.Where(i => i.Recipient == applicantUserId)
|
||||
.OrderByDescending(o => o.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var applicantData = new List<ApplicantData>();
|
||||
|
||||
foreach (var invite in invites)
|
||||
{
|
||||
var outputInvite = invite.Map();
|
||||
|
||||
var contract = (await context.Contracts.AsNoTracking()
|
||||
.FirstOrDefaultAsync(c => c.Id == invite.ContractId, cancellationToken))?.Map();
|
||||
|
||||
var fundingOrganisation = (await context.Organisations.AsNoTracking()
|
||||
.FirstOrDefaultAsync(o => o.Id == invite.OrganisationId, cancellationToken))?.Map();
|
||||
|
||||
var invitedOrganisation = (await context.Organisations.AsNoTracking()
|
||||
.FirstOrDefaultAsync(o => o.Id == invite.InvitedOrganisationId, cancellationToken))?.Map();
|
||||
|
||||
var awards = (await context.Awards.AsNoTracking()
|
||||
.Where(a => a.Id == invite.AwardId)
|
||||
.ToListAsync(cancellationToken))?.Select(a => a.Map()).ToArray();
|
||||
|
||||
var projectIds = (await context.Awards.AsNoTracking()
|
||||
.Where(a => a.Id == invite.AwardId && a.ProjectId.HasValue)
|
||||
.Select(a => a.ProjectId!.Value)
|
||||
.Distinct()
|
||||
.ToListAsync(cancellationToken)) ?? [];
|
||||
|
||||
var projects = (await context.Projects.AsNoTracking()
|
||||
.Where(p => projectIds.Contains(p.Id))
|
||||
.ToListAsync(cancellationToken))?.Select(p => p.Map()).ToArray() ?? [];
|
||||
|
||||
var data = new ApplicantData
|
||||
{
|
||||
Invite = outputInvite,
|
||||
Contract = contract,
|
||||
Awards = awards!,
|
||||
FundingOrganisation = fundingOrganisation,
|
||||
InvitedOrganisation = invitedOrganisation,
|
||||
Projects = projects
|
||||
};
|
||||
|
||||
applicantData.Add(data);
|
||||
}
|
||||
|
||||
return Result.Ok(applicantData.ToArray());
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace PostFundManagement.Domain.Models;
|
||||
|
||||
public sealed class ApplicantData
|
||||
{
|
||||
public Invite? Invite { get; set; }
|
||||
|
||||
public Contract? Contract { get; set; }
|
||||
|
||||
public Organisation? FundingOrganisation { get; set; }
|
||||
|
||||
public Organisation? InvitedOrganisation { get; set; }
|
||||
|
||||
public Award[] Awards { get; set; } = [];
|
||||
|
||||
public Project[] Projects { get; set; } = [];
|
||||
}
|
||||
Reference in New Issue
Block a user