mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-30 14:22:07 +03:00
829e8ed010
- Having these as destructured from the same package is hindering refactoring now - Events should really only ever be used server-side - i18n should be a shared module for now so it can be used everywhere until we figure out something better - Having them seperate also allows us to lint them properly
150 lines
5.0 KiB
JavaScript
150 lines
5.0 KiB
JavaScript
const fs = require('fs-extra');
|
|
|
|
const bridge = require('../../../bridge');
|
|
const validate = require('./validate');
|
|
const list = require('./list');
|
|
const ThemeStorage = require('./ThemeStorage');
|
|
const themeLoader = require('./loader');
|
|
const toJSON = require('./to-json');
|
|
|
|
const settingsCache = require('../settings/cache');
|
|
const i18n = require('../../../server/lib/common/i18n');
|
|
const logging = require('../../../shared/logging');
|
|
const errors = require('@tryghost/errors');
|
|
const debug = require('ghost-ignition').debug('api:themes');
|
|
const ObjectID = require('bson-objectid');
|
|
|
|
let themeStorage;
|
|
|
|
const getStorage = () => {
|
|
themeStorage = themeStorage || new ThemeStorage();
|
|
|
|
return themeStorage;
|
|
};
|
|
|
|
module.exports = {
|
|
getZip: (themeName) => {
|
|
const theme = list.get(themeName);
|
|
|
|
if (!theme) {
|
|
return Promise.reject(new errors.BadRequestError({
|
|
message: i18n.t('errors.api.themes.invalidThemeName')
|
|
}));
|
|
}
|
|
|
|
return getStorage().serve({
|
|
name: themeName
|
|
});
|
|
},
|
|
setFromZip: (zip) => {
|
|
const shortName = getStorage().getSanitizedFileName(zip.name.split('.zip')[0]);
|
|
const backupName = `${shortName}_${ObjectID()}`;
|
|
|
|
// check if zip name is casper.zip
|
|
if (zip.name === 'casper.zip') {
|
|
throw new errors.ValidationError({
|
|
message: i18n.t('errors.api.themes.overrideCasper')
|
|
});
|
|
}
|
|
|
|
let checkedTheme;
|
|
let renamedExisting = false;
|
|
|
|
return validate.checkSafe(zip, true)
|
|
.then((_checkedTheme) => {
|
|
checkedTheme = _checkedTheme;
|
|
|
|
return getStorage().exists(shortName);
|
|
})
|
|
.then((themeExists) => {
|
|
// CASE: move the existing theme to a backup folder
|
|
if (themeExists) {
|
|
renamedExisting = true;
|
|
return getStorage().rename(shortName, backupName);
|
|
}
|
|
})
|
|
.then(() => {
|
|
// CASE: store extracted theme
|
|
return getStorage().save({
|
|
name: shortName,
|
|
path: checkedTheme.path
|
|
});
|
|
})
|
|
.then(() => {
|
|
// CASE: loads the theme from the fs & sets the theme on the themeList
|
|
return themeLoader.loadOneTheme(shortName);
|
|
})
|
|
.then((loadedTheme) => {
|
|
const overrideTheme = (shortName === settingsCache.get('active_theme'));
|
|
// CASE: if this is the active theme, we are overriding
|
|
if (overrideTheme) {
|
|
debug('Activating theme (method C, on API "override")', shortName);
|
|
bridge.activateTheme(loadedTheme, checkedTheme);
|
|
}
|
|
|
|
// @TODO: unify the name across gscan and Ghost!
|
|
return {
|
|
themeOverridden: overrideTheme,
|
|
theme: toJSON(shortName, checkedTheme)
|
|
};
|
|
})
|
|
.catch((error) => {
|
|
// restore backup if we renamed an existing theme but saving failed
|
|
if (renamedExisting) {
|
|
return getStorage().exists(shortName).then((themeExists) => {
|
|
if (!themeExists) {
|
|
return getStorage().rename(backupName, shortName).then(() => {
|
|
throw error;
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
throw error;
|
|
})
|
|
.finally(() => {
|
|
// @TODO: we should probably do this as part of saving the theme
|
|
// CASE: remove extracted dir from gscan happens in background
|
|
if (checkedTheme) {
|
|
fs.remove(checkedTheme.path)
|
|
.catch((err) => {
|
|
logging.error(new errors.GhostError({err: err}));
|
|
});
|
|
}
|
|
|
|
// CASE: remove the backup we created earlier
|
|
getStorage()
|
|
.delete(backupName)
|
|
.catch((err) => {
|
|
logging.error(new errors.GhostError({err: err}));
|
|
});
|
|
});
|
|
},
|
|
destroy: function (themeName) {
|
|
if (themeName === 'casper') {
|
|
throw new errors.ValidationError({
|
|
message: i18n.t('errors.api.themes.destroyCasper')
|
|
});
|
|
}
|
|
|
|
if (themeName === settingsCache.get('active_theme')) {
|
|
throw new errors.ValidationError({
|
|
message: i18n.t('errors.api.themes.destroyActive')
|
|
});
|
|
}
|
|
|
|
const theme = list.get(themeName);
|
|
|
|
if (!theme) {
|
|
throw new errors.NotFoundError({
|
|
message: i18n.t('errors.api.themes.themeDoesNotExist')
|
|
});
|
|
}
|
|
|
|
return getStorage().delete(themeName)
|
|
.then(() => {
|
|
list.del(themeName);
|
|
});
|
|
}
|
|
};
|