Test for User Controller

This commit is contained in:
Charles 2026-01-21 10:01:13 +01:00
parent d26d1cb118
commit 01f73c2ef4
10 changed files with 675 additions and 30 deletions

View File

@ -58,6 +58,7 @@ export default class extends Controller {
table() { table() {
const columns = [ const columns = [
{ {
placeholder: "Aucun utilisateur trouvé",
title: "", title: "",
field: "isConnected", field: "isConnected",
width: 40, // small column width: 40, // small column

View File

@ -54,7 +54,18 @@ class OrganizationController extends AbstractController
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier()); $actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if($this->userService->hasAccessTo($actingUser, true)){ if($this->userService->hasAccessTo($actingUser, true)){
$orgCount = $this->organizationsRepository->count(['isDeleted' => false]); $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', [ return $this->render('organization/index.html.twig', [
'hasOrganizations' => $orgCount > 0 'hasOrganizations' => $orgCount > 0
]); ]);
@ -297,6 +308,17 @@ class OrganizationController extends AbstractController
$qb->andWhere('o.email LIKE :email') $qb->andWhere('o.email LIKE :email')
->setParameter('email', '%' . $filters['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 // Count total
$countQb = clone $qb; $countQb = clone $qb;
@ -319,7 +341,6 @@ class OrganizationController extends AbstractController
]; ];
}, $rows); }, $rows);
// Tabulator expects: data, last_page (total pages), or total row count depending on config
$lastPage = (int)ceil($total / $size); $lastPage = (int)ceil($total / $size);
return $this->json([ return $this->json([

View File

@ -77,6 +77,10 @@ class UserController extends AbstractController
// Chargement de l'utilisateur cible à afficher // Chargement de l'utilisateur cible à afficher
$user = $this->userRepository->find($id); $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)) { if (!$this->userService->hasAccessTo($user)) {
$this->loggerService->logAccessDenied($actingUser->getId()); $this->loggerService->logAccessDenied($actingUser->getId());
throw new AccessDeniedHttpException (self::ACCESS_DENIED); 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 // 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) { } catch (\Exception $e) {
// En cas d'erreur, désactiver l'édition et logger l'exception // 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 public function edit(int $id, Request $request): Response
{ {
$this->denyAccessUnlessGranted('ROLE_USER'); $this->denyAccessUnlessGranted('ROLE_USER');
try {
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier()); $actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if ($this->userService->hasAccessTo($actingUser)) {
$user = $this->userRepository->find($id); $user = $this->userRepository->find($id);
if (!$user) { if (!$user) {
$this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId()); $this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId());
throw $this->createNotFoundException(self::NOT_FOUND); throw $this->createNotFoundException(self::NOT_FOUND);
} }
try {
if ($this->userService->hasAccessTo($user)) {
$form = $this->createForm(UserForm::class, $user); $form = $this->createForm(UserForm::class, $user);
$form->handleRequest($request); $form->handleRequest($request);
@ -277,6 +282,13 @@ class UserController extends AbstractController
$this->loggerService->logEntityNotFound('Organization', ['id' => $orgId], $actingUser->getId()); $this->loggerService->logEntityNotFound('Organization', ['id' => $orgId], $actingUser->getId());
throw $this->createNotFoundException(self::NOT_FOUND); 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()) { if ($form->isSubmitted() && $form->isValid()) {
@ -334,7 +346,7 @@ class UserController extends AbstractController
} }
// Case : Organization provided and user doesn't already exist // Case : Organization provided and user doesn't already exist
if ($org) { if ($orgId) {
$this->userService->linkUserToOrganization( $this->userService->linkUserToOrganization(
$user, $user,
$org, $org,
@ -541,7 +553,6 @@ class UserController extends AbstractController
try { try {
$user = $this->userRepository->find($id); $user = $this->userRepository->find($id);
if (!$user) { if (!$user) {
// Security/audit log for missing user // Security/audit log for missing user
$this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId()); $this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId());
@ -550,10 +561,10 @@ class UserController extends AbstractController
} }
// Soft delete the user // Soft delete the user
$user->setIsActive(false); $user->setIsActive(false);
$user->setIsDeleted(true); $user->setIsDeleted(true);
$user->setModifiedAt(new \DateTimeImmutable('now')); $user->setModifiedAt(new \DateTimeImmutable('now'));
// Deactivate all org links // Deactivate all org links
$this->userOrganizationService->deactivateAllUserOrganizationLinks($actingUser, $user); $this->userOrganizationService->deactivateAllUserOrganizationLinks($actingUser, $user);
$this->loggerService->logOrganizationInformation($user->getId(), $actingUser->getId(), 'All user organization links deactivated'); $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 // No rethrow here: deletion succeeded; only notifications failed
} }
return new Response('', Response::HTTP_NO_CONTENT); // 204 return $this->redirectToRoute('user_index');
} catch (\Exception $e) { } catch (\Exception $e) {
// Route-level error logging → error.log // Route-level error logging → error.log
@ -609,7 +620,7 @@ class UserController extends AbstractController
throw $e; // keep 404 semantics 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(), 'statut' => $user->isActive(),
]; ];
}, $rows); }, $rows);
$lastPage = (int)ceil($total / $size); $lastPage = (int)ceil($total / $size);
return $this->json([ return $this->json([

View File

@ -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']); $roleAdmin = $this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'ADMIN']);
@ -166,8 +166,6 @@ class OrganizationsService
} }
} }
return $adminUO;
} }
} }

View File

@ -42,6 +42,7 @@ readonly class UserOrganizationService
$uos = $this->entityManager->getRepository(UsersOrganizations::class)->findBy(['organization' => $organizations, 'isActive' => true]); $uos = $this->entityManager->getRepository(UsersOrganizations::class)->findBy(['organization' => $organizations, 'isActive' => true]);
} }
//deactivate all UO links //deactivate all UO links
if (!empty($uos)) {
foreach ($uos as $uo) { foreach ($uos as $uo) {
$this->userOrganizationAppService->deactivateAllUserOrganizationsAppLinks($uo); $this->userOrganizationAppService->deactivateAllUserOrganizationsAppLinks($uo);
$this->loggerService->logOrganizationInformation($uo->getOrganization()->getId(), $actingUser->getId(), $this->loggerService->logOrganizationInformation($uo->getOrganization()->getId(), $actingUser->getId(),
@ -52,6 +53,8 @@ readonly class UserOrganizationService
} }
} }
}
} }

View File

@ -407,15 +407,18 @@ class UserService
return $rolesArray; 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(); $userRoles = $user->getRoles();
$actingUserRoles = $actingUser->getRoles(); $actingUserRoles = $actingUser->getRoles();
// if acting user is admin, he can´t edit super admin roles // 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; return false;
} }
if ($uo && $this->isAdminOfOrganization($uo->getOrganization())) {
return true;
}
return $isAdmin && !empty($org); return $isAdmin && !empty($org);
} }

View File

@ -7,7 +7,9 @@
<div class="card-title"> <div class="card-title">
<h2>Modifier l'utilisateur</h2> <h2>Modifier l'utilisateur</h2>
</div> </div>
{% if is_granted('ROLE_SUPER_ADMIN') %}
<a href="{{ path('user_delete', {'id': user.id}) }}" class="btn btn-danger m-3">Supprimer</a> <a href="{{ path('user_delete', {'id': user.id}) }}" class="btn btn-danger m-3">Supprimer</a>
{% endif %}
</div> </div>
<div class="card-body"> <div class="card-body">

View File

@ -9,7 +9,7 @@
<div class="card-header border-0"> <div class="card-header border-0">
<div class="d-flex justify-content-between align-items-center mb-3 "> <div class="d-flex justify-content-between align-items-center mb-3 ">
<h1>Gestion Utilisateurs</h1> <h1>Gestion Utilisateurs</h1>
<a href="{{ path('user_new') }}" class="btn btn-primary">Ajouter un utilisateur</a> {# <a href="{{ path('user_new') }}" class="btn btn-primary">Ajouter un utilisateur</a>#}
</div> </div>
</div> </div>

View File

@ -15,6 +15,9 @@
{% if canEdit %} {% if canEdit %}
<a href="{{ path('user_edit', {'id': user.id, 'organizationId': organizationId}) }}" <a href="{{ path('user_edit', {'id': user.id, 'organizationId': organizationId}) }}"
class="btn btn-primary">Modifier</a> class="btn btn-primary">Modifier</a>
{% elseif user.id == app.user.id %}
<a href="{{ path('user_edit', {'id': user.id}) }}"
class="btn btn-primary">Modifier</a>
{% endif %} {% endif %}
</div> </div>
</div> </div>

View File

@ -0,0 +1,604 @@
<?php
namespace App\Tests\Controller;
use App\Service\AwsService;
use PHPUnit\Framework\Attributes\Test;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use App\Entity\User;
use App\Entity\Apps;
use App\Entity\Roles;
use App\Entity\Organizations;
use App\Entity\UsersOrganizations;
use App\Entity\UserOrganizatonApp;
use App\Tests\Functional\AbstractFunctionalTest;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use function Symfony\Component\DependencyInjection\Loader\Configurator\param;
//This test will generate warning, ignore it
class UserControllerTest extends AbstractFunctionalTest
{
//region Index Tests
#[Test]
public function test_index_super_admin_success(): void
{
$admin = $this->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
}