*/ protected $attributes = [ 'active' => false, 'provider' => 's3', 'use_path_style' => false, ]; protected function casts(): array { return [ 'active' => 'boolean', 'provider' => StorageProvider::class, 'secret' => 'encrypted', 'key_file' => 'encrypted', 'use_path_style' => 'boolean', ]; } public static function current(): self { return static::query()->firstOrNew([]); } /** * Active isn't enough on its own — an admin could flip the toggle * before ever filling in real credentials (a blank bucket/key would * silently misroute every new upload to a broken disk). */ public function isConfigured(): bool { if (! $this->active || ! $this->filled('bucket')) { return false; } // What counts as "filled in" is per provider, because the two // authenticate with different things entirely: S3 wants a key and // a secret, GCS wants a service account key file. return match ($this->provider) { StorageProvider::S3 => $this->filled('key') && $this->filled('secret'), StorageProvider::Gcs => $this->filled('key_file'), }; } private function filled(string $attribute): bool { $value = $this->{$attribute}; return is_string($value) && $value !== ''; } }