From 484a3b445a6951c6e910720a06d54d2b6f68b871 Mon Sep 17 00:00:00 2001 From: MartinOscar <40749467+rmartinoscar@users.noreply.github.com> Date: Fri, 4 Apr 2025 00:56:15 +0200 Subject: [PATCH] Prevent `Server` primary `allocation` dissociation (#1197) --- .../AllocationsRelationManager.php | 23 +++++++++++++++---- app/Models/Allocation.php | 14 +++++++++++ lang/en/admin/server.php | 1 + 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/app/Filament/Admin/Resources/ServerResource/RelationManagers/AllocationsRelationManager.php b/app/Filament/Admin/Resources/ServerResource/RelationManagers/AllocationsRelationManager.php index ab5975dbc..736f56183 100644 --- a/app/Filament/Admin/Resources/ServerResource/RelationManagers/AllocationsRelationManager.php +++ b/app/Filament/Admin/Resources/ServerResource/RelationManagers/AllocationsRelationManager.php @@ -12,14 +12,16 @@ use Filament\Forms\Components\TextInput; use Filament\Forms\Get; use Filament\Forms\Set; use Filament\Resources\RelationManagers\RelationManager; -use Filament\Tables; +use Filament\Support\Exceptions\Halt; use Filament\Tables\Actions\Action; use Filament\Tables\Actions\AssociateAction; use Filament\Tables\Actions\CreateAction; +use Filament\Tables\Actions\DissociateBulkAction; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Columns\TextInputColumn; use Filament\Tables\Table; +use Illuminate\Database\Eloquent\Collection; /** * @method Server getOwnerRecord() @@ -96,10 +98,21 @@ class AllocationsRelationManager extends RelationManager ->recordSelectSearchColumns(['ip', 'port']) ->label(trans('admin/server.add_allocation')), ]) - ->bulkActions([ - Tables\Actions\BulkActionGroup::make([ - Tables\Actions\DissociateBulkAction::make(), - ]), + ->groupedBulkActions([ + DissociateBulkAction::make() + ->before(function (DissociateBulkAction $action, Collection $records) { + $records = $records->filter(function ($allocation) { + /** @var Allocation $allocation */ + return $allocation->id !== $this->getOwnerRecord()->allocation_id; + }); + + if ($records->isEmpty()) { + $action->failureNotificationTitle(trans('admin/server.notifications.dissociate_primary'))->failure(); + throw new Halt(); + } + + return $records; + }), ]); } } diff --git a/app/Models/Allocation.php b/app/Models/Allocation.php index 505ed4a2e..a63f57a50 100644 --- a/app/Models/Allocation.php +++ b/app/Models/Allocation.php @@ -72,6 +72,20 @@ class Allocation extends Model static::deleting(function (self $allocation) { throw_if($allocation->server_id, new ServerUsingAllocationException(trans('exceptions.allocations.server_using'))); }); + + static::updating(function ($allocation) { + $originalServerId = $allocation->getOriginal('server_id'); + if (!$originalServerId) { + return; + } + $server = Server::find($originalServerId); + if (!$server) { + return; + } + if ($allocation->isDirty('server_id') && is_null($allocation->server_id) && $allocation->id === $server->allocation_id) { + return false; + } + }); } protected function casts(): array diff --git a/lang/en/admin/server.php b/lang/en/admin/server.php index 2a546239d..97340b67a 100644 --- a/lang/en/admin/server.php +++ b/lang/en/admin/server.php @@ -120,6 +120,7 @@ return [ 'too_many_ports_body' => 'The current limit is :limit number of ports at one time.', 'invalid_port' => 'Port not in valid range', 'invalid_port_body' => ':i is not in the valid port range between :portFloor-:portCeil', + 'dissociate_primary' => 'Cannot dissociate primary allocation', 'already_exists' => 'Port already in use', 'already_exists_body' => ':i is already with an allocation', 'error_connecting' => 'Error connecting to :node',