From 5b6c4629431d2798429ab195180ddf3c48922fc0 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 2 Jun 2024 01:22:12 -0400 Subject: [PATCH 001/103] =?UTF-8?q?This=20isn=E2=80=99t=20typically=20used?= =?UTF-8?q?=20for=20a=20brand=20new=20server?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ServerResource/Pages/CreateServer.php | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index 78ee1eec47..8ac9eac403 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -285,29 +285,6 @@ public function form(Form $form): Form }) ->required(), - Forms\Components\ToggleButtons::make('skip_scripts') - ->label('Run Egg Install Script?') - ->default(false) - ->columnSpan([ - 'default' => 1, - 'sm' => 1, - 'md' => 1, - 'lg' => 1, - ]) - ->options([ - false => 'Yes', - true => 'Skip', - ]) - ->colors([ - false => 'primary', - true => 'danger', - ]) - ->icons([ - false => 'tabler-code', - true => 'tabler-code-off', - ]) - ->inline() - ->required(), Forms\Components\Textarea::make('startup') ->hintIcon('tabler-code') From 29f8ac625a65e20878210daaa70a069bb3b46404 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 2 Jun 2024 01:22:21 -0400 Subject: [PATCH 002/103] This is for the api --- app/Filament/Resources/ServerResource/Pages/CreateServer.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index 8ac9eac403..6f59608bd8 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -33,9 +33,6 @@ public function form(Form $form): Form 'lg' => 6, ]) ->schema([ - Forms\Components\TextInput::make('external_id') - ->maxLength(191) - ->hidden(), Forms\Components\TextInput::make('name') ->prefixIcon('tabler-server') From b220c582cc6bc6c75c094aed7149aa1622ba57d5 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 2 Jun 2024 01:22:33 -0400 Subject: [PATCH 003/103] Rearrange these --- .../ServerResource/Pages/CreateServer.php | 117 +++++++++--------- 1 file changed, 58 insertions(+), 59 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index 6f59608bd8..d7fc95a9d7 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -33,6 +33,47 @@ public function form(Form $form): Form 'lg' => 6, ]) ->schema([ + Forms\Components\Select::make('egg_id') + ->disabledOn('edit') + ->prefixIcon('tabler-egg') + ->columnSpan([ + 'default' => 2, + 'sm' => 2, + 'md' => 2, + 'lg' => 3, + ]) + ->relationship('egg', 'name') + ->searchable() + ->preload() + ->live() + ->afterStateUpdated(function ($state, Forms\Set $set, Forms\Get $get, $old) { + $egg = Egg::query()->find($state); + $set('startup', $egg->startup); + $set('image', ''); + + $variables = $egg->variables ?? []; + $serverVariables = collect(); + foreach ($variables as $variable) { + $serverVariables->add($variable->toArray()); + } + + $variables = []; + $set($path = 'server_variables', $serverVariables->sortBy(['sort'])->all()); + for ($i = 0; $i < $serverVariables->count(); $i++) { + $set("$path.$i.variable_value", $serverVariables[$i]['default_value']); + $set("$path.$i.variable_id", $serverVariables[$i]['id']); + $variables[$serverVariables[$i]['env_variable']] = $serverVariables[$i]['default_value']; + } + + $set('environment', $variables); + + $previousEgg = Egg::query()->find($old); + if (!$get('name') || $previousEgg?->getKebabName() === $get('name')) { + $set('name', $egg->getKebabName()); + } + }) + ->required(), + Forms\Components\TextInput::make('name') ->prefixIcon('tabler-server') @@ -56,6 +97,18 @@ public function form(Form $form): Form ->required() ->maxLength(191), + Forms\Components\Select::make('node_id') + ->disabledOn('edit') + ->prefixIcon('tabler-server-2') + ->default(fn () => Node::query()->latest()->first()?->id) + ->columnSpan(3) + ->live() + ->relationship('node', 'name') + ->searchable() + ->preload() + ->afterStateUpdated(fn (Forms\Set $set) => $set('allocation_id', null)) + ->required(), + Forms\Components\Select::make('owner_id') ->prefixIcon('tabler-user') ->default(auth()->user()->id) @@ -71,17 +124,11 @@ public function form(Form $form): Form ->preload() ->required(), - Forms\Components\Select::make('node_id') - ->disabledOn('edit') - ->prefixIcon('tabler-server-2') - ->default(fn () => Node::query()->latest()->first()?->id) - ->columnSpan(2) - ->live() - ->relationship('node', 'name') - ->searchable() - ->preload() - ->afterStateUpdated(fn (Forms\Set $set) => $set('allocation_id', null)) - ->required(), + Forms\Components\Textarea::make('description') + ->hidden() + ->default('') + ->required() + ->columnSpanFull(), Forms\Components\Select::make('allocation_id') ->preload() @@ -235,54 +282,6 @@ public function form(Form $form): Form ), ), - Forms\Components\Textarea::make('description') - ->hidden() - ->default('') - ->required() - ->columnSpanFull(), - - Forms\Components\Select::make('egg_id') - ->disabledOn('edit') - ->prefixIcon('tabler-egg') - ->columnSpan([ - 'default' => 2, - 'sm' => 2, - 'md' => 2, - 'lg' => 5, - ]) - ->relationship('egg', 'name') - ->searchable() - ->preload() - ->live() - ->afterStateUpdated(function ($state, Forms\Set $set, Forms\Get $get, $old) { - $egg = Egg::query()->find($state); - $set('startup', $egg->startup); - $set('image', ''); - - $variables = $egg->variables ?? []; - $serverVariables = collect(); - foreach ($variables as $variable) { - $serverVariables->add($variable->toArray()); - } - - $variables = []; - $set($path = 'server_variables', $serverVariables->sortBy(['sort'])->all()); - for ($i = 0; $i < $serverVariables->count(); $i++) { - $set("$path.$i.variable_value", $serverVariables[$i]['default_value']); - $set("$path.$i.variable_id", $serverVariables[$i]['id']); - $variables[$serverVariables[$i]['env_variable']] = $serverVariables[$i]['default_value']; - } - - $set('environment', $variables); - - $previousEgg = Egg::query()->find($old); - if (!$get('name') || $previousEgg?->getKebabName() === $get('name')) { - $set('name', $egg->getKebabName()); - } - }) - ->required(), - - Forms\Components\Textarea::make('startup') ->hintIcon('tabler-code') ->label('Startup Command') From 9c81c0ce181927bb8690e944f08dd5a89af9144d Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 2 Jun 2024 01:25:48 -0400 Subject: [PATCH 004/103] Use public member --- .../ServerResource/Pages/CreateServer.php | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index d7fc95a9d7..ec8ff4114c 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -22,6 +22,7 @@ class CreateServer extends CreateRecord { protected static string $resource = ServerResource::class; protected static bool $canCreateAnother = false; + public ?Egg $egg = null; public function form(Form $form): Form { @@ -47,11 +48,11 @@ public function form(Form $form): Form ->preload() ->live() ->afterStateUpdated(function ($state, Forms\Set $set, Forms\Get $get, $old) { - $egg = Egg::query()->find($state); - $set('startup', $egg->startup); + $this->egg = Egg::query()->find($state); + $set('startup', $this->egg->startup); $set('image', ''); - $variables = $egg->variables ?? []; + $variables = $this->egg->variables ?? []; $serverVariables = collect(); foreach ($variables as $variable) { $serverVariables->add($variable->toArray()); @@ -69,7 +70,7 @@ public function form(Form $form): Form $previousEgg = Egg::query()->find($old); if (!$get('name') || $previousEgg?->getKebabName() === $get('name')) { - $set('name', $egg->getKebabName()); + $set('name', $this->egg->getKebabName()); } }) ->required(), @@ -81,8 +82,7 @@ public function form(Form $form): Form ->suffixAction(Forms\Components\Actions\Action::make('random') ->icon('tabler-dice-' . random_int(1, 6)) ->action(function (Forms\Set $set, Forms\Get $get) { - $egg = Egg::find($get('egg_id')); - $prefix = $egg ? str($egg->name)->lower()->kebab() . '-' : ''; + $prefix = $this->egg ? str($this->egg->name)->lower()->kebab() . '-' : ''; $word = (new RandomWordService())->word(); @@ -177,7 +177,7 @@ public function form(Form $form): Form ->default(null) ->datalist([ $get('name'), - Egg::find($get('egg_id'))?->name, + $this->egg?->name, ]) ->helperText('Optional display name to help you remember what these are.') ->required(false), @@ -317,11 +317,11 @@ public function form(Form $form): Form ])) ->schema([ Forms\Components\Placeholder::make('Select an egg first to show its variables!') - ->hidden(fn (Forms\Get $get) => $get('egg_id')), + ->hidden(fn (Forms\Get $get) => $this->egg), Forms\Components\Placeholder::make('The selected egg has no variables!') - ->hidden(fn (Forms\Get $get) => !$get('egg_id') || - Egg::query()->find($get('egg_id'))?->variables()?->count() + ->hidden(fn (Forms\Get $get) => !$this->egg || + $this->egg->variables()?->count() ), Forms\Components\Repeater::make('server_variables') @@ -625,8 +625,7 @@ public function form(Form $form): Form ->label('Image Name') ->afterStateUpdated(fn (Forms\Set $set, $state) => $set('image', $state)) ->options(function ($state, Forms\Get $get, Forms\Set $set) { - $egg = Egg::query()->find($get('egg_id')); - $images = $egg->docker_images ?? []; + $images = $this->egg->docker_images ?? []; $currentImage = $get('image'); if (!$currentImage && $images) { @@ -644,8 +643,7 @@ public function form(Form $form): Form ->label('Image') ->debounce(500) ->afterStateUpdated(function ($state, Forms\Get $get, Forms\Set $set) { - $egg = Egg::query()->find($get('egg_id')); - $images = $egg->docker_images ?? []; + $images = $this->egg->docker_images ?? []; if (in_array($state, $images)) { $set('select_image', $state); From f480a271b34ed90d17a4ca7960dc30c399418864 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 2 Jun 2024 01:27:04 -0400 Subject: [PATCH 005/103] Simplify logic --- app/Filament/Resources/ServerResource/Pages/CreateServer.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index ec8ff4114c..7f6aee0444 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -320,9 +320,7 @@ public function form(Form $form): Form ->hidden(fn (Forms\Get $get) => $this->egg), Forms\Components\Placeholder::make('The selected egg has no variables!') - ->hidden(fn (Forms\Get $get) => !$this->egg || - $this->egg->variables()?->count() - ), + ->hidden(fn (Forms\Get $get) => $this->egg?->variables()?->count() !== 0), Forms\Components\Repeater::make('server_variables') ->relationship('serverVariables') From 4dbb55059d81288d9dded55144b665bfe8c40133 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 2 Jun 2024 01:38:30 -0400 Subject: [PATCH 006/103] Remove auto generated properties --- app/Models/ActivityLog.php | 36 ------------- app/Models/ActivityLogSubject.php | 16 ------ app/Models/Allocation.php | 33 ------------ app/Models/ApiKey.php | 49 ----------------- app/Models/Backup.php | 19 ------- app/Models/Database.php | 14 ----- app/Models/DatabaseHost.php | 12 ----- app/Models/Egg.php | 39 -------------- app/Models/EggVariable.php | 21 -------- app/Models/Mount.php | 13 ----- app/Models/Node.php | 28 ---------- app/Models/RecoveryToken.php | 7 --- app/Models/Schedule.php | 19 ------- app/Models/Server.php | 87 ------------------------------- app/Models/ServerTransfer.php | 17 ------ app/Models/ServerVariable.php | 10 ---- app/Models/Setting.php | 7 --- app/Models/Subuser.php | 10 ---- app/Models/Task.php | 14 ----- app/Models/User.php | 58 --------------------- app/Models/UserSSHKey.php | 32 ------------ 21 files changed, 541 deletions(-) diff --git a/app/Models/ActivityLog.php b/app/Models/ActivityLog.php index 06fd2d108b..06b9824ad5 100644 --- a/app/Models/ActivityLog.php +++ b/app/Models/ActivityLog.php @@ -12,42 +12,6 @@ use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Model as IlluminateModel; -/** - * \App\Models\ActivityLog. - * - * @property int $id - * @property string|null $batch - * @property string $event - * @property string $ip - * @property string|null $description - * @property string|null $actor_type - * @property int|null $actor_id - * @property int|null $api_key_id - * @property \Illuminate\Support\Collection|null $properties - * @property \Carbon\Carbon $timestamp - * @property IlluminateModel|\Eloquent $actor - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\ActivityLogSubject[] $subjects - * @property int|null $subjects_count - * @property \App\Models\ApiKey|null $apiKey - * - * @method static Builder|ActivityLog forActor(\Illuminate\Database\Eloquent\Model $actor) - * @method static Builder|ActivityLog forEvent(string $action) - * @method static Builder|ActivityLog newModelQuery() - * @method static Builder|ActivityLog newQuery() - * @method static Builder|ActivityLog query() - * @method static Builder|ActivityLog whereActorId($value) - * @method static Builder|ActivityLog whereActorType($value) - * @method static Builder|ActivityLog whereApiKeyId($value) - * @method static Builder|ActivityLog whereBatch($value) - * @method static Builder|ActivityLog whereDescription($value) - * @method static Builder|ActivityLog whereEvent($value) - * @method static Builder|ActivityLog whereId($value) - * @method static Builder|ActivityLog whereIp($value) - * @method static Builder|ActivityLog whereProperties($value) - * @method static Builder|ActivityLog whereTimestamp($value) - * - * @mixin \Eloquent - */ class ActivityLog extends Model { use MassPrunable; diff --git a/app/Models/ActivityLogSubject.php b/app/Models/ActivityLogSubject.php index 037d344f05..45b2c4ffe7 100644 --- a/app/Models/ActivityLogSubject.php +++ b/app/Models/ActivityLogSubject.php @@ -6,22 +6,6 @@ use Illuminate\Database\Eloquent\Relations\Pivot; use Illuminate\Database\Eloquent\SoftDeletes; -/** - * \App\Models\ActivityLogSubject. - * - * @property int $id - * @property int $activity_log_id - * @property int $subject_id - * @property string $subject_type - * @property \App\Models\ActivityLog|null $activityLog - * @property \Illuminate\Database\Eloquent\Model|\Eloquent $subject - * - * @method static \Illuminate\Database\Eloquent\Builder|ActivityLogSubject newModelQuery() - * @method static \Illuminate\Database\Eloquent\Builder|ActivityLogSubject newQuery() - * @method static \Illuminate\Database\Eloquent\Builder|ActivityLogSubject query() - * - * @mixin \Eloquent - */ class ActivityLogSubject extends Pivot { public $incrementing = true; diff --git a/app/Models/Allocation.php b/app/Models/Allocation.php index 33bc7f16de..c58514b847 100644 --- a/app/Models/Allocation.php +++ b/app/Models/Allocation.php @@ -6,39 +6,6 @@ use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Relations\BelongsTo; -/** - * App\Models\Allocation. - * - * @property int $id - * @property int $node_id - * @property string $ip - * @property string|null $ip_alias - * @property int $port - * @property int|null $server_id - * @property string|null $notes - * @property \Carbon\Carbon|null $created_at - * @property \Carbon\Carbon|null $updated_at - * @property string $alias - * @property bool $has_alias - * @property \App\Models\Server|null $server - * @property \App\Models\Node $node - * - * @method static \Database\Factories\AllocationFactory factory(...$parameters) - * @method static \Illuminate\Database\Eloquent\Builder|Allocation newModelQuery() - * @method static \Illuminate\Database\Eloquent\Builder|Allocation newQuery() - * @method static \Illuminate\Database\Eloquent\Builder|Allocation query() - * @method static \Illuminate\Database\Eloquent\Builder|Allocation whereCreatedAt($value) - * @method static \Illuminate\Database\Eloquent\Builder|Allocation whereId($value) - * @method static \Illuminate\Database\Eloquent\Builder|Allocation whereIp($value) - * @method static \Illuminate\Database\Eloquent\Builder|Allocation whereIpAlias($value) - * @method static \Illuminate\Database\Eloquent\Builder|Allocation whereNodeId($value) - * @method static \Illuminate\Database\Eloquent\Builder|Allocation whereNotes($value) - * @method static \Illuminate\Database\Eloquent\Builder|Allocation wherePort($value) - * @method static \Illuminate\Database\Eloquent\Builder|Allocation whereServerId($value) - * @method static \Illuminate\Database\Eloquent\Builder|Allocation whereUpdatedAt($value) - * - * @mixin \Eloquent - */ class Allocation extends Model { /** diff --git a/app/Models/ApiKey.php b/app/Models/ApiKey.php index 21c044c548..b7b0abb4e5 100644 --- a/app/Models/ApiKey.php +++ b/app/Models/ApiKey.php @@ -7,55 +7,6 @@ use App\Services\Acl\Api\AdminAcl; use Illuminate\Database\Eloquent\Relations\BelongsTo; -/** - * App\Models\ApiKey. - * - * @property int $id - * @property int $user_id - * @property int $key_type - * @property string $identifier - * @property string $token - * @property array|null $allowed_ips - * @property string|null $memo - * @property \Illuminate\Support\Carbon|null $last_used_at - * @property \Illuminate\Support\Carbon|null $expires_at - * @property \Illuminate\Support\Carbon|null $created_at - * @property \Illuminate\Support\Carbon|null $updated_at - * @property int $r_servers - * @property int $r_nodes - * @property int $r_allocations - * @property int $r_users - * @property int $r_eggs - * @property int $r_database_hosts - * @property int $r_server_databases - * @property int $r_mounts - * @property \App\Models\User $tokenable - * @property \App\Models\User $user - * - * @method static \Database\Factories\ApiKeyFactory factory(...$parameters) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey newModelQuery() - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey newQuery() - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey query() - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereAllowedIps($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereCreatedAt($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereId($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereIdentifier($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereKeyType($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereLastUsedAt($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereMemo($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereRAllocations($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereRDatabaseHosts($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereREggs($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereRNodes($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereRServerDatabases($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereRServers($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereRUsers($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereToken($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereUpdatedAt($value) - * @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereUserId($value) - * - * @mixin \Eloquent - */ class ApiKey extends Model { /** diff --git a/app/Models/Backup.php b/app/Models/Backup.php index 3f2a931d1e..48ab758b9d 100644 --- a/app/Models/Backup.php +++ b/app/Models/Backup.php @@ -6,25 +6,6 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Relations\BelongsTo; -/** - * @property int $id - * @property int $server_id - * @property string $uuid - * @property bool $is_successful - * @property bool $is_locked - * @property string $name - * @property string[] $ignored_files - * @property string $disk - * @property string|null $checksum - * @property int $bytes - * @property string|null $upload_id - * @property \Carbon\CarbonImmutable|null $completed_at - * @property \Carbon\CarbonImmutable $created_at - * @property \Carbon\CarbonImmutable $updated_at - * @property \Carbon\CarbonImmutable|null $deleted_at - * @property \App\Models\Server $server - * @property \App\Models\AuditLog[] $audits - */ class Backup extends Model { use SoftDeletes; diff --git a/app/Models/Database.php b/app/Models/Database.php index bd6bc6de34..5270257f77 100644 --- a/app/Models/Database.php +++ b/app/Models/Database.php @@ -5,20 +5,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Facades\DB; -/** - * @property int $id - * @property int $server_id - * @property int $database_host_id - * @property string $database - * @property string $username - * @property string $remote - * @property string $password - * @property int $max_connections - * @property \Carbon\Carbon $created_at - * @property \Carbon\Carbon $updated_at - * @property \App\Models\Server $server - * @property \App\Models\DatabaseHost $host - */ class Database extends Model { /** diff --git a/app/Models/DatabaseHost.php b/app/Models/DatabaseHost.php index 159e172613..e2ee4b3221 100644 --- a/app/Models/DatabaseHost.php +++ b/app/Models/DatabaseHost.php @@ -5,18 +5,6 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; -/** - * @property int $id - * @property string $name - * @property string $host - * @property int $port - * @property string $username - * @property string $password - * @property int|null $max_databases - * @property int|null $node_id - * @property \Carbon\CarbonImmutable $created_at - * @property \Carbon\CarbonImmutable $updated_at - */ class DatabaseHost extends Model { /** diff --git a/app/Models/Egg.php b/app/Models/Egg.php index 3e194bae33..7c8cb91375 100644 --- a/app/Models/Egg.php +++ b/app/Models/Egg.php @@ -8,45 +8,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Str; -/** - * @property int $id - * @property string $uuid - * @property string $author - * @property string $name - * @property string|null $description - * @property array|null $features - * @property string $docker_image -- deprecated, use $docker_images - * @property array $docker_images - * @property string $update_url - * @property bool $force_outgoing_ip - * @property array|null $file_denylist - * @property string|null $config_files - * @property string|null $config_startup - * @property string|null $config_logs - * @property string|null $config_stop - * @property int|null $config_from - * @property string|null $startup - * @property bool $script_is_privileged - * @property string|null $script_install - * @property string $script_entry - * @property string $script_container - * @property int|null $copy_script_from - * @property \Carbon\Carbon $created_at - * @property \Carbon\Carbon $updated_at - * @property string|null $copy_script_install - * @property string $copy_script_entry - * @property string $copy_script_container - * @property string|null $inherit_config_files - * @property string|null $inherit_config_startup - * @property string|null $inherit_config_logs - * @property string|null $inherit_config_stop - * @property string $inherit_file_denylist - * @property array|null $inherit_features - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\Server[] $servers - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\EggVariable[] $variables - * @property \App\Models\Egg|null $scriptFrom - * @property \App\Models\Egg|null $configFrom - */ class Egg extends Model { /** diff --git a/app/Models/EggVariable.php b/app/Models/EggVariable.php index 568830a5b0..ca5adf035c 100644 --- a/app/Models/EggVariable.php +++ b/app/Models/EggVariable.php @@ -5,27 +5,6 @@ use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\HasMany; -/** - * @property int $id - * @property int $egg_id - * @property null $sort - * @property string $name - * @property string $description - * @property string $env_variable - * @property string $default_value - * @property bool $user_viewable - * @property bool $user_editable - * @property string $rules - * @property \Carbon\CarbonImmutable $created_at - * @property \Carbon\CarbonImmutable $updated_at - * @property bool $required - * @property \App\Models\Egg $egg - * @property \App\Models\ServerVariable $serverVariable - * - * The "server_value" variable is only present on the object if you've loaded this model - * using the server relationship. - * @property string|null $server_value - */ class EggVariable extends Model { /** diff --git a/app/Models/Mount.php b/app/Models/Mount.php index aa335b9904..ea42941108 100644 --- a/app/Models/Mount.php +++ b/app/Models/Mount.php @@ -5,19 +5,6 @@ use Illuminate\Validation\Rules\NotIn; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -/** - * @property int $id - * @property string $uuid - * @property string $name - * @property string $description - * @property string $source - * @property string $target - * @property bool $read_only - * @property bool $user_mountable - * @property \App\Models\Egg[]|\Illuminate\Database\Eloquent\Collection $eggs - * @property \App\Models\Node[]|\Illuminate\Database\Eloquent\Collection $nodes - * @property \App\Models\Server[]|\Illuminate\Database\Eloquent\Collection $servers - */ class Mount extends Model { /** diff --git a/app/Models/Node.php b/app/Models/Node.php index 65aeaa0ea5..0c41abfe99 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -12,34 +12,6 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasManyThrough; -/** - * @property int $id - * @property string $uuid - * @property bool $public - * @property string $name - * @property string|null $description - * @property string $fqdn - * @property string $scheme - * @property bool $behind_proxy - * @property bool $maintenance_mode - * @property int $memory - * @property int $memory_overallocate - * @property int $disk - * @property int $disk_overallocate - * @property int $cpu - * @property int $cpu_overallocate - * @property int $upload_size - * @property string $daemon_token_id - * @property string $daemon_token - * @property int $daemon_listen - * @property int $daemon_sftp - * @property string $daemon_base - * @property \Carbon\Carbon $created_at - * @property \Carbon\Carbon $updated_at - * @property \App\Models\Mount[]|\Illuminate\Database\Eloquent\Collection $mounts - * @property \App\Models\Server[]|\Illuminate\Database\Eloquent\Collection $servers - * @property \App\Models\Allocation[]|\Illuminate\Database\Eloquent\Collection $allocations - */ class Node extends Model { use Notifiable; diff --git a/app/Models/RecoveryToken.php b/app/Models/RecoveryToken.php index c4fe8c8ae1..731347d711 100644 --- a/app/Models/RecoveryToken.php +++ b/app/Models/RecoveryToken.php @@ -4,13 +4,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; -/** - * @property int $id - * @property int $user_id - * @property string $token - * @property \Carbon\CarbonImmutable $created_at - * @property \App\Models\User $user - */ class RecoveryToken extends Model { /** diff --git a/app/Models/Schedule.php b/app/Models/Schedule.php index 7042d25a46..5bee2998e5 100644 --- a/app/Models/Schedule.php +++ b/app/Models/Schedule.php @@ -7,25 +7,6 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; -/** - * @property int $id - * @property int $server_id - * @property string $name - * @property string $cron_day_of_week - * @property string $cron_month - * @property string $cron_day_of_month - * @property string $cron_hour - * @property string $cron_minute - * @property bool $is_active - * @property bool $is_processing - * @property bool $only_when_online - * @property \Carbon\Carbon|null $last_run_at - * @property \Carbon\Carbon|null $next_run_at - * @property \Carbon\Carbon $created_at - * @property \Carbon\Carbon $updated_at - * @property \App\Models\Server $server - * @property \App\Models\Task[]|\Illuminate\Support\Collection $tasks - */ class Schedule extends Model { /** diff --git a/app/Models/Server.php b/app/Models/Server.php index 3c46573435..b8aef9f675 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -16,93 +16,6 @@ use Illuminate\Database\Eloquent\Relations\HasManyThrough; use App\Exceptions\Http\Server\ServerStateConflictException; -/** - * \App\Models\Server. - * - * @property int $id - * @property string|null $external_id - * @property string $uuid - * @property string $uuid_short - * @property int $node_id - * @property string $name - * @property string $description - * @property string|null $status - * @property bool $skip_scripts - * @property int $owner_id - * @property int $memory - * @property int $swap - * @property int $disk - * @property int $io - * @property int $cpu - * @property string|null $threads - * @property bool $oom_killer - * @property int $allocation_id - * @property int $egg_id - * @property string $startup - * @property string $image - * @property int|null $allocation_limit - * @property int|null $database_limit - * @property int $backup_limit - * @property \Illuminate\Support\Carbon|null $created_at - * @property \Illuminate\Support\Carbon|null $updated_at - * @property \Illuminate\Support\Carbon|null $installed_at - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\ActivityLog[] $activity - * @property int|null $activity_count - * @property \App\Models\Allocation|null $allocation - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\Allocation[] $allocations - * @property int|null $allocations_count - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\Backup[] $backups - * @property int|null $backups_count - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\Database[] $databases - * @property int|null $databases_count - * @property \App\Models\Egg|null $egg - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\Mount[] $mounts - * @property int|null $mounts_count - * @property \App\Models\Node $node - * @property \Illuminate\Notifications\DatabaseNotificationCollection|\Illuminate\Notifications\DatabaseNotification[] $notifications - * @property int|null $notifications_count - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\Schedule[] $schedules - * @property int|null $schedules_count - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\Subuser[] $subusers - * @property int|null $subusers_count - * @property \App\Models\ServerTransfer|null $transfer - * @property \App\Models\User $user - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\EggVariable[] $variables - * @property int|null $variables_count - * - * @method static \Database\Factories\ServerFactory factory(...$parameters) - * @method static \Illuminate\Database\Eloquent\Builder|Server newModelQuery() - * @method static \Illuminate\Database\Eloquent\Builder|Server newQuery() - * @method static \Illuminate\Database\Eloquent\Builder|Server query() - * @method static \Illuminate\Database\Eloquent\Builder|Server whereAllocationId($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereAllocationLimit($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereBackupLimit($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereCpu($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereCreatedAt($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereDatabaseLimit($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereDescription($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereDisk($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereEggId($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereExternalId($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereId($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereImage($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereIo($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereMemory($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereName($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereNodeId($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereOomKiller($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereOwnerId($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereSkipScripts($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereStartup($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereStatus($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereSwap($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereThreads($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereUpdatedAt($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereUuid($value) - * @method static \Illuminate\Database\Eloquent\Builder|Server whereuuid_short($value) - * - * @mixin \Eloquent - */ class Server extends Model { use Notifiable; diff --git a/app/Models/ServerTransfer.php b/app/Models/ServerTransfer.php index abfef3eb67..e4772005c1 100644 --- a/app/Models/ServerTransfer.php +++ b/app/Models/ServerTransfer.php @@ -5,23 +5,6 @@ use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\BelongsTo; -/** - * @property int $id - * @property int $server_id - * @property int $old_node - * @property int $new_node - * @property int $old_allocation - * @property int $new_allocation - * @property array|null $old_additional_allocations - * @property array|null $new_additional_allocations - * @property bool|null $successful - * @property bool $archived - * @property \Carbon\Carbon $created_at - * @property \Carbon\Carbon $updated_at - * @property \App\Models\Server $server - * @property \App\Models\Node $oldNode - * @property \App\Models\Node $newNode - */ class ServerTransfer extends Model { /** diff --git a/app/Models/ServerVariable.php b/app/Models/ServerVariable.php index 0c7eeffc56..1d8308eaff 100644 --- a/app/Models/ServerVariable.php +++ b/app/Models/ServerVariable.php @@ -4,16 +4,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; -/** - * @property int $id - * @property int $server_id - * @property int $variable_id - * @property string $variable_value - * @property \Carbon\CarbonImmutable|null $created_at - * @property \Carbon\CarbonImmutable|null $updated_at - * @property \App\Models\EggVariable $variable - * @property \App\Models\Server $server - */ class ServerVariable extends Model { /** diff --git a/app/Models/Setting.php b/app/Models/Setting.php index 4d4087f7c1..63d9cd3c98 100644 --- a/app/Models/Setting.php +++ b/app/Models/Setting.php @@ -2,13 +2,6 @@ namespace App\Models; -/** - * App\Models\Setting. - * - * @property int $id - * @property string $key - * @property string $value - */ class Setting extends Model { /** diff --git a/app/Models/Subuser.php b/app/Models/Subuser.php index 566c8a7412..3426f81cb3 100644 --- a/app/Models/Subuser.php +++ b/app/Models/Subuser.php @@ -6,16 +6,6 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; -/** - * @property int $id - * @property int $user_id - * @property int $server_id - * @property array $permissions - * @property \Carbon\Carbon $created_at - * @property \Carbon\Carbon $updated_at - * @property \App\Models\User $user - * @property \App\Models\Server $server - */ class Subuser extends Model { use Notifiable; diff --git a/app/Models/Task.php b/app/Models/Task.php index 6545ab5f5f..3f44b77998 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -5,20 +5,6 @@ use Illuminate\Database\Eloquent\Relations\HasOneThrough; use Illuminate\Database\Eloquent\Relations\BelongsTo; -/** - * @property int $id - * @property int $schedule_id - * @property int $sequence_id - * @property string $action - * @property string $payload - * @property int $time_offset - * @property bool $is_queued - * @property bool $continue_on_failure - * @property \Carbon\Carbon $created_at - * @property \Carbon\Carbon $updated_at - * @property \App\Models\Schedule $schedule - * @property \App\Models\Server $server - */ class Task extends Model { /** diff --git a/app/Models/User.php b/app/Models/User.php index f089aba070..6afd952301 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -25,64 +25,6 @@ use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract; use App\Notifications\SendPasswordReset as ResetPasswordNotification; -/** - * App\Models\User. - * - * @property int $id - * @property string|null $external_id - * @property string $uuid - * @property string $username - * @property string $email - * @property string|null $name_first - * @property string|null $name_last - * @property string $password - * @property string|null $remember_token - * @property string $language - * @property bool $root_admin - * @property bool $use_totp - * @property string|null $totp_secret - * @property \Illuminate\Support\Carbon|null $totp_authenticated_at - * @property bool $gravatar - * @property \Illuminate\Support\Carbon|null $created_at - * @property \Illuminate\Support\Carbon|null $updated_at - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\ApiKey[] $apiKeys - * @property int|null $api_keys_count - * @property string $name - * @property \Illuminate\Notifications\DatabaseNotificationCollection|\Illuminate\Notifications\DatabaseNotification[] $notifications - * @property int|null $notifications_count - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\RecoveryToken[] $recoveryTokens - * @property int|null $recovery_tokens_count - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\Server[] $servers - * @property int|null $servers_count - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\UserSSHKey[] $sshKeys - * @property int|null $ssh_keys_count - * @property \Illuminate\Database\Eloquent\Collection|\App\Models\ApiKey[] $tokens - * @property int|null $tokens_count - * - * @method static \Database\Factories\UserFactory factory(...$parameters) - * @method static Builder|User newModelQuery() - * @method static Builder|User newQuery() - * @method static Builder|User query() - * @method static Builder|User whereCreatedAt($value) - * @method static Builder|User whereEmail($value) - * @method static Builder|User whereExternalId($value) - * @method static Builder|User whereGravatar($value) - * @method static Builder|User whereId($value) - * @method static Builder|User whereLanguage($value) - * @method static Builder|User whereNameFirst($value) - * @method static Builder|User whereNameLast($value) - * @method static Builder|User wherePassword($value) - * @method static Builder|User whereRememberToken($value) - * @method static Builder|User whereRootAdmin($value) - * @method static Builder|User whereTotpAuthenticatedAt($value) - * @method static Builder|User whereTotpSecret($value) - * @method static Builder|User whereUpdatedAt($value) - * @method static Builder|User whereUseTotp($value) - * @method static Builder|User whereUsername($value) - * @method static Builder|User whereUuid($value) - * - * @mixin \Eloquent - */ class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, FilamentUser, HasAvatar, HasName { use Authenticatable; diff --git a/app/Models/UserSSHKey.php b/app/Models/UserSSHKey.php index 1cafb2d8bb..ff544c521f 100644 --- a/app/Models/UserSSHKey.php +++ b/app/Models/UserSSHKey.php @@ -5,38 +5,6 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Relations\BelongsTo; -/** - * \App\Models\UserSSHKey. - * - * @property int $id - * @property int $user_id - * @property string $name - * @property string $fingerprint - * @property string $public_key - * @property \Illuminate\Support\Carbon|null $created_at - * @property \Illuminate\Support\Carbon|null $updated_at - * @property \Illuminate\Support\Carbon|null $deleted_at - * @property \App\Models\User $user - * - * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey newModelQuery() - * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey newQuery() - * @method static \Illuminate\Database\Query\Builder|UserSSHKey onlyTrashed() - * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey query() - * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey whereCreatedAt($value) - * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey whereDeletedAt($value) - * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey whereFingerprint($value) - * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey whereId($value) - * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey whereName($value) - * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey wherePublicKey($value) - * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey whereUpdatedAt($value) - * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey whereUserId($value) - * @method static \Illuminate\Database\Query\Builder|UserSSHKey withTrashed() - * @method static \Illuminate\Database\Query\Builder|UserSSHKey withoutTrashed() - * - * @mixin \Eloquent - * - * @method static \Database\Factories\UserSSHKeyFactory factory(...$parameters) - */ class UserSSHKey extends Model { use SoftDeletes; From 71684dc517843c7f00811c95405f50be78928ed6 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 2 Jun 2024 01:38:42 -0400 Subject: [PATCH 007/103] Pint fix --- app/Filament/Resources/ServerResource/Pages/CreateServer.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index 7f6aee0444..7a2077cd92 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -75,7 +75,6 @@ public function form(Form $form): Form }) ->required(), - Forms\Components\TextInput::make('name') ->prefixIcon('tabler-server') ->label('Display Name') From 2e7c534a3b035828d58d0ae7aabea0e14f1e6c69 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 2 Jun 2024 16:58:21 -0400 Subject: [PATCH 008/103] =?UTF-8?q?Disable=20this=20if=20there=E2=80=99s?= =?UTF-8?q?=20no=20egg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Filament/Resources/ServerResource/Pages/CreateServer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index 7a2077cd92..162647e813 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -286,6 +286,7 @@ public function form(Form $form): Form ->label('Startup Command') ->required() ->live() + ->disabled(fn (Forms\Get $get) => $this->egg === null) ->columnSpan([ 'default' => 2, 'sm' => 4, From bbe09ced1dc9a3cdddf3289d07f9537af96aa6f8 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 2 Jun 2024 16:58:32 -0400 Subject: [PATCH 009/103] Add some new options for ports --- .../ServerResource/Pages/CreateServer.php | 216 +++++++----------- 1 file changed, 78 insertions(+), 138 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index 162647e813..b94b77f1eb 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -129,157 +129,97 @@ public function form(Form $form): Form ->required() ->columnSpanFull(), - Forms\Components\Select::make('allocation_id') - ->preload() - ->live() - ->prefixIcon('tabler-network') - ->label('Primary Allocation') - ->columnSpan(2) - ->disabled(fn (Forms\Get $get) => $get('node_id') === null) - ->searchable(['ip', 'port', 'ip_alias']) - ->afterStateUpdated(function (Forms\Set $set) { - $set('allocation_additional', null); - $set('allocation_additional.needstobeastringhere.extra_allocations', null); - }) - ->getOptionLabelFromRecordUsing( - fn (Allocation $allocation) => "$allocation->ip:$allocation->port" . - ($allocation->ip_alias ? " ($allocation->ip_alias)" : '') - ) - ->placeholder(function (Forms\Get $get) { - $node = Node::find($get('node_id')); - - if ($node?->allocations) { - return 'Select an Allocation'; - } - - return 'Create a New Allocation'; - }) - ->relationship( - 'allocation', - 'ip', - fn (Builder $query, Forms\Get $get) => $query - ->where('node_id', $get('node_id')) - ->whereNull('server_id'), - ) - ->createOptionForm(fn (Forms\Get $get) => [ - Forms\Components\TextInput::make('allocation_ip') - ->datalist(Node::find($get('node_id'))?->ipAddresses() ?? []) - ->label('IP Address') - ->inlineLabel() - ->ipv4() - ->helperText("Usually your machine's public IP unless you are port forwarding.") - // ->selectablePlaceholder(false) - ->required(), - Forms\Components\TextInput::make('allocation_alias') - ->label('Alias') - ->inlineLabel() - ->default(null) - ->datalist([ - $get('name'), - $this->egg?->name, - ]) - ->helperText('Optional display name to help you remember what these are.') - ->required(false), - Forms\Components\TagsInput::make('allocation_ports') - ->placeholder('Examples: 27015, 27017-27019') - ->helperText(new HtmlString(' + Forms\Components\TagsInput::make('ports') + ->columnSpan(3) + ->placeholder('Example: 25565, 8080, 1337-1340') + ->reorderable() + ->splitKeys(['Tab', ' ', ',']) + ->helperText(new HtmlString(' These are the ports that users can connect to this Server through.
- You would have to port forward these on your home network. + You would typically port forward these on your home network. ')) - ->label('Ports') - ->inlineLabel() - ->live() - ->afterStateUpdated(function ($state, Forms\Set $set) { - $ports = collect(); - $update = false; - foreach ($state as $portEntry) { - if (!str_contains($portEntry, '-')) { - if (is_numeric($portEntry)) { - $ports->push((int) $portEntry); - - continue; - } + ->label('Ports') + ->afterStateUpdated(function ($state, Forms\Set $set) { + $ports = collect(); + $update = false; + foreach ($state as $portEntry) { + if (!str_contains($portEntry, '-')) { + if (is_numeric($portEntry)) { + $ports->push((int) $portEntry); + + continue; + } - // Do not add non-numerical ports - $update = true; + // Do not add non-numerical ports + $update = true; - continue; - } + continue; + } - $update = true; - [$start, $end] = explode('-', $portEntry); - if (!is_numeric($start) || !is_numeric($end)) { - continue; - } + $update = true; + [$start, $end] = explode('-', $portEntry); + if (!is_numeric($start) || !is_numeric($end)) { + continue; + } - $start = max((int) $start, 0); - $end = min((int) $end, 2 ** 16 - 1); - for ($i = $start; $i <= $end; $i++) { - $ports->push($i); - } - } + $start = max((int) $start, 0); + $end = min((int) $end, 2 ** 16 - 1); + for ($i = $start; $i <= $end; $i++) { + $ports->push($i); + } + } - $uniquePorts = $ports->unique()->values(); - if ($ports->count() > $uniquePorts->count()) { - $update = true; - $ports = $uniquePorts; - } + $uniquePorts = $ports->unique()->values(); + if ($ports->count() > $uniquePorts->count()) { + $update = true; + $ports = $uniquePorts; + } - $sortedPorts = $ports->sort()->values(); - if ($sortedPorts->all() !== $ports->all()) { - $update = true; - $ports = $sortedPorts; - } + $sortedPorts = $ports->sort()->values(); + if ($sortedPorts->all() !== $ports->all()) { + $update = true; + $ports = $sortedPorts; + } - $ports = $ports->filter(fn ($port) => $port > 1024 && $port < 65535)->values(); + $ports = $ports->filter(fn ($port) => $port > 1024 && $port < 65535)->values(); - if ($update) { - $set('allocation_ports', $ports->all()); - } - }) - ->splitKeys(['Tab', ' ', ',']) - ->required(), - ]) - ->createOptionUsing(function (array $data, Forms\Get $get): int { - return collect( - resolve(AssignmentService::class)->handle(Node::find($get('node_id')), $data) - )->first(); + if ($update) { + $set('allocation_ports', $ports->all()); + } }) - ->required(), + ->live(), - Forms\Components\Repeater::make('allocation_additional') - ->label('Additional Allocations') - ->columnSpan(2) - ->addActionLabel('Add Allocation') - ->disabled(fn (Forms\Get $get) => $get('allocation_id') === null) - // ->addable() TODO disable when all allocations are taken - // ->addable() TODO disable until first additional allocation is selected - ->simple( - Forms\Components\Select::make('extra_allocations') - ->live() - ->preload() - ->disableOptionsWhenSelectedInSiblingRepeaterItems() - ->prefixIcon('tabler-network') - ->label('Additional Allocations') - ->columnSpan(2) - ->disabled(fn (Forms\Get $get) => $get('../../node_id') === null) - ->searchable(['ip', 'port', 'ip_alias']) - ->getOptionLabelFromRecordUsing( - fn (Allocation $allocation) => "$allocation->ip:$allocation->port" . - ($allocation->ip_alias ? " ($allocation->ip_alias)" : '') - ) - ->placeholder('Select additional Allocations') - ->disableOptionsWhenSelectedInSiblingRepeaterItems() - ->relationship( - 'allocations', - 'ip', - fn (Builder $query, Forms\Get $get, Forms\Components\Select $component, $state) => $query - ->where('node_id', $get('../../node_id')) - ->whereNot('id', $get('../../allocation_id')) - ->whereNull('server_id'), - ), - ), + Forms\Components\Select::make('primary_port') + ->live() + ->helperText(fn (Forms\Get $get) => match (true) { + !str_contains($get('startup'), '{{SERVER_PORT}}') => 'This is disabled because there is no primary server port in the startup command.', + empty($get('ports')) => 'This is disabled because you haven\'t entered any ports yet.', + true => 'This port will take the place of {{SERVER_PORT}} in your startup command.', + }) + ->columnSpan(3) + ->selectablePlaceholder(false) + ->disabled(fn (Forms\Get $get) => empty($get('ports')) || !str_contains($get('startup'), '{{SERVER_PORT}}')) + ->options(fn (Forms\Get $get) => $get('ports')) + ->label('Primary Port'), + + Forms\Components\KeyValue::make('pts') + // ->deletable(fn ($state) => empty($state) || dd('SERVER_PORT', array_keys($state), $state) || !in_array('SERVER_PORT', array_keys($state))) + // ->addable(false) + // ->editableKeys(false) + ->columnSpan(3) + ->keyLabel('Name') + ->valueLabel('Port') + ->label('Ports') + ->live(), + + Forms\Components\Placeholder::make('instructions') + ->label(new HtmlString('Port Instructions:

+ These are the ports that users can connect to this Server through. +
+ You would typically port forward these on your home network. + ')) + ->columnSpan(3), Forms\Components\Textarea::make('startup') ->hintIcon('tabler-code') From 768a45bbb81ceff492ece8f58854ca20c30a7a4b Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 2 Jun 2024 21:55:13 -0400 Subject: [PATCH 010/103] More updates --- .../ServerResource/Pages/CreateServer.php | 148 +++++++++--------- 1 file changed, 73 insertions(+), 75 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index b94b77f1eb..69dc7d1c04 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -140,86 +140,35 @@ public function form(Form $form): Form You would typically port forward these on your home network. ')) ->label('Ports') - ->afterStateUpdated(function ($state, Forms\Set $set) { - $ports = collect(); - $update = false; - foreach ($state as $portEntry) { - if (!str_contains($portEntry, '-')) { - if (is_numeric($portEntry)) { - $ports->push((int) $portEntry); - - continue; - } - - // Do not add non-numerical ports - $update = true; - - continue; - } - - $update = true; - [$start, $end] = explode('-', $portEntry); - if (!is_numeric($start) || !is_numeric($end)) { - continue; - } - - $start = max((int) $start, 0); - $end = min((int) $end, 2 ** 16 - 1); - for ($i = $start; $i <= $end; $i++) { - $ports->push($i); - } - } + ->afterStateUpdated(self::ports(...)) + ->live(), - $uniquePorts = $ports->unique()->values(); - if ($ports->count() > $uniquePorts->count()) { - $update = true; - $ports = $uniquePorts; - } + Forms\Components\Repeater::make('assignments') + ->columnSpan(3) + ->label('Port Assignments') + ->live() + ->default(function () { + $ports = ['SERVER_PORT' => null]; - $sortedPorts = $ports->sort()->values(); - if ($sortedPorts->all() !== $ports->all()) { - $update = true; - $ports = $sortedPorts; + if (!$this->egg) { + return $ports; } - $ports = $ports->filter(fn ($port) => $port > 1024 && $port < 65535)->values(); - - if ($update) { - $set('allocation_ports', $ports->all()); - } + return $ports; }) - ->live(), - - Forms\Components\Select::make('primary_port') - ->live() - ->helperText(fn (Forms\Get $get) => match (true) { - !str_contains($get('startup'), '{{SERVER_PORT}}') => 'This is disabled because there is no primary server port in the startup command.', - empty($get('ports')) => 'This is disabled because you haven\'t entered any ports yet.', - true => 'This port will take the place of {{SERVER_PORT}} in your startup command.', - }) - ->columnSpan(3) - ->selectablePlaceholder(false) - ->disabled(fn (Forms\Get $get) => empty($get('ports')) || !str_contains($get('startup'), '{{SERVER_PORT}}')) - ->options(fn (Forms\Get $get) => $get('ports')) - ->label('Primary Port'), - - Forms\Components\KeyValue::make('pts') - // ->deletable(fn ($state) => empty($state) || dd('SERVER_PORT', array_keys($state), $state) || !in_array('SERVER_PORT', array_keys($state))) - // ->addable(false) - // ->editableKeys(false) - ->columnSpan(3) - ->keyLabel('Name') - ->valueLabel('Port') - ->label('Ports') - ->live(), - - Forms\Components\Placeholder::make('instructions') - ->label(new HtmlString('Port Instructions:

- These are the ports that users can connect to this Server through. -
- You would typically port forward these on your home network. - ')) - ->columnSpan(3), + ->addable(false) + ->deletable(false) + ->simple( + Forms\Components\Select::make('port') + ->live() + // ->selectablePlaceholder(false) + // ->disabled(fn (Forms\Get $get) => empty($get('ports'))) + ->prefix('SERVER_PORT') + // ->email() + ->disableOptionsWhenSelectedInSiblingRepeaterItems() + ->options(fn (Forms\Get $get) => $get('../../ports')) + ->required(), + ), Forms\Components\Textarea::make('startup') ->hintIcon('tabler-code') @@ -642,4 +591,53 @@ private function getSelectOptionsFromRules(Forms\Get $get): array ->mapWithKeys(fn ($value) => [$value => $value]) ->all(); } + + public static function ports ($state, Forms\Set $set) { + $ports = collect(); + $update = false; + foreach ($state as $portEntry) { + if (!str_contains($portEntry, '-')) { + if (is_numeric($portEntry)) { + $ports->push((int) $portEntry); + + continue; + } + + // Do not add non-numerical ports + $update = true; + + continue; + } + + $update = true; + [$start, $end] = explode('-', $portEntry); + if (!is_numeric($start) || !is_numeric($end)) { + continue; + } + + $start = max((int) $start, 0); + $end = min((int) $end, 2 ** 16 - 1); + for ($i = $start; $i <= $end; $i++) { + $ports->push($i); + } + } + + $uniquePorts = $ports->unique()->values(); + if ($ports->count() > $uniquePorts->count()) { + $update = true; + $ports = $uniquePorts; + } + + $sortedPorts = $ports->sort()->values(); + if ($sortedPorts->all() !== $ports->all()) { + $update = true; + $ports = $sortedPorts; + } + + $ports = $ports->filter(fn ($port) => $port > 1024 && $port < 65535)->values(); + + if ($update) { + $set('ports', $ports->all()); + } + } } From dbad5ae9c7e141b6af77c8495b277c49f872761b Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Tue, 4 Jun 2024 11:40:19 -0400 Subject: [PATCH 011/103] WIP --- .../ServerResource/Pages/CreateServer.php | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index 69dc7d1c04..2307ef315e 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -3,15 +3,12 @@ namespace App\Filament\Resources\ServerResource\Pages; use App\Filament\Resources\ServerResource; -use App\Models\Allocation; use App\Models\Egg; use App\Models\Node; -use App\Services\Allocations\AssignmentService; use App\Services\Servers\RandomWordService; use App\Services\Servers\ServerCreationService; use Filament\Forms\Form; use Filament\Resources\Pages\CreateRecord; -use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Validator; use Closure; @@ -23,6 +20,8 @@ class CreateServer extends CreateRecord protected static string $resource = ServerResource::class; protected static bool $canCreateAnother = false; public ?Egg $egg = null; + public array $ports = []; + public array $eggDefaultPorts = []; public function form(Form $form): Form { @@ -54,10 +53,26 @@ public function form(Form $form): Form $variables = $this->egg->variables ?? []; $serverVariables = collect(); + $i = 0; + $this->ports = []; foreach ($variables as $variable) { $serverVariables->add($variable->toArray()); + if (str_contains($variable->rules, 'port')) { + $path = 'assignments'; + $this->eggDefaultPorts[$variable->default_value] = $variable->env_variable; + $this->ports[] = (int) $variable->default_value; + + $set("$path.$i", ['port' => $i]); + + // $set("$path.$i", (int) $variable->default_value); + // $set("$path.$i.port", (int) $variable->default_value); + $i++; + // $variables[$serverVariables[$i]['env_variable']] = $serverVariables[$i]['default_value']; + } } + $set('ports', array_keys($this->eggDefaultPorts)); + $variables = []; $set($path = 'server_variables', $serverVariables->sortBy(['sort'])->all()); for ($i = 0; $i < $serverVariables->count(); $i++) { @@ -145,28 +160,25 @@ public function form(Form $form): Form Forms\Components\Repeater::make('assignments') ->columnSpan(3) + ->defaultItems(fn () => count($this->eggDefaultPorts)) ->label('Port Assignments') + ->helperText(fn (Forms\Get $get) => empty($get('ports')) ? 'You must add ports to assign them!' : '') ->live() - ->default(function () { - $ports = ['SERVER_PORT' => null]; - - if (!$this->egg) { - return $ports; - } - - return $ports; - }) ->addable(false) ->deletable(false) + ->reorderable(false) ->simple( Forms\Components\Select::make('port') ->live() - // ->selectablePlaceholder(false) - // ->disabled(fn (Forms\Get $get) => empty($get('ports'))) - ->prefix('SERVER_PORT') - // ->email() + ->disabled(fn (Forms\Get $get) => empty($get('../../ports')) || empty($get('../../assignments'))) + ->prefix(function (Forms\Components\Component $component) { + $key = str($component->getStatePath())->beforeLast('.')->afterLast('.')->toString(); + $defaultPort = array_keys($this->eggDefaultPorts)[$key] ?? null; + + return $this->eggDefaultPorts[$defaultPort] ?? ''; + }) ->disableOptionsWhenSelectedInSiblingRepeaterItems() - ->options(fn (Forms\Get $get) => $get('../../ports')) + ->options(fn (Forms\Get $get) => $this->ports) ->required(), ), @@ -592,7 +604,7 @@ private function getSelectOptionsFromRules(Forms\Get $get): array ->all(); } - public static function ports ($state, Forms\Set $set) { + public function ports ($state, Forms\Set $set) { $ports = collect(); $update = false; foreach ($state as $portEntry) { @@ -603,13 +615,9 @@ public static function ports ($state, Forms\Set $set) { continue; } - // Do not add non-numerical ports - $update = true; - continue; } - $update = true; [$start, $end] = explode('-', $portEntry); if (!is_numeric($start) || !is_numeric($end)) { continue; @@ -624,20 +632,12 @@ public static function ports ($state, Forms\Set $set) { $uniquePorts = $ports->unique()->values(); if ($ports->count() > $uniquePorts->count()) { - $update = true; $ports = $uniquePorts; } - $sortedPorts = $ports->sort()->values(); - if ($sortedPorts->all() !== $ports->all()) { - $update = true; - $ports = $sortedPorts; - } - $ports = $ports->filter(fn ($port) => $port > 1024 && $port < 65535)->values(); - if ($update) { - $set('ports', $ports->all()); - } + $set('ports', $ports->all()); + $this->ports = $ports->all(); } } From 551175862e6d906bcc1b1fbd1807ba13005861c5 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Tue, 4 Jun 2024 15:38:45 -0400 Subject: [PATCH 012/103] Better kebab names --- app/Models/Egg.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/Models/Egg.php b/app/Models/Egg.php index 7c8cb91375..0bf0a750e7 100644 --- a/app/Models/Egg.php +++ b/app/Models/Egg.php @@ -281,6 +281,12 @@ public function configFrom(): BelongsTo public function getKebabName(): string { - return str($this->name)->kebab()->lower()->trim()->split('/[^\w\-]/')->join(''); + return str($this->name) + ->kebab() + ->replace('--', '-') + ->lower() + ->trim() + ->split('/[^\w\-]/') + ->join(''); } } From be6f79521e2f9123b089cec5ac0dfff6e3b3064d Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Tue, 4 Jun 2024 16:34:54 -0400 Subject: [PATCH 013/103] Wip --- .../Resources/ServerResource/Pages/CreateServer.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index 2307ef315e..401e79bae0 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -50,6 +50,8 @@ public function form(Form $form): Form $this->egg = Egg::query()->find($state); $set('startup', $this->egg->startup); $set('image', ''); + // $set('assignments', null); + $this->eggDefaultPorts = []; $variables = $this->egg->variables ?? []; $serverVariables = collect(); @@ -58,16 +60,10 @@ public function form(Form $form): Form foreach ($variables as $variable) { $serverVariables->add($variable->toArray()); if (str_contains($variable->rules, 'port')) { - $path = 'assignments'; $this->eggDefaultPorts[$variable->default_value] = $variable->env_variable; $this->ports[] = (int) $variable->default_value; - $set("$path.$i", ['port' => $i]); - - // $set("$path.$i", (int) $variable->default_value); - // $set("$path.$i.port", (int) $variable->default_value); - $i++; - // $variables[$serverVariables[$i]['env_variable']] = $serverVariables[$i]['default_value']; + $set("assignments.$i", ['port' => $i++]); } } From 81f218ddc955c98cdd88b4a24957af86da3913ef Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Thu, 6 Jun 2024 15:49:23 -0400 Subject: [PATCH 014/103] Skip port variables down below --- app/Filament/Resources/ServerResource/Pages/CreateServer.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index 401e79bae0..5279f5e703 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -58,13 +58,16 @@ public function form(Form $form): Form $i = 0; $this->ports = []; foreach ($variables as $variable) { - $serverVariables->add($variable->toArray()); if (str_contains($variable->rules, 'port')) { $this->eggDefaultPorts[$variable->default_value] = $variable->env_variable; $this->ports[] = (int) $variable->default_value; $set("assignments.$i", ['port' => $i++]); + + continue; } + + $serverVariables->add($variable->toArray()); } $set('ports', array_keys($this->eggDefaultPorts)); From b16a11c365749bff5719475091420322992ed683 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Thu, 6 Jun 2024 15:49:33 -0400 Subject: [PATCH 015/103] No longer reserved --- app/Models/EggVariable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/EggVariable.php b/app/Models/EggVariable.php index ca5adf035c..40c901a38e 100644 --- a/app/Models/EggVariable.php +++ b/app/Models/EggVariable.php @@ -16,7 +16,7 @@ class EggVariable extends Model /** * Reserved environment variable names. */ - public const RESERVED_ENV_NAMES = 'SERVER_MEMORY,SERVER_IP,SERVER_PORT,ENV,HOME,USER,STARTUP,SERVER_UUID,UUID'; + public const RESERVED_ENV_NAMES = 'SERVER_MEMORY,SERVER_IP,ENV,HOME,USER,STARTUP,SERVER_UUID,UUID'; /** * The table associated with the model. From 32e96dc0a695754989eb6e317daea079dd9456a2 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Thu, 6 Jun 2024 15:49:36 -0400 Subject: [PATCH 016/103] Wip --- .../2024_06_06_043350_modify_allocations.php | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 database/migrations/2024_06_06_043350_modify_allocations.php diff --git a/database/migrations/2024_06_06_043350_modify_allocations.php b/database/migrations/2024_06_06_043350_modify_allocations.php new file mode 100644 index 0000000000..4577b13051 --- /dev/null +++ b/database/migrations/2024_06_06_043350_modify_allocations.php @@ -0,0 +1,43 @@ +json('ports'); + }); + + Schema::dropIfExists('allocations'); + + Schema::table('servers', function (Blueprint $table) { + $table->dropColumn(['allocation_id', 'allocation_limit']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::create('allocations', function (Blueprint $table) { + $table->id(); + $table->unsignedInteger('node_id'); + $table->string('ip'); + $table->text('ip_alias'); + $table->unsignedMediumInteger('port'); + $table->unsignedInteger('server_id'); + $table->string('notes')->default(''); + $table->timestamps(); + + $table->unique(['node_id', 'ip', 'port']); + }); + } +}; From b1d7d210fc53098d1ebea047cbaaa01ace62c80e Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Fri, 7 Jun 2024 00:59:48 -0400 Subject: [PATCH 017/103] Allow startup command to change with server variable --- .../ServerResource/Pages/CreateServer.php | 79 +++++++++++-------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index 5279f5e703..24bb7afaee 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -50,37 +50,8 @@ public function form(Form $form): Form $this->egg = Egg::query()->find($state); $set('startup', $this->egg->startup); $set('image', ''); - // $set('assignments', null); - $this->eggDefaultPorts = []; - $variables = $this->egg->variables ?? []; - $serverVariables = collect(); - $i = 0; - $this->ports = []; - foreach ($variables as $variable) { - if (str_contains($variable->rules, 'port')) { - $this->eggDefaultPorts[$variable->default_value] = $variable->env_variable; - $this->ports[] = (int) $variable->default_value; - - $set("assignments.$i", ['port' => $i++]); - - continue; - } - - $serverVariables->add($variable->toArray()); - } - - $set('ports', array_keys($this->eggDefaultPorts)); - - $variables = []; - $set($path = 'server_variables', $serverVariables->sortBy(['sort'])->all()); - for ($i = 0; $i < $serverVariables->count(); $i++) { - $set("$path.$i.variable_value", $serverVariables[$i]['default_value']); - $set("$path.$i.variable_id", $serverVariables[$i]['id']); - $variables[$serverVariables[$i]['env_variable']] = $serverVariables[$i]['default_value']; - } - - $set('environment', $variables); + $this->resetEggVariables($set, $get); $previousEgg = Egg::query()->find($old); if (!$get('name') || $previousEgg?->getKebabName() === $get('name')) { @@ -146,7 +117,6 @@ public function form(Form $form): Form Forms\Components\TagsInput::make('ports') ->columnSpan(3) ->placeholder('Example: 25565, 8080, 1337-1340') - ->reorderable() ->splitKeys(['Tab', ' ', ',']) ->helperText(new HtmlString(' These are the ports that users can connect to this Server through. @@ -172,9 +142,8 @@ public function form(Form $form): Form ->disabled(fn (Forms\Get $get) => empty($get('../../ports')) || empty($get('../../assignments'))) ->prefix(function (Forms\Components\Component $component) { $key = str($component->getStatePath())->beforeLast('.')->afterLast('.')->toString(); - $defaultPort = array_keys($this->eggDefaultPorts)[$key] ?? null; - return $this->eggDefaultPorts[$defaultPort] ?? ''; + return $key; }) ->disableOptionsWhenSelectedInSiblingRepeaterItems() ->options(fn (Forms\Get $get) => $this->ports) @@ -187,6 +156,7 @@ public function form(Form $form): Form ->required() ->live() ->disabled(fn (Forms\Get $get) => $this->egg === null) + ->afterStateUpdated($this->resetEggVariables(...)) ->columnSpan([ 'default' => 2, 'sm' => 4, @@ -603,7 +573,7 @@ private function getSelectOptionsFromRules(Forms\Get $get): array ->all(); } - public function ports ($state, Forms\Set $set) { + public function ports($state, Forms\Set $set) { $ports = collect(); $update = false; foreach ($state as $portEntry) { @@ -639,4 +609,45 @@ public function ports ($state, Forms\Set $set) { $set('ports', $ports->all()); $this->ports = $ports->all(); } + + public function resetEggVariables(Forms\Set $set, Forms\Get $get) + { + $set('assignments', []); + + $i = 0; + $this->eggDefaultPorts = []; + if (str_contains($get('startup'), '{{SERVER_PORT}}')) { + $this->eggDefaultPorts['SERVER_PORT'] = null; + $set('assignments.SERVER_PORT', ['port' => null]); + } + + $variables = $this->egg->variables ?? []; + $serverVariables = collect(); + $this->ports = []; + foreach ($variables as $variable) { + if (str_contains($variable->rules, 'port')) { + $this->eggDefaultPorts[$variable->env_variable] = $variable->default_value; + $this->ports[] = (int) $variable->default_value; + + // $set("assignments.$i", ['port' => $i++]); + $set("assignments.$variable->env_variable", ['port' => $i++]); + + continue; + } + + $serverVariables->add($variable->toArray()); + } + + $set('ports', $this->ports); + + $variables = []; + $set($path = 'server_variables', $serverVariables->sortBy(['sort'])->all()); + for ($i = 0; $i < $serverVariables->count(); $i++) { + $set("$path.$i.variable_value", $serverVariables[$i]['default_value']); + $set("$path.$i.variable_id", $serverVariables[$i]['id']); + $variables[$serverVariables[$i]['env_variable']] = $serverVariables[$i]['default_value']; + } + + $set('environment', $variables); + } } From beadce96f63102e0b1ee1ab9c7d4a2fb8a773230 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 9 Jun 2024 08:20:31 -0400 Subject: [PATCH 018/103] Wip --- .../migrations/2024_06_06_043350_modify_allocations.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/database/migrations/2024_06_06_043350_modify_allocations.php b/database/migrations/2024_06_06_043350_modify_allocations.php index 4577b13051..308e1adea4 100644 --- a/database/migrations/2024_06_06_043350_modify_allocations.php +++ b/database/migrations/2024_06_06_043350_modify_allocations.php @@ -20,6 +20,10 @@ public function up(): void Schema::table('servers', function (Blueprint $table) { $table->dropColumn(['allocation_id', 'allocation_limit']); }); + + Schema::table('nodes', function (Blueprint $table) { + $table->boolean('strict_ports')->default(true); + }); } /** @@ -27,6 +31,10 @@ public function up(): void */ public function down(): void { + Schema::table('nodes', function (Blueprint $table) { + $table->dropColumn('strict_ports'); + }); + Schema::create('allocations', function (Blueprint $table) { $table->id(); $table->unsignedInteger('node_id'); From 9ad113bc616fd2a58f5fe1e2a4865faf07956716 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 9 Jun 2024 14:18:19 -0400 Subject: [PATCH 019/103] Move these --- .../ServerResource/Pages/CreateServer.php | 71 +++++++++---------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index 24bb7afaee..d76b3dcd87 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -33,6 +33,41 @@ public function form(Form $form): Form 'lg' => 6, ]) ->schema([ + Forms\Components\TextInput::make('name') + ->prefixIcon('tabler-server') + ->label('Display Name') + ->placeholder('Display name for your new Server') + ->suffixAction(Forms\Components\Actions\Action::make('random') + ->icon('tabler-dice-' . random_int(1, 6)) + ->action(function (Forms\Set $set) { + $prefix = $this->egg ? str($this->egg->name)->lower()->kebab() . '-' : ''; + + $set('name', $prefix . (new RandomWordService())->word()); + })) + ->columnSpan([ + 'default' => 2, + 'sm' => 4, + 'md' => 2, + 'lg' => 3, + ]) + ->required() + ->maxLength(191), + + Forms\Components\Select::make('owner_id') + ->prefixIcon('tabler-user') + ->default(auth()->user()->id) + ->label('Owner') + ->columnSpan([ + 'default' => 2, + 'sm' => 4, + 'md' => 2, + 'lg' => 3, + ]) + ->relationship('user', 'username') + ->searchable() + ->preload() + ->required(), + Forms\Components\Select::make('egg_id') ->disabledOn('edit') ->prefixIcon('tabler-egg') @@ -60,27 +95,6 @@ public function form(Form $form): Form }) ->required(), - Forms\Components\TextInput::make('name') - ->prefixIcon('tabler-server') - ->label('Display Name') - ->suffixAction(Forms\Components\Actions\Action::make('random') - ->icon('tabler-dice-' . random_int(1, 6)) - ->action(function (Forms\Set $set, Forms\Get $get) { - $prefix = $this->egg ? str($this->egg->name)->lower()->kebab() . '-' : ''; - - $word = (new RandomWordService())->word(); - - $set('name', $prefix . $word); - })) - ->columnSpan([ - 'default' => 2, - 'sm' => 4, - 'md' => 2, - 'lg' => 3, - ]) - ->required() - ->maxLength(191), - Forms\Components\Select::make('node_id') ->disabledOn('edit') ->prefixIcon('tabler-server-2') @@ -93,21 +107,6 @@ public function form(Form $form): Form ->afterStateUpdated(fn (Forms\Set $set) => $set('allocation_id', null)) ->required(), - Forms\Components\Select::make('owner_id') - ->prefixIcon('tabler-user') - ->default(auth()->user()->id) - ->label('Owner') - ->columnSpan([ - 'default' => 2, - 'sm' => 4, - 'md' => 2, - 'lg' => 3, - ]) - ->relationship('user', 'username') - ->searchable() - ->preload() - ->required(), - Forms\Components\Textarea::make('description') ->hidden() ->default('') From 17bc3de0d0d4c6531c7521af1052c6e02f46f52a Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Mon, 10 Jun 2024 20:34:46 -0400 Subject: [PATCH 020/103] Rename translation keys --- .../Allocation/CidrOutOfRangeException.php | 2 +- .../InvalidPortMappingException.php | 2 +- .../Allocation/PortOutOfRangeException.php | 2 +- .../TooManyPortsInRangeException.php | 2 +- .../ServerResource/Pages/CreateServer.php | 1301 +++++++++-------- lang/af/exceptions.php | 2 +- lang/ar/exceptions.php | 2 +- lang/be/exceptions.php | 2 +- lang/ca/exceptions.php | 2 +- lang/cs/exceptions.php | 2 +- lang/da/exceptions.php | 2 +- lang/de/exceptions.php | 2 +- lang/el/exceptions.php | 2 +- lang/en/exceptions.php | 2 +- lang/es/exceptions.php | 2 +- lang/fi/exceptions.php | 2 +- lang/fr/exceptions.php | 2 +- lang/he/exceptions.php | 2 +- lang/hi/exceptions.php | 2 +- lang/hr/exceptions.php | 2 +- lang/hu/exceptions.php | 2 +- lang/id/exceptions.php | 2 +- lang/it/exceptions.php | 2 +- lang/ja/exceptions.php | 2 +- lang/ko/exceptions.php | 2 +- lang/nl/exceptions.php | 2 +- lang/no/exceptions.php | 2 +- lang/pl/exceptions.php | 2 +- lang/pt/exceptions.php | 2 +- lang/ro/exceptions.php | 2 +- lang/ru/exceptions.php | 2 +- lang/sk/exceptions.php | 2 +- lang/sl/exceptions.php | 2 +- lang/sr/exceptions.php | 2 +- lang/sv/exceptions.php | 2 +- lang/th/exceptions.php | 2 +- lang/tr/exceptions.php | 2 +- lang/uk/exceptions.php | 2 +- lang/vi/exceptions.php | 2 +- lang/zh/exceptions.php | 2 +- 40 files changed, 761 insertions(+), 618 deletions(-) diff --git a/app/Exceptions/Service/Allocation/CidrOutOfRangeException.php b/app/Exceptions/Service/Allocation/CidrOutOfRangeException.php index cec0d528e2..ad0ec614af 100644 --- a/app/Exceptions/Service/Allocation/CidrOutOfRangeException.php +++ b/app/Exceptions/Service/Allocation/CidrOutOfRangeException.php @@ -11,6 +11,6 @@ class CidrOutOfRangeException extends DisplayException */ public function __construct() { - parent::__construct(trans('exceptions.allocations.cidr_out_of_range')); + parent::__construct(trans('exceptions.ports.cidr_out_of_range')); } } diff --git a/app/Exceptions/Service/Allocation/InvalidPortMappingException.php b/app/Exceptions/Service/Allocation/InvalidPortMappingException.php index d726c3181e..94683da7ee 100644 --- a/app/Exceptions/Service/Allocation/InvalidPortMappingException.php +++ b/app/Exceptions/Service/Allocation/InvalidPortMappingException.php @@ -11,6 +11,6 @@ class InvalidPortMappingException extends DisplayException */ public function __construct(mixed $port) { - parent::__construct(trans('exceptions.allocations.invalid_mapping', ['port' => $port])); + parent::__construct(trans('exceptions.ports.invalid_mapping', ['port' => $port])); } } diff --git a/app/Exceptions/Service/Allocation/PortOutOfRangeException.php b/app/Exceptions/Service/Allocation/PortOutOfRangeException.php index b328e0d242..e49d6dea35 100644 --- a/app/Exceptions/Service/Allocation/PortOutOfRangeException.php +++ b/app/Exceptions/Service/Allocation/PortOutOfRangeException.php @@ -11,6 +11,6 @@ class PortOutOfRangeException extends DisplayException */ public function __construct() { - parent::__construct(trans('exceptions.allocations.port_out_of_range')); + parent::__construct(trans('exceptions.ports.port_out_of_range')); } } diff --git a/app/Exceptions/Service/Allocation/TooManyPortsInRangeException.php b/app/Exceptions/Service/Allocation/TooManyPortsInRangeException.php index eb45844126..6bd2c571f6 100644 --- a/app/Exceptions/Service/Allocation/TooManyPortsInRangeException.php +++ b/app/Exceptions/Service/Allocation/TooManyPortsInRangeException.php @@ -11,6 +11,6 @@ class TooManyPortsInRangeException extends DisplayException */ public function __construct() { - parent::__construct(trans('exceptions.allocations.too_many_ports')); + parent::__construct(trans('exceptions.ports.too_many_ports')); } } diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index d76b3dcd87..2d92ddda71 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -3,534 +3,755 @@ namespace App\Filament\Resources\ServerResource\Pages; use App\Filament\Resources\ServerResource; +use App\Models\Allocation; use App\Models\Egg; use App\Models\Node; +use App\Services\Allocations\AssignmentService; use App\Services\Servers\RandomWordService; use App\Services\Servers\ServerCreationService; +use Filament\Forms\Components\Actions\Action; use Filament\Forms\Form; use Filament\Resources\Pages\CreateRecord; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; -use Illuminate\Support\Facades\Validator; -use Closure; use Filament\Forms; +use Filament\Forms\Components\Wizard; +use Illuminate\Support\Facades\Blade; +use Illuminate\Support\Facades\Validator; use Illuminate\Support\HtmlString; +use Closure; class CreateServer extends CreateRecord { protected static string $resource = ServerResource::class; protected static bool $canCreateAnother = false; - public ?Egg $egg = null; - public array $ports = []; - public array $eggDefaultPorts = []; + + public ?Node $node = null; public function form(Form $form): Form { return $form - ->columns([ - 'default' => 2, - 'sm' => 2, - 'md' => 4, - 'lg' => 6, - ]) ->schema([ - Forms\Components\TextInput::make('name') - ->prefixIcon('tabler-server') - ->label('Display Name') - ->placeholder('Display name for your new Server') - ->suffixAction(Forms\Components\Actions\Action::make('random') - ->icon('tabler-dice-' . random_int(1, 6)) - ->action(function (Forms\Set $set) { - $prefix = $this->egg ? str($this->egg->name)->lower()->kebab() . '-' : ''; - - $set('name', $prefix . (new RandomWordService())->word()); - })) - ->columnSpan([ - 'default' => 2, - 'sm' => 4, - 'md' => 2, - 'lg' => 3, - ]) - ->required() - ->maxLength(191), - - Forms\Components\Select::make('owner_id') - ->prefixIcon('tabler-user') - ->default(auth()->user()->id) - ->label('Owner') - ->columnSpan([ - 'default' => 2, - 'sm' => 4, - 'md' => 2, - 'lg' => 3, - ]) - ->relationship('user', 'username') - ->searchable() - ->preload() - ->required(), - - Forms\Components\Select::make('egg_id') - ->disabledOn('edit') - ->prefixIcon('tabler-egg') - ->columnSpan([ - 'default' => 2, - 'sm' => 2, - 'md' => 2, - 'lg' => 3, - ]) - ->relationship('egg', 'name') - ->searchable() - ->preload() - ->live() - ->afterStateUpdated(function ($state, Forms\Set $set, Forms\Get $get, $old) { - $this->egg = Egg::query()->find($state); - $set('startup', $this->egg->startup); - $set('image', ''); - - $this->resetEggVariables($set, $get); - - $previousEgg = Egg::query()->find($old); - if (!$get('name') || $previousEgg?->getKebabName() === $get('name')) { - $set('name', $this->egg->getKebabName()); - } - }) - ->required(), - - Forms\Components\Select::make('node_id') - ->disabledOn('edit') - ->prefixIcon('tabler-server-2') - ->default(fn () => Node::query()->latest()->first()?->id) - ->columnSpan(3) - ->live() - ->relationship('node', 'name') - ->searchable() - ->preload() - ->afterStateUpdated(fn (Forms\Set $set) => $set('allocation_id', null)) - ->required(), - - Forms\Components\Textarea::make('description') - ->hidden() - ->default('') - ->required() - ->columnSpanFull(), - - Forms\Components\TagsInput::make('ports') - ->columnSpan(3) - ->placeholder('Example: 25565, 8080, 1337-1340') - ->splitKeys(['Tab', ' ', ',']) - ->helperText(new HtmlString(' + Wizard::make([ + Wizard\Step::make('Information') + ->label('Information') + ->icon('tabler-info-circle') + ->completedIcon('tabler-check') + ->columns([ + 'default' => 2, + 'sm' => 2, + 'md' => 4, + 'lg' => 6, + ]) + ->schema([ + Forms\Components\TextInput::make('name') + ->prefixIcon('tabler-server') + ->label('Name') + ->suffixAction(Forms\Components\Actions\Action::make('random') + ->icon('tabler-dice-' . random_int(1, 6)) + ->action(function (Forms\Set $set, Forms\Get $get) { + $egg = Egg::find($get('egg_id')); + $prefix = $egg ? str($egg->name)->lower()->kebab() . '-' : ''; + + $word = (new RandomWordService())->word(); + + $set('name', $prefix . $word); + })) + ->columnSpan([ + 'default' => 2, + 'sm' => 4, + 'md' => 2, + 'lg' => 3, + ]) + ->required() + ->maxLength(191), + + Forms\Components\Select::make('owner_id') + ->prefixIcon('tabler-user') + ->default(auth()->user()->id) + ->label('Owner') + ->columnSpan([ + 'default' => 2, + 'sm' => 4, + 'md' => 2, + 'lg' => 3, + ]) + ->relationship('user', 'username') + ->searchable() + ->preload() + ->required(), + + Forms\Components\Select::make('node_id') + ->disabledOn('edit') + ->prefixIcon('tabler-server-2') + ->default(fn () => ($this->node = Node::query()->latest()->first())?->id) + ->columnSpan([ + 'default' => 1, + 'sm' => 2, + 'md' => 2, + 'lg' => 2, + ]) + ->live() + ->relationship('node', 'name') + ->searchable() + ->preload() + ->afterStateUpdated(function (Forms\Set $set, $state) { + $set('allocation_id', null); + $this->node = Node::find($state); + }) + ->required(), + + Forms\Components\Select::make('allocation_id') + ->preload() + ->live() + ->prefixIcon('tabler-network') + ->label('Primary Allocation') + ->columnSpan([ + 'default' => 1, + 'sm' => 2, + 'md' => 1, + 'lg' => 2, + ]) + ->disabled(fn (Forms\Get $get) => $get('node_id') === null) + ->searchable(['ip', 'port', 'ip_alias']) + ->afterStateUpdated(function (Forms\Set $set) { + $set('allocation_additional', null); + $set('allocation_additional.needstobeastringhere.extra_allocations', null); + }) + ->getOptionLabelFromRecordUsing( + fn (Allocation $allocation) => "$allocation->ip:$allocation->port" . + ($allocation->ip_alias ? " ($allocation->ip_alias)" : '') + ) + ->placeholder(function (Forms\Get $get) { + $node = Node::find($get('node_id')); + + if ($node?->allocations) { + return 'Select an Allocation'; + } + + return 'Create a New Allocation'; + }) + ->relationship( + 'allocation', + 'ip', + fn (Builder $query, Forms\Get $get) => $query + ->where('node_id', $get('node_id')) + ->whereNull('server_id'), + ) + ->createOptionForm(fn (Forms\Get $get) => [ + Forms\Components\TextInput::make('allocation_ip') + ->datalist(Node::find($get('node_id'))?->ipAddresses() ?? []) + ->label('IP Address') + ->inlineLabel() + ->ipv4() + ->helperText("Usually your machine's public IP unless you are port forwarding.") + // ->selectablePlaceholder(false) + ->required(), + Forms\Components\TextInput::make('allocation_alias') + ->label('Alias') + ->inlineLabel() + ->default(null) + ->datalist([ + $get('name'), + Egg::find($get('egg_id'))?->name, + ]) + ->helperText('Optional display name to help you remember what these are.') + ->required(false), + Forms\Components\TagsInput::make('allocation_ports') + ->placeholder('Examples: 27015, 27017-27019') + ->helperText(new HtmlString(' These are the ports that users can connect to this Server through.
- You would typically port forward these on your home network. + You would have to port forward these on your home network. ')) - ->label('Ports') - ->afterStateUpdated(self::ports(...)) - ->live(), - - Forms\Components\Repeater::make('assignments') - ->columnSpan(3) - ->defaultItems(fn () => count($this->eggDefaultPorts)) - ->label('Port Assignments') - ->helperText(fn (Forms\Get $get) => empty($get('ports')) ? 'You must add ports to assign them!' : '') - ->live() - ->addable(false) - ->deletable(false) - ->reorderable(false) - ->simple( - Forms\Components\Select::make('port') - ->live() - ->disabled(fn (Forms\Get $get) => empty($get('../../ports')) || empty($get('../../assignments'))) - ->prefix(function (Forms\Components\Component $component) { - $key = str($component->getStatePath())->beforeLast('.')->afterLast('.')->toString(); - - return $key; - }) - ->disableOptionsWhenSelectedInSiblingRepeaterItems() - ->options(fn (Forms\Get $get) => $this->ports) - ->required(), - ), - - Forms\Components\Textarea::make('startup') - ->hintIcon('tabler-code') - ->label('Startup Command') - ->required() - ->live() - ->disabled(fn (Forms\Get $get) => $this->egg === null) - ->afterStateUpdated($this->resetEggVariables(...)) - ->columnSpan([ - 'default' => 2, - 'sm' => 4, - 'md' => 4, - 'lg' => 6, - ]) - ->rows(function ($state) { - return str($state)->explode("\n")->reduce( - fn (int $carry, $line) => $carry + floor(strlen($line) / 125), - 0 - ); - }), - - Forms\Components\Hidden::make('environment')->default([]), - - Forms\Components\Hidden::make('start_on_completion')->default(true), - - Forms\Components\Section::make('Egg Variables') - ->icon('tabler-eggs') - ->iconColor('primary') - ->collapsible() - ->collapsed() - ->columnSpan(([ - 'default' => 2, - 'sm' => 4, - 'md' => 4, - 'lg' => 6, - ])) - ->schema([ - Forms\Components\Placeholder::make('Select an egg first to show its variables!') - ->hidden(fn (Forms\Get $get) => $this->egg), - - Forms\Components\Placeholder::make('The selected egg has no variables!') - ->hidden(fn (Forms\Get $get) => $this->egg?->variables()?->count() !== 0), - - Forms\Components\Repeater::make('server_variables') - ->relationship('serverVariables') - ->saveRelationshipsBeforeChildrenUsing(null) - ->saveRelationshipsUsing(null) - ->grid(2) - ->reorderable(false) - ->addable(false) - ->deletable(false) - ->default([]) - ->hidden(fn ($state) => empty($state)) - ->schema(function () { - - $text = Forms\Components\TextInput::make('variable_value') - ->hidden($this->shouldHideComponent(...)) - ->maxLength(191) - ->rules([ - fn (Forms\Get $get): Closure => function (string $attribute, $value, Closure $fail) use ($get) { - $validator = Validator::make(['validatorkey' => $value], [ - 'validatorkey' => $get('rules'), - ]); - - if ($validator->fails()) { - $message = str($validator->errors()->first())->replace('validatorkey', $get('name')); - - $fail($message); + ->label('Ports') + ->inlineLabel() + ->live() + ->afterStateUpdated(function ($state, Forms\Set $set) { + $ports = collect(); + $update = false; + foreach ($state as $portEntry) { + if (!str_contains($portEntry, '-')) { + if (is_numeric($portEntry)) { + $ports->push((int) $portEntry); + + continue; + } + + // Do not add non-numerical ports + $update = true; + + continue; + } + + $update = true; + [$start, $end] = explode('-', $portEntry); + if (!is_numeric($start) || !is_numeric($end)) { + continue; + } + + $start = max((int) $start, 0); + $end = min((int) $end, 2 ** 16 - 1); + for ($i = $start; $i <= $end; $i++) { + $ports->push($i); + } } - }, - ]); - - $select = Forms\Components\Select::make('variable_value') - ->hidden($this->shouldHideComponent(...)) - ->options($this->getSelectOptionsFromRules(...)) - ->selectablePlaceholder(false); - - $components = [$text, $select]; - - /** @var Forms\Components\Component $component */ - foreach ($components as &$component) { - $component = $component - ->live(onBlur: true) - ->hintIcon('tabler-code') - ->label(fn (Forms\Get $get) => $get('name')) - ->hintIconTooltip(fn (Forms\Get $get) => $get('rules')) - ->prefix(fn (Forms\Get $get) => '{{' . $get('env_variable') . '}}') - ->helperText(fn (Forms\Get $get) => empty($get('description')) ? '—' : $get('description')) - ->afterStateUpdated(function (Forms\Set $set, Forms\Get $get, $state) { - $environment = $get($envPath = '../../environment'); - $environment[$get('env_variable')] = $state; - $set($envPath, $environment); - }); - } - - return $components; - }) - ->columnSpan(2), - ]), - - Forms\Components\Section::make('Environment Management') - ->collapsed() - ->icon('tabler-server-cog') - ->iconColor('primary') - ->columns([ - 'default' => 2, - 'sm' => 4, - 'md' => 4, - 'lg' => 4, - ]) + + $uniquePorts = $ports->unique()->values(); + if ($ports->count() > $uniquePorts->count()) { + $update = true; + $ports = $uniquePorts; + } + + $sortedPorts = $ports->sort()->values(); + if ($sortedPorts->all() !== $ports->all()) { + $update = true; + $ports = $sortedPorts; + } + + $ports = $ports->filter(fn ($port) => $port > 1024 && $port < 65535)->values(); + + if ($update) { + $set('allocation_ports', $ports->all()); + } + }) + ->splitKeys(['Tab', ' ', ',']) + ->required(), + ]) + ->createOptionUsing(function (array $data, Forms\Get $get): int { + return collect( + resolve(AssignmentService::class)->handle(Node::find($get('node_id')), $data) + )->first(); + }) + ->required(), + + Forms\Components\Repeater::make('allocation_additional') + ->label('Additional Allocations') + ->columnSpan([ + 'default' => 1, + 'sm' => 2, + 'md' => 1, + 'lg' => 2, + ]) + ->addActionLabel('Add Allocation') + ->disabled(fn (Forms\Get $get) => $get('allocation_id') === null) + // ->addable() TODO disable when all allocations are taken + // ->addable() TODO disable until first additional allocation is selected + ->simple( + Forms\Components\Select::make('extra_allocations') + ->live() + ->preload() + ->disableOptionsWhenSelectedInSiblingRepeaterItems() + ->prefixIcon('tabler-network') + ->label('Additional Allocations') + ->columnSpan(2) + ->disabled(fn (Forms\Get $get) => $get('../../node_id') === null) + ->searchable(['ip', 'port', 'ip_alias']) + ->getOptionLabelFromRecordUsing( + fn (Allocation $allocation) => "$allocation->ip:$allocation->port" . + ($allocation->ip_alias ? " ($allocation->ip_alias)" : '') + ) + ->placeholder('Select additional Allocations') + ->disableOptionsWhenSelectedInSiblingRepeaterItems() + ->relationship( + 'allocations', + 'ip', + fn (Builder $query, Forms\Get $get, Forms\Components\Select $component, $state) => $query + ->where('node_id', $get('../../node_id')) + ->whereNot('id', $get('../../allocation_id')) + ->whereNull('server_id'), + ), + ), + + Forms\Components\TextInput::make('description') + ->placeholder('Description') + ->columnSpan([ + 'default' => 1, + 'sm' => 2, + 'md' => 2, + 'lg' => 6, + ]) + ->label('Notes'), + ]), + + Wizard\Step::make('Egg Configuration') + ->label('Egg Configuration') + ->icon('tabler-egg') + ->completedIcon('tabler-check') + ->columns([ + 'default' => 1, + 'sm' => 2, + 'md' => 2, + 'lg' => 4, + ]) + ->schema([ + Forms\Components\Select::make('egg_id') + ->prefixIcon('tabler-egg') + ->relationship('egg', 'name') + ->columnSpan([ + 'default' => 1, + 'sm' => 2, + 'md' => 2, + 'lg' => 3, + ]) + ->searchable() + ->preload() + ->live() + ->afterStateUpdated(function ($state, Forms\Set $set, Forms\Get $get, $old) { + $egg = Egg::query()->find($state); + $set('startup', $egg->startup); + $set('image', ''); + + $variables = $egg->variables ?? []; + $serverVariables = collect(); + foreach ($variables as $variable) { + $serverVariables->add($variable->toArray()); + } + + $variables = []; + $set($path = 'server_variables', $serverVariables->sortBy(['sort'])->all()); + for ($i = 0; $i < $serverVariables->count(); $i++) { + $set("$path.$i.variable_value", $serverVariables[$i]['default_value']); + $set("$path.$i.variable_id", $serverVariables[$i]['id']); + $variables[$serverVariables[$i]['env_variable']] = $serverVariables[$i]['default_value']; + } + + $set('environment', $variables); + + $previousEgg = Egg::query()->find($old); + if (!$get('name') || $previousEgg?->getKebabName() === $get('name')) { + $set('name', $egg->getKebabName()); + } + }) + ->required(), + + Forms\Components\ToggleButtons::make('skip_scripts') + ->label('Run Egg Install Script?') + ->default(false) + ->columnSpan([ + 'default' => 1, + 'sm' => 1, + 'md' => 1, + 'lg' => 1, + ]) + ->options([ + false => 'Yes', + true => 'Skip', + ]) + ->colors([ + false => 'primary', + true => 'danger', + ]) + ->icons([ + false => 'tabler-code', + true => 'tabler-code-off', + ]) + ->inline() + ->required(), + + Forms\Components\Textarea::make('startup') + ->hintIcon('tabler-code') + ->label('Startup Command') + ->hidden(fn (Forms\Get $get) => $get('egg_id') === null) + ->required() + ->live() + ->columnSpan([ + 'default' => 1, + 'sm' => 2, + 'md' => 2, + 'lg' => 4, + ]) + ->rows(function ($state) { + return str($state)->explode("\n")->reduce( + fn (int $carry, $line) => $carry + floor(strlen($line) / 125), + 1 + ); + }), + + Forms\Components\Hidden::make('environment')->default([]), + + Forms\Components\Hidden::make('start_on_completion')->default(true), + + Forms\Components\Section::make('Variables') + ->icon('tabler-eggs') + ->iconColor('primary') + ->hidden(fn (Forms\Get $get) => $get('egg_id') === null) + ->collapsible() + ->columnSpanFull() + ->schema([ + Forms\Components\Placeholder::make('Select an egg first to show its variables!') + ->hidden(fn (Forms\Get $get) => $get('egg_id')), + + Forms\Components\Placeholder::make('The selected egg has no variables!') + ->hidden(fn (Forms\Get $get) => !$get('egg_id') || + Egg::query()->find($get('egg_id'))?->variables()?->count() + ), + + Forms\Components\Repeater::make('server_variables') + ->label('') + ->relationship('serverVariables') + ->saveRelationshipsBeforeChildrenUsing(null) + ->saveRelationshipsUsing(null) + ->grid(2) + ->reorderable(false) + ->addable(false) + ->deletable(false) + ->default([]) + ->hidden(fn ($state) => empty($state)) + ->schema(function () { + + $text = Forms\Components\TextInput::make('variable_value') + ->hidden($this->shouldHideComponent(...)) + ->maxLength(191) + ->required(fn (Forms\Get $get) => in_array('required', explode('|', $get('rules')))) + ->rules( + fn (Forms\Get $get): Closure => function (string $attribute, $value, Closure $fail) use ($get) { + $validator = Validator::make(['validatorkey' => $value], [ + 'validatorkey' => $get('rules'), + ]); + + if ($validator->fails()) { + $message = str($validator->errors()->first())->replace('validatorkey', $get('name'))->toString(); + + $fail($message); + } + }, + ); + + $select = Forms\Components\Select::make('variable_value') + ->hidden($this->shouldHideComponent(...)) + ->options($this->getSelectOptionsFromRules(...)) + ->selectablePlaceholder(false); + + $components = [$text, $select]; + + /** @var Forms\Components\Component $component */ + foreach ($components as &$component) { + $component = $component + ->live(onBlur: true) + ->hintIcon('tabler-code') + ->label(fn (Forms\Get $get) => $get('name')) + ->hintIconTooltip(fn (Forms\Get $get) => $get('rules')) + ->prefix(fn (Forms\Get $get) => '{{' . $get('env_variable') . '}}') + ->helperText(fn (Forms\Get $get) => empty($get('description')) ? '—' : $get('description')) + ->afterStateUpdated(function (Forms\Set $set, Forms\Get $get, $state) { + $environment = $get($envPath = '../../environment'); + $environment[$get('env_variable')] = $state; + $set($envPath, $environment); + }); + } + + return $components; + }) + ->columnSpan(2), + ]), + ]), + Wizard\Step::make('Environment Configuration') + ->label('Environment Configuration') + ->icon('tabler-brand-docker') + ->completedIcon('tabler-check') + ->schema([ + Forms\Components\Fieldset::make('Resource Limits') + ->columnSpan([ + 'default' => 2, + 'sm' => 4, + 'md' => 4, + 'lg' => 6, + ]) + ->columns([ + 'default' => 1, + 'sm' => 2, + 'md' => 3, + 'lg' => 3, + ]) + ->schema([ + Forms\Components\Grid::make() + ->columns(4) + ->columnSpanFull() + ->schema([ + Forms\Components\ToggleButtons::make('unlimited_mem') + ->label('Memory')->inlineLabel()->inline() + ->default(true) + ->afterStateUpdated(fn (Forms\Set $set) => $set('memory', 0)) + ->live() + ->options([ + true => 'Unlimited', + false => 'Limited', + ]) + ->colors([ + true => 'primary', + false => 'warning', + ]) + ->columnSpan(2), + + Forms\Components\TextInput::make('memory') + ->dehydratedWhenHidden() + ->hidden(fn (Forms\Get $get) => $get('unlimited_mem')) + ->label('Memory Limit')->inlineLabel() + ->suffix('MiB') + ->default(0) + ->required() + ->columnSpan(2) + ->numeric() + ->minValue(0), + ]), + + Forms\Components\Grid::make() + ->columns(4) + ->columnSpanFull() + ->schema([ + Forms\Components\ToggleButtons::make('unlimited_disk') + ->label('Disk Space')->inlineLabel()->inline() + ->default(true) + ->live() + ->afterStateUpdated(fn (Forms\Set $set) => $set('disk', 0)) + ->options([ + true => 'Unlimited', + false => 'Limited', + ]) + ->colors([ + true => 'primary', + false => 'warning', + ]) + ->columnSpan(2), + + Forms\Components\TextInput::make('disk') + ->dehydratedWhenHidden() + ->hidden(fn (Forms\Get $get) => $get('unlimited_disk')) + ->label('Disk Space Limit')->inlineLabel() + ->suffix('MiB') + ->default(0) + ->required() + ->columnSpan(2) + ->numeric() + ->minValue(0), + ]), + + Forms\Components\Grid::make() + ->columns(4) + ->columnSpanFull() + ->schema([ + Forms\Components\ToggleButtons::make('unlimited_cpu') + ->label('CPU')->inlineLabel()->inline() + ->default(true) + ->afterStateUpdated(fn (Forms\Set $set) => $set('cpu', 0)) + ->live() + ->options([ + true => 'Unlimited', + false => 'Limited', + ]) + ->colors([ + true => 'primary', + false => 'warning', + ]) + ->columnSpan(2), + + Forms\Components\TextInput::make('cpu') + ->dehydratedWhenHidden() + ->hidden(fn (Forms\Get $get) => $get('unlimited_cpu')) + ->label('CPU Limit')->inlineLabel() + ->suffix('%') + ->default(0) + ->required() + ->columnSpan(2) + ->numeric() + ->minValue(0) + ->helperText('100% equals one CPU core.'), + ]), + + Forms\Components\Grid::make() + ->columns(4) + ->columnSpanFull() + ->schema([ + Forms\Components\ToggleButtons::make('swap_support') + ->live() + ->label('Enable Swap Memory') + ->inlineLabel() + ->inline() + ->columnSpan(2) + ->default('disabled') + ->afterStateUpdated(function ($state, Forms\Set $set) { + $value = match ($state) { + 'unlimited' => -1, + 'disabled' => 0, + 'limited' => 128, + }; + + $set('swap', $value); + }) + ->options([ + 'unlimited' => 'Unlimited', + 'limited' => 'Limited', + 'disabled' => 'Disabled', + ]) + ->colors([ + 'unlimited' => 'primary', + 'limited' => 'warning', + 'disabled' => 'danger', + ]), + + Forms\Components\TextInput::make('swap') + ->dehydratedWhenHidden() + ->hidden(fn (Forms\Get $get) => match ($get('swap_support')) { + 'disabled', 'unlimited' => true, + 'limited' => false, + }) + ->label('Swap Memory') + ->default(0) + ->suffix('MiB') + ->minValue(-1) + ->columnSpan(2) + ->inlineLabel() + ->required() + ->integer(), + ]), + + Forms\Components\Hidden::make('io') + ->helperText('The IO performance relative to other running containers') + ->label('Block IO Proportion') + ->default(500), + + Forms\Components\Grid::make() + ->columns(4) + ->columnSpanFull() + ->schema([ + Forms\Components\ToggleButtons::make('oom_killer') + ->label('OOM Killer') + ->inlineLabel()->inline() + ->default(false) + ->columnSpan(2) + ->options([ + false => 'Disabled', + true => 'Enabled', + ]) + ->colors([ + false => 'success', + true => 'danger', + ]), + + Forms\Components\TextInput::make('oom_disabled_hidden') + ->hidden(), + ]), + ]), + + Forms\Components\Fieldset::make('Feature Limits') + ->inlineLabel() + ->columnSpan([ + 'default' => 2, + 'sm' => 4, + 'md' => 4, + 'lg' => 6, + ]) + ->columns([ + 'default' => 1, + 'sm' => 2, + 'md' => 3, + 'lg' => 3, + ]) + ->schema([ + Forms\Components\TextInput::make('allocation_limit') + ->label('Allocations') + ->suffixIcon('tabler-network') + ->required() + ->numeric() + ->default(0), + Forms\Components\TextInput::make('database_limit') + ->label('Databases') + ->suffixIcon('tabler-database') + ->required() + ->numeric() + ->default(0), + Forms\Components\TextInput::make('backup_limit') + ->label('Backups') + ->suffixIcon('tabler-copy-check') + ->required() + ->numeric() + ->default(0), + ]), + Forms\Components\Fieldset::make('Docker Settings') + ->columnSpan([ + 'default' => 2, + 'sm' => 4, + 'md' => 4, + 'lg' => 6, + ]) + ->columns([ + 'default' => 1, + 'sm' => 2, + 'md' => 3, + 'lg' => 3, + ]) + ->schema([ + Forms\Components\Select::make('select_image') + ->label('Image Name') + ->afterStateUpdated(fn (Forms\Set $set, $state) => $set('image', $state)) + ->options(function ($state, Forms\Get $get, Forms\Set $set) { + $egg = Egg::query()->find($get('egg_id')); + $images = $egg->docker_images ?? []; + + $currentImage = $get('image'); + if (!$currentImage && $images) { + $defaultImage = collect($images)->first(); + $set('image', $defaultImage); + $set('select_image', $defaultImage); + } + + return array_flip($images) + ['ghcr.io/custom-image' => 'Custom Image']; + }) + ->selectablePlaceholder(false) + ->columnSpan(1), + + Forms\Components\TextInput::make('image') + ->label('Image') + ->debounce(500) + ->afterStateUpdated(function ($state, Forms\Get $get, Forms\Set $set) { + $egg = Egg::query()->find($get('egg_id')); + $images = $egg->docker_images ?? []; + + if (in_array($state, $images)) { + $set('select_image', $state); + } else { + $set('select_image', 'ghcr.io/custom-image'); + } + }) + ->placeholder('Enter a custom Image') + ->columnSpan(2), + + Forms\Components\KeyValue::make('docker_labels') + ->label('Container Labels') + ->keyLabel('Title') + ->valueLabel('Description') + ->columnSpan(3), + + Forms\Components\CheckboxList::make('mounts') + ->live() + ->relationship('mounts') + ->options(fn () => $this->node?->mounts->mapWithKeys(fn ($mount) => [$mount->id => $mount->name]) ?? []) + ->descriptions(fn () => $this->node?->mounts->mapWithKeys(fn ($mount) => [$mount->id => "$mount->source -> $mount->target"]) ?? []) + ->label('Mounts') + ->helperText(fn () => $this->node?->mounts->isNotEmpty() ? '' : 'No Mounts exist for this Node') + ->columnSpanFull(), + ]), + ]), + ]) ->columnSpanFull() - ->schema([ - Forms\Components\Fieldset::make('Resource Limits') - ->columnSpan([ - 'default' => 2, - 'sm' => 4, - 'md' => 4, - 'lg' => 6, - ]) - ->columns([ - 'default' => 1, - 'sm' => 2, - 'md' => 3, - 'lg' => 3, - ]) - ->schema([ - Forms\Components\Grid::make() - ->columns(4) - ->columnSpanFull() - ->schema([ - Forms\Components\ToggleButtons::make('unlimited_mem') - ->label('Memory')->inlineLabel()->inline() - ->default(true) - ->afterStateUpdated(fn (Forms\Set $set) => $set('memory', 0)) - ->live() - ->options([ - true => 'Unlimited', - false => 'Limited', - ]) - ->colors([ - true => 'primary', - false => 'warning', - ]) - ->columnSpan(2), - - Forms\Components\TextInput::make('memory') - ->dehydratedWhenHidden() - ->hidden(fn (Forms\Get $get) => $get('unlimited_mem')) - ->label('Memory Limit')->inlineLabel() - ->suffix('MiB') - ->default(0) - ->required() - ->columnSpan(2) - ->numeric() - ->minValue(0), - ]), - - Forms\Components\Grid::make() - ->columns(4) - ->columnSpanFull() - ->schema([ - Forms\Components\ToggleButtons::make('unlimited_disk') - ->label('Disk Space')->inlineLabel()->inline() - ->default(true) - ->live() - ->afterStateUpdated(fn (Forms\Set $set) => $set('disk', 0)) - ->options([ - true => 'Unlimited', - false => 'Limited', - ]) - ->colors([ - true => 'primary', - false => 'warning', - ]) - ->columnSpan(2), - - Forms\Components\TextInput::make('disk') - ->dehydratedWhenHidden() - ->hidden(fn (Forms\Get $get) => $get('unlimited_disk')) - ->label('Disk Space Limit')->inlineLabel() - ->suffix('MiB') - ->default(0) - ->required() - ->columnSpan(2) - ->numeric() - ->minValue(0), - ]), - - Forms\Components\Grid::make() - ->columns(4) - ->columnSpanFull() - ->schema([ - Forms\Components\ToggleButtons::make('unlimited_cpu') - ->label('CPU')->inlineLabel()->inline() - ->default(true) - ->afterStateUpdated(fn (Forms\Set $set) => $set('cpu', 0)) - ->live() - ->options([ - true => 'Unlimited', - false => 'Limited', - ]) - ->colors([ - true => 'primary', - false => 'warning', - ]) - ->columnSpan(2), - - Forms\Components\TextInput::make('cpu') - ->dehydratedWhenHidden() - ->hidden(fn (Forms\Get $get) => $get('unlimited_cpu')) - ->label('CPU Limit')->inlineLabel() - ->suffix('%') - ->default(0) - ->required() - ->columnSpan(2) - ->numeric() - ->minValue(0) - ->helperText('100% equals one CPU core.'), - ]), - - Forms\Components\Grid::make() - ->columns(4) - ->columnSpanFull() - ->schema([ - Forms\Components\ToggleButtons::make('swap_support') - ->live() - ->label('Enable Swap Memory') - ->inlineLabel() - ->inline() - ->columnSpan(2) - ->default('disabled') - ->afterStateUpdated(function ($state, Forms\Set $set) { - $value = match ($state) { - 'unlimited' => -1, - 'disabled' => 0, - 'limited' => 128, - }; - - $set('swap', $value); - }) - ->options([ - 'unlimited' => 'Unlimited', - 'limited' => 'Limited', - 'disabled' => 'Disabled', - ]) - ->colors([ - 'unlimited' => 'primary', - 'limited' => 'warning', - 'disabled' => 'danger', - ]), - - Forms\Components\TextInput::make('swap') - ->dehydratedWhenHidden() - ->hidden(fn (Forms\Get $get) => match ($get('swap_support')) { - 'disabled', 'unlimited' => true, - 'limited' => false, - }) - ->label('Swap Memory') - ->default(0) - ->suffix('MiB') - ->minValue(-1) - ->columnSpan(2) - ->inlineLabel() - ->required() - ->integer(), - ]), - - Forms\Components\Hidden::make('io') - ->helperText('The IO performance relative to other running containers') - ->label('Block IO Proportion') - ->default(500), - - Forms\Components\Grid::make() - ->columns(4) - ->columnSpanFull() - ->schema([ - Forms\Components\ToggleButtons::make('oom_killer') - ->label('OOM Killer') - ->inlineLabel()->inline() - ->default(false) - ->columnSpan(2) - ->options([ - false => 'Disabled', - true => 'Enabled', - ]) - ->colors([ - false => 'success', - true => 'danger', - ]), - - Forms\Components\TextInput::make('oom_disabled_hidden') - ->hidden(), - ]), - ]), - - Forms\Components\Fieldset::make('Feature Limits') - ->inlineLabel() - ->columnSpan([ - 'default' => 2, - 'sm' => 4, - 'md' => 4, - 'lg' => 6, - ]) - ->columns([ - 'default' => 1, - 'sm' => 2, - 'md' => 3, - 'lg' => 3, - ]) - ->schema([ - Forms\Components\TextInput::make('allocation_limit') - ->suffixIcon('tabler-network') - ->required() - ->numeric() - ->default(0), - Forms\Components\TextInput::make('database_limit') - ->suffixIcon('tabler-database') - ->required() - ->numeric() - ->default(0), - Forms\Components\TextInput::make('backup_limit') - ->suffixIcon('tabler-copy-check') - ->required() - ->numeric() - ->default(0), - ]), - Forms\Components\Fieldset::make('Docker Settings') - ->columnSpan([ - 'default' => 2, - 'sm' => 4, - 'md' => 4, - 'lg' => 6, - ]) - ->columns([ - 'default' => 1, - 'sm' => 2, - 'md' => 3, - 'lg' => 3, - ]) - ->schema([ - Forms\Components\Select::make('select_image') - ->label('Image Name') - ->afterStateUpdated(fn (Forms\Set $set, $state) => $set('image', $state)) - ->options(function ($state, Forms\Get $get, Forms\Set $set) { - $images = $this->egg->docker_images ?? []; - - $currentImage = $get('image'); - if (!$currentImage && $images) { - $defaultImage = collect($images)->first(); - $set('image', $defaultImage); - $set('select_image', $defaultImage); - } - - return array_flip($images) + ['ghcr.io/custom-image' => 'Custom Image']; - }) - ->selectablePlaceholder(false) - ->columnSpan(1), - - Forms\Components\TextInput::make('image') - ->label('Image') - ->debounce(500) - ->afterStateUpdated(function ($state, Forms\Get $get, Forms\Set $set) { - $images = $this->egg->docker_images ?? []; - - if (in_array($state, $images)) { - $set('select_image', $state); - } else { - $set('select_image', 'ghcr.io/custom-image'); - } - }) - ->placeholder('Enter a custom Image') - ->columnSpan(1), - - Forms\Components\KeyValue::make('docker_labels') - ->label('Container Labels') - ->keyLabel('Title') - ->valueLabel('Description') - ->columnSpan(3), - ]), - ]), + ->nextAction(fn (Action $action) => $action->label('Next Step')) + ->submitAction(new HtmlString(Blade::render(<<<'BLADE' + + Create Server + + BLADE))), ]); } + protected function getFormActions(): array + { + return []; + } + protected function handleRecordCreation(array $data): Model { $data['allocation_additional'] = collect($data['allocation_additional'])->filter()->all(); @@ -571,82 +792,4 @@ private function getSelectOptionsFromRules(Forms\Get $get): array ->mapWithKeys(fn ($value) => [$value => $value]) ->all(); } - - public function ports($state, Forms\Set $set) { - $ports = collect(); - $update = false; - foreach ($state as $portEntry) { - if (!str_contains($portEntry, '-')) { - if (is_numeric($portEntry)) { - $ports->push((int) $portEntry); - - continue; - } - - continue; - } - - [$start, $end] = explode('-', $portEntry); - if (!is_numeric($start) || !is_numeric($end)) { - continue; - } - - $start = max((int) $start, 0); - $end = min((int) $end, 2 ** 16 - 1); - for ($i = $start; $i <= $end; $i++) { - $ports->push($i); - } - } - - $uniquePorts = $ports->unique()->values(); - if ($ports->count() > $uniquePorts->count()) { - $ports = $uniquePorts; - } - - $ports = $ports->filter(fn ($port) => $port > 1024 && $port < 65535)->values(); - - $set('ports', $ports->all()); - $this->ports = $ports->all(); - } - - public function resetEggVariables(Forms\Set $set, Forms\Get $get) - { - $set('assignments', []); - - $i = 0; - $this->eggDefaultPorts = []; - if (str_contains($get('startup'), '{{SERVER_PORT}}')) { - $this->eggDefaultPorts['SERVER_PORT'] = null; - $set('assignments.SERVER_PORT', ['port' => null]); - } - - $variables = $this->egg->variables ?? []; - $serverVariables = collect(); - $this->ports = []; - foreach ($variables as $variable) { - if (str_contains($variable->rules, 'port')) { - $this->eggDefaultPorts[$variable->env_variable] = $variable->default_value; - $this->ports[] = (int) $variable->default_value; - - // $set("assignments.$i", ['port' => $i++]); - $set("assignments.$variable->env_variable", ['port' => $i++]); - - continue; - } - - $serverVariables->add($variable->toArray()); - } - - $set('ports', $this->ports); - - $variables = []; - $set($path = 'server_variables', $serverVariables->sortBy(['sort'])->all()); - for ($i = 0; $i < $serverVariables->count(); $i++) { - $set("$path.$i.variable_value", $serverVariables[$i]['default_value']); - $set("$path.$i.variable_id", $serverVariables[$i]['id']); - $variables[$serverVariables[$i]['env_variable']] = $serverVariables[$i]['default_value']; - } - - $set('environment', $variables); - } } diff --git a/lang/af/exceptions.php b/lang/af/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/af/exceptions.php +++ b/lang/af/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/ar/exceptions.php b/lang/ar/exceptions.php index 4de9d56aac..0c2656e1fc 100644 --- a/lang/ar/exceptions.php +++ b/lang/ar/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'يجب ألا يكون هناك أي خوادم مرتبطة بالعقدة لكي يتم حذفها.', 'daemon_off_config_updated' => 'تم تحديث تكوين الدايمون لكن، واجهت مشكلة أثناء محاولة تحديث ملف التكوين تلقائيًا على الدايمون. ستحتاج إلى تحديث ملف التكوين (config.yml) يدويًا لتطبيق هذه التغييرات.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'تم تعيين خادم حاليًا لهذا التخصيص. لا يمكن حذف التخصيص إلا إذا لم يكن هناك خادم معين حاليًا.', 'too_many_ports' => 'لا يتم دعم إضافة أكثر من 1000 منفذ في نطاق واحد دفعة واحدة.', 'invalid_mapping' => 'التعيين المقدم للمنفذ :port كان غير صالح ولا يمكن معالجته.', diff --git a/lang/be/exceptions.php b/lang/be/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/be/exceptions.php +++ b/lang/be/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/ca/exceptions.php b/lang/ca/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/ca/exceptions.php +++ b/lang/ca/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/cs/exceptions.php b/lang/cs/exceptions.php index 337f026138..2d7a1ac93b 100644 --- a/lang/cs/exceptions.php +++ b/lang/cs/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Uzel nesmí mít žádné s ním spojené servery, aby mohl být smazán', 'daemon_off_config_updated' => 'Konfigurace daemonu byla aktualizována, ale byla zde chyba při automatické aktualizaci souborů konfigurace Daemonu. Je třeba soubory konfigurace Daemonu aktualizovat manuálně (config.yml), aby změny damemonu byly aplikovány.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'Server již využívá tuhle alokaci. Pro odstranění alokace, nesmí být žádný server spojen s alokací.', 'too_many_ports' => 'Přidání více než 1000 portů v jednom rozsahu najednou není podporováno.', 'invalid_mapping' => 'Mapování poskytnuto pro :port bylo nesprávné a nebylo možné ho zpracovat.', diff --git a/lang/da/exceptions.php b/lang/da/exceptions.php index 544bec5814..8b546c30b5 100644 --- a/lang/da/exceptions.php +++ b/lang/da/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'En node må ikke have nogen servere tilknyttet for at kunne slettes.', 'daemon_off_config_updated' => 'Daemon konfiguration er blevet opdateret, men der opstod en fejl under forsøget på automatisk at opdatere konfigurationsfilen på daemonen. Du skal manuelt opdatere konfigurationsfilen (config.yml) for at daemonen kan anvende disse ændringer.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'En server er i øjeblikket tildelt denne tildeling. En tildeling kan kun slettes, hvis ingen server i øjeblikket er tildelt.', 'too_many_ports' => 'Tilføjede af flere end 1000 porte i en enkelt række ad gangen understøttes ikke.', 'invalid_mapping' => 'Den angivne kortlægning for :port var ugyldig og kunne ikke behandles.', diff --git a/lang/de/exceptions.php b/lang/de/exceptions.php index 72193edd95..7c091e21a2 100644 --- a/lang/de/exceptions.php +++ b/lang/de/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Ein Node darf keine Server haben, die mit ihm verknüpft sind, um gelöscht zu werden.', 'daemon_off_config_updated' => 'Die Daemon Konfiguration wurde aktualisiert, jedoch gab es einen Fehler bei dem Versuch, die Konfigurationsdatei des Daemon automatisch zu aktualisieren. Du musst die Konfigurationsdatei (config.yml) manuell anpassen, damit die Änderungen übernommen werden.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'Derzeit ist ein Server dieser Zuweisung zugewiesen. Eine Zuordnung kann nur gelöscht werden, wenn derzeit kein Server zugewiesen ist.', 'too_many_ports' => 'Das Hinzufügen von mehr als 1000 Ports in einem einzigen Bereich wird nicht unterstützt.', 'invalid_mapping' => 'Das für :port angegebene Mapping war ungültig und konnte nicht verarbeitet werden.', diff --git a/lang/el/exceptions.php b/lang/el/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/el/exceptions.php +++ b/lang/el/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/en/exceptions.php b/lang/en/exceptions.php index 3c9adf4c90..2cce4d85de 100644 --- a/lang/en/exceptions.php +++ b/lang/en/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/es/exceptions.php b/lang/es/exceptions.php index 19a6b31276..f01d42a767 100644 --- a/lang/es/exceptions.php +++ b/lang/es/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Un nodo no debe tener servidores vinculados a él para poder ser eliminado.', 'daemon_off_config_updated' => 'La configuración del daemon se ha actualizado, sin embargo, se encontró un error al intentar actualizar automáticamente el archivo de configuración en el daemon. Deberás actualizar manualmente el archivo de configuración (config.yml) para que el daemon aplique estos cambios.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'Actualmente hay un servidor asignado a esta asignación. Una asignación solo puede ser eliminada si ningún servidor está asignado actualmente.', 'too_many_ports' => 'Agregar más de 1000 puertos en un solo rango a la vez no está soportado.', 'invalid_mapping' => 'El mapeo proporcionado para el puerto :port era inválido y no pudo ser procesado.', diff --git a/lang/fi/exceptions.php b/lang/fi/exceptions.php index 84eee3d849..903eebdb2f 100644 --- a/lang/fi/exceptions.php +++ b/lang/fi/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Palvelimella ei saa olla siihen linkitettyjä palvelimia, jotta se voitaisiin poistaa.', 'daemon_off_config_updated' => 'Daemon konfiguraatio on päivitetty, mutta virhe ilmeni yritettäessä päivittää konfiguraatiota automaattisesti daemoniin. Sinun tulee päivittää daemonin konfiguraatio (config.yml) manuaalisesti, jotta muutokset voidaan ottaa käyttöön.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'Palvelin on tällä hetkellä määritelty tähän varaukseen. Varauksen voi poistaa vain, jos siihen ei ole tällä hetkellä määritettyä palvelinta.', 'too_many_ports' => 'Yli 1000 portin lisääminen yhteen alueeseen kerralla ei ole tuettua.', 'invalid_mapping' => ':port:lle annettu määritys oli virheellinen eikä sitä voitu käsitellä.', diff --git a/lang/fr/exceptions.php b/lang/fr/exceptions.php index 790cccf695..cc838b7c68 100644 --- a/lang/fr/exceptions.php +++ b/lang/fr/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Un nœud ne doit avoir aucun serveur lié à lui pour être supprimé.', 'daemon_off_config_updated' => 'La configuration du daemon a été mis à jour, cependant, une erreur s\'est produite lors de la tentative de mise à jour automatique du fichier de configuration sur le daemon. Vous devrez mettre à jour manuellement le fichier de configuration (core.json) pour qu\'il puisse appliquer ces modifications.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'Un serveur est actuellement affecté à cette allocation. Une allocation ne peut être supprimée que si aucun serveur n\'utilise cette dernière.', 'too_many_ports' => 'L\'ajout de plus de 1000 ports dans une seule plage à la fois n\'est pas supporté.', 'invalid_mapping' => 'Le mappage fourni pour :port est invalide et n\'a pas pu être traitée.', diff --git a/lang/he/exceptions.php b/lang/he/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/he/exceptions.php +++ b/lang/he/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/hi/exceptions.php b/lang/hi/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/hi/exceptions.php +++ b/lang/hi/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/hr/exceptions.php b/lang/hr/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/hr/exceptions.php +++ b/lang/hr/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/hu/exceptions.php b/lang/hu/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/hu/exceptions.php +++ b/lang/hu/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/id/exceptions.php b/lang/id/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/id/exceptions.php +++ b/lang/id/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/it/exceptions.php b/lang/it/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/it/exceptions.php +++ b/lang/it/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/ja/exceptions.php b/lang/ja/exceptions.php index a5bd12d3da..ee6c510cb4 100644 --- a/lang/ja/exceptions.php +++ b/lang/ja/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => '削除するには、ノードにサーバーがリンクされていない必要があります。', 'daemon_off_config_updated' => 'デーモンの設定が更新されました。しかし、デーモンの設定ファイルを自動的に更新しようとする際にエラーが発生しました。 これらの変更を適用するには、デーモンの設定ファイル(config.yml)を手動で更新する必要があります。', ], - 'allocations' => [ + 'ports' => [ 'server_using' => '現在サーバーは割り当てられています。割り当てはサーバーが現在割り当てられていない場合にのみ削除できます。', 'too_many_ports' => '一度に1000以上のポートを追加することはできません。', 'invalid_mapping' => ':port のマッピングは無効で、処理することができませんでした。', diff --git a/lang/ko/exceptions.php b/lang/ko/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/ko/exceptions.php +++ b/lang/ko/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/nl/exceptions.php b/lang/nl/exceptions.php index 6e2fe678f4..e4e42e6380 100644 --- a/lang/nl/exceptions.php +++ b/lang/nl/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Een node moet geen actieve servers meer hebben voordat deze kan worden verwijderd.', 'daemon_off_config_updated' => 'De daemonconfiguratie is bijgewerkt, er is echter een fout opgetreden bij het automatisch bijwerken van het configuratiebestand op de Daemon. U moet handmatig het configuratiebestand bijwerken (config.yml) voor de daemon om deze veranderingen toe te passen.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'Een server is momenteel toegewezen aan deze toewijzing. Een toewijzing kan alleen worden verwijderd als er momenteel geen server is toegewezen.', 'too_many_ports' => 'Meer dan 1000 poorten binnen één bereik toevoegen wordt niet ondersteund.', 'invalid_mapping' => 'De opgegeven toewijzing voor :port was ongeldig en kon niet worden verwerkt.', diff --git a/lang/no/exceptions.php b/lang/no/exceptions.php index f9a65b7448..923bbc11e2 100644 --- a/lang/no/exceptions.php +++ b/lang/no/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/pl/exceptions.php b/lang/pl/exceptions.php index d821676b12..bda35c9d5a 100644 --- a/lang/pl/exceptions.php +++ b/lang/pl/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Aby usunąć ten węzeł, nie możesz mieć podłączonych do niego serwerów.', 'daemon_off_config_updated' => 'Konfiguracja deamona została zaktualizowana, jednak wystąpił błąd podczas próby automatycznej aktualizacji pliku konfiguracyjnego deamona. Aby zastosować te zmiany, należy ręcznie zaktualizować plik konfiguracyjny (config.yml).', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'Serwer jest obecnie przypisany do tej alokacji. Alokację można usunąć tylko wtedy, gdy żaden serwer nie jest do niej przypisany.', 'too_many_ports' => 'Dodawanie więcej niż 1000 portów w jednym zakresie nie jest obsługiwane.', 'invalid_mapping' => 'Mapowanie podane dla :port było nieprawidłowe i nie mogło zostać przetworzone.', diff --git a/lang/pt/exceptions.php b/lang/pt/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/pt/exceptions.php +++ b/lang/pt/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/ro/exceptions.php b/lang/ro/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/ro/exceptions.php +++ b/lang/ro/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/ru/exceptions.php b/lang/ru/exceptions.php index 0054e46bea..7e758cd3c4 100644 --- a/lang/ru/exceptions.php +++ b/lang/ru/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Узел не должен иметь подключенных к нему серверов, чтобы быть удален.', 'daemon_off_config_updated' => 'Конфигурация демона была обновлена, но при попытке автоматического обновления конфигурационного файла произошла ошибка. Вам нужно вручную обновить конфигурационный файл (config.yml) для применения этих изменений.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'Сервер в настоящее время назначается для этого размещения. Распределение может быть удалено, только если ни один сервер не назначен.', 'too_many_ports' => 'Добавление более 1000 портов в одном диапазоне за раз не поддерживается.', 'invalid_mapping' => 'Сопоставление, предоставленное для порта {port}, было недопустимым и не могло быть обработано.', diff --git a/lang/sk/exceptions.php b/lang/sk/exceptions.php index 56a7b8424c..4b4732f180 100644 --- a/lang/sk/exceptions.php +++ b/lang/sk/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Uzol nemôže mať priradené žiadne servery aby mohol byť vymazaný.', 'daemon_off_config_updated' => 'Konfigurácia daemonu bola aktualizovaná, no pri pokuse o automatickú aktualizáciu konfigurácie na daemonovi sa vyskytla chyba. Budete musieť manuálne aktualizovať konfiguračný súbor (config.yml) aby sa táto zmena aplikovala na daemon.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'Server je momentálne priradený k tejto alokácii. Alokácia môže byť zmazaná, len ak k nej nieje priradený žiadny server.', 'too_many_ports' => 'Pridanie viac ako 1000 portov v jednom rozsahu nieje podporované.', 'invalid_mapping' => 'Mapovanie poskytnuté pre port :port nieje správne a nemohlo byť spracované.', diff --git a/lang/sl/exceptions.php b/lang/sl/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/sl/exceptions.php +++ b/lang/sl/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/sr/exceptions.php b/lang/sr/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/sr/exceptions.php +++ b/lang/sr/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/sv/exceptions.php b/lang/sv/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/sv/exceptions.php +++ b/lang/sv/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/th/exceptions.php b/lang/th/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/th/exceptions.php +++ b/lang/th/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/tr/exceptions.php b/lang/tr/exceptions.php index cdf44c0891..53c269e8ea 100644 --- a/lang/tr/exceptions.php +++ b/lang/tr/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Bir node\'un silinebilmesi için kendisine bağlı hiçbir sunucunun olmaması gerekir.', 'daemon_off_config_updated' => 'Daemon yapılandırması güncellendi, ancak Daemon\'daki yapılandırma dosyası otomatik olarak güncellenmeye çalışılırken bir hatayla karşılaşıldı. Bu değişiklikleri uygulamak için arka plan programının yapılandırma dosyasını (config.yml) manuel olarak güncellemeniz gerekecektir.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'Şu anda bu lokasyon bir sunucu atanmış. Bir lokasyon yalnızca şu anda hiçbir sunucu atanmamışsa silinebilir.', 'too_many_ports' => 'Tek bir aralığa 1000\'den fazla port (Bağlantı noktası) aynı anda eklenmesi desteklenmez.', 'invalid_mapping' => ':port için sağlanan eşleme geçersizdi ve uyhulanmadı.', diff --git a/lang/uk/exceptions.php b/lang/uk/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/uk/exceptions.php +++ b/lang/uk/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/vi/exceptions.php b/lang/vi/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/vi/exceptions.php +++ b/lang/vi/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/zh/exceptions.php b/lang/zh/exceptions.php index 3977c87c24..13cf4d8767 100644 --- a/lang/zh/exceptions.php +++ b/lang/zh/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'allocations' => [ + 'ports' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', From 0895bd2be5cea87bd1474b7329ae2c51185e7144 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Mon, 10 Jun 2024 20:35:36 -0400 Subject: [PATCH 021/103] Remove relation managers --- app/Filament/Resources/NodeResource.php | 1 - .../AllocationsRelationManager.php | 151 ------------------ .../ServerResource/Pages/EditServer.php | 7 - .../AllocationsRelationManager.php | 75 --------- 4 files changed, 234 deletions(-) delete mode 100644 app/Filament/Resources/NodeResource/RelationManagers/AllocationsRelationManager.php delete mode 100644 app/Filament/Resources/ServerResource/RelationManagers/AllocationsRelationManager.php diff --git a/app/Filament/Resources/NodeResource.php b/app/Filament/Resources/NodeResource.php index bff1e0a406..14b3d1bce0 100644 --- a/app/Filament/Resources/NodeResource.php +++ b/app/Filament/Resources/NodeResource.php @@ -23,7 +23,6 @@ public static function getNavigationBadge(): ?string public static function getRelations(): array { return [ - RelationManagers\AllocationsRelationManager::class, RelationManagers\NodesRelationManager::class, ]; } diff --git a/app/Filament/Resources/NodeResource/RelationManagers/AllocationsRelationManager.php b/app/Filament/Resources/NodeResource/RelationManagers/AllocationsRelationManager.php deleted file mode 100644 index f74cf1fca3..0000000000 --- a/app/Filament/Resources/NodeResource/RelationManagers/AllocationsRelationManager.php +++ /dev/null @@ -1,151 +0,0 @@ -schema([ - Forms\Components\TextInput::make('ip') - ->required() - ->maxLength(255), - ]); - } - - public function table(Table $table): Table - { - return $table - ->recordTitleAttribute('ip') - - // Non Primary Allocations - // ->checkIfRecordIsSelectableUsing(fn (Allocation $allocation) => $allocation->id !== $allocation->server?->allocation_id) - - // All assigned allocations - ->checkIfRecordIsSelectableUsing(fn (Allocation $allocation) => $allocation->server_id === null) - ->searchable() - ->columns([ - Tables\Columns\TextColumn::make('id'), - Tables\Columns\TextColumn::make('port') - ->searchable() - ->label('Port'), - Tables\Columns\TextColumn::make('server.name') - ->label('Server') - ->icon('tabler-brand-docker') - ->searchable() - ->url(fn (Allocation $allocation): string => $allocation->server ? route('filament.admin.resources.servers.edit', ['record' => $allocation->server]) : ''), - Tables\Columns\TextInputColumn::make('ip_alias') - ->searchable() - ->label('Alias'), - Tables\Columns\TextInputColumn::make('ip') - ->searchable() - ->label('IP'), - ]) - ->filters([ - // - ]) - ->actions([ - // - ]) - ->headerActions([ - Tables\Actions\Action::make('create new allocation')->label('Create Allocations') - ->form(fn () => [ - Forms\Components\TextInput::make('allocation_ip') - ->datalist($this->getOwnerRecord()->ipAddresses() ?? []) - ->label('IP Address') - ->inlineLabel() - ->ipv4() - ->helperText("Usually your machine's public IP unless you are port forwarding.") - ->required(), - Forms\Components\TextInput::make('allocation_alias') - ->label('Alias') - ->inlineLabel() - ->default(null) - ->helperText('Optional display name to help you remember what these are.') - ->required(false), - Forms\Components\TagsInput::make('allocation_ports') - ->placeholder('Examples: 27015, 27017-27019') - ->helperText(new HtmlString(' - These are the ports that users can connect to this Server through. -
- You would have to port forward these on your home network. - ')) - ->label('Ports') - ->inlineLabel() - ->live() - ->afterStateUpdated(function ($state, Forms\Set $set) { - $ports = collect(); - $update = false; - foreach ($state as $portEntry) { - if (!str_contains($portEntry, '-')) { - if (is_numeric($portEntry)) { - $ports->push((int) $portEntry); - - continue; - } - - // Do not add non numerical ports - $update = true; - - continue; - } - - $update = true; - [$start, $end] = explode('-', $portEntry); - if (!is_numeric($start) || !is_numeric($end)) { - continue; - } - - $start = max((int) $start, 0); - $end = min((int) $end, 2 ** 16 - 1); - foreach (range($start, $end) as $i) { - $ports->push($i); - } - } - - $uniquePorts = $ports->unique()->values(); - if ($ports->count() > $uniquePorts->count()) { - $update = true; - $ports = $uniquePorts; - } - - $sortedPorts = $ports->sort()->values(); - if ($sortedPorts->all() !== $ports->all()) { - $update = true; - $ports = $sortedPorts; - } - - $ports = $ports->filter(fn ($port) => $port > 1024 && $port < 65535)->values(); - - if ($update) { - $set('allocation_ports', $ports->all()); - } - }) - ->splitKeys(['Tab', ' ', ',']) - ->required(), - ]) - ->action(fn (array $data) => resolve(AssignmentService::class)->handle($this->getOwnerRecord(), $data)), - ]) - ->bulkActions([ - Tables\Actions\BulkActionGroup::make([ - // Tables\Actions\DissociateBulkAction::make(), - Tables\Actions\DeleteBulkAction::make(), - ]), - ]); - } -} diff --git a/app/Filament/Resources/ServerResource/Pages/EditServer.php b/app/Filament/Resources/ServerResource/Pages/EditServer.php index e425a0331a..ee6dec0682 100644 --- a/app/Filament/Resources/ServerResource/Pages/EditServer.php +++ b/app/Filament/Resources/ServerResource/Pages/EditServer.php @@ -745,13 +745,6 @@ protected function mutateFormDataBeforeSave(array $data): array return $data; } - public function getRelationManagers(): array - { - return [ - ServerResource\RelationManagers\AllocationsRelationManager::class, - ]; - } - private function shouldHideComponent(Forms\Get $get, Forms\Components\Component $component): bool { $containsRuleIn = str($get('rules'))->explode('|')->reduce( diff --git a/app/Filament/Resources/ServerResource/RelationManagers/AllocationsRelationManager.php b/app/Filament/Resources/ServerResource/RelationManagers/AllocationsRelationManager.php deleted file mode 100644 index ef200f8417..0000000000 --- a/app/Filament/Resources/ServerResource/RelationManagers/AllocationsRelationManager.php +++ /dev/null @@ -1,75 +0,0 @@ -schema([ - Forms\Components\TextInput::make('ip') - ->required() - ->maxLength(255), - ]); - } - - public function table(Table $table): Table - { - return $table - ->recordTitleAttribute('ip') - ->recordTitle(fn (Allocation $allocation) => "$allocation->ip:$allocation->port") - ->checkIfRecordIsSelectableUsing(fn (Allocation $record) => $record->id !== $this->getOwnerRecord()->allocation_id) - // ->actions - // ->groups - ->inverseRelationship('server') - ->columns([ - Tables\Columns\TextColumn::make('ip')->label('IP'), - Tables\Columns\TextColumn::make('port')->label('Port'), - Tables\Columns\TextInputColumn::make('ip_alias')->label('Alias'), - Tables\Columns\IconColumn::make('primary') - ->icon(fn ($state) => match ($state) { - false => 'tabler-star', - true => 'tabler-star-filled', - }) - ->color(fn ($state) => match ($state) { - false => 'gray', - true => 'warning', - }) - ->action(fn (Allocation $allocation) => $this->getOwnerRecord()->update(['allocation_id' => $allocation->id])) - ->default(fn (Allocation $allocation) => $allocation->id === $this->getOwnerRecord()->allocation_id) - ->label('Primary'), - ]) - ->filters([ - // - ]) - ->actions([ - Tables\Actions\Action::make('make-primary') - ->action(fn (Allocation $allocation) => $this->getOwnerRecord()->update(['allocation_id' => $allocation->id])) - ->label(fn (Allocation $allocation) => $allocation->id === $this->getOwnerRecord()->allocation_id ? '' : 'Make Primary'), - ]) - ->headerActions([ - //TODO Tables\Actions\CreateAction::make()->label('Create Allocation'), - Tables\Actions\AssociateAction::make() - ->multiple() - ->preloadRecordSelect() - ->recordSelectOptionsQuery(fn ($query) => $query->whereBelongsTo($this->getOwnerRecord()->node)) - ->label('Add Allocation'), - ]) - ->bulkActions([ - Tables\Actions\BulkActionGroup::make([ - Tables\Actions\DissociateBulkAction::make(), - Tables\Actions\DeleteBulkAction::make(), - ]), - ]); - } -} From f5edb34873ad9d369439c9600b9526321f8712f1 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Mon, 10 Jun 2024 21:32:46 -0400 Subject: [PATCH 022/103] Some filament changes for ports --- .../ServerResource/Pages/CreateServer.php | 330 ++++++++---------- .../ServerResource/Pages/ListServers.php | 8 +- 2 files changed, 139 insertions(+), 199 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index 2d92ddda71..b0e61dc32f 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -3,16 +3,13 @@ namespace App\Filament\Resources\ServerResource\Pages; use App\Filament\Resources\ServerResource; -use App\Models\Allocation; use App\Models\Egg; use App\Models\Node; -use App\Services\Allocations\AssignmentService; use App\Services\Servers\RandomWordService; use App\Services\Servers\ServerCreationService; use Filament\Forms\Components\Actions\Action; use Filament\Forms\Form; use Filament\Resources\Pages\CreateRecord; -use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Filament\Forms; use Filament\Forms\Components\Wizard; @@ -27,6 +24,9 @@ class CreateServer extends CreateRecord protected static bool $canCreateAnother = false; public ?Node $node = null; + public ?Egg $egg = null; + public array $ports = []; + public array $eggDefaultPorts = []; public function form(Form $form): Form { @@ -89,187 +89,24 @@ public function form(Form $form): Form 'default' => 1, 'sm' => 2, 'md' => 2, - 'lg' => 2, + 'lg' => 3, ]) ->live() ->relationship('node', 'name') ->searchable() ->preload() ->afterStateUpdated(function (Forms\Set $set, $state) { - $set('allocation_id', null); $this->node = Node::find($state); }) ->required(), - Forms\Components\Select::make('allocation_id') - ->preload() - ->live() - ->prefixIcon('tabler-network') - ->label('Primary Allocation') - ->columnSpan([ - 'default' => 1, - 'sm' => 2, - 'md' => 1, - 'lg' => 2, - ]) - ->disabled(fn (Forms\Get $get) => $get('node_id') === null) - ->searchable(['ip', 'port', 'ip_alias']) - ->afterStateUpdated(function (Forms\Set $set) { - $set('allocation_additional', null); - $set('allocation_additional.needstobeastringhere.extra_allocations', null); - }) - ->getOptionLabelFromRecordUsing( - fn (Allocation $allocation) => "$allocation->ip:$allocation->port" . - ($allocation->ip_alias ? " ($allocation->ip_alias)" : '') - ) - ->placeholder(function (Forms\Get $get) { - $node = Node::find($get('node_id')); - - if ($node?->allocations) { - return 'Select an Allocation'; - } - - return 'Create a New Allocation'; - }) - ->relationship( - 'allocation', - 'ip', - fn (Builder $query, Forms\Get $get) => $query - ->where('node_id', $get('node_id')) - ->whereNull('server_id'), - ) - ->createOptionForm(fn (Forms\Get $get) => [ - Forms\Components\TextInput::make('allocation_ip') - ->datalist(Node::find($get('node_id'))?->ipAddresses() ?? []) - ->label('IP Address') - ->inlineLabel() - ->ipv4() - ->helperText("Usually your machine's public IP unless you are port forwarding.") - // ->selectablePlaceholder(false) - ->required(), - Forms\Components\TextInput::make('allocation_alias') - ->label('Alias') - ->inlineLabel() - ->default(null) - ->datalist([ - $get('name'), - Egg::find($get('egg_id'))?->name, - ]) - ->helperText('Optional display name to help you remember what these are.') - ->required(false), - Forms\Components\TagsInput::make('allocation_ports') - ->placeholder('Examples: 27015, 27017-27019') - ->helperText(new HtmlString(' - These are the ports that users can connect to this Server through. -
- You would have to port forward these on your home network. - ')) - ->label('Ports') - ->inlineLabel() - ->live() - ->afterStateUpdated(function ($state, Forms\Set $set) { - $ports = collect(); - $update = false; - foreach ($state as $portEntry) { - if (!str_contains($portEntry, '-')) { - if (is_numeric($portEntry)) { - $ports->push((int) $portEntry); - - continue; - } - - // Do not add non-numerical ports - $update = true; - - continue; - } - - $update = true; - [$start, $end] = explode('-', $portEntry); - if (!is_numeric($start) || !is_numeric($end)) { - continue; - } - - $start = max((int) $start, 0); - $end = min((int) $end, 2 ** 16 - 1); - for ($i = $start; $i <= $end; $i++) { - $ports->push($i); - } - } - - $uniquePorts = $ports->unique()->values(); - if ($ports->count() > $uniquePorts->count()) { - $update = true; - $ports = $uniquePorts; - } - - $sortedPorts = $ports->sort()->values(); - if ($sortedPorts->all() !== $ports->all()) { - $update = true; - $ports = $sortedPorts; - } - - $ports = $ports->filter(fn ($port) => $port > 1024 && $port < 65535)->values(); - - if ($update) { - $set('allocation_ports', $ports->all()); - } - }) - ->splitKeys(['Tab', ' ', ',']) - ->required(), - ]) - ->createOptionUsing(function (array $data, Forms\Get $get): int { - return collect( - resolve(AssignmentService::class)->handle(Node::find($get('node_id')), $data) - )->first(); - }) - ->required(), - - Forms\Components\Repeater::make('allocation_additional') - ->label('Additional Allocations') - ->columnSpan([ - 'default' => 1, - 'sm' => 2, - 'md' => 1, - 'lg' => 2, - ]) - ->addActionLabel('Add Allocation') - ->disabled(fn (Forms\Get $get) => $get('allocation_id') === null) - // ->addable() TODO disable when all allocations are taken - // ->addable() TODO disable until first additional allocation is selected - ->simple( - Forms\Components\Select::make('extra_allocations') - ->live() - ->preload() - ->disableOptionsWhenSelectedInSiblingRepeaterItems() - ->prefixIcon('tabler-network') - ->label('Additional Allocations') - ->columnSpan(2) - ->disabled(fn (Forms\Get $get) => $get('../../node_id') === null) - ->searchable(['ip', 'port', 'ip_alias']) - ->getOptionLabelFromRecordUsing( - fn (Allocation $allocation) => "$allocation->ip:$allocation->port" . - ($allocation->ip_alias ? " ($allocation->ip_alias)" : '') - ) - ->placeholder('Select additional Allocations') - ->disableOptionsWhenSelectedInSiblingRepeaterItems() - ->relationship( - 'allocations', - 'ip', - fn (Builder $query, Forms\Get $get, Forms\Components\Select $component, $state) => $query - ->where('node_id', $get('../../node_id')) - ->whereNot('id', $get('../../allocation_id')) - ->whereNull('server_id'), - ), - ), - Forms\Components\TextInput::make('description') ->placeholder('Description') ->columnSpan([ 'default' => 1, 'sm' => 2, 'md' => 2, - 'lg' => 6, + 'lg' => 3, ]) ->label('Notes'), ]), @@ -285,42 +122,30 @@ public function form(Form $form): Form 'lg' => 4, ]) ->schema([ + Forms\Components\Select::make('egg_id') + ->disabledOn('edit') ->prefixIcon('tabler-egg') - ->relationship('egg', 'name') ->columnSpan([ - 'default' => 1, + 'default' => 2, 'sm' => 2, 'md' => 2, 'lg' => 3, ]) + ->relationship('egg', 'name') ->searchable() ->preload() ->live() ->afterStateUpdated(function ($state, Forms\Set $set, Forms\Get $get, $old) { - $egg = Egg::query()->find($state); - $set('startup', $egg->startup); + $this->egg = Egg::query()->find($state); + $set('startup', $this->egg?->startup); $set('image', ''); - $variables = $egg->variables ?? []; - $serverVariables = collect(); - foreach ($variables as $variable) { - $serverVariables->add($variable->toArray()); - } - - $variables = []; - $set($path = 'server_variables', $serverVariables->sortBy(['sort'])->all()); - for ($i = 0; $i < $serverVariables->count(); $i++) { - $set("$path.$i.variable_value", $serverVariables[$i]['default_value']); - $set("$path.$i.variable_id", $serverVariables[$i]['id']); - $variables[$serverVariables[$i]['env_variable']] = $serverVariables[$i]['default_value']; - } - - $set('environment', $variables); + $this->resetEggVariables($set, $get); $previousEgg = Egg::query()->find($old); if (!$get('name') || $previousEgg?->getKebabName() === $get('name')) { - $set('name', $egg->getKebabName()); + $set('name', $this->egg->getKebabName()); } }) ->required(), @@ -349,12 +174,52 @@ public function form(Form $form): Form ->inline() ->required(), + Forms\Components\TagsInput::make('ports') + ->columnSpan(2) + ->placeholder('Example: 25565, 8080, 1337-1340') + ->splitKeys(['Tab', ' ', ',']) + ->hidden(fn () => !$this->egg) + ->helperText(new HtmlString(' + These are the ports that users can connect to this Server through. +
+ You would typically port forward these on your home network. + ')) + ->label('Ports') + ->afterStateUpdated(self::ports(...)) + ->live(), + + Forms\Components\Repeater::make('assignments') + ->columnSpan(2) + ->defaultItems(fn () => count($this->eggDefaultPorts)) + ->label('Port Assignments') + ->helperText(fn (Forms\Get $get) => empty($get('ports')) ? 'You must add ports to assign them!' : '') + ->live() + ->addable(false) + ->deletable(false) + ->reorderable(false) + ->hidden(fn () => !$this->egg) + ->simple( + Forms\Components\Select::make('port') + ->live() + ->disabled(fn (Forms\Get $get) => empty($get('../../ports')) || empty($get('../../assignments'))) + ->prefix(function (Forms\Components\Component $component) { + $key = str($component->getStatePath())->beforeLast('.')->afterLast('.')->toString(); + + return $key; + }) + ->disableOptionsWhenSelectedInSiblingRepeaterItems() + ->options(fn (Forms\Get $get) => $this->ports) + ->required(), + ), + Forms\Components\Textarea::make('startup') + ->hidden(fn () => !$this->egg) ->hintIcon('tabler-code') ->label('Startup Command') - ->hidden(fn (Forms\Get $get) => $get('egg_id') === null) ->required() ->live() + ->disabled(fn (Forms\Get $get) => $this->egg === null) + ->afterStateUpdated($this->resetEggVariables(...)) ->columnSpan([ 'default' => 1, 'sm' => 2, @@ -364,7 +229,7 @@ public function form(Form $form): Form ->rows(function ($state) { return str($state)->explode("\n")->reduce( fn (int $carry, $line) => $carry + floor(strlen($line) / 125), - 1 + 0 ); }), @@ -446,6 +311,7 @@ public function form(Form $form): Form ->columnSpan(2), ]), ]), + Wizard\Step::make('Environment Configuration') ->label('Environment Configuration') ->icon('tabler-brand-docker') @@ -754,12 +620,14 @@ protected function getFormActions(): array protected function handleRecordCreation(array $data): Model { - $data['allocation_additional'] = collect($data['allocation_additional'])->filter()->all(); + foreach (array_keys($this->eggDefaultPorts) as $i => $env) { + $data['environment'][$env] = $data['ports'][$data['assignments'][$i]]; + } /** @var ServerCreationService $service */ $service = resolve(ServerCreationService::class); - return $service->handle($data); + return $service->handle($data, validateVariables: false); } private function shouldHideComponent(Forms\Get $get, Forms\Components\Component $component): bool @@ -792,4 +660,82 @@ private function getSelectOptionsFromRules(Forms\Get $get): array ->mapWithKeys(fn ($value) => [$value => $value]) ->all(); } + + public function ports($state, Forms\Set $set) + { + $ports = collect(); + $update = false; + foreach ($state as $portEntry) { + if (!str_contains($portEntry, '-')) { + if (is_numeric($portEntry)) { + $ports->push((int) $portEntry); + + continue; + } + + continue; + } + + [$start, $end] = explode('-', $portEntry); + if (!is_numeric($start) || !is_numeric($end)) { + continue; + } + + $start = max((int) $start, 0); + $end = min((int) $end, 2 ** 16 - 1); + for ($i = $start; $i <= $end; $i++) { + $ports->push($i); + } + } + + $uniquePorts = $ports->unique()->values(); + if ($ports->count() > $uniquePorts->count()) { + $ports = $uniquePorts; + } + + $ports = $ports->filter(fn ($port) => $port > 1024 && $port < 65535)->values(); + + $set('ports', $ports->all()); + $this->ports = $ports->all(); + } + + public function resetEggVariables(Forms\Set $set, Forms\Get $get) + { + $set('assignments', []); + + $i = 0; + $this->eggDefaultPorts = []; + if (str_contains($get('startup'), '{{SERVER_PORT}}')) { + $this->eggDefaultPorts['SERVER_PORT'] = null; + $set('assignments.SERVER_PORT', ['port' => null]); + } + + $variables = $this->egg->variables ?? []; + $serverVariables = collect(); + $this->ports = []; + foreach ($variables as $variable) { + if (str_contains($variable->rules, 'port')) { + $this->eggDefaultPorts[$variable->env_variable] = $variable->default_value; + $this->ports[] = (int) $variable->default_value; + + $set("assignments.$i", ['port' => $i++]); + + continue; + } + + $serverVariables->add($variable->toArray()); + } + + $set('ports', $this->ports); + + $variables = []; + $set($path = 'server_variables', $serverVariables->sortBy(['sort'])->all()); + for ($i = 0; $i < $serverVariables->count(); $i++) { + $set("$path.$i.variable_value", $serverVariables[$i]['default_value']); + $set("$path.$i.variable_id", $serverVariables[$i]['id']); + $variables[$serverVariables[$i]['env_variable']] = $serverVariables[$i]['default_value']; + } + + $set('environment', $variables); + } } diff --git a/app/Filament/Resources/ServerResource/Pages/ListServers.php b/app/Filament/Resources/ServerResource/Pages/ListServers.php index 0f150144dc..4a7c0725e9 100644 --- a/app/Filament/Resources/ServerResource/Pages/ListServers.php +++ b/app/Filament/Resources/ServerResource/Pages/ListServers.php @@ -68,13 +68,7 @@ public function table(Table $table): Table ->label('Owner') ->url(fn (Server $server): string => route('filament.admin.resources.users.edit', ['record' => $server->user])) ->sortable(), - Tables\Columns\SelectColumn::make('allocation_id') - ->label('Primary Allocation') - ->options(fn ($state, Server $server) => $server->allocations->mapWithKeys( - fn ($allocation) => [$allocation->id => $allocation->address]) - ) - ->selectablePlaceholder(false) - ->sortable(), + Tables\Columns\TextColumn::make('ports'), Tables\Columns\TextColumn::make('image')->hidden(), Tables\Columns\TextColumn::make('backups_count') ->counts('backups') From 510ae3c0df4fb4683d6e5c23417c21577b928716 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Mon, 10 Jun 2024 21:38:28 -0400 Subject: [PATCH 023/103] Swap this for now --- app/Filament/Resources/ServerResource/Pages/CreateServer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index b0e61dc32f..c1427810ad 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -718,7 +718,7 @@ public function resetEggVariables(Forms\Set $set, Forms\Get $get) $this->eggDefaultPorts[$variable->env_variable] = $variable->default_value; $this->ports[] = (int) $variable->default_value; - $set("assignments.$i", ['port' => $i++]); + $set("assignments.$variable->env_variable", ['port' => $i++]); continue; } From 36e2fa8e2b2dbe19a3ce2b45326883f773d67ea1 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Tue, 11 Jun 2024 16:58:50 -0400 Subject: [PATCH 024/103] Wip --- .../ServerUsingAllocationException.php | 9 - .../Resources/EggResource/Pages/CreateEgg.php | 2 +- .../Resources/EggResource/Pages/EditEgg.php | 2 +- .../ServersRelationManager.php | 5 - .../RelationManagers/NodesRelationManager.php | 5 - .../ServersRelationManager.php | 5 - .../Admin/Nodes/NodeViewController.php | 27 -- .../Controllers/Admin/NodesController.php | 97 ----- .../Admin/Servers/CreateServerController.php | 5 - .../Servers/ServerTransferController.php | 2 - .../Admin/Servers/ServerViewController.php | 4 - .../Nodes/AllocationController.php | 79 ---- .../Servers/ServerManagementController.php | 2 - .../Servers/NetworkAllocationController.php | 137 ------- .../Servers/ServerDetailsController.php | 2 +- .../Servers/ServerTransferController.php | 10 - .../Client/Server/ResourceBelongsToServer.php | 2 - .../Admin/Node/AllocationAliasFormRequest.php | 16 - .../Admin/Node/AllocationFormRequest.php | 17 - app/Http/Requests/Admin/ServerFormRequest.php | 27 +- .../Allocations/DeleteAllocationRequest.php | 13 - .../Allocations/GetAllocationsRequest.php | 13 - .../Allocations/StoreAllocationRequest.php | 34 -- .../Servers/StoreServerRequest.php | 26 +- .../UpdateServerBuildConfigurationRequest.php | 2 - .../Network/DeleteAllocationRequest.php | 14 - .../Servers/Network/GetNetworkRequest.php | 18 - .../Servers/Network/NewAllocationRequest.php | 14 - .../Network/SetPrimaryAllocationRequest.php | 11 - .../Network/UpdateAllocationRequest.php | 24 -- app/Models/Allocation.php | 100 ----- app/Models/Filters/MultiFieldServerFilter.php | 21 - app/Models/Node.php | 30 -- app/Models/Objects/Endpoint.php | 39 ++ app/Models/Server.php | 43 +- app/Providers/AppServiceProvider.php | 1 - app/Rules/Port.php | 6 +- .../Allocations/AssignmentService.php | 115 ------ .../FindAssignableAllocationService.php | 70 +--- .../Deployment/AllocationSelectionService.php | 150 ------- .../Servers/BuildModificationService.php | 67 +--- .../ServerConfigurationStructureService.php | 2 +- .../Servers/ServerCreationService.php | 66 +-- .../Servers/TransferServerService.php | 41 +- .../Servers/VariableValidatorService.php | 10 +- .../Api/Application/AllocationTransformer.php | 77 ---- .../Api/Application/NodeTransformer.php | 22 +- .../Api/Application/ServerTransformer.php | 34 +- .../Api/Client/AllocationTransformer.php | 28 -- .../Api/Client/ServerTransformer.php | 30 +- database/Factories/AllocationFactory.php | 36 -- .../2024_06_06_043350_modify_allocations.php | 34 +- resources/views/admin/servers/new.blade.php | 375 ------------------ .../views/admin/servers/view/manage.blade.php | 194 --------- routes/admin.php | 7 - routes/api-application.php | 7 - routes/api-client.php | 8 - .../Client/ClientApiIntegrationTestCase.php | 5 - .../Api/Client/ClientControllerTest.php | 53 --- .../AllocationAuthorizationTest.php | 57 --- .../Allocation/CreateNewAllocationTest.php | 93 ----- .../Allocation/DeleteAllocationTest.php | 105 ----- .../NetworkAllocationControllerTest.php | 140 ------- .../FindAssignableAllocationServiceTest.php | 174 -------- .../Servers/BuildModificationServiceTest.php | 157 -------- .../Servers/ServerCreationServiceTest.php | 27 +- .../Traits/Integration/CreatesTestModels.php | 11 +- 67 files changed, 143 insertions(+), 2916 deletions(-) delete mode 100644 app/Exceptions/Service/Allocation/ServerUsingAllocationException.php delete mode 100644 app/Http/Controllers/Api/Application/Nodes/AllocationController.php delete mode 100644 app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php delete mode 100644 app/Http/Requests/Admin/Node/AllocationAliasFormRequest.php delete mode 100644 app/Http/Requests/Admin/Node/AllocationFormRequest.php delete mode 100644 app/Http/Requests/Api/Application/Allocations/DeleteAllocationRequest.php delete mode 100644 app/Http/Requests/Api/Application/Allocations/GetAllocationsRequest.php delete mode 100644 app/Http/Requests/Api/Application/Allocations/StoreAllocationRequest.php delete mode 100644 app/Http/Requests/Api/Client/Servers/Network/DeleteAllocationRequest.php delete mode 100644 app/Http/Requests/Api/Client/Servers/Network/GetNetworkRequest.php delete mode 100644 app/Http/Requests/Api/Client/Servers/Network/NewAllocationRequest.php delete mode 100644 app/Http/Requests/Api/Client/Servers/Network/SetPrimaryAllocationRequest.php delete mode 100644 app/Http/Requests/Api/Client/Servers/Network/UpdateAllocationRequest.php delete mode 100644 app/Models/Allocation.php create mode 100644 app/Models/Objects/Endpoint.php delete mode 100644 app/Services/Allocations/AssignmentService.php delete mode 100644 app/Services/Deployment/AllocationSelectionService.php delete mode 100644 app/Transformers/Api/Application/AllocationTransformer.php delete mode 100644 app/Transformers/Api/Client/AllocationTransformer.php delete mode 100644 database/Factories/AllocationFactory.php delete mode 100644 resources/views/admin/servers/new.blade.php delete mode 100644 resources/views/admin/servers/view/manage.blade.php delete mode 100644 tests/Integration/Api/Client/Server/Allocation/AllocationAuthorizationTest.php delete mode 100644 tests/Integration/Api/Client/Server/Allocation/CreateNewAllocationTest.php delete mode 100644 tests/Integration/Api/Client/Server/Allocation/DeleteAllocationTest.php delete mode 100644 tests/Integration/Api/Client/Server/NetworkAllocationControllerTest.php delete mode 100644 tests/Integration/Services/Allocations/FindAssignableAllocationServiceTest.php diff --git a/app/Exceptions/Service/Allocation/ServerUsingAllocationException.php b/app/Exceptions/Service/Allocation/ServerUsingAllocationException.php deleted file mode 100644 index 60fac561e0..0000000000 --- a/app/Exceptions/Service/Allocation/ServerUsingAllocationException.php +++ /dev/null @@ -1,9 +0,0 @@ -columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]), Forms\Components\Toggle::make('force_outgoing_ip') ->hintIcon('tabler-question-mark') - ->hintIconTooltip("Forces all outgoing network traffic to have its Source IP NATed to the IP of the server's primary allocation IP. + ->hintIconTooltip("Forces all outgoing network traffic to have its Source IP NATed to the IP of the server's primary endpoint. Required for certain games to work properly when the Node has multiple public IP addresses. Enabling this option will disable internal networking for any servers using this egg, causing them to be unable to internally access other servers on the same node."), Forms\Components\Hidden::make('script_is_privileged') diff --git a/app/Filament/Resources/EggResource/Pages/EditEgg.php b/app/Filament/Resources/EggResource/Pages/EditEgg.php index f0ff69ce18..dd33919c54 100644 --- a/app/Filament/Resources/EggResource/Pages/EditEgg.php +++ b/app/Filament/Resources/EggResource/Pages/EditEgg.php @@ -62,7 +62,7 @@ public function form(Form $form): Form ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]), Forms\Components\Toggle::make('force_outgoing_ip') ->hintIcon('tabler-question-mark') - ->hintIconTooltip("Forces all outgoing network traffic to have its Source IP NATed to the IP of the server's primary allocation IP. + ->hintIconTooltip("Forces all outgoing network traffic to have its Source IP NATed to the IP of the server's endpoint. Required for certain games to work properly when the Node has multiple public IP addresses. Enabling this option will disable internal networking for any servers using this egg, causing them to be unable to internally access other servers on the same node."), Forms\Components\Hidden::make('script_is_privileged') diff --git a/app/Filament/Resources/EggResource/RelationManagers/ServersRelationManager.php b/app/Filament/Resources/EggResource/RelationManagers/ServersRelationManager.php index 3e72e42368..5f94523a0e 100644 --- a/app/Filament/Resources/EggResource/RelationManagers/ServersRelationManager.php +++ b/app/Filament/Resources/EggResource/RelationManagers/ServersRelationManager.php @@ -32,11 +32,6 @@ public function table(Table $table): Table ->url(fn (Server $server): string => route('filament.admin.resources.nodes.edit', ['record' => $server->node])), Tables\Columns\TextColumn::make('image') ->label('Docker Image'), - Tables\Columns\SelectColumn::make('allocation.id') - ->label('Primary Allocation') - ->options(fn ($state, Server $server) => [$server->allocation->id => $server->allocation->address]) - ->selectablePlaceholder(false) - ->sortable(), ]); } } diff --git a/app/Filament/Resources/NodeResource/RelationManagers/NodesRelationManager.php b/app/Filament/Resources/NodeResource/RelationManagers/NodesRelationManager.php index b9775b4c20..8fe609428a 100644 --- a/app/Filament/Resources/NodeResource/RelationManagers/NodesRelationManager.php +++ b/app/Filament/Resources/NodeResource/RelationManagers/NodesRelationManager.php @@ -32,11 +32,6 @@ public function table(Table $table): Table ->icon('tabler-egg') ->url(fn (Server $server): string => route('filament.admin.resources.eggs.edit', ['record' => $server->user])) ->sortable(), - Tables\Columns\SelectColumn::make('allocation.id') - ->label('Primary Allocation') - ->options(fn ($state, Server $server) => [$server->allocation->id => $server->allocation->address]) - ->selectablePlaceholder(false) - ->sortable(), Tables\Columns\TextColumn::make('memory')->icon('tabler-device-desktop-analytics'), Tables\Columns\TextColumn::make('cpu')->icon('tabler-cpu'), Tables\Columns\TextColumn::make('databases_count') diff --git a/app/Filament/Resources/UserResource/RelationManagers/ServersRelationManager.php b/app/Filament/Resources/UserResource/RelationManagers/ServersRelationManager.php index 7be484b60f..705eb92aff 100644 --- a/app/Filament/Resources/UserResource/RelationManagers/ServersRelationManager.php +++ b/app/Filament/Resources/UserResource/RelationManagers/ServersRelationManager.php @@ -66,11 +66,6 @@ public function table(Table $table): Table ->icon('tabler-egg') ->url(fn (Server $server): string => route('filament.admin.resources.eggs.edit', ['record' => $server->egg])) ->sortable(), - Tables\Columns\SelectColumn::make('allocation.id') - ->label('Primary Allocation') - ->options(fn ($state, Server $server) => [$server->allocation->id => $server->allocation->address]) - ->selectablePlaceholder(false) - ->sortable(), Tables\Columns\TextColumn::make('image')->hidden(), Tables\Columns\TextColumn::make('databases_count') ->counts('databases') diff --git a/app/Http/Controllers/Admin/Nodes/NodeViewController.php b/app/Http/Controllers/Admin/Nodes/NodeViewController.php index 95dc7ede0a..b3e9f26218 100644 --- a/app/Http/Controllers/Admin/Nodes/NodeViewController.php +++ b/app/Http/Controllers/Admin/Nodes/NodeViewController.php @@ -5,7 +5,6 @@ use Illuminate\View\View; use App\Models\Node; use Illuminate\Support\Collection; -use App\Models\Allocation; use App\Http\Controllers\Controller; use App\Traits\Controllers\JavascriptInjection; use App\Services\Helpers\SoftwareVersionService; @@ -56,32 +55,6 @@ public function configuration(Node $node): View return view('admin.nodes.view.configuration', compact('node')); } - /** - * Return the node allocation management page. - */ - public function allocations(Node $node): View - { - $node->setRelation( - 'allocations', - $node->allocations() - ->orderByRaw('server_id IS NOT NULL DESC, server_id IS NULL') - ->orderByRaw('INET_ATON(ip) ASC') - ->orderBy('port') - ->with('server:id,name') - ->paginate(50) - ); - - $this->plainInject(['node' => Collection::wrap($node)->only(['id'])]); - - return view('admin.nodes.view.allocation', [ - 'node' => $node, - 'allocations' => Allocation::query()->where('node_id', $node->id) - ->groupBy('ip') - ->orderByRaw('INET_ATON(ip) ASC') - ->get(['ip']), - ]); - } - /** * Return a listing of servers that exist for this specific node. */ diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index 66ba487f6d..ebb1f56c3d 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -3,10 +3,7 @@ namespace App\Http\Controllers\Admin; use Illuminate\View\View; -use Illuminate\Http\Request; use App\Models\Node; -use Illuminate\Http\Response; -use App\Models\Allocation; use Illuminate\Http\RedirectResponse; use Prologue\Alerts\AlertsMessageBag; use Illuminate\View\Factory as ViewFactory; @@ -15,11 +12,8 @@ use Illuminate\Cache\Repository as CacheRepository; use App\Services\Nodes\NodeCreationService; use App\Services\Nodes\NodeDeletionService; -use App\Services\Allocations\AssignmentService; use App\Services\Helpers\SoftwareVersionService; use App\Http\Requests\Admin\Node\NodeFormRequest; -use App\Http\Requests\Admin\Node\AllocationFormRequest; -use App\Http\Requests\Admin\Node\AllocationAliasFormRequest; class NodesController extends Controller { @@ -28,7 +22,6 @@ class NodesController extends Controller */ public function __construct( protected AlertsMessageBag $alert, - protected AssignmentService $assignmentService, protected CacheRepository $cache, protected NodeCreationService $creationService, protected NodeDeletionService $deletionService, @@ -46,19 +39,6 @@ public function create(): View|RedirectResponse return view('admin.nodes.new'); } - /** - * Post controller to create a new node on the system. - * - * @throws \App\Exceptions\Model\DataValidationException - */ - public function store(NodeFormRequest $request): RedirectResponse - { - $node = $this->creationService->handle($request->normalize()); - $this->alert->info(trans('admin/node.notices.node_created'))->flash(); - - return redirect()->route('admin.nodes.view.allocation', $node->id); - } - /** * Updates settings for a node. * @@ -73,83 +53,6 @@ public function updateSettings(NodeFormRequest $request, Node $node): RedirectRe return redirect()->route('admin.nodes.view.settings', $node->id)->withInput(); } - /** - * Removes a single allocation from a node. - * - * @throws \App\Exceptions\Service\Allocation\ServerUsingAllocationException - */ - public function allocationRemoveSingle(int $node, Allocation $allocation): Response - { - $allocation->delete(); - - return response('', 204); - } - - /** - * Removes multiple individual allocations from a node. - * - * @throws \App\Exceptions\Service\Allocation\ServerUsingAllocationException - */ - public function allocationRemoveMultiple(Request $request, int $node): Response - { - $allocations = $request->input('allocations'); - foreach ($allocations as $rawAllocation) { - $allocation = new Allocation(); - $allocation->id = $rawAllocation['id']; - $this->allocationRemoveSingle($node, $allocation); - } - - return response('', 204); - } - - /** - * Remove all allocations for a specific IP at once on a node. - */ - public function allocationRemoveBlock(Request $request, int $node): RedirectResponse - { - /** @var Node $node */ - $node = Node::query()->findOrFail($node); - $node->allocations() - ->where('ip', $request->input('ip')) - ->whereNull('server_id') - ->delete(); - - $this->alert->success(trans('admin/node.notices.unallocated_deleted', ['ip' => $request->input('ip')])) - ->flash(); - - return redirect()->route('admin.nodes.view.allocation', $node); - } - - /** - * Sets an alias for a specific allocation on a node. - * - * @throws \App\Exceptions\Model\DataValidationException - */ - public function allocationSetAlias(AllocationAliasFormRequest $request): \Symfony\Component\HttpFoundation\Response - { - $allocation = Allocation::query()->findOrFail($request->input('allocation_id')); - $alias = (empty($request->input('alias'))) ? null : $request->input('alias'); - $allocation->update(['ip_alias' => $alias]); - - return response('', 204); - } - - /** - * Creates new allocations on a node. - * - * @throws \App\Exceptions\Service\Allocation\CidrOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\InvalidPortMappingException - * @throws \App\Exceptions\Service\Allocation\PortOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\TooManyPortsInRangeException - */ - public function createAllocation(AllocationFormRequest $request, Node $node): RedirectResponse - { - $this->assignmentService->handle($node, $request->normalize()); - $this->alert->success(trans('admin/node.notices.allocations_added'))->flash(); - - return redirect()->route('admin.nodes.view.allocation', $node->id); - } - /** * Deletes a node from the system. * diff --git a/app/Http/Controllers/Admin/Servers/CreateServerController.php b/app/Http/Controllers/Admin/Servers/CreateServerController.php index c59e22fbeb..c06ed6e5d0 100644 --- a/app/Http/Controllers/Admin/Servers/CreateServerController.php +++ b/app/Http/Controllers/Admin/Servers/CreateServerController.php @@ -36,11 +36,6 @@ public function index(): View|RedirectResponse $eggs = Egg::with('variables')->get(); - \JavaScript::put([ - 'nodeData' => Node::getForServerCreation(), - 'eggs' => $eggs->keyBy('id'), - ]); - return view('admin.servers.new', [ 'eggs' => $eggs, 'nodes' => Node::all(), diff --git a/app/Http/Controllers/Admin/Servers/ServerTransferController.php b/app/Http/Controllers/Admin/Servers/ServerTransferController.php index 9fdaa7bf8e..7421c3f827 100644 --- a/app/Http/Controllers/Admin/Servers/ServerTransferController.php +++ b/app/Http/Controllers/Admin/Servers/ServerTransferController.php @@ -29,8 +29,6 @@ public function transfer(Request $request, Server $server): RedirectResponse { $validatedData = $request->validate([ 'node_id' => 'required|exists:nodes,id', - 'allocation_id' => 'required|bail|unique:servers|exists:allocations,id', - 'allocation_additional' => 'nullable', ]); if ($this->transferServerService->handle($server, $validatedData)) { diff --git a/app/Http/Controllers/Admin/Servers/ServerViewController.php b/app/Http/Controllers/Admin/Servers/ServerViewController.php index 594022a978..43e1a2ae82 100644 --- a/app/Http/Controllers/Admin/Servers/ServerViewController.php +++ b/app/Http/Controllers/Admin/Servers/ServerViewController.php @@ -121,10 +121,6 @@ public function manage(Server $server): View $canTransfer = true; } - \JavaScript::put([ - 'nodeData' => Node::getForServerCreation(), - ]); - return view('admin.servers.view.manage', [ 'nodes' => Node::all(), 'server' => $server, diff --git a/app/Http/Controllers/Api/Application/Nodes/AllocationController.php b/app/Http/Controllers/Api/Application/Nodes/AllocationController.php deleted file mode 100644 index 18e2f5cfce..0000000000 --- a/app/Http/Controllers/Api/Application/Nodes/AllocationController.php +++ /dev/null @@ -1,79 +0,0 @@ -allocations()) - ->allowedFilters([ - AllowedFilter::exact('ip'), - AllowedFilter::exact('port'), - 'ip_alias', - AllowedFilter::callback('server_id', function (Builder $builder, $value) { - if (empty($value) || is_bool($value) || !ctype_digit((string) $value)) { - return $builder->whereNull('server_id'); - } - - return $builder->where('server_id', $value); - }), - ]) - ->paginate($request->query('per_page') ?? 50); - - return $this->fractal->collection($allocations) - ->transformWith($this->getTransformer(AllocationTransformer::class)) - ->toArray(); - } - - /** - * Store new allocations for a given node. - * - * @throws \App\Exceptions\DisplayException - * @throws \App\Exceptions\Service\Allocation\CidrOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\InvalidPortMappingException - * @throws \App\Exceptions\Service\Allocation\PortOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\TooManyPortsInRangeException - */ - public function store(StoreAllocationRequest $request, Node $node): JsonResponse - { - $this->assignmentService->handle($node, $request->validated()); - - return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT); - } - - /** - * Delete a specific allocation from the Panel. - */ - public function delete(DeleteAllocationRequest $request, Node $node, Allocation $allocation): JsonResponse - { - $allocation->delete(); - - return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT); - } -} diff --git a/app/Http/Controllers/Api/Application/Servers/ServerManagementController.php b/app/Http/Controllers/Api/Application/Servers/ServerManagementController.php index d728ea83cd..dcb6ad795f 100644 --- a/app/Http/Controllers/Api/Application/Servers/ServerManagementController.php +++ b/app/Http/Controllers/Api/Application/Servers/ServerManagementController.php @@ -69,8 +69,6 @@ public function startTransfer(ServerWriteRequest $request, Server $server): Resp { $validatedData = $request->validate([ 'node_id' => 'required|exists:nodes,id', - 'allocation_id' => 'required|bail|unique:servers|exists:allocations,id', - 'allocation_additional' => 'nullable', ]); if ($this->transferServerService->handle($server, $validatedData)) { diff --git a/app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php b/app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php deleted file mode 100644 index 948fbbaced..0000000000 --- a/app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php +++ /dev/null @@ -1,137 +0,0 @@ -fractal->collection($server->allocations) - ->transformWith($this->getTransformer(AllocationTransformer::class)) - ->toArray(); - } - - /** - * Set the primary allocation for a server. - * - * @throws \App\Exceptions\Model\DataValidationException - */ - public function update(UpdateAllocationRequest $request, Server $server, Allocation $allocation): array - { - $original = $allocation->notes; - - $allocation->forceFill(['notes' => $request->input('notes')])->save(); - - if ($original !== $allocation->notes) { - Activity::event('server:allocation.notes') - ->subject($allocation) - ->property(['allocation' => $allocation->toString(), 'old' => $original, 'new' => $allocation->notes]) - ->log(); - } - - return $this->fractal->item($allocation) - ->transformWith($this->getTransformer(AllocationTransformer::class)) - ->toArray(); - } - - /** - * Set the primary allocation for a server. - * - * @throws \App\Exceptions\Model\DataValidationException - */ - public function setPrimary(SetPrimaryAllocationRequest $request, Server $server, Allocation $allocation): array - { - $server->allocation()->associate($allocation); - $server->save(); - - Activity::event('server:allocation.primary') - ->subject($allocation) - ->property('allocation', $allocation->toString()) - ->log(); - - return $this->fractal->item($allocation) - ->transformWith($this->getTransformer(AllocationTransformer::class)) - ->toArray(); - } - - /** - * Set the notes for the allocation for a server. - *s. - * - * @throws \App\Exceptions\DisplayException - */ - public function store(NewAllocationRequest $request, Server $server): array - { - if ($server->allocations()->count() >= $server->allocation_limit) { - throw new DisplayException('Cannot assign additional allocations to this server: limit has been reached.'); - } - - $allocation = $this->assignableAllocationService->handle($server); - - Activity::event('server:allocation.create') - ->subject($allocation) - ->property('allocation', $allocation->toString()) - ->log(); - - return $this->fractal->item($allocation) - ->transformWith($this->getTransformer(AllocationTransformer::class)) - ->toArray(); - } - - /** - * Delete an allocation from a server. - * - * @throws \App\Exceptions\DisplayException - */ - public function delete(DeleteAllocationRequest $request, Server $server, Allocation $allocation): JsonResponse - { - // Don't allow the deletion of allocations if the server does not have an - // allocation limit set. - if (empty($server->allocation_limit)) { - throw new DisplayException('You cannot delete allocations for this server: no allocation limit is set.'); - } - - if ($allocation->id === $server->allocation_id) { - throw new DisplayException('You cannot delete the primary allocation for this server.'); - } - - Allocation::query()->where('id', $allocation->id)->update([ - 'notes' => null, - 'server_id' => null, - ]); - - Activity::event('server:allocation.delete') - ->subject($allocation) - ->property('allocation', $allocation->toString()) - ->log(); - - return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT); - } -} diff --git a/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php b/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php index 8244530453..88ad0ed91c 100644 --- a/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php +++ b/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php @@ -48,7 +48,7 @@ public function list(Request $request): ServerConfigurationCollection // Avoid run-away N+1 SQL queries by preloading the relationships that are used // within each of the services called below. - $servers = Server::query()->with('allocations', 'egg', 'mounts', 'variables') + $servers = Server::query()->with('egg', 'mounts', 'variables') ->where('node_id', $node->id) // If you don't cast this to a string you'll end up with a stringified per_page returned in // the metadata, and then daemon will panic crash as a result. diff --git a/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php b/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php index 6a74521f94..95026b5d75 100644 --- a/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php +++ b/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php @@ -6,7 +6,6 @@ use App\Repositories\Daemon\DaemonServerRepository; use Illuminate\Http\Response; use Illuminate\Http\JsonResponse; -use App\Models\Allocation; use App\Models\ServerTransfer; use Illuminate\Database\ConnectionInterface; use App\Http\Controllers\Controller; @@ -53,13 +52,7 @@ public function success(Server $server): JsonResponse /** @var \App\Models\Server $server */ $server = $this->connection->transaction(function () use ($server, $transfer) { - $allocations = array_merge([$transfer->old_allocation], $transfer->old_additional_allocations); - - // Remove the old allocations for the server and re-assign the server to the new - // primary allocation and node. - Allocation::query()->whereIn('id', $allocations)->update(['server_id' => null]); $server->update([ - 'allocation_id' => $transfer->new_allocation, 'node_id' => $transfer->new_node, ]); @@ -93,9 +86,6 @@ protected function processFailedTransfer(ServerTransfer $transfer): JsonResponse { $this->connection->transaction(function () use (&$transfer) { $transfer->forceFill(['successful' => false])->saveOrFail(); - - $allocations = array_merge([$transfer->new_allocation], $transfer->new_additional_allocations); - Allocation::query()->whereIn('id', $allocations)->update(['server_id' => null]); }); return new JsonResponse([], Response::HTTP_NO_CONTENT); diff --git a/app/Http/Middleware/Api/Client/Server/ResourceBelongsToServer.php b/app/Http/Middleware/Api/Client/Server/ResourceBelongsToServer.php index 0ead01f1d5..c6f9719920 100644 --- a/app/Http/Middleware/Api/Client/Server/ResourceBelongsToServer.php +++ b/app/Http/Middleware/Api/Client/Server/ResourceBelongsToServer.php @@ -10,7 +10,6 @@ use App\Models\Subuser; use App\Models\Database; use App\Models\Schedule; -use App\Models\Allocation; use Illuminate\Database\Eloquent\Model; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -48,7 +47,6 @@ public function handle(Request $request, \Closure $next): mixed switch (get_class($model)) { // All of these models use "server_id" as the field key for the server // they are assigned to, so the logic is identical for them all. - case Allocation::class: case Backup::class: case Database::class: case Schedule::class: diff --git a/app/Http/Requests/Admin/Node/AllocationAliasFormRequest.php b/app/Http/Requests/Admin/Node/AllocationAliasFormRequest.php deleted file mode 100644 index 3da9f1896e..0000000000 --- a/app/Http/Requests/Admin/Node/AllocationAliasFormRequest.php +++ /dev/null @@ -1,16 +0,0 @@ - 'present|nullable|string', - 'allocation_id' => 'required|numeric|exists:allocations,id', - ]; - } -} diff --git a/app/Http/Requests/Admin/Node/AllocationFormRequest.php b/app/Http/Requests/Admin/Node/AllocationFormRequest.php deleted file mode 100644 index 1bd39c4059..0000000000 --- a/app/Http/Requests/Admin/Node/AllocationFormRequest.php +++ /dev/null @@ -1,17 +0,0 @@ - 'required|string', - 'allocation_alias' => 'sometimes|nullable|string|max:191', - 'allocation_ports' => 'required|array', - ]; - } -} diff --git a/app/Http/Requests/Admin/ServerFormRequest.php b/app/Http/Requests/Admin/ServerFormRequest.php index d3f9781288..aa59317313 100644 --- a/app/Http/Requests/Admin/ServerFormRequest.php +++ b/app/Http/Requests/Admin/ServerFormRequest.php @@ -3,7 +3,6 @@ namespace App\Http\Requests\Admin; use App\Models\Server; -use Illuminate\Validation\Rule; use Illuminate\Validation\Validator; class ServerFormRequest extends AdminFormRequest @@ -25,34 +24,10 @@ public function rules(): array */ public function withValidator(Validator $validator): void { - $validator->after(function ($validator) { + $validator->after(function (Validator $validator) { $validator->sometimes('node_id', 'required|numeric|bail|exists:nodes,id', function ($input) { return !$input->auto_deploy; }); - - $validator->sometimes('allocation_id', [ - 'required', - 'numeric', - 'bail', - Rule::exists('allocations', 'id')->where(function ($query) { - $query->where('node_id', $this->input('node_id')); - $query->whereNull('server_id'); - }), - ], function ($input) { - return !$input->auto_deploy; - }); - - $validator->sometimes('allocation_additional.*', [ - 'sometimes', - 'required', - 'numeric', - Rule::exists('allocations', 'id')->where(function ($query) { - $query->where('node_id', $this->input('node_id')); - $query->whereNull('server_id'); - }), - ], function ($input) { - return !$input->auto_deploy; - }); }); } } diff --git a/app/Http/Requests/Api/Application/Allocations/DeleteAllocationRequest.php b/app/Http/Requests/Api/Application/Allocations/DeleteAllocationRequest.php deleted file mode 100644 index 74077965e5..0000000000 --- a/app/Http/Requests/Api/Application/Allocations/DeleteAllocationRequest.php +++ /dev/null @@ -1,13 +0,0 @@ - 'required|string', - 'alias' => 'sometimes|nullable|string|max:191', - 'ports' => 'required|array', - 'ports.*' => 'string', - ]; - } - - public function validated($key = null, $default = null): array - { - $data = parent::validated(); - - return [ - 'allocation_ip' => $data['ip'], - 'allocation_ports' => $data['ports'], - 'allocation_alias' => $data['alias'] ?? null, - ]; - } -} diff --git a/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php b/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php index 263b7c540e..de729ff123 100644 --- a/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php +++ b/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php @@ -3,7 +3,6 @@ namespace App\Http\Requests\Api\Application\Servers; use App\Models\Server; -use Illuminate\Validation\Rule; use Illuminate\Validation\Validator; use App\Services\Acl\Api\AdminAcl; use App\Models\Objects\DeploymentObject; @@ -49,10 +48,6 @@ public function rules(): array 'feature_limits.allocations' => $rules['allocation_limit'], 'feature_limits.backups' => $rules['backup_limit'], - // Placeholders for rules added in withValidator() function. - 'allocation.default' => '', - 'allocation.additional.*' => '', - // Automatic deployment rules 'deploy' => 'sometimes|required|array', 'deploy.locations' => 'array', @@ -87,8 +82,7 @@ public function validated($key = null, $default = null): array 'cpu' => array_get($data, 'limits.cpu'), 'threads' => array_get($data, 'limits.threads'), 'skip_scripts' => array_get($data, 'skip_scripts', false), - 'allocation_id' => array_get($data, 'allocation.default'), - 'allocation_additional' => array_get($data, 'allocation.additional'), + 'ports' => array_get($data, 'ports'), 'start_on_completion' => array_get($data, 'start_on_completion', false), 'database_limit' => array_get($data, 'feature_limits.databases'), 'allocation_limit' => array_get($data, 'feature_limits.allocations'), @@ -104,24 +98,6 @@ public function validated($key = null, $default = null): array */ public function withValidator(Validator $validator): void { - $validator->sometimes('allocation.default', [ - 'required', 'integer', 'bail', - Rule::exists('allocations', 'id')->where(function ($query) { - $query->whereNull('server_id'); - }), - ], function ($input) { - return !$input->deploy; - }); - - $validator->sometimes('allocation.additional.*', [ - 'integer', - Rule::exists('allocations', 'id')->where(function ($query) { - $query->whereNull('server_id'); - }), - ], function ($input) { - return !$input->deploy; - }); - /** @deprecated use tags instead */ $validator->sometimes('deploy.locations', 'present', function ($input) { return $input->deploy; diff --git a/app/Http/Requests/Api/Application/Servers/UpdateServerBuildConfigurationRequest.php b/app/Http/Requests/Api/Application/Servers/UpdateServerBuildConfigurationRequest.php index 7b0fcad10b..f30e4d049b 100644 --- a/app/Http/Requests/Api/Application/Servers/UpdateServerBuildConfigurationRequest.php +++ b/app/Http/Requests/Api/Application/Servers/UpdateServerBuildConfigurationRequest.php @@ -15,7 +15,6 @@ public function rules(): array $rules = Server::getRulesForUpdate($this->parameter('server', Server::class)); return [ - 'allocation' => $rules['allocation_id'], 'oom_killer' => $rules['oom_killer'], 'limits' => 'sometimes|array', @@ -54,7 +53,6 @@ public function validated($key = null, $default = null): array { $data = parent::validated(); - $data['allocation_id'] = $data['allocation']; $data['database_limit'] = $data['feature_limits']['databases'] ?? null; $data['allocation_limit'] = $data['feature_limits']['allocations'] ?? null; $data['backup_limit'] = $data['feature_limits']['backups'] ?? null; diff --git a/app/Http/Requests/Api/Client/Servers/Network/DeleteAllocationRequest.php b/app/Http/Requests/Api/Client/Servers/Network/DeleteAllocationRequest.php deleted file mode 100644 index a5d76472d6..0000000000 --- a/app/Http/Requests/Api/Client/Servers/Network/DeleteAllocationRequest.php +++ /dev/null @@ -1,14 +0,0 @@ - array_merge($rules['notes'], ['present']), - ]; - } -} diff --git a/app/Models/Allocation.php b/app/Models/Allocation.php deleted file mode 100644 index c58514b847..0000000000 --- a/app/Models/Allocation.php +++ /dev/null @@ -1,100 +0,0 @@ - 'required|exists:nodes,id', - 'ip' => 'required|ip', - 'port' => 'required|numeric|between:1024,65535', - 'ip_alias' => 'nullable|string', - 'server_id' => 'nullable|exists:servers,id', - 'notes' => 'nullable|string|max:256', - ]; - - protected static function booted(): void - { - static::deleting(function (self $allocation) { - throw_if($allocation->server_id, new ServerUsingAllocationException(trans('exceptions.allocations.server_using'))); - }); - } - - protected function casts(): array - { - return [ - 'node_id' => 'integer', - 'port' => 'integer', - 'server_id' => 'integer', - ]; - } - - public function getRouteKeyName(): string - { - return $this->getKeyName(); - } - - /** - * Accessor to automatically provide the IP alias if defined. - */ - public function getAliasAttribute(?string $value): string - { - return (is_null($this->ip_alias)) ? $this->ip : $this->ip_alias; - } - - /** - * Accessor to quickly determine if this allocation has an alias. - */ - public function getHasAliasAttribute(?string $value): bool - { - return !is_null($this->ip_alias); - } - - public function address(): Attribute - { - return Attribute::make( - get: fn () => "$this->ip:$this->port", - ); - } - - public function toString(): string - { - return $this->address; - } - - /** - * Gets information for the server associated with this allocation. - */ - public function server(): BelongsTo - { - return $this->belongsTo(Server::class); - } - - /** - * Return the Node model associated with this allocation. - */ - public function node(): BelongsTo - { - return $this->belongsTo(Node::class); - } -} diff --git a/app/Models/Filters/MultiFieldServerFilter.php b/app/Models/Filters/MultiFieldServerFilter.php index da3f91f6d5..92495af475 100644 --- a/app/Models/Filters/MultiFieldServerFilter.php +++ b/app/Models/Filters/MultiFieldServerFilter.php @@ -2,7 +2,6 @@ namespace App\Models\Filters; -use Illuminate\Support\Str; use Spatie\QueryBuilder\Filters\Filter; use Illuminate\Database\Eloquent\Builder; @@ -32,26 +31,6 @@ public function __invoke(Builder $query, $value, string $property) // Only select the server values, otherwise you'll end up merging the allocation and // server objects together, resulting in incorrect behavior and returned values. ->select('servers.*') - ->join('allocations', 'allocations.server_id', '=', 'servers.id') - ->where(function (Builder $builder) use ($value) { - $parts = explode(':', $value); - - $builder->when( - !Str::startsWith($value, ':'), - // When the string does not start with a ":" it means we're looking for an IP or IP:Port - // combo, so use a query to handle that. - function (Builder $builder) use ($parts) { - $builder->orWhere('allocations.ip', $parts[0]); - if (!is_null($parts[1] ?? null)) { - $builder->where('allocations.port', 'LIKE', "{$parts[1]}%"); - } - }, - // Otherwise, just try to search for that specific port in the allocations. - function (Builder $builder) use ($value) { - $builder->orWhere('allocations.port', 'LIKE', substr($value, 1) . '%'); - } - ); - }) ->groupBy('servers.id'); return; diff --git a/app/Models/Node.php b/app/Models/Node.php index d0b9bb5a1b..a933d16fee 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -201,14 +201,6 @@ public function servers(): HasMany return $this->hasMany(Server::class); } - /** - * Gets the allocations associated with a node. - */ - public function allocations(): HasMany - { - return $this->hasMany(Allocation::class); - } - /** * Returns a boolean if the node is viable for an additional server to be placed on it. */ @@ -238,28 +230,6 @@ public function isViable(int $memory, int $disk, int $cpu): bool return true; } - public static function getForServerCreation() - { - return self::with('allocations')->get()->map(function (Node $item) { - $filtered = $item->getRelation('allocations')->where('server_id', null)->map(function ($map) { - return collect($map)->only(['id', 'ip', 'port']); - }); - - $ports = $filtered->map(function ($map) { - return [ - 'id' => $map['id'], - 'text' => sprintf('%s:%s', $map['ip'], $map['port']), - ]; - })->values(); - - return [ - 'id' => $item->id, - 'text' => $item->name, - 'allocations' => $ports, - ]; - })->values(); - } - public function systemInformation(): array { return once(function () { diff --git a/app/Models/Objects/Endpoint.php b/app/Models/Objects/Endpoint.php new file mode 100644 index 0000000000..cc8de189dd --- /dev/null +++ b/app/Models/Objects/Endpoint.php @@ -0,0 +1,39 @@ +ip = $ip; + $this->port = $port; + } +} diff --git a/app/Models/Server.php b/app/Models/Server.php index 491b64b2b6..076c62ff79 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -41,11 +41,6 @@ class Server extends Model 'installed_at' => null, ]; - /** - * The default relationships to load for all server models. - */ - protected $with = ['allocation']; - /** * Fields that are not mass assignable. */ @@ -65,7 +60,6 @@ class Server extends Model 'threads' => 'nullable|regex:/^[0-9-,]+$/', 'oom_killer' => 'sometimes|boolean', 'disk' => 'required|numeric|min:0', - 'allocation_id' => 'required|bail|unique:servers|exists:allocations,id', 'egg_id' => 'required|exists:eggs,id', 'startup' => 'required|string', 'skip_scripts' => 'sometimes|boolean', @@ -73,6 +67,7 @@ class Server extends Model 'database_limit' => 'present|nullable|integer|min:0', 'allocation_limit' => 'sometimes|nullable|integer|min:0', 'backup_limit' => 'present|nullable|integer|min:0', + 'ports' => 'array', ]; protected function casts(): array @@ -88,27 +83,33 @@ protected function casts(): array 'io' => 'integer', 'cpu' => 'integer', 'oom_killer' => 'boolean', - 'allocation_id' => 'integer', 'egg_id' => 'integer', 'database_limit' => 'integer', 'allocation_limit' => 'integer', 'backup_limit' => 'integer', - self::CREATED_AT => 'datetime', - self::UPDATED_AT => 'datetime', 'deleted_at' => 'datetime', 'installed_at' => 'datetime', 'docker_labels' => 'array', + 'ports' => 'array', ]; } /** * Returns the format for server allocations when communicating with the Daemon. */ - public function getAllocationMappings(): array + public function getPortMappings(): array { - return $this->allocations->where('node_id', $this->node_id)->groupBy('ip')->map(function ($item) { - return $item->pluck('port'); - })->toArray(); + $defaultIp = '0.0.0.0'; + + $ports = collect($this->ports) + ->map(fn ($port) => str_contains($port, ':') ? $port : "$defaultIp:$port") + ->mapToGroups(function ($port) { + [$ip, $port] = explode(':', $port); + + return [$ip => (int) $port]; + }); + + return $ports->all(); } public function isInstalled(): bool @@ -137,22 +138,6 @@ public function subusers(): HasMany return $this->hasMany(Subuser::class, 'server_id', 'id'); } - /** - * Gets the default allocation for a server. - */ - public function allocation(): BelongsTo - { - return $this->belongsTo(Allocation::class); - } - - /** - * Gets all allocations associated with this server. - */ - public function allocations(): HasMany - { - return $this->hasMany(Allocation::class); - } - /** * Gets information for the egg associated with this server. */ diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 5817890b1b..c0dcc1a64c 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -45,7 +45,6 @@ public function boot(): void } Relation::enforceMorphMap([ - 'allocation' => Models\Allocation::class, 'api_key' => Models\ApiKey::class, 'backup' => Models\Backup::class, 'database' => Models\Database::class, diff --git a/app/Rules/Port.php b/app/Rules/Port.php index 7225509c03..f2a598c124 100644 --- a/app/Rules/Port.php +++ b/app/Rules/Port.php @@ -23,12 +23,12 @@ public function validate(string $attribute, mixed $value, Closure $fail): void $fail('The :attribute must be an integer.'); } - if ($value < 0) { - $fail('The :attribute must be greater or equal to 0.'); + if ($value <= 1024) { + $fail('The :attribute must be greater than 1024.'); } if ($value > 65535) { - $fail('The :attribute must be less or equal to 65535.'); + $fail('The :attribute must be less than 65535.'); } } } diff --git a/app/Services/Allocations/AssignmentService.php b/app/Services/Allocations/AssignmentService.php deleted file mode 100644 index 3788d6bf89..0000000000 --- a/app/Services/Allocations/AssignmentService.php +++ /dev/null @@ -1,115 +0,0 @@ - self::CIDR_MIN_BITS || $explode[1] < self::CIDR_MAX_BITS)) { - throw new CidrOutOfRangeException(); - } - } - - try { - // TODO: how should we approach supporting IPv6 with this? - // gethostbyname only supports IPv4, but the alternative (dns_get_record) returns - // an array of records, which is not ideal for this use case, we need a SINGLE - // IP to use, not multiple. - $underlying = gethostbyname($data['allocation_ip']); - $parsed = Network::parse($underlying); - } catch (\Exception $exception) { - throw new DisplayException("Could not parse provided allocation IP address ({$data['allocation_ip']}): {$exception->getMessage()}", $exception); - } - - $this->connection->beginTransaction(); - - $ids = []; - foreach ($parsed as $ip) { - foreach ($data['allocation_ports'] as $port) { - if (!is_digit($port) && !preg_match(self::PORT_RANGE_REGEX, $port)) { - throw new InvalidPortMappingException($port); - } - - $insertData = []; - if (preg_match(self::PORT_RANGE_REGEX, $port, $matches)) { - $block = range($matches[1], $matches[2]); - - if (count($block) > self::PORT_RANGE_LIMIT) { - throw new TooManyPortsInRangeException(); - } - - if ((int) $matches[1] <= self::PORT_FLOOR || (int) $matches[2] > self::PORT_CEIL) { - throw new PortOutOfRangeException(); - } - - foreach ($block as $unit) { - $insertData[] = [ - 'node_id' => $node->id, - 'ip' => $ip->__toString(), - 'port' => (int) $unit, - 'ip_alias' => array_get($data, 'allocation_alias'), - 'server_id' => null, - ]; - } - } else { - if ((int) $port <= self::PORT_FLOOR || (int) $port > self::PORT_CEIL) { - throw new PortOutOfRangeException(); - } - - $insertData[] = [ - 'node_id' => $node->id, - 'ip' => $ip->__toString(), - 'port' => (int) $port, - 'ip_alias' => array_get($data, 'allocation_alias'), - 'server_id' => null, - ]; - } - - foreach ($insertData as $insert) { - $allocation = Allocation::query()->create($insert); - $ids[] = $allocation->id; - } - } - } - - $this->connection->commit(); - - return $ids; - } -} diff --git a/app/Services/Allocations/FindAssignableAllocationService.php b/app/Services/Allocations/FindAssignableAllocationService.php index 5c62b7539e..6f9958a6af 100644 --- a/app/Services/Allocations/FindAssignableAllocationService.php +++ b/app/Services/Allocations/FindAssignableAllocationService.php @@ -4,51 +4,26 @@ use Webmozart\Assert\Assert; use App\Models\Server; -use App\Models\Allocation; use App\Exceptions\Service\Allocation\AutoAllocationNotEnabledException; use App\Exceptions\Service\Allocation\NoAutoAllocationSpaceAvailableException; class FindAssignableAllocationService { - /** - * FindAssignableAllocationService constructor. - */ - public function __construct(private AssignmentService $service) + public function __construct() { } /** - * Finds an existing unassigned allocation and attempts to assign it to the given server. If - * no allocation can be found, a new one will be created with a random port between the defined - * range from the configuration. - * - * @throws \App\Exceptions\DisplayException - * @throws \App\Exceptions\Service\Allocation\CidrOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\InvalidPortMappingException - * @throws \App\Exceptions\Service\Allocation\PortOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\TooManyPortsInRangeException + * @throws AutoAllocationNotEnabledException + * @throws NoAutoAllocationSpaceAvailableException */ - public function handle(Server $server): Allocation + public function handle(Server $server): int { if (!config('panel.client_features.allocations.enabled')) { throw new AutoAllocationNotEnabledException(); } - // Attempt to find a given available allocation for a server. If one cannot be found - // we will fall back to attempting to create a new allocation that can be used for the - // server. - /** @var \App\Models\Allocation|null $allocation */ - $allocation = $server->node->allocations() - ->where('ip', $server->allocation->ip) - ->whereNull('server_id') - ->inRandomOrder() - ->first(); - - $allocation = $allocation ?? $this->createNewAllocation($server); - - $allocation->update(['server_id' => $server->id]); - - return $allocation->refresh(); + return $this->createNewAllocation($server); } /** @@ -56,16 +31,12 @@ public function handle(Server $server): Allocation * in the settings. If there are no matches in that range, or something is wrong with the * range information provided an exception will be raised. * - * @throws \App\Exceptions\DisplayException - * @throws \App\Exceptions\Service\Allocation\CidrOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\InvalidPortMappingException - * @throws \App\Exceptions\Service\Allocation\PortOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\TooManyPortsInRangeException + * @throws NoAutoAllocationSpaceAvailableException */ - protected function createNewAllocation(Server $server): Allocation + protected function createNewAllocation(Server $server): int { - $start = config('panel.client_features.allocations.range_start', null); - $end = config('panel.client_features.allocations.range_end', null); + $start = config('panel.client_features.allocations.range_start'); + $end = config('panel.client_features.allocations.range_end'); if (!$start || !$end) { throw new NoAutoAllocationSpaceAvailableException(); @@ -74,8 +45,7 @@ protected function createNewAllocation(Server $server): Allocation Assert::integerish($start); Assert::integerish($end); - // Get all of the currently allocated ports for the node so that we can figure out - // which port might be available. + // Get all the currently allocated ports for the node so that we can figure out which port might be available. $ports = $server->node->allocations() ->where('ip', $server->allocation->ip) ->whereBetween('port', [$start, $end]) @@ -86,26 +56,8 @@ protected function createNewAllocation(Server $server): Allocation // array of ports to create a new allocation to assign to the server. $available = array_diff(range($start, $end), $ports->toArray()); - // If we've already allocated all of the ports, just abort. - if (empty($available)) { - throw new NoAutoAllocationSpaceAvailableException(); - } - // Pick a random port out of the remaining available ports. /** @var int $port */ - $port = $available[array_rand($available)]; - - $this->service->handle($server->node, [ - 'allocation_ip' => $server->allocation->ip, - 'allocation_ports' => [$port], - ]); - - /** @var \App\Models\Allocation $allocation */ - $allocation = $server->node->allocations() - ->where('ip', $server->allocation->ip) - ->where('port', $port) - ->firstOrFail(); - - return $allocation; + return $available[array_rand($available)]; } } diff --git a/app/Services/Deployment/AllocationSelectionService.php b/app/Services/Deployment/AllocationSelectionService.php deleted file mode 100644 index 3868d0b383..0000000000 --- a/app/Services/Deployment/AllocationSelectionService.php +++ /dev/null @@ -1,150 +0,0 @@ -dedicated = $dedicated; - - return $this; - } - - /** - * A list of node IDs that should be used when selecting an allocation. If empty, all - * nodes will be used to filter with. - */ - public function setNodes(array $nodes): self - { - $this->nodes = $nodes; - - return $this; - } - - /** - * An array of individual ports or port ranges to use when selecting an allocation. If - * empty, all ports will be considered when finding an allocation. If set, only ports appearing - * in the array or range will be used. - * - * @throws \App\Exceptions\DisplayException - */ - public function setPorts(array $ports): self - { - $stored = []; - foreach ($ports as $port) { - if (is_digit($port)) { - $stored[] = $port; - } - - // Ranges are stored in the ports array as an array which can be - // better processed in the repository. - if (preg_match(AssignmentService::PORT_RANGE_REGEX, $port, $matches)) { - if (abs((int) $matches[2] - (int) $matches[1]) > AssignmentService::PORT_RANGE_LIMIT) { - throw new DisplayException(trans('exceptions.allocations.too_many_ports')); - } - - $stored[] = [$matches[1], $matches[2]]; - } - } - - $this->ports = $stored; - - return $this; - } - - /** - * Return a single allocation that should be used as the default allocation for a server. - * - * @throws \App\Exceptions\Service\Deployment\NoViableAllocationException - */ - public function handle(): Allocation - { - $allocation = $this->getRandomAllocation($this->nodes, $this->ports, $this->dedicated); - - if (is_null($allocation)) { - throw new NoViableAllocationException(trans('exceptions.deployment.no_viable_allocations')); - } - - return $allocation; - } - - /** - * Return a single allocation from those meeting the requirements. - */ - private function getRandomAllocation(array $nodes = [], array $ports = [], bool $dedicated = false): ?Allocation - { - $query = Allocation::query() - ->whereNull('server_id') - ->whereIn('node_id', $nodes); - - if (!empty($ports)) { - $query->where(function ($inner) use ($ports) { - $whereIn = []; - foreach ($ports as $port) { - if (is_array($port)) { - $inner->orWhereBetween('port', $port); - - continue; - } - - $whereIn[] = $port; - } - - if (!empty($whereIn)) { - $inner->orWhereIn('port', $whereIn); - } - }); - } - - // If this allocation should not be shared with any other servers get - // the data and modify the query as necessary, - if ($dedicated) { - $discard = $this->getDiscardableDedicatedAllocations($nodes); - - if (!empty($discard)) { - $query->whereNotIn('ip', $discard); - } - } - - return $query->inRandomOrder()->first(); - } - - /** - * Return a result set of node ips that already have at least one - * server assigned to that IP. This allows for filtering out sets for - * dedicated allocation IPs. - * - * If an array of nodes is passed the results will be limited to allocations - * in those nodes. - */ - private function getDiscardableDedicatedAllocations(array $nodes = []): array - { - $query = Allocation::query()->whereNotNull('server_id'); - - if (!empty($nodes)) { - $query->whereIn('node_id', $nodes); - } - - return $query->groupBy('ip') - ->get() - ->pluck('ip') - ->toArray(); - } -} diff --git a/app/Services/Servers/BuildModificationService.php b/app/Services/Servers/BuildModificationService.php index f7c7403249..3b74af0657 100644 --- a/app/Services/Servers/BuildModificationService.php +++ b/app/Services/Servers/BuildModificationService.php @@ -4,9 +4,7 @@ use Illuminate\Support\Arr; use App\Models\Server; -use App\Models\Allocation; use Illuminate\Database\ConnectionInterface; -use App\Exceptions\DisplayException; use App\Repositories\Daemon\DaemonServerRepository; use App\Exceptions\Http\Connection\DaemonConnectionException; @@ -32,20 +30,12 @@ public function handle(Server $server, array $data): Server { /** @var \App\Models\Server $server */ $server = $this->connection->transaction(function () use ($server, $data) { - $this->processAllocations($server, $data); - - if (isset($data['allocation_id']) && $data['allocation_id'] != $server->allocation_id) { - $existingAllocation = $server->allocations()->findOrFail($data['allocation_id']); - - throw_unless($existingAllocation, new DisplayException('The requested default allocation is not currently assigned to this server.')); - } - if (!isset($data['oom_killer']) && isset($data['oom_disabled'])) { $data['oom_killer'] = !$data['oom_disabled']; } // If any of these values are passed through in the data array go ahead and set them correctly on the server model. - $merge = Arr::only($data, ['oom_killer', 'memory', 'swap', 'io', 'cpu', 'threads', 'disk', 'allocation_id']); + $merge = Arr::only($data, ['oom_killer', 'memory', 'swap', 'io', 'cpu', 'threads', 'disk', 'ports']); $server->forceFill(array_merge($merge, [ 'database_limit' => Arr::get($data, 'database_limit', 0) ?? null, @@ -72,59 +62,4 @@ public function handle(Server $server, array $data): Server return $server; } - - /** - * Process the allocations being assigned in the data and ensure they are available for a server. - * - * @throws \App\Exceptions\DisplayException - */ - private function processAllocations(Server $server, array &$data): void - { - if (empty($data['add_allocations']) && empty($data['remove_allocations'])) { - return; - } - - // Handle the addition of allocations to this server. Only assign allocations that are not currently - // assigned to a different server, and only allocations on the same node as the server. - if (!empty($data['add_allocations'])) { - $query = Allocation::query() - ->where('node_id', $server->node_id) - ->whereIn('id', $data['add_allocations']) - ->whereNull('server_id'); - - // Keep track of all the allocations we're just now adding so that we can use the first - // one to reset the default allocation to. - $freshlyAllocated = $query->first()?->id; - - $query->update(['server_id' => $server->id, 'notes' => null]); - } - - if (!empty($data['remove_allocations'])) { - foreach ($data['remove_allocations'] as $allocation) { - // If we are attempting to remove the default allocation for the server, see if we can reassign - // to the first provided value in add_allocations. If there is no new first allocation then we - // will throw an exception back. - if ($allocation === ($data['allocation_id'] ?? $server->allocation_id)) { - if (empty($freshlyAllocated)) { - throw new DisplayException('You are attempting to delete the default allocation for this server but there is no fallback allocation to use.'); - } - - // Update the default allocation to be the first allocation that we are creating. - $data['allocation_id'] = $freshlyAllocated; - } - } - - // Remove any of the allocations we got that are currently assigned to this server on - // this node. Also set the notes to null, otherwise when re-allocated to a new server those - // notes will be carried over. - Allocation::query()->where('node_id', $server->node_id) - ->where('server_id', $server->id) - // Only remove the allocations that we didn't also attempt to add to the server... - ->whereIn('id', array_diff($data['remove_allocations'], $data['add_allocations'] ?? [])) - ->update([ - 'notes' => null, - 'server_id' => null, - ]); - } - } } diff --git a/app/Services/Servers/ServerConfigurationStructureService.php b/app/Services/Servers/ServerConfigurationStructureService.php index 43fd9f76c6..b71d6995d8 100644 --- a/app/Services/Servers/ServerConfigurationStructureService.php +++ b/app/Services/Servers/ServerConfigurationStructureService.php @@ -69,7 +69,7 @@ protected function returnFormat(Server $server): array 'ip' => $server->allocation->ip, 'port' => $server->allocation->port, ], - 'mappings' => $server->getAllocationMappings(), + 'mappings' => $server->getPortMappings(), ], 'egg' => [ 'id' => $server->egg->uuid, diff --git a/app/Services/Servers/ServerCreationService.php b/app/Services/Servers/ServerCreationService.php index d555f7876b..fe39b8501c 100644 --- a/app/Services/Servers/ServerCreationService.php +++ b/app/Services/Servers/ServerCreationService.php @@ -10,12 +10,9 @@ use Webmozart\Assert\Assert; use App\Models\Server; use Illuminate\Support\Collection; -use App\Models\Allocation; use Illuminate\Database\ConnectionInterface; use App\Models\Objects\DeploymentObject; use App\Repositories\Daemon\DaemonServerRepository; -use App\Services\Deployment\FindViableNodesService; -use App\Services\Deployment\AllocationSelectionService; use App\Exceptions\Http\Connection\DaemonConnectionException; class ServerCreationService @@ -24,27 +21,23 @@ class ServerCreationService * ServerCreationService constructor. */ public function __construct( - private AllocationSelectionService $allocationSelectionService, private ConnectionInterface $connection, private DaemonServerRepository $daemonServerRepository, - private FindViableNodesService $findViableNodesService, private ServerDeletionService $serverDeletionService, private VariableValidatorService $validatorService ) { } /** - * Create a server on the Panel and trigger a request to the Daemon to begin the server - * creation process. This function will attempt to set as many additional values - * as possible given the input data. For example, if an allocation_id is passed with - * no node_id the node_is will be picked from the allocation. + * Create a server on the Panel and trigger a request to the Daemon to begin the server creation process. + * This function will attempt to set as many additional values as possible given the input data. * * @throws \Throwable * @throws \App\Exceptions\DisplayException * @throws \Illuminate\Validation\ValidationException * @throws \App\Exceptions\Service\Deployment\NoViableAllocationException */ - public function handle(array $data, DeploymentObject $deployment = null): Server + public function handle(array $data, DeploymentObject $deployment = null, $validateVariables = true): Server { if (!isset($data['oom_killer']) && isset($data['oom_disabled'])) { $data['oom_killer'] = !$data['oom_disabled']; @@ -53,22 +46,15 @@ public function handle(array $data, DeploymentObject $deployment = null): Server // If a deployment object has been passed we need to get the allocation // that the server should use, and assign the node from that allocation. if ($deployment instanceof DeploymentObject) { - $allocation = $this->configureDeployment($data, $deployment); - $data['allocation_id'] = $allocation->id; - $data['node_id'] = $allocation->node_id; + // Todo: Refactor + // $allocation = $this->configureDeployment($data, $deployment); } - // Auto-configure the node based on the selected allocation - // if no node was defined. - if (empty($data['node_id'])) { - Assert::false(empty($data['allocation_id']), 'Expected a non-empty allocation_id in server creation data.'); - - $data['node_id'] = Allocation::query()->findOrFail($data['allocation_id'])->node_id; - } + Assert::false(empty($data['node_id'])); $eggVariableData = $this->validatorService ->setUserLevel(User::USER_LEVEL_ADMIN) - ->handle(Arr::get($data, 'egg_id'), Arr::get($data, 'environment', [])); + ->handle(Arr::get($data, 'egg_id'), Arr::get($data, 'environment', []), $validateVariables); // Due to the design of the Daemon, we need to persist this server to the disk // before we can actually create it on the Daemon. @@ -80,7 +66,6 @@ public function handle(array $data, DeploymentObject $deployment = null): Server // Create the server and assign any additional allocations to it. $server = $this->createModel($data); - $this->storeAssignedAllocations($server, $data); $this->storeEggVariables($server, $eggVariableData); return $server; @@ -99,28 +84,6 @@ public function handle(array $data, DeploymentObject $deployment = null): Server return $server; } - /** - * Gets an allocation to use for automatic deployment. - * - * @throws \App\Exceptions\DisplayException - * @throws \App\Exceptions\Service\Deployment\NoViableAllocationException - */ - private function configureDeployment(array $data, DeploymentObject $deployment): Allocation - { - /** @var Collection<\App\Models\Node> $nodes */ - $nodes = $this->findViableNodesService->handle( - Arr::get($data, 'memory', 0), - Arr::get($data, 'disk', 0), - Arr::get($data, 'cpu', 0), - Arr::get($data, 'tags', []), - ); - - return $this->allocationSelectionService->setDedicated($deployment->isDedicated()) - ->setNodes($nodes->pluck('id')->toArray()) - ->setPorts($deployment->getPorts()) - ->handle(); - } - /** * Store the server in the database and return the model. * @@ -158,21 +121,6 @@ private function createModel(array $data): Server ]); } - /** - * Configure the allocations assigned to this server. - */ - private function storeAssignedAllocations(Server $server, array $data): void - { - $records = [$data['allocation_id']]; - if (isset($data['allocation_additional']) && is_array($data['allocation_additional'])) { - $records = array_merge($records, $data['allocation_additional']); - } - - Allocation::query()->whereIn('id', $records)->update([ - 'server_id' => $server->id, - ]); - } - /** * Process environment variables passed for this server and store them in the database. */ diff --git a/app/Services/Servers/TransferServerService.php b/app/Services/Servers/TransferServerService.php index 4312369dd7..c948f3b9c5 100644 --- a/app/Services/Servers/TransferServerService.php +++ b/app/Services/Servers/TransferServerService.php @@ -3,7 +3,6 @@ namespace App\Services\Servers; use App\Exceptions\Http\Connection\DaemonConnectionException; -use App\Models\Allocation; use App\Models\Node; use App\Models\Server; use App\Models\ServerTransfer; @@ -52,8 +51,6 @@ private function notify(Server $server, Plain $token): void public function handle(Server $server, array $data): bool { $node_id = $data['node_id']; - $allocation_id = intval($data['allocation_id']); - $additional_allocations = array_map(intval(...), $data['allocation_additional'] ?? []); // Check if the node is viable for the transfer. $node = Node::query() @@ -71,23 +68,15 @@ public function handle(Server $server, array $data): bool $server->validateTransferState(); - $this->connection->transaction(function () use ($server, $node_id, $allocation_id, $additional_allocations) { - // Create a new ServerTransfer entry. + $this->connection->transaction(function () use ($server, $node_id) { $transfer = new ServerTransfer(); $transfer->server_id = $server->id; $transfer->old_node = $server->node_id; $transfer->new_node = $node_id; - $transfer->old_allocation = $server->allocation_id; - $transfer->new_allocation = $allocation_id; - $transfer->old_additional_allocations = $server->allocations->where('id', '!=', $server->allocation_id)->pluck('id')->all(); - $transfer->new_additional_allocations = $additional_allocations; $transfer->save(); - // Add the allocations to the server, so they cannot be automatically assigned while the transfer is in progress. - $this->assignAllocationsToServer($server, $node_id, $allocation_id, $additional_allocations); - // Generate a token for the destination node that the source node can use to authenticate with. $token = $this->nodeJWTService ->setExpiresAt(CarbonImmutable::now()->addMinutes(15)) @@ -102,32 +91,4 @@ public function handle(Server $server, array $data): bool return true; } - - /** - * Assigns the specified allocations to the specified server. - */ - private function assignAllocationsToServer(Server $server, int $node_id, int $allocation_id, array $additional_allocations) - { - $allocations = $additional_allocations; - $allocations[] = $allocation_id; - - $node = Node::query()->findOrFail($node_id); - $unassigned = $node->allocations() - ->whereNull('server_id') - ->pluck('id') - ->toArray(); - - $updateIds = []; - foreach ($allocations as $allocation) { - if (!in_array($allocation, $unassigned)) { - continue; - } - - $updateIds[] = $allocation; - } - - if (!empty($updateIds)) { - Allocation::query()->whereIn('id', $updateIds)->update(['server_id' => $server->id]); - } - } } diff --git a/app/Services/Servers/VariableValidatorService.php b/app/Services/Servers/VariableValidatorService.php index 75f4a59b14..a55e27bf60 100644 --- a/app/Services/Servers/VariableValidatorService.php +++ b/app/Services/Servers/VariableValidatorService.php @@ -25,7 +25,7 @@ public function __construct(private ValidationFactory $validator) * * @throws \Illuminate\Validation\ValidationException */ - public function handle(int $egg, array $fields = []): Collection + public function handle(int $egg, array $fields = [], $validate = false): Collection { $query = EggVariable::query()->where('egg_id', $egg); if (!$this->isUserLevel(User::USER_LEVEL_ADMIN)) { @@ -44,9 +44,11 @@ public function handle(int $egg, array $fields = []): Collection $customAttributes['environment.' . $variable->env_variable] = trans('validation.internal.variable_value', ['env' => $variable->name]); } - $validator = $this->validator->make($data, $rules, [], $customAttributes); - if ($validator->fails()) { - throw new ValidationException($validator); + if ($validate) { + $validator = $this->validator->make($data, $rules, [], $customAttributes); + if ($validator->fails()) { + throw new ValidationException($validator); + } } return Collection::make($variables)->map(function ($item) use ($fields) { diff --git a/app/Transformers/Api/Application/AllocationTransformer.php b/app/Transformers/Api/Application/AllocationTransformer.php deleted file mode 100644 index 7f5bf88270..0000000000 --- a/app/Transformers/Api/Application/AllocationTransformer.php +++ /dev/null @@ -1,77 +0,0 @@ - $allocation->id, - 'ip' => $allocation->ip, - 'alias' => $allocation->ip_alias, - 'port' => $allocation->port, - 'notes' => $allocation->notes, - 'assigned' => !is_null($allocation->server_id), - ]; - } - - /** - * Load the node relationship onto a given transformation. - * - * @throws \App\Exceptions\Transformer\InvalidTransformerLevelException - */ - public function includeNode(Allocation $allocation): Item|NullResource - { - if (!$this->authorize(AdminAcl::RESOURCE_NODES)) { - return $this->null(); - } - - return $this->item( - $allocation->node, - $this->makeTransformer(NodeTransformer::class), - Node::RESOURCE_NAME - ); - } - - /** - * Load the server relationship onto a given transformation. - * - * @throws \App\Exceptions\Transformer\InvalidTransformerLevelException - */ - public function includeServer(Allocation $allocation): Item|NullResource - { - if (!$this->authorize(AdminAcl::RESOURCE_SERVERS) || !$allocation->server) { - return $this->null(); - } - - return $this->item( - $allocation->server, - $this->makeTransformer(ServerTransformer::class), - Server::RESOURCE_NAME - ); - } -} diff --git a/app/Transformers/Api/Application/NodeTransformer.php b/app/Transformers/Api/Application/NodeTransformer.php index 670e4bcac5..dabf8c40df 100644 --- a/app/Transformers/Api/Application/NodeTransformer.php +++ b/app/Transformers/Api/Application/NodeTransformer.php @@ -12,7 +12,7 @@ class NodeTransformer extends BaseTransformer /** * List of resources that can be included. */ - protected array $availableIncludes = ['allocations', 'servers']; + protected array $availableIncludes = ['servers']; /** * Return the resource name for the JSONAPI output. @@ -45,26 +45,6 @@ public function transform(Node $node): array return $response; } - /** - * Return the nodes associated with this location. - * - * @throws \App\Exceptions\Transformer\InvalidTransformerLevelException - */ - public function includeAllocations(Node $node): Collection|NullResource - { - if (!$this->authorize(AdminAcl::RESOURCE_ALLOCATIONS)) { - return $this->null(); - } - - $node->loadMissing('allocations'); - - return $this->collection( - $node->getRelation('allocations'), - $this->makeTransformer(AllocationTransformer::class), - 'allocation' - ); - } - /** * Return the nodes associated with this location. * diff --git a/app/Transformers/Api/Application/ServerTransformer.php b/app/Transformers/Api/Application/ServerTransformer.php index 90836cc248..e754b94521 100644 --- a/app/Transformers/Api/Application/ServerTransformer.php +++ b/app/Transformers/Api/Application/ServerTransformer.php @@ -17,7 +17,6 @@ class ServerTransformer extends BaseTransformer * List of resources that can be included. */ protected array $availableIncludes = [ - 'allocations', 'user', 'subusers', 'egg', @@ -76,7 +75,6 @@ public function transform(Server $server): array ], 'user' => $server->owner_id, 'node' => $server->node_id, - 'allocation' => $server->allocation_id, 'egg' => $server->egg_id, 'container' => [ 'startup_command' => $server->startup, @@ -87,23 +85,23 @@ public function transform(Server $server): array ], $server->getUpdatedAtColumn() => $this->formatTimestamp($server->updated_at), $server->getCreatedAtColumn() => $this->formatTimestamp($server->created_at), - ]; - } - - /** - * Return a generic array of allocations for this server. - * - * @throws \App\Exceptions\Transformer\InvalidTransformerLevelException - */ - public function includeAllocations(Server $server): Collection|NullResource - { - if (!$this->authorize(AdminAcl::RESOURCE_ALLOCATIONS)) { - return $this->null(); - } - - $server->loadMissing('allocations'); - return $this->collection($server->getRelation('allocations'), $this->makeTransformer(AllocationTransformer::class), 'allocation'); + 'allocations' => collect($server->ports)->map(function ($port) { + $ip = '0.0.0.0'; + if (str_contains($port, ':')) { + [$ip, $port] = explode(':', $port); + } + + return [ + 'id' => random_int(1, PHP_INT_MAX), + 'ip' => $ip, + 'alias' => null, + 'port' => (int) $port, + 'notes' => null, + 'assigned' => false, + ]; + })->all(), + ]; } /** diff --git a/app/Transformers/Api/Client/AllocationTransformer.php b/app/Transformers/Api/Client/AllocationTransformer.php deleted file mode 100644 index 4fd84ed61d..0000000000 --- a/app/Transformers/Api/Client/AllocationTransformer.php +++ /dev/null @@ -1,28 +0,0 @@ - $model->id, - 'ip' => $model->ip, - 'ip_alias' => $model->ip_alias, - 'port' => $model->port, - 'notes' => $model->notes, - 'is_default' => $model->server->allocation_id === $model->id, - ]; - } -} diff --git a/app/Transformers/Api/Client/ServerTransformer.php b/app/Transformers/Api/Client/ServerTransformer.php index 07cd64dbd2..b5c410f4a6 100644 --- a/app/Transformers/Api/Client/ServerTransformer.php +++ b/app/Transformers/Api/Client/ServerTransformer.php @@ -6,7 +6,6 @@ use App\Models\Server; use App\Models\Subuser; use League\Fractal\Resource\Item; -use App\Models\Allocation; use App\Models\Permission; use Illuminate\Container\Container; use App\Models\EggVariable; @@ -16,7 +15,7 @@ class ServerTransformer extends BaseClientTransformer { - protected array $defaultIncludes = ['allocations', 'variables']; + protected array $defaultIncludes = ['variables']; protected array $availableIncludes = ['egg', 'subusers']; @@ -78,33 +77,6 @@ public function transform(Server $server): array ]; } - /** - * Returns the allocations associated with this server. - * - * @throws \App\Exceptions\Transformer\InvalidTransformerLevelException - */ - public function includeAllocations(Server $server): Collection - { - $transformer = $this->makeTransformer(AllocationTransformer::class); - - $user = $this->request->user(); - // While we include this permission, we do need to actually handle it slightly different here - // for the purpose of keeping things functionally working. If the user doesn't have read permissions - // for the allocations we'll only return the primary server allocation, and any notes associated - // with it will be hidden. - // - // This allows us to avoid too much permission regression, without also hiding information that - // is generally needed for the frontend to make sense when browsing or searching results. - if (!$user->can(Permission::ACTION_ALLOCATION_READ, $server)) { - $primary = clone $server->allocation; - $primary->notes = null; - - return $this->collection([$primary], $transformer, Allocation::RESOURCE_NAME); - } - - return $this->collection($server->allocations, $transformer, Allocation::RESOURCE_NAME); - } - /** * @throws \App\Exceptions\Transformer\InvalidTransformerLevelException */ diff --git a/database/Factories/AllocationFactory.php b/database/Factories/AllocationFactory.php deleted file mode 100644 index 19405b7024..0000000000 --- a/database/Factories/AllocationFactory.php +++ /dev/null @@ -1,36 +0,0 @@ - $this->faker->unique()->ipv4(), - 'port' => $this->faker->unique()->numberBetween(1024, 65535), - ]; - } - - /** - * Attaches the allocation to a specific server model. - */ - public function forServer(Server $server): self - { - return $this->for($server)->for($server->node); - } -} diff --git a/database/migrations/2024_06_06_043350_modify_allocations.php b/database/migrations/2024_06_06_043350_modify_allocations.php index 308e1adea4..42c07b1aa9 100644 --- a/database/migrations/2024_06_06_043350_modify_allocations.php +++ b/database/migrations/2024_06_06_043350_modify_allocations.php @@ -11,14 +11,37 @@ */ public function up(): void { + Schema::table('server_transfers', function (Blueprint $table) { + $table->dropColumn(['old_allocation', 'new_allocation', 'old_additional_allocations', 'new_additional_allocations']); + }); + + Schema::table('servers', function (Blueprint $table) { + $table->json('ports')->nullable(); + }); + + DB::table('servers')->update(['ports' => '[]']); + Schema::table('servers', function (Blueprint $table) { - $table->json('ports'); + $table->json('ports')->change(); }); + dd('works?'); + + $portMappings = []; + foreach (DB::table('allocations')->get() as $allocation) { + $portMappings[$allocation->server_id][] = "$allocation->ip:$allocation->port"; + } + + foreach ($portMappings as $serverId => $ports) { + DB::table('servers') + ->where('id', $serverId) + ->update(['ports' => json_encode($ports)]); + } + Schema::dropIfExists('allocations'); Schema::table('servers', function (Blueprint $table) { - $table->dropColumn(['allocation_id', 'allocation_limit']); + $table->dropColumn(['allocation_id']); }); Schema::table('nodes', function (Blueprint $table) { @@ -47,5 +70,12 @@ public function down(): void $table->unique(['node_id', 'ip', 'port']); }); + + Schema::table('server_transfers', function (Blueprint $table) { + $table->integer('old_node'); + $table->integer('new_node'); + $table->json('old_additional_allocations')->nullable(); + $table->json('new_additional_allocations')->nullable(); + }); } }; diff --git a/resources/views/admin/servers/new.blade.php b/resources/views/admin/servers/new.blade.php deleted file mode 100644 index 4aac49d397..0000000000 --- a/resources/views/admin/servers/new.blade.php +++ /dev/null @@ -1,375 +0,0 @@ -@extends('layouts.admin') - -@section('title') - New Server -@endsection - -@section('content-header') -

Create ServerAdd a new server to the panel.

- -@endsection - -@section('content') -
-
-
-
-
-

Core Details

-
- -
-
-
- - -

Character limits: a-z A-Z 0-9 _ - . and [Space].

-
- -
- - -

Email address of the Server Owner.

-
-
- -
-
- - -

A brief description of this server.

-
- -
-
- - -
-
-
-
-
-
-
- -
-
-
- -
-

Allocation Management

-
- -
-
- - - -

The node which this server will be deployed to.

-
- -
- - -

The main allocation that will be assigned to this server.

-
- -
- - -

Additional allocations to assign to this server on creation.

-
-
-
-
-
- -
-
-
- -
-

Application Feature Limits

-
- -
-
- -
- -
-

The total number of databases a user is allowed to create for this server.

-
-
- -
- -
-

The total number of allocations a user is allowed to create for this server.

-
-
- -
- -
-

The total number of backups that can be created for this server.

-
-
-
-
-
-
-
-
-
-

Resource Management

-
- -
-
- - -
- - % -
- -

If you do not want to limit CPU usage, set the value to 0. To determine a value, take the number of threads and multiply it by 100. For example, on a quad core system without hyperthreading (4 * 100 = 400) there is 400% available. To limit a server to using half of a single thread, you would set the value to 50. To allow a server to use up to two threads, set the value to 200.

-

- -
- - -
- -
- -

Advanced: Enter the specific CPU threads that this process can run on, or leave blank to allow all threads. This can be a single number, or a comma separated list. Example: 0, 0-1,3, or 0,1,3,4.

-
-
- -
-
- - -
- - MiB -
- -

The maximum amount of memory allowed for this container. Setting this to 0 will allow unlimited memory in a container.

-
- -
- - -
- - MiB -
- -

Setting this to 0 will disable swap space on this server. Setting to -1 will allow unlimited swap.

-
-
- -
-
- - -
- - MiB -
- -

This server will not be allowed to boot if it is using more than this amount of space. If a server goes over this limit while running it will be safely stopped and locked until enough space is available. Set to 0 to allow unlimited disk usage.

-
- -
- - -
- -
- -

Advanced: The IO performance of this server relative to other running containers on the system. Value should be between 10 and 1000. Please see this documentation for more information about it.

-
-
-
- - -
- -

Terminates the server if it breaches the memory limits. Enabling OOM killer may cause server processes to exit unexpectedly.

-
-
-
-
-
- -
-
-
-
-

Egg Configuration

-
- -
-
- - - -

Select the Egg that will define how this server should operate.

-
- -
-
- - -
- -

If the selected Egg has an install script attached to it, the script will run during the install. If you would like to skip this step, check this box.

-
-
-
-
- -
-
-
-

Docker Configuration

-
- -
-
- - - -

This is the default Docker image that will be used to run this server. Select an image from the dropdown above, or enter a custom image in the text field above.

-
-
-
-
-
- -
-
-
-
-

Startup Configuration

-
- -
-
- - -

The following data substitutes are available for the startup command: @{{SERVER_MEMORY}}, @{{SERVER_IP}}, and @{{SERVER_PORT}}. They will be replaced with the allocated memory, server IP, and server port respectively.

-
-
- -
-

Egg Variables

-
- -
- - -
-
-
-
-@endsection - -@section('footer-scripts') - @parent - {!! Theme::js('vendor/lodash/lodash.js') !!} - - - - {!! Theme::js('js/admin/new-server.js?v=20220530') !!} - - -@endsection diff --git a/resources/views/admin/servers/view/manage.blade.php b/resources/views/admin/servers/view/manage.blade.php deleted file mode 100644 index eba2f8ab7b..0000000000 --- a/resources/views/admin/servers/view/manage.blade.php +++ /dev/null @@ -1,194 +0,0 @@ -@extends('layouts.admin') - -@section('title') - Server — {{ $server->name }}: Manage -@endsection - -@section('content-header') -

{{ $server->name }}Additional actions to control this server.

- -@endsection - -@section('content') - @include('admin.servers.partials.navigation') -
-
-
-
-

Reinstall Server

-
-
-

This will reinstall the server with the assigned egg scripts. Danger! This could overwrite server data.

-
- -
-
-
-
-
-

Install Status

-
-
-

If you need to change the install status from uninstalled to installed, or vice versa, you may do so with the button below.

-
- -
-
- - @if(! $server->isSuspended()) -
-
-
-

Suspend Server

-
-
-

This will suspend the server, stop any running processes, and immediately block the user from being able to access their files or otherwise manage the server through the panel or API.

-
- -
-
- @else -
-
-
-

Unsuspend Server

-
-
-

This will unsuspend the server and restore normal user access.

-
- -
-
- @endif - - @if(is_null($server->transfer)) -
-
-
-

Transfer Server

-
-
-

- Transfer this server to another node connected to this panel. - Warning! This feature has not been fully tested and may have bugs. -

-
- - -
-
- @else -
-
-
-

Transfer Server

-
-
-

- This server is currently being transferred to another node. - Transfer was initiated at {{ $server->transfer->created_at }} -

-
- - -
-
- @endif -
- - -@endsection - -@section('footer-scripts') - @parent - {!! Theme::js('vendor/lodash/lodash.js') !!} - - @if($canTransfer) - {!! Theme::js('js/admin/server/transfer.js') !!} - @endif -@endsection diff --git a/routes/admin.php b/routes/admin.php index 3786b876a1..894f3db6dc 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -137,21 +137,14 @@ Route::get('/view/{node:id}', [Admin\Nodes\NodeViewController::class, 'index'])->name('admin.nodes.view'); Route::get('/view/{node:id}/settings', [Admin\Nodes\NodeViewController::class, 'settings'])->name('admin.nodes.view.settings'); Route::get('/view/{node:id}/configuration', [Admin\Nodes\NodeViewController::class, 'configuration'])->name('admin.nodes.view.configuration'); - Route::get('/view/{node:id}/allocation', [Admin\Nodes\NodeViewController::class, 'allocations'])->name('admin.nodes.view.allocation'); Route::get('/view/{node:id}/servers', [Admin\Nodes\NodeViewController::class, 'servers'])->name('admin.nodes.view.servers'); Route::get('/view/{node:id}/system-information', Admin\Nodes\SystemInformationController::class); - Route::post('/new', [Admin\NodesController::class, 'store']); - Route::post('/view/{node:id}/allocation', [Admin\NodesController::class, 'createAllocation']); - Route::post('/view/{node:id}/allocation/remove', [Admin\NodesController::class, 'allocationRemoveBlock'])->name('admin.nodes.view.allocation.removeBlock'); - Route::post('/view/{node:id}/allocation/alias', [Admin\NodesController::class, 'allocationSetAlias'])->name('admin.nodes.view.allocation.setAlias'); Route::post('/view/{node:id}/settings/token', Admin\NodeAutoDeployController::class)->name('admin.nodes.view.configuration.token'); Route::patch('/view/{node:id}/settings', [Admin\NodesController::class, 'updateSettings']); Route::delete('/view/{node:id}/delete', [Admin\NodesController::class, 'delete'])->name('admin.nodes.view.delete'); - Route::delete('/view/{node:id}/allocation/remove/{allocation:id}', [Admin\NodesController::class, 'allocationRemoveSingle'])->name('admin.nodes.view.allocation.removeSingle'); - Route::delete('/view/{node:id}/allocations', [Admin\NodesController::class, 'allocationRemoveMultiple'])->name('admin.nodes.view.allocation.removeMultiple'); }); /* diff --git a/routes/api-application.php b/routes/api-application.php index c213c74ab3..87d83956ff 100644 --- a/routes/api-application.php +++ b/routes/api-application.php @@ -40,12 +40,6 @@ Route::patch('/{node:id}', [Application\Nodes\NodeController::class, 'update']); Route::delete('/{node:id}', [Application\Nodes\NodeController::class, 'delete']); - - Route::prefix('/{node:id}/allocations')->group(function () { - Route::get('/', [Application\Nodes\AllocationController::class, 'index'])->name('api.application.allocations'); - Route::post('/', [Application\Nodes\AllocationController::class, 'store']); - Route::delete('/{allocation:id}', [Application\Nodes\AllocationController::class, 'delete'])->name('api.application.allocations.view'); - }); }); /* @@ -72,7 +66,6 @@ Route::post('/{server:id}/transfer', [Application\Servers\ServerManagementController::class, 'startTransfer'])->name('api.application.servers.transfer'); Route::post('/{server:id}/transfer/cancel', [Application\Servers\ServerManagementController::class, 'cancelTransfer'])->name('api.application.servers.transfer.cancel'); - Route::delete('/{server:id}', [Application\Servers\ServerController::class, 'delete']); Route::delete('/{server:id}/{force?}', [Application\Servers\ServerController::class, 'delete']); // Database Management Endpoint diff --git a/routes/api-client.php b/routes/api-client.php index ed1190af64..7da1ecfa68 100644 --- a/routes/api-client.php +++ b/routes/api-client.php @@ -96,14 +96,6 @@ Route::delete('/{schedule}/tasks/{task}', [Client\Servers\ScheduleTaskController::class, 'delete']); }); - Route::prefix('/network')->group(function () { - Route::get('/allocations', [Client\Servers\NetworkAllocationController::class, 'index']); - Route::post('/allocations', [Client\Servers\NetworkAllocationController::class, 'store']); - Route::post('/allocations/{allocation}', [Client\Servers\NetworkAllocationController::class, 'update']); - Route::post('/allocations/{allocation}/primary', [Client\Servers\NetworkAllocationController::class, 'setPrimary']); - Route::delete('/allocations/{allocation}', [Client\Servers\NetworkAllocationController::class, 'delete']); - }); - Route::prefix('/users')->group(function () { Route::get('/', [Client\Servers\SubuserController::class, 'index']); Route::post('/', [Client\Servers\SubuserController::class, 'store']); diff --git a/tests/Integration/Api/Client/ClientApiIntegrationTestCase.php b/tests/Integration/Api/Client/ClientApiIntegrationTestCase.php index e909bb41ec..1090eae476 100644 --- a/tests/Integration/Api/Client/ClientApiIntegrationTestCase.php +++ b/tests/Integration/Api/Client/ClientApiIntegrationTestCase.php @@ -11,9 +11,7 @@ use App\Models\Database; use App\Models\Schedule; use Illuminate\Support\Collection; -use App\Models\Allocation; use App\Models\DatabaseHost; -use App\Tests\Integration\TestResponse; use App\Tests\Integration\IntegrationTestCase; use Illuminate\Database\Eloquent\Model as EloquentModel; use App\Transformers\Api\Client\BaseClientTransformer; @@ -59,9 +57,6 @@ protected function link(mixed $model, string $append = null): string case Task::class: $link = "/api/client/servers/{$model->schedule->server->uuid}/schedules/{$model->schedule->id}/tasks/$model->id"; break; - case Allocation::class: - $link = "/api/client/servers/{$model->server->uuid}/network/allocations/$model->id"; - break; case Backup::class: $link = "/api/client/servers/{$model->server->uuid}/backups/$model->uuid"; break; diff --git a/tests/Integration/Api/Client/ClientControllerTest.php b/tests/Integration/Api/Client/ClientControllerTest.php index 29805711f5..cc2d1d38d7 100644 --- a/tests/Integration/Api/Client/ClientControllerTest.php +++ b/tests/Integration/Api/Client/ClientControllerTest.php @@ -5,7 +5,6 @@ use App\Models\User; use App\Models\Server; use App\Models\Subuser; -use App\Models\Allocation; use App\Models\Permission; class ClientControllerTest extends ClientApiIntegrationTestCase @@ -95,49 +94,6 @@ public function testServersAreFilteredUsingNameAndUuidInformation(): void ->assertJsonPath('data.1.attributes.identifier', $servers[2]->uuid_short); } - /** - * Test that using ?filter[*]=:25565 or ?filter[*]=192.168.1.1:25565 returns only those servers - * with the same allocation for the given user. - */ - public function testServersAreFilteredUsingAllocationInformation(): void - { - /** @var \App\Models\User $user */ - /** @var \App\Models\Server $server */ - [$user, $server] = $this->generateTestAccount(); - $server2 = $this->createServerModel(['user_id' => $user->id, 'node_id' => $server->node_id]); - - $allocation = Allocation::factory()->create(['node_id' => $server->node_id, 'server_id' => $server->id, 'ip' => '192.168.1.1', 'port' => 25565]); - $allocation2 = Allocation::factory()->create(['node_id' => $server->node_id, 'server_id' => $server2->id, 'ip' => '192.168.1.1', 'port' => 25570]); - - $server->update(['allocation_id' => $allocation->id]); - $server2->update(['allocation_id' => $allocation2->id]); - - $server->refresh(); - $server2->refresh(); - - $this->actingAs($user)->getJson('/api/client?filter[*]=192.168.1.1') - ->assertOk() - ->assertJsonCount(2, 'data') - ->assertJsonPath('data.0.attributes.identifier', $server->uuid_short) - ->assertJsonPath('data.1.attributes.identifier', $server2->uuid_short); - - $this->actingAs($user)->getJson('/api/client?filter[*]=192.168.1.1:25565') - ->assertOk() - ->assertJsonCount(1, 'data') - ->assertJsonPath('data.0.attributes.identifier', $server->uuid_short); - - $this->actingAs($user)->getJson('/api/client?filter[*]=:25570') - ->assertOk() - ->assertJsonCount(1, 'data') - ->assertJsonPath('data.0.attributes.identifier', $server2->uuid_short); - - $this->actingAs($user)->getJson('/api/client?filter[*]=:255') - ->assertOk() - ->assertJsonCount(2, 'data') - ->assertJsonPath('data.0.attributes.identifier', $server->uuid_short) - ->assertJsonPath('data.1.attributes.identifier', $server2->uuid_short); - } - /** * Test that servers where the user is a subuser are returned by default in the API call. */ @@ -311,13 +267,6 @@ public function testOnlyPrimaryAllocationIsReturnedToSubuser(): void { /** @var \App\Models\Server $server */ [$user, $server] = $this->generateTestAccount([Permission::ACTION_WEBSOCKET_CONNECT]); - $server->allocation->notes = 'Test notes'; - $server->allocation->save(); - - Allocation::factory()->times(2)->create([ - 'node_id' => $server->node_id, - 'server_id' => $server->id, - ]); $server->refresh(); $response = $this->actingAs($user)->getJson('/api/client'); @@ -327,8 +276,6 @@ public function testOnlyPrimaryAllocationIsReturnedToSubuser(): void $response->assertJsonPath('data.0.attributes.server_owner', false); $response->assertJsonPath('data.0.attributes.uuid', $server->uuid); $response->assertJsonCount(1, 'data.0.attributes.relationships.allocations.data'); - $response->assertJsonPath('data.0.attributes.relationships.allocations.data.0.attributes.id', $server->allocation->id); - $response->assertJsonPath('data.0.attributes.relationships.allocations.data.0.attributes.notes', null); } public static function filterTypeDataProvider(): array diff --git a/tests/Integration/Api/Client/Server/Allocation/AllocationAuthorizationTest.php b/tests/Integration/Api/Client/Server/Allocation/AllocationAuthorizationTest.php deleted file mode 100644 index 6cd798e165..0000000000 --- a/tests/Integration/Api/Client/Server/Allocation/AllocationAuthorizationTest.php +++ /dev/null @@ -1,57 +0,0 @@ -generateTestAccount(); - // Will be a subuser of $server2. - $server2 = $this->createServerModel(); - // And as no access to $server3. - $server3 = $this->createServerModel(); - - // Set the API $user as a subuser of server 2, but with no permissions - // to do anything with the allocations for that server. - Subuser::factory()->create(['server_id' => $server2->id, 'user_id' => $user->id]); - - $allocation1 = Allocation::factory()->create(['server_id' => $server1->id, 'node_id' => $server1->node_id]); - $allocation2 = Allocation::factory()->create(['server_id' => $server2->id, 'node_id' => $server2->node_id]); - $allocation3 = Allocation::factory()->create(['server_id' => $server3->id, 'node_id' => $server3->node_id]); - - // This is the only valid call for this test, accessing the allocation for the same - // server that the API user is the owner of. - $response = $this->actingAs($user)->json($method, $this->link($server1, '/network/allocations/' . $allocation1->id . $endpoint)); - $this->assertTrue($response->status() <= 204 || $response->status() === 400 || $response->status() === 422); - - // This request fails because the allocation is valid for that server but the user - // making the request is not authorized to perform that action. - $this->actingAs($user)->json($method, $this->link($server2, '/network/allocations/' . $allocation2->id . $endpoint))->assertForbidden(); - - // Both of these should report a 404 error due to the allocations being linked to - // servers that are not the same as the server in the request, or are assigned - // to a server for which the user making the request has no access to. - $this->actingAs($user)->json($method, $this->link($server1, '/network/allocations/' . $allocation2->id . $endpoint))->assertNotFound(); - $this->actingAs($user)->json($method, $this->link($server1, '/network/allocations/' . $allocation3->id . $endpoint))->assertNotFound(); - $this->actingAs($user)->json($method, $this->link($server2, '/network/allocations/' . $allocation3->id . $endpoint))->assertNotFound(); - $this->actingAs($user)->json($method, $this->link($server3, '/network/allocations/' . $allocation3->id . $endpoint))->assertNotFound(); - } - - public static function methodDataProvider(): array - { - return [ - ['POST', ''], - ['DELETE', ''], - ['POST', '/primary'], - ]; - } -} diff --git a/tests/Integration/Api/Client/Server/Allocation/CreateNewAllocationTest.php b/tests/Integration/Api/Client/Server/Allocation/CreateNewAllocationTest.php deleted file mode 100644 index 395e283a2d..0000000000 --- a/tests/Integration/Api/Client/Server/Allocation/CreateNewAllocationTest.php +++ /dev/null @@ -1,93 +0,0 @@ -set('panel.client_features.allocations.enabled', true); - config()->set('panel.client_features.allocations.range_start', 5000); - config()->set('panel.client_features.allocations.range_end', 5050); - } - - /** - * Tests that a new allocation can be properly assigned to a server. - * - * @dataProvider permissionDataProvider - */ - public function testNewAllocationCanBeAssignedToServer(array $permission): void - { - /** @var \App\Models\Server $server */ - [$user, $server] = $this->generateTestAccount($permission); - $server->update(['allocation_limit' => 2]); - - $response = $this->actingAs($user)->postJson($this->link($server, '/network/allocations')); - $response->assertJsonPath('object', Allocation::RESOURCE_NAME); - - $matched = Allocation::query()->findOrFail($response->json('attributes.id')); - - $this->assertSame($server->id, $matched->server_id); - $this->assertJsonTransformedWith($response->json('attributes'), $matched); - } - - /** - * Test that a user without the required permissions cannot create an allocation for - * the server instance. - */ - public function testAllocationCannotBeCreatedIfUserDoesNotHavePermission(): void - { - /** @var \App\Models\Server $server */ - [$user, $server] = $this->generateTestAccount([Permission::ACTION_ALLOCATION_UPDATE]); - $server->update(['allocation_limit' => 2]); - - $this->actingAs($user)->postJson($this->link($server, '/network/allocations'))->assertForbidden(); - } - - /** - * Test that an error is returned to the user if this feature is not enabled on the system. - */ - public function testAllocationCannotBeCreatedIfNotEnabled(): void - { - config()->set('panel.client_features.allocations.enabled', false); - - /** @var \App\Models\Server $server */ - [$user, $server] = $this->generateTestAccount(); - $server->update(['allocation_limit' => 2]); - - $this->actingAs($user)->postJson($this->link($server, '/network/allocations')) - ->assertStatus(Response::HTTP_BAD_REQUEST) - ->assertJsonPath('errors.0.code', 'AutoAllocationNotEnabledException') - ->assertJsonPath('errors.0.detail', 'Server auto-allocation is not enabled for this instance.'); - } - - /** - * Test that an allocation cannot be created if the server has reached its allocation limit. - */ - public function testAllocationCannotBeCreatedIfServerIsAtLimit(): void - { - /** @var \App\Models\Server $server */ - [$user, $server] = $this->generateTestAccount(); - $server->update(['allocation_limit' => 1]); - - $this->actingAs($user)->postJson($this->link($server, '/network/allocations')) - ->assertStatus(Response::HTTP_BAD_REQUEST) - ->assertJsonPath('errors.0.code', 'DisplayException') - ->assertJsonPath('errors.0.detail', 'Cannot assign additional allocations to this server: limit has been reached.'); - } - - public static function permissionDataProvider(): array - { - return [[[Permission::ACTION_ALLOCATION_CREATE]], [[]]]; - } -} diff --git a/tests/Integration/Api/Client/Server/Allocation/DeleteAllocationTest.php b/tests/Integration/Api/Client/Server/Allocation/DeleteAllocationTest.php deleted file mode 100644 index 07f101a62e..0000000000 --- a/tests/Integration/Api/Client/Server/Allocation/DeleteAllocationTest.php +++ /dev/null @@ -1,105 +0,0 @@ -generateTestAccount($permission); - $server->update(['allocation_limit' => 2]); - - /** @var \App\Models\Allocation $allocation */ - $allocation = Allocation::factory()->create([ - 'server_id' => $server->id, - 'node_id' => $server->node_id, - 'notes' => 'hodor', - ]); - - $this->actingAs($user)->deleteJson($this->link($allocation))->assertStatus(Response::HTTP_NO_CONTENT); - - $this->assertDatabaseHas('allocations', ['id' => $allocation->id, 'server_id' => null, 'notes' => null]); - } - - /** - * Test that an error is returned if the user does not have permissiont to delete an allocation. - */ - public function testErrorIsReturnedIfUserDoesNotHavePermission(): void - { - /** @var \App\Models\Server $server */ - [$user, $server] = $this->generateTestAccount([Permission::ACTION_ALLOCATION_CREATE]); - - /** @var \App\Models\Allocation $allocation */ - $allocation = Allocation::factory()->create([ - 'server_id' => $server->id, - 'node_id' => $server->node_id, - 'notes' => 'hodor', - ]); - - $this->actingAs($user)->deleteJson($this->link($allocation))->assertForbidden(); - - $this->assertDatabaseHas('allocations', ['id' => $allocation->id, 'server_id' => $server->id]); - } - - /** - * Test that an allocation is not deleted if it is currently marked as the primary allocation - * for the server. - */ - public function testErrorIsReturnedIfAllocationIsPrimary(): void - { - /** @var \App\Models\Server $server */ - [$user, $server] = $this->generateTestAccount(); - $server->update(['allocation_limit' => 2]); - - $this->actingAs($user)->deleteJson($this->link($server->allocation)) - ->assertStatus(Response::HTTP_BAD_REQUEST) - ->assertJsonPath('errors.0.code', 'DisplayException') - ->assertJsonPath('errors.0.detail', 'You cannot delete the primary allocation for this server.'); - } - - public function testAllocationCannotBeDeletedIfServerLimitIsNotDefined(): void - { - [$user, $server] = $this->generateTestAccount(); - - /** @var \App\Models\Allocation $allocation */ - $allocation = Allocation::factory()->forServer($server)->create(['notes' => 'Test notes']); - - $this->actingAs($user)->deleteJson($this->link($allocation)) - ->assertStatus(400) - ->assertJsonPath('errors.0.detail', 'You cannot delete allocations for this server: no allocation limit is set.'); - - $allocation->refresh(); - $this->assertNotNull($allocation->notes); - $this->assertEquals($server->id, $allocation->server_id); - } - - /** - * Test that an allocation cannot be deleted if it does not belong to the server instance. - */ - public function testErrorIsReturnedIfAllocationDoesNotBelongToServer(): void - { - /** @var \App\Models\Server $server */ - [$user, $server] = $this->generateTestAccount(); - [, $server2] = $this->generateTestAccount(); - - $this->actingAs($user)->deleteJson($this->link($server2->allocation))->assertNotFound(); - $this->actingAs($user)->deleteJson($this->link($server, "/network/allocations/{$server2->allocation_id}"))->assertNotFound(); - } - - public static function permissionDataProvider(): array - { - return [[[Permission::ACTION_ALLOCATION_DELETE]], [[]]]; - } -} diff --git a/tests/Integration/Api/Client/Server/NetworkAllocationControllerTest.php b/tests/Integration/Api/Client/Server/NetworkAllocationControllerTest.php deleted file mode 100644 index b1e7279eba..0000000000 --- a/tests/Integration/Api/Client/Server/NetworkAllocationControllerTest.php +++ /dev/null @@ -1,140 +0,0 @@ -generateTestAccount(); - - $response = $this->actingAs($user)->getJson($this->link($server, '/network/allocations')); - - $response->assertOk(); - $response->assertJsonPath('object', 'list'); - $response->assertJsonCount(1, 'data'); - - $this->assertJsonTransformedWith($response->json('data.0.attributes'), $server->allocation); - } - - /** - * Test that allocations cannot be returned without the required user permissions. - */ - public function testServerAllocationsAreNotReturnedWithoutPermission(): void - { - [$user, $server] = $this->generateTestAccount(); - $user2 = User::factory()->create(); - - $server->owner_id = $user2->id; - $server->save(); - - $this->actingAs($user)->getJson($this->link($server, '/network/allocations')) - ->assertNotFound(); - - [$user, $server] = $this->generateTestAccount([Permission::ACTION_ALLOCATION_CREATE]); - - $this->actingAs($user)->getJson($this->link($server, '/network/allocations')) - ->assertForbidden(); - } - - /** - * Tests that notes on an allocation can be set correctly. - * - * @dataProvider updatePermissionsDataProvider - */ - public function testAllocationNotesCanBeUpdated(array $permissions): void - { - [$user, $server] = $this->generateTestAccount($permissions); - $allocation = $server->allocation; - - $this->assertNull($allocation->notes); - - $this->actingAs($user)->postJson($this->link($allocation), []) - ->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY) - ->assertJsonPath('errors.0.meta.rule', 'present'); - - $this->actingAs($user)->postJson($this->link($allocation), ['notes' => 'Test notes']) - ->assertOk() - ->assertJsonPath('object', Allocation::RESOURCE_NAME) - ->assertJsonPath('attributes.notes', 'Test notes'); - - $allocation = $allocation->refresh(); - - $this->assertSame('Test notes', $allocation->notes); - - $this->actingAs($user)->postJson($this->link($allocation), ['notes' => null]) - ->assertOk() - ->assertJsonPath('object', Allocation::RESOURCE_NAME) - ->assertJsonPath('attributes.notes', null); - - $allocation = $allocation->refresh(); - - $this->assertNull($allocation->notes); - } - - public function testAllocationNotesCannotBeUpdatedByInvalidUsers(): void - { - [$user, $server] = $this->generateTestAccount(); - $user2 = User::factory()->create(); - - $server->owner_id = $user2->id; - $server->save(); - - $this->actingAs($user)->postJson($this->link($server->allocation))->assertNotFound(); - - [$user, $server] = $this->generateTestAccount([Permission::ACTION_ALLOCATION_CREATE]); - - $this->actingAs($user)->postJson($this->link($server->allocation))->assertForbidden(); - } - - /** - * @dataProvider updatePermissionsDataProvider - */ - public function testPrimaryAllocationCanBeModified(array $permissions): void - { - [$user, $server] = $this->generateTestAccount($permissions); - $allocation = $server->allocation; - $allocation2 = Allocation::factory()->create(['node_id' => $server->node_id, 'server_id' => $server->id]); - - $server->allocation_id = $allocation->id; - $server->save(); - - $this->actingAs($user)->postJson($this->link($allocation2, '/primary')) - ->assertOk(); - - $server = $server->refresh(); - - $this->assertSame($allocation2->id, $server->allocation_id); - } - - public function testPrimaryAllocationCannotBeModifiedByInvalidUser(): void - { - [$user, $server] = $this->generateTestAccount(); - $user2 = User::factory()->create(); - - $server->owner_id = $user2->id; - $server->save(); - - $this->actingAs($user)->postJson($this->link($server->allocation, '/primary')) - ->assertNotFound(); - - [$user, $server] = $this->generateTestAccount([Permission::ACTION_ALLOCATION_CREATE]); - - $this->actingAs($user)->postJson($this->link($server->allocation, '/primary')) - ->assertForbidden(); - } - - public static function updatePermissionsDataProvider(): array - { - return [[[]], [[Permission::ACTION_ALLOCATION_UPDATE]]]; - } -} diff --git a/tests/Integration/Services/Allocations/FindAssignableAllocationServiceTest.php b/tests/Integration/Services/Allocations/FindAssignableAllocationServiceTest.php deleted file mode 100644 index 382703b036..0000000000 --- a/tests/Integration/Services/Allocations/FindAssignableAllocationServiceTest.php +++ /dev/null @@ -1,174 +0,0 @@ -set('panel.client_features.allocations.enabled', true); - config()->set('panel.client_features.allocations.range_start', 0); - config()->set('panel.client_features.allocations.range_end', 0); - } - - /** - * Test that an unassigned allocation is preferred rather than creating an entirely new - * allocation for the server. - */ - public function testExistingAllocationIsPreferred(): void - { - $server = $this->createServerModel(); - - $created = Allocation::factory()->create([ - 'node_id' => $server->node_id, - 'ip' => $server->allocation->ip, - ]); - - $response = $this->getService()->handle($server); - - $this->assertSame($created->id, $response->id); - $this->assertSame($server->allocation->ip, $response->ip); - $this->assertSame($server->node_id, $response->node_id); - $this->assertSame($server->id, $response->server_id); - $this->assertNotSame($server->allocation_id, $response->id); - } - - /** - * Test that a new allocation is created if there is not a free one available. - */ - public function testNewAllocationIsCreatedIfOneIsNotFound(): void - { - $server = $this->createServerModel(); - config()->set('panel.client_features.allocations.range_start', 5000); - config()->set('panel.client_features.allocations.range_end', 5005); - - $response = $this->getService()->handle($server); - $this->assertSame($server->id, $response->server_id); - $this->assertSame($server->allocation->ip, $response->ip); - $this->assertSame($server->node_id, $response->node_id); - $this->assertNotSame($server->allocation_id, $response->id); - $this->assertTrue($response->port >= 5000 && $response->port <= 5005); - } - - /** - * Test that a currently assigned port is never assigned to a server. - */ - public function testOnlyPortNotInUseIsCreated(): void - { - $server = $this->createServerModel(); - $server2 = $this->createServerModel(['node_id' => $server->node_id]); - - config()->set('panel.client_features.allocations.range_start', 5000); - config()->set('panel.client_features.allocations.range_end', 5001); - - Allocation::factory()->create([ - 'server_id' => $server2->id, - 'node_id' => $server->node_id, - 'ip' => $server->allocation->ip, - 'port' => 5000, - ]); - - $response = $this->getService()->handle($server); - $this->assertSame(5001, $response->port); - } - - public function testExceptionIsThrownIfNoMoreAllocationsCanBeCreatedInRange(): void - { - $server = $this->createServerModel(); - $server2 = $this->createServerModel(['node_id' => $server->node_id]); - config()->set('panel.client_features.allocations.range_start', 5000); - config()->set('panel.client_features.allocations.range_end', 5005); - - for ($i = 5000; $i <= 5005; $i++) { - Allocation::factory()->create([ - 'ip' => $server->allocation->ip, - 'port' => $i, - 'node_id' => $server->node_id, - 'server_id' => $server2->id, - ]); - } - - $this->expectException(NoAutoAllocationSpaceAvailableException::class); - $this->expectExceptionMessage('Cannot assign additional allocation: no more space available on node.'); - - $this->getService()->handle($server); - } - - /** - * Test that we only auto-allocate from the current server's IP address space, and not a random - * IP address available on that node. - */ - public function testExceptionIsThrownIfOnlyFreePortIsOnADifferentIp(): void - { - $server = $this->createServerModel(); - - Allocation::factory()->times(5)->create(['node_id' => $server->node_id]); - - $this->expectException(NoAutoAllocationSpaceAvailableException::class); - $this->expectExceptionMessage('Cannot assign additional allocation: no more space available on node.'); - - $this->getService()->handle($server); - } - - public function testExceptionIsThrownIfStartOrEndRangeIsNotDefined(): void - { - $server = $this->createServerModel(); - - $this->expectException(NoAutoAllocationSpaceAvailableException::class); - $this->expectExceptionMessage('Cannot assign additional allocation: no more space available on node.'); - - $this->getService()->handle($server); - } - - public function testExceptionIsThrownIfStartOrEndRangeIsNotNumeric(): void - { - $server = $this->createServerModel(); - config()->set('panel.client_features.allocations.range_start', 'hodor'); - config()->set('panel.client_features.allocations.range_end', 10); - - try { - $this->getService()->handle($server); - $this->fail('This assertion should not be reached.'); - } catch (\Exception $exception) { - $this->assertInstanceOf(\InvalidArgumentException::class, $exception); - $this->assertSame('Expected an integerish value. Got: string', $exception->getMessage()); - } - - config()->set('panel.client_features.allocations.range_start', 10); - config()->set('panel.client_features.allocations.range_end', 'hodor'); - - try { - $this->getService()->handle($server); - $this->fail('This assertion should not be reached.'); - } catch (\Exception $exception) { - $this->assertInstanceOf(\InvalidArgumentException::class, $exception); - $this->assertSame('Expected an integerish value. Got: string', $exception->getMessage()); - } - } - - public function testExceptionIsThrownIfFeatureIsNotEnabled(): void - { - config()->set('panel.client_features.allocations.enabled', false); - $server = $this->createServerModel(); - - $this->expectException(AutoAllocationNotEnabledException::class); - - $this->getService()->handle($server); - } - - private function getService(): FindAssignableAllocationService - { - return $this->app->make(FindAssignableAllocationService::class); - } -} diff --git a/tests/Integration/Services/Servers/BuildModificationServiceTest.php b/tests/Integration/Services/Servers/BuildModificationServiceTest.php index 152b11039f..e633a5d2ae 100644 --- a/tests/Integration/Services/Servers/BuildModificationServiceTest.php +++ b/tests/Integration/Services/Servers/BuildModificationServiceTest.php @@ -6,9 +6,7 @@ use GuzzleHttp\Psr7\Request; use GuzzleHttp\Psr7\Response; use App\Models\Server; -use App\Models\Allocation; use GuzzleHttp\Exception\RequestException; -use App\Exceptions\DisplayException; use App\Tests\Integration\IntegrationTestCase; use App\Repositories\Daemon\DaemonServerRepository; use App\Services\Servers\BuildModificationService; @@ -28,76 +26,6 @@ protected function setUp(): void $this->daemonServerRepository = $this->mock(DaemonServerRepository::class); } - /** - * Test that allocations can be added and removed from a server. Only the allocations on the - * current node and belonging to this server should be modified. - */ - public function testAllocationsCanBeModifiedForTheServer(): void - { - $server = $this->createServerModel(); - $server2 = $this->createServerModel(); - - /** @var \App\Models\Allocation[] $allocations */ - $allocations = Allocation::factory()->times(4)->create(['node_id' => $server->node_id, 'notes' => 'Random notes']); - - $initialAllocationId = $server->allocation_id; - $allocations[0]->update(['server_id' => $server->id, 'notes' => 'Test notes']); - - // Some additional test allocations for the other server, not the server we are attempting - // to modify. - $allocations[2]->update(['server_id' => $server2->id]); - $allocations[3]->update(['server_id' => $server2->id]); - - $this->daemonServerRepository->expects('setServer->sync')->andReturnUndefined(); - - $response = $this->getService()->handle($server, [ - // Attempt to add one new allocation, and an allocation assigned to another server. The - // other server allocation should be ignored, and only the allocation for this server should - // be used. - 'add_allocations' => [$allocations[2]->id, $allocations[1]->id], - // Remove the default server allocation, ensuring that the new allocation passed through - // in the data becomes the default allocation. - 'remove_allocations' => [$server->allocation_id, $allocations[0]->id, $allocations[3]->id], - ]); - - $this->assertInstanceOf(Server::class, $response); - - // Only one allocation should exist for this server now. - $this->assertCount(1, $response->allocations); - $this->assertSame($allocations[1]->id, $response->allocation_id); - $this->assertNull($response->allocation->notes); - - // These two allocations should not have been touched. - $this->assertDatabaseHas('allocations', ['id' => $allocations[2]->id, 'server_id' => $server2->id]); - $this->assertDatabaseHas('allocations', ['id' => $allocations[3]->id, 'server_id' => $server2->id]); - - // Both of these allocations should have been removed from the server, and have had their - // notes properly reset. - $this->assertDatabaseHas('allocations', ['id' => $initialAllocationId, 'server_id' => null, 'notes' => null]); - $this->assertDatabaseHas('allocations', ['id' => $allocations[0]->id, 'server_id' => null, 'notes' => null]); - } - - /** - * Test that an exception is thrown if removing the default allocation without also assigning - * new allocations to the server. - */ - public function testExceptionIsThrownIfRemovingTheDefaultAllocation(): void - { - $server = $this->createServerModel(); - /** @var \App\Models\Allocation[] $allocations */ - $allocations = Allocation::factory()->times(4)->create(['node_id' => $server->node_id]); - - $allocations[0]->update(['server_id' => $server->id]); - - $this->expectException(DisplayException::class); - $this->expectExceptionMessage('You are attempting to delete the default allocation for this server but there is no fallback allocation to use.'); - - $this->getService()->handle($server, [ - 'add_allocations' => [], - 'remove_allocations' => [$server->allocation_id, $allocations[0]->id], - ]); - } - /** * Test that the build data for the server is properly passed along to the daemon instance so that * the server data is updated in realtime. This test also ensures that only certain fields get updated @@ -164,91 +92,6 @@ public function testConnectionExceptionIsIgnoredWhenUpdatingServerSettings(): vo $this->assertDatabaseHas('servers', ['id' => $response->id, 'memory' => 256, 'disk' => 10240]); } - /** - * Test that no exception is thrown if we are only removing an allocation. - */ - public function testNoExceptionIsThrownIfOnlyRemovingAllocation(): void - { - $server = $this->createServerModel(); - /** @var \App\Models\Allocation $allocation */ - $allocation = Allocation::factory()->create(['node_id' => $server->node_id, 'server_id' => $server->id]); - - $this->daemonServerRepository->expects('setServer->sync')->andReturnUndefined(); - - $this->getService()->handle($server, [ - 'remove_allocations' => [$allocation->id], - ]); - - $this->assertDatabaseHas('allocations', ['id' => $allocation->id, 'server_id' => null]); - } - - /** - * Test that allocations in both the add and remove arrays are only added, and not removed. - * This scenario wouldn't really happen in the UI, but it is possible to perform via the API, - * so we want to make sure that the logic being used doesn't break if the allocation exists - * in both arrays. - * - * We'll default to adding the allocation in this case. - */ - public function testAllocationInBothAddAndRemoveIsAdded(): void - { - $server = $this->createServerModel(); - /** @var \App\Models\Allocation $allocation */ - $allocation = Allocation::factory()->create(['node_id' => $server->node_id]); - - $this->daemonServerRepository->expects('setServer->sync')->andReturnUndefined(); - - $this->getService()->handle($server, [ - 'add_allocations' => [$allocation->id], - 'remove_allocations' => [$allocation->id], - ]); - - $this->assertDatabaseHas('allocations', ['id' => $allocation->id, 'server_id' => $server->id]); - } - - /** - * Test that using the same allocation ID multiple times in the array does not cause an error. - */ - public function testUsingSameAllocationIdMultipleTimesDoesNotError(): void - { - $server = $this->createServerModel(); - /** @var \App\Models\Allocation $allocation */ - $allocation = Allocation::factory()->create(['node_id' => $server->node_id, 'server_id' => $server->id]); - /** @var \App\Models\Allocation $allocation2 */ - $allocation2 = Allocation::factory()->create(['node_id' => $server->node_id]); - - $this->daemonServerRepository->expects('setServer->sync')->andReturnUndefined(); - - $this->getService()->handle($server, [ - 'add_allocations' => [$allocation2->id, $allocation2->id], - 'remove_allocations' => [$allocation->id, $allocation->id], - ]); - - $this->assertDatabaseHas('allocations', ['id' => $allocation->id, 'server_id' => null]); - $this->assertDatabaseHas('allocations', ['id' => $allocation2->id, 'server_id' => $server->id]); - } - - /** - * Test that any changes we made to the server or allocations are rolled back if there is an - * exception while performing any action. This is different from the connection exception - * test which should properly ignore connection issues. We want any other type of exception - * to properly be thrown back to the caller. - */ - public function testThatUpdatesAreRolledBackIfExceptionIsEncountered(): void - { - $server = $this->createServerModel(); - /** @var \App\Models\Allocation $allocation */ - $allocation = Allocation::factory()->create(['node_id' => $server->node_id]); - - $this->daemonServerRepository->expects('setServer->sync')->andThrows(new DisplayException('Test')); - - $this->expectException(DisplayException::class); - - $this->getService()->handle($server, ['add_allocations' => [$allocation->id]]); - - $this->assertDatabaseHas('allocations', ['id' => $allocation->id, 'server_id' => null]); - } - private function getService(): BuildModificationService { return $this->app->make(BuildModificationService::class); diff --git a/tests/Integration/Services/Servers/ServerCreationServiceTest.php b/tests/Integration/Services/Servers/ServerCreationServiceTest.php index c0b82a285d..e6a008b837 100644 --- a/tests/Integration/Services/Servers/ServerCreationServiceTest.php +++ b/tests/Integration/Services/Servers/ServerCreationServiceTest.php @@ -9,7 +9,6 @@ use App\Models\User; use GuzzleHttp\Psr7\Response; use App\Models\Server; -use App\Models\Allocation; use Illuminate\Foundation\Testing\WithFaker; use GuzzleHttp\Exception\BadResponseException; use Illuminate\Validation\ValidationException; @@ -59,13 +58,8 @@ public function testServerIsCreatedWithDeploymentObject(): void /** @var \App\Models\Node $node */ $node = Node::factory()->create(); - /** @var \App\Models\Allocation[]|\Illuminate\Database\Eloquent\Collection $allocations */ - $allocations = Allocation::factory()->times(5)->create([ - 'node_id' => $node->id, - ]); - $deployment = (new DeploymentObject())->setDedicated(true)->setPorts([ - $allocations[0]->port, + 1234, ]); $egg = $this->cloneEggAndVariables($this->bungeecord); @@ -87,9 +81,7 @@ public function testServerIsCreatedWithDeploymentObject(): void 'startup' => 'java server2.jar', 'image' => 'java:8', 'egg_id' => $egg->id, - 'allocation_additional' => [ - $allocations[4]->id, - ], + 'ports' => [1234, 2345, 3456], 'environment' => [ 'BUNGEE_VERSION' => '123', 'SERVER_JARFILE' => 'server2.jar', @@ -125,18 +117,13 @@ public function testServerIsCreatedWithDeploymentObject(): void $this->assertSame('server2.jar', $response->variables[1]->server_value); foreach ($data as $key => $value) { - if (in_array($key, ['allocation_additional', 'environment', 'start_on_completion'])) { + if (in_array($key, ['environment', 'start_on_completion'])) { continue; } $this->assertSame($value, $response->{$key}, "Failed asserting equality of '$key' in server response. Got: [{$response->{$key}}] Expected: [$value]"); } - $this->assertCount(2, $response->allocations); - $this->assertSame($response->allocation_id, $response->allocations[0]->id); - $this->assertSame($allocations[0]->id, $response->allocations[0]->id); - $this->assertSame($allocations[4]->id, $response->allocations[1]->id); - $this->assertFalse($response->isSuspended()); $this->assertFalse($response->oom_killer); $this->assertSame(0, $response->database_limit); @@ -156,17 +143,11 @@ public function testErrorEncounteredByDaemonCausesServerToBeDeleted(): void /** @var \App\Models\Node $node */ $node = Node::factory()->create(); - /** @var \App\Models\Allocation $allocation */ - $allocation = Allocation::factory()->create([ - 'node_id' => $node->id, - ]); - $data = [ 'name' => $this->faker->name(), 'description' => $this->faker->sentence(), 'owner_id' => $user->id, - 'allocation_id' => $allocation->id, - 'node_id' => $allocation->node_id, + 'node_id' => $node->id, 'memory' => 256, 'swap' => 128, 'disk' => 100, diff --git a/tests/Traits/Integration/CreatesTestModels.php b/tests/Traits/Integration/CreatesTestModels.php index 12d6459347..68d54beda6 100644 --- a/tests/Traits/Integration/CreatesTestModels.php +++ b/tests/Traits/Integration/CreatesTestModels.php @@ -8,7 +8,6 @@ use App\Models\User; use App\Models\Server; use App\Models\Subuser; -use App\Models\Allocation; trait CreatesTestModels { @@ -37,12 +36,6 @@ public function createServerModel(array $attributes = []): Server $attributes['node_id'] = $node->id; } - if (!isset($attributes['allocation_id'])) { - /** @var \App\Models\Allocation $allocation */ - $allocation = Allocation::factory()->create(['node_id' => $attributes['node_id']]); - $attributes['allocation_id'] = $allocation->id; - } - if (empty($attributes['egg_id'])) { $egg = $this->getBungeecordEgg(); @@ -54,10 +47,8 @@ public function createServerModel(array $attributes = []): Server /** @var \App\Models\Server $server */ $server = Server::factory()->create($attributes); - Allocation::query()->where('id', $server->allocation_id)->update(['server_id' => $server->id]); - return $server->fresh([ - 'user', 'node', 'allocation', 'egg', + 'user', 'node', 'egg', ]); } From e15d515f71f3c5ab0efbe6f06ec597e01d31a284 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Fri, 14 Jun 2024 07:54:07 -0400 Subject: [PATCH 025/103] Wip --- app/Models/Server.php | 6 ++++++ app/Services/Servers/StartupCommandService.php | 3 +++ 2 files changed, 9 insertions(+) diff --git a/app/Models/Server.php b/app/Models/Server.php index 076c62ff79..f119eceb56 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -308,4 +308,10 @@ public function retrieveStatus(): string return cache()->get("servers.$this->uuid.container.status") ?? 'missing'; } + + public function getPrimaryEndpoint() + { + dd($this->ports); + dd($this->variables); + } } diff --git a/app/Services/Servers/StartupCommandService.php b/app/Services/Servers/StartupCommandService.php index 4703eb0753..3dd7cdc119 100644 --- a/app/Services/Servers/StartupCommandService.php +++ b/app/Services/Servers/StartupCommandService.php @@ -11,6 +11,9 @@ class StartupCommandService */ public function handle(Server $server, bool $hideAllValues = false): string { + $endpoint = $server->getPrimaryEndpoint(); + + $find = ['{{SERVER_MEMORY}}', '{{SERVER_IP}}', '{{SERVER_PORT}}']; $replace = [$server->memory, $server->allocation->ip, $server->allocation->port]; From 30051ab0d7495421e606ca32bb37f03e327b76ee Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 05:14:30 -0400 Subject: [PATCH 026/103] Add tooltips for versions --- resources/views/livewire/node-system-information.blade.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/views/livewire/node-system-information.blade.php b/resources/views/livewire/node-system-information.blade.php index 77436db06e..724e6282b9 100644 --- a/resources/views/livewire/node-system-information.blade.php +++ b/resources/views/livewire/node-system-information.blade.php @@ -1,8 +1,9 @@
- @switch($node->systemInformation()['version'] ?? 'false') + @switch($version = $node->systemInformation()['version'] ?? 'false') @case('false') true]) /> @@ -10,6 +11,7 @@ @default true]) @style([\Filament\Support\get_color_css_variables('success', shades: [400, 500], alias: 'tables::columns.icon-column.item') => true]) /> From 4cba1540ac7c68518c17f116cc49d68ba2ac67f7 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 05:14:54 -0400 Subject: [PATCH 027/103] Add endpoints --- app/Casts/EndpointCollection.php | 41 +++++++++++++++++++ app/Livewire/EndpointSynth.php | 26 ++++++++++++ app/Models/Objects/Endpoint.php | 30 +++++++------- app/Models/Server.php | 18 +++++--- app/Providers/AppServiceProvider.php | 4 ++ .../Servers/StartupCommandService.php | 4 +- 6 files changed, 102 insertions(+), 21 deletions(-) create mode 100644 app/Casts/EndpointCollection.php create mode 100644 app/Livewire/EndpointSynth.php diff --git a/app/Casts/EndpointCollection.php b/app/Casts/EndpointCollection.php new file mode 100644 index 0000000000..ece0268ae4 --- /dev/null +++ b/app/Casts/EndpointCollection.php @@ -0,0 +1,41 @@ +map(function ($value) { + return new Endpoint($value); + }); + } + + public function set($model, $key, $value, $attributes) + { + if (!$value instanceof Collection) { + return new Collection(); + } + + return $value->map(fn ($endpoint) => (string) $endpoint); + } + }; + } +} diff --git a/app/Livewire/EndpointSynth.php b/app/Livewire/EndpointSynth.php new file mode 100644 index 0000000000..91a5d1e386 --- /dev/null +++ b/app/Livewire/EndpointSynth.php @@ -0,0 +1,26 @@ +ip = $ip ?? self::INADDR_ANY; + $this->port = (int) $port; - $ip = $address; - if (str_contains($address, ':')) { - [$ip, $port] = explode(':', $address); + if (str_contains($port, ':')) { + [$this->ip, $this->port] = explode(':', $port); + } - throw_unless(is_numeric($port), new InvalidArgumentException("Port ($port) must be a number")); + throw_unless(filter_var($this->ip, FILTER_VALIDATE_IP) !== false, new InvalidArgumentException("$this->ip is an invalid IP address")); + throw_unless($this->port > self::PORT_FLOOR, "Port $this->port must be greater than " . self::PORT_FLOOR); + throw_unless($this->port < self::PORT_CEIL, "Port $this->port must be less than " . self::PORT_CEIL); + } - $port = (int) $port; + public function __toString() + { + if ($this->ip === self::INADDR_ANY) { + return (string) $this->port; } - throw_unless(is_int($port), new InvalidArgumentException("Port ($port) must be an integer")); - throw_unless(filter_var($ip, FILTER_VALIDATE_IP) !== false, new InvalidArgumentException("$ip is an invalid IP address")); - - $this->ip = $ip; - $this->port = $port; + return "$this->ip:$this->port"; } } diff --git a/app/Models/Server.php b/app/Models/Server.php index f119eceb56..52fce7771a 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -2,8 +2,10 @@ namespace App\Models; +use App\Casts\EndpointCollection; use App\Enums\ServerState; use App\Exceptions\Http\Connection\DaemonConnectionException; +use App\Models\Objects\Endpoint; use GuzzleHttp\Exception\GuzzleException; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Notifications\Notifiable; @@ -67,7 +69,6 @@ class Server extends Model 'database_limit' => 'present|nullable|integer|min:0', 'allocation_limit' => 'sometimes|nullable|integer|min:0', 'backup_limit' => 'present|nullable|integer|min:0', - 'ports' => 'array', ]; protected function casts(): array @@ -90,7 +91,7 @@ protected function casts(): array 'deleted_at' => 'datetime', 'installed_at' => 'datetime', 'docker_labels' => 'array', - 'ports' => 'array', + 'ports' => EndpointCollection::class, ]; } @@ -309,9 +310,16 @@ public function retrieveStatus(): string return cache()->get("servers.$this->uuid.container.status") ?? 'missing'; } - public function getPrimaryEndpoint() + public function getPrimaryEndpoint(): ?Endpoint { - dd($this->ports); - dd($this->variables); + $endpoint = $this->ports->first(); + + $portEggVariable = $this->variables->firstWhere('env_variable', 'SERVER_PORT'); + if ($portEggVariable) { + $portServerVariable = $this->serverVariables->firstWhere('variable_id', $portEggVariable->id); + $endpoint = new Endpoint($portServerVariable->variable_value); + } + + return $endpoint; } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index c0dcc1a64c..76474321a1 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -3,6 +3,7 @@ namespace App\Providers; use App\Extensions\Themes\Theme; +use App\Livewire\EndpointSynth; use App\Models; use App\Models\ApiKey; use App\Models\Node; @@ -21,6 +22,7 @@ use Illuminate\Support\ServiceProvider; use Illuminate\Support\Str; use Laravel\Sanctum\Sanctum; +use Livewire\Livewire; class AppServiceProvider extends ServiceProvider { @@ -72,6 +74,8 @@ public function boot(): void $this->bootAuth(); $this->bootBroadcast(); + Livewire::propertySynthesizer(EndpointSynth::class); + $bearerTokens = fn (OpenApi $openApi) => $openApi->secure(SecurityScheme::http('bearer')); Gate::define('viewApiDocs', fn () => true); Scramble::registerApi('application', ['api_path' => 'api/application', 'info' => ['version' => '1.0']]); diff --git a/app/Services/Servers/StartupCommandService.php b/app/Services/Servers/StartupCommandService.php index 3dd7cdc119..f75e613fc6 100644 --- a/app/Services/Servers/StartupCommandService.php +++ b/app/Services/Servers/StartupCommandService.php @@ -2,6 +2,7 @@ namespace App\Services\Servers; +use App\Models\Objects\Endpoint; use App\Models\Server; class StartupCommandService @@ -13,9 +14,8 @@ public function handle(Server $server, bool $hideAllValues = false): string { $endpoint = $server->getPrimaryEndpoint(); - $find = ['{{SERVER_MEMORY}}', '{{SERVER_IP}}', '{{SERVER_PORT}}']; - $replace = [$server->memory, $server->allocation->ip, $server->allocation->port]; + $replace = [$server->memory, $endpoint->ip ?? Endpoint::INADDR_ANY, $endpoint->port ?? '']; foreach ($server->variables as $variable) { $find[] = '{{' . $variable->env_variable . '}}'; From 405aa857b1f251c30ccad3a47a53bf53aa6851ff Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 05:23:33 -0400 Subject: [PATCH 028/103] Reset these for now --- lang/af/exceptions.php | 2 +- lang/ar/exceptions.php | 2 +- lang/be/exceptions.php | 2 +- lang/ca/exceptions.php | 2 +- lang/cs/exceptions.php | 2 +- lang/da/exceptions.php | 2 +- lang/de/exceptions.php | 2 +- lang/el/exceptions.php | 2 +- lang/en/exceptions.php | 2 +- lang/es/exceptions.php | 2 +- lang/fi/exceptions.php | 2 +- lang/fr/exceptions.php | 2 +- lang/he/exceptions.php | 2 +- lang/hi/exceptions.php | 2 +- lang/hr/exceptions.php | 2 +- lang/hu/exceptions.php | 2 +- lang/id/exceptions.php | 2 +- lang/it/exceptions.php | 2 +- lang/ja/exceptions.php | 2 +- lang/ko/exceptions.php | 2 +- lang/nl/exceptions.php | 2 +- lang/no/exceptions.php | 2 +- lang/pl/exceptions.php | 2 +- lang/pt/exceptions.php | 2 +- lang/ro/exceptions.php | 2 +- lang/ru/exceptions.php | 2 +- lang/sk/exceptions.php | 2 +- lang/sl/exceptions.php | 2 +- lang/sr/exceptions.php | 2 +- lang/sv/exceptions.php | 2 +- lang/th/exceptions.php | 2 +- lang/tr/exceptions.php | 2 +- lang/uk/exceptions.php | 2 +- lang/vi/exceptions.php | 2 +- lang/zh/exceptions.php | 2 +- 35 files changed, 35 insertions(+), 35 deletions(-) diff --git a/lang/af/exceptions.php b/lang/af/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/af/exceptions.php +++ b/lang/af/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/ar/exceptions.php b/lang/ar/exceptions.php index 0c2656e1fc..4de9d56aac 100644 --- a/lang/ar/exceptions.php +++ b/lang/ar/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'يجب ألا يكون هناك أي خوادم مرتبطة بالعقدة لكي يتم حذفها.', 'daemon_off_config_updated' => 'تم تحديث تكوين الدايمون لكن، واجهت مشكلة أثناء محاولة تحديث ملف التكوين تلقائيًا على الدايمون. ستحتاج إلى تحديث ملف التكوين (config.yml) يدويًا لتطبيق هذه التغييرات.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'تم تعيين خادم حاليًا لهذا التخصيص. لا يمكن حذف التخصيص إلا إذا لم يكن هناك خادم معين حاليًا.', 'too_many_ports' => 'لا يتم دعم إضافة أكثر من 1000 منفذ في نطاق واحد دفعة واحدة.', 'invalid_mapping' => 'التعيين المقدم للمنفذ :port كان غير صالح ولا يمكن معالجته.', diff --git a/lang/be/exceptions.php b/lang/be/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/be/exceptions.php +++ b/lang/be/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/ca/exceptions.php b/lang/ca/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/ca/exceptions.php +++ b/lang/ca/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/cs/exceptions.php b/lang/cs/exceptions.php index 2d7a1ac93b..337f026138 100644 --- a/lang/cs/exceptions.php +++ b/lang/cs/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Uzel nesmí mít žádné s ním spojené servery, aby mohl být smazán', 'daemon_off_config_updated' => 'Konfigurace daemonu byla aktualizována, ale byla zde chyba při automatické aktualizaci souborů konfigurace Daemonu. Je třeba soubory konfigurace Daemonu aktualizovat manuálně (config.yml), aby změny damemonu byly aplikovány.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'Server již využívá tuhle alokaci. Pro odstranění alokace, nesmí být žádný server spojen s alokací.', 'too_many_ports' => 'Přidání více než 1000 portů v jednom rozsahu najednou není podporováno.', 'invalid_mapping' => 'Mapování poskytnuto pro :port bylo nesprávné a nebylo možné ho zpracovat.', diff --git a/lang/da/exceptions.php b/lang/da/exceptions.php index 8b546c30b5..544bec5814 100644 --- a/lang/da/exceptions.php +++ b/lang/da/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'En node må ikke have nogen servere tilknyttet for at kunne slettes.', 'daemon_off_config_updated' => 'Daemon konfiguration er blevet opdateret, men der opstod en fejl under forsøget på automatisk at opdatere konfigurationsfilen på daemonen. Du skal manuelt opdatere konfigurationsfilen (config.yml) for at daemonen kan anvende disse ændringer.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'En server er i øjeblikket tildelt denne tildeling. En tildeling kan kun slettes, hvis ingen server i øjeblikket er tildelt.', 'too_many_ports' => 'Tilføjede af flere end 1000 porte i en enkelt række ad gangen understøttes ikke.', 'invalid_mapping' => 'Den angivne kortlægning for :port var ugyldig og kunne ikke behandles.', diff --git a/lang/de/exceptions.php b/lang/de/exceptions.php index 7c091e21a2..72193edd95 100644 --- a/lang/de/exceptions.php +++ b/lang/de/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Ein Node darf keine Server haben, die mit ihm verknüpft sind, um gelöscht zu werden.', 'daemon_off_config_updated' => 'Die Daemon Konfiguration wurde aktualisiert, jedoch gab es einen Fehler bei dem Versuch, die Konfigurationsdatei des Daemon automatisch zu aktualisieren. Du musst die Konfigurationsdatei (config.yml) manuell anpassen, damit die Änderungen übernommen werden.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'Derzeit ist ein Server dieser Zuweisung zugewiesen. Eine Zuordnung kann nur gelöscht werden, wenn derzeit kein Server zugewiesen ist.', 'too_many_ports' => 'Das Hinzufügen von mehr als 1000 Ports in einem einzigen Bereich wird nicht unterstützt.', 'invalid_mapping' => 'Das für :port angegebene Mapping war ungültig und konnte nicht verarbeitet werden.', diff --git a/lang/el/exceptions.php b/lang/el/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/el/exceptions.php +++ b/lang/el/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/en/exceptions.php b/lang/en/exceptions.php index 2cce4d85de..3c9adf4c90 100644 --- a/lang/en/exceptions.php +++ b/lang/en/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/es/exceptions.php b/lang/es/exceptions.php index f01d42a767..19a6b31276 100644 --- a/lang/es/exceptions.php +++ b/lang/es/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Un nodo no debe tener servidores vinculados a él para poder ser eliminado.', 'daemon_off_config_updated' => 'La configuración del daemon se ha actualizado, sin embargo, se encontró un error al intentar actualizar automáticamente el archivo de configuración en el daemon. Deberás actualizar manualmente el archivo de configuración (config.yml) para que el daemon aplique estos cambios.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'Actualmente hay un servidor asignado a esta asignación. Una asignación solo puede ser eliminada si ningún servidor está asignado actualmente.', 'too_many_ports' => 'Agregar más de 1000 puertos en un solo rango a la vez no está soportado.', 'invalid_mapping' => 'El mapeo proporcionado para el puerto :port era inválido y no pudo ser procesado.', diff --git a/lang/fi/exceptions.php b/lang/fi/exceptions.php index 903eebdb2f..84eee3d849 100644 --- a/lang/fi/exceptions.php +++ b/lang/fi/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Palvelimella ei saa olla siihen linkitettyjä palvelimia, jotta se voitaisiin poistaa.', 'daemon_off_config_updated' => 'Daemon konfiguraatio on päivitetty, mutta virhe ilmeni yritettäessä päivittää konfiguraatiota automaattisesti daemoniin. Sinun tulee päivittää daemonin konfiguraatio (config.yml) manuaalisesti, jotta muutokset voidaan ottaa käyttöön.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'Palvelin on tällä hetkellä määritelty tähän varaukseen. Varauksen voi poistaa vain, jos siihen ei ole tällä hetkellä määritettyä palvelinta.', 'too_many_ports' => 'Yli 1000 portin lisääminen yhteen alueeseen kerralla ei ole tuettua.', 'invalid_mapping' => ':port:lle annettu määritys oli virheellinen eikä sitä voitu käsitellä.', diff --git a/lang/fr/exceptions.php b/lang/fr/exceptions.php index cc838b7c68..790cccf695 100644 --- a/lang/fr/exceptions.php +++ b/lang/fr/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Un nœud ne doit avoir aucun serveur lié à lui pour être supprimé.', 'daemon_off_config_updated' => 'La configuration du daemon a été mis à jour, cependant, une erreur s\'est produite lors de la tentative de mise à jour automatique du fichier de configuration sur le daemon. Vous devrez mettre à jour manuellement le fichier de configuration (core.json) pour qu\'il puisse appliquer ces modifications.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'Un serveur est actuellement affecté à cette allocation. Une allocation ne peut être supprimée que si aucun serveur n\'utilise cette dernière.', 'too_many_ports' => 'L\'ajout de plus de 1000 ports dans une seule plage à la fois n\'est pas supporté.', 'invalid_mapping' => 'Le mappage fourni pour :port est invalide et n\'a pas pu être traitée.', diff --git a/lang/he/exceptions.php b/lang/he/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/he/exceptions.php +++ b/lang/he/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/hi/exceptions.php b/lang/hi/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/hi/exceptions.php +++ b/lang/hi/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/hr/exceptions.php b/lang/hr/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/hr/exceptions.php +++ b/lang/hr/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/hu/exceptions.php b/lang/hu/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/hu/exceptions.php +++ b/lang/hu/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/id/exceptions.php b/lang/id/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/id/exceptions.php +++ b/lang/id/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/it/exceptions.php b/lang/it/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/it/exceptions.php +++ b/lang/it/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/ja/exceptions.php b/lang/ja/exceptions.php index ee6c510cb4..a5bd12d3da 100644 --- a/lang/ja/exceptions.php +++ b/lang/ja/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => '削除するには、ノードにサーバーがリンクされていない必要があります。', 'daemon_off_config_updated' => 'デーモンの設定が更新されました。しかし、デーモンの設定ファイルを自動的に更新しようとする際にエラーが発生しました。 これらの変更を適用するには、デーモンの設定ファイル(config.yml)を手動で更新する必要があります。', ], - 'ports' => [ + 'allocations' => [ 'server_using' => '現在サーバーは割り当てられています。割り当てはサーバーが現在割り当てられていない場合にのみ削除できます。', 'too_many_ports' => '一度に1000以上のポートを追加することはできません。', 'invalid_mapping' => ':port のマッピングは無効で、処理することができませんでした。', diff --git a/lang/ko/exceptions.php b/lang/ko/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/ko/exceptions.php +++ b/lang/ko/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/nl/exceptions.php b/lang/nl/exceptions.php index e4e42e6380..6e2fe678f4 100644 --- a/lang/nl/exceptions.php +++ b/lang/nl/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Een node moet geen actieve servers meer hebben voordat deze kan worden verwijderd.', 'daemon_off_config_updated' => 'De daemonconfiguratie is bijgewerkt, er is echter een fout opgetreden bij het automatisch bijwerken van het configuratiebestand op de Daemon. U moet handmatig het configuratiebestand bijwerken (config.yml) voor de daemon om deze veranderingen toe te passen.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'Een server is momenteel toegewezen aan deze toewijzing. Een toewijzing kan alleen worden verwijderd als er momenteel geen server is toegewezen.', 'too_many_ports' => 'Meer dan 1000 poorten binnen één bereik toevoegen wordt niet ondersteund.', 'invalid_mapping' => 'De opgegeven toewijzing voor :port was ongeldig en kon niet worden verwerkt.', diff --git a/lang/no/exceptions.php b/lang/no/exceptions.php index 923bbc11e2..f9a65b7448 100644 --- a/lang/no/exceptions.php +++ b/lang/no/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/pl/exceptions.php b/lang/pl/exceptions.php index bda35c9d5a..d821676b12 100644 --- a/lang/pl/exceptions.php +++ b/lang/pl/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Aby usunąć ten węzeł, nie możesz mieć podłączonych do niego serwerów.', 'daemon_off_config_updated' => 'Konfiguracja deamona została zaktualizowana, jednak wystąpił błąd podczas próby automatycznej aktualizacji pliku konfiguracyjnego deamona. Aby zastosować te zmiany, należy ręcznie zaktualizować plik konfiguracyjny (config.yml).', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'Serwer jest obecnie przypisany do tej alokacji. Alokację można usunąć tylko wtedy, gdy żaden serwer nie jest do niej przypisany.', 'too_many_ports' => 'Dodawanie więcej niż 1000 portów w jednym zakresie nie jest obsługiwane.', 'invalid_mapping' => 'Mapowanie podane dla :port było nieprawidłowe i nie mogło zostać przetworzone.', diff --git a/lang/pt/exceptions.php b/lang/pt/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/pt/exceptions.php +++ b/lang/pt/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/ro/exceptions.php b/lang/ro/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/ro/exceptions.php +++ b/lang/ro/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/ru/exceptions.php b/lang/ru/exceptions.php index 7e758cd3c4..0054e46bea 100644 --- a/lang/ru/exceptions.php +++ b/lang/ru/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Узел не должен иметь подключенных к нему серверов, чтобы быть удален.', 'daemon_off_config_updated' => 'Конфигурация демона была обновлена, но при попытке автоматического обновления конфигурационного файла произошла ошибка. Вам нужно вручную обновить конфигурационный файл (config.yml) для применения этих изменений.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'Сервер в настоящее время назначается для этого размещения. Распределение может быть удалено, только если ни один сервер не назначен.', 'too_many_ports' => 'Добавление более 1000 портов в одном диапазоне за раз не поддерживается.', 'invalid_mapping' => 'Сопоставление, предоставленное для порта {port}, было недопустимым и не могло быть обработано.', diff --git a/lang/sk/exceptions.php b/lang/sk/exceptions.php index 4b4732f180..56a7b8424c 100644 --- a/lang/sk/exceptions.php +++ b/lang/sk/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Uzol nemôže mať priradené žiadne servery aby mohol byť vymazaný.', 'daemon_off_config_updated' => 'Konfigurácia daemonu bola aktualizovaná, no pri pokuse o automatickú aktualizáciu konfigurácie na daemonovi sa vyskytla chyba. Budete musieť manuálne aktualizovať konfiguračný súbor (config.yml) aby sa táto zmena aplikovala na daemon.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'Server je momentálne priradený k tejto alokácii. Alokácia môže byť zmazaná, len ak k nej nieje priradený žiadny server.', 'too_many_ports' => 'Pridanie viac ako 1000 portov v jednom rozsahu nieje podporované.', 'invalid_mapping' => 'Mapovanie poskytnuté pre port :port nieje správne a nemohlo byť spracované.', diff --git a/lang/sl/exceptions.php b/lang/sl/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/sl/exceptions.php +++ b/lang/sl/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/sr/exceptions.php b/lang/sr/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/sr/exceptions.php +++ b/lang/sr/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/sv/exceptions.php b/lang/sv/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/sv/exceptions.php +++ b/lang/sv/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/th/exceptions.php b/lang/th/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/th/exceptions.php +++ b/lang/th/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/tr/exceptions.php b/lang/tr/exceptions.php index 53c269e8ea..cdf44c0891 100644 --- a/lang/tr/exceptions.php +++ b/lang/tr/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'Bir node\'un silinebilmesi için kendisine bağlı hiçbir sunucunun olmaması gerekir.', 'daemon_off_config_updated' => 'Daemon yapılandırması güncellendi, ancak Daemon\'daki yapılandırma dosyası otomatik olarak güncellenmeye çalışılırken bir hatayla karşılaşıldı. Bu değişiklikleri uygulamak için arka plan programının yapılandırma dosyasını (config.yml) manuel olarak güncellemeniz gerekecektir.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'Şu anda bu lokasyon bir sunucu atanmış. Bir lokasyon yalnızca şu anda hiçbir sunucu atanmamışsa silinebilir.', 'too_many_ports' => 'Tek bir aralığa 1000\'den fazla port (Bağlantı noktası) aynı anda eklenmesi desteklenmez.', 'invalid_mapping' => ':port için sağlanan eşleme geçersizdi ve uyhulanmadı.', diff --git a/lang/uk/exceptions.php b/lang/uk/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/uk/exceptions.php +++ b/lang/uk/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/vi/exceptions.php b/lang/vi/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/vi/exceptions.php +++ b/lang/vi/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', diff --git a/lang/zh/exceptions.php b/lang/zh/exceptions.php index 13cf4d8767..3977c87c24 100644 --- a/lang/zh/exceptions.php +++ b/lang/zh/exceptions.php @@ -6,7 +6,7 @@ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], - 'ports' => [ + 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', From bcb7240ed242591743f0313b2dbf59085453cbf5 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 05:24:19 -0400 Subject: [PATCH 029/103] Pint fixes --- app/Casts/EndpointCollection.php | 4 +--- app/Models/Objects/Endpoint.php | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/Casts/EndpointCollection.php b/app/Casts/EndpointCollection.php index ece0268ae4..701f10b288 100644 --- a/app/Casts/EndpointCollection.php +++ b/app/Casts/EndpointCollection.php @@ -6,8 +6,6 @@ use Illuminate\Contracts\Database\Eloquent\Castable; use Illuminate\Contracts\Database\Eloquent\CastsAttributes; use Illuminate\Support\Collection; -use Stringable; -use TypeError; class EndpointCollection implements Castable { @@ -17,7 +15,7 @@ public static function castUsing(array $arguments) { public function get($model, $key, $value, $attributes) { - if (! isset($attributes[$key])) { + if (!isset($attributes[$key])) { return new Collection(); } diff --git a/app/Models/Objects/Endpoint.php b/app/Models/Objects/Endpoint.php index 69772c00bd..61224fd29a 100644 --- a/app/Models/Objects/Endpoint.php +++ b/app/Models/Objects/Endpoint.php @@ -17,7 +17,8 @@ class Endpoint public int $port; public string $ip; - public function __construct(string|int $port, string $ip = null) { + public function __construct(string|int $port, string $ip = null) + { $this->ip = $ip ?? self::INADDR_ANY; $this->port = (int) $port; From b47f40bd13ab8e3dbed1d0e8293a6b49dddc3303 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 05:24:57 -0400 Subject: [PATCH 030/103] Remove debug --- database/migrations/2024_06_06_043350_modify_allocations.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/database/migrations/2024_06_06_043350_modify_allocations.php b/database/migrations/2024_06_06_043350_modify_allocations.php index 42c07b1aa9..b794478e71 100644 --- a/database/migrations/2024_06_06_043350_modify_allocations.php +++ b/database/migrations/2024_06_06_043350_modify_allocations.php @@ -25,8 +25,6 @@ public function up(): void $table->json('ports')->change(); }); - dd('works?'); - $portMappings = []; foreach (DB::table('allocations')->get() as $allocation) { $portMappings[$allocation->server_id][] = "$allocation->ip:$allocation->port"; From 1a26f5ce9e83345540e26c9e04730eed8d03d320 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 05:34:56 -0400 Subject: [PATCH 031/103] This goes first --- database/migrations/2024_06_06_043350_modify_allocations.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/database/migrations/2024_06_06_043350_modify_allocations.php b/database/migrations/2024_06_06_043350_modify_allocations.php index b794478e71..72cd27db8d 100644 --- a/database/migrations/2024_06_06_043350_modify_allocations.php +++ b/database/migrations/2024_06_06_043350_modify_allocations.php @@ -36,12 +36,12 @@ public function up(): void ->update(['ports' => json_encode($ports)]); } - Schema::dropIfExists('allocations'); - Schema::table('servers', function (Blueprint $table) { $table->dropColumn(['allocation_id']); }); + Schema::dropIfExists('allocations'); + Schema::table('nodes', function (Blueprint $table) { $table->boolean('strict_ports')->default(true); }); From 7c25fc2a9d4d3ab49a98cd633de4948ce4bf16ce Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 05:39:53 -0400 Subject: [PATCH 032/103] Revert these doc blocks --- app/Models/ActivityLog.php | 36 ++++++++++++++++++++++++++++ app/Models/ActivityLogSubject.php | 16 +++++++++++++ app/Models/Backup.php | 19 +++++++++++++++ app/Models/Database.php | 14 +++++++++++ app/Models/DatabaseHost.php | 12 ++++++++++ app/Models/Egg.php | 39 +++++++++++++++++++++++++++++++ app/Models/EggVariable.php | 21 +++++++++++++++++ app/Models/Mount.php | 13 +++++++++++ app/Models/Node.php | 30 ++++++++++++++++++++++++ app/Models/RecoveryToken.php | 7 ++++++ app/Models/Schedule.php | 19 +++++++++++++++ app/Models/ServerTransfer.php | 17 ++++++++++++++ app/Models/ServerVariable.php | 10 ++++++++ app/Models/Setting.php | 7 ++++++ app/Models/Subuser.php | 10 ++++++++ app/Models/Task.php | 14 +++++++++++ app/Models/UserSSHKey.php | 32 +++++++++++++++++++++++++ 17 files changed, 316 insertions(+) diff --git a/app/Models/ActivityLog.php b/app/Models/ActivityLog.php index 06b9824ad5..06fd2d108b 100644 --- a/app/Models/ActivityLog.php +++ b/app/Models/ActivityLog.php @@ -12,6 +12,42 @@ use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Model as IlluminateModel; +/** + * \App\Models\ActivityLog. + * + * @property int $id + * @property string|null $batch + * @property string $event + * @property string $ip + * @property string|null $description + * @property string|null $actor_type + * @property int|null $actor_id + * @property int|null $api_key_id + * @property \Illuminate\Support\Collection|null $properties + * @property \Carbon\Carbon $timestamp + * @property IlluminateModel|\Eloquent $actor + * @property \Illuminate\Database\Eloquent\Collection|\App\Models\ActivityLogSubject[] $subjects + * @property int|null $subjects_count + * @property \App\Models\ApiKey|null $apiKey + * + * @method static Builder|ActivityLog forActor(\Illuminate\Database\Eloquent\Model $actor) + * @method static Builder|ActivityLog forEvent(string $action) + * @method static Builder|ActivityLog newModelQuery() + * @method static Builder|ActivityLog newQuery() + * @method static Builder|ActivityLog query() + * @method static Builder|ActivityLog whereActorId($value) + * @method static Builder|ActivityLog whereActorType($value) + * @method static Builder|ActivityLog whereApiKeyId($value) + * @method static Builder|ActivityLog whereBatch($value) + * @method static Builder|ActivityLog whereDescription($value) + * @method static Builder|ActivityLog whereEvent($value) + * @method static Builder|ActivityLog whereId($value) + * @method static Builder|ActivityLog whereIp($value) + * @method static Builder|ActivityLog whereProperties($value) + * @method static Builder|ActivityLog whereTimestamp($value) + * + * @mixin \Eloquent + */ class ActivityLog extends Model { use MassPrunable; diff --git a/app/Models/ActivityLogSubject.php b/app/Models/ActivityLogSubject.php index 45b2c4ffe7..037d344f05 100644 --- a/app/Models/ActivityLogSubject.php +++ b/app/Models/ActivityLogSubject.php @@ -6,6 +6,22 @@ use Illuminate\Database\Eloquent\Relations\Pivot; use Illuminate\Database\Eloquent\SoftDeletes; +/** + * \App\Models\ActivityLogSubject. + * + * @property int $id + * @property int $activity_log_id + * @property int $subject_id + * @property string $subject_type + * @property \App\Models\ActivityLog|null $activityLog + * @property \Illuminate\Database\Eloquent\Model|\Eloquent $subject + * + * @method static \Illuminate\Database\Eloquent\Builder|ActivityLogSubject newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|ActivityLogSubject newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|ActivityLogSubject query() + * + * @mixin \Eloquent + */ class ActivityLogSubject extends Pivot { public $incrementing = true; diff --git a/app/Models/Backup.php b/app/Models/Backup.php index 48ab758b9d..3f2a931d1e 100644 --- a/app/Models/Backup.php +++ b/app/Models/Backup.php @@ -6,6 +6,25 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Relations\BelongsTo; +/** + * @property int $id + * @property int $server_id + * @property string $uuid + * @property bool $is_successful + * @property bool $is_locked + * @property string $name + * @property string[] $ignored_files + * @property string $disk + * @property string|null $checksum + * @property int $bytes + * @property string|null $upload_id + * @property \Carbon\CarbonImmutable|null $completed_at + * @property \Carbon\CarbonImmutable $created_at + * @property \Carbon\CarbonImmutable $updated_at + * @property \Carbon\CarbonImmutable|null $deleted_at + * @property \App\Models\Server $server + * @property \App\Models\AuditLog[] $audits + */ class Backup extends Model { use SoftDeletes; diff --git a/app/Models/Database.php b/app/Models/Database.php index 5270257f77..bd6bc6de34 100644 --- a/app/Models/Database.php +++ b/app/Models/Database.php @@ -5,6 +5,20 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Facades\DB; +/** + * @property int $id + * @property int $server_id + * @property int $database_host_id + * @property string $database + * @property string $username + * @property string $remote + * @property string $password + * @property int $max_connections + * @property \Carbon\Carbon $created_at + * @property \Carbon\Carbon $updated_at + * @property \App\Models\Server $server + * @property \App\Models\DatabaseHost $host + */ class Database extends Model { /** diff --git a/app/Models/DatabaseHost.php b/app/Models/DatabaseHost.php index e2ee4b3221..159e172613 100644 --- a/app/Models/DatabaseHost.php +++ b/app/Models/DatabaseHost.php @@ -5,6 +5,18 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; +/** + * @property int $id + * @property string $name + * @property string $host + * @property int $port + * @property string $username + * @property string $password + * @property int|null $max_databases + * @property int|null $node_id + * @property \Carbon\CarbonImmutable $created_at + * @property \Carbon\CarbonImmutable $updated_at + */ class DatabaseHost extends Model { /** diff --git a/app/Models/Egg.php b/app/Models/Egg.php index 0bf0a750e7..bf90c9e126 100644 --- a/app/Models/Egg.php +++ b/app/Models/Egg.php @@ -8,6 +8,45 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Str; +/** + * @property int $id + * @property string $uuid + * @property string $author + * @property string $name + * @property string|null $description + * @property array|null $features + * @property string $docker_image -- deprecated, use $docker_images + * @property array $docker_images + * @property string $update_url + * @property bool $force_outgoing_ip + * @property array|null $file_denylist + * @property string|null $config_files + * @property string|null $config_startup + * @property string|null $config_logs + * @property string|null $config_stop + * @property int|null $config_from + * @property string|null $startup + * @property bool $script_is_privileged + * @property string|null $script_install + * @property string $script_entry + * @property string $script_container + * @property int|null $copy_script_from + * @property \Carbon\Carbon $created_at + * @property \Carbon\Carbon $updated_at + * @property string|null $copy_script_install + * @property string $copy_script_entry + * @property string $copy_script_container + * @property string|null $inherit_config_files + * @property string|null $inherit_config_startup + * @property string|null $inherit_config_logs + * @property string|null $inherit_config_stop + * @property string $inherit_file_denylist + * @property array|null $inherit_features + * @property \Illuminate\Database\Eloquent\Collection|\App\Models\Server[] $servers + * @property \Illuminate\Database\Eloquent\Collection|\App\Models\EggVariable[] $variables + * @property \App\Models\Egg|null $scriptFrom + * @property \App\Models\Egg|null $configFrom + */ class Egg extends Model { /** diff --git a/app/Models/EggVariable.php b/app/Models/EggVariable.php index 40c901a38e..f847efd84c 100644 --- a/app/Models/EggVariable.php +++ b/app/Models/EggVariable.php @@ -5,6 +5,27 @@ use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\HasMany; +/** + * @property int $id + * @property int $egg_id + * @property null $sort + * @property string $name + * @property string $description + * @property string $env_variable + * @property string $default_value + * @property bool $user_viewable + * @property bool $user_editable + * @property string $rules + * @property \Carbon\CarbonImmutable $created_at + * @property \Carbon\CarbonImmutable $updated_at + * @property bool $required + * @property \App\Models\Egg $egg + * @property \App\Models\ServerVariable $serverVariable + * + * The "server_value" variable is only present on the object if you've loaded this model + * using the server relationship. + * @property string|null $server_value + */ class EggVariable extends Model { /** diff --git a/app/Models/Mount.php b/app/Models/Mount.php index ea42941108..aa335b9904 100644 --- a/app/Models/Mount.php +++ b/app/Models/Mount.php @@ -5,6 +5,19 @@ use Illuminate\Validation\Rules\NotIn; use Illuminate\Database\Eloquent\Relations\BelongsToMany; +/** + * @property int $id + * @property string $uuid + * @property string $name + * @property string $description + * @property string $source + * @property string $target + * @property bool $read_only + * @property bool $user_mountable + * @property \App\Models\Egg[]|\Illuminate\Database\Eloquent\Collection $eggs + * @property \App\Models\Node[]|\Illuminate\Database\Eloquent\Collection $nodes + * @property \App\Models\Server[]|\Illuminate\Database\Eloquent\Collection $servers + */ class Mount extends Model { /** diff --git a/app/Models/Node.php b/app/Models/Node.php index a933d16fee..72d01f8b95 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -12,6 +12,36 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasManyThrough; +/** + * @property int $id + * @property string $uuid + * @property bool $public + * @property string $name + * @property string|null $description + * @property string $fqdn + * @property string $scheme + * @property bool $behind_proxy + * @property bool $maintenance_mode + * @property int $memory + * @property int $memory_overallocate + * @property int $disk + * @property int $disk_overallocate + * @property int $cpu + * @property int $cpu_overallocate + * @property int $upload_size + * @property string $daemon_token_id + * @property string $daemon_token + * @property int $daemon_listen + * @property int $daemon_sftp + * @property string|null $daemon_sftp_alias + * @property string $daemon_base + * @property array $tags + * @property \Carbon\Carbon $created_at + * @property \Carbon\Carbon $updated_at + * @property \App\Models\Mount[]|\Illuminate\Database\Eloquent\Collection $mounts + * @property \App\Models\Server[]|\Illuminate\Database\Eloquent\Collection $servers + * @property \App\Models\Allocation[]|\Illuminate\Database\Eloquent\Collection $allocations + */ class Node extends Model { use Notifiable; diff --git a/app/Models/RecoveryToken.php b/app/Models/RecoveryToken.php index 731347d711..c4fe8c8ae1 100644 --- a/app/Models/RecoveryToken.php +++ b/app/Models/RecoveryToken.php @@ -4,6 +4,13 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; +/** + * @property int $id + * @property int $user_id + * @property string $token + * @property \Carbon\CarbonImmutable $created_at + * @property \App\Models\User $user + */ class RecoveryToken extends Model { /** diff --git a/app/Models/Schedule.php b/app/Models/Schedule.php index 5bee2998e5..7042d25a46 100644 --- a/app/Models/Schedule.php +++ b/app/Models/Schedule.php @@ -7,6 +7,25 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; +/** + * @property int $id + * @property int $server_id + * @property string $name + * @property string $cron_day_of_week + * @property string $cron_month + * @property string $cron_day_of_month + * @property string $cron_hour + * @property string $cron_minute + * @property bool $is_active + * @property bool $is_processing + * @property bool $only_when_online + * @property \Carbon\Carbon|null $last_run_at + * @property \Carbon\Carbon|null $next_run_at + * @property \Carbon\Carbon $created_at + * @property \Carbon\Carbon $updated_at + * @property \App\Models\Server $server + * @property \App\Models\Task[]|\Illuminate\Support\Collection $tasks + */ class Schedule extends Model { /** diff --git a/app/Models/ServerTransfer.php b/app/Models/ServerTransfer.php index e4772005c1..abfef3eb67 100644 --- a/app/Models/ServerTransfer.php +++ b/app/Models/ServerTransfer.php @@ -5,6 +5,23 @@ use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\BelongsTo; +/** + * @property int $id + * @property int $server_id + * @property int $old_node + * @property int $new_node + * @property int $old_allocation + * @property int $new_allocation + * @property array|null $old_additional_allocations + * @property array|null $new_additional_allocations + * @property bool|null $successful + * @property bool $archived + * @property \Carbon\Carbon $created_at + * @property \Carbon\Carbon $updated_at + * @property \App\Models\Server $server + * @property \App\Models\Node $oldNode + * @property \App\Models\Node $newNode + */ class ServerTransfer extends Model { /** diff --git a/app/Models/ServerVariable.php b/app/Models/ServerVariable.php index 1d8308eaff..0c7eeffc56 100644 --- a/app/Models/ServerVariable.php +++ b/app/Models/ServerVariable.php @@ -4,6 +4,16 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; +/** + * @property int $id + * @property int $server_id + * @property int $variable_id + * @property string $variable_value + * @property \Carbon\CarbonImmutable|null $created_at + * @property \Carbon\CarbonImmutable|null $updated_at + * @property \App\Models\EggVariable $variable + * @property \App\Models\Server $server + */ class ServerVariable extends Model { /** diff --git a/app/Models/Setting.php b/app/Models/Setting.php index 63d9cd3c98..4d4087f7c1 100644 --- a/app/Models/Setting.php +++ b/app/Models/Setting.php @@ -2,6 +2,13 @@ namespace App\Models; +/** + * App\Models\Setting. + * + * @property int $id + * @property string $key + * @property string $value + */ class Setting extends Model { /** diff --git a/app/Models/Subuser.php b/app/Models/Subuser.php index 3426f81cb3..566c8a7412 100644 --- a/app/Models/Subuser.php +++ b/app/Models/Subuser.php @@ -6,6 +6,16 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; +/** + * @property int $id + * @property int $user_id + * @property int $server_id + * @property array $permissions + * @property \Carbon\Carbon $created_at + * @property \Carbon\Carbon $updated_at + * @property \App\Models\User $user + * @property \App\Models\Server $server + */ class Subuser extends Model { use Notifiable; diff --git a/app/Models/Task.php b/app/Models/Task.php index 3f44b77998..6545ab5f5f 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -5,6 +5,20 @@ use Illuminate\Database\Eloquent\Relations\HasOneThrough; use Illuminate\Database\Eloquent\Relations\BelongsTo; +/** + * @property int $id + * @property int $schedule_id + * @property int $sequence_id + * @property string $action + * @property string $payload + * @property int $time_offset + * @property bool $is_queued + * @property bool $continue_on_failure + * @property \Carbon\Carbon $created_at + * @property \Carbon\Carbon $updated_at + * @property \App\Models\Schedule $schedule + * @property \App\Models\Server $server + */ class Task extends Model { /** diff --git a/app/Models/UserSSHKey.php b/app/Models/UserSSHKey.php index ff544c521f..1cafb2d8bb 100644 --- a/app/Models/UserSSHKey.php +++ b/app/Models/UserSSHKey.php @@ -5,6 +5,38 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Relations\BelongsTo; +/** + * \App\Models\UserSSHKey. + * + * @property int $id + * @property int $user_id + * @property string $name + * @property string $fingerprint + * @property string $public_key + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property \Illuminate\Support\Carbon|null $deleted_at + * @property \App\Models\User $user + * + * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey newQuery() + * @method static \Illuminate\Database\Query\Builder|UserSSHKey onlyTrashed() + * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey query() + * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey whereDeletedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey whereFingerprint($value) + * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey whereName($value) + * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey wherePublicKey($value) + * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey whereUpdatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey whereUserId($value) + * @method static \Illuminate\Database\Query\Builder|UserSSHKey withTrashed() + * @method static \Illuminate\Database\Query\Builder|UserSSHKey withoutTrashed() + * + * @mixin \Eloquent + * + * @method static \Database\Factories\UserSSHKeyFactory factory(...$parameters) + */ class UserSSHKey extends Model { use SoftDeletes; From 375a64a38e88275bb5e5a3bb237686bf6bf0ee44 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 05:40:21 -0400 Subject: [PATCH 033/103] Remove these relationships --- app/Models/Server.php | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/app/Models/Server.php b/app/Models/Server.php index 5aca895dd5..5aed0ad068 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -224,22 +224,6 @@ public function subusers(): HasMany return $this->hasMany(Subuser::class, 'server_id', 'id'); } - /** - * Gets the default allocation for a server. - */ - public function allocation(): BelongsTo - { - return $this->belongsTo(Allocation::class); - } - - /** - * Gets all allocations associated with this server. - */ - public function allocations(): HasMany - { - return $this->hasMany(Allocation::class); - } - /** * Gets information for the egg associated with this server. */ From a97341f6f22c3318a44b155b82f5b80bc07058c9 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 05:40:25 -0400 Subject: [PATCH 034/103] Cast to int --- app/Models/Objects/Endpoint.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Models/Objects/Endpoint.php b/app/Models/Objects/Endpoint.php index 61224fd29a..428898f74b 100644 --- a/app/Models/Objects/Endpoint.php +++ b/app/Models/Objects/Endpoint.php @@ -23,7 +23,8 @@ public function __construct(string|int $port, string $ip = null) $this->port = (int) $port; if (str_contains($port, ':')) { - [$this->ip, $this->port] = explode(':', $port); + [$this->ip, $port] = explode(':', $port); + $this->port = (int) $port; } throw_unless(filter_var($this->ip, FILTER_VALIDATE_IP) !== false, new InvalidArgumentException("$this->ip is an invalid IP address")); From 459d90e8d1c0e23d7eedea67082a75624a3328a3 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 05:44:53 -0400 Subject: [PATCH 035/103] Revert this --- app/Models/Server.php | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/app/Models/Server.php b/app/Models/Server.php index 5aed0ad068..2214c9eaf8 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -2,8 +2,10 @@ namespace App\Models; +use App\Casts\EndpointCollection; use App\Enums\ServerState; use App\Exceptions\Http\Connection\DaemonConnectionException; +use App\Models\Objects\Endpoint; use GuzzleHttp\Exception\GuzzleException; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Notifications\Notifiable; @@ -128,11 +130,6 @@ class Server extends Model 'installed_at' => null, ]; - /** - * The default relationships to load for all server models. - */ - protected $with = ['allocation']; - /** * Fields that are not mass assignable. */ @@ -152,7 +149,6 @@ class Server extends Model 'threads' => 'nullable|regex:/^[0-9-,]+$/', 'oom_killer' => 'sometimes|boolean', 'disk' => 'required|numeric|min:0', - 'allocation_id' => 'required|bail|unique:servers|exists:allocations,id', 'egg_id' => 'required|exists:eggs,id', 'startup' => 'required|string', 'skip_scripts' => 'sometimes|boolean', @@ -175,27 +171,33 @@ protected function casts(): array 'io' => 'integer', 'cpu' => 'integer', 'oom_killer' => 'boolean', - 'allocation_id' => 'integer', 'egg_id' => 'integer', 'database_limit' => 'integer', 'allocation_limit' => 'integer', 'backup_limit' => 'integer', - self::CREATED_AT => 'datetime', - self::UPDATED_AT => 'datetime', 'deleted_at' => 'datetime', 'installed_at' => 'datetime', 'docker_labels' => 'array', + 'ports' => EndpointCollection::class, ]; } /** * Returns the format for server allocations when communicating with the Daemon. */ - public function getAllocationMappings(): array + public function getPortMappings(): array { - return $this->allocations->where('node_id', $this->node_id)->groupBy('ip')->map(function ($item) { - return $item->pluck('port'); - })->toArray(); + $defaultIp = '0.0.0.0'; + + $ports = collect($this->ports) + ->map(fn ($port) => str_contains($port, ':') ? $port : "$defaultIp:$port") + ->mapToGroups(function ($port) { + [$ip, $port] = explode(':', $port); + + return [$ip => (int) $port]; + }); + + return $ports->all(); } public function isInstalled(): bool @@ -394,4 +396,17 @@ public function retrieveStatus(): string return cache()->get("servers.$this->uuid.container.status") ?? 'missing'; } + + public function getPrimaryEndpoint(): ?Endpoint + { + $endpoint = $this->ports->first(); + + $portEggVariable = $this->variables->firstWhere('env_variable', 'SERVER_PORT'); + if ($portEggVariable) { + $portServerVariable = $this->serverVariables->firstWhere('variable_id', $portEggVariable->id); + $endpoint = new Endpoint($portServerVariable->variable_value); + } + + return $endpoint; + } } From 8ea57bc46b30423bf26c3e9a48a34fbd17b8108a Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 05:53:29 -0400 Subject: [PATCH 036/103] Remove unused audit logs --- app/Models/AuditLog.php | 82 ----------------------------------------- app/Models/Backup.php | 1 - 2 files changed, 83 deletions(-) delete mode 100644 app/Models/AuditLog.php diff --git a/app/Models/AuditLog.php b/app/Models/AuditLog.php deleted file mode 100644 index aa9d57d6a8..0000000000 --- a/app/Models/AuditLog.php +++ /dev/null @@ -1,82 +0,0 @@ - 'required|uuid', - 'action' => 'required|string|max:191', - 'subaction' => 'nullable|string|max:191', - 'device' => 'array', - 'device.ip_address' => 'ip', - 'device.user_agent' => 'string', - 'metadata' => 'array', - ]; - - protected $table = 'audit_logs'; - - protected $guarded = [ - 'id', - 'created_at', - ]; - - protected function casts(): array - { - return [ - 'is_system' => 'bool', - 'device' => 'array', - 'metadata' => 'array', - 'created_at' => 'immutable_datetime', - ]; - } - - public function user(): BelongsTo - { - return $this->belongsTo(User::class); - } - - public function server(): BelongsTo - { - return $this->belongsTo(Server::class); - } - - /** - * Creates a new AuditLog model and returns it, attaching device information and the - * currently authenticated user if available. This model is not saved at this point, so - * you can always make modifications to it as needed before saving. - * - * @deprecated - */ - public static function instance(string $action, array $metadata, bool $isSystem = false): self - { - /** @var \Illuminate\Http\Request $request */ - $request = Container::getInstance()->make('request'); - if ($isSystem || !$request instanceof Request) { - $request = null; - } - - return (new self())->fill([ - 'uuid' => Uuid::uuid4()->toString(), - 'is_system' => $isSystem, - 'user_id' => ($request && $request->user()) ? $request->user()->id : null, - 'server_id' => null, - 'action' => $action, - 'device' => $request ? [ - 'ip_address' => $request->getClientIp() ?? '127.0.0.1', - 'user_agent' => $request->userAgent() ?? '', - ] : [], - 'metadata' => $metadata, - ]); - } -} diff --git a/app/Models/Backup.php b/app/Models/Backup.php index 3f2a931d1e..00381fbdf0 100644 --- a/app/Models/Backup.php +++ b/app/Models/Backup.php @@ -23,7 +23,6 @@ * @property \Carbon\CarbonImmutable $updated_at * @property \Carbon\CarbonImmutable|null $deleted_at * @property \App\Models\Server $server - * @property \App\Models\AuditLog[] $audits */ class Backup extends Model { From 44e0dd3e09fade5ebf008abdfb299734c7e86c8f Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 06:01:24 -0400 Subject: [PATCH 037/103] Remove final refs --- app/Models/Server.php | 11 +++++++++++ .../Allocations/FindAssignableAllocationService.php | 12 ++++++------ .../Servers/ServerConfigurationStructureService.php | 4 ++-- app/Services/Servers/ServerDeletionService.php | 2 -- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/app/Models/Server.php b/app/Models/Server.php index 2214c9eaf8..a9ef398b45 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Notifications\Notifiable; use Illuminate\Database\Query\JoinClause; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\Http; use Psr\Http\Message\ResponseInterface; use Illuminate\Database\Eloquent\Relations\HasOne; @@ -103,6 +104,16 @@ * @method static \Illuminate\Database\Eloquent\Builder|Server whereUuid($value) * @method static \Illuminate\Database\Eloquent\Builder|Server whereuuid_short($value) * + * @property array|null $docker_labels + * @property Collection|null $ports + * @property-read \Illuminate\Database\Eloquent\Collection $eggVariables + * @property-read int|null $egg_variables_count + * @property-read \Illuminate\Database\Eloquent\Collection $serverVariables + * @property-read int|null $server_variables_count + * @method static \Illuminate\Database\Eloquent\Builder|Server whereDockerLabels($value) + * @method static \Illuminate\Database\Eloquent\Builder|Server whereInstalledAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Server wherePorts($value) + * @method static \Illuminate\Database\Eloquent\Builder|Server whereUuidShort($value) * @mixin \Eloquent */ class Server extends Model diff --git a/app/Services/Allocations/FindAssignableAllocationService.php b/app/Services/Allocations/FindAssignableAllocationService.php index 6f9958a6af..a6c8852074 100644 --- a/app/Services/Allocations/FindAssignableAllocationService.php +++ b/app/Services/Allocations/FindAssignableAllocationService.php @@ -2,6 +2,8 @@ namespace App\Services\Allocations; +use App\Models\Objects\Endpoint; +use Illuminate\Support\Collection; use Webmozart\Assert\Assert; use App\Models\Server; use App\Exceptions\Service\Allocation\AutoAllocationNotEnabledException; @@ -45,11 +47,10 @@ protected function createNewAllocation(Server $server): int Assert::integerish($start); Assert::integerish($end); - // Get all the currently allocated ports for the node so that we can figure out which port might be available. - $ports = $server->node->allocations() - ->where('ip', $server->allocation->ip) - ->whereBetween('port', [$start, $end]) - ->pluck('port'); + $ports = $server->node->servers + ->reduce(fn (Collection $result, $value) => $result->merge($value), collect()) + ->map(fn (Endpoint $endpoint) => $endpoint->port) + ->filter(fn (int $port): bool => $port >= $start && $port <= $end); // Compute the difference of the range and the currently created ports, finding // any port that does not already exist in the database. We will then use this @@ -57,7 +58,6 @@ protected function createNewAllocation(Server $server): int $available = array_diff(range($start, $end), $ports->toArray()); // Pick a random port out of the remaining available ports. - /** @var int $port */ return $available[array_rand($available)]; } } diff --git a/app/Services/Servers/ServerConfigurationStructureService.php b/app/Services/Servers/ServerConfigurationStructureService.php index 77c6a2d663..a29d80bffb 100644 --- a/app/Services/Servers/ServerConfigurationStructureService.php +++ b/app/Services/Servers/ServerConfigurationStructureService.php @@ -66,8 +66,8 @@ protected function returnFormat(Server $server): array 'allocations' => [ 'force_outgoing_ip' => $server->egg->force_outgoing_ip, 'default' => [ - 'ip' => $server->allocation->ip, - 'port' => $server->allocation->port, + 'ip' => $server->getPrimaryEndpoint()->ip, + 'port' => $server->getPrimaryEndpoint()->port, ], 'mappings' => $server->getPortMappings(), ], diff --git a/app/Services/Servers/ServerDeletionService.php b/app/Services/Servers/ServerDeletionService.php index 97e6995c77..71e9ee19ee 100644 --- a/app/Services/Servers/ServerDeletionService.php +++ b/app/Services/Servers/ServerDeletionService.php @@ -77,8 +77,6 @@ public function handle(Server $server): void } } - $server->allocations()->update(['server_id' => null]); - $server->delete(); }); } From 2b58160da9feb37b0d6c7d4b596bd6a2580aceb2 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 06:04:20 -0400 Subject: [PATCH 038/103] Drop it --- database/migrations/2024_06_06_043350_modify_allocations.php | 1 + 1 file changed, 1 insertion(+) diff --git a/database/migrations/2024_06_06_043350_modify_allocations.php b/database/migrations/2024_06_06_043350_modify_allocations.php index 72cd27db8d..8a195b778a 100644 --- a/database/migrations/2024_06_06_043350_modify_allocations.php +++ b/database/migrations/2024_06_06_043350_modify_allocations.php @@ -37,6 +37,7 @@ public function up(): void } Schema::table('servers', function (Blueprint $table) { + $table->dropForeign('servers_allocation_id_foreign'); $table->dropColumn(['allocation_id']); }); From 6976fa8989896043dbefbccb20bfb0b5de3365ef Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 06:57:11 -0400 Subject: [PATCH 039/103] Try again --- database/migrations/2024_06_06_043350_modify_allocations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/migrations/2024_06_06_043350_modify_allocations.php b/database/migrations/2024_06_06_043350_modify_allocations.php index 8a195b778a..08878d0daf 100644 --- a/database/migrations/2024_06_06_043350_modify_allocations.php +++ b/database/migrations/2024_06_06_043350_modify_allocations.php @@ -37,7 +37,7 @@ public function up(): void } Schema::table('servers', function (Blueprint $table) { - $table->dropForeign('servers_allocation_id_foreign'); + $table->dropForeign(['allocation_id']); $table->dropColumn(['allocation_id']); }); From eff8e509ef96777a4d76e7925ee5ff9f2d2b062a Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 07:19:01 -0400 Subject: [PATCH 040/103] Wrap in transaction --- .../2024_06_06_043350_modify_allocations.php | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/database/migrations/2024_06_06_043350_modify_allocations.php b/database/migrations/2024_06_06_043350_modify_allocations.php index 08878d0daf..f8a4241d2a 100644 --- a/database/migrations/2024_06_06_043350_modify_allocations.php +++ b/database/migrations/2024_06_06_043350_modify_allocations.php @@ -2,6 +2,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; return new class extends Migration @@ -11,40 +12,42 @@ */ public function up(): void { - Schema::table('server_transfers', function (Blueprint $table) { - $table->dropColumn(['old_allocation', 'new_allocation', 'old_additional_allocations', 'new_additional_allocations']); - }); + DB::transaction(function () { + Schema::table('server_transfers', function (Blueprint $table) { + $table->dropColumn(['old_allocation', 'new_allocation', 'old_additional_allocations', 'new_additional_allocations']); + }); - Schema::table('servers', function (Blueprint $table) { - $table->json('ports')->nullable(); - }); + Schema::table('servers', function (Blueprint $table) { + $table->json('ports')->nullable(); + }); - DB::table('servers')->update(['ports' => '[]']); + DB::table('servers')->update(['ports' => '[]']); - Schema::table('servers', function (Blueprint $table) { - $table->json('ports')->change(); - }); + Schema::table('servers', function (Blueprint $table) { + $table->json('ports')->change(); + }); - $portMappings = []; - foreach (DB::table('allocations')->get() as $allocation) { - $portMappings[$allocation->server_id][] = "$allocation->ip:$allocation->port"; - } + $portMappings = []; + foreach (DB::table('allocations')->get() as $allocation) { + $portMappings[$allocation->server_id][] = "$allocation->ip:$allocation->port"; + } - foreach ($portMappings as $serverId => $ports) { - DB::table('servers') - ->where('id', $serverId) - ->update(['ports' => json_encode($ports)]); - } + foreach ($portMappings as $serverId => $ports) { + DB::table('servers') + ->where('id', $serverId) + ->update(['ports' => json_encode($ports)]); + } - Schema::table('servers', function (Blueprint $table) { - $table->dropForeign(['allocation_id']); - $table->dropColumn(['allocation_id']); - }); + Schema::table('servers', function (Blueprint $table) { + $table->dropUnique(['allocation_id']); + $table->dropColumn(['allocation_id']); + }); - Schema::dropIfExists('allocations'); + Schema::dropIfExists('allocations'); - Schema::table('nodes', function (Blueprint $table) { - $table->boolean('strict_ports')->default(true); + Schema::table('nodes', function (Blueprint $table) { + $table->boolean('strict_ports')->default(true); + }); }); } From b24ff8bb2650a9ae7a49f729209e02fb972358f1 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 15 Jun 2024 07:27:17 -0400 Subject: [PATCH 041/103] Unwrap transaction --- .../2024_06_06_043350_modify_allocations.php | 58 ++++++++++--------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/database/migrations/2024_06_06_043350_modify_allocations.php b/database/migrations/2024_06_06_043350_modify_allocations.php index f8a4241d2a..e6d2ce12d8 100644 --- a/database/migrations/2024_06_06_043350_modify_allocations.php +++ b/database/migrations/2024_06_06_043350_modify_allocations.php @@ -12,42 +12,46 @@ */ public function up(): void { - DB::transaction(function () { - Schema::table('server_transfers', function (Blueprint $table) { - $table->dropColumn(['old_allocation', 'new_allocation', 'old_additional_allocations', 'new_additional_allocations']); - }); + Schema::table('server_transfers', function (Blueprint $table) { + $table->dropColumn(['old_allocation', 'new_allocation', 'old_additional_allocations', 'new_additional_allocations']); + }); + + Schema::table('servers', function (Blueprint $table) { + $table->json('ports')->nullable(); + }); - Schema::table('servers', function (Blueprint $table) { - $table->json('ports')->nullable(); - }); + DB::table('servers')->update(['ports' => '[]']); - DB::table('servers')->update(['ports' => '[]']); + Schema::table('servers', function (Blueprint $table) { + $table->json('ports')->change(); + }); - Schema::table('servers', function (Blueprint $table) { - $table->json('ports')->change(); - }); + $portMappings = []; + foreach (DB::table('allocations')->get() as $allocation) { + $portMappings[$allocation->server_id][] = "$allocation->ip:$allocation->port"; + } - $portMappings = []; - foreach (DB::table('allocations')->get() as $allocation) { - $portMappings[$allocation->server_id][] = "$allocation->ip:$allocation->port"; - } + foreach ($portMappings as $serverId => $ports) { + DB::table('servers') + ->where('id', $serverId) + ->update(['ports' => json_encode($ports)]); + } - foreach ($portMappings as $serverId => $ports) { - DB::table('servers') - ->where('id', $serverId) - ->update(['ports' => json_encode($ports)]); + Schema::table('servers', function (Blueprint $table) { + try { + $table->dropForeign(['allocation_id']); + } catch (Exception) { + // pass } - Schema::table('servers', function (Blueprint $table) { - $table->dropUnique(['allocation_id']); - $table->dropColumn(['allocation_id']); - }); + $table->dropUnique(['allocation_id']); + $table->dropColumn(['allocation_id']); + }); - Schema::dropIfExists('allocations'); + Schema::dropIfExists('allocations'); - Schema::table('nodes', function (Blueprint $table) { - $table->boolean('strict_ports')->default(true); - }); + Schema::table('nodes', function (Blueprint $table) { + $table->boolean('strict_ports')->default(true); }); } From f57232bc2310f0124f9de14217e4027df8db5953 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 16 Jun 2024 11:50:08 -0400 Subject: [PATCH 042/103] Fix tests --- app/Casts/EndpointCollection.php | 6 +++++- .../Application/Servers/StoreServerRequest.php | 5 +++++ app/Models/Objects/DeploymentObject.php | 13 +++++++++++++ app/Models/Objects/Endpoint.php | 10 ++++++++-- .../ServerConfigurationStructureService.php | 8 ++++---- app/Services/Servers/ServerCreationService.php | 9 +-------- .../Servers/VariableValidatorService.php | 2 +- .../Api/Client/ServerTransformer.php | 2 ++ .../2024_06_06_043350_modify_allocations.php | 18 +++++++----------- .../Api/Client/ClientControllerTest.php | 12 ++++++++---- .../Servers/BuildModificationServiceTest.php | 2 +- .../Servers/ServerCreationServiceTest.php | 8 ++++++++ 12 files changed, 63 insertions(+), 32 deletions(-) diff --git a/app/Casts/EndpointCollection.php b/app/Casts/EndpointCollection.php index 701f10b288..7fca4a1cec 100644 --- a/app/Casts/EndpointCollection.php +++ b/app/Casts/EndpointCollection.php @@ -28,10 +28,14 @@ public function get($model, $key, $value, $attributes) public function set($model, $key, $value, $attributes) { - if (!$value instanceof Collection) { + if (!is_array($value) && !$value instanceof Collection) { return new Collection(); } + if (!$value instanceof Collection) { + $value = new Collection($value); + } + return $value->map(fn ($endpoint) => (string) $endpoint); } }; diff --git a/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php b/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php index 0bc31a3699..a6c2e5da7c 100644 --- a/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php +++ b/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php @@ -110,6 +110,10 @@ public function withValidator(Validator $validator): void $validator->sometimes('deploy.port_range', 'present', function ($input) { return $input->deploy; }); + + $validator->sometimes('deploy.node_id', 'present', function ($input) { + return $input->deploy; + }); } /** @@ -125,6 +129,7 @@ public function getDeploymentObject(): ?DeploymentObject $object->setDedicated($this->input('deploy.dedicated_ip', false)); $object->setTags($this->input('deploy.tags', $this->input('deploy.locations', []))); $object->setPorts($this->input('deploy.port_range', [])); + $object->setNode($this->input('deploy.node_id')); return $object; } diff --git a/app/Models/Objects/DeploymentObject.php b/app/Models/Objects/DeploymentObject.php index b7a4ebaf3f..b518819108 100644 --- a/app/Models/Objects/DeploymentObject.php +++ b/app/Models/Objects/DeploymentObject.php @@ -2,6 +2,8 @@ namespace App\Models\Objects; +use App\Models\Node; + class DeploymentObject { private bool $dedicated = false; @@ -10,6 +12,8 @@ class DeploymentObject private array $ports = []; + private Node $node; + public function isDedicated(): bool { return $this->dedicated; @@ -46,4 +50,13 @@ public function setTags(array $tags): self return $this; } + public function getNode(): Node + { + return $this->node; + } + + public function setNode(Node $node): self + { + $this->node = $node; + } } diff --git a/app/Models/Objects/Endpoint.php b/app/Models/Objects/Endpoint.php index 428898f74b..c4c67542b1 100644 --- a/app/Models/Objects/Endpoint.php +++ b/app/Models/Objects/Endpoint.php @@ -2,9 +2,10 @@ namespace App\Models\Objects; +use Illuminate\Contracts\Support\Jsonable; use InvalidArgumentException; -class Endpoint +class Endpoint implements Jsonable { public const CIDR_MAX_BITS = 27; public const CIDR_MIN_BITS = 32; @@ -32,7 +33,7 @@ public function __construct(string|int $port, string $ip = null) throw_unless($this->port < self::PORT_CEIL, "Port $this->port must be less than " . self::PORT_CEIL); } - public function __toString() + public function __toString(): string { if ($this->ip === self::INADDR_ANY) { return (string) $this->port; @@ -40,4 +41,9 @@ public function __toString() return "$this->ip:$this->port"; } + + public function toJson($options = 0): string + { + return json_encode($this->__toString()); + } } diff --git a/app/Services/Servers/ServerConfigurationStructureService.php b/app/Services/Servers/ServerConfigurationStructureService.php index a29d80bffb..a8e761847e 100644 --- a/app/Services/Servers/ServerConfigurationStructureService.php +++ b/app/Services/Servers/ServerConfigurationStructureService.php @@ -17,8 +17,8 @@ public function __construct(private EnvironmentService $environment) /** * Return a configuration array for a specific server when passed a server model. * - * DO NOT MODIFY THIS FUNCTION. This powers legacy code handling for the new daemon - * daemon, if you modify the structure eggs will break unexpectedly. + * DO NOT MODIFY THIS FUNCTION. This powers legacy code handling for wings + * if you modify the structure eggs will break unexpectedly. */ public function handle(Server $server, array $override = []): array { @@ -66,8 +66,8 @@ protected function returnFormat(Server $server): array 'allocations' => [ 'force_outgoing_ip' => $server->egg->force_outgoing_ip, 'default' => [ - 'ip' => $server->getPrimaryEndpoint()->ip, - 'port' => $server->getPrimaryEndpoint()->port, + 'ip' => $server->getPrimaryEndpoint()?->ip, + 'port' => $server->getPrimaryEndpoint()?->port, ], 'mappings' => $server->getPortMappings(), ], diff --git a/app/Services/Servers/ServerCreationService.php b/app/Services/Servers/ServerCreationService.php index ae2fb12d84..34a50a26d9 100644 --- a/app/Services/Servers/ServerCreationService.php +++ b/app/Services/Servers/ServerCreationService.php @@ -51,13 +51,6 @@ public function handle(array $data, DeploymentObject $deployment = null, $valida $data['image'] = $data['image'] ?? collect($egg->docker_images)->first(); $data['startup'] = $data['startup'] ?? $egg->startup; - // If a deployment object has been passed we need to get the allocation - // that the server should use, and assign the node from that allocation. - if ($deployment instanceof DeploymentObject) { - // Todo: Refactor - // $allocation = $this->configureDeployment($data, $deployment); - } - Assert::false(empty($data['node_id'])); $eggVariableData = $this->validatorService @@ -118,7 +111,7 @@ private function createModel(array $data): Server 'cpu' => Arr::get($data, 'cpu'), 'threads' => Arr::get($data, 'threads'), 'oom_killer' => Arr::get($data, 'oom_killer') ?? false, - 'allocation_id' => Arr::get($data, 'allocation_id'), + 'ports' => Arr::get($data, 'ports') ?? [], 'egg_id' => Arr::get($data, 'egg_id'), 'startup' => Arr::get($data, 'startup'), 'image' => Arr::get($data, 'image'), diff --git a/app/Services/Servers/VariableValidatorService.php b/app/Services/Servers/VariableValidatorService.php index a55e27bf60..bfa986007f 100644 --- a/app/Services/Servers/VariableValidatorService.php +++ b/app/Services/Servers/VariableValidatorService.php @@ -25,7 +25,7 @@ public function __construct(private ValidationFactory $validator) * * @throws \Illuminate\Validation\ValidationException */ - public function handle(int $egg, array $fields = [], $validate = false): Collection + public function handle(int $egg, array $fields = [], $validate = true): Collection { $query = EggVariable::query()->where('egg_id', $egg); if (!$this->isUserLevel(User::USER_LEVEL_ADMIN)) { diff --git a/app/Transformers/Api/Client/ServerTransformer.php b/app/Transformers/Api/Client/ServerTransformer.php index b5c410f4a6..6021b59004 100644 --- a/app/Transformers/Api/Client/ServerTransformer.php +++ b/app/Transformers/Api/Client/ServerTransformer.php @@ -3,6 +3,7 @@ namespace App\Transformers\Api\Client; use App\Models\Egg; +use App\Models\Objects\Endpoint; use App\Models\Server; use App\Models\Subuser; use League\Fractal\Resource\Item; @@ -74,6 +75,7 @@ public function transform(Server $server): array // This field is deprecated, please use "status". 'is_installing' => !$server->isInstalled(), 'is_transferring' => !is_null($server->transfer), + 'ports' => $user->can(Permission::ACTION_ALLOCATION_READ, $server) ? $server->ports : collect(), ]; } diff --git a/database/migrations/2024_06_06_043350_modify_allocations.php b/database/migrations/2024_06_06_043350_modify_allocations.php index e6d2ce12d8..ceeb516664 100644 --- a/database/migrations/2024_06_06_043350_modify_allocations.php +++ b/database/migrations/2024_06_06_043350_modify_allocations.php @@ -20,12 +20,6 @@ public function up(): void $table->json('ports')->nullable(); }); - DB::table('servers')->update(['ports' => '[]']); - - Schema::table('servers', function (Blueprint $table) { - $table->json('ports')->change(); - }); - $portMappings = []; foreach (DB::table('allocations')->get() as $allocation) { $portMappings[$allocation->server_id][] = "$allocation->ip:$allocation->port"; @@ -37,13 +31,15 @@ public function up(): void ->update(['ports' => json_encode($ports)]); } - Schema::table('servers', function (Blueprint $table) { - try { + try { + Schema::table('servers', function (Blueprint $table) { $table->dropForeign(['allocation_id']); - } catch (Exception) { - // pass - } + }); + } catch (Throwable) { + + } + Schema::table('servers', function (Blueprint $table) { $table->dropUnique(['allocation_id']); $table->dropColumn(['allocation_id']); }); diff --git a/tests/Integration/Api/Client/ClientControllerTest.php b/tests/Integration/Api/Client/ClientControllerTest.php index cc2d1d38d7..aed0fe8f71 100644 --- a/tests/Integration/Api/Client/ClientControllerTest.php +++ b/tests/Integration/Api/Client/ClientControllerTest.php @@ -2,6 +2,7 @@ namespace App\Tests\Integration\Api\Client; +use App\Models\Objects\Endpoint; use App\Models\User; use App\Models\Server; use App\Models\Subuser; @@ -260,13 +261,16 @@ public function testNoServersAreReturnedIfAdminFilterIsPassedByRegularUser(strin } /** - * Test that a subuser without the allocation.read permission is only able to see the primary - * allocation for the server. + * Test that a subuser without the allocation.read permission cannot see any ports */ - public function testOnlyPrimaryAllocationIsReturnedToSubuser(): void + public function testNoPortsAreReturnedToSubuser(): void { /** @var \App\Models\Server $server */ [$user, $server] = $this->generateTestAccount([Permission::ACTION_WEBSOCKET_CONNECT]); + $server->ports->add(new Endpoint(1234)); + $server->ports->add(new Endpoint(2345, '1.2.3.4')); + $server->ports->add(new Endpoint(3456)); + $server->save(); $server->refresh(); $response = $this->actingAs($user)->getJson('/api/client'); @@ -275,7 +279,7 @@ public function testOnlyPrimaryAllocationIsReturnedToSubuser(): void $response->assertJsonCount(1, 'data'); $response->assertJsonPath('data.0.attributes.server_owner', false); $response->assertJsonPath('data.0.attributes.uuid', $server->uuid); - $response->assertJsonCount(1, 'data.0.attributes.relationships.allocations.data'); + $response->assertJsonCount(0, 'data.0.attributes.ports'); } public static function filterTypeDataProvider(): array diff --git a/tests/Integration/Services/Servers/BuildModificationServiceTest.php b/tests/Integration/Services/Servers/BuildModificationServiceTest.php index e633a5d2ae..7b269cac83 100644 --- a/tests/Integration/Services/Servers/BuildModificationServiceTest.php +++ b/tests/Integration/Services/Servers/BuildModificationServiceTest.php @@ -31,7 +31,7 @@ protected function setUp(): void * the server data is updated in realtime. This test also ensures that only certain fields get updated * for the server, and not just any arbitrary field. */ - public function testServerBuildDataIsProperlyUpdatedOndaemon(): void + public function testServerBuildDataIsProperlyUpdatedOnDaemon(): void { $server = $this->createServerModel(); diff --git a/tests/Integration/Services/Servers/ServerCreationServiceTest.php b/tests/Integration/Services/Servers/ServerCreationServiceTest.php index e6a008b837..9cedbfea20 100644 --- a/tests/Integration/Services/Servers/ServerCreationServiceTest.php +++ b/tests/Integration/Services/Servers/ServerCreationServiceTest.php @@ -2,6 +2,7 @@ namespace App\Tests\Integration\Services\Servers; +use App\Models\Objects\Endpoint; use Mockery\MockInterface; use App\Models\Egg; use GuzzleHttp\Psr7\Request; @@ -82,6 +83,7 @@ public function testServerIsCreatedWithDeploymentObject(): void 'image' => 'java:8', 'egg_id' => $egg->id, 'ports' => [1234, 2345, 3456], + 'node_id' => $node->id, 'environment' => [ 'BUNGEE_VERSION' => '123', 'SERVER_JARFILE' => 'server2.jar', @@ -121,6 +123,12 @@ public function testServerIsCreatedWithDeploymentObject(): void continue; } + if ($key === 'ports') { + $this->assertSame($value, $response->ports->map(fn (Endpoint $endpoint) => $endpoint->port)->all()); + + continue; + } + $this->assertSame($value, $response->{$key}, "Failed asserting equality of '$key' in server response. Got: [{$response->{$key}}] Expected: [$value]"); } From d9dc932e075812104b9d3091035c8a077b4c73e2 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 16 Jun 2024 11:55:54 -0400 Subject: [PATCH 043/103] Remove unused import --- app/Transformers/Api/Client/ServerTransformer.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Transformers/Api/Client/ServerTransformer.php b/app/Transformers/Api/Client/ServerTransformer.php index 6021b59004..2b70bb7d5b 100644 --- a/app/Transformers/Api/Client/ServerTransformer.php +++ b/app/Transformers/Api/Client/ServerTransformer.php @@ -3,7 +3,6 @@ namespace App\Transformers\Api\Client; use App\Models\Egg; -use App\Models\Objects\Endpoint; use App\Models\Server; use App\Models\Subuser; use League\Fractal\Resource\Item; From a8699704dec733ad3302e9f37b95bf8172e422d2 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 16 Jun 2024 11:56:21 -0400 Subject: [PATCH 044/103] Fix return --- app/Models/Objects/DeploymentObject.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Models/Objects/DeploymentObject.php b/app/Models/Objects/DeploymentObject.php index b518819108..be423402db 100644 --- a/app/Models/Objects/DeploymentObject.php +++ b/app/Models/Objects/DeploymentObject.php @@ -58,5 +58,7 @@ public function getNode(): Node public function setNode(Node $node): self { $this->node = $node; + + return $this; } } From 738707b251f9c873f26e274051024824c8328130 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 16 Jun 2024 12:30:28 -0400 Subject: [PATCH 045/103] Add validation rule --- app/Models/Server.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Models/Server.php b/app/Models/Server.php index a9ef398b45..96c5520064 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -167,6 +167,7 @@ class Server extends Model 'database_limit' => 'present|nullable|integer|min:0', 'allocation_limit' => 'sometimes|nullable|integer|min:0', 'backup_limit' => 'present|nullable|integer|min:0', + 'ports' => 'nullable|array', ]; protected function casts(): array From c7bea4f0241b2d424041eb767c93d999bbd94802 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 16 Jun 2024 12:30:42 -0400 Subject: [PATCH 046/103] This was wrong but somehow worked in sqlite, wut --- app/Casts/EndpointCollection.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Casts/EndpointCollection.php b/app/Casts/EndpointCollection.php index 7fca4a1cec..f4a1e21cad 100644 --- a/app/Casts/EndpointCollection.php +++ b/app/Casts/EndpointCollection.php @@ -36,7 +36,9 @@ public function set($model, $key, $value, $attributes) $value = new Collection($value); } - return $value->map(fn ($endpoint) => (string) $endpoint); + return [ + 'ports' => $value->toJson(), + ]; } }; } From ff261f9c99de57d8a57c6ab23c6d40b1f9061f9f Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 16 Jun 2024 13:07:12 -0400 Subject: [PATCH 047/103] Realism --- .../2024_06_06_043350_modify_allocations.php | 44 +++++++------------ 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/database/migrations/2024_06_06_043350_modify_allocations.php b/database/migrations/2024_06_06_043350_modify_allocations.php index ceeb516664..418b26ed96 100644 --- a/database/migrations/2024_06_06_043350_modify_allocations.php +++ b/database/migrations/2024_06_06_043350_modify_allocations.php @@ -1,5 +1,7 @@ $ports) { - DB::table('servers') - ->where('id', $serverId) - ->update(['ports' => json_encode($ports)]); + /** @var Server $server */ + $server = Server::find($serverId); + if (!$server) { + // Orphaned Allocations + + continue; + } + + foreach ($ports as $port) { + $server->ports ??= collect(); + $server->ports->add(new Endpoint($port)); + } + $server->save(); } try { @@ -36,7 +48,7 @@ public function up(): void $table->dropForeign(['allocation_id']); }); } catch (Throwable) { - + // pass for databases that don't support this like sqlite } Schema::table('servers', function (Blueprint $table) { @@ -56,28 +68,6 @@ public function up(): void */ public function down(): void { - Schema::table('nodes', function (Blueprint $table) { - $table->dropColumn('strict_ports'); - }); - - Schema::create('allocations', function (Blueprint $table) { - $table->id(); - $table->unsignedInteger('node_id'); - $table->string('ip'); - $table->text('ip_alias'); - $table->unsignedMediumInteger('port'); - $table->unsignedInteger('server_id'); - $table->string('notes')->default(''); - $table->timestamps(); - - $table->unique(['node_id', 'ip', 'port']); - }); - - Schema::table('server_transfers', function (Blueprint $table) { - $table->integer('old_node'); - $table->integer('new_node'); - $table->json('old_additional_allocations')->nullable(); - $table->json('new_additional_allocations')->nullable(); - }); + // Too much time to ensure this works correctly, please take a backup if necessary } }; From 9d9720a5a26f0105387abd6df143fb81d2df3e2d Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Mon, 17 Jun 2024 10:47:43 -0400 Subject: [PATCH 048/103] Start servers by default --- app/Services/Servers/ServerCreationService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Services/Servers/ServerCreationService.php b/app/Services/Servers/ServerCreationService.php index 34a50a26d9..e35c6f798e 100644 --- a/app/Services/Servers/ServerCreationService.php +++ b/app/Services/Servers/ServerCreationService.php @@ -74,7 +74,7 @@ public function handle(array $data, DeploymentObject $deployment = null, $valida try { $this->daemonServerRepository->setServer($server)->create( - Arr::get($data, 'start_on_completion', false) ?? false + Arr::get($data, 'start_on_completion', true) ?? true, ); } catch (DaemonConnectionException $exception) { $this->serverDeletionService->withForce()->handle($server); From 69acc48b5e3674b62e27968705014df1688f70be Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Mon, 17 Jun 2024 10:47:55 -0400 Subject: [PATCH 049/103] Use constants --- .../DatabaseHostResource/Pages/CreateDatabaseHost.php | 3 ++- .../DatabaseHostResource/Pages/EditDatabaseHost.php | 3 ++- app/Rules/Port.php | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/Filament/Resources/DatabaseHostResource/Pages/CreateDatabaseHost.php b/app/Filament/Resources/DatabaseHostResource/Pages/CreateDatabaseHost.php index dd37e5c26f..450efd925d 100644 --- a/app/Filament/Resources/DatabaseHostResource/Pages/CreateDatabaseHost.php +++ b/app/Filament/Resources/DatabaseHostResource/Pages/CreateDatabaseHost.php @@ -3,6 +3,7 @@ namespace App\Filament\Resources\DatabaseHostResource\Pages; use App\Filament\Resources\DatabaseHostResource; +use App\Models\Objects\Endpoint; use Filament\Resources\Pages\CreateRecord; use Filament\Forms; use Filament\Forms\Components\Section; @@ -44,7 +45,7 @@ public function form(Form $form): Form ->numeric() ->default(3306) ->minValue(0) - ->maxValue(65535), + ->maxValue(Endpoint::PORT_CEIL), Forms\Components\TextInput::make('max_databases') ->label('Max databases') ->helpertext('Blank is unlimited.') diff --git a/app/Filament/Resources/DatabaseHostResource/Pages/EditDatabaseHost.php b/app/Filament/Resources/DatabaseHostResource/Pages/EditDatabaseHost.php index 1e46e6055f..ba72d59e90 100644 --- a/app/Filament/Resources/DatabaseHostResource/Pages/EditDatabaseHost.php +++ b/app/Filament/Resources/DatabaseHostResource/Pages/EditDatabaseHost.php @@ -4,6 +4,7 @@ use App\Filament\Resources\DatabaseHostResource; use App\Models\DatabaseHost; +use App\Models\Objects\Endpoint; use Filament\Actions; use Filament\Resources\Pages\EditRecord; use Filament\Forms; @@ -39,7 +40,7 @@ public function form(Form $form): Form ->required() ->numeric() ->minValue(0) - ->maxValue(65535), + ->maxValue(Endpoint::PORT_CEIL), Forms\Components\TextInput::make('max_databases') ->label('Max databases') ->helpertext('Blank is unlimited.') diff --git a/app/Rules/Port.php b/app/Rules/Port.php index f2a598c124..910d00379e 100644 --- a/app/Rules/Port.php +++ b/app/Rules/Port.php @@ -2,6 +2,7 @@ namespace App\Rules; +use App\Models\Objects\Endpoint; use Closure; use Illuminate\Contracts\Validation\ValidationRule; @@ -23,11 +24,11 @@ public function validate(string $attribute, mixed $value, Closure $fail): void $fail('The :attribute must be an integer.'); } - if ($value <= 1024) { + if ($value <= Endpoint::PORT_FLOOR) { $fail('The :attribute must be greater than 1024.'); } - if ($value > 65535) { + if ($value > Endpoint::PORT_CEIL) { $fail('The :attribute must be less than 65535.'); } } From 3fa714c7e36477f857eb6bc0c65a369aa0766a2b Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Mon, 17 Jun 2024 10:48:05 -0400 Subject: [PATCH 050/103] Refactor --- .../ServerResource/Pages/CreateServer.php | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index 2b4b0e7fe0..6444eb9ca1 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -5,6 +5,7 @@ use App\Filament\Resources\ServerResource; use App\Models\Egg; use App\Models\Node; +use App\Models\Objects\Endpoint; use App\Services\Servers\RandomWordService; use App\Services\Servers\ServerCreationService; use Filament\Forms\Components\Actions\Action; @@ -664,28 +665,25 @@ private function getSelectOptionsFromRules(Forms\Get $get): array public function ports($state, Forms\Set $set) { $ports = collect(); - $update = false; foreach ($state as $portEntry) { - if (!str_contains($portEntry, '-')) { - if (is_numeric($portEntry)) { - $ports->push((int) $portEntry); - + if (str_contains($portEntry, '-')) { + [$start, $end] = explode('-', $portEntry); + if (!is_numeric($start) || !is_numeric($end)) { continue; } - continue; + $start = max((int) $start, Endpoint::PORT_FLOOR); + $end = min((int) $end, Endpoint::PORT_CEIL); + for ($i = $start; $i <= $end; $i++) { + $ports->push($i); + } } - [$start, $end] = explode('-', $portEntry); - if (!is_numeric($start) || !is_numeric($end)) { + if (!is_numeric($portEntry)) { continue; } - $start = max((int) $start, 0); - $end = min((int) $end, 2 ** 16 - 1); - for ($i = $start; $i <= $end; $i++) { - $ports->push($i); - } + $ports->push((int) $portEntry); } $uniquePorts = $ports->unique()->values(); From 05573f64dd0a6cc0114bdfefa4c166d843b065d2 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Mon, 17 Jun 2024 11:46:40 -0400 Subject: [PATCH 051/103] Group servers --- .../ServerResource/Pages/ListServers.php | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/ListServers.php b/app/Filament/Resources/ServerResource/Pages/ListServers.php index 434cc4edad..7d6f8f7bcf 100644 --- a/app/Filament/Resources/ServerResource/Pages/ListServers.php +++ b/app/Filament/Resources/ServerResource/Pages/ListServers.php @@ -3,10 +3,14 @@ namespace App\Filament\Resources\ServerResource\Pages; use App\Filament\Resources\ServerResource; +use App\Models\Egg; +use App\Models\Node; use App\Models\Server; +use App\Models\User; use Filament\Actions; use Filament\Resources\Pages\ListRecords; use Filament\Tables\Actions\CreateAction; +use Filament\Tables\Grouping\Group; use Filament\Tables\Table; use Filament\Tables; @@ -18,6 +22,12 @@ public function table(Table $table): Table { return $table ->searchable(false) + ->defaultGroup('node.name') + ->groups([ + Group::make('node.name')->getDescriptionFromRecordUsing(fn (Server $server): string => str($server->node->description)->limit(150)), + Group::make('user.username')->getDescriptionFromRecordUsing(fn (Server $server): string => $server->user->email), + Group::make('egg.name')->getDescriptionFromRecordUsing(fn (Server $server): string => str($server->egg->description)->limit(150)), + ]) ->columns([ Tables\Columns\TextColumn::make('status') ->default('unknown') @@ -52,26 +62,22 @@ public function table(Table $table): Table Tables\Columns\TextColumn::make('node.name') ->icon('tabler-server-2') ->url(fn (Server $server): string => route('filament.admin.resources.nodes.edit', ['record' => $server->node])) + ->hidden(fn (Table $table) => $table->getGrouping()->getId() === 'node.name') ->sortable() ->searchable(), Tables\Columns\TextColumn::make('egg.name') ->icon('tabler-egg') ->url(fn (Server $server): string => route('filament.admin.resources.eggs.edit', ['record' => $server->egg])) + ->hidden(fn (Table $table) => $table->getGrouping()->getId() === 'egg.name') ->sortable() ->searchable(), Tables\Columns\TextColumn::make('user.username') ->icon('tabler-user') ->label('Owner') ->url(fn (Server $server): string => route('filament.admin.resources.users.edit', ['record' => $server->user])) + ->hidden(fn (Table $table) => $table->getGrouping()->getId() === 'user.username') ->sortable(), Tables\Columns\TextColumn::make('ports'), - Tables\Columns\TextColumn::make('image')->hidden(), - Tables\Columns\TextColumn::make('backups_count') - ->counts('backups') - ->label('Backups') - ->icon('tabler-file-download') - ->numeric() - ->sortable(), ]) ->actions([ Tables\Actions\Action::make('View') From f699fd54592b95fda7596f388aa45675868d8ced Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Mon, 17 Jun 2024 11:46:58 -0400 Subject: [PATCH 052/103] Make ports into badges --- app/Filament/Resources/ServerResource/Pages/ListServers.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Filament/Resources/ServerResource/Pages/ListServers.php b/app/Filament/Resources/ServerResource/Pages/ListServers.php index 7d6f8f7bcf..2eeeea2e58 100644 --- a/app/Filament/Resources/ServerResource/Pages/ListServers.php +++ b/app/Filament/Resources/ServerResource/Pages/ListServers.php @@ -77,7 +77,9 @@ public function table(Table $table): Table ->url(fn (Server $server): string => route('filament.admin.resources.users.edit', ['record' => $server->user])) ->hidden(fn (Table $table) => $table->getGrouping()->getId() === 'user.username') ->sortable(), - Tables\Columns\TextColumn::make('ports'), + Tables\Columns\TextColumn::make('ports') + ->badge() + ->separator(), ]) ->actions([ Tables\Actions\Action::make('View') From 48f4c35d0b7f2cfc8462d027e5ecf4025486bc3b Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Mon, 17 Jun 2024 11:55:32 -0400 Subject: [PATCH 053/103] Can be null apparently --- app/Filament/Resources/ServerResource/Pages/ListServers.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/ListServers.php b/app/Filament/Resources/ServerResource/Pages/ListServers.php index 2eeeea2e58..a6a907fd42 100644 --- a/app/Filament/Resources/ServerResource/Pages/ListServers.php +++ b/app/Filament/Resources/ServerResource/Pages/ListServers.php @@ -62,20 +62,20 @@ public function table(Table $table): Table Tables\Columns\TextColumn::make('node.name') ->icon('tabler-server-2') ->url(fn (Server $server): string => route('filament.admin.resources.nodes.edit', ['record' => $server->node])) - ->hidden(fn (Table $table) => $table->getGrouping()->getId() === 'node.name') + ->hidden(fn (Table $table) => $table->getGrouping()?->getId() === 'node.name') ->sortable() ->searchable(), Tables\Columns\TextColumn::make('egg.name') ->icon('tabler-egg') ->url(fn (Server $server): string => route('filament.admin.resources.eggs.edit', ['record' => $server->egg])) - ->hidden(fn (Table $table) => $table->getGrouping()->getId() === 'egg.name') + ->hidden(fn (Table $table) => $table->getGrouping()?->getId() === 'egg.name') ->sortable() ->searchable(), Tables\Columns\TextColumn::make('user.username') ->icon('tabler-user') ->label('Owner') ->url(fn (Server $server): string => route('filament.admin.resources.users.edit', ['record' => $server->user])) - ->hidden(fn (Table $table) => $table->getGrouping()->getId() === 'user.username') + ->hidden(fn (Table $table) => $table->getGrouping()?->getId() === 'user.username') ->sortable(), Tables\Columns\TextColumn::make('ports') ->badge() From 32018399b62c5e87f7f1105674c6a2b8b912b081 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Mon, 17 Jun 2024 18:15:35 -0400 Subject: [PATCH 054/103] Add server io weight default --- app/Filament/Resources/ServerResource/Pages/CreateServer.php | 2 +- config/panel.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index 6444eb9ca1..48a2cf123b 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -476,7 +476,7 @@ public function form(Form $form): Form Forms\Components\Hidden::make('io') ->helperText('The IO performance relative to other running containers') ->label('Block IO Proportion') - ->default(500), + ->default(config('panel.default_io_weight')), Forms\Components\Grid::make() ->columns(4) diff --git a/config/panel.php b/config/panel.php index 7b049f1459..a8b73ad2e3 100644 --- a/config/panel.php +++ b/config/panel.php @@ -177,4 +177,6 @@ ], 'use_binary_prefix' => env('PANEL_USE_BINARY_PREFIX', true), + + 'default_io_weight' => env('PANEL_IO_WEIGHT', 500), ]; From ba5b81cf2dc4eb5135c77d5b9a786f2c192f4719 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Mon, 17 Jun 2024 18:15:45 -0400 Subject: [PATCH 055/103] Show localhost --- app/Models/Objects/Endpoint.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/Models/Objects/Endpoint.php b/app/Models/Objects/Endpoint.php index c4c67542b1..18b80b71b5 100644 --- a/app/Models/Objects/Endpoint.php +++ b/app/Models/Objects/Endpoint.php @@ -14,6 +14,7 @@ class Endpoint implements Jsonable public const PORT_RANGE_LIMIT = 1000; public const PORT_RANGE_REGEX = '/^(\d{4,5})-(\d{4,5})$/'; public const INADDR_ANY = '0.0.0.0'; + public const INADDR_LOOPBACK = '127.0.0.1'; public int $port; public string $ip; @@ -35,11 +36,17 @@ public function __construct(string|int $port, string $ip = null) public function __toString(): string { - if ($this->ip === self::INADDR_ANY) { + $ip = $this->ip; + + if ($ip === self::INADDR_ANY) { return (string) $this->port; } - return "$this->ip:$this->port"; + if ($ip === self::INADDR_LOOPBACK) { + $ip = 'localhost'; + } + + return "$ip:$this->port"; } public function toJson($options = 0): string From 7986505b99c2a5ef21db7c61cdac98c47c4e410b Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Mon, 17 Jun 2024 18:15:56 -0400 Subject: [PATCH 056/103] =?UTF-8?q?Don=E2=80=99t=20report=20status=20anymo?= =?UTF-8?q?re?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Models/Node.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/Models/Node.php b/app/Models/Node.php index 72d01f8b95..3423fc614c 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -285,11 +285,10 @@ public function systemInformation(): array public function serverStatuses(): array { - $statuses = []; try { - $statuses = Http::daemon($this)->connectTimeout(1)->timeout(1)->get('/api/servers')->json() ?? []; - } catch (Exception $exception) { - report($exception); + $statuses = Http::daemon($this)->connectTimeout(1)->timeout(1)->throw()->get('/api/servers')->json() ?? []; + } catch (Exception) { + $statuses = []; } foreach ($statuses as $status) { From 958e8fac8a2ef5192e2ca2c130942fe1068c5eff Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Mon, 17 Jun 2024 18:18:48 -0400 Subject: [PATCH 057/103] Simplify states and statuses and resolve #362 --- app/Enums/ContainerStatus.php | 3 ++ .../ServerResource/Pages/EditServer.php | 52 +++++-------------- .../ServerResource/Pages/ListServers.php | 23 ++------ app/Models/Server.php | 31 +++++++++++ 4 files changed, 49 insertions(+), 60 deletions(-) diff --git a/app/Enums/ContainerStatus.php b/app/Enums/ContainerStatus.php index ba9effa647..b3b57d2b0e 100644 --- a/app/Enums/ContainerStatus.php +++ b/app/Enums/ContainerStatus.php @@ -12,6 +12,7 @@ enum ContainerStatus: string case Paused = 'paused'; case Dead = 'dead'; case Removing = 'removing'; + case Offline = 'offline'; // HTTP Based case Missing = 'missing'; @@ -27,6 +28,7 @@ public function icon(): string self::Dead => 'tabler-heart-x', self::Removing => 'tabler-heart-down', self::Missing => 'tabler-heart-question', + self::Offline => 'tabler-heart-bolt', }; } @@ -41,6 +43,7 @@ public function color(): string self::Dead => 'danger', self::Removing => 'warning', self::Missing => 'danger', + self::Offline => 'gray', }; } } diff --git a/app/Filament/Resources/ServerResource/Pages/EditServer.php b/app/Filament/Resources/ServerResource/Pages/EditServer.php index 8d742d22b6..61efcee7e3 100644 --- a/app/Filament/Resources/ServerResource/Pages/EditServer.php +++ b/app/Filament/Resources/ServerResource/Pages/EditServer.php @@ -39,47 +39,19 @@ public function form(Form $form): Form 'lg' => 4, ]) ->schema([ - Forms\Components\ToggleButtons::make('docker') - ->label('Container Status')->inline()->inlineLabel() - ->formatStateUsing(function ($state, Server $server) { - if ($server->node_id === null) { - return 'unknown'; - } - - /** @var DaemonServerRepository $service */ - $service = resolve(DaemonServerRepository::class); - $details = $service->setServer($server)->getDetails(); - - return $details['state'] ?? 'unknown'; - }) - ->options(fn ($state) => collect(ContainerStatus::cases())->filter(fn ($containerStatus) => $containerStatus->value === $state)->mapWithKeys( - fn (ContainerStatus $state) => [$state->value => str($state->value)->replace('_', ' ')->ucwords()] + Forms\Components\ToggleButtons::make('condition') + ->label('') + ->inline() + ->formatStateUsing(fn (Server $server) => $server->condition) + ->options(fn ($state) => collect(ContainerStatus::cases())->merge(ServerState::cases()) + ->filter(fn ($condition) => $condition->value === $state) + ->mapWithKeys(fn ($state) => [$state->value => str($state->value)->replace('_', ' ')->ucwords()]) + ) + ->colors(collect(ContainerStatus::cases())->merge(ServerState::cases())->mapWithKeys( + fn ($status) => [$status->value => $status->color()] )) - ->colors(collect(ContainerStatus::cases())->mapWithKeys( - fn (ContainerStatus $status) => [$status->value => $status->color()] - )) - ->icons(collect(ContainerStatus::cases())->mapWithKeys( - fn (ContainerStatus $status) => [$status->value => $status->icon()] - )) - ->columnSpan([ - 'default' => 1, - 'sm' => 2, - 'md' => 2, - 'lg' => 2, - ]), - - Forms\Components\ToggleButtons::make('status') - ->label('Server State')->inline()->inlineLabel() - ->helperText('') - ->formatStateUsing(fn ($state) => $state ?? ServerState::Normal) - ->options(fn ($state) => collect(ServerState::cases())->filter(fn ($serverState) => $serverState->value === $state)->mapWithKeys( - fn (ServerState $state) => [$state->value => str($state->value)->replace('_', ' ')->ucwords()] - )) - ->colors(collect(ServerState::cases())->mapWithKeys( - fn (ServerState $state) => [$state->value => $state->color()] - )) - ->icons(collect(ServerState::cases())->mapWithKeys( - fn (ServerState $state) => [$state->value => $state->icon()] + ->icons(collect(ContainerStatus::cases())->merge(ServerState::cases())->mapWithKeys( + fn ($status) => [$status->value => $status->icon()] )) ->columnSpan([ 'default' => 1, diff --git a/app/Filament/Resources/ServerResource/Pages/ListServers.php b/app/Filament/Resources/ServerResource/Pages/ListServers.php index a6a907fd42..4919c6e0ca 100644 --- a/app/Filament/Resources/ServerResource/Pages/ListServers.php +++ b/app/Filament/Resources/ServerResource/Pages/ListServers.php @@ -29,28 +29,11 @@ public function table(Table $table): Table Group::make('egg.name')->getDescriptionFromRecordUsing(fn (Server $server): string => str($server->egg->description)->limit(150)), ]) ->columns([ - Tables\Columns\TextColumn::make('status') + Tables\Columns\TextColumn::make('condition') ->default('unknown') ->badge() - ->default(fn (Server $server) => $server->status ?? $server->retrieveStatus()) - ->icon(fn ($state) => match ($state) { - 'node_fail' => 'tabler-server-off', - 'running' => 'tabler-heartbeat', - 'removing' => 'tabler-heart-x', - 'offline' => 'tabler-heart-off', - 'paused' => 'tabler-heart-pause', - 'installing' => 'tabler-heart-bolt', - 'suspended' => 'tabler-heart-cancel', - default => 'tabler-heart-question', - }) - ->color(fn ($state): string => match ($state) { - 'running' => 'success', - 'installing', 'restarting' => 'primary', - 'paused', 'removing' => 'warning', - 'node_fail', 'install_failed', 'suspended' => 'danger', - default => 'gray', - }), - + ->icon(fn (Server $server) => $server->conditionIcon()) + ->color(fn (Server $server) => $server->conditionColor()), Tables\Columns\TextColumn::make('uuid') ->hidden() ->label('UUID') diff --git a/app/Models/Server.php b/app/Models/Server.php index 96c5520064..f80ddcdc43 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -3,10 +3,12 @@ namespace App\Models; use App\Casts\EndpointCollection; +use App\Enums\ContainerStatus; use App\Enums\ServerState; use App\Exceptions\Http\Connection\DaemonConnectionException; use App\Models\Objects\Endpoint; use GuzzleHttp\Exception\GuzzleException; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Notifications\Notifiable; use Illuminate\Database\Query\JoinClause; @@ -409,6 +411,35 @@ public function retrieveStatus(): string return cache()->get("servers.$this->uuid.container.status") ?? 'missing'; } + public function condition(): Attribute + { + return Attribute::make( + get: fn () => $this->status?->value ?? $this->retrieveStatus(), + ); + } + + public function conditionIcon(): string + { + if ($this->status === null) { + $containerStatus = ContainerStatus::from($this->retrieveStatus()); + + return $containerStatus->icon(); + } + + return $this->status->icon(); + } + + public function conditionColor(): string + { + if ($this->status === null) { + $containerStatus = ContainerStatus::from($this->retrieveStatus()); + + return $containerStatus->color(); + } + + return $this->status->color(); + } + public function getPrimaryEndpoint(): ?Endpoint { $endpoint = $this->ports->first(); From d4484f52548f9761589ab8769181819c43b11d7b Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Tue, 18 Jun 2024 10:59:50 -0400 Subject: [PATCH 058/103] Handle nulls --- app/Livewire/EndpointSynth.php | 4 ++++ app/Models/Server.php | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/app/Livewire/EndpointSynth.php b/app/Livewire/EndpointSynth.php index 91a5d1e386..87352dbd2a 100644 --- a/app/Livewire/EndpointSynth.php +++ b/app/Livewire/EndpointSynth.php @@ -21,6 +21,10 @@ public function dehydrate($target) public function hydrate($value) { + if (!is_string($value) && !is_int($value)) { + return null; + } + return new Endpoint($value); } } diff --git a/app/Models/Server.php b/app/Models/Server.php index f80ddcdc43..c1f6d127e2 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -447,6 +447,10 @@ public function getPrimaryEndpoint(): ?Endpoint $portEggVariable = $this->variables->firstWhere('env_variable', 'SERVER_PORT'); if ($portEggVariable) { $portServerVariable = $this->serverVariables->firstWhere('variable_id', $portEggVariable->id); + if (! $portServerVariable) { + return null; + } + $endpoint = new Endpoint($portServerVariable->variable_value); } From 48fd3cc84eb7ed1731fa91e56631d91065a89634 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Tue, 18 Jun 2024 10:59:56 -0400 Subject: [PATCH 059/103] Add restore to simplify form --- .../ServerResource/Pages/EditServer.php | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/EditServer.php b/app/Filament/Resources/ServerResource/Pages/EditServer.php index 61efcee7e3..f5542ac6f1 100644 --- a/app/Filament/Resources/ServerResource/Pages/EditServer.php +++ b/app/Filament/Resources/ServerResource/Pages/EditServer.php @@ -461,6 +461,13 @@ public function form(Form $form): Form Forms\Components\Textarea::make('startup') ->label('Startup Command') ->required() + ->hintAction(Forms\Components\Actions\Action::make('startup-restore') + ->label('Restore Default') + ->icon('tabler-restore') + ->action(fn (Forms\Get $get, Forms\Set $set) => + $set('startup', Egg::find($get('egg_id'))?->startup ?? '') + ) + ) ->columnSpan([ 'default' => 2, 'sm' => 4, @@ -474,22 +481,6 @@ public function form(Form $form): Form ); }), - Forms\Components\Textarea::make('defaultStartup') - ->hintAction(CopyAction::make()) - ->label('Default Startup Command') - ->disabled() - ->formatStateUsing(function ($state, Forms\Get $get, Forms\Set $set) { - $egg = Egg::query()->find($get('egg_id')); - - return $egg->startup; - }) - ->columnSpan([ - 'default' => 2, - 'sm' => 4, - 'md' => 4, - 'lg' => 6, - ]), - Forms\Components\Repeater::make('server_variables') ->relationship('serverVariables') ->grid() From eb0bad82e653418e8c0958a2fd6c30e80c3e66ae Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 22 Jun 2024 11:30:08 -0400 Subject: [PATCH 060/103] Wip --- .../ServerResource/Pages/EditServer.php | 155 ++++++++++++++++-- 1 file changed, 143 insertions(+), 12 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/EditServer.php b/app/Filament/Resources/ServerResource/Pages/EditServer.php index f5542ac6f1..aef49d6920 100644 --- a/app/Filament/Resources/ServerResource/Pages/EditServer.php +++ b/app/Filament/Resources/ServerResource/Pages/EditServer.php @@ -2,6 +2,9 @@ namespace App\Filament\Resources\ServerResource\Pages; +use App\Models\Node; +use App\Models\Objects\Endpoint; +use Illuminate\Support\HtmlString; use LogicException; use App\Filament\Resources\ServerResource; use App\Http\Controllers\Admin\ServersController; @@ -15,7 +18,6 @@ use App\Models\Egg; use App\Models\Server; use App\Models\ServerVariable; -use App\Repositories\Daemon\DaemonServerRepository; use App\Services\Servers\ServerDeletionService; use Filament\Forms\Components\Tabs; use Filament\Forms\Form; @@ -27,6 +29,11 @@ class EditServer extends EditRecord { + public ?Node $node = null; + public ?Egg $egg = null; + public array $ports = []; + public array $eggDefaultPorts = []; + protected static string $resource = ServerResource::class; public function form(Form $form): Form @@ -152,7 +159,8 @@ public function form(Form $form): Form ]) ->disabled(), ]), - Tabs\Tab::make('Environment') + Tabs\Tab::make('env-tab') + ->label('Environment') ->icon('tabler-brand-docker') ->schema([ Forms\Components\Fieldset::make('Resource Limits') @@ -437,6 +445,9 @@ public function form(Form $form): Form 'md' => 3, 'lg' => 5, ]) + ->afterStateHydrated(function (Forms\Set $set, Forms\Get $get) { + // $this->resetEggVariables($set, $get); + }) ->relationship('egg', 'name') ->searchable() ->preload() @@ -458,6 +469,50 @@ public function form(Form $form): Form ]) ->required(), + Forms\Components\TagsInput::make('ports') + ->columnSpan(3) + ->placeholder('Example: 25565, 8080, 1337-1340') + ->splitKeys(['Tab', ' ', ',']) + ->helperText(new HtmlString(' + These are the ports that users can connect to this Server through. +
+ You would typically port forward these on your home network. + ')) + ->label('Ports') + ->formatStateUsing(fn (Server $server) => $server->ports->map(fn ($port) => (string) $port)->all()) + ->afterStateUpdated(self::ports(...)) + ->hintAction( + Forms\Components\Actions\Action::make('asdf') + ->action(function (Forms\Get $get, Forms\Set $set) { + $this->resetEggVariables($set, $get); + })) + ->live(), + + Forms\Components\Repeater::make('assignments') + ->columnSpan(3) + ->defaultItems(fn () => count($this->eggDefaultPorts)) + ->label('Port Assignments') + ->helperText(fn (Forms\Get $get) => empty($get('ports')) ? 'You must add ports to assign them!' : '') + ->live() + ->addable(false) + ->deletable(false) + ->reorderable(false) + ->simple( + Forms\Components\Select::make('port') + ->live() + ->disabled(fn (Forms\Get $get) => empty($get('../../ports')) || empty($get('../../assignments'))) + ->prefix(function (Forms\Components\Component $component) { + $key = str($component->getStatePath())->beforeLast('.')->afterLast('.')->toString(); + + dump($key); + + return $key; + }) + ->disableOptionsWhenSelectedInSiblingRepeaterItems() + ->options(fn (Forms\Get $get) => $this->ports) + ->required(), + ), + Forms\Components\Textarea::make('startup') ->label('Startup Command') ->required() @@ -474,12 +529,11 @@ public function form(Form $form): Form 'md' => 4, 'lg' => 6, ]) - ->rows(function ($state) { - return str($state)->explode("\n")->reduce( - fn (int $carry, $line) => $carry + floor(strlen($line) / 125), - 0 - ); - }), + ->rows(fn ($state) => str($state)->explode("\n")->reduce( + fn (int $carry, $line) => $carry + floor(strlen($line) / 125), 0 + )), + + Forms\Components\Hidden::make('environment')->default([]), Forms\Components\Repeater::make('server_variables') ->relationship('serverVariables') @@ -523,10 +577,10 @@ public function form(Form $form): Form $component = $component ->live(onBlur: true) ->hintIcon('tabler-code') - ->label(fn (ServerVariable $serverVariable) => $serverVariable->variable->name) - ->hintIconTooltip(fn (ServerVariable $serverVariable) => $serverVariable->variable->rules) - ->prefix(fn (ServerVariable $serverVariable) => '{{' . $serverVariable->variable->env_variable . '}}') - ->helperText(fn (ServerVariable $serverVariable) => empty($serverVariable->variable->description) ? '—' : $serverVariable->variable->description); + ->label(fn (ServerVariable $serverVariable) => $serverVariable->variable?->name) + ->hintIconTooltip(fn (ServerVariable $serverVariable) => $serverVariable->variable?->rules) + ->prefix(fn (ServerVariable $serverVariable) => '{{' . $serverVariable->variable?->env_variable . '}}') + ->helperText(fn (ServerVariable $serverVariable) => empty($serverVariable->variable?->description) ? '—' : $serverVariable->variable->description); } return $components; @@ -740,4 +794,81 @@ private function getSelectOptionsFromRules(Forms\Get $get): array ->mapWithKeys(fn ($value) => [$value => $value]) ->all(); } + + public function ports($state, Forms\Set $set) + { + $ports = collect(); + foreach ($state as $portEntry) { + if (str_contains($portEntry, '-')) { + [$start, $end] = explode('-', $portEntry); + if (!is_numeric($start) || !is_numeric($end)) { + continue; + } + + $start = max((int) $start, Endpoint::PORT_FLOOR); + $end = min((int) $end, Endpoint::PORT_CEIL); + for ($i = $start; $i <= $end; $i++) { + $ports->push($i); + } + } + + if (!is_numeric($portEntry)) { + continue; + } + + $ports->push((int) $portEntry); + } + + $uniquePorts = $ports->unique()->values(); + if ($ports->count() > $uniquePorts->count()) { + $ports = $uniquePorts; + } + + $ports = $ports->filter(fn ($port) => $port > 1024 && $port < 65535)->values(); + + $set('ports', $ports->all()); + $this->ports = $ports->all(); + } + + public function resetEggVariables(Forms\Set $set, Forms\Get $get) + { + $set('assignments', []); + + $i = 0; + $this->eggDefaultPorts = []; + if (str_contains($get('startup'), '{{SERVER_PORT}}')) { + $this->eggDefaultPorts['SERVER_PORT'] = null; + $set('assignments.SERVER_PORT', ['port' => null]); + } + + $variables = $this->getRecord()->egg->variables ?? []; + $serverVariables = collect(); + $this->ports = []; + foreach ($variables as $variable) { + if (str_contains($variable->rules, 'port')) { + $this->eggDefaultPorts[$variable->env_variable] = $variable->default_value; + $this->ports[] = (int) $variable->default_value; + + $set("assignments.$variable->env_variable", ['port' => $i++]); + + continue; + } + + $serverVariables->add($variable->toArray()); + } + + $set('ports', $this->ports); + + $variables = []; + $set($path = 'server_variables', $serverVariables->sortBy(['sort'])->all()); + for ($i = 0; $i < $serverVariables->count(); $i++) { + $set("$path.$i.variable_value", $serverVariables[$i]['default_value']); + $set("$path.$i.variable_id", $serverVariables[$i]['id']); + $variables[$serverVariables[$i]['env_variable']] = $serverVariables[$i]['default_value']; + } + + $set('environment', $variables); + + // dump($variables, $this->ports, $this->eggDefaultPorts, $get('assignments')); + } } From e7ee86a9149b5e10ecfc9f28dee640ec6aa5a17d Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 23 Jun 2024 22:31:41 -0400 Subject: [PATCH 061/103] Fix whoopsie --- app/Filament/Resources/UserResource/Pages/EditProfile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Filament/Resources/UserResource/Pages/EditProfile.php b/app/Filament/Resources/UserResource/Pages/EditProfile.php index f59a5b56ec..dc712163a9 100644 --- a/app/Filament/Resources/UserResource/Pages/EditProfile.php +++ b/app/Filament/Resources/UserResource/Pages/EditProfile.php @@ -191,7 +191,7 @@ protected function getForms(): array Tab::make('API Keys') ->icon('tabler-key') ->schema([ - Grid::make('asdf')->columns(5)->schema([ + Grid::make(5)->schema([ Section::make('Create API Key')->columnSpan(3)->schema([ TextInput::make('description') ->live(), From 755632f9d5ac5e85044647f51dc8b4d75e85432a Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 23 Jun 2024 22:32:37 -0400 Subject: [PATCH 062/103] Wip --- .../ServerResource/Pages/EditServer.php | 113 +++++++++++++++--- 1 file changed, 98 insertions(+), 15 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/EditServer.php b/app/Filament/Resources/ServerResource/Pages/EditServer.php index aef49d6920..76dcc710ac 100644 --- a/app/Filament/Resources/ServerResource/Pages/EditServer.php +++ b/app/Filament/Resources/ServerResource/Pages/EditServer.php @@ -4,6 +4,7 @@ use App\Models\Node; use App\Models\Objects\Endpoint; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\HtmlString; use LogicException; use App\Filament\Resources\ServerResource; @@ -445,9 +446,6 @@ public function form(Form $form): Form 'md' => 3, 'lg' => 5, ]) - ->afterStateHydrated(function (Forms\Set $set, Forms\Get $get) { - // $this->resetEggVariables($set, $get); - }) ->relationship('egg', 'name') ->searchable() ->preload() @@ -481,16 +479,56 @@ public function form(Form $form): Form ->label('Ports') ->formatStateUsing(fn (Server $server) => $server->ports->map(fn ($port) => (string) $port)->all()) ->afterStateUpdated(self::ports(...)) - ->hintAction( - Forms\Components\Actions\Action::make('asdf') - ->action(function (Forms\Get $get, Forms\Set $set) { - $this->resetEggVariables($set, $get); - })) ->live(), + Forms\Components\Repeater::make('portVariables') + ->label('Port Assignments (SV)') + ->columnSpan(3) + ->addable(false) + ->deletable(false) + + ->mutateRelationshipDataBeforeSaveUsing(function ($data) { + $portIndex = $data['port']; + unset($data['port']); + + return [ + 'variable_value' => (string) $this->ports[$portIndex], + ]; + }) + + ->relationship('serverVariables', function (Builder $query) { + $query->whereHas('variable', function (Builder $query) { + $query->where('rules', 'like', '%port%'); + }); + }) + + ->simple( + Forms\Components\Select::make('port') + ->live() + ->disabled(fn (Forms\Get $get) => empty($get('../../ports')) || empty($get('../../assignments'))) + ->prefix(function (Forms\Components\Component $component, ServerVariable $serverVariable) { + return $serverVariable->variable->env_variable; + }) + + ->formatStateUsing(function (ServerVariable $serverVariable, Forms\Get $get) { + return array_search($serverVariable->variable_value, array_values($get('../../ports'))); + }) + + ->disableOptionsWhenSelectedInSiblingRepeaterItems() + ->options(fn (Forms\Get $get) => $this->ports) + ->required(), + ) + , + Forms\Components\Repeater::make('assignments') ->columnSpan(3) - ->defaultItems(fn () => count($this->eggDefaultPorts)) + ->afterStateHydrated(function (Forms\Set $set, Forms\Get $get, Server $server) { + $this->ports($ports = $get('ports'), $set); + + foreach ($this->portOptions($server->egg) as $key => $port) { + $set("assignments.$key", ['port' => $portIndex = array_search($port, array_values($ports))]); + } + }) ->label('Port Assignments') ->helperText(fn (Forms\Get $get) => empty($get('ports')) ? 'You must add ports to assign them!' : '') ->live() @@ -504,7 +542,6 @@ public function form(Form $form): Form ->prefix(function (Forms\Components\Component $component) { $key = str($component->getStatePath())->beforeLast('.')->afterLast('.')->toString(); - dump($key); return $key; }) @@ -536,7 +573,11 @@ public function form(Form $form): Form Forms\Components\Hidden::make('environment')->default([]), Forms\Components\Repeater::make('server_variables') - ->relationship('serverVariables') + ->relationship('serverVariables', function (Builder $query) { + $query->whereHas('variable', function (Builder $query) { + $query->whereNot('rules', 'like', '%port%'); + }); + }) ->grid() ->mutateRelationshipDataBeforeSaveUsing(function (array &$data): array { foreach ($data as $key => $value) { @@ -764,12 +805,18 @@ protected function mutateFormDataBeforeSave(array $data): array return $data; } - private function shouldHideComponent(Forms\Get $get, Forms\Components\Component $component): bool + private function shouldHideComponent(ServerVariable $serverVariable, Forms\Components\Component $component): bool { - $containsRuleIn = str($get('rules'))->explode('|')->reduce( + $rules = str($serverVariable->variable->rules)->explode('|'); + + $containsRuleIn = $rules->reduce( fn ($result, $value) => $result === true && !str($value)->startsWith('in:'), true ); + if ($rules->contains('port')) { + return true; + } + if ($component instanceof Forms\Components\Select) { return $containsRuleIn; } @@ -781,9 +828,10 @@ private function shouldHideComponent(Forms\Get $get, Forms\Components\Component throw new \Exception('Component type not supported: ' . $component::class); } - private function getSelectOptionsFromRules(Forms\Get $get): array + private function getSelectOptionsFromRules(ServerVariable $serverVariable): array { - $inRule = str($get('rules'))->explode('|')->reduce( + $rules = str($serverVariable->variable->rules)->explode('|'); + $inRule = $rules->reduce( fn ($result, $value) => str($value)->startsWith('in:') ? $value : $result, '' ); @@ -871,4 +919,39 @@ public function resetEggVariables(Forms\Set $set, Forms\Get $get) // dump($variables, $this->ports, $this->eggDefaultPorts, $get('assignments')); } + + public function portOptions(Egg $egg, string $startup = null): array + { + if ($egg instanceof Server) { + $egg = $egg->egg; + } + + $options = []; + + if (empty($startup)) { + $startup = $egg->startup; + } + + if (str_contains($startup, '{{SERVER_PORT}}')) { + $options['SERVER_PORT'] = null; + } + + // startup SERVER_PORT + // ... + // ... + + foreach ($egg->variables as $variable) { + if (!in_array('port', explode('|', $variable->rules))) { + continue; + } + + // dump($variable); + + $options[$variable->env_variable] = $variable->default_value; + } + +// dump($options); + + return $options; + } } From 343a5b81bc5ce06001bcde28640e69265553ae16 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Wed, 26 Jun 2024 21:38:18 -0400 Subject: [PATCH 063/103] Almost done --- .../ServerResource/Pages/EditServer.php | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/app/Filament/Resources/ServerResource/Pages/EditServer.php b/app/Filament/Resources/ServerResource/Pages/EditServer.php index 76dcc710ac..d9881cebd6 100644 --- a/app/Filament/Resources/ServerResource/Pages/EditServer.php +++ b/app/Filament/Resources/ServerResource/Pages/EditServer.php @@ -518,10 +518,7 @@ public function form(Form $form): Form ->options(fn (Forms\Get $get) => $this->ports) ->required(), ) - , - Forms\Components\Repeater::make('assignments') - ->columnSpan(3) ->afterStateHydrated(function (Forms\Set $set, Forms\Get $get, Server $server) { $this->ports($ports = $get('ports'), $set); @@ -529,27 +526,8 @@ public function form(Form $form): Form $set("assignments.$key", ['port' => $portIndex = array_search($port, array_values($ports))]); } }) - ->label('Port Assignments') - ->helperText(fn (Forms\Get $get) => empty($get('ports')) ? 'You must add ports to assign them!' : '') - ->live() - ->addable(false) - ->deletable(false) - ->reorderable(false) - ->simple( - Forms\Components\Select::make('port') - ->live() - ->disabled(fn (Forms\Get $get) => empty($get('../../ports')) || empty($get('../../assignments'))) - ->prefix(function (Forms\Components\Component $component) { - $key = str($component->getStatePath())->beforeLast('.')->afterLast('.')->toString(); - - - return $key; - }) - ->disableOptionsWhenSelectedInSiblingRepeaterItems() - ->options(fn (Forms\Get $get) => $this->ports) - ->required(), - ), - + , + Forms\Components\Textarea::make('startup') ->label('Startup Command') ->required() From 7c8b204d13dfc1500daee0026360bc08ea98ace3 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Wed, 26 Jun 2024 21:42:57 -0400 Subject: [PATCH 064/103] Remove network tab --- .../server/network/AllocationRow.tsx | 119 ------------------ .../server/network/DeleteAllocationButton.tsx | 61 --------- .../server/network/NetworkContainer.tsx | 84 ------------- resources/scripts/routers/routes.ts | 7 -- 4 files changed, 271 deletions(-) delete mode 100644 resources/scripts/components/server/network/AllocationRow.tsx delete mode 100644 resources/scripts/components/server/network/DeleteAllocationButton.tsx delete mode 100644 resources/scripts/components/server/network/NetworkContainer.tsx diff --git a/resources/scripts/components/server/network/AllocationRow.tsx b/resources/scripts/components/server/network/AllocationRow.tsx deleted file mode 100644 index e68bc3359f..0000000000 --- a/resources/scripts/components/server/network/AllocationRow.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import React, { memo, useCallback, useState } from 'react'; -import isEqual from 'react-fast-compare'; -import tw from 'twin.macro'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faNetworkWired } from '@fortawesome/free-solid-svg-icons'; -import InputSpinner from '@/components/elements/InputSpinner'; -import { Textarea } from '@/components/elements/Input'; -import Can from '@/components/elements/Can'; -import { Button } from '@/components/elements/button/index'; -import GreyRowBox from '@/components/elements/GreyRowBox'; -import { Allocation } from '@/api/server/getServer'; -import styled from 'styled-components/macro'; -import { debounce } from 'debounce'; -import setServerAllocationNotes from '@/api/server/network/setServerAllocationNotes'; -import { useFlashKey } from '@/plugins/useFlash'; -import { ServerContext } from '@/state/server'; -import CopyOnClick from '@/components/elements/CopyOnClick'; -import DeleteAllocationButton from '@/components/server/network/DeleteAllocationButton'; -import setPrimaryServerAllocation from '@/api/server/network/setPrimaryServerAllocation'; -import getServerAllocations from '@/api/swr/getServerAllocations'; -import { ip } from '@/lib/formatters'; -import Code from '@/components/elements/Code'; - -const Label = styled.label` - ${tw`uppercase text-xs mt-1 text-neutral-400 block px-1 select-none transition-colors duration-150`} -`; - -interface Props { - allocation: Allocation; -} - -const AllocationRow = ({ allocation }: Props) => { - const [loading, setLoading] = useState(false); - const { clearFlashes, clearAndAddHttpError } = useFlashKey('server:network'); - const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid); - const { mutate } = getServerAllocations(); - - const onNotesChanged = useCallback((id: number, notes: string) => { - mutate((data) => data?.map((a) => (a.id === id ? { ...a, notes } : a)), false); - }, []); - - const setAllocationNotes = debounce((notes: string) => { - setLoading(true); - clearFlashes(); - - setServerAllocationNotes(uuid, allocation.id, notes) - .then(() => onNotesChanged(allocation.id, notes)) - .catch((error) => clearAndAddHttpError(error)) - .then(() => setLoading(false)); - }, 750); - - const setPrimaryAllocation = () => { - clearFlashes(); - mutate((data) => data?.map((a) => ({ ...a, isDefault: a.id === allocation.id })), false); - - setPrimaryServerAllocation(uuid, allocation.id).catch((error) => { - clearAndAddHttpError(error); - mutate(); - }); - }; - - return ( - -
-
- -
-
- {allocation.alias ? ( - - - {allocation.alias} - - - ) : ( - - {ip(allocation.ip)} - - )} - -
-
- {allocation.port} - -
-
-
- -