diff --git a/src/Controller/PermissionController.php b/src/Controller/PermissionController.php index e7566710..d08c7f38 100644 --- a/src/Controller/PermissionController.php +++ b/src/Controller/PermissionController.php @@ -16,6 +16,7 @@ use App\Event\PermissionSectionsEvent; use App\Event\PermissionsEvent; use App\Form\RoleType; use App\Model\PermissionSection; +use App\Repository\Query\UserQuery; use App\Repository\RoleRepository; use App\Repository\UserRepository; use App\Security\RolePermissionManager; @@ -46,7 +47,7 @@ final class PermissionController extends AbstractController #[Route(path: '', name: 'admin_user_permissions', methods: ['GET', 'POST'])] #[IsGranted('role_permissions')] - public function permissions(EventDispatcherInterface $dispatcher, CsrfTokenManagerInterface $csrfTokenManager, RoleService $roleService): Response + public function permissions(EventDispatcherInterface $dispatcher, CsrfTokenManagerInterface $csrfTokenManager, RoleService $roleService, UserRepository $userRepository): Response { $all = $this->roleRepository->findAll(); $existing = []; @@ -151,7 +152,10 @@ final class PermissionController extends AbstractController $page->setHelp('permissions.html'); $page->setActionName('user_permissions'); + $users = $userRepository->getUsersForQuery(new UserQuery()); + return $this->render('permission/permissions.html.twig', [ + 'users' => $users, 'page_setup' => $page, 'token' => $csrfTokenManager->refreshToken(self::TOKEN_NAME)->getValue(), 'roles' => array_values($roles), diff --git a/src/Entity/Role.php b/src/Entity/Role.php index d2c3224d..eaa9403c 100644 --- a/src/Entity/Role.php +++ b/src/Entity/Role.php @@ -46,4 +46,9 @@ class Role return $this; } + + public function isUser(): bool + { + return $this->name === User::ROLE_USER; + } } diff --git a/src/Form/RoleType.php b/src/Form/RoleType.php index c27c31d7..9b552857 100644 --- a/src/Form/RoleType.php +++ b/src/Form/RoleType.php @@ -34,22 +34,43 @@ final class RoleType extends AbstractType ] ]); + $replacer = function ($roleName): ?string { + if ($roleName === null) { + return null; + } + + if (\is_string($roleName)) { + $roleName = preg_replace('/[^a-zA-Z_]/', '_', $roleName); + $roleName = preg_replace('/_+/', '_', $roleName ?? ''); + $roleName = ltrim($roleName ?? '', '_'); + $roleName = rtrim($roleName, '_'); + $roleName = strtoupper($roleName); + } + + return $roleName; + }; + // help the user to figure out the allowed name $builder->get('name')->addViewTransformer( new CallbackTransformer( - function ($roleName) { - if (\is_string($roleName)) { - $roleName = str_replace(' ', '_', $roleName); - $roleName = str_replace('-', '_', $roleName); - } - - return $roleName; + function ($roleName) use ($replacer) { + return $replacer($roleName); }, function ($roleName) { return $roleName; } ) ); + $builder->get('name')->addModelTransformer( + new CallbackTransformer( + function ($roleName) { + return $roleName; + }, + function ($roleName) use ($replacer) { + return $replacer($roleName); + } + ) + ); } public function configureOptions(OptionsResolver $resolver): void diff --git a/templates/permission/permissions.html.twig b/templates/permission/permissions.html.twig index bfce0618..3ba77fac 100644 --- a/templates/permission/permissions.html.twig +++ b/templates/permission/permissions.html.twig @@ -9,6 +9,7 @@ 'name': 'alwaysVisible', } %} {% set canEditPermissions = is_granted('role_permissions') %} +
{% for role in roles %} {% set class = 'alwaysVisible text-center' %} {% if role.name == 'ROLE_SUPER_ADMIN' %} @@ -16,17 +17,48 @@ {% elseif role.name == 'ROLE_USER' %} {% set class = class ~ ' bg-green-lt' %} {% endif %} - {% set options = {'class': class} %} - {% if canEditPermissions and (role.name not in system_roles) %} - {% set widget %} -  {{ icon('trash') }} - {% endset %} - {% set options = options|merge({'html_after': widget}) %} + {% set columns = columns|merge({(role.name): {'class': class}}) %} + {% set roleUsers = [] %} + {% for user in users %} + {% if user.hasRole(role.getName()) %} + {% set roleUsers = roleUsers|merge([user]) %} + {% endif %} + {% endfor %} + + {% if not role.isUser() %} +
+
+
+
+

+ {{ role.getName()|trans }} + {% if canEditPermissions and (role.name not in system_roles) %} +   + {{ icon('trash') }} + {% endif %} +

+
+ {% if is_granted('view_user') %} + {{ 'amount'|trans }}: {{ roleUsers|length }} + {% else %} + Total {{ roleUsers|length }} users + {% endif %} +
+
+
+
+ {% for user in roleUsers %} + {{ widgets.user_avatar(user, user.displayName, 'avatar-rounded avatar-xs') }} + {% endfor %} +
+
+
+
+
{% endif %} - {% set columns = columns|merge({ - (role.name): options, - }) %} {% endfor %} +
+ {% set tableName = 'user_admin_permissions' %} diff --git a/tests/Controller/PermissionControllerTest.php b/tests/Controller/PermissionControllerTest.php index 32efd721..8b543742 100644 --- a/tests/Controller/PermissionControllerTest.php +++ b/tests/Controller/PermissionControllerTest.php @@ -19,17 +19,17 @@ use App\Entity\User; */ class PermissionControllerTest extends ControllerBaseTest { - public function testIsSecure() + public function testIsSecure(): void { $this->assertUrlIsSecured('/admin/permissions'); } - public function testIsSecureForRole() + public function testIsSecureForRole(): void { $this->assertUrlIsSecuredForRole(User::ROLE_ADMIN, '/admin/permissions'); } - public function testPermissions() + public function testPermissions(): void { $client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN); $this->assertAccessIsGranted($client, '/admin/permissions'); @@ -52,17 +52,17 @@ class PermissionControllerTest extends ControllerBaseTest self::assertStringContainsString('', $content); } - public function testCreateRoleIsSecured() + public function testCreateRoleIsSecured(): void { $this->assertUrlIsSecured('/admin/permissions/roles/create'); } - public function testCreateRoleIsSecuredForRole() + public function testCreateRoleIsSecuredForRole(): void { $this->assertUrlIsSecuredForRole(User::ROLE_ADMIN, '/admin/permissions'); } - public function testCreateRole() + public function testCreateRole(): void { $client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN); $this->assertAccessIsGranted($client, '/admin/permissions/roles/create'); @@ -79,17 +79,17 @@ class PermissionControllerTest extends ControllerBaseTest $this->assertTableHeader($content); } - public function testDeleteRoleIsSecured() + public function testDeleteRoleIsSecured(): void { $this->assertUrlIsSecured('/admin/permissions/roles/1/delete/sdfsdfsdfsd'); } - public function testDeleteRoleIsSecuredForRole() + public function testDeleteRoleIsSecuredForRole(): void { $this->assertUrlIsSecuredForRole(User::ROLE_ADMIN, '/admin/permissions'); } - public function testDeleteRole() + public function testDeleteRole(): void { $client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN); $this->assertAccessIsGranted($client, '/admin/permissions/roles/create'); @@ -132,7 +132,7 @@ class PermissionControllerTest extends ControllerBaseTest $this->assertEquals(['ROLE_TEAMLEAD', 'ROLE_SUPER_ADMIN', 'TEST_ROLE', 'ROLE_USER'], $user->getRoles()); $this->request($client, '/admin/permissions'); - $node = $client->getCrawler()->filter('table.dataTable thead th a.confirmation-link'); + $node = $client->getCrawler()->filter('div.card .card-title a.confirmation-link'); self::assertEquals(1, $node->count()); $this->request($client, $node->attr('href')); @@ -148,17 +148,17 @@ class PermissionControllerTest extends ControllerBaseTest $this->assertEquals(['ROLE_TEAMLEAD', 'ROLE_SUPER_ADMIN', 'ROLE_USER'], $user->getRoles()); } - public function testSavePermissionIsSecured() + public function testSavePermissionIsSecured(): void { $this->assertUrlIsSecured('/admin/permissions/roles/1/view_user/1/asdfasdf', 'POST'); } - public function testSavePermissionIsSecuredForRole() + public function testSavePermissionIsSecuredForRole(): void { $this->assertUrlIsSecuredForRole(User::ROLE_ADMIN, '/admin/permissions'); } - public function testSavePermission() + public function testSavePermission(): void { $client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN); $this->assertAccessIsGranted($client, '/admin/permissions/roles/create'); diff --git a/tests/Entity/RoleTest.php b/tests/Entity/RoleTest.php index d8462ad3..66b9f014 100644 --- a/tests/Entity/RoleTest.php +++ b/tests/Entity/RoleTest.php @@ -22,6 +22,7 @@ class RoleTest extends TestCase $sut = new Role(); self::assertNull($sut->getId()); self::assertNull($sut->getName()); + self::assertFalse($sut->isUser()); } public function testSetterAndGetter(): void @@ -30,8 +31,13 @@ class RoleTest extends TestCase $sut->setName('foo'); self::assertEquals('FOO', $sut->getName()); + self::assertFalse($sut->isUser()); $sut->setName('BAR'); self::assertEquals('BAR', $sut->getName()); + self::assertFalse($sut->isUser()); + + $sut->setName('ROLE_USER'); + self::assertTrue($sut->isUser()); } } diff --git a/tests/phpstan.neon b/tests/phpstan.neon index 02bcd497..68afa73e 100644 --- a/tests/phpstan.neon +++ b/tests/phpstan.neon @@ -2572,66 +2572,6 @@ parameters: count: 1 path: Controller/PermissionControllerTest.php - - - message: "#^Method App\\\\Tests\\\\Controller\\\\PermissionControllerTest\\:\\:testCreateRole\\(\\) has no return type specified\\.$#" - count: 1 - path: Controller/PermissionControllerTest.php - - - - message: "#^Method App\\\\Tests\\\\Controller\\\\PermissionControllerTest\\:\\:testCreateRoleIsSecured\\(\\) has no return type specified\\.$#" - count: 1 - path: Controller/PermissionControllerTest.php - - - - message: "#^Method App\\\\Tests\\\\Controller\\\\PermissionControllerTest\\:\\:testCreateRoleIsSecuredForRole\\(\\) has no return type specified\\.$#" - count: 1 - path: Controller/PermissionControllerTest.php - - - - message: "#^Method App\\\\Tests\\\\Controller\\\\PermissionControllerTest\\:\\:testDeleteRole\\(\\) has no return type specified\\.$#" - count: 1 - path: Controller/PermissionControllerTest.php - - - - message: "#^Method App\\\\Tests\\\\Controller\\\\PermissionControllerTest\\:\\:testDeleteRoleIsSecured\\(\\) has no return type specified\\.$#" - count: 1 - path: Controller/PermissionControllerTest.php - - - - message: "#^Method App\\\\Tests\\\\Controller\\\\PermissionControllerTest\\:\\:testDeleteRoleIsSecuredForRole\\(\\) has no return type specified\\.$#" - count: 1 - path: Controller/PermissionControllerTest.php - - - - message: "#^Method App\\\\Tests\\\\Controller\\\\PermissionControllerTest\\:\\:testIsSecure\\(\\) has no return type specified\\.$#" - count: 1 - path: Controller/PermissionControllerTest.php - - - - message: "#^Method App\\\\Tests\\\\Controller\\\\PermissionControllerTest\\:\\:testIsSecureForRole\\(\\) has no return type specified\\.$#" - count: 1 - path: Controller/PermissionControllerTest.php - - - - message: "#^Method App\\\\Tests\\\\Controller\\\\PermissionControllerTest\\:\\:testPermissions\\(\\) has no return type specified\\.$#" - count: 1 - path: Controller/PermissionControllerTest.php - - - - message: "#^Method App\\\\Tests\\\\Controller\\\\PermissionControllerTest\\:\\:testSavePermission\\(\\) has no return type specified\\.$#" - count: 1 - path: Controller/PermissionControllerTest.php - - - - message: "#^Method App\\\\Tests\\\\Controller\\\\PermissionControllerTest\\:\\:testSavePermissionIsSecured\\(\\) has no return type specified\\.$#" - count: 1 - path: Controller/PermissionControllerTest.php - - - - message: "#^Method App\\\\Tests\\\\Controller\\\\PermissionControllerTest\\:\\:testSavePermissionIsSecuredForRole\\(\\) has no return type specified\\.$#" - count: 1 - path: Controller/PermissionControllerTest.php - - message: "#^Parameter \\#1 \\$content of method App\\\\Tests\\\\Controller\\\\PermissionControllerTest\\:\\:assertTableHeader\\(\\) expects string, string\\|false given\\.$#" count: 2