Skip to content

Instantly share code, notes, and snippets.

@rosinghal
Last active December 15, 2021 08:46
Show Gist options
  • Save rosinghal/2d3de68cb9dfdb5f48bb94973a423bb9 to your computer and use it in GitHub Desktop.
Save rosinghal/2d3de68cb9dfdb5f48bb94973a423bb9 to your computer and use it in GitHub Desktop.
Export HelpScout docs to CSV
const Axios = require("axios");
const { createObjectCsvWriter } = require("csv-writer");
const HELPSCOUT_API_KEY = "<<YOUR_HELPSCOUT_API_KEY>>";
const helpscoutInstance = Axios.create({
baseURL: "https://docsapi.helpscout.net/v1",
auth: {
username: HELPSCOUT_API_KEY,
password: "X"
}
});
const asyncForEach = async (array, callback) => {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
};
const fetchSites = () => {
console.log(`Fetching sites`);
return helpscoutInstance.get(`/sites`);
};
const fetchCollections = siteId => {
console.log(`Fetching collections`);
return helpscoutInstance.get(`/collections`, {
params: {
siteId
}
});
};
const fetchCategoriesByCollectionId = collectionId => {
console.log(`Fetching categories for collection #${collectionId}`);
return helpscoutInstance.get(`/collections/${collectionId}/categories`);
};
const fetchArticlesByCollectionId = (collectionId, pageSize = 100) => {
console.log(`Fetching articles for collection #${collectionId}`);
return helpscoutInstance.get(`/collections/${collectionId}/articles`, {
params: {
pageSize
}
});
};
const fetchArticlesByCategoryId = (categoryId, pageSize = 100) => {
console.log(`Fetching articles for category #${categoryId}`);
return helpscoutInstance.get(`/categories/${categoryId}/articles`, {
params: {
pageSize
}
});
};
const fetchArticleById = articleId => {
console.log(`Fetching article #${articleId}`);
return helpscoutInstance.get(`/articles/${articleId}`);
};
const createCSV = (name, rows) => {
const csvWriter = createObjectCsvWriter({
path: `${name}.csv`,
header: Object.keys(rows[0]).map(key => ({ id: key, title: key }))
});
csvWriter.writeRecords(rows);
};
const init = async () => {
const rows = [];
const sites = (await fetchSites()).data.sites.items;
const collections = (await fetchCollections()).data.collections.items;
await asyncForEach(collections, async collection => {
const categoriesForCollection = (
await fetchCategoriesByCollectionId(collection.id)
).data.categories.items;
const articlesForCollectionResponse = await fetchArticlesByCollectionId(
collection.id
);
if (articlesForCollectionResponse.data.articles.pages > 1) {
console.error("Pages need addressing");
}
const articlesForCollection =
articlesForCollectionResponse.data.articles.items;
await asyncForEach(
articlesForCollection,
async articleForCollection => {
const { article } = (
await fetchArticleById(articleForCollection.id)
).data;
const [
primaryArticleCategory,
...otherArticleCategories
] = article.categories.map(categoryId => {
return categoriesForCollection.find(
cc => cc.id === categoryId && cc.name !== "Uncategorized"
);
});
const row = {
title: article.name,
slug: `${article.number}-${article.slug}`,
description: article.text,
site_name: sites.find(s => s.id === collection.siteId)
.cname,
collection_name: collection.name,
collection_slug: `${collection.number}-${collection.slug}`,
category_name: primaryArticleCategory ? primaryArticleCategory.name : "",
category_slug: primaryArticleCategory ? `${primaryArticleCategory.number}-${primaryArticleCategory.slug}` : "",
other_categories_name: otherArticleCategories
.map(ac => ac.name)
.join(","),
other_categories_slug: otherArticleCategories
.map(ac => `${ac.number}-${ac.slug}`)
.join(","),
created_at: article.createdAt || article.updatedAt,
updated_at: article.updatedAt,
status: article.status === "published" ? "publish" : "draft",
tags: article.keywords ? article.keywords.join(",") : "",
helpscout_url: article.publicUrl
};
rows.push(row);
}
);
});
createCSV("test", rows);
};
init();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment