MailProvider::class, 'client_secret' => 'encrypted', 'access_token' => 'encrypted', 'refresh_token' => 'encrypted', 'token_expires_at' => 'datetime', 'last_refreshed_at' => 'datetime', ]; } public static function for(MailProvider $provider): self { return static::query()->firstOrNew(['provider' => $provider->value]); } /** * Whether the connect flow can be started: the admin has entered the * app registration, even if no mailbox is connected yet. */ public function configured(): bool { return $this->filled('client_id') && $this->filled('client_secret'); } /** * Whether transports can send through this connection. A half-torn * state (configured but never connected, or tokens cleared by a * disconnect) behaves as "not usable" rather than failing inside a * queued job — the same rule SocialSettings::usable() follows. */ public function usable(): bool { return $this->configured() && $this->filled('refresh_token'); } private function filled(string $attribute): bool { $value = $this->getAttribute($attribute); return is_string($value) && trim($value) !== ''; } }