feat: Activation de compte utilisateur avec validation token
L'inscription Classeo se fait via invitation : un admin crée un compte, l'utilisateur reçoit un lien d'activation par email pour définir son mot de passe. Ce flow sécurisé évite les inscriptions non autorisées et garantit que seuls les utilisateurs légitimes accèdent au système. Points clés de l'implémentation : - Tokens d'activation à usage unique stockés en cache (Redis/filesystem) - Validation du consentement parental pour les mineurs < 15 ans (RGPD) - L'échec d'activation ne consume pas le token (retry possible) - Users dans un cache séparé sans TTL (pas d'expiration) - Hot reload en dev (FrankenPHP sans mode worker) Story: 1.3 - Inscription et activation de compte
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Administration\Domain\Exception;
|
||||
|
||||
use App\Administration\Domain\Model\ActivationToken\ActivationTokenId;
|
||||
use RuntimeException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
final class ActivationTokenAlreadyUsedException extends RuntimeException
|
||||
{
|
||||
public static function forToken(ActivationTokenId $tokenId): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'Activation token "%s" has already been used.',
|
||||
$tokenId,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Administration\Domain\Exception;
|
||||
|
||||
use App\Administration\Domain\Model\ActivationToken\ActivationTokenId;
|
||||
use RuntimeException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
final class ActivationTokenExpiredException extends RuntimeException
|
||||
{
|
||||
public static function forToken(ActivationTokenId $tokenId): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'Activation token "%s" has expired.',
|
||||
$tokenId,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Administration\Domain\Exception;
|
||||
|
||||
use App\Administration\Domain\Model\ActivationToken\ActivationTokenId;
|
||||
use RuntimeException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
final class ActivationTokenNotFoundException extends RuntimeException
|
||||
{
|
||||
public static function withId(ActivationTokenId $tokenId): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'Activation token with ID "%s" not found.',
|
||||
$tokenId,
|
||||
));
|
||||
}
|
||||
|
||||
public static function withTokenValue(string $tokenValue): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'Activation token with value "%s" not found.',
|
||||
$tokenValue,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Administration\Domain\Exception;
|
||||
|
||||
use App\Administration\Domain\Model\User\StatutCompte;
|
||||
use App\Administration\Domain\Model\User\UserId;
|
||||
use RuntimeException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
final class CompteNonActivableException extends RuntimeException
|
||||
{
|
||||
public static function carStatutIncompatible(UserId $userId, StatutCompte $statut): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'Le compte "%s" ne peut pas être activé car son statut est "%s".',
|
||||
$userId,
|
||||
$statut->value,
|
||||
));
|
||||
}
|
||||
|
||||
public static function carConsentementManquant(UserId $userId): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'Le compte "%s" ne peut pas être activé : consentement parental manquant.',
|
||||
$userId,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Administration\Domain\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
final class EmailInvalideException extends RuntimeException
|
||||
{
|
||||
public static function pourAdresse(string $email): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'L\'adresse email "%s" n\'est pas valide.',
|
||||
$email,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Administration\Domain\Exception;
|
||||
|
||||
use App\Administration\Domain\Model\User\Email;
|
||||
use App\Administration\Domain\Model\User\UserId;
|
||||
use RuntimeException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
final class UserNotFoundException extends RuntimeException
|
||||
{
|
||||
public static function withId(UserId $userId): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'User with ID "%s" not found.',
|
||||
$userId,
|
||||
));
|
||||
}
|
||||
|
||||
public static function withEmail(Email $email): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'User with email "%s" not found.',
|
||||
$email,
|
||||
));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user