diff --git a/packages/strapi-plugin-content-type-builder/controllers/ContentTypes.js b/packages/strapi-plugin-content-type-builder/controllers/ContentTypes.js index adae50d9ba..225290f7a0 100644 --- a/packages/strapi-plugin-content-type-builder/controllers/ContentTypes.js +++ b/packages/strapi-plugin-content-type-builder/controllers/ContentTypes.js @@ -5,10 +5,19 @@ const _ = require('lodash'); const { validateContentTypeInput, validateUpdateContentTypeInput, + validateKind, } = require('./validation/content-type'); module.exports = { - getContentTypes(ctx) { + async getContentTypes(ctx) { + const { kind } = ctx.query; + + try { + await validateKind(kind); + } catch (error) { + return ctx.send({ error }, 400); + } + const contentTypeService = strapi.plugins['content-type-builder'].services.contenttypes; @@ -17,6 +26,13 @@ module.exports = { if (uid.startsWith('strapi::')) return false; if (uid === 'plugins::upload.file') return false; // TODO: add a flag in the content type instead + if ( + kind && + _.get(strapi.contentTypes[uid], 'kind', 'collectionType') !== kind + ) { + return false; + } + return true; }) .map(uid => diff --git a/packages/strapi-plugin-content-type-builder/controllers/validation/component.js b/packages/strapi-plugin-content-type-builder/controllers/validation/component.js index ad978c2cf9..fd62d0361b 100644 --- a/packages/strapi-plugin-content-type-builder/controllers/validation/component.js +++ b/packages/strapi-plugin-content-type-builder/controllers/validation/component.js @@ -6,6 +6,7 @@ const yup = require('yup'); const { isValidCategoryName, isValidIcon } = require('./common'); const formatYupErrors = require('./yup-formatter'); const createSchema = require('./model-schema'); +const removeEmptyDefaults = require('./remove-empty-defaults'); const { modelTypes, DEFAULT_TYPES } = require('./constants'); const VALID_RELATIONS = ['oneWay', 'manyWay']; @@ -63,26 +64,7 @@ const validateComponentInput = data => { }; const validateUpdateComponentInput = data => { - // convert zero length string on default attributes to undefined - if (_.has(data, ['component', 'attributes'])) { - Object.keys(data.component.attributes).forEach(attribute => { - if (data.component.attributes[attribute].default === '') { - data.component.attributes[attribute].default = undefined; - } - }); - } - - if (_.has(data, 'components') && Array.isArray(data.components)) { - data.components.forEach(data => { - if (_.has(data, 'attributes') && _.has(data, 'uid')) { - Object.keys(data.attributes).forEach(attribute => { - if (data.attributes[attribute].default === '') { - data.attributes[attribute].default = undefined; - } - }); - } - }); - } + removeEmptyDefaults(data); return yup .object({ diff --git a/packages/strapi-plugin-content-type-builder/controllers/validation/constants.js b/packages/strapi-plugin-content-type-builder/controllers/validation/constants.js index f96f7ad400..1b9f15cf90 100644 --- a/packages/strapi-plugin-content-type-builder/controllers/validation/constants.js +++ b/packages/strapi-plugin-content-type-builder/controllers/validation/constants.js @@ -3,6 +3,9 @@ const CONTENT_TYPE = 'CONTENT_TYPE'; const COMPONENT = 'COMPONENT'; +const SINGLE_TYPE = 'singleType'; +const COLLECTION_TYPE = 'collectionType'; + const DEFAULT_TYPES = [ // advanced types 'media', @@ -30,6 +33,10 @@ const FORBIDDEN_ATTRIBUTE_NAMES = ['__component', '__contentType']; module.exports = { DEFAULT_TYPES, + typeKinds: { + SINGLE_TYPE, + COLLECTION_TYPE, + }, modelTypes: { CONTENT_TYPE, COMPONENT, 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 f6046b726a..af8ab4fcd9 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,35 +2,61 @@ const _ = require('lodash'); const yup = require('yup'); + const formatYupErrors = require('./yup-formatter'); - const createSchema = require('./model-schema'); +const removeEmptyDefaults = require('./remove-empty-defaults'); const { nestedComponentSchema } = require('./component'); -const { modelTypes, DEFAULT_TYPES } = require('./constants'); +const { modelTypes, DEFAULT_TYPES, typeKinds } = require('./constants'); -const VALID_RELATIONS = [ - 'oneWay', - 'manyWay', - 'oneToOne', - 'oneToMany', - 'manyToOne', - 'manyToMany', -]; +/** + * Allowed relation per type kind + */ +const VALID_RELATIONS = { + [typeKinds.SINGLE_TYPE]: ['oneWay', 'manyWay'], + [typeKinds.COLLECTION_TYPE]: [ + 'oneWay', + 'manyWay', + 'oneToOne', + 'oneToMany', + 'manyToOne', + 'manyToMany', + ], +}; + +/** + * Allowed types + */ const VALID_TYPES = [...DEFAULT_TYPES, 'component', 'dynamiczone']; -const contentTypeSchema = createSchema(VALID_TYPES, VALID_RELATIONS, { - modelType: modelTypes.CONTENT_TYPE, -}); +/** + * Returns a yup schema to validate a content type payload + * @param {Object} data payload + */ +const createContentTypeSchema = data => { + const kind = _.get(data, 'kind', typeKinds.COLLECTION_TYPE); -const createContentTypeSchema = yup - .object({ - contentType: contentTypeSchema.required().noUnknown(), - components: nestedComponentSchema, - }) - .noUnknown(); + const contentTypeSchema = createSchema( + VALID_TYPES, + VALID_RELATIONS[kind] || [], + { + modelType: modelTypes.CONTENT_TYPE, + } + ); + return yup + .object({ + contentType: contentTypeSchema.required().noUnknown(), + components: nestedComponentSchema, + }) + .noUnknown(); +}; + +/** + * Validator for content type creation + */ const validateContentTypeInput = data => { - return createContentTypeSchema + return createContentTypeSchema(data) .validate(data, { strict: true, abortEarly: false, @@ -38,29 +64,13 @@ const validateContentTypeInput = data => { .catch(error => Promise.reject(formatYupErrors(error))); }; +/** + * Validator for content type edition + */ const validateUpdateContentTypeInput = data => { - // convert zero length string on default attributes to undefined - if (_.has(data, 'attributes')) { - Object.keys(data.attributes).forEach(attribute => { - if (data.attributes[attribute].default === '') { - data.attributes[attribute].default = undefined; - } - }); - } + removeEmptyDefaults(data); - if (_.has(data, 'components') && Array.isArray(data.components)) { - data.components.forEach(data => { - if (_.has(data, 'attributes') && _.has(data, 'uid')) { - Object.keys(data.attributes).forEach(attribute => { - if (data.attributes[attribute].default === '') { - data.attributes[attribute].default = undefined; - } - }); - } - }); - } - - return createContentTypeSchema + return createContentTypeSchema(data) .validate(data, { strict: true, abortEarly: false, @@ -68,7 +78,20 @@ const validateUpdateContentTypeInput = data => { .catch(error => Promise.reject(formatYupErrors(error))); }; +/** + * Validates type kind + */ +const validateKind = kind => { + return yup + .string() + .oneOf([typeKinds.SINGLE_TYPE, typeKinds.COLLECTION_TYPE]) + .nullable() + .validate(kind) + .catch(error => Promise.reject(formatYupErrors(error))); +}; + module.exports = { validateContentTypeInput, validateUpdateContentTypeInput, + validateKind, }; diff --git a/packages/strapi-plugin-content-type-builder/controllers/validation/model-schema.js b/packages/strapi-plugin-content-type-builder/controllers/validation/model-schema.js index ce58fe233d..dd43517b59 100644 --- a/packages/strapi-plugin-content-type-builder/controllers/validation/model-schema.js +++ b/packages/strapi-plugin-content-type-builder/controllers/validation/model-schema.js @@ -3,72 +3,88 @@ const _ = require('lodash'); const yup = require('yup'); -const { FORBIDDEN_ATTRIBUTE_NAMES } = require('./constants'); +const { + modelTypes, + FORBIDDEN_ATTRIBUTE_NAMES, + typeKinds, +} = require('./constants'); const { isValidCollectionName, isValidKey } = require('./common'); const { getTypeShape } = require('./types'); const getRelationValidator = require('./relations'); -const createSchema = (types, relations, { modelType } = {}) => - yup - .object({ - name: yup - .string() - .min(1) - .required('name.required'), - description: yup.string(), - connection: yup.string(), - collectionName: yup - .string() - .nullable() - .test(isValidCollectionName), - attributes: yup.lazy(attributes => { - return yup - .object() - .shape( - _.mapValues(attributes, (attribute, key) => { - if (FORBIDDEN_ATTRIBUTE_NAMES.includes(key)) { - return yup.object().test({ - name: 'forbiddenKeys', - message: `Attribute keys cannot be one of ${FORBIDDEN_ATTRIBUTE_NAMES.join( - ', ' - )}`, - test: () => false, - }); - } - - if (_.has(attribute, 'type')) { - const shape = { - type: yup - .string() - .oneOf(types) - .required(), - configurable: yup.boolean().nullable(), - private: yup.boolean().nullable(), - ...getTypeShape(attribute, { modelType }), - }; - - return yup - .object(shape) - .test(isValidKey(key)) - .noUnknown(); - } else if (_.has(attribute, 'target')) { - const shape = getRelationValidator(attribute, relations); - - return yup - .object(shape) - .test(isValidKey(key)) - .noUnknown(); - } +const createSchema = (types, relations, { modelType } = {}) => { + const schema = yup.object({ + name: yup + .string() + .min(1) + .required('name.required'), + description: yup.string(), + connection: yup.string(), + collectionName: yup + .string() + .nullable() + .test(isValidCollectionName), + attributes: yup.lazy(attributes => { + return yup + .object() + .shape( + _.mapValues(attributes, (attribute, key) => { + if (FORBIDDEN_ATTRIBUTE_NAMES.includes(key)) { return yup.object().test({ - name: 'mustHaveTypeOrTarget', - message: 'Attribute must have either a type or a target', + name: 'forbiddenKeys', + message: `Attribute keys cannot be one of ${FORBIDDEN_ATTRIBUTE_NAMES.join( + ', ' + )}`, test: () => false, }); - }) - ) - .required('attributes.required'); - }), - }) - .noUnknown(); + } + + if (_.has(attribute, 'type')) { + const shape = { + type: yup + .string() + .oneOf(types) + .required(), + configurable: yup.boolean().nullable(), + private: yup.boolean().nullable(), + ...getTypeShape(attribute, { modelType }), + }; + + return yup + .object(shape) + .test(isValidKey(key)) + .noUnknown(); + } else if (_.has(attribute, 'target')) { + const shape = getRelationValidator(attribute, relations); + + return yup + .object(shape) + .test(isValidKey(key)) + .noUnknown(); + } + return yup.object().test({ + name: 'mustHaveTypeOrTarget', + message: 'Attribute must have either a type or a target', + test: () => false, + }); + }) + ) + .required('attributes.required'); + }), + }); + + if (modelType === modelTypes.CONTENT_TYPE) { + return schema + .shape({ + kind: yup + .string() + .oneOf([typeKinds.SINGLE_TYPE, typeKinds.COLLECTION_TYPE]) + .nullable(), + }) + .noUnknown(); + } + + return schema.noUnknown(); +}; module.exports = createSchema; diff --git a/packages/strapi-plugin-content-type-builder/controllers/validation/relations.js b/packages/strapi-plugin-content-type-builder/controllers/validation/relations.js index e9375af1ed..854ed050ac 100644 --- a/packages/strapi-plugin-content-type-builder/controllers/validation/relations.js +++ b/packages/strapi-plugin-content-type-builder/controllers/validation/relations.js @@ -2,14 +2,14 @@ const yup = require('yup'); const { validators, isValidName } = require('./common'); +const { typeKinds } = require('./constants'); const REVERSE_RELATIONS = ['oneToOne', 'oneToMany', 'manyToOne', 'manyToMany']; module.exports = (obj, validNatures) => { - const contentTypesUIDs = Object.keys(strapi.contentTypes).concat([ - '__self__', - '__contentType__', - ]); + const contentTypesUIDs = Object.keys(strapi.contentTypes) + .filter(key => strapi.contentTypes[key].kind === typeKinds.COLLECTION_TYPE) + .concat(['__self__', '__contentType__']); return { target: yup diff --git a/packages/strapi-plugin-content-type-builder/controllers/validation/remove-empty-defaults.js b/packages/strapi-plugin-content-type-builder/controllers/validation/remove-empty-defaults.js new file mode 100644 index 0000000000..aa197e14be --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/controllers/validation/remove-empty-defaults.js @@ -0,0 +1,30 @@ +'use strict'; + +const _ = require('lodash'); + +/** + * Convert zero length string on default attributes to undefined + */ +module.exports = data => { + if (_.has(data, 'attributes')) { + Object.keys(data.attributes).forEach(attribute => { + if (data.attributes[attribute].default === '') { + data.attributes[attribute].default = undefined; + } + }); + } + + if (_.has(data, 'components') && Array.isArray(data.components)) { + data.components.forEach(data => { + if (_.has(data, 'attributes') && _.has(data, 'uid')) { + Object.keys(data.attributes).forEach(attribute => { + if (data.attributes[attribute].default === '') { + data.attributes[attribute].default = undefined; + } + }); + } + }); + } + + return data; +}; diff --git a/packages/strapi-plugin-content-type-builder/services/ContentTypes.js b/packages/strapi-plugin-content-type-builder/services/ContentTypes.js index 7eeab3c87a..c20c173895 100644 --- a/packages/strapi-plugin-content-type-builder/services/ContentTypes.js +++ b/packages/strapi-plugin-content-type-builder/services/ContentTypes.js @@ -17,7 +17,7 @@ const { nameToSlug } = require('../utils/helpers'); * @param {Object} contentType */ const formatContentType = contentType => { - const { uid, plugin, connection, collectionName, info } = contentType; + const { uid, kind, plugin, connection, collectionName, info } = contentType; return { uid, @@ -26,6 +26,7 @@ const formatContentType = contentType => { name: _.get(info, 'name') || _.upperFirst(pluralize(uid)), description: _.get(info, 'description', ''), connection, + kind: kind || 'collectionType', collectionName, attributes: formatAttributes(contentType), }, diff --git a/packages/strapi-plugin-content-type-builder/services/__tests__/__snapshots__/content-types.test.js.snap b/packages/strapi-plugin-content-type-builder/services/__tests__/__snapshots__/content-types.test.js.snap new file mode 100644 index 0000000000..c3e31a32c0 --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/services/__tests__/__snapshots__/content-types.test.js.snap @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Content types service format ContentType Returns consistent schemas 1`] = ` +Object { + "plugin": "some-plugin", + "schema": Object { + "attributes": Object { + "title": Object { + "type": "string", + }, + }, + "collectionName": "tests", + "connection": "default", + "description": "My description", + "kind": "singleType", + "name": "My name", + }, + "uid": "test-uid", +} +`; diff --git a/packages/strapi-plugin-content-type-builder/services/__tests__/content-types.test.js b/packages/strapi-plugin-content-type-builder/services/__tests__/content-types.test.js new file mode 100644 index 0000000000..7c9a9393da --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/services/__tests__/content-types.test.js @@ -0,0 +1,54 @@ +const { formatContentType } = require('../ContentTypes'); + +describe('Content types service', () => { + describe('format ContentType', () => { + const contentType = { + uid: 'test-uid', + kind: 'singleType', + plugin: 'some-plugin', + connection: 'default', + collectionName: 'tests', + info: { + name: 'My name', + description: 'My description', + }, + attributes: { + title: { + type: 'string', + }, + }, + }; + + it('Returns consistent schemas', () => { + expect(formatContentType(contentType)).toMatchSnapshot(); + }); + + it('Sets default kind', () => { + expect( + formatContentType({ + ...contentType, + kind: undefined, + }) + ).toMatchObject({ + schema: { + kind: 'collectionType', + }, + }); + }); + + it('Generates a default name', () => { + expect( + formatContentType({ + ...contentType, + info: { + name: undefined, + }, + }) + ).toMatchObject({ + schema: { + name: 'Test-uids', + }, + }); + }); + }); +}); diff --git a/packages/strapi-plugin-content-type-builder/services/schema-builder/content-type-builder.js b/packages/strapi-plugin-content-type-builder/services/schema-builder/content-type-builder.js index aa8efe08a8..99dc15ddbe 100644 --- a/packages/strapi-plugin-content-type-builder/services/schema-builder/content-type-builder.js +++ b/packages/strapi-plugin-content-type-builder/services/schema-builder/content-type-builder.js @@ -6,6 +6,7 @@ const pluralize = require('pluralize'); const { isRelation, toUID, isConfigurable } = require('../../utils/attributes'); const { nameToSlug, nameToCollectionName } = require('../../utils/helpers'); +const { typeKinds } = require('../../controllers/validation/constants'); const createSchemaHandler = require('./schema-handler'); module.exports = function createComponentBuilder() { @@ -80,6 +81,7 @@ module.exports = function createComponentBuilder() { contentType .setUID(uid) .set('connection', infos.connection || defaultConnection) + .set('kind', infos.kind || typeKinds.COLLECTION_TYPE) .set('collectionName', infos.collectionName || defaultCollectionName) .set(['info', 'name'], infos.name) .set(['info', 'description'], infos.description) @@ -197,9 +199,12 @@ module.exports = function createComponentBuilder() { } }); + // TODO: handle kind change => update routes.json file somehow + contentType .set('connection', infos.connection) .set('collectionName', infos.collectionName) + .set('kind', infos.kind || contentType.schema.kind) .set(['info', 'name'], infos.name) .set(['info', 'description'], infos.description) .setAttributes(this.convertAttributes(newAttributes)); @@ -220,7 +225,6 @@ module.exports = function createComponentBuilder() { ct.removeContentType(uid); }); - // TODO: clear api when a contentType is deleted return this.contentTypes.get(uid).delete(); }, }; diff --git a/packages/strapi-plugin-content-type-builder/test/__snapshots__/content-types.test.e2e.js.snap b/packages/strapi-plugin-content-type-builder/test/__snapshots__/content-types.test.e2e.js.snap new file mode 100644 index 0000000000..869c2f81f7 --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/test/__snapshots__/content-types.test.e2e.js.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Content Type Builder - Content types Collection Types Get collection type returns full schema and informations 1`] = ` +Object { + "data": Object { + "schema": Object { + "attributes": Object { + "title": Object { + "type": "string", + }, + }, + "collectionName": "test_collection_types", + "connection": "default", + "description": "", + "kind": "collectionType", + "name": "Test Collection Type", + }, + "uid": "application::test-collection-type.test-collection-type", + }, +} +`; + +exports[`Content Type Builder - Content types Single Types Get single type returns full schema and informations 1`] = ` +Object { + "data": Object { + "schema": Object { + "attributes": Object { + "title": Object { + "type": "string", + }, + }, + "collectionName": "test_single_types", + "connection": "default", + "description": "", + "kind": "singleType", + "name": "Test Single Type", + }, + "uid": "application::test-single-type.test-single-type", + }, +} +`; diff --git a/packages/strapi-plugin-content-type-builder/test/components.test.e2e.js b/packages/strapi-plugin-content-type-builder/test/components.test.e2e.js index e5c8b8d181..5a0553c86f 100644 --- a/packages/strapi-plugin-content-type-builder/test/components.test.e2e.js +++ b/packages/strapi-plugin-content-type-builder/test/components.test.e2e.js @@ -4,7 +4,7 @@ const waitRestart = require('../../../test/helpers/waitRestart'); let rq; -describe.only('Content Type Builder - Components', () => { +describe('Content Type Builder - Components', () => { beforeAll(async () => { const token = await registerAndLogin(); rq = createAuthRequest(token); diff --git a/packages/strapi-plugin-content-type-builder/test/content-types.test.e2e.js b/packages/strapi-plugin-content-type-builder/test/content-types.test.e2e.js new file mode 100644 index 0000000000..e665808295 --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/test/content-types.test.e2e.js @@ -0,0 +1,97 @@ +/** + * Integration test for the content-type-buidler content types managment apis + */ +'use strict'; + +const { registerAndLogin } = require('../../../test/helpers/auth'); +const { createAuthRequest } = require('../../../test/helpers/request'); +const waitRestart = require('../../../test/helpers/waitRestart'); + +let rq; + +describe('Content Type Builder - Content types', () => { + beforeAll(async () => { + const token = await registerAndLogin(); + rq = createAuthRequest(token); + }, 60000); + + afterEach(() => waitRestart()); + + describe('Collection Types', () => { + const collectionTypeUID = + 'application::test-collection-type.test-collection-type'; + + test('Successfull creation of a collection type', async () => { + const res = await rq({ + method: 'POST', + url: '/content-type-builder/content-types', + body: { + contentType: { + name: 'Test Collection Type', + attributes: { + title: { + type: 'string', + }, + }, + }, + }, + }); + + expect(res.statusCode).toBe(201); + expect(res.body).toEqual({ + data: { + uid: collectionTypeUID, + }, + }); + }); + + test('Get collection type returns full schema and informations', async () => { + const res = await rq({ + method: 'GET', + url: `/content-type-builder/content-types/${collectionTypeUID}`, + }); + + expect(res.statusCode).toBe(200); + expect(res.body).toMatchSnapshot(); + }); + }); + + describe('Single Types', () => { + const singleTypeUID = 'application::test-single-type.test-single-type'; + + test('Successfull creation of a single type', async () => { + const res = await rq({ + method: 'POST', + url: '/content-type-builder/content-types', + body: { + contentType: { + kind: 'singleType', + name: 'Test Single Type', + attributes: { + title: { + type: 'string', + }, + }, + }, + }, + }); + + expect(res.statusCode).toBe(201); + expect(res.body).toEqual({ + data: { + uid: singleTypeUID, + }, + }); + }); + + test('Get single type returns full schema and informations', async () => { + const res = await rq({ + method: 'GET', + url: `/content-type-builder/content-types/${singleTypeUID}`, + }); + + expect(res.statusCode).toBe(200); + expect(res.body).toMatchSnapshot(); + }); + }); +}); diff --git a/packages/strapi-plugin-users-permissions/config/functions/bootstrap.js b/packages/strapi-plugin-users-permissions/config/functions/bootstrap.js index 86eaa2ac1b..65fa9cc001 100644 --- a/packages/strapi-plugin-users-permissions/config/functions/bootstrap.js +++ b/packages/strapi-plugin-users-permissions/config/functions/bootstrap.js @@ -11,19 +11,6 @@ const _ = require('lodash'); const uuid = require('uuid/v4'); module.exports = async () => { - if (!_.get(strapi.plugins['users-permissions'], 'config.jwtSecret')) { - const jwtSecret = uuid(); - _.set(strapi.plugins['users-permissions'], 'config.jwtSecret', jwtSecret); - - strapi.reload.isWatching = false; - await strapi.fs.writePluginFile( - 'users-permissions', - 'config/jwt.json', - JSON.stringify({ jwtSecret }, null, 2) - ); - strapi.reload.isWatching = true; - } - const pluginStore = strapi.store({ environment: '', type: 'plugin', @@ -173,7 +160,22 @@ module.exports = async () => { await pluginStore.set({ key: 'advanced', value }); } - return strapi.plugins[ + await strapi.plugins[ 'users-permissions' ].services.userspermissions.initialize(); + + if (!_.get(strapi.plugins['users-permissions'], 'config.jwtSecret')) { + const jwtSecret = uuid(); + _.set(strapi.plugins['users-permissions'], 'config.jwtSecret', jwtSecret); + + strapi.reload.isWatching = false; + + await strapi.fs.writePluginFile( + 'users-permissions', + 'config/jwt.json', + JSON.stringify({ jwtSecret }, null, 2) + ); + + strapi.reload.isWatching = true; + } }; diff --git a/packages/strapi-plugin-users-permissions/services/UsersPermissions.js b/packages/strapi-plugin-users-permissions/services/UsersPermissions.js index 46bbfff641..788c4ae134 100644 --- a/packages/strapi-plugin-users-permissions/services/UsersPermissions.js +++ b/packages/strapi-plugin-users-permissions/services/UsersPermissions.js @@ -474,18 +474,17 @@ module.exports = { } // Create two first default roles. - await Promise.all([ - strapi.query('role', 'users-permissions').create({ - name: 'Authenticated', - description: 'Default role given to authenticated user.', - type: 'authenticated', - }), - strapi.query('role', 'users-permissions').create({ - name: 'Public', - description: 'Default role given to unauthenticated user.', - type: 'public', - }), - ]); + await strapi.query('role', 'users-permissions').create({ + name: 'Authenticated', + description: 'Default role given to authenticated user.', + type: 'authenticated', + }); + + await strapi.query('role', 'users-permissions').create({ + name: 'Public', + description: 'Default role given to unauthenticated user.', + type: 'public', + }); return this.updatePermissions(); }, diff --git a/packages/strapi/lib/Strapi.js b/packages/strapi/lib/Strapi.js index b6b9a8918b..887f7bc978 100644 --- a/packages/strapi/lib/Strapi.js +++ b/packages/strapi/lib/Strapi.js @@ -13,18 +13,9 @@ const chalk = require('chalk'); const CLITable = require('cli-table3'); const utils = require('./utils'); -const { - loadConfig, - loadApis, - loadAdmin, - loadPlugins, - loadMiddlewares, - loadHooks, - bootstrap, - loadExtensions, - initCoreStore, - loadComponents, -} = require('./core'); +const loadModules = require('./core/load-modules'); +const bootstrap = require('./core/bootstrap'); +const initCoreStore = require('./core/init-core-store'); const initializeMiddlewares = require('./middlewares'); const initializeHooks = require('./hooks'); const createStrapiFs = require('./core/fs'); @@ -304,51 +295,16 @@ class Strapi extends EventEmitter { } }); - const [ - config, - api, - admin, - plugins, - middlewares, - hook, - extensions, - components, - ] = await Promise.all([ - loadConfig(this), - loadApis(this), - loadAdmin(this), - loadPlugins(this), - loadMiddlewares(this), - loadHooks(this.config), - loadExtensions(this.config), - loadComponents(this), - ]); + const modules = await loadModules(this); - _.merge(this.config, config); + _.merge(this.config, modules.config); - this.api = api; - this.admin = admin; - this.components = components; - this.plugins = plugins; - this.middleware = middlewares; - this.hook = hook; - - /** - * Handle plugin extensions - */ - // merge extensions config folders - _.mergeWith(this.plugins, extensions.merges, (objValue, srcValue, key) => { - // concat routes - if (_.isArray(srcValue) && _.isArray(objValue) && key === 'routes') { - return srcValue.concat(objValue); - } - }); - // overwrite plugins with extensions overwrites - extensions.overwrites.forEach(({ path, mod }) => { - _.assign(_.get(this.plugins, path), mod); - }); - - // Populate AST with configurations. + this.api = modules.api; + this.admin = modules.admin; + this.components = modules.components; + this.plugins = modules.plugins; + this.middleware = modules.middlewares; + this.hook = modules.hook; await bootstrap(this); diff --git a/packages/strapi/lib/core/bootstrap.js b/packages/strapi/lib/core/bootstrap.js index 08f7a93efe..9a35c6feb6 100644 --- a/packages/strapi/lib/core/bootstrap.js +++ b/packages/strapi/lib/core/bootstrap.js @@ -5,9 +5,11 @@ const _ = require('lodash'); const { createController, createService } = require('../core-api'); const getURLFromSegments = require('../utils/url-from-segments'); -const pickSchema = obj => - _.cloneDeep( - _.pick(obj, [ +const getKind = obj => obj.kind || 'collectionType'; + +const pickSchema = model => { + const schema = _.cloneDeep( + _.pick(model, [ 'connection', 'collectionName', 'info', @@ -16,6 +18,10 @@ const pickSchema = obj => ]) ); + schema.kind = getKind(model); + return schema; +}; + module.exports = function(strapi) { // Retrieve Strapi version. strapi.config.uuid = _.get(strapi.config.info, 'strapi.uuid', ''); @@ -75,10 +81,12 @@ module.exports = function(strapi) { Object.assign(model, { __schema__: pickSchema(model), + kind: getKind(model), modelType: 'contentType', uid: `application::${apiName}.${modelName}`, apiName, modelName, + globalId: model.globalId || _.upperFirst(_.camelCase(modelName)), collectionName: model.collectionName || `${modelName}`.toLocaleLowerCase(), @@ -157,6 +165,7 @@ module.exports = function(strapi) { Object.assign(model, { __schema__: pickSchema(model), modelType: 'contentType', + kind: getKind(model), uid: `strapi::${key}`, plugin: 'admin', modelName: key, @@ -192,6 +201,7 @@ module.exports = function(strapi) { Object.assign(model, { __schema__: pickSchema(model), modelType: 'contentType', + kind: getKind(model), modelName: key, uid: `plugins::${pluginName}.${key}`, plugin: pluginName, diff --git a/packages/strapi/lib/core/index.js b/packages/strapi/lib/core/index.js deleted file mode 100644 index 72f750c432..0000000000 --- a/packages/strapi/lib/core/index.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; - -const loadConfig = require('./load-config'); -const loadApis = require('./load-apis'); -const loadAdmin = require('./load-admin'); -const loadPlugins = require('./load-plugins'); -const loadMiddlewares = require('./load-middlewares'); -const loadExtensions = require('./load-extensions'); -const loadHooks = require('./load-hooks'); -const bootstrap = require('./bootstrap'); -const initCoreStore = require('./init-core-store'); -const loadComponents = require('./load-components'); - -module.exports = { - loadConfig, - loadApis, - loadAdmin, - loadPlugins, - loadMiddlewares, - loadHooks, - loadExtensions, - loadComponents, - bootstrap, - initCoreStore, -}; diff --git a/packages/strapi/lib/core/load-modules.js b/packages/strapi/lib/core/load-modules.js new file mode 100644 index 0000000000..f28a9d42ae --- /dev/null +++ b/packages/strapi/lib/core/load-modules.js @@ -0,0 +1,73 @@ +/** + * Load Modules is the root module loader. + * This is where all the strapi enviornment is laoded + * - APIs + * - Plugins + * - Hooks + * - Middlewres + * - Components + * - ContentTypes + */ +'use strict'; + +const _ = require('lodash'); + +const loadConfig = require('./load-config'); +const loadApis = require('./load-apis'); +const loadAdmin = require('./load-admin'); +const loadPlugins = require('./load-plugins'); +const loadMiddlewares = require('./load-middlewares'); +const loadExtensions = require('./load-extensions'); +const loadHooks = require('./load-hooks'); +const loadComponents = require('./load-components'); + +module.exports = async strapi => { + const [ + config, + api, + admin, + plugins, + middlewares, + hook, + extensions, + components, + ] = await Promise.all([ + loadConfig(strapi), + loadApis(strapi), + loadAdmin(strapi), + loadPlugins(strapi), + loadMiddlewares(strapi), + loadHooks(strapi.config), + loadExtensions(strapi.config), + loadComponents(strapi), + ]); + + // TODO: move this into the appropriate loaders + + /** + * Handle plugin extensions + */ + // merge extensions config folders + _.mergeWith(plugins, extensions.merges, (objValue, srcValue, key) => { + // concat routes + if (_.isArray(srcValue) && _.isArray(objValue) && key === 'routes') { + return srcValue.concat(objValue); + } + }); + + // overwrite plugins with extensions overwrites + extensions.overwrites.forEach(({ path, mod }) => { + _.assign(_.get(plugins, path), mod); + }); + + return { + config, + api, + admin, + plugins, + middlewares, + hook, + extensions, + components, + }; +}; diff --git a/packages/strapi/lib/load/load-files.js b/packages/strapi/lib/load/load-files.js index 4dab6aef39..33143bb6c8 100644 --- a/packages/strapi/lib/load/load-files.js +++ b/packages/strapi/lib/load/load-files.js @@ -1,8 +1,8 @@ 'use strict'; const path = require('path'); -const glob = require('./glob'); const _ = require('lodash'); +const glob = require('./glob'); const filePathToPath = require('./filepath-to-prop-path'); /**