diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index c20a6de41..39e361dc3 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -475,27 +475,34 @@ class ServersController extends Controller return redirect()->route('admin.servers.view.delete', $id); } - // // - // public function postUpdateServerStartup(Request $request, $id) - // { - // try { - // $server = new ServerRepository; - // $server->updateStartup($id, $request->except([ - // '_token', - // ]), true); - // Alert::success('Server startup variables were successfully updated.')->flash(); - // } catch (\Pterodactyl\Exceptions\DisplayException $e) { - // Alert::danger($e->getMessage())->flash(); - // } catch (\Exception $e) { - // Log::error($e); - // Alert::danger('An unhandled exception occured while attemping to update startup variables for this server. Please try again.')->flash(); - // } finally { - // return redirect()->route('admin.servers.view', [ - // 'id' => $id, - // 'tab' => 'tab_startup', - // ])->withInput(); - // } - // } + /** + * Update the startup command as well as variables. + * + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function saveStartup(Request $request, $id) + { + $repo = new ServerRepository; + + try { + $repo->updateStartup($id, $request->except('_token'), true); + + Alert::success('Startup variables were successfully modified and assigned for this server.')->flash(); + } catch(DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (TransferException $ex) { + Log::warning($ex); + Alert::danger('A TransferException occurred while attempting to update the startup for this server, please ensure the daemon is running. This error has been logged.')->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An unhandled exception occured while attemping to update startup variables for this server. This error has been logged.')->flash(); + } + + return redirect()->route('admin.servers.view.startup', $id); + } + // // public function postDatabase(Request $request, $id) // { diff --git a/app/Http/Controllers/Server/ServerController.php b/app/Http/Controllers/Server/ServerController.php index 07dee5439..7be93ff61 100644 --- a/app/Http/Controllers/Server/ServerController.php +++ b/app/Http/Controllers/Server/ServerController.php @@ -309,9 +309,7 @@ class ServerController extends Controller try { $repo = new ServerRepository; - $repo->updateStartup($server->id, $request->except([ - '_token', - ])); + $repo->updateStartup($server->id, $request->except('_token')); Alert::success('Server startup variables were successfully updated.')->flash(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index 69e596a64..c40de6d18 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -174,6 +174,10 @@ class AdminRoutes 'uses' => 'Admin\ServersController@viewStartup', ]); + $router->post('/view/{id}/startup', [ + 'uses' => 'Admin\ServersController@saveStartup', + ]); + $router->get('/view/{id}/database', [ 'as' => 'admin.servers.view.database', 'uses' => 'Admin\ServersController@viewDatabase', diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index c8063b384..377450f66 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -617,87 +617,63 @@ class ServerRepository { $server = Models\Server::with('variables', 'option.variables')->findOrFail($id); - DB::beginTransaction(); - - try { - // Check the startup + DB::transaction(function () use ($admin, $data, $server) { if (isset($data['startup']) && $admin) { $server->startup = $data['startup']; $server->save(); } - // Check those Variables - $server->option->variables->transform(function ($item, $key) use ($server) { - $displayValue = $server->variables->where('variable_id', $item->id)->pluck('variable_value')->first(); - $item->server_value = (! is_null($displayValue)) ? $displayValue : $item->default_value; - - return $item; - }); - - $variableList = []; if ($server->option->variables) { - foreach ($server->option->variables as &$variable) { - // Move on if the new data wasn't even sent - if (! isset($data[$variable->env_variable])) { - $variableList[] = [ - 'id' => $variable->id, - 'env' => $variable->env_variable, - 'val' => $variable->server_value, - ]; + foreach($server->option->variables as &$variable) { + $set = isset($data['env_' . $variable->id]); + + // Variable is required but was not passed into the function. + if ($variable->required && ! $set) { + throw new DisplayException('A required variable (' . $variable->env_variable . ') was not passed in the request.'); + } + + // If user is not an admin and are trying to edit a non-editable field + // or an invisible field just silently skip the variable. + if (! $admin && (! $variable->user_editable || ! $variable->user_viewable)) { continue; } - // Update Empty but skip validation - if (empty($data[$variable->env_variable])) { - $variableList[] = [ - 'id' => $variable->id, - 'env' => $variable->env_variable, - 'val' => null, - ]; - continue; - } - - // Is the variable required? - // @TODO: is this even logical to perform this check? - if (isset($data[$variable->env_variable]) && empty($data[$variable->env_variable])) { - if ($variable->required) { - throw new DisplayException('A required service option variable field (' . $variable->env_variable . ') was included in this request but was left blank.'); + // Confirm value is valid when compared aganist regex. + // @TODO: switch to Laravel validation rules. + if ($set && ! is_null($variable->regex)) { + if (! preg_match($variable->regex, $data['env_' . $variable->id])) { + throw new DisplayException('The value passed for a variable (' . $variable->env_variable . ') could not be matched aganist the regex for that field (' . $variable->regex . ').'); } } - // Variable hidden and/or not user editable - if ((! $variable->user_viewable || ! $variable->user_editable) && ! $admin) { - throw new DisplayException('A service option variable field (' . $variable->env_variable . ') does not exist or you do not have permission to edit it.'); + $svar = Models\ServerVariable::firstOrNew([ + 'server_id' => $server->id, + 'variable_id' => $variable->id, + ]); + + // Set the value; if one was not passed set it to the default value + if ($set) { + $svar->variable_value = $data['env_' . $variable->id]; + + // Not passed, check if this record exists if so keep value, otherwise set default + } else { + $svar->variable_value = ($svar->exists) ? $svar->variable_value : $variable->default_value; } - // Check aganist Regex Pattern - if (! is_null($variable->regex) && ! preg_match($variable->regex, $data[$variable->env_variable])) { - throw new DisplayException('Failed to validate service option variable field (' . $variable->env_variable . ') aganist regex (' . $variable->regex . ').'); - } - - $variableList[] = [ - 'id' => $variable->id, - 'env' => $variable->env_variable, - 'val' => $data[$variable->env_variable], - ]; + $svar->save(); } } - // Add Variables - $environmentVariables = [ - 'STARTUP' => $server->startup, - ]; - foreach ($variableList as $item) { - $environmentVariables[$item['env']] = $item['val']; + // Reload Variables + $server->load('variables'); + $environment = $server->option->variables->map(function ($item, $key) use ($server) { + $display = $server->variables->where('variable_id', $item->id)->pluck('variable_value')->first(); - // Update model or make a new record if it doesn't exist. - $model = Models\ServerVariable::firstOrNew([ - 'variable_id' => $item['id'], - 'server_id' => $server->id, - ]); - $model->variable_value = $item['val']; - $model->save(); - } + return [ + 'variable' => $item->env_variable, + 'value' => (! is_null($display)) ? $display : $item->default_value, + ]; + }); $server->node->guzzleClient([ 'X-Access-Server' => $server->uuid, @@ -705,21 +681,11 @@ class ServerRepository ])->request('PATCH', '/server', [ 'json' => [ 'build' => [ - 'env|overwrite' => $environmentVariables, + 'env|overwrite' => $environment->pluck('value', 'variable')->merge(['STARTUP' => $server->startup]), ], ], ]); - - DB::commit(); - - return true; - } catch (TransferException $ex) { - DB::rollBack(); - throw new DisplayException('An error occured while attempting to update the server configuration.', $ex); - } catch (\Exception $ex) { - DB::rollBack(); - throw $ex; - } + }); } public function queueDeletion($id, $force = false) diff --git a/resources/lang/en/server.php b/resources/lang/en/server.php index 0f77c1fe8..d8cae3ae2 100644 --- a/resources/lang/en/server.php +++ b/resources/lang/en/server.php @@ -233,6 +233,8 @@ return [ 'command' => 'Startup Command', 'edit_params' => 'Edit Parameters', 'update' => 'Update Startup Parameters', + 'startup_var' => 'Startup Command Variable', + 'startup_regex' => 'Verification Regex', ], 'sftp' => [ 'header' => 'SFTP Configuration', diff --git a/resources/lang/en/strings.php b/resources/lang/en/strings.php index ee2939f31..b3abb2bc1 100644 --- a/resources/lang/en/strings.php +++ b/resources/lang/en/strings.php @@ -63,4 +63,6 @@ return [ '2fa' => '2FA', 'logout' => 'Logout', 'admin_cp' => 'Admin Control Panel', + 'optional' => 'Optional', + 'read_only' => 'Read Only', ]; diff --git a/resources/themes/pterodactyl/admin/servers/view/startup.blade.php b/resources/themes/pterodactyl/admin/servers/view/startup.blade.php index e69de29bb..5e4175ad2 100644 --- a/resources/themes/pterodactyl/admin/servers/view/startup.blade.php +++ b/resources/themes/pterodactyl/admin/servers/view/startup.blade.php @@ -0,0 +1,115 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.admin') + +@section('title') + Server — {{ $server->name }}: Startup +@endsection + +@section('content-header') +

{{ $server->name }}Control startup command as well as variables.

+ +@endsection + +@section('content') +
+
+ +
+
+
+
+
+
+
+

Startup Command Modification

+
+
+ +
+ {{ $server->option->display_executable }} + +
+

Edit your server's startup command here. The following variables are available by default: @{{SERVER_MEMORY}}, @{{SERVER_IP}}, and @{{SERVER_PORT}}.

+
+ +
+
+ @foreach($server->option->variables as $variable) +
+
+
+

{{ $variable->name }}

+
+
+ +

{{ $variable->description }}

+

+ @if($variable->required)Required@elseOptional@endif + @if($variable->user_viewable)Visible@elseHidden@endif + @if($variable->user_editable)Editable@elseLocked@endif +

+
+ +
+
+ @endforeach +
+
+@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/themes/pterodactyl/server/settings/startup.blade.php b/resources/themes/pterodactyl/server/settings/startup.blade.php index 745d0d3fd..981d8e60c 100644 --- a/resources/themes/pterodactyl/server/settings/startup.blade.php +++ b/resources/themes/pterodactyl/server/settings/startup.blade.php @@ -35,64 +35,76 @@ @section('content')
-
-
-
-

@lang('server.config.startup.command')

-
-
-
- {{ $service->executable }} - +
+
+
+
+

@lang('server.config.startup.command')

-
-
-
-
-
-
-

@lang('server.config.startup.edit_params')

-
- @can('edit-startup', $server) - -
- @foreach($variables as $item) -
- -
- user_editable === 1) - name="{{ $item->env_variable }}" - @else - readonly="readonly" - @endif - class="form-control" value="{{ old($item->env_variable, $item->a_serverValue) }}" data-action="matchRegex" data-regex="{{ $item->regex }}" /> -
-

{!! $item->description !!}

-
- @endforeach +
+
+ {{ $service->executable }} +
+
+ @can('edit-startup', $server) - - @else -
-
-

@lang('auth.not_authorized')

+ @endcan +
+
+ @can('edit-startup', $server) + @foreach($variables as $variable) +
+
+
+

{{ $variable->name }}

+
+
+ user_editable) + name="env_{{ $variable->id }}" + @else + readonly + @endif + class="form-control" type="text" value="{{ old('env_' . $variable->id, $variable->server_value) }}" /> +

{{ $variable->description }}

+

+ @if($variable->required && $variable->user_editable) + @lang('strings.required') + @elseif(! $variable->required && $variable->user_editable) + @lang('strings.optional') + @endif + @if(! $variable->user_editable) + @lang('strings.read_only') + @endif +

+
+
- @endcan -
-
+ @endforeach + @endcan +
@endsection @section('footer-scripts') @parent {!! Theme::js('js/frontend/server.socket.js') !!} + @endsection