Add logic to set the correct leaf when in edition

Signed-off-by: soupette <cyril.lpz@gmail.com>
This commit is contained in:
soupette 2021-02-19 17:34:52 +01:00
parent b256776fbb
commit d6e70a737d
5 changed files with 98 additions and 30 deletions

View File

@ -10,9 +10,9 @@ import formatPermissionsToAPI from './utils/formatPermissionsToAPI';
import init from './init'; import init from './init';
import reducer, { initialState } from './reducer'; 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, () => const [{ layouts, modifiedData }, dispatch] = useReducer(reducer, initialState, () =>
init(layout) init(layout, permissions)
); );
useImperativeHandle(ref, () => { useImperativeHandle(ref, () => {
@ -112,11 +112,13 @@ const Permissions = forwardRef(({ layout, isFormDisabled }, ref) => {
}); });
Permissions.defaultProps = { Permissions.defaultProps = {
permissions: [],
layout, layout,
}; };
Permissions.propTypes = { Permissions.propTypes = {
layout: PropTypes.object, layout: PropTypes.object,
isFormDisabled: PropTypes.bool.isRequired, isFormDisabled: PropTypes.bool.isRequired,
permissions: PropTypes.array,
}; };
export default memo(Permissions); export default memo(Permissions);

View File

@ -2,7 +2,7 @@ import createDefaultCTFormFromLayout from './utils/createDefaultCTFormFromLayout
import createDefaultPluginsFormFromLayout from './utils/createDefaultPluginsFormFromLayout'; import createDefaultPluginsFormFromLayout from './utils/createDefaultPluginsFormFromLayout';
import formatLayoutForSettingsAndPlugins from './utils/formatLayoutForSettingsAndPlugins'; import formatLayoutForSettingsAndPlugins from './utils/formatLayoutForSettingsAndPlugins';
const init = layout => { const init = (layout, permissions) => {
const { const {
conditions, conditions,
sections: { collectionTypes, singleTypes, plugins, settings }, sections: { collectionTypes, singleTypes, plugins, settings },
@ -17,7 +17,8 @@ const init = layout => {
collectionTypes: createDefaultCTFormFromLayout( collectionTypes: createDefaultCTFormFromLayout(
collectionTypes, collectionTypes,
collectionTypes.actions || [], collectionTypes.actions || [],
conditions conditions,
permissions
), ),
singleTypes: createDefaultCTFormFromLayout(singleTypes, singleTypes.actions || [], conditions), singleTypes: createDefaultCTFormFromLayout(singleTypes, singleTypes.actions || [], conditions),
plugins: createDefaultPluginsFormFromLayout(layouts.plugins, conditions), plugins: createDefaultPluginsFormFromLayout(layouts.plugins, conditions),

View File

@ -1,13 +1,13 @@
import { merge, isEmpty, set } from 'lodash'; import { merge, get, isEmpty, set } from 'lodash';
/** /**
* Creates the default condition form: { [conditionId]: false } * Creates the default condition form: { [conditionId]: false }
* @param {object} conditions.id Id of the condition * @param {object} conditions.id Id of the condition
* @returns {object} * @returns {object}
*/ */
const createDefaultConditionsForm = conditions => const createDefaultConditionsForm = (conditions, initialConditions = []) =>
conditions.reduce((acc, current) => { conditions.reduce((acc, current) => {
acc[current.id] = false; acc[current.id] = initialConditions.indexOf(current.id) !== -1;
return acc; return acc;
}, {}); }, {});
@ -16,16 +16,26 @@ const createDefaultConditionsForm = conditions =>
* Create the default form a property (fields, locales) with all the values * Create the default form a property (fields, locales) with all the values
* set to false * set to false
* @param {object} property.children ex: {children: [{value: 'foo',}]} * @param {object} property.children ex: {children: [{value: 'foo',}]}
* @param {array<string>} The found property values retrieved from the role associated permissions
* @returns {object} ex: { foo: false } * @returns {object} ex: { foo: false }
* *
*/ */
const createDefaultPropertyForms = ({ children }) => { const createDefaultPropertyForms = ({ children }, propertyValues, prefix = '') => {
return children.reduce((acc, current) => { return children.reduce((acc, current) => {
if (current.children) { 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; return acc;
}, {}); }, {});
@ -43,12 +53,16 @@ const createDefaultPropertyForms = ({ children }) => {
* } * }
* @returns {object} In this case it will return { fields: { name: false } } * @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) => { return propertiesArray.reduce((acc, currentPropertyName) => {
const foundProperty = ctLayout.properties.find(({ value }) => value === currentPropertyName); const foundProperty = ctLayout.properties.find(({ value }) => value === currentPropertyName);
if (foundProperty) { if (foundProperty) {
const propertyForm = createDefaultPropertyForms(foundProperty); const matchingPermissionPropertyValues = get(matchingPermission, foundProperty.value, []);
const propertyForm = createDefaultPropertyForms(
foundProperty,
matchingPermissionPropertyValues
);
acc[currentPropertyName] = propertyForm; 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) => { return actionArray.reduce((defaultForm, current) => {
const actionSubjects = current.subjects; const actionSubjects = current.subjects;
@ -105,17 +124,26 @@ const createDefaultCTFormFromLayout = ({ subjects }, actionArray, conditionArray
// The object has the following shape: { [ctUID]: { [actionId]: { [property]: { enabled: false } } } } // The object has the following shape: { [ctUID]: { [actionId]: { [property]: { enabled: false } } } }
const contentTypesActions = Object.keys(subjectLayouts).reduce((acc, currentCTUID) => { const contentTypesActions = Object.keys(subjectLayouts).reduce((acc, currentCTUID) => {
const { actionId, applyToProperties } = current; const { actionId, applyToProperties } = current;
const conditionsForm = createDefaultConditionsForm(conditionArray);
const matchingPermission = findMatchingPermission(initialPermissions, actionId, currentCTUID);
const conditionsForm = createDefaultConditionsForm(
conditionArray,
get(matchingPermission, 'conditions', [])
);
if (isEmpty(applyToProperties)) { if (isEmpty(applyToProperties)) {
set(acc, [currentCTUID, actionId], { enabled: false, conditions: conditionsForm }); set(acc, [currentCTUID, actionId], {
enabled: matchingPermission !== undefined,
conditions: conditionsForm,
});
return acc; return acc;
} }
const propertiesForm = createDefaultPropertiesForm( const propertiesForm = createDefaultPropertiesForm(
applyToProperties, applyToProperties,
subjectLayouts[currentCTUID] subjectLayouts[currentCTUID],
matchingPermission
); );
set(acc, [currentCTUID, actionId], { ...propertiesForm, conditions: conditionsForm }); 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 default createDefaultCTFormFromLayout;
export { export {
createDefaultConditionsForm, createDefaultConditionsForm,

View File

@ -20,7 +20,7 @@ const conditions = [
describe('ADMIN | COMPONENTS | Permissions | utils', () => { describe('ADMIN | COMPONENTS | Permissions | utils', () => {
describe('createConditionForm', () => { 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 = { const expected = {
'admin::is-creator': false, 'admin::is-creator': false,
'admin::has-same-role-as-creator': false, 'admin::has-same-role-as-creator': false,
@ -28,10 +28,21 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => {
expect(createDefaultConditionsForm(conditions)).toEqual(expected); 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,', () => { 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 = { const data = {
children: [ children: [
{ {
@ -47,10 +58,10 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => {
bar: false, 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 = { const data = {
children: [ children: [
{ {
@ -74,17 +85,18 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => {
}, },
], ],
}; };
const propertyValues = ['foo', 'bar.foo.bar'];
const expected = { const expected = {
foo: false, foo: true,
bar: { bar: {
name: false, name: false,
foo: { 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 = [ const actions = [
{ {
label: 'Create', label: 'Create',
@ -312,12 +325,12 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => {
fields: { fields: {
postal_coder: false, postal_coder: false,
categories: false, categories: false,
cover: false, cover: true,
images: false, images: false,
city: false, city: false,
}, },
conditions: { conditions: {
'admin::is-creator': false, 'admin::is-creator': true,
'admin::has-same-role-as-creator': false, 'admin::has-same-role-as-creator': false,
}, },
}, },
@ -336,10 +349,10 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => {
f2: false, f2: false,
services: { name: false, media: false, closing: { name: { test: false } } }, services: { name: false, media: false, closing: { name: { test: false } } },
dz: false, dz: false,
relation: false, relation: true,
}, },
locales: { locales: {
en: false, en: true,
fr: false, fr: false,
}, },
conditions: { 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
);
}); });
}); });

View File

@ -36,7 +36,6 @@ const EditPage = () => {
isLoading: isRoleLoading, isLoading: isRoleLoading,
onSubmitSucceeded, onSubmitSucceeded,
} = useFetchRole(id); } = useFetchRole(id);
console.log({ rolePermissions });
/* eslint-disable indent */ /* eslint-disable indent */
const headerActions = (handleSubmit, handleReset) => const headerActions = (handleSubmit, handleReset) =>
@ -177,7 +176,11 @@ const EditPage = () => {
/> />
{!isLayoutLoading && !isRoleLoading && ( {!isLayoutLoading && !isRoleLoading && (
<Padded top bottom size="md"> <Padded top bottom size="md">
<Permissions isFormDisabled={isFormDisabled} ref={permissionsRef} /> <Permissions
isFormDisabled={isFormDisabled}
permissions={rolePermissions}
ref={permissionsRef}
/>
</Padded> </Padded>
)} )}
</ContainerFluid> </ContainerFluid>