|
'use strict'; |
|
|
|
const fs = require('fs'); |
|
const axios = require('axios'); |
|
const debug = require('debug')('front'); |
|
const delay = require('delay'); |
|
|
|
const FRONT_APP_ID = process.env.FRONT_APP_ID || ''; |
|
const FRONT_API_SECRET = process.env.FRONT_API_SECRET || ''; |
|
const FRONT_INBOX_ID = process.env.FRONT_INBOX_ID || ''; |
|
|
|
// Log all requests to the console if debug is enabled |
|
axios.interceptors.request.use(config => { |
|
debug(`Request: ${config.url}`); |
|
return config; |
|
}); |
|
|
|
/** |
|
* Account for API rate limiting. |
|
* http://docs.frontapp.com/docs/public-api#rate-limiting |
|
* |
|
* Will delay based on the Retry-After header and then retry. Unfortunately, |
|
* this won't cancel any subsequent/parallel requests. |
|
*/ |
|
axios.interceptors.response.use(null, err => { |
|
if (err.status === 429 && err.headers['retry-after']) { |
|
const ms = err.headers['retry-after'] * 1000; |
|
|
|
debug(`Delaying because of rate limiting: ${err.headers['retry-after']} seconds`); |
|
|
|
return delay(ms).then(() => { |
|
return axios(err.config); |
|
}); |
|
} |
|
|
|
throw err; |
|
}); |
|
|
|
/** |
|
* Performs a request to the Front API. |
|
* |
|
* @param {String} url Relative or absolute URL. If relative, the base URL will be prepended |
|
* @return {Promise} |
|
*/ |
|
function performRequest(url) { |
|
return axios |
|
.get(url, { |
|
// http://docs.frontapp.com/docs/public-api#target |
|
baseURL: `https://api.frontapp.com/companies/${FRONT_APP_ID}`, |
|
// http://docs.frontapp.com/docs/public-api#authentication |
|
auth: { |
|
username: FRONT_APP_ID, |
|
password: FRONT_API_SECRET |
|
}, |
|
params: { |
|
pageSize: 1000 |
|
} |
|
}); |
|
} |
|
|
|
/** |
|
* Writes the given contents to a file with the given filename. |
|
* |
|
* @param {String} filename |
|
* @param {String} contents |
|
* @return void |
|
*/ |
|
function writeToFile(filename, contents) { |
|
fs.writeFile(filename, contents, (err) => { |
|
if (err) { |
|
console.error(err); |
|
} |
|
debug(`Written: ${filename}`); |
|
}) |
|
} |
|
|
|
/** |
|
* Retrieves all conversations for a given inbox. |
|
* http://docs.frontapp.com/docs/inbox-conversations |
|
* |
|
* @param {String} inboxId |
|
* @return {Promise} |
|
*/ |
|
function getConversationsForInbox(inboxId) { |
|
// http://docs.frontapp.com/v1.0/docs/pagination |
|
const url = `/inboxes/${inboxId}/conversations/all`; |
|
|
|
let conversations = []; |
|
|
|
function handleResponse(res) { |
|
if (res.data.conversations) { |
|
conversations = conversations.concat(res.data.conversations); |
|
} |
|
if (res.data.pages.next_url) { |
|
return performRequest(res.data.pages.next_url).then(handleResponse); |
|
} |
|
} |
|
|
|
return performRequest(url) |
|
.then(handleResponse) |
|
.then(() => conversations); |
|
} |
|
|
|
/** |
|
* Retrieves all data for a given conversation. |
|
* http://docs.frontapp.com/docs/get-conversation |
|
* |
|
* Please note that the messages are paginated. We set the default pageSize to |
|
* 1000 (maximum allowed). If you have conversations with more than 1000 messages, |
|
* you need to adapt this script for message pagination. |
|
* |
|
* This endpoint doesn't have a `pages` object with pagination information, so |
|
* you'd have to figure it out yourself by checking the length of the `messages` |
|
* array and making additional requests (with the `page=n` param) if necessary. |
|
* |
|
* @param {Object} conversation |
|
* @return {Promise} |
|
*/ |
|
function getConversation(conversation) { |
|
return performRequest(conversation.url).then(res => res.data); |
|
} |
|
|
|
/** |
|
* Retrieves all data for a given message. |
|
* http://docs.frontapp.com/docs/get-message |
|
* |
|
* @param {Object} message |
|
* @return {Promise} |
|
*/ |
|
function getMessage(message) { |
|
return performRequest(message.url).then(res => res.data); |
|
} |
|
|
|
/** |
|
* Retrieves all messages for a given conversation. Will update the `messages` |
|
* key of the conversation with the retrieved messages. |
|
* |
|
* @param {Object} conversation |
|
* @return {Promise} |
|
*/ |
|
function getMessagesForConversation(conversation) { |
|
return axios.all(conversation.messages.map(getMessage)) |
|
.then(messages => { |
|
conversation.messages = messages; |
|
return conversation; |
|
}); |
|
} |
|
|
|
console.time('export'); |
|
new Promise((resolve, reject) => { |
|
if (!FRONT_INBOX_ID) { |
|
reject(new Error('no FRONT_INBOX_ID specified')); |
|
} |
|
resolve(FRONT_INBOX_ID); |
|
}) |
|
.then(getConversationsForInbox) |
|
.then(conversations => { |
|
return axios.all(conversations.map(getConversation)) |
|
}) |
|
.then(conversations => { |
|
return axios.all(conversations.map(getMessagesForConversation)) |
|
}) |
|
.then(conversations => { |
|
writeToFile(`${FRONT_INBOX_ID}.json`, JSON.stringify(conversations, null, 4)); |
|
console.timeEnd('export'); |
|
}) |
|
.catch(err => { |
|
console.error(err); |
|
}); |