el.xwx.moe/pages/api/v1/archives/[linkId].ts

191 lines
5.6 KiB
TypeScript
Raw Normal View History

2023-11-19 15:22:27 -06:00
import type { NextApiRequest, NextApiResponse } from "next";
import readFile from "@/lib/api/storage/readFile";
import { prisma } from "@/lib/api/db";
import { ArchivedFormat } from "@/types/global";
import verifyUser from "@/lib/api/verifyUser";
import getPermission from "@/lib/api/getPermission";
import { UsersAndCollections } from "@prisma/client";
import formidable from "formidable";
import createFile from "@/lib/api/storage/createFile";
import fs from "fs";
import verifyToken from "@/lib/api/verifyToken";
import generatePreview from "@/lib/api/generatePreview";
2024-04-08 18:35:06 -05:00
import createFolder from "@/lib/api/storage/createFolder";
export const config = {
api: {
bodyParser: false,
},
};
2023-11-19 15:22:27 -06:00
export default async function Index(req: NextApiRequest, res: NextApiResponse) {
const linkId = Number(req.query.linkId);
const format = Number(req.query.format);
2023-12-23 11:11:47 -06:00
const isPreview = Boolean(req.query.preview);
2023-11-19 15:22:27 -06:00
let suffix: string;
2023-11-19 15:22:27 -06:00
2023-11-25 02:19:02 -06:00
if (format === ArchivedFormat.png) suffix = ".png";
else if (format === ArchivedFormat.jpeg) suffix = ".jpeg";
2023-11-19 15:22:27 -06:00
else if (format === ArchivedFormat.pdf) suffix = ".pdf";
else if (format === ArchivedFormat.readability) suffix = "_readability.json";
2024-06-27 20:58:07 -05:00
else if (format === ArchivedFormat.monolith) suffix = ".html";
2023-11-19 15:22:27 -06:00
//@ts-ignore
2023-11-19 15:22:27 -06:00
if (!linkId || !suffix)
return res.status(401).json({ response: "Invalid parameters." });
if (req.method === "GET") {
const token = await verifyToken({ req });
const userId = typeof token === "string" ? undefined : token?.id;
2023-11-19 15:22:27 -06:00
const collectionIsAccessible = await prisma.collection.findFirst({
where: {
links: {
some: {
id: linkId,
},
2023-11-19 15:22:27 -06:00
},
OR: [
{ ownerId: userId || -1 },
{ members: { some: { userId: userId || -1 } } },
{ isPublic: true },
],
2023-11-19 15:22:27 -06:00
},
});
if (!collectionIsAccessible)
return res
.status(401)
.json({ response: "You don't have access to this collection." });
2023-12-23 11:11:47 -06:00
if (isPreview) {
const { file, contentType, status } = await readFile(
`archives/preview/${collectionIsAccessible.id}/${linkId}.jpeg`
);
2023-12-23 11:11:47 -06:00
res.setHeader("Content-Type", contentType).status(status as number);
2023-12-23 11:11:47 -06:00
return res.send(file);
} else {
const { file, contentType, status } = await readFile(
`archives/${collectionIsAccessible.id}/${linkId + suffix}`
);
res.setHeader("Content-Type", contentType).status(status as number);
return res.send(file);
}
2024-03-20 08:56:14 -05:00
} else if (req.method === "POST") {
const user = await verifyUser({ req, res });
if (!user) return;
const collectionPermissions = await getPermission({
userId: user.id,
linkId,
});
const memberHasAccess = collectionPermissions?.members.some(
(e: UsersAndCollections) => e.userId === user.id && e.canCreate
);
if (!(collectionPermissions?.ownerId === user.id || memberHasAccess))
return { response: "Collection is not accessible.", status: 401 };
// await uploadHandler(linkId, )
2024-06-27 21:23:47 -05:00
const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER || 30000);
const numberOfLinksTheUserHas = await prisma.link.count({
where: {
collection: {
ownerId: user.id,
},
},
});
if (numberOfLinksTheUserHas > MAX_LINKS_PER_USER)
return {
response: `Error: Each user can only have a maximum of ${MAX_LINKS_PER_USER} Links.`,
status: 400,
};
2024-06-27 11:39:03 -05:00
const MAX_UPLOAD_SIZE = Number(
process.env.NEXT_PUBLIC_MAX_FILE_BUFFER || 10
);
2024-03-20 08:56:14 -05:00
const form = formidable({
maxFields: 1,
maxFiles: 1,
2024-06-27 11:39:03 -05:00
maxFileSize: MAX_UPLOAD_SIZE * 1048576,
2024-03-20 08:56:14 -05:00
});
form.parse(req, async (err, fields, files) => {
const allowedMIMETypes = [
"application/pdf",
"image/png",
"image/jpg",
"image/jpeg",
];
if (
err ||
!files.file ||
!files.file[0] ||
!allowedMIMETypes.includes(files.file[0].mimetype || "")
) {
// Handle parsing error
return res.status(500).json({
response: `Sorry, we couldn't process your file. Please ensure it's a PDF, PNG, or JPG format and doesn't exceed ${MAX_UPLOAD_SIZE}MB.`,
});
} else {
const fileBuffer = fs.readFileSync(files.file[0].filepath);
const linkStillExists = await prisma.link.findUnique({
where: { id: linkId },
});
if (linkStillExists && files.file[0].mimetype?.includes("image")) {
2024-04-08 18:35:06 -05:00
const collectionId = collectionPermissions?.id as number;
createFolder({
filePath: `archives/preview/${collectionId}`,
});
generatePreview(fileBuffer, collectionId, linkId);
}
2024-03-20 08:56:14 -05:00
if (linkStillExists) {
await createFile({
filePath: `archives/${collectionPermissions?.id}/${
linkId + suffix
}`,
data: fileBuffer,
});
await prisma.link.update({
where: { id: linkId },
data: {
preview: files.file[0].mimetype?.includes("pdf")
? "unavailable"
: undefined,
image: files.file[0].mimetype?.includes("image")
? `archives/${collectionPermissions?.id}/${linkId + suffix}`
: null,
pdf: files.file[0].mimetype?.includes("pdf")
? `archives/${collectionPermissions?.id}/${linkId + suffix}`
: null,
2024-03-20 08:56:14 -05:00
lastPreserved: new Date().toISOString(),
},
});
}
fs.unlinkSync(files.file[0].filepath);
}
return res.status(200).json({
response: files,
});
});
}
2023-11-19 15:22:27 -06:00
}