Ghost/core/server/services/settings/index.js
Aileen Nowak 63642fd8ad YAML settings loader and parser
closes #9528

These code changes introduce a YAML parser which will load and parse YAML files from the `/content/settings` directory. There are three major parts involved:

1. `ensure-settings.js`: this fn takes care that on bootstrap, the supported files are present in the `/content/settings` directory. If the files are not present, they get copied back from our default files. The default files to copy from are located in `core/server/services/settings`.

2. `loader.js`: the settings loader reads the requested `yaml` file from the disk and passes it to the yaml parser, which returns a `json` object of the file. The settings loader throws an error, if the file is not accessible, e. g. because of permission errors.

3. `yaml-parser`: gets passed a `yaml` file and returns a `json` object. If the file is not parseable, it returns a clear error that contains the information, what and where the parsing error occurred (e. g. line number and reason).

- added a `get()` fn to settings services, that returns the settings object that's asked for. e. g. `settings.get('routes').then(()...` will return the `routes` settings.
- added a `getAll()` fn to settings services, that returns all available settings in an object. The object looks like: `{routes: {routes: {}, collections: {}, resources: {}}, globals: {value: {}}`, assuming that we have to supported settings `routes` and `globals`.

Further additions:
- config `contentPath` for `settings`
- config overrides for default `yaml` files location in `/core/server/services/settings`

**Important**: These code changes are in preparation for Dynamic Routing and not yet used. The process of copying the supported `yaml` files (in this first step, the `routes.yaml` file) is not yet activated.
2018-04-15 19:40:22 +02:00

111 lines
3.6 KiB
JavaScript

/**
* Settings Lib
* A collection of utilities for handling settings including a cache
*/
var SettingsModel = require('../../models/settings').Settings,
SettingsCache = require('./cache'),
SettingsLoader = require('./loader'),
// EnsureSettingsFiles = require('./ensure-settings'),
_ = require('lodash'),
common = require('../../lib/common'),
debug = require('ghost-ignition').debug('services:settings:index');
module.exports = {
init: function init() {
const knownSettings = this.knownSettings();
debug('init settings service for:', knownSettings);
// TODO: uncomment this section, once we want to
// copy the default routes.yaml file into the /content/settings
// folder
// Make sure that supported settings files are available
// inside of the `content/setting` directory
// return EnsureSettingsFiles(knownSettings)
// .then(() => {
// Update the defaults
return SettingsModel.populateDefaults()
.then(function (settingsCollection) {
// Initialise the cache with the result
// This will bind to events for further updates
SettingsCache.init(settingsCollection);
});
// });
},
/**
* Global place to switch on more available settings.
*/
knownSettings: function knownSettings() {
return ['routes'];
},
/**
* Getter for YAML settings.
* Example: `settings.get('routes').then(...)`
* will return an Object like this:
* {routes: {}, collections: {}, resources: {}}
* @param {String} setting type of supported setting.
* @returns {Promise<Object>} settingsFile
* @description Returns settings object as defined per YAML files in
* `/content/settings` directory.
*/
get: function get(setting) {
const knownSettings = this.knownSettings();
// CASE: this should be an edge case and only if internal usage of the
// getter is incorrect.
if (!setting || _.indexOf(knownSettings, setting) < 0) {
return Promise.reject(new common.errors.IncorrectUsageError({
message: `Requested setting is not supported: '${setting}'.`,
help: `Please use only the supported settings: ${knownSettings}.`
}));
}
return SettingsLoader(setting)
.then((settingsFile) => {
debug('setting loaded and parsed:', settingsFile);
return settingsFile;
});
},
/**
* Getter for all YAML settings.
* Example: `settings.getAll().then(...)`
* will return an Object like this (assuming we're supporting `routes`
* and `globals`):
* {
* routes: {
* routes: null,
* collections: { '/': [Object] },
* resources: { tag: '/tag/{slug}/', author: '/author/{slug}/' }
* },
* globals: {
* config: { url: 'testblog.com' }
* }
* }
* @returns {Promise<Object>} settingsObject
* @description Returns all settings object as defined per YAML files in
* `/content/settings` directory.
*/
getAll: function getAll() {
const knownSettings = this.knownSettings(),
props = {};
_.each(knownSettings, function (setting) {
props[setting] = SettingsLoader(setting);
});
return Promise.props(props)
.then((settingsFile) => {
debug('all settings loaded and parsed:', settingsFile);
return settingsFile;
});
}
};