Allow admins to "lock" allocations (#1811)

This commit is contained in:
Boy132 2025-11-08 21:54:41 +01:00 committed by GitHub
parent 6ed84b5584
commit cec141889a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 93 additions and 7 deletions

View File

@ -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]);
}
}),
]);
}

View File

@ -73,15 +73,22 @@ 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'))
->tooltip(trans('server/network.locked_helper'))
->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 +100,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))

View File

@ -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,10 +73,17 @@ 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
{
static::updating(function (self $allocation) {
if (is_null($allocation->server_id)) {
$allocation->is_locked = false;
}
});
static::deleting(function (self $allocation) {
throw_if($allocation->server_id, new ServerUsingAllocationException(trans('exceptions.allocations.server_using')));
});
@ -83,6 +95,7 @@ class Allocation extends Model
'node_id' => 'integer',
'port' => 'integer',
'server_id' => 'integer',
'is_locked' => 'bool',
];
}

View File

@ -191,6 +191,7 @@ class ServerCreationService
->get()
->each(function (Allocation $allocation) use ($server) {
$allocation->server_id = $server->id;
$allocation->is_locked = true;
$allocation->save();
});
}

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('allocations', function (Blueprint $table) {
$table->boolean('is_locked')->default(false);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('allocations', function (Blueprint $table) {
$table->dropColumn('is_locked');
});
}
};

View File

@ -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',

View File

@ -12,4 +12,6 @@ return [
'primary' => 'Primary',
'make' => 'Make',
'delete' => 'Delete',
'locked' => 'Locked?',
'locked_helper' => 'Locked allocations can only be deleted by admins',
];