From ad5e253a070077cd6c410375291d4b1a8c02b8ad Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Mon, 15 Feb 2016 15:21:28 -0500 Subject: [PATCH] Really basic initial implementation of service management --- .../Controllers/Admin/ServiceController.php | 145 ++++++++++++++++++ app/Http/Routes/AdminRoutes.php | 38 +++++ app/Models/Service.php | 7 + app/Models/ServiceOptions.php | 7 + app/Models/ServiceVariables.php | 7 + app/Repositories/ServiceRepository/Option.php | 48 ++++++ .../ServiceRepository/Service.php | 63 ++++++++ .../ServiceRepository/Variable.php | 77 ++++++++++ .../views/admin/services/index.blade.php | 55 +++++++ resources/views/admin/services/new.blade.php | 0 .../admin/services/options/new.blade.php | 0 .../admin/services/options/view.blade.php | 140 +++++++++++++++++ resources/views/admin/services/view.blade.php | 118 ++++++++++++++ 13 files changed, 705 insertions(+) create mode 100644 app/Http/Controllers/Admin/ServiceController.php create mode 100644 app/Repositories/ServiceRepository/Option.php create mode 100644 app/Repositories/ServiceRepository/Service.php create mode 100644 app/Repositories/ServiceRepository/Variable.php create mode 100644 resources/views/admin/services/index.blade.php create mode 100644 resources/views/admin/services/new.blade.php create mode 100644 resources/views/admin/services/options/new.blade.php create mode 100644 resources/views/admin/services/options/view.blade.php create mode 100644 resources/views/admin/services/view.blade.php diff --git a/app/Http/Controllers/Admin/ServiceController.php b/app/Http/Controllers/Admin/ServiceController.php new file mode 100644 index 00000000..981a8b32 --- /dev/null +++ b/app/Http/Controllers/Admin/ServiceController.php @@ -0,0 +1,145 @@ + + * + * 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. + */ +namespace Pterodactyl\Http\Controllers\Admin; + +use Alert; +use DB; +use Log; +use Validator; + +use Pterodactyl\Models; +use Pterodactyl\Repositories\ServiceRepository; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Exceptions\DisplayValidationException; + +use Pterodactyl\Http\Controllers\Controller; +use Illuminate\Http\Request; + +class ServiceController extends Controller +{ + + public function __construct() + { + // + } + + public function getIndex(Request $request) + { + return view('admin.services.index', [ + 'services' => Models\Service::all() + ]); + } + + public function getNew(Request $request) + { + // + } + + public function postNew(Request $request) + { + // + } + + public function getService(Request $request, $service) + { + return view('admin.services.view', [ + 'service' => Models\Service::findOrFail($service), + 'options' => Models\ServiceOptions::select( + 'service_options.*', + DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.option = service_options.id) as c_servers') + )->where('parent_service', $service)->get() + ]); + } + + public function postService(Request $request, $service) + { + try { + $repo = new ServiceRepository\Service; + $repo->update($service, $request->except([ + '_token' + ])); + Alert::success('Successfully updated this service.')->flash(); + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.services.service', $service)->withErrors(json_decode($ex->getMessage()))->withInput(); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An error occurred while attempting to update this service.')->flash(); + } + return redirect()->route('admin.services.service', $service)->withInput(); + } + + public function getOption(Request $request, $option) + { + $opt = Models\ServiceOptions::findOrFail($option); + return view('admin.services.options.view', [ + 'service' => Models\Service::findOrFail($opt->parent_service), + 'option' => $opt, + 'variables' => Models\ServiceVariables::where('option_id', $option)->get(), + 'servers' => Models\Server::select('servers.*', 'users.email as a_ownerEmail') + ->join('users', 'users.id', '=', 'servers.owner') + ->where('option', $option) + ->paginate(10) + ]); + } + + public function postOption(Request $request, $option) + { + // editing option + } + + public function postOptionVariable(Request $request, $option, $variable) + { + if ($variable === 'new') { + // adding new variable + } else { + try { + $repo = new ServiceRepository\Variable; + + // Because of the way old() works on the display side we prefix all of the variables with thier ID + // We need to remove that prefix here since the repo doesn't want it. + $data = []; + foreach($request->except(['_token']) as $id => $val) { + $data[str_replace($variable.'_', '', $id)] = $val; + } + $repo->update($variable, $data); + Alert::success('Successfully updated variable.')->flash(); + } catch (DisplayValidationException $ex) { + $data = []; + foreach(json_decode($ex->getMessage(), true) as $id => $val) { + $data[$variable.'_'.$id] = $val; + } + return redirect()->route('admin.services.option', $option)->withErrors((object) $data)->withInput(); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An error occurred while attempting to update this service.')->flash(); + } + return redirect()->route('admin.services.option', $option)->withInput(); + } + } + +} diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index f4d12111..34bcf94a 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -334,6 +334,44 @@ class AdminRoutes { ]); }); + // Service Routes + $router->group([ + 'prefix' => 'admin/services', + 'middleware' => [ + 'auth', + 'admin', + 'csrf' + ] + ], function () use ($router) { + $router->get('/', [ + 'as' => 'admin.services', + 'uses' => 'Admin\ServiceController@getIndex' + ]); + + $router->get('/service/{id}', [ + 'as' => 'admin.services.service', + 'uses' => 'Admin\ServiceController@getService' + ]); + + $router->post('/service/{id}', [ + 'uses' => 'Admin\ServiceController@postService' + ]); + + $router->get('/option/{id}', [ + 'as' => 'admin.services.option', + 'uses' => 'Admin\ServiceController@getOption' + ]); + + $router->post('/option/{id}', [ + 'uses' => 'Admin\ServiceController@postOption' + ]); + + $router->post('/option/{option}/{variable}', [ + 'as' => 'admin.services.option.variable', + 'uses' => 'Admin\ServiceController@postOptionVariable' + ]); + }); + } } diff --git a/app/Models/Service.php b/app/Models/Service.php index 2004588f..e1d3e23e 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -35,4 +35,11 @@ class Service extends Model */ protected $table = 'services'; + /** + * Fields that are not mass assignable. + * + * @var array + */ + protected $guarded = ['id', 'created_at', 'updated_at']; + } diff --git a/app/Models/ServiceOptions.php b/app/Models/ServiceOptions.php index abe0a0dd..393445a4 100644 --- a/app/Models/ServiceOptions.php +++ b/app/Models/ServiceOptions.php @@ -35,6 +35,13 @@ class ServiceOptions extends Model */ protected $table = 'service_options'; + /** + * Fields that are not mass assignable. + * + * @var array + */ + protected $guarded = ['id', 'created_at', 'updated_at']; + /** * Cast values to correct type. * diff --git a/app/Models/ServiceVariables.php b/app/Models/ServiceVariables.php index 94399c8a..8b7f203b 100644 --- a/app/Models/ServiceVariables.php +++ b/app/Models/ServiceVariables.php @@ -35,6 +35,13 @@ class ServiceVariables extends Model */ protected $table = 'service_variables'; + /** + * Fields that are not mass assignable. + * + * @var array + */ + protected $guarded = ['id', 'created_at', 'updated_at']; + /** * Cast values to correct type. * diff --git a/app/Repositories/ServiceRepository/Option.php b/app/Repositories/ServiceRepository/Option.php new file mode 100644 index 00000000..0b4d705c --- /dev/null +++ b/app/Repositories/ServiceRepository/Option.php @@ -0,0 +1,48 @@ + + * + * 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. + */ +namespace Pterodactyl\Repositories\ServiceRepository; + +use DB; +use Validator; + +use Pterodactyl\Models; +use Pterodactyl\Services\UuidService; + +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Exceptions\DisplayValidationException; + +class Option +{ + + public function __construct() + { + // + } + + public function update($id, array $data) + { + + } + +} diff --git a/app/Repositories/ServiceRepository/Service.php b/app/Repositories/ServiceRepository/Service.php new file mode 100644 index 00000000..bd9f6a9f --- /dev/null +++ b/app/Repositories/ServiceRepository/Service.php @@ -0,0 +1,63 @@ + + * + * 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. + */ +namespace Pterodactyl\Repositories\ServiceRepository; + +use DB; +use Validator; + +use Pterodactyl\Models; +use Pterodactyl\Services\UuidService; + +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Exceptions\DisplayValidationException; + +class Service +{ + + public function __construct() + { + // + } + + public function update($id, array $data) + { + $service = Models\Service::findOrFail($id); + + $validator = Validator::make($data, [ + 'name' => 'sometimes|required|string|min:1|max:255', + 'description' => 'sometimes|required|string', + 'file' => 'sometimes|required|regex:/^[\w.-]{1,50}$/', + 'executable' => 'sometimes|required|max:255|regex:/^(.*)$/', + 'startup' => 'sometimes|required|string' + ]); + + if ($validator->fails()) { + throw new DisplayValidationException($validator->errors()); + } + + $service->fill($data); + $service->save(); + } + +} diff --git a/app/Repositories/ServiceRepository/Variable.php b/app/Repositories/ServiceRepository/Variable.php new file mode 100644 index 00000000..88a21e5c --- /dev/null +++ b/app/Repositories/ServiceRepository/Variable.php @@ -0,0 +1,77 @@ + + * + * 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. + */ +namespace Pterodactyl\Repositories\ServiceRepository; + +use DB; +use Validator; + +use Pterodactyl\Models; +use Pterodactyl\Services\UuidService; + +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Exceptions\DisplayValidationException; + +class Variable +{ + + public function __construct() + { + // + } + + public function update($id, array $data) + { + $variable = Models\ServiceVariables::findOrFail($id); + + $validator = Validator::make($data, [ + 'name' => 'sometimes|required|string|min:1|max:255', + 'description' => 'sometimes|required|string', + 'env_variable' => 'sometimes|required|regex:/^[\w]{1,255}$/', + 'default_value' => 'sometimes|required|string', + 'user_viewable' => 'sometimes|required|numeric|size:1', + 'user_editable' => 'sometimes|required|numeric|size:1', + 'required' => 'sometimes|required|numeric|size:1', + 'regex' => 'sometimes|required|string|min:1' + ]); + + if ($validator->fails()) { + throw new DisplayValidationException($validator->errors()); + } + + $data['default_value'] = (isset($data['default_value'])) ? $data['default_value'] : $variable->default_value; + $data['regex'] = (isset($data['regex'])) ? $data['regex'] : $variable->regex; + + if (!preg_match($data['regex'], $data['default_value'])) { + throw new DisplayException('The default value you entered cannot violate the regex requirements.'); + } + + $data['user_viewable'] = (isset($data['user_viewable']) && in_array((int) $data['user_viewable'], [0, 1])) ? $data['user_viewable'] : $variable->user_viewable; + $data['user_editable'] = (isset($data['user_editable']) && in_array((int) $data['user_editable'], [0, 1])) ? $data['user_editable'] : $variable->user_editable; + $data['required'] = (isset($data['required']) && in_array((int) $data['required'], [0, 1])) ? $data['required'] : $variable->required; + + $variable->fill($data); + $variable->save(); + } + +} diff --git a/resources/views/admin/services/index.blade.php b/resources/views/admin/services/index.blade.php new file mode 100644 index 00000000..66b9b4e8 --- /dev/null +++ b/resources/views/admin/services/index.blade.php @@ -0,0 +1,55 @@ +{{-- Copyright (c) 2015 - 2016 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') + Manage Services +@endsection + +@section('content') +
+ +

Server Services


+ + + + + + + + + @foreach ($services as $service) + + + + + @endforeach + +
Service TypeDescription
{{ $service->name }}{!! $service->description !!}
+
+ +@endsection diff --git a/resources/views/admin/services/new.blade.php b/resources/views/admin/services/new.blade.php new file mode 100644 index 00000000..e69de29b diff --git a/resources/views/admin/services/options/new.blade.php b/resources/views/admin/services/options/new.blade.php new file mode 100644 index 00000000..e69de29b diff --git a/resources/views/admin/services/options/view.blade.php b/resources/views/admin/services/options/view.blade.php new file mode 100644 index 00000000..1eb51173 --- /dev/null +++ b/resources/views/admin/services/options/view.blade.php @@ -0,0 +1,140 @@ +{{-- Copyright (c) 2015 - 2016 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') + Manage Services +@endsection + +@section('content') +
+ +

Servers

+ + + + + + + + + + + @foreach ($servers as $server) + + + + + + + @endforeach + +
NameOwnerConnectionUpdated
{{ $server->name }}{{ $server->a_ownerEmail }}{{ $server->ip }}:{{ $server->port }}{{ $server->updated_at }}
+

Option Variables


+ @foreach($variables as $variable) +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+ +
+ +

Accessed in startup by using {{{{ $variable->env_variable }}}} prameter.

+
+
+
+ +
+ +

The default value to use for this field.

+
+
+
+ +
+ +

Regex code to use when verifying the contents of the field.

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {!! csrf_field() !!} + +
+
+
+
+ @endforeach +
+ +@endsection diff --git a/resources/views/admin/services/view.blade.php b/resources/views/admin/services/view.blade.php new file mode 100644 index 00000000..9526ed5f --- /dev/null +++ b/resources/views/admin/services/view.blade.php @@ -0,0 +1,118 @@ +{{-- Copyright (c) 2015 - 2016 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') + Manage Services +@endsection + +@section('content') +
+ +

Service Options


+ + + + + + + + + + + + @foreach($options as $option) + + + + + + + + @endforeach + +
Option NameDescriptionDocker ImageTagServers
{{ $option->name }}{!! $option->description !!}{{ $option->docker_image }}{{ $option->tag }}{{ $option->c_servers }}
+
+
+
+
+ +
+ +

This should be a descriptive category name that emcompasses all of the options within the service.

+
+
+
+ +
+ +
+
+
+
+
+ +
+ /src/services/ + + /index.js +
+

This should be the name of the folder on the daemon that contains all of the service logic. Changing this can have unintended effects on servers or causes errors to occur.

+
+
+ +
+ +
+

Changing this has no effect on operation of the daemon, it is simply used for display purposes on the panel. This can be changed per-option.

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

This is the default startup that will be used for all servers created using this service. This can be changed per-option.

+
+
+
+
+ {!! csrf_field() !!} + +
+
+
+
+
+ +@endsection