UNPKG

gridsome-source-confluence

Version:
420 lines (419 loc) 18.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const confluence_1 = require("./interface/confluence"); const confluence_2 = __importDefault(require("./services/confluence")); const nanoid_1 = require("nanoid"); const node_html_parser_1 = __importDefault(require("node-html-parser")); const slugify_1 = __importDefault(require("slugify")); const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); class ConfluenceSource { constructor(gridsomeAPI, config) { this.config = config; gridsomeAPI.loadSource(async (action) => { if (!(await this.validateConfig())) { return; } this.confluence = new confluence_2.default(config); this.log("Retrieving data."); this.gridsomeStore = action; fs_1.default.existsSync(`./static/images/confluence`) && fs_1.default.rmSync(`./static/images/confluence/`, { recursive: true, force: true }); await this.getSpaces(config.space_key); action.addCollection(this.getTypeName("Home")); action.addCollection(this.getTypeName("Parent")); action.addCollection(this.getTypeName("Child")); await this.getHomepage(); await this.getParentPages(); await this.getChildPages(); await this.setSlugs(); if (this.config.download_images) { await this.createDownloadLinks(); await this.downloadAttachments(); } await this.alterBody(); await this.createNodes(); this.log("Retrieval of data is done!"); }); } async validateConfig() { if (!this.config.base_url) { console.error("[Confluence]", "Missing the `baseUrl` option"); return false; } if (!this.config.public_only && (!this.config.username || !this.config.password)) { console.error("[Confluence]", "When public_only is disabled you need to add a username/password"); return false; } return true; } async getSpaces(spaces) { this.log("Get Spaces"); let returnSpaces = []; if (spaces) { let spaceArray = spaces.split(","); if (spaceArray.length === 0) { spaceArray = [spaces]; } const axiosResponse = spaceArray.map((space) => this.confluence.GetSpace(space)); await Promise.all(axiosResponse).then((res) => { res.forEach((response) => { returnSpaces.push({ key: response.data.key, content_id: response.data.homepage.id, title: response.data.homepage.title, pages: [], attachments: [], }); }); }); } else { returnSpaces = await this.confluence.GetSpaces().then((res) => { return res.data.results .filter((x) => { return x.type === confluence_1.SpacesType.GLOBAL; }) .map((el) => { return { key: el.key, content_id: el.homepage.id, title: el.homepage.title, pages: [], attachments: [], }; }); }); } this.spaces = returnSpaces; } async getHomepage() { this.log("Get Homepage"); const axiosResponse = this.spaces.map((space) => { return this.confluence.GetContentById(space.content_id); }); return Promise.all(axiosResponse).then((res) => { res.forEach((el) => { this.log(`Homepage: ${el.data.title}`); const spaceIndex = this.spaces.findIndex((space) => space.key === el.data.space.key); let labels = el.data.metadata.labels.results.map((label) => label.name); if (labels.length === 0) { labels = [""]; } this.spaces[spaceIndex].pages.push({ id: el.data.id, homepage: true, space: el.data.space.key, created_date: el.data.history.createdDate, modified_date: el.data.history.lastUpdated.when, title: el.data.title, body: el.data.body.view.value, position: el.data.extensions.position, anchor: [], description: "", slug: "", labels: labels, }); }); }); } async getParentPages() { this.log("Get ParentPages"); const axiosResponse = this.spaces.map((space) => { return this.confluence.GetContentChildPage(space.content_id); }); return Promise.all(axiosResponse).then((res) => { res.forEach((el) => { el.data.results.forEach(async (res) => { this.log(`Parent Page: ${res.title}`); const spaceIndex = this.spaces.findIndex((space) => space.key === res.space.key); let labels = res.metadata.labels.results.map((label) => label.name); if (labels.length === 0) { labels = [""]; } this.spaces[spaceIndex].pages.push({ id: res.id, space: res.space.key, title: res.title, created_date: res.history.createdDate, modified_date: res.history.lastUpdated.when, body: res.body.view.value, position: res.extensions.position, anchor: [], description: "", slug: "", labels: labels, }); }); }); }); } async getChildPages() { this.log("Get ChildPages"); const axiosResponse = []; let pages = []; this.spaces.map((space) => { space.pages.map((page) => { pages.push(page.id); }); }); while (pages.length !== 0) { pages.forEach((page) => axiosResponse.push(this.confluence.GetContentChildPage(page))); await Promise.all(axiosResponse).then((res) => { pages = []; res.forEach((el) => { el.data.results.forEach((res) => { var _a; const parentPageId = (_a = el.config.url) === null || _a === void 0 ? void 0 : _a.replace(/\D/g, ""); const spaceIndex = this.spaces.findIndex((space) => space.key === res.space.key); if (!this.spaces[spaceIndex].pages.find((page) => page.id === res.id)) { let labels = res.metadata.labels.results.map((label) => label.name); if (labels.length === 0) { labels = [""]; } this.spaces[spaceIndex].pages.push({ id: res.id, space: res.space.key, title: res.title, created_date: res.history.createdDate, modified_date: res.history.lastUpdated.when, body: res.body.view.value, parent_page: parentPageId, position: res.extensions.position, anchor: [], description: "", slug: "", labels: labels, }); pages.push(res.id); } }); }); }); } } async alterBody() { this.log("Alter Body"); this.spaces.forEach((space) => { space.pages.forEach((page) => { const htmlRoot = node_html_parser_1.default(page.body); htmlRoot.querySelectorAll("a").forEach((a) => { if (a.getAttribute("data-linked-resource-type") == "page") { const contentId = a.getAttribute("data-linked-resource-id"); if (contentId) { const slug = this.createSlug(space.key, contentId); a.replaceWith(`<a href="${slug}/">${a.innerHTML}</a>`); } } else if (a.getAttribute("class") == "external-link") { a.setAttribute("target", `_blank`); } }); const querySelectP = htmlRoot.querySelector("p"); if (querySelectP && querySelectP.rawText) { page.description = querySelectP.rawText.substr(0, 200); } const headers = htmlRoot.querySelectorAll("h1,h2,h3,h4,h5,h6,h7"); const anchor = headers.map((header, headerIndex) => { const anchorSlug = `id-${slugify_1.default(header.text, { trim: true, lower: true, remove: /[*+~.,/()&'"!?:@]/g })}`; header.setAttribute("id", anchorSlug); return { title: header.text, position: headerIndex + 1, anchor: anchorSlug, heading_size: header.tagName, }; }); const titleSlug = `id-${slugify_1.default(page.title, { trim: true, lower: true, remove: /[*+~.,/()&'"!?:@]/g })}`; htmlRoot.insertAdjacentHTML("afterbegin", `<h1 id="${titleSlug}">${page.title}</h1>`); page.anchor = [ { title: page.title, position: 0, anchor: titleSlug, heading_size: "H1", }, ...anchor, ]; if (page.anchor.length === 0) { page.anchor.push({ title: "", position: 0, anchor: "", heading_size: "", }); } htmlRoot.querySelectorAll("img").forEach((img) => { if (img.hasAttribute("data-media-id")) { const attachmentIndex = space.attachments.findIndex((att) => att.id === img.getAttribute("data-media-id")); if (attachmentIndex != -1) { img.replaceWith(`<img src="${space.attachments[attachmentIndex].path}">`); } } if (img.hasAttribute("data-emoji-id")) { const path = img.getAttribute("src"); img.setAttribute("src", `${this.config.base_url}${path}`); } }); page.body = `<div>${htmlRoot.toString()}</div>`; }); }); } async createDownloadLinks() { this.log("Creating Download Links"); const axiosResponse = []; this.spaces.forEach((space) => { !fs_1.default.existsSync(`./static/images/confluence/${space.key}`) && fs_1.default.mkdirSync(`./static/images/confluence/${space.key}`, { recursive: true }); space.pages.forEach((page) => { axiosResponse.push(this.confluence.GetContentChildAttachment(page.id)); }); }); await Promise.all(axiosResponse).then((res) => { res.forEach((attachments) => { attachments.data.results.forEach(async (attachment) => { var _a; const fileName = nanoid_1.nanoid(10); const fileExtension = path_1.default.parse(attachment.title).ext.toLowerCase(); if (fileExtension.includes(".jpeg") || fileExtension.includes(".jpg") || fileExtension.includes(".png") || fileExtension.includes(".svg") || fileExtension.includes(".gif")) { if (!fileExtension) { return; } const spaceIndex = this.spaces.findIndex((space) => space.key === attachment.space.key); const contentId = (_a = attachments.config.url) === null || _a === void 0 ? void 0 : _a.replace(/\D/g, ""); this.spaces[spaceIndex].attachments.push({ id: attachment.extensions.fileId, space_key: attachment.space.key, file_name: `${fileName}${fileExtension}`, content_id: contentId, file_size: attachment.extensions.fileSize, downloaded: false, path: `/images/confluence/${attachment.space.key}/${fileName}${fileExtension}`, download_link: attachment._links.download, }); } }); }); }); } async downloadAttachments() { this.log("Downloading Attachments"); let attachments = []; this.spaces.forEach((space) => space.attachments.forEach((attachment) => { if (!attachment.downloaded) { attachments.push(attachment); } })); let batch = 1; while (attachments.length !== 0) { const axiosResponse = []; let count = 0; attachments.every((attachment) => { count++; if (!attachment.downloaded) { axiosResponse.push(this.confluence.GetAttachment(attachment.download_link)); } if (count === 100) { return; } else { return true; } }); if (batch) { this.log(`Downloading batch ${batch} still needs a total of ${attachments.length} attachments`); } await Promise.all(axiosResponse).then(async (attachmentsResponse) => { for await (const attachmentResponse of attachmentsResponse) { if (attachmentResponse) { const attachmentIndex = attachments.findIndex((x) => `/wiki${x.download_link}` === attachmentResponse.config.url); const filePath = path_1.default.resolve(`./static/images/confluence/${attachments[attachmentIndex].space_key}`, `${attachments[attachmentIndex].file_name}`); await new Promise((resolve, reject) => { const stream = fs_1.default.createWriteStream(filePath); attachmentResponse.data.pipe(stream); stream.on("finish", resolve); stream.on("error", reject); }); attachments[attachmentIndex].downloaded = true; } } }); attachments = []; this.spaces.forEach((space) => space.attachments.forEach((attachment) => { if (!attachment.downloaded) { attachments.push(attachment); } })); batch++; } } async setSlugs() { this.log("Set Slugs"); this.spaces.forEach((space) => { space.pages.forEach((page) => { page.slug = this.createSlug(space.key, page.id); }); }); } createSlug(spaceKey, pageId) { const spaceIndex = this.spaces.findIndex((space) => space.key === spaceKey); let id = pageId; let slug = ""; let done = false; while (!done) { const page = this.spaces[spaceIndex].pages.filter((page) => page.id == id); if (page.length === 1) { slug = `/${slugify_1.default(page[0].title, { trim: true, lower: true, remove: /[*+~./()'"!?:@]/g })}${slug}`; if (page[0].parent_page) { id = page[0].parent_page; continue; } done = true; } else { done = true; } } return slug; } getTypeName(name) { const prefix = this.config.prefix || "Confluence"; return `${prefix}${name}`; } log(message) { if (this.config.debug) { console.log("[Confluence]", message); } } async createNodes() { this.log("CreateNodes"); this.spaces.forEach((space) => { space.pages.forEach((page) => { if (page.parent_page) { const childCollection = this.gridsomeStore.getCollection(this.getTypeName("Child")); childCollection.addNode({ ...page, }); } else if (page.homepage) { const homeCollection = this.gridsomeStore.getCollection(this.getTypeName("Home")); homeCollection.addNode({ ...page, }); } else { const parentCollection = this.gridsomeStore.getCollection(this.getTypeName("Parent")); parentCollection.addNode({ ...page, }); } }); }); } } module.exports = ConfluenceSource;