From 63c56d96f28a3e9127ca7b9d61877b0e2882a0f2 Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Thu, 7 May 2020 00:56:33 +0200 Subject: [PATCH] Check pluralize name in ctb Signed-off-by: Alexandre Bodin --- .../validation/__tests__/content-type.test.js | 27 ++++++++++++++++++- .../controllers/validation/content-type.js | 19 +++++++++++-- 2 files changed, 43 insertions(+), 3 deletions(-) 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 20cb3da061..116f86f5d9 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 @@ -1,4 +1,8 @@ -const { validateKind, validateUpdateContentTypeInput } = require('../content-type'); +const { + validateKind, + validateUpdateContentTypeInput, + validateContentTypeInput, +} = require('../content-type'); describe('Content type validator', () => { global.strapi = { @@ -58,6 +62,27 @@ describe('Content type validator', () => { }); }); + describe('Prevents use of names without plural form', () => { + test('Throws when using name without plural form', async () => { + const data = { + contentType: { + name: 'news', + attributes: { + title: { + type: 'string', + }, + }, + }, + }; + + await validateContentTypeInput(data).catch(err => { + expect(err).toMatchObject({ + 'contentType.name': [expect.stringMatching('cannot be pluralized')], + }); + }); + }); + }); + describe('validateUpdateContentTypeInput', () => { test('Deletes empty defaults', async () => { const data = { 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 4c896c7206..f0f84a40ad 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 @@ -2,13 +2,13 @@ const _ = require('lodash'); const yup = require('yup'); -const { formatYupErrors } = require('strapi-utils'); +const { formatYupErrors, nameToSlug } = require('strapi-utils'); +const pluralize = require('pluralize'); 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 @@ -42,6 +42,7 @@ const createContentTypeSchema = (data, { isEdition = false } = {}) => { }).shape({ name: yup .string() + .test(hasPluralName) .test(alreadyUsedContentTypeName(isEdition)) .test(forbiddenContentTypeNameValidator()) .min(1) @@ -105,11 +106,25 @@ const forbiddenContentTypeNameValidator = () => { if (reservedNames.includes(nameToSlug(value))) { return false; } + return true; }, }; }; +const hasPluralName = { + name: 'hasPluralName', + message: + 'Content Type name `${value}` cannot be pluralized. \nSuggestion: add Item after the name (e.g News -> NewsItem).', + test: value => { + if (pluralize.singular(value) === pluralize(value)) { + return false; + } + + return true; + }, +}; + const alreadyUsedContentTypeName = isEdition => { const usedNames = Object.values(strapi.contentTypes).map(ct => ct.modelName);