using DMSBLL.ESSDocument;
using FastEndpoints;
using GB5Shared.DTO.Framework.Enum;
using GB5Shared.DTO.Framework.Login;
using GB5Shared.DTO.Framework.ResponseStandard;
using Newtonsoft.Json;
namespace DMSSL.EndPoints.ESSDocument
{
///
/// Downloads the file encrypted with the employee's personal secret key.
/// POST is used (not GET) so the secret key never appears in the URL or server logs.
/// Returns raw binary — NOT wrapped in ResponseStandardDTO.
///
public class DownloadDocumentSecure : Endpoint
{
public readonly IESSDocumentBLL _ESSDocumentBLL;
public DownloadDocumentSecure(IESSDocumentBLL essDocumentBLL)
{
_ESSDocumentBLL = essDocumentBLL;
}
public record DownloadDocumentSecureParameters(
[property: FromHeader] string Login,
[property: QueryParam] int AttachmentId,
[property: FromBody] string SecretKey
);
public override void Configure()
{
Post("/ESSDocument/DownloadDocumentSecure");
AllowAnonymous();
}
public override async Task HandleAsync(DownloadDocumentSecureParameters req, CancellationToken ct)
{
if (string.IsNullOrWhiteSpace(req.SecretKey))
{
await WriteJsonResponseAsync(
400, FrameworkEnumDTO.ResponseStatus.Failed,
"SecretKey is required.", ct);
return;
}
LoginDTO? loginDTO;
try
{
loginDTO = JsonConvert.DeserializeObject(req.Login);
if (loginDTO is null) throw new Exception();
}
catch
{
await WriteJsonResponseAsync(
401, FrameworkEnumDTO.ResponseStatus.Unauthorized,
"The login token is missing or invalid. Please sign in and try again.", ct);
return;
}
try
{
var (stream, mimeType, fileName) = await _ESSDocumentBLL.DownloadDocumentSecure(
req.AttachmentId, req.SecretKey, loginDTO, ct);
HttpContext.Response.StatusCode = 200;
HttpContext.Response.ContentType = mimeType;
HttpContext.Response.Headers.Append("Content-Disposition",
$"attachment; filename=\"{Uri.EscapeDataString(fileName)}\"");
HttpContext.Response.Headers.Append("Cache-Control", "no-store");
await using (stream)
await stream.CopyToAsync(HttpContext.Response.Body, ct);
}
catch (UnauthorizedAccessException)
{
await WriteJsonResponseAsync(
403, FrameworkEnumDTO.ResponseStatus.Forbidden,
"You do not have permission to access this document.", ct);
}
catch (FileNotFoundException)
{
await WriteJsonResponseAsync(
404, FrameworkEnumDTO.ResponseStatus.NotFound,
"The requested document was not found.", ct);
}
catch (ArgumentException ex)
{
await WriteJsonResponseAsync(
400, FrameworkEnumDTO.ResponseStatus.Failed,
ex.Message, ct);
}
}
private Task WriteJsonResponseAsync(
int httpStatus,
FrameworkEnumDTO.ResponseStatus responseStatus,
string message,
CancellationToken ct)
{
var body = new ResponseStandardDTO