Implemented missing file handling endpoints
Added contract update endpoint
This commit is contained in:
@@ -60,6 +60,27 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
|
||||
return Result.Ok(cached.FromJson<Domain.Models.Evidence[]>());
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<string>> GetEvidenceUrlAsync(string evidenceIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<string>>>)(async () =>
|
||||
{
|
||||
var cacheKey = HashService.ToMd5Hash($"getevidenceurl-{evidenceIdHash}").Value;
|
||||
|
||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cached))
|
||||
{
|
||||
var result = await service.GetEvidenceUrlAsync(evidenceIdHash, cancellationToken);
|
||||
|
||||
if (result.IsFailed) return result;
|
||||
|
||||
await cache.SetStringAsync(cacheKey, result.Value, cancellationToken);
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return Result.Ok(cached);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<Indicator>> GetIndicatorAsync(string indicatorId, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<Indicator>>>)(async () =>
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ using PostFundManagement.Infrastructure.Database;
|
||||
namespace PostFundManagement.Application.Services.Evidence;
|
||||
|
||||
public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> contextFactory, HashService hashService,
|
||||
[FromKeyedServices(Constants.EvidenceBucketName)] IS3Service s3Service) : IEvidenceService
|
||||
[FromKeyedServices(Constants.GeneralBucketName)] IS3Service s3Service) : IEvidenceService
|
||||
{
|
||||
public async ValueTask<Result> CreateEvidenceAsync(Guid userId, IFormCollection form, IFormFile file, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result>>)(async () =>
|
||||
@@ -22,13 +22,12 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
|
||||
|
||||
await using var stream = file.OpenReadStream();
|
||||
|
||||
var uploadResult = await s3Service.UploadFileAsync(file.FileName, stream, file.ContentType, cancellationToken);
|
||||
var uploadResult = await s3Service.UploadFileAsync(file.FileName, "evidence", stream,
|
||||
file.ContentType, cancellationToken);
|
||||
|
||||
if (uploadResult.IsFailed)
|
||||
return Result.Fail(uploadResult.Errors);
|
||||
|
||||
var documentUrl = uploadResult.Value;
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var evidence = new Domain.Entities.Evidence
|
||||
@@ -41,7 +40,7 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
Version = 1,
|
||||
Type = type,
|
||||
DocumentUrl = documentUrl,
|
||||
DocumentUrl = uploadResult.Value,
|
||||
Status = ApprovalStatus.Pending
|
||||
};
|
||||
|
||||
@@ -238,4 +237,31 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
|
||||
|
||||
return Result.OkIf(changedTotal > 0, UpdateError.New);
|
||||
}));
|
||||
|
||||
public async ValueTask<Result<string>> GetEvidenceUrlAsync(string evidenceIdHash, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<string>>>)(async () =>
|
||||
{
|
||||
var decodeResult = hashService.DecodeLongIdHash(evidenceIdHash);
|
||||
|
||||
if (decodeResult.IsFailed)
|
||||
return Result.Fail(IdDecodeError.Create()
|
||||
.CausedBy(decodeResult.Errors));
|
||||
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var evidence = await context.Evidences.AsNoTracking().FirstOrDefaultAsync(e => e.Id == decodeResult.Value, cancellationToken);
|
||||
|
||||
if (evidence is null)
|
||||
return Result.Fail<string>(NotFoundError.New);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(evidence.DocumentUrl))
|
||||
return Result.Fail<string>(ValidationError.Create("Ecidence is invalid, has no saved documentUrl"));
|
||||
|
||||
var secureDownloadUrlResult = await s3Service.GeneratePresignedUrlAsync(evidence.DocumentUrl,
|
||||
TimeSpan.FromMinutes(15), null, cancellationToken);
|
||||
|
||||
return Result.OkIf(secureDownloadUrlResult.IsSuccess && !string.IsNullOrWhiteSpace(secureDownloadUrlResult.Value),
|
||||
NotFoundError.Create("Failed to generate secure file url"))
|
||||
.ToResult(secureDownloadUrlResult.Value);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -3,19 +3,19 @@ using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Evidence;
|
||||
|
||||
public record UpdateEvidenceRequest([Required] long EvidenceId,
|
||||
public sealed record UpdateEvidenceRequest([Required] long EvidenceId,
|
||||
[Required] int Version,
|
||||
[Required] EvidenceType EvidenceType,
|
||||
[Required] ApprovalStatus Status);
|
||||
|
||||
public record RecordActualRequest([Required] decimal ActualAmount);
|
||||
public sealed record RecordActualRequest([Required] decimal ActualAmount);
|
||||
|
||||
public record CreateMilestoneRequest([Required] long ProjectId,
|
||||
public sealed record CreateMilestoneRequest([Required] long ProjectId,
|
||||
[Required] DateTime DueAt,
|
||||
[Required][MaxLength(LabelLength)] string Name,
|
||||
[Required] Priority Priority);
|
||||
|
||||
public record CreateIndicatorRequest([Required] long ProjectId,
|
||||
public sealed record CreateIndicatorRequest([Required] long ProjectId,
|
||||
[Required][MaxLength(LabelLength)] string Name,
|
||||
[Required] UnitOfMeasure UnitOfMeasure,
|
||||
[Required] decimal BaselineAmount,
|
||||
|
||||
Reference in New Issue
Block a user