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 { /// /// Streams a file for inline browser preview. /// Returns raw binary — NOT wrapped in ResponseStandardDTO. /// Sets Content-Disposition: inline so the browser renders it (e.g. PDF viewer). /// public class PreviewDocument : Endpoint { public readonly IESSDocumentBLL _ESSDocumentBLL; public PreviewDocument(IESSDocumentBLL essDocumentBLL) { _ESSDocumentBLL = essDocumentBLL; } public record PreviewDocumentParameters( [property: FromHeader] string Login, [property: QueryParam] int AttachmentId ); public override void Configure() { Get("/ESSDocument/PreviewDocument"); AllowAnonymous(); } public override async Task HandleAsync(PreviewDocumentParameters req, CancellationToken ct) { 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.PreviewDocument( req.AttachmentId, loginDTO, ct); HttpContext.Response.StatusCode = 200; HttpContext.Response.ContentType = mimeType; HttpContext.Response.Headers.Append("Content-Disposition", "inline"); HttpContext.Response.Headers.Append("X-Content-Type-Options", "nosniff"); HttpContext.Response.Headers.Append("Cache-Control", "no-store, no-cache, must-revalidate"); await using (stream) await stream.CopyToAsync(HttpContext.Response.Body, ct); } catch (UnauthorizedAccessException) { await WriteJsonResponseAsync( 403, FrameworkEnumDTO.ResponseStatus.Forbidden, "You do not have permission to preview this document.", ct); } catch (FileNotFoundException) { await WriteJsonResponseAsync( 404, FrameworkEnumDTO.ResponseStatus.NotFound, "The requested document was not found.", ct); } catch (Exception ex) { await WriteJsonResponseAsync( 500, FrameworkEnumDTO.ResponseStatus.Forbidden, // ← use Forbidden like DownloadDocument does $"Error: {ex.Message}", ct); } } private Task WriteJsonResponseAsync( int httpStatus, FrameworkEnumDTO.ResponseStatus responseStatus, string message, CancellationToken ct) { var body = new ResponseStandardDTO { Status = responseStatus, Body = message, ErrorBody = message }; HttpContext.Response.StatusCode = httpStatus; HttpContext.Response.ContentType = "application/json"; return HttpContext.Response.WriteAsync(JsonConvert.SerializeObject(body), ct); } } }