1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-31 00:16:47 +01:00

Added simple name-validation

This commit is contained in:
ivaosthu 2016-11-05 11:37:59 +01:00
parent efd562556b
commit a0276a61d2
7 changed files with 49 additions and 2 deletions

View File

@ -29,6 +29,26 @@ module.exports = function (app, config) {
.catch(() => res.status(404).json({ error: 'Could not find feature' })); .catch(() => res.status(404).json({ error: 'Could not find feature' }));
}); });
app.post('/features-validate', (req, res) => {
req.checkBody('name', 'Name is required').notEmpty();
req.checkBody('name', 'Name must match format ^[0-9a-zA-Z\\.\\-]+$').matches(/^[0-9a-zA-Z\\.\\-]+$/i);
validateRequest(req)
.then(validateFormat)
.then(validateUniqueName)
.then(() => res.status(201).end())
.catch(NameExistsError, () => {
res.status(403)
.json([{ msg: `A feature named '${req.body.name}' already exists.` }])
.end();
})
.catch(ValidationError, () => res.status(400).json(req.validationErrors()))
.catch(err => {
logger.error('Could not create feature toggle', err);
res.status(500).end();
});
});
app.post('/features', (req, res) => { app.post('/features', (req, res) => {
req.checkBody('name', 'Name is required').notEmpty(); req.checkBody('name', 'Name is required').notEmpty();
req.checkBody('name', 'Name must match format ^[0-9a-zA-Z\\.\\-]+$').matches(/^[0-9a-zA-Z\\.\\-]+$/i); req.checkBody('name', 'Name must match format ^[0-9a-zA-Z\\.\\-]+$').matches(/^[0-9a-zA-Z\\.\\-]+$/i);

View File

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { hashHistory } from 'react-router'; import { hashHistory } from 'react-router';
import { createFeatureToggles } from '../../store/feature-actions'; import { createFeatureToggles, validateName } from '../../store/feature-actions';
import { createMapper, createActions } from '../input-helpers'; import { createMapper, createActions } from '../input-helpers';
import FormComponent from './form'; import FormComponent from './form';
@ -33,6 +33,13 @@ const prepare = (methods, dispatch) => {
methods.removeFromList('strategies', v); methods.removeFromList('strategies', v);
}; };
methods.validateName = (v) => {
const featureToggleName = v.target.value;
validateName(featureToggleName)
.then(() => methods.setValue('nameError', undefined))
.catch((err) => methods.setValue('nameError', err.message));
};
return methods; return methods;
}; };
const actions = createActions({ id: ID, prepare }); const actions = createActions({ id: ID, prepare });

View File

@ -57,6 +57,8 @@ const prepare = (methods, dispatch) => {
methods.updateInList('strategies', v, n); methods.updateInList('strategies', v, n);
}; };
methods.validateName = () => {};
return methods; return methods;
}; };

View File

@ -17,6 +17,7 @@ class AddFeatureToggleComponent extends Component {
const { const {
input, input,
setValue, setValue,
validateName,
addStrategy, addStrategy,
removeStrategy, removeStrategy,
updateStrategy, updateStrategy,
@ -27,6 +28,7 @@ class AddFeatureToggleComponent extends Component {
const { const {
name, // eslint-disable-line name, // eslint-disable-line
nameError,
description, description,
enabled, enabled,
} = input; } = input;
@ -42,6 +44,8 @@ class AddFeatureToggleComponent extends Component {
disabled={editmode} disabled={editmode}
required required
value={name} value={name}
error={nameError}
onBlur={(v) => validateName(v)}
onChange={(v) => setValue('name', v)} /> onChange={(v) => setValue('name', v)} />
<Input <Input
type="text" type="text"
@ -84,6 +88,7 @@ AddFeatureToggleComponent.propTypes = {
updateStrategy: PropTypes.func.isRequired, updateStrategy: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired, onCancel: PropTypes.func.isRequired,
validateName: PropTypes.func.isRequired,
editmode: PropTypes.bool, editmode: PropTypes.bool,
}; };

View File

@ -1,6 +1,7 @@
import { throwIfNotSuccess, headers } from './helper'; import { throwIfNotSuccess, headers } from './helper';
const URI = '/features'; const URI = '/features';
const URI_VALIDATE = '/features-validate';
function fetchAll () { function fetchAll () {
return fetch(URI) return fetch(URI)
@ -16,6 +17,14 @@ function create (featureToggle) {
}).then(throwIfNotSuccess); }).then(throwIfNotSuccess);
} }
function validate (featureToggle) {
return fetch(URI_VALIDATE, {
method: 'POST',
headers,
body: JSON.stringify(featureToggle),
}).then(throwIfNotSuccess);
}
function update (featureToggle) { function update (featureToggle) {
return fetch(`${URI}/${featureToggle.name}`, { return fetch(`${URI}/${featureToggle.name}`, {
method: 'PUT', method: 'PUT',
@ -33,6 +42,7 @@ function remove (featureToggleName) {
module.exports = { module.exports = {
fetchAll, fetchAll,
create, create,
validate,
update, update,
remove, remove,
}; };

View File

@ -2,7 +2,7 @@ const defaultErrorMessage = 'Unexptected exception when talking to unleash-api';
export function throwIfNotSuccess (response) { export function throwIfNotSuccess (response) {
if (!response.ok) { if (!response.ok) {
if (response.status > 400 && response.status < 404) { if (response.status > 399 && response.status < 404) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
response.json().then(body => { response.json().then(body => {
const errorMsg = body && body.length > 0 ? body[0].msg : defaultErrorMessage; const errorMsg = body && body.length > 0 ? body[0].msg : defaultErrorMessage;

View File

@ -88,3 +88,6 @@ export function removeFeatureToggle (featureToggleName) {
}; };
} }
export function validateName (featureToggleName) {
return api.validate({ name: featureToggleName });
}