Les parents doivent pouvoir suivre la scolarité de leurs enfants (notes, emploi du temps, devoirs). Cela nécessite un lien formalisé entre le compte parent et le compte élève, géré par les administrateurs. Le lien est établi soit manuellement via l'interface d'administration, soit automatiquement lors de l'activation du compte parent lorsque l'invitation inclut un élève cible. Ce lien conditionne l'accès aux données scolaires de l'enfant (autorisations vérifiées par un voter dédié).
168 lines
5.9 KiB
PHP
168 lines
5.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Unit\Administration\Infrastructure\Api\Provider;
|
|
|
|
use ApiPlatform\Metadata\GetCollection;
|
|
use App\Administration\Application\Query\GetStudentsForParent\GetStudentsForParentHandler;
|
|
use App\Administration\Domain\Model\StudentGuardian\RelationshipType;
|
|
use App\Administration\Domain\Model\StudentGuardian\StudentGuardian;
|
|
use App\Administration\Domain\Model\User\Email;
|
|
use App\Administration\Domain\Model\User\Role;
|
|
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\MyChildrenProvider;
|
|
use App\Administration\Infrastructure\Api\Resource\MyChildrenResource;
|
|
use App\Administration\Infrastructure\Persistence\InMemory\InMemoryStudentGuardianRepository;
|
|
use App\Administration\Infrastructure\Security\SecurityUser;
|
|
use App\Shared\Domain\Tenant\TenantId;
|
|
use App\Shared\Infrastructure\Tenant\TenantConfig;
|
|
use App\Shared\Infrastructure\Tenant\TenantContext;
|
|
use App\Shared\Infrastructure\Tenant\TenantId as InfraTenantId;
|
|
use DateTimeImmutable;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Symfony\Bundle\SecurityBundle\Security;
|
|
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
|
|
use Symfony\Component\Security\Core\User\UserInterface;
|
|
|
|
final class MyChildrenProviderTest extends TestCase
|
|
{
|
|
private const string TENANT_ID = '550e8400-e29b-41d4-a716-446655440002';
|
|
private const string SUBDOMAIN = 'ecole-alpha';
|
|
private const string PARENT_ID = '550e8400-e29b-41d4-a716-446655440020';
|
|
private const string STUDENT_ID = '550e8400-e29b-41d4-a716-446655440010';
|
|
|
|
private InMemoryStudentGuardianRepository $repository;
|
|
private TenantContext $tenantContext;
|
|
private SecurityUser $securityUser;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->repository = new InMemoryStudentGuardianRepository();
|
|
|
|
$this->tenantContext = new TenantContext();
|
|
$this->tenantContext->setCurrentTenant(new TenantConfig(
|
|
tenantId: InfraTenantId::fromString(self::TENANT_ID),
|
|
subdomain: self::SUBDOMAIN,
|
|
databaseUrl: 'postgresql://test',
|
|
));
|
|
|
|
$this->securityUser = new SecurityUser(
|
|
userId: UserId::fromString(self::PARENT_ID),
|
|
email: 'parent@example.com',
|
|
hashedPassword: '$argon2id$hashed',
|
|
tenantId: TenantId::fromString(self::TENANT_ID),
|
|
roles: [Role::PARENT->value],
|
|
);
|
|
}
|
|
|
|
#[Test]
|
|
public function returnsChildrenForAuthenticatedParent(): void
|
|
{
|
|
$link = StudentGuardian::lier(
|
|
studentId: UserId::fromString(self::STUDENT_ID),
|
|
guardianId: UserId::fromString(self::PARENT_ID),
|
|
relationshipType: RelationshipType::FATHER,
|
|
tenantId: TenantId::fromString(self::TENANT_ID),
|
|
createdAt: new DateTimeImmutable('2026-02-10 10:00:00'),
|
|
);
|
|
$this->repository->save($link);
|
|
|
|
$provider = $this->createProvider();
|
|
|
|
$results = $provider->provide(new GetCollection());
|
|
|
|
self::assertCount(1, $results);
|
|
self::assertInstanceOf(MyChildrenResource::class, $results[0]);
|
|
self::assertSame((string) $link->id, $results[0]->id);
|
|
self::assertSame(self::STUDENT_ID, $results[0]->studentId);
|
|
self::assertSame('père', $results[0]->relationshipType);
|
|
self::assertSame('Père', $results[0]->relationshipLabel);
|
|
}
|
|
|
|
#[Test]
|
|
public function returnsEmptyArrayWhenNoChildren(): void
|
|
{
|
|
$provider = $this->createProvider();
|
|
|
|
$results = $provider->provide(new GetCollection());
|
|
|
|
self::assertSame([], $results);
|
|
}
|
|
|
|
#[Test]
|
|
public function throwsUnauthorizedWhenNotAuthenticated(): void
|
|
{
|
|
$security = $this->createMock(Security::class);
|
|
$security->method('getUser')->willReturn(null);
|
|
|
|
$provider = $this->createProvider(security: $security);
|
|
|
|
$this->expectException(UnauthorizedHttpException::class);
|
|
|
|
$provider->provide(new GetCollection());
|
|
}
|
|
|
|
#[Test]
|
|
public function throwsUnauthorizedWhenNoTenant(): void
|
|
{
|
|
$tenantContext = new TenantContext();
|
|
|
|
$provider = $this->createProvider(tenantContext: $tenantContext);
|
|
|
|
$this->expectException(UnauthorizedHttpException::class);
|
|
|
|
$provider->provide(new GetCollection());
|
|
}
|
|
|
|
#[Test]
|
|
public function throwsUnauthorizedWhenNotSecurityUser(): void
|
|
{
|
|
$nonSecurityUser = $this->createMock(UserInterface::class);
|
|
|
|
$security = $this->createMock(Security::class);
|
|
$security->method('getUser')->willReturn($nonSecurityUser);
|
|
|
|
$provider = $this->createProvider(security: $security);
|
|
|
|
$this->expectException(UnauthorizedHttpException::class);
|
|
|
|
$provider->provide(new GetCollection());
|
|
}
|
|
|
|
private function createProvider(
|
|
?TenantContext $tenantContext = null,
|
|
?Security $security = null,
|
|
): MyChildrenProvider {
|
|
$studentUser = User::creer(
|
|
email: new Email('student@example.com'),
|
|
role: Role::ELEVE,
|
|
tenantId: TenantId::fromString(self::TENANT_ID),
|
|
schoolName: 'École Test',
|
|
dateNaissance: null,
|
|
createdAt: new DateTimeImmutable('2026-02-10 10:00:00'),
|
|
);
|
|
|
|
$userRepository = $this->createMock(UserRepository::class);
|
|
$userRepository->method('get')->willReturn($studentUser);
|
|
|
|
$handler = new GetStudentsForParentHandler($this->repository, $userRepository);
|
|
|
|
$tenantContext ??= $this->tenantContext;
|
|
|
|
if ($security === null) {
|
|
$security = $this->createMock(Security::class);
|
|
$security->method('getUser')->willReturn($this->securityUser);
|
|
}
|
|
|
|
return new MyChildrenProvider(
|
|
$handler,
|
|
$security,
|
|
$tenantContext,
|
|
);
|
|
}
|
|
}
|