*/ final readonly class PireonIdentity implements Arrayable { public function __construct( public int $id, public string $name, public string $email, public bool $isActive, /** @var array */ public array $roles = [], /** @var array */ public array $appRoles = [], public ?CarbonImmutable $approvedAt = null, public ?CarbonImmutable $createdAt = null, ) {} /** * @param array $payload */ public static function fromResponse(array $payload): self { // The server wraps some responses in a "data" envelope and returns // others bare; accept either shape. $payload = $payload['data'] ?? $payload; return new self( id: (int) $payload['id'], name: (string) ($payload['name'] ?? ''), email: (string) ($payload['email'] ?? ''), isActive: (bool) ($payload['is_active'] ?? true), roles: array_values(array_map('strval', $payload['roles'] ?? [])), appRoles: array_values(array_map('strval', $payload['app_roles'] ?? [])), approvedAt: isset($payload['approved_at']) ? CarbonImmutable::parse($payload['approved_at']) : null, createdAt: isset($payload['created_at']) ? CarbonImmutable::parse($payload['created_at']) : null, ); } /** * Self-registered accounts stay unapproved until an administrator on the * identity server approves them. */ public function isApproved(): bool { return $this->approvedAt !== null; } /** * Whether this identity is allowed to open a session here at all, per the * `require_active_account` / `require_approved_account` settings. */ public function isUsable(): bool { if (config('pireon.require_active_account') && ! $this->isActive) { return false; } return ! (config('pireon.require_approved_account') && ! $this->isApproved()); } /** * @return array */ public function toArray(): array { return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'is_active' => $this->isActive, 'roles' => $this->roles, 'app_roles' => $this->appRoles, 'approved_at' => $this->approvedAt?->toIso8601String(), 'created_at' => $this->createdAt?->toIso8601String(), ]; } }