Expose "get actions as map" & update sync actions

Co-authored-by: Ben Irvin <innerdvations@users.noreply.github.com>
This commit is contained in:
Convly 2022-08-23 16:02:45 +02:00
parent cb87200099
commit 6abea9cd85
4 changed files with 70 additions and 31 deletions

View File

@ -454,7 +454,7 @@ class Strapi {
await this.runLifecyclesFunctions(LIFECYCLES.BOOTSTRAP);
// TODO: is this the best place for this?
await this.contentAPI.permissions.syncActions();
await this.contentAPI.permissions.registerActions();
this.cron.start();

View File

@ -1,6 +1,6 @@
'use strict';
const { uniq } = require('lodash');
const _ = require('lodash');
const permissions = require('./permissions');
/**
@ -30,30 +30,70 @@ const createContentAPI = (/* strapi */) => {
condition: permissions.providers.createConditionProvider(),
};
const syncActions = async () => {
// Register actions
const apiRoutesName = Object.values(strapi.api)
.map((api) => api.routes)
.reduce((acc, routesMap) => {
const routes = Object.values(routesMap)
// Only content api routes
.filter((p) => p.type === 'content-api')
// Resolve every handler name for each route
.reduce((a, p) => a.concat(p.routes.map((i) => i.handler)), []);
return acc.concat(routes);
}, []);
const pluginsRoutesname = Object.values(strapi.plugins)
.map((plugin) => plugin.routes['content-api'] || {})
.map((p) => (p.routes || []).map((i) => i.handler))
.flat();
const actions = apiRoutesName.concat(pluginsRoutesname);
Promise.all(
uniq(actions).map((action) =>
providers.action.register(action).catch(() => {
strapi.log.warn(`Trying to add action that already exists: ${action}`);
})
)
);
const getActionsMap = () => {
const actionMap = {};
const isContentApi = (action) => {
if (!_.has(action, Symbol.for('__type__'))) {
return false;
}
return action[Symbol.for('__type__')].includes('content-api');
};
const registerAPIsActions = (apis, source) => {
_.forEach(apis, (api, apiName) => {
const controllers = _.reduce(
api.controllers,
(acc, controller, controllerName) => {
const contentApiActions = _.pickBy(controller, isContentApi);
if (_.isEmpty(contentApiActions)) {
return acc;
}
acc[controllerName] = Object.keys(contentApiActions);
return acc;
},
{}
);
if (!_.isEmpty(controllers)) {
actionMap[`${source}::${apiName}`] = { controllers };
}
});
};
registerAPIsActions(strapi.api, 'api');
registerAPIsActions(strapi.plugins, 'plugin');
return actionMap;
};
const registerActions = async () => {
const actionsMap = getActionsMap();
// For each API
for (const [api, value] of Object.entries(actionsMap)) {
const { controllers } = value;
// Register controllers methods as actions
for (const [controller, actions] of Object.entries(controllers)) {
// Register each action individually
await Promise.all(
actions.map((action) => {
const actionUID = `${api}.${controller}.${action}`;
return providers.action
.register(actionUID, { api, controller, action, uid: actionUID })
.catch(() => {
strapi.log.warn(`Trying to add action that already exists: ${actionUID}`);
});
})
);
}
}
};
// create permission engine
@ -65,7 +105,8 @@ const createContentAPI = (/* strapi */) => {
permissions: {
engine,
providers,
syncActions,
registerActions,
getActionsMap,
},
};
};

View File

@ -8,12 +8,12 @@ module.exports = (options = {}) => {
return {
...provider,
async register(action) {
async register(action, payload) {
if (strapi.isLoaded) {
throw new Error(`You can't register new actions outside the bootstrap function.`);
}
return provider.register(action, { name: action });
return provider.register(action, payload);
},
};
};

View File

@ -171,8 +171,6 @@ module.exports = ({ strapi }) => ({
const toDelete = _.difference(permissionsFoundInDB, allActions);
// NOTE: actions are registered in content API bootstrap syncActions
await Promise.all(
toDelete.map((action) => {
return strapi.query('plugin::users-permissions.permission').delete({ where: { action } });