*/ use HasFactory, HasUuid; protected $fillable = [ 'host_id', 'instance_id', 'ip', 'reason', 'attempts', 'strikes', 'blocked_at', 'expires_at', 'released_at', 'released_by_type', 'released_by_id', ]; protected function casts(): array { return [ 'attempts' => 'integer', 'strikes' => 'integer', 'blocked_at' => 'datetime', 'expires_at' => 'datetime', 'released_at' => 'datetime', ]; } public function host(): BelongsTo { return $this->belongsTo(Host::class); } public function instance(): BelongsTo { return $this->belongsTo(Instance::class); } /** Wer vorzeitig aufgehoben hat — Operator oder Customer, wenn jemand. */ public function releasedBy(): MorphTo { return $this->morphTo(); } /** Was gerade gilt: noch nicht aufgehoben und noch nicht abgelaufen. */ public function scopeActive(Builder $query): Builder { return $query->whereNull('released_at')->where('expires_at', '>', now()); } /** * Hebt die Sperre vorzeitig auf — am Datensatz UND, wenn das Subjekt einen * erreichbaren Host hat, in dessen Firewall. `$by` ist null, wenn der * Kernel sie ohnehin schon fallen ließ (Ablauf) und niemand sie manuell * aufgehoben hat; sonst der Operator oder Customer, der den Knopf gedrückt * hat (R23-Modal auf der aufrufenden Seite, nicht hier). */ /** * Hebt die Sperre auf — und sagt, ob die Regel wirklich gefallen ist. * * Der Datensatz wird IMMER zuerst gespeichert, auch wenn der Host gerade * nicht erreichbar ist: er ist die Sperre, die Firewall-Menge nur ihr * Abdruck (siehe Klassenkopf), und `reapplyActiveBlocks()` traegt beim * naechsten Lauf nur noch ein, was hier aktiv steht. * * Der Rueckgabewert ist deshalb NICHT „hat es geklappt", sondern „steht * die Firewall schon nach". Er wird gebraucht, weil `HostFirewall::apply()` * jeden Fehlschlag schluckt und nur ins Log meldet — ohne ihn faende der * Mensch am Bildschirm „Sperre aufgehoben." vor, waehrend die Adresse * weiter ausgesperrt ist und er sich das nicht erklaeren kann. */ public function release(?Model $by): bool { $this->releasedBy()->associate($by); $this->released_at = now(); $this->save(); $host = $this->host ?? $this->instance?->host; if ($host === null) { return true; // Kein Host, keine Regel — nichts, was nachhinken koennte. } return app(HostFirewall::class)->release($host, $this->ip); } }