diff --git a/core/frontend/services/routing/index.js b/core/frontend/services/routing/index.js index 2a480bc74a..6382b36a8a 100644 --- a/core/frontend/services/routing/index.js +++ b/core/frontend/services/routing/index.js @@ -7,6 +7,10 @@ module.exports = { return require('./registry'); }, + get settings() { + return require('./settings'); + }, + get helpers() { return require('./helpers'); }, diff --git a/core/frontend/services/routing/settings.js b/core/frontend/services/routing/settings.js new file mode 100644 index 0000000000..15f18db262 --- /dev/null +++ b/core/frontend/services/routing/settings.js @@ -0,0 +1,100 @@ +const moment = require('moment-timezone'); +const fs = require('fs-extra'); +const path = require('path'); +const urlService = require('../url'); + +const common = require('../../../server/lib/common'); +const config = require('../../../server/config'); + +/** + * The `routes.yaml` file offers a way to configure your Ghost blog. It's currently a setting feature + * we have added. That's why the `routes.yaml` file is treated as a "setting" right now. + * If we want to add single permissions for this file (e.g. upload/download routes.yaml), we can add later. + * + * How does it work? + * + * - we first reset all url generators (each url generator belongs to one express router) + * - we don't destroy the resources, we only release them (this avoids reloading all resources from the db again) + * - then we reload the whole site app, which will reset all routers and re-create the url generators + */ +const setFromFilePath = (filePath) => { + const settingsPath = config.getContentPath('settings'); + const backupRoutesPath = path.join(settingsPath, `routes-${moment().format('YYYY-MM-DD-HH-mm-ss')}.yaml`); + + return fs.copy(`${settingsPath}/routes.yaml`, backupRoutesPath) + .then(() => { + return fs.copy(filePath, `${settingsPath}/routes.yaml`); + }) + .then(() => { + urlService.resetGenerators({releaseResourcesOnly: true}); + }) + .then(() => { + const siteApp = require('../../../server/web/site/app'); + + const bringBackValidRoutes = () => { + urlService.resetGenerators({releaseResourcesOnly: true}); + + return fs.copy(backupRoutesPath, `${settingsPath}/routes.yaml`) + .then(() => { + return siteApp.reload(); + }); + }; + + try { + siteApp.reload(); + } catch (err) { + return bringBackValidRoutes() + .finally(() => { + throw err; + }); + } + + let tries = 0; + + function isBlogRunning() { + return Promise.delay(1000) + .then(() => { + if (!urlService.hasFinished()) { + if (tries > 5) { + throw new common.errors.InternalServerError({ + message: 'Could not load routes.yaml file.' + }); + } + + tries = tries + 1; + return isBlogRunning(); + } + }); + } + + return isBlogRunning() + .catch((err) => { + return bringBackValidRoutes() + .finally(() => { + throw err; + }); + }); + }); +}; + +const get = () => { + const routesPath = path.join(config.getContentPath('settings'), 'routes.yaml'); + + return fs.readFile(routesPath, 'utf-8') + .catch((err) => { + if (err.code === 'ENOENT') { + return Promise.resolve([]); + } + + if (common.errors.utils.isIgnitionError(err)) { + throw err; + } + + throw new common.errors.NotFoundError({ + err: err + }); + }); +}; + +module.exports.setFromFilePath = setFromFilePath; +module.exports.get = get; diff --git a/core/server/api/v0.1/settings.js b/core/server/api/v0.1/settings.js index 06e4526204..0b5987653a 100644 --- a/core/server/api/v0.1/settings.js +++ b/core/server/api/v0.1/settings.js @@ -2,14 +2,10 @@ // RESTful API for the Setting resource const Promise = require('bluebird'), _ = require('lodash'), - moment = require('moment-timezone'), - fs = require('fs-extra'), - path = require('path'), - config = require('../../config'), models = require('../../models'), canThis = require('../../services/permissions').canThis, localUtils = require('./utils'), - urlService = require('../../../frontend/services/url'), + routing = require('../../../frontend/services/routing'), common = require('../../lib/common'), settingsCache = require('../../services/settings/cache'), docName = 'settings'; @@ -255,67 +251,17 @@ settings = { }); }, - /** - * The `routes.yaml` file offers a way to configure your Ghost blog. It's currently a setting feature - * we have added. That's why the `routes.yaml` file is treated as a "setting" right now. - * If we want to add single permissions for this file (e.g. upload/download routes.yaml), we can add later. - * - * How does it work? - * - * - we first reset all url generators (each url generator belongs to one express router) - * - we don't destroy the resources, we only release them (this avoids reloading all resources from the db again) - * - then we reload the whole site app, which will reset all routers and re-create the url generators - */ upload(options) { - const backupRoutesPath = path.join(config.getContentPath('settings'), `routes-${moment().format('YYYY-MM-DD-HH-mm-ss')}.yaml`); - return localUtils.handlePermissions('settings', 'edit')(options) .then(() => { - return fs.copy(`${config.getContentPath('settings')}/routes.yaml`, backupRoutesPath); - }) - .then(() => { - return fs.copy(options.path, `${config.getContentPath('settings')}/routes.yaml`); - }) - .then(() => { - urlService.resetGenerators({releaseResourcesOnly: true}); - }) - .then(() => { - const siteApp = require('../../web/site/app'); - - try { - return siteApp.reload(); - } catch (err) { - // bring back backup, otherwise your Ghost blog is broken - return fs.copy(backupRoutesPath, `${config.getContentPath('settings')}/routes.yaml`) - .then(() => { - return siteApp.reload(); - }) - .then(() => { - throw err; - }); - } + return routing.settings.setFromFilePath(options.path); }); }, download(options) { - const routesPath = path.join(config.getContentPath('settings'), 'routes.yaml'); - return localUtils.handlePermissions('settings', 'browse')(options) .then(() => { - return fs.readFile(routesPath, 'utf-8'); - }) - .catch((err) => { - if (err.code === 'ENOENT') { - return Promise.resolve([]); - } - - if (common.errors.utils.isIgnitionError(err)) { - throw err; - } - - throw new common.errors.NotFoundError({ - err: err - }); + return routing.settings.get(); }); } }; diff --git a/core/server/api/v2/settings.js b/core/server/api/v2/settings.js index 4823e9ab8c..7927a7461e 100644 --- a/core/server/api/v2/settings.js +++ b/core/server/api/v2/settings.js @@ -1,11 +1,7 @@ const Promise = require('bluebird'); const _ = require('lodash'); -const moment = require('moment-timezone'); -const fs = require('fs-extra'); -const path = require('path'); -const config = require('../../config'); const models = require('../../models'); -const urlService = require('../../../frontend/services/url'); +const routing = require('../../../frontend/services/routing'); const common = require('../../lib/common'); const settingsCache = require('../../services/settings/cache'); @@ -151,62 +147,7 @@ module.exports = { method: 'edit' }, query(frame) { - const backupRoutesPath = path.join(config.getContentPath('settings'), `routes-${moment().format('YYYY-MM-DD-HH-mm-ss')}.yaml`); - - return fs.copy(`${config.getContentPath('settings')}/routes.yaml`, backupRoutesPath) - .then(() => { - return fs.copy(frame.file.path, `${config.getContentPath('settings')}/routes.yaml`); - }) - .then(() => { - urlService.resetGenerators({releaseResourcesOnly: true}); - }) - .then(() => { - const siteApp = require('../../web/site/app'); - - const bringBackValidRoutes = () => { - urlService.resetGenerators({releaseResourcesOnly: true}); - - return fs.copy(backupRoutesPath, `${config.getContentPath('settings')}/routes.yaml`) - .then(() => { - return siteApp.reload(); - }); - }; - - try { - siteApp.reload(); - } catch (err) { - return bringBackValidRoutes() - .finally(() => { - throw err; - }); - } - - let tries = 0; - - function isBlogRunning() { - return Promise.delay(1000) - .then(() => { - if (!urlService.hasFinished()) { - if (tries > 5) { - throw new common.errors.InternalServerError({ - message: 'Could not load routes.yaml file.' - }); - } - - tries = tries + 1; - return isBlogRunning(); - } - }); - } - - return isBlogRunning() - .catch((err) => { - return bringBackValidRoutes() - .finally(() => { - throw err; - }); - }); - }); + return routing.settings.setFromFilePath(frame.file.path); } }, @@ -224,22 +165,7 @@ module.exports = { method: 'browse' }, query() { - const routesPath = path.join(config.getContentPath('settings'), 'routes.yaml'); - - return fs.readFile(routesPath, 'utf-8') - .catch((err) => { - if (err.code === 'ENOENT') { - return Promise.resolve([]); - } - - if (common.errors.utils.isIgnitionError(err)) { - throw err; - } - - throw new common.errors.NotFoundError({ - err: err - }); - }); + return routing.settings.get(); } } };