Implemented missing file handling endpoints
Added contract update endpoint
This commit is contained in:
@@ -10,14 +10,55 @@ public abstract class S3ServiceBase(IAmazonS3 amazonS3)
|
||||
protected abstract string BucketName { get; }
|
||||
protected abstract string CdnBaseUrl { get; }
|
||||
|
||||
public virtual async ValueTask<Result<string>> UploadFileAsync(string fileName, Stream fileStream, string contentType, CancellationToken cancellationToken = default) =>
|
||||
public string GenerateCdnUrl(string fileKey) => $"{CdnBaseUrl}/{fileKey}";
|
||||
|
||||
public virtual async ValueTask<Result<string>> GeneratePresignedUrlAsync(string fileKey, TimeSpan duration, string? contentType = null, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<string>>>)(async () =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(BucketName))
|
||||
return Result.Fail<string>(Domain.Errors.ValidationError.Create("Bucket name is not configured."));
|
||||
return Result.Fail(ValidationError.Create("Bucket name is not configured."));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(fileKey))
|
||||
return Result.Fail(ValidationError.Create("File key is required."));
|
||||
|
||||
var request = new GetPreSignedUrlRequest
|
||||
{
|
||||
BucketName = BucketName,
|
||||
Key = fileKey,
|
||||
Expires = DateTime.UtcNow.Add(duration),
|
||||
Verb = HttpVerb.GET
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(contentType))
|
||||
{
|
||||
request.ResponseHeaderOverrides.ContentType = contentType;
|
||||
request.ResponseHeaderOverrides.ContentDisposition = "inline";
|
||||
}
|
||||
|
||||
var presignedUrl = await Client.GetPreSignedURLAsync(request);
|
||||
|
||||
return Result.FailIf(string.IsNullOrWhiteSpace(presignedUrl),
|
||||
CreateError.Create("Failed to create presigned URL"))
|
||||
.ToResult(presignedUrl);
|
||||
}));
|
||||
|
||||
private static string CreateFileKey(string path, string fileName, string fileHash)
|
||||
{
|
||||
var cleanSubPath = path.Replace('\\', '/').Trim('/');
|
||||
|
||||
return string.IsNullOrWhiteSpace(cleanSubPath)
|
||||
? $"{fileHash.ToLower(CultureInfo.InvariantCulture)}_{fileName}"
|
||||
: $"{cleanSubPath}/{fileHash.ToLower(CultureInfo.InvariantCulture)}_{fileName}";
|
||||
}
|
||||
|
||||
public virtual async ValueTask<Result<string>> UploadFileAsync(string fileName, string subPath, Stream fileStream, string contentType, CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<ValueTask<Result<string>>>)(async () =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(BucketName))
|
||||
return Result.Fail<string>(ValidationError.Create("Bucket name is not configured."));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(CdnBaseUrl))
|
||||
return Result.Fail<string>(Domain.Errors.ValidationError.Create("CDN base URL is not configured."));
|
||||
return Result.Fail<string>(ValidationError.Create("CDN base URL is not configured."));
|
||||
|
||||
await using var stream = new MemoryStream();
|
||||
|
||||
@@ -31,7 +72,7 @@ public abstract class S3ServiceBase(IAmazonS3 amazonS3)
|
||||
if (string.IsNullOrWhiteSpace(fileHash))
|
||||
return Result.Fail<string>(CreateError.Create("Failed to compute file hash."));
|
||||
|
||||
var fileKey = $"{fileHash.ToLower(CultureInfo.InvariantCulture)}{Path.GetExtension(fileName)}";
|
||||
var fileKey = CreateFileKey(subPath, fileName, fileHash);
|
||||
|
||||
var putRequest = new PutObjectRequest
|
||||
{
|
||||
@@ -48,7 +89,7 @@ public abstract class S3ServiceBase(IAmazonS3 amazonS3)
|
||||
|
||||
return response.HttpStatusCode != HttpStatusCode.OK
|
||||
? Result.Fail<string>(CreateError.Create($"Failed to upload {fileName} to S3."))
|
||||
: Result.Ok($"{CdnBaseUrl}/{fileKey}");
|
||||
: Result.Ok(fileKey);
|
||||
}));
|
||||
|
||||
public virtual async ValueTask<Result> DeleteFileAsync(string fileKey, CancellationToken cancellationToken = default) =>
|
||||
@@ -63,7 +104,7 @@ public abstract class S3ServiceBase(IAmazonS3 amazonS3)
|
||||
Key = fileKey
|
||||
}, cancellationToken);
|
||||
|
||||
return Result.FailIf(response.HttpStatusCode == HttpStatusCode.NoContent,
|
||||
return Result.FailIf(response.HttpStatusCode == HttpStatusCode.NoContent,
|
||||
UpdateError.Create($"Failed to delete {fileKey} from S3."));
|
||||
}));
|
||||
}
|
||||
@@ -27,4 +27,6 @@ public interface IEvidenceService
|
||||
ValueTask<Result<Evidence[]>> GetProjectEvidencesAsync(string projectIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> UpdateEvidenceAsync(UpdateEvidenceRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<string>> GetEvidenceUrlAsync(string evidenceIdHash, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -25,4 +25,10 @@ public interface IGrantsService
|
||||
ValueTask<Result> CreateBudgetAsync(CreateBudgetRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> CreateAwardAsync(CreateAwardRequest request, Guid userId, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result<string>> GetContractUrlAsync(string contractIdHash, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> UploadContractAsync(string contractIdHash, Guid userId, IFormFile file, CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<Result> UpdateContractAsync(UpdateContractRequest request, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user