Use actual MIME type for trust center file exports
The export endpoint was hardcoding application/pdf for all trust center files. Now the real MIME type from the stored file metadata is threaded through the service layer and returned as a data URI, so non-PDF files are handled correctly on the frontend. Watermarking is only applied when the file is actually a PDF. Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
@@ -164,8 +164,19 @@ type Props = {
|
|||||||
queryRef: PreloadedQuery<DocumentPageQueryType>;
|
queryRef: PreloadedQuery<DocumentPageQueryType>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function isPdfFilename(name: string): boolean {
|
function isPdfDataUri(dataUri: string): boolean {
|
||||||
return name.toLowerCase().endsWith(".pdf");
|
return dataUri.startsWith("data:application/pdf;");
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractBase64Data(dataUri: string): string {
|
||||||
|
const commaIndex = dataUri.indexOf(",");
|
||||||
|
if (commaIndex === -1) return dataUri;
|
||||||
|
return dataUri.substring(commaIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractMimeType(dataUri: string): string {
|
||||||
|
const match = dataUri.match(/^data:([^;]+);/);
|
||||||
|
return match?.[1] ?? "application/octet-stream";
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNodeTitle(node: DocumentPageQueryType["response"]["node"]): string | undefined {
|
function getNodeTitle(node: DocumentPageQueryType["response"]["node"]): string | undefined {
|
||||||
@@ -276,7 +287,7 @@ export function DocumentPage({ queryRef }: Props) {
|
|||||||
variables: { input: { trustCenterFileId: node.id } },
|
variables: { input: { trustCenterFileId: node.id } },
|
||||||
onCompleted: (response, errors) => {
|
onCompleted: (response, errors) => {
|
||||||
if (onCompletedErrors(errors)) return;
|
if (onCompletedErrors(errors)) return;
|
||||||
if (isPdfFilename(node.name)) {
|
if (isPdfDataUri(response.exportTrustCenterFile.data)) {
|
||||||
setPdfData(response.exportTrustCenterFile.data);
|
setPdfData(response.exportTrustCenterFile.data);
|
||||||
} else {
|
} else {
|
||||||
setFileData(response.exportTrustCenterFile.data);
|
setFileData(response.exportTrustCenterFile.data);
|
||||||
@@ -359,16 +370,18 @@ export function DocumentPage({ queryRef }: Props) {
|
|||||||
|
|
||||||
const isRequesting = isRequestingAccess || isRequestingFileAccess || isRequestingReportAccess;
|
const isRequesting = isRequestingAccess || isRequestingFileAccess || isRequestingReportAccess;
|
||||||
const hasRequested = node.access?.status === "REQUESTED";
|
const hasRequested = node.access?.status === "REQUESTED";
|
||||||
const isPdf = node.__typename === "Document" || node.__typename === "Report" || (node.__typename === "TrustCenterFile" && isPdfFilename(node.name));
|
const isPdf = node.__typename === "Document" || node.__typename === "Report" || (node.__typename === "TrustCenterFile" && pdfData !== null);
|
||||||
|
|
||||||
const handleDownload = () => {
|
const handleDownload = () => {
|
||||||
if (!fileData || !nodeTitle) return;
|
if (!fileData || !nodeTitle) return;
|
||||||
const byteCharacters = atob(fileData);
|
const base64 = extractBase64Data(fileData);
|
||||||
|
const mimeType = extractMimeType(fileData);
|
||||||
|
const byteCharacters = atob(base64);
|
||||||
const byteNumbers = new Uint8Array(byteCharacters.length);
|
const byteNumbers = new Uint8Array(byteCharacters.length);
|
||||||
for (let i = 0; i < byteCharacters.length; i++) {
|
for (let i = 0; i < byteCharacters.length; i++) {
|
||||||
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
||||||
}
|
}
|
||||||
const blob = new Blob([byteNumbers]);
|
const blob = new Blob([byteNumbers], { type: mimeType });
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
const a = document.createElement("a");
|
const a = document.createElement("a");
|
||||||
a.href = url;
|
a.href = url;
|
||||||
|
|||||||
@@ -490,14 +490,14 @@ func (r *mutationResolver) ExportTrustCenterFile(ctx context.Context, input type
|
|||||||
}
|
}
|
||||||
|
|
||||||
if trustCenterFile.TrustCenterVisibility == coredata.TrustCenterVisibilityPublic {
|
if trustCenterFile.TrustCenterVisibility == coredata.TrustCenterVisibilityPublic {
|
||||||
fileData, err := trustService.TrustCenterFiles.ExportFileWithoutWatermark(ctx, input.TrustCenterFileID)
|
fileData, mimeType, err := trustService.TrustCenterFiles.ExportFileWithoutWatermark(ctx, input.TrustCenterFileID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot export trust center file", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot export trust center file", log.Error(err))
|
||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &types.ExportTrustCenterFilePayload{
|
return &types.ExportTrustCenterFilePayload{
|
||||||
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(fileData)),
|
Data: fmt.Sprintf("data:%s;base64,%s", mimeType, base64.StdEncoding.EncodeToString(fileData)),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -519,14 +519,14 @@ func (r *mutationResolver) ExportTrustCenterFile(ctx context.Context, input type
|
|||||||
return nil, gqlutils.Forbiddenf(ctx, "access denied: no permission to access this file")
|
return nil, gqlutils.Forbiddenf(ctx, "access denied: no permission to access this file")
|
||||||
}
|
}
|
||||||
|
|
||||||
fileData, err := trustService.TrustCenterFiles.ExportFile(ctx, input.TrustCenterFileID, identity.EmailAddress)
|
fileData, mimeType, err := trustService.TrustCenterFiles.ExportFile(ctx, input.TrustCenterFileID, identity.EmailAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot export trust center file", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot export trust center file", log.Error(err))
|
||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &types.ExportTrustCenterFilePayload{
|
return &types.ExportTrustCenterFilePayload{
|
||||||
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(fileData)),
|
Data: fmt.Sprintf("data:%s;base64,%s", mimeType, base64.StdEncoding.EncodeToString(fileData)),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -97,31 +97,34 @@ func (s *TrustCenterFileService) ExportFile(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
trustCenterFileID gid.GID,
|
trustCenterFileID gid.GID,
|
||||||
email mail.Addr,
|
email mail.Addr,
|
||||||
) ([]byte, error) {
|
) ([]byte, string, error) {
|
||||||
pdfData, err := s.exportFileData(ctx, trustCenterFileID)
|
fileData, mimeType, err := s.exportFileData(ctx, trustCenterFileID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot export trust center file: %w", err)
|
return nil, "", fmt.Errorf("cannot export trust center file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
watermarkedPDF, err := watermarkpdf.AddConfidentialWithTimestamp(pdfData, email)
|
if mimeType == "application/pdf" {
|
||||||
|
watermarkedPDF, err := watermarkpdf.AddConfidentialWithTimestamp(fileData, email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot add watermark to PDF: %w", err)
|
return nil, "", fmt.Errorf("cannot add watermark to PDF: %w", err)
|
||||||
|
}
|
||||||
|
return watermarkedPDF, mimeType, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return watermarkedPDF, nil
|
return fileData, mimeType, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TrustCenterFileService) ExportFileWithoutWatermark(
|
func (s *TrustCenterFileService) ExportFileWithoutWatermark(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
trustCenterFileID gid.GID,
|
trustCenterFileID gid.GID,
|
||||||
) ([]byte, error) {
|
) ([]byte, string, error) {
|
||||||
return s.exportFileData(ctx, trustCenterFileID)
|
return s.exportFileData(ctx, trustCenterFileID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TrustCenterFileService) exportFileData(
|
func (s *TrustCenterFileService) exportFileData(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
trustCenterFileID gid.GID,
|
trustCenterFileID gid.GID,
|
||||||
) ([]byte, error) {
|
) ([]byte, string, error) {
|
||||||
var trustCenterFile *coredata.TrustCenterFile
|
var trustCenterFile *coredata.TrustCenterFile
|
||||||
var file *coredata.File
|
var file *coredata.File
|
||||||
|
|
||||||
@@ -139,7 +142,7 @@ func (s *TrustCenterFileService) exportFileData(
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := s.svc.s3.GetObject(ctx, &s3.GetObjectInput{
|
result, err := s.svc.s3.GetObject(ctx, &s3.GetObjectInput{
|
||||||
@@ -147,14 +150,14 @@ func (s *TrustCenterFileService) exportFileData(
|
|||||||
Key: new(file.FileKey),
|
Key: new(file.FileKey),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot download file from S3: %w", err)
|
return nil, "", fmt.Errorf("cannot download file from S3: %w", err)
|
||||||
}
|
}
|
||||||
defer func() { _ = result.Body.Close() }()
|
defer func() { _ = result.Body.Close() }()
|
||||||
|
|
||||||
fileData, err := io.ReadAll(result.Body)
|
fileData, err := io.ReadAll(result.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot read file data: %w", err)
|
return nil, "", fmt.Errorf("cannot read file data: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileData, nil
|
return fileData, file.MimeType, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user