el.xwx.moe/lib/api/controllers/migration/importFromHTMLFile.ts

200 lines
5.2 KiB
TypeScript
Raw Normal View History

import { prisma } from "@/lib/api/db";
import createFolder from "@/lib/api/storage/createFolder";
import { JSDOM } from "jsdom";
2023-12-19 16:20:09 -06:00
const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000;
2023-10-16 17:27:04 -05:00
export default async function importFromHTMLFile(
userId: number,
rawData: string
) {
2023-11-07 07:03:35 -06:00
const dom = new JSDOM(rawData);
const document = dom.window.document;
2023-12-19 16:20:09 -06:00
const bookmarks = document.querySelectorAll("A");
const totalImports = bookmarks.length;
const numberOfLinksTheUserHas = await prisma.link.count({
where: {
collection: {
ownerId: userId,
},
},
});
if (totalImports + numberOfLinksTheUserHas > MAX_LINKS_PER_USER)
return {
response: `Error: Each user can only have a maximum of ${MAX_LINKS_PER_USER} Links.`,
status: 400,
};
2023-11-07 07:03:35 -06:00
const folders = document.querySelectorAll("H3");
2024-02-10 01:47:58 -06:00
let unorganizedCollectionId: number | null = null;
2024-02-10 01:47:58 -06:00
if (folders.length === 0) {
const unorganizedCollection = await prisma.collection.findFirst({
where: {
name: "Imported",
ownerId: userId,
},
});
2024-02-10 01:47:58 -06:00
if (!unorganizedCollection) {
const newUnorganizedCollection = await prisma.collection.create({
data: {
name: "Imported",
description:
"Automatically created collection for imported bookmarks.",
ownerId: userId,
},
});
unorganizedCollectionId = newUnorganizedCollection.id;
} else {
unorganizedCollectionId = unorganizedCollection.id;
}
2024-02-10 01:47:58 -06:00
createFolder({ filePath: `archives/${unorganizedCollectionId}` });
}
2024-02-10 01:47:58 -06:00
await prisma
.$transaction(
async () => {
if (unorganizedCollectionId) {
// @ts-ignore
for (const bookmark of bookmarks) {
2024-02-14 09:35:59 -06:00
createBookmark(userId, bookmark, unorganizedCollectionId);
2024-02-10 01:47:58 -06:00
}
} else {
// @ts-ignore
for (const folder of folders) {
2024-02-15 11:26:42 -06:00
await createCollectionAndBookmarks(
userId,
folder,
folder.nextElementSibling,
null
);
2023-11-07 07:03:35 -06:00
}
}
},
{ timeout: 30000 }
)
.catch((err) => console.log(err));
return { response: "Success.", status: 200 };
}
2024-02-14 09:35:59 -06:00
2024-02-15 11:26:42 -06:00
const createCollectionAndBookmarks = async (
userId: number,
folder: any,
folderContent: any,
parentId: number | null
) => {
const findCollection = await prisma.collection.findFirst({
where: {
name: folder.textContent.trim(),
ownerId: userId,
},
});
const checkIfCollectionExists = findCollection;
let collectionId = findCollection?.id;
if (!checkIfCollectionExists || !collectionId) {
const newCollection = await prisma.collection.create({
data: {
name: folder.textContent.trim(),
description: "",
color: "#0ea5e9",
isPublic: false,
ownerId: userId,
parentId
},
});
createFolder({ filePath: `archives/${newCollection.id}` });
collectionId = newCollection.id;
}
createFolder({ filePath: `archives/${collectionId}` });
const bookmarks = folderContent.querySelectorAll("A");
for (const bookmark of bookmarks) {
createBookmark(userId, bookmark, collectionId);
}
const subfolders = folderContent.querySelectorAll("H3");
for (const subfolder of subfolders) {
await createCollectionAndBookmarks(userId, subfolder, subfolder.nextElementSibling, collectionId);
}
};
2024-02-14 09:35:59 -06:00
const createBookmark = async (
userId: number,
bookmark: any,
collectionId: number
) => {
// Move up to the parent node (<DT>) and then find the next sibling
let parentDT = bookmark.parentNode;
let nextSibling = parentDT ? parentDT.nextSibling : null;
let description = "";
// Loop through siblings to skip any potential text nodes or whitespace
while (nextSibling && nextSibling.nodeType !== 1) {
nextSibling = nextSibling.nextSibling;
}
// Check if the next sibling element is a <DD> tag and use its content as the description
if (nextSibling && nextSibling.tagName === "DD") {
description = nextSibling.textContent.trim();
}
2024-02-15 11:26:42 -06:00
const linkName = bookmark.textContent.trim();
const linkURL = bookmark.getAttribute("HREF");
const existingLink = await prisma.link.findFirst({
where: {
url: linkURL,
collectionId
},
});
// Create the link only if it doesn't already exist
if (!existingLink) {
await prisma.link.create({
data: {
name: linkName,
url: linkURL,
tags: bookmark.getAttribute("TAGS")
? {
2024-02-14 09:35:59 -06:00
connectOrCreate: bookmark
.getAttribute("TAGS")
.split(",")
.map((tag: string) =>
tag
? {
2024-02-15 11:26:42 -06:00
where: {
data: {
2024-02-14 09:35:59 -06:00
name: tag.trim(),
2024-02-15 11:26:42 -06:00
ownerId: userId,
},
},
create: {
name: tag.trim(),
owner: {
connect: {
id: userId,
2024-02-14 09:35:59 -06:00
},
},
2024-02-15 11:26:42 -06:00
},
}
2024-02-14 09:35:59 -06:00
: undefined
),
}
2024-02-15 11:26:42 -06:00
: undefined,
description,
collectionId,
},
});
}
};