Permission-Capability/CapabilitySet mapping algorithm

Capabilities are mapped from permissions using the following algorithm

capability-mapping-20241011-133035.png
@startuml !theme mono !pragma useVerticalIf on skinparam conditionStyle inside skinparam defaultTextAlignment center skinparam defaultFontSize 12 <style> activityDiagram { activity { MaximumWidth 600 backgroundColor #f0f0f0 LineColor DimGrey } diamond { HorizontalAlignment center } group { LineColor LightGrey FontSize 10 } } </style> group folio-permission-utils { :read permission mapping overrides from URL and store it as ""permissionMappingOverrides"";<<input>> if (""permission"" in ""permissionMappingOverrides"") then (yes) :read capability by permission name from mappingOverrides;<<input>> :return PermissionData with (resource, action, type);<<output>> end; else (no) :define DATA_SETTINGS_ACTIONS ""VIEW -> [ "get", "view", "read", "get-all", "read-all", "search" ]"" ""CREATE -> [ "post", "create", "write" ]"" ""EDIT -> [ "put", "edit", "update", "patch" ]"" ""DELETE -> [ "delete", "delete-all" ]"" ""MANAGE -> [ "all", "manage", "allops" ]"";<<input>> :define SETTINGS_KEYWORD ""[ "module", "settings" ]"";<<input>> :define DATA_KEYWORD_IDENTIFIERS ""[ "item", "collection", "items" ]"";<<input>> :define DATA_SUFFIXES ""[ ".item.post" ]"""; <<input>> :define PROCEDURAL_KEYWORDS ""[ "post", "download", "export", "assign", "restore", "approve", "reopen", "start", "unopen", "validate", "resend", "run-jobs", "stop-jobs", "generate", "reset", "test", "import", "cancel", "exportCSV", "showHidden", "updateEncumbrances", "execute", "move" ]"";<<input>> :split permission name by ""."";<<task>> :store it as ""permissionParts"";<<output>> group calculatePermissionType { if (""permissionParts"" contains any of ""SETTING_KEYWORDS"" \nOR ""permissionName"" start with ""SETTINGS_KEYWORDS"") then (yes) :define capability/capability set type as ""SETTINGS"";<<output>> else if (""name"" end with any of ""PROCEDURAL_KEYWORDS""\nAND ""permissionParts"" NOT contains\nany of ""DATA_KEYWORD_IDENTIFIERS"") then (yes) :define capability/capability set type as ""PROCEDURAL"";<<output>> else if (""name"" end with any of ""DATA_SUFFIXES"") then (yes) :define capability/capability set type as ""DATA"";<<output>> else if (""permissionParts"" contains\n any of ""PROCEDURAL_KEYWORDS"") then (yes) :define capability/capability set type as ""PROCEDURAL"";<<output>> else (no) :define capability/capability set type as ""DATA"";<<output>> end if } group calculatePermissionResourceAndAction { if (""permissionParts"" size == 1) then (yes) :define resource as ""null"" and action as ""null"";<<output>> else (no) :try resolve action from last part of ""permissionParts"" using resolved ""type"";<<task>> :store resolved action as ""action"";<<output>> if (type is ""PROCEDURAL"") then (yes) :define resource as substring before action and action as ""EXECUTE"" //""search_index_inventory_reindex.execute"" -> ""Search Index Inventory Reindex | EXECUTE""// //""ui-inventory.item.move"" -> ""UI-Inventory Item | EXECUTE""//;<<output>> else if (""action"" is ""null"" AND ""type"" is ""SETTINGS"") then (yes) :define resource as substring before action and action as ""VIEW"" //""module.circulation-log.enabled"" -> ""Module Circulation-Log Enabled | VIEW""//;<<output>> else (no) :define resource as substring before action with resolved action //""browse_subjects_instances_coll.view"" -> ""Browse Subjects Instances Coll | VIEW""// //""inventory-storage.items.collection.get"" -> ""Inventory-Storage Items Collection | VIEW""//;<<output>> end if end if } end if :return PermissionData with (resource, action, type);<<output>> end } @enduml

The permission mapping overrides are stored in the following format (Mapping-overrides by Eureka )

[ "{sourcePermissionName}": { "resource": "{expectedCapabilityName}", "type": "{expectedCapabilityType}", "action": "{expectedCapabilityAction}" } ]