From d67d731ea9d44384e9f438ef43f2365d9cc920ec Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Wed, 29 Apr 2020 10:55:47 +0200 Subject: [PATCH] Add alreadyUse and forbidden content type check on name Signed-off-by: Alexandre Bodin --- .../strapi-database/lib/constants/index.js | 2 +- .../strapi-database/lib/database-manager.js | 2 +- .../validation/__tests__/content-type.test.js | 1 + .../controllers/validation/content-type.js | 39 +++++++++++++++++++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/packages/strapi-database/lib/constants/index.js b/packages/strapi-database/lib/constants/index.js index 8233401bae..da41612ee4 100644 --- a/packages/strapi-database/lib/constants/index.js +++ b/packages/strapi-database/lib/constants/index.js @@ -1,7 +1,7 @@ 'use strict'; // contentTypes and components reserved names -const RESERVED_MODEL_NAMES = ['admin']; +const RESERVED_MODEL_NAMES = ['admin', 'boolean', 'date', 'date-time', 'time', 'upload']; // attribute reserved names const RESERVED_ATTRIBUTE_NAMES = ['_id', 'id', 'length', 'attributes', 'relations', 'changed']; diff --git a/packages/strapi-database/lib/database-manager.js b/packages/strapi-database/lib/database-manager.js index 9f9c07b3c4..e69f766fe4 100644 --- a/packages/strapi-database/lib/database-manager.js +++ b/packages/strapi-database/lib/database-manager.js @@ -122,7 +122,7 @@ class DatabaseManager { getReservedNames() { return { - model: constants.RESERVED_MODEL_NAMES, + models: constants.RESERVED_MODEL_NAMES, attributes: [ ...constants.RESERVED_ATTRIBUTE_NAMES, ...(strapi.db.connectors.default.defaultTimestamps || []), diff --git a/packages/strapi-plugin-content-type-builder/controllers/validation/__tests__/content-type.test.js b/packages/strapi-plugin-content-type-builder/controllers/validation/__tests__/content-type.test.js index 9f369b944f..61d40f20fa 100644 --- a/packages/strapi-plugin-content-type-builder/controllers/validation/__tests__/content-type.test.js +++ b/packages/strapi-plugin-content-type-builder/controllers/validation/__tests__/content-type.test.js @@ -2,6 +2,7 @@ const { validateKind, validateUpdateContentTypeInput } = require('../content-typ describe('Content type validator', () => { global.strapi = { + contentTypes: {}, plugins: { 'content-type-builder': { services: { diff --git a/packages/strapi-plugin-content-type-builder/controllers/validation/content-type.js b/packages/strapi-plugin-content-type-builder/controllers/validation/content-type.js index d94338cb3d..b6286bb2c9 100644 --- a/packages/strapi-plugin-content-type-builder/controllers/validation/content-type.js +++ b/packages/strapi-plugin-content-type-builder/controllers/validation/content-type.js @@ -8,6 +8,7 @@ const createSchema = require('./model-schema'); const { removeEmptyDefaults, removeDeletedUIDTargetFields } = require('./data-transform'); const { nestedComponentSchema } = require('./component'); const { modelTypes, DEFAULT_TYPES, typeKinds } = require('./constants'); +const { nameToSlug } = require('strapi-utils'); /** * Allowed relation per type kind @@ -38,6 +39,13 @@ const createContentTypeSchema = data => { const contentTypeSchema = createSchema(VALID_TYPES, VALID_RELATIONS[kind] || [], { modelType: modelTypes.CONTENT_TYPE, + }).shape({ + name: yup + .string() + .test(alreadyUsedContentTypeName()) + .test(forbiddenContentTypeNameValidator()) + .min(1) + .required(), }); return yup @@ -86,6 +94,37 @@ const validateUpdateContentTypeInput = data => { .catch(error => Promise.reject(formatYupErrors(error))); }; +const forbiddenContentTypeNameValidator = () => { + const reservedNames = strapi.plugins['content-type-builder'].services.builder.getReservedNames() + .models; + + return { + name: 'forbiddenContentTypeName', + message: `Content Type name cannot be one of ${reservedNames.join(', ')}`, + test: value => { + if (reservedNames.includes(nameToSlug(value))) { + return false; + } + return true; + }, + }; +}; + +const alreadyUsedContentTypeName = () => { + const usedNames = Object.values(strapi.contentTypes).map(ct => ct.modelName); + + return { + name: 'nameAlreadyUsed', + message: 'Content Type name `${value}` is already being used.', + test: value => { + if (usedNames.includes(nameToSlug(value))) { + return false; + } + return true; + }, + }; +}; + /** * Validates type kind */