From 34865d4288cfe09e8180837f2f7e8b088c6ddbab Mon Sep 17 00:00:00 2001 From: Boy132 Date: Fri, 6 Jun 2025 14:19:09 +0200 Subject: [PATCH 01/10] Fix hostname env variable name in rust egg (#1435) --- database/Seeders/eggs/rust/egg-rust.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/database/Seeders/eggs/rust/egg-rust.json b/database/Seeders/eggs/rust/egg-rust.json index b38868888..ebe84d132 100644 --- a/database/Seeders/eggs/rust/egg-rust.json +++ b/database/Seeders/eggs/rust/egg-rust.json @@ -4,7 +4,7 @@ "version": "PLCN_v1", "update_url": "https:\/\/github.com\/pelican-dev\/panel\/raw\/main\/database\/Seeders\/eggs\/rust\/egg-rust.json" }, - "exported_at": "2025-03-18T12:36:48+00:00", + "exported_at": "2025-06-06T11:57:17+00:00", "name": "Rust", "author": "panel@example.com", "uuid": "bace2dfb-209c-452a-9459-7d6f340b07ae", @@ -20,7 +20,7 @@ "ghcr.io\/parkervcp\/games:rust": "ghcr.io\/parkervcp\/games:rust" }, "file_denylist": [], - "startup": ".\/RustDedicated -batchmode +server.port {{SERVER_PORT}} +server.queryport {{QUERY_PORT}} +server.identity \"rust\" +rcon.port {{RCON_PORT}} +rcon.web true +server.hostname \\\"{{HOSTNAME}}\\\" +server.level \\\"{{LEVEL}}\\\" +server.description \\\"{{DESCRIPTION}}\\\" +server.url \\\"{{SERVER_URL}}\\\" +server.headerimage \\\"{{SERVER_IMG}}\\\" +server.logoimage \\\"{{SERVER_LOGO}}\\\" +server.maxplayers {{MAX_PLAYERS}} +rcon.password \\\"{{RCON_PASS}}\\\" +server.saveinterval {{SAVEINTERVAL}} +app.port {{APP_PORT}} $( [ -z ${MAP_URL} ] && printf %s \"+server.worldsize \\\"{{WORLD_SIZE}}\\\" +server.seed \\\"{{WORLD_SEED}}\\\"\" || printf %s \"+server.levelurl {{MAP_URL}}\" ) {{ADDITIONAL_ARGS}}", + "startup": ".\/RustDedicated -batchmode +server.port {{SERVER_PORT}} +server.queryport {{QUERY_PORT}} +server.identity \"rust\" +rcon.port {{RCON_PORT}} +rcon.web true +server.hostname \\\"{{SERVER_HOSTNAME}}\\\" +server.level \\\"{{LEVEL}}\\\" +server.description \\\"{{DESCRIPTION}}\\\" +server.url \\\"{{SERVER_URL}}\\\" +server.headerimage \\\"{{SERVER_IMG}}\\\" +server.logoimage \\\"{{SERVER_LOGO}}\\\" +server.maxplayers {{MAX_PLAYERS}} +rcon.password \\\"{{RCON_PASS}}\\\" +server.saveinterval {{SAVEINTERVAL}} +app.port {{APP_PORT}} $( [ -z ${MAP_URL} ] && printf %s \"+server.worldsize \\\"{{WORLD_SIZE}}\\\" +server.seed \\\"{{WORLD_SEED}}\\\"\" || printf %s \"+server.levelurl {{MAP_URL}}\" ) {{ADDITIONAL_ARGS}}", "config": { "files": "{}", "startup": "{\r\n \"done\": \"Server startup complete\"\r\n}", @@ -38,7 +38,7 @@ { "name": "Server Name", "description": "The name of your server in the public server list.", - "env_variable": "HOSTNAME", + "env_variable": "SERVER_HOSTNAME", "default_value": "A Rust Server", "user_viewable": true, "user_editable": true, From 65deffc6e6288fd2106eb0765f7af1dff0311f01 Mon Sep 17 00:00:00 2001 From: pelican-vehikl Date: Fri, 6 Jun 2025 23:06:28 -0400 Subject: [PATCH 02/10] Create new description endpoint (#1136) Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com> --- .../Api/Client/Servers/SettingsController.php | 33 +++++++++++++------ .../Settings/DescriptionServerRequest.php | 30 +++++++++++++++++ .../Servers/Settings/RenameServerRequest.php | 1 - app/Models/Permission.php | 4 ++- lang/en/server/users.php | 3 +- routes/api-client.php | 1 + .../Client/Server/SettingsControllerTest.php | 5 --- 7 files changed, 59 insertions(+), 18 deletions(-) create mode 100644 app/Http/Requests/Api/Client/Servers/Settings/DescriptionServerRequest.php diff --git a/app/Http/Controllers/Api/Client/Servers/SettingsController.php b/app/Http/Controllers/Api/Client/Servers/SettingsController.php index 169f825b5..6bc765a08 100644 --- a/app/Http/Controllers/Api/Client/Servers/SettingsController.php +++ b/app/Http/Controllers/Api/Client/Servers/SettingsController.php @@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api\Client\Servers; use App\Facades\Activity; use App\Http\Controllers\Api\Client\ClientApiController; +use App\Http\Requests\Api\Client\Servers\Settings\DescriptionServerRequest; use App\Http\Requests\Api\Client\Servers\Settings\ReinstallServerRequest; use App\Http\Requests\Api\Client\Servers\Settings\RenameServerRequest; use App\Http\Requests\Api\Client\Servers\Settings\SetDockerImageRequest; @@ -34,24 +35,36 @@ class SettingsController extends ClientApiController public function rename(RenameServerRequest $request, Server $server): JsonResponse { $name = $request->input('name'); - $description = $request->has('description') ? (string) $request->input('description') : $server->description; - if ($server->name !== $name) { + $server->update(['name' => $name]); + + if ($server->wasChanged('name')) { Activity::event('server:settings.rename') - ->property(['old' => $server->name, 'new' => $name]) + ->property(['old' => $server->getOriginal('name'), 'new' => $name]) ->log(); - $server->name = $name; } - if ($server->description !== $description && config('panel.editable_server_descriptions')) { + return new JsonResponse([], Response::HTTP_NO_CONTENT); + } + + /** + * Update server description + */ + public function description(DescriptionServerRequest $request, Server $server): JsonResponse + { + if (!config('panel.editable_server_descriptions')) { + return new JsonResponse([], Response::HTTP_FORBIDDEN); + } + + $description = $request->input('description'); + $server->update(['description' => $description ?? '']); + + if ($server->wasChanged('description')) { Activity::event('server:settings.description') - ->property(['old' => $server->description, 'new' => $description]) + ->property(['old' => $server->getOriginal('description'), 'new' => $description]) ->log(); - $server->description = $description; } - $server->save(); - return new JsonResponse([], Response::HTTP_NO_CONTENT); } @@ -80,7 +93,7 @@ class SettingsController extends ClientApiController */ public function dockerImage(SetDockerImageRequest $request, Server $server): JsonResponse { - if (!in_array($server->image, array_values($server->egg->docker_images))) { + if (!in_array($server->image, $server->egg->docker_images)) { throw new BadRequestHttpException('This server\'s Docker image has been manually set by an administrator and cannot be updated.'); } diff --git a/app/Http/Requests/Api/Client/Servers/Settings/DescriptionServerRequest.php b/app/Http/Requests/Api/Client/Servers/Settings/DescriptionServerRequest.php new file mode 100644 index 000000000..ba2fa2125 --- /dev/null +++ b/app/Http/Requests/Api/Client/Servers/Settings/DescriptionServerRequest.php @@ -0,0 +1,30 @@ + 'string|nullable', + ]; + } +} diff --git a/app/Http/Requests/Api/Client/Servers/Settings/RenameServerRequest.php b/app/Http/Requests/Api/Client/Servers/Settings/RenameServerRequest.php index c68e0d444..fb7d8e677 100644 --- a/app/Http/Requests/Api/Client/Servers/Settings/RenameServerRequest.php +++ b/app/Http/Requests/Api/Client/Servers/Settings/RenameServerRequest.php @@ -26,7 +26,6 @@ class RenameServerRequest extends ClientApiRequest implements ClientPermissionsR { return [ 'name' => Server::getRules()['name'], - 'description' => 'string|nullable', ]; } } diff --git a/app/Models/Permission.php b/app/Models/Permission.php index d9f489102..82718f06f 100644 --- a/app/Models/Permission.php +++ b/app/Models/Permission.php @@ -97,6 +97,8 @@ class Permission extends Model implements Validatable public const ACTION_SETTINGS_RENAME = 'settings.rename'; + public const ACTION_SETTINGS_DESCRIPTION = 'settings.description'; + public const ACTION_SETTINGS_REINSTALL = 'settings.reinstall'; public const ACTION_ACTIVITY_READ = 'activity.read'; @@ -176,7 +178,7 @@ class Permission extends Model implements Validatable [ 'name' => 'settings', 'icon' => 'tabler-settings', - 'permissions' => ['rename', 'reinstall'], + 'permissions' => ['rename', 'description', 'reinstall'], ], [ 'name' => 'activity', diff --git a/lang/en/server/users.php b/lang/en/server/users.php index cb570da58..99486bd48 100644 --- a/lang/en/server/users.php +++ b/lang/en/server/users.php @@ -16,7 +16,8 @@ return [ 'startup_update' => 'Allows a user to modify the startup variables for the server.', 'startup_docker_image' => 'Allows a user to modify the Docker image used when running the server.', 'settings_reinstall' => 'Allows a user to trigger a reinstall of this server.', - 'settings_rename' => 'Allows a user to rename this server and change the description of it.', + 'settings_rename' => 'Allows a user to rename this server.', + 'settings_description' => 'Allows a user to change the description of this server.', 'activity_read' => 'Allows a user to view the activity logs for the server.', 'websocket_*' => 'Allows a user access to the websocket for this server.', 'control_console' => 'Allows a user to send data to the server console.', diff --git a/routes/api-client.php b/routes/api-client.php index 0feceeb78..c5ab1d3ba 100644 --- a/routes/api-client.php +++ b/routes/api-client.php @@ -129,6 +129,7 @@ Route::prefix('/servers/{server:uuid}')->middleware([ServerSubject::class, Authe Route::prefix('/settings')->group(function () { Route::post('/rename', [Client\Servers\SettingsController::class, 'rename']); + Route::post('/description', [Client\Servers\SettingsController::class, 'description']); Route::post('/reinstall', [Client\Servers\SettingsController::class, 'reinstall']); Route::put('/docker-image', [Client\Servers\SettingsController::class, 'dockerImage']); }); diff --git a/tests/Integration/Api/Client/Server/SettingsControllerTest.php b/tests/Integration/Api/Client/Server/SettingsControllerTest.php index a0a722651..ded84ce1d 100644 --- a/tests/Integration/Api/Client/Server/SettingsControllerTest.php +++ b/tests/Integration/Api/Client/Server/SettingsControllerTest.php @@ -21,11 +21,9 @@ class SettingsControllerTest extends ClientApiIntegrationTestCase /** @var \App\Models\Server $server */ [$user, $server] = $this->generateTestAccount($permissions); $originalName = $server->name; - $originalDescription = $server->description; $response = $this->actingAs($user)->postJson("/api/client/servers/$server->uuid/settings/rename", [ 'name' => '', - 'description' => '', ]); $response->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY); @@ -33,18 +31,15 @@ class SettingsControllerTest extends ClientApiIntegrationTestCase $server = $server->refresh(); $this->assertSame($originalName, $server->name); - $this->assertSame($originalDescription, $server->description); $this->actingAs($user) ->postJson("/api/client/servers/$server->uuid/settings/rename", [ 'name' => 'Test Server Name', - 'description' => 'This is a test server.', ]) ->assertStatus(Response::HTTP_NO_CONTENT); $server = $server->refresh(); $this->assertSame('Test Server Name', $server->name); - $this->assertSame('This is a test server.', $server->description); } /** From bd2a00760dae0567ce7ad0b4f8e2b3a2450fdf4f Mon Sep 17 00:00:00 2001 From: Boy132 Date: Sat, 7 Jun 2025 14:16:01 +0200 Subject: [PATCH 03/10] Fix error handling for deleting backups (#1434) --- .../Server/Resources/BackupResource.php | 25 ++++++++++++++++--- app/Services/Backups/DeleteBackupService.php | 9 +++---- .../Backups/DeleteBackupServiceTest.php | 6 ++--- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/app/Filament/Server/Resources/BackupResource.php b/app/Filament/Server/Resources/BackupResource.php index d163b751b..dc0a11600 100644 --- a/app/Filament/Server/Resources/BackupResource.php +++ b/app/Filament/Server/Resources/BackupResource.php @@ -14,6 +14,7 @@ use App\Repositories\Daemon\DaemonBackupRepository; use App\Services\Backups\DownloadLinkService; use App\Filament\Components\Tables\Columns\BytesColumn; use App\Filament\Components\Tables\Columns\DateTimeColumn; +use App\Services\Backups\DeleteBackupService; use Filament\Facades\Filament; use Filament\Forms\Components\Checkbox; use Filament\Forms\Components\Placeholder; @@ -30,6 +31,7 @@ use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; use Illuminate\Database\Eloquent\Model; +use Illuminate\Http\Client\ConnectionException; use Illuminate\Http\Request; class BackupResource extends Resource @@ -142,7 +144,7 @@ class BackupResource extends Resource ->send(); } - if (!$backup->is_successful && is_null($backup->completed_at)) { //TODO Change to Notifications + if (!$backup->is_successful && is_null($backup->completed_at)) { return Notification::make() ->danger() ->title('Backup Restore Failed') @@ -175,9 +177,26 @@ class BackupResource extends Resource ->visible(fn (Backup $backup) => $backup->status === BackupStatus::Successful), DeleteAction::make('delete') ->disabled(fn (Backup $backup) => $backup->is_locked) - ->modalDescription(fn (Backup $backup) => 'Do you wish to delete, ' . $backup->name . '?') + ->modalDescription(fn (Backup $backup) => 'Do you wish to delete ' . $backup->name . '?') ->modalSubmitActionLabel('Delete Backup') - ->action(fn (BackupController $backupController, Backup $backup, Request $request) => $backupController->delete($request, $server, $backup)) + ->action(function (Backup $backup, DeleteBackupService $deleteBackupService) { + try { + $deleteBackupService->handle($backup); + } catch (ConnectionException) { + Notification::make() + ->title('Could not delete backup') + ->body('Connection to node failed') + ->danger() + ->send(); + + return; + } + + Activity::event('server:backup.delete') + ->subject($backup) + ->property(['name' => $backup->name, 'failed' => !$backup->is_successful]) + ->log(); + }) ->visible(fn (Backup $backup) => $backup->status !== BackupStatus::InProgress), ]), ]); diff --git a/app/Services/Backups/DeleteBackupService.php b/app/Services/Backups/DeleteBackupService.php index a2402fdee..04cf9e548 100644 --- a/app/Services/Backups/DeleteBackupService.php +++ b/app/Services/Backups/DeleteBackupService.php @@ -6,12 +6,11 @@ use App\Extensions\Filesystem\S3Filesystem; use Aws\S3\S3Client; use Illuminate\Http\Response; use App\Models\Backup; -use GuzzleHttp\Exception\ClientException; use Illuminate\Database\ConnectionInterface; use App\Extensions\Backups\BackupManager; use App\Repositories\Daemon\DaemonBackupRepository; use App\Exceptions\Service\Backup\BackupLockedException; -use Illuminate\Http\Client\ConnectionException; +use Exception; class DeleteBackupService { @@ -48,12 +47,10 @@ class DeleteBackupService $this->connection->transaction(function () use ($backup) { try { $this->daemonBackupRepository->setServer($backup->server)->delete($backup); - } catch (ConnectionException $exception) { - $previous = $exception->getPrevious(); - + } catch (Exception $exception) { // Don't fail the request if the Daemon responds with a 404, just assume the backup // doesn't actually exist and remove its reference from the Panel as well. - if (!$previous instanceof ClientException || $previous->getResponse()->getStatusCode() !== Response::HTTP_NOT_FOUND) { + if ($exception->getCode() !== Response::HTTP_NOT_FOUND) { throw $exception; } } diff --git a/tests/Integration/Services/Backups/DeleteBackupServiceTest.php b/tests/Integration/Services/Backups/DeleteBackupServiceTest.php index d280a95c7..8c0ac8ad2 100644 --- a/tests/Integration/Services/Backups/DeleteBackupServiceTest.php +++ b/tests/Integration/Services/Backups/DeleteBackupServiceTest.php @@ -2,10 +2,8 @@ namespace App\Tests\Integration\Services\Backups; -use GuzzleHttp\Psr7\Request; use GuzzleHttp\Psr7\Response; use App\Models\Backup; -use GuzzleHttp\Exception\ClientException; use App\Extensions\Backups\BackupManager; use App\Extensions\Filesystem\S3Filesystem; use App\Services\Backups\DeleteBackupService; @@ -54,7 +52,7 @@ class DeleteBackupServiceTest extends IntegrationTestCase $backup = Backup::factory()->create(['server_id' => $server->id]); $mock = $this->mock(DaemonBackupRepository::class); - $mock->expects('setServer->delete')->with($backup)->andThrow(new ConnectionException(previous: new ClientException('', new Request('DELETE', '/'), new Response(404)))); + $mock->expects('setServer->delete')->with($backup)->andThrow(new ConnectionException(code: 404)); $this->app->make(DeleteBackupService::class)->handle($backup); @@ -69,7 +67,7 @@ class DeleteBackupServiceTest extends IntegrationTestCase $backup = Backup::factory()->create(['server_id' => $server->id]); $mock = $this->mock(DaemonBackupRepository::class); - $mock->expects('setServer->delete')->with($backup)->andThrow(new ConnectionException(previous: new ClientException('', new Request('DELETE', '/'), new Response(500)))); + $mock->expects('setServer->delete')->with($backup)->andThrow(new ConnectionException(code: 500)); $this->expectException(ConnectionException::class); From af609994b637e975886c3daed26765c411493700 Mon Sep 17 00:00:00 2001 From: JoanFo <161775222+JoanFo1456@users.noreply.github.com> Date: Sun, 8 Jun 2025 09:11:56 +0200 Subject: [PATCH 04/10] Fix missing font (#1404) Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com> --- app/Filament/Pages/Auth/EditProfile.php | 41 +++++++++++-------- .../components/server-console.blade.php | 2 +- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/app/Filament/Pages/Auth/EditProfile.php b/app/Filament/Pages/Auth/EditProfile.php index a5437b159..9bf66b4ef 100644 --- a/app/Filament/Pages/Auth/EditProfile.php +++ b/app/Filament/Pages/Auth/EditProfile.php @@ -32,6 +32,7 @@ use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\ToggleButtons; use Filament\Forms\Get; +use Filament\Forms\Set; use Filament\Notifications\Notification; use Filament\Pages\Auth\EditProfile as BaseEditProfile; use Filament\Support\Colors\Color; @@ -402,30 +403,38 @@ class EditProfile extends BaseEditProfile }) ->reactive() ->default('monospace') - ->afterStateUpdated(fn ($state, callable $set) => $set('font_preview', $state)), + ->afterStateUpdated(fn ($state, Set $set) => $set('font_preview', $state)), Placeholder::make('font_preview') ->label(trans('profile.font_preview')) ->columnSpan(2) ->content(function (Get $get) { $fontName = $get('console_font') ?? 'monospace'; $fontSize = $get('console_font_size') . 'px'; - $fontUrl = asset("storage/fonts/{$fontName}.ttf"); + $style = << - @font-face { - font-family: "CustomPreviewFont"; - src: url("$fontUrl"); - } - .preview-text { - font-family: "CustomPreviewFont"; - font-size: $fontSize; - margin-top: 10px; - display: block; - } - - The quick blue pelican jumps over the lazy pterodactyl. :) - HTML); + + The quick blue pelican jumps over the lazy pterodactyl. :) + HTML); }), TextInput::make('console_graph_period') ->label(trans('profile.graph_period')) diff --git a/resources/views/filament/components/server-console.blade.php b/resources/views/filament/components/server-console.blade.php index 366f814c7..b7ddf0537 100644 --- a/resources/views/filament/components/server-console.blade.php +++ b/resources/views/filament/components/server-console.blade.php @@ -5,7 +5,7 @@ $userFontSize = auth()->user()->getCustomization()['console_font_size'] ?? 14; $userRows = auth()->user()->getCustomization()['console_rows'] ?? 30; @endphp - @if($userFont) + @if($userFont !== "monospace")