From 01f73c2ef40e6424b8de53f817205d17df36185b Mon Sep 17 00:00:00 2001 From: Charles Date: Wed, 21 Jan 2026 10:01:13 +0100 Subject: [PATCH] Test for User Controller --- assets/controllers/user_controller.js | 1 + src/Controller/OrganizationController.php | 25 +- src/Controller/UserController.php | 38 +- src/Service/OrganizationsService.php | 4 +- src/Service/UserOrganizationService.php | 17 +- src/Service/UserService.php | 7 +- templates/user/edit.html.twig | 2 + templates/user/index.html.twig | 2 +- templates/user/userInformation.html.twig | 5 +- tests/Controller/UserControllerTest.php | 604 ++++++++++++++++++++++ 10 files changed, 675 insertions(+), 30 deletions(-) create mode 100644 tests/Controller/UserControllerTest.php diff --git a/assets/controllers/user_controller.js b/assets/controllers/user_controller.js index e8fd81f..c94cd8e 100644 --- a/assets/controllers/user_controller.js +++ b/assets/controllers/user_controller.js @@ -58,6 +58,7 @@ export default class extends Controller { table() { const columns = [ { + placeholder: "Aucun utilisateur trouvé", title: "", field: "isConnected", width: 40, // small column diff --git a/src/Controller/OrganizationController.php b/src/Controller/OrganizationController.php index ac8c076..96df1a2 100644 --- a/src/Controller/OrganizationController.php +++ b/src/Controller/OrganizationController.php @@ -54,7 +54,18 @@ class OrganizationController extends AbstractController $actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier()); if($this->userService->hasAccessTo($actingUser, true)){ $orgCount = $this->organizationsRepository->count(['isDeleted' => false]); - + if(!$this->isGranted("ROLE_SUPER_ADMIN")){ + $userUO = $this->entityManager->getRepository(UsersOrganizations::class)->findBy(['users' => $actingUser, 'isActive' => true]); + $uoAdmin = 0; + foreach($userUO as $u){ + if($this->userService->isAdminOfOrganization($u->getOrganization())){ + $uoAdmin++; + } + } + if($uoAdmin === 1){ + return $this->redirectToRoute('organization_show', ['id' => $userUO[0]->getOrganization()->getId()]); + } + } return $this->render('organization/index.html.twig', [ 'hasOrganizations' => $orgCount > 0 ]); @@ -297,6 +308,17 @@ class OrganizationController extends AbstractController $qb->andWhere('o.email LIKE :email') ->setParameter('email', '%' . $filters['email'] . '%'); } + if(!$this->isGranted('ROLE_SUPER_ADMIN')) { + $actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier()); + $uo = $this->entityManager->getRepository(UsersOrganizations::class)->findBy(['users' => $actingUser]); + foreach ($uo as $item) { + if($this->userService->isAdminOfOrganization($item->getOrganization())) { + $qb->andWhere('o.id = :orgId') + ->setParameter('orgId', $item->getOrganization()->getId()); + } + } + } + // Count total $countQb = clone $qb; @@ -319,7 +341,6 @@ class OrganizationController extends AbstractController ]; }, $rows); - // Tabulator expects: data, last_page (total pages), or total row count depending on config $lastPage = (int)ceil($total / $size); return $this->json([ diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index e3af065..32dc466 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -77,6 +77,10 @@ class UserController extends AbstractController // Chargement de l'utilisateur cible à afficher $user = $this->userRepository->find($id); + if (!$user) { + $this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId()); + throw $this->createNotFoundException(self::NOT_FOUND); + } if (!$this->userService->hasAccessTo($user)) { $this->loggerService->logAccessDenied($actingUser->getId()); throw new AccessDeniedHttpException (self::ACCESS_DENIED); @@ -166,7 +170,7 @@ class UserController extends AbstractController // ------------------------------------------------------------------- // Calcul du flag de modification : utilisateur admin ET exactement 1 UO - $canEdit = $this->userService->canEditRolesCheck($actingUser, $user, $organization, $this->isGranted('ROLE_ADMIN')); + $canEdit = $this->userService->canEditRolesCheck($actingUser, $user, $organization, $this->isGranted('ROLE_ADMIN'), $singleUo); } catch (\Exception $e) { // En cas d'erreur, désactiver l'édition et logger l'exception @@ -187,14 +191,15 @@ class UserController extends AbstractController public function edit(int $id, Request $request): Response { $this->denyAccessUnlessGranted('ROLE_USER'); + $actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier()); + $user = $this->userRepository->find($id); + if (!$user) { + $this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId()); + throw $this->createNotFoundException(self::NOT_FOUND); + } try { - $actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier()); - if ($this->userService->hasAccessTo($actingUser)) { - $user = $this->userRepository->find($id); - if (!$user) { - $this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId()); - throw $this->createNotFoundException(self::NOT_FOUND); - } + if ($this->userService->hasAccessTo($user)) { + $form = $this->createForm(UserForm::class, $user); $form->handleRequest($request); @@ -277,6 +282,13 @@ class UserController extends AbstractController $this->loggerService->logEntityNotFound('Organization', ['id' => $orgId], $actingUser->getId()); throw $this->createNotFoundException(self::NOT_FOUND); } + if($this->isGranted('ROLE_ADMIN') && !$this->userService->isAdminOfOrganization($org) && !$this->isGranted('ROLE_SUPER_ADMIN')) { + $this->loggerService->logAccessDenied($actingUser->getId()); + throw $this->createAccessDeniedException(self::ACCESS_DENIED); + } + }elseif($this->isGranted('ROLE_ADMIN')) { + $this->loggerService->logAccessDenied($actingUser->getId()); + throw $this->createAccessDeniedException(self::ACCESS_DENIED); } if ($form->isSubmitted() && $form->isValid()) { @@ -334,7 +346,7 @@ class UserController extends AbstractController } // Case : Organization provided and user doesn't already exist - if ($org) { + if ($orgId) { $this->userService->linkUserToOrganization( $user, $org, @@ -541,7 +553,6 @@ class UserController extends AbstractController try { $user = $this->userRepository->find($id); - if (!$user) { // Security/audit log for missing user $this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId()); @@ -550,10 +561,10 @@ class UserController extends AbstractController } // Soft delete the user + $user->setIsActive(false); $user->setIsDeleted(true); $user->setModifiedAt(new \DateTimeImmutable('now')); - // Deactivate all org links $this->userOrganizationService->deactivateAllUserOrganizationLinks($actingUser, $user); $this->loggerService->logOrganizationInformation($user->getId(), $actingUser->getId(), 'All user organization links deactivated'); @@ -596,7 +607,7 @@ class UserController extends AbstractController // No rethrow here: deletion succeeded; only notifications failed } - return new Response('', Response::HTTP_NO_CONTENT); // 204 + return $this->redirectToRoute('user_index'); } catch (\Exception $e) { // Route-level error logging → error.log @@ -609,7 +620,7 @@ class UserController extends AbstractController throw $e; // keep 404 semantics } - return new Response('', Response::HTTP_INTERNAL_SERVER_ERROR); + return $this->redirectToRoute('user_index'); } } @@ -722,7 +733,6 @@ class UserController extends AbstractController 'statut' => $user->isActive(), ]; }, $rows); - $lastPage = (int)ceil($total / $size); return $this->json([ diff --git a/src/Service/OrganizationsService.php b/src/Service/OrganizationsService.php index 5ce58ae..25e2400 100644 --- a/src/Service/OrganizationsService.php +++ b/src/Service/OrganizationsService.php @@ -76,7 +76,7 @@ class OrganizationsService } - public function notifyOrganizationAdmins(array $data, string $type): UsersOrganizations + public function notifyOrganizationAdmins(array $data, string $type): void { $roleAdmin = $this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'ADMIN']); @@ -166,8 +166,6 @@ class OrganizationsService } } - - return $adminUO; } } diff --git a/src/Service/UserOrganizationService.php b/src/Service/UserOrganizationService.php index afd2d42..b5caca9 100644 --- a/src/Service/UserOrganizationService.php +++ b/src/Service/UserOrganizationService.php @@ -42,14 +42,17 @@ readonly class UserOrganizationService $uos = $this->entityManager->getRepository(UsersOrganizations::class)->findBy(['organization' => $organizations, 'isActive' => true]); } //deactivate all UO links - foreach ($uos as $uo) { - $this->userOrganizationAppService->deactivateAllUserOrganizationsAppLinks($uo); - $this->loggerService->logOrganizationInformation($uo->getOrganization()->getId(), $actingUser->getId(), - 'Uo link deactivated'); - $uo->setIsActive(false); - $this->entityManager->persist($uo); - $this->actionService->createAction("Deactivate UO link", $actingUser, $uo->getOrganization(), $uo->getOrganization()->getName() ); + if (!empty($uos)) { + foreach ($uos as $uo) { + $this->userOrganizationAppService->deactivateAllUserOrganizationsAppLinks($uo); + $this->loggerService->logOrganizationInformation($uo->getOrganization()->getId(), $actingUser->getId(), + 'Uo link deactivated'); + $uo->setIsActive(false); + $this->entityManager->persist($uo); + $this->actionService->createAction("Deactivate UO link", $actingUser, $uo->getOrganization(), $uo->getOrganization()->getName() ); + } } + } diff --git a/src/Service/UserService.php b/src/Service/UserService.php index a8078a4..211203e 100644 --- a/src/Service/UserService.php +++ b/src/Service/UserService.php @@ -407,15 +407,18 @@ class UserService return $rolesArray; } - public function canEditRolesCheck(User $actingUser, User $user, $org, bool $isAdmin): bool + public function canEditRolesCheck(User $actingUser, User $user, $org, bool $isAdmin, UsersOrganizations $uo = null): bool { $userRoles = $user->getRoles(); $actingUserRoles = $actingUser->getRoles(); // if acting user is admin, he can´t edit super admin roles - if (in_array('ROLE_SUPER_ADMIN', $userRoles, true) && !in_array('ROLE_SUPER_ADMIN', $actingUserRoles, true)) { + if (!in_array('ROLE_SUPER_ADMIN', $actingUserRoles, true) && in_array('ROLE_SUPER_ADMIN', $userRoles, true)) { return false; } + if ($uo && $this->isAdminOfOrganization($uo->getOrganization())) { + return true; + } return $isAdmin && !empty($org); } diff --git a/templates/user/edit.html.twig b/templates/user/edit.html.twig index a45edf6..6dee523 100644 --- a/templates/user/edit.html.twig +++ b/templates/user/edit.html.twig @@ -7,7 +7,9 @@

Modifier l'utilisateur

+ {% if is_granted('ROLE_SUPER_ADMIN') %} Supprimer + {% endif %}
diff --git a/templates/user/index.html.twig b/templates/user/index.html.twig index f2fb290..99550e6 100644 --- a/templates/user/index.html.twig +++ b/templates/user/index.html.twig @@ -9,7 +9,7 @@

Gestion Utilisateurs

- Ajouter un utilisateur +{# Ajouter un utilisateur#}
diff --git a/templates/user/userInformation.html.twig b/templates/user/userInformation.html.twig index c4f50c9..207638a 100644 --- a/templates/user/userInformation.html.twig +++ b/templates/user/userInformation.html.twig @@ -15,7 +15,10 @@ {% if canEdit %} Modifier - {% endif %} + {% elseif user.id == app.user.id %} + Modifier + {% endif %}
diff --git a/tests/Controller/UserControllerTest.php b/tests/Controller/UserControllerTest.php new file mode 100644 index 0000000..c132178 --- /dev/null +++ b/tests/Controller/UserControllerTest.php @@ -0,0 +1,604 @@ +createUser('admin@admin.com', ['ROLE_SUPER_ADMIN']); + $this->client->loginUser($admin); + + $this->client->request('GET', '/user/'); + self::assertResponseIsSuccessful(); + self::assertSelectorTextNotContains('body', 'Aucun utilisateur trouvé'); + self::assertSelectorExists('#tabulator-userList'); + + } + + #[Test] + public function test_index_regular_user_forbidden(): void + { + // 1. Arrange + $user = $this->createUser('user@mail.com'); + $this->client->loginUser($user); + + // 2. Act + $this->client->request('GET', '/user/'); + // 3. Assert + self::assertResponseStatusCodeSame(403); + + } + + //Can't test for no users as page is designed to always have at least one user (the logged in one) + //endregion + + //region Show Tests + + #[Test] + public function test_view_super_admin(): void + { + $admin = $this->createUser('admin@admin', ['ROLE_SUPER_ADMIN']); + $this->client->loginUser($admin); + + $role = $this->createRole('ADMIN'); + $role2 = $this->createRole('EMPTY'); + $app = $this->createApp('Test App'); + $organization = $this->createOrganization('Test Org'); + $uo = $this->createUOLink($admin, $organization); + $uoa = $this->createUOALink($uo, $app, $role); + + $this->client->request('GET', '/user/view/' . $admin->getId()); + self::assertResponseIsSuccessful(); + self::assertSelectorTextContains('body', $admin->getEmail()); + self::assertSelectorTextContains('body', $admin->getName()); + self::assertSelectorTextContains('body', $app->getName()); + self::assertSelectorTextContains('body', ucfirst(strtolower($role->getName()))); + self::assertCheckboxChecked("roles[]", ucfirst(strtolower($role->getName()))); + } + + #[Test] + public function test_view_regular_user_forbidden(): void + { + // 1. Arrange + $user = $this->createUser('user@email.com'); + $user2 = $this->createUser('user2@email.com'); + $this->client->loginUser($user); + // 2. Act + $this->client->request('GET', '/user/view/' . $user2->getId()); + // 3. Assert + self::assertResponseStatusCodeSame(403); + } + + #[Test] + public function test_view_admin(): void + { + $admin = $this->createUser('admin@admin', ['ROLE_ADMIN']); + $user = $this->createUser('user@admin'); + $this->client->loginUser($admin); + + $role = $this->createRole('ADMIN'); + $role2 = $this->createRole('USER'); + $app = $this->createApp('Test App'); + $organization = $this->createOrganization('Test Org'); + $uo = $this->createUOLink($admin, $organization); + $uo2 = $this->createUOLink($user, $organization); + $uoa = $this->createUOALink($uo, $app, $role); + $uoa2 = $this->createUOALink($uo2, $app, $role2); + + $this->client->request('GET', '/user/view/' . $user->getId() . '?organizationId=' . $organization->getId()); + self::assertResponseIsSuccessful(); + self::assertSelectorTextContains('body', $user->getEmail()); + self::assertSelectorTextContains('body', $user->getName()); + self::assertSelectorTextContains('body', $app->getName()); + self::assertSelectorTextContains('body', ucfirst(strtolower($role->getName()))); + } + + #[Test] + public function test_view_admin_different_organization_forbidden(): void + { + $admin = $this->createUser('admin@admin', ['ROLE_ADMIN']); + $user = $this->createUser('user@admin'); + $this->client->loginUser($admin); + + $role = $this->createRole('ADMIN'); + $role2 = $this->createRole('USER'); + $app = $this->createApp('Test App'); + $organization = $this->createOrganization('Test Org'); + $organization2 = $this->createOrganization('Test Org2'); + $uo = $this->createUOLink($admin, $organization); + $uo2 = $this->createUOLink($user, $organization2); + $uoa = $this->createUOALink($uo, $app, $role); + $uoa2 = $this->createUOALink($uo2, $app, $role2); + + $this->client->request('GET', '/user/view/' . $user->getId() . '?organizationId=' . $organization->getId()); + self::assertResponseStatusCodeSame(403); + } + + #[Test] + public function test_view_user_self_success(): void + { + $user = $this->createUser('user@email.com'); + $this->client->loginUser($user); + $this->client->request('GET', '/user/view/' . $user->getId()); + self::assertResponseIsSuccessful(); + self::assertSelectorTextContains('body', $user->getEmail()); + } + + #[Test] + public function test_view_user_self_with_organization_success(): void + { + $user = $this->createUser('user@email.com'); + $organization = $this->createOrganization('Test Org'); + $uo = $this->createUOLink($user, $organization); + $this->client->loginUser($user); + $this->client->request('GET', '/user/view/' . $user->getId()); + self::assertResponseIsSuccessful(); + self::assertSelectorTextContains('body', $user->getEmail()); + } + + #[Test] + public function test_view_user_not_found(): void + { + $admin = $this->createUser('admin@admin', ['ROLE_SUPER_ADMIN']); + $this->client->loginUser($admin); + + $this->client->request('GET', '/user/view/999999'); + self::assertResponseStatusCodeSame(404); + } + //endregion + + //region Edit Tests + + #[Test] + public function test_edit_super_admin_success(): void + { + $admin = $this->createUser('admin@admin', ['ROLE_SUPER_ADMIN']); + $this->client->loginUser($admin); + $this->client->request('GET', '/user/edit/' . $admin->getId()); + self::assertResponseIsSuccessful(); + self::assertSelectorTextContains('body', 'Modifier l\'utilisateur'); + } + + #[Test] + public function test_edit_regular_user_forbidden(): void + { + // 1. Arrange + $user = $this->createUser('user@mail.com'); + $this->client->loginUser($user); + // 2. Act + $this->client->request('GET', '/user/edit/' . $user->getId()); + // 3. Assert + self::assertResponseIsSuccessful(); + self::assertSelectorTextContains('body', 'Modifier l\'utilisateur'); + } + + #[Test] + public function test_edit_other_user_forbidden(): void + { + // 1. Arrange + $user = $this->createUser('user@email.com'); + $user2 = $this->createUser('user2@email.com'); + $this->client->loginUser($user); + // 2. Act + $this->client->request('GET', '/user/edit/' . $user2->getId()); + // 3. Assert + self::assertResponseStatusCodeSame(403); + } + + #[Test] + public function test_edit_user_not_found(): void + { + $admin = $this->createUser('admin@admin', ['ROLE_SUPER_ADMIN']); + $this->client->loginUser($admin); + + $this->client->request('GET', '/user/edit/999999'); + self::assertResponseStatusCodeSame(404); + } + + #[Test] + public function test_edit_super_admin_edit_other_user_success(): void + { + // 1. Arrange: Disable reboot to keep our AWS mock alive + $this->client->disableReboot(); + + $admin = $this->createUser('admin@user.com', ['ROLE_SUPER_ADMIN']); + $this->client->loginUser($admin); + + // 2. MOCK AWS Service (Crucial!) + // Your code calls $awsService->PutDocObj, so we must intercept that. + // 2. MOCK AWS Service + $awsMock = $this->createMock(AwsService::class); + $awsMock->expects($this->any()) + ->method('PutDocObj') + ->willReturn(1); // <--- FIXED: Return an integer, not a boolean + + // Inject the mock into the test container + static::getContainer()->set(AwsService::class, $awsMock); + + // 3. Create a Dummy Image File + $tempFile = tempnam(sys_get_temp_dir(), 'test_logo'); + file_put_contents($tempFile, 'fake image content'); // Create a dummy file + + $logo = new UploadedFile( + $tempFile, + 'logo.png', + 'image/png', + null, + true // 'test' mode = true + ); + + // 4. Act: Submit the Edit Form + $this->client->request('GET', '/user/edit/' . $admin->getId()); + $this->client->submitForm('Enregistrer', [ + 'user_form[email]' => 'new@mail.com', + 'user_form[name]' => 'New Name', + 'user_form[pictureUrl]' => $logo, + ]); + + // 5. Assert + self::assertResponseRedirects('/user/view/' . $admin->getId()); + $this->client->followRedirect(); + self::assertSelectorTextContains('body', 'new@mail.com'); + + // Clean up the temporary file} + unlink($tempFile); + } + + #[Test] + public function test_edit_admin_user_not_found(): void + { + $admin = $this->createUser('admin@admin', ['ROLE_SUPER_ADMIN']); + $this->client->loginUser($admin); + $this->client->request('GET', '/user/edit/999999'); + self::assertResponseStatusCodeSame(404); + } + + #[Test] + public function test_edit_admin_edit_other_user_success(): void + { + // 1. Arrange: Disable reboot to keep our AWS mock alive + $this->client->disableReboot(); + + $admin = $this->createUser('admin@user.com', ['ROLE_ADMIN']); + $user = $this->createUser('user@user.com'); + $this->client->loginUser($admin); + $org = $this->createOrganization('Test Org'); + $uoAdmin = $this->createUOLink($admin, $org); + $uoUser = $this->createUOLink($user, $org); + $app = $this->createApp('Test App'); + $roleAdmin = $this->createRole('ADMIN'); + $roleUser = $this->createRole('USER'); + $this->createUOALink($uoAdmin, $app, $roleAdmin); + $this->createUOALink($uoUser, $app, $roleUser); + + // 2. MOCK AWS Service (Crucial!) + // Your code calls $awsService->PutDocObj, so we must intercept that. + // 2. MOCK AWS Service + $awsMock = $this->createMock(AwsService::class); + $awsMock->expects($this->any()) + ->method('PutDocObj') + ->willReturn(1); // <--- FIXED: Return an integer, not a boolean + + // Inject the mock into the test container + static::getContainer()->set(AwsService::class, $awsMock); + + // 3. Create a Dummy Image File + $tempFile = tempnam(sys_get_temp_dir(), 'test_logo'); + file_put_contents($tempFile, 'fake image content'); // Create a dummy file + + $logo = new UploadedFile( + $tempFile, + 'logo.png', + 'image/png', + null, + true // 'test' mode = true + ); + + // 4. Act: Submit the Edit Form + $this->client->request('GET', '/user/edit/' . $user->getId() . '?organizationId=' . $org->getId()); + $this->client->submitForm('Enregistrer', [ + 'user_form[email]' => 'new@mail.com', + 'user_form[name]' => 'New Name', + 'user_form[pictureUrl]' => $logo, + ]); + + // 5. Assert + self::assertResponseRedirects('/user/view/' . $user->getId() . '?organizationId=' . $org->getId()); + $this->client->followRedirect(); + self::assertSelectorTextContains('body', 'new@mail.com'); + + // Clean up the temporary file} + unlink($tempFile); + } + + + #[Test] + public function test_edit_admin_edit_other_user_different_organization_forbidden(): void + { + // 1. Arrange: Disable reboot to keep our AWS mock alive + $this->client->disableReboot(); + + $admin = $this->createUser('admin@user.com', ['ROLE_ADMIN']); + $user = $this->createUser('user@user.com'); + $this->client->loginUser($admin); + $org = $this->createOrganization('Test Org'); + $org2 = $this->createOrganization('Test Org2'); + $uoAdmin = $this->createUOLink($admin, $org); + $uoUser = $this->createUOLink($user, $org2); + $app = $this->createApp('Test App'); + $roleAdmin = $this->createRole('ADMIN'); + $roleUser = $this->createRole('USER'); + $this->createUOALink($uoAdmin, $app, $roleAdmin); + $this->createUOALink($uoUser, $app, $roleUser); + + // 2. MOCK AWS Service (Crucial!) + // Your code calls $awsService->PutDocObj, so we must intercept that. + // 2. MOCK AWS Service + $awsMock = $this->createMock(AwsService::class); + $awsMock->expects($this->any()) + ->method('PutDocObj') + ->willReturn(1); // <--- FIXED: Return an integer, not a boolean + + // Inject the mock into the test container + static::getContainer()->set(AwsService::class, $awsMock); + + // 3. Create a Dummy Image File + $tempFile = tempnam(sys_get_temp_dir(), 'test_logo'); + file_put_contents($tempFile, 'fake image content'); // Create a dummy file + + $logo = new UploadedFile( + $tempFile, + 'logo.png', + 'image/png', + null, + true // 'test' mode = true + ); + + // 4. Act: Submit the Edit Form + $this->client->request('GET', '/user/edit/' . $user->getId() . '?organizationId=' . $org2->getId()); + // 5. Assert + self::assertResponseStatusCodeSame(403); + } + + #[Test] + public function test_edit_user_not_found_admin(): void + { + $admin = $this->createUser('admin@admin', ['ROLE_ADMIN']); + $this->client->loginUser($admin); + + $this->client->request('GET', '/user/edit/999999'); + self::assertResponseStatusCodeSame(404); + } + + #[Test] + public function test_edit_user_self_success(): void + { + $user = $this->createUser('user@email.com'); + $this->client->loginUser($user); + $this->client->request('GET', '/user/edit/' . $user->getId()); + self::assertResponseIsSuccessful(); + self::assertSelectorTextContains('body', 'Modifier l\'utilisateur'); + $this->client->submitForm('Enregistrer', [ + 'user_form[email]' => 'new@email.com', + 'user_form[name]' => 'New Name', + ]); + self::assertResponseRedirects('/user/view/' . $user->getId()); + $this->client->followRedirect(); + self::assertSelectorTextContains('body', 'new@email.com'); + } + + #[Test] + public function test_edit_user_self_with_organization_success(): void + { + $user = $this->createUser('user@email.com'); + $this->client->loginUser($user); + $org = $this->createOrganization('Test Org'); + $this->createUOLink($user, $org); + $this->client->request('GET', '/user/edit/' . $user->getId() . '?organizationId=' . $org->getId()); + self::assertResponseIsSuccessful(); + self::assertSelectorTextContains('body', 'Modifier l\'utilisateur'); + $this->client->submitForm('Enregistrer', [ + 'user_form[email]' => 'new@email.com', + 'user_form[name]' => 'New Name', + ]); + self::assertResponseRedirects('/user/view/' . $user->getId() . '?organizationId=' . $org->getId()); + $this->client->followRedirect(); + self::assertSelectorTextContains('body', 'new@email.com'); + } + //endregion + + //region Create Tests + + #[Test] + public function test_create_super_admin_forbidden(): void + { + $admin = $this->createUser('admin@admin.com', ['ROLE_SUPER_ADMIN']); + $this->client->loginUser($admin); + $this->client->request('GET', '/user/new'); + $this->client->followRedirect(); + self::assertResponseStatusCodeSame(403); + } + + #[Test] + public function test_create_regular_user_forbidden(): void + { + // 1. Arrange + $user = $this->createUser('user@email.com'); + $this->client->loginUser($user); + // 2. Act + $this->client->request('GET', '/user/new'); + // 3. Assert + self::assertResponseStatusCodeSame(403); + } + + #[Test] + public function test_create_admin_forbidden(): void + { + // 1. Arrange + $admin = $this->createUser('admin@email.com', ['ROLE_ADMIN']); + $this->client->loginUser($admin); + // 2. Act + $this->client->request('GET', '/user/new'); + // 3. Assert + self::assertResponseRedirects('/user/'); + $this->client->followRedirect(); + self::assertResponseStatusCodeSame(403); + } + + #[Test] + public function test_create_super_admin_valid(): void + { + $admin = $this->createUser('admin@admin.com', ['ROLE_SUPER_ADMIN']); + $this->client->loginUser($admin); + $org = $this->createOrganization('Test Org'); + $uo = $this->createUOLink($admin, $org); + $app = $this->createApp('Test App'); + $role = $this->createRole('ADMIN'); + $this->createUOALink($uo, $app, $role); + $this->client->request('GET', '/user/new?organizationId=' . $org->getId()); + self::assertResponseIsSuccessful(); + $this->client->submitForm('Enregistrer', [ + 'user_form[email]' => 'email@email.com', + 'user_form[name]' => 'name', + 'user_form[surname]' => 'surname' + ]); + self::assertResponseRedirects('/organization/view/' . $org->getId()); + $this->client->followRedirect(); + self::assertCount(2, $this->entityManager->getRepository(User::class)->findAll()); + self::assertCount(2, $this->entityManager->getRepository(UsersOrganizations::class)->findAll()); + } + + #[Test] + public function test_create_admin_valid(): void + { + $admin = $this->createUser('admin@admin.com', ['ROLE_ADMIN']); + $this->client->loginUser($admin); + $org = $this->createOrganization('Test Org'); + $uo = $this->createUOLink($admin, $org); + $app = $this->createApp('Test App'); + $role = $this->createRole('ADMIN'); + $this->createUOALink($uo, $app, $role); + $this->client->request('GET', '/user/new?organizationId=' . $org->getId()); + self::assertResponseIsSuccessful(); + $this->client->submitForm('Enregistrer', [ + 'user_form[email]' => 'email@email.com', + 'user_form[name]' => 'name', + 'user_form[surname]' => 'surname' + ]); + self::assertResponseRedirects('/organization/view/' . $org->getId()); + $this->client->followRedirect(); + self::assertCount(2, $this->entityManager->getRepository(User::class)->findAll()); + self::assertCount(2, $this->entityManager->getRepository(UsersOrganizations::class)->findAll()); + } + + #[Test] + public function test_create_admin_no_organization_forbidden(): void + { + $admin = $this->createUser('user@email.com', ['ROLE_ADMIN']); + $this->client->loginUser($admin); + $this->client->request('GET', '/user/new'); + self::assertResponseRedirects('/user/'); + $this->client->followRedirect(); + self::assertResponseStatusCodeSame(403); + } + + //endregion + + //region Delete Tests + #[Test] + public function test_delete_super_admin_success(): void + { + $admin = $this->createUser('admin@admin.com', ['ROLE_SUPER_ADMIN']); + $user = $this->createUser('user@emai.com'); + $this->client->loginUser($admin); + $org = $this->createOrganization('Test Org'); + $app = $this->createApp('Test App'); + $role = $this->createRole('USER'); + $uoUser = $this->createUOLink($user, $org); + $this->createUOALink($uoUser, $app, $role); + $this->client->request('POST', '/user/delete/' . $user->getId()); + self::assertResponseRedirects('/user/'); + $this->client->followRedirect(); + self::assertCount(2, $this->entityManager->getRepository(User::class)->findAll()); + self::assertCount(1, $this->entityManager->getRepository(UsersOrganizations::class)->findAll()); + self::assertCount(1, $this->entityManager->getRepository(UserOrganizatonApp::class)->findAll()); + } + + #[Test] + public function test_delete_admin_forbidden(): void + { + $admin = $this->createUser('admin@email.com', ['ROLE_ADMIN']); + $user = $this->createUser('user@email.com'); + $this->client->loginUser($admin); + $this->client->request('POST', '/user/delete/' . $user->getId()); + self::assertResponseStatusCodeSame(403); + } + + #[Test] + public function test_delete_not_found(): void + { + $admin = $this->createUser('admin@eamil.com', ['ROLE_SUPER_ADMIN']); + $this->client->loginUser($admin); + $this->client->request('POST', '/user/delete/999999'); + self::assertResponseStatusCodeSame(404); + } + + //endregion + + // même erreur que pour la sécurité. Problème lié au SSO. + //region activate/deactivate tests + +// #[Test] +// public function test_deactivate_super_admin_success(): void +// { +// $admin = $this->createUser('admin@email.com', ['ROLE_SUPER_ADMIN']); +// $user = $this->createUser('user@email.com'); +// $this->client->loginUser($admin); +// $org = $this->createOrganization('Test Org'); +// $app = $this->createApp('Test App'); +// $role = $this->createRole('USER'); +// $uoUser = $this->createUOLink($user, $org); +// $this->createUOALink($uoUser, $app, $role); +// $this->client->request('POST', '/user/activeStatus/' . $user->getId(), ['status' => 'deactivate']); +// self::assertResponseRedirects('/user/'); +// $this->client->followRedirect(); +// +// } + + //endregion + // même erreur que pour la sécurité. Problème lié au SSO. + //region tabulator tests +// #[Test] +// public function test_tabulator_super_admin_success(): void{ +// $admin = $this->createUser('admin@email.com', ['ROLE_SUPER_ADMIN']); +// $this->client->loginUser($admin); +// $this->client->request('GET', '/user/data'); +// self::assertResponseIsSuccessful(); +// self::assertResponseHeaderSame('Content-Type', 'application/json'); +// +// $response = $this->client->getResponse(); +// $data = json_decode($response->getContent(), true); +// self::assertArrayHasKey('data', $data); +// } + + //endregion +} \ No newline at end of file