mirror of
https://github.com/scratchfoundation/scratch-l10n.git
synced 2024-12-22 13:42:30 -05:00
30b1975e94
* Fixed a bug in the push script (tags were not saved as correct structured json, so they weren’t getting put into transifex) * extended FreshDesk API with functions to update knowledge base. Functions automatically try to create the item if it isn’t found for updating * tx-pull-help-names: pulls category and folder name translations from transifex and updates them in Freshdesk (Note, since we don’t send people into the knowledge base, these aren’t really public, but the actual folders and categories have to exist to be able to save articles) * tx-pull-help-articles: pull article translations from Transifex and update the Freshdesk KB. * help-utils: utility functions for the tx-pull-help-* scripts. Handles limiting the number of things happening in parallel - currently two languages may be processed at the same time.
155 lines
5.3 KiB
JavaScript
155 lines
5.3 KiB
JavaScript
// interface to FreshDesk Solutions (knowledge base) api
|
|
|
|
const fetch = require('node-fetch');
|
|
class FreshdeskApi {
|
|
|
|
constructor (baseUrl, apiKey) {
|
|
this.baseUrl = baseUrl;
|
|
this._auth = 'Basic ' + new Buffer(`${apiKey}:X`).toString('base64');
|
|
this.defaultHeaders = {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': this._auth
|
|
};
|
|
this.rateLimited = false;
|
|
}
|
|
|
|
/**
|
|
* Checks the status of a response. If status is not ok, or the body is not json raise exception
|
|
* @param {object} res The response object
|
|
* @returns {object} the response if it is ok
|
|
*/
|
|
checkStatus (res) {
|
|
if (res.ok) {
|
|
if (res.headers.get('content-type').indexOf('application/json') !== -1) {
|
|
return res;
|
|
}
|
|
throw new Error(`response not json: ${res.headers.get('content-type')}`);
|
|
}
|
|
let err = new Error(`response ${res.statusText}`);
|
|
err.code = res.status;
|
|
throw err;
|
|
}
|
|
|
|
listCategories () {
|
|
return fetch(`${this.baseUrl}/api/v2/solutions/categories`, {headers: this.defaultHeaders})
|
|
.then(this.checkStatus)
|
|
.then(res => res.json());
|
|
}
|
|
|
|
listFolders (category) {
|
|
return fetch(
|
|
`${this.baseUrl}/api/v2/solutions/categories/${category.id}/folders`,
|
|
{headers: this.defaultHeaders})
|
|
.then(this.checkStatus)
|
|
.then(res => res.json());
|
|
}
|
|
|
|
listArticles (folder) {
|
|
return fetch(
|
|
`${this.baseUrl}/api/v2/solutions/folders/${folder.id}/articles`,
|
|
{headers: this.defaultHeaders})
|
|
.then(this.checkStatus)
|
|
.then(res => res.json());
|
|
}
|
|
|
|
updateCategoryTranslation (id, locale, body) {
|
|
if (this.rateLimited) {
|
|
process.stdout.write(`Rate limited, skipping id: ${id} for ${locale}\n`);
|
|
return -1;
|
|
}
|
|
return fetch(
|
|
`${this.baseUrl}/api/v2/solutions/categories/${id}/${locale}`,
|
|
{
|
|
method: 'put',
|
|
body: JSON.stringify(body),
|
|
headers: this.defaultHeaders
|
|
})
|
|
.then(this.checkStatus)
|
|
.then(res => res.json())
|
|
.catch((err) => {
|
|
if (err.code === 404) {
|
|
// not found, try create instead
|
|
return fetch(
|
|
`${this.baseUrl}/api/v2/solutions/categories/${id}/${locale}`,
|
|
{
|
|
method: 'post',
|
|
body: JSON.stringify(body),
|
|
headers: this.defaultHeaders
|
|
})
|
|
.then(this.checkStatus)
|
|
.then(res => res.json());
|
|
}
|
|
// re-raise the error otherwise
|
|
throw err;
|
|
});
|
|
}
|
|
|
|
updateFolderTranslation (id, locale, body) {
|
|
if (this.rateLimited) {
|
|
process.stdout.write(`Rate limited, skipping id: ${id} for ${locale}\n`);
|
|
return -1;
|
|
}
|
|
return fetch(
|
|
`${this.baseUrl}/api/v2/solutions/folders/${id}/${locale}`,
|
|
{
|
|
method: 'put',
|
|
body: JSON.stringify(body),
|
|
headers: this.defaultHeaders
|
|
})
|
|
.then(this.checkStatus)
|
|
.then(res => res.json())
|
|
.catch((err) => {
|
|
if (err.code === 404) {
|
|
// not found, try create instead
|
|
return fetch(
|
|
`${this.baseUrl}/api/v2/solutions/folders/${id}/${locale}`,
|
|
{
|
|
method: 'post',
|
|
body: JSON.stringify(body),
|
|
headers: this.defaultHeaders
|
|
})
|
|
.then(this.checkStatus)
|
|
.then(res => res.json());
|
|
}
|
|
// re-raise the error otherwise
|
|
throw err;
|
|
});
|
|
}
|
|
|
|
updateArticleTranslation (id, locale, body) {
|
|
if (this.rateLimited) {
|
|
process.stdout.write(`Rate limited, skipping id: ${id} for ${locale}\n`);
|
|
return -1;
|
|
}
|
|
return fetch(
|
|
`${this.baseUrl}/api/v2/solutions/articles/${id}/${locale}`,
|
|
{
|
|
method: 'put',
|
|
body: JSON.stringify(body),
|
|
headers: this.defaultHeaders
|
|
})
|
|
.then(this.checkStatus)
|
|
.then(res => res.json())
|
|
.catch((err) => {
|
|
if (err.code === 404) {
|
|
// not found, try create instead
|
|
return fetch(
|
|
`${this.baseUrl}/api/v2/solutions/articles/${id}/${locale}`,
|
|
{
|
|
method: 'post',
|
|
body: JSON.stringify(body),
|
|
headers: this.defaultHeaders
|
|
})
|
|
.then(this.checkStatus)
|
|
.then(res => res.json());
|
|
}
|
|
if (err.code === 429) {
|
|
this.rateLimited = true;
|
|
}
|
|
// re-raise the error otherwise
|
|
throw err;
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = FreshdeskApi;
|