diff --git a/config/permissions.yaml b/config/permissions.yaml index c7eefd4b..41617666 100644 --- a/config/permissions.yaml +++ b/config/permissions.yaml @@ -93,9 +93,9 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co <<: *PART_CONTAINING label: "perm.part.manufacturers" - devices: + projects: <<: *PART_CONTAINING - label: "perm.part.devices" + label: "perm.projects" attachment_types: <<: *PART_CONTAINING diff --git a/src/Controller/ProjectController.php b/src/Controller/ProjectController.php index 916f32e6..4a78b784 100644 --- a/src/Controller/ProjectController.php +++ b/src/Controller/ProjectController.php @@ -80,7 +80,7 @@ class ProjectController extends AbstractController if($project) { $this->denyAccessUnlessGranted('edit', $project); } else { - $this->denyAccessUnlessGranted('@devices.edit'); + $this->denyAccessUnlessGranted('@projects.edit'); } $builder = $this->createFormBuilder(); diff --git a/src/Controller/TreeController.php b/src/Controller/TreeController.php index f5d8bd81..6ab3b420 100644 --- a/src/Controller/TreeController.php +++ b/src/Controller/TreeController.php @@ -138,7 +138,7 @@ class TreeController extends AbstractController */ public function deviceTree(?Project $device = null): JsonResponse { - if ($this->isGranted('@devices.read')) { + if ($this->isGranted('@projects.read')) { $tree = $this->treeGenerator->getTreeView(Project::class, $device, 'devices'); } else { return new JsonResponse("Access denied", 403); diff --git a/src/DataFixtures/GroupFixtures.php b/src/DataFixtures/GroupFixtures.php index 3a93d14e..93e93b79 100644 --- a/src/DataFixtures/GroupFixtures.php +++ b/src/DataFixtures/GroupFixtures.php @@ -72,7 +72,7 @@ class GroupFixtures extends Fixture private function addDevicesPermissions(Group $group): void { - $this->permissionManager->setAllOperationsOfPermission($group, 'devices', true); + $this->permissionManager->setAllOperationsOfPermission($group, 'projects', true); } } diff --git a/src/Entity/Parts/PartTraits/ProjectTrait.php b/src/Entity/Parts/PartTraits/ProjectTrait.php index 19bc0dff..58697427 100644 --- a/src/Entity/Parts/PartTraits/ProjectTrait.php +++ b/src/Entity/Parts/PartTraits/ProjectTrait.php @@ -62,7 +62,7 @@ trait ProjectTrait /** - * Get all devices which uses this part. + * Get all projects which uses this part. * * @return Project[] * all devices which uses this part as a one-dimensional array of Device objects * (empty array if there are no ones) diff --git a/src/Entity/UserSystem/PermissionData.php b/src/Entity/UserSystem/PermissionData.php index 30fa48be..2d3292a4 100644 --- a/src/Entity/UserSystem/PermissionData.php +++ b/src/Entity/UserSystem/PermissionData.php @@ -40,7 +40,7 @@ final class PermissionData implements \JsonSerializable /** * The current schema version of the permission data */ - public const CURRENT_SCHEMA_VERSION = 1; + public const CURRENT_SCHEMA_VERSION = 2; /** * @var array This array contains the permission values for each permission @@ -69,6 +69,56 @@ final class PermissionData implements \JsonSerializable } } + /** + * Checks if any of the operations of the given permission is defined (meaning it is either ALLOW or DENY) + * @param string $permission + * @return bool + */ + public function isAnyOperationOfPermissionSet(string $permission): bool + { + return !empty($this->data[$permission]); + } + + /** + * Returns an associative array containing all defined (non-INHERIT) operations of the given permission. + * @param string $permission + * @return array An array in the form ["operation" => value], returns an empty array if no operations are defined + */ + public function getAllDefinedOperationsOfPermission(string $permission): array + { + if (empty($this->data[$permission])) { + return []; + } + + return $this->data[$permission]; + } + + /** + * Sets all operations of the given permission via the given array. + * The data is an array in the form [$operation => $value], all existing values will be overwritten/deleted. + * @param string $permission + * @param array $data + * @return $this + */ + public function setAllOperationsOfPermission(string $permission, array $data): self + { + $this->data[$permission] = $data; + + return $this; + } + + /** + * Removes a whole permission from the data including all operations (effectivly setting them to INHERIT) + * @param string $permission + * @return $this + */ + public function removePermission(string $permission): self + { + unset($this->data[$permission]); + + return $this; + } + /** * Check if a permission value is set for the given permission and operation (meaning there value is not inherit). * @param string $permission diff --git a/src/Security/Voter/ParameterVoter.php b/src/Security/Voter/ParameterVoter.php index 713a14c9..525a75b6 100644 --- a/src/Security/Voter/ParameterVoter.php +++ b/src/Security/Voter/ParameterVoter.php @@ -96,7 +96,7 @@ class ParameterVoter extends ExtendedVoter } elseif ($subject instanceof CurrencyParameter) { $param = 'currencies'; } elseif ($subject instanceof ProjectParameter) { - $param = 'devices'; + $param = 'projects'; } elseif ($subject instanceof FootprintParameter) { $param = 'footprints'; } elseif ($subject instanceof GroupParameter) { diff --git a/src/Security/Voter/StructureVoter.php b/src/Security/Voter/StructureVoter.php index 6c7bb6a2..df88e113 100644 --- a/src/Security/Voter/StructureVoter.php +++ b/src/Security/Voter/StructureVoter.php @@ -40,7 +40,7 @@ class StructureVoter extends ExtendedVoter protected const OBJ_PERM_MAP = [ AttachmentType::class => 'attachment_types', Category::class => 'categories', - Project::class => 'devices', + Project::class => 'projects', Footprint::class => 'footprints', Manufacturer::class => 'manufacturers', Storelocation::class => 'storelocations', diff --git a/src/Services/UserSystem/PermissionPresetsHelper.php b/src/Services/UserSystem/PermissionPresetsHelper.php index 83ab0026..20ae7248 100644 --- a/src/Services/UserSystem/PermissionPresetsHelper.php +++ b/src/Services/UserSystem/PermissionPresetsHelper.php @@ -111,6 +111,7 @@ class PermissionPresetsHelper $this->permissionResolver->setAllOperationsOfPermission($permHolder, 'currencies', PermissionData::ALLOW); $this->permissionResolver->setAllOperationsOfPermission($permHolder, 'measurement_units', PermissionData::ALLOW); $this->permissionResolver->setAllOperationsOfPermission($permHolder, 'suppliers', PermissionData::ALLOW); + $this->permissionResolver->setAllOperationsOfPermission($permHolder, 'projects', PermissionData::ALLOW); //Attachments permissions $this->permissionResolver->setPermission($permHolder, 'attachments', 'show_private', PermissionData::ALLOW); @@ -150,8 +151,8 @@ class PermissionPresetsHelper $this->permissionResolver->setPermission($perm_holder, 'labels', 'edit_options', PermissionData::ALLOW); $this->permissionResolver->setPermission($perm_holder, 'labels', 'read_profiles', PermissionData::ALLOW); - //Set devices permissions - $this->permissionResolver->setPermission($perm_holder, 'devices', 'read', PermissionData::ALLOW); + //Set projects permissions + $this->permissionResolver->setPermission($perm_holder, 'projects', 'read', PermissionData::ALLOW); return $perm_holder; } diff --git a/src/Services/UserSystem/PermissionSchemaUpdater.php b/src/Services/UserSystem/PermissionSchemaUpdater.php index fa031595..b4320c48 100644 --- a/src/Services/UserSystem/PermissionSchemaUpdater.php +++ b/src/Services/UserSystem/PermissionSchemaUpdater.php @@ -133,4 +133,14 @@ class PermissionSchemaUpdater $holder->getPermissions()->setPermissionValue('parts_stock', 'move', $new_value); } } + + private function upgradeSchemaToVersion2(HasPermissionsInterface $holder): void + { + //If the projects permissions are not defined yet, rename devices permission to projects (just copy its data over) + if (!$holder->getPermissions()->isAnyOperationOfPermissionSet('projects')) { + $operations_value = $holder->getPermissions()->getAllDefinedOperationsOfPermission('devices'); + $holder->getPermissions()->setAllOperationsOfPermission('projects', $operations_value); + $holder->getPermissions()->removePermission('devices'); + } + } } \ No newline at end of file diff --git a/templates/Parts/info/_projects.html.twig b/templates/Parts/info/_projects.html.twig index e9d58c6e..7adb2182 100644 --- a/templates/Parts/info/_projects.html.twig +++ b/templates/Parts/info/_projects.html.twig @@ -28,7 +28,7 @@ - {% trans %}part.info.add_part_to_project{% endtrans %} diff --git a/templates/Parts/info/_tools.html.twig b/templates/Parts/info/_tools.html.twig index b9d7e0d4..2c76062b 100644 --- a/templates/Parts/info/_tools.html.twig +++ b/templates/Parts/info/_tools.html.twig @@ -53,7 +53,7 @@ {{ dropdown.profile_dropdown('part', part.id) }} - {% trans %}part.info.add_part_to_project{% endtrans %} diff --git a/templates/Projects/info/_bom.html.twig b/templates/Projects/info/_bom.html.twig index ac19c530..42ffd015 100644 --- a/templates/Projects/info/_bom.html.twig +++ b/templates/Projects/info/_bom.html.twig @@ -4,7 +4,7 @@ {{ datatables.datatable(datatable, 'elements/datatables/datatables', 'projects') }} - {% trans %}project.info.bom_add_parts{% endtrans %} diff --git a/templates/components/datatables.macro.html.twig b/templates/components/datatables.macro.html.twig index d6aa19cd..0c5c170c 100644 --- a/templates/components/datatables.macro.html.twig +++ b/templates/components/datatables.macro.html.twig @@ -49,7 +49,7 @@ - + diff --git a/templates/components/tree_macros.html.twig b/templates/components/tree_macros.html.twig index 4d0846f6..b85fcc88 100644 --- a/templates/components/tree_macros.html.twig +++ b/templates/components/tree_macros.html.twig @@ -6,7 +6,7 @@ ['footprints', path('tree_footprint_root'), 'footprint.labelp', is_granted('@footprints.read') and is_granted('@parts.read')], ['manufacturers', path('tree_manufacturer_root'), 'manufacturer.labelp', is_granted('@manufacturers.read') and is_granted('@parts.read')], ['suppliers', path('tree_supplier_root'), 'supplier.labelp', is_granted('@suppliers.read') and is_granted('@parts.read')], - ['devices', path('tree_device_root'), 'project.labelp', is_granted('@devices.read')], + ['devices', path('tree_device_root'), 'project.labelp', is_granted('@projects.read')], ['tools', path('tree_tools'), 'tools.label', true], ] %} diff --git a/tests/Entity/UserSystem/PermissionDataTest.php b/tests/Entity/UserSystem/PermissionDataTest.php index 681c5082..5107c2a0 100644 --- a/tests/Entity/UserSystem/PermissionDataTest.php +++ b/tests/Entity/UserSystem/PermissionDataTest.php @@ -158,4 +158,61 @@ class PermissionDataTest extends TestCase $data->setSchemaVersion(12345); $this->assertEquals(12345, $data->getSchemaVersion()); } + + public function testIsAnyOperationOfPermissionSet() + { + $data = new PermissionData(); + + //Initially no operation of any permission is set + $this->assertFalse($data->isAnyOperationOfPermissionSet('perm1')); + + $data->setPermissionValue('perm1', 'op1', PermissionData::ALLOW); + $this->assertTrue($data->isAnyOperationOfPermissionSet('perm1')); + } + + public function testGetAllDefinedOperationsOfPermission() + { + $data = new PermissionData(); + + $this->assertEmpty($data->getAllDefinedOperationsOfPermission('perm1')); + + $data->setPermissionValue('perm1', 'op1', PermissionData::ALLOW); + $data->setPermissionValue('perm1', 'op2', PermissionData::DISALLOW); + + $this->assertEquals([ + 'op1' => PermissionData::ALLOW, 'op2' => PermissionData::DISALLOW, + ], + $data->getAllDefinedOperationsOfPermission('perm1')); + } + + public function testSetAllOperationsOfPermission() + { + $data = new PermissionData(); + + $data->setAllOperationsOfPermission('perm1', [ + 'op1' => PermissionData::ALLOW, + 'op2' => PermissionData::DISALLOW, + ]); + + $this->assertEquals([ + 'op1' => PermissionData::ALLOW, 'op2' => PermissionData::DISALLOW, + ], + $data->getAllDefinedOperationsOfPermission('perm1')); + } + + public function testRemovePermission() + { + $data = new PermissionData(); + + $data->setPermissionValue('perm1', 'op1', PermissionData::ALLOW); + $data->setPermissionValue('perm1', 'op2', PermissionData::DISALLOW); + + $this->assertTrue($data->isPermissionSet('perm1', 'op1')); + $this->assertTrue($data->isPermissionSet('perm1', 'op2')); + + $data->removePermission('perm1'); + + $this->assertFalse($data->isPermissionSet('perm1', 'op1')); + $this->assertFalse($data->isPermissionSet('perm1', 'op2')); + } } diff --git a/tests/Services/UserSystem/PermissionSchemaUpdaterTest.php b/tests/Services/UserSystem/PermissionSchemaUpdaterTest.php index 3ed48cf5..79abb89c 100644 --- a/tests/Services/UserSystem/PermissionSchemaUpdaterTest.php +++ b/tests/Services/UserSystem/PermissionSchemaUpdaterTest.php @@ -97,4 +97,20 @@ class PermissionSchemaUpdaterTest extends WebTestCase self::assertEquals(PermissionData::ALLOW, $user->getPermissions()->getPermissionValue('parts_stock', 'add')); self::assertEquals(PermissionData::ALLOW, $user->getPermissions()->getPermissionValue('parts_stock', 'withdraw')); } + + public function testUpgradeSchemaToVersion2() + { + $perm_data = new PermissionData(); + $perm_data->setSchemaVersion(1); + $perm_data->setPermissionValue('devices', 'read', PermissionData::ALLOW); + $perm_data->setPermissionValue('devices', 'edit', PermissionData::INHERIT); + $perm_data->setPermissionValue('devices', 'delete', PermissionData::DISALLOW); + $user = new TestPermissionHolder($perm_data); + + //After the upgrade all operations should be available under the name "projects" with the same values + self::assertTrue($this->service->upgradeSchema($user, 2)); + self::assertEquals(PermissionData::ALLOW, $user->getPermissions()->getPermissionValue('projects', 'read')); + self::assertEquals(PermissionData::INHERIT, $user->getPermissions()->getPermissionValue('projects', 'edit')); + self::assertEquals(PermissionData::DISALLOW, $user->getPermissions()->getPermissionValue('projects', 'delete')); + } } diff --git a/translations/messages.de.xlf b/translations/messages.de.xlf index 36b60369..aadc374c 100644 --- a/translations/messages.de.xlf +++ b/translations/messages.de.xlf @@ -8111,14 +8111,14 @@ Element 3 Hersteller - + obsolete obsolete - perm.part.devices - Baugruppen + perm.projects + Projekte diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 5653956e..d66f855a 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -3284,7 +3284,7 @@ Sub elements will be moved upwards.]]> statistics.devices_count - Number of devices + Number of projects @@ -8112,14 +8112,14 @@ Element 3 Manufacturers - + obsolete obsolete - perm.part.devices - Devices + perm.projects + Projects