add extend fn to controller registry

This commit is contained in:
Pierre Noël 2021-08-26 18:44:11 +02:00
parent 45100abdf7
commit 9362311924
14 changed files with 96 additions and 108 deletions

View File

@ -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
}
}
}
}
}

View File

@ -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 = () => {};

View File

@ -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,
});

View File

@ -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) => {

View File

@ -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}`);
},

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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.

View File

@ -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;
};

View File

@ -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,

View File

@ -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;

View File

@ -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) => {

View File

@ -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) {