mirror of
https://github.com/strapi/strapi.git
synced 2025-08-26 09:42:09 +00:00

* Add a domain layer for the permission, rework the engine handling of the permissions Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Add permissions-fields-to-properties migration for the admin Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Removes useless console.log Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Remove debug logLevel from provider-login.test.e2e.js Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Adds the new layout for the GET permissions, allow to subscribe to actionRegistered events, adds i18n handlers Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix typo Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Update permissions validators Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Update unit tests Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Update integrations test + fix some validation issues Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Change plugins & settings section format for the permissions layout * only return locales property to localized subjects for the permission's layout * Do not send the locales property to the permission's layout when there is no locales created * Add the 'locales' property to publish & delete routes * Fix unwanted mutation of the sections builder states on multiple builds * Fix units tests with (new engine) * Fix admin-role e2e test - Add locales property to the update payload * fix e2e testsé * Update e2e snapshots * Fix unit test for i18n bootstrap * Add mocks for i18n/bootstrap test * Fix has-locale condition & updatePermission validator * Avoid mutation in migration, always authorize super admin for has-locales condition * Rework rbac domain objects, add a hook module and a provider factory * Remove old providers * Update the admin services & tests for the new rbac domain & providers * Fix tests, bootstrap functions & services following rbac domain rework * Update migration runner * PR comments Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Remove useless console.log * Fix sanitizeCondition bug * Section builder rework * Add test for the section-builder section & add jsdoc for the permission domain * pr comments (without the migrations) * fix fields-to-properties migration * Add jsdoc for the sections-builder * Moves createBoundAbstractDomain from permission domain to the engine service * Remove debug logLevel for admin role test (e2e) * Fix core-store * Fix hooks & move business logic from i18n bootstrap to dedicated services * add route get-non-localized-fields * use write and read permission * refacto * add input validator * add route doc * handle ST Co-authored-by: Pierre Noël <petersg83@gmail.com> Co-authored-by: Alexandre BODIN <alexandrebodin@users.noreply.github.com>
216 lines
5.7 KiB
JavaScript
216 lines
5.7 KiB
JavaScript
'use strict';
|
|
|
|
const {
|
|
flatMap,
|
|
reject,
|
|
isNil,
|
|
isArray,
|
|
prop,
|
|
xor,
|
|
uniq,
|
|
map,
|
|
difference,
|
|
differenceWith,
|
|
pipe,
|
|
} = require('lodash/fp');
|
|
const pmap = require('p-map');
|
|
const { EDITOR_CODE } = require('../constants');
|
|
const { getBoundActionsBySubject, BOUND_ACTIONS_FOR_FIELDS } = require('../../domain/role');
|
|
const { getService } = require('../../utils');
|
|
const permissionDomain = require('../../domain/permission/index');
|
|
|
|
/**
|
|
* Delete permissions of roles in database
|
|
* @param rolesIds ids of roles
|
|
* @returns {Promise<array>}
|
|
*/
|
|
const deleteByRolesIds = async rolesIds => {
|
|
const deletedPermissions = await strapi
|
|
.query('permission', 'admin')
|
|
.delete({ role_in: rolesIds });
|
|
|
|
return permissionDomain.toPermission(deletedPermissions);
|
|
};
|
|
|
|
/**
|
|
* Delete permissions
|
|
* @param ids ids of permissions
|
|
* @returns {Promise<array>}
|
|
*/
|
|
const deleteByIds = async ids => {
|
|
const deletedPermissions = await strapi.query('permission', 'admin').delete({ id_in: ids });
|
|
|
|
return permissionDomain.toPermission(deletedPermissions);
|
|
};
|
|
|
|
/**
|
|
* Create many permissions
|
|
* @param permissions
|
|
* @returns {Promise<*[]|*>}
|
|
*/
|
|
const createMany = async permissions => {
|
|
const createdPermissions = await strapi.query('permission', 'admin').createMany(permissions);
|
|
|
|
return permissionDomain.toPermission(createdPermissions);
|
|
};
|
|
|
|
/**
|
|
* Update a permission
|
|
* @returns {Promise<*[]|*>}
|
|
* @param params
|
|
* @param attributes
|
|
*/
|
|
const update = async (params, attributes) => {
|
|
const updatedPermissions = await strapi.query('permission', 'admin').update(params, attributes);
|
|
|
|
return permissionDomain.toPermission(updatedPermissions);
|
|
};
|
|
|
|
/**
|
|
* Find assigned permissions in the database
|
|
* @param params query params to find the permissions
|
|
* @returns {Promise<Permission[]>}
|
|
*/
|
|
const find = async (params = {}) => {
|
|
const rawPermissions = await strapi.query('permission', 'admin').find(params, []);
|
|
|
|
return permissionDomain.toPermission(rawPermissions);
|
|
};
|
|
|
|
/**
|
|
* Find all permissions for a user
|
|
* @param roles
|
|
* @returns {Promise<Permission[]>}
|
|
*/
|
|
const findUserPermissions = async ({ roles }) => {
|
|
if (!isArray(roles)) {
|
|
return [];
|
|
}
|
|
|
|
return find({ role_in: roles.map(prop('id')), _limit: -1 });
|
|
};
|
|
|
|
/**
|
|
* Removes permissions in database that don't exist anymore
|
|
* @returns {Promise<>}
|
|
*/
|
|
const cleanPermissionsInDatabase = async () => {
|
|
const { actionProvider } = getService('permission');
|
|
const pageSize = 200;
|
|
let total = Infinity;
|
|
|
|
for (let page = 1; page * pageSize < total; page++) {
|
|
// 1. Find invalid permissions and collect their ID to delete them later
|
|
const { pagination, results } = await strapi
|
|
.query('permission', 'admin')
|
|
.findPage({ page, pageSize }, []);
|
|
|
|
total = pagination.total;
|
|
|
|
const permissions = permissionDomain.toPermission(results);
|
|
|
|
const permissionsIdToRemove = permissions.reduce((ids, permission) => {
|
|
const isRegisteredAction = actionProvider.has(permission.action);
|
|
|
|
const { subjects } = actionProvider.get(permission.action) || {};
|
|
const isInvalidSubject = isArray(subjects) && !subjects.includes(permission.subject);
|
|
|
|
// If the permission has an invalid action or an invalid subject, then add it to the toBeRemoved collection
|
|
if (!isRegisteredAction || isInvalidSubject) {
|
|
ids.push(permission.id);
|
|
}
|
|
|
|
return ids;
|
|
}, []);
|
|
|
|
// 2. Clean permissions' fields (add required ones, remove the non-existing ones)
|
|
const remainingPermissions = permissions.filter(
|
|
permission => !permissionsIdToRemove.includes(permission.id)
|
|
);
|
|
const permissionsWithCleanFields = getService('content-type').cleanPermissionFields(
|
|
remainingPermissions
|
|
);
|
|
|
|
// Update only the ones that need to be updated
|
|
const permissionsNeedingToBeUpdated = differenceWith(
|
|
(a, b) => {
|
|
return a.id === b.id && xor(a.properties.fields, b.properties.fields).length === 0;
|
|
},
|
|
permissionsWithCleanFields,
|
|
remainingPermissions
|
|
);
|
|
|
|
const updatePromiseProvider = permission => {
|
|
return update({ id: permission.id }, permission);
|
|
};
|
|
|
|
// Execute all the queries, update the database
|
|
await Promise.all([
|
|
deleteByIds(permissionsIdToRemove),
|
|
pmap(permissionsNeedingToBeUpdated, updatePromiseProvider, {
|
|
concurrency: 100,
|
|
stopOnError: true,
|
|
}),
|
|
]);
|
|
}
|
|
};
|
|
|
|
const ensureBoundPermissionsInDatabase = async () => {
|
|
if (strapi.EE) {
|
|
return;
|
|
}
|
|
|
|
const contentTypes = Object.values(strapi.contentTypes);
|
|
const editorRole = await strapi.query('role', 'admin').findOne({ code: EDITOR_CODE }, []);
|
|
|
|
if (isNil(editorRole)) {
|
|
return;
|
|
}
|
|
|
|
for (const contentType of contentTypes) {
|
|
const boundActions = getBoundActionsBySubject(editorRole, contentType.uid);
|
|
|
|
const permissions = await find({
|
|
subject: contentType.uid,
|
|
action_in: boundActions,
|
|
role: editorRole.id,
|
|
});
|
|
|
|
if (permissions.length === 0) {
|
|
return;
|
|
}
|
|
|
|
const fields = pipe(
|
|
flatMap(permissionDomain.getProperty('fields')),
|
|
reject(isNil),
|
|
uniq
|
|
)(permissions);
|
|
|
|
// Handle the scenario where permissions are missing
|
|
const missingActions = difference(map('action', permissions), boundActions);
|
|
|
|
if (missingActions.length > 0) {
|
|
const permissions = missingActions.map(action => ({
|
|
action,
|
|
subject: contentType.uid,
|
|
properties: {
|
|
fields: BOUND_ACTIONS_FOR_FIELDS.includes(action) ? fields : null,
|
|
},
|
|
role: editorRole.id,
|
|
}));
|
|
|
|
await createMany(permissions);
|
|
}
|
|
}
|
|
};
|
|
|
|
module.exports = {
|
|
createMany,
|
|
find,
|
|
deleteByRolesIds,
|
|
deleteByIds,
|
|
findUserPermissions,
|
|
cleanPermissionsInDatabase,
|
|
ensureBoundPermissionsInDatabase,
|
|
};
|