mirror of
https://github.com/strapi/strapi.git
synced 2025-08-31 12:23:05 +00:00
Validate content-type-buildeer group schema
This commit is contained in:
parent
81ae3aab1a
commit
c530afa8a3
@ -7,7 +7,10 @@
|
|||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"increments": true,
|
"increments": true,
|
||||||
"timestamps": true,
|
"timestamps": [
|
||||||
|
"created_at",
|
||||||
|
"updated_at"
|
||||||
|
],
|
||||||
"comment": ""
|
"comment": ""
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
@ -24,14 +27,17 @@
|
|||||||
"type": "json"
|
"type": "json"
|
||||||
},
|
},
|
||||||
"number": {
|
"number": {
|
||||||
"type": "integer"
|
"type": "biginteger"
|
||||||
},
|
},
|
||||||
"date": {
|
"date": {
|
||||||
"type": "date"
|
"type": "date"
|
||||||
},
|
},
|
||||||
"enum": {
|
"enum": {
|
||||||
"type": "enumeration",
|
"type": "enumeration",
|
||||||
"enum": ["morning,", "noon"]
|
"enum": [
|
||||||
|
"morning,",
|
||||||
|
"noon"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"bool": {
|
"bool": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@ -54,18 +60,16 @@
|
|||||||
},
|
},
|
||||||
"manyTags": {
|
"manyTags": {
|
||||||
"collection": "tag",
|
"collection": "tag",
|
||||||
"dominant": true,
|
"via": "linkedArticles",
|
||||||
"via": "linkedArticles"
|
"dominant": true
|
||||||
},
|
},
|
||||||
"fb_cta": {
|
"fb_cta": {
|
||||||
"type": "group",
|
"type": "group",
|
||||||
"group": "cta_facebook",
|
"group": "cta_facebook"
|
||||||
"repeatable": false
|
|
||||||
},
|
},
|
||||||
"mainIngredient": {
|
"mainIngredient": {
|
||||||
"type": "group",
|
"type": "group",
|
||||||
"group": "ingredients",
|
"group": "ingredients"
|
||||||
"repeatable": false
|
|
||||||
},
|
},
|
||||||
"ingredients": {
|
"ingredients": {
|
||||||
"type": "group",
|
"type": "group",
|
||||||
@ -73,6 +77,30 @@
|
|||||||
"repeatable": true,
|
"repeatable": true,
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"max": 10
|
"max": 10
|
||||||
|
},
|
||||||
|
"blabla": {
|
||||||
|
"enum": [
|
||||||
|
"one",
|
||||||
|
"two",
|
||||||
|
"three"
|
||||||
|
],
|
||||||
|
"type": "enumeration",
|
||||||
|
"unique": true,
|
||||||
|
"enumName": "azd",
|
||||||
|
"default": "azd",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"article": {
|
||||||
|
"columnName": "azdazd",
|
||||||
|
"unique": true,
|
||||||
|
"model": "article",
|
||||||
|
"via": "articlea"
|
||||||
|
},
|
||||||
|
"articlea": {
|
||||||
|
"columnName": "azdazd",
|
||||||
|
"unique": true,
|
||||||
|
"model": "article",
|
||||||
|
"via": "article"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -18,4 +18,4 @@
|
|||||||
"via": "manyTags"
|
"via": "manyTags"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,26 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const yup = require('yup');
|
const validateGroupInput = require('./validation/group');
|
||||||
const formatYupErrors = require('./utils/yup-formatter');
|
|
||||||
|
|
||||||
const groupSchema = yup
|
|
||||||
.object({
|
|
||||||
name: yup.string().required('name.required'),
|
|
||||||
description: yup.string(),
|
|
||||||
connection: yup.string(),
|
|
||||||
collectionName: yup.string(),
|
|
||||||
attributes: yup.object().required('attributes.required'),
|
|
||||||
})
|
|
||||||
.noUnknown();
|
|
||||||
|
|
||||||
const validateGroupInput = async data =>
|
|
||||||
groupSchema
|
|
||||||
.validate(data, {
|
|
||||||
strict: true,
|
|
||||||
abortEarly: false,
|
|
||||||
})
|
|
||||||
.catch(error => Promise.reject(formatYupErrors(error)));
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Groups controller
|
* Groups controller
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const yup = require('yup');
|
||||||
|
|
||||||
|
const VALID_TYPES = [
|
||||||
|
// advanced types
|
||||||
|
'media',
|
||||||
|
|
||||||
|
// scalar types
|
||||||
|
'string',
|
||||||
|
'text',
|
||||||
|
'richtext',
|
||||||
|
'json',
|
||||||
|
'enumeration',
|
||||||
|
'password',
|
||||||
|
'email',
|
||||||
|
'integer',
|
||||||
|
'float',
|
||||||
|
'decimal',
|
||||||
|
'date',
|
||||||
|
'boolean',
|
||||||
|
];
|
||||||
|
|
||||||
|
const validators = {
|
||||||
|
required: yup.boolean(),
|
||||||
|
unique: yup.boolean(),
|
||||||
|
minLength: yup
|
||||||
|
.number()
|
||||||
|
.integer()
|
||||||
|
.positive(),
|
||||||
|
maxLength: yup
|
||||||
|
.number()
|
||||||
|
.integer()
|
||||||
|
.positive(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const NAME_REGEX = new RegExp('^[A-Za-z][_0-9A-Za-z]*$');
|
||||||
|
|
||||||
|
const isValidName = {
|
||||||
|
name: 'isValidName',
|
||||||
|
message: '${path} must match the following regex: /^[_A-Za-z][_0-9A-Za-z]*/^',
|
||||||
|
test: val => NAME_REGEX.test(val),
|
||||||
|
};
|
||||||
|
|
||||||
|
const isValidKey = key => ({
|
||||||
|
name: 'isValidKey',
|
||||||
|
message: `Attribute name '${key}' must match the following regex: /^[_A-Za-z][_0-9A-Za-z]*/^`,
|
||||||
|
test: () => NAME_REGEX.test(key),
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
validators,
|
||||||
|
|
||||||
|
isValidName,
|
||||||
|
isValidKey,
|
||||||
|
|
||||||
|
VALID_TYPES,
|
||||||
|
};
|
@ -0,0 +1,60 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const yup = require('yup');
|
||||||
|
const _ = require('lodash');
|
||||||
|
const formatYupErrors = require('./yup-formatter');
|
||||||
|
|
||||||
|
const { isValidName, isValidKey } = require('./common');
|
||||||
|
const getTypeValidator = require('./types');
|
||||||
|
const getRelationValidator = require('./relations');
|
||||||
|
|
||||||
|
module.exports = data => {
|
||||||
|
return groupSchema
|
||||||
|
.validate(data, {
|
||||||
|
strict: true,
|
||||||
|
abortEarly: false,
|
||||||
|
})
|
||||||
|
.catch(error => Promise.reject(formatYupErrors(error)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const groupSchema = yup
|
||||||
|
.object({
|
||||||
|
name: yup
|
||||||
|
.string()
|
||||||
|
.min(1)
|
||||||
|
.test(isValidName)
|
||||||
|
.required('name.required'),
|
||||||
|
description: yup.string(),
|
||||||
|
connection: yup.string(),
|
||||||
|
collectionName: yup.string().test(isValidName),
|
||||||
|
attributes: yup.lazy(obj => {
|
||||||
|
return yup
|
||||||
|
.object()
|
||||||
|
.shape(
|
||||||
|
_.mapValues(obj, (value, key) => {
|
||||||
|
return yup.lazy(obj => {
|
||||||
|
let shape;
|
||||||
|
if (_.has(obj, 'type')) {
|
||||||
|
shape = getTypeValidator(obj);
|
||||||
|
} else if (_.has(obj, 'target')) {
|
||||||
|
shape = getRelationValidator(obj);
|
||||||
|
} else {
|
||||||
|
return yup.object().test({
|
||||||
|
name: 'mustHaveTypeOrTarget',
|
||||||
|
message: 'Attribute must have either a type or a target',
|
||||||
|
test: () => false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return yup
|
||||||
|
.object()
|
||||||
|
.shape(shape)
|
||||||
|
.test(isValidKey(key))
|
||||||
|
.noUnknown();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.required('attributes.required');
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.noUnknown();
|
@ -0,0 +1,42 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const yup = require('yup');
|
||||||
|
const _ = require('lodash');
|
||||||
|
const { validators } = require('./common');
|
||||||
|
|
||||||
|
const VALID_NATURES = ['oneWay', 'manyWay'];
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
return {
|
||||||
|
target: yup
|
||||||
|
.mixed()
|
||||||
|
.when('plugin', plugin => {
|
||||||
|
if (!plugin)
|
||||||
|
return yup
|
||||||
|
.string()
|
||||||
|
.oneOf(
|
||||||
|
Object.keys(strapi.models).filter(name => name !== 'core_store')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (plugin === 'admin')
|
||||||
|
return yup.string().oneOf(Object.keys(strapi.admin.models));
|
||||||
|
|
||||||
|
if (plugin)
|
||||||
|
return yup
|
||||||
|
.string()
|
||||||
|
.oneOf(Object.keys(_.get(strapi.plugins, [plugin, 'models'], {})));
|
||||||
|
})
|
||||||
|
.required(),
|
||||||
|
nature: yup
|
||||||
|
.string()
|
||||||
|
.oneOf(VALID_NATURES)
|
||||||
|
.required(),
|
||||||
|
plugin: yup.string().oneOf(Object.keys(strapi.plugins)),
|
||||||
|
unique: validators.unique,
|
||||||
|
|
||||||
|
// TODO: remove once front-end stop sending them even if useless
|
||||||
|
columnName: yup.string(),
|
||||||
|
key: yup.string(),
|
||||||
|
targetColumnName: yup.string(),
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,132 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const yup = require('yup');
|
||||||
|
const { validators, VALID_TYPES, isValidName } = require('./common');
|
||||||
|
|
||||||
|
module.exports = obj => {
|
||||||
|
return {
|
||||||
|
type: yup
|
||||||
|
.string()
|
||||||
|
.oneOf(VALID_TYPES)
|
||||||
|
.required(),
|
||||||
|
...getTypeShape(obj),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTypeShape = obj => {
|
||||||
|
switch (obj.type) {
|
||||||
|
/**
|
||||||
|
* complexe types
|
||||||
|
*/
|
||||||
|
|
||||||
|
case 'media': {
|
||||||
|
return {
|
||||||
|
multiple: yup.boolean(),
|
||||||
|
required: validators.required,
|
||||||
|
unique: validators.unique,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scalar types
|
||||||
|
*/
|
||||||
|
case 'string':
|
||||||
|
case 'text':
|
||||||
|
case 'richtext': {
|
||||||
|
return {
|
||||||
|
default: yup.string(),
|
||||||
|
required: validators.required,
|
||||||
|
unique: validators.unique,
|
||||||
|
min: validators.minLength,
|
||||||
|
max: validators.maxLength,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'json': {
|
||||||
|
return {
|
||||||
|
required: validators.required,
|
||||||
|
unique: validators.unique,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'enumeration': {
|
||||||
|
return {
|
||||||
|
enum: yup
|
||||||
|
.array()
|
||||||
|
.of(yup.string().test(isValidName))
|
||||||
|
.min(1)
|
||||||
|
.required(),
|
||||||
|
default: yup
|
||||||
|
.string()
|
||||||
|
.when('enum', enumVal => yup.string().oneOf(enumVal)),
|
||||||
|
enumName: yup.string().test(isValidName),
|
||||||
|
required: validators.required,
|
||||||
|
unique: validators.unique,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'password': {
|
||||||
|
return {
|
||||||
|
required: validators.required,
|
||||||
|
min: validators.minLength,
|
||||||
|
max: validators.maxLength,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'email': {
|
||||||
|
return {
|
||||||
|
default: yup.string().email(),
|
||||||
|
required: validators.required,
|
||||||
|
unique: validators.unique,
|
||||||
|
min: validators.minLength,
|
||||||
|
max: validators.maxLength,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'integer': {
|
||||||
|
return {
|
||||||
|
default: yup.number().integer(),
|
||||||
|
required: validators.required,
|
||||||
|
unique: validators.unique,
|
||||||
|
min: yup
|
||||||
|
.number()
|
||||||
|
.integer()
|
||||||
|
.positive(),
|
||||||
|
max: yup
|
||||||
|
.number()
|
||||||
|
.integer()
|
||||||
|
.positive(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'float': {
|
||||||
|
return {
|
||||||
|
default: yup.number(),
|
||||||
|
required: validators.required,
|
||||||
|
unique: validators.unique,
|
||||||
|
min: yup.number().positive(),
|
||||||
|
max: yup.number().positive(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'decimal': {
|
||||||
|
return {
|
||||||
|
default: yup.number(),
|
||||||
|
required: validators.required,
|
||||||
|
unique: validators.unique,
|
||||||
|
min: yup.number().positive(),
|
||||||
|
max: yup.number().positive(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'date': {
|
||||||
|
return {
|
||||||
|
default: yup.date(),
|
||||||
|
required: validators.required,
|
||||||
|
unique: validators.unique,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'boolean': {
|
||||||
|
return {
|
||||||
|
default: yup.boolean(),
|
||||||
|
required: validators.required,
|
||||||
|
unique: validators.unique,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -201,9 +201,9 @@ const convertAttributes = attributes => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_.has(attribute, 'target')) {
|
if (_.has(attribute, 'target')) {
|
||||||
const { target, nature, required, unique, plugin } = attribute;
|
const { target, nature, unique, plugin } = attribute;
|
||||||
|
|
||||||
// ingore relation which aren't oneWay or manyWay (except for images)
|
// ingore relation which aren't oneWay or manyWay
|
||||||
if (!['oneWay', 'manyWay'].includes(nature)) {
|
if (!['oneWay', 'manyWay'].includes(nature)) {
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
@ -211,7 +211,6 @@ const convertAttributes = attributes => {
|
|||||||
acc[key] = {
|
acc[key] = {
|
||||||
[nature === 'oneWay' ? 'model' : 'collection']: target,
|
[nature === 'oneWay' ? 'model' : 'collection']: target,
|
||||||
plugin: plugin ? _.trim(plugin) : undefined,
|
plugin: plugin ? _.trim(plugin) : undefined,
|
||||||
required: required === true ? true : undefined,
|
|
||||||
unique: unique === true ? true : undefined,
|
unique: unique === true ? true : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ describe.only('Content Type Builder - Groups', () => {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: '/content-type-builder/groups',
|
url: '/content-type-builder/groups',
|
||||||
body: {
|
body: {
|
||||||
name: 'some-group',
|
name: 'SomeGroup',
|
||||||
attributes: {
|
attributes: {
|
||||||
title: {
|
title: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@ -58,7 +58,7 @@ describe.only('Content Type Builder - Groups', () => {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: '/content-type-builder/groups',
|
url: '/content-type-builder/groups',
|
||||||
body: {
|
body: {
|
||||||
name: 'some-group',
|
name: 'someGroup',
|
||||||
attributes: {},
|
attributes: {},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -121,7 +121,7 @@ describe.only('Content Type Builder - Groups', () => {
|
|||||||
data: {
|
data: {
|
||||||
uid: 'some_group',
|
uid: 'some_group',
|
||||||
schema: {
|
schema: {
|
||||||
name: 'some-group',
|
name: 'SomeGroup',
|
||||||
description: '',
|
description: '',
|
||||||
connection: 'default',
|
connection: 'default',
|
||||||
collectionName: 'groups_some_groups',
|
collectionName: 'groups_some_groups',
|
||||||
@ -176,7 +176,7 @@ describe.only('Content Type Builder - Groups', () => {
|
|||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
url: '/content-type-builder/groups/some_group',
|
url: '/content-type-builder/groups/some_group',
|
||||||
body: {
|
body: {
|
||||||
name: 'New Group',
|
name: 'NewGroup',
|
||||||
attributes: {},
|
attributes: {},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user