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

199 lines
4.9 KiB
TypeScript
Raw Normal View History

import { prisma } from "@/lib/api/db";
import createFolder from "@/lib/api/storage/createFolder";
import { JSDOM } from "jsdom";
import { parse, Node, Element, TextNode } from "himalaya";
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;
// remove bad tags
document.querySelectorAll("meta").forEach((e) => (e.outerHTML = e.innerHTML));
document.querySelectorAll("META").forEach((e) => (e.outerHTML = e.innerHTML));
document.querySelectorAll("P").forEach((e) => (e.outerHTML = e.innerHTML));
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,
};
const jsonData = parse(document.documentElement.outerHTML);
for (const item of jsonData) {
console.log(item);
await processBookmarks(userId, item as Element);
2024-02-10 01:47:58 -06:00
}
return { response: "Success.", status: 200 };
}
async function processBookmarks(
userId: number,
data: Node,
parentCollectionId?: number
) {
if (data.type === "element") {
for (const item of data.children) {
if (item.type === "element" && item.tagName === "dt") {
2024-02-18 10:07:50 -06:00
// process collection or sub-collection
let collectionId;
const collectionName = item.children.find(
(e) => e.type === "element" && e.tagName === "h3"
) as Element;
if (collectionName) {
collectionId = await createCollection(
userId,
(collectionName.children[0] as TextNode).content,
parentCollectionId
);
}
await processBookmarks(
userId,
item,
collectionId || parentCollectionId
);
} else if (item.type === "element" && item.tagName === "a") {
2024-02-18 10:07:50 -06:00
// process link
const linkUrl = item?.attributes.find((e) => e.key === "href")?.value;
const linkName = (
item?.children.find((e) => e.type === "text") as TextNode
)?.content;
const linkTags = item?.attributes
.find((e) => e.key === "tags")
?.value.split(",");
if (linkUrl && parentCollectionId) {
await createLink(
userId,
linkUrl,
parentCollectionId,
linkName,
"",
linkTags
);
} else if (linkUrl) {
// create a collection named "Imported Bookmarks" and add the link to it
const collectionId = await createCollection(userId, "Imports");
await createLink(
userId,
linkUrl,
collectionId,
linkName,
"",
linkTags
);
2023-11-07 07:03:35 -06:00
}
await processBookmarks(userId, item, parentCollectionId);
} else {
2024-02-18 10:07:50 -06:00
// process anything else
await processBookmarks(userId, item, parentCollectionId);
}
}
}
}
2024-02-14 09:35:59 -06:00
const createCollection = async (
2024-02-15 11:26:42 -06:00
userId: number,
collectionName: string,
parentId?: number
2024-02-15 11:26:42 -06:00
) => {
const findCollection = await prisma.collection.findFirst({
where: {
parentId,
name: collectionName,
2024-02-15 11:26:42 -06:00
ownerId: userId,
},
});
if (findCollection) {
return findCollection.id;
2024-02-15 11:26:42 -06:00
}
const collectionId = await prisma.collection.create({
data: {
name: collectionName,
parent: parentId
? {
connect: {
id: parentId,
},
}
: undefined,
owner: {
connect: {
id: userId,
},
},
},
});
2024-02-15 11:26:42 -06:00
createFolder({ filePath: `archives/${collectionId.id}` });
2024-02-15 11:26:42 -06:00
return collectionId.id;
2024-02-15 11:26:42 -06:00
};
const createLink = async (
2024-02-14 09:35:59 -06:00
userId: number,
url: string,
collectionId: number,
name?: string,
description?: string,
tags?: string[]
2024-02-14 09:35:59 -06:00
) => {
await prisma.link.create({
data: {
name: name || "",
url,
description,
collectionId,
tags:
tags && tags[0]
2024-02-15 11:26:42 -06:00
? {
connectOrCreate: tags.map((tag: string) => {
return (
{
2024-02-15 11:26:42 -06:00
where: {
name_ownerId: {
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
},
} || undefined
);
}),
}
2024-02-15 11:26:42 -06:00
: undefined,
},
});
};