feat: Permettre au super admin de se connecter et accéder à son dashboard
Le super admin (table super_admins, master DB) ne pouvait pas se connecter via /api/login car ce firewall n'utilisait que le provider tenant. De même, le JWT n'était pas enrichi pour les super admins, l'endpoint /api/me/roles les rejetait, et le frontend redirigeait systématiquement vers /dashboard. Un chain provider (super_admin + tenant) résout l'authentification, le JwtPayloadEnricher et MyRolesProvider gèrent désormais les deux types d'utilisateurs, et le frontend redirige selon le rôle après login.
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Unit\Administration\Infrastructure\Api\Provider;
|
||||
|
||||
use ApiPlatform\Metadata\Get;
|
||||
use App\Administration\Application\Port\ActiveRoleStore;
|
||||
use App\Administration\Application\Service\RoleContext;
|
||||
use App\Administration\Domain\Model\User\Email;
|
||||
use App\Administration\Domain\Model\User\Role;
|
||||
use App\Administration\Domain\Model\User\StatutCompte;
|
||||
use App\Administration\Domain\Model\User\User;
|
||||
use App\Administration\Domain\Model\User\UserId;
|
||||
use App\Administration\Domain\Repository\UserRepository;
|
||||
use App\Administration\Infrastructure\Api\Provider\MyRolesProvider;
|
||||
use App\Administration\Infrastructure\Security\SecurityUser;
|
||||
use App\Shared\Domain\Tenant\TenantId;
|
||||
use App\SuperAdmin\Domain\Model\SuperAdmin\SuperAdminId;
|
||||
use App\SuperAdmin\Infrastructure\Security\SecuritySuperAdmin;
|
||||
use DateTimeImmutable;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
|
||||
|
||||
final class MyRolesProviderTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
public function provideReturnsSuperAdminRoleForSecuritySuperAdmin(): void
|
||||
{
|
||||
$security = $this->createMock(Security::class);
|
||||
$security->method('getUser')->willReturn(
|
||||
new SecuritySuperAdmin(
|
||||
superAdminId: SuperAdminId::generate(),
|
||||
email: 'sadmin@test.com',
|
||||
hashedPassword: 'hashed',
|
||||
)
|
||||
);
|
||||
|
||||
$userRepository = $this->createMock(UserRepository::class);
|
||||
$roleContext = new RoleContext(new NullActiveRoleStore());
|
||||
|
||||
$provider = new MyRolesProvider($security, $userRepository, $roleContext);
|
||||
$output = $provider->provide(new Get());
|
||||
|
||||
self::assertSame('ROLE_SUPER_ADMIN', $output->activeRole);
|
||||
self::assertSame('Super Admin', $output->activeRoleLabel);
|
||||
self::assertCount(1, $output->roles);
|
||||
self::assertSame('ROLE_SUPER_ADMIN', $output->roles[0]['value']);
|
||||
self::assertSame('Super Admin', $output->roles[0]['label']);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function provideReturnsUserRolesForSecurityUser(): void
|
||||
{
|
||||
$userId = UserId::generate();
|
||||
$tenantId = TenantId::fromString('550e8400-e29b-41d4-a716-446655440002');
|
||||
|
||||
$securityUser = new SecurityUser(
|
||||
userId: $userId,
|
||||
email: 'user@example.com',
|
||||
hashedPassword: 'hashed',
|
||||
tenantId: $tenantId,
|
||||
roles: ['ROLE_PARENT'],
|
||||
);
|
||||
|
||||
$security = $this->createMock(Security::class);
|
||||
$security->method('getUser')->willReturn($securityUser);
|
||||
|
||||
$user = User::reconstitute(
|
||||
id: $userId,
|
||||
email: new Email('user@example.com'),
|
||||
roles: [Role::PARENT],
|
||||
tenantId: $tenantId,
|
||||
schoolName: 'Test',
|
||||
statut: StatutCompte::ACTIF,
|
||||
dateNaissance: null,
|
||||
createdAt: new DateTimeImmutable(),
|
||||
hashedPassword: 'hashed',
|
||||
activatedAt: new DateTimeImmutable(),
|
||||
consentementParental: null,
|
||||
);
|
||||
|
||||
$userRepository = $this->createMock(UserRepository::class);
|
||||
$userRepository->method('get')->willReturn($user);
|
||||
|
||||
$roleContext = new RoleContext(new NullActiveRoleStore());
|
||||
|
||||
$provider = new MyRolesProvider($security, $userRepository, $roleContext);
|
||||
$output = $provider->provide(new Get());
|
||||
|
||||
self::assertSame('ROLE_PARENT', $output->activeRole);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function provideThrowsUnauthorizedForUnknownUserType(): void
|
||||
{
|
||||
$security = $this->createMock(Security::class);
|
||||
$security->method('getUser')->willReturn(null);
|
||||
|
||||
$userRepository = $this->createMock(UserRepository::class);
|
||||
$roleContext = new RoleContext(new NullActiveRoleStore());
|
||||
|
||||
$provider = new MyRolesProvider($security, $userRepository, $roleContext);
|
||||
|
||||
$this->expectException(UnauthorizedHttpException::class);
|
||||
$provider->provide(new Get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class NullActiveRoleStore implements ActiveRoleStore
|
||||
{
|
||||
public function store(User $user, Role $role): void
|
||||
{
|
||||
}
|
||||
|
||||
public function get(User $user): ?Role
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function clear(User $user): void
|
||||
{
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user