fix: serialize datacenter delete (lock+deactivate+recheck); store logo before deleting old
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>feat/portal-design
parent
01383e7e5e
commit
249efa0553
|
|
@ -3,6 +3,8 @@
|
|||
namespace App\Livewire\Admin;
|
||||
|
||||
use App\Models\Datacenter;
|
||||
use App\Models\Host;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use LivewireUI\Modal\ModalComponent;
|
||||
|
||||
/**
|
||||
|
|
@ -28,14 +30,24 @@ class ConfirmDeleteDatacenter extends ModalComponent
|
|||
|
||||
public function delete()
|
||||
{
|
||||
$dc = Datacenter::query()->where('uuid', $this->uuid)->withCount('hosts')->first();
|
||||
// Serialize the guard with the delete: lock the datacenter row and
|
||||
// re-check host membership inside the same transaction so a host created
|
||||
// concurrently can't be orphaned (hosts.datacenter is a bare code).
|
||||
DB::transaction(function () {
|
||||
$dc = Datacenter::query()->where('uuid', $this->uuid)->lockForUpdate()->first();
|
||||
if ($dc === null) {
|
||||
return;
|
||||
}
|
||||
// Deactivate first so HostCreate's `exists:…,active,1` rule blocks any
|
||||
// new host for this code while we finish deleting.
|
||||
$dc->update(['active' => false]);
|
||||
|
||||
// Re-check under the current state — never delete a datacenter with hosts.
|
||||
if ($dc === null || $dc->hosts_count > 0) {
|
||||
return $this->redirectRoute('admin.datacenters', navigate: true);
|
||||
}
|
||||
if (Host::query()->where('datacenter', $dc->code)->exists()) {
|
||||
return; // still has hosts — leave it (deactivated)
|
||||
}
|
||||
|
||||
$dc->delete();
|
||||
$dc->delete();
|
||||
});
|
||||
|
||||
return $this->redirectRoute('admin.datacenters', navigate: true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,11 +103,13 @@ class Settings extends Component
|
|||
]);
|
||||
|
||||
if ($this->logo !== null) {
|
||||
// Replace any previous logo; validated MIME/size above.
|
||||
if ($this->brandLogoPath !== null) {
|
||||
Storage::disk('public')->delete($this->brandLogoPath);
|
||||
}
|
||||
// Store the new file FIRST; only drop the old one once the write
|
||||
// succeeded, so a failed upload never leaves a dangling reference.
|
||||
$old = $this->brandLogoPath;
|
||||
$this->brandLogoPath = $this->logo->store('branding', 'public');
|
||||
if ($old !== null && $old !== $this->brandLogoPath) {
|
||||
Storage::disk('public')->delete($old);
|
||||
}
|
||||
$this->logo = null;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue