diff --git a/config/permissions.yaml b/config/permissions.yaml index c7eefd4b..8c96a3a8 100644 --- a/config/permissions.yaml +++ b/config/permissions.yaml @@ -27,7 +27,7 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co 'currencies.read', 'attachment_types.read', 'measurement_units.read'] edit: label: "perm.edit" - alsoSet: ['read', 'parts_stock.withdraw', 'parts_stock.add', 'parts_stock.move'] + alsoSet: ['read'] #['read', 'parts_stock.withdraw', 'parts_stock.add', 'parts_stock.move'] create: label: "perm.create" alsoSet: ['read', 'edit'] diff --git a/src/Controller/GroupController.php b/src/Controller/GroupController.php index 69099dbd..63d32c7b 100644 --- a/src/Controller/GroupController.php +++ b/src/Controller/GroupController.php @@ -32,6 +32,7 @@ use App\Services\ImportExportSystem\EntityExporter; use App\Services\ImportExportSystem\EntityImporter; use App\Services\Trees\StructuralElementRecursionHelper; use App\Services\UserSystem\PermissionPresetsHelper; +use App\Services\UserSystem\PermissionSchemaUpdater; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; @@ -54,8 +55,11 @@ class GroupController extends BaseAdminController * @Route("/{id}/edit/{timestamp}", requirements={"id"="\d+"}, name="group_edit") * @Route("/{id}/", requirements={"id"="\d+"}) */ - public function edit(Group $entity, Request $request, EntityManagerInterface $em, PermissionPresetsHelper $permissionPresetsHelper, ?string $timestamp = null): Response + public function edit(Group $entity, Request $request, EntityManagerInterface $em, PermissionPresetsHelper $permissionPresetsHelper, PermissionSchemaUpdater $permissionSchemaUpdater, ?string $timestamp = null): Response { + //Do an upgrade of the permission schema if needed (so the user can see the permissions a user get on next request (even if it was not done yet) + $permissionSchemaUpdater->groupUpgradeSchemaRecursively($entity); + //Handle permissions presets if ($request->request->has('permission_preset')) { $this->denyAccessUnlessGranted('edit_permissions', $entity); diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index c72ea7fe..826510b5 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -35,6 +35,7 @@ use App\Services\ImportExportSystem\EntityExporter; use App\Services\ImportExportSystem\EntityImporter; use App\Services\Trees\StructuralElementRecursionHelper; use App\Services\UserSystem\PermissionPresetsHelper; +use App\Services\UserSystem\PermissionSchemaUpdater; use Doctrine\ORM\EntityManagerInterface; use Exception; use InvalidArgumentException; @@ -82,10 +83,12 @@ class UserController extends AdminPages\BaseAdminController * * @throws Exception */ - public function edit(User $entity, Request $request, EntityManagerInterface $em, PermissionPresetsHelper $permissionPresetsHelper, ?string $timestamp = null): Response + public function edit(User $entity, Request $request, EntityManagerInterface $em, PermissionPresetsHelper $permissionPresetsHelper, PermissionSchemaUpdater $permissionSchemaUpdater, ?string $timestamp = null): Response { - //Handle 2FA disabling + //Do an upgrade of the permission schema if needed (so the user can see the permissions a user get on next request (even if it was not done yet) + $permissionSchemaUpdater->userUpgradeSchemaRecursively($entity); + //Handle 2FA disabling if ($request->request->has('reset_2fa')) { //Check if the admin has the needed permissions $this->denyAccessUnlessGranted('set_password', $entity); diff --git a/src/EventSubscriber/UserSystem/UpgradePermissionsSchemaSubscriber.php b/src/EventSubscriber/UserSystem/UpgradePermissionsSchemaSubscriber.php new file mode 100644 index 00000000..cda163c4 --- /dev/null +++ b/src/EventSubscriber/UserSystem/UpgradePermissionsSchemaSubscriber.php @@ -0,0 +1,73 @@ +. + */ + +namespace App\EventSubscriber\UserSystem; + +use App\Entity\UserSystem\User; +use App\Services\UserSystem\PermissionSchemaUpdater; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; +use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\Security\Core\Security; + +/** + * The purpose of this event subscriber is to check if the permission schema of the current user is up to date and upgrade it automatically if needed. + */ +class UpgradePermissionsSchemaSubscriber implements EventSubscriberInterface +{ + private Security $security; + private PermissionSchemaUpdater $permissionSchemaUpdater; + private EntityManagerInterface $entityManager; + private FlashBagInterface $flashBag; + + public function __construct(Security $security, PermissionSchemaUpdater $permissionSchemaUpdater, EntityManagerInterface $entityManager, FlashBagInterface $flashBag) + { + $this->security = $security; + $this->permissionSchemaUpdater = $permissionSchemaUpdater; + $this->entityManager = $entityManager; + $this->flashBag = $flashBag; + } + + public function onRequest(RequestEvent $event): void + { + if (!$event->isMainRequest()) { + return; + } + + $user = $this->security->getUser(); + if (null === $user) { + //Retrieve anonymous user + $user = $this->entityManager->getRepository(User::class)->getAnonymousUser(); + } + + if ($this->permissionSchemaUpdater->isSchemaUpdateNeeded($user)) { + $this->permissionSchemaUpdater->userUpgradeSchemaRecursively($user); + $this->entityManager->flush(); + $this->flashBag->add('notice', 'user.permissions_schema_updated'); + } + } + + public static function getSubscribedEvents(): array + { + return [KernelEvents::REQUEST => 'onRequest']; + } +} \ No newline at end of file diff --git a/src/Services/UserSystem/PermissionSchemaUpdater.php b/src/Services/UserSystem/PermissionSchemaUpdater.php index fabad3db..634d63d8 100644 --- a/src/Services/UserSystem/PermissionSchemaUpdater.php +++ b/src/Services/UserSystem/PermissionSchemaUpdater.php @@ -20,7 +20,9 @@ namespace App\Services\UserSystem; +use App\Entity\UserSystem\Group; use App\Entity\UserSystem\PermissionData; +use App\Entity\UserSystem\User; use App\Security\Interfaces\HasPermissionsInterface; class PermissionSchemaUpdater @@ -42,7 +44,8 @@ class PermissionSchemaUpdater } /** - * Upgrades the permission schema of the given user/group to the chosen version + * Upgrades the permission schema of the given user/group to the chosen version. + * Please note that this function does not flush the changes to DB! * @param HasPermissionsInterface $holder * @param int $target_version * @return bool True, if an upgrade was done, false if it was not needed. @@ -76,6 +79,42 @@ class PermissionSchemaUpdater return true; } + /** + * Upgrades the permission schema of the given group and all of its parent groups to the chosen version. + * Please note that this function does not flush the changes to DB! + * @param Group $group + * @param int $target_version + * @return bool True if an upgrade was done, false if it was not needed. + */ + public function groupUpgradeSchemaRecursively(Group $group, int $target_version = PermissionData::CURRENT_SCHEMA_VERSION): bool + { + $updated = $this->upgradeSchema($group, $target_version); + + /** @var Group $parent */ + $parent = $group->getParent(); + while ($parent) { + $updated = $this->upgradeSchema($parent, $target_version) || $updated; + $parent = $parent->getParent(); + } + + return $updated; + } + + /** + * Upgrades the permissions schema of the given users and its parent (including parent groups) to the chosen version. + * Please note that this function does not flush the changes to DB! + * @param User $user + * @param int $target_version + * @return bool True if an upgrade was done, false if it was not needed. + */ + public function userUpgradeSchemaRecursively(User $user, int $target_version = PermissionData::CURRENT_SCHEMA_VERSION): bool + { + $updated = $this->upgradeSchema($user, $target_version); + $updated = $this->groupUpgradeSchemaRecursively($user->getGroup(), $target_version) || $updated; + + return $updated; + } + private function upgradeSchemaToVersion1(HasPermissionsInterface $holder): void { //Use the part edit permission to set the preset value for the new part stock permission diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 585cf567..072af113 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -10217,5 +10217,11 @@ Element 3 Move parts between lots + + + user.permissions_schema_updated + The permission schema of your user were upgraded to the latest version. + +