Feat/import export (#136)

* added import/export functionality
This commit is contained in:
Daniel
2023-08-10 12:16:44 -04:00
committed by GitHub
parent 159075b38b
commit d008c441b7
16 changed files with 352 additions and 93 deletions
+30 -25
View File
@@ -10,7 +10,10 @@ export default async function archive(linkId: number, url: string) {
try {
await page.goto(url, { waitUntil: "domcontentloaded" });
await autoScroll(page);
await page.evaluate(
autoScroll,
Number(process.env.AUTOSCROLL_TIMEOUT) || 30
);
const linkExists = await prisma.link.findUnique({
where: {
@@ -47,29 +50,31 @@ export default async function archive(linkId: number, url: string) {
}
}
const autoScroll = async (page: Page) => {
await page.evaluate(async () => {
const timeoutPromise = new Promise<void>((_, reject) => {
setTimeout(() => {
reject(new Error("Auto scroll took too long (more than 20 seconds)."));
}, 20000);
});
const scrollingPromise = new Promise<void>((resolve) => {
let totalHeight = 0;
let distance = 100;
let scrollDown = setInterval(() => {
let scrollHeight = document.body.scrollHeight;
window.scrollBy(0, distance);
totalHeight += distance;
if (totalHeight >= scrollHeight) {
clearInterval(scrollDown);
window.scroll(0, 0);
resolve();
}
}, 100);
});
await Promise.race([scrollingPromise, timeoutPromise]);
const autoScroll = async (AUTOSCROLL_TIMEOUT: number) => {
const timeoutPromise = new Promise<void>((_, reject) => {
setTimeout(() => {
reject(
new Error(
`Auto scroll took too long (more than ${AUTOSCROLL_TIMEOUT} seconds).`
)
);
}, AUTOSCROLL_TIMEOUT * 1000);
});
const scrollingPromise = new Promise<void>((resolve) => {
let totalHeight = 0;
let distance = 100;
let scrollDown = setInterval(() => {
let scrollHeight = document.body.scrollHeight;
window.scrollBy(0, distance);
totalHeight += distance;
if (totalHeight >= scrollHeight) {
clearInterval(scrollDown);
window.scroll(0, 0);
resolve();
}
}, 100);
});
await Promise.race([scrollingPromise, timeoutPromise]);
};
@@ -40,14 +40,6 @@ export default async function postCollection(
name: collection.name.trim(),
description: collection.description,
color: collection.color,
members: {
create: collection.members.map((e) => ({
user: { connect: { id: e.user.id } },
canCreate: e.canCreate,
canUpdate: e.canUpdate,
canDelete: e.canDelete,
})),
},
},
include: {
_count: {
+24
View File
@@ -0,0 +1,24 @@
import { prisma } from "@/lib/api/db";
export default async function getData(userId: number) {
const user = await prisma.user.findUnique({
where: { id: userId },
include: {
collections: {
include: {
links: {
include: {
tags: true,
},
},
},
},
},
});
if (!user) return { response: "User not found.", status: 404 };
const { password, id, image, ...userData } = user;
return { response: userData, status: 200 };
}
+86
View File
@@ -0,0 +1,86 @@
import { prisma } from "@/lib/api/db";
import { Backup } from "@/types/global";
import createFolder from "@/lib/api/storage/createFolder";
export default async function getData(userId: number, data: Backup) {
// Import collections
try {
data.collections.forEach(async (e) => {
e.name = e.name.trim();
const findCollection = await prisma.user.findUnique({
where: {
id: userId,
},
select: {
collections: {
where: {
name: e.name,
},
},
},
});
const checkIfCollectionExists = findCollection?.collections[0];
let collectionId = findCollection?.collections[0]?.id;
if (!checkIfCollectionExists) {
const newCollection = await prisma.collection.create({
data: {
owner: {
connect: {
id: userId,
},
},
name: e.name,
description: e.description,
color: e.color,
},
});
createFolder({ filePath: `archives/${newCollection.id}` });
collectionId = newCollection.id;
}
// Import Links
e.links.forEach(async (e) => {
const newLink = await prisma.link.create({
data: {
url: e.url,
name: e.name,
description: e.description,
collection: {
connect: {
id: collectionId,
},
},
tags: {
connectOrCreate: e.tags.map((tag) => ({
where: {
name_ownerId: {
name: tag.name.trim(),
ownerId: userId,
},
},
create: {
name: tag.name.trim(),
owner: {
connect: {
id: userId,
},
},
},
})),
},
},
});
});
});
} catch (err) {
console.log(err);
}
return { response: "Success.", status: 200 };
}
+1 -4
View File
@@ -20,9 +20,6 @@ export default async function postLink(
};
}
// This has to move above we assign link.collection.name
// Because if the link is null (write then delete text on collection)
// It will try to do trim on empty string and will throw and error, this prevents it.
if (!link.collection.name) {
link.collection.name = "Unnamed Collection";
}
@@ -54,7 +51,7 @@ export default async function postLink(
? link.description
: await getTitle(link.url);
const newLink: Link = await prisma.link.create({
const newLink = await prisma.link.create({
data: {
url: link.url,
name: link.name,
+39 -14
View File
@@ -9,12 +9,14 @@ import s3Client from "./s3Client";
import util from "util";
type ReturnContentTypes =
| "text/plain"
| "text/html"
| "image/jpeg"
| "image/png"
| "application/pdf";
export default async function readFile({ filePath }: { filePath: string }) {
export default async function readFile(filePath: string) {
const isRequestingAvatar = filePath.startsWith("uploads/avatar");
let contentType: ReturnContentTypes;
if (s3Client) {
@@ -28,6 +30,7 @@ export default async function readFile({ filePath }: { filePath: string }) {
| {
file: Buffer | string;
contentType: ReturnContentTypes;
status: number;
}
| undefined;
@@ -38,11 +41,12 @@ export default async function readFile({ filePath }: { filePath: string }) {
try {
await headObjectAsync(bucketParams);
} catch (err) {
contentType = "text/plain";
contentType = "text/html";
returnObject = {
file: "File not found, it's possible that the file you're looking for either doesn't exist or hasn't been created yet.",
file: isRequestingAvatar ? "File not found." : fileNotFoundTemplate,
contentType,
status: isRequestingAvatar ? 200 : 400,
};
}
@@ -60,14 +64,14 @@ export default async function readFile({ filePath }: { filePath: string }) {
// if (filePath.endsWith(".jpg"))
contentType = "image/jpeg";
}
returnObject = { file: data as Buffer, contentType };
returnObject = { file: data as Buffer, contentType, status: 200 };
}
return returnObject;
} catch (err) {
console.log("Error:", err);
contentType = "text/plain";
contentType = "text/html";
return {
file: "An internal occurred, please contact support.",
contentType,
@@ -77,13 +81,7 @@ export default async function readFile({ filePath }: { filePath: string }) {
const storagePath = process.env.STORAGE_FOLDER || "data";
const creationPath = path.join(process.cwd(), storagePath + "/" + filePath);
const file = fs.existsSync(creationPath)
? fs.readFileSync(creationPath)
: "File not found, it's possible that the file you're looking for either doesn't exist or hasn't been created yet.";
if (file.toString().startsWith("File not found")) {
contentType = "text/plain";
} else if (filePath.endsWith(".pdf")) {
if (filePath.endsWith(".pdf")) {
contentType = "application/pdf";
} else if (filePath.endsWith(".png")) {
contentType = "image/png";
@@ -92,7 +90,16 @@ export default async function readFile({ filePath }: { filePath: string }) {
contentType = "image/jpeg";
}
return { file, contentType };
if (!fs.existsSync(creationPath))
return {
file: isRequestingAvatar ? "File not found." : fileNotFoundTemplate,
contentType: "text/html",
status: isRequestingAvatar ? 200 : 400,
};
else {
const file = fs.readFileSync(creationPath);
return { file, contentType, status: 200 };
}
}
}
@@ -105,3 +112,21 @@ const streamToBuffer = (stream: any) => {
stream.on("end", () => resolve(Buffer.concat(chunks)));
});
};
const fileNotFoundTemplate = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File not found</title>
</head>
<body style="margin-left: auto; margin-right: auto; max-width: 500px; padding: 1rem; font-family: sans-serif; background-color: rgb(251, 251, 251);">
<h1>File not found</h1>
<h2>It is possible that the file you're looking for either doesn't exist or hasn't been created yet.</h2>
<h3>Some possible reasons are:</h3>
<ul>
<li>You are trying to access a file too early, before it has been fully archived.</li>
<li>The file doesn't exist either because it encountered an error while being archived, or it simply doesn't exist.</li>
</ul>
</body>
</html>`;