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.
126 lines
3.6 KiB
PHP
126 lines
3.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\SuperAdmin\Domain\Model\SuperAdmin;
|
|
|
|
use App\Shared\Domain\AggregateRoot;
|
|
use App\SuperAdmin\Domain\Event\SuperAdminCree;
|
|
use App\SuperAdmin\Domain\Event\SuperAdminDesactive;
|
|
use App\SuperAdmin\Domain\Exception\SuperAdminDejaActifException;
|
|
use App\SuperAdmin\Domain\Exception\SuperAdminNonActifException;
|
|
use DateTimeImmutable;
|
|
|
|
/**
|
|
* Aggregate Root for Super Admin — lives in the master database, not per-tenant.
|
|
*
|
|
* A Super Admin can manage all establishments and switch between tenant contexts.
|
|
* Authentication is separate from regular users (different user provider, different table).
|
|
*/
|
|
final class SuperAdmin extends AggregateRoot
|
|
{
|
|
public private(set) ?DateTimeImmutable $lastLoginAt = null;
|
|
|
|
private function __construct(
|
|
public private(set) SuperAdminId $id,
|
|
public private(set) string $email,
|
|
public private(set) string $hashedPassword,
|
|
public private(set) string $firstName,
|
|
public private(set) string $lastName,
|
|
public private(set) SuperAdminStatus $status,
|
|
public private(set) DateTimeImmutable $createdAt,
|
|
) {
|
|
}
|
|
|
|
public static function creer(
|
|
string $email,
|
|
string $hashedPassword,
|
|
string $firstName,
|
|
string $lastName,
|
|
DateTimeImmutable $createdAt,
|
|
): self {
|
|
$superAdmin = new self(
|
|
id: SuperAdminId::generate(),
|
|
email: $email,
|
|
hashedPassword: $hashedPassword,
|
|
firstName: $firstName,
|
|
lastName: $lastName,
|
|
status: SuperAdminStatus::ACTIF,
|
|
createdAt: $createdAt,
|
|
);
|
|
|
|
$superAdmin->recordEvent(new SuperAdminCree(
|
|
superAdminId: $superAdmin->id,
|
|
email: $superAdmin->email,
|
|
occurredOn: $createdAt,
|
|
));
|
|
|
|
return $superAdmin;
|
|
}
|
|
|
|
public function enregistrerConnexion(DateTimeImmutable $at): void
|
|
{
|
|
if ($this->status !== SuperAdminStatus::ACTIF) {
|
|
throw SuperAdminNonActifException::pourConnexion($this->id);
|
|
}
|
|
|
|
$this->lastLoginAt = $at;
|
|
}
|
|
|
|
public function desactiver(DateTimeImmutable $at): void
|
|
{
|
|
if ($this->status !== SuperAdminStatus::ACTIF) {
|
|
throw SuperAdminNonActifException::pourDesactivation($this->id);
|
|
}
|
|
|
|
$this->status = SuperAdminStatus::INACTIF;
|
|
|
|
$this->recordEvent(new SuperAdminDesactive(
|
|
superAdminId: $this->id,
|
|
occurredOn: $at,
|
|
));
|
|
}
|
|
|
|
public function reactiver(DateTimeImmutable $at): void
|
|
{
|
|
if ($this->status === SuperAdminStatus::ACTIF) {
|
|
throw SuperAdminDejaActifException::pourReactivation($this->id);
|
|
}
|
|
|
|
$this->status = SuperAdminStatus::ACTIF;
|
|
}
|
|
|
|
public function peutSeConnecter(): bool
|
|
{
|
|
return $this->status === SuperAdminStatus::ACTIF;
|
|
}
|
|
|
|
/**
|
|
* @internal For Infrastructure use only
|
|
*/
|
|
public static function reconstitute(
|
|
SuperAdminId $id,
|
|
string $email,
|
|
string $hashedPassword,
|
|
string $firstName,
|
|
string $lastName,
|
|
SuperAdminStatus $status,
|
|
DateTimeImmutable $createdAt,
|
|
?DateTimeImmutable $lastLoginAt = null,
|
|
): self {
|
|
$superAdmin = new self(
|
|
id: $id,
|
|
email: $email,
|
|
hashedPassword: $hashedPassword,
|
|
firstName: $firstName,
|
|
lastName: $lastName,
|
|
status: $status,
|
|
createdAt: $createdAt,
|
|
);
|
|
|
|
$superAdmin->lastLoginAt = $lastLoginAt;
|
|
|
|
return $superAdmin;
|
|
}
|
|
}
|