Les administrateurs d'établissement avaient besoin de gérer le calendrier scolaire (FR80) pour que l'EDT et les devoirs respectent automatiquement les jours non travaillés. Sans cette configuration centralisée, chaque module devait gérer indépendamment les contraintes de dates. Le calendrier s'appuie sur l'API data.education.gouv.fr pour importer les vacances officielles par zone (A/B/C) et calcule les 11 jours fériés français (dont les fêtes mobiles liées à Pâques). Les enseignants sont notifiés par email lors de l'ajout d'une journée pédagogique. Un query IsSchoolDay et une validation des dates d'échéance de devoirs permettent aux autres modules de s'intégrer sans couplage direct.
147 lines
4.2 KiB
PHP
147 lines
4.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Unit\Administration\Infrastructure\Security;
|
|
|
|
use App\Administration\Domain\Model\User\Role;
|
|
use App\Administration\Infrastructure\Security\CalendarVoter;
|
|
use PHPUnit\Framework\Attributes\DataProvider;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
|
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
|
|
use Symfony\Component\Security\Core\User\UserInterface;
|
|
|
|
final class CalendarVoterTest extends TestCase
|
|
{
|
|
private CalendarVoter $voter;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->voter = new CalendarVoter();
|
|
}
|
|
|
|
#[Test]
|
|
public function itAbstainsForUnrelatedAttributes(): void
|
|
{
|
|
$token = $this->tokenWithRole(Role::ADMIN->value);
|
|
|
|
$result = $this->voter->vote($token, null, ['SOME_OTHER_ATTRIBUTE']);
|
|
|
|
self::assertSame(Voter::ACCESS_ABSTAIN, $result);
|
|
}
|
|
|
|
#[Test]
|
|
public function itDeniesAccessToUnauthenticatedUsers(): void
|
|
{
|
|
$token = $this->createMock(TokenInterface::class);
|
|
$token->method('getUser')->willReturn(null);
|
|
|
|
$result = $this->voter->vote($token, null, [CalendarVoter::VIEW]);
|
|
|
|
self::assertSame(Voter::ACCESS_DENIED, $result);
|
|
}
|
|
|
|
// --- VIEW ---
|
|
|
|
#[Test]
|
|
#[DataProvider('viewAllowedRolesProvider')]
|
|
public function itGrantsViewToStaffRoles(string $role): void
|
|
{
|
|
$token = $this->tokenWithRole($role);
|
|
|
|
$result = $this->voter->vote($token, null, [CalendarVoter::VIEW]);
|
|
|
|
self::assertSame(Voter::ACCESS_GRANTED, $result);
|
|
}
|
|
|
|
/**
|
|
* @return iterable<string, array{string}>
|
|
*/
|
|
public static function viewAllowedRolesProvider(): iterable
|
|
{
|
|
yield 'SUPER_ADMIN' => [Role::SUPER_ADMIN->value];
|
|
yield 'ADMIN' => [Role::ADMIN->value];
|
|
yield 'PROF' => [Role::PROF->value];
|
|
yield 'VIE_SCOLAIRE' => [Role::VIE_SCOLAIRE->value];
|
|
yield 'SECRETARIAT' => [Role::SECRETARIAT->value];
|
|
}
|
|
|
|
#[Test]
|
|
#[DataProvider('viewDeniedRolesProvider')]
|
|
public function itDeniesViewToNonStaffRoles(string $role): void
|
|
{
|
|
$token = $this->tokenWithRole($role);
|
|
|
|
$result = $this->voter->vote($token, null, [CalendarVoter::VIEW]);
|
|
|
|
self::assertSame(Voter::ACCESS_DENIED, $result);
|
|
}
|
|
|
|
/**
|
|
* @return iterable<string, array{string}>
|
|
*/
|
|
public static function viewDeniedRolesProvider(): iterable
|
|
{
|
|
yield 'PARENT' => [Role::PARENT->value];
|
|
yield 'ELEVE' => [Role::ELEVE->value];
|
|
}
|
|
|
|
// --- CONFIGURE ---
|
|
|
|
#[Test]
|
|
#[DataProvider('configureAllowedRolesProvider')]
|
|
public function itGrantsConfigureToAdminRoles(string $role): void
|
|
{
|
|
$token = $this->tokenWithRole($role);
|
|
|
|
$result = $this->voter->vote($token, null, [CalendarVoter::CONFIGURE]);
|
|
|
|
self::assertSame(Voter::ACCESS_GRANTED, $result);
|
|
}
|
|
|
|
/**
|
|
* @return iterable<string, array{string}>
|
|
*/
|
|
public static function configureAllowedRolesProvider(): iterable
|
|
{
|
|
yield 'SUPER_ADMIN' => [Role::SUPER_ADMIN->value];
|
|
yield 'ADMIN' => [Role::ADMIN->value];
|
|
}
|
|
|
|
#[Test]
|
|
#[DataProvider('configureDeniedRolesProvider')]
|
|
public function itDeniesConfigureToNonAdminRoles(string $role): void
|
|
{
|
|
$token = $this->tokenWithRole($role);
|
|
|
|
$result = $this->voter->vote($token, null, [CalendarVoter::CONFIGURE]);
|
|
|
|
self::assertSame(Voter::ACCESS_DENIED, $result);
|
|
}
|
|
|
|
/**
|
|
* @return iterable<string, array{string}>
|
|
*/
|
|
public static function configureDeniedRolesProvider(): iterable
|
|
{
|
|
yield 'PROF' => [Role::PROF->value];
|
|
yield 'VIE_SCOLAIRE' => [Role::VIE_SCOLAIRE->value];
|
|
yield 'SECRETARIAT' => [Role::SECRETARIAT->value];
|
|
yield 'PARENT' => [Role::PARENT->value];
|
|
yield 'ELEVE' => [Role::ELEVE->value];
|
|
}
|
|
|
|
private function tokenWithRole(string $role): TokenInterface
|
|
{
|
|
$user = $this->createMock(UserInterface::class);
|
|
$user->method('getRoles')->willReturn([$role]);
|
|
|
|
$token = $this->createMock(TokenInterface::class);
|
|
$token->method('getUser')->willReturn($user);
|
|
|
|
return $token;
|
|
}
|
|
}
|