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": {
|
||||
"increments": true,
|
||||
"timestamps": true,
|
||||
"timestamps": [
|
||||
"created_at",
|
||||
"updated_at"
|
||||
],
|
||||
"comment": ""
|
||||
},
|
||||
"attributes": {
|
||||
@ -24,14 +27,17 @@
|
||||
"type": "json"
|
||||
},
|
||||
"number": {
|
||||
"type": "integer"
|
||||
"type": "biginteger"
|
||||
},
|
||||
"date": {
|
||||
"type": "date"
|
||||
},
|
||||
"enum": {
|
||||
"type": "enumeration",
|
||||
"enum": ["morning,", "noon"]
|
||||
"enum": [
|
||||
"morning,",
|
||||
"noon"
|
||||
]
|
||||
},
|
||||
"bool": {
|
||||
"type": "boolean"
|
||||
@ -54,18 +60,16 @@
|
||||
},
|
||||
"manyTags": {
|
||||
"collection": "tag",
|
||||
"dominant": true,
|
||||
"via": "linkedArticles"
|
||||
"via": "linkedArticles",
|
||||
"dominant": true
|
||||
},
|
||||
"fb_cta": {
|
||||
"type": "group",
|
||||
"group": "cta_facebook",
|
||||
"repeatable": false
|
||||
"group": "cta_facebook"
|
||||
},
|
||||
"mainIngredient": {
|
||||
"type": "group",
|
||||
"group": "ingredients",
|
||||
"repeatable": false
|
||||
"group": "ingredients"
|
||||
},
|
||||
"ingredients": {
|
||||
"type": "group",
|
||||
@ -73,6 +77,30 @@
|
||||
"repeatable": true,
|
||||
"min": 1,
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,26 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const yup = require('yup');
|
||||
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)));
|
||||
|
||||
const validateGroupInput = require('./validation/group');
|
||||
/**
|
||||
* 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')) {
|
||||
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)) {
|
||||
return acc;
|
||||
}
|
||||
@ -211,7 +211,6 @@ const convertAttributes = attributes => {
|
||||
acc[key] = {
|
||||
[nature === 'oneWay' ? 'model' : 'collection']: target,
|
||||
plugin: plugin ? _.trim(plugin) : undefined,
|
||||
required: required === true ? true : undefined,
|
||||
unique: unique === true ? true : undefined,
|
||||
};
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ describe.only('Content Type Builder - Groups', () => {
|
||||
method: 'POST',
|
||||
url: '/content-type-builder/groups',
|
||||
body: {
|
||||
name: 'some-group',
|
||||
name: 'SomeGroup',
|
||||
attributes: {
|
||||
title: {
|
||||
type: 'string',
|
||||
@ -58,7 +58,7 @@ describe.only('Content Type Builder - Groups', () => {
|
||||
method: 'POST',
|
||||
url: '/content-type-builder/groups',
|
||||
body: {
|
||||
name: 'some-group',
|
||||
name: 'someGroup',
|
||||
attributes: {},
|
||||
},
|
||||
});
|
||||
@ -121,7 +121,7 @@ describe.only('Content Type Builder - Groups', () => {
|
||||
data: {
|
||||
uid: 'some_group',
|
||||
schema: {
|
||||
name: 'some-group',
|
||||
name: 'SomeGroup',
|
||||
description: '',
|
||||
connection: 'default',
|
||||
collectionName: 'groups_some_groups',
|
||||
|
Loading…
x
Reference in New Issue
Block a user