diff --git a/packages/strapi-admin/admin/src/components/Roles/Permissions/index.js b/packages/strapi-admin/admin/src/components/Roles/Permissions/index.js index b5d4b4a002..dd89bf1c4b 100644 --- a/packages/strapi-admin/admin/src/components/Roles/Permissions/index.js +++ b/packages/strapi-admin/admin/src/components/Roles/Permissions/index.js @@ -10,9 +10,9 @@ import formatPermissionsToAPI from './utils/formatPermissionsToAPI'; import init from './init'; import reducer, { initialState } from './reducer'; -const Permissions = forwardRef(({ layout, isFormDisabled }, ref) => { +const Permissions = forwardRef(({ layout, isFormDisabled, permissions }, ref) => { const [{ layouts, modifiedData }, dispatch] = useReducer(reducer, initialState, () => - init(layout) + init(layout, permissions) ); useImperativeHandle(ref, () => { @@ -112,11 +112,13 @@ const Permissions = forwardRef(({ layout, isFormDisabled }, ref) => { }); Permissions.defaultProps = { + permissions: [], layout, }; Permissions.propTypes = { layout: PropTypes.object, isFormDisabled: PropTypes.bool.isRequired, + permissions: PropTypes.array, }; export default memo(Permissions); diff --git a/packages/strapi-admin/admin/src/components/Roles/Permissions/init.js b/packages/strapi-admin/admin/src/components/Roles/Permissions/init.js index 22f21383c0..193d571ba1 100644 --- a/packages/strapi-admin/admin/src/components/Roles/Permissions/init.js +++ b/packages/strapi-admin/admin/src/components/Roles/Permissions/init.js @@ -2,7 +2,7 @@ import createDefaultCTFormFromLayout from './utils/createDefaultCTFormFromLayout import createDefaultPluginsFormFromLayout from './utils/createDefaultPluginsFormFromLayout'; import formatLayoutForSettingsAndPlugins from './utils/formatLayoutForSettingsAndPlugins'; -const init = layout => { +const init = (layout, permissions) => { const { conditions, sections: { collectionTypes, singleTypes, plugins, settings }, @@ -17,7 +17,8 @@ const init = layout => { collectionTypes: createDefaultCTFormFromLayout( collectionTypes, collectionTypes.actions || [], - conditions + conditions, + permissions ), singleTypes: createDefaultCTFormFromLayout(singleTypes, singleTypes.actions || [], conditions), plugins: createDefaultPluginsFormFromLayout(layouts.plugins, conditions), diff --git a/packages/strapi-admin/admin/src/components/Roles/Permissions/utils/createDefaultCTFormFromLayout.js b/packages/strapi-admin/admin/src/components/Roles/Permissions/utils/createDefaultCTFormFromLayout.js index 794e95705d..4830309957 100644 --- a/packages/strapi-admin/admin/src/components/Roles/Permissions/utils/createDefaultCTFormFromLayout.js +++ b/packages/strapi-admin/admin/src/components/Roles/Permissions/utils/createDefaultCTFormFromLayout.js @@ -1,13 +1,13 @@ -import { merge, isEmpty, set } from 'lodash'; +import { merge, get, isEmpty, set } from 'lodash'; /** * Creates the default condition form: { [conditionId]: false } * @param {object} conditions.id Id of the condition * @returns {object} */ -const createDefaultConditionsForm = conditions => +const createDefaultConditionsForm = (conditions, initialConditions = []) => conditions.reduce((acc, current) => { - acc[current.id] = false; + acc[current.id] = initialConditions.indexOf(current.id) !== -1; return acc; }, {}); @@ -16,16 +16,26 @@ const createDefaultConditionsForm = conditions => * Create the default form a property (fields, locales) with all the values * set to false * @param {object} property.children ex: {children: [{value: 'foo',}]} + * @param {array} The found property values retrieved from the role associated permissions * @returns {object} ex: { foo: false } * */ -const createDefaultPropertyForms = ({ children }) => { +const createDefaultPropertyForms = ({ children }, propertyValues, prefix = '') => { return children.reduce((acc, current) => { if (current.children) { - return { ...acc, [current.value]: createDefaultPropertyForms(current) }; + return { + ...acc, + [current.value]: createDefaultPropertyForms( + current, + propertyValues, + `${prefix}${current.value}.` + ), + }; } - acc[current.value] = false; + const hasProperty = propertyValues.indexOf(`${prefix}${current.value}`) !== -1; + + acc[current.value] = hasProperty; return acc; }, {}); @@ -43,12 +53,16 @@ const createDefaultPropertyForms = ({ children }) => { * } * @returns {object} In this case it will return { fields: { name: false } } */ -const createDefaultPropertiesForm = (propertiesArray, ctLayout) => { +const createDefaultPropertiesForm = (propertiesArray, ctLayout, matchingPermission) => { return propertiesArray.reduce((acc, currentPropertyName) => { const foundProperty = ctLayout.properties.find(({ value }) => value === currentPropertyName); if (foundProperty) { - const propertyForm = createDefaultPropertyForms(foundProperty); + const matchingPermissionPropertyValues = get(matchingPermission, foundProperty.value, []); + const propertyForm = createDefaultPropertyForms( + foundProperty, + matchingPermissionPropertyValues + ); acc[currentPropertyName] = propertyForm; } @@ -89,7 +103,12 @@ const findLayouts = (allLayouts, subjects) => { * } * } */ -const createDefaultCTFormFromLayout = ({ subjects }, actionArray, conditionArray) => { +const createDefaultCTFormFromLayout = ( + { subjects }, + actionArray, + conditionArray, + initialPermissions = [] +) => { return actionArray.reduce((defaultForm, current) => { const actionSubjects = current.subjects; @@ -105,17 +124,26 @@ const createDefaultCTFormFromLayout = ({ subjects }, actionArray, conditionArray // The object has the following shape: { [ctUID]: { [actionId]: { [property]: { enabled: false } } } } const contentTypesActions = Object.keys(subjectLayouts).reduce((acc, currentCTUID) => { const { actionId, applyToProperties } = current; - const conditionsForm = createDefaultConditionsForm(conditionArray); + + const matchingPermission = findMatchingPermission(initialPermissions, actionId, currentCTUID); + const conditionsForm = createDefaultConditionsForm( + conditionArray, + get(matchingPermission, 'conditions', []) + ); if (isEmpty(applyToProperties)) { - set(acc, [currentCTUID, actionId], { enabled: false, conditions: conditionsForm }); + set(acc, [currentCTUID, actionId], { + enabled: matchingPermission !== undefined, + conditions: conditionsForm, + }); return acc; } const propertiesForm = createDefaultPropertiesForm( applyToProperties, - subjectLayouts[currentCTUID] + subjectLayouts[currentCTUID], + matchingPermission ); set(acc, [currentCTUID, actionId], { ...propertiesForm, conditions: conditionsForm }); @@ -127,6 +155,9 @@ const createDefaultCTFormFromLayout = ({ subjects }, actionArray, conditionArray }, {}); }; +const findMatchingPermission = (permissions, action, subject) => + permissions.find(perm => perm.action === action && perm.subject === subject); + export default createDefaultCTFormFromLayout; export { createDefaultConditionsForm, diff --git a/packages/strapi-admin/admin/src/components/Roles/Permissions/utils/tests/createDefaultCTFormFromLayout.test.js b/packages/strapi-admin/admin/src/components/Roles/Permissions/utils/tests/createDefaultCTFormFromLayout.test.js index 2f426f70a8..c9e1ff1d83 100644 --- a/packages/strapi-admin/admin/src/components/Roles/Permissions/utils/tests/createDefaultCTFormFromLayout.test.js +++ b/packages/strapi-admin/admin/src/components/Roles/Permissions/utils/tests/createDefaultCTFormFromLayout.test.js @@ -20,7 +20,7 @@ const conditions = [ describe('ADMIN | COMPONENTS | Permissions | utils', () => { describe('createConditionForm', () => { - it('should return an object with all the values set to false', () => { + it('should return an object with all the leafs set to false', () => { const expected = { 'admin::is-creator': false, 'admin::has-same-role-as-creator': false, @@ -28,10 +28,21 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => { expect(createDefaultConditionsForm(conditions)).toEqual(expected); }); + + it('should return an object with the leafs set to true when the initial conditions contains the condition', () => { + const expected = { + 'admin::is-creator': false, + 'admin::has-same-role-as-creator': true, + }; + + expect( + createDefaultConditionsForm(conditions, ['test', 'admin::has-same-role-as-creator']) + ).toEqual(expected); + }); }); describe('createDefaultPropertyForms,', () => { - it('should return an object with keys corresponding to the property value and all the values set to false', () => { + it('should return an object with keys corresponding to the property value and all the leafs set to false', () => { const data = { children: [ { @@ -47,10 +58,10 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => { bar: false, }; - expect(createDefaultPropertyForms(data)).toEqual(expected); + expect(createDefaultPropertyForms(data, [])).toEqual(expected); }); - it('should create the default form for a complex object', () => { + it('should create the default form for a complex object when the second argument is not an empty array', () => { const data = { children: [ { @@ -74,17 +85,18 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => { }, ], }; + const propertyValues = ['foo', 'bar.foo.bar']; const expected = { - foo: false, + foo: true, bar: { name: false, foo: { - bar: false, + bar: true, }, }, }; - expect(createDefaultPropertyForms(data)).toEqual(expected); + expect(createDefaultPropertyForms(data, propertyValues)).toEqual(expected); }); }); @@ -286,6 +298,7 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => { ], }, ]; + const actions = [ { label: 'Create', @@ -312,12 +325,12 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => { fields: { postal_coder: false, categories: false, - cover: false, + cover: true, images: false, city: false, }, conditions: { - 'admin::is-creator': false, + 'admin::is-creator': true, 'admin::has-same-role-as-creator': false, }, }, @@ -336,10 +349,10 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => { f2: false, services: { name: false, media: false, closing: { name: { test: false } } }, dz: false, - relation: false, + relation: true, }, locales: { - en: false, + en: true, fr: false, }, conditions: { @@ -360,7 +373,25 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => { }, }; - expect(createDefaultCTFormFromLayout({ subjects }, actions, conditions)).toEqual(expected); + const permissions = [ + { + action: 'content-manager.explorer.create', + subject: 'restaurant', + fields: ['relation'], + locales: ['en'], + }, + { + action: 'content-manager.explorer.create', + subject: 'address', + fields: ['cover'], + locales: ['fr'], + conditions: ['admin::is-creator'], + }, + ]; + + expect(createDefaultCTFormFromLayout({ subjects }, actions, conditions, permissions)).toEqual( + expected + ); }); }); diff --git a/packages/strapi-admin/admin/src/containers/Roles/EditPage/index.js b/packages/strapi-admin/admin/src/containers/Roles/EditPage/index.js index 2ef8fb2971..72b2abad5f 100644 --- a/packages/strapi-admin/admin/src/containers/Roles/EditPage/index.js +++ b/packages/strapi-admin/admin/src/containers/Roles/EditPage/index.js @@ -36,7 +36,6 @@ const EditPage = () => { isLoading: isRoleLoading, onSubmitSucceeded, } = useFetchRole(id); - console.log({ rolePermissions }); /* eslint-disable indent */ const headerActions = (handleSubmit, handleReset) => @@ -177,7 +176,11 @@ const EditPage = () => { /> {!isLayoutLoading && !isRoleLoading && ( - + )}