update branch

Merge branch 'plugin/settings-manager-dev' of github.com:soupette/strapi into plugin/settings-manager-dev
This commit is contained in:
cyril lopez 2017-07-12 14:26:08 +02:00
commit 53606ae6c9
6 changed files with 452 additions and 40 deletions

View File

@ -1 +1,4 @@
{}
{
"menu.section.global-settings": "Global settings",
"menu.section.environments": "Environments"
}

View File

@ -2,8 +2,48 @@
"routes": [
{
"method": "GET",
"path": "/",
"handler": "SettingsManager.index",
"path": "/menu",
"handler": "SettingsManager.menu",
"config": {
"policies": []
}
},
{
"method": "GET",
"path": "/environments",
"handler": "SettingsManager.environments",
"config": {
"policies": []
}
},
{
"method": "GET",
"path": "/:slug",
"handler": "SettingsManager.get",
"config": {
"policies": []
}
},
{
"method": "GET",
"path": "/:slug/:env",
"handler": "SettingsManager.get",
"config": {
"policies": []
}
},
{
"method": "PUT",
"path": "/:slug",
"handler": "SettingsManager.update",
"config": {
"policies": []
}
},
{
"method": "PUT",
"path": "/:slug/:env",
"handler": "SettingsManager.update",
"config": {
"policies": []
}

View File

@ -1,25 +1,54 @@
'use strict';
/**
* SettingsManager.js controller
*
* @description: A set of functions called "actions" of the `settings-manager` plugin.
*/
module.exports = {
menu: async ctx => {
const Service = strapi.plugins['settings-manager'].services.settingsmanager;
/**
* Default action.
*
* @return {Object}
*/
ctx.send(Service.menu);
},
index: async (ctx) => {
// Add your own logic here.
environments: async ctx => {
const Service = strapi.plugins['settings-manager'].services.settingsmanager;
// Send 200 `ok`
ctx.send({
message: 'ok'
});
}
ctx.send({ environments: Service.getEnvironments() });
},
get: async ctx => {
const Service = strapi.plugins['settings-manager'].services.settingsmanager;
const { slug, env } = ctx.params;
if (env && _.isEmpty(_.find(Service.getEnvironments(), { name: env }))) return ctx.badData('request.error.environment');
const model = env ? Service[slug](env) : Service[slug];
if (_.isUndefined(model)) return ctx.badData('request.error.config');
ctx.send(model);
},
update: async ctx => {
const Service = strapi.plugins['settings-manager'].services.settingsmanager;
const { slug, env } = ctx.params;
let params = ctx.request.body;
if (env && _.isEmpty(_.find(Service.getEnvironments(), { name: env }))) return ctx.badData('request.error.environment');
const model = env ? Service[slug](env) : Service[slug];
if (_.isUndefined(config)) return ctx.badData('request.error.config');
const items = Service.getItems(model);
params = Service.cleanParams(params, items);
let validationErrors = Service.paramsValidation(params, items);
if (!_.isEmpty(validationErrors)) {
return ctx.badData(null, validationErrors);
}
Service.updateSettings(params, items, env);
ctx.send();
},
};

View File

@ -1,7 +1,7 @@
{
"name": "strapi-plugin-settings-manager",
"version": "0.0.0",
"description": "This is the description of the plugin.",
"version": "0.1.0",
"description": "Strapi plugin to manage settings.",
"strapi": {
"name": "settings-manager",
"icon": "ion-document-text",
@ -24,20 +24,21 @@
"test": "echo Tests are not implemented.",
"prepublish": "npm run build"
},
"dependencies": {},
"dependencies": {
},
"devDependencies": {
"strapi-helper-plugin": "3.0.0-alpha.3"
},
"author": {
"name": "A Strapi developer",
"email": "",
"url": ""
"name": "Strapi team",
"email": "hi@strapi.io",
"url": "http://strapi.io"
},
"maintainers": [
{
"name": "A Strapi developer",
"email": "",
"url": ""
"name": "Strapi team",
"email": "hi@strapi.io",
"url": "http://strapi.io"
}
],
"engines": {

View File

@ -1,11 +1,344 @@
'use strict';
/**
* SettingsManager.js service
*
* @description: A set of functions similar to controller's actions to avoid code duplication.
*/
const fs = require('fs');
const path = require('path');
module.exports = {
menu: {
sections: [
{
name: 'menu.section.global-settings',
items: [
{
slug: 'general',
name: 'menu.item.general',
icon: 'globe'
},
{
slug: 'languages',
name: 'menu.item.languages',
icon: 'language'
},
{
slug: 'advenced',
name: 'menu.item.advenced',
icon: 'cogs'
}
]
},
{
name: 'menu.section.environments',
items: [
{
slug: 'databases',
name: 'menu.item.databases',
icon: 'databases'
},
{
slug: 'security',
name: 'menu.item.security',
icon: 'shield'
},
{
slug: 'server',
name: 'menu.item.server',
icon: 'server'
}
]
}
]
},
general: {
name: 'form.general',
description: 'form.general.desc',
sections: [
{
name: '',
items: [
{
name: 'form.general.name',
target: 'package.name',
type: 'string',
value: strapi.config.name,
validations : {
maxLength: 255,
required: true
}
},
{
name: 'form.general.description',
target: 'package.description',
type: 'string',
value: strapi.config.description,
validations : {
maxLength: 255,
required: true
}
},
{
name: 'form.general.version',
target: 'package.version',
type: 'string',
value: strapi.config.version,
validations : {
maxLength: 255,
required: true
}
}
]
}
]
},
security: env => {
return {
name: 'form.security',
description: 'form.security.desc',
sections: [
{
name: 'form.security.session',
items: [
{
name: 'form.security.session.key',
target: 'security.session.key',
type: 'string',
value: strapi.config.environments[env].security.session.key
},
{
name: 'form.security.session.maxAge',
target: 'security.session.maxAge',
type: 'number',
value: strapi.config.environments[env].security.session.maxAge
}
]
},
{
name: '',
items: [
{
name: 'form.security.xframe',
target: 'security.xframe',
type: 'enum',
value: strapi.config.environments[env].security.xframe,
items: [
{
name: 'server.xframe.deny',
value: 'DENY',
},
{
name: 'server.xframe.sameorigin',
value: 'SAMEORIGIN',
},
{
name: 'server.xframe.allow-from',
value: 'ALLOW-FROM',
},
]
},
{
name: 'form.security.xssProtection',
target: 'security.xssProtection',
type: 'boolean',
value: strapi.config.environments[env].security.xssProtection
}
]
},
{
name: 'form.security.cors',
items: [
{
name: 'form.security.cors.origin',
target: 'security.cors.origin',
type: 'string',
value: strapi.config.environments[env].security.cors.origin,
}
]
}
]
};
},
server: env => {
return {
name: 'form.server',
description: 'form.server.desc',
sections: [
{
name: '',
items: [
{
name: 'form.server.host',
target: 'server.host',
type: 'string',
value: strapi.config.environments[env].server.host
},
{
name: 'form.server.port',
target: 'server.port',
type: 'number',
value: strapi.config.environments[env].server.port
}
]
},
{
name: 'form.server.parser',
items: [
{
name: 'form.server.parser.xframe',
target: 'server.xframe',
type: 'enum',
value: strapi.config.environments[env].server.xframe,
items: [
{
name: 'server.xframe.deny',
value: 'DENY',
},
{
name: 'server.xframe.sameorigin',
value: 'SAMEORIGIN',
},
{
name: 'server.xframe.allow-from',
value: 'ALLOW-FROM',
},
]
},
{
name: 'form.server.xssProtection',
target: 'server.xssProtection',
type: 'boolean',
value: strapi.config.environments[env].server.xssProtection
}
]
},
{
name: 'form.server.cors',
items: [
{
name: 'form.server.cors.origin',
target: 'server.cors.origin',
type: 'string',
value: strapi.config.environments[env].server.cors.origin
}
]
}
]
};
},
getEnvironments: () => {
return _.map(_.keys(strapi.config.environments), environment => {
return {
name: environment,
active: (strapi.config.environment === environment)
}
});
},
getItems: model => {
let items = [];
_.forEach(model.sections, section => items = _.concat(items, section.items));
return items;
},
cleanParams: (params, items) => {
const cleanParams = {};
_.forEach(items, ({ target }) => _.has(params, target) ? _.set(cleanParams, target, _.get(params, target)) : '');
return cleanParams;
},
paramsValidation: (params, items) => {
let errors = [];
const checkType = (input, { type, target }) => {
if ((type === 'string' || type === 'text') && !_.isString(input)) errors.push({
target: target,
message: 'form.error.type.string'
});
if (type === 'number' && !_.isNumber(input)) errors.push({
target: target,
message: 'form.error.type.number'
});
if (type === 'boolean' && !_.isBoolean(input)) errors.push({
target: target,
message: 'form.error.type.boolean'
});
};
const checkValidations = (input, item) => {
_.forEach(item.validations, (value, key) => {
if (key === 'required' && (_.isNull(input) || _.isEmpty(input) || _.isUndefined(input))) errors.push({
target: item.target,
message: 'form.error.validation.required'
});
if (key === 'max' && parseInt(input) > value) errors.push({
target: item.target,
message: 'form.error.validation.max'
});
if (key === 'min' && parseInt(input) < value) errors.push({
target: item.target,
message: 'form.error.validation.min'
});
if (key === 'maxLength' && input.length > value) errors.push({
target: item.target,
message: 'form.error.validation.maxLength'
});
if (key === 'minLength' && input.length < value) errors.push({
target: item.target,
message: 'form.error.validation.minLength'
});
});
};
_.forEach(items, item => {
if (_.has(params, item.target)) {
const input = _.get(params, item.target, null);
checkType(input, item)
checkValidations(input, item)
}
});
if (!_.isEmpty(errors)) {
const grpTarget = _.groupBy(errors, 'target');
errors = _.map(grpTarget, (errs, target) => {
return {
target,
messages: _.map(errs, err => err.message)
}
});
}
return errors;
},
updateSettings: (params, items, env = '') => {
const appPath = process.cwd();
_.forEach(items, ({ target }) => {
if (_.has(params, target)) {
const input = _.get(params, target, null);
const [file, ...objPath] = target.split('.');
let filePath = (file === 'package') ? path.join(appPath, 'package.json') : path.join(appPath, 'config', 'environments', env, `${_.replace(file, '.', '/')}.json`);
const fileContent = require(filePath);
_.set(fileContent, objPath, input);
fs.writeFileSync(filePath, JSON.stringify(fileContent, null, 2), 'utf8');
}
});
}
};

View File

@ -51,13 +51,19 @@ module.exports = async function(ctx, next) {
}
// Empty body is considered as `notFound` response.
if (!ctx.body) {
ctx.notFound();
if (_.isUndefined(ctx.body) && _.isUndefined(ctx.status)) {
return ctx.notFound();
}
// Format `ctx.body` and `ctx.status`.
ctx.status = ctx.body.isBoom ? ctx.body.output.statusCode : ctx.status;
ctx.body = ctx.body.isBoom ? ctx.body.output.payload : ctx.body;
if (_.isObject(ctx.body)) {
if (ctx.body.isBoom && ctx.body.data) {
ctx.body.output.payload.data = ctx.body.data;
}
// Format `ctx.body` and `ctx.status`.
ctx.status = ctx.body.isBoom ? ctx.body.output.statusCode : ctx.status;
ctx.body = ctx.body.isBoom ? ctx.body.output.payload : ctx.body;
}
// Call custom responses.
if (_.isFunction(_.get(strapi.config, `responses.${ctx.status}`))) {