Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f1c4d03ca |
@@ -32,7 +32,7 @@ import {
|
||||
DocumentWithLinksAndLinkCountAndViewCount,
|
||||
DocumentWithVersion,
|
||||
} from "@/lib/types";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn, ensureFileExtension } from "@/lib/utils";
|
||||
import { supportsAdvancedExcelMode } from "@/lib/utils/get-content-type";
|
||||
import { fileIcon } from "@/lib/utils/get-file-icon";
|
||||
|
||||
@@ -477,7 +477,10 @@ export default function DocumentHeader({
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = prismaDocument.name;
|
||||
a.download = ensureFileExtension(prismaDocument.name, {
|
||||
type: documentVersion.type || undefined,
|
||||
contentType: documentVersion.contentType || undefined,
|
||||
});
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Download, MoreVerticalIcon } from "lucide-react";
|
||||
import { useTheme } from "next-themes";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import { timeAgo } from "@/lib/utils";
|
||||
import { ensureFileExtension, timeAgo } from "@/lib/utils";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { fileIcon } from "@/lib/utils/get-file-icon";
|
||||
import {
|
||||
@@ -136,7 +136,10 @@ export default function DocumentCard({
|
||||
disposition && disposition.match(/filename="(.+)"/);
|
||||
link.download = filenameMatch
|
||||
? decodeURIComponent(filenameMatch[1])
|
||||
: document.name;
|
||||
: ensureFileExtension(document.name, {
|
||||
type: document.versions[0]?.type || undefined,
|
||||
contentType: document.versions[0]?.contentType || undefined,
|
||||
});
|
||||
link.rel = "noopener noreferrer";
|
||||
window.document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
@@ -91,6 +91,7 @@ export type DocumentVersion = {
|
||||
hasPages: boolean;
|
||||
isVertical: boolean;
|
||||
updatedAt: Date;
|
||||
contentType: string;
|
||||
};
|
||||
|
||||
type DataroomDocument = {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Document, Page, pdfjs } from "react-pdf";
|
||||
|
||||
import { useSafePageViewTracker } from "@/lib/tracking/safe-page-view-tracker";
|
||||
import { getTrackingOptions } from "@/lib/tracking/tracking-config";
|
||||
import { ensureFileExtension } from "@/lib/utils";
|
||||
|
||||
import Nav from "@/components/view/nav";
|
||||
|
||||
@@ -231,7 +232,7 @@ export default function PDFViewer(props: any) {
|
||||
//create <a/> to download the file
|
||||
const a = document.createElement("a");
|
||||
a.href = window.URL.createObjectURL(fileData);
|
||||
a.download = props.name;
|
||||
a.download = ensureFileExtension(props.name, { type: "pdf" });
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
|
||||
|
||||
@@ -141,6 +141,7 @@ export async function fetchDataroomLinkData({
|
||||
file: true,
|
||||
isVertical: true,
|
||||
updatedAt: true,
|
||||
contentType: true,
|
||||
},
|
||||
take: 1,
|
||||
},
|
||||
@@ -323,6 +324,7 @@ export async function fetchDataroomDocumentLinkData({
|
||||
hasPages: true,
|
||||
file: true,
|
||||
isVertical: true,
|
||||
contentType: true,
|
||||
},
|
||||
take: 1,
|
||||
},
|
||||
|
||||
@@ -15,6 +15,8 @@ import { ParsedUrlQuery } from "querystring";
|
||||
import { toast } from "sonner";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { getExtensionFromContentType } from "./utils/get-content-type";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
@@ -41,6 +43,69 @@ export function getFileNameWithPdfExtension(filename?: string): string {
|
||||
return `${nameWithoutExt}.pdf`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures a filename has the correct file extension based on document type or contentType
|
||||
* If the filename already has an extension, it is preserved.
|
||||
* If not, the appropriate extension is added based on the provided type/contentType.
|
||||
*/
|
||||
export function ensureFileExtension(
|
||||
filename?: string,
|
||||
options?: {
|
||||
type?: string;
|
||||
contentType?: string;
|
||||
},
|
||||
): string {
|
||||
if (!filename) return "document";
|
||||
|
||||
// Check if filename already has an extension
|
||||
const hasExtension = /\.[^/.]+$/.test(filename);
|
||||
|
||||
if (hasExtension) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
// If no extension, determine the appropriate one
|
||||
let extension = "";
|
||||
|
||||
// First try to get extension from contentType if provided
|
||||
if (options?.contentType) {
|
||||
const ext = getExtensionFromContentType(options.contentType);
|
||||
if (ext) {
|
||||
extension = ext;
|
||||
}
|
||||
}
|
||||
|
||||
// If no extension from contentType, try using the document type
|
||||
if (!extension && options?.type) {
|
||||
switch (options.type) {
|
||||
case "pdf":
|
||||
extension = "pdf";
|
||||
break;
|
||||
case "image":
|
||||
extension = "png"; // default image extension
|
||||
break;
|
||||
case "sheet":
|
||||
extension = "xlsx";
|
||||
break;
|
||||
case "docs":
|
||||
extension = "docx";
|
||||
break;
|
||||
case "slides":
|
||||
extension = "pptx";
|
||||
break;
|
||||
case "video":
|
||||
extension = "mp4";
|
||||
break;
|
||||
default:
|
||||
// No extension determined
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return filename with extension if one was determined
|
||||
return extension ? `${filename}.${extension}` : filename;
|
||||
}
|
||||
|
||||
interface SWRError extends Error {
|
||||
status: number;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { waitUntil } from "@vercel/functions";
|
||||
import { getFile } from "@/lib/files/get-file";
|
||||
import { notifyDocumentDownload } from "@/lib/integrations/slack/events";
|
||||
import prisma from "@/lib/prisma";
|
||||
import { getFileNameWithPdfExtension } from "@/lib/utils";
|
||||
import { ensureFileExtension, getFileNameWithPdfExtension } from "@/lib/utils";
|
||||
import { getIpAddress } from "@/lib/utils/ip";
|
||||
|
||||
export const config = {
|
||||
@@ -281,7 +281,15 @@ export default async function handle(
|
||||
res.setHeader("Content-Type", "application/pdf");
|
||||
res.setHeader(
|
||||
"Content-Disposition",
|
||||
`attachment; filename="${encodeURIComponent(downloadDocuments[0].document!.name)}"`,
|
||||
`attachment; filename="${encodeURIComponent(
|
||||
ensureFileExtension(downloadDocuments[0].document!.name, {
|
||||
type:
|
||||
downloadDocuments[0].document!.versions[0].type || undefined,
|
||||
contentType:
|
||||
downloadDocuments[0].document!.versions[0].contentType ||
|
||||
undefined,
|
||||
}),
|
||||
)}"`,
|
||||
);
|
||||
res.setHeader("Content-Length", Buffer.from(pdfBuffer).length);
|
||||
res.setHeader("Cache-Control", "no-cache");
|
||||
@@ -295,7 +303,14 @@ export default async function handle(
|
||||
downloadDocuments[0].document!.versions[0].contentType ||
|
||||
headResponse.headers.get("content-type") ||
|
||||
"application/octet-stream";
|
||||
const fileName = downloadDocuments[0].document!.name;
|
||||
const fileName = ensureFileExtension(
|
||||
downloadDocuments[0].document!.name,
|
||||
{
|
||||
type: downloadDocuments[0].document!.versions[0].type || undefined,
|
||||
contentType:
|
||||
downloadDocuments[0].document!.versions[0].contentType || undefined,
|
||||
},
|
||||
);
|
||||
|
||||
// For all other files, return direct download URL
|
||||
return res.status(200).json({
|
||||
|
||||
Reference in New Issue
Block a user