UNPKG

lunr-elastic-search

Version:

Uses Lunr.js to index and search the knowledge base.

143 lines (122 loc) 4.95 kB
import * as util from '../util' import _axios from 'axios' import flatten from 'array-flatten' const fields = ['title', 'description_text', 'body_text', 'tags', 'meta_title', 'meta_description', 'meta_keywords'] // the fields that will be indexed /** * The lunr.js builder plugin. * Meant to be used like `builder.use(plugin)` * * @memberof plugin.freshdesk * @return {void} */ function plugin () { this.ref('id') fields.forEach(f => this.field(f)) } /** * Fetches all the solution articles and forum posts from the designated source. * * @memberof plugin.freshdesk * @param {string} domain the domain of the API to make the request to * @param {string} user the username for the API * @param {string} pass the password for the API * @return {object[]} a list of processed solution articles, forum topics, and forum comments */ async function fetch ( domain, user, pass ) { const solutions = _axios.create({ baseURL: `https://${domain}.freshdesk.com/api/v2/solutions/`, auth: { username: user, password: pass } }) // gets a list of all the articles const categories = await get(solutions, 'categories') const folders = await getAllItemsIn(categories, solutions, id => `categories/${id}/folders`) const articles = await getAllItemsIn(folders, solutions, id => `folders/${id}/articles`) const processedArticles = await getAllItemsIn(articles, solutions, id => `articles/${id}`).then(arts => arts.map(a => process(a, 'solution'))) // process each article after fetching it const posts = _axios.create({ baseURL: `https://${domain}.freshdesk.com/api/v2/discussions/`, auth: { username: user, password: pass } }) // gets a list of all the articles const discussionCategories = await get(posts, 'categories') const forums = await getAllItemsIn(discussionCategories, posts, id => `categories/${id}/forums`).then(ary => ary.filter(t => hasComments(t))) const topics = await getAllItemsIn(forums, posts, id => `forums/${id}/topics`).then(ary => ary.filter(t => hasComments(t))) const comments = await getAllItemsIn(topics, posts, id => `topics/${id}/comments`).then(cmts => cmts.map(comment => process(comment, 'forum'))) return [...comments, ...processedArticles, ...topics.map(e => process(e, 'forum'))] } function hasComments (topic) { return topic.comments_count > 0 } /** * Helper function to get all the items from a list of parent resources. * * @private * @param {object[]} ary list of parent resources * @param {axios.Instance} axios the preconfigured axios instance * @param {Function} buildURL function to build the endpoint URL relative to the baseURL in the axios instance * @return {object[]} a list of child resources */ async function getAllItemsIn (ary, axios, buildURL) { return flatten.depth(await Promise.all(ary.map(({id}) => get(axios, buildURL(id)))), 1) } /** * Helper function to make axios get request. * * @private * @param {axios.Instance} axios the preconfigured axios instance * @param {string} url the url to access relative to the baseURL in the axios instance * @return {object} data of axios response */ async function get (axios, url) { return axios.get(url).then(({data}) => { let ret const baseURL = axios.defaults.baseURL if (data.constructor.name === 'Array') { ret = data.map(doc => { return {...doc, documentSource: {url: baseURL + url}} }) } else if (data.constructor.name === 'Object') { ret = {...data, documentSource: {url: baseURL + url}} } return ret }) } /** * Modify the documents so that they can be indexed correctly. * * @memberof plugin.freshdesk * @param {object} doc the document to be processed * @param {?string} source the source of the document * @return {object} the processed document */ function process (doc, source = '') { const obj = {...doc} // dup the document obj.tags = obj.tags ? obj.tags.join(' ') : '' // lunr can't index an array of strings so join the tags into 1 string if (obj.seo_data) Object.keys(obj.seo_data).forEach(k => { obj[k] = obj.seo_data[k] }) // map seo_data to root field so that it can indexed (lunr can't index nested fields) if (obj.documentSource) obj.documentSource = {...obj.documentSource, type: source} fields.forEach(f => { obj[f] = obj[f] || '' }) // if any fields are null then it will impact lunr search results return obj } /** * Checks to see if certain functions are defined. * * @return {Boolean} * @memberOf plugin.freshdesk */ function isSupported () { return util.definedFunction(Object.keys) && util.definedFunction([].forEach) } /** * Contains functions for interacting with the freshdesk API and processing those responses. * * @namespace freshdesk * @memberOf plugin */ export {fields, plugin, process, fetch, isSupported}