2017-07-24 19:58:03 +02:00
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
// Dependencies.
|
|
|
|
|
const path = require('path');
|
|
|
|
|
const glob = require('glob');
|
|
|
|
|
const utils = require('../utils');
|
2017-09-21 17:28:46 +02:00
|
|
|
|
const {merge, setWith, get, upperFirst, isString, isEmpty, isObject, pullAll, defaults, isPlainObject, forEach } = require('lodash');
|
2017-07-24 19:58:03 +02:00
|
|
|
|
|
|
|
|
|
module.exports.nested = function() {
|
|
|
|
|
return Promise.all([
|
|
|
|
|
// Load root configurations.
|
|
|
|
|
new Promise((resolve, reject) => {
|
|
|
|
|
glob('./config/**/*.*(js|json)', {}, (err, files) => {
|
|
|
|
|
if (err) {
|
|
|
|
|
return reject(err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
utils.loadConfig.call(this, files).then(resolve).catch(reject);
|
|
|
|
|
});
|
|
|
|
|
}),
|
|
|
|
|
// Load APIs configurations.
|
|
|
|
|
new Promise((resolve, reject) => {
|
|
|
|
|
glob('./api/*/config/**/*.*(js|json)', {}, (err, files) => {
|
|
|
|
|
if (err) {
|
|
|
|
|
return reject(err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
utils.loadConfig.call(this, files).then(resolve).catch(reject);
|
|
|
|
|
});
|
|
|
|
|
}),
|
|
|
|
|
// Load plugins configurations.
|
|
|
|
|
new Promise((resolve, reject) => {
|
|
|
|
|
glob('./plugins/*/config/**/*.*(js|json)', {}, (err, files) => {
|
|
|
|
|
if (err) {
|
|
|
|
|
return reject(err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
utils.loadConfig.call(this, files).then(resolve).catch(reject);
|
|
|
|
|
});
|
|
|
|
|
}),
|
2017-09-21 14:46:50 +02:00
|
|
|
|
// Load admin configurations.
|
2017-07-28 18:34:13 +02:00
|
|
|
|
new Promise((resolve, reject) => {
|
|
|
|
|
glob('./admin/config/**/*.*(js|json)', {}, (err, files) => {
|
|
|
|
|
if (err) {
|
|
|
|
|
return reject(err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
utils.loadConfig.call(this, files).then(resolve).catch(reject);
|
|
|
|
|
});
|
|
|
|
|
}),
|
|
|
|
|
// Load plugins configurations.
|
2017-07-24 19:58:03 +02:00
|
|
|
|
new Promise((resolve, reject) => {
|
|
|
|
|
setWith(
|
|
|
|
|
this,
|
|
|
|
|
'config.info',
|
|
|
|
|
require(path.resolve(process.cwd(), 'package.json')),
|
|
|
|
|
Object
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
resolve();
|
|
|
|
|
})
|
|
|
|
|
]);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
module.exports.app = async function() {
|
2017-07-25 17:12:18 +02:00
|
|
|
|
// Retrieve Strapi version.
|
2017-11-08 15:03:55 +01:00
|
|
|
|
this.config.uuid = get(this.config.info, 'strapi.uuid', '');
|
2017-07-25 17:12:18 +02:00
|
|
|
|
this.config.info.strapi = (get(this.config, 'info.dependencies.strapi') || '').replace(/(\^|~)/g, ''),
|
|
|
|
|
this.config.info.node = process.versions.node;
|
|
|
|
|
|
2017-07-24 19:58:03 +02:00
|
|
|
|
// Set connections.
|
|
|
|
|
this.connections = {};
|
|
|
|
|
|
2017-07-26 18:53:48 +02:00
|
|
|
|
// Set current environment config.
|
|
|
|
|
this.config.currentEnvironment = this.config.environments[this.config.environment] || {};
|
|
|
|
|
|
|
|
|
|
// Set current connections.
|
|
|
|
|
this.config.connections = get(this.config.currentEnvironment, `database.connections`, {});
|
|
|
|
|
|
2017-08-10 15:38:08 +02:00
|
|
|
|
if (get(this.config, 'language.enabled')) {
|
2017-08-03 14:06:59 +02:00
|
|
|
|
this.config.language.locales = Object.keys(strapi.config.locales);
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-28 18:34:13 +02:00
|
|
|
|
// Template literal string.
|
|
|
|
|
this.config = templateConfigurations(this.config);
|
|
|
|
|
|
2017-08-10 15:38:08 +02:00
|
|
|
|
// Initialize main router to use it in middlewares.
|
2017-10-23 10:48:19 +02:00
|
|
|
|
this.router = this.koaMiddlewares.routerJoi();
|
2017-08-10 15:38:08 +02:00
|
|
|
|
|
2017-07-26 18:53:48 +02:00
|
|
|
|
// Define required middlewares categories.
|
|
|
|
|
const middlewareCategories = ['request', 'response', 'security', 'server'];
|
|
|
|
|
|
|
|
|
|
// Flatten middlewares configurations.
|
|
|
|
|
const flattenMiddlewaresConfig = middlewareCategories.reduce((acc, index) => {
|
2017-07-28 15:31:11 +02:00
|
|
|
|
const current = merge(this.config.currentEnvironment[index], {
|
|
|
|
|
public: defaults(this.config.public, {
|
|
|
|
|
enabled: true
|
|
|
|
|
}),
|
|
|
|
|
favicon: defaults(this.config.favicon, {
|
|
|
|
|
enabled: true
|
|
|
|
|
})
|
|
|
|
|
});
|
2017-07-26 18:53:48 +02:00
|
|
|
|
|
|
|
|
|
if (isObject(current)) {
|
|
|
|
|
acc = merge(acc, current);
|
|
|
|
|
} else {
|
|
|
|
|
acc[index] = current;
|
|
|
|
|
}
|
2017-07-25 17:12:18 +02:00
|
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
2017-08-10 15:38:08 +02:00
|
|
|
|
// These middlewares cannot be disabled.
|
|
|
|
|
merge(flattenMiddlewaresConfig, {
|
2017-10-02 14:17:44 +02:00
|
|
|
|
// Necessary middlewares for the core.
|
2017-08-10 15:38:08 +02:00
|
|
|
|
responses: {
|
|
|
|
|
enabled: true
|
|
|
|
|
},
|
|
|
|
|
router: {
|
|
|
|
|
enabled: true
|
|
|
|
|
},
|
|
|
|
|
logger: {
|
|
|
|
|
enabled: true
|
|
|
|
|
},
|
|
|
|
|
boom: {
|
|
|
|
|
enabled: true
|
2017-10-02 14:17:44 +02:00
|
|
|
|
},
|
|
|
|
|
// Necessary middlewares for the administration panel.
|
|
|
|
|
cors: {
|
|
|
|
|
enabled: true
|
|
|
|
|
},
|
|
|
|
|
xframe: {
|
|
|
|
|
enabled: true
|
|
|
|
|
},
|
|
|
|
|
xss: {
|
|
|
|
|
enabled: true
|
2017-08-10 15:38:08 +02:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2017-07-27 13:06:05 +02:00
|
|
|
|
// Exclude database and custom.
|
2017-07-26 18:53:48 +02:00
|
|
|
|
middlewareCategories.push('database');
|
|
|
|
|
|
|
|
|
|
// Flatten hooks configurations.
|
|
|
|
|
const flattenHooksConfig = pullAll(Object.keys(this.config.currentEnvironment), middlewareCategories).reduce((acc, index) => {
|
|
|
|
|
const current = this.config.currentEnvironment[index];
|
|
|
|
|
|
|
|
|
|
if (isObject(current)) {
|
|
|
|
|
acc = merge(acc, {
|
|
|
|
|
[index]: current
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
acc[index] = current;
|
|
|
|
|
}
|
2017-07-25 17:12:18 +02:00
|
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
2017-07-28 15:31:11 +02:00
|
|
|
|
// Enable hooks and dependencies related to the connections.
|
|
|
|
|
for (let name in this.config.connections) {
|
|
|
|
|
const connection = this.config.connections[name];
|
|
|
|
|
const connector = connection.connector.replace('strapi-', '');
|
|
|
|
|
|
|
|
|
|
enableHookNestedDependencies.call(this, connector, flattenHooksConfig);
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-26 18:53:48 +02:00
|
|
|
|
// Preset config in alphabetical order.
|
2017-07-28 18:34:13 +02:00
|
|
|
|
this.config.middleware.settings = Object.keys(this.middleware).reduce((acc, current) => {
|
2017-07-26 18:53:48 +02:00
|
|
|
|
// Try to find the settings in the current environment, then in the main configurations.
|
|
|
|
|
const currentSettings = flattenMiddlewaresConfig[current] || this.config[current];
|
2017-07-27 13:06:05 +02:00
|
|
|
|
acc[current] = !isObject(currentSettings) ? {} : currentSettings;
|
|
|
|
|
|
|
|
|
|
if (!acc[current].hasOwnProperty('enabled')) {
|
|
|
|
|
this.log.warn(`(middleware:${current}) wasn't loaded due to missing key \`enabled\` in the configuration`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ensure that enabled key exist by forcing to false.
|
|
|
|
|
defaults(acc[current], { enabled : false });
|
2017-07-25 17:12:18 +02:00
|
|
|
|
|
2017-07-26 18:53:48 +02:00
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
2017-07-28 15:31:11 +02:00
|
|
|
|
this.config.hook.settings = Object.keys(this.hook).reduce((acc, current) => {
|
2017-07-26 18:53:48 +02:00
|
|
|
|
// Try to find the settings in the current environment, then in the main configurations.
|
|
|
|
|
const currentSettings = flattenHooksConfig[current] || this.config[current];
|
2017-07-27 13:06:05 +02:00
|
|
|
|
|
|
|
|
|
if (isString(currentSettings)) {
|
|
|
|
|
acc[current] = currentSettings;
|
|
|
|
|
} else {
|
|
|
|
|
acc[current] = !isObject(currentSettings) ? {} : currentSettings;
|
|
|
|
|
|
|
|
|
|
if (!acc[current].hasOwnProperty('enabled')) {
|
|
|
|
|
this.log.warn(`(hook:${current}) wasn't loaded due to missing key \`enabled\` in the configuration`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ensure that enabled key exist by forcing to false.
|
|
|
|
|
defaults(acc[current], { enabled : false });
|
|
|
|
|
}
|
2017-07-25 17:12:18 +02:00
|
|
|
|
|
2017-07-26 18:53:48 +02:00
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
2017-07-24 19:58:03 +02:00
|
|
|
|
|
|
|
|
|
// Set controllers.
|
2017-07-25 17:12:18 +02:00
|
|
|
|
this.controllers = Object.keys(this.api || []).reduce((acc, key) => {
|
2017-07-24 19:58:03 +02:00
|
|
|
|
for (let index in this.api[key].controllers) {
|
|
|
|
|
if (!this.api[key].controllers[index].identity) {
|
|
|
|
|
this.api[key].controllers[index].identity = upperFirst(index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
acc[index] = this.api[key].controllers[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
|
|
// Set models.
|
2017-07-25 17:12:18 +02:00
|
|
|
|
this.models = Object.keys(this.api || []).reduce((acc, key) => {
|
2017-07-24 19:58:03 +02:00
|
|
|
|
for (let index in this.api[key].models) {
|
|
|
|
|
if (!this.api[key].models[index].globalId) {
|
|
|
|
|
this.api[key].models[index].globalId = upperFirst(index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
acc[index] = this.api[key].models[index];
|
|
|
|
|
}
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
|
|
// Set services.
|
2017-07-25 17:12:18 +02:00
|
|
|
|
this.services = Object.keys(this.api || []).reduce((acc, key) => {
|
2017-07-24 19:58:03 +02:00
|
|
|
|
for (let index in this.api[key].services) {
|
|
|
|
|
acc[index] = this.api[key].services[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
|
|
// Set routes.
|
2017-07-25 17:12:18 +02:00
|
|
|
|
this.config.routes = Object.keys(this.api || []).reduce((acc, key) => {
|
2017-07-24 19:58:03 +02:00
|
|
|
|
return acc.concat(get(this.api[key], 'config.routes') || {});
|
|
|
|
|
}, []);
|
|
|
|
|
|
2017-07-28 18:34:13 +02:00
|
|
|
|
// Set admin controllers.
|
|
|
|
|
this.admin.controllers = Object.keys(this.admin.controllers || []).reduce((acc, key) => {
|
|
|
|
|
if (!this.admin.controllers[key].identity) {
|
|
|
|
|
this.admin.controllers[key].identity = key;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
acc[key] = this.admin.controllers[key];
|
|
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
|
|
// Set admin models.
|
|
|
|
|
this.admin.models = Object.keys(this.admin.models || []).reduce((acc, key) => {
|
|
|
|
|
if (!this.admin.models[key].identity) {
|
|
|
|
|
this.admin.models[key].identity = upperFirst(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
acc[key] = this.admin.models[key];
|
|
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
|
|
this.plugins = Object.keys(this.plugins).reduce((acc, key) => {
|
|
|
|
|
this.plugins[key].controllers = Object.keys(this.plugins[key].controllers || []).reduce((sum, index) => {
|
|
|
|
|
if (!this.plugins[key].controllers[index].identity) {
|
|
|
|
|
this.plugins[key].controllers[index].identity = index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sum[index] = this.plugins[key].controllers[index];
|
|
|
|
|
|
|
|
|
|
return sum;
|
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
|
|
acc[key] = this.plugins[key];
|
|
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
2017-08-10 15:38:08 +02:00
|
|
|
|
this.config.port = get(this.config.currentEnvironment, 'server.port') || this.config.port;
|
|
|
|
|
this.config.url = `http://${this.config.host}:${this.config.port}`;
|
2017-07-24 19:58:03 +02:00
|
|
|
|
};
|
2017-07-28 15:31:11 +02:00
|
|
|
|
|
2017-10-10 12:49:23 +02:00
|
|
|
|
const enableHookNestedDependencies = function (name, flattenHooksConfig, force = false) {
|
2017-07-31 16:49:15 +02:00
|
|
|
|
if (!this.hook[name]) {
|
2017-09-21 17:28:46 +02:00
|
|
|
|
this.log.warn(`(hook:${name}) \`strapi-${name}\` is missing in your dependencies. Please run \`npm install strapi-${name}\``);
|
2017-07-31 16:49:15 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-28 15:31:11 +02:00
|
|
|
|
// Couldn't find configurations for this hook.
|
|
|
|
|
if (isEmpty(get(flattenHooksConfig, name, true))) {
|
2017-09-21 17:28:46 +02:00
|
|
|
|
// Check if database connector is used
|
2017-10-03 12:26:52 +02:00
|
|
|
|
const modelsUsed = Object.keys(this.api || {})
|
2017-09-29 17:06:01 +02:00
|
|
|
|
.filter(x => isObject(this.api[x].models)) // Filter API with models
|
|
|
|
|
.map(x => this.api[x].models) // Keep models
|
2017-10-03 12:26:52 +02:00
|
|
|
|
.filter(models => {
|
|
|
|
|
const apiModelsUsed = Object.keys(models).filter(model => {
|
|
|
|
|
const connector = get(this.config.connections, models[model].connection, {}).connector;
|
|
|
|
|
|
|
|
|
|
if (connector) {
|
|
|
|
|
return connector.replace('strapi-', '') === name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return apiModelsUsed.length !== 0
|
|
|
|
|
}) || 0; // Filter model with the right connector
|
2017-09-21 17:28:46 +02:00
|
|
|
|
|
2017-07-28 15:31:11 +02:00
|
|
|
|
flattenHooksConfig[name] = {
|
2017-10-10 12:49:23 +02:00
|
|
|
|
enabled: force || modelsUsed.length > 0 // Will return false if there is no model, else true.
|
2017-07-28 15:31:11 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Enabled dependencies.
|
|
|
|
|
if (get(this.hook, `${name}.dependencies`, []).length > 0) {
|
|
|
|
|
this.hook[name].dependencies.forEach(dependency => {
|
2017-10-10 12:49:23 +02:00
|
|
|
|
enableHookNestedDependencies.call(this, dependency.replace('strapi-', ''), flattenHooksConfig, true);
|
2017-07-28 15:31:11 +02:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-07-31 15:05:44 +02:00
|
|
|
|
};
|
2017-07-28 18:34:13 +02:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Allow dynamic config values through
|
|
|
|
|
* the native ES6 template string function.
|
|
|
|
|
*/
|
|
|
|
|
const templateConfigurations = function (obj) {
|
|
|
|
|
// Allow values which looks like such as
|
|
|
|
|
// an ES6 literal string without parenthesis inside (aka function call).
|
|
|
|
|
const regex = /\$\{[^()]*\}/g;
|
|
|
|
|
|
|
|
|
|
return Object.keys(obj).reduce((acc, key) => {
|
|
|
|
|
if (isPlainObject(obj[key])) {
|
|
|
|
|
acc[key] = templateConfigurations(obj[key]);
|
|
|
|
|
} else if (isString(obj[key]) && regex.test(obj[key])) {
|
|
|
|
|
acc[key] = eval('`' + obj[key] + '`');
|
|
|
|
|
} else {
|
|
|
|
|
acc[key] = obj[key];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
2017-07-31 15:05:44 +02:00
|
|
|
|
};
|