diff --git a/examples/getstarted/api/country/models/Country.settings.json b/examples/getstarted/api/country/models/Country.settings.json index fd54aa3efd..229a51aa23 100755 --- a/examples/getstarted/api/country/models/Country.settings.json +++ b/examples/getstarted/api/country/models/Country.settings.json @@ -5,23 +5,39 @@ "displayName": "Country", "singularName": "country", "pluralName": "countries", - "description": "" + "description": "", + "name": "Country" }, "options": { "draftAndPublish": false, "comment": "" }, + "pluginOptions": { + "i18n": { + "localized": true + } + }, "attributes": { "name": { "type": "string", "required": true, - "minLength": 3 + "minLength": 3, + "pluginOptions": { + "i18n": { + "localized": true + } + } }, "code": { "type": "string", "maxLength": 3, "unique": true, - "minLength": 2 + "minLength": 2, + "pluginOptions": { + "i18n": { + "localized": true + } + } } } } diff --git a/examples/getstarted/config/functions/register.js b/examples/getstarted/config/functions/register.js new file mode 100644 index 0000000000..81a7f05c45 --- /dev/null +++ b/examples/getstarted/config/functions/register.js @@ -0,0 +1,10 @@ +'use strict'; + +/** + * An asynchronous register function that runs before + * your application is loaded. + * + * This gives you an opportunity to extend code. + */ + +module.exports = () => {}; diff --git a/packages/core/strapi/lib/Strapi.js b/packages/core/strapi/lib/Strapi.js index 92968913b1..bd5d5b0f33 100644 --- a/packages/core/strapi/lib/Strapi.js +++ b/packages/core/strapi/lib/Strapi.js @@ -165,7 +165,7 @@ class Strapi { async openAdmin({ isInitialized }) { const shouldOpenAdmin = - this.config.environment === 'development' && + this.config.get('environment') === 'development' && this.config.get('server.admin.autoOpen', true) !== false; if (shouldOpenAdmin || !isInitialized) { @@ -302,7 +302,7 @@ class Strapi { await this.db.schema.sync(); this.store = createCoreStore({ - environment: this.config.environment, + environment: this.config.get('environment'), db: this.db, }); diff --git a/packages/core/strapi/lib/core/bootstrap.js b/packages/core/strapi/lib/core/bootstrap.js index 60807c5e9f..18210109fd 100644 --- a/packages/core/strapi/lib/core/bootstrap.js +++ b/packages/core/strapi/lib/core/bootstrap.js @@ -33,9 +33,10 @@ module.exports = function(strapi) { const allApisSchemas = Object.values(strapi.api).flatMap(api => Object.values(api.models)); validateContentTypesUnicity(allApisSchemas); - // set default services and default controllers + // add user's content-types, controller and services for (const apiName in strapi.api) { const api = strapi.api[apiName]; + _.defaultsDeep(api, { config: { routes: [] } }); // TODO: remove V4 for (const modelName in api.models) { const model = api.models[modelName]; model.info.displayName = model.info.displayName || model.info.name; @@ -45,31 +46,18 @@ module.exports = function(strapi) { strapi.container.get('content-types').add(`api::${apiName}`, { [modelName]: { schema: model, actions: model.actions, lifecycles: model.lifecycles }, }); - const contentType = strapi.contentType(`api::${apiName}.${modelName}`); const { service, controller } = createCoreApi({ model: contentType, api, strapi }); + // TODO: remove V4 _.set(strapi.api[apiName], ['services', modelName], service); _.set(strapi.api[apiName], ['controllers', modelName], controller); + + strapi.container.get('controllers').add(`api::${apiName}`, { [modelName]: controller }); + strapi.container.get('services').add(`api::${apiName}`, { [modelName]: service }); } } - // Set user's controllers. - strapi.controllers = Object.keys(strapi.api || []).reduce((acc, apiName) => { - strapi.container.get('controllers').add(`api::${apiName}`, strapi.api[apiName].controllers); - for (let controllerName in strapi.api[apiName].controllers) { - let controller = strapi.api[apiName].controllers[controllerName]; - acc[controllerName] = controller; - } - - return acc; - }, {}); - - // Set routes. - strapi.config.routes = Object.keys(strapi.api || []).reduce((acc, key) => { - return acc.concat(_.get(strapi.api[key], 'config.routes') || {}); - }, []); - // TODO: delete v3 code _.forEach(strapi.plugins, plugin => { _.forEach(plugin.middlewares, (middleware, middlewareUID) => { diff --git a/packages/core/strapi/lib/core/domain/module/index.js b/packages/core/strapi/lib/core/domain/module/index.js index 9633c468f5..8a3f6560ee 100644 --- a/packages/core/strapi/lib/core/domain/module/index.js +++ b/packages/core/strapi/lib/core/domain/module/index.js @@ -2,6 +2,8 @@ const { validateModule } = require('./validation'); +const uidToPath = uid => uid.replace('::', '.'); + const createModule = (namespace, rawModule, strapi) => { try { validateModule(rawModule); @@ -38,9 +40,12 @@ const createModule = (namespace, rawModule, strapi) => { strapi.container.get('policies').add(namespace, rawModule.policies); strapi.container.get('middlewares').add(namespace, rawModule.middlewares); strapi.container.get('controllers').add(namespace, rawModule.controllers); - strapi.container.get('config').set(namespace.replace('::', '.'), rawModule.config); + strapi.container.get('config').set(uidToPath(namespace), rawModule.config); }, routes: rawModule.routes, // TODO: to remove v3 + config(path) { + return strapi.container.get('config').get(`${uidToPath(namespace)}.${path}`); + }, contentType(ctName) { return strapi.container.get('content-types').get(`${namespace}.${ctName}`); }, diff --git a/packages/core/strapi/lib/core/registries/controllers.js b/packages/core/strapi/lib/core/registries/controllers.js index 09ef3b14cc..223c940484 100644 --- a/packages/core/strapi/lib/core/registries/controllers.js +++ b/packages/core/strapi/lib/core/registries/controllers.js @@ -3,7 +3,7 @@ const { pickBy, has } = require('lodash/fp'); const { addNamespace } = require('../utils'); -const policiesRegistry = () => { +const controllersRegistry = () => { const controllers = {}; return { @@ -24,7 +24,15 @@ const policiesRegistry = () => { controllers[uid] = controller; } }, + extend(controllerUID, extendFn) { + const currentController = this.get(controllerUID); + if (!currentController) { + throw new Error(`Controller ${controllerUID} doesn't exist`); + } + const newController = extendFn(currentController); + controllers[controllerUID] = newController; + }, }; }; -module.exports = policiesRegistry; +module.exports = controllersRegistry; diff --git a/packages/core/strapi/lib/core/registries/services.js b/packages/core/strapi/lib/core/registries/services.js index 6bc47010db..8e3b480646 100644 --- a/packages/core/strapi/lib/core/registries/services.js +++ b/packages/core/strapi/lib/core/registries/services.js @@ -4,7 +4,7 @@ const _ = require('lodash'); const { pickBy, has } = require('lodash/fp'); const { addNamespace } = require('../utils'); -const contentTypesRegistry = strapi => { +const servicesRegistry = strapi => { const services = {}; const instanciatedServices = {}; @@ -42,4 +42,4 @@ const contentTypesRegistry = strapi => { }; }; -module.exports = contentTypesRegistry; +module.exports = servicesRegistry; diff --git a/packages/core/strapi/lib/middlewares/router/index.js b/packages/core/strapi/lib/middlewares/router/index.js index e77ca4f9e4..20e82b7d51 100644 --- a/packages/core/strapi/lib/middlewares/router/index.js +++ b/packages/core/strapi/lib/middlewares/router/index.js @@ -6,6 +6,7 @@ // Public node modules. const _ = require('lodash'); +const { getOr } = require('lodash/fp'); const Router = require('koa-router'); const createEndpointComposer = require('./utils/composeEndpoint'); @@ -16,7 +17,7 @@ module.exports = strapi => { const router = new Router({ prefix: '/admin' }); for (const route of strapi.admin.routes) { - composeEndpoint(route, { plugin: 'admin', router }); + composeEndpoint(route, { pluginName: 'admin', router }); } strapi.app.use(router.routes()).use(router.allowedMethods()); @@ -31,7 +32,7 @@ module.exports = strapi => { for (const route of plugin.routes || []) { const hasPrefix = _.has(route.config, 'prefix'); composeEndpoint(route, { - plugin: pluginName, + pluginName, router: hasPrefix ? strapi.router : router, }); } @@ -41,15 +42,19 @@ module.exports = strapi => { }; const registerAPIRoutes = () => { - strapi.router.prefix(strapi.config.get('middleware.settings.router.prefix', '')); + for (const apiName in strapi.api) { + const api = strapi.api[apiName]; + const routes = getOr([], 'config.routes', api); - for (const route of strapi.config.routes) { - composeEndpoint(route, { router: strapi.router }); + for (const route of routes) { + composeEndpoint(route, { apiName, router: strapi.router }); + } } }; return { initialize() { + strapi.router.prefix(strapi.config.get('middleware.settings.router.prefix', '')); registerAPIRoutes(); registerAdminRoutes(); registerPluginRoutes(); diff --git a/packages/core/strapi/lib/middlewares/router/utils/composeEndpoint.js b/packages/core/strapi/lib/middlewares/router/utils/composeEndpoint.js index 29ddb83e22..ecf55001b3 100644 --- a/packages/core/strapi/lib/middlewares/router/utils/composeEndpoint.js +++ b/packages/core/strapi/lib/middlewares/router/utils/composeEndpoint.js @@ -2,7 +2,7 @@ const _ = require('lodash'); const compose = require('koa-compose'); -const { yup } = require('@strapi/utils'); +const { yup, policy: policyUtils } = require('@strapi/utils'); const policyOrMiddlewareSchema = yup.lazy(value => { if (typeof value === 'string') { @@ -62,19 +62,19 @@ const validateRouteConfig = routeConfig => { } }; -// Strapi utilities. -const { finder, policy: policyUtils } = require('@strapi/utils'); - module.exports = strapi => { const routerChecker = createRouteChecker(strapi); - return (routeConfig, { plugin, router }) => { + return (routeConfig, { pluginName, router, apiName }) => { validateRouteConfig(routeConfig); try { const middlewares = resolveMiddlewares(routeConfig); - const { method, endpoint, policies, action } = routerChecker(routeConfig, plugin); + const { method, endpoint, policies, action } = routerChecker(routeConfig, { + pluginName, + apiName, + }); if (_.isUndefined(action) || !_.isFunction(action)) { return strapi.log.warn( @@ -113,7 +113,7 @@ const getMethod = route => _.trim(_.toLower(route.method)); const getEndpoint = route => _.trim(route.path); const createRouteChecker = strapi => { - return (value, plugin) => { + return (value, { pluginName, apiName }) => { const method = getMethod(value); const endpoint = getEndpoint(value); @@ -123,16 +123,15 @@ const createRouteChecker = strapi => { let controller; - if (plugin) { - if (plugin === 'admin') { + if (pluginName) { + if (pluginName === 'admin') { controller = strapi.admin.controllers[controllerKey]; } else { - controller = strapi.plugin(plugin).controller(controllerKey); + controller = strapi.plugin(pluginName).controller(controllerKey); } } else { - controller = strapi.controllers[controllerKey]; + controller = strapi.container.get('controllers').get(`api::${apiName}.${controllerKey}`); } - if (!_.isFunction(controller[actionName])) { strapi.stopWithError( `Error creating endpoint ${method} ${endpoint}: handler not found "${controllerKey}.${actionName}"` @@ -141,13 +140,6 @@ const createRouteChecker = strapi => { const action = controller[actionName].bind(controller); - // Retrieve the API's name where the controller is located - // to access to the right validators - const currentApiName = finder( - strapi.plugin(plugin) || strapi.api || strapi.admin, - controllerKey - ); - const { bodyPolicy } = policyUtils; const globalPolicy = policyUtils.globalPolicy({ @@ -155,13 +147,13 @@ const createRouteChecker = strapi => { action: actionName, method, endpoint, - plugin, + plugin: pluginName, }); const policyOption = _.get(value, 'config.policies', []); const routePolicies = policyOption.map(policyConfig => { - return policyUtils.get(policyConfig, plugin, currentApiName); + return policyUtils.get(policyConfig, { pluginName, apiName }); }); // Init policies array. diff --git a/packages/core/utils/lib/finder.js b/packages/core/utils/lib/finder.js deleted file mode 100644 index bb005cdf23..0000000000 --- a/packages/core/utils/lib/finder.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -/** - * Module dependencies - */ - -const _ = require('lodash'); - -/** - * Find controller's location - */ - -module.exports = (api, controller) => { - if (!_.isObject(api)) { - throw new Error('Should be an object'); - } - if (_.isString(controller)) { - controller = controller.toLowerCase(); - } else { - throw new Error('Should be an object or a string'); - } - - const where = _.findKey(api, o => { - return _.get(o, `controllers.${controller}`); - }); - - // Return the API's name where the controller is located - return where; -}; diff --git a/packages/core/utils/lib/index.js b/packages/core/utils/lib/index.js index d6d38554bd..0eaeb93576 100644 --- a/packages/core/utils/lib/index.js +++ b/packages/core/utils/lib/index.js @@ -12,7 +12,6 @@ const { const parseMultipartData = require('./parse-multipart'); const sanitizeEntity = require('./sanitize-entity'); const parseType = require('./parse-type'); -const finder = require('./finder'); const policy = require('./policy'); const templateConfiguration = require('./template-configuration'); const { yup, formatYupErrors } = require('./validators'); @@ -40,7 +39,6 @@ const providerFactory = require('./provider-factory'); module.exports = { yup, formatYupErrors, - finder, policy, templateConfiguration, convertRestQueryParams, diff --git a/packages/core/utils/lib/policy.js b/packages/core/utils/lib/policy.js index 37e19ec65b..615c09399f 100644 --- a/packages/core/utils/lib/policy.js +++ b/packages/core/utils/lib/policy.js @@ -38,7 +38,7 @@ const resolvePolicy = policyName => { return resolver ? resolveHandler(resolver.get)(policyName) : undefined; }; -const searchLocalPolicy = (policy, plugin, apiName) => { +const searchLocalPolicy = (policy, { pluginName, apiName }) => { let [absoluteApiName, policyName] = policy.split('.'); let absoluteApi = _.get(strapi.api, absoluteApiName); const resolver = policyResolvers.find(({ name }) => name === 'plugin'); @@ -47,9 +47,9 @@ const searchLocalPolicy = (policy, plugin, apiName) => { return resolveHandler(getPolicyIn(absoluteApi, policyName)); } - const pluginPolicy = `${PLUGIN_PREFIX}${plugin}.${policy}`; + const pluginPolicy = `${PLUGIN_PREFIX}${pluginName}.${policy}`; - if (plugin && resolver.exists(pluginPolicy)) { + if (pluginName && resolver.exists(pluginPolicy)) { return resolveHandler(resolver.get(pluginPolicy)); } @@ -137,7 +137,7 @@ const policyResolvers = [ }, ]; -const get = (policy, plugin, apiName) => { +const get = (policy, { pluginName, apiName }) => { if (typeof policy === 'function') { return policy; } @@ -150,7 +150,7 @@ const get = (policy, plugin, apiName) => { return _.isPlainObject(policy) ? resolvedPolicy(args) : resolvedPolicy; } - const localPolicy = searchLocalPolicy(policy, plugin, apiName); + const localPolicy = searchLocalPolicy(policy, { pluginName, apiName }); if (localPolicy !== undefined) { return localPolicy; diff --git a/packages/plugins/i18n/server/services/core-api.js b/packages/plugins/i18n/server/services/core-api.js index 7acfa86f63..b618fd0580 100644 --- a/packages/plugins/i18n/server/services/core-api.js +++ b/packages/plugins/i18n/server/services/core-api.js @@ -199,21 +199,12 @@ const addCreateLocalizationAction = contentType => { const localizationRoute = createLocalizationRoute(contentType); - strapi.config.routes.push(localizationRoute); + strapi.api[apiName].config.routes.push(localizationRoute); - // TODO: to replace with: - // strapi.controllers.extends(`api::${apiName}.${modelName}`, (contr) => ({ - // ...controller, - // createLocalization = createLocalizationHandler(contentType), - // })); - // OR - // strapi.api(apiName).controllers.extends(modelName, (contr) => ({ - // ...controller, - // createLocalization = createLocalizationHandler(contentType), - // })); - - const controller = strapi.container.get('controllers').get(`api::${apiName}.${modelName}`); - controller.createLocalization = createLocalizationHandler(contentType); + strapi.container.get('controllers').extend(`api::${apiName}.${modelName}`, controller => ({ + ...controller, + createLocalization: createLocalizationHandler(contentType), + })); }; const mergeCustomizer = (dest, src) => { diff --git a/packages/plugins/users-permissions/server/middlewares/users-permissions.js b/packages/plugins/users-permissions/server/middlewares/users-permissions.js index e43b173bc3..aaf5e4ddcc 100644 --- a/packages/plugins/users-permissions/server/middlewares/users-permissions.js +++ b/packages/plugins/users-permissions/server/middlewares/users-permissions.js @@ -1,6 +1,7 @@ 'use strict'; const _ = require('lodash'); +const { getOr } = require('lodash/fp'); module.exports = { defaults: { 'users-permissions': { enabled: true } }, @@ -16,10 +17,13 @@ module.exports = { } }); - _.forEach(strapi.config.routes, value => { - if (_.get(value.config, 'policies')) { - value.config.policies.unshift('plugin::users-permissions.permissions'); - } + _.forEach(strapi.api, api => { + const routes = getOr([], 'config.routes', api); + _.forEach(routes, route => { + if (_.get(route.config, 'policies')) { + route.config.policies.unshift('plugin::users-permissions.permissions'); + } + }); }); if (strapi.plugins) {