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 @@
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