import type { KnowledgeBase, KnowledgeBaseArticle } from "@toolctrl/db/prisma-browser"; import { createKnowledgeBaseArticle, getKbArticleBySlug, getKnowledgeBaseArticlesForTemplateExport, updateKnowledgeBaseArticle, } from "../db/kbArticles.db.server"; import { createKnowledgeBaseCategory, getKbCategoryBySlug, getKnowledgeBaseCategoriesForTemplateExport, updateKnowledgeBaseCategory, } from "../db/kbCategories.db.server"; import { createKnowledgeBase, getAllKnowledgeBases, getKnowledgeBaseBySlug, updateKnowledgeBase } from "../db/knowledgeBase.db.server"; import { KbNavLinkDto } from "../dtos/KbNavLinkDto"; import { KnowledgeBasesTemplateDto } from "../dtos/KnowledgeBasesTemplateDto"; import { KnowledgeBaseCategoryWithDetails } from "../helpers/KbCategoryModelHelper"; import { createKnowledgeBaseCategorySection, updateKnowledgeBaseCategorySection } from "../db/kbCategorySections.db.server"; import { adminGetAllUsersNames } from "~/utils/db/users.db.server"; async function getTemplate(): Promise { const template: KnowledgeBasesTemplateDto = { knowledgeBases: [], categories: [], articles: [], }; const allKbs = await getAllKnowledgeBases(); const categoriesByKnowledgeBaseId = groupByKnowledgeBaseId( await getKnowledgeBaseCategoriesForTemplateExport({ knowledgeBaseIds: allKbs.map((kb) => kb.id) }) ); const articlesByKnowledgeBaseId = groupByKnowledgeBaseId(await getKnowledgeBaseArticlesForTemplateExport({ knowledgeBaseIds: allKbs.map((kb) => kb.id) })); for (const kb of allKbs) { template.knowledgeBases.push({ basePath: kb.basePath, slug: kb.slug, title: kb.title, description: kb.description, defaultLanguage: kb.defaultLanguage, layout: kb.layout, color: kb.color, enabled: kb.enabled, languages: JSON.parse(kb.languages) as string[], links: JSON.parse(kb.links) as KbNavLinkDto[], logo: kb.logo, seoImage: kb.seoImage, }); const allCategories = categoriesByKnowledgeBaseId.get(kb.id) ?? []; for (const category of allCategories) { template.categories.push({ knowledgeBaseSlug: kb.slug, slug: category.slug, order: category.order, title: category.title, description: category.description, icon: category.icon, language: category.language, seoImage: category.seoImage, sections: category.sections.map((section) => ({ order: section.order, title: section.title, description: section.description, })), }); } const allArticles = articlesByKnowledgeBaseId.get(kb.id) ?? []; for (const article of allArticles) { template.articles.push({ knowledgeBaseSlug: kb.slug, categorySlug: article.category?.slug ?? null, categorySectionOrder: article.section?.order ?? null, slug: article.slug, title: article.title, description: article.description, order: article.order, contentDraft: article.contentDraft, contentPublished: article.contentPublished, contentPublishedAsText: article.contentPublishedAsText, contentType: article.contentType, language: article.language, featuredOrder: article.featuredOrder, seoImage: article.seoImage, publishedAt: article.publishedAt ? article.publishedAt.toISOString() : null, createdByUserEmail: article.createdByUser?.email ?? null, relatedArticles: article.relatedArticles.map(({ relatedArticle }) => ({ slug: relatedArticle.slug, })), }); } } return template; } function groupByKnowledgeBaseId(items: T[]) { const grouped = new Map(); for (const item of items) { const current = grouped.get(item.knowledgeBaseId); if (current) { current.push(item); } else { grouped.set(item.knowledgeBaseId, [item]); } } return grouped; } async function importKbs({ template, currentUserId }: { template: KnowledgeBasesTemplateDto; currentUserId: string }) { let created = { kbs: 0, categories: 0, sections: 0, articles: 0, }; let updated = { kbs: 0, categories: 0, sections: 0, articles: 0, }; const allUsers = await adminGetAllUsersNames(); for (const kb of template.knowledgeBases) { if (!kb.basePath) { kb.basePath = "/"; } let existing: KnowledgeBase | null = await getKnowledgeBaseBySlug(kb.slug); if (existing) { await updateKnowledgeBase(existing.id, { basePath: kb.basePath, slug: kb.slug, title: kb.title, description: kb.description, defaultLanguage: kb.defaultLanguage, layout: kb.layout, color: kb.color, enabled: kb.enabled, languages: JSON.stringify(kb.languages), links: JSON.stringify(kb.links), logo: kb.logo, seoImage: kb.seoImage, }); updated.kbs++; } else { existing = await createKnowledgeBase({ basePath: kb.basePath, slug: kb.slug, title: kb.title, description: kb.description, defaultLanguage: kb.defaultLanguage, layout: kb.layout, color: kb.color, enabled: kb.enabled, languages: JSON.stringify(kb.languages), links: JSON.stringify(kb.links), logo: kb.logo, seoImage: kb.seoImage, }); created.kbs++; } for (const category of template.categories.filter((c) => c.knowledgeBaseSlug === kb.slug)) { let existingCategory: KnowledgeBaseCategoryWithDetails | null = await getKbCategoryBySlug({ knowledgeBaseId: existing.id, slug: category.slug, language: category.language, }); if (existingCategory) { await updateKnowledgeBaseCategory(existingCategory.id, { title: category.title, order: category.order, description: category.description, icon: category.icon, language: category.language, seoImage: category.seoImage, }); updated.categories++; } else { existingCategory = await createKnowledgeBaseCategory({ knowledgeBaseId: existing.id, slug: category.slug, title: category.title, order: category.order, description: category.description, icon: category.icon, language: category.language, seoImage: category.seoImage, }); created.categories++; } for (const section of category.sections) { let existingSection: { id: string; order: number; title: string; description: string } | null = null; if (existingCategory) { existingSection = existingCategory.sections.find((s) => s.order === section.order) ?? null; } if (existingSection) { await updateKnowledgeBaseCategorySection(existingSection.id, { title: section.title, description: section.description, }); updated.sections++; } else { await createKnowledgeBaseCategorySection({ categoryId: existingCategory?.id ?? null, order: section.order, title: section.title, description: section.description, }); created.sections++; } } } for (const article of template.articles.filter((a) => a.knowledgeBaseSlug === kb.slug)) { let existingArticle: KnowledgeBaseArticle | null = await getKbArticleBySlug({ knowledgeBaseId: existing.id, slug: article.slug, language: article.language, }); let category: KnowledgeBaseCategoryWithDetails | null = null; let sectionId: string | null = null; if (article.categorySlug) { category = await getKbCategoryBySlug({ knowledgeBaseId: existing.id, slug: article.categorySlug, language: article.language, }); if (category && article.categorySectionOrder) { const section = category.sections.find((s) => s.order === article.categorySectionOrder); if (section) { sectionId = section.id; } } } let createdByUserId = currentUserId; if (article.createdByUserEmail) { const user = allUsers.find((f) => f.email === article.createdByUserEmail); if (user) { createdByUserId = user.id; } } if (existingArticle) { await updateKnowledgeBaseArticle(existingArticle.id, { categoryId: category?.id ?? null, sectionId: sectionId, slug: article.slug, title: article.title, description: article.description, order: article.order, contentDraft: article.contentDraft, contentPublished: article.contentPublished, contentPublishedAsText: article.contentPublishedAsText, contentType: article.contentType, language: article.language, featuredOrder: article.featuredOrder, createdByUserId, seoImage: article.seoImage, publishedAt: article.publishedAt ? new Date(article.publishedAt) : null, }); updated.articles++; } else { existingArticle = await createKnowledgeBaseArticle({ knowledgeBaseId: existing.id, categoryId: category?.id ?? null, sectionId: sectionId, slug: article.slug, title: article.title, description: article.description, order: article.order, contentDraft: article.contentDraft, contentPublished: article.contentPublished, contentPublishedAsText: article.contentPublishedAsText, contentType: article.contentType, language: article.language, featuredOrder: article.featuredOrder, createdByUserId, seoImage: article.seoImage, publishedAt: article.publishedAt ? new Date(article.publishedAt) : null, }); created.articles++; } } } return { created, updated, }; } export default { getTemplate, importKbs, };