1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-28 00:06:53 +01:00

Add schema validation for strategies

This commit is contained in:
ivaosthu 2016-12-12 21:44:21 +01:00
parent e60c7c5cfc
commit bc82aa6e77
4 changed files with 47 additions and 20 deletions

View File

@ -0,0 +1,20 @@
'use strict';
const joi = require('joi');
const strategySchema = joi.object().keys({
name: joi.string()
.regex(/^[a-zA-Z0-9\\.\\-]{3,30}$/)
.required(),
description: joi.string(),
parameters: joi.array()
.required()
.items(joi.object().keys({
name: joi.string().required(),
type: joi.string().required(),
description: joi.string(),
required: joi.boolean(),
})),
});
module.exports = strategySchema;

View File

@ -1,29 +1,28 @@
'use strict'; 'use strict';
const joi = require('joi');
const eventType = require('../event-type'); const eventType = require('../event-type');
const logger = require('../logger'); const logger = require('../logger');
const NameExistsError = require('../error/name-exists-error'); const NameExistsError = require('../error/name-exists-error');
const ValidationError = require('../error/validation-error.js');
const NotFoundError = require('../error/notfound-error');
const validateRequest = require('../error/validate-request');
const extractUser = require('../extract-user'); const extractUser = require('../extract-user');
const strategySchema = require('./strategy-schema');
const version = 1; const version = 1;
const handleError = (req, res, error) => { const handleError = (req, res, error) => {
switch (error.constructor) { switch (error.name) {
case NotFoundError: case 'NotFoundError':
return res return res
.status(404) .status(404)
.end(); .end();
case NameExistsError: case 'NameExistsError':
return res return res
.status(403) .status(403)
.json([{ msg: `A strategy named '${req.body.name}' already exists.` }]) .json([{ msg: `A strategy named '${req.body.name}' already exists.` }])
.end(); .end();
case ValidationError: case 'ValidationError':
return res return res
.status(400) .status(400)
.json(req.validationErrors()) .json(error)
.end(); .end();
default: default:
logger.error('Could perfom operation', error); logger.error('Could perfom operation', error);
@ -64,14 +63,10 @@ module.exports = function (app, config) {
}); });
app.post('/strategies', (req, res) => { app.post('/strategies', (req, res) => {
req.checkBody('name', 'Name is required').notEmpty(); const data = req.body;
req.checkBody('name', 'Name must match format ^[0-9a-zA-Z\\.\\-]+$').matches(/^[0-9a-zA-Z\\.\\-]+$/i); validateInput(data)
const newStrategy = req.body;
validateRequest(req)
.then(validateStrategyName) .then(validateStrategyName)
.then(() => eventStore.store({ .then((newStrategy) => eventStore.store({
type: eventType.STRATEGY_CREATED, type: eventType.STRATEGY_CREATED,
createdBy: extractUser(req), createdBy: extractUser(req),
data: newStrategy, data: newStrategy,
@ -80,11 +75,22 @@ module.exports = function (app, config) {
.catch(error => handleError(req, res, error)); .catch(error => handleError(req, res, error));
}); });
function validateStrategyName (req) { function validateStrategyName (data) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
strategyStore.getStrategy(req.body.name) strategyStore.getStrategy(data.name)
.then(() => reject(new NameExistsError('Feature name already exist'))) .then(() => reject(new NameExistsError('Feature name already exist')))
.catch(() => resolve(req)); .catch(() => resolve(data));
});
}
function validateInput (data) {
return new Promise((resolve, reject) => {
joi.validate(data, strategySchema, (err, cleaned) => {
if (err) {
return reject(err);
}
return resolve(cleaned);
});
}); });
} }
}; };

View File

@ -2,6 +2,7 @@
const { getInstance } = require('db-migrate'); const { getInstance } = require('db-migrate');
const parseDbUrl = require('parse-database-url'); const parseDbUrl = require('parse-database-url');
require('db-migrate-shared').log.silence(true);
function migrateDb ({ databaseUrl, databaseSchema = 'public' }) { function migrateDb ({ databaseUrl, databaseSchema = 'public' }) {
const custom = parseDbUrl(databaseUrl); const custom = parseDbUrl(databaseUrl);

View File

@ -42,7 +42,7 @@ test.serial('creates a new strategy', async (t) => {
const { request, destroy } = await setupApp('strategy_api_serial'); const { request, destroy } = await setupApp('strategy_api_serial');
return request return request
.post('/api/strategies') .post('/api/strategies')
.send({ name: 'myCustomStrategy', description: 'Best strategy ever.' }) .send({ name: 'myCustomStrategy', description: 'Best strategy ever.', parameters: [] })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(201) .expect(201)
.then(destroy); .then(destroy);
@ -62,7 +62,7 @@ test.serial('refuses to create a strategy with an existing name', async (t) => {
const { request, destroy } = await setupApp('strategy_api_serial'); const { request, destroy } = await setupApp('strategy_api_serial');
return request return request
.post('/api/strategies') .post('/api/strategies')
.send({ name: 'default' }) .send({ name: 'default', parameters: [] })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(403) .expect(403)
.then(destroy); .then(destroy);