From 27074153192bbf171ccf5a53570615868c98ef49 Mon Sep 17 00:00:00 2001 From: "a.bouhuolia" Date: Mon, 27 Dec 2021 15:04:57 +0200 Subject: [PATCH] feat: Role form permissions dependecies. --- package.json | 1 + src/common/permissionsSchema.js | 156 ++++++------------ .../Users/Roles/RolesForm/utils.js | 67 +++++++- 3 files changed, 120 insertions(+), 104 deletions(-) diff --git a/package.json b/package.json index b94ddb316..0ef5d4084 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "cross-env": "^7.0.2", "css-loader": "3.4.2", "deep-map-keys": "^2.0.1", + "dependency-graph": "^0.11.0", "dotenv": "8.2.0", "dotenv-expand": "5.1.0", "eslint": "^6.6.0", diff --git a/src/common/permissionsSchema.js b/src/common/permissionsSchema.js index 2bc0fdcac..b319e3cdd 100644 --- a/src/common/permissionsSchema.js +++ b/src/common/permissionsSchema.js @@ -47,52 +47,20 @@ export const permissions = [ label: 'Items', subject: AbilitySubject.Item, permissions: [ - { - label: 'View', - key: ItemAction.View, - relatedColumn: PermissionColumn.View, - }, - { - label: 'Create', - key: ItemAction.Create, - relatedColumn: PermissionColumn.Create, - }, - { - label: 'Edit', - key: ItemAction.Edit, - relatedColumn: PermissionColumn.Edit, - }, - { - label: 'Delete', - key: ItemAction.Delete, - relatedColumn: PermissionColumn.Delete, - }, + { label: 'View', key: ItemAction.View, relatedColumn: PermissionColumn.View }, + { label: 'Create', key: ItemAction.Create, relatedColumn: PermissionColumn.Create, depend: [{ key: ItemAction.View }] }, + { label: 'Edit', key: ItemAction.Edit, relatedColumn: PermissionColumn.Edit, depend: [{ key: ItemAction.Create }], }, + { label: 'Delete', key: ItemAction.Delete, relatedColumn: PermissionColumn.Delete, depend: [{ key: ItemAction.Edit }] }, ], }, { label: 'Inventory adjustments', subject: AbilitySubject.InventoryAdjustment, permissions: [ - { - label: 'View', - key: ItemAction.View, - relatedColumn: PermissionColumn.View, - }, - { - label: 'Create', - key: ItemAction.Create, - relatedColumn: PermissionColumn.Create, - }, - { - label: 'Edit', - key: ItemAction.Edit, - relatedColumn: PermissionColumn.Edit, - }, - { - label: 'Delete', - key: ItemAction.Delete, - relatedColumn: PermissionColumn.Delete, - }, + { label: 'View', key: ItemAction.View, relatedColumn: PermissionColumn.View }, + { label: 'Create', key: ItemAction.Create, relatedColumn: PermissionColumn.Create, depend: [{ key: ItemAction.View }] }, + { label: 'Edit', key: ItemAction.Edit, relatedColumn: PermissionColumn.Edit, depend: [{ key: ItemAction.Create }] }, + { label: 'Delete', key: ItemAction.Delete, relatedColumn: PermissionColumn.Delete, depend: [{ key: ItemAction.Edit }] }, ], }, ], @@ -113,26 +81,10 @@ export const permissions = [ label: 'Customers', subject: AbilitySubject.Customer, permissions: [ - { - label: 'View', - key: CustomerAction.View, - relatedColumn: PermissionColumn.View, - }, - { - label: 'Create', - key: CustomerAction.Create, - relatedColumn: PermissionColumn.Create, - }, - { - label: 'Edit', - key: CustomerAction.Edit, - relatedColumn: PermissionColumn.Edit, - }, - { - label: 'Delete', - key: CustomerAction.Delete, - relatedColumn: PermissionColumn.Delete, - }, + { label: 'View', key: CustomerAction.View, relatedColumn: PermissionColumn.View, }, + { label: 'Create', key: CustomerAction.Create, relatedColumn: PermissionColumn.Create, depend: [{ key: CustomerAction.View }] }, + { label: 'Edit', key: CustomerAction.Edit, relatedColumn: PermissionColumn.Edit, depend: [{ key: CustomerAction.Create }] }, + { label: 'Delete', key: CustomerAction.Delete, relatedColumn: PermissionColumn.Delete, depend: [{ key: CustomerAction.Edit }] }, ], }, { @@ -148,16 +100,19 @@ export const permissions = [ label: 'Create', key: VendorAction.Create, relatedColumn: PermissionColumn.Create, + depend: [{ key: VendorAction.View }] }, { label: 'Edit', key: VendorAction.Edit, relatedColumn: PermissionColumn.Edit, + depend: [{ key: VendorAction.Create }] }, { label: 'Delete', key: VendorAction.Delete, relatedColumn: PermissionColumn.Delete, + depend: [{ key: VendorAction.Edit }] }, ], }, @@ -188,44 +143,31 @@ export const permissions = [ label: 'Create', key: SaleInvoiceAction.Create, relatedColumn: PermissionColumn.Create, + depend: [{ key: SaleInvoiceAction.View }] }, { label: 'Edit', key: SaleInvoiceAction.Edit, relatedColumn: PermissionColumn.Edit, + depend: [{ key: SaleInvoiceAction.Create }] }, { label: 'Delete', key: SaleInvoiceAction.Delete, relatedColumn: PermissionColumn.Delete, + depend: [{ key: SaleInvoiceAction.Edit }] }, - { label: 'Written-off invoice', key: SaleInvoiceAction.Writeoff }, + { label: 'Written-off invoice', key: SaleInvoiceAction.Writeoff, depend:[{ key: SaleInvoiceAction.Edit }] }, ], }, { label: 'Sale Estimate', subject: AbilitySubject.Estimate, permissions: [ - { - label: 'View', - key: SaleEstimateAction.View, - relatedColumn: PermissionColumn.View, - }, - { - label: 'Create', - key: SaleEstimateAction.Create, - relatedColumn: PermissionColumn.Create, - }, - { - label: 'Edit', - key: SaleEstimateAction.Edit, - relatedColumn: PermissionColumn.Edit, - }, - { - label: 'Delete', - key: SaleEstimateAction.Delete, - relatedColumn: PermissionColumn.Delete, - }, + { label: 'View', key: SaleEstimateAction.View, relatedColumn: PermissionColumn.View, }, + { label: 'Create', key: SaleEstimateAction.Create, relatedColumn: PermissionColumn.Create, depend:[{ key: SaleEstimateAction.View }] }, + { label: 'Edit', key: SaleEstimateAction.Edit, relatedColumn: PermissionColumn.Edit, depend:[{ key: SaleEstimateAction.Create }] }, + { label: 'Delete', key: SaleEstimateAction.Delete, relatedColumn: PermissionColumn.Delete, depend:[{ key: SaleEstimateAction.Edit }] }, ], }, { @@ -241,16 +183,19 @@ export const permissions = [ label: 'Create', key: SaleReceiptAction.Create, relatedColumn: PermissionColumn.Create, + depend:[{ key: SaleReceiptAction.View }] }, { label: 'Edit', key: SaleReceiptAction.Edit, relatedColumn: PermissionColumn.Edit, + depend:[{ key: SaleReceiptAction.Create }] }, { label: 'Delete', key: SaleReceiptAction.Delete, relatedColumn: PermissionColumn.Delete, + depend:[{ key: SaleReceiptAction.Edit }] }, ], }, @@ -258,27 +203,11 @@ export const permissions = [ label: 'Credit note', subject: AbilitySubject.CreditNote, permissions: [ - { - label: 'View', - key: CreditNoteAction.View, - relatedColumn: PermissionColumn.View, - }, - { - label: 'Create', - key: CreditNoteAction.Create, - relatedColumn: PermissionColumn.Create, - }, - { - label: 'Edit', - key: CreditNoteAction.Edit, - relatedColumn: PermissionColumn.Edit, - }, - { - label: 'Delete', - key: CreditNoteAction.Delete, - relatedColumn: PermissionColumn.Delete, - }, - { label: 'Refund credit note', key: CreditNoteAction.Refund }, + { label: 'View', key: CreditNoteAction.View, relatedColumn: PermissionColumn.View }, + { label: 'Create', key: CreditNoteAction.Create, relatedColumn: PermissionColumn.Create, depend:[{ key: CreditNoteAction.View }] }, + { label: 'Edit', key: CreditNoteAction.Edit, relatedColumn: PermissionColumn.Edit, depend:[{ key: CreditNoteAction.Create }] }, + { label: 'Delete', key: CreditNoteAction.Delete, relatedColumn: PermissionColumn.Delete, depend:[{ key: CreditNoteAction.Edit }] }, + { label: 'Refund credit note', key: CreditNoteAction.Refund, depend:[{ key: CreditNoteAction.View }] }, ], }, { @@ -294,16 +223,19 @@ export const permissions = [ label: 'Create', key: PaymentReceiveAction.Create, relatedColumn: PermissionColumn.Create, + depend:[{ key: PaymentReceiveAction.View }] }, { label: 'Edit', key: PaymentReceiveAction.Edit, relatedColumn: PermissionColumn.Edit, + depend:[{ key: PaymentReceiveAction.Create }] }, { label: 'Delete', key: PaymentReceiveAction.Delete, relatedColumn: PermissionColumn.Delete, + depend:[{ key: PaymentReceiveAction.Edit }] }, ], }, @@ -334,16 +266,19 @@ export const permissions = [ label: 'Create', key: BillAction.Create, relatedColumn: PermissionColumn.Create, + depend:[{ key: BillAction.View }] }, { label: 'Edit', key: BillAction.Edit, relatedColumn: PermissionColumn.Edit, + depend:[{ key: BillAction.Create }] }, { label: 'Delete', key: BillAction.Delete, relatedColumn: PermissionColumn.Delete, + depend:[{ key: BillAction.Edit }] }, ], }, @@ -360,18 +295,21 @@ export const permissions = [ label: 'Create', key: VendorCreditAction.Create, relatedColumn: PermissionColumn.Create, + depend: [{ key: VendorCreditAction.View }] }, { label: 'Edit', key: VendorCreditAction.Edit, relatedColumn: PermissionColumn.Edit, + depend: [{ key: VendorCreditAction.Create }] }, { label: 'Delete', key: VendorCreditAction.Delete, relatedColumn: PermissionColumn.Delete, + depend: [{ key: VendorCreditAction.Edit }] }, - { label: 'Refund vendor credit', key: VendorCreditAction.Refund }, + { label: 'Refund vendor credit', key: VendorCreditAction.Refund, depend: [{ key: VendorCreditAction.View }] }, ], }, { @@ -387,16 +325,19 @@ export const permissions = [ label: 'Create', key: PaymentMadeAction.Create, relatedColumn: PermissionColumn.Create, + depend: [{ key: PaymentMadeAction.View }] }, { label: 'Edit', key: PaymentMadeAction.Edit, relatedColumn: PermissionColumn.Edit, + depend: [{ key: PaymentMadeAction.Create }] }, { label: 'Delete', key: PaymentMadeAction.Delete, relatedColumn: PermissionColumn.Delete, + depend: [{ key: PaymentMadeAction.Edit }] }, ], }, @@ -427,16 +368,19 @@ export const permissions = [ label: 'Create', key: ManualJournalAction.Create, relatedColumn: PermissionColumn.Create, + depend: [{ key: ManualJournalAction.View }] }, { label: 'Edit', key: ManualJournalAction.Edit, relatedColumn: PermissionColumn.Edit, + depend: [{ key: ManualJournalAction.Create }] }, { label: 'Delete', key: ManualJournalAction.Delete, relatedColumn: PermissionColumn.Delete, + depend: [{ key: ManualJournalAction.Edit }] }, ], }, @@ -453,16 +397,19 @@ export const permissions = [ label: 'Create', key: AccountAction.Create, relatedColumn: PermissionColumn.Create, + depend: [{ key: AccountAction.View }] }, { label: 'Edit', key: AccountAction.Edit, relatedColumn: PermissionColumn.Edit, + depend: [{ key: AccountAction.Create }] }, { label: 'Delete', key: AccountAction.Delete, relatedColumn: PermissionColumn.Delete, + depend: [{ key: AccountAction.Edit }] }, { label: 'Transactions locking', @@ -483,16 +430,19 @@ export const permissions = [ label: 'Create', key: ExpenseAction.Create, relatedColumn: PermissionColumn.Create, + depend: [{ key: ExpenseAction.View }] }, { label: 'Edit', key: ExpenseAction.Edit, relatedColumn: PermissionColumn.Edit, + depend: [{ key: ExpenseAction.Create }] }, { label: 'Delete', key: ExpenseAction.Delete, relatedColumn: PermissionColumn.Delete, + depend: [{ key: ExpenseAction.Edit }] }, ], }, diff --git a/src/containers/Preferences/Users/Roles/RolesForm/utils.js b/src/containers/Preferences/Users/Roles/RolesForm/utils.js index 66ab75d2a..7cac3cb25 100644 --- a/src/containers/Preferences/Users/Roles/RolesForm/utils.js +++ b/src/containers/Preferences/Users/Roles/RolesForm/utils.js @@ -1,6 +1,8 @@ -import { chain } from 'lodash'; +import { chain, isEmpty, castArray, memoize } from 'lodash'; import * as R from 'ramda'; +import { DepGraph } from 'dependency-graph'; import { + permissions as PERMISSIONS_SCHEMA, getPermissionsSchemaService, getPermissionsSchemaServices, } from 'common/permissionsSchema'; @@ -176,11 +178,23 @@ export const handleCheckboxPermissionChange = R.curry( (form, permission, service, event) => { const { subject } = service; const isChecked = event.currentTarget.checked; + + const permissionsGraph = memoizedPermissionsGraph(); + const dependencies = isChecked + ? permissionsGraph.dependenciesOf(`${subject}/${permission.key}`) + : permissionsGraph.dependantsOf(`${subject}/${permission.key}`); + + const newDependsPermiss = chain(dependencies) + .map((dep) => [dep, isChecked]) + .fromPairs() + .value(); + const newValues = { ...form.values, permissions: { ...form.values.permissions, [`${subject}/${permission.key}`]: isChecked, + ...newDependsPermiss, }, }; const isFullChecked = isServiceFullChecked(subject, newValues.permissions); @@ -193,6 +207,10 @@ export const handleCheckboxPermissionChange = R.curry( `serviceFullAccess.${subject}`, detarmineCheckboxState(isFullChecked, isFullUnchecked), ); + + dependencies.forEach((depKey) => { + form.setFieldValue(`permissions.${depKey}`, isChecked); + }); }, ); @@ -243,3 +261,50 @@ export const handleCheckboxFullAccessChange = R.curry( }); }, ); + +/** + * Retrieves all flatten modules permissions. + */ +export function getAllFlattenPermissionsSchema() { + return chain(PERMISSIONS_SCHEMA) + .map((module) => module.services) + .flatten() + .map((module) => + module.permissions.map((permission) => ({ + subject: module.subject, + ...permission, + })), + ) + .flatten() + .value(); +} + +/** + * Retrieve the permissions schema dependencies graph. + * @returns {DepGraph} + */ +export const getPermissionsSchemaGraph = () => { + const graph = new DepGraph(); + const permissions = getAllFlattenPermissionsSchema(); + + permissions.forEach((permission) => { + graph.addNode(`${permission.subject}/${permission.key}`, permission); + }); + const nodesOrder = graph.overallOrder(); + + nodesOrder.forEach((key) => { + const node = graph.getNodeData(key); + + if (isEmpty(node.depend)) return; + + const depends = castArray(node.depend); + + depends.forEach((dependRelation) => { + const subject = dependRelation.subject || node.subject; + graph.addDependency(key, `${subject}/${dependRelation.key}`); + }); + }); + return graph; +}; + +const memoizedPermissionsGraph = memoize(getPermissionsSchemaGraph);