From d81294a5a0e16c2c9c37a192237fb04a7c6ed2d7 Mon Sep 17 00:00:00 2001 From: Boy132 Date: Tue, 14 Oct 2025 09:00:11 +0200 Subject: [PATCH] add allocation locking --- .../AllocationsRelationManager.php | 41 ++++++++++++++++--- .../Allocations/AllocationResource.php | 10 ++++- app/Models/Allocation.php | 7 ++++ .../Servers/ServerCreationService.php | 1 + ...14_065517_add_is_locked_to_allocations.php | 28 +++++++++++++ lang/en/admin/server.php | 4 ++ lang/en/server/network.php | 2 + 7 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 database/migrations/2025_10_14_065517_add_is_locked_to_allocations.php diff --git a/app/Filament/Admin/Resources/Servers/RelationManagers/AllocationsRelationManager.php b/app/Filament/Admin/Resources/Servers/RelationManagers/AllocationsRelationManager.php index 296a0fdb8..ad6d21208 100644 --- a/app/Filament/Admin/Resources/Servers/RelationManagers/AllocationsRelationManager.php +++ b/app/Filament/Admin/Resources/Servers/RelationManagers/AllocationsRelationManager.php @@ -60,16 +60,35 @@ class AllocationsRelationManager extends RelationManager ->action(fn (Allocation $allocation) => $this->getOwnerRecord()->update(['allocation_id' => $allocation->id]) && $this->deselectAllTableRecords()) ->default(fn (Allocation $allocation) => $allocation->id === $this->getOwnerRecord()->allocation_id) ->label(trans('admin/server.primary')), + IconColumn::make('is_locked') + ->label(trans('admin/server.locked')) + ->tooltip(trans('admin/server.locked_helper')) + ->trueIcon('tabler-lock') + ->falseIcon('tabler-lock-open'), ]) ->recordActions([ Action::make('make-primary') ->label(trans('admin/server.make_primary')) ->action(fn (Allocation $allocation) => $this->getOwnerRecord()->update(['allocation_id' => $allocation->id]) && $this->deselectAllTableRecords()) ->hidden(fn (Allocation $allocation) => $allocation->id === $this->getOwnerRecord()->allocation_id), + Action::make('lock') + ->label(trans('admin/server.lock')) + ->action(fn (Allocation $allocation) => $allocation->update(['is_locked' => true]) && $this->deselectAllTableRecords()) + ->hidden(fn (Allocation $allocation) => $allocation->is_locked), + Action::make('unlock') + ->label(trans('admin/server.unlock')) + ->action(fn (Allocation $allocation) => $allocation->update(['is_locked' => false]) && $this->deselectAllTableRecords()) + ->visible(fn (Allocation $allocation) => $allocation->is_locked), DissociateAction::make() ->after(function (Allocation $allocation) { - $allocation->update(['notes' => null]); - $this->getOwnerRecord()->allocation_id && $this->getOwnerRecord()->update(['allocation_id' => $this->getOwnerRecord()->allocations()->first()?->id]); + $allocation->update([ + 'notes' => null, + 'is_locked' => false, + ]); + + if (!$this->getOwnerRecord()->allocation_id) { + $this->getOwnerRecord()->update(['allocation_id' => $this->getOwnerRecord()->allocations()->first()?->id]); + } }), ]) ->headerActions([ @@ -116,13 +135,25 @@ class AllocationsRelationManager extends RelationManager ->recordSelectOptionsQuery(fn ($query) => $query->whereBelongsTo($this->getOwnerRecord()->node)->whereNull('server_id')) ->recordSelectSearchColumns(['ip', 'port']) ->label(trans('admin/server.add_allocation')) - ->after(fn (array $data) => !$this->getOwnerRecord()->allocation_id && $this->getOwnerRecord()->update(['allocation_id' => $data['recordId'][0]])), + ->after(function (array $data) { + Allocation::whereIn('id', array_values(array_unique($data['recordId'])))->update(['is_locked' => true]); + + if (!$this->getOwnerRecord()->allocation_id) { + $this->getOwnerRecord()->update(['allocation_id' => $data['recordId'][0]]); + } + }), ]) ->groupedBulkActions([ DissociateBulkAction::make() ->after(function () { - Allocation::whereNull('server_id')->update(['notes' => null]); - $this->getOwnerRecord()->allocation_id && $this->getOwnerRecord()->update(['allocation_id' => $this->getOwnerRecord()->allocations()->first()?->id]); + Allocation::whereNull('server_id')->update([ + 'notes' => null, + 'is_locked' => false, + ]); + + if (!$this->getOwnerRecord()->allocation_id) { + $this->getOwnerRecord()->update(['allocation_id' => $this->getOwnerRecord()->allocations()->first()?->id]); + } }), ]); } diff --git a/app/Filament/Server/Resources/Allocations/AllocationResource.php b/app/Filament/Server/Resources/Allocations/AllocationResource.php index 92e70c554..c15dc9814 100644 --- a/app/Filament/Server/Resources/Allocations/AllocationResource.php +++ b/app/Filament/Server/Resources/Allocations/AllocationResource.php @@ -73,15 +73,21 @@ class AllocationResource extends Resource ->action(fn (Allocation $allocation) => user()?->can(PERMISSION::ACTION_ALLOCATION_UPDATE, $server) && $server->update(['allocation_id' => $allocation->id])) ->default(fn (Allocation $allocation) => $allocation->id === $server->allocation_id) ->label(trans('server/network.primary')), + IconColumn::make('is_locked') + ->label(trans('server/network.locked')) + ->trueIcon('tabler-lock') + ->falseIcon('tabler-lock-open'), ]) ->recordActions([ DetachAction::make() + ->visible(fn (Allocation $allocation) => !$allocation->is_locked || user()?->can('update', $allocation->node)) ->authorize(fn () => user()?->can(Permission::ACTION_ALLOCATION_DELETE, $server)) ->label(trans('server/network.delete')) ->icon('tabler-trash') ->action(function (Allocation $allocation) { - Allocation::query()->where('id', $allocation->id)->update([ + Allocation::where('id', $allocation->id)->update([ 'notes' => null, + 'is_locked' => false, 'server_id' => null, ]); @@ -93,7 +99,7 @@ class AllocationResource extends Resource ->after(fn (Allocation $allocation) => $allocation->id === $server->allocation_id && $server->update(['allocation_id' => $server->allocations()->first()?->id])), ]) ->toolbarActions([ - Action::make('addAllocation') + Action::make('add_allocation') ->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge) ->icon(fn () => $server->allocations()->count() >= $server->allocation_limit ? 'tabler-network-off' : 'tabler-network') ->authorize(fn () => user()?->can(Permission::ACTION_ALLOCATION_CREATE, $server)) diff --git a/app/Models/Allocation.php b/app/Models/Allocation.php index 6c7ac88a9..b43dc3daf 100644 --- a/app/Models/Allocation.php +++ b/app/Models/Allocation.php @@ -29,6 +29,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; * @property string $address * @property Server|null $server * @property Node $node + * @property bool $is_locked * * @method static AllocationFactory factory(...$parameters) * @method static Builder|Allocation newModelQuery() @@ -55,6 +56,10 @@ class Allocation extends Model */ public const RESOURCE_NAME = 'allocation'; + protected $attributes = [ + 'is_locked' => false, + ]; + /** * Fields that are not mass assignable. */ @@ -68,6 +73,7 @@ class Allocation extends Model 'ip_alias' => ['nullable', 'string'], 'server_id' => ['nullable', 'exists:servers,id'], 'notes' => ['nullable', 'string', 'max:256'], + 'is_locked' => ['boolean'], ]; protected static function booted(): void @@ -83,6 +89,7 @@ class Allocation extends Model 'node_id' => 'integer', 'port' => 'integer', 'server_id' => 'integer', + 'is_locked' => 'bool', ]; } diff --git a/app/Services/Servers/ServerCreationService.php b/app/Services/Servers/ServerCreationService.php index f2483c5f6..f15f84f34 100644 --- a/app/Services/Servers/ServerCreationService.php +++ b/app/Services/Servers/ServerCreationService.php @@ -191,6 +191,7 @@ class ServerCreationService ->get() ->each(function (Allocation $allocation) use ($server) { $allocation->server_id = $server->id; + $allocation->is_locked = true; $allocation->save(); }); } diff --git a/database/migrations/2025_10_14_065517_add_is_locked_to_allocations.php b/database/migrations/2025_10_14_065517_add_is_locked_to_allocations.php new file mode 100644 index 000000000..f7c429cb2 --- /dev/null +++ b/database/migrations/2025_10_14_065517_add_is_locked_to_allocations.php @@ -0,0 +1,28 @@ +boolean('is_locked')->default(false); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('allocations', function (Blueprint $table) { + $table->dropColumn('is_locked'); + }); + } +}; diff --git a/lang/en/admin/server.php b/lang/en/admin/server.php index cd74c4159..935ca8232 100644 --- a/lang/en/admin/server.php +++ b/lang/en/admin/server.php @@ -13,6 +13,10 @@ return [ 'ports' => 'Ports', 'alias' => 'Alias', 'alias_helper' => 'Optional display name to help you remember what these are.', + 'locked' => 'Locked?', + 'locked_helper' => 'Users won\'t be able to delete locked allocations', + 'lock' => 'Lock', + 'unlock' => 'Unlock', 'name' => 'Name', 'external_id' => 'External ID', 'owner' => 'Owner', diff --git a/lang/en/server/network.php b/lang/en/server/network.php index 21ef09012..6ff0bf1bb 100644 --- a/lang/en/server/network.php +++ b/lang/en/server/network.php @@ -12,4 +12,6 @@ return [ 'primary' => 'Primary', 'make' => 'Make', 'delete' => 'Delete', + 'locked' => 'Locked?', + 'locked_helper' => 'Locked allocations can only be deleted by admins', ];