Skip to content

Commit 3a4911a

Browse files
upload route now converts images to PDFs and uploads both to admin-buffer
1 parent 8f17a1b commit 3a4911a

File tree

4 files changed

+337
-69
lines changed

4 files changed

+337
-69
lines changed

src/app/api/admin/route.ts

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
import { PDFDocument } from "pdf-lib";
3+
4+
import { connectToDatabase } from "@/lib/mongoose";
5+
import cloudinary from "cloudinary";
6+
import {
7+
type IAdminUpload,
8+
type ConverttoPDFResponse,
9+
CloudinaryUploadResult,
10+
} from "@/interface";
11+
import Paper from "@/db/papers";
12+
import { handleAPIError } from "@/util/error";
13+
14+
cloudinary.v2.config({
15+
cloud_name: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME,
16+
api_key: process.env.CLOUDINARY_API_KEY,
17+
api_secret: process.env.CLOUDINARY_SECRET,
18+
});
19+
20+
export async function POST(req: Request) {
21+
try {
22+
if (!process.env.NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET) {
23+
return NextResponse.json({ message: "ServerMisconfig" }, { status: 500 });
24+
}
25+
const uploadPreset = process.env.NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET;
26+
const formData = await req.formData();
27+
const files: File[] = formData.getAll("files") as File[];
28+
29+
const subject = formData.get("subject") as string;
30+
const slot = formData.get("slot") as string;
31+
const year = formData.get("year") as string;
32+
const exam = formData.get("exam") as string;
33+
const isPdf = formData.get("isPdf") === "true"; // Convert string to boolean
34+
35+
await connectToDatabase();
36+
let finalUrl: string | undefined = "";
37+
let thumbnailUrl: string | undefined = "";
38+
const existingPaper = await Paper.findOne({
39+
subject,
40+
slot,
41+
year,
42+
exam,
43+
});
44+
if (existingPaper) {
45+
return NextResponse.json(
46+
{ message: "Paper already exists" },
47+
{ status: 409 },
48+
);
49+
}
50+
if (!files || files.length === 0) {
51+
return NextResponse.json(
52+
{ error: "No files received." },
53+
{ status: 400 },
54+
);
55+
}
56+
if (!isPdf) {
57+
try {
58+
if (!process.env.NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET) {
59+
return;
60+
}
61+
62+
const mergedPdfBytes = await CreatePDF(files);
63+
finalUrl = await uploadPDFFile(mergedPdfBytes, uploadPreset);
64+
} catch (error) {
65+
return NextResponse.json(
66+
{ error: "Failed to process PDF" },
67+
{ status: 500 },
68+
);
69+
}
70+
} else {
71+
finalUrl = await uploadPDFFile(files[0] as File, uploadPreset);
72+
}
73+
const thumbnailResponse = cloudinary.v2.image(finalUrl!, {
74+
format: "jpg",
75+
});
76+
thumbnailUrl = thumbnailResponse
77+
.replace("pdf", "jpg")
78+
.replace("upload", "upload/w_400,h_400,c_fill")
79+
.replace(/<img src='|'\s*\/>/g, "");
80+
81+
const paper = new Paper({
82+
finalUrl,
83+
thumbnailUrl,
84+
subject,
85+
slot,
86+
year,
87+
exam,
88+
});
89+
await paper.save();
90+
return NextResponse.json(
91+
{ status: "success", url: finalUrl, thumbnailUrl: thumbnailUrl },
92+
{ status: 201 },
93+
);
94+
} catch (error) {
95+
console.error(error);
96+
return NextResponse.json(
97+
{ message: "Failed to upload papers", error },
98+
99+
{ status: 500 },
100+
);
101+
}
102+
}
103+
104+
export async function DELETE(req: Request) {
105+
try {
106+
const url = new URL(req.url);
107+
const public_id = url.searchParams.get("public_id");
108+
const type = url.searchParams.get("type");
109+
110+
if (!public_id || !type) {
111+
return NextResponse.json(
112+
{ message: "Missing parameters: public_id or type" },
113+
{ status: 400 },
114+
);
115+
}
116+
await cloudinary.v2.uploader.destroy(public_id, {
117+
type: type,
118+
});
119+
120+
return NextResponse.json({ message: "Asset deleted successfully" });
121+
} catch (error) {
122+
return NextResponse.json(
123+
{ message: "Failed to delete asset", error },
124+
{ status: 500 },
125+
);
126+
}
127+
}
128+
async function uploadPDFFile(file: File | ArrayBuffer, uploadPreset: string) {
129+
let bytes;
130+
if(file instanceof File)
131+
{
132+
console.log("PDF file");
133+
bytes = await file.arrayBuffer();
134+
}
135+
else
136+
{
137+
console.log("Non PDF file");
138+
bytes = file as ArrayBuffer;
139+
}
140+
return uploadFile(bytes, uploadPreset, "application/pdf")
141+
}
142+
async function uploadFile(bytes: ArrayBuffer, uploadPreset: string, fileType: string) {
143+
try {
144+
const buffer = Buffer.from(bytes);
145+
const dataUrl = `data:${fileType};base64,${buffer.toString("base64")}`;
146+
147+
const uploadResult: CloudinaryUploadResult =
148+
await cloudinary.v2.uploader.unsigned_upload(dataUrl, uploadPreset);
149+
150+
return uploadResult.secure_url;
151+
} catch (e) {
152+
throw (e);
153+
}
154+
}
155+
async function CreatePDF(files: File[]) {
156+
const pdfDoc = await PDFDocument.create();
157+
158+
const orderedFiles = Array.from(files).sort((a, b) => {
159+
return a.name.localeCompare(b.name);
160+
});
161+
162+
for (const file of orderedFiles) {
163+
const fileBlob = new Blob([file]);
164+
const imgBytes = Buffer.from(await fileBlob.arrayBuffer());
165+
let img;
166+
if (file instanceof File) {
167+
if (file.type === "image/png") {
168+
img = await pdfDoc.embedPng(imgBytes);
169+
} else if (file.type === "image/jpeg" || file.type === "image/jpg") {
170+
img = await pdfDoc.embedJpg(imgBytes);
171+
} else {
172+
continue;
173+
}
174+
const page = pdfDoc.addPage([img.width, img.height]);
175+
page.drawImage(img, {
176+
x: 0,
177+
y: 0,
178+
width: img.width,
179+
height: img.height,
180+
});
181+
}
182+
}
183+
184+
const mergedPdfBytes = await pdfDoc.save();
185+
return mergedPdfBytes;
186+
}

0 commit comments

Comments
 (0)