mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-21 01:41:46 +03:00
84c88683ba
refs https://github.com/TryGhost/Team/issues/694 - The controller code is not meant to contain complex business logic. - Kept the pattern used in all modules under services/themes. The install module shold be refactored into a class with DI pattern when touched next.
70 lines
2.2 KiB
JavaScript
70 lines
2.2 KiB
JavaScript
const fs = require('fs-extra');
|
|
const os = require('os');
|
|
const path = require('path');
|
|
const security = require('@tryghost/security');
|
|
const request = require('@tryghost/request');
|
|
const errors = require('@tryghost/errors/lib/errors');
|
|
const limitService = require('../../services/limits');
|
|
const i18n = require('../../../shared/i18n');
|
|
const {setFromZip} = require('./storage');
|
|
|
|
/**
|
|
*
|
|
* @param {String} ref - theme reference in "Org/RepoName" format
|
|
* @returns {Promise<any>}
|
|
*/
|
|
const installFromGithub = async (ref) => {
|
|
const [org, repo] = ref.toLowerCase().split('/');
|
|
|
|
//TODO: move the organization check to config
|
|
if (limitService.isLimited('customThemes') && org.toLowerCase() !== 'tryghost') {
|
|
await limitService.errorIfWouldGoOverLimit('customThemes', {value: repo.toLowerCase()});
|
|
}
|
|
|
|
// omit /:ref so we fetch the default branch
|
|
const zipUrl = `https://api.github.com/repos/${org}/${repo}/zipball`;
|
|
const zipName = `${repo}.zip`;
|
|
|
|
// store zip in a unique temporary folder to avoid conflicts
|
|
const downloadBase = path.join(os.tmpdir(), security.identifier.uid(10));
|
|
const downloadPath = path.join(downloadBase, zipName);
|
|
|
|
await fs.ensureDir(downloadBase);
|
|
|
|
try {
|
|
// download zip file
|
|
const response = await request(zipUrl, {
|
|
followRedirect: true,
|
|
headers: {
|
|
accept: 'application/vnd.github.v3+json'
|
|
},
|
|
encoding: null
|
|
});
|
|
|
|
await fs.writeFile(downloadPath, response.body);
|
|
|
|
// install theme from zip
|
|
const zip = {
|
|
path: downloadPath,
|
|
name: zipName
|
|
};
|
|
const {theme, themeOverridden} = await setFromZip(zip);
|
|
|
|
return {theme, themeOverridden};
|
|
} catch (e) {
|
|
if (e.statusCode && e.statusCode === 404) {
|
|
return Promise.reject(new errors.BadRequestError({
|
|
message: i18n.t('errors.api.themes.repoDoesNotExist'),
|
|
context: zipUrl
|
|
}));
|
|
}
|
|
|
|
throw e;
|
|
} finally {
|
|
// clean up tmp dir with downloaded file
|
|
fs.remove(downloadBase);
|
|
}
|
|
};
|
|
|
|
module.exports.installFromGithub = installFromGithub;
|