From 659c33f0e8b909c64f6778af614efd5a79ca224f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Mon, 7 Nov 2016 15:55:57 -0500 Subject: [PATCH 001/599] Fixes a bug that allows a user to bypass 2FA authentication requirements This bug was reported to us by a user (@Ferry#1704) on Discord on Monday, November 7th, 2016. It was disclosed that it was possible to bypass the 2FA checkpoint by clicking outside of the modal which would prompt the modal to close, but not submit the form. The user could then press the login button which would trigger an error. Due to this error being triggered the authentication attempt was not cancelled. On the next page load the application recognized the user as logged in and continued on to the panel. At no time was it possible to login without using the correct email address and password. As a result of this bug we have re-factored the Authentication code for logins to address the persistent session. Previously accounts were manually logged back out on 2FA failure. However, as this bug demonstrated, causing a fatal error in the code would prevent the logout code from firing, thus preserving their session state. This commit modifies the code to use a non-persistent login to handle 2FA checking. In order for the session to be saved the application must complete all portions of the login without any errors, at which point the user is persistently authenticated using Auth::login(). This resolves the ability to cause an exception and bypass 2FA verification. --- app/Http/Controllers/Auth/LoginController.php | 14 ++++++-------- resources/views/auth/login.blade.php | 5 ++++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 197e69592..2a6903144 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -103,7 +103,7 @@ class LoginController extends Controller } // Is the email & password valid? - if (!Auth::attempt([ + if (!Auth::once([ 'email' => $request->input('email'), 'password' => $request->input('password') ], $request->has('remember'))) { @@ -116,14 +116,10 @@ class LoginController extends Controller } - $G2FA = new Google2FA(); - $user = User::select('use_totp', 'totp_secret')->where('email', $request->input('email'))->first(); - // Verify TOTP Token was Valid - if($user->use_totp === 1) { - if(!$G2FA->verifyKey($user->totp_secret, $request->input('totp_token'))) { - - Auth::logout(); + if(Auth::user()->use_totp === 1) { + $G2FA = new Google2FA(); + if(is_null($request->input('totp_token')) || !$G2FA->verifyKey(Auth::user()->totp_secret, $request->input('totp_token'))) { if (!$lockedOut) { $this->incrementLoginAttempts($request); @@ -135,6 +131,8 @@ class LoginController extends Controller } } + // Successfully Authenticated. + Auth::login(Auth::user(), $request->has('remember')); return $this->sendLoginResponse($request); } diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index 2000dad22..9ab5cdbf0 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -125,7 +125,10 @@ $(document).ready(function() { } }).done(function (data) { if (typeof data.id !== 'undefined') { - $('#openTOTP').modal('show'); + $('#openTOTP').modal({ + backdrop: 'static', + keyboard: false + }); $('#openTOTP').on('shown.bs.modal', function() { $('#totp_token').focus(); }); From c52dfe67991910ba8e55a8cf7b8fc67ba1ac83e3 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Mon, 7 Nov 2016 15:59:52 -0500 Subject: [PATCH 002/599] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d612005e8..952c50709 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ This file is a running track of new features and fixes to each version of the pa This project follows [Semantic Versioning](http://semver.org) guidelines. +## v0.5.1 (Bodacious Boreopterus) +### Fixed +* Fixes a bug that allowed a user to bypass 2FA authentication if using the correct username and password for an account. + ## v0.5.0 (Bodacious Boreopterus) After nearly a month in the works, version `v0.5.0` is finally here! 🎉 From b8a6a15b08215f130ad24adb170b364fa1798001 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Mon, 7 Nov 2016 20:08:25 -0500 Subject: [PATCH 003/599] Set version to 'canary' on development branch Official releases are either merged into master or branched off where their version number is then incremented. --- config/app.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/app.php b/config/app.php index 3093b43d0..619e51039 100644 --- a/config/app.php +++ b/config/app.php @@ -4,7 +4,7 @@ return [ 'env' => env('APP_ENV', 'production'), - 'version' => env('APP_VERSION', 'v0.5.0'), + 'version' => env('APP_VERSION', 'canary'), /* |-------------------------------------------------------------------------- From cfd5e0e85415c412474d726f58028f0681228e74 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 9 Nov 2016 17:58:14 -0500 Subject: [PATCH 004/599] Implement base service file modification through panel --- app/Console/Commands/CleanServiceBackup.php | 73 +++++++ app/Console/Kernel.php | 1 + .../Controllers/Admin/ServiceController.php | 33 ++++ app/Http/Routes/AdminRoutes.php | 9 + app/Models/Checksum.php | 54 ++++++ .../ServiceRepository/Service.php | 41 ++++ .../2016_11_09_163911_add_checksums_table.php | 36 ++++ .../views/admin/services/config.blade.php | 180 ++++++++++++++++++ resources/views/admin/services/view.blade.php | 1 + resources/views/layouts/admin.blade.php | 17 ++ storage/app/.gitignore | 4 +- storage/app/services/minecraft/index.js | 60 ++++++ storage/app/services/minecraft/main.json | 75 ++++++++ storage/app/services/srcds/index.js | 57 ++++++ storage/app/services/srcds/main.json | 25 +++ storage/app/services/terraria/index.js | 57 ++++++ storage/app/services/terraria/main.json | 24 +++ storage/app/services/voice/index.js | 57 ++++++ storage/app/services/voice/main.json | 52 +++++ 19 files changed, 855 insertions(+), 1 deletion(-) create mode 100644 app/Console/Commands/CleanServiceBackup.php create mode 100644 app/Models/Checksum.php create mode 100644 database/migrations/2016_11_09_163911_add_checksums_table.php create mode 100644 resources/views/admin/services/config.blade.php create mode 100644 storage/app/services/minecraft/index.js create mode 100644 storage/app/services/minecraft/main.json create mode 100644 storage/app/services/srcds/index.js create mode 100644 storage/app/services/srcds/main.json create mode 100644 storage/app/services/terraria/index.js create mode 100644 storage/app/services/terraria/main.json create mode 100644 storage/app/services/voice/index.js create mode 100644 storage/app/services/voice/main.json diff --git a/app/Console/Commands/CleanServiceBackup.php b/app/Console/Commands/CleanServiceBackup.php new file mode 100644 index 000000000..82453d6c7 --- /dev/null +++ b/app/Console/Commands/CleanServiceBackup.php @@ -0,0 +1,73 @@ + + * + * 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\Console\Commands; + +use Carbon; +use Storage; +use Illuminate\Console\Command; + +class CleanServiceBackup extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'pterodactyl:cleanservices'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Cleans .bak files assocaited with service backups whene editing files through the panel.'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $files = Storage::files('services/.bak'); + + foreach($files as $file) { + $lastModified = Carbon::createFromTimestamp(Storage::lastModified($file)); + if ($lastModified->diffInMinutes(Carbon::now()) > 5) { + $this->info('Deleting ' . $file); + Storage::delete($file); + } + } + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index c8276b447..4cd65f46e 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -21,6 +21,7 @@ class Kernel extends ConsoleKernel \Pterodactyl\Console\Commands\ClearTasks::class, \Pterodactyl\Console\Commands\ClearServices::class, \Pterodactyl\Console\Commands\UpdateEmailSettings::class, + \Pterodactyl\Console\Commands\CleanServiceBackup::class, ]; /** diff --git a/app/Http/Controllers/Admin/ServiceController.php b/app/Http/Controllers/Admin/ServiceController.php index dc5977470..35294343e 100644 --- a/app/Http/Controllers/Admin/ServiceController.php +++ b/app/Http/Controllers/Admin/ServiceController.php @@ -27,6 +27,7 @@ use Alert; use DB; use Log; use Validator; +use Storage; use Pterodactyl\Models; use Pterodactyl\Repositories\ServiceRepository; @@ -274,4 +275,36 @@ class ServiceController extends Controller return redirect()->route('admin.services.option', [$service, $option]); } + public function getConfiguration(Request $request, $serviceId) + { + $service = Models\Service::findOrFail($serviceId); + return view('admin.services.config', [ + 'service' => $service, + 'contents' => [ + 'json' => Storage::get('services/' . $service->file . '/main.json'), + 'index' => Storage::get('services/' . $service->file . '/index.js') + ] + ]); + } + + public function postConfiguration(Request $request, $serviceId) + { + try { + $repo = new ServiceRepository\Service; + $repo->updateFile($serviceId, $request->except([ + '_token' + ])); + return response('', 204); + } catch (DisplayException $ex) { + return response()->json([ + 'error' => $ex->getMessage() + ], 503); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => 'An error occured while attempting to save the file.' + ], 503); + } + } + } diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index bfc07b725..726fccc26 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -379,6 +379,15 @@ class AdminRoutes { 'uses' => 'Admin\ServiceController@deleteService' ]); + $router->get('/service/{id}/configuration', [ + 'as' => 'admin.services.service.config', + 'uses' => 'Admin\ServiceController@getConfiguration' + ]); + + $router->post('/service/{id}/configuration', [ + 'uses' => 'Admin\ServiceController@postConfiguration' + ]); + $router->get('/service/{service}/option/new', [ 'as' => 'admin.services.option.new', 'uses' => 'Admin\ServiceController@newOption' diff --git a/app/Models/Checksum.php b/app/Models/Checksum.php new file mode 100644 index 000000000..8038b7bf0 --- /dev/null +++ b/app/Models/Checksum.php @@ -0,0 +1,54 @@ + + * + * 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\Models; + +use Illuminate\Database\Eloquent\Model; + +class Checksum extends Model +{ + + /** + * The table associated with the model. + * + * @var string + */ + protected $table = 'checksums'; + + /** + * Fields that are not mass assignable. + * + * @var array + */ + protected $guarded = ['id', 'created_at', 'updated_at']; + + /** + * Cast values to correct type. + * + * @var array + */ + protected $casts = [ + 'service' => 'integer' + ]; + +} diff --git a/app/Repositories/ServiceRepository/Service.php b/app/Repositories/ServiceRepository/Service.php index 8feb92c1e..4dc1755b3 100644 --- a/app/Repositories/ServiceRepository/Service.php +++ b/app/Repositories/ServiceRepository/Service.php @@ -26,6 +26,7 @@ namespace Pterodactyl\Repositories\ServiceRepository; use DB; use Validator; use Uuid; +use Storage; use Pterodactyl\Models; use Pterodactyl\Services\UuidService; @@ -110,4 +111,44 @@ class Service } } + public function updateFile($id, array $data) + { + $service = Models\Service::findOrFail($id); + + $validator = Validator::make($data, [ + 'file' => 'required|in:index,main', + 'contents' => 'required|string' + ]); + + if ($validator->fails()) { + throw new DisplayValidationException($validator->errors()); + } + + $filename = ($data['file'] === 'main') ? 'main.json' : 'index.js'; + $filepath = 'services/' . $service->file . '/' . $filename; + $backup = 'services/.bak/' . str_random(12) . '.bak'; + + DB::beginTransaction(); + + try { + Storage::move($filepath, $backup); + Storage::put($filepath, $data['contents']); + + $checksum = Models\Checksum::firstOrNew([ + 'service' => $service->id, + 'filename' => $filename + ]); + + $checksum->checksum = sha1_file(storage_path('app/' . $filepath)); + $checksum->save(); + + DB::commit(); + } catch(\Exception $ex) { + DB::rollback(); + Storage::move($backup, $filepath); + throw $ex; + } + + } + } diff --git a/database/migrations/2016_11_09_163911_add_checksums_table.php b/database/migrations/2016_11_09_163911_add_checksums_table.php new file mode 100644 index 000000000..4935faaf2 --- /dev/null +++ b/database/migrations/2016_11_09_163911_add_checksums_table.php @@ -0,0 +1,36 @@ +increments('id'); + $table->integer('service')->unsigned(); + $table->string('filename'); + $table->char('checksum', 40); + $table->timestamps(); + + $table->foreign('service')->references('id')->on('services'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('checksums'); + } +} diff --git a/resources/views/admin/services/config.blade.php b/resources/views/admin/services/config.blade.php new file mode 100644 index 000000000..fbfa01d38 --- /dev/null +++ b/resources/views/admin/services/config.blade.php @@ -0,0 +1,180 @@ +{{-- 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 Service Configuration +@endsection + +@section('content') +
+ +

Service Configuration


+ +
+
+
+
+
+
+
+
{{ $contents['json'] }}
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
{{ $contents['index'] }}
+
+
+
+
+ +
+
+
+
+
+
+
+{!! Theme::js('js/vendor/ace/ace.js') !!} +{!! Theme::js('js/vendor/ace/ext-modelist.js') !!} + +@endsection diff --git a/resources/views/admin/services/view.blade.php b/resources/views/admin/services/view.blade.php index e05d061fd..4de4d6e9d 100644 --- a/resources/views/admin/services/view.blade.php +++ b/resources/views/admin/services/view.blade.php @@ -106,6 +106,7 @@
{!! csrf_field() !!} +
diff --git a/resources/views/layouts/admin.blade.php b/resources/views/layouts/admin.blade.php index 803c222a2..f8ff0a493 100644 --- a/resources/views/layouts/admin.blade.php +++ b/resources/views/layouts/admin.blade.php @@ -35,6 +35,23 @@ {!! Theme::js('js/vendor/sweetalert/sweetalert.min.js') !!} {!! Theme::js('js/vendor/fuelux/fuelux.min.js') !!} {!! Theme::js('js/admin.min.js') !!} + {!! Theme::js('js/bootstrap-notify.min.js') !!} + @show {{ Settings::get('company') }} - @yield('title') diff --git a/storage/app/.gitignore b/storage/app/.gitignore index c96a04f00..8d9045b3f 100755 --- a/storage/app/.gitignore +++ b/storage/app/.gitignore @@ -1,2 +1,4 @@ * -!.gitignore \ No newline at end of file +!.gitignore +!services/* +services/.bak/* diff --git a/storage/app/services/minecraft/index.js b/storage/app/services/minecraft/index.js new file mode 100644 index 000000000..67c4dbb2f --- /dev/null +++ b/storage/app/services/minecraft/index.js @@ -0,0 +1,60 @@ +'use strict'; + +/** + * Pterodactyl - Daemon + * 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. + */ +const rfr = require('rfr'); +const _ = require('lodash'); + +const Configuration = rfr('src/services/minecraft/main.json'); +const Core = rfr('src/services/index.js'); + +class Service extends Core { + constructor(server) { + super(server, Configuration); + } + + onPreflight(next) { + return super.onPreflight(next); + } + + onStart(next) { + return super.onStart(next); + } + + onConsole(data) { + // Hide the output spam from Bungeecord getting pinged. + if (_.endsWith(data, '<-> InitialHandler has connected')) return; + return super.onConsole(data); + } + + onStop(next) { + return super.onStop(next); + } + + doQuery(next) { + return super.doQuery(next); + } + +} + +module.exports = Service; diff --git a/storage/app/services/minecraft/main.json b/storage/app/services/minecraft/main.json new file mode 100644 index 000000000..1a94258ad --- /dev/null +++ b/storage/app/services/minecraft/main.json @@ -0,0 +1,75 @@ +{ + "latest": { + "tag": "^(latest)$", + "symlink": "vanilla" + }, + "vanilla": { + "tag": "^(vanilla){1}(-[\\w\\d.-]+)?$", + "startup": { + "done": ")! For help, type ", + "userInteraction": [ + "Go to eula.txt for more info." + ] + }, + "stop": "stop", + "configs": { + "server.properties": { + "parser": "properties", + "find": { + "server-ip": "0.0.0.0", + "enable-query": "true", + "server-port": "{{ build.default.port }}", + "query.port": "{{ build.default.port }}" + } + } + }, + "log": { + "custom": false, + "location": "logs/latest.log" + }, + "query": "minecraftping" + }, + "spigot": { + "tag": "^(spigot)$", + "symlink": "vanilla", + "configs": { + "spigot.yml": { + "parser": "yaml", + "find": { + "settings.restart-on-crash": "false" + } + } + } + }, + "bungeecord": { + "tag": "^(bungeecord)$", + "startup": { + "done": "Listening on " + }, + "stop": "end", + "configs": { + "config.yml": { + "parser": "yaml", + "find": { + "listeners[0].query_enabled": true, + "listeners[0].query_port": "{{ build.default.port }}", + "listeners[0].host": "0.0.0.0:{{ build.default.port }}" + } + } + }, + "log": { + "custom": false, + "location": "proxy.log.0" + }, + "query": "minecraftping" + }, + "sponge": { + "tag": "^(sponge)$", + "symlink": "vanilla", + "startup": { + "userInteraction": [ + "You need to agree to the EULA" + ] + } + } +} diff --git a/storage/app/services/srcds/index.js b/storage/app/services/srcds/index.js new file mode 100644 index 000000000..29b0439f4 --- /dev/null +++ b/storage/app/services/srcds/index.js @@ -0,0 +1,57 @@ +'use strict'; + +/** + * Pterodactyl - Daemon + * 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. + */ +const rfr = require('rfr'); + +const Configuration = rfr('src/services/srcds/main.json'); +const Core = rfr('src/services/index.js'); + +class Service extends Core { + constructor(server) { + super(server, Configuration); + } + + onPreflight(next) { + return super.onPreflight(next); + } + + onStart(next) { + return super.onStart(next); + } + + onConsole(data) { + return super.onConsole(data); + } + + onStop(next) { + return super.onStop(next); + } + + doQuery(next) { + return super.doQuery(next); + } + +} + +module.exports = Service; diff --git a/storage/app/services/srcds/main.json b/storage/app/services/srcds/main.json new file mode 100644 index 000000000..fdd65e333 --- /dev/null +++ b/storage/app/services/srcds/main.json @@ -0,0 +1,25 @@ +{ + "srcds": { + "tag": "^(srcds)$", + "startup": { + "done": "Assigned anonymous gameserver Steam ID", + "userInteraction": [] + }, + "stop": "quit", + "configs": {}, + "log": { + "custom": true, + "location": "logs/latest.log" + }, + "query": "protocol-valve" + }, + "ark": { + "tag": "^(ark)$", + "symlink": "srcds", + "startup": { + "done": "Setting breakpad minidump AppID" + }, + "stop": "^C", + "query": "none" + } +} diff --git a/storage/app/services/terraria/index.js b/storage/app/services/terraria/index.js new file mode 100644 index 000000000..55b396afe --- /dev/null +++ b/storage/app/services/terraria/index.js @@ -0,0 +1,57 @@ +'use strict'; + +/** + * Pterodactyl - Daemon + * 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. + */ +const rfr = require('rfr'); + +const Configuration = rfr('src/services/terraria/main.json'); +const Core = rfr('src/services/index.js'); + +class Service extends Core { + constructor(server) { + super(server, Configuration); + } + + onPreflight(next) { + return super.onPreflight(next); + } + + onStart(next) { + return super.onStart(next); + } + + onConsole(data) { + return super.onConsole(data); + } + + onStop(next) { + return super.onStop(next); + } + + doQuery(next) { + return super.doQuery(next); + } + +} + +module.exports = Service; diff --git a/storage/app/services/terraria/main.json b/storage/app/services/terraria/main.json new file mode 100644 index 000000000..c2a74d5b9 --- /dev/null +++ b/storage/app/services/terraria/main.json @@ -0,0 +1,24 @@ +{ + "tshock": { + "tag": "^(tshock)$", + "startup": { + "done": "Type 'help' for a list of commands", + "userInteraction": [] + }, + "stop": "exit", + "configs": { + "tshock/config.json": { + "parser": "json", + "find": { + "ServerPort": "{{ build.default.port }}", + "MaxSlots": "{{ build.env.MAX_SLOTS }}" + } + } + }, + "log": { + "custom": false, + "location": "ServerLog.txt" + }, + "query": "none" + } +} diff --git a/storage/app/services/voice/index.js b/storage/app/services/voice/index.js new file mode 100644 index 000000000..022b417aa --- /dev/null +++ b/storage/app/services/voice/index.js @@ -0,0 +1,57 @@ +'use strict'; + +/** + * Pterodactyl - Daemon + * 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. + */ +const rfr = require('rfr'); + +const Configuration = rfr('src/services/voice/main.json'); +const Core = rfr('src/services/index.js'); + +class Service extends Core { + constructor(server) { + super(server, Configuration); + } + + onPreflight(next) { + return super.onPreflight(next); + } + + onStart(next) { + return super.onStart(next); + } + + onConsole(data) { + return super.onConsole(data); + } + + onStop(next) { + return super.onStop(next); + } + + doQuery(next) { + return super.doQuery(next); + } + +} + +module.exports = Service; diff --git a/storage/app/services/voice/main.json b/storage/app/services/voice/main.json new file mode 100644 index 000000000..0479dd884 --- /dev/null +++ b/storage/app/services/voice/main.json @@ -0,0 +1,52 @@ +{ + "mumble": { + "tag": "^(mumble)$", + "startup": { + "done": "Server listening on", + "userInteraction": [ + "Generating new server certificate" + ] + }, + "stop": "^C", + "configs": { + "murmur.ini": { + "parser": "ini", + "find": { + "logfile": "murmur.log", + "port": "{{ build.default.port }}", + "host": "0.0.0.0", + "users": "{{ build.env.MAX_USERS }}" + } + } + }, + "log": { + "custom": true, + "location": "logs/murmur.log" + }, + "query": "mumbleping" + }, + "teamspeak": { + "tag": "^(ts3)$", + "startup": { + "done": "listening on 0.0.0.0:", + "userInteraction": [] + }, + "stop": "^C", + "configs": { + "ts3server.ini": { + "parser": "ini", + "find": { + "default_voice_port": "{{ build.default.port }}", + "voice_ip": "0.0.0.0", + "query_port": "{{ build.default.port }}", + "query_ip": "0.0.0.0" + } + } + }, + "log": { + "custom": true, + "location": "logs/ts3.log" + }, + "query": "none" + } +} From 1f47eda3b39f43ea578abf176e09f06fafc21f33 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 9 Nov 2016 17:59:57 -0500 Subject: [PATCH 005/599] Run 'pterodactyl:cleanservices' twice a day to prevent a huge file buildup --- app/Console/Kernel.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 4cd65f46e..53f80281d 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -34,5 +34,6 @@ class Kernel extends ConsoleKernel { $schedule->command('pterodactyl:tasks')->everyMinute()->withoutOverlapping(); $schedule->command('pterodactyl:tasks:clearlog')->twiceDaily(3, 15); + $schedule->command('pterodactyl:cleanservices')->twiceDaily(1, 13); } } From a1bc6fa2d3275aff647dd23f7202cb99aaeedacb Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 15 Nov 2016 20:20:32 -0500 Subject: [PATCH 006/599] Push changes that support creations of service packs and basic listing --- app/Http/Controllers/Admin/PackController.php | 108 ++++++++++ app/Http/Routes/AdminRoutes.php | 26 +++ app/Models/ServicePack.php | 60 ++++++ app/Repositories/ServiceRepository/Pack.php | 105 ++++++++++ .../ServiceRepository/Service.php | 15 +- .../2016_11_09_163911_add_checksums_table.php | 36 ---- .../2016_11_11_220649_add_pack_support.php | 46 +++++ ...6_11_11_231731_set_service_name_unique.php | 32 +++ public/themes/default/css/pterodactyl.css | 11 + .../admin/services/options/view.blade.php | 1 + .../views/admin/services/packs/edit.blade.php | 0 .../admin/services/packs/index.blade.php | 69 +++++++ .../views/admin/services/packs/new.blade.php | 192 ++++++++++++++++++ storage/app/.gitignore | 2 + storage/app/packs/.githold | 0 15 files changed, 654 insertions(+), 49 deletions(-) create mode 100644 app/Http/Controllers/Admin/PackController.php create mode 100644 app/Models/ServicePack.php create mode 100644 app/Repositories/ServiceRepository/Pack.php delete mode 100644 database/migrations/2016_11_09_163911_add_checksums_table.php create mode 100644 database/migrations/2016_11_11_220649_add_pack_support.php create mode 100644 database/migrations/2016_11_11_231731_set_service_name_unique.php create mode 100644 resources/views/admin/services/packs/edit.blade.php create mode 100644 resources/views/admin/services/packs/index.blade.php create mode 100644 resources/views/admin/services/packs/new.blade.php create mode 100644 storage/app/packs/.githold diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php new file mode 100644 index 000000000..9d2474395 --- /dev/null +++ b/app/Http/Controllers/Admin/PackController.php @@ -0,0 +1,108 @@ + + * + * 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 Log; +use Storage; + +use Pterodactyl\Models; +use Pterodactyl\Repositories\ServiceRepository\Pack; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Exceptions\DisplayValidationException; +use Pterodactyl\Exceptions\DisplayException; + +use Illuminate\Http\Request; + +class PackController extends Controller +{ + public function __construct() + { + // + } + + public function list(Request $request, $id) + { + $option = Models\ServiceOptions::findOrFail($id); + return view('admin.services.packs.index', [ + 'packs' => Models\ServicePack::where('option', $option->id)->get(), + 'service' => Models\Service::findOrFail($option->parent_service), + 'option' => $option + ]); + } + + public function new(Request $request, $opt = null) + { + $options = Models\ServiceOptions::select( + 'services.name AS p_service', + 'service_options.id', + 'service_options.name' + )->join('services', 'services.id', '=', 'service_options.parent_service')->get(); + + $array = []; + foreach($options as &$option) { + if (!array_key_exists($option->p_service, $array)) { + $array[$option->p_service] = []; + } + + $array[$option->p_service] = array_merge($array[$option->p_service], [[ + 'id' => $option->id, + 'name' => $option->name + ]]); + } + + return view('admin.services.packs.new', [ + 'services' => $array, + 'packFor' => $opt, + ]); + } + + public function create(Request $request) + { + // dd($request->all()); + try { + $repo = new Pack; + $id = $repo->create($request->except([ + '_token' + ])); + Alert::success('Successfully created new service!')->flash(); + return redirect()->route('admin.services.packs.edit', $id)->withInput(); + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.services.packs.new', $request->input('option'))->withErrors(json_decode($ex->getMessage()))->withInput(); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An error occured while attempting to add a new service pack.')->flash(); + } + return redirect()->route('admin.services.packs.new', $request->input('option'))->withInput(); + + } + + public function edit(Request $request, $id) + { + $pack = Models\ServicePack::findOrFail($id); + dd($pack, Storage::url('packs/' . $pack->uuid)); + } +} diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index 726fccc26..73679de69 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -430,6 +430,32 @@ class AdminRoutes { ]); }); + // Service Packs + $router->group([ + 'prefix' => 'admin/services/packs', + 'middleware' => [ + 'auth', + 'admin', + 'csrf' + ] + ], function () use ($router) { + $router->get('/new/{option?}', [ + 'as' => 'admin.services.packs.new', + 'uses' => 'Admin\PackController@new' + ]); + $router->post('/new', [ + 'uses' => 'Admin\PackController@create' + ]); + $router->get('/for/{option}', [ + 'as' => 'admin.services.packs.for', + 'uses' => 'Admin\PackController@list' + ]); + $router->get('/edit/{pack}', [ + 'as' => 'admin.services.packs.edit', + 'uses' => 'Admin\PackController@edit' + ]); + }); + } } diff --git a/app/Models/ServicePack.php b/app/Models/ServicePack.php new file mode 100644 index 000000000..f43be94b6 --- /dev/null +++ b/app/Models/ServicePack.php @@ -0,0 +1,60 @@ + + * + * 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\Models; + +use Illuminate\Database\Eloquent\Model; + +class ServicePack extends Model +{ + + /** + * The table associated with the model. + * + * @var string + */ + protected $table = 'service_packs'; + + /** + * Fields that are not mass assignable. + * + * @var array + */ + protected $guarded = ['id', 'created_at', 'updated_at']; + + /** + * Cast values to correct type. + * + * @var array + */ + protected $casts = [ + 'option' => 'integer', + 'build_memory' => 'integer', + 'build_swap' => 'integer', + 'build_cpu' => 'integer', + 'build_io' => 'integer', + 'selectable' => 'boolean', + 'visible' => 'boolean' + ]; + +} diff --git a/app/Repositories/ServiceRepository/Pack.php b/app/Repositories/ServiceRepository/Pack.php new file mode 100644 index 000000000..b644dae56 --- /dev/null +++ b/app/Repositories/ServiceRepository/Pack.php @@ -0,0 +1,105 @@ + + * + * 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 Storage; +use Uuid; +use Validator; + +use Pterodactyl\Models; +use Pterodactyl\Services\UuidService; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Exceptions\DisplayValidationException; + +class Pack +{ + + public function __construct() + { + // + } + + public function create(array $data) + { + $validator = Validator::make($data, [ + 'name' => 'required|string', + 'version' => 'required|string', + 'description' => 'string', + 'option' => 'required|exists:service_options,id', + 'selectable' => 'sometimes|boolean', + 'visible' => 'sometimes|boolean', + 'build_memory' => 'required|integer|min:0', + 'build_swap' => 'required|integer|min:0', + 'build_cpu' => 'required|integer|min:0', + 'build_io' => 'required|integer|min:10|max:1000', + 'build_container' => 'required|string', + 'build_script' => 'sometimes|string' + ]); + + if ($validator->fails()) { + throw new DisplayValidationException($validator->errors()); + } + + if (isset($data['file_upload'])) { + if (!$data['file_upload']->isValid()) { + throw new DisplayException('The file provided does not appear to be valid.'); + } + + if (!in_array($data['file_upload']->getMimeType(), [ + 'application/zip', + 'application/gzip' + ])) { + throw new DisplayException('The file provided does not meet the required filetypes of application/zip or application/gzip.'); + } + } + + DB::transaction(function () use ($data) { + $uuid = new UuidService; + $pack = Models\ServicePack::create([ + 'option' => $data['option'], + 'uuid' => $uuid->generate('servers', 'uuid'), + 'build_memory' => $data['build_memory'], + 'build_swap' => $data['build_swap'], + 'build_cpu' => $data['build_swap'], + 'build_io' => $data['build_io'], + 'build_script' => (empty($data['build_script'])) ? null : $data['build_script'], + 'build_container' => $data['build_container'], + 'name' => $data['name'], + 'version' => $data['version'], + 'description' => (empty($data['description'])) ? null : $data['description'], + 'selectable' => isset($data['selectable']), + 'visible' => isset($data['visible']) + ]); + + $filename = ($data['file_upload']->getMimeType() === 'application/zip') ? 'archive.zip' : 'archive.tar.gz'; + $data['file_upload']->storeAs('packs/' . $pack->uuid, $filename); + + $pack->save(); + + return $pack->id; + }); + } + +} diff --git a/app/Repositories/ServiceRepository/Service.php b/app/Repositories/ServiceRepository/Service.php index 4dc1755b3..91062dcb7 100644 --- a/app/Repositories/ServiceRepository/Service.php +++ b/app/Repositories/ServiceRepository/Service.php @@ -101,6 +101,8 @@ class Service DB::beginTransaction(); try { + Storage::deleteDirectory('services/' . $service->file); + Models\ServiceVariables::whereIn('option_id', $options->get()->toArray())->delete(); $options->delete(); $service->delete(); @@ -128,23 +130,10 @@ class Service $filepath = 'services/' . $service->file . '/' . $filename; $backup = 'services/.bak/' . str_random(12) . '.bak'; - DB::beginTransaction(); - try { Storage::move($filepath, $backup); Storage::put($filepath, $data['contents']); - - $checksum = Models\Checksum::firstOrNew([ - 'service' => $service->id, - 'filename' => $filename - ]); - - $checksum->checksum = sha1_file(storage_path('app/' . $filepath)); - $checksum->save(); - - DB::commit(); } catch(\Exception $ex) { - DB::rollback(); Storage::move($backup, $filepath); throw $ex; } diff --git a/database/migrations/2016_11_09_163911_add_checksums_table.php b/database/migrations/2016_11_09_163911_add_checksums_table.php deleted file mode 100644 index 4935faaf2..000000000 --- a/database/migrations/2016_11_09_163911_add_checksums_table.php +++ /dev/null @@ -1,36 +0,0 @@ -increments('id'); - $table->integer('service')->unsigned(); - $table->string('filename'); - $table->char('checksum', 40); - $table->timestamps(); - - $table->foreign('service')->references('id')->on('services'); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::drop('checksums'); - } -} diff --git a/database/migrations/2016_11_11_220649_add_pack_support.php b/database/migrations/2016_11_11_220649_add_pack_support.php new file mode 100644 index 000000000..87a66b40a --- /dev/null +++ b/database/migrations/2016_11_11_220649_add_pack_support.php @@ -0,0 +1,46 @@ +increments('id'); + $table->unsignedInteger('option'); + $table->char('uuid', 36)->unique(); + $table->unsignedInteger('build_memory')->nullable(); + $table->unsignedInteger('build_swap')->nullable(); + $table->unsignedInteger('build_cpu')->nullable(); + $table->unsignedInteger('build_io')->nullable(); + $table->text('build_script')->nullable(); + $table->string('build_container')->default('alpine:latest'); + $table->string('name'); + $table->string('version'); + $table->text('description')->nullable(); + $table->boolean('selectable')->default(true); + $table->boolean('visible')->default(true); + $table->timestamps(); + + $table->foreign('option')->references('id')->on('service_options'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('service_packs'); + } +} diff --git a/database/migrations/2016_11_11_231731_set_service_name_unique.php b/database/migrations/2016_11_11_231731_set_service_name_unique.php new file mode 100644 index 000000000..4db76f8e8 --- /dev/null +++ b/database/migrations/2016_11_11_231731_set_service_name_unique.php @@ -0,0 +1,32 @@ +unique('name'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('services', function (Blueprint $table) { + $table->dropUnique('services_name_unique'); + }); + } +} diff --git a/public/themes/default/css/pterodactyl.css b/public/themes/default/css/pterodactyl.css index 607da8d1f..fb24beda9 100755 --- a/public/themes/default/css/pterodactyl.css +++ b/public/themes/default/css/pterodactyl.css @@ -307,3 +307,14 @@ td.has-progress { padding:0; border:0; } + +.fuelux .checkbox-formheight.checkbox-custom.checkbox-inline.highlight { + height: 36px; + padding: 10px 8px 4px 28px; + width: 100%; +} + +.fuelux .checkbox-formheight.checkbox-custom.checkbox-inline.highlight:before { + left: 8px; + top: 11px; +} diff --git a/resources/views/admin/services/options/view.blade.php b/resources/views/admin/services/options/view.blade.php index d5de1a910..414f8974a 100644 --- a/resources/views/admin/services/options/view.blade.php +++ b/resources/views/admin/services/options/view.blade.php @@ -30,6 +30,7 @@
  • Services
  • {{ $service->name }}
  • {{ $option->name }}
  • +
  • Service Packs
  • Warning! This page contains advanced settings that the panel and daemon use to control servers. Modifying information on this page is not recommended unless you are absolutely sure of what you are doing.

    Settings


    diff --git a/resources/views/admin/services/packs/edit.blade.php b/resources/views/admin/services/packs/edit.blade.php new file mode 100644 index 000000000..e69de29bb diff --git a/resources/views/admin/services/packs/index.blade.php b/resources/views/admin/services/packs/index.blade.php new file mode 100644 index 000000000..2ec5ed0e4 --- /dev/null +++ b/resources/views/admin/services/packs/index.blade.php @@ -0,0 +1,69 @@ +{{-- 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') + Service Packs for {{ $option->name }} +@endsection + +@section('content') +
    + +

    Service Packs


    + + + + + + + + + + + + @foreach ($packs as $pack) + + + + + + + + @endforeach + + + + +
    NameVersionUUIDSelectableVisible
    {{ $pack->name }}{{ $pack->version }}{{ $pack->uuid }}@if($pack->selectable)@else@endif@if($pack->visible)@else@endif
    + + + + + + +
    +
    +@endsection diff --git a/resources/views/admin/services/packs/new.blade.php b/resources/views/admin/services/packs/new.blade.php new file mode 100644 index 000000000..0c75e8d05 --- /dev/null +++ b/resources/views/admin/services/packs/new.blade.php @@ -0,0 +1,192 @@ +{{-- 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') + Add New Service Pack +@endsection + +@section('content') +
    + +

    New Service Pack


    +
    +
    +
    + +
    + +

    The name of the pack which will be seen in dropdown menus and to users.

    +
    +
    +
    + +
    + +

    The version of the program included in this pack.

    +
    +
    +
    + +
    + +

    Provide a description of the pack which will be shown to users.

    +
    +
    +
    +
    +
    + + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    Build Parameters
    +
    +
    +
    + +
    + + MB +
    +
    +
    + +
    + + MB +
    +
    +
    + +
    + + % +
    +
    +
    + +
    + + I/O +
    +
    +
    +
    +

    If you would like to set limits on the build container you may do so above. Setting memory, swap, or cpu to 0 will allow unlimited resource utilization. IO must be in a range between 10 to 1000 and is a relative weighting to other container IO usage.

    +
    +
    +
    +
    +
    + +
    + +

    Provide the docker container image that will be used to build this service pack. This container is only used if a build script is provided below.

    +
    +
    +
    + +
    + +

    This script will be run inside the container if provided. You should use this script to download any additional dependencies or compile packages as necessary on the node. Your uploaded archive (if provided), will be available in /input as archive.tar.gz or as archive.zip depending on what format you uploaded as. Your completed pack should be saved as package.tar.gz in the /output directory (e.g. /output/package.tar.gz).

    +
    +
    +
    +
    +
    +
    +
    +
    +
    File Upload
    +
    +
    +
    + + +

    This package file must either be a .zip or .tar.gz archive of files to use for either building or running this pack.

    If your file is larger than 20MB we recommend uploading it using SFTP. Once you have added this pack to the system, a path will be provided where you should upload the file. + This is currently configured with the following limits: upload_max_filesize={{ ini_get('upload_max_filesize') }} and post_max_size={{ ini_get('post_max_size') }}. If your file is larger than either of those values this request will fail.

    +
    +
    +
    +
    +
    +
    +
    +
    +
    + {!! csrf_field() !!} + +
    +
    + +
    +{!! Theme::js('js/vendor/ace/ace.js') !!} +{!! Theme::js('js/vendor/ace/ext-modelist.js') !!} + +@endsection diff --git a/storage/app/.gitignore b/storage/app/.gitignore index 8d9045b3f..104980aa3 100755 --- a/storage/app/.gitignore +++ b/storage/app/.gitignore @@ -1,4 +1,6 @@ * !.gitignore !services/* +packs/**/* services/.bak/* +!packs/.githold diff --git a/storage/app/packs/.githold b/storage/app/packs/.githold new file mode 100644 index 000000000..e69de29bb From 09c2dcc1b6123e4b70b938a81907cb6c7c2915dd Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 15 Nov 2016 23:12:47 -0500 Subject: [PATCH 007/599] Support for viewing and exporting packs --- app/Http/Controllers/Admin/PackController.php | 102 ++++++-- app/Http/Routes/AdminRoutes.php | 21 +- .../admin/services/options/view.blade.php | 1 - .../{index.blade.php => byoption.blade.php} | 13 +- .../admin/services/packs/byservice.blade.php | 67 ++++++ .../views/admin/services/packs/edit.blade.php | 217 ++++++++++++++++++ .../views/admin/services/packs/new.blade.php | 1 + resources/views/layouts/admin.blade.php | 2 + 8 files changed, 403 insertions(+), 21 deletions(-) rename resources/views/admin/services/packs/{index.blade.php => byoption.blade.php} (86%) create mode 100644 resources/views/admin/services/packs/byservice.blade.php diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php index 9d2474395..5a7ecf49d 100644 --- a/app/Http/Controllers/Admin/PackController.php +++ b/app/Http/Controllers/Admin/PackController.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Http\Controllers\Admin; use Alert; +use DB; use Log; use Storage; @@ -42,17 +43,7 @@ class PackController extends Controller // } - public function list(Request $request, $id) - { - $option = Models\ServiceOptions::findOrFail($id); - return view('admin.services.packs.index', [ - 'packs' => Models\ServicePack::where('option', $option->id)->get(), - 'service' => Models\Service::findOrFail($option->parent_service), - 'option' => $option - ]); - } - - public function new(Request $request, $opt = null) + protected function formatServices() { $options = Models\ServiceOptions::select( 'services.name AS p_service', @@ -72,8 +63,41 @@ class PackController extends Controller ]]); } + return $array; + } + + public function listAll(Request $request) + { + // + } + + public function listByOption(Request $request, $id) + { + $option = Models\ServiceOptions::findOrFail($id); + return view('admin.services.packs.byoption', [ + 'packs' => Models\ServicePack::where('option', $option->id)->get(), + 'service' => Models\Service::findOrFail($option->parent_service), + 'option' => $option + ]); + } + + public function listByService(Request $request, $id) + { + return view('admin.services.packs.byservice', [ + 'service' => Models\Service::findOrFail($id), + 'options' => Models\ServiceOptions::select( + 'service_options.id', + 'service_options.name', + DB::raw('(SELECT COUNT(id) FROM service_packs WHERE service_packs.option = service_options.id) AS p_count') + )->where('parent_service', $id)->get() + ]); + } + + public function new(Request $request, $opt = null) + { + return view('admin.services.packs.new', [ - 'services' => $array, + 'services' => $this->formatServices(), 'packFor' => $opt, ]); } @@ -103,6 +127,58 @@ class PackController extends Controller public function edit(Request $request, $id) { $pack = Models\ServicePack::findOrFail($id); - dd($pack, Storage::url('packs/' . $pack->uuid)); + $option = Models\ServiceOptions::select('id', 'parent_service', 'name')->where('id', $pack->option)->first(); + return view('admin.services.packs.edit', [ + 'pack' => $pack, + 'services' => $this->formatServices(), + 'files' => Storage::files('packs/' . $pack->uuid), + 'service' => Models\Service::findOrFail($option->parent_service), + 'option' => $option + ]); + } + + public function export(Request $request, $id, $files = false) + { + $pack = Models\ServicePack::findOrFail($id); + $json = [ + 'name' => $pack->name, + 'version' => $pack->version, + 'description' => $pack->dscription, + 'selectable' => (bool) $pack->selectable, + 'visible' => (bool) $pack->visible, + 'build' => [ + 'memory' => $pack->build_memory, + 'swap' => $pack->build_swap, + 'cpu' => $pack->build_cpu, + 'io' => $pack->build_io, + 'container' => $pack->build_container, + 'script' => $pack->build_script + ] + ]; + + $filename = tempnam(sys_get_temp_dir(), 'pterodactyl_'); + if ((bool) $files) { + $zip = new \ZipArchive; + if (!$zip->open($filename, \ZipArchive::CREATE)) { + exit("cannot open <$filename>\n"); + } + + $files = Storage::files('packs/' . $pack->uuid); + foreach ($files as $file) { + $zip->addFile(storage_path('app/' . $file), basename(storage_path('app/' . $file))); + } + + $zip->addFromString('import.json', json_encode($json, JSON_PRETTY_PRINT)); + $zip->close(); + + return response()->download($filename, 'pack-' . $pack->name . '.zip')->deleteFileAfterSend(true); + } else { + $fp = fopen($filename, 'a+'); + fwrite($fp, json_encode($json, JSON_PRETTY_PRINT)); + fclose($fp); + return response()->download($filename, 'pack-' . $pack->name . '.json', [ + 'Content-Type' => 'application/json' + ])->deleteFileAfterSend(true); + } } } diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index 73679de69..d84de184c 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -446,14 +446,29 @@ class AdminRoutes { $router->post('/new', [ 'uses' => 'Admin\PackController@create' ]); - $router->get('/for/{option}', [ - 'as' => 'admin.services.packs.for', - 'uses' => 'Admin\PackController@list' + $router->get('/', [ + 'as' => 'admin.services.packs', + 'uses' => 'Admin\PackController@listAll' + ]); + $router->get('/for/option/{option}', [ + 'as' => 'admin.services.packs.option', + 'uses' => 'Admin\PackController@listByOption' + ]); + $router->get('/for/service/{service}', [ + 'as' => 'admin.services.packs.service', + 'uses' => 'Admin\PackController@listByService' ]); $router->get('/edit/{pack}', [ 'as' => 'admin.services.packs.edit', 'uses' => 'Admin\PackController@edit' ]); + $router->post('/edit/{pack}', [ + 'uses' => 'Admin\PackController@update' + ]); + $router->get('/edit/{pack}/export/{archive?}', [ + 'as' => 'admin.services.packs.export', + 'uses' => 'Admin\PackController@export' + ]); }); } diff --git a/resources/views/admin/services/options/view.blade.php b/resources/views/admin/services/options/view.blade.php index 414f8974a..d5de1a910 100644 --- a/resources/views/admin/services/options/view.blade.php +++ b/resources/views/admin/services/options/view.blade.php @@ -30,7 +30,6 @@
  • Services
  • {{ $service->name }}
  • {{ $option->name }}
  • -
  • Service Packs
  • Warning! This page contains advanced settings that the panel and daemon use to control servers. Modifying information on this page is not recommended unless you are absolutely sure of what you are doing.

    Settings


    diff --git a/resources/views/admin/services/packs/index.blade.php b/resources/views/admin/services/packs/byoption.blade.php similarity index 86% rename from resources/views/admin/services/packs/index.blade.php rename to resources/views/admin/services/packs/byoption.blade.php index 2ec5ed0e4..6ec8f03e1 100644 --- a/resources/views/admin/services/packs/index.blade.php +++ b/resources/views/admin/services/packs/byoption.blade.php @@ -28,9 +28,9 @@

    Service Packs


    @@ -46,7 +46,7 @@ @foreach ($packs as $pack) - + @@ -66,4 +66,9 @@
    {{ $pack->name }}{{ $pack->name }} {{ $pack->version }} {{ $pack->uuid }} @if($pack->selectable)@else@endif
    + @endsection diff --git a/resources/views/admin/services/packs/byservice.blade.php b/resources/views/admin/services/packs/byservice.blade.php new file mode 100644 index 000000000..ddb538ac5 --- /dev/null +++ b/resources/views/admin/services/packs/byservice.blade.php @@ -0,0 +1,67 @@ +{{-- 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') + Service Packs for {{ $service->name }} +@endsection + +@section('content') +
    + +

    Service Packs


    + + + + + + + + + @foreach ($options as $option) + + + + + @endforeach + + + + +
    NameTotal Packs
    {{ $option->name }}{{ $option->p_count }}
    + + + + + + +
    +
    + +@endsection diff --git a/resources/views/admin/services/packs/edit.blade.php b/resources/views/admin/services/packs/edit.blade.php index e69de29bb..abc89fe99 100644 --- a/resources/views/admin/services/packs/edit.blade.php +++ b/resources/views/admin/services/packs/edit.blade.php @@ -0,0 +1,217 @@ +{{-- 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') + Add New Service Pack +@endsection + +@section('content') +
    + +

    Manage Service Pack


    +
    +
    +
    + +
    + +

    The name of the pack which will be seen in dropdown menus and to users.

    +
    +
    +
    + +
    + +

    The version of the program included in this pack.

    +
    +
    +
    + +
    + +

    Provide a description of the pack which will be shown to users.

    +
    +
    +
    +
    +
    + + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    Build Parameters
    +
    +
    +
    + +
    + + MB +
    +
    +
    + +
    + + MB +
    +
    +
    + +
    + + % +
    +
    +
    + +
    + + I/O +
    +
    +
    +
    +

    If you would like to set limits on the build container you may do so above. Setting memory, swap, or cpu to 0 will allow unlimited resource utilization. IO must be in a range between 10 to 1000 and is a relative weighting to other container IO usage.

    +
    +
    +
    +
    +
    + +
    + +

    Provide the docker container image that will be used to build this service pack. This container is only used if a build script is provided below.

    +
    +
    +
    + +
    {{ $pack->build_script }}
    + +

    This script will be run inside the container if provided. You should use this script to download any additional dependencies or compile packages as necessary on the node. Your uploaded archive (if provided), will be available in /input as archive.tar.gz or as archive.zip depending on what format you uploaded as. Your completed pack should be saved as package.tar.gz in the /output directory (e.g. /output/package.tar.gz).

    +
    +
    +
    +
    +
    +
    +
    +
    +
    Package Archive
    +
    +
    +
    + @if(count($files) > 1) +
    Warning! Service packs should only contain a single pack archive in either .zip or .tar.gz format. We've detected more than one file for this pack.
    + @endif + + + + + + + + + + + @foreach($files as &$file) + + + + + + + @endforeach + +
    FilenameFile SizeSHA1 HashLast Modified
    {{ basename($file) }}{{ Storage::size($file) }} Bytes{{ sha1_file(storage_path('app/' . $file)) }}{{ Carbon::createFromTimestamp(Storage::lastModified($file))->toDateTimeString() }}
    +

    If you wish to modify or upload a new file it should be uploaded to {{ storage_path('app/packs/' . $pack->uuid) }} as either archive.zip or archive.tar.gz.

    +
    +
    +
    +
    +
    +
    +
    +
    +
    + {!! csrf_field() !!} + + + +
    +
    + +
    +{!! Theme::js('js/vendor/ace/ace.js') !!} +{!! Theme::js('js/vendor/ace/ext-modelist.js') !!} + +@endsection diff --git a/resources/views/admin/services/packs/new.blade.php b/resources/views/admin/services/packs/new.blade.php index 0c75e8d05..b6895636f 100644 --- a/resources/views/admin/services/packs/new.blade.php +++ b/resources/views/admin/services/packs/new.blade.php @@ -172,6 +172,7 @@ {!! Theme::js('js/vendor/ace/ext-modelist.js') !!} +@endsection From d4729427aa9a267b79edcfe8cab2c1e88f6f5279 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 16 Nov 2016 17:22:22 -0500 Subject: [PATCH 009/599] Support for uploading templates for installing packs --- app/Http/Controllers/Admin/PackController.php | 32 ++++++- app/Http/Routes/AdminRoutes.php | 7 ++ app/Repositories/ServiceRepository/Pack.php | 96 +++++++++++++++++-- .../admin/services/packs/byoption.blade.php | 18 +++- .../views/admin/services/packs/new.blade.php | 2 +- .../admin/services/packs/upload.blade.php | 45 +++++++++ 6 files changed, 187 insertions(+), 13 deletions(-) create mode 100644 resources/views/admin/services/packs/upload.blade.php diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php index e16c94686..acb05c7a7 100644 --- a/app/Http/Controllers/Admin/PackController.php +++ b/app/Http/Controllers/Admin/PackController.php @@ -97,7 +97,6 @@ class PackController extends Controller public function new(Request $request, $opt = null) { - return view('admin.services.packs.new', [ 'services' => $this->formatServices(), 'packFor' => $opt, @@ -106,7 +105,6 @@ class PackController extends Controller public function create(Request $request) { - // dd($request->all()); try { $repo = new Pack; $id = $repo->create($request->except([ @@ -123,7 +121,6 @@ class PackController extends Controller Alert::danger('An error occured while attempting to add a new service pack.')->flash(); } return redirect()->route('admin.services.packs.new', $request->input('option'))->withInput(); - } public function edit(Request $request, $id) @@ -179,7 +176,7 @@ class PackController extends Controller if ((bool) $files) { $zip = new \ZipArchive; if (!$zip->open($filename, \ZipArchive::CREATE)) { - exit("cannot open <$filename>\n"); + abort(503, 'Unable to open file for writing.'); } $files = Storage::files('packs/' . $pack->uuid); @@ -200,4 +197,31 @@ class PackController extends Controller ])->deleteFileAfterSend(true); } } + + public function uploadForm(Request $request, $for = null) { + return view('admin.services.packs.upload', [ + 'services' => $this->formatServices(), + 'for' => $for + ]); + } + + public function postUpload(Request $request) + { + try { + $repo = new Pack; + $id = $repo->createWithTemplate($request->except([ + '_token' + ])); + Alert::success('Successfully created new service!')->flash(); + return redirect()->route('admin.services.packs.edit', $id)->withInput(); + } catch (DisplayValidationException $ex) { + return redirect()->back()->withErrors(json_decode($ex->getMessage()))->withInput(); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An error occured while attempting to add a new service pack.')->flash(); + } + return redirect()->back(); + } } diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index d84de184c..96819bbbe 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -446,6 +446,13 @@ class AdminRoutes { $router->post('/new', [ 'uses' => 'Admin\PackController@create' ]); + $router->get('/upload/{option?}', [ + 'as' => 'admin.services.packs.uploadForm', + 'uses' => 'Admin\PackController@uploadForm' + ]); + $router->post('/upload', [ + 'uses' => 'Admin\PackController@postUpload' + ]); $router->get('/', [ 'as' => 'admin.services.packs', 'uses' => 'Admin\PackController@listAll' diff --git a/app/Repositories/ServiceRepository/Pack.php b/app/Repositories/ServiceRepository/Pack.php index 4e3d190bc..c4b3529de 100644 --- a/app/Repositories/ServiceRepository/Pack.php +++ b/app/Repositories/ServiceRepository/Pack.php @@ -46,7 +46,7 @@ class Pack $validator = Validator::make($data, [ 'name' => 'required|string', 'version' => 'required|string', - 'description' => 'string', + 'description' => 'sometimes|nullable|string', 'option' => 'required|exists:service_options,id', 'selectable' => 'sometimes|boolean', 'visible' => 'sometimes|boolean', @@ -55,7 +55,7 @@ class Pack 'build_cpu' => 'required|integer|min:0', 'build_io' => 'required|integer|min:10|max:1000', 'build_container' => 'required|string', - 'build_script' => 'sometimes|string' + 'build_script' => 'sometimes|nullable|string' ]); if ($validator->fails()) { @@ -75,7 +75,8 @@ class Pack } } - DB::transaction(function () use ($data) { + DB::beginTransaction(); + try { $uuid = new UuidService; $pack = Models\ServicePack::create([ 'option' => $data['option'], @@ -93,13 +94,94 @@ class Pack 'visible' => isset($data['visible']) ]); - $filename = ($data['file_upload']->getMimeType() === 'application/zip') ? 'archive.zip' : 'archive.tar.gz'; - $data['file_upload']->storeAs('packs/' . $pack->uuid, $filename); + Storage::makeDirectory('packs/' . $pack->uuid); + if (isset($data['file_upload'])) { + $filename = ($data['file_upload']->getMimeType() === 'application/zip') ? 'archive.zip' : 'archive.tar.gz'; + $data['file_upload']->storeAs('packs/' . $pack->uuid, $filename); + } - $pack->save(); + DB::commit(); + } catch (\Exception $ex) { + DB::rollBack(); + throw $ex; + } + return $pack->id; + } + + public function createWithTemplate(array $data) + { + if (!isset($data['file_upload'])) { + throw new DisplayException('No template file was found submitted with this request.'); + } + + if (!$data['file_upload']->isValid()) { + throw new DisplayException('The file provided does not appear to be valid.'); + } + + if (!in_array($data['file_upload']->getMimeType(), [ + 'application/zip', + 'text/plain', + 'application/json' + ])) { + throw new DisplayException('The file provided (' . $data['file_upload']->getMimeType() . ') does not meet the required filetypes of application/zip or application/json.'); + } + + if ($data['file_upload']->getMimeType() === 'application/zip') { + $zip = new \ZipArchive; + if (!$zip->open($data['file_upload']->path())) { + throw new DisplayException('The uploaded archive was unable to be opened.'); + } + + $isZip = $zip->locateName('archive.zip'); + $isTar = $zip->locateName('archive.tar.gz'); + + if ($zip->locateName('import.json') === false || ($isZip === false && $isTar === false)) { + throw new DisplayException('This contents of the provided archive were in an invalid format.'); + } + + $json = json_decode($zip->getFromName('import.json')); + $id = $this->create([ + 'name' => $json->name, + 'version' => $json->version, + 'description' => $json->description, + 'option' => $data['option'], + 'selectable' => $json->selectable, + 'visible' => $json->visible, + 'build_memory' => $json->build->memory, + 'build_swap' => $json->build->swap, + 'build_cpu' => $json->build->cpu, + 'build_io' => $json->build->io, + 'build_container' => $json->build->container, + 'build_script' => $json->build->script + ]); + + $pack = Models\ServicePack::findOrFail($id); + if (!$zip->extractTo(storage_path('app/packs/' . $pack->uuid), ($isZip === false) ? 'archive.tar.gz' : 'archive.zip')) { + $pack->delete(); + throw new DisplayException('Unable to extract the archive file to the correct location.'); + } + + $zip->close(); return $pack->id; - }); + } else { + $json = json_decode(file_get_contents($data['file_upload']->path())); + return $this->create([ + 'name' => $json->name, + 'version' => $json->version, + 'description' => $json->description, + 'option' => $data['option'], + 'selectable' => $json->selectable, + 'visible' => $json->visible, + 'build_memory' => $json->build->memory, + 'build_swap' => $json->build->swap, + 'build_cpu' => $json->build->cpu, + 'build_io' => $json->build->io, + 'build_container' => $json->build->container, + 'build_script' => $json->build->script + ]); + } + } public function update($id, array $data) diff --git a/resources/views/admin/services/packs/byoption.blade.php b/resources/views/admin/services/packs/byoption.blade.php index 6ec8f03e1..cc285d16f 100644 --- a/resources/views/admin/services/packs/byoption.blade.php +++ b/resources/views/admin/services/packs/byoption.blade.php @@ -58,7 +58,7 @@ - + @@ -69,6 +69,22 @@ @endsection diff --git a/resources/views/admin/services/packs/new.blade.php b/resources/views/admin/services/packs/new.blade.php index b6895636f..af658cce4 100644 --- a/resources/views/admin/services/packs/new.blade.php +++ b/resources/views/admin/services/packs/new.blade.php @@ -152,7 +152,7 @@

    This package file must either be a .zip or .tar.gz archive of files to use for either building or running this pack.

    If your file is larger than 20MB we recommend uploading it using SFTP. Once you have added this pack to the system, a path will be provided where you should upload the file. - This is currently configured with the following limits: upload_max_filesize={{ ini_get('upload_max_filesize') }} and post_max_size={{ ini_get('post_max_size') }}. If your file is larger than either of those values this request will fail.

    + This server is currently configured with the following limits: upload_max_filesize={{ ini_get('upload_max_filesize') }} and post_max_size={{ ini_get('post_max_size') }}. If your file is larger than either of those values this request will fail.

    diff --git a/resources/views/admin/services/packs/upload.blade.php b/resources/views/admin/services/packs/upload.blade.php new file mode 100644 index 000000000..e9ca020fa --- /dev/null +++ b/resources/views/admin/services/packs/upload.blade.php @@ -0,0 +1,45 @@ + From 5600f3201c85e43de14965c2ee2d522c8e77baba Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 18 Nov 2016 17:31:57 -0500 Subject: [PATCH 010/599] Add support for deleting service packs. --- app/Http/Controllers/Admin/PackController.php | 39 +++++++++++++------ app/Repositories/ServiceRepository/Pack.php | 9 +++++ .../views/admin/services/packs/edit.blade.php | 5 ++- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php index acb05c7a7..c94a001d6 100644 --- a/app/Http/Controllers/Admin/PackController.php +++ b/app/Http/Controllers/Admin/PackController.php @@ -138,19 +138,34 @@ class PackController extends Controller public function update(Request $request, $id) { - try { - $repo = new Pack; - $repo->update($id, $request->except([ - '_token' - ])); - Alert::success('Service pack has been successfully updated.')->flash(); - } catch (DisplayValidationException $ex) { - return redirect()->route('admin.services.packs.edit', $id)->withErrors(json_decode($ex->getMessage()))->withInput(); - } catch (\Exception $ex) { - Log::error($ex); - Alert::danger('An error occured while attempting to add edit this pack.')->flash(); + if (!is_null($request->input('action_delete'))) { + try { + $repo = new Pack; + $repo->delete($id); + Alert::success('The requested service pack has been deleted from the system.')->flash(); + return redirect()->route('admin.services.packs'); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An error occured while attempting to delete this pack.')->flash(); + } + return redirect()->route('admin.services.packs.edit', $id); + } else { + try { + $repo = new Pack; + $repo->update($id, $request->except([ + '_token' + ])); + Alert::success('Service pack has been successfully updated.')->flash(); + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.services.packs.edit', $id)->withErrors(json_decode($ex->getMessage()))->withInput(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An error occured while attempting to add edit this pack.')->flash(); + } + return redirect()->route('admin.services.packs.edit', $id); } - return redirect()->route('admin.services.packs.edit', $id); } public function export(Request $request, $id, $files = false) diff --git a/app/Repositories/ServiceRepository/Pack.php b/app/Repositories/ServiceRepository/Pack.php index c4b3529de..5d8591b69 100644 --- a/app/Repositories/ServiceRepository/Pack.php +++ b/app/Repositories/ServiceRepository/Pack.php @@ -225,4 +225,13 @@ class Pack }); } + public function delete($id) { + $pack = Models\ServicePack::findOrFail($id); + // @TODO Check for linked servers; foreign key should block this. + DB::transaction(function () use ($pack) { + $pack->delete(); + Storage::deleteDirectory('packs/' . $pack->uuid); + }); + } + } diff --git a/resources/views/admin/services/packs/edit.blade.php b/resources/views/admin/services/packs/edit.blade.php index abc89fe99..b71256fd9 100644 --- a/resources/views/admin/services/packs/edit.blade.php +++ b/resources/views/admin/services/packs/edit.blade.php @@ -186,8 +186,9 @@
    {!! csrf_field() !!} - - + + +
    From fc2ce11a394a6ef0b6e9467d3b74bc9db6587e9a Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 18 Nov 2016 18:22:26 -0500 Subject: [PATCH 011/599] Add template, add files when new service is added. --- .../ServiceRepository/Service.php | 26 ++++++++++------ storage/app/services/.templates/index.js | 31 +++++++++++++++++++ 2 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 storage/app/services/.templates/index.js diff --git a/app/Repositories/ServiceRepository/Service.php b/app/Repositories/ServiceRepository/Service.php index 91062dcb7..9e8328839 100644 --- a/app/Repositories/ServiceRepository/Service.php +++ b/app/Repositories/ServiceRepository/Service.php @@ -47,7 +47,7 @@ class Service $validator = Validator::make($data, [ 'name' => 'required|string|min:1|max:255', 'description' => 'required|string', - 'file' => 'required|regex:/^[\w.-]{1,50}$/', + 'file' => 'required|unique:services,file|regex:/^[\w.-]{1,50}$/', 'executable' => 'max:255|regex:/^(.*)$/', 'startup' => 'string' ]); @@ -56,15 +56,23 @@ class Service throw new DisplayValidationException($validator->errors()); } - if (Models\Service::where('file', $data['file'])->first()) { - throw new DisplayException('A service using that configuration file already exists on the system.'); - } - $data['author'] = env('SERVICE_AUTHOR', (string) Uuid::generate(4)); $service = new Models\Service; - $service->fill($data); - $service->save(); + DB::beginTransaction(); + + try { + $service->fill($data); + $service->save(); + + Storage::put('services/' . $data['file'] . '/main.json', '{}'); + Storage::copy('services/.templates/index.js', 'services/' . $data['file'] . '/index.js'); + + DB::commit(); + } catch (\Exception $ex) { + DB::rollBack(); + throw $ex; + } return $service->id; } @@ -101,11 +109,11 @@ class Service DB::beginTransaction(); try { - Storage::deleteDirectory('services/' . $service->file); - Models\ServiceVariables::whereIn('option_id', $options->get()->toArray())->delete(); $options->delete(); $service->delete(); + + Storage::deleteDirectory('services/' . $service->file); DB::commit(); } catch (\Exception $ex) { DB::rollBack(); diff --git a/storage/app/services/.templates/index.js b/storage/app/services/.templates/index.js new file mode 100644 index 000000000..aa60eec19 --- /dev/null +++ b/storage/app/services/.templates/index.js @@ -0,0 +1,31 @@ +'use strict'; + +/** + * Pterodactyl - Daemon + * 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. + */ +const rfr = require('rfr'); + +const Core = rfr('src/services/index.js'); + +class Service extends Core {} + +module.exports = Service; From 00e125c042f5b2297108c47e887c3ec09045a9d7 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 18 Nov 2016 18:22:34 -0500 Subject: [PATCH 012/599] Update templates --- storage/app/services/minecraft/index.js | 22 ------------------- storage/app/services/minecraft/main.json | 8 ------- storage/app/services/srcds/index.js | 28 +----------------------- storage/app/services/srcds/main.json | 2 -- storage/app/services/terraria/index.js | 28 +----------------------- storage/app/services/terraria/main.json | 1 - storage/app/services/voice/index.js | 28 +----------------------- storage/app/services/voice/main.json | 2 -- 8 files changed, 3 insertions(+), 116 deletions(-) diff --git a/storage/app/services/minecraft/index.js b/storage/app/services/minecraft/index.js index 67c4dbb2f..2d7f812c3 100644 --- a/storage/app/services/minecraft/index.js +++ b/storage/app/services/minecraft/index.js @@ -25,36 +25,14 @@ const rfr = require('rfr'); const _ = require('lodash'); -const Configuration = rfr('src/services/minecraft/main.json'); const Core = rfr('src/services/index.js'); class Service extends Core { - constructor(server) { - super(server, Configuration); - } - - onPreflight(next) { - return super.onPreflight(next); - } - - onStart(next) { - return super.onStart(next); - } - onConsole(data) { // Hide the output spam from Bungeecord getting pinged. if (_.endsWith(data, '<-> InitialHandler has connected')) return; return super.onConsole(data); } - - onStop(next) { - return super.onStop(next); - } - - doQuery(next) { - return super.doQuery(next); - } - } module.exports = Service; diff --git a/storage/app/services/minecraft/main.json b/storage/app/services/minecraft/main.json index 1a94258ad..b131d9885 100644 --- a/storage/app/services/minecraft/main.json +++ b/storage/app/services/minecraft/main.json @@ -1,10 +1,5 @@ { - "latest": { - "tag": "^(latest)$", - "symlink": "vanilla" - }, "vanilla": { - "tag": "^(vanilla){1}(-[\\w\\d.-]+)?$", "startup": { "done": ")! For help, type ", "userInteraction": [ @@ -30,7 +25,6 @@ "query": "minecraftping" }, "spigot": { - "tag": "^(spigot)$", "symlink": "vanilla", "configs": { "spigot.yml": { @@ -42,7 +36,6 @@ } }, "bungeecord": { - "tag": "^(bungeecord)$", "startup": { "done": "Listening on " }, @@ -64,7 +57,6 @@ "query": "minecraftping" }, "sponge": { - "tag": "^(sponge)$", "symlink": "vanilla", "startup": { "userInteraction": [ diff --git a/storage/app/services/srcds/index.js b/storage/app/services/srcds/index.js index 29b0439f4..aa60eec19 100644 --- a/storage/app/services/srcds/index.js +++ b/storage/app/services/srcds/index.js @@ -24,34 +24,8 @@ */ const rfr = require('rfr'); -const Configuration = rfr('src/services/srcds/main.json'); const Core = rfr('src/services/index.js'); -class Service extends Core { - constructor(server) { - super(server, Configuration); - } - - onPreflight(next) { - return super.onPreflight(next); - } - - onStart(next) { - return super.onStart(next); - } - - onConsole(data) { - return super.onConsole(data); - } - - onStop(next) { - return super.onStop(next); - } - - doQuery(next) { - return super.doQuery(next); - } - -} +class Service extends Core {} module.exports = Service; diff --git a/storage/app/services/srcds/main.json b/storage/app/services/srcds/main.json index fdd65e333..989a67537 100644 --- a/storage/app/services/srcds/main.json +++ b/storage/app/services/srcds/main.json @@ -1,6 +1,5 @@ { "srcds": { - "tag": "^(srcds)$", "startup": { "done": "Assigned anonymous gameserver Steam ID", "userInteraction": [] @@ -14,7 +13,6 @@ "query": "protocol-valve" }, "ark": { - "tag": "^(ark)$", "symlink": "srcds", "startup": { "done": "Setting breakpad minidump AppID" diff --git a/storage/app/services/terraria/index.js b/storage/app/services/terraria/index.js index 55b396afe..aa60eec19 100644 --- a/storage/app/services/terraria/index.js +++ b/storage/app/services/terraria/index.js @@ -24,34 +24,8 @@ */ const rfr = require('rfr'); -const Configuration = rfr('src/services/terraria/main.json'); const Core = rfr('src/services/index.js'); -class Service extends Core { - constructor(server) { - super(server, Configuration); - } - - onPreflight(next) { - return super.onPreflight(next); - } - - onStart(next) { - return super.onStart(next); - } - - onConsole(data) { - return super.onConsole(data); - } - - onStop(next) { - return super.onStop(next); - } - - doQuery(next) { - return super.doQuery(next); - } - -} +class Service extends Core {} module.exports = Service; diff --git a/storage/app/services/terraria/main.json b/storage/app/services/terraria/main.json index c2a74d5b9..6eacd7498 100644 --- a/storage/app/services/terraria/main.json +++ b/storage/app/services/terraria/main.json @@ -1,6 +1,5 @@ { "tshock": { - "tag": "^(tshock)$", "startup": { "done": "Type 'help' for a list of commands", "userInteraction": [] diff --git a/storage/app/services/voice/index.js b/storage/app/services/voice/index.js index 022b417aa..aa60eec19 100644 --- a/storage/app/services/voice/index.js +++ b/storage/app/services/voice/index.js @@ -24,34 +24,8 @@ */ const rfr = require('rfr'); -const Configuration = rfr('src/services/voice/main.json'); const Core = rfr('src/services/index.js'); -class Service extends Core { - constructor(server) { - super(server, Configuration); - } - - onPreflight(next) { - return super.onPreflight(next); - } - - onStart(next) { - return super.onStart(next); - } - - onConsole(data) { - return super.onConsole(data); - } - - onStop(next) { - return super.onStop(next); - } - - doQuery(next) { - return super.doQuery(next); - } - -} +class Service extends Core {} module.exports = Service; diff --git a/storage/app/services/voice/main.json b/storage/app/services/voice/main.json index 0479dd884..6bc8e5c95 100644 --- a/storage/app/services/voice/main.json +++ b/storage/app/services/voice/main.json @@ -1,6 +1,5 @@ { "mumble": { - "tag": "^(mumble)$", "startup": { "done": "Server listening on", "userInteraction": [ @@ -26,7 +25,6 @@ "query": "mumbleping" }, "teamspeak": { - "tag": "^(ts3)$", "startup": { "done": "listening on 0.0.0.0:", "userInteraction": [] From ee78a3947b38106b4df82d3849696dfb2c23cc8c Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 18 Nov 2016 18:34:45 -0500 Subject: [PATCH 013/599] Grammatical display changes --- resources/views/admin/services/new.blade.php | 2 +- resources/views/admin/services/packs/byoption.blade.php | 4 ++-- resources/views/admin/services/packs/byservice.blade.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/views/admin/services/new.blade.php b/resources/views/admin/services/new.blade.php index cd421ef9c..ce7f0f4f0 100644 --- a/resources/views/admin/services/new.blade.php +++ b/resources/views/admin/services/new.blade.php @@ -55,7 +55,7 @@ /index.js -

    This should be the name of the folder on the daemon that contains all of the service logic.

    +

    This should be a unique alpha-numeric (a-z) name used to identify the service.

    diff --git a/resources/views/admin/services/packs/byoption.blade.php b/resources/views/admin/services/packs/byoption.blade.php index cc285d16f..626958566 100644 --- a/resources/views/admin/services/packs/byoption.blade.php +++ b/resources/views/admin/services/packs/byoption.blade.php @@ -36,7 +36,7 @@ - + @@ -47,7 +47,7 @@ @foreach ($packs as $pack) - + diff --git a/resources/views/admin/services/packs/byservice.blade.php b/resources/views/admin/services/packs/byservice.blade.php index ddb538ac5..f73572c33 100644 --- a/resources/views/admin/services/packs/byservice.blade.php +++ b/resources/views/admin/services/packs/byservice.blade.php @@ -35,7 +35,7 @@
    NamePack Name Version UUID Selectable
    {{ $pack->name }}{{ $pack->version }}{{ $pack->version }} {{ $pack->uuid }} @if($pack->selectable)@else@endif @if($pack->visible)@else@endif
    - + From 57d62c4ed39ad847caed3448bfb410932054db52 Mon Sep 17 00:00:00 2001 From: Bent Haase Date: Sat, 19 Nov 2016 21:57:58 +0100 Subject: [PATCH 014/599] Fix time axis for node and server view Nope, the current month is not a valid minute --- resources/views/admin/nodes/view.blade.php | 2 +- resources/views/server/index.blade.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/views/admin/nodes/view.blade.php b/resources/views/admin/nodes/view.blade.php index 010e0910a..cf71bd691 100644 --- a/resources/views/admin/nodes/view.blade.php +++ b/resources/views/admin/nodes/view.blade.php @@ -674,7 +674,7 @@ $(document).ready(function () { memoryData.push(parseInt(data.stats.memory / (1024 * 1024))); var m = new Date(); - timeLabels.push($.format.date(new Date(), 'HH:MM:ss')); + timeLabels.push($.format.date(new Date(), 'HH:mm:ss')); CPUChart.update(); MemoryChart.update(); diff --git a/resources/views/server/index.blade.php b/resources/views/server/index.blade.php index 5cfec8a2c..0b59be40d 100644 --- a/resources/views/server/index.blade.php +++ b/resources/views/server/index.blade.php @@ -300,7 +300,7 @@ $(window).load(function () { memoryData.push(parseInt(proc.data.memory.total / (1024 * 1024))); var m = new Date(); - timeLabels.push($.format.date(new Date(), 'HH:MM:ss')); + timeLabels.push($.format.date(new Date(), 'HH:mm:ss')); CPUChart.update(); MemoryChart.update(); From 0e89ecb42737a0eb3de2facbe3faf1f0b5e9bca5 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 Nov 2016 16:19:25 -0500 Subject: [PATCH 015/599] Handle node: properly when doing server searches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Uses the node name rather than the node’s ID by default. --- .../Controllers/Admin/ServersController.php | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 8f0b184c6..15dd1abd6 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -68,14 +68,21 @@ class ServersController extends Controller $match = str_replace('"', '', $match); if (strpos($match, ':')) { list($field, $term) = explode(':', $match); - $field = (strpos($field, '.')) ? $field : 'servers.' . $field; + if ($field === 'node') { + $field = 'nodes.name'; + } else if (!strpos($field, '.')) { + $field = 'servers.' . $field; + } + $query->orWhere($field, 'LIKE', '%' . $term . '%'); } else { $query->where('servers.name', 'LIKE', '%' . $match . '%'); - $query->orWhere('servers.username', 'LIKE', '%' . $match . '%'); - $query->orWhere('users.email', 'LIKE', '%' . $match . '%'); - $query->orWhere('allocations.port', 'LIKE', '%' . $match . '%'); - $query->orWhere('allocations.ip', 'LIKE', '%' . $match . '%'); + $query->orWhere([ + ['servers.username', 'LIKE', '%' . $match . '%'], + ['users.email', 'LIKE', '%' . $match . '%'], + ['allocations.port', 'LIKE', '%' . $match . '%'], + ['allocations.ip', 'LIKE', '%' . $match . '%'], + ]); } } } From 723b608e0c9321843552919c8db3e12703194c47 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 Nov 2016 16:29:13 -0500 Subject: [PATCH 016/599] Implement node deletion properly, fixes #173 --- .../Controllers/Admin/NodesController.php | 26 ++++++++++--------- app/Repositories/NodeRepository.php | 26 +++++++++++++++++-- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index 24ac37614..ef77da4e0 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -253,20 +253,22 @@ class NodesController extends Controller public function deleteNode(Request $request, $id) { - $node = Models\Node::findOrFail($id); - $servers = Models\Server::where('node', $id)->count(); - if ($servers > 0) { - Alert::danger('You cannot delete a node with servers currently attached to it.')->flash(); - return redirect()->route('admin.nodes.view', [ - 'id' => $id, - 'tab' => 'tab_delete' - ]); + try { + $repo = new NodeRepository; + $repo->delete($id); + Alert::success('Successfully deleted the requested node from the panel.')->flash(); + return redirect()->route('admin.nodes'); + } catch (DisplayException $e) { + Alert::danger($e->getMessage())->flash(); + } catch (\Exception $e) { + Log::error($e); + Alert::danger('An unhandled exception occured while attempting to delete this node. Please try again.')->flash(); } - $node->delete(); - Alert::success('Node successfully deleted.')->flash(); - return redirect()->route('admin.nodes'); - + return redirect()->route('admin.nodes.view', [ + 'id' => $id, + 'tab' => 'tab_delete' + ]); } } diff --git a/app/Repositories/NodeRepository.php b/app/Repositories/NodeRepository.php index a23cc7455..2d579f274 100644 --- a/app/Repositories/NodeRepository.php +++ b/app/Repositories/NodeRepository.php @@ -229,8 +229,30 @@ class NodeRepository { public function delete($id) { - // @TODO: add logic; - return true; + $node = Models\Node::findOrFail($id); + if (Models\Server::where('node', $id)->count() > 0) { + throw new DisplayException('You cannot delete a node with servers currently attached to it.'); + } + + DB::beginTransaction(); + + try { + // Unlink Database Servers + Models\DatabaseServer::where('linked_node', $node->id)->update([ + 'linked_node' => null, + ]); + + // Delete Allocations + Models\Allocation::where('node', $node->id)->delete(); + + // Delete Node + $node->delete(); + + DB::commit(); + } catch (\Exception $ex) { + DB::rollback(); + throw $ex; + } } } From 1ad715f1a3192524efff9ec5e241d431ec94d5b1 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 Nov 2016 17:34:14 -0500 Subject: [PATCH 017/599] Improve database management for servers, fixes #181 --- app/Repositories/DatabaseRepository.php | 40 +++++++++++++------- resources/views/admin/servers/view.blade.php | 2 +- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/app/Repositories/DatabaseRepository.php b/app/Repositories/DatabaseRepository.php index c1c9b4e37..8861549be 100644 --- a/app/Repositories/DatabaseRepository.php +++ b/app/Repositories/DatabaseRepository.php @@ -56,13 +56,12 @@ class DatabaseRepository { } DB::beginTransaction(); - try { $db = new Models\Database; $db->fill([ 'server_id' => $server->id, 'db_server' => $options['db_server'], - 'database' => $server->uuidShort . '_' . $options['database'], + 'database' => "s{$server->id}_{$options['database']}", 'username' => $server->uuidShort . '_' . str_random(7), 'remote' => $options['remote'], 'password' => Crypt::encrypt(str_random(20)) @@ -90,16 +89,29 @@ class DatabaseRepository { $capsule->setAsGlobal(); - Capsule::statement('CREATE DATABASE ' . $db->database); - Capsule::statement('CREATE USER \'' . $db->username . '\'@\'' . $db->remote . '\' IDENTIFIED BY \'' . Crypt::decrypt($db->password) . '\''); - Capsule::statement('GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON ' . $db->database . '.* TO \'' . $db->username . '\'@\'' . $db->remote . '\''); - Capsule::statement('FLUSH PRIVILEGES'); - - DB::commit(); - return true; } catch (\Exception $ex) { - DB::rollback(); - throw $ex; + DB::rollBack(); + throw new DisplayException('There was an error while connecting to the Database Host Server. Please check the error logs.', $ex); + } + + try { + Capsule::statement('CREATE DATABASE `' . $db->database . '`'); + Capsule::statement('CREATE USER `' . $db->username . '`@`' . $db->remote . '` IDENTIFIED BY \'' . Crypt::decrypt($db->password) . '\''); + Capsule::statement('GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON `' . $db->database . '`.* TO `' . $db->username . '`@`' . $db->remote . '`'); + Capsule::statement('FLUSH PRIVILEGES'); + DB::commit(); + } catch (\Exception $ex) { + try { + Capsule::statement('DROP DATABASE `' . $db->database . '`'); + Capsule::statement('DROP USER `' . $db->username . '`@`' . $db->remote . '`'); + } catch (\Exception $exi) { + // ignore it, if it fails its probably + // because we failed to ever make the DB + // or the user on the system. + } finally { + DB::rollBack(); + throw $ex; + } } } @@ -138,7 +150,7 @@ class DatabaseRepository { $capsule->setAsGlobal(); Capsule::statement(sprintf( - 'SET PASSWORD FOR \'%s\'@\'%s\' = PASSWORD(\'%s\')', + 'SET PASSWORD FOR `%s`@`%s` = PASSWORD(\'%s\')', $db->username, $db->remote, $password @@ -182,8 +194,8 @@ class DatabaseRepository { $capsule->setAsGlobal(); - Capsule::statement('DROP USER \'' . $db->username . '\'@\'' . $db->remote . '\''); - Capsule::statement('DROP DATABASE ' . $db->database); + Capsule::statement('DROP USER `' . $db->username . '`@`' . $db->remote . '`'); + Capsule::statement('DROP DATABASE `' . $db->database . '`'); $db->delete(); diff --git a/resources/views/admin/servers/view.blade.php b/resources/views/admin/servers/view.blade.php index d6178d872..cb429ebe9 100644 --- a/resources/views/admin/servers/view.blade.php +++ b/resources/views/admin/servers/view.blade.php @@ -373,7 +373,7 @@
    -
    {{ $server->uuidShort }}_
    +
    s{{ $server->id }}_
    From d93f88f4713164b7947b8f51dca820c6f960d810 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 Nov 2016 17:49:56 -0500 Subject: [PATCH 018/599] Properly display node status with newer daemon versions --- resources/views/admin/nodes/index.blade.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resources/views/admin/nodes/index.blade.php b/resources/views/admin/nodes/index.blade.php index dcfd41629..689a9dda4 100644 --- a/resources/views/admin/nodes/index.blade.php +++ b/resources/views/admin/nodes/index.blade.php @@ -78,6 +78,9 @@ function pingNodes() { $.ajax({ type: 'GET', url: $(element).data('location'), + headers: { + 'X-Access-Token': '{{ $node->daemonSecret }}' + }, timeout: 5000 }).done(function (data) { $(element).removeClass('text-muted').find('i').removeClass().addClass('fa fa-fw fa-heartbeat faa-pulse animated').css('color', '#50af51'); From edaae40df939bd6ad182e8bd7fa135202ef512b7 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 Nov 2016 18:23:10 -0500 Subject: [PATCH 019/599] Add some quick daemon information when viewing nodes --- resources/views/admin/nodes/index.blade.php | 37 +++++++++++---------- resources/views/admin/nodes/view.blade.php | 30 +++++++++++++++++ 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/resources/views/admin/nodes/index.blade.php b/resources/views/admin/nodes/index.blade.php index 689a9dda4..114f3a0cf 100644 --- a/resources/views/admin/nodes/index.blade.php +++ b/resources/views/admin/nodes/index.blade.php @@ -70,24 +70,27 @@ @endsection diff --git a/resources/views/admin/nodes/view.blade.php b/resources/views/admin/nodes/view.blade.php index cf71bd691..b67505c3b 100644 --- a/resources/views/admin/nodes/view.blade.php +++ b/resources/views/admin/nodes/view.blade.php @@ -69,6 +69,18 @@
    NameService Option Total Packs
    + + + + + + + + + + + + @@ -777,6 +789,24 @@ $(document).ready(function () { element.parent().removeClass('has-error has-success'); } + (function getInformation() { + $.ajax({ + method: 'GET', + url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}', + timeout: 5000, + headers: { + 'X-Access-Token': '{{ $node->daemonSecret }}' + }, + }).done(function (data) { + $('[data-attr="info-version"]').html(data.version); + $('[data-attr="info-system"]').html(data.system.type + '(' + data.system.arch + ') ' + data.system.release + ''); + $('[data-attr="info-cpus"]').html(data.system.cpus); + }).fail(function (jqXHR) { + + }).always(function() { + setTimeout(getInformation, 10000); + }); + })(); }); @endsection From 261535d83dc6dbaf28f0fa509453d87c844bc709 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 Nov 2016 18:52:19 -0500 Subject: [PATCH 020/599] Fix broken block ending for script --- resources/views/admin/nodes/index.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/admin/nodes/index.blade.php b/resources/views/admin/nodes/index.blade.php index 114f3a0cf..ea3752433 100644 --- a/resources/views/admin/nodes/index.blade.php +++ b/resources/views/admin/nodes/index.blade.php @@ -91,6 +91,6 @@ $(document).ready(function () { }); }); })(); -} +}); @endsection From 90cd2b677e696901934d9a44c7a5ab107ffd1b5f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 Nov 2016 19:29:57 -0500 Subject: [PATCH 021/599] Add version checking to daemon and panel Also includes some buttons for users to get help from the panel. --- app/Console/Commands/ShowVersion.php | 3 +- app/Facades/Version.php | 35 ++++++++ app/Services/VersionService.php | 93 ++++++++++++++++++++++ config/app.php | 1 + resources/views/admin/index.blade.php | 32 ++++++-- resources/views/admin/nodes/view.blade.php | 2 +- 6 files changed, 157 insertions(+), 9 deletions(-) create mode 100644 app/Facades/Version.php create mode 100644 app/Services/VersionService.php diff --git a/app/Console/Commands/ShowVersion.php b/app/Console/Commands/ShowVersion.php index 0dcce04a1..2033f9b0f 100644 --- a/app/Console/Commands/ShowVersion.php +++ b/app/Console/Commands/ShowVersion.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Console\Commands; use Illuminate\Console\Command; +use Version; class ShowVersion extends Command { @@ -58,6 +59,6 @@ class ShowVersion extends Command */ public function handle() { - $this->info('You are running Pterodactyl Panel ' . config('app.version')); + $this->info('You are running Pterodactyl Panel v' . Version::getCurrentPanel() . ' (' . ((Version::isLatestPanel()) ? 'Up to Date' : 'Latest: ' . Version::getDaemon()) . ')'); } } diff --git a/app/Facades/Version.php b/app/Facades/Version.php new file mode 100644 index 000000000..840862600 --- /dev/null +++ b/app/Facades/Version.php @@ -0,0 +1,35 @@ + + * + * 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\Facades; + +use Illuminate\Support\Facades\Facade; + +class Version extends Facade +{ + + protected static function getFacadeAccessor() + { + return '\Pterodactyl\Services\VersionService'; + } +} diff --git a/app/Services/VersionService.php b/app/Services/VersionService.php new file mode 100644 index 000000000..5afb97e46 --- /dev/null +++ b/app/Services/VersionService.php @@ -0,0 +1,93 @@ + + * + * 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\Services; + +use Cache; +use GuzzleHttp\Client; + +class VersionService +{ + + protected static $versions; + + /** + * Constructor + */ + public function __construct() + { + self::$versions = Cache::remember('versions', env('VERSION_CACHE_TIME', 60), function () { + $client = new Client(); + + try { + $response = $client->request('GET', env('VERSION_CHECK_URL', 'https://cdn.pterodactyl.io/releases/latest.json')); + + if ($response->getStatusCode() === 200) { + return json_decode($response->getBody()); + } else { + throw new \Exception('Invalid response code.'); + } + } catch (\Exception $ex) { + // Failed request, just return errored version. + return (object) [ + 'panel' => 'error', + 'daemon' => 'error', + ]; + } + }); + } + + public static function getPanel() + { + return self::$versions->panel; + } + + public static function getDaemon() + { + return self::$versions->daemon; + } + + public function getCurrentPanel() + { + return config('app.version'); + } + + public static function isLatestPanel() + { + if (config('app.version') === 'canary') { + return true; + } + + return (version_compare(config('app.version'), self::$versions->panel) >= 0); + } + + public static function isLatestDaemon($daemon) + { + if ($daemon === '0.0.0-canary') { + return true; + } + + return (version_compare($daemon, self::$versions->daemon) >= 0); + } + +} diff --git a/config/app.php b/config/app.php index 619e51039..a3c3ff532 100644 --- a/config/app.php +++ b/config/app.php @@ -217,6 +217,7 @@ return [ 'URL' => Illuminate\Support\Facades\URL::class, 'Uuid' => Webpatser\Uuid\Uuid::class, 'Validator' => Illuminate\Support\Facades\Validator::class, + 'Version' => Pterodactyl\Facades\Version::class, 'View' => Illuminate\Support\Facades\View::class, ], diff --git a/resources/views/admin/index.blade.php b/resources/views/admin/index.blade.php index 27e8d52e9..85ffa5708 100644 --- a/resources/views/admin/index.blade.php +++ b/resources/views/admin/index.blade.php @@ -24,13 +24,31 @@ @endsection @section('content') -
    - -

    Pterodactyl Admin Control Panel


    -

    Welcome to the most advanced, lightweight, and user-friendly open source game server control panel.

    -

    You are running version {{ config('app.version') }}.

    +
    +
    + +

    Pterodactyl Admin Control Panel


    + @if (Version::isLatestPanel()) +
    You are running Pterodactyl Panel version {{ Version::getCurrentPanel() }}. Your panel is up-to-date!
    + @else +
    + Your panel is not up-to-date! The latest version is {{ Version::getPanel() }} and you are currently running version {{ Version::getCurrentPanel() }}. +
    + @endif +
    +
    + - - +{!! Theme::js('js/files/index.js') !!} +{!! Theme::js('js/files/contextmenu.js') !!} +{!! Theme::js('js/files/actions.js') !!} + {!! Theme::js('js/plugins/minecraft/eula.js') !!} @endif +@endsection diff --git a/resources/themes/pterodactyl/server/settings/sftp.blade.php b/resources/themes/pterodactyl/server/settings/sftp.blade.php new file mode 100644 index 000000000..7f85c152a --- /dev/null +++ b/resources/themes/pterodactyl/server/settings/sftp.blade.php @@ -0,0 +1,114 @@ +{{-- 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.master') + +@section('title') + SFTP Settings +@endsection + +@section('content-header') +

    SFTP ConfigurationAccount details for SFTP connections.

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

    Change SFTP Password

    +
    + @can('reset-sftp', $server) +
    +
    +
    + +
    + +

    {{ trans('auth.password_requirements') }}

    +
    +
    +
    + + + @else +
    +
    +

    You are not authorized to perform this action.

    +
    +
    + @endcan +
    +
    +
    +
    +
    +

    SFTP Details

    +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + +
    + +
    +
    + @can('view-sftp-password', $server) +
    + +
    + sftp_password))value="{{ Crypt::decrypt($server->sftp_password) }}"@endif /> +
    +
    + @endcan +
    + +
    +
    +
    +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/server.socket.js') !!} +@endsection From 1a6532d3690d7cbe06567037a456948855c1c9f5 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Mon, 16 Jan 2017 16:36:48 -0500 Subject: [PATCH 117/599] Correct link to new Discord channel invite --- resources/views/admin/index.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/admin/index.blade.php b/resources/views/admin/index.blade.php index 85ffa5708..6c2481a97 100644 --- a/resources/views/admin/index.blade.php +++ b/resources/views/admin/index.blade.php @@ -41,7 +41,7 @@
    From 31b4589eabf717a2b89890b6d869726ec1e6f87f Mon Sep 17 00:00:00 2001 From: Jakob Date: Wed, 18 Jan 2017 00:21:05 +0100 Subject: [PATCH 118/599] Contribution to feature/new-theme (#254) * add translation to navigation * redesign base.api.index view add translations * remove license derp * translate never in base.api.index view * simplify user drop down for now add translations --- resources/lang/en/base.php | 8 ++ resources/lang/en/navigation.php | 27 +++++++ resources/lang/en/strings.php | 8 ++ .../pterodactyl/base/api/index.blade.php | 81 +++++++++++++++++++ .../pterodactyl/layouts/master.blade.php | 46 ++++++----- 5 files changed, 149 insertions(+), 21 deletions(-) create mode 100644 resources/lang/en/navigation.php create mode 100644 resources/themes/pterodactyl/base/api/index.blade.php diff --git a/resources/lang/en/base.php b/resources/lang/en/base.php index 49f90ff33..bc0571912 100644 --- a/resources/lang/en/base.php +++ b/resources/lang/en/base.php @@ -7,6 +7,14 @@ return [ 'header_sub' => 'Servers you own and have access to.', 'list' => 'Server List', ], + 'api' => [ + 'index' => [ + 'header' => 'API Access', + 'header_sub' => 'Manage your API access keys.', + 'list' => 'API Keys', + 'create_new' => 'Create new API key' + ], + ], 'account' => [ 'header' => 'Your Account', 'header_sub' => 'Manage your account details.', diff --git a/resources/lang/en/navigation.php b/resources/lang/en/navigation.php new file mode 100644 index 000000000..679188e47 --- /dev/null +++ b/resources/lang/en/navigation.php @@ -0,0 +1,27 @@ + 'Home', + 'account' => [ + 'header' => 'ACCOUNT MANAGEMENT', + 'my_account' => 'My Account', + 'security_controls' => 'Security Controls', + 'api_access' => 'API Access', + 'my_servers' => 'My Servers' + ], + 'server' => [ + 'header' => 'SERVER MANAGEMENT', + 'console' => 'Console', + 'file_management' => 'File Management', + 'file_browser' => 'File Browser', + 'create_file' => 'Create File', + 'upload_files' => 'Upload Files', + 'subusers' => 'Subusers', + 'task_management' => 'Task Management', + 'configuration' => 'Configuration', + 'port_allocations' => 'Port Allocations', + 'sftp_settings' => 'SFTP Settings', + 'startup_parameters' => 'Startup Parameters', + 'databases' => 'Databases' + ], +]; diff --git a/resources/lang/en/strings.php b/resources/lang/en/strings.php index 95d6bc347..98b3304f9 100644 --- a/resources/lang/en/strings.php +++ b/resources/lang/en/strings.php @@ -28,4 +28,12 @@ return [ 'configuration' => 'Configuration', 'sftp' => 'SFTP', 'databases' => 'Databases', + 'memo' => 'Memo', + 'created' => 'Created', + 'expires' => 'Expires', + 'public_key' => 'Public key', + 'api_access' => 'Api Access', + 'never' => 'never', + 'sign_out' => 'Sign out', + 'admin_control' => 'Admin Control' ]; diff --git a/resources/themes/pterodactyl/base/api/index.blade.php b/resources/themes/pterodactyl/base/api/index.blade.php new file mode 100644 index 000000000..8d59ba153 --- /dev/null +++ b/resources/themes/pterodactyl/base/api/index.blade.php @@ -0,0 +1,81 @@ +{{-- 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.master') + +@section('title') + {{ trans('base.api.index.header') }} +@endsection + +@section('content-header') +

    {{ trans('base.api.index.header') }}{{ trans('base.api.index.header_sub')}}

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

    {{ trans('base.api.index.list')}}

    +
    +
    +
    Daemon Version
    System Information
    Total CPU Cores
    Total Servers {{ count($servers) }}
    + + + + + + + + + @foreach ($keys as $key) + + + + + + + + @endforeach + +
    {{ trans('strings.public_key') }}{{ trans('strings.memo') }}
    {{ $key->public }}{{ $key->memo }} + +
    +
    + + + + +@endsection diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index a7200587a..048cd6db6 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -55,12 +55,16 @@ - + --}}
  • @@ -107,46 +111,46 @@ @endif ",{"class":"select2-results__options select2-results__options--nested"});m.append(i),g.append(h),g.append(m)}else this.template(b,c);return a.data(c,"data",b),c},c.prototype.bind=function(b,c){var d=this,e=b.id+"-results";this.$results.attr("id",e),b.on("results:all",function(a){d.clear(),d.append(a.data),b.isOpen()&&(d.setClasses(),d.highlightFirstItem())}),b.on("results:append",function(a){d.append(a.data),b.isOpen()&&d.setClasses()}),b.on("query",function(a){d.hideMessages(),d.showLoading(a)}),b.on("select",function(){b.isOpen()&&(d.setClasses(),d.highlightFirstItem())}),b.on("unselect",function(){b.isOpen()&&(d.setClasses(),d.highlightFirstItem())}),b.on("open",function(){d.$results.attr("aria-expanded","true"),d.$results.attr("aria-hidden","false"),d.setClasses(),d.ensureHighlightVisible()}),b.on("close",function(){d.$results.attr("aria-expanded","false"),d.$results.attr("aria-hidden","true"),d.$results.removeAttr("aria-activedescendant")}),b.on("results:toggle",function(){var a=d.getHighlightedResults();0!==a.length&&a.trigger("mouseup")}),b.on("results:select",function(){var a=d.getHighlightedResults();if(0!==a.length){var b=a.data("data");"true"==a.attr("aria-selected")?d.trigger("close",{}):d.trigger("select",{data:b})}}),b.on("results:previous",function(){var a=d.getHighlightedResults(),b=d.$results.find("[aria-selected]"),c=b.index(a);if(0!==c){var e=c-1;0===a.length&&(e=0);var f=b.eq(e);f.trigger("mouseenter");var g=d.$results.offset().top,h=f.offset().top,i=d.$results.scrollTop()+(h-g);0===e?d.$results.scrollTop(0):0>h-g&&d.$results.scrollTop(i)}}),b.on("results:next",function(){var a=d.getHighlightedResults(),b=d.$results.find("[aria-selected]"),c=b.index(a),e=c+1;if(!(e>=b.length)){var f=b.eq(e);f.trigger("mouseenter");var g=d.$results.offset().top+d.$results.outerHeight(!1),h=f.offset().top+f.outerHeight(!1),i=d.$results.scrollTop()+h-g;0===e?d.$results.scrollTop(0):h>g&&d.$results.scrollTop(i)}}),b.on("results:focus",function(a){a.element.addClass("select2-results__option--highlighted")}),b.on("results:message",function(a){d.displayMessage(a)}),a.fn.mousewheel&&this.$results.on("mousewheel",function(a){var b=d.$results.scrollTop(),c=d.$results.get(0).scrollHeight-b+a.deltaY,e=a.deltaY>0&&b-a.deltaY<=0,f=a.deltaY<0&&c<=d.$results.height();e?(d.$results.scrollTop(0),a.preventDefault(),a.stopPropagation()):f&&(d.$results.scrollTop(d.$results.get(0).scrollHeight-d.$results.height()),a.preventDefault(),a.stopPropagation())}),this.$results.on("mouseup",".select2-results__option[aria-selected]",function(b){var c=a(this),e=c.data("data");return"true"===c.attr("aria-selected")?void(d.options.get("multiple")?d.trigger("unselect",{originalEvent:b,data:e}):d.trigger("close",{})):void d.trigger("select",{originalEvent:b,data:e})}),this.$results.on("mouseenter",".select2-results__option[aria-selected]",function(b){var c=a(this).data("data");d.getHighlightedResults().removeClass("select2-results__option--highlighted"),d.trigger("results:focus",{data:c,element:a(this)})})},c.prototype.getHighlightedResults=function(){var a=this.$results.find(".select2-results__option--highlighted");return a},c.prototype.destroy=function(){this.$results.remove()},c.prototype.ensureHighlightVisible=function(){var a=this.getHighlightedResults();if(0!==a.length){var b=this.$results.find("[aria-selected]"),c=b.index(a),d=this.$results.offset().top,e=a.offset().top,f=this.$results.scrollTop()+(e-d),g=e-d;f-=2*a.outerHeight(!1),2>=c?this.$results.scrollTop(0):(g>this.$results.outerHeight()||0>g)&&this.$results.scrollTop(f)}},c.prototype.template=function(b,c){var d=this.options.get("templateResult"),e=this.options.get("escapeMarkup"),f=d(b,c);null==f?c.style.display="none":"string"==typeof f?c.innerHTML=e(f):a(c).append(f)},c}),b.define("select2/keys",[],function(){var a={BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46};return a}),b.define("select2/selection/base",["jquery","../utils","../keys"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,b.Observable),d.prototype.render=function(){var b=a('');return this._tabindex=0,null!=this.$element.data("old-tabindex")?this._tabindex=this.$element.data("old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),b.attr("title",this.$element.attr("title")),b.attr("tabindex",this._tabindex),this.$selection=b,b},d.prototype.bind=function(a,b){var d=this,e=(a.id+"-container",a.id+"-results");this.container=a,this.$selection.on("focus",function(a){d.trigger("focus",a)}),this.$selection.on("blur",function(a){d._handleBlur(a)}),this.$selection.on("keydown",function(a){d.trigger("keypress",a),a.which===c.SPACE&&a.preventDefault()}),a.on("results:focus",function(a){d.$selection.attr("aria-activedescendant",a.data._resultId)}),a.on("selection:update",function(a){d.update(a.data)}),a.on("open",function(){d.$selection.attr("aria-expanded","true"),d.$selection.attr("aria-owns",e),d._attachCloseHandler(a)}),a.on("close",function(){d.$selection.attr("aria-expanded","false"),d.$selection.removeAttr("aria-activedescendant"),d.$selection.removeAttr("aria-owns"),d.$selection.focus(),d._detachCloseHandler(a)}),a.on("enable",function(){d.$selection.attr("tabindex",d._tabindex)}),a.on("disable",function(){d.$selection.attr("tabindex","-1")})},d.prototype._handleBlur=function(b){var c=this;window.setTimeout(function(){document.activeElement==c.$selection[0]||a.contains(c.$selection[0],document.activeElement)||c.trigger("blur",b)},1)},d.prototype._attachCloseHandler=function(b){a(document.body).on("mousedown.select2."+b.id,function(b){var c=a(b.target),d=c.closest(".select2"),e=a(".select2.select2-container--open");e.each(function(){var b=a(this);if(this!=d[0]){var c=b.data("element");c.select2("close")}})})},d.prototype._detachCloseHandler=function(b){a(document.body).off("mousedown.select2."+b.id)},d.prototype.position=function(a,b){var c=b.find(".selection");c.append(a)},d.prototype.destroy=function(){this._detachCloseHandler(this.container)},d.prototype.update=function(a){throw new Error("The `update` method must be defined in child classes.")},d}),b.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(a,b,c,d){function e(){e.__super__.constructor.apply(this,arguments)}return c.Extend(e,b),e.prototype.render=function(){var a=e.__super__.render.call(this);return a.addClass("select2-selection--single"),a.html(''),a},e.prototype.bind=function(a,b){var c=this;e.__super__.bind.apply(this,arguments);var d=a.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",d),this.$selection.attr("aria-labelledby",d),this.$selection.on("mousedown",function(a){1===a.which&&c.trigger("toggle",{originalEvent:a})}),this.$selection.on("focus",function(a){}),this.$selection.on("blur",function(a){}),a.on("focus",function(b){a.isOpen()||c.$selection.focus()}),a.on("selection:update",function(a){c.update(a.data)})},e.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},e.prototype.display=function(a,b){var c=this.options.get("templateSelection"),d=this.options.get("escapeMarkup");return d(c(a,b))},e.prototype.selectionContainer=function(){return a("")},e.prototype.update=function(a){if(0===a.length)return void this.clear();var b=a[0],c=this.$selection.find(".select2-selection__rendered"),d=this.display(b,c);c.empty().append(d),c.prop("title",b.title||b.text)},e}),b.define("select2/selection/multiple",["jquery","./base","../utils"],function(a,b,c){function d(a,b){d.__super__.constructor.apply(this,arguments)}return c.Extend(d,b),d.prototype.render=function(){var a=d.__super__.render.call(this);return a.addClass("select2-selection--multiple"),a.html('
      '),a},d.prototype.bind=function(b,c){var e=this;d.__super__.bind.apply(this,arguments),this.$selection.on("click",function(a){e.trigger("toggle",{originalEvent:a})}),this.$selection.on("click",".select2-selection__choice__remove",function(b){if(!e.options.get("disabled")){var c=a(this),d=c.parent(),f=d.data("data");e.trigger("unselect",{originalEvent:b,data:f})}})},d.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},d.prototype.display=function(a,b){var c=this.options.get("templateSelection"),d=this.options.get("escapeMarkup");return d(c(a,b))},d.prototype.selectionContainer=function(){var b=a('
    • ×
    • ');return b},d.prototype.update=function(a){if(this.clear(),0!==a.length){for(var b=[],d=0;d1;if(d||c)return a.call(this,b);this.clear();var e=this.createPlaceholder(this.placeholder);this.$selection.find(".select2-selection__rendered").append(e)},b}),b.define("select2/selection/allowClear",["jquery","../keys"],function(a,b){function c(){}return c.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),null==this.placeholder&&this.options.get("debug")&&window.console&&console.error&&console.error("Select2: The `allowClear` option should be used in combination with the `placeholder` option."),this.$selection.on("mousedown",".select2-selection__clear",function(a){d._handleClear(a)}),b.on("keypress",function(a){d._handleKeyboardClear(a,b)})},c.prototype._handleClear=function(a,b){if(!this.options.get("disabled")){var c=this.$selection.find(".select2-selection__clear");if(0!==c.length){b.stopPropagation();for(var d=c.data("data"),e=0;e0||0===c.length)){var d=a('×');d.data("data",c),this.$selection.find(".select2-selection__rendered").prepend(d)}},c}),b.define("select2/selection/search",["jquery","../utils","../keys"],function(a,b,c){function d(a,b,c){a.call(this,b,c)}return d.prototype.render=function(b){var c=a('');this.$searchContainer=c,this.$search=c.find("input");var d=b.call(this);return this._transferTabIndex(),d},d.prototype.bind=function(a,b,d){var e=this;a.call(this,b,d),b.on("open",function(){e.$search.trigger("focus")}),b.on("close",function(){e.$search.val(""),e.$search.removeAttr("aria-activedescendant"),e.$search.trigger("focus")}),b.on("enable",function(){e.$search.prop("disabled",!1),e._transferTabIndex()}),b.on("disable",function(){e.$search.prop("disabled",!0)}),b.on("focus",function(a){e.$search.trigger("focus")}),b.on("results:focus",function(a){e.$search.attr("aria-activedescendant",a.id)}),this.$selection.on("focusin",".select2-search--inline",function(a){e.trigger("focus",a)}),this.$selection.on("focusout",".select2-search--inline",function(a){e._handleBlur(a)}),this.$selection.on("keydown",".select2-search--inline",function(a){a.stopPropagation(),e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented();var b=a.which;if(b===c.BACKSPACE&&""===e.$search.val()){var d=e.$searchContainer.prev(".select2-selection__choice");if(d.length>0){var f=d.data("data");e.searchRemoveChoice(f),a.preventDefault()}}});var f=document.documentMode,g=f&&11>=f;this.$selection.on("input.searchcheck",".select2-search--inline",function(a){return g?void e.$selection.off("input.search input.searchcheck"):void e.$selection.off("keyup.search")}),this.$selection.on("keyup.search input.search",".select2-search--inline",function(a){if(g&&"input"===a.type)return void e.$selection.off("input.search input.searchcheck");var b=a.which;b!=c.SHIFT&&b!=c.CTRL&&b!=c.ALT&&b!=c.TAB&&e.handleSearch(a)})},d.prototype._transferTabIndex=function(a){this.$search.attr("tabindex",this.$selection.attr("tabindex")),this.$selection.attr("tabindex","-1")},d.prototype.createPlaceholder=function(a,b){this.$search.attr("placeholder",b.text)},d.prototype.update=function(a,b){var c=this.$search[0]==document.activeElement;this.$search.attr("placeholder",""),a.call(this,b),this.$selection.find(".select2-selection__rendered").append(this.$searchContainer),this.resizeSearch(),c&&this.$search.focus()},d.prototype.handleSearch=function(){if(this.resizeSearch(),!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},d.prototype.searchRemoveChoice=function(a,b){this.trigger("unselect",{data:b}),this.$search.val(b.text),this.handleSearch()},d.prototype.resizeSearch=function(){this.$search.css("width","25px");var a="";if(""!==this.$search.attr("placeholder"))a=this.$selection.find(".select2-selection__rendered").innerWidth();else{var b=this.$search.val().length+1;a=.75*b+"em"}this.$search.css("width",a)},d}),b.define("select2/selection/eventRelay",["jquery"],function(a){function b(){}return b.prototype.bind=function(b,c,d){var e=this,f=["open","opening","close","closing","select","selecting","unselect","unselecting"],g=["opening","closing","selecting","unselecting"];b.call(this,c,d),c.on("*",function(b,c){if(-1!==a.inArray(b,f)){c=c||{};var d=a.Event("select2:"+b,{params:c});e.$element.trigger(d),-1!==a.inArray(b,g)&&(c.prevented=d.isDefaultPrevented())}})},b}),b.define("select2/translation",["jquery","require"],function(a,b){function c(a){this.dict=a||{}}return c.prototype.all=function(){return this.dict},c.prototype.get=function(a){return this.dict[a]},c.prototype.extend=function(b){this.dict=a.extend({},b.all(),this.dict)},c._cache={},c.loadPath=function(a){if(!(a in c._cache)){var d=b(a);c._cache[a]=d}return new c(c._cache[a])},c}),b.define("select2/diacritics",[],function(){var a={"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ω":"ω","ς":"σ"};return a}),b.define("select2/data/base",["../utils"],function(a){function b(a,c){b.__super__.constructor.call(this)}return a.Extend(b,a.Observable),b.prototype.current=function(a){throw new Error("The `current` method must be defined in child classes.")},b.prototype.query=function(a,b){throw new Error("The `query` method must be defined in child classes.")},b.prototype.bind=function(a,b){},b.prototype.destroy=function(){},b.prototype.generateResultId=function(b,c){var d=b.id+"-result-";return d+=a.generateChars(4),d+=null!=c.id?"-"+c.id.toString():"-"+a.generateChars(4)},b}),b.define("select2/data/select",["./base","../utils","jquery"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,a),d.prototype.current=function(a){var b=[],d=this;this.$element.find(":selected").each(function(){var a=c(this),e=d.item(a);b.push(e)}),a(b)},d.prototype.select=function(a){var b=this;if(a.selected=!0,c(a.element).is("option"))return a.element.selected=!0,void this.$element.trigger("change"); +if(this.$element.prop("multiple"))this.current(function(d){var e=[];a=[a],a.push.apply(a,d);for(var f=0;f=0){var k=f.filter(d(j)),l=this.item(k),m=c.extend(!0,{},j,l),n=this.option(m);k.replaceWith(n)}else{var o=this.option(j);if(j.children){var p=this.convertToOptions(j.children);b.appendMany(o,p)}h.push(o)}}return h},d}),b.define("select2/data/ajax",["./array","../utils","jquery"],function(a,b,c){function d(a,b){this.ajaxOptions=this._applyDefaults(b.get("ajax")),null!=this.ajaxOptions.processResults&&(this.processResults=this.ajaxOptions.processResults),d.__super__.constructor.call(this,a,b)}return b.Extend(d,a),d.prototype._applyDefaults=function(a){var b={data:function(a){return c.extend({},a,{q:a.term})},transport:function(a,b,d){var e=c.ajax(a);return e.then(b),e.fail(d),e}};return c.extend({},b,a,!0)},d.prototype.processResults=function(a){return a},d.prototype.query=function(a,b){function d(){var d=f.transport(f,function(d){var f=e.processResults(d,a);e.options.get("debug")&&window.console&&console.error&&(f&&f.results&&c.isArray(f.results)||console.error("Select2: The AJAX results did not return an array in the `results` key of the response.")),b(f)},function(){d.status&&"0"===d.status||e.trigger("results:message",{message:"errorLoading"})});e._request=d}var e=this;null!=this._request&&(c.isFunction(this._request.abort)&&this._request.abort(),this._request=null);var f=c.extend({type:"GET"},this.ajaxOptions);"function"==typeof f.url&&(f.url=f.url.call(this.$element,a)),"function"==typeof f.data&&(f.data=f.data.call(this.$element,a)),this.ajaxOptions.delay&&null!=a.term?(this._queryTimeout&&window.clearTimeout(this._queryTimeout),this._queryTimeout=window.setTimeout(d,this.ajaxOptions.delay)):d()},d}),b.define("select2/data/tags",["jquery"],function(a){function b(b,c,d){var e=d.get("tags"),f=d.get("createTag");void 0!==f&&(this.createTag=f);var g=d.get("insertTag");if(void 0!==g&&(this.insertTag=g),b.call(this,c,d),a.isArray(e))for(var h=0;h0&&b.term.length>this.maximumInputLength?void this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumSelectionLength",[],function(){function a(a,b,c){this.maximumSelectionLength=c.get("maximumSelectionLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){var d=this;this.current(function(e){var f=null!=e?e.length:0;return d.maximumSelectionLength>0&&f>=d.maximumSelectionLength?void d.trigger("results:message",{message:"maximumSelected",args:{maximum:d.maximumSelectionLength}}):void a.call(d,b,c)})},a}),b.define("select2/dropdown",["jquery","./utils"],function(a,b){function c(a,b){this.$element=a,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('');return b.attr("dir",this.options.get("dir")),this.$dropdown=b,b},c.prototype.bind=function(){},c.prototype.position=function(a,b){},c.prototype.destroy=function(){this.$dropdown.remove()},c}),b.define("select2/dropdown/search",["jquery","../utils"],function(a,b){function c(){}return c.prototype.render=function(b){var c=b.call(this),d=a('');return this.$searchContainer=d,this.$search=d.find("input"),c.prepend(d),c},c.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),this.$search.on("keydown",function(a){e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented()}),this.$search.on("input",function(b){a(this).off("keyup")}),this.$search.on("keyup input",function(a){e.handleSearch(a)}),c.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus(),window.setTimeout(function(){e.$search.focus()},0)}),c.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val("")}),c.on("focus",function(){c.isOpen()&&e.$search.focus()}),c.on("results:all",function(a){if(null==a.query.term||""===a.query.term){var b=e.showSearch(a);b?e.$searchContainer.removeClass("select2-search--hide"):e.$searchContainer.addClass("select2-search--hide")}})},c.prototype.handleSearch=function(a){if(!this._keyUpPrevented){var b=this.$search.val();this.trigger("query",{term:b})}this._keyUpPrevented=!1},c.prototype.showSearch=function(a,b){return!0},c}),b.define("select2/dropdown/hidePlaceholder",[],function(){function a(a,b,c,d){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c,d)}return a.prototype.append=function(a,b){b.results=this.removePlaceholder(b.results),a.call(this,b)},a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.removePlaceholder=function(a,b){for(var c=b.slice(0),d=b.length-1;d>=0;d--){var e=b[d];this.placeholder.id===e.id&&c.splice(d,1)}return c},a}),b.define("select2/dropdown/infiniteScroll",["jquery"],function(a){function b(a,b,c,d){this.lastParams={},a.call(this,b,c,d),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return b.prototype.append=function(a,b){this.$loadingMore.remove(),this.loading=!1,a.call(this,b),this.showLoadingMore(b)&&this.$results.append(this.$loadingMore)},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),c.on("query",function(a){e.lastParams=a,e.loading=!0}),c.on("query:append",function(a){e.lastParams=a,e.loading=!0}),this.$results.on("scroll",function(){var b=a.contains(document.documentElement,e.$loadingMore[0]);if(!e.loading&&b){var c=e.$results.offset().top+e.$results.outerHeight(!1),d=e.$loadingMore.offset().top+e.$loadingMore.outerHeight(!1);c+50>=d&&e.loadMore()}})},b.prototype.loadMore=function(){this.loading=!0;var b=a.extend({},{page:1},this.lastParams);b.page++,this.trigger("query:append",b)},b.prototype.showLoadingMore=function(a,b){return b.pagination&&b.pagination.more},b.prototype.createLoadingMore=function(){var b=a('
    • '),c=this.options.get("translations").get("loadingMore");return b.html(c(this.lastParams)),b},b}),b.define("select2/dropdown/attachBody",["jquery","../utils"],function(a,b){function c(b,c,d){this.$dropdownParent=d.get("dropdownParent")||a(document.body),b.call(this,c,d)}return c.prototype.bind=function(a,b,c){var d=this,e=!1;a.call(this,b,c),b.on("open",function(){d._showDropdown(),d._attachPositioningHandler(b),e||(e=!0,b.on("results:all",function(){d._positionDropdown(),d._resizeDropdown()}),b.on("results:append",function(){d._positionDropdown(),d._resizeDropdown()}))}),b.on("close",function(){d._hideDropdown(),d._detachPositioningHandler(b)}),this.$dropdownContainer.on("mousedown",function(a){a.stopPropagation()})},c.prototype.destroy=function(a){a.call(this),this.$dropdownContainer.remove()},c.prototype.position=function(a,b,c){b.attr("class",c.attr("class")),b.removeClass("select2"),b.addClass("select2-container--open"),b.css({position:"absolute",top:-999999}),this.$container=c},c.prototype.render=function(b){var c=a(""),d=b.call(this);return c.append(d),this.$dropdownContainer=c,c},c.prototype._hideDropdown=function(a){this.$dropdownContainer.detach()},c.prototype._attachPositioningHandler=function(c,d){var e=this,f="scroll.select2."+d.id,g="resize.select2."+d.id,h="orientationchange.select2."+d.id,i=this.$container.parents().filter(b.hasScroll);i.each(function(){a(this).data("select2-scroll-position",{x:a(this).scrollLeft(),y:a(this).scrollTop()})}),i.on(f,function(b){var c=a(this).data("select2-scroll-position");a(this).scrollTop(c.y)}),a(window).on(f+" "+g+" "+h,function(a){e._positionDropdown(),e._resizeDropdown()})},c.prototype._detachPositioningHandler=function(c,d){var e="scroll.select2."+d.id,f="resize.select2."+d.id,g="orientationchange.select2."+d.id,h=this.$container.parents().filter(b.hasScroll);h.off(e),a(window).off(e+" "+f+" "+g)},c.prototype._positionDropdown=function(){var b=a(window),c=this.$dropdown.hasClass("select2-dropdown--above"),d=this.$dropdown.hasClass("select2-dropdown--below"),e=null,f=this.$container.offset();f.bottom=f.top+this.$container.outerHeight(!1);var g={height:this.$container.outerHeight(!1)};g.top=f.top,g.bottom=f.top+g.height;var h={height:this.$dropdown.outerHeight(!1)},i={top:b.scrollTop(),bottom:b.scrollTop()+b.height()},j=i.topf.bottom+h.height,l={left:f.left,top:g.bottom},m=this.$dropdownParent;"static"===m.css("position")&&(m=m.offsetParent());var n=m.offset();l.top-=n.top,l.left-=n.left,c||d||(e="below"),k||!j||c?!j&&k&&c&&(e="below"):e="above",("above"==e||c&&"below"!==e)&&(l.top=g.top-n.top-h.height),null!=e&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+e),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+e)),this.$dropdownContainer.css(l)},c.prototype._resizeDropdown=function(){var a={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(a.minWidth=a.width,a.position="relative",a.width="auto"),this.$dropdown.css(a)},c.prototype._showDropdown=function(a){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},c}),b.define("select2/dropdown/minimumResultsForSearch",[],function(){function a(b){for(var c=0,d=0;d0&&(l.dataAdapter=j.Decorate(l.dataAdapter,r)),l.maximumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,s)),l.maximumSelectionLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,t)),l.tags&&(l.dataAdapter=j.Decorate(l.dataAdapter,p)),(null!=l.tokenSeparators||null!=l.tokenizer)&&(l.dataAdapter=j.Decorate(l.dataAdapter,q)),null!=l.query){var C=b(l.amdBase+"compat/query");l.dataAdapter=j.Decorate(l.dataAdapter,C)}if(null!=l.initSelection){var D=b(l.amdBase+"compat/initSelection");l.dataAdapter=j.Decorate(l.dataAdapter,D)}}if(null==l.resultsAdapter&&(l.resultsAdapter=c,null!=l.ajax&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,x)),null!=l.placeholder&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,w)),l.selectOnClose&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,A))),null==l.dropdownAdapter){if(l.multiple)l.dropdownAdapter=u;else{var E=j.Decorate(u,v);l.dropdownAdapter=E}if(0!==l.minimumResultsForSearch&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,z)),l.closeOnSelect&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,B)),null!=l.dropdownCssClass||null!=l.dropdownCss||null!=l.adaptDropdownCssClass){var F=b(l.amdBase+"compat/dropdownCss");l.dropdownAdapter=j.Decorate(l.dropdownAdapter,F)}l.dropdownAdapter=j.Decorate(l.dropdownAdapter,y)}if(null==l.selectionAdapter){if(l.multiple?l.selectionAdapter=e:l.selectionAdapter=d,null!=l.placeholder&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,f)),l.allowClear&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,g)),l.multiple&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,h)),null!=l.containerCssClass||null!=l.containerCss||null!=l.adaptContainerCssClass){var G=b(l.amdBase+"compat/containerCss");l.selectionAdapter=j.Decorate(l.selectionAdapter,G)}l.selectionAdapter=j.Decorate(l.selectionAdapter,i)}if("string"==typeof l.language)if(l.language.indexOf("-")>0){var H=l.language.split("-"),I=H[0];l.language=[l.language,I]}else l.language=[l.language];if(a.isArray(l.language)){var J=new k;l.language.push("en");for(var K=l.language,L=0;L0){for(var f=a.extend(!0,{},e),g=e.children.length-1;g>=0;g--){var h=e.children[g],i=c(d,h);null==i&&f.children.splice(g,1)}return f.children.length>0?f:c(d,f)}var j=b(e.text).toUpperCase(),k=b(d.term).toUpperCase();return j.indexOf(k)>-1?e:null}this.defaults={amdBase:"./",amdLanguageBase:"./i18n/",closeOnSelect:!0,debug:!1,dropdownAutoWidth:!1,escapeMarkup:j.escapeMarkup,language:C,matcher:c,minimumInputLength:0,maximumInputLength:0,maximumSelectionLength:0,minimumResultsForSearch:0,selectOnClose:!1,sorter:function(a){return a},templateResult:function(a){return a.text},templateSelection:function(a){return a.text},theme:"default",width:"resolve"}},D.prototype.set=function(b,c){var d=a.camelCase(b),e={};e[d]=c;var f=j._convertData(e);a.extend(this.defaults,f)};var E=new D;return E}),b.define("select2/options",["require","jquery","./defaults","./utils"],function(a,b,c,d){function e(b,e){if(this.options=b,null!=e&&this.fromElement(e),this.options=c.apply(this.options),e&&e.is("input")){var f=a(this.get("amdBase")+"compat/inputData");this.options.dataAdapter=d.Decorate(this.options.dataAdapter,f)}}return e.prototype.fromElement=function(a){var c=["select2"];null==this.options.multiple&&(this.options.multiple=a.prop("multiple")),null==this.options.disabled&&(this.options.disabled=a.prop("disabled")),null==this.options.language&&(a.prop("lang")?this.options.language=a.prop("lang").toLowerCase():a.closest("[lang]").prop("lang")&&(this.options.language=a.closest("[lang]").prop("lang"))),null==this.options.dir&&(a.prop("dir")?this.options.dir=a.prop("dir"):a.closest("[dir]").prop("dir")?this.options.dir=a.closest("[dir]").prop("dir"):this.options.dir="ltr"),a.prop("disabled",this.options.disabled),a.prop("multiple",this.options.multiple),a.data("select2Tags")&&(this.options.debug&&window.console&&console.warn&&console.warn('Select2: The `data-select2-tags` attribute has been changed to use the `data-data` and `data-tags="true"` attributes and will be removed in future versions of Select2.'),a.data("data",a.data("select2Tags")),a.data("tags",!0)),a.data("ajaxUrl")&&(this.options.debug&&window.console&&console.warn&&console.warn("Select2: The `data-ajax-url` attribute has been changed to `data-ajax--url` and support for the old attribute will be removed in future versions of Select2."),a.attr("ajax--url",a.data("ajaxUrl")),a.data("ajax--url",a.data("ajaxUrl")));var e={};e=b.fn.jquery&&"1."==b.fn.jquery.substr(0,2)&&a[0].dataset?b.extend(!0,{},a[0].dataset,a.data()):a.data();var f=b.extend(!0,{},e);f=d._convertData(f);for(var g in f)b.inArray(g,c)>-1||(b.isPlainObject(this.options[g])?b.extend(this.options[g],f[g]):this.options[g]=f[g]);return this},e.prototype.get=function(a){return this.options[a]},e.prototype.set=function(a,b){this.options[a]=b},e}),b.define("select2/core",["jquery","./options","./utils","./keys"],function(a,b,c,d){var e=function(a,c){null!=a.data("select2")&&a.data("select2").destroy(),this.$element=a,this.id=this._generateId(a),c=c||{},this.options=new b(c,a),e.__super__.constructor.call(this);var d=a.attr("tabindex")||0;a.data("old-tabindex",d),a.attr("tabindex","-1");var f=this.options.get("dataAdapter");this.dataAdapter=new f(a,this.options);var g=this.render();this._placeContainer(g);var h=this.options.get("selectionAdapter");this.selection=new h(a,this.options),this.$selection=this.selection.render(),this.selection.position(this.$selection,g);var i=this.options.get("dropdownAdapter");this.dropdown=new i(a,this.options),this.$dropdown=this.dropdown.render(),this.dropdown.position(this.$dropdown,g);var j=this.options.get("resultsAdapter");this.results=new j(a,this.options,this.dataAdapter),this.$results=this.results.render(),this.results.position(this.$results,this.$dropdown);var k=this;this._bindAdapters(),this._registerDomEvents(),this._registerDataEvents(),this._registerSelectionEvents(),this._registerDropdownEvents(),this._registerResultsEvents(),this._registerEvents(),this.dataAdapter.current(function(a){k.trigger("selection:update",{data:a})}),a.addClass("select2-hidden-accessible"),a.attr("aria-hidden","true"),this._syncAttributes(),a.data("select2",this)};return c.Extend(e,c.Observable),e.prototype._generateId=function(a){var b="";return b=null!=a.attr("id")?a.attr("id"):null!=a.attr("name")?a.attr("name")+"-"+c.generateChars(2):c.generateChars(4),b=b.replace(/(:|\.|\[|\]|,)/g,""),b="select2-"+b},e.prototype._placeContainer=function(a){a.insertAfter(this.$element);var b=this._resolveWidth(this.$element,this.options.get("width"));null!=b&&a.css("width",b)},e.prototype._resolveWidth=function(a,b){var c=/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;if("resolve"==b){var d=this._resolveWidth(a,"style");return null!=d?d:this._resolveWidth(a,"element")}if("element"==b){var e=a.outerWidth(!1);return 0>=e?"auto":e+"px"}if("style"==b){var f=a.attr("style");if("string"!=typeof f)return null;for(var g=f.split(";"),h=0,i=g.length;i>h;h+=1){var j=g[h].replace(/\s/g,""),k=j.match(c);if(null!==k&&k.length>=1)return k[1]}return null}return b},e.prototype._bindAdapters=function(){this.dataAdapter.bind(this,this.$container),this.selection.bind(this,this.$container),this.dropdown.bind(this,this.$container),this.results.bind(this,this.$container)},e.prototype._registerDomEvents=function(){var b=this;this.$element.on("change.select2",function(){b.dataAdapter.current(function(a){b.trigger("selection:update",{data:a})})}),this.$element.on("focus.select2",function(a){b.trigger("focus",a)}),this._syncA=c.bind(this._syncAttributes,this),this._syncS=c.bind(this._syncSubtree,this),this.$element[0].attachEvent&&this.$element[0].attachEvent("onpropertychange",this._syncA);var d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;null!=d?(this._observer=new d(function(c){a.each(c,b._syncA),a.each(c,b._syncS)}),this._observer.observe(this.$element[0],{attributes:!0,childList:!0,subtree:!1})):this.$element[0].addEventListener&&(this.$element[0].addEventListener("DOMAttrModified",b._syncA,!1),this.$element[0].addEventListener("DOMNodeInserted",b._syncS,!1),this.$element[0].addEventListener("DOMNodeRemoved",b._syncS,!1))},e.prototype._registerDataEvents=function(){var a=this;this.dataAdapter.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerSelectionEvents=function(){var b=this,c=["toggle","focus"];this.selection.on("toggle",function(){b.toggleDropdown()}),this.selection.on("focus",function(a){b.focus(a)}),this.selection.on("*",function(d,e){-1===a.inArray(d,c)&&b.trigger(d,e)})},e.prototype._registerDropdownEvents=function(){var a=this;this.dropdown.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerResultsEvents=function(){var a=this;this.results.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerEvents=function(){var a=this;this.on("open",function(){a.$container.addClass("select2-container--open")}),this.on("close",function(){a.$container.removeClass("select2-container--open")}),this.on("enable",function(){a.$container.removeClass("select2-container--disabled")}),this.on("disable",function(){a.$container.addClass("select2-container--disabled")}),this.on("blur",function(){a.$container.removeClass("select2-container--focus")}),this.on("query",function(b){a.isOpen()||a.trigger("open",{}),this.dataAdapter.query(b,function(c){a.trigger("results:all",{data:c,query:b})})}),this.on("query:append",function(b){this.dataAdapter.query(b,function(c){a.trigger("results:append",{data:c,query:b})})}),this.on("keypress",function(b){var c=b.which;a.isOpen()?c===d.ESC||c===d.TAB||c===d.UP&&b.altKey?(a.close(),b.preventDefault()):c===d.ENTER?(a.trigger("results:select",{}),b.preventDefault()):c===d.SPACE&&b.ctrlKey?(a.trigger("results:toggle",{}),b.preventDefault()):c===d.UP?(a.trigger("results:previous",{}),b.preventDefault()):c===d.DOWN&&(a.trigger("results:next",{}),b.preventDefault()):(c===d.ENTER||c===d.SPACE||c===d.DOWN&&b.altKey)&&(a.open(),b.preventDefault())})},e.prototype._syncAttributes=function(){this.options.set("disabled",this.$element.prop("disabled")),this.options.get("disabled")?(this.isOpen()&&this.close(),this.trigger("disable",{})):this.trigger("enable",{})},e.prototype._syncSubtree=function(a,b){var c=!1,d=this;if(!a||!a.target||"OPTION"===a.target.nodeName||"OPTGROUP"===a.target.nodeName){if(b)if(b.addedNodes&&b.addedNodes.length>0)for(var e=0;e0&&(c=!0);else c=!0;c&&this.dataAdapter.current(function(a){d.trigger("selection:update",{data:a})})}},e.prototype.trigger=function(a,b){var c=e.__super__.trigger,d={open:"opening",close:"closing",select:"selecting",unselect:"unselecting"};if(void 0===b&&(b={}),a in d){var f=d[a],g={prevented:!1,name:a,args:b};if(c.call(this,f,g),g.prevented)return void(b.prevented=!0)}c.call(this,a,b)},e.prototype.toggleDropdown=function(){this.options.get("disabled")||(this.isOpen()?this.close():this.open())},e.prototype.open=function(){this.isOpen()||this.trigger("query",{})},e.prototype.close=function(){this.isOpen()&&this.trigger("close",{})},e.prototype.isOpen=function(){return this.$container.hasClass("select2-container--open")},e.prototype.hasFocus=function(){return this.$container.hasClass("select2-container--focus")},e.prototype.focus=function(a){this.hasFocus()||(this.$container.addClass("select2-container--focus"),this.trigger("focus",{}))},e.prototype.enable=function(a){this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("enable")` method has been deprecated and will be removed in later Select2 versions. Use $element.prop("disabled") instead.'),(null==a||0===a.length)&&(a=[!0]);var b=!a[0];this.$element.prop("disabled",b)},e.prototype.data=function(){this.options.get("debug")&&arguments.length>0&&window.console&&console.warn&&console.warn('Select2: Data can no longer be set using `select2("data")`. You should consider setting the value instead using `$element.val()`.');var a=[];return this.dataAdapter.current(function(b){a=b}),a},e.prototype.val=function(b){if(this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("val")` method has been deprecated and will be removed in later Select2 versions. Use $element.val() instead.'),null==b||0===b.length)return this.$element.val();var c=b[0];a.isArray(c)&&(c=a.map(c,function(a){return a.toString()})),this.$element.val(c).trigger("change")},e.prototype.destroy=function(){this.$container.remove(),this.$element[0].detachEvent&&this.$element[0].detachEvent("onpropertychange",this._syncA),null!=this._observer?(this._observer.disconnect(),this._observer=null):this.$element[0].removeEventListener&&(this.$element[0].removeEventListener("DOMAttrModified",this._syncA,!1),this.$element[0].removeEventListener("DOMNodeInserted",this._syncS,!1),this.$element[0].removeEventListener("DOMNodeRemoved",this._syncS,!1)),this._syncA=null,this._syncS=null,this.$element.off(".select2"),this.$element.attr("tabindex",this.$element.data("old-tabindex")),this.$element.removeClass("select2-hidden-accessible"),this.$element.attr("aria-hidden","false"),this.$element.removeData("select2"),this.dataAdapter.destroy(),this.selection.destroy(),this.dropdown.destroy(),this.results.destroy(),this.dataAdapter=null,this.selection=null,this.dropdown=null,this.results=null; +},e.prototype.render=function(){var b=a('');return b.attr("dir",this.options.get("dir")),this.$container=b,this.$container.addClass("select2-container--"+this.options.get("theme")),b.data("element",this.$element),b},e}),b.define("select2/compat/utils",["jquery"],function(a){function b(b,c,d){var e,f,g=[];e=a.trim(b.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each(function(){0===this.indexOf("select2-")&&g.push(this)})),e=a.trim(c.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each(function(){0!==this.indexOf("select2-")&&(f=d(this),null!=f&&g.push(f))})),b.attr("class",g.join(" "))}return{syncCssClasses:b}}),b.define("select2/compat/containerCss",["jquery","./utils"],function(a,b){function c(a){return null}function d(){}return d.prototype.render=function(d){var e=d.call(this),f=this.options.get("containerCssClass")||"";a.isFunction(f)&&(f=f(this.$element));var g=this.options.get("adaptContainerCssClass");if(g=g||c,-1!==f.indexOf(":all:")){f=f.replace(":all:","");var h=g;g=function(a){var b=h(a);return null!=b?b+" "+a:a}}var i=this.options.get("containerCss")||{};return a.isFunction(i)&&(i=i(this.$element)),b.syncCssClasses(e,this.$element,g),e.css(i),e.addClass(f),e},d}),b.define("select2/compat/dropdownCss",["jquery","./utils"],function(a,b){function c(a){return null}function d(){}return d.prototype.render=function(d){var e=d.call(this),f=this.options.get("dropdownCssClass")||"";a.isFunction(f)&&(f=f(this.$element));var g=this.options.get("adaptDropdownCssClass");if(g=g||c,-1!==f.indexOf(":all:")){f=f.replace(":all:","");var h=g;g=function(a){var b=h(a);return null!=b?b+" "+a:a}}var i=this.options.get("dropdownCss")||{};return a.isFunction(i)&&(i=i(this.$element)),b.syncCssClasses(e,this.$element,g),e.css(i),e.addClass(f),e},d}),b.define("select2/compat/initSelection",["jquery"],function(a){function b(a,b,c){c.get("debug")&&window.console&&console.warn&&console.warn("Select2: The `initSelection` option has been deprecated in favor of a custom data adapter that overrides the `current` method. This method is now called multiple times instead of a single time when the instance is initialized. Support will be removed for the `initSelection` option in future versions of Select2"),this.initSelection=c.get("initSelection"),this._isInitialized=!1,a.call(this,b,c)}return b.prototype.current=function(b,c){var d=this;return this._isInitialized?void b.call(this,c):void this.initSelection.call(null,this.$element,function(b){d._isInitialized=!0,a.isArray(b)||(b=[b]),c(b)})},b}),b.define("select2/compat/inputData",["jquery"],function(a){function b(a,b,c){this._currentData=[],this._valueSeparator=c.get("valueSeparator")||",","hidden"===b.prop("type")&&c.get("debug")&&console&&console.warn&&console.warn("Select2: Using a hidden input with Select2 is no longer supported and may stop working in the future. It is recommended to use a ` + + +
      + + + + +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('vendor/select2/select2.full.min.js') !!} + {!! Theme::js('js/frontend/server.socket.js') !!} + {!! Theme::js('js/vendor/ace/ace.js') !!} + {!! Theme::js('js/vendor/ace/ext-modelist.js') !!} + {!! Theme::js('js/vendor/lodash/lodash.js') !!} + {!! Theme::js('js/frontend/files/editor.js') !!} + +@endsection From 994588c82d30dabde831d87b9ee2c2b29b9a800a Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 20 Jan 2017 17:19:42 -0500 Subject: [PATCH 137/599] Set the old theme on admin center until new theme is done --- app/Http/Middleware/AdminAuthenticate.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/Http/Middleware/AdminAuthenticate.php b/app/Http/Middleware/AdminAuthenticate.php index 78b73fb72..505d7c08c 100644 --- a/app/Http/Middleware/AdminAuthenticate.php +++ b/app/Http/Middleware/AdminAuthenticate.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Http\Middleware; +use Theme; use Closure; use Illuminate\Contracts\Auth\Guard; @@ -68,6 +69,8 @@ class AdminAuthenticate return abort(403); } + // @TODO: eventually update admin themes + Theme::set('default'); return $next($request); } } From 3d2278ba3e0d979125ccf45c09e3735467996851 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 20 Jan 2017 23:39:37 -0500 Subject: [PATCH 138/599] Add subuser list and new subuser views Holy :cow2: translations are annoying to implement for these views. --- .../Controllers/Server/SubuserController.php | 2 +- public/themes/pterodactyl/css/pterodactyl.css | 8 + resources/lang/en/server.php | 160 +++++++ resources/lang/en/strings.php | 1 + .../pterodactyl/server/users/index.blade.php | 86 ++++ .../pterodactyl/server/users/new.blade.php | 412 ++++++++++++++++++ 6 files changed, 668 insertions(+), 1 deletion(-) create mode 100644 resources/themes/pterodactyl/server/users/index.blade.php create mode 100644 resources/themes/pterodactyl/server/users/new.blade.php diff --git a/app/Http/Controllers/Server/SubuserController.php b/app/Http/Controllers/Server/SubuserController.php index 48de4621d..69db75bf7 100644 --- a/app/Http/Controllers/Server/SubuserController.php +++ b/app/Http/Controllers/Server/SubuserController.php @@ -55,7 +55,7 @@ class SubuserController extends Controller return view('server.users.index', [ 'server' => $server, 'node' => Models\Node::find($server->node), - 'subusers' => Models\Subuser::select('subusers.*', 'users.email as a_userEmail') + 'subusers' => Models\Subuser::select('subusers.*', 'users.email', 'users.username') ->join('users', 'users.id', '=', 'subusers.user_id') ->where('server_id', $server->id) ->get(), diff --git a/public/themes/pterodactyl/css/pterodactyl.css b/public/themes/pterodactyl/css/pterodactyl.css index 4d1e94bf0..f9e8d8a75 100644 --- a/public/themes/pterodactyl/css/pterodactyl.css +++ b/public/themes/pterodactyl/css/pterodactyl.css @@ -113,3 +113,11 @@ td.has-progress { color: #cccccc; height: 0; } + +.box-header > .form-group { + margin-bottom: 0; +} + +.box-header > .form-group > div > p.small { + margin: 0; +} diff --git a/resources/lang/en/server.php b/resources/lang/en/server.php index e0fe67ad2..656430dac 100644 --- a/resources/lang/en/server.php +++ b/resources/lang/en/server.php @@ -6,6 +6,166 @@ return [ 'header' => 'Server Console', 'header_sub' => 'Control your server in real time.', ], + 'users' => [ + 'header' => 'Manage Users', + 'header_sub' => 'Control who can access your server.', + 'configure' => 'Configure Permissions', + 'list' => 'Accounts with Access', + 'add' => 'Add New Subuser', + 'new' => [ + 'header' => 'Add New User', + 'header_sub' => 'Add a new user with permissions to this server.', + 'email' => 'Email Address', + 'email_help' => 'Enter the email address for the user you wish to invite to manage this server.', + 'power_header' => 'Power Management', + 'file_header' => 'File Management', + 'subuser_header' => 'Subuser Management', + 'server_header' => 'Server Management', + 'task_header' => 'Task Management', + 'sftp_header' => 'SFTP Management', + 'db_header' => 'Database Management', + 'start' => [ + 'title' => 'Start Server', + 'description' => 'Allows user to start the server.', + ], + 'stop' => [ + 'title' => 'Stop Server', + 'description' => 'Allows user to stop the server.', + ], + 'restart' => [ + 'title' => 'Stop Server', + 'description' => 'Allows user to restart the server.', + ], + 'kill' => [ + 'title' => 'Stop Server', + 'description' => 'Allows user to kill the server process.', + ], + 'command' => [ + 'title' => 'Send Console Command', + 'description' => 'Allows sending a command from the console. If the user does not have stop or restart permissions they cannot send the application\'s stop command.', + ], + 'list_files' => [ + 'title' => 'List Files', + 'description' => 'Allows user to list all files and folders on the server but not view file contents.', + ], + 'edit_files' => [ + 'title' => 'Edit Files', + 'description' => 'Allows user to open a file for viewing only.', + ], + 'save_files' => [ + 'title' => 'Save Files', + 'description' => 'Allows user to save modified file contents.', + ], + 'move_files' => [ + 'title' => 'Rename & Move Files', + 'description' => 'Allows user to move and rename files and folders on the filesystem.', + ], + 'copy_files' => [ + 'title' => 'Copy Files', + 'description' => 'Allows user to copy files and folders on the filesystem.', + ], + 'compress_files' => [ + 'title' => 'Compress Files', + 'description' => 'Allows user to make archives of files and folders on the system.', + ], + 'decompress_files' => [ + 'title' => 'Decompress Files', + 'description' => 'Allows user to decompress .zip and .tar(.gz) archives.', + ], + 'create_files' => [ + 'title' => 'Create Files', + 'description' => 'Allows user to create a new file within the panel.', + ], + 'upload_files' => [ + 'title' => 'Upload Files', + 'description' => 'Allows user to upload files through the file manager.', + ], + 'delete_files' => [ + 'title' => 'Delete Files', + 'description' => 'Allows user to delete files from the system.', + ], + 'download_files' => [ + 'title' => 'Download Files', + 'description' => 'Allows user to download files. If a user is given this permission they can download and view file contents even if that permission is not assigned on the panel.', + ], + 'list_subusers' => [ + 'title' => 'List Subusers', + 'description' => 'Allows user to view a listing of all subusers assigned to the server.', + ], + 'view_subuser' => [ + 'title' => 'View Subuser', + 'description' => 'Allows user to view permissions assigned to subusers.', + ], + 'edit_subuser' => [ + 'title' => 'Edit Subuser', + 'description' => 'Allows a user to edit permissions assigned to other subusers.', + ], + 'create_subuser' => [ + 'title' => 'Create Subuser', + 'description' => 'Allows user to create additional subusers on the server.', + ], + 'delete_subuser' => [ + 'title' => 'Delete Subuser', + 'description' => 'Allows a user to delete other subusers on the server.', + ], + 'set_connection' => [ + 'title' => 'Set Default Connection', + 'description' => 'Allows user to set the default connection used for a server as well as view avaliable ports.', + ], + 'view_startup' => [ + 'title' => 'View Startup Command', + 'description' => 'Allows user to view the startup command and associated variables for a server.', + ], + 'edit_startup' => [ + 'title' => 'Edit Startup Command', + 'description' => 'Allows a user to modify startup variables for a server.', + ], + 'list_tasks' => [ + 'title' => 'List Tasks', + 'description' => 'Allows a user to list all tasks (enabled and disabled) on a server.', + ], + 'view_task' => [ + 'title' => 'View Task', + 'description' => 'Allows a user to view a specific task\'s details.', + ], + 'toggle_task' => [ + 'title' => 'Toggle Task', + 'description' => 'Allows a user to toggle a task on or off.', + ], + 'queue_task' => [ + 'title' => 'Queue Task', + 'description' => 'Allows a user to queue a task to run on next cycle.', + ], + 'create_task' => [ + 'title' => 'Create Task', + 'description' => 'Allows a user to create new tasks.', + ], + 'delete_task' => [ + 'title' => 'Delete Task', + 'description' => 'Allows a user to delete a task.', + ], + 'view_sftp' => [ + 'title' => 'View SFTP Details', + 'description' => 'Allows user to view the server\'s SFTP information but not the password.', + ], + 'view_sftp_password' => [ + 'title' => 'View SFTP Password', + 'description' => 'Allows user to view the SFTP password for the server.', + ], + 'reset_sftp' => [ + 'title' => 'Reset SFTP Password', + 'description' => 'Allows user to change the SFTP password for the server.', + ], + 'view_databases' => [ + 'title' => 'View Database Details', + 'description' => 'Allows user to view all databases associated with this server including the usernames and passwords for the databases.', + ], + 'reset_db_password' => [ + 'title' => 'Reset Database Password', + 'description' => 'Allows a user to reset passwords for databases.', + ], + ], + ], 'files' => [ 'header' => 'File Manager', 'header_sub' => 'Manage all of your files directly from the web.', diff --git a/resources/lang/en/strings.php b/resources/lang/en/strings.php index 01062a6de..324f956a9 100644 --- a/resources/lang/en/strings.php +++ b/resources/lang/en/strings.php @@ -50,4 +50,5 @@ return [ 'make_primary' => 'Make Primary', 'none' => 'None', 'cancel' => 'Cancel', + 'created_at' => 'Created At', ]; diff --git a/resources/themes/pterodactyl/server/users/index.blade.php b/resources/themes/pterodactyl/server/users/index.blade.php new file mode 100644 index 000000000..6e63bd10d --- /dev/null +++ b/resources/themes/pterodactyl/server/users/index.blade.php @@ -0,0 +1,86 @@ +{{-- 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.master') + +@section('title') + @lang('server.users.header') +@endsection + +@section('content-header') +

      @lang('server.users.header')@lang('server.users.header_sub')

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

      @lang('server.users.list')

      +
      +
      + + + + + + + + @can('view-subuser', $server)@endcan + @can('delete-subuser', $server)@endcan + + @foreach($subusers as $user) + + + + + @can('view-subuser', $server) + + @endcan + @can('delete-subuser', $server) + + @endcan + + @endforeach + +
      @lang('strings.username')@lang('strings.email')
      User Image{{ $user->username }} + {{ $user->email }} + + + + + + + +
      +
      + @can('create-subuser', $server) + + @endcan +
      +
      +
      +@endsection diff --git a/resources/themes/pterodactyl/server/users/new.blade.php b/resources/themes/pterodactyl/server/users/new.blade.php new file mode 100644 index 000000000..3ee194c45 --- /dev/null +++ b/resources/themes/pterodactyl/server/users/new.blade.php @@ -0,0 +1,412 @@ +{{-- 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.master') + +@section('title') + @lang('server.users.new.header') +@endsection + +@section('content-header') +

      @lang('server.users.new.header')@lang('server.users.new.header_sub')

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

      @lang('server.users.new.email_help')

      +
      +
      +
      + +
      +
      +
      +
      +
      + {{-- Left Side --}} +
      +
      +
      +
      +

      @lang('server.users.new.power_header')

      +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      @lang('server.users.new.subuser_header')

      +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      @lang('server.users.new.server_header')

      +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      @lang('server.users.new.sftp_header')

      +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +
      + {{-- Right Side --}} +
      +
      +
      +
      +

      @lang('server.users.new.file_header')

      +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      @lang('server.users.new.task_header')

      +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      @lang('server.users.new.db_header')

      +
      +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +
      + +@endsection + +@section('footer-scripts') + @parent + +@endsection From 95f574ec674b7d4c85c62182ff8291025600a15e Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 20 Jan 2017 23:48:12 -0500 Subject: [PATCH 139/599] Sidebar and API View tweaks --- resources/lang/en/base.php | 6 +- .../themes/pterodactyl/base/api/new.blade.php | 124 +++++++++--------- .../pterodactyl/layouts/master.blade.php | 8 +- 3 files changed, 71 insertions(+), 67 deletions(-) diff --git a/resources/lang/en/base.php b/resources/lang/en/base.php index fc1d3e8c6..392a23d1d 100644 --- a/resources/lang/en/base.php +++ b/resources/lang/en/base.php @@ -24,7 +24,7 @@ return [ 'header' => 'API Access', 'header_sub' => 'Manage your API access keys.', 'list' => 'API Keys', - 'create_new' => 'Create new API key', + 'create_new' => 'Create New API key', ], 'new' => [ 'header' => 'New API Key', @@ -32,7 +32,7 @@ return [ 'form_title' => 'Details', 'descriptive_memo' => [ 'title' => 'Descriptive Memo', - 'description' => 'Enter a breif description of what this API key will be used for.' + 'description' => 'Enter a brief description of what this API key will be used for.' ], 'allowed_ips' => [ 'title' => 'Allowed IPs', @@ -103,7 +103,7 @@ return [ ], 'view' => [ 'title' => 'Show Single Server', - 'description' => 'Allows viewing details about a specific server including the daemon_token as current process information.', + 'description' => 'Allows viewing details about a specific server including the daemon_token as well as current process information.', ], 'list' => [ 'title' => 'List Servers', diff --git a/resources/themes/pterodactyl/base/api/new.blade.php b/resources/themes/pterodactyl/base/api/new.blade.php index 9afe90bd3..8030d671c 100644 --- a/resources/themes/pterodactyl/base/api/new.blade.php +++ b/resources/themes/pterodactyl/base/api/new.blade.php @@ -89,14 +89,14 @@
      @lang('base.api.new.base.title')
      -
      +
      @@ -107,54 +107,54 @@
      @lang('base.api.new.user_management.title')
      -
      +
      -
      +
      -
      +
      -
      +
      -
      +
      @@ -164,54 +164,54 @@
      @lang('base.api.new.node_management.title')
      -
      +
      -
      +
      -
      +
      -
      +
      -
      +
      @@ -229,9 +229,9 @@ GET @lang('base.api.new.server_management.server.title') -

      +

      @lang('base.api.new.server_management.server.description') -

      +

      @@ -239,9 +239,9 @@ GET @lang('base.api.new.server_management.power.title') -

      +

      @lang('base.api.new.server_management.power.description') -

      +

      @if(Auth::user()->isRootAdmin()) @@ -250,10 +250,10 @@ GET @lang('base.api.new.server_management.view.title') -

      +

      @lang('strings.danger') @lang('base.api.new.server_management.view.description') -

      +

      @@ -261,9 +261,9 @@ GET @lang('base.api.new.server_management.list.title') -

      +

      @lang('base.api.new.server_management.list.description') -

      +

      @@ -271,9 +271,9 @@ POST @lang('base.api.new.server_management.create.title') -

      +

      @lang('base.api.new.server_management.create.description') -

      +

      @@ -281,9 +281,9 @@ PATCH @lang('base.api.new.server_management.config.title') -

      +

      @lang('base.api.new.server_management.config.description') -

      +

      @@ -291,9 +291,9 @@ PATCH @lang('base.api.new.server_management.build.title') -

      +

      @lang('base.api.new.server_management.build.description') -

      +

      @@ -301,9 +301,9 @@ POST @lang('base.api.new.server_management.suspend.title') -

      +

      @lang('base.api.new.server_management.suspend.description') -

      +

      @@ -311,9 +311,9 @@ POST @lang('base.api.new.server_management.unsuspend.title') -

      +

      @lang('base.api.new.server_management.unsuspend.description') -

      +

      @@ -321,9 +321,9 @@ DELETE @lang('base.api.new.server_management.delete.title') -

      +

      @lang('base.api.new.server_management.delete.description') -

      +

      @endif @@ -335,26 +335,26 @@
      @lang('base.api.new.service_management.title')
      -
      +
      -
      +
      @@ -364,15 +364,15 @@
      @lang('base.api.new.location_management.title')
      -
      +
      diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index 8399d0bc0..260a1a6a3 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -123,7 +123,7 @@ @lang('navigation.account.security_controls') -
    • +
    • @lang('navigation.account.api_access') @@ -157,7 +157,11 @@
    • @lang('navigation.server.create_file')
    • -
    • +
    • Subusers From 8e9069cced6f7d41321deb00cedd0a2086389894 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 21 Jan 2017 00:04:09 -0500 Subject: [PATCH 140/599] Subuser updates --- app/Repositories/SubuserRepository.php | 9 +- resources/lang/en/server.php | 9 +- .../pterodactyl/server/users/new.blade.php | 3 +- .../pterodactyl/server/users/view.blade.php | 417 ++++++++++++++++++ 4 files changed, 433 insertions(+), 5 deletions(-) create mode 100644 resources/themes/pterodactyl/server/users/view.blade.php diff --git a/app/Repositories/SubuserRepository.php b/app/Repositories/SubuserRepository.php index dfc72b38b..a25c7f12e 100644 --- a/app/Repositories/SubuserRepository.php +++ b/app/Repositories/SubuserRepository.php @@ -133,10 +133,15 @@ class SubuserRepository // Determine if this user exists or if we need to make them an account. $user = Models\User::where('email', $data['email'])->first(); if (! $user) { - $password = str_random(16); try { $repo = new UserRepository; - $uid = $repo->create($data['email'], $password); + $uid = $repo->create([ + 'email' => $data['email'], + 'username' => substr(str_replace('@', '', $data['email']), 0, 8), + 'name_first' => 'John', + 'name_last' => 'Doe', + 'root_admin' => false, + ]); $user = Models\User::findOrFail($uid); } catch (\Exception $ex) { throw $ex; diff --git a/resources/lang/en/server.php b/resources/lang/en/server.php index 656430dac..bfb304f55 100644 --- a/resources/lang/en/server.php +++ b/resources/lang/en/server.php @@ -12,6 +12,11 @@ return [ 'configure' => 'Configure Permissions', 'list' => 'Accounts with Access', 'add' => 'Add New Subuser', + 'update' => 'Update Subuser', + 'edit' => [ + 'header' => 'Edit Subuser', + 'header_sub' => 'Modify user\'s access to server.' + ], 'new' => [ 'header' => 'Add New User', 'header_sub' => 'Add a new user with permissions to this server.', @@ -33,11 +38,11 @@ return [ 'description' => 'Allows user to stop the server.', ], 'restart' => [ - 'title' => 'Stop Server', + 'title' => 'Restart Server', 'description' => 'Allows user to restart the server.', ], 'kill' => [ - 'title' => 'Stop Server', + 'title' => 'Kill Server', 'description' => 'Allows user to kill the server process.', ], 'command' => [ diff --git a/resources/themes/pterodactyl/server/users/new.blade.php b/resources/themes/pterodactyl/server/users/new.blade.php index 3ee194c45..6236be984 100644 --- a/resources/themes/pterodactyl/server/users/new.blade.php +++ b/resources/themes/pterodactyl/server/users/new.blade.php @@ -43,7 +43,8 @@
      - + {!! csrf_field() !!} +

      @lang('server.users.new.email_help')

      diff --git a/resources/themes/pterodactyl/server/users/view.blade.php b/resources/themes/pterodactyl/server/users/view.blade.php new file mode 100644 index 000000000..129a403b9 --- /dev/null +++ b/resources/themes/pterodactyl/server/users/view.blade.php @@ -0,0 +1,417 @@ +{{-- 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.master') + +@section('title') + @lang('server.users.new.header') +@endsection + +@section('content-header') +

      @lang('server.users.edit.header')@lang('server.users.edit.header_sub')

      + +@endsection + +@section('content') +@can('edit-subuser', $server) +
      +@endcan +
      +
      +
      +
      +
      + +
      + {!! csrf_field() !!} + +
      +
      +
      + @can('edit-subuser', $server) + + @endcan +
      +
      +
      +
      +
      + {{-- Left Side --}} +
      +
      +
      +
      +

      @lang('server.users.new.power_header')

      +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      @lang('server.users.new.subuser_header')

      +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      @lang('server.users.new.server_header')

      +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      @lang('server.users.new.sftp_header')

      +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +
      + {{-- Right Side --}} +
      +
      +
      +
      +

      @lang('server.users.new.file_header')

      +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      @lang('server.users.new.task_header')

      +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      @lang('server.users.new.db_header')

      +
      +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +
      +@can('edit-subuser', $server) +
      +@endcan +@endsection + +@section('footer-scripts') + @parent + +@endsection From db7b741b286b3c44d6c3435a0593f87dd3293ab5 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 21 Jan 2017 13:49:14 -0500 Subject: [PATCH 141/599] Show server status in sidebar properly on subuser views --- .../Controllers/Server/SubuserController.php | 25 ++++++++++++++++--- .../pterodactyl/server/users/index.blade.php | 5 ++++ .../pterodactyl/server/users/new.blade.php | 1 + .../pterodactyl/server/users/view.blade.php | 1 + 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Server/SubuserController.php b/app/Http/Controllers/Server/SubuserController.php index 69db75bf7..97c4e5ab8 100644 --- a/app/Http/Controllers/Server/SubuserController.php +++ b/app/Http/Controllers/Server/SubuserController.php @@ -28,6 +28,7 @@ use DB; use Log; use Auth; use Alert; +use Javascript; use Pterodactyl\Models; use Illuminate\Http\Request; use Pterodactyl\Exceptions\DisplayException; @@ -51,10 +52,16 @@ class SubuserController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('list-subusers', $server); + $node = Models\Node::find($server->node); + + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + ]); return view('server.users.index', [ 'server' => $server, - 'node' => Models\Node::find($server->node), + 'node' => $node, 'subusers' => Models\Subuser::select('subusers.*', 'users.email', 'users.username') ->join('users', 'users.id', '=', 'subusers.user_id') ->where('server_id', $server->id) @@ -66,6 +73,12 @@ class SubuserController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('view-subuser', $server); + $node = Models\Node::find($server->node); + + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + ]); $subuser = Models\Subuser::select('subusers.*', 'users.email as a_userEmail') ->join('users', 'users.id', '=', 'subusers.user_id') @@ -87,7 +100,7 @@ class SubuserController extends Controller return view('server.users.view', [ 'server' => $server, - 'node' => Models\Node::find($server->node), + 'node' => $node, 'subuser' => $subuser, 'permissions' => $permissions, ]); @@ -137,10 +150,16 @@ class SubuserController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('create-subuser', $server); + $node = Models\Node::find($server->node); + + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + ]); return view('server.users.new', [ 'server' => $server, - 'node' => Models\Node::find($server->node), + 'node' => $node, ]); } diff --git a/resources/themes/pterodactyl/server/users/index.blade.php b/resources/themes/pterodactyl/server/users/index.blade.php index 6e63bd10d..ebb675d20 100644 --- a/resources/themes/pterodactyl/server/users/index.blade.php +++ b/resources/themes/pterodactyl/server/users/index.blade.php @@ -84,3 +84,8 @@
    • @endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/server.socket.js') !!} +@endsection diff --git a/resources/themes/pterodactyl/server/users/new.blade.php b/resources/themes/pterodactyl/server/users/new.blade.php index 6236be984..5bec326b7 100644 --- a/resources/themes/pterodactyl/server/users/new.blade.php +++ b/resources/themes/pterodactyl/server/users/new.blade.php @@ -400,6 +400,7 @@ @section('footer-scripts') @parent + {!! Theme::js('js/frontend/server.socket.js') !!} +@endsection From fa0f32584e075bc79a4598ccaa8994a6dbf7e493 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 21 Jan 2017 15:44:06 -0500 Subject: [PATCH 144/599] Update laroute --- public/js/laroute.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/laroute.js b/public/js/laroute.js index 0a6634c73..f9a87a665 100644 --- a/public/js/laroute.js +++ b/public/js/laroute.js @@ -6,7 +6,7 @@ absolute: false, rootUrl: 'http://pterodactyl.app', - routes : [{"host":null,"methods":["GET","HEAD"],"uri":"admin","name":"admin.index","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/settings","name":"admin.settings","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getSettings"},{"host":null,"methods":["POST"],"uri":"admin\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\BaseController@postSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users","name":"admin.users","action":"Pterodactyl\Http\Controllers\Admin\UserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/accounts.json","name":"admin.users.json","action":"Pterodactyl\Http\Controllers\Admin\UserController@getJson"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/view\/{id}","name":"admin.users.view","action":"Pterodactyl\Http\Controllers\Admin\UserController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@updateUser"},{"host":null,"methods":["DELETE"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@deleteUser"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/new","name":"admin.users.new","action":"Pterodactyl\Http\Controllers\Admin\UserController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers","name":"admin.servers","action":"Pterodactyl\Http\Controllers\Admin\ServersController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/new","name":"admin.servers.new","action":"Pterodactyl\Http\Controllers\Admin\ServersController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/get-nodes","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerGetNodes"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/get-ips","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerGetIps"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/service-options","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerServiceOptions"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/option-details","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerOptionDetails"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}","name":"admin.servers.view","action":"Pterodactyl\Http\Controllers\Admin\ServersController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/database","name":"admin.servers.database","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postDatabase"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/container","name":"admin.servers.post.container","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateContainerDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/startup","name":"admin.servers.post.startup","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerStartup"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/rebuild","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerToggleBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/build","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerUpdateBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/suspend","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postSuspendServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/unsuspend","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUnsuspendServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/installed","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postToggleInstall"},{"host":null,"methods":["DELETE"],"uri":"admin\/servers\/view\/{id}\/{force?}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@deleteServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/queuedDeletion","name":"admin.servers.post.queuedDeletion","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postQueuedDeletionHandler"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes","name":"admin.nodes","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/new","name":"admin.nodes.new","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.view","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@postView"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/deallocate\/single\/{allocation}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@deallocateSingle"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/deallocate\/block","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@deallocateBlock"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/alias","name":"admin.nodes.alias","action":"Pterodactyl\Http\Controllers\Admin\NodesController@setAlias"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/allocations.json","name":"admin.nodes.view.allocations","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getAllocationsJson"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocations","name":"admin.nodes.post.allocations","action":"Pterodactyl\Http\Controllers\Admin\NodesController@postAllocations"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/deploy","name":"admin.nodes.deply","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getScript"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.delete","action":"Pterodactyl\Http\Controllers\Admin\NodesController@deleteNode"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/{id}\/configurationtoken","name":"admin.nodes.configuration-token","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getConfigurationToken"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/locations","name":"admin.locations","action":"Pterodactyl\Http\Controllers\Admin\LocationsController@getIndex"},{"host":null,"methods":["DELETE"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@deleteLocation"},{"host":null,"methods":["PATCH"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@patchLocation"},{"host":null,"methods":["POST"],"uri":"admin\/locations","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@postLocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases","name":"admin.databases","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases\/new","name":"admin.databases.new","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/databases\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@postNew"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete\/{id}","name":"admin.databases.delete","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteDatabase"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete-server\/{id}","name":"admin.databases.delete-server","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteServer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services","name":"admin.services","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/new","name":"admin.services.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/services\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}","name":"admin.services.service","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getService"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postService"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}\/configuration","name":"admin.services.service.config","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getConfiguration"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}\/configuration","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/new","name":"admin.services.option.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@newOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":"admin.services.option","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOption"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{service}\/option\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":"admin.services.option.variable.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}","name":"admin.services.option.variable","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOptionVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}\/delete","name":"admin.services.option.variable.delete","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/new\/{option?}","name":"admin.services.packs.new","action":"Pterodactyl\Http\Controllers\Admin\PackController@new"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/upload\/{option?}","name":"admin.services.packs.uploadForm","action":"Pterodactyl\Http\Controllers\Admin\PackController@uploadForm"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/upload","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@postUpload"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs","name":"admin.services.packs","action":"Pterodactyl\Http\Controllers\Admin\PackController@listAll"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/option\/{option}","name":"admin.services.packs.option","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/service\/{service}","name":"admin.services.packs.service","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}","name":"admin.services.packs.edit","action":"Pterodactyl\Http\Controllers\Admin\PackController@edit"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/edit\/{pack}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}\/export\/{archive?}","name":"admin.services.packs.export","action":"Pterodactyl\Http\Controllers\Admin\PackController@export"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login","name":"auth.login","action":"Pterodactyl\Http\Controllers\Auth\LoginController@showLoginForm"},{"host":null,"methods":["POST"],"uri":"auth\/login","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@login"},{"host":null,"methods":["POST"],"uri":"auth\/login\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@checkTotp"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password","name":"auth.password","action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm"},{"host":null,"methods":["POST"],"uri":"auth\/password","name":null,"action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password\/reset\/{token}","name":"auth.reset","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@showResetForm"},{"host":null,"methods":["POST"],"uri":"auth\/password\/reset","name":"auth.reset.post","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@reset"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/logout","name":"auth.logout","action":"Pterodactyl\Http\Controllers\Auth\LoginController@logout"},{"host":null,"methods":["GET","HEAD"],"uri":"\/","name":"index","action":"Pterodactyl\Http\Controllers\Base\IndexController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"index","name":null,"action":"Closure"},{"host":null,"methods":["GET","HEAD"],"uri":"password-gen\/{length}","name":"password-gen","action":"Pterodactyl\Http\Controllers\Base\IndexController@getPassword"},{"host":null,"methods":["GET","HEAD"],"uri":"account","name":"account","action":"Pterodactyl\Http\Controllers\Base\AccountController@index"},{"host":null,"methods":["POST"],"uri":"account\/password","name":"account.password","action":"Pterodactyl\Http\Controllers\Base\AccountController@password"},{"host":null,"methods":["POST"],"uri":"account\/email","name":"account.email","action":"Pterodactyl\Http\Controllers\Base\AccountController@email"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api","name":"account.api","action":"Pterodactyl\Http\Controllers\Base\APIController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api\/new","name":"account.api.new","action":"Pterodactyl\Http\Controllers\Base\APIController@create"},{"host":null,"methods":["POST"],"uri":"account\/api\/new","name":null,"action":"Pterodactyl\Http\Controllers\Base\APIController@save"},{"host":null,"methods":["DELETE"],"uri":"account\/api\/revoke\/{key}","name":null,"action":"Pterodactyl\Http\Controllers\Base\APIController@revoke"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security","name":"account.security","action":"Pterodactyl\Http\Controllers\Base\SecurityController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security\/revoke\/{id}","name":"account.security.revoke","action":"Pterodactyl\Http\Controllers\Base\SecurityController@revoke"},{"host":null,"methods":["PUT"],"uri":"account\/security\/totp","name":"account.security.totp","action":"Pterodactyl\Http\Controllers\Base\SecurityController@generateTotp"},{"host":null,"methods":["POST"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@setTotp"},{"host":null,"methods":["DELETE"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@disableTotp"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services","name":"daemon.services","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@list"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services\/pull\/{service}\/{file}","name":"remote.install","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"language\/{lang}","name":"langauge.set","action":"Pterodactyl\Http\Controllers\Base\LanguageController@setLanguage"},{"host":null,"methods":["POST"],"uri":"remote\/download","name":"remote.download","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postDownload"},{"host":null,"methods":["POST"],"uri":"remote\/install","name":"remote.install","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postInstall"},{"host":null,"methods":["POST"],"uri":"remote\/event","name":"remote.event","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@event"},{"host":null,"methods":["GET","HEAD"],"uri":"remote\/configuration\/{token}","name":"remote.configuration","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@getConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}","name":"server.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings","name":"server.settings","action":"Pterodactyl\Http\Controllers\Server\ServerController@getSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/databases","name":"server.settings.databases","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDatabases"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/sftp","name":"server.settings.sftp","action":"Pterodactyl\Http\Controllers\Server\ServerController@getSFTP"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/sftp","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsSFTP"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/startup","name":"server.settings.startup","action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files","name":"server.files.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getFiles"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/edit\/{file}","name":"server.files.edit","action":"Pterodactyl\Http\Controllers\Server\ServerController@getEditFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/download\/{file}","name":"server.files.download","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDownloadFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/add","name":"server.files.add","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAddFile"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/directory-list","name":"server.files.directory-list","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postDirectoryList"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/save","name":"server.files.save","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSaveFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users","name":"server.subusers","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/new","name":"server.subusers.new","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/view\/{id}","name":"server.subusers.view","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getView"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postView"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/users\/delete\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@deleteSubuser"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks","name":"server.tasks","action":"Pterodactyl\Http\Controllers\Server\TaskController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/view\/{id}","name":"server.tasks.view","action":"Pterodactyl\Http\Controllers\Server\TaskController@getView"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/new","name":"server.tasks.new","action":"Pterodactyl\Http\Controllers\Server\TaskController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\TaskController@postNew"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/tasks\/delete\/{id}","name":"server.tasks.delete","action":"Pterodactyl\Http\Controllers\Server\TaskController@deleteTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/toggle\/{id}","name":"server.tasks.toggle","action":"Pterodactyl\Http\Controllers\Server\TaskController@toggleTask"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/ajax\/status","name":"server.ajax.status","action":"Pterodactyl\Http\Controllers\Server\AjaxController@getStatus"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/set-primary","name":null,"action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSetPrimary"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/settings\/reset-database-password","name":"server.ajax.reset-database-password","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postResetDatabasePassword"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/open","name":"debugbar.openhandler","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@handle"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/clockwork\/{id}","name":"debugbar.clockwork","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@clockwork"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/stylesheets","name":"debugbar.assets.css","action":"Barryvdh\Debugbar\Controllers\AssetController@css"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/javascript","name":"debugbar.assets.js","action":"Barryvdh\Debugbar\Controllers\AssetController@js"}], + routes : [{"host":null,"methods":["GET","HEAD"],"uri":"admin","name":"admin.index","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/settings","name":"admin.settings","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getSettings"},{"host":null,"methods":["POST"],"uri":"admin\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\BaseController@postSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users","name":"admin.users","action":"Pterodactyl\Http\Controllers\Admin\UserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/accounts.json","name":"admin.users.json","action":"Pterodactyl\Http\Controllers\Admin\UserController@getJson"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/view\/{id}","name":"admin.users.view","action":"Pterodactyl\Http\Controllers\Admin\UserController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@updateUser"},{"host":null,"methods":["DELETE"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@deleteUser"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/new","name":"admin.users.new","action":"Pterodactyl\Http\Controllers\Admin\UserController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers","name":"admin.servers","action":"Pterodactyl\Http\Controllers\Admin\ServersController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/new","name":"admin.servers.new","action":"Pterodactyl\Http\Controllers\Admin\ServersController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/get-nodes","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerGetNodes"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/get-ips","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerGetIps"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/service-options","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerServiceOptions"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/option-details","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerOptionDetails"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}","name":"admin.servers.view","action":"Pterodactyl\Http\Controllers\Admin\ServersController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/database","name":"admin.servers.database","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postDatabase"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/container","name":"admin.servers.post.container","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateContainerDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/startup","name":"admin.servers.post.startup","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerStartup"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/rebuild","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerToggleBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/build","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerUpdateBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/suspend","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postSuspendServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/unsuspend","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUnsuspendServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/installed","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postToggleInstall"},{"host":null,"methods":["DELETE"],"uri":"admin\/servers\/view\/{id}\/{force?}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@deleteServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/queuedDeletion","name":"admin.servers.post.queuedDeletion","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postQueuedDeletionHandler"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes","name":"admin.nodes","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/new","name":"admin.nodes.new","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.view","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@postView"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/deallocate\/single\/{allocation}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@deallocateSingle"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/deallocate\/block","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@deallocateBlock"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/alias","name":"admin.nodes.alias","action":"Pterodactyl\Http\Controllers\Admin\NodesController@setAlias"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/allocations.json","name":"admin.nodes.view.allocations","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getAllocationsJson"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocations","name":"admin.nodes.post.allocations","action":"Pterodactyl\Http\Controllers\Admin\NodesController@postAllocations"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/deploy","name":"admin.nodes.deply","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getScript"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.delete","action":"Pterodactyl\Http\Controllers\Admin\NodesController@deleteNode"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/{id}\/configurationtoken","name":"admin.nodes.configuration-token","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getConfigurationToken"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/locations","name":"admin.locations","action":"Pterodactyl\Http\Controllers\Admin\LocationsController@getIndex"},{"host":null,"methods":["DELETE"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@deleteLocation"},{"host":null,"methods":["PATCH"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@patchLocation"},{"host":null,"methods":["POST"],"uri":"admin\/locations","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@postLocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases","name":"admin.databases","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases\/new","name":"admin.databases.new","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/databases\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@postNew"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete\/{id}","name":"admin.databases.delete","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteDatabase"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete-server\/{id}","name":"admin.databases.delete-server","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteServer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services","name":"admin.services","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/new","name":"admin.services.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/services\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}","name":"admin.services.service","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getService"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postService"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}\/configuration","name":"admin.services.service.config","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getConfiguration"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}\/configuration","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/new","name":"admin.services.option.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@newOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":"admin.services.option","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOption"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{service}\/option\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":"admin.services.option.variable.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}","name":"admin.services.option.variable","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOptionVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}\/delete","name":"admin.services.option.variable.delete","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/new\/{option?}","name":"admin.services.packs.new","action":"Pterodactyl\Http\Controllers\Admin\PackController@new"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/upload\/{option?}","name":"admin.services.packs.uploadForm","action":"Pterodactyl\Http\Controllers\Admin\PackController@uploadForm"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/upload","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@postUpload"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs","name":"admin.services.packs","action":"Pterodactyl\Http\Controllers\Admin\PackController@listAll"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/option\/{option}","name":"admin.services.packs.option","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/service\/{service}","name":"admin.services.packs.service","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}","name":"admin.services.packs.edit","action":"Pterodactyl\Http\Controllers\Admin\PackController@edit"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/edit\/{pack}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}\/export\/{archive?}","name":"admin.services.packs.export","action":"Pterodactyl\Http\Controllers\Admin\PackController@export"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login","name":"auth.login","action":"Pterodactyl\Http\Controllers\Auth\LoginController@showLoginForm"},{"host":null,"methods":["POST"],"uri":"auth\/login","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@login"},{"host":null,"methods":["POST"],"uri":"auth\/login\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@checkTotp"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password","name":"auth.password","action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm"},{"host":null,"methods":["POST"],"uri":"auth\/password","name":null,"action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password\/reset\/{token}","name":"auth.reset","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@showResetForm"},{"host":null,"methods":["POST"],"uri":"auth\/password\/reset","name":"auth.reset.post","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@reset"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/logout","name":"auth.logout","action":"Pterodactyl\Http\Controllers\Auth\LoginController@logout"},{"host":null,"methods":["GET","HEAD"],"uri":"\/","name":"index","action":"Pterodactyl\Http\Controllers\Base\IndexController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"index","name":null,"action":"Closure"},{"host":null,"methods":["GET","HEAD"],"uri":"password-gen\/{length}","name":"password-gen","action":"Pterodactyl\Http\Controllers\Base\IndexController@getPassword"},{"host":null,"methods":["GET","HEAD"],"uri":"account","name":"account","action":"Pterodactyl\Http\Controllers\Base\AccountController@index"},{"host":null,"methods":["POST"],"uri":"account\/password","name":"account.password","action":"Pterodactyl\Http\Controllers\Base\AccountController@password"},{"host":null,"methods":["POST"],"uri":"account\/email","name":"account.email","action":"Pterodactyl\Http\Controllers\Base\AccountController@email"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api","name":"account.api","action":"Pterodactyl\Http\Controllers\Base\APIController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api\/new","name":"account.api.new","action":"Pterodactyl\Http\Controllers\Base\APIController@create"},{"host":null,"methods":["POST"],"uri":"account\/api\/new","name":null,"action":"Pterodactyl\Http\Controllers\Base\APIController@save"},{"host":null,"methods":["DELETE"],"uri":"account\/api\/revoke\/{key}","name":null,"action":"Pterodactyl\Http\Controllers\Base\APIController@revoke"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security","name":"account.security","action":"Pterodactyl\Http\Controllers\Base\SecurityController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security\/revoke\/{id}","name":"account.security.revoke","action":"Pterodactyl\Http\Controllers\Base\SecurityController@revoke"},{"host":null,"methods":["PUT"],"uri":"account\/security\/totp","name":"account.security.totp","action":"Pterodactyl\Http\Controllers\Base\SecurityController@generateTotp"},{"host":null,"methods":["POST"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@setTotp"},{"host":null,"methods":["DELETE"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@disableTotp"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services","name":"daemon.services","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@list"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services\/pull\/{service}\/{file}","name":"remote.install","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"language\/{lang}","name":"langauge.set","action":"Pterodactyl\Http\Controllers\Base\LanguageController@setLanguage"},{"host":null,"methods":["POST"],"uri":"remote\/download","name":"remote.download","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postDownload"},{"host":null,"methods":["POST"],"uri":"remote\/install","name":"remote.install","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postInstall"},{"host":null,"methods":["POST"],"uri":"remote\/event","name":"remote.event","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@event"},{"host":null,"methods":["GET","HEAD"],"uri":"remote\/configuration\/{token}","name":"remote.configuration","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@getConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}","name":"server.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings","name":"server.settings","action":"Pterodactyl\Http\Controllers\Server\ServerController@getSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/databases","name":"server.settings.databases","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDatabases"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/sftp","name":"server.settings.sftp","action":"Pterodactyl\Http\Controllers\Server\ServerController@getSFTP"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/sftp","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsSFTP"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/startup","name":"server.settings.startup","action":"Pterodactyl\Http\Controllers\Server\ServerController@getStartup"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/allocation","name":"server.settings.allocation","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files","name":"server.files.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getFiles"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/edit\/{file}","name":"server.files.edit","action":"Pterodactyl\Http\Controllers\Server\ServerController@getEditFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/download\/{file}","name":"server.files.download","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDownloadFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/add","name":"server.files.add","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAddFile"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/directory-list","name":"server.files.directory-list","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postDirectoryList"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/save","name":"server.files.save","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSaveFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users","name":"server.subusers","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/new","name":"server.subusers.new","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/view\/{id}","name":"server.subusers.view","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getView"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postView"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/users\/delete\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@deleteSubuser"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks","name":"server.tasks","action":"Pterodactyl\Http\Controllers\Server\TaskController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/view\/{id}","name":"server.tasks.view","action":"Pterodactyl\Http\Controllers\Server\TaskController@getView"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/new","name":"server.tasks.new","action":"Pterodactyl\Http\Controllers\Server\TaskController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\TaskController@postNew"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/tasks\/delete\/{id}","name":"server.tasks.delete","action":"Pterodactyl\Http\Controllers\Server\TaskController@deleteTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/toggle\/{id}","name":"server.tasks.toggle","action":"Pterodactyl\Http\Controllers\Server\TaskController@toggleTask"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/ajax\/status","name":"server.ajax.status","action":"Pterodactyl\Http\Controllers\Server\AjaxController@getStatus"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/set-primary","name":null,"action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSetPrimary"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/settings\/reset-database-password","name":"server.ajax.reset-database-password","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postResetDatabasePassword"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/open","name":"debugbar.openhandler","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@handle"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/clockwork\/{id}","name":"debugbar.clockwork","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@clockwork"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/stylesheets","name":"debugbar.assets.css","action":"Barryvdh\Debugbar\Controllers\AssetController@css"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/javascript","name":"debugbar.assets.js","action":"Barryvdh\Debugbar\Controllers\AssetController@js"}], prefix: '', route : function (name, parameters, route) { From 19da4eda042c514cb625e878d0a746cdccf0de48 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 21 Jan 2017 15:51:05 -0500 Subject: [PATCH 145/599] Update views, remove old theme views --- CHANGELOG.md | 1 + README.md | 6 + resources/views/auth/login.blade.php | 148 ----- .../views/auth/passwords/email.blade.php | 63 --- .../views/auth/passwords/reset.blade.php | 82 --- resources/views/base/account.blade.php | 90 --- resources/views/base/api/index.blade.php | 109 ---- resources/views/base/api/new.blade.php | 278 ---------- resources/views/base/index.blade.php | 124 ----- resources/views/base/security.blade.php | 205 ------- resources/views/layouts/master.blade.php | 313 ----------- resources/views/server/files/add.blade.php | 290 ---------- resources/views/server/files/edit.blade.php | 103 ---- resources/views/server/files/index.blade.php | 190 ------- resources/views/server/files/list.blade.php | 160 ------ resources/views/server/index.blade.php | 522 ------------------ resources/views/server/settings.blade.php | 246 --------- resources/views/server/tasks/index.blade.php | 156 ------ resources/views/server/tasks/new.blade.php | 172 ------ resources/views/server/tasks/view.blade.php | 0 resources/views/server/users/index.blade.php | 107 ---- resources/views/server/users/new.blade.php | 301 ---------- resources/views/server/users/view.blade.php | 290 ---------- 23 files changed, 7 insertions(+), 3949 deletions(-) delete mode 100644 resources/views/auth/login.blade.php delete mode 100644 resources/views/auth/passwords/email.blade.php delete mode 100644 resources/views/auth/passwords/reset.blade.php delete mode 100644 resources/views/base/account.blade.php delete mode 100644 resources/views/base/api/index.blade.php delete mode 100644 resources/views/base/api/new.blade.php delete mode 100644 resources/views/base/index.blade.php delete mode 100644 resources/views/base/security.blade.php delete mode 100644 resources/views/layouts/master.blade.php delete mode 100644 resources/views/server/files/add.blade.php delete mode 100644 resources/views/server/files/edit.blade.php delete mode 100644 resources/views/server/files/index.blade.php delete mode 100644 resources/views/server/files/list.blade.php delete mode 100644 resources/views/server/index.blade.php delete mode 100644 resources/views/server/settings.blade.php delete mode 100644 resources/views/server/tasks/index.blade.php delete mode 100644 resources/views/server/tasks/new.blade.php delete mode 100644 resources/views/server/tasks/view.blade.php delete mode 100644 resources/views/server/users/index.blade.php delete mode 100644 resources/views/server/users/new.blade.php delete mode 100644 resources/views/server/users/view.blade.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d4d6b613..f2ee47a5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Basic service pack implementation to allow assignment of modpacks or software to a server to pre-install applications and allow users to update. * Users can now have a username as well as client name assigned to their account. * Ability to create a node through the CLI using `pterodactyl:node` as well as locations via `pterodactyl:location`. +* New theme (AdminLTE) for front-end with tweaks to backend files to work properly with it. ### Fixed * Bug causing error logs to be spammed if someone timed out on an ajax based page. diff --git a/README.md b/README.md index 88c02a171..a26d41468 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ A huge thanks to [PhraseApp](https://phraseapp.com) who provide us the software Ace Editor - [license](https://github.com/ajaxorg/ace/blob/master/LICENSE) - [homepage](https://ace.c9.io) +AdminLTE - [license](https://github.com/almasaeed2010/AdminLTE/blob/master/LICENSE) - [homepage](https://almsaeedstudio.com) + Animate.css - [license](https://github.com/daneden/animate.css/blob/master/LICENSE) - [homepage](http://daneden.github.io/animate.css/) Async.js - [license](https://github.com/caolan/async/blob/master/LICENSE) - [homepage](https://github.com/caolan/async/) @@ -57,8 +59,12 @@ jQuery Terminal - [license](https://github.com/jcubic/jquery.terminal/blob/maste Lodash - [license](https://github.com/lodash/lodash/blob/master/LICENSE) - [homepage](https://lodash.com/) +Select2 - [license](https://github.com/select2/select2/blob/master/LICENSE.md) - [homepage](https://select2.github.io) + Socket.io - [license](https://github.com/socketio/socket.io/blob/master/LICENSE) - [homepage](http://socket.io) +Socket.io File Upload - [license](https://github.com/vote539/socketio-file-upload/blob/master/server.js#L1-L27) - [homepage](https://github.com/vote539/socketio-file-upload) + SweetAlert - [license](https://github.com/t4t5/sweetalert/blob/master/LICENSE) - [homepage](http://t4t5.github.io/sweetalert/) Typeahead — [license](https://github.com/bassjobsen/Bootstrap-3-Typeahead/blob/master/bootstrap3-typeahead.js) — [homepage](https://github.com/bassjobsen/Bootstrap-3-Typeahead) diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php deleted file mode 100644 index 9ab5cdbf0..000000000 --- a/resources/views/auth/login.blade.php +++ /dev/null @@ -1,148 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} -{{-- Some Modifications (c) 2015 Dylan Seidt --}} - -{{-- 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.master') - -@section('title', 'Login') - - -@section('right-nav') -@endsection - -@section('sidebar') -@endsection - -@section('resp-alerts') -@endsection - -@section('resp-errors') -@endsection - -@section('content') -
      - @if (count($errors) > 0) -
      - - {{ trans('strings.whoops') }}! {{ trans('auth.errorencountered') }}

      -
        - @foreach ($errors->all() as $error) -
      • {{ $error }}
      • - @endforeach -
      -
      - @endif - @foreach (Alert::getMessages() as $type => $messages) - @foreach ($messages as $message) - - @endforeach - @endforeach -
      - {{ trans('strings.login') }} -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      -
      - -
      -
      -
      -
      - {!! csrf_field() !!} - - -
      -
      -
      -
      -
      - -
      - -@endsection diff --git a/resources/views/auth/passwords/email.blade.php b/resources/views/auth/passwords/email.blade.php deleted file mode 100644 index 064373a53..000000000 --- a/resources/views/auth/passwords/email.blade.php +++ /dev/null @@ -1,63 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} -{{-- Some Modifications (c) 2015 Dylan Seidt --}} - -{{-- 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.master') - -@section('title', 'Reset Password') - - -@section('right-nav') -@endsection - -@section('sidebar') -@endsection - -@section('content') -
      -
      - {{ trans('auth.resetpassword') }} -
      - @if (session('status')) -
      - {{ trans('strings.success') }}! {{ trans('auth.emailsent') }} -
      - @endif -
      - -
      - - @if ($errors->has('email')) - - {{ $errors->first('email') }} - - @endif -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      -
      -@endsection diff --git a/resources/views/auth/passwords/reset.blade.php b/resources/views/auth/passwords/reset.blade.php deleted file mode 100644 index 5151ce7a2..000000000 --- a/resources/views/auth/passwords/reset.blade.php +++ /dev/null @@ -1,82 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} -{{-- Some Modifications (c) 2015 Dylan Seidt --}} - -{{-- 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.master') - -@section('title', 'Reset Password') - - -@section('right-nav') -@endsection - -@section('sidebar') -@endsection - -@section('content') -
      -
      - {{ trans('auth.resetpassword') }} -
      - -
      - -
      - - @if ($errors->has('email')) - - {{ $errors->first('email') }} - - @endif -
      -
      -
      - -
      - - @if ($errors->has('password')) - - {{ $errors->first('password') }} - - @endif -

      {{ trans('base.password_req') }}

      -
      -
      -
      - -
      - - @if ($errors->has('password_confirmation')) - - {{ $errors->first('password_confirmation') }} - - @endif -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      -
      -@endsection diff --git a/resources/views/base/account.blade.php b/resources/views/base/account.blade.php deleted file mode 100644 index 629d5885b..000000000 --- a/resources/views/base/account.blade.php +++ /dev/null @@ -1,90 +0,0 @@ -{{-- 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.master') - -@section('title', 'Your Account') - -@section('sidebar-server') -@endsection - -@section('content') -
      -
      -
      -

      {{ trans('base.account.update_pass') }}


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

      {{ trans('base.password_req') }}

      -
      -
      -
      - -
      - -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      -

      {{ trans('base.account.update_email') }}


      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      -
      - -@endsection diff --git a/resources/views/base/api/index.blade.php b/resources/views/base/api/index.blade.php deleted file mode 100644 index 0fcc69a79..000000000 --- a/resources/views/base/api/index.blade.php +++ /dev/null @@ -1,109 +0,0 @@ -{{-- 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.master') - -@section('title', 'API Access') - -@section('sidebar-server') -@endsection - -@section('scripts') - @parent - {!! Theme::css('css/vendor/sweetalert/sweetalert.min.css') !!} - {!! Theme::js('js/vendor/sweetalert/sweetalert.min.js') !!} -@endsection - -@section('content') -
      - - - - - - - - - - - - @foreach ($keys as $key) - - - - - - - - @endforeach - -
      Public KeyMemoCreatedExpires
      {{ $key->public }}{{ $key->memo }}{{ (new Carbon($key->created_at))->toDayDateTimeString() }} - @if(is_null($key->expires_at)) - Never - @else - {{ (new Carbon($key->expires_at))->toDayDateTimeString() }} - @endif -
      - -
      - -@endsection diff --git a/resources/views/base/api/new.blade.php b/resources/views/base/api/new.blade.php deleted file mode 100644 index 0fb75caac..000000000 --- a/resources/views/base/api/new.blade.php +++ /dev/null @@ -1,278 +0,0 @@ -{{-- 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.master') - -@section('title', 'API Access') - -@section('sidebar-server') -@endsection - -@section('content') -
      -
      -
      -
        -
      • - 1Permissions - -
      • - @if(Auth::user()->root_admin === 1) -
      • - 2Admin - -
      • - @endif -
      • - @if(Auth::user()->root_admin === 1)3 @else 2 @endifSecurity - -
      • -
      -
      -
      - - -
      -
      -
      -
      -
      Any servers that you are a subuser for will be accessible through this API with the same permissions that you currently have.
      -
      -
      -

      Base Information


      -
      -
      -
      -
      -
      -
      -

      Server Management


      -
      -
      -
      -
      -
      -
      -
      - @if(Auth::user()->root_admin === 1) -
      -
      -
      -
      -
      -
      -
      -
      -
      -

      User Management


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

      Server Management


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

      Node Management


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

      Service Management


      -
      -
      -
      -
      -

      Location Management


      -
      -
      -
      -
      -
      - @endif -
      -
      - -
      - -

      Enter a breif description of what this API key will be used for.

      -
      -
      -
      - -
      - -

      Enter a line delimitated list of IPs that are allowed to access the API using this key. CIDR notation is allowed. Leave blank to allow any IP.

      -
      -
      -
      -
      - {!! csrf_field() !!} -
      -
      -
      - -@endsection diff --git a/resources/views/base/index.blade.php b/resources/views/base/index.blade.php deleted file mode 100644 index 00472d98d..000000000 --- a/resources/views/base/index.blade.php +++ /dev/null @@ -1,124 +0,0 @@ -{{-- 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.master') - -@section('title', 'Your Servers') - -@section('sidebar-server') -@endsection - -@section('content') -
      - @if (Auth::user()->root_admin == 1) -
      {{ trans('base.view_as_admin') }}
      - @endif - @if (!$servers->isEmpty()) - - - - @if (Auth::user()->root_admin == 1) - - @endif - - - - - - - - - - @foreach ($servers as $server) - - @if (Auth::user()->root_admin == 1) - - @endif - - - - - - - - @endforeach - -
      {{ trans('base.server_name') }}{{ trans('strings.node') }}{{ trans('strings.connection') }}{{ trans('strings.status') }}
      - @if ($server->owner === Auth::user()->id) - - @else - - @endif - {{ $server->name }}{{ $server->nodeName }}@if(!is_null($server->ip_alias)){{ $server->ip_alias }}@else{{ $server->ip }}@endif:{{ $server->port }}@if($server->suspended === 1)Suspended@else--@endif
      -
      -
      {!! $servers->render() !!}
      -
      - @else -
      {{ trans('base.no_servers') }}
      - @endif -
      - -@endsection diff --git a/resources/views/base/security.blade.php b/resources/views/base/security.blade.php deleted file mode 100644 index 48b730555..000000000 --- a/resources/views/base/security.blade.php +++ /dev/null @@ -1,205 +0,0 @@ -{{-- 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.master') - -@section('title', 'Account Security') - -@section('sidebar-server') -@endsection - -@section('content') -
      - @foreach (Alert::getMessages() as $type => $messages) - @foreach ($messages as $message) - - @endforeach - @endforeach -

      Active Sessions


      - - - - - - - - - - - - @foreach($sessions as $session) - - payload)) ?> - - - - - - - @endforeach - -
      Session IDIP AddressUser AgentLast Activity
      {{ substr($session->id, 0, 8) }}{{ $session->ip_address }}{{ $session->user_agent }} - @if((time() - $session->last_activity < 10)) - just now - @else - {{ date('D, M j \a\t H:i:s', $session->last_activity) }} - @endif -
      - -

      {{ trans('base.account.totp_header') }} @if (Auth::user()->use_totp === 1){{ trans('strings.enabled') }}@else{{ trans('strings.disabled') }}@endif


      - @if (Auth::user()->use_totp === 1) -
      -
      {{ trans('base.account.totp_disable') }}
      -
      -

      {{ trans('base.account.totp_disable_help') }}

      -
      -
      -
      -
      - {{ trans('base.account.totp_token') }} - - - {!! csrf_field() !!} - {{ method_field('DELETE') }} - - -
      -
      -
      -
      -
      - @else -
      -
      -

      {{ trans('base.account.totp_header') }}

      -
      -
      -

      {{ trans('base.account.totp_enable_help') }}

      -
      {{ trans('base.account.totp_apps') }}
      -
      -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      - @endif - - -
      - -@endsection diff --git a/resources/views/layouts/master.blade.php b/resources/views/layouts/master.blade.php deleted file mode 100644 index 1f6feb8e0..000000000 --- a/resources/views/layouts/master.blade.php +++ /dev/null @@ -1,313 +0,0 @@ -{{-- 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. --}} - - - - @section('scripts') - - - - {!! Theme::css('css/vendor/bootstrap/bootstrap.css') !!} - {!! Theme::css('css/pterodactyl.css') !!} - {!! Theme::css('css/animate.css') !!} - {!! Theme::css('css/vendor/fontawesome/font-awesome.min.css') !!} - {!! Theme::css('css/vendor/sweetalert/sweetalert.min.css') !!} - {!! Theme::css('css/vendor/fuelux/fuelux.min.css') !!} - {!! Theme::js('js/vendor/jquery/jquery.min.js') !!} - {!! Theme::js('js/vendor/bootstrap/bootstrap.min.js') !!} - {!! Theme::js('js/vendor/socketio/socket.io.min.js') !!} - {!! Theme::js('js/vendor/sweetalert/sweetalert.min.js') !!} - {!! Theme::js('js/vendor/fuelux/fuelux.min.js') !!} - {!! Theme::js('js/admin.min.js') !!} - {!! Theme::js('js/bootstrap-notify.min.js') !!} - - @section('server-socket') - @if (isset($server->name) && isset($node->name)) - - @endif - @show - @show - {{ Settings::get('company') }} - @yield('title') - - -
      - -
      - -
      -
      -
      - @section('resp-errors') - @if (count($errors) > 0) -
      - - {{ trans('strings.whoops') }}! {{ trans('auth.errorencountered') }}

      -
        - @foreach ($errors->all() as $error) -
      • {{ $error }}
      • - @endforeach -
      -
      - @endif - @show - @section('resp-alerts') - @foreach (Alert::getMessages() as $type => $messages) - @foreach ($messages as $message) - - @endforeach - @endforeach - @show -
      -
      -
      - @yield('content') -
      -
      -
      - -
      - - - diff --git a/resources/views/server/files/add.blade.php b/resources/views/server/files/add.blade.php deleted file mode 100644 index ac3fdadea..000000000 --- a/resources/views/server/files/add.blade.php +++ /dev/null @@ -1,290 +0,0 @@ -{{-- 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.master') - -@section('title') - Add File to: {{ $server->name }} -@endsection - -@section('scripts') - @parent - {!! Theme::js('js/vendor/upload/client.min.js') !!} - {!! Theme::js('js/vendor/lodash/lodash.js') !!} -@endsection - -@section('content') -
      - -
      -
      -
      -
      -
      - Save As: - -
      -

      All files are saved relative to /home/container. You can enter more of the path into the Save As field to save the file into a specific folder.

      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - - -
      -
      - -
      -
      -
      - @can('upload-files', $server) -
      -
      -
      -
      - Upload Directory: - -
      -

      All files are saved relative to /home/container. You can enter more of the path into the Save As field to save the file into a specific folder.

      -
      -
      - -
      Edit the path location above before you upload files. They will automatically be placed in the directory you specify above. You can change this each time you upload a new file without having to press anything else. The directory must exist before performing an upload.
      - - -
      -
      -

      Drag and Drop File(s) Here

      -

      The maximum size for web-based file uploads is currently {{ $node->upload_size }} MB.

      -
      -
      - -
      - @endcan -
      -
      -{!! Theme::js('js/vendor/ace/ace.js') !!} -{!! Theme::js('js/vendor/ace/ext-modelist.js') !!} - -@endsection diff --git a/resources/views/server/files/edit.blade.php b/resources/views/server/files/edit.blade.php deleted file mode 100644 index ed6c38637..000000000 --- a/resources/views/server/files/edit.blade.php +++ /dev/null @@ -1,103 +0,0 @@ -{{-- 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.master') - -@section('title') - Managing Files for: {{ $server->name }} -@endsection - -@section('content') -
      -

      Editing File: /home/container/{{ $file }}

      -
      -
      -
      {{ $contents }}
      -
      -
      - @can('save-files', $server) -
      -
      -
      - - - {{ trans('server.files.back') }} -
      -
      - @endcan -
      -{!! Theme::js('js/vendor/ace/ace.js') !!} -{!! Theme::js('js/vendor/ace/ext-modelist.js') !!} - -@endsection diff --git a/resources/views/server/files/index.blade.php b/resources/views/server/files/index.blade.php deleted file mode 100644 index 987556b63..000000000 --- a/resources/views/server/files/index.blade.php +++ /dev/null @@ -1,190 +0,0 @@ -{{-- 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.master') - -@section('title') - Managing Files for: {{ $server->name }} -@endsection - -@section('scripts') - @parent - {!! Theme::js('js/vendor/async/async.min.js') !!} - {!! Theme::js('js/vendor/lodash/lodash.js') !!} - {!! Theme::js('js/vendor/upload/client.min.js') !!} -@endsection - -@section('content') -
      -
      -
      -
      - {{ trans('server.files.loading') }} -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -

      File Path Information

      -
      -
      - When configuring any file paths in your server plugins or settings you should use /home/container as your base path. The maximum size for web-based file uploads is currently {{ $node->upload_size }} MB. -
      -
      -
      -
      -
      -@if(App::environment('production')) - {!! Theme::js('js/filemanager.min.js') !!} -@else - {!! Theme::js('js/files/index.js') !!} - {!! Theme::js('js/files/contextmenu.js') !!} - {!! Theme::js('js/files/actions.js') !!} -@endif - -@endsection diff --git a/resources/views/server/files/list.blade.php b/resources/views/server/files/list.blade.php deleted file mode 100644 index ea56a580e..000000000 --- a/resources/views/server/files/list.blade.php +++ /dev/null @@ -1,160 +0,0 @@ -{{-- 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. --}} - - - - - - - - - - - - - - - - @if (isset($directory['first']) && $directory['first'] === true) - - - - - - - - @endif - @if (isset($directory['show']) && $directory['show'] === true) - - - - - - - - @endif - @foreach ($folders as $folder) - - - - - - - - @endforeach - @foreach ($files as $file) - - - - - - - - @endforeach - -
      File NameSizeLast Modified
      - /home/container{{ $directory['header'] }} - - - - - -
      - ← {{ $directory['link_show'] }} -
      - {{ $folder['entry'] }} - {{ $folder['size'] }} - timezone(env('APP_TIMEZONE', 'America/New_York')); ?> - @if($carbon->diffInMinutes(Carbon::now()) > 60) - {{ $carbon->format('m/d/y H:i:s') }} - @elseif($carbon->diffInSeconds(Carbon::now()) < 5 || $carbon->isFuture()) - seconds ago - @else - {{ $carbon->diffForHumans() }} - @endif -
      - {{-- oh boy --}} - @if(in_array($file['mime'], [ - 'application/x-7z-compressed', - 'application/zip', - 'application/x-compressed-zip', - 'application/x-tar', - 'application/x-gzip', - 'application/x-bzip', - 'application/x-bzip2', - 'application/java-archive' - ])) - - @elseif(in_array($file['mime'], [ - 'application/json', - 'application/javascript', - 'application/xml', - 'application/xhtml+xml', - 'text/xml', - 'text/css', - 'text/html', - 'text/x-perl', - 'text/x-shellscript' - ])) - - @elseif(starts_with($file['mime'], 'image')) - - @elseif(starts_with($file['mime'], 'video')) - - @elseif(starts_with($file['mime'], 'video')) - - @elseif(starts_with($file['mime'], 'application/vnd.ms-powerpoint')) - - @elseif(in_array($file['mime'], [ - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', - 'application/msword' - ]) || starts_with($file['mime'], 'application/vnd.ms-word')) - - @elseif(in_array($file['mime'], [ - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', - ]) || starts_with($file['mime'], 'application/vnd.ms-excel')) - - @elseif($file['mime'] === 'application/pdf') - - @else - - @endif - - @if(in_array($file['mime'], $editableMime)) - @can('edit-files', $server) - {{ $file['entry'] }} - @else - {{ $file['entry'] }} - @endcan - @else - {{ $file['entry'] }} - @endif - {{ $file['size'] }} - timezone(env('APP_TIMEZONE', 'America/New_York')); ?> - @if($carbon->diffInMinutes(Carbon::now()) > 60) - {{ $carbon->format('m/d/y H:i:s') }} - @elseif($carbon->diffInSeconds(Carbon::now()) < 5 || $carbon->isFuture()) - seconds ago - @else - {{ $carbon->diffForHumans() }} - @endif -
      diff --git a/resources/views/server/index.blade.php b/resources/views/server/index.blade.php deleted file mode 100644 index 8da04161b..000000000 --- a/resources/views/server/index.blade.php +++ /dev/null @@ -1,522 +0,0 @@ -{{-- 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.master') - -@section('title') - Viewing Server: {{ $server->name }} -@endsection - -@section('scripts') - @parent - {!! Theme::css('css/jquery.terminal.css') !!} - {!! Theme::js('js/jquery.mousewheel-min.js') !!} - {!! Theme::js('js/jquery.terminal-0.11.23.min.js') !!} - {!! Theme::js('js/unix_formatting.js') !!} - {!! Theme::js('js/vendor/chartjs/chart.min.js') !!} - {!! Theme::js('js/vendor/jquery/jquery-dateFormat.min.js') !!} -@endsection - -@section('content') -
      - -
      -
      -
      -
      -
      -
      -
      - - -
      -
      -
      -
      -
      - @can('power-start', $server)@endcan - @can('power-restart', $server)@endcan - @can('power-stop', $server)@endcan - @can('power-kill', $server)@endcan - - -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - -
      -
      -
      -
      - -
      -
      -
      -
      -
      - @can('view-allocation', $server) -
      -
      -
      -
      -
      Below is a listing of all avaliable IPs and Ports for your service. To change the default connection address for your server, simply click on the one you would like to make default below.
      - - - - - - - - @foreach ($allocations as $allocation) - - - - - - - @endforeach -
      IP AddressAliasPort
      - {{ $allocation->ip }} - ip_alias))class="muted"@endif> - @if(is_null($allocation->ip_alias)) - none - @else - {{ $allocation->ip_alias }} - @endif - {{ $allocation->port }} - @if($allocation->id === $server->allocation) - Primary - @else - Make Primary - @endif -
      -
      -
      -
      - @endcan -
      -
      - -@if($server->a_serviceFile === 'minecraft') - {!! Theme::js('js/plugins/minecraft/eula.js') !!} -@endif - -@endsection diff --git a/resources/views/server/settings.blade.php b/resources/views/server/settings.blade.php deleted file mode 100644 index 4acead9e8..000000000 --- a/resources/views/server/settings.blade.php +++ /dev/null @@ -1,246 +0,0 @@ -{{-- 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.master') - -@section('title') - Server Settings -@endsection - -@section('content') -
      -

      Server Settings


      - -
      - @can('view-sftp', $server) -
      -
      -
      -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      -
      -
      - -
      -
      - @can('reset-sftp', $server) -
      - -
      - - - {!! csrf_field() !!} - - -
      -

      Passwords must meet the following requirements: at least one uppercase character, one lowercase character, one digit, and be at least 8 characters in length. Click here to generate one to use.

      -
      - @endcan -
      -
      - @can('view-sftp-password', $server) - -
      - -
      - @endcan -
      -
      -
      -
      -
      - @endcan - @can('view-startup', $server) -
      -
      -
      -
      -
      -
      -
      - -
      - {{ $service->executable }} - -
      -
      -
      -
      - @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 -
      -
      -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      - @endcan -
      -
      -
      - @endcan - @can('view-databases', $server) -
      -
      -
      -
      - @if(count($databases) > 0) - - - - - - - - - - - @foreach($databases as $database) - - - - - - - @endforeach - -
      DatabaseUsernamePasswordDB Server
      {{ $database->database }}{{ $database->username }}{{ Crypt::decrypt($database->password) }} @can('reset-db-password', $server)@endcan{{ $database->a_host }}:{{ $database->a_port }}
      - @else -
      - There are no databases configured for this server. - @if(Auth::user()->root_admin === 1) - Add a new database. - @endif -
      - @endif -
      -
      -
      - @endcan -
      -
      - -@endsection diff --git a/resources/views/server/tasks/index.blade.php b/resources/views/server/tasks/index.blade.php deleted file mode 100644 index 9c76dece8..000000000 --- a/resources/views/server/tasks/index.blade.php +++ /dev/null @@ -1,156 +0,0 @@ -{{-- 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.master') - -@section('title') - Scheduled Tasks -@endsection - -@section('content') -
      -

      Manage Scheduled Tasks


      - - - - - - - - @can('delete-task', $server)@endcan - @can('toggle-task', $server)@endcan - - - - @foreach($tasks as $task) - active === 0)class="text-disabled"@endif> - {{-- --}} - - - - - @can('delete-task', $server) - - @endcan - @can('toggle-task', $server) - - @endcan - - - @endforeach - -
      ActionDataLast RunNext Run
      {{ $actions[$task->action] }}{{ $actions[$task->action] }}{{ $task->data }}{{ Carbon::parse($task->last_run)->toDayDateTimeString() }}

      ({{ Carbon::parse($task->last_run)->diffForHumans() }})

      - @if($task->active !== 0) - {{ Carbon::parse($task->next_run)->toDayDateTimeString() }}

      ({{ Carbon::parse($task->next_run)->diffForHumans() }})

      - @else - n/a - @endif -
      - @can('create-task', $server) - - @endcan -
      - -@endsection diff --git a/resources/views/server/tasks/new.blade.php b/resources/views/server/tasks/new.blade.php deleted file mode 100644 index 230a8399f..000000000 --- a/resources/views/server/tasks/new.blade.php +++ /dev/null @@ -1,172 +0,0 @@ -{{-- 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.master') - -@section('title') - Scheduled Tasks -@endsection - -@section('content') -
      -

      Create Scheduled Task
      Current System Time: {{ Carbon::now()->toDayDateTimeString() }}


      -
      -
      You may use either the dropdown selection boxes or enter custom cron variables into the fields below.
      -
      -
      -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      -
      -
      -
      -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      -
      -
      -
      -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      -
      -
      -
      -
      -
      - -
      - -
      -
      -
      - -
      - -

      For example, if you selected Send Command enter the command here. If you selected Send Power Option put the power action here (e.g. restart).

      -
      -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      - -@endsection diff --git a/resources/views/server/tasks/view.blade.php b/resources/views/server/tasks/view.blade.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/resources/views/server/users/index.blade.php b/resources/views/server/users/index.blade.php deleted file mode 100644 index 96a1d40ff..000000000 --- a/resources/views/server/users/index.blade.php +++ /dev/null @@ -1,107 +0,0 @@ -{{-- 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.master') - -@section('title') - Viewing Subusers -@endsection - -@section('content') -
      -

      Manage Sub-Users


      - - - - - - @can('view-subuser', $server)@endcan - @can('delete-subuser', $server)@endcan - - - - @foreach($subusers as $user) - - - - @can('view-subuser', $server) - - @endcan - @can('delete-subuser', $server) - - @endcan - - @endforeach - -
      EmailCreated
      {{ $user->a_userEmail }}{{ $user->created_at }}
      - @can('create-subuser', $server) -
      -
      - -
      -
      - @endcan -
      - -@endsection diff --git a/resources/views/server/users/new.blade.php b/resources/views/server/users/new.blade.php deleted file mode 100644 index 1f1bca4e1..000000000 --- a/resources/views/server/users/new.blade.php +++ /dev/null @@ -1,301 +0,0 @@ -{{-- 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.master') - -@section('title') - Create New Subuser -@endsection - -@section('content') -
      -

      Create New Subuser
      - @can('edit-subuser', $server) -
      - @endcan - -
      -
      -
      - -
      - -
      -
      -
      -
      -
      -
      -

      Power Management


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

      File Management


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

      Subuser Management


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

      Server Management


      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -

      Database Management


      -
      -
      -
      -
      -
      -
      -

      SFTP Management


      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -

      Task Management


      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - @can('edit-subuser', $server) -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      - @endcan -

      - -@endsection diff --git a/resources/views/server/users/view.blade.php b/resources/views/server/users/view.blade.php deleted file mode 100644 index 9d76060b5..000000000 --- a/resources/views/server/users/view.blade.php +++ /dev/null @@ -1,290 +0,0 @@ -{{-- 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.master') - -@section('title') - Manage Subuser: {{ $subuser->a_userEmail }} -@endsection - -@section('content') -
      -

      Manage Subuser {{ $subuser->a_userEmail }}


      - @can('edit-subuser', $server) -
      - @endcan -
      -
      -

      Power Management


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

      File Management


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

      Subuser Management


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

      Server Management


      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -

      Database Management


      -
      -
      -
      -
      -
      -
      -

      SFTP Management


      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -

      Task Management


      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - @can('edit-subuser', $server) -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      - @endcan -
      - -@endsection From 355697dbb5db990b984bcddb0f97fea9d21db812 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 21 Jan 2017 15:56:32 -0500 Subject: [PATCH 146/599] Apply fixes from StyleCI (#260) --- app/Http/Controllers/Server/TaskController.php | 2 ++ app/Http/Middleware/AdminAuthenticate.php | 1 + app/Models/User.php | 5 +++-- resources/lang/en/base.php | 4 ++-- resources/lang/en/server.php | 4 ++-- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/Server/TaskController.php b/app/Http/Controllers/Server/TaskController.php index a5cd01512..fc81a95f0 100644 --- a/app/Http/Controllers/Server/TaskController.php +++ b/app/Http/Controllers/Server/TaskController.php @@ -73,6 +73,7 @@ class TaskController extends Controller 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), ]); + return view('server.tasks.new', [ 'server' => $server, 'node' => $node, @@ -89,6 +90,7 @@ class TaskController extends Controller $repo->create($server->id, $request->except([ '_token', ])); + return redirect()->route('server.tasks', $uuid); } catch (DisplayValidationException $ex) { return redirect()->route('server.tasks.new', $uuid)->withErrors(json_decode($ex->getMessage()))->withInput(); diff --git a/app/Http/Middleware/AdminAuthenticate.php b/app/Http/Middleware/AdminAuthenticate.php index 505d7c08c..56125b32a 100644 --- a/app/Http/Middleware/AdminAuthenticate.php +++ b/app/Http/Middleware/AdminAuthenticate.php @@ -71,6 +71,7 @@ class AdminAuthenticate // @TODO: eventually update admin themes Theme::set('default'); + return $next($request); } } diff --git a/app/Models/User.php b/app/Models/User.php index 384e06059..3d0998b35 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -150,9 +150,10 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac /** * Return true or false depending on wether the user is root admin or not. * - * @return boolean the user is root admin + * @return bool the user is root admin */ - public function isRootAdmin() { + public function isRootAdmin() + { return $this->root_admin === 1; } } diff --git a/resources/lang/en/base.php b/resources/lang/en/base.php index 392a23d1d..4891ff61b 100644 --- a/resources/lang/en/base.php +++ b/resources/lang/en/base.php @@ -32,11 +32,11 @@ return [ 'form_title' => 'Details', 'descriptive_memo' => [ 'title' => 'Descriptive Memo', - 'description' => 'Enter a brief description of what this API key will be used for.' + 'description' => 'Enter a brief description of what this API key will be used for.', ], 'allowed_ips' => [ 'title' => 'Allowed IPs', - 'description' => 'Enter a line delimitated list of IPs that are allowed to access the API using this key. CIDR notation is allowed. Leave blank to allow any IP.' + 'description' => 'Enter a line delimitated list of IPs that are allowed to access the API using this key. CIDR notation is allowed. Leave blank to allow any IP.', ], 'base' => [ 'title' => 'Base Information', diff --git a/resources/lang/en/server.php b/resources/lang/en/server.php index f629c52d3..05d42a71f 100644 --- a/resources/lang/en/server.php +++ b/resources/lang/en/server.php @@ -46,7 +46,7 @@ return [ 'update' => 'Update Subuser', 'edit' => [ 'header' => 'Edit Subuser', - 'header_sub' => 'Modify user\'s access to server.' + 'header_sub' => 'Modify user\'s access to server.', ], 'new' => [ 'header' => 'Add New User', @@ -255,7 +255,7 @@ return [ 'header_sub' => 'Control the IPs and ports available on this server.', 'available' => 'Available Allocations', 'help' => 'Allocation Help', - 'help_text' => 'The list to the left includes all available IPs and ports that are open for your server to use for incoming connections.' + 'help_text' => 'The list to the left includes all available IPs and ports that are open for your server to use for incoming connections.', ], ], ]; From 046e9152eb07ff64dbc96886294648f941028d66 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 21 Jan 2017 17:23:48 -0500 Subject: [PATCH 147/599] Update .phraseapp.yml --- .phraseapp.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.phraseapp.yml b/.phraseapp.yml index 2a6efe552..007c00ebb 100644 --- a/.phraseapp.yml +++ b/.phraseapp.yml @@ -9,18 +9,18 @@ phraseapp: - file: ./resources/lang//auth.php params: tag: "auth" - # - file: ./resources/lang//base.php - # params: - # tag: "base" + - file: ./resources/lang//base.php + params: + tag: "base" - file: ./resources/lang//pagination.php params: tag: "pagination" - file: ./resources/lang//passwords.php params: tag: "passwords" - # - file: ./resources/lang//server.php - # params: - # tag: "server" + - file: ./resources/lang//server.php + params: + tag: "server" - file: ./resources/lang//strings.php params: tag: "strings" From 9025f1f5833d75b667bf08e011fd4b61c91b8686 Mon Sep 17 00:00:00 2001 From: Emmet Young Date: Mon, 23 Jan 2017 00:47:09 +1100 Subject: [PATCH 148/599] Repair user creation functionality Repair functionality of the make user console command (pterodactyl:user) Fix up the user repository, was using the old $password instead of the changed format $data['password'] Change User model to allow root_admin to be a fillable item. --- app/Console/Commands/MakeUser.php | 16 +++++++++++----- app/Models/User.php | 2 +- app/Repositories/UserRepository.php | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/app/Console/Commands/MakeUser.php b/app/Console/Commands/MakeUser.php index f1992836b..2cd4bcf02 100644 --- a/app/Console/Commands/MakeUser.php +++ b/app/Console/Commands/MakeUser.php @@ -35,6 +35,9 @@ class MakeUser extends Command * @var string */ protected $signature = 'pterodactyl:user + {--firstname= : First name to use for this account.} + {--lastname= : Last name to use for this account.} + {--username= : Username to use for this account.} {--email= : Email address to use for this account.} {--password= : Password to assign to the user.} {--admin= : Boolean flag for if user should be an admin.}'; @@ -63,19 +66,22 @@ class MakeUser extends Command */ public function handle() { - $email = is_null($this->option('email')) ? $this->ask('Email') : $this->option('email'); - $password = is_null($this->option('password')) ? $this->secret('Password') : $this->option('password'); + $data['name_first'] = is_null($this->option('firstname')) ? $this->ask('First Name') : $this->option('firstname'); + $data['name_last'] = is_null($this->option('lastname')) ? $this->ask('Last Name') : $this->option('lastname'); + $data['username'] = is_null($this->option('username')) ? $this->ask('Username') : $this->option('username'); + $data['email'] = is_null($this->option('email')) ? $this->ask('Email') : $this->option('email'); + $data['password'] = is_null($this->option('password')) ? $this->secret('Password') : $this->option('password'); $password_confirmation = is_null($this->option('password')) ? $this->secret('Confirm Password') : $this->option('password'); - if ($password !== $password_confirmation) { + if ($data['password'] !== $password_confirmation) { return $this->error('The passwords provided did not match!'); } - $admin = is_null($this->option('admin')) ? $this->confirm('Is this user a root administrator?') : $this->option('admin'); + $data['root_admin'] = is_null($this->option('admin')) ? $this->confirm('Is this user a root administrator?') : $this->option('admin'); try { $user = new UserRepository; - $user->create($email, $password, $admin); + $user->create($data); return $this->info('User successfully created.'); } catch (\Exception $ex) { diff --git a/app/Models/User.php b/app/Models/User.php index 3d0998b35..88a9d9549 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -67,7 +67,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac * * @var [type] */ - protected $fillable = ['username', 'email', 'name_first', 'name_last', 'password', 'language', 'use_totp', 'totp_secret', 'gravatar']; + protected $fillable = ['username', 'email', 'name_first', 'name_last', 'password', 'language', 'use_totp', 'totp_secret', 'gravatar', 'root_admin']; /** * Cast values to correct type. diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index db715fbbc..7c3af08db 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -90,7 +90,7 @@ class UserRepository 'username' => $data['username'], 'name_first' => $data['name_first'], 'name_last' => $data['name_last'], - 'password' => Hash::make((empty($data['password'])) ? str_random(30) : $password), + 'password' => Hash::make((empty($data['password'])) ? str_random(30) : $data['password']), 'root_admin' => $data['root_admin'], 'language' => Settings::get('default_language', 'en'), ]); From 7654d3652a048d375f80357070ea4b9d99b04b57 Mon Sep 17 00:00:00 2001 From: Emmet Young Date: Mon, 23 Jan 2017 01:13:53 +1100 Subject: [PATCH 149/599] Only show admin control menu if the user is a root admin --- resources/themes/pterodactyl/layouts/master.blade.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index 2a548e36a..5abb74b90 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -62,7 +62,9 @@ {{-- ';return buildMenu}},{key:'rightClick',value:function rightClick(){var _this=this;$('[data-action="toggleMenu"]').on('mousedown',function(event){event.preventDefault();_this.showMenu(event)});$('#file_listing > tbody td').on('contextmenu',function(event){_this.showMenu(event)})}},{key:'showMenu',value:function showMenu(event){var _this2=this;var parent=$(event.target).closest('tr');var menu=$(this.makeMenu(parent));if(parent.data('type')==='disabled')return;event.preventDefault();$(menu).appendTo('body');$(menu).data('invokedOn',$(event.target)).show().css({position:'absolute',left:event.pageX-150,top:event.pageY});this.activeLine=parent;this.activeLine.addClass('active');var Actions=new ActionsClass(parent,menu);if(Pterodactyl.permissions.moveFiles){$(menu).find('li[data-action="move"]').unbind().on('click',function(e){e.preventDefault();Actions.move()});$(menu).find('li[data-action="rename"]').unbind().on('click',function(e){e.preventDefault();Actions.rename()})}if(Pterodactyl.permissions.copyFiles){$(menu).find('li[data-action="copy"]').unbind().on('click',function(e){e.preventDefault();Actions.copy()})}if(Pterodactyl.permissions.compressFiles){if(parent.data('type')==='folder'){$(menu).find('li[data-action="compress"]').removeClass('hidden')}$(menu).find('li[data-action="compress"]').unbind().on('click',function(e){e.preventDefault();Actions.compress()})}if(Pterodactyl.permissions.decompressFiles){if(_.without(['application/zip','application/gzip','application/x-gzip'],parent.data('mime')).length<3){$(menu).find('li[data-action="decompress"]').removeClass('hidden')}$(menu).find('li[data-action="decompress"]').unbind().on('click',function(e){e.preventDefault();Actions.decompress()})}if(Pterodactyl.permissions.createFiles){$(menu).find('li[data-action="folder"]').unbind().on('click',function(e){e.preventDefault();Actions.folder()})}if(Pterodactyl.permissions.downloadFiles){if(parent.data('type')==='file'){$(menu).find('li[data-action="download"]').removeClass('hidden')}$(menu).find('li[data-action="download"]').unbind().on('click',function(e){e.preventDefault();Actions.download()})}if(Pterodactyl.permissions.deleteFiles){$(menu).find('li[data-action="delete"]').unbind().on('click',function(e){e.preventDefault();Actions.delete()})}$(window).unbind().on('click',function(event){if($(event.target).is('.disable-menu-hide')){event.preventDefault();return}$(menu).unbind().remove();if(!_.isNull(_this2.activeLine))_this2.activeLine.removeClass('active')})}},{key:'directoryClick',value:function directoryClick(){$('a[data-action="directory-view"]').on('click',function(event){event.preventDefault();var path=$(this).parent().data('path')||'';var name=$(this).parent().data('name')||'';window.location.hash=encodeURIComponent(path+name);Files.list()})}}]);return ContextMenuClass}();window.ContextMenu=new ContextMenuClass; +'use strict';var _typeof=typeof Symbol==='function'&&typeof Symbol.iterator==='symbol'?function(obj){return typeof obj}:function(obj){return obj&&typeof Symbol==='function'&&obj.constructor===Symbol&&obj!==Symbol.prototype?'symbol':typeof obj};var _createClass=function(){function defineProperties(target,props){for(var i=0;i\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass ActionsClass {\n constructor(element, menu) {\n this.element = element;\n this.menu = menu;\n }\n\n destroy() {\n this.element = undefined;\n }\n\n folder() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n let inputValue = `${currentPath}${currentName}/`;\n if ($(this.element).data('type') === 'file') {\n inputValue = currentPath;\n }\n swal({\n type: 'input',\n title: 'Create Folder',\n text: 'Please enter the path and folder name below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: inputValue\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/folder`,\n timeout: 10000,\n data: JSON.stringify({\n path: val,\n }),\n }).done(data => {\n swal.close();\n Files.list();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n }\n\n move() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n swal({\n type: 'input',\n title: 'Move File',\n text: 'Please enter the new path for the file below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: `${currentPath}${currentName}`,\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/move`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${val}`,\n }),\n }).done(data => {\n nameBlock.parent().addClass('warning').delay(200).fadeOut();\n swal.close();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n\n }\n\n rename() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentLink = nameBlock.find('a');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const attachEditor = `\n \n \n `;\n\n nameBlock.html(attachEditor);\n const inputField = nameBlock.find('input');\n const inputLoader = nameBlock.find('.input-loader');\n\n inputField.focus();\n inputField.on('blur keydown', e => {\n // Save Field\n if (\n (e.type === 'keydown' && e.which === 27)\n || e.type === 'blur'\n || (e.type === 'keydown' && e.which === 13 && currentName === inputField.val())\n ) {\n if (!_.isEmpty(currentLink)) {\n nameBlock.html(currentLink);\n } else {\n nameBlock.html(currentName);\n }\n inputField.remove();\n ContextMenu.unbind().run();\n return;\n }\n\n if (e.type === 'keydown' && e.which !== 13) return;\n\n inputLoader.show();\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/rename`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${currentPath}${inputField.val()}`,\n }),\n }).done(data => {\n nameBlock.attr('data-name', inputField.val());\n if (!_.isEmpty(currentLink)) {\n let newLink = currentLink.attr('href');\n if (nameBlock.parent().data('type') !== 'folder') {\n newLink = newLink.substr(0, newLink.lastIndexOf('/')) + '/' + inputField.val();\n }\n currentLink.attr('href', newLink);\n nameBlock.html(\n currentLink.html(inputField.val())\n );\n } else {\n nameBlock.html(inputField.val());\n }\n inputField.remove();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n nameBlock.addClass('has-error').delay(2000).queue(() => {\n nameBlock.removeClass('has-error').dequeue();\n });\n inputField.popover({\n animation: true,\n placement: 'top',\n content: error,\n title: 'Save Error'\n }).popover('show');\n }).always(() => {\n inputLoader.remove();\n ContextMenu.unbind().run();\n });\n });\n }\n\n copy() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n swal({\n type: 'input',\n title: 'Copy File',\n text: 'Please enter the new path for the copied file below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: `${currentPath}${currentName}`,\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/copy`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${val}`,\n }),\n }).done(data => {\n swal({\n type: 'success',\n title: '',\n text: 'File successfully copied.'\n });\n Files.list();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n }\n\n download() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const fileName = decodeURIComponent(nameBlock.attr('data-name'));\n const filePath = decodeURIComponent(nameBlock.data('path'));\n\n window.location = `/server/${Pterodactyl.server.uuidShort}/files/download/${filePath}${fileName}`;\n }\n\n delete() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const delPath = decodeURIComponent(nameBlock.data('path'));\n const delName = decodeURIComponent(nameBlock.data('name'));\n\n swal({\n type: 'warning',\n title: '',\n text: 'Are you sure you want to delete ' + delName + '? There is no reversing this action.',\n html: true,\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true\n }, () => {\n $.ajax({\n type: 'DELETE',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/f/${delPath}${delName}`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n }\n }).done(data => {\n nameBlock.parent().addClass('warning').delay(200).fadeOut();\n swal({\n type: 'success',\n title: 'File Deleted'\n });\n }).fail(jqXHR => {\n console.error(jqXHR);\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: 'An error occured while attempting to delete this file. Please try again.',\n });\n });\n });\n }\n\n decompress() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const compPath = decodeURIComponent(nameBlock.data('path'));\n const compName = decodeURIComponent(nameBlock.data('name'));\n\n swal({\n title: ' Decompressing...',\n text: 'This might take a few seconds to complete.',\n html: true,\n allowOutsideClick: false,\n allowEscapeKey: false,\n showConfirmButton: false,\n });\n\n $.ajax({\n type: 'POST',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/decompress`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n data: JSON.stringify({\n files: `${compPath}${compName}`\n })\n }).done(data => {\n swal.close();\n Files.list(compPath);\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: error\n });\n });\n }\n\n compress() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const compPath = decodeURIComponent(nameBlock.data('path'));\n const compName = decodeURIComponent(nameBlock.data('name'));\n\n $.ajax({\n type: 'POST',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/compress`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n data: JSON.stringify({\n files: `${compPath}${compName}`,\n to: compPath.toString()\n })\n }).done(data => {\n Files.list(compPath, err => {\n if (err) return;\n const fileListing = $('#file_listing').find(`[data-name=\"${data.saved_as}\"]`).parent();\n fileListing.addClass('success pulsate').delay(3000).queue(() => {\n fileListing.removeClass('success pulsate').dequeue();\n });\n });\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: error\n });\n });\n }\n}\n","\"use strict\";\n\n// Copyright (c) 2015 - 2016 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass ContextMenuClass {\n constructor() {\n this.activeLine = null;\n }\n\n run() {\n this.directoryClick();\n this.rightClick();\n }\n\n makeMenu(parent) {\n $(document).find('#fileOptionMenu').remove();\n if (!_.isNull(this.activeLine)) this.activeLine.removeClass('active');\n\n let newFilePath = $('#headerTableRow').attr('data-currentDir');\n if (parent.data('type') === 'folder') {\n const nameBlock = parent.find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n newFilePath = `${currentPath}${currentName}`;\n }\n\n let buildMenu = '
        ';\n\n if (Pterodactyl.permissions.moveFiles) {\n buildMenu += '
      • Rename
      • \\\n
      • Move
      • ';\n }\n\n if (Pterodactyl.permissions.copyFiles) {\n buildMenu += '
      • Copy
      • ';\n }\n\n if (Pterodactyl.permissions.compressFiles) {\n buildMenu += '
      • Compress
      • ';\n }\n\n if (Pterodactyl.permissions.decompressFiles) {\n buildMenu += '
      • Decompress
      • ';\n }\n\n if (Pterodactyl.permissions.createFiles) {\n buildMenu += '
      • \\\n
      • New File
      • \\\n
      • New Folder
      • ';\n }\n\n if (Pterodactyl.permissions.downloadFiles || Pterodactyl.permissions.deleteFiles) {\n buildMenu += '
      • ';\n }\n\n if (Pterodactyl.permissions.downloadFiles) {\n buildMenu += '
      • Download
      • ';\n }\n\n if (Pterodactyl.permissions.deleteFiles) {\n buildMenu += '
      • Delete
      • ';\n }\n\n buildMenu += '
      ';\n return buildMenu;\n }\n\n rightClick() {\n $('[data-action=\"toggleMenu\"]').on('mousedown', event => {\n event.preventDefault();\n this.showMenu(event);\n });\n $('#file_listing > tbody td').on('contextmenu', event => {\n this.showMenu(event);\n });\n }\n\n showMenu(event) {\n const parent = $(event.target).closest('tr');\n const menu = $(this.makeMenu(parent));\n\n if (parent.data('type') === 'disabled') return;\n event.preventDefault();\n\n $(menu).appendTo('body');\n $(menu).data('invokedOn', $(event.target)).show().css({\n position: 'absolute',\n left: event.pageX - 150,\n top: event.pageY,\n });\n\n this.activeLine = parent;\n this.activeLine.addClass('active');\n\n // Handle Events\n const Actions = new ActionsClass(parent, menu);\n if (Pterodactyl.permissions.moveFiles) {\n $(menu).find('li[data-action=\"move\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.move();\n });\n $(menu).find('li[data-action=\"rename\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.rename();\n });\n }\n\n if (Pterodactyl.permissions.copyFiles) {\n $(menu).find('li[data-action=\"copy\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.copy();\n });\n }\n\n if (Pterodactyl.permissions.compressFiles) {\n if (parent.data('type') === 'folder') {\n $(menu).find('li[data-action=\"compress\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"compress\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.compress();\n });\n }\n\n if (Pterodactyl.permissions.decompressFiles) {\n if (_.without(['application/zip', 'application/gzip', 'application/x-gzip'], parent.data('mime')).length < 3) {\n $(menu).find('li[data-action=\"decompress\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"decompress\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.decompress();\n });\n }\n\n if (Pterodactyl.permissions.createFiles) {\n $(menu).find('li[data-action=\"folder\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.folder();\n });\n }\n\n if (Pterodactyl.permissions.downloadFiles) {\n if (parent.data('type') === 'file') {\n $(menu).find('li[data-action=\"download\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"download\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.download();\n });\n }\n\n if (Pterodactyl.permissions.deleteFiles) {\n $(menu).find('li[data-action=\"delete\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.delete();\n });\n }\n\n $(window).unbind().on('click', event => {\n if($(event.target).is('.disable-menu-hide')) {\n event.preventDefault();\n return;\n }\n $(menu).unbind().remove();\n if(!_.isNull(this.activeLine)) this.activeLine.removeClass('active');\n });\n }\n\n directoryClick() {\n $('a[data-action=\"directory-view\"]').on('click', function (event) {\n event.preventDefault();\n\n const path = $(this).parent().data('path') || '';\n const name = $(this).parent().data('name') || '';\n\n window.location.hash = encodeURIComponent(path + name);\n Files.list();\n });\n }\n}\n\nwindow.ContextMenu = new ContextMenuClass;\n","\"use strict\";\n\n// Copyright (c) 2015 - 2016 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass FileManager {\n constructor() {\n this.list(this.decodeHash());\n }\n\n list(path, next) {\n if (_.isUndefined(path)) {\n path = this.decodeHash();\n }\n\n this.loader(true);\n $.ajax({\n type: 'POST',\n url: Pterodactyl.meta.directoryList,\n headers: {\n 'X-CSRF-Token': Pterodactyl.meta.csrftoken,\n },\n data: {\n directory: path,\n },\n }).done(data => {\n this.loader(false);\n $('#load_files').slideUp(10).html(data).slideDown(10, () => {\n ContextMenu.run();\n this.reloadFilesButton();\n if (_.isFunction(next)) {\n return next();\n }\n });\n $('#internal_alert').slideUp();\n\n if (typeof Siofu === 'object') {\n Siofu.listenOnInput(document.getElementById(\"files_touch_target\"));\n }\n }).fail(jqXHR => {\n this.loader(false);\n if (_.isFunction(next)) {\n return next(new Error('Failed to load file listing.'));\n }\n swal({\n type: 'error',\n title: 'File Error',\n text: 'An error occured while attempting to process this request. Please try again.',\n });\n console.error(jqXHR);\n });\n }\n\n loader(show) {\n if (show){\n $('.file-overlay').fadeIn(100);\n } else {\n $('.file-overlay').fadeOut(100);\n }\n }\n\n reloadFilesButton() {\n $('i[data-action=\"reload-files\"]').unbind().on('click', () => {\n $('i[data-action=\"reload-files\"]').addClass('fa-spin');\n this.list();\n });\n }\n\n decodeHash() {\n return decodeURIComponent(window.location.hash.substring(1));\n }\n\n}\n\nwindow.Files = new FileManager;\n"]} \ No newline at end of file From bf7b58470a47af92b56965aeb6eb9642a2ed8070 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 24 Jan 2017 17:57:08 -0500 Subject: [PATCH 160/599] Update copyright headers --- LICENSE.md | 2 +- README.md | 2 +- app/Console/Commands/AddLocation.php | 2 +- app/Console/Commands/AddNode.php | 2 +- app/Console/Commands/CleanServiceBackup.php | 2 +- app/Console/Commands/ClearServices.php | 2 +- app/Console/Commands/ClearTasks.php | 2 +- app/Console/Commands/MakeUser.php | 2 +- app/Console/Commands/RunTasks.php | 2 +- app/Console/Commands/ShowVersion.php | 2 +- app/Console/Commands/UpdateEmailSettings.php | 2 +- app/Console/Commands/UpdateEnvironment.php | 2 +- app/Events/ServerDeleted.php | 2 +- app/Exceptions/AccountNotFoundException.php | 2 +- app/Exceptions/DisplayException.php | 2 +- app/Exceptions/DisplayValidationException.php | 2 +- app/Facades/Version.php | 2 +- app/Http/Controllers/API/BaseController.php | 2 +- app/Http/Controllers/API/LocationController.php | 2 +- app/Http/Controllers/API/NodeController.php | 2 +- app/Http/Controllers/API/ServerController.php | 2 +- app/Http/Controllers/API/ServiceController.php | 2 +- app/Http/Controllers/API/User/InfoController.php | 2 +- app/Http/Controllers/API/User/ServerController.php | 2 +- app/Http/Controllers/API/UserController.php | 2 +- app/Http/Controllers/Admin/BaseController.php | 2 +- app/Http/Controllers/Admin/DatabaseController.php | 2 +- app/Http/Controllers/Admin/LocationsController.php | 2 +- app/Http/Controllers/Admin/NodesController.php | 2 +- app/Http/Controllers/Admin/PackController.php | 2 +- app/Http/Controllers/Admin/ServersController.php | 2 +- app/Http/Controllers/Admin/ServiceController.php | 2 +- app/Http/Controllers/Admin/UserController.php | 2 +- app/Http/Controllers/Auth/LoginController.php | 2 +- app/Http/Controllers/Base/APIController.php | 2 +- app/Http/Controllers/Base/AccountController.php | 2 +- app/Http/Controllers/Base/IndexController.php | 2 +- app/Http/Controllers/Base/LanguageController.php | 2 +- app/Http/Controllers/Base/SecurityController.php | 2 +- app/Http/Controllers/Daemon/ServiceController.php | 2 +- app/Http/Controllers/Remote/RemoteController.php | 2 +- app/Http/Controllers/Server/AjaxController.php | 2 +- app/Http/Controllers/Server/ServerController.php | 2 +- app/Http/Controllers/Server/SubuserController.php | 2 +- app/Http/Controllers/Server/TaskController.php | 2 +- app/Http/Middleware/APISecretToken.php | 2 +- app/Http/Middleware/AdminAuthenticate.php | 2 +- app/Http/Middleware/CheckServer.php | 2 +- app/Http/Middleware/LanguageMiddleware.php | 2 +- app/Http/Routes/APIRoutes.php | 2 +- app/Http/Routes/AdminRoutes.php | 2 +- app/Http/Routes/AuthRoutes.php | 2 +- app/Http/Routes/BaseRoutes.php | 2 +- app/Http/Routes/DaemonRoutes.php | 2 +- app/Http/Routes/LanguageRoutes.php | 2 +- app/Http/Routes/RemoteRoutes.php | 2 +- app/Http/Routes/ServerRoutes.php | 2 +- app/Jobs/DeleteServer.php | 2 +- app/Jobs/SendScheduledTask.php | 2 +- app/Jobs/SuspendServer.php | 2 +- app/Listeners/DeleteServerListener.php | 2 +- app/Models/APIKey.php | 2 +- app/Models/APILog.php | 2 +- app/Models/APIPermission.php | 2 +- app/Models/Allocation.php | 2 +- app/Models/Checksum.php | 2 +- app/Models/Database.php | 2 +- app/Models/DatabaseServer.php | 2 +- app/Models/Download.php | 2 +- app/Models/Location.php | 2 +- app/Models/Node.php | 2 +- app/Models/NodeConfigurationToken.php | 2 +- app/Models/Permission.php | 2 +- app/Models/Server.php | 2 +- app/Models/ServerVariables.php | 2 +- app/Models/Service.php | 2 +- app/Models/ServiceOptions.php | 2 +- app/Models/ServicePack.php | 2 +- app/Models/ServiceVariables.php | 2 +- app/Models/Session.php | 2 +- app/Models/Subuser.php | 2 +- app/Models/Task.php | 2 +- app/Models/TaskLog.php | 2 +- app/Models/User.php | 2 +- app/Notifications/AccountCreated.php | 2 +- app/Notifications/SendPasswordReset.php | 2 +- app/Policies/ServerPolicy.php | 2 +- app/Repositories/APIRepository.php | 2 +- app/Repositories/Daemon/CommandRepository.php | 2 +- app/Repositories/Daemon/FileRepository.php | 2 +- app/Repositories/Daemon/PowerRepository.php | 2 +- app/Repositories/DatabaseRepository.php | 2 +- app/Repositories/HelperRepository.php | 2 +- app/Repositories/LocationRepository.php | 2 +- app/Repositories/NodeRepository.php | 2 +- app/Repositories/ServerRepository.php | 2 +- app/Repositories/ServiceRepository/Option.php | 2 +- app/Repositories/ServiceRepository/Pack.php | 2 +- app/Repositories/ServiceRepository/Service.php | 2 +- app/Repositories/ServiceRepository/Variable.php | 2 +- app/Repositories/SubuserRepository.php | 2 +- app/Repositories/TaskRepository.php | 2 +- app/Repositories/UserRepository.php | 2 +- app/Services/APILogService.php | 2 +- app/Services/DeploymentService.php | 2 +- app/Services/NotificationService.php | 2 +- app/Services/UuidService.php | 2 +- app/Services/VersionService.php | 2 +- app/Transformers/AllocationTransformer.php | 2 +- app/Transformers/NodeTransformer.php | 2 +- app/Transformers/ServerTransformer.php | 2 +- app/Transformers/UserTransformer.php | 2 +- database/seeds/MinecraftServiceTableSeeder.php | 2 +- database/seeds/SourceServiceTableSeeder.php | 2 +- database/seeds/TerrariaServiceTableSeeder.php | 2 +- database/seeds/VoiceServiceTableSeeder.php | 2 +- public/js/admin.min.js | 2 +- public/js/filemanager.min.js.map | 2 +- public/js/files/actions.js | 2 +- public/js/files/contextmenu.js | 2 +- public/js/files/index.js | 2 +- public/js/plugins/minecraft/eula.js | 2 +- public/themes/default/css/pterodactyl.css | 2 +- public/themes/pterodactyl/js/frontend/2fa-modal.js | 2 +- public/themes/pterodactyl/js/frontend/console.js | 2 +- public/themes/pterodactyl/js/frontend/files/editor.js | 2 +- .../themes/pterodactyl/js/frontend/files/filemanager.min.js.map | 2 +- public/themes/pterodactyl/js/frontend/files/src/actions.js | 2 +- public/themes/pterodactyl/js/frontend/files/src/contextmenu.js | 2 +- public/themes/pterodactyl/js/frontend/files/src/index.js | 2 +- public/themes/pterodactyl/js/frontend/files/upload.js | 2 +- public/themes/pterodactyl/js/frontend/server.socket.js | 2 +- public/themes/pterodactyl/js/frontend/serverlist.js | 2 +- public/themes/pterodactyl/js/frontend/tasks.js | 2 +- resources/themes/pterodactyl/auth/login.blade.php | 2 +- resources/themes/pterodactyl/auth/passwords/email.blade.php | 2 +- resources/themes/pterodactyl/auth/passwords/reset.blade.php | 2 +- resources/themes/pterodactyl/base/account.blade.php | 2 +- resources/themes/pterodactyl/base/api/index.blade.php | 2 +- resources/themes/pterodactyl/base/api/new.blade.php | 2 +- resources/themes/pterodactyl/base/index.blade.php | 2 +- resources/themes/pterodactyl/base/security.blade.php | 2 +- resources/themes/pterodactyl/errors/403.blade.php | 2 +- resources/themes/pterodactyl/errors/404.blade.php | 2 +- resources/themes/pterodactyl/layouts/auth.blade.php | 2 +- resources/themes/pterodactyl/layouts/error.blade.php | 2 +- resources/themes/pterodactyl/layouts/master.blade.php | 2 +- resources/themes/pterodactyl/server/files/add.blade.php | 2 +- resources/themes/pterodactyl/server/files/edit.blade.php | 2 +- resources/themes/pterodactyl/server/files/index.blade.php | 2 +- resources/themes/pterodactyl/server/files/list.blade.php | 2 +- resources/themes/pterodactyl/server/index.blade.php | 2 +- .../themes/pterodactyl/server/settings/allocation.blade.php | 2 +- .../themes/pterodactyl/server/settings/databases.blade.php | 2 +- resources/themes/pterodactyl/server/settings/sftp.blade.php | 2 +- resources/themes/pterodactyl/server/settings/startup.blade.php | 2 +- resources/themes/pterodactyl/server/tasks/index.blade.php | 2 +- resources/themes/pterodactyl/server/tasks/new.blade.php | 2 +- resources/themes/pterodactyl/server/users/index.blade.php | 2 +- resources/themes/pterodactyl/server/users/new.blade.php | 2 +- resources/themes/pterodactyl/server/users/view.blade.php | 2 +- resources/views/admin/databases/index.blade.php | 2 +- resources/views/admin/databases/new.blade.php | 2 +- resources/views/admin/index.blade.php | 2 +- resources/views/admin/locations/index.blade.php | 2 +- resources/views/admin/nodes/index.blade.php | 2 +- resources/views/admin/nodes/new.blade.php | 2 +- resources/views/admin/nodes/remote/deploy.blade.php | 2 +- resources/views/admin/nodes/view.blade.php | 2 +- resources/views/admin/servers/index.blade.php | 2 +- resources/views/admin/servers/new.blade.php | 2 +- resources/views/admin/servers/view.blade.php | 2 +- resources/views/admin/services/config.blade.php | 2 +- resources/views/admin/services/index.blade.php | 2 +- resources/views/admin/services/new.blade.php | 2 +- resources/views/admin/services/options/new.blade.php | 2 +- resources/views/admin/services/options/variable.blade.php | 2 +- resources/views/admin/services/options/view.blade.php | 2 +- resources/views/admin/services/packs/byoption.blade.php | 2 +- resources/views/admin/services/packs/byservice.blade.php | 2 +- resources/views/admin/services/packs/edit.blade.php | 2 +- resources/views/admin/services/packs/index.blade.php | 2 +- resources/views/admin/services/packs/new.blade.php | 2 +- resources/views/admin/services/view.blade.php | 2 +- resources/views/admin/settings.blade.php | 2 +- resources/views/admin/users/index.blade.php | 2 +- resources/views/admin/users/new.blade.php | 2 +- resources/views/admin/users/view.blade.php | 2 +- resources/views/emails/added-subuser.blade.php | 2 +- resources/views/emails/new-account.blade.php | 2 +- resources/views/emails/new_password.blade.php | 2 +- resources/views/errors/403.blade.php | 2 +- resources/views/errors/404.blade.php | 2 +- resources/views/errors/installing.blade.php | 2 +- resources/views/errors/suspended.blade.php | 2 +- resources/views/layouts/admin.blade.php | 2 +- storage/app/services/.templates/index.js | 2 +- storage/app/services/minecraft/index.js | 2 +- storage/app/services/srcds/index.js | 2 +- storage/app/services/terraria/index.js | 2 +- storage/app/services/voice/index.js | 2 +- 201 files changed, 201 insertions(+), 201 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index b4b61b7c2..929536020 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ # The MIT License (MIT) ``` -Copyright (c) 2015 - 2016 Dane Everitt +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 diff --git a/README.md b/README.md index a26d41468..30f0062b4 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Support for using Pterodactyl can be found on our [wiki](https://github.com/Pter ## License ``` -Copyright (c) 2015 - 2016 Dane Everitt +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 diff --git a/app/Console/Commands/AddLocation.php b/app/Console/Commands/AddLocation.php index e9fa8bed3..d9da92466 100644 --- a/app/Console/Commands/AddLocation.php +++ b/app/Console/Commands/AddLocation.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Console/Commands/AddNode.php b/app/Console/Commands/AddNode.php index d1f1c809c..4b4468422 100644 --- a/app/Console/Commands/AddNode.php +++ b/app/Console/Commands/AddNode.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Console/Commands/CleanServiceBackup.php b/app/Console/Commands/CleanServiceBackup.php index 93af785f4..0a6a3e272 100644 --- a/app/Console/Commands/CleanServiceBackup.php +++ b/app/Console/Commands/CleanServiceBackup.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Console/Commands/ClearServices.php b/app/Console/Commands/ClearServices.php index 803425185..db62d268c 100644 --- a/app/Console/Commands/ClearServices.php +++ b/app/Console/Commands/ClearServices.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Console/Commands/ClearTasks.php b/app/Console/Commands/ClearTasks.php index dde631f29..26f0da761 100644 --- a/app/Console/Commands/ClearTasks.php +++ b/app/Console/Commands/ClearTasks.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Console/Commands/MakeUser.php b/app/Console/Commands/MakeUser.php index 2cd4bcf02..05803dd3b 100644 --- a/app/Console/Commands/MakeUser.php +++ b/app/Console/Commands/MakeUser.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Console/Commands/RunTasks.php b/app/Console/Commands/RunTasks.php index d9e610973..7807f8dbd 100644 --- a/app/Console/Commands/RunTasks.php +++ b/app/Console/Commands/RunTasks.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Console/Commands/ShowVersion.php b/app/Console/Commands/ShowVersion.php index 357cdc1fe..199a905b1 100644 --- a/app/Console/Commands/ShowVersion.php +++ b/app/Console/Commands/ShowVersion.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Console/Commands/UpdateEmailSettings.php b/app/Console/Commands/UpdateEmailSettings.php index 54655ebc9..620982b98 100644 --- a/app/Console/Commands/UpdateEmailSettings.php +++ b/app/Console/Commands/UpdateEmailSettings.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Console/Commands/UpdateEnvironment.php b/app/Console/Commands/UpdateEnvironment.php index 0f1b01f10..085b081df 100644 --- a/app/Console/Commands/UpdateEnvironment.php +++ b/app/Console/Commands/UpdateEnvironment.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Events/ServerDeleted.php b/app/Events/ServerDeleted.php index 86770e9eb..95f8e33e1 100644 --- a/app/Events/ServerDeleted.php +++ b/app/Events/ServerDeleted.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Exceptions/AccountNotFoundException.php b/app/Exceptions/AccountNotFoundException.php index 160427b27..f8e36ed49 100644 --- a/app/Exceptions/AccountNotFoundException.php +++ b/app/Exceptions/AccountNotFoundException.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Exceptions/DisplayException.php b/app/Exceptions/DisplayException.php index 1c9869079..c1b701f36 100644 --- a/app/Exceptions/DisplayException.php +++ b/app/Exceptions/DisplayException.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Exceptions/DisplayValidationException.php b/app/Exceptions/DisplayValidationException.php index a172bfce4..3d8a4fda2 100644 --- a/app/Exceptions/DisplayValidationException.php +++ b/app/Exceptions/DisplayValidationException.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Facades/Version.php b/app/Facades/Version.php index f4aa8b116..2ce007360 100644 --- a/app/Facades/Version.php +++ b/app/Facades/Version.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/API/BaseController.php b/app/Http/Controllers/API/BaseController.php index 6a3822bad..085803a11 100755 --- a/app/Http/Controllers/API/BaseController.php +++ b/app/Http/Controllers/API/BaseController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/API/LocationController.php b/app/Http/Controllers/API/LocationController.php index 8b772151c..3bae975d8 100755 --- a/app/Http/Controllers/API/LocationController.php +++ b/app/Http/Controllers/API/LocationController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/API/NodeController.php b/app/Http/Controllers/API/NodeController.php index ce71a08da..0eda949f4 100755 --- a/app/Http/Controllers/API/NodeController.php +++ b/app/Http/Controllers/API/NodeController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/API/ServerController.php b/app/Http/Controllers/API/ServerController.php index ee56a3bad..b24cdac62 100755 --- a/app/Http/Controllers/API/ServerController.php +++ b/app/Http/Controllers/API/ServerController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/API/ServiceController.php b/app/Http/Controllers/API/ServiceController.php index 7f2bbe765..aa8b4ac29 100755 --- a/app/Http/Controllers/API/ServiceController.php +++ b/app/Http/Controllers/API/ServiceController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/API/User/InfoController.php b/app/Http/Controllers/API/User/InfoController.php index 326be99c6..00923b866 100644 --- a/app/Http/Controllers/API/User/InfoController.php +++ b/app/Http/Controllers/API/User/InfoController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/API/User/ServerController.php b/app/Http/Controllers/API/User/ServerController.php index 8f0e01956..c63a482fa 100644 --- a/app/Http/Controllers/API/User/ServerController.php +++ b/app/Http/Controllers/API/User/ServerController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/API/UserController.php b/app/Http/Controllers/API/UserController.php index c3a658a0e..a330ef61c 100755 --- a/app/Http/Controllers/API/UserController.php +++ b/app/Http/Controllers/API/UserController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/Admin/BaseController.php b/app/Http/Controllers/Admin/BaseController.php index 9eb273013..0f54a8ee6 100644 --- a/app/Http/Controllers/Admin/BaseController.php +++ b/app/Http/Controllers/Admin/BaseController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/Admin/DatabaseController.php b/app/Http/Controllers/Admin/DatabaseController.php index 33b4ff263..4a7fc3631 100644 --- a/app/Http/Controllers/Admin/DatabaseController.php +++ b/app/Http/Controllers/Admin/DatabaseController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/Admin/LocationsController.php b/app/Http/Controllers/Admin/LocationsController.php index 46544ebb6..889123b43 100644 --- a/app/Http/Controllers/Admin/LocationsController.php +++ b/app/Http/Controllers/Admin/LocationsController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index e7f53fa7f..594365f73 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php index fdf1b5a1a..abda49c8e 100644 --- a/app/Http/Controllers/Admin/PackController.php +++ b/app/Http/Controllers/Admin/PackController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 2dce69589..9aece9c4e 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/Admin/ServiceController.php b/app/Http/Controllers/Admin/ServiceController.php index 4e1b3b1b3..7a70c58da 100644 --- a/app/Http/Controllers/Admin/ServiceController.php +++ b/app/Http/Controllers/Admin/ServiceController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index dd73856c4..9a2c6fd04 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index d381fcdd4..9890077f1 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/app/Http/Controllers/Base/APIController.php b/app/Http/Controllers/Base/APIController.php index 46d0e013d..611638c95 100644 --- a/app/Http/Controllers/Base/APIController.php +++ b/app/Http/Controllers/Base/APIController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/app/Http/Controllers/Base/AccountController.php b/app/Http/Controllers/Base/AccountController.php index f5f0e406e..8db513bd5 100644 --- a/app/Http/Controllers/Base/AccountController.php +++ b/app/Http/Controllers/Base/AccountController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/app/Http/Controllers/Base/IndexController.php b/app/Http/Controllers/Base/IndexController.php index 8bdaddf63..160bc67e6 100644 --- a/app/Http/Controllers/Base/IndexController.php +++ b/app/Http/Controllers/Base/IndexController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/app/Http/Controllers/Base/LanguageController.php b/app/Http/Controllers/Base/LanguageController.php index 1051759ef..e4967ee5e 100644 --- a/app/Http/Controllers/Base/LanguageController.php +++ b/app/Http/Controllers/Base/LanguageController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/Base/SecurityController.php b/app/Http/Controllers/Base/SecurityController.php index a3f71612e..cf8bf2dc1 100644 --- a/app/Http/Controllers/Base/SecurityController.php +++ b/app/Http/Controllers/Base/SecurityController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/app/Http/Controllers/Daemon/ServiceController.php b/app/Http/Controllers/Daemon/ServiceController.php index 63c449f2d..e362f0d06 100644 --- a/app/Http/Controllers/Daemon/ServiceController.php +++ b/app/Http/Controllers/Daemon/ServiceController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/Remote/RemoteController.php b/app/Http/Controllers/Remote/RemoteController.php index 600e3d0d0..b0aa0983e 100644 --- a/app/Http/Controllers/Remote/RemoteController.php +++ b/app/Http/Controllers/Remote/RemoteController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/Server/AjaxController.php b/app/Http/Controllers/Server/AjaxController.php index c1cf51635..da4d058ac 100644 --- a/app/Http/Controllers/Server/AjaxController.php +++ b/app/Http/Controllers/Server/AjaxController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/Server/ServerController.php b/app/Http/Controllers/Server/ServerController.php index 209e59bbc..593049ca1 100644 --- a/app/Http/Controllers/Server/ServerController.php +++ b/app/Http/Controllers/Server/ServerController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/Server/SubuserController.php b/app/Http/Controllers/Server/SubuserController.php index b93d3d7fe..a8761c717 100644 --- a/app/Http/Controllers/Server/SubuserController.php +++ b/app/Http/Controllers/Server/SubuserController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Controllers/Server/TaskController.php b/app/Http/Controllers/Server/TaskController.php index fc81a95f0..8c49ad6bc 100644 --- a/app/Http/Controllers/Server/TaskController.php +++ b/app/Http/Controllers/Server/TaskController.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Middleware/APISecretToken.php b/app/Http/Middleware/APISecretToken.php index 04e033a99..a1c203c9d 100755 --- a/app/Http/Middleware/APISecretToken.php +++ b/app/Http/Middleware/APISecretToken.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Middleware/AdminAuthenticate.php b/app/Http/Middleware/AdminAuthenticate.php index 56125b32a..c0d74f262 100644 --- a/app/Http/Middleware/AdminAuthenticate.php +++ b/app/Http/Middleware/AdminAuthenticate.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Middleware/CheckServer.php b/app/Http/Middleware/CheckServer.php index 99ff35afd..cd83bd9d1 100644 --- a/app/Http/Middleware/CheckServer.php +++ b/app/Http/Middleware/CheckServer.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Middleware/LanguageMiddleware.php b/app/Http/Middleware/LanguageMiddleware.php index 1a4d6ff92..58426063f 100644 --- a/app/Http/Middleware/LanguageMiddleware.php +++ b/app/Http/Middleware/LanguageMiddleware.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Routes/APIRoutes.php b/app/Http/Routes/APIRoutes.php index b897ce1c3..a4fb84c60 100755 --- a/app/Http/Routes/APIRoutes.php +++ b/app/Http/Routes/APIRoutes.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index 731052238..e3a81cb66 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/app/Http/Routes/AuthRoutes.php b/app/Http/Routes/AuthRoutes.php index 6859893d1..491bebe41 100644 --- a/app/Http/Routes/AuthRoutes.php +++ b/app/Http/Routes/AuthRoutes.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/app/Http/Routes/BaseRoutes.php b/app/Http/Routes/BaseRoutes.php index 9c42cbd61..41bb93b53 100644 --- a/app/Http/Routes/BaseRoutes.php +++ b/app/Http/Routes/BaseRoutes.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/app/Http/Routes/DaemonRoutes.php b/app/Http/Routes/DaemonRoutes.php index ab8b733ab..b993e3759 100644 --- a/app/Http/Routes/DaemonRoutes.php +++ b/app/Http/Routes/DaemonRoutes.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Routes/LanguageRoutes.php b/app/Http/Routes/LanguageRoutes.php index 17fefd1d8..588711023 100644 --- a/app/Http/Routes/LanguageRoutes.php +++ b/app/Http/Routes/LanguageRoutes.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Routes/RemoteRoutes.php b/app/Http/Routes/RemoteRoutes.php index a42a611e9..ba8f47f9b 100644 --- a/app/Http/Routes/RemoteRoutes.php +++ b/app/Http/Routes/RemoteRoutes.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Http/Routes/ServerRoutes.php b/app/Http/Routes/ServerRoutes.php index dd65110ac..079bbf449 100644 --- a/app/Http/Routes/ServerRoutes.php +++ b/app/Http/Routes/ServerRoutes.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Jobs/DeleteServer.php b/app/Jobs/DeleteServer.php index ea1688625..a42637ff2 100644 --- a/app/Jobs/DeleteServer.php +++ b/app/Jobs/DeleteServer.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Jobs/SendScheduledTask.php b/app/Jobs/SendScheduledTask.php index fb155af19..dd7a56e27 100644 --- a/app/Jobs/SendScheduledTask.php +++ b/app/Jobs/SendScheduledTask.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Jobs/SuspendServer.php b/app/Jobs/SuspendServer.php index 752325b67..e4920f263 100644 --- a/app/Jobs/SuspendServer.php +++ b/app/Jobs/SuspendServer.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Listeners/DeleteServerListener.php b/app/Listeners/DeleteServerListener.php index c6f5b0183..616f4c141 100644 --- a/app/Listeners/DeleteServerListener.php +++ b/app/Listeners/DeleteServerListener.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/APIKey.php b/app/Models/APIKey.php index 3ba610a3f..4b94b6782 100644 --- a/app/Models/APIKey.php +++ b/app/Models/APIKey.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/APILog.php b/app/Models/APILog.php index 0e2a1a16d..5b481d8ff 100644 --- a/app/Models/APILog.php +++ b/app/Models/APILog.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/APIPermission.php b/app/Models/APIPermission.php index 415c41c5e..5bed095ff 100644 --- a/app/Models/APIPermission.php +++ b/app/Models/APIPermission.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/Allocation.php b/app/Models/Allocation.php index ce08da5d9..10308ebdd 100644 --- a/app/Models/Allocation.php +++ b/app/Models/Allocation.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/Checksum.php b/app/Models/Checksum.php index 5e775a59f..6db275624 100644 --- a/app/Models/Checksum.php +++ b/app/Models/Checksum.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/Database.php b/app/Models/Database.php index ed8049b85..99e768c29 100644 --- a/app/Models/Database.php +++ b/app/Models/Database.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/DatabaseServer.php b/app/Models/DatabaseServer.php index 38b8611d1..74fd88694 100644 --- a/app/Models/DatabaseServer.php +++ b/app/Models/DatabaseServer.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/Download.php b/app/Models/Download.php index 9adb8596c..d2c3dd885 100644 --- a/app/Models/Download.php +++ b/app/Models/Download.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/Location.php b/app/Models/Location.php index 7b8a2d5cc..5c8feb9fa 100644 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/Node.php b/app/Models/Node.php index 478a69076..5b82a2429 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/NodeConfigurationToken.php b/app/Models/NodeConfigurationToken.php index d7a309adc..dd029ec78 100644 --- a/app/Models/NodeConfigurationToken.php +++ b/app/Models/NodeConfigurationToken.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/Permission.php b/app/Models/Permission.php index 05c83fc9b..008473f3c 100644 --- a/app/Models/Permission.php +++ b/app/Models/Permission.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/Server.php b/app/Models/Server.php index a2f7d7382..b90d0c510 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/ServerVariables.php b/app/Models/ServerVariables.php index 8c11c8af5..c6c6970bc 100644 --- a/app/Models/ServerVariables.php +++ b/app/Models/ServerVariables.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/Service.php b/app/Models/Service.php index bd10ee884..8c0f27790 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/ServiceOptions.php b/app/Models/ServiceOptions.php index ca2c0fbc3..fe7e23f10 100644 --- a/app/Models/ServiceOptions.php +++ b/app/Models/ServiceOptions.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/ServicePack.php b/app/Models/ServicePack.php index 9b5256a3b..cefcc0a32 100644 --- a/app/Models/ServicePack.php +++ b/app/Models/ServicePack.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/ServiceVariables.php b/app/Models/ServiceVariables.php index b46690f54..5082d714e 100644 --- a/app/Models/ServiceVariables.php +++ b/app/Models/ServiceVariables.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/Session.php b/app/Models/Session.php index 9beef05ff..9af347bbe 100644 --- a/app/Models/Session.php +++ b/app/Models/Session.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/Subuser.php b/app/Models/Subuser.php index 798f54f79..8d4a5b133 100644 --- a/app/Models/Subuser.php +++ b/app/Models/Subuser.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/Task.php b/app/Models/Task.php index 63a326c4f..7f5e18182 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/TaskLog.php b/app/Models/TaskLog.php index a07937373..0ec947ae9 100644 --- a/app/Models/TaskLog.php +++ b/app/Models/TaskLog.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Models/User.php b/app/Models/User.php index 88a9d9549..8d1d7fb71 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Notifications/AccountCreated.php b/app/Notifications/AccountCreated.php index 8d0815b5e..55cfe416b 100644 --- a/app/Notifications/AccountCreated.php +++ b/app/Notifications/AccountCreated.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Notifications/SendPasswordReset.php b/app/Notifications/SendPasswordReset.php index 5b4301688..31939945e 100644 --- a/app/Notifications/SendPasswordReset.php +++ b/app/Notifications/SendPasswordReset.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php index 6c1a864ee..f297fe829 100644 --- a/app/Policies/ServerPolicy.php +++ b/app/Policies/ServerPolicy.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/APIRepository.php b/app/Repositories/APIRepository.php index bbe4aaca9..7ce94f34b 100644 --- a/app/Repositories/APIRepository.php +++ b/app/Repositories/APIRepository.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/Daemon/CommandRepository.php b/app/Repositories/Daemon/CommandRepository.php index 23c3755bc..5631518dc 100644 --- a/app/Repositories/Daemon/CommandRepository.php +++ b/app/Repositories/Daemon/CommandRepository.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/Daemon/FileRepository.php b/app/Repositories/Daemon/FileRepository.php index 3994eca2b..d1319cf91 100644 --- a/app/Repositories/Daemon/FileRepository.php +++ b/app/Repositories/Daemon/FileRepository.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/Daemon/PowerRepository.php b/app/Repositories/Daemon/PowerRepository.php index eb1b6a020..705ea3e82 100644 --- a/app/Repositories/Daemon/PowerRepository.php +++ b/app/Repositories/Daemon/PowerRepository.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/DatabaseRepository.php b/app/Repositories/DatabaseRepository.php index 075084281..1abf8e155 100644 --- a/app/Repositories/DatabaseRepository.php +++ b/app/Repositories/DatabaseRepository.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/HelperRepository.php b/app/Repositories/HelperRepository.php index add441da2..1e3248173 100644 --- a/app/Repositories/HelperRepository.php +++ b/app/Repositories/HelperRepository.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/LocationRepository.php b/app/Repositories/LocationRepository.php index 94cc246bb..79196ff35 100644 --- a/app/Repositories/LocationRepository.php +++ b/app/Repositories/LocationRepository.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/NodeRepository.php b/app/Repositories/NodeRepository.php index 021626e97..d55446196 100644 --- a/app/Repositories/NodeRepository.php +++ b/app/Repositories/NodeRepository.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 84bb8c225..88618a476 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/ServiceRepository/Option.php b/app/Repositories/ServiceRepository/Option.php index d6408d9ef..8ddcdc006 100644 --- a/app/Repositories/ServiceRepository/Option.php +++ b/app/Repositories/ServiceRepository/Option.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/ServiceRepository/Pack.php b/app/Repositories/ServiceRepository/Pack.php index 61327261f..ae68c1a6b 100644 --- a/app/Repositories/ServiceRepository/Pack.php +++ b/app/Repositories/ServiceRepository/Pack.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/ServiceRepository/Service.php b/app/Repositories/ServiceRepository/Service.php index becc290e6..eb41a9fee 100644 --- a/app/Repositories/ServiceRepository/Service.php +++ b/app/Repositories/ServiceRepository/Service.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/ServiceRepository/Variable.php b/app/Repositories/ServiceRepository/Variable.php index 4f95e5c3a..fbd258444 100644 --- a/app/Repositories/ServiceRepository/Variable.php +++ b/app/Repositories/ServiceRepository/Variable.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/SubuserRepository.php b/app/Repositories/SubuserRepository.php index a25c7f12e..afa27493e 100644 --- a/app/Repositories/SubuserRepository.php +++ b/app/Repositories/SubuserRepository.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/TaskRepository.php b/app/Repositories/TaskRepository.php index b285f65be..c42a00482 100644 --- a/app/Repositories/TaskRepository.php +++ b/app/Repositories/TaskRepository.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index 933db40cc..b46727e1b 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/app/Services/APILogService.php b/app/Services/APILogService.php index ee2bf3b00..f43693aca 100644 --- a/app/Services/APILogService.php +++ b/app/Services/APILogService.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Services/DeploymentService.php b/app/Services/DeploymentService.php index 207cacc94..5f2a99473 100644 --- a/app/Services/DeploymentService.php +++ b/app/Services/DeploymentService.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Services/NotificationService.php b/app/Services/NotificationService.php index 690945246..bb76db9b6 100644 --- a/app/Services/NotificationService.php +++ b/app/Services/NotificationService.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Services/UuidService.php b/app/Services/UuidService.php index 09bfde0d9..6f81f1465 100644 --- a/app/Services/UuidService.php +++ b/app/Services/UuidService.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Services/VersionService.php b/app/Services/VersionService.php index 135a04585..d12c77760 100644 --- a/app/Services/VersionService.php +++ b/app/Services/VersionService.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Transformers/AllocationTransformer.php b/app/Transformers/AllocationTransformer.php index 3a8ac43f7..8ca06a9c8 100644 --- a/app/Transformers/AllocationTransformer.php +++ b/app/Transformers/AllocationTransformer.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Transformers/NodeTransformer.php b/app/Transformers/NodeTransformer.php index a5ac61442..01d707f37 100755 --- a/app/Transformers/NodeTransformer.php +++ b/app/Transformers/NodeTransformer.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Transformers/ServerTransformer.php b/app/Transformers/ServerTransformer.php index a6ef28a1f..12707cd04 100755 --- a/app/Transformers/ServerTransformer.php +++ b/app/Transformers/ServerTransformer.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/app/Transformers/UserTransformer.php b/app/Transformers/UserTransformer.php index 14ef4bca3..c36baaa69 100755 --- a/app/Transformers/UserTransformer.php +++ b/app/Transformers/UserTransformer.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/database/seeds/MinecraftServiceTableSeeder.php b/database/seeds/MinecraftServiceTableSeeder.php index e0df5b36c..28f61343e 100644 --- a/database/seeds/MinecraftServiceTableSeeder.php +++ b/database/seeds/MinecraftServiceTableSeeder.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/database/seeds/SourceServiceTableSeeder.php b/database/seeds/SourceServiceTableSeeder.php index fc2ff640f..838814db8 100644 --- a/database/seeds/SourceServiceTableSeeder.php +++ b/database/seeds/SourceServiceTableSeeder.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/database/seeds/TerrariaServiceTableSeeder.php b/database/seeds/TerrariaServiceTableSeeder.php index 42a0bedce..bd3089ea2 100644 --- a/database/seeds/TerrariaServiceTableSeeder.php +++ b/database/seeds/TerrariaServiceTableSeeder.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/database/seeds/VoiceServiceTableSeeder.php b/database/seeds/VoiceServiceTableSeeder.php index 18876ef80..1fca3a475 100644 --- a/database/seeds/VoiceServiceTableSeeder.php +++ b/database/seeds/VoiceServiceTableSeeder.php @@ -1,7 +1,7 @@ . + * 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 diff --git a/public/js/admin.min.js b/public/js/admin.min.js index 54179cd27..b012c35d0 100755 --- a/public/js/admin.min.js +++ b/public/js/admin.min.js @@ -1,6 +1,6 @@ /** * Pterodactyl - Panel - * Copyright (c) 2015 - 2016 Dane Everitt + * 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 diff --git a/public/js/filemanager.min.js.map b/public/js/filemanager.min.js.map index 7f4e29816..9c35c1f6e 100644 --- a/public/js/filemanager.min.js.map +++ b/public/js/filemanager.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["files/actions.js","files/contextmenu.js","files/index.js"],"names":[],"mappings":"AAAA,a,8oBAqBM,a,YACF,sBAAY,OAAZ,CAAqB,IAArB,CAA2B,oCACvB,KAAK,OAAL,CAAe,OAAf,CACA,KAAK,IAAL,CAAY,IACf,C,kEAES,CACN,KAAK,OAAL,CAAe,SAClB,C,uCAEQ,CACL,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,GAAI,eAAgB,WAAhB,CAA8B,WAA9B,IAAJ,CACA,GAAI,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,MAArB,IAAiC,MAArC,CAA6C,CACzC,WAAa,WAChB,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,eAFN,CAGD,KAAM,8CAHL,CAID,iBAAkB,IAJjB,CAKD,kBAAmB,IALlB,CAMD,eAAgB,KANf,CAOD,oBAAqB,IAPpB,CAQD,WAAY,UARX,CAAL,CASG,SAAC,GAAD,CAAS,CACR,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,sBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,KAAM,GADW,CAAf,CATH,CAAP,EAYG,IAZH,CAYQ,cAAQ,CACZ,KAAK,KAAL,GACA,MAAM,IAAN,EACH,CAfD,EAeG,IAfH,CAeQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,EAFN,CAGD,KAAM,KAHL,CAAL,CAKH,CA1BD,CA2BH,CArCD,CAsCH,C,mCAEM,CACH,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,KAAK,CACD,KAAM,OADL,CAED,MAAO,WAFN,CAGD,KAAM,+CAHL,CAID,iBAAkB,IAJjB,CAKD,kBAAmB,IALlB,CAMD,eAAgB,KANf,CAOD,oBAAqB,IAPpB,CAQD,cAAe,WAAf,CAA6B,WAR5B,CAAL,CASG,SAAC,GAAD,CAAS,CACR,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,oBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,QAAS,WAAT,CAAuB,WADN,CAEjB,MAAO,GAFU,CAAf,CATH,CAAP,EAaG,IAbH,CAaQ,cAAQ,CACZ,UAAU,MAAV,GAAmB,QAAnB,CAA4B,SAA5B,EAAuC,KAAvC,CAA6C,GAA7C,EAAkD,OAAlD,GACA,KAAK,KAAL,EACH,CAhBD,EAgBG,IAhBH,CAgBQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,EAFN,CAGD,KAAM,KAHL,CAAL,CAKH,CA3BD,CA4BH,CAtCD,CAwCH,C,uCAEQ,CACL,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,UAAU,IAAV,CAAe,GAAf,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,uFACwD,WADxD,4GAAN,CAKA,UAAU,IAAV,CAAe,YAAf,EACA,GAAM,YAAa,UAAU,IAAV,CAAe,OAAf,CAAnB,CACA,GAAM,aAAc,UAAU,IAAV,CAAe,eAAf,CAApB,CAEA,WAAW,KAAX,GACA,WAAW,EAAX,CAAc,cAAd,CAA8B,WAAK,CAE/B,GACK,EAAE,IAAF,GAAW,SAAX,EAAwB,EAAE,KAAF,GAAY,EAArC,EACG,EAAE,IAAF,GAAW,MADd,EAEI,EAAE,IAAF,GAAW,SAAX,EAAwB,EAAE,KAAF,GAAY,EAApC,EAA0C,cAAgB,WAAW,GAAX,EAHlE,CAIE,CACE,GAAI,CAAC,EAAE,OAAF,CAAU,WAAV,CAAL,CAA6B,CACzB,UAAU,IAAV,CAAe,WAAf,CACH,CAFD,IAEO,CACH,UAAU,IAAV,CAAe,WAAf,CACH,CACD,WAAW,MAAX,GACA,YAAY,MAAZ,GAAqB,GAArB,GACA,MACH,CAED,GAAI,EAAE,IAAF,GAAW,SAAX,EAAwB,EAAE,KAAF,GAAY,EAAxC,CAA4C,OAE5C,YAAY,IAAZ,GACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,sBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,QAAS,WAAT,CAAuB,WADN,CAEjB,MAAO,WAAP,CAAqB,WAAW,GAAX,EAFJ,CAAf,CATH,CAAP,EAaG,IAbH,CAaQ,cAAQ,CACZ,UAAU,IAAV,CAAe,WAAf,CAA4B,WAAW,GAAX,EAA5B,EACA,GAAI,CAAC,EAAE,OAAF,CAAU,WAAV,CAAL,CAA6B,CACzB,GAAI,SAAU,YAAY,IAAZ,CAAiB,MAAjB,CAAd,CACA,GAAI,UAAU,MAAV,GAAmB,IAAnB,CAAwB,MAAxB,IAAoC,QAAxC,CAAkD,CAC9C,QAAU,QAAQ,MAAR,CAAe,CAAf,CAAkB,QAAQ,WAAR,CAAoB,GAApB,CAAlB,EAA8C,GAA9C,CAAoD,WAAW,GAAX,EACjE,CACD,YAAY,IAAZ,CAAiB,MAAjB,CAAyB,OAAzB,EACA,UAAU,IAAV,CACI,YAAY,IAAZ,CAAiB,WAAW,GAAX,EAAjB,CADJ,CAGH,CATD,IASO,CACH,UAAU,IAAV,CAAe,WAAW,GAAX,EAAf,CACH,CACD,WAAW,MAAX,EACH,CA5BD,EA4BG,IA5BH,CA4BQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,UAAU,QAAV,CAAmB,WAAnB,EAAgC,KAAhC,CAAsC,IAAtC,EAA4C,KAA5C,CAAkD,UAAM,CACpD,UAAU,WAAV,CAAsB,WAAtB,EAAmC,OAAnC,EACH,CAFD,EAGA,WAAW,OAAX,CAAmB,CACf,UAAW,IADI,CAEf,UAAW,KAFI,CAGf,QAAS,KAHM,CAIf,MAAO,YAJQ,CAAnB,EAKG,OALH,CAKW,MALX,CAMH,CA3CD,EA2CG,MA3CH,CA2CU,UAAM,CACZ,YAAY,MAAZ,GACA,YAAY,MAAZ,GAAqB,GAArB,EACH,CA9CD,CA+CH,CArED,CAsEH,C,mCAEM,CACH,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,KAAK,CACD,KAAM,OADL,CAED,MAAO,WAFN,CAGD,KAAM,sDAHL,CAID,iBAAkB,IAJjB,CAKD,kBAAmB,IALlB,CAMD,eAAgB,KANf,CAOD,oBAAqB,IAPpB,CAQD,cAAe,WAAf,CAA6B,WAR5B,CAAL,CASG,SAAC,GAAD,CAAS,CACR,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,oBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,QAAS,WAAT,CAAuB,WADN,CAEjB,MAAO,GAFU,CAAf,CATH,CAAP,EAaG,IAbH,CAaQ,cAAQ,CACZ,KAAK,CACD,KAAM,SADL,CAED,MAAO,EAFN,CAGD,KAAM,2BAHL,CAAL,EAKA,MAAM,IAAN,EACH,CApBD,EAoBG,IApBH,CAoBQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,EAFN,CAGD,KAAM,KAHL,CAAL,CAKH,CA/BD,CAgCH,CA1CD,CA2CH,C,2CAEU,CACP,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAAjB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CAEA,OAAO,QAAP,YAA6B,YAAY,MAAZ,CAAmB,SAAhD,oBAA4E,QAA5E,CAAuF,QAC1F,C,wCAEQ,CACL,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,SAAU,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAhB,CACA,GAAM,SAAU,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAhB,CAEA,KAAK,CACD,KAAM,SADL,CAED,MAAO,EAFN,CAGD,KAAM,yCAA2C,OAA3C,CAAqD,8DAH1D,CAID,KAAM,IAJL,CAKD,iBAAkB,IALjB,CAMD,kBAAmB,IANlB,CAOD,eAAgB,KAPf,CAQD,oBAAqB,IARpB,CAAL,CASG,UAAM,CACL,EAAE,IAAF,CAAO,CACH,KAAM,QADH,CAEH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,mBAA6G,OAA7G,CAAuH,OAFpH,CAGH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAHN,CAAP,EAOG,IAPH,CAOQ,cAAQ,CACZ,UAAU,MAAV,GAAmB,QAAnB,CAA4B,SAA5B,EAAuC,KAAvC,CAA6C,GAA7C,EAAkD,OAAlD,GACA,KAAK,CACD,KAAM,SADL,CAED,MAAO,cAFN,CAAL,CAIH,CAbD,EAaG,IAbH,CAaQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,KAAK,CACD,KAAM,OADL,CAED,MAAO,SAFN,CAGD,KAAM,IAHL,CAID,KAAM,0EAJL,CAAL,CAMH,CArBD,CAsBH,CAhCD,CAiCH,C,+CAEY,CACT,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CAEA,KAAK,CACD,MAAO,wDADN,CAED,KAAM,4CAFL,CAGD,KAAM,IAHL,CAID,kBAAmB,KAJlB,CAKD,eAAgB,KALf,CAMD,kBAAmB,KANlB,CAAL,EASA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,0BAFG,CAGH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAHN,CAOH,YAAa,iCAPV,CAQH,KAAM,KAAK,SAAL,CAAe,CACjB,SAAU,QAAV,CAAqB,QADJ,CAAf,CARH,CAAP,EAWG,IAXH,CAWQ,cAAQ,CACZ,KAAK,KAAL,GACA,MAAM,IAAN,CAAW,QAAX,CACH,CAdD,EAcG,IAdH,CAcQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,SAFN,CAGD,KAAM,IAHL,CAID,KAAM,KAJL,CAAL,CAMH,CA1BD,CA2BH,C,2CAEU,CACP,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CAEA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,wBAFG,CAGH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAHN,CAOH,YAAa,iCAPV,CAQH,KAAM,KAAK,SAAL,CAAe,CACjB,SAAU,QAAV,CAAqB,QADJ,CAEjB,GAAI,SAAS,QAAT,EAFa,CAAf,CARH,CAAP,EAYG,IAZH,CAYQ,cAAQ,CACZ,MAAM,IAAN,CAAW,QAAX,CAAqB,aAAO,CACxB,GAAI,GAAJ,CAAS,OACT,GAAM,aAAc,EAAE,eAAF,EAAmB,IAAnB,gBAAuC,KAAK,QAA5C,OAA0D,MAA1D,EAApB,CACA,YAAY,QAAZ,CAAqB,iBAArB,EAAwC,KAAxC,CAA8C,IAA9C,EAAoD,KAApD,CAA0D,UAAM,CAC5D,YAAY,WAAZ,CAAwB,iBAAxB,EAA2C,OAA3C,EACH,CAFD,CAGH,CAND,CAOH,CApBD,EAoBG,IApBH,CAoBQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,SAFN,CAGD,KAAM,IAHL,CAID,KAAM,KAJL,CAAL,CAMH,CAhCD,CAiCH,C;;ACxYL,a,8oBAqBM,iB,YACF,2BAAc,wCACV,KAAK,UAAL,CAAkB,IACrB,C,8DAEK,CACF,KAAK,cAAL,GACA,KAAK,UAAL,EACH,C,0CAEQ,M,CAAQ,CACb,EAAE,QAAF,EAAY,IAAZ,CAAiB,iBAAjB,EAAoC,MAApC,GACA,GAAI,CAAC,EAAE,MAAF,CAAS,KAAK,UAAd,CAAL,CAAgC,KAAK,UAAL,CAAgB,WAAhB,CAA4B,QAA5B,EAEhC,GAAI,aAAc,EAAE,iBAAF,EAAqB,IAArB,CAA0B,iBAA1B,CAAlB,CACA,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,QAA5B,CAAsC,CAClC,GAAM,WAAY,OAAO,IAAP,CAAY,4BAAZ,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CACA,eAAiB,WAAjB,CAA+B,WAClC,CAED,GAAI,WAAY,kFAAhB,CAEA,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,WAAa,iPAEhB,CAED,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,WAAa,kGAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,WAAa,kIAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,eAA5B,CAA6C,CACzC,WAAa,8HAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,WAAa,+FAC4C,YAAY,MAAZ,CAAmB,SAD/D,CAC0E,kBAD1E,CAC+F,WAD/F,CAC6G,6MAE7H,CAED,GAAI,YAAY,WAAZ,CAAwB,aAAxB,EAAyC,YAAY,WAAZ,CAAwB,WAArE,CAAkF,CAC9E,WAAa,2BAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,WAAa,4HAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,WAAa,0HAChB,CAED,WAAa,OAAb,CACA,MAAO,UACV,C,+CAEY,gBACT,EAAE,4BAAF,EAAgC,EAAhC,CAAmC,WAAnC,CAAgD,UAAM,CAClD,MAAM,cAAN,GACA,MAAK,QAAL,CAAc,KAAd,CACH,CAHD,EAIA,EAAE,0BAAF,EAA8B,EAA9B,CAAiC,aAAjC,CAAgD,eAAS,CACrD,MAAK,QAAL,CAAc,KAAd,CACH,CAFD,CAGH,C,0CAEQ,K,CAAO,iBACZ,GAAM,QAAS,EAAE,MAAM,MAAR,EAAgB,OAAhB,CAAwB,IAAxB,CAAf,CACA,GAAM,MAAO,EAAE,KAAK,QAAL,CAAc,MAAd,CAAF,CAAb,CAEA,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,UAA5B,CAAwC,OACxC,MAAM,cAAN,GAEA,EAAE,IAAF,EAAQ,QAAR,CAAiB,MAAjB,EACA,EAAE,IAAF,EAAQ,IAAR,CAAa,WAAb,CAA0B,EAAE,MAAM,MAAR,CAA1B,EAA2C,IAA3C,GAAkD,GAAlD,CAAsD,CAClD,SAAU,UADwC,CAElD,KAAM,MAAM,KAAN,CAAc,GAF8B,CAGlD,IAAK,MAAM,KAHuC,CAAtD,EAMA,KAAK,UAAL,CAAkB,MAAlB,CACA,KAAK,UAAL,CAAgB,QAAhB,CAAyB,QAAzB,EAGA,GAAM,SAAU,GAAI,aAAJ,CAAiB,MAAjB,CAAyB,IAAzB,CAAhB,CACA,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,EAAE,IAAF,EAAQ,IAAR,CAAa,wBAAb,EAAuC,MAAvC,GAAgD,EAAhD,CAAmD,OAAnD,CAA4D,WAAK,CAC7D,EAAE,cAAF,GACA,QAAQ,IAAR,EACH,CAHD,EAIA,EAAE,IAAF,EAAQ,IAAR,CAAa,0BAAb,EAAyC,MAAzC,GAAkD,EAAlD,CAAqD,OAArD,CAA8D,WAAK,CAC/D,EAAE,cAAF,GACA,QAAQ,MAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,EAAE,IAAF,EAAQ,IAAR,CAAa,wBAAb,EAAuC,MAAvC,GAAgD,EAAhD,CAAmD,OAAnD,CAA4D,WAAK,CAC7D,EAAE,cAAF,GACA,QAAQ,IAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,QAA5B,CAAsC,CAClC,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,WAA3C,CAAuD,QAAvD,CACH,CACD,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,MAA3C,GAAoD,EAApD,CAAuD,OAAvD,CAAgE,WAAK,CACjE,EAAE,cAAF,GACA,QAAQ,QAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,eAA5B,CAA6C,CACzC,GAAI,EAAE,OAAF,CAAU,CAAC,iBAAD,CAAoB,kBAApB,CAAwC,oBAAxC,CAAV,CAAyE,OAAO,IAAP,CAAY,MAAZ,CAAzE,EAA8F,MAA9F,CAAuG,CAA3G,CAA8G,CAC1G,EAAE,IAAF,EAAQ,IAAR,CAAa,8BAAb,EAA6C,WAA7C,CAAyD,QAAzD,CACH,CACD,EAAE,IAAF,EAAQ,IAAR,CAAa,8BAAb,EAA6C,MAA7C,GAAsD,EAAtD,CAAyD,OAAzD,CAAkE,WAAK,CACnE,EAAE,cAAF,GACA,QAAQ,UAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,EAAE,IAAF,EAAQ,IAAR,CAAa,0BAAb,EAAyC,MAAzC,GAAkD,EAAlD,CAAqD,OAArD,CAA8D,WAAK,CAC/D,EAAE,cAAF,GACA,QAAQ,MAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,MAA5B,CAAoC,CAChC,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,WAA3C,CAAuD,QAAvD,CACH,CACD,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,MAA3C,GAAoD,EAApD,CAAuD,OAAvD,CAAgE,WAAK,CACjE,EAAE,cAAF,GACA,QAAQ,QAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,EAAE,IAAF,EAAQ,IAAR,CAAa,0BAAb,EAAyC,MAAzC,GAAkD,EAAlD,CAAqD,OAArD,CAA8D,WAAK,CAC/D,EAAE,cAAF,GACA,QAAQ,MAAR,EACH,CAHD,CAIH,CAED,EAAE,MAAF,EAAU,EAAV,CAAa,OAAb,CAAsB,UAAM,CACxB,EAAE,IAAF,EAAQ,MAAR,GACA,GAAG,CAAC,EAAE,MAAF,CAAS,OAAK,UAAd,CAAJ,CAA+B,OAAK,UAAL,CAAgB,WAAhB,CAA4B,QAA5B,CAClC,CAHD,CAIH,C,uDAEgB,CACb,EAAE,iCAAF,EAAqC,EAArC,CAAwC,OAAxC,CAAiD,SAAU,KAAV,CAAiB,CAC9D,MAAM,cAAN,GAEA,GAAM,MAAO,EAAE,IAAF,EAAQ,MAAR,GAAiB,IAAjB,CAAsB,MAAtB,GAAiC,EAA9C,CACA,GAAM,MAAO,EAAE,IAAF,EAAQ,MAAR,GAAiB,IAAjB,CAAsB,MAAtB,GAAiC,EAA9C,CAEA,OAAO,QAAP,CAAgB,IAAhB,CAAuB,mBAAmB,KAAO,IAA1B,CAAvB,CACA,MAAM,IAAN,EACH,CARD,CASH,C,+BAGL,OAAO,WAAP,CAAqB,GAAI,iBAAzB;AClMA,a,8oBAqBM,Y,YACF,sBAAc,mCACV,KAAK,IAAL,CAAU,KAAK,UAAL,EAAV,CACH,C,0DAEI,I,CAAM,I,CAAM,gBACb,GAAI,EAAE,WAAF,CAAc,IAAd,CAAJ,CAAyB,CACrB,KAAO,KAAK,UAAL,EACV,CAED,KAAK,MAAL,CAAY,IAAZ,EACA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,IAAK,YAAY,IAAZ,CAAiB,aAFnB,CAGH,QAAS,CACL,eAAgB,YAAY,IAAZ,CAAiB,SAD5B,CAHN,CAMH,KAAM,CACF,UAAW,IADT,CANH,CAAP,EASG,IATH,CASQ,cAAQ,CACZ,MAAK,MAAL,CAAY,KAAZ,EACA,EAAE,aAAF,EAAiB,OAAjB,GAA2B,IAA3B,CAAgC,IAAhC,EAAsC,SAAtC,CAAgD,GAAhD,CAAqD,UAAM,CACvD,YAAY,GAAZ,GACA,MAAK,iBAAL,GACA,GAAI,EAAE,UAAF,CAAa,IAAb,CAAJ,CAAwB,CACpB,MAAO,OACV,CACJ,CAND,EAOA,EAAE,iBAAF,EAAqB,OAArB,EACH,CAnBD,EAmBG,IAnBH,CAmBQ,eAAS,CACb,MAAK,MAAL,CAAY,KAAZ,EACA,GAAI,EAAE,UAAF,CAAa,IAAb,CAAJ,CAAwB,CACpB,MAAO,MAAK,GAAI,MAAJ,CAAU,8BAAV,CAAL,CACV,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,YAFN,CAGD,KAAM,8EAHL,CAAL,EAKA,QAAQ,GAAR,CAAY,KAAZ,CACH,CA9BD,CA+BH,C,sCAEM,I,CAAM,CACT,GAAI,EAAE,aAAF,EAAiB,MAAjB,GAA4B,CAAhC,CAAmC,OAEnC,GAAI,OAAS,IAAb,CAAkB,CACd,GAAI,QAAS,EAAE,aAAF,EAAiB,MAAjB,EAAb,CACA,GAAI,OAAQ,EAAE,mBAAF,EAAuB,KAAvB,EAAZ,CACA,GAAI,eAAiB,OAAS,CAAV,CAAe,EAAnC,CACA,GAAI,cAAgB,MAAQ,CAAT,CAAc,EAAjC,CAEA,EAAE,cAAF,EAAkB,GAAlB,CAAsB,CAClB,MAAO,aADW,CAElB,OAAQ,YAFU,CAGlB,YAAa,MAHK,CAAtB,EAMA,EAAE,mBAAF,EAAuB,GAAvB,CAA2B,QAA3B,CAAsC,OAAS,CAA/C,EAAmD,IAAnD,EACH,CAbD,IAaO,CACH,EAAE,mBAAF,EAAuB,IAAvB,EACH,CACJ,C,6DAEmB,iBAChB,EAAE,+BAAF,EAAmC,MAAnC,GAA4C,EAA5C,CAA+C,OAA/C,CAAwD,UAAM,CAC1D,EAAE,+BAAF,EAAmC,QAAnC,CAA4C,SAA5C,EACA,OAAK,IAAL,EACH,CAHD,CAIH,C,+CAEY,CACT,MAAO,oBAAmB,OAAO,QAAP,CAAgB,IAAhB,CAAqB,SAArB,CAA+B,CAA/B,CAAnB,CACV,C,0BAIL,OAAO,KAAP,CAAe,GAAI,YAAnB","file":"filemanager.min.js","sourcesContent":["\"use strict\";\n\n// Copyright (c) 2015 - 2016 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass ActionsClass {\n constructor(element, menu) {\n this.element = element;\n this.menu = menu;\n }\n\n destroy() {\n this.element = undefined;\n }\n\n folder() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n let inputValue = `${currentPath}${currentName}/`;\n if ($(this.element).data('type') === 'file') {\n inputValue = currentPath;\n }\n swal({\n type: 'input',\n title: 'Create Folder',\n text: 'Please enter the path and folder name below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: inputValue\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/folder`,\n timeout: 10000,\n data: JSON.stringify({\n path: val,\n }),\n }).done(data => {\n swal.close();\n Files.list();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n }\n\n move() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n swal({\n type: 'input',\n title: 'Move File',\n text: 'Please enter the new path for the file below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: `${currentPath}${currentName}`,\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/move`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${val}`,\n }),\n }).done(data => {\n nameBlock.parent().addClass('warning').delay(200).fadeOut();\n swal.close();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n\n }\n\n rename() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentLink = nameBlock.find('a');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const attachEditor = `\n \n \n `;\n\n nameBlock.html(attachEditor);\n const inputField = nameBlock.find('input');\n const inputLoader = nameBlock.find('.input-loader');\n\n inputField.focus();\n inputField.on('blur keydown', e => {\n // Save Field\n if (\n (e.type === 'keydown' && e.which === 27)\n || e.type === 'blur'\n || (e.type === 'keydown' && e.which === 13 && currentName === inputField.val())\n ) {\n if (!_.isEmpty(currentLink)) {\n nameBlock.html(currentLink);\n } else {\n nameBlock.html(currentName);\n }\n inputField.remove();\n ContextMenu.unbind().run();\n return;\n }\n\n if (e.type === 'keydown' && e.which !== 13) return;\n\n inputLoader.show();\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/rename`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${currentPath}${inputField.val()}`,\n }),\n }).done(data => {\n nameBlock.attr('data-name', inputField.val());\n if (!_.isEmpty(currentLink)) {\n let newLink = currentLink.attr('href');\n if (nameBlock.parent().data('type') !== 'folder') {\n newLink = newLink.substr(0, newLink.lastIndexOf('/')) + '/' + inputField.val();\n }\n currentLink.attr('href', newLink);\n nameBlock.html(\n currentLink.html(inputField.val())\n );\n } else {\n nameBlock.html(inputField.val());\n }\n inputField.remove();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n nameBlock.addClass('has-error').delay(2000).queue(() => {\n nameBlock.removeClass('has-error').dequeue();\n });\n inputField.popover({\n animation: true,\n placement: 'top',\n content: error,\n title: 'Save Error'\n }).popover('show');\n }).always(() => {\n inputLoader.remove();\n ContextMenu.unbind().run();\n });\n });\n }\n\n copy() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n swal({\n type: 'input',\n title: 'Copy File',\n text: 'Please enter the new path for the copied file below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: `${currentPath}${currentName}`,\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/copy`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${val}`,\n }),\n }).done(data => {\n swal({\n type: 'success',\n title: '',\n text: 'File successfully copied.'\n });\n Files.list();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n }\n\n download() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const fileName = decodeURIComponent(nameBlock.attr('data-name'));\n const filePath = decodeURIComponent(nameBlock.data('path'));\n\n window.location = `/server/${Pterodactyl.server.uuidShort}/files/download/${filePath}${fileName}`;\n }\n\n delete() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const delPath = decodeURIComponent(nameBlock.data('path'));\n const delName = decodeURIComponent(nameBlock.data('name'));\n\n swal({\n type: 'warning',\n title: '',\n text: 'Are you sure you want to delete ' + delName + '? There is no reversing this action.',\n html: true,\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true\n }, () => {\n $.ajax({\n type: 'DELETE',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/f/${delPath}${delName}`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n }\n }).done(data => {\n nameBlock.parent().addClass('warning').delay(200).fadeOut();\n swal({\n type: 'success',\n title: 'File Deleted'\n });\n }).fail(jqXHR => {\n console.error(jqXHR);\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: 'An error occured while attempting to delete this file. Please try again.',\n });\n });\n });\n }\n\n decompress() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const compPath = decodeURIComponent(nameBlock.data('path'));\n const compName = decodeURIComponent(nameBlock.data('name'));\n\n swal({\n title: ' Decompressing...',\n text: 'This might take a few seconds to complete.',\n html: true,\n allowOutsideClick: false,\n allowEscapeKey: false,\n showConfirmButton: false,\n });\n\n $.ajax({\n type: 'POST',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/decompress`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n data: JSON.stringify({\n files: `${compPath}${compName}`\n })\n }).done(data => {\n swal.close();\n Files.list(compPath);\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: error\n });\n });\n }\n\n compress() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const compPath = decodeURIComponent(nameBlock.data('path'));\n const compName = decodeURIComponent(nameBlock.data('name'));\n\n $.ajax({\n type: 'POST',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/compress`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n data: JSON.stringify({\n files: `${compPath}${compName}`,\n to: compPath.toString()\n })\n }).done(data => {\n Files.list(compPath, err => {\n if (err) return;\n const fileListing = $('#file_listing').find(`[data-name=\"${data.saved_as}\"]`).parent();\n fileListing.addClass('success pulsate').delay(3000).queue(() => {\n fileListing.removeClass('success pulsate').dequeue();\n });\n });\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: error\n });\n });\n }\n}\n","\"use strict\";\n\n// Copyright (c) 2015 - 2016 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass ContextMenuClass {\n constructor() {\n this.activeLine = null;\n }\n\n run() {\n this.directoryClick();\n this.rightClick();\n }\n\n makeMenu(parent) {\n $(document).find('#fileOptionMenu').remove();\n if (!_.isNull(this.activeLine)) this.activeLine.removeClass('active');\n\n let newFilePath = $('#headerTableRow').attr('data-currentDir');\n if (parent.data('type') === 'folder') {\n const nameBlock = parent.find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n newFilePath = `${currentPath}${currentName}`;\n }\n\n let buildMenu = '
        ';\n\n if (Pterodactyl.permissions.moveFiles) {\n buildMenu += '
      • Rename
      • \\\n
      • Move
      • ';\n }\n\n if (Pterodactyl.permissions.copyFiles) {\n buildMenu += '
      • Copy
      • ';\n }\n\n if (Pterodactyl.permissions.compressFiles) {\n buildMenu += '
      • Compress
      • ';\n }\n\n if (Pterodactyl.permissions.decompressFiles) {\n buildMenu += '
      • Decompress
      • ';\n }\n\n if (Pterodactyl.permissions.createFiles) {\n buildMenu += '
      • \\\n
      • New File
      • \\\n
      • New Folder
      • ';\n }\n\n if (Pterodactyl.permissions.downloadFiles || Pterodactyl.permissions.deleteFiles) {\n buildMenu += '
      • ';\n }\n\n if (Pterodactyl.permissions.downloadFiles) {\n buildMenu += '
      • Download
      • ';\n }\n\n if (Pterodactyl.permissions.deleteFiles) {\n buildMenu += '
      • Delete
      • ';\n }\n\n buildMenu += '
      ';\n return buildMenu;\n }\n\n rightClick() {\n $('[data-action=\"toggleMenu\"]').on('mousedown', () => {\n event.preventDefault();\n this.showMenu(event);\n });\n $('#file_listing > tbody td').on('contextmenu', event => {\n this.showMenu(event);\n });\n }\n\n showMenu(event) {\n const parent = $(event.target).closest('tr');\n const menu = $(this.makeMenu(parent));\n\n if (parent.data('type') === 'disabled') return;\n event.preventDefault();\n\n $(menu).appendTo('body');\n $(menu).data('invokedOn', $(event.target)).show().css({\n position: 'absolute',\n left: event.pageX - 150,\n top: event.pageY,\n });\n\n this.activeLine = parent;\n this.activeLine.addClass('active');\n\n // Handle Events\n const Actions = new ActionsClass(parent, menu);\n if (Pterodactyl.permissions.moveFiles) {\n $(menu).find('li[data-action=\"move\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.move();\n });\n $(menu).find('li[data-action=\"rename\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.rename();\n });\n }\n\n if (Pterodactyl.permissions.copyFiles) {\n $(menu).find('li[data-action=\"copy\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.copy();\n });\n }\n\n if (Pterodactyl.permissions.compressFiles) {\n if (parent.data('type') === 'folder') {\n $(menu).find('li[data-action=\"compress\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"compress\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.compress();\n });\n }\n\n if (Pterodactyl.permissions.decompressFiles) {\n if (_.without(['application/zip', 'application/gzip', 'application/x-gzip'], parent.data('mime')).length < 3) {\n $(menu).find('li[data-action=\"decompress\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"decompress\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.decompress();\n });\n }\n\n if (Pterodactyl.permissions.createFiles) {\n $(menu).find('li[data-action=\"folder\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.folder();\n });\n }\n\n if (Pterodactyl.permissions.downloadFiles) {\n if (parent.data('type') === 'file') {\n $(menu).find('li[data-action=\"download\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"download\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.download();\n });\n }\n\n if (Pterodactyl.permissions.deleteFiles) {\n $(menu).find('li[data-action=\"delete\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.delete();\n });\n }\n\n $(window).on('click', () => {\n $(menu).remove();\n if(!_.isNull(this.activeLine)) this.activeLine.removeClass('active');\n });\n }\n\n directoryClick() {\n $('a[data-action=\"directory-view\"]').on('click', function (event) {\n event.preventDefault();\n\n const path = $(this).parent().data('path') || '';\n const name = $(this).parent().data('name') || '';\n\n window.location.hash = encodeURIComponent(path + name);\n Files.list();\n });\n }\n}\n\nwindow.ContextMenu = new ContextMenuClass;\n","\"use strict\";\n\n// Copyright (c) 2015 - 2016 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass FileManager {\n constructor() {\n this.list(this.decodeHash());\n }\n\n list(path, next) {\n if (_.isUndefined(path)) {\n path = this.decodeHash();\n }\n\n this.loader(true);\n $.ajax({\n type: 'POST',\n url: Pterodactyl.meta.directoryList,\n headers: {\n 'X-CSRF-Token': Pterodactyl.meta.csrftoken,\n },\n data: {\n directory: path,\n },\n }).done(data => {\n this.loader(false);\n $('#load_files').slideUp().html(data).slideDown(100, () => {\n ContextMenu.run();\n this.reloadFilesButton();\n if (_.isFunction(next)) {\n return next();\n }\n });\n $('#internal_alert').slideUp();\n }).fail(jqXHR => {\n this.loader(false);\n if (_.isFunction(next)) {\n return next(new Error('Failed to load file listing.'));\n }\n swal({\n type: 'error',\n title: 'File Error',\n text: 'An error occured while attempting to process this request. Please try again.',\n });\n console.log(jqXHR);\n });\n }\n\n loader(show) {\n if ($('#load_files').height() < 5) return;\n\n if (show === true){\n var height = $('#load_files').height();\n var width = $('.ajax_loading_box').width();\n var center_height = (height / 2) - 30;\n var center_width = (width / 2) - 30;\n\n $('#position_me').css({\n 'top': center_height,\n 'left': center_width,\n 'font-size': '60px'\n });\n\n $('.ajax_loading_box').css('height', (height + 5)).show();\n } else {\n $('.ajax_loading_box').hide();\n }\n }\n\n reloadFilesButton() {\n $('i[data-action=\"reload-files\"]').unbind().on('click', () => {\n $('i[data-action=\"reload-files\"]').addClass('fa-spin');\n this.list();\n });\n }\n\n decodeHash() {\n return decodeURIComponent(window.location.hash.substring(1));\n }\n\n}\n\nwindow.Files = new FileManager;\n"]} \ No newline at end of file +{"version":3,"sources":["files/actions.js","files/contextmenu.js","files/index.js"],"names":[],"mappings":"AAAA,a,8oBAqBM,a,YACF,sBAAY,OAAZ,CAAqB,IAArB,CAA2B,oCACvB,KAAK,OAAL,CAAe,OAAf,CACA,KAAK,IAAL,CAAY,IACf,C,kEAES,CACN,KAAK,OAAL,CAAe,SAClB,C,uCAEQ,CACL,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,GAAI,eAAgB,WAAhB,CAA8B,WAA9B,IAAJ,CACA,GAAI,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,MAArB,IAAiC,MAArC,CAA6C,CACzC,WAAa,WAChB,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,eAFN,CAGD,KAAM,8CAHL,CAID,iBAAkB,IAJjB,CAKD,kBAAmB,IALlB,CAMD,eAAgB,KANf,CAOD,oBAAqB,IAPpB,CAQD,WAAY,UARX,CAAL,CASG,SAAC,GAAD,CAAS,CACR,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,sBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,KAAM,GADW,CAAf,CATH,CAAP,EAYG,IAZH,CAYQ,cAAQ,CACZ,KAAK,KAAL,GACA,MAAM,IAAN,EACH,CAfD,EAeG,IAfH,CAeQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,EAFN,CAGD,KAAM,KAHL,CAAL,CAKH,CA1BD,CA2BH,CArCD,CAsCH,C,mCAEM,CACH,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,KAAK,CACD,KAAM,OADL,CAED,MAAO,WAFN,CAGD,KAAM,+CAHL,CAID,iBAAkB,IAJjB,CAKD,kBAAmB,IALlB,CAMD,eAAgB,KANf,CAOD,oBAAqB,IAPpB,CAQD,cAAe,WAAf,CAA6B,WAR5B,CAAL,CASG,SAAC,GAAD,CAAS,CACR,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,oBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,QAAS,WAAT,CAAuB,WADN,CAEjB,MAAO,GAFU,CAAf,CATH,CAAP,EAaG,IAbH,CAaQ,cAAQ,CACZ,UAAU,MAAV,GAAmB,QAAnB,CAA4B,SAA5B,EAAuC,KAAvC,CAA6C,GAA7C,EAAkD,OAAlD,GACA,KAAK,KAAL,EACH,CAhBD,EAgBG,IAhBH,CAgBQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,EAFN,CAGD,KAAM,KAHL,CAAL,CAKH,CA3BD,CA4BH,CAtCD,CAwCH,C,uCAEQ,CACL,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,UAAU,IAAV,CAAe,GAAf,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,uFACwD,WADxD,4GAAN,CAKA,UAAU,IAAV,CAAe,YAAf,EACA,GAAM,YAAa,UAAU,IAAV,CAAe,OAAf,CAAnB,CACA,GAAM,aAAc,UAAU,IAAV,CAAe,eAAf,CAApB,CAEA,WAAW,KAAX,GACA,WAAW,EAAX,CAAc,cAAd,CAA8B,WAAK,CAE/B,GACK,EAAE,IAAF,GAAW,SAAX,EAAwB,EAAE,KAAF,GAAY,EAArC,EACG,EAAE,IAAF,GAAW,MADd,EAEI,EAAE,IAAF,GAAW,SAAX,EAAwB,EAAE,KAAF,GAAY,EAApC,EAA0C,cAAgB,WAAW,GAAX,EAHlE,CAIE,CACE,GAAI,CAAC,EAAE,OAAF,CAAU,WAAV,CAAL,CAA6B,CACzB,UAAU,IAAV,CAAe,WAAf,CACH,CAFD,IAEO,CACH,UAAU,IAAV,CAAe,WAAf,CACH,CACD,WAAW,MAAX,GACA,YAAY,MAAZ,GAAqB,GAArB,GACA,MACH,CAED,GAAI,EAAE,IAAF,GAAW,SAAX,EAAwB,EAAE,KAAF,GAAY,EAAxC,CAA4C,OAE5C,YAAY,IAAZ,GACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,sBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,QAAS,WAAT,CAAuB,WADN,CAEjB,MAAO,WAAP,CAAqB,WAAW,GAAX,EAFJ,CAAf,CATH,CAAP,EAaG,IAbH,CAaQ,cAAQ,CACZ,UAAU,IAAV,CAAe,WAAf,CAA4B,WAAW,GAAX,EAA5B,EACA,GAAI,CAAC,EAAE,OAAF,CAAU,WAAV,CAAL,CAA6B,CACzB,GAAI,SAAU,YAAY,IAAZ,CAAiB,MAAjB,CAAd,CACA,GAAI,UAAU,MAAV,GAAmB,IAAnB,CAAwB,MAAxB,IAAoC,QAAxC,CAAkD,CAC9C,QAAU,QAAQ,MAAR,CAAe,CAAf,CAAkB,QAAQ,WAAR,CAAoB,GAApB,CAAlB,EAA8C,GAA9C,CAAoD,WAAW,GAAX,EACjE,CACD,YAAY,IAAZ,CAAiB,MAAjB,CAAyB,OAAzB,EACA,UAAU,IAAV,CACI,YAAY,IAAZ,CAAiB,WAAW,GAAX,EAAjB,CADJ,CAGH,CATD,IASO,CACH,UAAU,IAAV,CAAe,WAAW,GAAX,EAAf,CACH,CACD,WAAW,MAAX,EACH,CA5BD,EA4BG,IA5BH,CA4BQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,UAAU,QAAV,CAAmB,WAAnB,EAAgC,KAAhC,CAAsC,IAAtC,EAA4C,KAA5C,CAAkD,UAAM,CACpD,UAAU,WAAV,CAAsB,WAAtB,EAAmC,OAAnC,EACH,CAFD,EAGA,WAAW,OAAX,CAAmB,CACf,UAAW,IADI,CAEf,UAAW,KAFI,CAGf,QAAS,KAHM,CAIf,MAAO,YAJQ,CAAnB,EAKG,OALH,CAKW,MALX,CAMH,CA3CD,EA2CG,MA3CH,CA2CU,UAAM,CACZ,YAAY,MAAZ,GACA,YAAY,MAAZ,GAAqB,GAArB,EACH,CA9CD,CA+CH,CArED,CAsEH,C,mCAEM,CACH,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,KAAK,CACD,KAAM,OADL,CAED,MAAO,WAFN,CAGD,KAAM,sDAHL,CAID,iBAAkB,IAJjB,CAKD,kBAAmB,IALlB,CAMD,eAAgB,KANf,CAOD,oBAAqB,IAPpB,CAQD,cAAe,WAAf,CAA6B,WAR5B,CAAL,CASG,SAAC,GAAD,CAAS,CACR,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,oBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,QAAS,WAAT,CAAuB,WADN,CAEjB,MAAO,GAFU,CAAf,CATH,CAAP,EAaG,IAbH,CAaQ,cAAQ,CACZ,KAAK,CACD,KAAM,SADL,CAED,MAAO,EAFN,CAGD,KAAM,2BAHL,CAAL,EAKA,MAAM,IAAN,EACH,CApBD,EAoBG,IApBH,CAoBQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,EAFN,CAGD,KAAM,KAHL,CAAL,CAKH,CA/BD,CAgCH,CA1CD,CA2CH,C,2CAEU,CACP,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAAjB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CAEA,OAAO,QAAP,YAA6B,YAAY,MAAZ,CAAmB,SAAhD,oBAA4E,QAA5E,CAAuF,QAC1F,C,wCAEQ,CACL,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,SAAU,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAhB,CACA,GAAM,SAAU,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAhB,CAEA,KAAK,CACD,KAAM,SADL,CAED,MAAO,EAFN,CAGD,KAAM,yCAA2C,OAA3C,CAAqD,8DAH1D,CAID,KAAM,IAJL,CAKD,iBAAkB,IALjB,CAMD,kBAAmB,IANlB,CAOD,eAAgB,KAPf,CAQD,oBAAqB,IARpB,CAAL,CASG,UAAM,CACL,EAAE,IAAF,CAAO,CACH,KAAM,QADH,CAEH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,mBAA6G,OAA7G,CAAuH,OAFpH,CAGH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAHN,CAAP,EAOG,IAPH,CAOQ,cAAQ,CACZ,UAAU,MAAV,GAAmB,QAAnB,CAA4B,SAA5B,EAAuC,KAAvC,CAA6C,GAA7C,EAAkD,OAAlD,GACA,KAAK,CACD,KAAM,SADL,CAED,MAAO,cAFN,CAAL,CAIH,CAbD,EAaG,IAbH,CAaQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,KAAK,CACD,KAAM,OADL,CAED,MAAO,SAFN,CAGD,KAAM,IAHL,CAID,KAAM,0EAJL,CAAL,CAMH,CArBD,CAsBH,CAhCD,CAiCH,C,+CAEY,CACT,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CAEA,KAAK,CACD,MAAO,wDADN,CAED,KAAM,4CAFL,CAGD,KAAM,IAHL,CAID,kBAAmB,KAJlB,CAKD,eAAgB,KALf,CAMD,kBAAmB,KANlB,CAAL,EASA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,0BAFG,CAGH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAHN,CAOH,YAAa,iCAPV,CAQH,KAAM,KAAK,SAAL,CAAe,CACjB,SAAU,QAAV,CAAqB,QADJ,CAAf,CARH,CAAP,EAWG,IAXH,CAWQ,cAAQ,CACZ,KAAK,KAAL,GACA,MAAM,IAAN,CAAW,QAAX,CACH,CAdD,EAcG,IAdH,CAcQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,SAFN,CAGD,KAAM,IAHL,CAID,KAAM,KAJL,CAAL,CAMH,CA1BD,CA2BH,C,2CAEU,CACP,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CAEA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,wBAFG,CAGH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAHN,CAOH,YAAa,iCAPV,CAQH,KAAM,KAAK,SAAL,CAAe,CACjB,SAAU,QAAV,CAAqB,QADJ,CAEjB,GAAI,SAAS,QAAT,EAFa,CAAf,CARH,CAAP,EAYG,IAZH,CAYQ,cAAQ,CACZ,MAAM,IAAN,CAAW,QAAX,CAAqB,aAAO,CACxB,GAAI,GAAJ,CAAS,OACT,GAAM,aAAc,EAAE,eAAF,EAAmB,IAAnB,gBAAuC,KAAK,QAA5C,OAA0D,MAA1D,EAApB,CACA,YAAY,QAAZ,CAAqB,iBAArB,EAAwC,KAAxC,CAA8C,IAA9C,EAAoD,KAApD,CAA0D,UAAM,CAC5D,YAAY,WAAZ,CAAwB,iBAAxB,EAA2C,OAA3C,EACH,CAFD,CAGH,CAND,CAOH,CApBD,EAoBG,IApBH,CAoBQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,SAFN,CAGD,KAAM,IAHL,CAID,KAAM,KAJL,CAAL,CAMH,CAhCD,CAiCH,C;;ACxYL,a,8oBAqBM,iB,YACF,2BAAc,wCACV,KAAK,UAAL,CAAkB,IACrB,C,8DAEK,CACF,KAAK,cAAL,GACA,KAAK,UAAL,EACH,C,0CAEQ,M,CAAQ,CACb,EAAE,QAAF,EAAY,IAAZ,CAAiB,iBAAjB,EAAoC,MAApC,GACA,GAAI,CAAC,EAAE,MAAF,CAAS,KAAK,UAAd,CAAL,CAAgC,KAAK,UAAL,CAAgB,WAAhB,CAA4B,QAA5B,EAEhC,GAAI,aAAc,EAAE,iBAAF,EAAqB,IAArB,CAA0B,iBAA1B,CAAlB,CACA,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,QAA5B,CAAsC,CAClC,GAAM,WAAY,OAAO,IAAP,CAAY,4BAAZ,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CACA,eAAiB,WAAjB,CAA+B,WAClC,CAED,GAAI,WAAY,kFAAhB,CAEA,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,WAAa,iPAEhB,CAED,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,WAAa,kGAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,WAAa,kIAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,eAA5B,CAA6C,CACzC,WAAa,8HAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,WAAa,+FAC4C,YAAY,MAAZ,CAAmB,SAD/D,CAC0E,kBAD1E,CAC+F,WAD/F,CAC6G,6MAE7H,CAED,GAAI,YAAY,WAAZ,CAAwB,aAAxB,EAAyC,YAAY,WAAZ,CAAwB,WAArE,CAAkF,CAC9E,WAAa,2BAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,WAAa,4HAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,WAAa,0HAChB,CAED,WAAa,OAAb,CACA,MAAO,UACV,C,+CAEY,gBACT,EAAE,4BAAF,EAAgC,EAAhC,CAAmC,WAAnC,CAAgD,UAAM,CAClD,MAAM,cAAN,GACA,MAAK,QAAL,CAAc,KAAd,CACH,CAHD,EAIA,EAAE,0BAAF,EAA8B,EAA9B,CAAiC,aAAjC,CAAgD,eAAS,CACrD,MAAK,QAAL,CAAc,KAAd,CACH,CAFD,CAGH,C,0CAEQ,K,CAAO,iBACZ,GAAM,QAAS,EAAE,MAAM,MAAR,EAAgB,OAAhB,CAAwB,IAAxB,CAAf,CACA,GAAM,MAAO,EAAE,KAAK,QAAL,CAAc,MAAd,CAAF,CAAb,CAEA,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,UAA5B,CAAwC,OACxC,MAAM,cAAN,GAEA,EAAE,IAAF,EAAQ,QAAR,CAAiB,MAAjB,EACA,EAAE,IAAF,EAAQ,IAAR,CAAa,WAAb,CAA0B,EAAE,MAAM,MAAR,CAA1B,EAA2C,IAA3C,GAAkD,GAAlD,CAAsD,CAClD,SAAU,UADwC,CAElD,KAAM,MAAM,KAAN,CAAc,GAF8B,CAGlD,IAAK,MAAM,KAHuC,CAAtD,EAMA,KAAK,UAAL,CAAkB,MAAlB,CACA,KAAK,UAAL,CAAgB,QAAhB,CAAyB,QAAzB,EAGA,GAAM,SAAU,GAAI,aAAJ,CAAiB,MAAjB,CAAyB,IAAzB,CAAhB,CACA,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,EAAE,IAAF,EAAQ,IAAR,CAAa,wBAAb,EAAuC,MAAvC,GAAgD,EAAhD,CAAmD,OAAnD,CAA4D,WAAK,CAC7D,EAAE,cAAF,GACA,QAAQ,IAAR,EACH,CAHD,EAIA,EAAE,IAAF,EAAQ,IAAR,CAAa,0BAAb,EAAyC,MAAzC,GAAkD,EAAlD,CAAqD,OAArD,CAA8D,WAAK,CAC/D,EAAE,cAAF,GACA,QAAQ,MAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,EAAE,IAAF,EAAQ,IAAR,CAAa,wBAAb,EAAuC,MAAvC,GAAgD,EAAhD,CAAmD,OAAnD,CAA4D,WAAK,CAC7D,EAAE,cAAF,GACA,QAAQ,IAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,QAA5B,CAAsC,CAClC,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,WAA3C,CAAuD,QAAvD,CACH,CACD,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,MAA3C,GAAoD,EAApD,CAAuD,OAAvD,CAAgE,WAAK,CACjE,EAAE,cAAF,GACA,QAAQ,QAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,eAA5B,CAA6C,CACzC,GAAI,EAAE,OAAF,CAAU,CAAC,iBAAD,CAAoB,kBAApB,CAAwC,oBAAxC,CAAV,CAAyE,OAAO,IAAP,CAAY,MAAZ,CAAzE,EAA8F,MAA9F,CAAuG,CAA3G,CAA8G,CAC1G,EAAE,IAAF,EAAQ,IAAR,CAAa,8BAAb,EAA6C,WAA7C,CAAyD,QAAzD,CACH,CACD,EAAE,IAAF,EAAQ,IAAR,CAAa,8BAAb,EAA6C,MAA7C,GAAsD,EAAtD,CAAyD,OAAzD,CAAkE,WAAK,CACnE,EAAE,cAAF,GACA,QAAQ,UAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,EAAE,IAAF,EAAQ,IAAR,CAAa,0BAAb,EAAyC,MAAzC,GAAkD,EAAlD,CAAqD,OAArD,CAA8D,WAAK,CAC/D,EAAE,cAAF,GACA,QAAQ,MAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,MAA5B,CAAoC,CAChC,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,WAA3C,CAAuD,QAAvD,CACH,CACD,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,MAA3C,GAAoD,EAApD,CAAuD,OAAvD,CAAgE,WAAK,CACjE,EAAE,cAAF,GACA,QAAQ,QAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,EAAE,IAAF,EAAQ,IAAR,CAAa,0BAAb,EAAyC,MAAzC,GAAkD,EAAlD,CAAqD,OAArD,CAA8D,WAAK,CAC/D,EAAE,cAAF,GACA,QAAQ,MAAR,EACH,CAHD,CAIH,CAED,EAAE,MAAF,EAAU,EAAV,CAAa,OAAb,CAAsB,UAAM,CACxB,EAAE,IAAF,EAAQ,MAAR,GACA,GAAG,CAAC,EAAE,MAAF,CAAS,OAAK,UAAd,CAAJ,CAA+B,OAAK,UAAL,CAAgB,WAAhB,CAA4B,QAA5B,CAClC,CAHD,CAIH,C,uDAEgB,CACb,EAAE,iCAAF,EAAqC,EAArC,CAAwC,OAAxC,CAAiD,SAAU,KAAV,CAAiB,CAC9D,MAAM,cAAN,GAEA,GAAM,MAAO,EAAE,IAAF,EAAQ,MAAR,GAAiB,IAAjB,CAAsB,MAAtB,GAAiC,EAA9C,CACA,GAAM,MAAO,EAAE,IAAF,EAAQ,MAAR,GAAiB,IAAjB,CAAsB,MAAtB,GAAiC,EAA9C,CAEA,OAAO,QAAP,CAAgB,IAAhB,CAAuB,mBAAmB,KAAO,IAA1B,CAAvB,CACA,MAAM,IAAN,EACH,CARD,CASH,C,+BAGL,OAAO,WAAP,CAAqB,GAAI,iBAAzB;AClMA,a,8oBAqBM,Y,YACF,sBAAc,mCACV,KAAK,IAAL,CAAU,KAAK,UAAL,EAAV,CACH,C,0DAEI,I,CAAM,I,CAAM,gBACb,GAAI,EAAE,WAAF,CAAc,IAAd,CAAJ,CAAyB,CACrB,KAAO,KAAK,UAAL,EACV,CAED,KAAK,MAAL,CAAY,IAAZ,EACA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,IAAK,YAAY,IAAZ,CAAiB,aAFnB,CAGH,QAAS,CACL,eAAgB,YAAY,IAAZ,CAAiB,SAD5B,CAHN,CAMH,KAAM,CACF,UAAW,IADT,CANH,CAAP,EASG,IATH,CASQ,cAAQ,CACZ,MAAK,MAAL,CAAY,KAAZ,EACA,EAAE,aAAF,EAAiB,OAAjB,GAA2B,IAA3B,CAAgC,IAAhC,EAAsC,SAAtC,CAAgD,GAAhD,CAAqD,UAAM,CACvD,YAAY,GAAZ,GACA,MAAK,iBAAL,GACA,GAAI,EAAE,UAAF,CAAa,IAAb,CAAJ,CAAwB,CACpB,MAAO,OACV,CACJ,CAND,EAOA,EAAE,iBAAF,EAAqB,OAArB,EACH,CAnBD,EAmBG,IAnBH,CAmBQ,eAAS,CACb,MAAK,MAAL,CAAY,KAAZ,EACA,GAAI,EAAE,UAAF,CAAa,IAAb,CAAJ,CAAwB,CACpB,MAAO,MAAK,GAAI,MAAJ,CAAU,8BAAV,CAAL,CACV,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,YAFN,CAGD,KAAM,8EAHL,CAAL,EAKA,QAAQ,GAAR,CAAY,KAAZ,CACH,CA9BD,CA+BH,C,sCAEM,I,CAAM,CACT,GAAI,EAAE,aAAF,EAAiB,MAAjB,GAA4B,CAAhC,CAAmC,OAEnC,GAAI,OAAS,IAAb,CAAkB,CACd,GAAI,QAAS,EAAE,aAAF,EAAiB,MAAjB,EAAb,CACA,GAAI,OAAQ,EAAE,mBAAF,EAAuB,KAAvB,EAAZ,CACA,GAAI,eAAiB,OAAS,CAAV,CAAe,EAAnC,CACA,GAAI,cAAgB,MAAQ,CAAT,CAAc,EAAjC,CAEA,EAAE,cAAF,EAAkB,GAAlB,CAAsB,CAClB,MAAO,aADW,CAElB,OAAQ,YAFU,CAGlB,YAAa,MAHK,CAAtB,EAMA,EAAE,mBAAF,EAAuB,GAAvB,CAA2B,QAA3B,CAAsC,OAAS,CAA/C,EAAmD,IAAnD,EACH,CAbD,IAaO,CACH,EAAE,mBAAF,EAAuB,IAAvB,EACH,CACJ,C,6DAEmB,iBAChB,EAAE,+BAAF,EAAmC,MAAnC,GAA4C,EAA5C,CAA+C,OAA/C,CAAwD,UAAM,CAC1D,EAAE,+BAAF,EAAmC,QAAnC,CAA4C,SAA5C,EACA,OAAK,IAAL,EACH,CAHD,CAIH,C,+CAEY,CACT,MAAO,oBAAmB,OAAO,QAAP,CAAgB,IAAhB,CAAqB,SAArB,CAA+B,CAA/B,CAAnB,CACV,C,0BAIL,OAAO,KAAP,CAAe,GAAI,YAAnB","file":"filemanager.min.js","sourcesContent":["\"use strict\";\n\n// Copyright (c) 2015 - 2017 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass ActionsClass {\n constructor(element, menu) {\n this.element = element;\n this.menu = menu;\n }\n\n destroy() {\n this.element = undefined;\n }\n\n folder() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n let inputValue = `${currentPath}${currentName}/`;\n if ($(this.element).data('type') === 'file') {\n inputValue = currentPath;\n }\n swal({\n type: 'input',\n title: 'Create Folder',\n text: 'Please enter the path and folder name below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: inputValue\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/folder`,\n timeout: 10000,\n data: JSON.stringify({\n path: val,\n }),\n }).done(data => {\n swal.close();\n Files.list();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n }\n\n move() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n swal({\n type: 'input',\n title: 'Move File',\n text: 'Please enter the new path for the file below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: `${currentPath}${currentName}`,\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/move`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${val}`,\n }),\n }).done(data => {\n nameBlock.parent().addClass('warning').delay(200).fadeOut();\n swal.close();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n\n }\n\n rename() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentLink = nameBlock.find('a');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const attachEditor = `\n \n \n `;\n\n nameBlock.html(attachEditor);\n const inputField = nameBlock.find('input');\n const inputLoader = nameBlock.find('.input-loader');\n\n inputField.focus();\n inputField.on('blur keydown', e => {\n // Save Field\n if (\n (e.type === 'keydown' && e.which === 27)\n || e.type === 'blur'\n || (e.type === 'keydown' && e.which === 13 && currentName === inputField.val())\n ) {\n if (!_.isEmpty(currentLink)) {\n nameBlock.html(currentLink);\n } else {\n nameBlock.html(currentName);\n }\n inputField.remove();\n ContextMenu.unbind().run();\n return;\n }\n\n if (e.type === 'keydown' && e.which !== 13) return;\n\n inputLoader.show();\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/rename`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${currentPath}${inputField.val()}`,\n }),\n }).done(data => {\n nameBlock.attr('data-name', inputField.val());\n if (!_.isEmpty(currentLink)) {\n let newLink = currentLink.attr('href');\n if (nameBlock.parent().data('type') !== 'folder') {\n newLink = newLink.substr(0, newLink.lastIndexOf('/')) + '/' + inputField.val();\n }\n currentLink.attr('href', newLink);\n nameBlock.html(\n currentLink.html(inputField.val())\n );\n } else {\n nameBlock.html(inputField.val());\n }\n inputField.remove();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n nameBlock.addClass('has-error').delay(2000).queue(() => {\n nameBlock.removeClass('has-error').dequeue();\n });\n inputField.popover({\n animation: true,\n placement: 'top',\n content: error,\n title: 'Save Error'\n }).popover('show');\n }).always(() => {\n inputLoader.remove();\n ContextMenu.unbind().run();\n });\n });\n }\n\n copy() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n swal({\n type: 'input',\n title: 'Copy File',\n text: 'Please enter the new path for the copied file below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: `${currentPath}${currentName}`,\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/copy`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${val}`,\n }),\n }).done(data => {\n swal({\n type: 'success',\n title: '',\n text: 'File successfully copied.'\n });\n Files.list();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n }\n\n download() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const fileName = decodeURIComponent(nameBlock.attr('data-name'));\n const filePath = decodeURIComponent(nameBlock.data('path'));\n\n window.location = `/server/${Pterodactyl.server.uuidShort}/files/download/${filePath}${fileName}`;\n }\n\n delete() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const delPath = decodeURIComponent(nameBlock.data('path'));\n const delName = decodeURIComponent(nameBlock.data('name'));\n\n swal({\n type: 'warning',\n title: '',\n text: 'Are you sure you want to delete ' + delName + '? There is no reversing this action.',\n html: true,\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true\n }, () => {\n $.ajax({\n type: 'DELETE',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/f/${delPath}${delName}`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n }\n }).done(data => {\n nameBlock.parent().addClass('warning').delay(200).fadeOut();\n swal({\n type: 'success',\n title: 'File Deleted'\n });\n }).fail(jqXHR => {\n console.error(jqXHR);\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: 'An error occured while attempting to delete this file. Please try again.',\n });\n });\n });\n }\n\n decompress() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const compPath = decodeURIComponent(nameBlock.data('path'));\n const compName = decodeURIComponent(nameBlock.data('name'));\n\n swal({\n title: ' Decompressing...',\n text: 'This might take a few seconds to complete.',\n html: true,\n allowOutsideClick: false,\n allowEscapeKey: false,\n showConfirmButton: false,\n });\n\n $.ajax({\n type: 'POST',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/decompress`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n data: JSON.stringify({\n files: `${compPath}${compName}`\n })\n }).done(data => {\n swal.close();\n Files.list(compPath);\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: error\n });\n });\n }\n\n compress() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const compPath = decodeURIComponent(nameBlock.data('path'));\n const compName = decodeURIComponent(nameBlock.data('name'));\n\n $.ajax({\n type: 'POST',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/compress`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n data: JSON.stringify({\n files: `${compPath}${compName}`,\n to: compPath.toString()\n })\n }).done(data => {\n Files.list(compPath, err => {\n if (err) return;\n const fileListing = $('#file_listing').find(`[data-name=\"${data.saved_as}\"]`).parent();\n fileListing.addClass('success pulsate').delay(3000).queue(() => {\n fileListing.removeClass('success pulsate').dequeue();\n });\n });\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: error\n });\n });\n }\n}\n","\"use strict\";\n\n// Copyright (c) 2015 - 2017 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass ContextMenuClass {\n constructor() {\n this.activeLine = null;\n }\n\n run() {\n this.directoryClick();\n this.rightClick();\n }\n\n makeMenu(parent) {\n $(document).find('#fileOptionMenu').remove();\n if (!_.isNull(this.activeLine)) this.activeLine.removeClass('active');\n\n let newFilePath = $('#headerTableRow').attr('data-currentDir');\n if (parent.data('type') === 'folder') {\n const nameBlock = parent.find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n newFilePath = `${currentPath}${currentName}`;\n }\n\n let buildMenu = '
        ';\n\n if (Pterodactyl.permissions.moveFiles) {\n buildMenu += '
      • Rename
      • \\\n
      • Move
      • ';\n }\n\n if (Pterodactyl.permissions.copyFiles) {\n buildMenu += '
      • Copy
      • ';\n }\n\n if (Pterodactyl.permissions.compressFiles) {\n buildMenu += '
      • Compress
      • ';\n }\n\n if (Pterodactyl.permissions.decompressFiles) {\n buildMenu += '
      • Decompress
      • ';\n }\n\n if (Pterodactyl.permissions.createFiles) {\n buildMenu += '
      • \\\n
      • New File
      • \\\n
      • New Folder
      • ';\n }\n\n if (Pterodactyl.permissions.downloadFiles || Pterodactyl.permissions.deleteFiles) {\n buildMenu += '
      • ';\n }\n\n if (Pterodactyl.permissions.downloadFiles) {\n buildMenu += '
      • Download
      • ';\n }\n\n if (Pterodactyl.permissions.deleteFiles) {\n buildMenu += '
      • Delete
      • ';\n }\n\n buildMenu += '
      ';\n return buildMenu;\n }\n\n rightClick() {\n $('[data-action=\"toggleMenu\"]').on('mousedown', () => {\n event.preventDefault();\n this.showMenu(event);\n });\n $('#file_listing > tbody td').on('contextmenu', event => {\n this.showMenu(event);\n });\n }\n\n showMenu(event) {\n const parent = $(event.target).closest('tr');\n const menu = $(this.makeMenu(parent));\n\n if (parent.data('type') === 'disabled') return;\n event.preventDefault();\n\n $(menu).appendTo('body');\n $(menu).data('invokedOn', $(event.target)).show().css({\n position: 'absolute',\n left: event.pageX - 150,\n top: event.pageY,\n });\n\n this.activeLine = parent;\n this.activeLine.addClass('active');\n\n // Handle Events\n const Actions = new ActionsClass(parent, menu);\n if (Pterodactyl.permissions.moveFiles) {\n $(menu).find('li[data-action=\"move\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.move();\n });\n $(menu).find('li[data-action=\"rename\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.rename();\n });\n }\n\n if (Pterodactyl.permissions.copyFiles) {\n $(menu).find('li[data-action=\"copy\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.copy();\n });\n }\n\n if (Pterodactyl.permissions.compressFiles) {\n if (parent.data('type') === 'folder') {\n $(menu).find('li[data-action=\"compress\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"compress\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.compress();\n });\n }\n\n if (Pterodactyl.permissions.decompressFiles) {\n if (_.without(['application/zip', 'application/gzip', 'application/x-gzip'], parent.data('mime')).length < 3) {\n $(menu).find('li[data-action=\"decompress\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"decompress\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.decompress();\n });\n }\n\n if (Pterodactyl.permissions.createFiles) {\n $(menu).find('li[data-action=\"folder\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.folder();\n });\n }\n\n if (Pterodactyl.permissions.downloadFiles) {\n if (parent.data('type') === 'file') {\n $(menu).find('li[data-action=\"download\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"download\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.download();\n });\n }\n\n if (Pterodactyl.permissions.deleteFiles) {\n $(menu).find('li[data-action=\"delete\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.delete();\n });\n }\n\n $(window).on('click', () => {\n $(menu).remove();\n if(!_.isNull(this.activeLine)) this.activeLine.removeClass('active');\n });\n }\n\n directoryClick() {\n $('a[data-action=\"directory-view\"]').on('click', function (event) {\n event.preventDefault();\n\n const path = $(this).parent().data('path') || '';\n const name = $(this).parent().data('name') || '';\n\n window.location.hash = encodeURIComponent(path + name);\n Files.list();\n });\n }\n}\n\nwindow.ContextMenu = new ContextMenuClass;\n","\"use strict\";\n\n// Copyright (c) 2015 - 2017 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass FileManager {\n constructor() {\n this.list(this.decodeHash());\n }\n\n list(path, next) {\n if (_.isUndefined(path)) {\n path = this.decodeHash();\n }\n\n this.loader(true);\n $.ajax({\n type: 'POST',\n url: Pterodactyl.meta.directoryList,\n headers: {\n 'X-CSRF-Token': Pterodactyl.meta.csrftoken,\n },\n data: {\n directory: path,\n },\n }).done(data => {\n this.loader(false);\n $('#load_files').slideUp().html(data).slideDown(100, () => {\n ContextMenu.run();\n this.reloadFilesButton();\n if (_.isFunction(next)) {\n return next();\n }\n });\n $('#internal_alert').slideUp();\n }).fail(jqXHR => {\n this.loader(false);\n if (_.isFunction(next)) {\n return next(new Error('Failed to load file listing.'));\n }\n swal({\n type: 'error',\n title: 'File Error',\n text: 'An error occured while attempting to process this request. Please try again.',\n });\n console.log(jqXHR);\n });\n }\n\n loader(show) {\n if ($('#load_files').height() < 5) return;\n\n if (show === true){\n var height = $('#load_files').height();\n var width = $('.ajax_loading_box').width();\n var center_height = (height / 2) - 30;\n var center_width = (width / 2) - 30;\n\n $('#position_me').css({\n 'top': center_height,\n 'left': center_width,\n 'font-size': '60px'\n });\n\n $('.ajax_loading_box').css('height', (height + 5)).show();\n } else {\n $('.ajax_loading_box').hide();\n }\n }\n\n reloadFilesButton() {\n $('i[data-action=\"reload-files\"]').unbind().on('click', () => {\n $('i[data-action=\"reload-files\"]').addClass('fa-spin');\n this.list();\n });\n }\n\n decodeHash() {\n return decodeURIComponent(window.location.hash.substring(1));\n }\n\n}\n\nwindow.Files = new FileManager;\n"]} \ No newline at end of file diff --git a/public/js/files/actions.js b/public/js/files/actions.js index 9ff978539..f286f4c1f 100644 --- a/public/js/files/actions.js +++ b/public/js/files/actions.js @@ -1,6 +1,6 @@ "use strict"; -// Copyright (c) 2015 - 2016 Dane Everitt +// 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 diff --git a/public/js/files/contextmenu.js b/public/js/files/contextmenu.js index f61b7bb28..7c91ac004 100644 --- a/public/js/files/contextmenu.js +++ b/public/js/files/contextmenu.js @@ -1,6 +1,6 @@ "use strict"; -// Copyright (c) 2015 - 2016 Dane Everitt +// 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 diff --git a/public/js/files/index.js b/public/js/files/index.js index a8142123f..f833ab2af 100644 --- a/public/js/files/index.js +++ b/public/js/files/index.js @@ -1,6 +1,6 @@ "use strict"; -// Copyright (c) 2015 - 2016 Dane Everitt +// 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 diff --git a/public/js/plugins/minecraft/eula.js b/public/js/plugins/minecraft/eula.js index 7077288b4..2d1e047e5 100644 --- a/public/js/plugins/minecraft/eula.js +++ b/public/js/plugins/minecraft/eula.js @@ -1,4 +1,4 @@ -// Copyright (c) 2015 - 2016 Dane Everitt +// 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 diff --git a/public/themes/default/css/pterodactyl.css b/public/themes/default/css/pterodactyl.css index f6e37f4e7..902373abd 100755 --- a/public/themes/default/css/pterodactyl.css +++ b/public/themes/default/css/pterodactyl.css @@ -1,6 +1,6 @@ /** * Pterodactyl - Panel - * Copyright (c) 2015 - 2016 Dane Everitt + * 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 diff --git a/public/themes/pterodactyl/js/frontend/2fa-modal.js b/public/themes/pterodactyl/js/frontend/2fa-modal.js index 492cb1607..75fb621f0 100644 --- a/public/themes/pterodactyl/js/frontend/2fa-modal.js +++ b/public/themes/pterodactyl/js/frontend/2fa-modal.js @@ -1,4 +1,4 @@ -// Copyright (c) 2015 - 2016 Dane Everitt +// 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 diff --git a/public/themes/pterodactyl/js/frontend/console.js b/public/themes/pterodactyl/js/frontend/console.js index 92a22e6f7..2d30586ec 100644 --- a/public/themes/pterodactyl/js/frontend/console.js +++ b/public/themes/pterodactyl/js/frontend/console.js @@ -1,4 +1,4 @@ -// Copyright (c) 2015 - 2016 Dane Everitt +// 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 diff --git a/public/themes/pterodactyl/js/frontend/files/editor.js b/public/themes/pterodactyl/js/frontend/files/editor.js index 208538fa1..70206c6fe 100644 --- a/public/themes/pterodactyl/js/frontend/files/editor.js +++ b/public/themes/pterodactyl/js/frontend/files/editor.js @@ -1,4 +1,4 @@ -// Copyright (c) 2015 - 2016 Dane Everitt +// 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 diff --git a/public/themes/pterodactyl/js/frontend/files/filemanager.min.js.map b/public/themes/pterodactyl/js/frontend/files/filemanager.min.js.map index 6a0d7eaaf..5ff51f1c0 100644 --- a/public/themes/pterodactyl/js/frontend/files/filemanager.min.js.map +++ b/public/themes/pterodactyl/js/frontend/files/filemanager.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["src/actions.js","src/contextmenu.js","src/index.js"],"names":[],"mappings":"AAAA,a,8oBAqBM,a,YACF,sBAAY,OAAZ,CAAqB,IAArB,CAA2B,oCACvB,KAAK,OAAL,CAAe,OAAf,CACA,KAAK,IAAL,CAAY,IACf,C,kEAES,CACN,KAAK,OAAL,CAAe,SAClB,C,uCAEQ,CACL,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,GAAI,eAAgB,WAAhB,CAA8B,WAA9B,IAAJ,CACA,GAAI,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,MAArB,IAAiC,MAArC,CAA6C,CACzC,WAAa,WAChB,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,eAFN,CAGD,KAAM,8CAHL,CAID,iBAAkB,IAJjB,CAKD,kBAAmB,IALlB,CAMD,eAAgB,KANf,CAOD,oBAAqB,IAPpB,CAQD,WAAY,UARX,CAAL,CASG,SAAC,GAAD,CAAS,CACR,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,sBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,KAAM,GADW,CAAf,CATH,CAAP,EAYG,IAZH,CAYQ,cAAQ,CACZ,KAAK,KAAL,GACA,MAAM,IAAN,EACH,CAfD,EAeG,IAfH,CAeQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,EAFN,CAGD,KAAM,KAHL,CAAL,CAKH,CA1BD,CA2BH,CArCD,CAsCH,C,mCAEM,CACH,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,KAAK,CACD,KAAM,OADL,CAED,MAAO,WAFN,CAGD,KAAM,+CAHL,CAID,iBAAkB,IAJjB,CAKD,kBAAmB,IALlB,CAMD,eAAgB,KANf,CAOD,oBAAqB,IAPpB,CAQD,cAAe,WAAf,CAA6B,WAR5B,CAAL,CASG,SAAC,GAAD,CAAS,CACR,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,oBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,QAAS,WAAT,CAAuB,WADN,CAEjB,MAAO,GAFU,CAAf,CATH,CAAP,EAaG,IAbH,CAaQ,cAAQ,CACZ,UAAU,MAAV,GAAmB,QAAnB,CAA4B,SAA5B,EAAuC,KAAvC,CAA6C,GAA7C,EAAkD,OAAlD,GACA,KAAK,KAAL,EACH,CAhBD,EAgBG,IAhBH,CAgBQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,EAFN,CAGD,KAAM,KAHL,CAAL,CAKH,CA3BD,CA4BH,CAtCD,CAwCH,C,uCAEQ,CACL,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,UAAU,IAAV,CAAe,GAAf,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,uFACwD,WADxD,4GAAN,CAKA,UAAU,IAAV,CAAe,YAAf,EACA,GAAM,YAAa,UAAU,IAAV,CAAe,OAAf,CAAnB,CACA,GAAM,aAAc,UAAU,IAAV,CAAe,eAAf,CAApB,CAEA,WAAW,KAAX,GACA,WAAW,EAAX,CAAc,cAAd,CAA8B,WAAK,CAE/B,GACK,EAAE,IAAF,GAAW,SAAX,EAAwB,EAAE,KAAF,GAAY,EAArC,EACG,EAAE,IAAF,GAAW,MADd,EAEI,EAAE,IAAF,GAAW,SAAX,EAAwB,EAAE,KAAF,GAAY,EAApC,EAA0C,cAAgB,WAAW,GAAX,EAHlE,CAIE,CACE,GAAI,CAAC,EAAE,OAAF,CAAU,WAAV,CAAL,CAA6B,CACzB,UAAU,IAAV,CAAe,WAAf,CACH,CAFD,IAEO,CACH,UAAU,IAAV,CAAe,WAAf,CACH,CACD,WAAW,MAAX,GACA,YAAY,MAAZ,GAAqB,GAArB,GACA,MACH,CAED,GAAI,EAAE,IAAF,GAAW,SAAX,EAAwB,EAAE,KAAF,GAAY,EAAxC,CAA4C,OAE5C,YAAY,IAAZ,GACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,sBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,QAAS,WAAT,CAAuB,WADN,CAEjB,MAAO,WAAP,CAAqB,WAAW,GAAX,EAFJ,CAAf,CATH,CAAP,EAaG,IAbH,CAaQ,cAAQ,CACZ,UAAU,IAAV,CAAe,WAAf,CAA4B,WAAW,GAAX,EAA5B,EACA,GAAI,CAAC,EAAE,OAAF,CAAU,WAAV,CAAL,CAA6B,CACzB,GAAI,SAAU,YAAY,IAAZ,CAAiB,MAAjB,CAAd,CACA,GAAI,UAAU,MAAV,GAAmB,IAAnB,CAAwB,MAAxB,IAAoC,QAAxC,CAAkD,CAC9C,QAAU,QAAQ,MAAR,CAAe,CAAf,CAAkB,QAAQ,WAAR,CAAoB,GAApB,CAAlB,EAA8C,GAA9C,CAAoD,WAAW,GAAX,EACjE,CACD,YAAY,IAAZ,CAAiB,MAAjB,CAAyB,OAAzB,EACA,UAAU,IAAV,CACI,YAAY,IAAZ,CAAiB,WAAW,GAAX,EAAjB,CADJ,CAGH,CATD,IASO,CACH,UAAU,IAAV,CAAe,WAAW,GAAX,EAAf,CACH,CACD,WAAW,MAAX,EACH,CA5BD,EA4BG,IA5BH,CA4BQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,UAAU,QAAV,CAAmB,WAAnB,EAAgC,KAAhC,CAAsC,IAAtC,EAA4C,KAA5C,CAAkD,UAAM,CACpD,UAAU,WAAV,CAAsB,WAAtB,EAAmC,OAAnC,EACH,CAFD,EAGA,WAAW,OAAX,CAAmB,CACf,UAAW,IADI,CAEf,UAAW,KAFI,CAGf,QAAS,KAHM,CAIf,MAAO,YAJQ,CAAnB,EAKG,OALH,CAKW,MALX,CAMH,CA3CD,EA2CG,MA3CH,CA2CU,UAAM,CACZ,YAAY,MAAZ,GACA,YAAY,MAAZ,GAAqB,GAArB,EACH,CA9CD,CA+CH,CArED,CAsEH,C,mCAEM,CACH,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,KAAK,CACD,KAAM,OADL,CAED,MAAO,WAFN,CAGD,KAAM,sDAHL,CAID,iBAAkB,IAJjB,CAKD,kBAAmB,IALlB,CAMD,eAAgB,KANf,CAOD,oBAAqB,IAPpB,CAQD,cAAe,WAAf,CAA6B,WAR5B,CAAL,CASG,SAAC,GAAD,CAAS,CACR,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,oBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,QAAS,WAAT,CAAuB,WADN,CAEjB,MAAO,GAFU,CAAf,CATH,CAAP,EAaG,IAbH,CAaQ,cAAQ,CACZ,KAAK,CACD,KAAM,SADL,CAED,MAAO,EAFN,CAGD,KAAM,2BAHL,CAAL,EAKA,MAAM,IAAN,EACH,CApBD,EAoBG,IApBH,CAoBQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,EAFN,CAGD,KAAM,KAHL,CAAL,CAKH,CA/BD,CAgCH,CA1CD,CA2CH,C,2CAEU,CACP,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAAjB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CAEA,OAAO,QAAP,YAA6B,YAAY,MAAZ,CAAmB,SAAhD,oBAA4E,QAA5E,CAAuF,QAC1F,C,wCAEQ,CACL,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,SAAU,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAhB,CACA,GAAM,SAAU,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAhB,CAEA,KAAK,CACD,KAAM,SADL,CAED,MAAO,EAFN,CAGD,KAAM,yCAA2C,OAA3C,CAAqD,8DAH1D,CAID,KAAM,IAJL,CAKD,iBAAkB,IALjB,CAMD,kBAAmB,IANlB,CAOD,eAAgB,KAPf,CAQD,oBAAqB,IARpB,CAAL,CASG,UAAM,CACL,EAAE,IAAF,CAAO,CACH,KAAM,QADH,CAEH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,mBAA6G,OAA7G,CAAuH,OAFpH,CAGH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAHN,CAAP,EAOG,IAPH,CAOQ,cAAQ,CACZ,UAAU,MAAV,GAAmB,QAAnB,CAA4B,SAA5B,EAAuC,KAAvC,CAA6C,GAA7C,EAAkD,OAAlD,GACA,KAAK,CACD,KAAM,SADL,CAED,MAAO,cAFN,CAAL,CAIH,CAbD,EAaG,IAbH,CAaQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,KAAK,CACD,KAAM,OADL,CAED,MAAO,SAFN,CAGD,KAAM,IAHL,CAID,KAAM,0EAJL,CAAL,CAMH,CArBD,CAsBH,CAhCD,CAiCH,C,+CAEY,CACT,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CAEA,KAAK,CACD,MAAO,wDADN,CAED,KAAM,4CAFL,CAGD,KAAM,IAHL,CAID,kBAAmB,KAJlB,CAKD,eAAgB,KALf,CAMD,kBAAmB,KANlB,CAAL,EASA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,0BAFG,CAGH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAHN,CAOH,YAAa,iCAPV,CAQH,KAAM,KAAK,SAAL,CAAe,CACjB,SAAU,QAAV,CAAqB,QADJ,CAAf,CARH,CAAP,EAWG,IAXH,CAWQ,cAAQ,CACZ,KAAK,KAAL,GACA,MAAM,IAAN,CAAW,QAAX,CACH,CAdD,EAcG,IAdH,CAcQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,SAFN,CAGD,KAAM,IAHL,CAID,KAAM,KAJL,CAAL,CAMH,CA1BD,CA2BH,C,2CAEU,CACP,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CAEA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,wBAFG,CAGH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAHN,CAOH,YAAa,iCAPV,CAQH,KAAM,KAAK,SAAL,CAAe,CACjB,SAAU,QAAV,CAAqB,QADJ,CAEjB,GAAI,SAAS,QAAT,EAFa,CAAf,CARH,CAAP,EAYG,IAZH,CAYQ,cAAQ,CACZ,MAAM,IAAN,CAAW,QAAX,CAAqB,aAAO,CACxB,GAAI,GAAJ,CAAS,OACT,GAAM,aAAc,EAAE,eAAF,EAAmB,IAAnB,gBAAuC,KAAK,QAA5C,OAA0D,MAA1D,EAApB,CACA,YAAY,QAAZ,CAAqB,iBAArB,EAAwC,KAAxC,CAA8C,IAA9C,EAAoD,KAApD,CAA0D,UAAM,CAC5D,YAAY,WAAZ,CAAwB,iBAAxB,EAA2C,OAA3C,EACH,CAFD,CAGH,CAND,CAOH,CApBD,EAoBG,IApBH,CAoBQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,SAFN,CAGD,KAAM,IAHL,CAID,KAAM,KAJL,CAAL,CAMH,CAhCD,CAiCH,C;;ACxYL,a,8oBAqBM,iB,YACF,2BAAc,wCACV,KAAK,UAAL,CAAkB,IACrB,C,8DAEK,CACF,KAAK,cAAL,GACA,KAAK,UAAL,EACH,C,0CAEQ,M,CAAQ,CACb,EAAE,QAAF,EAAY,IAAZ,CAAiB,iBAAjB,EAAoC,MAApC,GACA,GAAI,CAAC,EAAE,MAAF,CAAS,KAAK,UAAd,CAAL,CAAgC,KAAK,UAAL,CAAgB,WAAhB,CAA4B,QAA5B,EAEhC,GAAI,aAAc,EAAE,iBAAF,EAAqB,IAArB,CAA0B,iBAA1B,CAAlB,CACA,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,QAA5B,CAAsC,CAClC,GAAM,WAAY,OAAO,IAAP,CAAY,4BAAZ,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CACA,eAAiB,WAAjB,CAA+B,WAClC,CAED,GAAI,WAAY,kFAAhB,CAEA,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,WAAa,iPAEhB,CAED,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,WAAa,kGAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,WAAa,kIAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,eAA5B,CAA6C,CACzC,WAAa,8HAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,WAAa,+FAC4C,YAAY,MAAZ,CAAmB,SAD/D,CAC0E,kBAD1E,CAC+F,WAD/F,CAC6G,6MAE7H,CAED,GAAI,YAAY,WAAZ,CAAwB,aAAxB,EAAyC,YAAY,WAAZ,CAAwB,WAArE,CAAkF,CAC9E,WAAa,2BAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,WAAa,4HAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,WAAa,0HAChB,CAED,WAAa,OAAb,CACA,MAAO,UACV,C,+CAEY,gBACT,EAAE,4BAAF,EAAgC,EAAhC,CAAmC,WAAnC,CAAgD,eAAS,CACrD,MAAM,cAAN,GACA,MAAK,QAAL,CAAc,KAAd,CACH,CAHD,EAIA,EAAE,0BAAF,EAA8B,EAA9B,CAAiC,aAAjC,CAAgD,eAAS,CACrD,MAAK,QAAL,CAAc,KAAd,CACH,CAFD,CAGH,C,0CAEQ,K,CAAO,iBACZ,GAAM,QAAS,EAAE,MAAM,MAAR,EAAgB,OAAhB,CAAwB,IAAxB,CAAf,CACA,GAAM,MAAO,EAAE,KAAK,QAAL,CAAc,MAAd,CAAF,CAAb,CAEA,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,UAA5B,CAAwC,OACxC,MAAM,cAAN,GAEA,EAAE,IAAF,EAAQ,QAAR,CAAiB,MAAjB,EACA,EAAE,IAAF,EAAQ,IAAR,CAAa,WAAb,CAA0B,EAAE,MAAM,MAAR,CAA1B,EAA2C,IAA3C,GAAkD,GAAlD,CAAsD,CAClD,SAAU,UADwC,CAElD,KAAM,MAAM,KAAN,CAAc,GAF8B,CAGlD,IAAK,MAAM,KAHuC,CAAtD,EAMA,KAAK,UAAL,CAAkB,MAAlB,CACA,KAAK,UAAL,CAAgB,QAAhB,CAAyB,QAAzB,EAGA,GAAM,SAAU,GAAI,aAAJ,CAAiB,MAAjB,CAAyB,IAAzB,CAAhB,CACA,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,EAAE,IAAF,EAAQ,IAAR,CAAa,wBAAb,EAAuC,MAAvC,GAAgD,EAAhD,CAAmD,OAAnD,CAA4D,WAAK,CAC7D,EAAE,cAAF,GACA,QAAQ,IAAR,EACH,CAHD,EAIA,EAAE,IAAF,EAAQ,IAAR,CAAa,0BAAb,EAAyC,MAAzC,GAAkD,EAAlD,CAAqD,OAArD,CAA8D,WAAK,CAC/D,EAAE,cAAF,GACA,QAAQ,MAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,EAAE,IAAF,EAAQ,IAAR,CAAa,wBAAb,EAAuC,MAAvC,GAAgD,EAAhD,CAAmD,OAAnD,CAA4D,WAAK,CAC7D,EAAE,cAAF,GACA,QAAQ,IAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,QAA5B,CAAsC,CAClC,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,WAA3C,CAAuD,QAAvD,CACH,CACD,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,MAA3C,GAAoD,EAApD,CAAuD,OAAvD,CAAgE,WAAK,CACjE,EAAE,cAAF,GACA,QAAQ,QAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,eAA5B,CAA6C,CACzC,GAAI,EAAE,OAAF,CAAU,CAAC,iBAAD,CAAoB,kBAApB,CAAwC,oBAAxC,CAAV,CAAyE,OAAO,IAAP,CAAY,MAAZ,CAAzE,EAA8F,MAA9F,CAAuG,CAA3G,CAA8G,CAC1G,EAAE,IAAF,EAAQ,IAAR,CAAa,8BAAb,EAA6C,WAA7C,CAAyD,QAAzD,CACH,CACD,EAAE,IAAF,EAAQ,IAAR,CAAa,8BAAb,EAA6C,MAA7C,GAAsD,EAAtD,CAAyD,OAAzD,CAAkE,WAAK,CACnE,EAAE,cAAF,GACA,QAAQ,UAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,EAAE,IAAF,EAAQ,IAAR,CAAa,0BAAb,EAAyC,MAAzC,GAAkD,EAAlD,CAAqD,OAArD,CAA8D,WAAK,CAC/D,EAAE,cAAF,GACA,QAAQ,MAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,MAA5B,CAAoC,CAChC,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,WAA3C,CAAuD,QAAvD,CACH,CACD,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,MAA3C,GAAoD,EAApD,CAAuD,OAAvD,CAAgE,WAAK,CACjE,EAAE,cAAF,GACA,QAAQ,QAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,EAAE,IAAF,EAAQ,IAAR,CAAa,0BAAb,EAAyC,MAAzC,GAAkD,EAAlD,CAAqD,OAArD,CAA8D,WAAK,CAC/D,EAAE,cAAF,GACA,QAAQ,MAAR,EACH,CAHD,CAIH,CAED,EAAE,MAAF,EAAU,MAAV,GAAmB,EAAnB,CAAsB,OAAtB,CAA+B,eAAS,CACpC,GAAG,EAAE,MAAM,MAAR,EAAgB,EAAhB,CAAmB,oBAAnB,CAAH,CAA6C,CACzC,MAAM,cAAN,GACA,MACH,CACD,EAAE,IAAF,EAAQ,MAAR,GAAiB,MAAjB,GACA,GAAG,CAAC,EAAE,MAAF,CAAS,OAAK,UAAd,CAAJ,CAA+B,OAAK,UAAL,CAAgB,WAAhB,CAA4B,QAA5B,CAClC,CAPD,CAQH,C,uDAEgB,CACb,EAAE,iCAAF,EAAqC,EAArC,CAAwC,OAAxC,CAAiD,SAAU,KAAV,CAAiB,CAC9D,MAAM,cAAN,GAEA,GAAM,MAAO,EAAE,IAAF,EAAQ,MAAR,GAAiB,IAAjB,CAAsB,MAAtB,GAAiC,EAA9C,CACA,GAAM,MAAO,EAAE,IAAF,EAAQ,MAAR,GAAiB,IAAjB,CAAsB,MAAtB,GAAiC,EAA9C,CAEA,OAAO,QAAP,CAAgB,IAAhB,CAAuB,mBAAmB,KAAO,IAA1B,CAAvB,CACA,MAAM,IAAN,EACH,CARD,CASH,C,+BAGL,OAAO,WAAP,CAAqB,GAAI,iBAAzB;ACtMA,a,q3BAqBM,Y,YACF,sBAAc,mCACV,KAAK,IAAL,CAAU,KAAK,UAAL,EAAV,CACH,C,0DAEI,I,CAAM,I,CAAM,gBACb,GAAI,EAAE,WAAF,CAAc,IAAd,CAAJ,CAAyB,CACrB,KAAO,KAAK,UAAL,EACV,CAED,KAAK,MAAL,CAAY,IAAZ,EACA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,IAAK,YAAY,IAAZ,CAAiB,aAFnB,CAGH,QAAS,CACL,eAAgB,YAAY,IAAZ,CAAiB,SAD5B,CAHN,CAMH,KAAM,CACF,UAAW,IADT,CANH,CAAP,EASG,IATH,CASQ,cAAQ,CACZ,MAAK,MAAL,CAAY,KAAZ,EACA,EAAE,aAAF,EAAiB,OAAjB,CAAyB,EAAzB,EAA6B,IAA7B,CAAkC,IAAlC,EAAwC,SAAxC,CAAkD,EAAlD,CAAsD,UAAM,CACxD,YAAY,GAAZ,GACA,MAAK,iBAAL,GACA,GAAI,EAAE,UAAF,CAAa,IAAb,CAAJ,CAAwB,CACpB,MAAO,OACV,CACJ,CAND,EAOA,EAAE,iBAAF,EAAqB,OAArB,GAEA,GAAI,OAAO,MAAP,mCAAO,KAAP,KAAiB,QAArB,CAA+B,CAC3B,MAAM,aAAN,CAAoB,SAAS,cAAT,CAAwB,oBAAxB,CAApB,CACH,CACJ,CAvBD,EAuBG,IAvBH,CAuBQ,eAAS,CACb,MAAK,MAAL,CAAY,KAAZ,EACA,GAAI,EAAE,UAAF,CAAa,IAAb,CAAJ,CAAwB,CACpB,MAAO,MAAK,GAAI,MAAJ,CAAU,8BAAV,CAAL,CACV,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,YAFN,CAGD,KAAM,8EAHL,CAAL,EAKA,QAAQ,KAAR,CAAc,KAAd,CACH,CAlCD,CAmCH,C,sCAEM,I,CAAM,CACT,GAAI,IAAJ,CAAS,CACL,EAAE,eAAF,EAAmB,MAAnB,CAA0B,GAA1B,CACH,CAFD,IAEO,CACH,EAAE,eAAF,EAAmB,OAAnB,CAA2B,GAA3B,CACH,CACJ,C,6DAEmB,iBAChB,EAAE,+BAAF,EAAmC,MAAnC,GAA4C,EAA5C,CAA+C,OAA/C,CAAwD,UAAM,CAC1D,EAAE,+BAAF,EAAmC,QAAnC,CAA4C,SAA5C,EACA,OAAK,IAAL,EACH,CAHD,CAIH,C,+CAEY,CACT,MAAO,oBAAmB,OAAO,QAAP,CAAgB,IAAhB,CAAqB,SAArB,CAA+B,CAA/B,CAAnB,CACV,C,0BAIL,OAAO,KAAP,CAAe,GAAI,YAAnB","file":"filemanager.min.js","sourcesContent":["\"use strict\";\n\n// Copyright (c) 2015 - 2016 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass ActionsClass {\n constructor(element, menu) {\n this.element = element;\n this.menu = menu;\n }\n\n destroy() {\n this.element = undefined;\n }\n\n folder() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n let inputValue = `${currentPath}${currentName}/`;\n if ($(this.element).data('type') === 'file') {\n inputValue = currentPath;\n }\n swal({\n type: 'input',\n title: 'Create Folder',\n text: 'Please enter the path and folder name below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: inputValue\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/folder`,\n timeout: 10000,\n data: JSON.stringify({\n path: val,\n }),\n }).done(data => {\n swal.close();\n Files.list();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n }\n\n move() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n swal({\n type: 'input',\n title: 'Move File',\n text: 'Please enter the new path for the file below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: `${currentPath}${currentName}`,\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/move`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${val}`,\n }),\n }).done(data => {\n nameBlock.parent().addClass('warning').delay(200).fadeOut();\n swal.close();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n\n }\n\n rename() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentLink = nameBlock.find('a');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const attachEditor = `\n \n \n `;\n\n nameBlock.html(attachEditor);\n const inputField = nameBlock.find('input');\n const inputLoader = nameBlock.find('.input-loader');\n\n inputField.focus();\n inputField.on('blur keydown', e => {\n // Save Field\n if (\n (e.type === 'keydown' && e.which === 27)\n || e.type === 'blur'\n || (e.type === 'keydown' && e.which === 13 && currentName === inputField.val())\n ) {\n if (!_.isEmpty(currentLink)) {\n nameBlock.html(currentLink);\n } else {\n nameBlock.html(currentName);\n }\n inputField.remove();\n ContextMenu.unbind().run();\n return;\n }\n\n if (e.type === 'keydown' && e.which !== 13) return;\n\n inputLoader.show();\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/rename`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${currentPath}${inputField.val()}`,\n }),\n }).done(data => {\n nameBlock.attr('data-name', inputField.val());\n if (!_.isEmpty(currentLink)) {\n let newLink = currentLink.attr('href');\n if (nameBlock.parent().data('type') !== 'folder') {\n newLink = newLink.substr(0, newLink.lastIndexOf('/')) + '/' + inputField.val();\n }\n currentLink.attr('href', newLink);\n nameBlock.html(\n currentLink.html(inputField.val())\n );\n } else {\n nameBlock.html(inputField.val());\n }\n inputField.remove();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n nameBlock.addClass('has-error').delay(2000).queue(() => {\n nameBlock.removeClass('has-error').dequeue();\n });\n inputField.popover({\n animation: true,\n placement: 'top',\n content: error,\n title: 'Save Error'\n }).popover('show');\n }).always(() => {\n inputLoader.remove();\n ContextMenu.unbind().run();\n });\n });\n }\n\n copy() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n swal({\n type: 'input',\n title: 'Copy File',\n text: 'Please enter the new path for the copied file below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: `${currentPath}${currentName}`,\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/copy`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${val}`,\n }),\n }).done(data => {\n swal({\n type: 'success',\n title: '',\n text: 'File successfully copied.'\n });\n Files.list();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n }\n\n download() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const fileName = decodeURIComponent(nameBlock.attr('data-name'));\n const filePath = decodeURIComponent(nameBlock.data('path'));\n\n window.location = `/server/${Pterodactyl.server.uuidShort}/files/download/${filePath}${fileName}`;\n }\n\n delete() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const delPath = decodeURIComponent(nameBlock.data('path'));\n const delName = decodeURIComponent(nameBlock.data('name'));\n\n swal({\n type: 'warning',\n title: '',\n text: 'Are you sure you want to delete ' + delName + '? There is no reversing this action.',\n html: true,\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true\n }, () => {\n $.ajax({\n type: 'DELETE',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/f/${delPath}${delName}`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n }\n }).done(data => {\n nameBlock.parent().addClass('warning').delay(200).fadeOut();\n swal({\n type: 'success',\n title: 'File Deleted'\n });\n }).fail(jqXHR => {\n console.error(jqXHR);\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: 'An error occured while attempting to delete this file. Please try again.',\n });\n });\n });\n }\n\n decompress() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const compPath = decodeURIComponent(nameBlock.data('path'));\n const compName = decodeURIComponent(nameBlock.data('name'));\n\n swal({\n title: ' Decompressing...',\n text: 'This might take a few seconds to complete.',\n html: true,\n allowOutsideClick: false,\n allowEscapeKey: false,\n showConfirmButton: false,\n });\n\n $.ajax({\n type: 'POST',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/decompress`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n data: JSON.stringify({\n files: `${compPath}${compName}`\n })\n }).done(data => {\n swal.close();\n Files.list(compPath);\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: error\n });\n });\n }\n\n compress() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const compPath = decodeURIComponent(nameBlock.data('path'));\n const compName = decodeURIComponent(nameBlock.data('name'));\n\n $.ajax({\n type: 'POST',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/compress`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n data: JSON.stringify({\n files: `${compPath}${compName}`,\n to: compPath.toString()\n })\n }).done(data => {\n Files.list(compPath, err => {\n if (err) return;\n const fileListing = $('#file_listing').find(`[data-name=\"${data.saved_as}\"]`).parent();\n fileListing.addClass('success pulsate').delay(3000).queue(() => {\n fileListing.removeClass('success pulsate').dequeue();\n });\n });\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: error\n });\n });\n }\n}\n","\"use strict\";\n\n// Copyright (c) 2015 - 2016 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass ContextMenuClass {\n constructor() {\n this.activeLine = null;\n }\n\n run() {\n this.directoryClick();\n this.rightClick();\n }\n\n makeMenu(parent) {\n $(document).find('#fileOptionMenu').remove();\n if (!_.isNull(this.activeLine)) this.activeLine.removeClass('active');\n\n let newFilePath = $('#headerTableRow').attr('data-currentDir');\n if (parent.data('type') === 'folder') {\n const nameBlock = parent.find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n newFilePath = `${currentPath}${currentName}`;\n }\n\n let buildMenu = '
        ';\n\n if (Pterodactyl.permissions.moveFiles) {\n buildMenu += '
      • Rename
      • \\\n
      • Move
      • ';\n }\n\n if (Pterodactyl.permissions.copyFiles) {\n buildMenu += '
      • Copy
      • ';\n }\n\n if (Pterodactyl.permissions.compressFiles) {\n buildMenu += '
      • Compress
      • ';\n }\n\n if (Pterodactyl.permissions.decompressFiles) {\n buildMenu += '
      • Decompress
      • ';\n }\n\n if (Pterodactyl.permissions.createFiles) {\n buildMenu += '
      • \\\n
      • New File
      • \\\n
      • New Folder
      • ';\n }\n\n if (Pterodactyl.permissions.downloadFiles || Pterodactyl.permissions.deleteFiles) {\n buildMenu += '
      • ';\n }\n\n if (Pterodactyl.permissions.downloadFiles) {\n buildMenu += '
      • Download
      • ';\n }\n\n if (Pterodactyl.permissions.deleteFiles) {\n buildMenu += '
      • Delete
      • ';\n }\n\n buildMenu += '
      ';\n return buildMenu;\n }\n\n rightClick() {\n $('[data-action=\"toggleMenu\"]').on('mousedown', event => {\n event.preventDefault();\n this.showMenu(event);\n });\n $('#file_listing > tbody td').on('contextmenu', event => {\n this.showMenu(event);\n });\n }\n\n showMenu(event) {\n const parent = $(event.target).closest('tr');\n const menu = $(this.makeMenu(parent));\n\n if (parent.data('type') === 'disabled') return;\n event.preventDefault();\n\n $(menu).appendTo('body');\n $(menu).data('invokedOn', $(event.target)).show().css({\n position: 'absolute',\n left: event.pageX - 150,\n top: event.pageY,\n });\n\n this.activeLine = parent;\n this.activeLine.addClass('active');\n\n // Handle Events\n const Actions = new ActionsClass(parent, menu);\n if (Pterodactyl.permissions.moveFiles) {\n $(menu).find('li[data-action=\"move\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.move();\n });\n $(menu).find('li[data-action=\"rename\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.rename();\n });\n }\n\n if (Pterodactyl.permissions.copyFiles) {\n $(menu).find('li[data-action=\"copy\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.copy();\n });\n }\n\n if (Pterodactyl.permissions.compressFiles) {\n if (parent.data('type') === 'folder') {\n $(menu).find('li[data-action=\"compress\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"compress\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.compress();\n });\n }\n\n if (Pterodactyl.permissions.decompressFiles) {\n if (_.without(['application/zip', 'application/gzip', 'application/x-gzip'], parent.data('mime')).length < 3) {\n $(menu).find('li[data-action=\"decompress\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"decompress\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.decompress();\n });\n }\n\n if (Pterodactyl.permissions.createFiles) {\n $(menu).find('li[data-action=\"folder\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.folder();\n });\n }\n\n if (Pterodactyl.permissions.downloadFiles) {\n if (parent.data('type') === 'file') {\n $(menu).find('li[data-action=\"download\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"download\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.download();\n });\n }\n\n if (Pterodactyl.permissions.deleteFiles) {\n $(menu).find('li[data-action=\"delete\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.delete();\n });\n }\n\n $(window).unbind().on('click', event => {\n if($(event.target).is('.disable-menu-hide')) {\n event.preventDefault();\n return;\n }\n $(menu).unbind().remove();\n if(!_.isNull(this.activeLine)) this.activeLine.removeClass('active');\n });\n }\n\n directoryClick() {\n $('a[data-action=\"directory-view\"]').on('click', function (event) {\n event.preventDefault();\n\n const path = $(this).parent().data('path') || '';\n const name = $(this).parent().data('name') || '';\n\n window.location.hash = encodeURIComponent(path + name);\n Files.list();\n });\n }\n}\n\nwindow.ContextMenu = new ContextMenuClass;\n","\"use strict\";\n\n// Copyright (c) 2015 - 2016 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass FileManager {\n constructor() {\n this.list(this.decodeHash());\n }\n\n list(path, next) {\n if (_.isUndefined(path)) {\n path = this.decodeHash();\n }\n\n this.loader(true);\n $.ajax({\n type: 'POST',\n url: Pterodactyl.meta.directoryList,\n headers: {\n 'X-CSRF-Token': Pterodactyl.meta.csrftoken,\n },\n data: {\n directory: path,\n },\n }).done(data => {\n this.loader(false);\n $('#load_files').slideUp(10).html(data).slideDown(10, () => {\n ContextMenu.run();\n this.reloadFilesButton();\n if (_.isFunction(next)) {\n return next();\n }\n });\n $('#internal_alert').slideUp();\n\n if (typeof Siofu === 'object') {\n Siofu.listenOnInput(document.getElementById(\"files_touch_target\"));\n }\n }).fail(jqXHR => {\n this.loader(false);\n if (_.isFunction(next)) {\n return next(new Error('Failed to load file listing.'));\n }\n swal({\n type: 'error',\n title: 'File Error',\n text: 'An error occured while attempting to process this request. Please try again.',\n });\n console.error(jqXHR);\n });\n }\n\n loader(show) {\n if (show){\n $('.file-overlay').fadeIn(100);\n } else {\n $('.file-overlay').fadeOut(100);\n }\n }\n\n reloadFilesButton() {\n $('i[data-action=\"reload-files\"]').unbind().on('click', () => {\n $('i[data-action=\"reload-files\"]').addClass('fa-spin');\n this.list();\n });\n }\n\n decodeHash() {\n return decodeURIComponent(window.location.hash.substring(1));\n }\n\n}\n\nwindow.Files = new FileManager;\n"]} \ No newline at end of file +{"version":3,"sources":["src/actions.js","src/contextmenu.js","src/index.js"],"names":[],"mappings":"AAAA,a,8oBAqBM,a,YACF,sBAAY,OAAZ,CAAqB,IAArB,CAA2B,oCACvB,KAAK,OAAL,CAAe,OAAf,CACA,KAAK,IAAL,CAAY,IACf,C,kEAES,CACN,KAAK,OAAL,CAAe,SAClB,C,uCAEQ,CACL,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,GAAI,eAAgB,WAAhB,CAA8B,WAA9B,IAAJ,CACA,GAAI,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,MAArB,IAAiC,MAArC,CAA6C,CACzC,WAAa,WAChB,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,eAFN,CAGD,KAAM,8CAHL,CAID,iBAAkB,IAJjB,CAKD,kBAAmB,IALlB,CAMD,eAAgB,KANf,CAOD,oBAAqB,IAPpB,CAQD,WAAY,UARX,CAAL,CASG,SAAC,GAAD,CAAS,CACR,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,sBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,KAAM,GADW,CAAf,CATH,CAAP,EAYG,IAZH,CAYQ,cAAQ,CACZ,KAAK,KAAL,GACA,MAAM,IAAN,EACH,CAfD,EAeG,IAfH,CAeQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,EAFN,CAGD,KAAM,KAHL,CAAL,CAKH,CA1BD,CA2BH,CArCD,CAsCH,C,mCAEM,CACH,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,KAAK,CACD,KAAM,OADL,CAED,MAAO,WAFN,CAGD,KAAM,+CAHL,CAID,iBAAkB,IAJjB,CAKD,kBAAmB,IALlB,CAMD,eAAgB,KANf,CAOD,oBAAqB,IAPpB,CAQD,cAAe,WAAf,CAA6B,WAR5B,CAAL,CASG,SAAC,GAAD,CAAS,CACR,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,oBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,QAAS,WAAT,CAAuB,WADN,CAEjB,MAAO,GAFU,CAAf,CATH,CAAP,EAaG,IAbH,CAaQ,cAAQ,CACZ,UAAU,MAAV,GAAmB,QAAnB,CAA4B,SAA5B,EAAuC,KAAvC,CAA6C,GAA7C,EAAkD,OAAlD,GACA,KAAK,KAAL,EACH,CAhBD,EAgBG,IAhBH,CAgBQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,EAFN,CAGD,KAAM,KAHL,CAAL,CAKH,CA3BD,CA4BH,CAtCD,CAwCH,C,uCAEQ,CACL,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,UAAU,IAAV,CAAe,GAAf,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,uFACwD,WADxD,4GAAN,CAKA,UAAU,IAAV,CAAe,YAAf,EACA,GAAM,YAAa,UAAU,IAAV,CAAe,OAAf,CAAnB,CACA,GAAM,aAAc,UAAU,IAAV,CAAe,eAAf,CAApB,CAEA,WAAW,KAAX,GACA,WAAW,EAAX,CAAc,cAAd,CAA8B,WAAK,CAE/B,GACK,EAAE,IAAF,GAAW,SAAX,EAAwB,EAAE,KAAF,GAAY,EAArC,EACG,EAAE,IAAF,GAAW,MADd,EAEI,EAAE,IAAF,GAAW,SAAX,EAAwB,EAAE,KAAF,GAAY,EAApC,EAA0C,cAAgB,WAAW,GAAX,EAHlE,CAIE,CACE,GAAI,CAAC,EAAE,OAAF,CAAU,WAAV,CAAL,CAA6B,CACzB,UAAU,IAAV,CAAe,WAAf,CACH,CAFD,IAEO,CACH,UAAU,IAAV,CAAe,WAAf,CACH,CACD,WAAW,MAAX,GACA,YAAY,MAAZ,GAAqB,GAArB,GACA,MACH,CAED,GAAI,EAAE,IAAF,GAAW,SAAX,EAAwB,EAAE,KAAF,GAAY,EAAxC,CAA4C,OAE5C,YAAY,IAAZ,GACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,sBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,QAAS,WAAT,CAAuB,WADN,CAEjB,MAAO,WAAP,CAAqB,WAAW,GAAX,EAFJ,CAAf,CATH,CAAP,EAaG,IAbH,CAaQ,cAAQ,CACZ,UAAU,IAAV,CAAe,WAAf,CAA4B,WAAW,GAAX,EAA5B,EACA,GAAI,CAAC,EAAE,OAAF,CAAU,WAAV,CAAL,CAA6B,CACzB,GAAI,SAAU,YAAY,IAAZ,CAAiB,MAAjB,CAAd,CACA,GAAI,UAAU,MAAV,GAAmB,IAAnB,CAAwB,MAAxB,IAAoC,QAAxC,CAAkD,CAC9C,QAAU,QAAQ,MAAR,CAAe,CAAf,CAAkB,QAAQ,WAAR,CAAoB,GAApB,CAAlB,EAA8C,GAA9C,CAAoD,WAAW,GAAX,EACjE,CACD,YAAY,IAAZ,CAAiB,MAAjB,CAAyB,OAAzB,EACA,UAAU,IAAV,CACI,YAAY,IAAZ,CAAiB,WAAW,GAAX,EAAjB,CADJ,CAGH,CATD,IASO,CACH,UAAU,IAAV,CAAe,WAAW,GAAX,EAAf,CACH,CACD,WAAW,MAAX,EACH,CA5BD,EA4BG,IA5BH,CA4BQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,UAAU,QAAV,CAAmB,WAAnB,EAAgC,KAAhC,CAAsC,IAAtC,EAA4C,KAA5C,CAAkD,UAAM,CACpD,UAAU,WAAV,CAAsB,WAAtB,EAAmC,OAAnC,EACH,CAFD,EAGA,WAAW,OAAX,CAAmB,CACf,UAAW,IADI,CAEf,UAAW,KAFI,CAGf,QAAS,KAHM,CAIf,MAAO,YAJQ,CAAnB,EAKG,OALH,CAKW,MALX,CAMH,CA3CD,EA2CG,MA3CH,CA2CU,UAAM,CACZ,YAAY,MAAZ,GACA,YAAY,MAAZ,GAAqB,GAArB,EACH,CA9CD,CA+CH,CArED,CAsEH,C,mCAEM,CACH,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CAEA,KAAK,CACD,KAAM,OADL,CAED,MAAO,WAFN,CAGD,KAAM,sDAHL,CAID,iBAAkB,IAJjB,CAKD,kBAAmB,IALlB,CAMD,eAAgB,KANf,CAOD,oBAAqB,IAPpB,CAQD,cAAe,WAAf,CAA6B,WAR5B,CAAL,CASG,SAAC,GAAD,CAAS,CACR,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAFN,CAMH,YAAa,iCANV,CAOH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,oBAPG,CAQH,QAAS,KARN,CASH,KAAM,KAAK,SAAL,CAAe,CACjB,QAAS,WAAT,CAAuB,WADN,CAEjB,MAAO,GAFU,CAAf,CATH,CAAP,EAaG,IAbH,CAaQ,cAAQ,CACZ,KAAK,CACD,KAAM,SADL,CAED,MAAO,EAFN,CAGD,KAAM,2BAHL,CAAL,EAKA,MAAM,IAAN,EACH,CApBD,EAoBG,IApBH,CAoBQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,EAFN,CAGD,KAAM,KAHL,CAAL,CAKH,CA/BD,CAgCH,CA1CD,CA2CH,C,2CAEU,CACP,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAAjB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CAEA,OAAO,QAAP,YAA6B,YAAY,MAAZ,CAAmB,SAAhD,oBAA4E,QAA5E,CAAuF,QAC1F,C,wCAEQ,CACL,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,SAAU,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAhB,CACA,GAAM,SAAU,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAhB,CAEA,KAAK,CACD,KAAM,SADL,CAED,MAAO,EAFN,CAGD,KAAM,yCAA2C,OAA3C,CAAqD,8DAH1D,CAID,KAAM,IAJL,CAKD,iBAAkB,IALjB,CAMD,kBAAmB,IANlB,CAOD,eAAgB,KAPf,CAQD,oBAAqB,IARpB,CAAL,CASG,UAAM,CACL,EAAE,IAAF,CAAO,CACH,KAAM,QADH,CAEH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,mBAA6G,OAA7G,CAAuH,OAFpH,CAGH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAHN,CAAP,EAOG,IAPH,CAOQ,cAAQ,CACZ,UAAU,MAAV,GAAmB,QAAnB,CAA4B,SAA5B,EAAuC,KAAvC,CAA6C,GAA7C,EAAkD,OAAlD,GACA,KAAK,CACD,KAAM,SADL,CAED,MAAO,cAFN,CAAL,CAIH,CAbD,EAaG,IAbH,CAaQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,KAAK,CACD,KAAM,OADL,CAED,MAAO,SAFN,CAGD,KAAM,IAHL,CAID,KAAM,0EAJL,CAAL,CAMH,CArBD,CAsBH,CAhCD,CAiCH,C,+CAEY,CACT,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CAEA,KAAK,CACD,MAAO,wDADN,CAED,KAAM,4CAFL,CAGD,KAAM,IAHL,CAID,kBAAmB,KAJlB,CAKD,eAAgB,KALf,CAMD,kBAAmB,KANlB,CAAL,EASA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,0BAFG,CAGH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAHN,CAOH,YAAa,iCAPV,CAQH,KAAM,KAAK,SAAL,CAAe,CACjB,SAAU,QAAV,CAAqB,QADJ,CAAf,CARH,CAAP,EAWG,IAXH,CAWQ,cAAQ,CACZ,KAAK,KAAL,GACA,MAAM,IAAN,CAAW,QAAX,CACH,CAdD,EAcG,IAdH,CAcQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,SAFN,CAGD,KAAM,IAHL,CAID,KAAM,KAJL,CAAL,CAMH,CA1BD,CA2BH,C,2CAEU,CACP,GAAM,WAAY,EAAE,KAAK,OAAP,EAAgB,IAAhB,CAAqB,4BAArB,CAAlB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CACA,GAAM,UAAW,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAAjB,CAEA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,IAAQ,YAAY,IAAZ,CAAiB,MAAzB,OAAqC,YAAY,IAAZ,CAAiB,IAAtD,KAA8D,YAAY,IAAZ,CAAiB,YAA/E,wBAFG,CAGH,QAAS,CACL,iBAAkB,YAAY,MAAZ,CAAmB,YADhC,CAEL,kBAAmB,YAAY,MAAZ,CAAmB,IAFjC,CAHN,CAOH,YAAa,iCAPV,CAQH,KAAM,KAAK,SAAL,CAAe,CACjB,SAAU,QAAV,CAAqB,QADJ,CAEjB,GAAI,SAAS,QAAT,EAFa,CAAf,CARH,CAAP,EAYG,IAZH,CAYQ,cAAQ,CACZ,MAAM,IAAN,CAAW,QAAX,CAAqB,aAAO,CACxB,GAAI,GAAJ,CAAS,OACT,GAAM,aAAc,EAAE,eAAF,EAAmB,IAAnB,gBAAuC,KAAK,QAA5C,OAA0D,MAA1D,EAApB,CACA,YAAY,QAAZ,CAAqB,iBAArB,EAAwC,KAAxC,CAA8C,IAA9C,EAAoD,KAApD,CAA0D,UAAM,CAC5D,YAAY,WAAZ,CAAwB,iBAAxB,EAA2C,OAA3C,EACH,CAFD,CAGH,CAND,CAOH,CApBD,EAoBG,IApBH,CAoBQ,eAAS,CACb,QAAQ,KAAR,CAAc,KAAd,EACA,GAAI,OAAQ,wDAAZ,CACA,GAAI,MAAO,OAAM,YAAb,GAA8B,WAA9B,EAA6C,MAAO,OAAM,YAAN,CAAmB,KAA1B,GAAoC,WAArF,CAAkG,CAC9F,MAAQ,MAAM,YAAN,CAAmB,KAC9B,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,SAFN,CAGD,KAAM,IAHL,CAID,KAAM,KAJL,CAAL,CAMH,CAhCD,CAiCH,C;;ACxYL,a,8oBAqBM,iB,YACF,2BAAc,wCACV,KAAK,UAAL,CAAkB,IACrB,C,8DAEK,CACF,KAAK,cAAL,GACA,KAAK,UAAL,EACH,C,0CAEQ,M,CAAQ,CACb,EAAE,QAAF,EAAY,IAAZ,CAAiB,iBAAjB,EAAoC,MAApC,GACA,GAAI,CAAC,EAAE,MAAF,CAAS,KAAK,UAAd,CAAL,CAAgC,KAAK,UAAL,CAAgB,WAAhB,CAA4B,QAA5B,EAEhC,GAAI,aAAc,EAAE,iBAAF,EAAqB,IAArB,CAA0B,iBAA1B,CAAlB,CACA,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,QAA5B,CAAsC,CAClC,GAAM,WAAY,OAAO,IAAP,CAAY,4BAAZ,CAAlB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,WAAf,CAAnB,CAApB,CACA,GAAM,aAAc,mBAAmB,UAAU,IAAV,CAAe,MAAf,CAAnB,CAApB,CACA,eAAiB,WAAjB,CAA+B,WAClC,CAED,GAAI,WAAY,kFAAhB,CAEA,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,WAAa,iPAEhB,CAED,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,WAAa,kGAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,WAAa,kIAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,eAA5B,CAA6C,CACzC,WAAa,8HAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,WAAa,+FAC4C,YAAY,MAAZ,CAAmB,SAD/D,CAC0E,kBAD1E,CAC+F,WAD/F,CAC6G,6MAE7H,CAED,GAAI,YAAY,WAAZ,CAAwB,aAAxB,EAAyC,YAAY,WAAZ,CAAwB,WAArE,CAAkF,CAC9E,WAAa,2BAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,WAAa,4HAChB,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,WAAa,0HAChB,CAED,WAAa,OAAb,CACA,MAAO,UACV,C,+CAEY,gBACT,EAAE,4BAAF,EAAgC,EAAhC,CAAmC,WAAnC,CAAgD,eAAS,CACrD,MAAM,cAAN,GACA,MAAK,QAAL,CAAc,KAAd,CACH,CAHD,EAIA,EAAE,0BAAF,EAA8B,EAA9B,CAAiC,aAAjC,CAAgD,eAAS,CACrD,MAAK,QAAL,CAAc,KAAd,CACH,CAFD,CAGH,C,0CAEQ,K,CAAO,iBACZ,GAAM,QAAS,EAAE,MAAM,MAAR,EAAgB,OAAhB,CAAwB,IAAxB,CAAf,CACA,GAAM,MAAO,EAAE,KAAK,QAAL,CAAc,MAAd,CAAF,CAAb,CAEA,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,UAA5B,CAAwC,OACxC,MAAM,cAAN,GAEA,EAAE,IAAF,EAAQ,QAAR,CAAiB,MAAjB,EACA,EAAE,IAAF,EAAQ,IAAR,CAAa,WAAb,CAA0B,EAAE,MAAM,MAAR,CAA1B,EAA2C,IAA3C,GAAkD,GAAlD,CAAsD,CAClD,SAAU,UADwC,CAElD,KAAM,MAAM,KAAN,CAAc,GAF8B,CAGlD,IAAK,MAAM,KAHuC,CAAtD,EAMA,KAAK,UAAL,CAAkB,MAAlB,CACA,KAAK,UAAL,CAAgB,QAAhB,CAAyB,QAAzB,EAGA,GAAM,SAAU,GAAI,aAAJ,CAAiB,MAAjB,CAAyB,IAAzB,CAAhB,CACA,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,EAAE,IAAF,EAAQ,IAAR,CAAa,wBAAb,EAAuC,MAAvC,GAAgD,EAAhD,CAAmD,OAAnD,CAA4D,WAAK,CAC7D,EAAE,cAAF,GACA,QAAQ,IAAR,EACH,CAHD,EAIA,EAAE,IAAF,EAAQ,IAAR,CAAa,0BAAb,EAAyC,MAAzC,GAAkD,EAAlD,CAAqD,OAArD,CAA8D,WAAK,CAC/D,EAAE,cAAF,GACA,QAAQ,MAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,SAA5B,CAAuC,CACnC,EAAE,IAAF,EAAQ,IAAR,CAAa,wBAAb,EAAuC,MAAvC,GAAgD,EAAhD,CAAmD,OAAnD,CAA4D,WAAK,CAC7D,EAAE,cAAF,GACA,QAAQ,IAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,QAA5B,CAAsC,CAClC,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,WAA3C,CAAuD,QAAvD,CACH,CACD,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,MAA3C,GAAoD,EAApD,CAAuD,OAAvD,CAAgE,WAAK,CACjE,EAAE,cAAF,GACA,QAAQ,QAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,eAA5B,CAA6C,CACzC,GAAI,EAAE,OAAF,CAAU,CAAC,iBAAD,CAAoB,kBAApB,CAAwC,oBAAxC,CAAV,CAAyE,OAAO,IAAP,CAAY,MAAZ,CAAzE,EAA8F,MAA9F,CAAuG,CAA3G,CAA8G,CAC1G,EAAE,IAAF,EAAQ,IAAR,CAAa,8BAAb,EAA6C,WAA7C,CAAyD,QAAzD,CACH,CACD,EAAE,IAAF,EAAQ,IAAR,CAAa,8BAAb,EAA6C,MAA7C,GAAsD,EAAtD,CAAyD,OAAzD,CAAkE,WAAK,CACnE,EAAE,cAAF,GACA,QAAQ,UAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,EAAE,IAAF,EAAQ,IAAR,CAAa,0BAAb,EAAyC,MAAzC,GAAkD,EAAlD,CAAqD,OAArD,CAA8D,WAAK,CAC/D,EAAE,cAAF,GACA,QAAQ,MAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,aAA5B,CAA2C,CACvC,GAAI,OAAO,IAAP,CAAY,MAAZ,IAAwB,MAA5B,CAAoC,CAChC,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,WAA3C,CAAuD,QAAvD,CACH,CACD,EAAE,IAAF,EAAQ,IAAR,CAAa,4BAAb,EAA2C,MAA3C,GAAoD,EAApD,CAAuD,OAAvD,CAAgE,WAAK,CACjE,EAAE,cAAF,GACA,QAAQ,QAAR,EACH,CAHD,CAIH,CAED,GAAI,YAAY,WAAZ,CAAwB,WAA5B,CAAyC,CACrC,EAAE,IAAF,EAAQ,IAAR,CAAa,0BAAb,EAAyC,MAAzC,GAAkD,EAAlD,CAAqD,OAArD,CAA8D,WAAK,CAC/D,EAAE,cAAF,GACA,QAAQ,MAAR,EACH,CAHD,CAIH,CAED,EAAE,MAAF,EAAU,MAAV,GAAmB,EAAnB,CAAsB,OAAtB,CAA+B,eAAS,CACpC,GAAG,EAAE,MAAM,MAAR,EAAgB,EAAhB,CAAmB,oBAAnB,CAAH,CAA6C,CACzC,MAAM,cAAN,GACA,MACH,CACD,EAAE,IAAF,EAAQ,MAAR,GAAiB,MAAjB,GACA,GAAG,CAAC,EAAE,MAAF,CAAS,OAAK,UAAd,CAAJ,CAA+B,OAAK,UAAL,CAAgB,WAAhB,CAA4B,QAA5B,CAClC,CAPD,CAQH,C,uDAEgB,CACb,EAAE,iCAAF,EAAqC,EAArC,CAAwC,OAAxC,CAAiD,SAAU,KAAV,CAAiB,CAC9D,MAAM,cAAN,GAEA,GAAM,MAAO,EAAE,IAAF,EAAQ,MAAR,GAAiB,IAAjB,CAAsB,MAAtB,GAAiC,EAA9C,CACA,GAAM,MAAO,EAAE,IAAF,EAAQ,MAAR,GAAiB,IAAjB,CAAsB,MAAtB,GAAiC,EAA9C,CAEA,OAAO,QAAP,CAAgB,IAAhB,CAAuB,mBAAmB,KAAO,IAA1B,CAAvB,CACA,MAAM,IAAN,EACH,CARD,CASH,C,+BAGL,OAAO,WAAP,CAAqB,GAAI,iBAAzB;ACtMA,a,q3BAqBM,Y,YACF,sBAAc,mCACV,KAAK,IAAL,CAAU,KAAK,UAAL,EAAV,CACH,C,0DAEI,I,CAAM,I,CAAM,gBACb,GAAI,EAAE,WAAF,CAAc,IAAd,CAAJ,CAAyB,CACrB,KAAO,KAAK,UAAL,EACV,CAED,KAAK,MAAL,CAAY,IAAZ,EACA,EAAE,IAAF,CAAO,CACH,KAAM,MADH,CAEH,IAAK,YAAY,IAAZ,CAAiB,aAFnB,CAGH,QAAS,CACL,eAAgB,YAAY,IAAZ,CAAiB,SAD5B,CAHN,CAMH,KAAM,CACF,UAAW,IADT,CANH,CAAP,EASG,IATH,CASQ,cAAQ,CACZ,MAAK,MAAL,CAAY,KAAZ,EACA,EAAE,aAAF,EAAiB,OAAjB,CAAyB,EAAzB,EAA6B,IAA7B,CAAkC,IAAlC,EAAwC,SAAxC,CAAkD,EAAlD,CAAsD,UAAM,CACxD,YAAY,GAAZ,GACA,MAAK,iBAAL,GACA,GAAI,EAAE,UAAF,CAAa,IAAb,CAAJ,CAAwB,CACpB,MAAO,OACV,CACJ,CAND,EAOA,EAAE,iBAAF,EAAqB,OAArB,GAEA,GAAI,OAAO,MAAP,mCAAO,KAAP,KAAiB,QAArB,CAA+B,CAC3B,MAAM,aAAN,CAAoB,SAAS,cAAT,CAAwB,oBAAxB,CAApB,CACH,CACJ,CAvBD,EAuBG,IAvBH,CAuBQ,eAAS,CACb,MAAK,MAAL,CAAY,KAAZ,EACA,GAAI,EAAE,UAAF,CAAa,IAAb,CAAJ,CAAwB,CACpB,MAAO,MAAK,GAAI,MAAJ,CAAU,8BAAV,CAAL,CACV,CACD,KAAK,CACD,KAAM,OADL,CAED,MAAO,YAFN,CAGD,KAAM,8EAHL,CAAL,EAKA,QAAQ,KAAR,CAAc,KAAd,CACH,CAlCD,CAmCH,C,sCAEM,I,CAAM,CACT,GAAI,IAAJ,CAAS,CACL,EAAE,eAAF,EAAmB,MAAnB,CAA0B,GAA1B,CACH,CAFD,IAEO,CACH,EAAE,eAAF,EAAmB,OAAnB,CAA2B,GAA3B,CACH,CACJ,C,6DAEmB,iBAChB,EAAE,+BAAF,EAAmC,MAAnC,GAA4C,EAA5C,CAA+C,OAA/C,CAAwD,UAAM,CAC1D,EAAE,+BAAF,EAAmC,QAAnC,CAA4C,SAA5C,EACA,OAAK,IAAL,EACH,CAHD,CAIH,C,+CAEY,CACT,MAAO,oBAAmB,OAAO,QAAP,CAAgB,IAAhB,CAAqB,SAArB,CAA+B,CAA/B,CAAnB,CACV,C,0BAIL,OAAO,KAAP,CAAe,GAAI,YAAnB","file":"filemanager.min.js","sourcesContent":["\"use strict\";\n\n// Copyright (c) 2015 - 2017 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass ActionsClass {\n constructor(element, menu) {\n this.element = element;\n this.menu = menu;\n }\n\n destroy() {\n this.element = undefined;\n }\n\n folder() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n let inputValue = `${currentPath}${currentName}/`;\n if ($(this.element).data('type') === 'file') {\n inputValue = currentPath;\n }\n swal({\n type: 'input',\n title: 'Create Folder',\n text: 'Please enter the path and folder name below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: inputValue\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/folder`,\n timeout: 10000,\n data: JSON.stringify({\n path: val,\n }),\n }).done(data => {\n swal.close();\n Files.list();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n }\n\n move() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n swal({\n type: 'input',\n title: 'Move File',\n text: 'Please enter the new path for the file below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: `${currentPath}${currentName}`,\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/move`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${val}`,\n }),\n }).done(data => {\n nameBlock.parent().addClass('warning').delay(200).fadeOut();\n swal.close();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n\n }\n\n rename() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentLink = nameBlock.find('a');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const attachEditor = `\n \n \n `;\n\n nameBlock.html(attachEditor);\n const inputField = nameBlock.find('input');\n const inputLoader = nameBlock.find('.input-loader');\n\n inputField.focus();\n inputField.on('blur keydown', e => {\n // Save Field\n if (\n (e.type === 'keydown' && e.which === 27)\n || e.type === 'blur'\n || (e.type === 'keydown' && e.which === 13 && currentName === inputField.val())\n ) {\n if (!_.isEmpty(currentLink)) {\n nameBlock.html(currentLink);\n } else {\n nameBlock.html(currentName);\n }\n inputField.remove();\n ContextMenu.unbind().run();\n return;\n }\n\n if (e.type === 'keydown' && e.which !== 13) return;\n\n inputLoader.show();\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/rename`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${currentPath}${inputField.val()}`,\n }),\n }).done(data => {\n nameBlock.attr('data-name', inputField.val());\n if (!_.isEmpty(currentLink)) {\n let newLink = currentLink.attr('href');\n if (nameBlock.parent().data('type') !== 'folder') {\n newLink = newLink.substr(0, newLink.lastIndexOf('/')) + '/' + inputField.val();\n }\n currentLink.attr('href', newLink);\n nameBlock.html(\n currentLink.html(inputField.val())\n );\n } else {\n nameBlock.html(inputField.val());\n }\n inputField.remove();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n nameBlock.addClass('has-error').delay(2000).queue(() => {\n nameBlock.removeClass('has-error').dequeue();\n });\n inputField.popover({\n animation: true,\n placement: 'top',\n content: error,\n title: 'Save Error'\n }).popover('show');\n }).always(() => {\n inputLoader.remove();\n ContextMenu.unbind().run();\n });\n });\n }\n\n copy() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n swal({\n type: 'input',\n title: 'Copy File',\n text: 'Please enter the new path for the copied file below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: `${currentPath}${currentName}`,\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/copy`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${val}`,\n }),\n }).done(data => {\n swal({\n type: 'success',\n title: '',\n text: 'File successfully copied.'\n });\n Files.list();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n }\n\n download() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const fileName = decodeURIComponent(nameBlock.attr('data-name'));\n const filePath = decodeURIComponent(nameBlock.data('path'));\n\n window.location = `/server/${Pterodactyl.server.uuidShort}/files/download/${filePath}${fileName}`;\n }\n\n delete() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const delPath = decodeURIComponent(nameBlock.data('path'));\n const delName = decodeURIComponent(nameBlock.data('name'));\n\n swal({\n type: 'warning',\n title: '',\n text: 'Are you sure you want to delete ' + delName + '? There is no reversing this action.',\n html: true,\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true\n }, () => {\n $.ajax({\n type: 'DELETE',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/f/${delPath}${delName}`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n }\n }).done(data => {\n nameBlock.parent().addClass('warning').delay(200).fadeOut();\n swal({\n type: 'success',\n title: 'File Deleted'\n });\n }).fail(jqXHR => {\n console.error(jqXHR);\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: 'An error occured while attempting to delete this file. Please try again.',\n });\n });\n });\n }\n\n decompress() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const compPath = decodeURIComponent(nameBlock.data('path'));\n const compName = decodeURIComponent(nameBlock.data('name'));\n\n swal({\n title: ' Decompressing...',\n text: 'This might take a few seconds to complete.',\n html: true,\n allowOutsideClick: false,\n allowEscapeKey: false,\n showConfirmButton: false,\n });\n\n $.ajax({\n type: 'POST',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/decompress`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n data: JSON.stringify({\n files: `${compPath}${compName}`\n })\n }).done(data => {\n swal.close();\n Files.list(compPath);\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: error\n });\n });\n }\n\n compress() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const compPath = decodeURIComponent(nameBlock.data('path'));\n const compName = decodeURIComponent(nameBlock.data('name'));\n\n $.ajax({\n type: 'POST',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/compress`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n data: JSON.stringify({\n files: `${compPath}${compName}`,\n to: compPath.toString()\n })\n }).done(data => {\n Files.list(compPath, err => {\n if (err) return;\n const fileListing = $('#file_listing').find(`[data-name=\"${data.saved_as}\"]`).parent();\n fileListing.addClass('success pulsate').delay(3000).queue(() => {\n fileListing.removeClass('success pulsate').dequeue();\n });\n });\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: error\n });\n });\n }\n}\n","\"use strict\";\n\n// Copyright (c) 2015 - 2017 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass ContextMenuClass {\n constructor() {\n this.activeLine = null;\n }\n\n run() {\n this.directoryClick();\n this.rightClick();\n }\n\n makeMenu(parent) {\n $(document).find('#fileOptionMenu').remove();\n if (!_.isNull(this.activeLine)) this.activeLine.removeClass('active');\n\n let newFilePath = $('#headerTableRow').attr('data-currentDir');\n if (parent.data('type') === 'folder') {\n const nameBlock = parent.find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n newFilePath = `${currentPath}${currentName}`;\n }\n\n let buildMenu = '
        ';\n\n if (Pterodactyl.permissions.moveFiles) {\n buildMenu += '
      • Rename
      • \\\n
      • Move
      • ';\n }\n\n if (Pterodactyl.permissions.copyFiles) {\n buildMenu += '
      • Copy
      • ';\n }\n\n if (Pterodactyl.permissions.compressFiles) {\n buildMenu += '
      • Compress
      • ';\n }\n\n if (Pterodactyl.permissions.decompressFiles) {\n buildMenu += '
      • Decompress
      • ';\n }\n\n if (Pterodactyl.permissions.createFiles) {\n buildMenu += '
      • \\\n
      • New File
      • \\\n
      • New Folder
      • ';\n }\n\n if (Pterodactyl.permissions.downloadFiles || Pterodactyl.permissions.deleteFiles) {\n buildMenu += '
      • ';\n }\n\n if (Pterodactyl.permissions.downloadFiles) {\n buildMenu += '
      • Download
      • ';\n }\n\n if (Pterodactyl.permissions.deleteFiles) {\n buildMenu += '
      • Delete
      • ';\n }\n\n buildMenu += '
      ';\n return buildMenu;\n }\n\n rightClick() {\n $('[data-action=\"toggleMenu\"]').on('mousedown', event => {\n event.preventDefault();\n this.showMenu(event);\n });\n $('#file_listing > tbody td').on('contextmenu', event => {\n this.showMenu(event);\n });\n }\n\n showMenu(event) {\n const parent = $(event.target).closest('tr');\n const menu = $(this.makeMenu(parent));\n\n if (parent.data('type') === 'disabled') return;\n event.preventDefault();\n\n $(menu).appendTo('body');\n $(menu).data('invokedOn', $(event.target)).show().css({\n position: 'absolute',\n left: event.pageX - 150,\n top: event.pageY,\n });\n\n this.activeLine = parent;\n this.activeLine.addClass('active');\n\n // Handle Events\n const Actions = new ActionsClass(parent, menu);\n if (Pterodactyl.permissions.moveFiles) {\n $(menu).find('li[data-action=\"move\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.move();\n });\n $(menu).find('li[data-action=\"rename\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.rename();\n });\n }\n\n if (Pterodactyl.permissions.copyFiles) {\n $(menu).find('li[data-action=\"copy\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.copy();\n });\n }\n\n if (Pterodactyl.permissions.compressFiles) {\n if (parent.data('type') === 'folder') {\n $(menu).find('li[data-action=\"compress\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"compress\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.compress();\n });\n }\n\n if (Pterodactyl.permissions.decompressFiles) {\n if (_.without(['application/zip', 'application/gzip', 'application/x-gzip'], parent.data('mime')).length < 3) {\n $(menu).find('li[data-action=\"decompress\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"decompress\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.decompress();\n });\n }\n\n if (Pterodactyl.permissions.createFiles) {\n $(menu).find('li[data-action=\"folder\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.folder();\n });\n }\n\n if (Pterodactyl.permissions.downloadFiles) {\n if (parent.data('type') === 'file') {\n $(menu).find('li[data-action=\"download\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"download\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.download();\n });\n }\n\n if (Pterodactyl.permissions.deleteFiles) {\n $(menu).find('li[data-action=\"delete\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.delete();\n });\n }\n\n $(window).unbind().on('click', event => {\n if($(event.target).is('.disable-menu-hide')) {\n event.preventDefault();\n return;\n }\n $(menu).unbind().remove();\n if(!_.isNull(this.activeLine)) this.activeLine.removeClass('active');\n });\n }\n\n directoryClick() {\n $('a[data-action=\"directory-view\"]').on('click', function (event) {\n event.preventDefault();\n\n const path = $(this).parent().data('path') || '';\n const name = $(this).parent().data('name') || '';\n\n window.location.hash = encodeURIComponent(path + name);\n Files.list();\n });\n }\n}\n\nwindow.ContextMenu = new ContextMenuClass;\n","\"use strict\";\n\n// Copyright (c) 2015 - 2017 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass FileManager {\n constructor() {\n this.list(this.decodeHash());\n }\n\n list(path, next) {\n if (_.isUndefined(path)) {\n path = this.decodeHash();\n }\n\n this.loader(true);\n $.ajax({\n type: 'POST',\n url: Pterodactyl.meta.directoryList,\n headers: {\n 'X-CSRF-Token': Pterodactyl.meta.csrftoken,\n },\n data: {\n directory: path,\n },\n }).done(data => {\n this.loader(false);\n $('#load_files').slideUp(10).html(data).slideDown(10, () => {\n ContextMenu.run();\n this.reloadFilesButton();\n if (_.isFunction(next)) {\n return next();\n }\n });\n $('#internal_alert').slideUp();\n\n if (typeof Siofu === 'object') {\n Siofu.listenOnInput(document.getElementById(\"files_touch_target\"));\n }\n }).fail(jqXHR => {\n this.loader(false);\n if (_.isFunction(next)) {\n return next(new Error('Failed to load file listing.'));\n }\n swal({\n type: 'error',\n title: 'File Error',\n text: 'An error occured while attempting to process this request. Please try again.',\n });\n console.error(jqXHR);\n });\n }\n\n loader(show) {\n if (show){\n $('.file-overlay').fadeIn(100);\n } else {\n $('.file-overlay').fadeOut(100);\n }\n }\n\n reloadFilesButton() {\n $('i[data-action=\"reload-files\"]').unbind().on('click', () => {\n $('i[data-action=\"reload-files\"]').addClass('fa-spin');\n this.list();\n });\n }\n\n decodeHash() {\n return decodeURIComponent(window.location.hash.substring(1));\n }\n\n}\n\nwindow.Files = new FileManager;\n"]} \ No newline at end of file diff --git a/public/themes/pterodactyl/js/frontend/files/src/actions.js b/public/themes/pterodactyl/js/frontend/files/src/actions.js index 9ff978539..f286f4c1f 100644 --- a/public/themes/pterodactyl/js/frontend/files/src/actions.js +++ b/public/themes/pterodactyl/js/frontend/files/src/actions.js @@ -1,6 +1,6 @@ "use strict"; -// Copyright (c) 2015 - 2016 Dane Everitt +// 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 diff --git a/public/themes/pterodactyl/js/frontend/files/src/contextmenu.js b/public/themes/pterodactyl/js/frontend/files/src/contextmenu.js index dd6c37f56..2e51b095c 100644 --- a/public/themes/pterodactyl/js/frontend/files/src/contextmenu.js +++ b/public/themes/pterodactyl/js/frontend/files/src/contextmenu.js @@ -1,6 +1,6 @@ "use strict"; -// Copyright (c) 2015 - 2016 Dane Everitt +// 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 diff --git a/public/themes/pterodactyl/js/frontend/files/src/index.js b/public/themes/pterodactyl/js/frontend/files/src/index.js index b7edbce8c..ac5d3fa16 100644 --- a/public/themes/pterodactyl/js/frontend/files/src/index.js +++ b/public/themes/pterodactyl/js/frontend/files/src/index.js @@ -1,6 +1,6 @@ "use strict"; -// Copyright (c) 2015 - 2016 Dane Everitt +// 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 diff --git a/public/themes/pterodactyl/js/frontend/files/upload.js b/public/themes/pterodactyl/js/frontend/files/upload.js index 452ceaf5e..7e2477029 100644 --- a/public/themes/pterodactyl/js/frontend/files/upload.js +++ b/public/themes/pterodactyl/js/frontend/files/upload.js @@ -1,4 +1,4 @@ -// Copyright (c) 2015 - 2016 Dane Everitt +// 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 diff --git a/public/themes/pterodactyl/js/frontend/server.socket.js b/public/themes/pterodactyl/js/frontend/server.socket.js index 64b1c78a2..49b22ddf0 100644 --- a/public/themes/pterodactyl/js/frontend/server.socket.js +++ b/public/themes/pterodactyl/js/frontend/server.socket.js @@ -1,4 +1,4 @@ -// Copyright (c) 2015 - 2016 Dane Everitt +// 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 diff --git a/public/themes/pterodactyl/js/frontend/serverlist.js b/public/themes/pterodactyl/js/frontend/serverlist.js index 12929c2ab..605c33d2f 100644 --- a/public/themes/pterodactyl/js/frontend/serverlist.js +++ b/public/themes/pterodactyl/js/frontend/serverlist.js @@ -1,4 +1,4 @@ -// Copyright (c) 2015 - 2016 Dane Everitt +// 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 diff --git a/public/themes/pterodactyl/js/frontend/tasks.js b/public/themes/pterodactyl/js/frontend/tasks.js index c990559e7..38563a92b 100644 --- a/public/themes/pterodactyl/js/frontend/tasks.js +++ b/public/themes/pterodactyl/js/frontend/tasks.js @@ -1,4 +1,4 @@ -// Copyright (c) 2015 - 2016 Dane Everitt +// 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 diff --git a/resources/themes/pterodactyl/auth/login.blade.php b/resources/themes/pterodactyl/auth/login.blade.php index 6582356ad..82ff3d564 100644 --- a/resources/themes/pterodactyl/auth/login.blade.php +++ b/resources/themes/pterodactyl/auth/login.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/auth/passwords/email.blade.php b/resources/themes/pterodactyl/auth/passwords/email.blade.php index a8e8202bb..317c6d842 100644 --- a/resources/themes/pterodactyl/auth/passwords/email.blade.php +++ b/resources/themes/pterodactyl/auth/passwords/email.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/auth/passwords/reset.blade.php b/resources/themes/pterodactyl/auth/passwords/reset.blade.php index cc1998e15..cb00994e0 100644 --- a/resources/themes/pterodactyl/auth/passwords/reset.blade.php +++ b/resources/themes/pterodactyl/auth/passwords/reset.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/base/account.blade.php b/resources/themes/pterodactyl/base/account.blade.php index beec27402..75615dfa0 100644 --- a/resources/themes/pterodactyl/base/account.blade.php +++ b/resources/themes/pterodactyl/base/account.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/base/api/index.blade.php b/resources/themes/pterodactyl/base/api/index.blade.php index be921614c..6509d891f 100644 --- a/resources/themes/pterodactyl/base/api/index.blade.php +++ b/resources/themes/pterodactyl/base/api/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/base/api/new.blade.php b/resources/themes/pterodactyl/base/api/new.blade.php index 8030d671c..d2778b3c9 100644 --- a/resources/themes/pterodactyl/base/api/new.blade.php +++ b/resources/themes/pterodactyl/base/api/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/base/index.blade.php b/resources/themes/pterodactyl/base/index.blade.php index 25e2e4f4b..c6066c25a 100644 --- a/resources/themes/pterodactyl/base/index.blade.php +++ b/resources/themes/pterodactyl/base/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/base/security.blade.php b/resources/themes/pterodactyl/base/security.blade.php index cab949ea8..666a790bc 100644 --- a/resources/themes/pterodactyl/base/security.blade.php +++ b/resources/themes/pterodactyl/base/security.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/errors/403.blade.php b/resources/themes/pterodactyl/errors/403.blade.php index f46e14751..225852a15 100644 --- a/resources/themes/pterodactyl/errors/403.blade.php +++ b/resources/themes/pterodactyl/errors/403.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/errors/404.blade.php b/resources/themes/pterodactyl/errors/404.blade.php index 9979502e0..39ace2669 100644 --- a/resources/themes/pterodactyl/errors/404.blade.php +++ b/resources/themes/pterodactyl/errors/404.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/layouts/auth.blade.php b/resources/themes/pterodactyl/layouts/auth.blade.php index 6e4280d61..58758f4fa 100644 --- a/resources/themes/pterodactyl/layouts/auth.blade.php +++ b/resources/themes/pterodactyl/layouts/auth.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/layouts/error.blade.php b/resources/themes/pterodactyl/layouts/error.blade.php index 58e67f22a..fd78fd81e 100644 --- a/resources/themes/pterodactyl/layouts/error.blade.php +++ b/resources/themes/pterodactyl/layouts/error.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index cf8d13bcf..19b03380f 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/server/files/add.blade.php b/resources/themes/pterodactyl/server/files/add.blade.php index 0e7742c53..d605b8dd5 100644 --- a/resources/themes/pterodactyl/server/files/add.blade.php +++ b/resources/themes/pterodactyl/server/files/add.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/server/files/edit.blade.php b/resources/themes/pterodactyl/server/files/edit.blade.php index d060fee5d..fece93d10 100644 --- a/resources/themes/pterodactyl/server/files/edit.blade.php +++ b/resources/themes/pterodactyl/server/files/edit.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/server/files/index.blade.php b/resources/themes/pterodactyl/server/files/index.blade.php index f9d46e069..932176a9a 100644 --- a/resources/themes/pterodactyl/server/files/index.blade.php +++ b/resources/themes/pterodactyl/server/files/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/server/files/list.blade.php b/resources/themes/pterodactyl/server/files/list.blade.php index 9f2eb66ce..ab9d51703 100644 --- a/resources/themes/pterodactyl/server/files/list.blade.php +++ b/resources/themes/pterodactyl/server/files/list.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/server/index.blade.php b/resources/themes/pterodactyl/server/index.blade.php index 87dfe79f9..67e6c956c 100644 --- a/resources/themes/pterodactyl/server/index.blade.php +++ b/resources/themes/pterodactyl/server/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/server/settings/allocation.blade.php b/resources/themes/pterodactyl/server/settings/allocation.blade.php index 546279142..f2782a88c 100644 --- a/resources/themes/pterodactyl/server/settings/allocation.blade.php +++ b/resources/themes/pterodactyl/server/settings/allocation.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/server/settings/databases.blade.php b/resources/themes/pterodactyl/server/settings/databases.blade.php index 31e099804..b69b0f36d 100644 --- a/resources/themes/pterodactyl/server/settings/databases.blade.php +++ b/resources/themes/pterodactyl/server/settings/databases.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/server/settings/sftp.blade.php b/resources/themes/pterodactyl/server/settings/sftp.blade.php index 1c146c33d..747b93412 100644 --- a/resources/themes/pterodactyl/server/settings/sftp.blade.php +++ b/resources/themes/pterodactyl/server/settings/sftp.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/server/settings/startup.blade.php b/resources/themes/pterodactyl/server/settings/startup.blade.php index 4d48e2470..745d0d3fd 100644 --- a/resources/themes/pterodactyl/server/settings/startup.blade.php +++ b/resources/themes/pterodactyl/server/settings/startup.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/server/tasks/index.blade.php b/resources/themes/pterodactyl/server/tasks/index.blade.php index dc6e2b239..cd0f529e3 100644 --- a/resources/themes/pterodactyl/server/tasks/index.blade.php +++ b/resources/themes/pterodactyl/server/tasks/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/server/tasks/new.blade.php b/resources/themes/pterodactyl/server/tasks/new.blade.php index 03db43b1f..045d2fe8d 100644 --- a/resources/themes/pterodactyl/server/tasks/new.blade.php +++ b/resources/themes/pterodactyl/server/tasks/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/server/users/index.blade.php b/resources/themes/pterodactyl/server/users/index.blade.php index b047487e9..f44849758 100644 --- a/resources/themes/pterodactyl/server/users/index.blade.php +++ b/resources/themes/pterodactyl/server/users/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/server/users/new.blade.php b/resources/themes/pterodactyl/server/users/new.blade.php index 5bec326b7..5cbe5617f 100644 --- a/resources/themes/pterodactyl/server/users/new.blade.php +++ b/resources/themes/pterodactyl/server/users/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/themes/pterodactyl/server/users/view.blade.php b/resources/themes/pterodactyl/server/users/view.blade.php index eda1e92c2..b697edc34 100644 --- a/resources/themes/pterodactyl/server/users/view.blade.php +++ b/resources/themes/pterodactyl/server/users/view.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/databases/index.blade.php b/resources/views/admin/databases/index.blade.php index a4aa30e7b..f45e70192 100644 --- a/resources/views/admin/databases/index.blade.php +++ b/resources/views/admin/databases/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/databases/new.blade.php b/resources/views/admin/databases/new.blade.php index fa6d71a1b..24ff27007 100644 --- a/resources/views/admin/databases/new.blade.php +++ b/resources/views/admin/databases/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/index.blade.php b/resources/views/admin/index.blade.php index 6c2481a97..b0758f27c 100644 --- a/resources/views/admin/index.blade.php +++ b/resources/views/admin/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/locations/index.blade.php b/resources/views/admin/locations/index.blade.php index b1cb27c59..9aaf49faa 100644 --- a/resources/views/admin/locations/index.blade.php +++ b/resources/views/admin/locations/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/nodes/index.blade.php b/resources/views/admin/nodes/index.blade.php index 26a9fe98d..29546d4ea 100644 --- a/resources/views/admin/nodes/index.blade.php +++ b/resources/views/admin/nodes/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/nodes/new.blade.php b/resources/views/admin/nodes/new.blade.php index 08c8e7bfe..07227daa7 100644 --- a/resources/views/admin/nodes/new.blade.php +++ b/resources/views/admin/nodes/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/nodes/remote/deploy.blade.php b/resources/views/admin/nodes/remote/deploy.blade.php index 19b29c908..b7283fcfd 100644 --- a/resources/views/admin/nodes/remote/deploy.blade.php +++ b/resources/views/admin/nodes/remote/deploy.blade.php @@ -1,7 +1,7 @@ #!/bin/bash #### # Pterodactyl - Panel - # Copyright (c) 2015 - 2016 Dane Everitt + # 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 diff --git a/resources/views/admin/nodes/view.blade.php b/resources/views/admin/nodes/view.blade.php index ef5c1b57a..a0ed696e7 100644 --- a/resources/views/admin/nodes/view.blade.php +++ b/resources/views/admin/nodes/view.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/servers/index.blade.php b/resources/views/admin/servers/index.blade.php index 67a913037..612d2905c 100644 --- a/resources/views/admin/servers/index.blade.php +++ b/resources/views/admin/servers/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/servers/new.blade.php b/resources/views/admin/servers/new.blade.php index 5eda226f2..2c3d655a2 100644 --- a/resources/views/admin/servers/new.blade.php +++ b/resources/views/admin/servers/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/servers/view.blade.php b/resources/views/admin/servers/view.blade.php index a3cc399e1..abad871d9 100644 --- a/resources/views/admin/servers/view.blade.php +++ b/resources/views/admin/servers/view.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/services/config.blade.php b/resources/views/admin/services/config.blade.php index fbfa01d38..2aa814428 100644 --- a/resources/views/admin/services/config.blade.php +++ b/resources/views/admin/services/config.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/services/index.blade.php b/resources/views/admin/services/index.blade.php index 4106964e9..453f1582f 100644 --- a/resources/views/admin/services/index.blade.php +++ b/resources/views/admin/services/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/services/new.blade.php b/resources/views/admin/services/new.blade.php index ce7f0f4f0..1bb829e00 100644 --- a/resources/views/admin/services/new.blade.php +++ b/resources/views/admin/services/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/services/options/new.blade.php b/resources/views/admin/services/options/new.blade.php index 7749682dc..5585fad0f 100644 --- a/resources/views/admin/services/options/new.blade.php +++ b/resources/views/admin/services/options/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/services/options/variable.blade.php b/resources/views/admin/services/options/variable.blade.php index 9cfceea60..2c8ff8957 100644 --- a/resources/views/admin/services/options/variable.blade.php +++ b/resources/views/admin/services/options/variable.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/services/options/view.blade.php b/resources/views/admin/services/options/view.blade.php index d5de1a910..bffb2057e 100644 --- a/resources/views/admin/services/options/view.blade.php +++ b/resources/views/admin/services/options/view.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/services/packs/byoption.blade.php b/resources/views/admin/services/packs/byoption.blade.php index 626958566..23dbf2951 100644 --- a/resources/views/admin/services/packs/byoption.blade.php +++ b/resources/views/admin/services/packs/byoption.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/services/packs/byservice.blade.php b/resources/views/admin/services/packs/byservice.blade.php index f73572c33..8475de289 100644 --- a/resources/views/admin/services/packs/byservice.blade.php +++ b/resources/views/admin/services/packs/byservice.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/services/packs/edit.blade.php b/resources/views/admin/services/packs/edit.blade.php index b71256fd9..b7ba5fcde 100644 --- a/resources/views/admin/services/packs/edit.blade.php +++ b/resources/views/admin/services/packs/edit.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/services/packs/index.blade.php b/resources/views/admin/services/packs/index.blade.php index d346dc3ae..6456ca317 100644 --- a/resources/views/admin/services/packs/index.blade.php +++ b/resources/views/admin/services/packs/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/services/packs/new.blade.php b/resources/views/admin/services/packs/new.blade.php index af658cce4..c31f1c77e 100644 --- a/resources/views/admin/services/packs/new.blade.php +++ b/resources/views/admin/services/packs/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/services/view.blade.php b/resources/views/admin/services/view.blade.php index 4de4d6e9d..887478aca 100644 --- a/resources/views/admin/services/view.blade.php +++ b/resources/views/admin/services/view.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/settings.blade.php b/resources/views/admin/settings.blade.php index ac5964f92..09e66d6fc 100644 --- a/resources/views/admin/settings.blade.php +++ b/resources/views/admin/settings.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/admin/users/index.blade.php b/resources/views/admin/users/index.blade.php index 5b9f59ce0..7e85c8fe9 100644 --- a/resources/views/admin/users/index.blade.php +++ b/resources/views/admin/users/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Some Modifications (c) 2015 Dylan Seidt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} diff --git a/resources/views/admin/users/new.blade.php b/resources/views/admin/users/new.blade.php index 8e0297b51..8e0bf5f7a 100644 --- a/resources/views/admin/users/new.blade.php +++ b/resources/views/admin/users/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Some Modifications (c) 2015 Dylan Seidt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} diff --git a/resources/views/admin/users/view.blade.php b/resources/views/admin/users/view.blade.php index 7b817e3a4..0a5d8230d 100644 --- a/resources/views/admin/users/view.blade.php +++ b/resources/views/admin/users/view.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Some Modifications (c) 2015 Dylan Seidt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} diff --git a/resources/views/emails/added-subuser.blade.php b/resources/views/emails/added-subuser.blade.php index a468eb298..c6d0d47d2 100644 --- a/resources/views/emails/added-subuser.blade.php +++ b/resources/views/emails/added-subuser.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/emails/new-account.blade.php b/resources/views/emails/new-account.blade.php index 093d626b1..1240cbc2c 100644 --- a/resources/views/emails/new-account.blade.php +++ b/resources/views/emails/new-account.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/emails/new_password.blade.php b/resources/views/emails/new_password.blade.php index 69b671baa..882cf2af3 100644 --- a/resources/views/emails/new_password.blade.php +++ b/resources/views/emails/new_password.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/errors/403.blade.php b/resources/views/errors/403.blade.php index aef80166e..bc83eb24a 100644 --- a/resources/views/errors/403.blade.php +++ b/resources/views/errors/403.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/errors/404.blade.php b/resources/views/errors/404.blade.php index 6988e78a6..bdaec2cd4 100644 --- a/resources/views/errors/404.blade.php +++ b/resources/views/errors/404.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/errors/installing.blade.php b/resources/views/errors/installing.blade.php index c68ec61f3..8a8d5c292 100644 --- a/resources/views/errors/installing.blade.php +++ b/resources/views/errors/installing.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/errors/suspended.blade.php b/resources/views/errors/suspended.blade.php index 442f85ec0..f96f13d60 100644 --- a/resources/views/errors/suspended.blade.php +++ b/resources/views/errors/suspended.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/resources/views/layouts/admin.blade.php b/resources/views/layouts/admin.blade.php index 2b309c2a4..f21e1a0c7 100644 --- a/resources/views/layouts/admin.blade.php +++ b/resources/views/layouts/admin.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- 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 --}} diff --git a/storage/app/services/.templates/index.js b/storage/app/services/.templates/index.js index aa60eec19..f6b6695d0 100644 --- a/storage/app/services/.templates/index.js +++ b/storage/app/services/.templates/index.js @@ -2,7 +2,7 @@ /** * Pterodactyl - Daemon - * Copyright (c) 2015 - 2016 Dane Everitt + * 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 diff --git a/storage/app/services/minecraft/index.js b/storage/app/services/minecraft/index.js index 2d7f812c3..b53364bec 100644 --- a/storage/app/services/minecraft/index.js +++ b/storage/app/services/minecraft/index.js @@ -2,7 +2,7 @@ /** * Pterodactyl - Daemon - * Copyright (c) 2015 - 2016 Dane Everitt + * 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 diff --git a/storage/app/services/srcds/index.js b/storage/app/services/srcds/index.js index aa60eec19..f6b6695d0 100644 --- a/storage/app/services/srcds/index.js +++ b/storage/app/services/srcds/index.js @@ -2,7 +2,7 @@ /** * Pterodactyl - Daemon - * Copyright (c) 2015 - 2016 Dane Everitt + * 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 diff --git a/storage/app/services/terraria/index.js b/storage/app/services/terraria/index.js index aa60eec19..f6b6695d0 100644 --- a/storage/app/services/terraria/index.js +++ b/storage/app/services/terraria/index.js @@ -2,7 +2,7 @@ /** * Pterodactyl - Daemon - * Copyright (c) 2015 - 2016 Dane Everitt + * 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 diff --git a/storage/app/services/voice/index.js b/storage/app/services/voice/index.js index aa60eec19..f6b6695d0 100644 --- a/storage/app/services/voice/index.js +++ b/storage/app/services/voice/index.js @@ -2,7 +2,7 @@ /** * Pterodactyl - Daemon - * Copyright (c) 2015 - 2016 Dane Everitt + * 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 From a137e6ed72f04cefa8bd70b34478bf937f177d06 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 24 Jan 2017 19:15:03 -0500 Subject: [PATCH 161/599] Add base implementation of extendable events classes Modified server deletion to use internal event handlers from the Eloquent models themselves. Also added a few preliminary event handlers in the `Pterodactyl\Events\ namespace that users can hook into in EventServiceProvider to perform their own actions as they please (such as push notifications and such). --- .../{ServerDeleted.php => Server/Created.php} | 9 +- .../Server/Creating.php} | 37 +++----- app/Events/Server/Deleted.php | 45 ++++++++++ app/Events/Server/Deleting.php | 45 ++++++++++ app/Events/User/Created.php | 45 ++++++++++ app/Events/User/Creating.php | 45 ++++++++++ app/Events/User/Deleted.php | 45 ++++++++++ app/Events/User/Deleting.php | 45 ++++++++++ app/Models/Node.php | 3 + app/Models/Server.php | 3 +- app/Notifications/ServerCreated.php | 22 +++++ app/Observers/ServerObserver.php | 89 +++++++++++++++++++ app/Observers/UserObserver.php | 75 ++++++++++++++++ app/Providers/AppServiceProvider.php | 29 +++++- app/Providers/EventServiceProvider.php | 6 +- app/Repositories/ServerRepository.php | 5 +- 16 files changed, 506 insertions(+), 42 deletions(-) rename app/Events/{ServerDeleted.php => Server/Created.php} (89%) rename app/{Listeners/DeleteServerListener.php => Events/Server/Creating.php} (60%) create mode 100644 app/Events/Server/Deleted.php create mode 100644 app/Events/Server/Deleting.php create mode 100644 app/Events/User/Created.php create mode 100644 app/Events/User/Creating.php create mode 100644 app/Events/User/Deleted.php create mode 100644 app/Events/User/Deleting.php create mode 100644 app/Observers/ServerObserver.php create mode 100644 app/Observers/UserObserver.php diff --git a/app/Events/ServerDeleted.php b/app/Events/Server/Created.php similarity index 89% rename from app/Events/ServerDeleted.php rename to app/Events/Server/Created.php index 95f8e33e1..d5a308876 100644 --- a/app/Events/ServerDeleted.php +++ b/app/Events/Server/Created.php @@ -22,11 +22,12 @@ * SOFTWARE. */ -namespace Pterodactyl\Events; +namespace Pterodactyl\Events\Server; +use Pterodactyl\Models\Server; use Illuminate\Queue\SerializesModels; -class ServerDeleted +class Created { use SerializesModels; @@ -37,8 +38,8 @@ class ServerDeleted * * @return void */ - public function __construct($id) + public function __construct(Server $server) { - $this->server = $id; + $this->server = $server; } } diff --git a/app/Listeners/DeleteServerListener.php b/app/Events/Server/Creating.php similarity index 60% rename from app/Listeners/DeleteServerListener.php rename to app/Events/Server/Creating.php index 616f4c141..cbba63eb1 100644 --- a/app/Listeners/DeleteServerListener.php +++ b/app/Events/Server/Creating.php @@ -22,41 +22,24 @@ * SOFTWARE. */ -namespace Pterodactyl\Listeners; +namespace Pterodactyl\Events\Server; -use Carbon; -use Pterodactyl\Jobs\DeleteServer; -use Pterodactyl\Jobs\SuspendServer; -use Pterodactyl\Events\ServerDeleted; -use Illuminate\Foundation\Bus\DispatchesJobs; +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; -class DeleteServerListener +class Creating { - use DispatchesJobs; + use SerializesModels; + + public $server; /** - * Create the event listener. + * Create a new event instance. * * @return void */ - public function __construct() + public function __construct(Server $server) { - // - } - - /** - * Handle the event. - * - * @param DeleteServerEvent $event - * @return void - */ - public function handle(ServerDeleted $event) - { - $this->dispatch((new SuspendServer($event->server))->onQueue(env('QUEUE_HIGH', 'high'))); - $this->dispatch( - (new DeleteServer($event->server)) - ->delay(Carbon::now()->addMinutes(env('APP_DELETE_MINUTES', 10))) - ->onQueue(env('QUEUE_STANDARD', 'standard')) - ); + $this->server = $server; } } diff --git a/app/Events/Server/Deleted.php b/app/Events/Server/Deleted.php new file mode 100644 index 000000000..b36dca12d --- /dev/null +++ b/app/Events/Server/Deleted.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\Server; + +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; + +class Deleted +{ + use SerializesModels; + + public $server; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } +} diff --git a/app/Events/Server/Deleting.php b/app/Events/Server/Deleting.php new file mode 100644 index 000000000..bb18e1ee9 --- /dev/null +++ b/app/Events/Server/Deleting.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\Server; + +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; + +class Deleting +{ + use SerializesModels; + + public $server; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } +} diff --git a/app/Events/User/Created.php b/app/Events/User/Created.php new file mode 100644 index 000000000..a00bdd450 --- /dev/null +++ b/app/Events/User/Created.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\User; + +use Pterodactyl\Models\User; +use Illuminate\Queue\SerializesModels; + +class Created +{ + use SerializesModels; + + public $user; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } +} diff --git a/app/Events/User/Creating.php b/app/Events/User/Creating.php new file mode 100644 index 000000000..39a50f0c8 --- /dev/null +++ b/app/Events/User/Creating.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\User; + +use Pterodactyl\Models\User; +use Illuminate\Queue\SerializesModels; + +class Creating +{ + use SerializesModels; + + public $user; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } +} diff --git a/app/Events/User/Deleted.php b/app/Events/User/Deleted.php new file mode 100644 index 000000000..348c859c9 --- /dev/null +++ b/app/Events/User/Deleted.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\User; + +use Pterodactyl\Models\User; +use Illuminate\Queue\SerializesModels; + +class Deleted +{ + use SerializesModels; + + public $user; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } +} diff --git a/app/Events/User/Deleting.php b/app/Events/User/Deleting.php new file mode 100644 index 000000000..5bbd91366 --- /dev/null +++ b/app/Events/User/Deleting.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\User; + +use Pterodactyl\Models\User; +use Illuminate\Queue\SerializesModels; + +class Deleting +{ + use SerializesModels; + + public $user; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } +} diff --git a/app/Models/Node.php b/app/Models/Node.php index 5b82a2429..a5cbce464 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -26,9 +26,12 @@ namespace Pterodactyl\Models; use GuzzleHttp\Client; use Illuminate\Database\Eloquent\Model; +use Illuminate\Notifications\Notifiable; class Node extends Model { + use Notifiable; + /** * The table associated with the model. * diff --git a/app/Models/Server.php b/app/Models/Server.php index b90d0c510..3a11603c2 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -26,11 +26,12 @@ namespace Pterodactyl\Models; use Auth; use Illuminate\Database\Eloquent\Model; +use Illuminate\Notifications\Notifiable; use Illuminate\Database\Eloquent\SoftDeletes; class Server extends Model { - use SoftDeletes; + use Notifiable, SoftDeletes; /** * The table associated with the model. diff --git a/app/Notifications/ServerCreated.php b/app/Notifications/ServerCreated.php index a581a8fb2..a8e8b59f0 100644 --- a/app/Notifications/ServerCreated.php +++ b/app/Notifications/ServerCreated.php @@ -1,4 +1,26 @@ . + * + * 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\Notifications; diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php new file mode 100644 index 000000000..82c403a8a --- /dev/null +++ b/app/Observers/ServerObserver.php @@ -0,0 +1,89 @@ +. + * + * 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\Observers; + +use Carbon; +use Pterodactyl\Events; +use Pterodactyl\Models\Server; +use Pterodactyl\Jobs\DeleteServer; +use Pterodactyl\Jobs\SuspendServer; +use Illuminate\Foundation\Bus\DispatchesJobs; + +class ServerObserver +{ + use DispatchesJobs; + + /** + * Listen to the Server deleted event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function creating(Server $server) + { + event(new Events\Server\Creating($server)); + } + + /** + * Listen to the Server deleted event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function created(Server $server) + { + event(new Events\Server\Created($server)); + } + + /** + * Listen to the Server deleted event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function deleting(Server $server) + { + event(new Events\Server\Deleting($server)); + + $this->dispatch((new SuspendServer($server->id))->onQueue(env('QUEUE_HIGH', 'high'))); + } + + /** + * Listen to the Server deleted event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function deleted(Server $server) + { + event(new Events\Server\Deleted($server)); + + $this->dispatch( + (new DeleteServer($server->id)) + ->delay(Carbon::now()->addMinutes(env('APP_DELETE_MINUTES', 10))) + ->onQueue(env('QUEUE_STANDARD', 'standard')) + ); + } +} diff --git a/app/Observers/UserObserver.php b/app/Observers/UserObserver.php new file mode 100644 index 000000000..e0624e268 --- /dev/null +++ b/app/Observers/UserObserver.php @@ -0,0 +1,75 @@ +. + * + * 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\Observers; + +use Pterodactyl\Events; +use Pterodactyl\Models\User; + +class UserObserver +{ + /** + * Listen to the User creating event. + * + * @param User $user The eloquent User model. + * @return void + */ + public function creating(User $user) + { + event(new Events\User\Creating($user)); + } + + /** + * Listen to the User created event. + * + * @param User $user The eloquent User model. + * @return void + */ + public function created(User $user) + { + event(new Events\User\Created($user)); + } + + /** + * Listen to the User deleting event. + * + * @param User $user The eloquent User model. + * @return void + */ + public function deleting(User $user) + { + event(new Events\User\Deleting($user)); + } + + /** + * Listen to the User deleted event. + * + * @param User $user The eloquent User model. + * @return void + */ + public function deleted(User $user) + { + event(new Events\User\Deleted($user)); + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index d0d1dd9e4..d71ea056b 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -1,8 +1,34 @@ . + * + * 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\Providers; +use Pterodactyl\Models\User; +use Pterodactyl\Models\Server; use Illuminate\Support\ServiceProvider; +use Pterodactyl\Observers\UserObserver; +use Pterodactyl\Observers\ServerObserver; class AppServiceProvider extends ServiceProvider { @@ -13,7 +39,8 @@ class AppServiceProvider extends ServiceProvider */ public function boot() { - // + User::observe(UserObserver::class); + Server::observe(ServerObserver::class); } /** diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 7ec0d48ae..0e31100c3 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -12,11 +12,7 @@ class EventServiceProvider extends ServiceProvider * * @var array */ - protected $listen = [ - 'Pterodactyl\Events\ServerDeleted' => [ - 'Pterodactyl\Listeners\DeleteServerListener', - ], - ]; + protected $listen = []; /** * Register any other events for your application. diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 88618a476..9f762bc4a 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -29,7 +29,6 @@ use Log; use Crypt; use Validator; use Pterodactyl\Models; -use Pterodactyl\Events\ServerDeleted; use Pterodactyl\Services\UuidService; use Pterodactyl\Services\DeploymentService; use Pterodactyl\Exceptions\DisplayException; @@ -797,9 +796,7 @@ class ServerRepository } $server->delete(); - DB::commit(); - - event(new ServerDeleted($server->id)); + return DB::commit(); } catch (\Exception $ex) { DB::rollBack(); throw $ex; From 58de6125c2cf9ed108b913e44c071e38099289a4 Mon Sep 17 00:00:00 2001 From: Emmet Young Date: Wed, 25 Jan 2017 22:01:57 +1100 Subject: [PATCH 162/599] Location should be validated on creation of a server, --- app/Repositories/ServerRepository.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 9f762bc4a..9e16de31e 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -92,6 +92,7 @@ class ServerRepository 'disk' => 'required|numeric|min:0', 'service' => 'required|numeric|min:1|exists:services,id', 'option' => 'required|numeric|min:1|exists:service_options,id', + 'location' => 'required|numeric|min:1|exists:locations,id', 'pack' => 'sometimes|nullable|numeric|min:0', 'startup' => 'string', 'custom_image_name' => 'required_if:use_custom_image,on', From 96e50506a17a40b53a0af50441f24a4c784c75f7 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 25 Jan 2017 16:37:01 -0500 Subject: [PATCH 163/599] Move notification email of server created into the event listener --- app/Notifications/ServerCreated.php | 14 +++++++------- app/Observers/ServerObserver.php | 13 +++++++++++++ app/Repositories/ServerRepository.php | 11 ----------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/app/Notifications/ServerCreated.php b/app/Notifications/ServerCreated.php index a8e8b59f0..a867e26c7 100644 --- a/app/Notifications/ServerCreated.php +++ b/app/Notifications/ServerCreated.php @@ -66,12 +66,12 @@ class ServerCreated extends Notification implements ShouldQueue public function toMail($notifiable) { return (new MailMessage) - ->line('A new server as been assigned to your account.') - ->line('Server Name: ' . $this->server->name) - ->line('Memory: ' . $this->server->memory . ' MB') - ->line('Node: ' . $this->server->node) - ->line('Type: ' . $this->server->service . ' - ' . $this->server->option) - ->action('Peel Off the Protective Wrap', route('server.index', $this->server->uuidShort)) - ->line('Please let us know if you have any additional questions or concerns!'); + ->line('A new server as been assigned to your account.') + ->line('Server Name: ' . $this->server->name) + ->line('Memory: ' . $this->server->memory . ' MB') + ->line('Node: ' . $this->server->node) + ->line('Type: ' . $this->server->service . ' - ' . $this->server->option) + ->action('Peel Off the Protective Wrap', route('server.index', $this->server->uuidShort)) + ->line('Please let us know if you have any additional questions or concerns!'); } } diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php index 82c403a8a..ed6246ed4 100644 --- a/app/Observers/ServerObserver.php +++ b/app/Observers/ServerObserver.php @@ -26,9 +26,11 @@ namespace Pterodactyl\Observers; use Carbon; use Pterodactyl\Events; +use Pterodactyl\Models\User; use Pterodactyl\Models\Server; use Pterodactyl\Jobs\DeleteServer; use Pterodactyl\Jobs\SuspendServer; +use Pterodactyl\Notifications\ServerCreated; use Illuminate\Foundation\Bus\DispatchesJobs; class ServerObserver @@ -55,6 +57,17 @@ class ServerObserver public function created(Server $server) { event(new Events\Server\Created($server)); + + // Queue Notification Email + $user = User::findOrFail($server->owner); + $user->notify((new ServerCreated([ + 'name' => $server->name, + 'memory' => $server->memory, + 'node' => $node->name, + 'service' => $service->name, + 'option' => $option->name, + 'uuidShort' => $server->uuidShort, + ]))); } /** diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 9e16de31e..324e1f47d 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -32,7 +32,6 @@ use Pterodactyl\Models; use Pterodactyl\Services\UuidService; use Pterodactyl\Services\DeploymentService; use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Notifications\ServerCreated; use Pterodactyl\Exceptions\DisplayValidationException; class ServerRepository @@ -300,16 +299,6 @@ class ServerRepository ]); } - // Queue Notification Email - $user->notify((new ServerCreated([ - 'name' => $server->name, - 'memory' => $server->memory, - 'node' => $node->name, - 'service' => $service->name, - 'option' => $option->name, - 'uuidShort' => $server->uuidShort, - ]))); - $client = Models\Node::guzzleRequest($node->id); $client->request('POST', '/servers', [ 'headers' => [ From 95730da41920a797c74e265eb23696108c2ae606 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 25 Jan 2017 16:57:15 -0500 Subject: [PATCH 164/599] Fix pack edit display --- resources/views/admin/services/packs/edit.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/admin/services/packs/edit.blade.php b/resources/views/admin/services/packs/edit.blade.php index b7ba5fcde..0c05d4f99 100644 --- a/resources/views/admin/services/packs/edit.blade.php +++ b/resources/views/admin/services/packs/edit.blade.php @@ -65,7 +65,7 @@ @foreach($services as $service => $options) @foreach($options as $option) - + @endforeach @endforeach From 95d0c646f9f64624f37290b44fc68e32b209407b Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 25 Jan 2017 18:20:41 -0500 Subject: [PATCH 165/599] Require packs to be a tarball --- app/Repositories/ServiceRepository/Pack.php | 15 +++++---------- .../views/admin/services/packs/edit.blade.php | 2 +- .../views/admin/services/packs/new.blade.php | 4 ++-- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/app/Repositories/ServiceRepository/Pack.php b/app/Repositories/ServiceRepository/Pack.php index ae68c1a6b..c5dee34a4 100644 --- a/app/Repositories/ServiceRepository/Pack.php +++ b/app/Repositories/ServiceRepository/Pack.php @@ -66,11 +66,8 @@ class Pack throw new DisplayException('The file provided does not appear to be valid.'); } - if (! in_array($data['file_upload']->getMimeType(), [ - 'application/zip', - 'application/gzip', - ])) { - throw new DisplayException('The file provided does not meet the required filetypes of application/zip or application/gzip.'); + if ($data['file_upload']->getMimeType() !== 'application/gzip') { + throw new DisplayException('The file provided does not meet the required filetype of application/gzip.'); } } @@ -95,8 +92,7 @@ class Pack Storage::makeDirectory('packs/' . $pack->uuid); if (isset($data['file_upload'])) { - $filename = ($data['file_upload']->getMimeType() === 'application/zip') ? 'archive.zip' : 'archive.tar.gz'; - $data['file_upload']->storeAs('packs/' . $pack->uuid, $filename); + $data['file_upload']->storeAs('packs/' . $pack->uuid, 'archive.tar.gz'); } DB::commit(); @@ -132,10 +128,9 @@ class Pack throw new DisplayException('The uploaded archive was unable to be opened.'); } - $isZip = $zip->locateName('archive.zip'); $isTar = $zip->locateName('archive.tar.gz'); - if ($zip->locateName('import.json') === false || ($isZip === false && $isTar === false)) { + if (! $zip->locateName('import.json') || ! $isTar) { throw new DisplayException('This contents of the provided archive were in an invalid format.'); } @@ -156,7 +151,7 @@ class Pack ]); $pack = Models\ServicePack::findOrFail($id); - if (! $zip->extractTo(storage_path('app/packs/' . $pack->uuid), ($isZip === false) ? 'archive.tar.gz' : 'archive.zip')) { + if (! $zip->extractTo(storage_path('app/packs/' . $pack->uuid), 'archive.tar.gz')) { $pack->delete(); throw new DisplayException('Unable to extract the archive file to the correct location.'); } diff --git a/resources/views/admin/services/packs/edit.blade.php b/resources/views/admin/services/packs/edit.blade.php index 0c05d4f99..0cdd80705 100644 --- a/resources/views/admin/services/packs/edit.blade.php +++ b/resources/views/admin/services/packs/edit.blade.php @@ -175,7 +175,7 @@ @endforeach -

      If you wish to modify or upload a new file it should be uploaded to {{ storage_path('app/packs/' . $pack->uuid) }} as either archive.zip or archive.tar.gz.

      +

      If you wish to modify or upload a new file it should be uploaded to {{ storage_path('app/packs/' . $pack->uuid) }} as archive.tar.gz.

      diff --git a/resources/views/admin/services/packs/new.blade.php b/resources/views/admin/services/packs/new.blade.php index c31f1c77e..7a5be8f47 100644 --- a/resources/views/admin/services/packs/new.blade.php +++ b/resources/views/admin/services/packs/new.blade.php @@ -150,8 +150,8 @@
      - -

      This package file must either be a .zip or .tar.gz archive of files to use for either building or running this pack.

      If your file is larger than 20MB we recommend uploading it using SFTP. Once you have added this pack to the system, a path will be provided where you should upload the file. + +

      This package file must be a .tar.gz archive of files to use for either building or running this pack.

      If your file is larger than 20MB we recommend uploading it using SFTP. Once you have added this pack to the system, a path will be provided where you should upload the file. This server is currently configured with the following limits: upload_max_filesize={{ ini_get('upload_max_filesize') }} and post_max_size={{ ini_get('post_max_size') }}. If your file is larger than either of those values this request will fail.

      From e6d3e750241d6da988588083784993c872051ef7 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 25 Jan 2017 18:25:31 -0500 Subject: [PATCH 166/599] Add new daemon routes for pack handling --- .../Controllers/Daemon/PackController.php | 96 +++++++++++++++++++ app/Http/Routes/DaemonRoutes.php | 9 ++ 2 files changed, 105 insertions(+) create mode 100644 app/Http/Controllers/Daemon/PackController.php diff --git a/app/Http/Controllers/Daemon/PackController.php b/app/Http/Controllers/Daemon/PackController.php new file mode 100644 index 000000000..245b88627 --- /dev/null +++ b/app/Http/Controllers/Daemon/PackController.php @@ -0,0 +1,96 @@ +. + * + * 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\Daemon; + +use Storage; +use Pterodactyl\Models; +use Illuminate\Http\Request; +use Pterodactyl\Http\Controllers\Controller; + +class PackController extends Controller +{ + /** + * Controller Constructor. + */ + public function __construct() + { + // + } + + /** + * Pulls an install pack archive from the system + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function pull(Request $request, $uuid) + { + $pack = Models\ServicePack::where('uuid', $uuid)->first(); + + if (!$pack) { + return response()->json([ 'error' => 'No such pack.' ], 404); + } + + if (! Storage::exists('packs/' . $pack->uuid . '/archive.tar.gz')) { + return response()->json([ 'error' => 'There is no archive available for this pack.' ], 503); + } + + return response()->download(storage_path('app/packs/' . $pack->uuid . '/archive.tar.gz')); + } + + /** + * Returns the hash information for a pack. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function hash(Request $request, $uuid) + { + $pack = Models\ServicePack::where('uuid', $uuid)->first(); + + if (!$pack) { + return response()->json([ 'error' => 'No such pack.' ], 404); + } + + if (! Storage::exists('packs/' . $pack->uuid . '/archive.tar.gz')) { + return response()->json([ 'error' => 'There is no archive available for this pack.' ], 503); + } + + return response()->json([ + 'archive.tar.gz' => sha1_file(storage_path('app/packs/' . $pack->uuid . '/archive.tar.gz')), + ]); + } + + /** + * Pulls an update pack archive from the system + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function pullUpdate(Request $request) + { + + } +} diff --git a/app/Http/Routes/DaemonRoutes.php b/app/Http/Routes/DaemonRoutes.php index b993e3759..3792dc8fd 100644 --- a/app/Http/Routes/DaemonRoutes.php +++ b/app/Http/Routes/DaemonRoutes.php @@ -40,6 +40,15 @@ class DaemonRoutes 'as' => 'remote.install', 'uses' => 'Daemon\ServiceController@pull', ]); + + $router->get('packs/pull/{uuid}', [ + 'as' => 'daemon.pack.pull', + 'uses' => 'Daemon\PackController@pull', + ]); + $router->get('packs/pull/{uuid}/hash', [ + 'as' => 'daemon.pack.hash', + 'uses' => 'Daemon\PackController@hash', + ]); }); } } From 96f5d158116c4d4be14c904a3e4170bd974c3e38 Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Thu, 26 Jan 2017 22:12:33 +0100 Subject: [PATCH 167/599] switch console javascript code to revealing module pattern to avoid global variables --- .../themes/pterodactyl/js/frontend/console.js | 369 +++++++++--------- 1 file changed, 195 insertions(+), 174 deletions(-) diff --git a/public/themes/pterodactyl/js/frontend/console.js b/public/themes/pterodactyl/js/frontend/console.js index 2d30586ec..bbee56465 100644 --- a/public/themes/pterodactyl/js/frontend/console.js +++ b/public/themes/pterodactyl/js/frontend/console.js @@ -20,187 +20,208 @@ var CONSOLE_PUSH_COUNT = 50; var CONSOLE_PUSH_FREQ = 200; -(function initConsole() { - window.TerminalQueue = []; - window.Terminal = $('#terminal').terminal(function (command, term) { - Socket.emit('send command', command); - }, { - greetings: '', - name: Pterodactyl.server.uuid, - height: 450, - exit: false, - prompt: Pterodactyl.server.username + ':~$ ', - scrollOnEcho: false, - scrollBottomOffset: 5, - onBlur: function (terminal) { - return false; - } - }); +const Console = (function () { - Socket.on('initial status', function (data) { - Terminal.clear(); - if (data.status === 1 || data.status === 2) { - Socket.emit('send server log'); - } - }); -})(); + var terminalQueue; + var terminal; -(function pushOutputQueue() { - if (TerminalQueue.length > CONSOLE_PUSH_COUNT) { - // console throttled warning show + function initConsole() { + termianlQueue = []; + terminal = $('#terminal').terminal(function (command, term) { + Socket.emit('send command', command); + }, { + greetings: '', + name: Pterodactyl.server.uuid, + height: 450, + exit: false, + prompt: Pterodactyl.server.username + ':~$ ', + scrollOnEcho: false, + scrollBottomOffset: 5, + onBlur: function (terminal) { + return false; + } + }); + + Socket.on('initial status', function (data) { + terminal.clear(); + if (data.status === 1 || data.status === 2) { + Socket.emit('send server log'); + } + }); } - if (TerminalQueue.length > 0) { - for (var i = 0; i < CONSOLE_PUSH_COUNT && TerminalQueue.length > 0; i++) { - Terminal.echo(TerminalQueue[0]); - TerminalQueue.shift(); + function pushOutputQueue() { + if (termianlQueue.length > CONSOLE_PUSH_COUNT) { + // console throttled warning show } + + if (termianlQueue.length > 0) { + for (var i = 0; i < CONSOLE_PUSH_COUNT && termianlQueue.length > 0; i++) { + terminal.echo(termianlQueue[0]); + termianlQueue.shift(); + } + } + + window.setTimeout(pushOutputQueue, CONSOLE_PUSH_FREQ); } - window.setTimeout(pushOutputQueue, CONSOLE_PUSH_FREQ); -})(); + return { + init: function () { + $('[data-attr="power"]').click(function (event) { + if (! $(this).hasClass('disabled')) { + Socket.emit('set status', $(this).data('action')); + } + }); + + var ctc = $('#chart_cpu'); + var timeLabels = []; + var cpuData = []; + var CPUChart = new Chart(ctc, { + type: 'line', + data: { + labels: timeLabels, + datasets: [ + { + label: "Percent Use", + fill: false, + lineTension: 0.03, + backgroundColor: "#00A1CB", + borderColor: "#00A1CB", + borderCapStyle: 'butt', + borderDash: [], + borderDashOffset: 0.0, + borderJoinStyle: 'miter', + pointBorderColor: "rgba(75,192,192,1)", + pointBackgroundColor: "#fff", + pointBorderWidth: 1, + pointHoverRadius: 5, + pointHoverBackgroundColor: "rgba(75,192,192,1)", + pointHoverBorderColor: "rgba(220,220,220,1)", + pointHoverBorderWidth: 2, + pointRadius: 1, + pointHitRadius: 10, + data: cpuData, + spanGaps: false, + } + ] + }, + options: { + title: { + display: true, + text: 'CPU Usage (as Percent Total)' + }, + legend: { + display: false, + }, + animation: { + duration: 1, + } + } + }); + + var ctm = $('#chart_memory'); + var memoryData = []; + var MemoryChart = new Chart(ctm, { + type: 'line', + data: { + labels: timeLabels, + datasets: [ + { + label: "Memory Use", + fill: false, + lineTension: 0.03, + backgroundColor: "#01A4A4", + borderColor: "#01A4A4", + borderCapStyle: 'butt', + borderDash: [], + borderDashOffset: 0.0, + borderJoinStyle: 'miter', + pointBorderColor: "rgba(75,192,192,1)", + pointBackgroundColor: "#fff", + pointBorderWidth: 1, + pointHoverRadius: 5, + pointHoverBackgroundColor: "rgba(75,192,192,1)", + pointHoverBorderColor: "rgba(220,220,220,1)", + pointHoverBorderWidth: 2, + pointRadius: 1, + pointHitRadius: 10, + data: memoryData, + spanGaps: false, + } + ] + }, + options: { + title: { + display: true, + text: 'Memory Usage (in Megabytes)' + }, + legend: { + display: false, + }, + animation: { + duration: 1, + } + } + }); + Socket.on('proc', function (proc) { + if (cpuData.length > 10) { + cpuData.shift(); + memoryData.shift(); + timeLabels.shift(); + } + + var cpuUse = (Pterodactyl.server.cpu > 0) ? parseFloat(((proc.data.cpu.total / Pterodactyl.server.cpu) * 100).toFixed(3).toString()) : proc.data.cpu.total; + cpuData.push(cpuUse); + memoryData.push(parseInt(proc.data.memory.total / (1024 * 1024))); + + var m = new Date(); + timeLabels.push($.format.date(new Date(), 'HH:mm:ss')); + + CPUChart.update(); + MemoryChart.update(); + }); + + // Update Listings on Initial Status + Socket.on('initial status', function (data) { + updateServerPowerControls(data.status); + }); + + // Update Listings on Status + Socket.on('status', function (data) { + updateServerPowerControls(data.status); + }); + + function updateServerPowerControls (data) { + // Server is On or Starting + if(data == 1 || data == 2) { + $('[data-attr="power"][data-action="start"]').addClass('disabled'); + $('[data-attr="power"][data-action="stop"], [data-attr="power"][data-action="restart"]').removeClass('disabled'); + } else { + if (data == 0) { + $('[data-attr="power"][data-action="start"]').removeClass('disabled'); + } + $('[data-attr="power"][data-action="stop"], [data-attr="power"][data-action="restart"]').addClass('disabled'); + } + + if(data !== 0) { + $('[data-attr="power"][data-action="kill"]').removeClass('disabled'); + } else { + $('[data-attr="power"][data-action="kill"]').addClass('disabled'); + } + } + }, + + getTerminal: function() { + return terminal + }, + + getTerminalQueue: function() { + return terminalQueue + }, + } + +}); $(document).ready(function () { - $('[data-attr="power"]').click(function (event) { - if (! $(this).hasClass('disabled')) { - Socket.emit('set status', $(this).data('action')); - } - }); - - var ctc = $('#chart_cpu'); - var timeLabels = []; - var cpuData = []; - var CPUChart = new Chart(ctc, { - type: 'line', - data: { - labels: timeLabels, - datasets: [ - { - label: "Percent Use", - fill: false, - lineTension: 0.03, - backgroundColor: "#00A1CB", - borderColor: "#00A1CB", - borderCapStyle: 'butt', - borderDash: [], - borderDashOffset: 0.0, - borderJoinStyle: 'miter', - pointBorderColor: "rgba(75,192,192,1)", - pointBackgroundColor: "#fff", - pointBorderWidth: 1, - pointHoverRadius: 5, - pointHoverBackgroundColor: "rgba(75,192,192,1)", - pointHoverBorderColor: "rgba(220,220,220,1)", - pointHoverBorderWidth: 2, - pointRadius: 1, - pointHitRadius: 10, - data: cpuData, - spanGaps: false, - } - ] - }, - options: { - title: { - display: true, - text: 'CPU Usage (as Percent Total)' - }, - legend: { - display: false, - }, - animation: { - duration: 1, - } - } - }); - - var ctm = $('#chart_memory'); - var memoryData = []; - var MemoryChart = new Chart(ctm, { - type: 'line', - data: { - labels: timeLabels, - datasets: [ - { - label: "Memory Use", - fill: false, - lineTension: 0.03, - backgroundColor: "#01A4A4", - borderColor: "#01A4A4", - borderCapStyle: 'butt', - borderDash: [], - borderDashOffset: 0.0, - borderJoinStyle: 'miter', - pointBorderColor: "rgba(75,192,192,1)", - pointBackgroundColor: "#fff", - pointBorderWidth: 1, - pointHoverRadius: 5, - pointHoverBackgroundColor: "rgba(75,192,192,1)", - pointHoverBorderColor: "rgba(220,220,220,1)", - pointHoverBorderWidth: 2, - pointRadius: 1, - pointHitRadius: 10, - data: memoryData, - spanGaps: false, - } - ] - }, - options: { - title: { - display: true, - text: 'Memory Usage (in Megabytes)' - }, - legend: { - display: false, - }, - animation: { - duration: 1, - } - } - }); - Socket.on('proc', function (proc) { - if (cpuData.length > 10) { - cpuData.shift(); - memoryData.shift(); - timeLabels.shift(); - } - - var cpuUse = (Pterodactyl.server.cpu > 0) ? parseFloat(((proc.data.cpu.total / Pterodactyl.server.cpu) * 100).toFixed(3).toString()) : proc.data.cpu.total; - cpuData.push(cpuUse); - memoryData.push(parseInt(proc.data.memory.total / (1024 * 1024))); - - var m = new Date(); - timeLabels.push($.format.date(new Date(), 'HH:mm:ss')); - - CPUChart.update(); - MemoryChart.update(); - }); - - // Update Listings on Initial Status - Socket.on('initial status', function (data) { - updateServerPowerControls(data.status); - }); - - // Update Listings on Status - Socket.on('status', function (data) { - updateServerPowerControls(data.status); - }); - - function updateServerPowerControls (data) { - // Server is On or Starting - if(data == 1 || data == 2) { - $('[data-attr="power"][data-action="start"]').addClass('disabled'); - $('[data-attr="power"][data-action="stop"], [data-attr="power"][data-action="restart"]').removeClass('disabled'); - } else { - if (data == 0) { - $('[data-attr="power"][data-action="start"]').removeClass('disabled'); - } - $('[data-attr="power"][data-action="stop"], [data-attr="power"][data-action="restart"]').addClass('disabled'); - } - - if(data !== 0) { - $('[data-attr="power"][data-action="kill"]').removeClass('disabled'); - } else { - $('[data-attr="power"][data-action="kill"]').addClass('disabled'); - } - } + Console.init(); }); From 5142dce0e0f83e6f3d9e203d3eb533eac7e0f4f0 Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Thu, 26 Jan 2017 22:20:04 +0100 Subject: [PATCH 168/599] reorganize code of console module --- .../themes/pterodactyl/js/frontend/console.js | 289 +++++++++--------- 1 file changed, 152 insertions(+), 137 deletions(-) diff --git a/public/themes/pterodactyl/js/frontend/console.js b/public/themes/pterodactyl/js/frontend/console.js index bbee56465..5af50eeae 100644 --- a/public/themes/pterodactyl/js/frontend/console.js +++ b/public/themes/pterodactyl/js/frontend/console.js @@ -25,6 +25,12 @@ const Console = (function () { var terminalQueue; var terminal; + var cpuChart; + var cpuData; + var memoryChart; + var memoryData; + var timeLabels; + function initConsole() { termianlQueue = []; terminal = $('#terminal').terminal(function (command, term) { @@ -41,13 +47,134 @@ const Console = (function () { return false; } }); + } + function initGraphs() { + var ctc = $('#chart_cpu'); + var timeLabels = []; + var cpuData = []; + var CPUChart = new Chart(ctc, { + type: 'line', + data: { + labels: timeLabels, + datasets: [ + { + label: "Percent Use", + fill: false, + lineTension: 0.03, + backgroundColor: "#00A1CB", + borderColor: "#00A1CB", + borderCapStyle: 'butt', + borderDash: [], + borderDashOffset: 0.0, + borderJoinStyle: 'miter', + pointBorderColor: "rgba(75,192,192,1)", + pointBackgroundColor: "#fff", + pointBorderWidth: 1, + pointHoverRadius: 5, + pointHoverBackgroundColor: "rgba(75,192,192,1)", + pointHoverBorderColor: "rgba(220,220,220,1)", + pointHoverBorderWidth: 2, + pointRadius: 1, + pointHitRadius: 10, + data: cpuData, + spanGaps: false, + } + ] + }, + options: { + title: { + display: true, + text: 'CPU Usage (as Percent Total)' + }, + legend: { + display: false, + }, + animation: { + duration: 1, + } + } + }); + + var ctm = $('#chart_memory'); + var memoryData = []; + var MemoryChart = new Chart(ctm, { + type: 'line', + data: { + labels: timeLabels, + datasets: [ + { + label: "Memory Use", + fill: false, + lineTension: 0.03, + backgroundColor: "#01A4A4", + borderColor: "#01A4A4", + borderCapStyle: 'butt', + borderDash: [], + borderDashOffset: 0.0, + borderJoinStyle: 'miter', + pointBorderColor: "rgba(75,192,192,1)", + pointBackgroundColor: "#fff", + pointBorderWidth: 1, + pointHoverRadius: 5, + pointHoverBackgroundColor: "rgba(75,192,192,1)", + pointHoverBorderColor: "rgba(220,220,220,1)", + pointHoverBorderWidth: 2, + pointRadius: 1, + pointHitRadius: 10, + data: memoryData, + spanGaps: false, + } + ] + }, + options: { + title: { + display: true, + text: 'Memory Usage (in Megabytes)' + }, + legend: { + display: false, + }, + animation: { + duration: 1, + } + } + }); + } + + function addSocketListeners() { + // Update Listings on Initial Status Socket.on('initial status', function (data) { + updateServerPowerControls(data.status); + terminal.clear(); if (data.status === 1 || data.status === 2) { Socket.emit('send server log'); } }); + + // Update Listings on Status + Socket.on('status', function (data) { + updateServerPowerControls(data.status); + }); + + Socket.on('proc', function (proc) { + if (cpuData.length > 10) { + cpuData.shift(); + memoryData.shift(); + timeLabels.shift(); + } + + var cpuUse = (Pterodactyl.server.cpu > 0) ? parseFloat(((proc.data.cpu.total / Pterodactyl.server.cpu) * 100).toFixed(3).toString()) : proc.data.cpu.total; + cpuData.push(cpuUse); + memoryData.push(parseInt(proc.data.memory.total / (1024 * 1024))); + + var m = new Date(); + timeLabels.push($.format.date(new Date(), 'HH:mm:ss')); + + CPUChart.update(); + MemoryChart.update(); + }); } function pushOutputQueue() { @@ -65,150 +192,38 @@ const Console = (function () { window.setTimeout(pushOutputQueue, CONSOLE_PUSH_FREQ); } + function updateServerPowerControls (data) { + // Server is On or Starting + if(data == 1 || data == 2) { + $('[data-attr="power"][data-action="start"]').addClass('disabled'); + $('[data-attr="power"][data-action="stop"], [data-attr="power"][data-action="restart"]').removeClass('disabled'); + } else { + if (data == 0) { + $('[data-attr="power"][data-action="start"]').removeClass('disabled'); + } + $('[data-attr="power"][data-action="stop"], [data-attr="power"][data-action="restart"]').addClass('disabled'); + } + + if(data !== 0) { + $('[data-attr="power"][data-action="kill"]').removeClass('disabled'); + } else { + $('[data-attr="power"][data-action="kill"]').addClass('disabled'); + } + } + return { init: function () { + + initConsole(); + pushOutputQueue(); + initGraphs(); + addSocketListeners(); + $('[data-attr="power"]').click(function (event) { if (! $(this).hasClass('disabled')) { Socket.emit('set status', $(this).data('action')); } }); - - var ctc = $('#chart_cpu'); - var timeLabels = []; - var cpuData = []; - var CPUChart = new Chart(ctc, { - type: 'line', - data: { - labels: timeLabels, - datasets: [ - { - label: "Percent Use", - fill: false, - lineTension: 0.03, - backgroundColor: "#00A1CB", - borderColor: "#00A1CB", - borderCapStyle: 'butt', - borderDash: [], - borderDashOffset: 0.0, - borderJoinStyle: 'miter', - pointBorderColor: "rgba(75,192,192,1)", - pointBackgroundColor: "#fff", - pointBorderWidth: 1, - pointHoverRadius: 5, - pointHoverBackgroundColor: "rgba(75,192,192,1)", - pointHoverBorderColor: "rgba(220,220,220,1)", - pointHoverBorderWidth: 2, - pointRadius: 1, - pointHitRadius: 10, - data: cpuData, - spanGaps: false, - } - ] - }, - options: { - title: { - display: true, - text: 'CPU Usage (as Percent Total)' - }, - legend: { - display: false, - }, - animation: { - duration: 1, - } - } - }); - - var ctm = $('#chart_memory'); - var memoryData = []; - var MemoryChart = new Chart(ctm, { - type: 'line', - data: { - labels: timeLabels, - datasets: [ - { - label: "Memory Use", - fill: false, - lineTension: 0.03, - backgroundColor: "#01A4A4", - borderColor: "#01A4A4", - borderCapStyle: 'butt', - borderDash: [], - borderDashOffset: 0.0, - borderJoinStyle: 'miter', - pointBorderColor: "rgba(75,192,192,1)", - pointBackgroundColor: "#fff", - pointBorderWidth: 1, - pointHoverRadius: 5, - pointHoverBackgroundColor: "rgba(75,192,192,1)", - pointHoverBorderColor: "rgba(220,220,220,1)", - pointHoverBorderWidth: 2, - pointRadius: 1, - pointHitRadius: 10, - data: memoryData, - spanGaps: false, - } - ] - }, - options: { - title: { - display: true, - text: 'Memory Usage (in Megabytes)' - }, - legend: { - display: false, - }, - animation: { - duration: 1, - } - } - }); - Socket.on('proc', function (proc) { - if (cpuData.length > 10) { - cpuData.shift(); - memoryData.shift(); - timeLabels.shift(); - } - - var cpuUse = (Pterodactyl.server.cpu > 0) ? parseFloat(((proc.data.cpu.total / Pterodactyl.server.cpu) * 100).toFixed(3).toString()) : proc.data.cpu.total; - cpuData.push(cpuUse); - memoryData.push(parseInt(proc.data.memory.total / (1024 * 1024))); - - var m = new Date(); - timeLabels.push($.format.date(new Date(), 'HH:mm:ss')); - - CPUChart.update(); - MemoryChart.update(); - }); - - // Update Listings on Initial Status - Socket.on('initial status', function (data) { - updateServerPowerControls(data.status); - }); - - // Update Listings on Status - Socket.on('status', function (data) { - updateServerPowerControls(data.status); - }); - - function updateServerPowerControls (data) { - // Server is On or Starting - if(data == 1 || data == 2) { - $('[data-attr="power"][data-action="start"]').addClass('disabled'); - $('[data-attr="power"][data-action="stop"], [data-attr="power"][data-action="restart"]').removeClass('disabled'); - } else { - if (data == 0) { - $('[data-attr="power"][data-action="start"]').removeClass('disabled'); - } - $('[data-attr="power"][data-action="stop"], [data-attr="power"][data-action="restart"]').addClass('disabled'); - } - - if(data !== 0) { - $('[data-attr="power"][data-action="kill"]').removeClass('disabled'); - } else { - $('[data-attr="power"][data-action="kill"]').addClass('disabled'); - } - } }, getTerminal: function() { From 344e3b43302802ce1c378b7caf0c31ab02de92af Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Thu, 26 Jan 2017 22:57:33 +0100 Subject: [PATCH 169/599] =?UTF-8?q?add=20console=20notification=20on=20new?= =?UTF-8?q?=20output=20that=20is=20out=20of=20view=20fix=20the=20revealing?= =?UTF-8?q?=20module=20pattern=20(browser=20cache=20=F0=9F=98=92)=20change?= =?UTF-8?q?=20graph=20colors=20to=20theme=20primary=20color=20move=20Socke?= =?UTF-8?q?t.on(=E2=80=9Aconsole=E2=80=99)=20to=20console.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/themes/pterodactyl/css/pterodactyl.css | 21 +++++ .../themes/pterodactyl/js/frontend/console.js | 77 ++++++++++++------- .../pterodactyl/js/frontend/server.socket.js | 4 - .../themes/pterodactyl/server/index.blade.php | 5 +- 4 files changed, 75 insertions(+), 32 deletions(-) diff --git a/public/themes/pterodactyl/css/pterodactyl.css b/public/themes/pterodactyl/css/pterodactyl.css index 5c849120d..16dbe1547 100644 --- a/public/themes/pterodactyl/css/pterodactyl.css +++ b/public/themes/pterodactyl/css/pterodactyl.css @@ -125,3 +125,24 @@ td.has-progress { .no-margin { margin: 0 !important; } + +.position-relative { + position: relative; +} + +.terminal-notify { + position: absolute; + right: 10px; + bottom: 10px; + /* Browsers usually have a 17px scrollbar which is visible in the terminal */ + padding: 7px 24px 7px 7px; + border-top-left-radius: 3px; + background: white; + color: black; + opacity: .5; + cursor: pointer; +} + +.terminal-notify:hover { + opacity: .9; +} diff --git a/public/themes/pterodactyl/js/frontend/console.js b/public/themes/pterodactyl/js/frontend/console.js index 5af50eeae..3977379c5 100644 --- a/public/themes/pterodactyl/js/frontend/console.js +++ b/public/themes/pterodactyl/js/frontend/console.js @@ -17,10 +17,10 @@ // 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. -var CONSOLE_PUSH_COUNT = 50; -var CONSOLE_PUSH_FREQ = 200; -const Console = (function () { +var Console = (function () { + var CONSOLE_PUSH_COUNT = 50; + var CONSOLE_PUSH_FREQ = 200; var terminalQueue; var terminal; @@ -31,8 +31,10 @@ const Console = (function () { var memoryData; var timeLabels; + var $terminalNotify; + function initConsole() { - termianlQueue = []; + terminalQueue = []; terminal = $('#terminal').terminal(function (command, term) { Socket.emit('send command', command); }, { @@ -47,13 +49,25 @@ const Console = (function () { return false; } }); + + $terminalNotify = $('#terminalNotify'); + $terminalNotify.on('click', function () { + terminal.scroll_to_bottom(); + $terminalNotify.addClass('hidden'); + }) + + terminal.on('scroll', function () { + if (terminal.is_bottom()) { + $terminalNotify.addClass('hidden'); + } + }) } function initGraphs() { var ctc = $('#chart_cpu'); - var timeLabels = []; - var cpuData = []; - var CPUChart = new Chart(ctc, { + timeLabels = []; + cpuData = []; + cpuChart = new Chart(ctc, { type: 'line', data: { labels: timeLabels, @@ -62,17 +76,17 @@ const Console = (function () { label: "Percent Use", fill: false, lineTension: 0.03, - backgroundColor: "#00A1CB", - borderColor: "#00A1CB", + backgroundColor: "#3c8dbc", + borderColor: "#3c8dbc", borderCapStyle: 'butt', borderDash: [], borderDashOffset: 0.0, borderJoinStyle: 'miter', - pointBorderColor: "rgba(75,192,192,1)", + pointBorderColor: "#3c8dbc", pointBackgroundColor: "#fff", pointBorderWidth: 1, pointHoverRadius: 5, - pointHoverBackgroundColor: "rgba(75,192,192,1)", + pointHoverBackgroundColor: "#3c8dbc", pointHoverBorderColor: "rgba(220,220,220,1)", pointHoverBorderWidth: 2, pointRadius: 1, @@ -97,8 +111,8 @@ const Console = (function () { }); var ctm = $('#chart_memory'); - var memoryData = []; - var MemoryChart = new Chart(ctm, { + memoryData = []; + memoryChart = new Chart(ctm, { type: 'line', data: { labels: timeLabels, @@ -107,17 +121,17 @@ const Console = (function () { label: "Memory Use", fill: false, lineTension: 0.03, - backgroundColor: "#01A4A4", - borderColor: "#01A4A4", + backgroundColor: "#3c8dbc", + borderColor: "#3c8dbc", borderCapStyle: 'butt', borderDash: [], borderDashOffset: 0.0, borderJoinStyle: 'miter', - pointBorderColor: "rgba(75,192,192,1)", + pointBorderColor: "#3c8dbc", pointBackgroundColor: "#fff", pointBorderWidth: 1, pointHoverRadius: 5, - pointHoverBackgroundColor: "rgba(75,192,192,1)", + pointHoverBackgroundColor: "#3c8dbc", pointHoverBorderColor: "rgba(220,220,220,1)", pointHoverBorderWidth: 2, pointRadius: 1, @@ -158,6 +172,10 @@ const Console = (function () { updateServerPowerControls(data.status); }); + Socket.on('console', function (data) { + terminalQueue.push(data.line); + }); + Socket.on('proc', function (proc) { if (cpuData.length > 10) { cpuData.shift(); @@ -172,20 +190,25 @@ const Console = (function () { var m = new Date(); timeLabels.push($.format.date(new Date(), 'HH:mm:ss')); - CPUChart.update(); - MemoryChart.update(); + cpuChart.update(); + memoryChart.update(); }); } function pushOutputQueue() { - if (termianlQueue.length > CONSOLE_PUSH_COUNT) { + if (terminalQueue.length > CONSOLE_PUSH_COUNT) { // console throttled warning show } - if (termianlQueue.length > 0) { - for (var i = 0; i < CONSOLE_PUSH_COUNT && termianlQueue.length > 0; i++) { - terminal.echo(termianlQueue[0]); - termianlQueue.shift(); + if (terminalQueue.length > 0) { + for (var i = 0; i < CONSOLE_PUSH_COUNT && terminalQueue.length > 0; i++) { + terminal.echo(terminalQueue[0]); + terminalQueue.shift(); + } + + // Show + if (!terminal.is_bottom()) { + $terminalNotify.removeClass('hidden'); } } @@ -226,16 +249,16 @@ const Console = (function () { }); }, - getTerminal: function() { + getTerminal: function () { return terminal }, - getTerminalQueue: function() { + getTerminalQueue: function () { return terminalQueue }, } -}); +})(); $(document).ready(function () { Console.init(); diff --git a/public/themes/pterodactyl/js/frontend/server.socket.js b/public/themes/pterodactyl/js/frontend/server.socket.js index 49b22ddf0..c789b2854 100644 --- a/public/themes/pterodactyl/js/frontend/server.socket.js +++ b/public/themes/pterodactyl/js/frontend/server.socket.js @@ -73,10 +73,6 @@ Socket.on('status', function (data) { setStatusIcon(data.status); }); - - Socket.on('console', function (data) { - TerminalQueue.push(data.line); - }); })(); function setStatusIcon(status) { diff --git a/resources/themes/pterodactyl/server/index.blade.php b/resources/themes/pterodactyl/server/index.blade.php index 67e6c956c..27605d2f8 100644 --- a/resources/themes/pterodactyl/server/index.blade.php +++ b/resources/themes/pterodactyl/server/index.blade.php @@ -40,8 +40,11 @@
      -
      +
      +
      - @if(count($servers) === 0) + @if(count($node->servers) === 0)
      @@ -459,7 +456,7 @@
      From 323f1d943f17250b7ed2ab1506869b4bc479c93e Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 5 Feb 2017 17:58:17 -0500 Subject: [PATCH 205/599] Completed model updates for Services --- .../Controllers/API/ServiceController.php | 2 +- app/Http/Controllers/Admin/PackController.php | 80 ++++++------------- .../Controllers/Admin/ServersController.php | 4 +- .../Controllers/Admin/ServiceController.php | 71 ++++++++-------- .../Controllers/Server/ServerController.php | 2 +- app/Models/Service.php | 35 +++++++- app/Models/ServiceOptions.php | 24 +++++- app/Models/ServicePack.php | 10 +++ app/Models/ServiceVariables.php | 5 ++ app/Observers/ServerObserver.php | 2 +- app/Repositories/ServerRepository.php | 4 +- app/Repositories/ServiceRepository/Option.php | 2 +- app/Repositories/ServiceRepository/Pack.php | 31 ++++--- .../ServiceRepository/Service.php | 15 ++-- .../ServiceRepository/Variable.php | 28 +++++-- .../2017_02_05_164123_AdjustColumnNames.php | 40 ++++++++++ ...64516_AdjustColumnNamesForServicePacks.php | 40 ++++++++++ .../views/admin/services/index.blade.php | 2 +- .../admin/services/options/variable.blade.php | 6 +- .../admin/services/options/view.blade.php | 23 +++--- .../admin/services/packs/byoption.blade.php | 4 +- .../admin/services/packs/byservice.blade.php | 4 +- .../views/admin/services/packs/edit.blade.php | 12 +-- .../views/admin/services/packs/new.blade.php | 8 +- .../admin/services/packs/upload.blade.php | 8 +- resources/views/admin/services/view.blade.php | 4 +- 26 files changed, 299 insertions(+), 167 deletions(-) create mode 100644 database/migrations/2017_02_05_164123_AdjustColumnNames.php create mode 100644 database/migrations/2017_02_05_164516_AdjustColumnNamesForServicePacks.php diff --git a/app/Http/Controllers/API/ServiceController.php b/app/Http/Controllers/API/ServiceController.php index 257ace766..81d5a955d 100755 --- a/app/Http/Controllers/API/ServiceController.php +++ b/app/Http/Controllers/API/ServiceController.php @@ -53,7 +53,7 @@ class ServiceController extends BaseController return [ 'service' => $service, 'options' => Models\ServiceOptions::select('id', 'name', 'description', 'tag', 'docker_image') - ->where('parent_service', $service->id) + ->where('service_id', $service->id) ->with('variables') ->with('packs') ->get(), diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php index 628cd54b8..3e6685f28 100644 --- a/app/Http/Controllers/Admin/PackController.php +++ b/app/Http/Controllers/Admin/PackController.php @@ -42,64 +42,29 @@ class PackController extends Controller // } - protected function formatServices() - { - $options = Models\ServiceOptions::select( - 'services.name AS p_service', - 'service_options.id', - 'service_options.name' - )->join('services', 'services.id', '=', 'service_options.parent_service')->get(); - - $array = []; - foreach ($options as &$option) { - if (! array_key_exists($option->p_service, $array)) { - $array[$option->p_service] = []; - } - - $array[$option->p_service] = array_merge($array[$option->p_service], [[ - 'id' => $option->id, - 'name' => $option->name, - ]]); - } - - return $array; - } - public function listAll(Request $request) { - return view('admin.services.packs.index', [ - 'services' => Models\Service::all(), - ]); + return view('admin.services.packs.index', ['services' => Models\Service::all()]); } public function listByOption(Request $request, $id) { - $option = Models\ServiceOptions::findOrFail($id); - return view('admin.services.packs.byoption', [ - 'packs' => Models\ServicePack::where('option', $option->id)->get(), - 'service' => Models\Service::findOrFail($option->parent_service), - 'option' => $option, + 'option' => Models\ServiceOptions::with('service', 'packs')->findOrFail($id) ]); } public function listByService(Request $request, $id) { return view('admin.services.packs.byservice', [ - 'service' => Models\Service::findOrFail($id), - 'options' => Models\ServiceOptions::select( - 'service_options.id', - 'service_options.name', - DB::raw('(SELECT COUNT(id) FROM service_packs WHERE service_packs.option = service_options.id) AS p_count') - )->where('parent_service', $id)->get(), + 'service' => Models\Service::with('options', 'options.packs')->findOrFail($id), ]); } public function new(Request $request, $opt = null) { return view('admin.services.packs.new', [ - 'services' => $this->formatServices(), - 'packFor' => $opt, + 'services' => Models\Service::with('options')->get(), ]); } @@ -107,12 +72,18 @@ class PackController extends Controller { try { $repo = new Pack; - $id = $repo->create($request->except([ - '_token', + $pack = $repo->create($request->only([ + 'name', + 'version', + 'description', + 'option', + 'selectable', + 'visible', + 'file_upload', ])); Alert::success('Successfully created new service!')->flash(); - return redirect()->route('admin.services.packs.edit', $id)->withInput(); + return redirect()->route('admin.services.packs.edit', $pack->id)->withInput(); } catch (DisplayValidationException $ex) { return redirect()->route('admin.services.packs.new', $request->input('option'))->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { @@ -127,15 +98,12 @@ class PackController extends Controller public function edit(Request $request, $id) { - $pack = Models\ServicePack::findOrFail($id); - $option = Models\ServiceOptions::select('id', 'parent_service', 'name')->where('id', $pack->option)->first(); + $pack = Models\ServicePack::with('option.service')->findOrFail($id); return view('admin.services.packs.edit', [ 'pack' => $pack, - 'services' => $this->formatServices(), + 'services' => Models\Service::all()->load('options'), 'files' => Storage::files('packs/' . $pack->uuid), - 'service' => Models\Service::findOrFail($option->parent_service), - 'option' => $option, ]); } @@ -159,8 +127,13 @@ class PackController extends Controller } else { try { $repo = new Pack; - $repo->update($id, $request->except([ - '_token', + $repo->update($id, $request->only([ + 'name', + 'version', + 'description', + 'option', + 'selectable', + 'visible', ])); Alert::success('Service pack has been successfully updated.')->flash(); } catch (DisplayValidationException $ex) { @@ -215,8 +188,7 @@ class PackController extends Controller public function uploadForm(Request $request, $for = null) { return view('admin.services.packs.upload', [ - 'services' => $this->formatServices(), - 'for' => $for, + 'services' => Models\Service::all()->load('options'), ]); } @@ -224,12 +196,10 @@ class PackController extends Controller { try { $repo = new Pack; - $id = $repo->createWithTemplate($request->except([ - '_token', - ])); + $pack = $repo->createWithTemplate($request->only(['option', 'file_upload'])); Alert::success('Successfully created new service!')->flash(); - return redirect()->route('admin.services.packs.edit', $id)->withInput(); + return redirect()->route('admin.services.packs.edit', $pack->id)->withInput(); } catch (DisplayValidationException $ex) { return redirect()->back()->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index f75508139..eee134d3e 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -244,7 +244,7 @@ class ServersController extends Controller $service = Models\Service::select('executable', 'startup')->where('id', $request->input('service'))->first(); - return response()->json(Models\ServiceOptions::select('id', 'name', 'docker_image')->where('parent_service', $request->input('service'))->orderBy('name', 'asc')->get()); + return response()->json(Models\ServiceOptions::select('id', 'name', 'docker_image')->where('service_id', $request->input('service'))->orderBy('name', 'asc')->get()); } /** @@ -264,7 +264,7 @@ class ServersController extends Controller $option = Models\ServiceOptions::select( DB::raw('COALESCE(service_options.executable, services.executable) as executable'), DB::raw('COALESCE(service_options.startup, services.startup) as startup') - )->leftJoin('services', 'services.id', '=', 'service_options.parent_service') + )->leftJoin('services', 'services.id', '=', 'service_options.service_id') ->where('service_options.id', $request->input('option')) ->first(); diff --git a/app/Http/Controllers/Admin/ServiceController.php b/app/Http/Controllers/Admin/ServiceController.php index 70de4f88e..f8951993a 100644 --- a/app/Http/Controllers/Admin/ServiceController.php +++ b/app/Http/Controllers/Admin/ServiceController.php @@ -45,10 +45,7 @@ class ServiceController extends Controller public function getIndex(Request $request) { return view('admin.services.index', [ - 'services' => Models\Service::select( - 'services.*', - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.service = services.id) as c_servers') - )->get(), + 'services' => Models\Service::withCount('servers')->get(), ]); } @@ -61,12 +58,16 @@ class ServiceController extends Controller { try { $repo = new ServiceRepository\Service; - $id = $repo->create($request->except([ - '_token', + $service = $repo->create($request->only([ + 'name', + 'description', + 'file', + 'executable', + 'startup', ])); Alert::success('Successfully created new service!')->flash(); - return redirect()->route('admin.services.service', $id); + return redirect()->route('admin.services.service', $service->id); } catch (DisplayValidationException $ex) { return redirect()->route('admin.services.new')->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { @@ -82,11 +83,7 @@ class ServiceController extends Controller 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(), + 'service' => Models\Service::with('options', 'options.servers')->findOrFail($service), ]); } @@ -94,8 +91,12 @@ class ServiceController extends Controller { try { $repo = new ServiceRepository\Service; - $repo->update($service, $request->except([ - '_token', + $repo->update($service, $request->only([ + 'name', + 'description', + 'file', + 'executable', + 'startup', ])); Alert::success('Successfully updated this service.')->flash(); } catch (DisplayValidationException $ex) { @@ -130,16 +131,11 @@ class ServiceController extends Controller public function getOption(Request $request, $service, $option) { - $opt = Models\ServiceOptions::findOrFail($option); + $option = Models\ServiceOptions::with('service', 'variables')->findOrFail($option); + $option->setRelation('servers', $option->servers()->with('user')->paginate(25)); 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_id') - ->where('option', $option) - ->paginate(10), + 'option' => $option, ]); } @@ -147,8 +143,13 @@ class ServiceController extends Controller { try { $repo = new ServiceRepository\Option; - $repo->update($option, $request->except([ - '_token', + $repo->update($option, $request->only([ + 'name', + 'description', + 'tag', + 'executable', + 'docker_image', + 'startup', ])); Alert::success('Option settings successfully updated.')->flash(); } catch (DisplayValidationException $ex) { @@ -164,13 +165,12 @@ class ServiceController extends Controller public function deleteOption(Request $request, $service, $option) { try { - $service = Models\ServiceOptions::select('parent_service')->where('id', $option)->first(); $repo = new ServiceRepository\Option; $repo->delete($option); Alert::success('Successfully deleted that option.')->flash(); - return redirect()->route('admin.services.service', $service->parent_service); + return redirect()->route('admin.services.service', $service); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); } catch (\Exception $ex) { @@ -218,8 +218,7 @@ class ServiceController extends Controller public function getNewVariable(Request $request, $service, $option) { return view('admin.services.options.variable', [ - 'service' => Models\Service::findOrFail($service), - 'option' => Models\ServiceOptions::where('parent_service', $service)->where('id', $option)->firstOrFail(), + 'option' => Models\ServiceOptions::with('service')->findOrFail($option), ]); } @@ -227,8 +226,15 @@ class ServiceController extends Controller { try { $repo = new ServiceRepository\Variable; - $repo->create($option, $request->except([ - '_token', + $repo->create($option, $request->only([ + 'name', + 'description', + 'env_variable', + 'default_value', + 'user_viewable', + 'user_editable', + 'required', + 'regex', ])); Alert::success('Successfully added new variable to this option.')->flash(); @@ -305,8 +311,9 @@ class ServiceController extends Controller { try { $repo = new ServiceRepository\Service; - $repo->updateFile($serviceId, $request->except([ - '_token', + $repo->updateFile($serviceId, $request->only([ + 'file', + 'contents', ])); return response('', 204); diff --git a/app/Http/Controllers/Server/ServerController.php b/app/Http/Controllers/Server/ServerController.php index 75378ddc1..12fb41ad1 100644 --- a/app/Http/Controllers/Server/ServerController.php +++ b/app/Http/Controllers/Server/ServerController.php @@ -224,7 +224,7 @@ class ServerController extends Controller $service = Models\Service::select( DB::raw('IFNULL(service_options.executable, services.executable) as executable') - )->leftJoin('service_options', 'service_options.parent_service', '=', 'services.id') + )->leftJoin('service_options', 'service_options.service_id', '=', 'services.id') ->where('service_options.id', $server->option_id) ->where('services.id', $server->service_id) ->first(); diff --git a/app/Models/Service.php b/app/Models/Service.php index 8c0f27790..d7900b632 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -40,5 +40,38 @@ class Service extends Model * * @var array */ - protected $guarded = ['id', 'created_at', 'updated_at']; + protected $fillable = ['id', 'created_at', 'updated_at']; + + /** + * Gets all service options associated with this service. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function options() + { + return $this->hasMany(ServiceOptions::class); + } + + /** + * Returns all of the packs associated with a service, regardless of the service option. + * + * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough + */ + public function packs() + { + return $this->hasManyThrough( + 'Pterodactyl\Models\ServicePack', 'Pterodactyl\Models\ServiceOptions', + 'service_id', 'option_id' + ); + } + + /** + * Gets all servers associated with this service. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function servers() + { + return $this->hasMany(Server::class); + } } diff --git a/app/Models/ServiceOptions.php b/app/Models/ServiceOptions.php index 9b4a3a7ae..9cd61a702 100644 --- a/app/Models/ServiceOptions.php +++ b/app/Models/ServiceOptions.php @@ -48,9 +48,29 @@ class ServiceOptions extends Model * @var array */ protected $casts = [ - 'parent_service' => 'integer', + 'service_id' => 'integer', ]; + /** + * Gets service associated with a service option. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function service() + { + return $this->belongsTo(Service::class); + } + + /** + * Gets all servers associated with this service option. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function servers() + { + return $this->hasMany(Server::class, 'option_id'); + } + /** * Gets all variables associated with this service. * @@ -68,6 +88,6 @@ class ServiceOptions extends Model */ public function packs() { - return $this->hasMany(ServicePack::class, 'option'); + return $this->hasMany(ServicePack::class, 'option_id'); } } diff --git a/app/Models/ServicePack.php b/app/Models/ServicePack.php index cefcc0a32..7c9a624ff 100644 --- a/app/Models/ServicePack.php +++ b/app/Models/ServicePack.php @@ -56,4 +56,14 @@ class ServicePack extends Model 'selectable' => 'boolean', 'visible' => 'boolean', ]; + + /** + * Gets option associated with a service pack. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function option() + { + return $this->belongsTo(ServiceOptions::class); + } } diff --git a/app/Models/ServiceVariables.php b/app/Models/ServiceVariables.php index 5082d714e..f088202e7 100644 --- a/app/Models/ServiceVariables.php +++ b/app/Models/ServiceVariables.php @@ -53,4 +53,9 @@ class ServiceVariables extends Model 'user_editable' => 'integer', 'required' => 'integer', ]; + + public function serverVariables() + { + return $this->hasMany(ServerVariables::class, 'variable_id'); + } } diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php index cacb9c82f..626847aa4 100644 --- a/app/Observers/ServerObserver.php +++ b/app/Observers/ServerObserver.php @@ -62,7 +62,7 @@ class ServerObserver $user = Models\User::findOrFail($server->owner_id); $node = Models\Node::select('name')->where('id', $server->node_id)->first(); $service = Models\Service::select('services.name', 'service_options.name as optionName') - ->join('service_options', 'service_options.parent_service', '=', 'services.id') + ->join('service_options', 'service_options.service_id', '=', 'services.id') ->where('services.id', $server->service_id) ->where('service_options.id', $server->option_id) ->first(); diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 3cd3d32ba..fe2a2f840 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -163,7 +163,7 @@ class ServerRepository // We know the service and option exists because of the validation. // We need to verify that the option exists for the service, and then check for // any required variable fields. (fields are labeled env_) - $option = Models\ServiceOptions::where('id', $data['option'])->where('parent_service', $data['service'])->first(); + $option = Models\ServiceOptions::where('id', $data['option'])->where('service_id', $data['service'])->first(); if (! $option) { throw new DisplayException('The requested service option does not exist for the specified service.'); } @@ -181,7 +181,7 @@ class ServerRepository } // Load up the Service Information - $service = Models\Service::find($option->parent_service); + $service = Models\Service::find($option->service_id); // Check those Variables $variables = Models\ServiceVariables::where('option_id', $data['option'])->get(); diff --git a/app/Repositories/ServiceRepository/Option.php b/app/Repositories/ServiceRepository/Option.php index 8ddcdc006..ddac543d6 100644 --- a/app/Repositories/ServiceRepository/Option.php +++ b/app/Repositories/ServiceRepository/Option.php @@ -63,7 +63,7 @@ class Option } $option = new Models\ServiceOptions; - $option->parent_service = $service->id; + $option->service_id = $service->id; $option->fill($data); $option->save(); diff --git a/app/Repositories/ServiceRepository/Pack.php b/app/Repositories/ServiceRepository/Pack.php index 03858ed67..c3cc2dc9c 100644 --- a/app/Repositories/ServiceRepository/Pack.php +++ b/app/Repositories/ServiceRepository/Pack.php @@ -69,8 +69,8 @@ class Pack try { $uuid = new UuidService; $pack = Models\ServicePack::create([ - 'option' => $data['option'], - 'uuid' => $uuid->generate('servers', 'uuid'), + 'option_id' => $data['option'], + 'uuid' => $uuid->generate('service_packs', 'uuid'), 'name' => $data['name'], 'version' => $data['version'], 'description' => (empty($data['description'])) ? null : $data['description'], @@ -89,7 +89,7 @@ class Pack throw $ex; } - return $pack->id; + return $pack; } public function createWithTemplate(array $data) @@ -123,7 +123,7 @@ class Pack } $json = json_decode($zip->getFromName('import.json')); - $id = $this->create([ + $pack = $this->create([ 'name' => $json->name, 'version' => $json->version, 'description' => $json->description, @@ -132,7 +132,6 @@ class Pack 'visible' => $json->visible, ]); - $pack = Models\ServicePack::findOrFail($id); if (! $zip->extractTo(storage_path('app/packs/' . $pack->uuid), 'archive.tar.gz')) { $pack->delete(); throw new DisplayException('Unable to extract the archive file to the correct location.'); @@ -140,7 +139,7 @@ class Pack $zip->close(); - return $pack->id; + return $pack; } else { $json = json_decode(file_get_contents($data['file_upload']->path())); @@ -170,18 +169,16 @@ class Pack throw new DisplayValidationException($validator->errors()); } - DB::transaction(function () use ($id, $data) { - Models\ServicePack::findOrFail($id)->update([ - 'option' => $data['option'], - 'name' => $data['name'], - 'version' => $data['version'], - 'description' => (empty($data['description'])) ? null : $data['description'], - 'selectable' => isset($data['selectable']), - 'visible' => isset($data['visible']), - ]); + Models\ServicePack::findOrFail($id)->update([ + 'option_id' => $data['option'], + 'name' => $data['name'], + 'version' => $data['version'], + 'description' => (empty($data['description'])) ? null : $data['description'], + 'selectable' => isset($data['selectable']), + 'visible' => isset($data['visible']), + ]); - return true; - }); + return; } public function delete($id) diff --git a/app/Repositories/ServiceRepository/Service.php b/app/Repositories/ServiceRepository/Service.php index eb41a9fee..fd6ffe629 100644 --- a/app/Repositories/ServiceRepository/Service.php +++ b/app/Repositories/ServiceRepository/Service.php @@ -55,23 +55,18 @@ class Service $data['author'] = env('SERVICE_AUTHOR', (string) Uuid::generate(4)); - $service = new Models\Service; DB::beginTransaction(); - try { - $service->fill($data); - $service->save(); - - Storage::put('services/' . $data['file'] . '/main.json', '{}'); - Storage::copy('services/.templates/index.js', 'services/' . $data['file'] . '/index.js'); - + $service = Models\Service::create($data); + Storage::put('services/' . $service->file . '/main.json', '{}'); + Storage::copy('services/.templates/index.js', 'services/' . $service->file . '/index.js'); DB::commit(); } catch (\Exception $ex) { DB::rollBack(); throw $ex; } - return $service->id; + return $service; } public function update($id, array $data) @@ -99,7 +94,7 @@ class Service { $service = Models\Service::findOrFail($id); $servers = Models\Server::where('service', $service->id)->get(); - $options = Models\ServiceOptions::select('id')->where('parent_service', $service->id); + $options = Models\ServiceOptions::select('id')->where('service_id', $service->id); if (count($servers) !== 0) { throw new DisplayException('You cannot delete a service that has servers associated with it.'); diff --git a/app/Repositories/ServiceRepository/Variable.php b/app/Repositories/ServiceRepository/Variable.php index fbd258444..bc7ab4c13 100644 --- a/app/Repositories/ServiceRepository/Variable.php +++ b/app/Repositories/ServiceRepository/Variable.php @@ -39,7 +39,7 @@ class Variable public function create($id, array $data) { - $option = Models\ServiceOptions::findOrFail($id); + $option = Models\ServiceOptions::select('id')->findOrFail($id); $validator = Validator::make($data, [ 'name' => 'required|string|min:1|max:255', @@ -67,21 +67,22 @@ class Variable $data['user_viewable'] = (isset($data['user_viewable']) && in_array((int) $data['user_viewable'], [0, 1])) ? $data['user_viewable'] : 0; $data['user_editable'] = (isset($data['user_editable']) && in_array((int) $data['user_editable'], [0, 1])) ? $data['user_editable'] : 0; $data['required'] = (isset($data['required']) && in_array((int) $data['required'], [0, 1])) ? $data['required'] : 0; + $data['option_id'] = $option->id; - $variable = new Models\ServiceVariables; - $variable->option_id = $option->id; - $variable->fill($data); + $variable = Models\ServiceVariables::create($data); - return $variable->save(); + return $variable; } public function delete($id) { - $variable = Models\ServiceVariables::findOrFail($id); + $variable = Models\ServiceVariables::with('serverVariables')->findOrFail($id); DB::beginTransaction(); try { - Models\ServerVariables::where('variable_id', $variable->id)->delete(); + foreach($variable->serverVariables as $svar) { + $svar->delete(); + } $variable->delete(); DB::commit(); @@ -125,7 +126,18 @@ class Variable $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); + // Not using $data because the function that passes into this function + // can't do $requst->only() due to the page setup. + $variable->fill([ + 'name' => $data['name'], + 'description' => $data['description'], + 'env_variable' => $data['env_variable'], + 'default_value' => $data['default_value'], + 'user_viewable' => $data['user_viewable'], + 'user_editable' => $data['user_editable'], + 'required' => $data['required'], + 'regex' => $data['regex'], + ]); return $variable->save(); } diff --git a/database/migrations/2017_02_05_164123_AdjustColumnNames.php b/database/migrations/2017_02_05_164123_AdjustColumnNames.php new file mode 100644 index 000000000..ddb37b891 --- /dev/null +++ b/database/migrations/2017_02_05_164123_AdjustColumnNames.php @@ -0,0 +1,40 @@ +dropForeign('service_options_parent_service_foreign'); + $table->dropIndex('service_options_parent_service_foreign'); + + $table->renameColumn('parent_service', 'service_id'); + $table->foreign('service_id')->references('id')->on('services'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('service_options', function (Blueprint $table) { + $table->dropForeign('service_options_service_id_foreign'); + $table->dropIndex('service_options_service_id_foreign'); + + $table->renameColumn('service_id', 'parent_service'); + $table->foreign('parent_service')->references('id')->on('services'); + }); + } +} diff --git a/database/migrations/2017_02_05_164516_AdjustColumnNamesForServicePacks.php b/database/migrations/2017_02_05_164516_AdjustColumnNamesForServicePacks.php new file mode 100644 index 000000000..5e57ffef3 --- /dev/null +++ b/database/migrations/2017_02_05_164516_AdjustColumnNamesForServicePacks.php @@ -0,0 +1,40 @@ +dropForeign('service_packs_option_foreign'); + $table->dropIndex('service_packs_option_foreign'); + + $table->renameColumn('option', 'option_id'); + $table->foreign('option_id')->references('id')->on('service_options'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('service_packs', function (Blueprint $table) { + $table->dropForeign('service_packs_option_id_foreign'); + $table->dropIndex('service_packs_option_id_foreign'); + + $table->renameColumn('option_id', 'option'); + $table->foreign('option')->references('id')->on('service_options'); + }); + } +} diff --git a/resources/views/admin/services/index.blade.php b/resources/views/admin/services/index.blade.php index 453f1582f..c97df4cf1 100644 --- a/resources/views/admin/services/index.blade.php +++ b/resources/views/admin/services/index.blade.php @@ -44,7 +44,7 @@ {{ $service->name }} {!! $service->description !!} - {{ $service->c_servers }} + {{ $service->servers_count }} @endforeach diff --git a/resources/views/admin/services/options/variable.blade.php b/resources/views/admin/services/options/variable.blade.php index 2c8ff8957..5ed9540c3 100644 --- a/resources/views/admin/services/options/variable.blade.php +++ b/resources/views/admin/services/options/variable.blade.php @@ -28,12 +28,12 @@

      New Option Variable


      -
      +
      diff --git a/resources/views/admin/services/options/view.blade.php b/resources/views/admin/services/options/view.blade.php index e3eb61a12..f40bc8154 100644 --- a/resources/views/admin/services/options/view.blade.php +++ b/resources/views/admin/services/options/view.blade.php @@ -28,12 +28,12 @@
      Warning! This page contains advanced settings that the panel and daemon use to control servers. Modifying information on this page is not recommended unless you are absolutely sure of what you are doing.

      Settings


      - +
      @@ -74,7 +74,7 @@
      - +

      To use the default startup of the parent service simply leave this field blank.

      @@ -88,9 +88,9 @@
      -

      Variables


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

      Variables


      + @foreach($option->variables as $variable) +
      @@ -158,7 +158,7 @@
      {!! csrf_field() !!} - +
      @@ -175,16 +175,19 @@ - @foreach ($servers as $server) + @foreach ($option->servers as $server) {{ $server->name }} - {{ $server->a_ownerEmail }} + {{ $server->user->email }} {{ $server->updated_at }} @endforeach - +
      + {!! $option->servers->render() !!} +
      +
      diff --git a/resources/views/admin/services/packs/byoption.blade.php b/resources/views/admin/services/packs/byoption.blade.php index 23dbf2951..f781a3a3c 100644 --- a/resources/views/admin/services/packs/byoption.blade.php +++ b/resources/views/admin/services/packs/byoption.blade.php @@ -29,7 +29,7 @@
    • Admin Control
    • Services
    • Packs
    • -
    • {{ $service->name }}
    • +
    • {{ $option->service->name }}
    • {{ $option->name }}
    • Service Packs


      @@ -44,7 +44,7 @@ - @foreach ($packs as $pack) + @foreach ($option->packs as $pack) {{ $pack->name }} {{ $pack->version }} diff --git a/resources/views/admin/services/packs/byservice.blade.php b/resources/views/admin/services/packs/byservice.blade.php index 8475de289..f36ce4e4c 100644 --- a/resources/views/admin/services/packs/byservice.blade.php +++ b/resources/views/admin/services/packs/byservice.blade.php @@ -40,10 +40,10 @@ - @foreach ($options as $option) + @foreach ($service->options as $option) {{ $option->name }} - {{ $option->p_count }} + {{ $option->packs->count() }} @endforeach diff --git a/resources/views/admin/services/packs/edit.blade.php b/resources/views/admin/services/packs/edit.blade.php index dcb67d5df..cc6470b3b 100644 --- a/resources/views/admin/services/packs/edit.blade.php +++ b/resources/views/admin/services/packs/edit.blade.php @@ -29,8 +29,8 @@
    • Admin Control
    • Services
    • Packs
    • -
    • {{ $service->name }}
    • -
    • {{ $option->name }}
    • +
    • {{ $pack->option->service->name }}
    • +
    • {{ $pack->option->name }}
    • {{ $pack->name }} ({{ $pack->version }})
    • Manage Service Pack


      @@ -62,10 +62,10 @@
      diff --git a/resources/views/admin/services/packs/new.blade.php b/resources/views/admin/services/packs/new.blade.php index 82601bc62..d5b0440da 100644 --- a/resources/views/admin/services/packs/new.blade.php +++ b/resources/views/admin/services/packs/new.blade.php @@ -59,10 +59,10 @@
      diff --git a/resources/views/admin/services/packs/upload.blade.php b/resources/views/admin/services/packs/upload.blade.php index e9ca020fa..cb5e548d8 100644 --- a/resources/views/admin/services/packs/upload.blade.php +++ b/resources/views/admin/services/packs/upload.blade.php @@ -12,10 +12,10 @@
      diff --git a/resources/views/admin/services/view.blade.php b/resources/views/admin/services/view.blade.php index 887478aca..6b660a5ac 100644 --- a/resources/views/admin/services/view.blade.php +++ b/resources/views/admin/services/view.blade.php @@ -41,12 +41,12 @@ - @foreach($options as $option) + @foreach($service->options as $option) {{ $option->name }} {!! $option->description !!} {{ $option->tag }} - {{ $option->c_servers }} + {{ $option->servers->count() }} @endforeach From b1389262e2c333d740e889e0d96baf3651133db1 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 5 Feb 2017 18:00:39 -0500 Subject: [PATCH 206/599] Use belongsTo versus hasOne when more logical. --- app/Models/Database.php | 8 ++++---- app/Models/DatabaseServer.php | 4 ++-- app/Models/Node.php | 4 ++-- app/Models/Server.php | 16 ++++++++-------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/Models/Database.php b/app/Models/Database.php index c316d6e0a..b5e9d39ad 100644 --- a/app/Models/Database.php +++ b/app/Models/Database.php @@ -62,20 +62,20 @@ class Database extends Model /** * Gets the host database server associated with a database. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function host() { - return $this->hasOne(DatabaseServer::class, 'id', 'db_server'); + return $this->belongsTo(DatabaseServer::class, 'db_server'); } /** * Gets the server associated with a database. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function server() { - return $this->hasOne(Server::class, 'id', 'server_id'); + return $this->belongsTo(Server::class); } } diff --git a/app/Models/DatabaseServer.php b/app/Models/DatabaseServer.php index 7713f59bf..c71d1b8d7 100644 --- a/app/Models/DatabaseServer.php +++ b/app/Models/DatabaseServer.php @@ -63,10 +63,10 @@ class DatabaseServer extends Model /** * Gets the node associated with a database host. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function node() { - return $this->hasOne(Node::class, 'id', 'linked_node'); + return $this->belongsTo(Node::class, 'linked_node'); } } diff --git a/app/Models/Node.php b/app/Models/Node.php index 2be35568e..936682644 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -220,11 +220,11 @@ class Node extends Model /** * Gets the location associated with a node. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function location() { - return $this->hasOne(Location::class, 'id', 'location_id'); + return $this->belongsTo(Location::class); } /** diff --git a/app/Models/Server.php b/app/Models/Server.php index f7e8bdbed..abe512e69 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -221,11 +221,11 @@ class Server extends Model /** * Gets the user who owns the server. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function user() { - return $this->hasOne(User::class, 'id', 'owner_id'); + return $this->belongsTo(User::class, 'owner_id'); } /** @@ -251,21 +251,21 @@ class Server extends Model /** * Gets information for the service associated with this server. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function service() { - return $this->hasOne(Service::class, 'id', 'service_id'); + return $this->belongsTo(Service::class); } /** * Gets information for the service option associated with this server. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function option() { - return $this->hasOne(ServiceOptions::class, 'id', 'option_id'); + return $this->belongsTo(ServiceOptions::class); } /** @@ -281,11 +281,11 @@ class Server extends Model /** * Gets information for the node associated with this server. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function node() { - return $this->hasOne(Node::class, 'id', 'node_id'); + return $this->belongsTo(Node::class); } /** From 02458c909d3110a56004e3da5ed19afe16077f12 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 5 Feb 2017 19:19:46 -0500 Subject: [PATCH 207/599] Improves server model and cleans up model code calls. --- .../Controllers/API/User/InfoController.php | 2 +- app/Http/Controllers/Base/IndexController.php | 2 +- app/Models/Allocation.php | 11 +++++ app/Models/Server.php | 46 +++++------------ app/Models/Subuser.php | 33 ++----------- app/Models/User.php | 49 +++++++++++++++---- .../themes/pterodactyl/base/index.blade.php | 4 +- .../pterodactyl/layouts/master.blade.php | 4 +- 8 files changed, 71 insertions(+), 80 deletions(-) diff --git a/app/Http/Controllers/API/User/InfoController.php b/app/Http/Controllers/API/User/InfoController.php index 228a66819..844e493dc 100644 --- a/app/Http/Controllers/API/User/InfoController.php +++ b/app/Http/Controllers/API/User/InfoController.php @@ -32,7 +32,7 @@ class InfoController extends BaseController { public function me(Request $request) { - return Models\Server::getUserServers()->map(function ($server) { + return $request->user()->serverAccessCollection()->map(function ($server) { return [ 'id' => $server->uuidShort, 'uuid' => $server->uuid, diff --git a/app/Http/Controllers/Base/IndexController.php b/app/Http/Controllers/Base/IndexController.php index 160bc67e6..e59ceb068 100644 --- a/app/Http/Controllers/Base/IndexController.php +++ b/app/Http/Controllers/Base/IndexController.php @@ -48,7 +48,7 @@ class IndexController extends Controller public function getIndex(Request $request) { return view('base.index', [ - 'servers' => Server::getUserServers(10), + 'servers' => $request->user()->serverAccessCollection(10)->load('node', 'allocation'), ]); } diff --git a/app/Models/Allocation.php b/app/Models/Allocation.php index 34b6baec5..2df21976f 100644 --- a/app/Models/Allocation.php +++ b/app/Models/Allocation.php @@ -52,4 +52,15 @@ class Allocation extends Model 'port' => 'integer', 'server_id' => 'integer', ]; + + /** + * Accessor to automatically provide the IP alias if defined. + * + * @param null|string $value + * @return string + */ + public function getAliasAttribute($value) + { + return (is_null($this->ip_alias)) ? $this->ip : $this->ip_alias; + } } diff --git a/app/Models/Server.php b/app/Models/Server.php index abe512e69..ff63af0e5 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -103,40 +103,6 @@ class Server extends Model self::$user = Auth::user(); } - /** - * Returns array of all servers owned by the logged in user. - * Returns all users servers if user is a root admin. - * - * @return \Illuminate\Database\Eloquent\Collection - */ - public static function getUserServers($paginate = null) - { - $query = self::select( - 'servers.*', - 'nodes.name as nodeName', - 'locations.short as a_locationShort', - 'allocations.ip', - 'allocations.ip_alias', - 'allocations.port', - 'services.name as a_serviceName', - 'service_options.name as a_serviceOptionName' - )->join('nodes', 'servers.node_id', '=', 'nodes.id') - ->join('locations', 'nodes.location_id', '=', 'locations.id') - ->join('services', 'servers.service_id', '=', 'services.id') - ->join('service_options', 'servers.option_id', '=', 'service_options.id') - ->join('allocations', 'servers.allocation_id', '=', 'allocations.id'); - - if (self::$user->root_admin !== 1) { - $query->whereIn('servers.id', Subuser::accessServers()); - } - - if (is_numeric($paginate)) { - return $query->paginate($paginate); - } - - return $query->get(); - } - /** * Returns a single server specified by UUID. * DO NOT USE THIS TO MODIFY SERVER DETAILS OR SAVE THOSE DETAILS. @@ -150,7 +116,7 @@ class Server extends Model $query = self::with('service', 'node')->where('uuidShort', $uuid)->orWhere('uuid', $uuid); if (! Auth::user()->isRootAdmin()) { - $query->whereIn('id', Subuser::accessServers()); + $query->whereIn('id', Auth::user()->serverAccessArray()); } $result = $query->first(); @@ -228,6 +194,16 @@ class Server extends Model return $this->belongsTo(User::class, 'owner_id'); } + /** + * Gets the default allocation for a server. + * + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function allocation() + { + return $this->hasOne(Allocation::class, 'id', 'allocation_id'); + } + /** * Gets all allocations associated with this server. * diff --git a/app/Models/Subuser.php b/app/Models/Subuser.php index 8d4a5b133..ea855d671 100644 --- a/app/Models/Subuser.php +++ b/app/Models/Subuser.php @@ -55,33 +55,8 @@ class Subuser extends Model * * @var array */ - protected $casts = [ - 'user_id' => 'integer', - 'server_id' => 'integer', - ]; - - /** - * @var mixed - */ - protected static $user; - - /** - * Constructor. - */ - public function __construct() - { - self::$user = Auth::user(); - } - - /** - * Returns an array of each server ID that the user has access to. - * - * @return array - */ - public static function accessServers() - { - $union = self::select('server_id')->where('user_id', self::$user->id); - - return Server::select('id')->where('owner', self::$user->id)->union($union)->pluck('id'); - } + protected $casts = [ + 'user_id' => 'integer', + 'server_id' => 'integer', + ]; } diff --git a/app/Models/User.php b/app/Models/User.php index 7dba0cf0d..1714dcebf 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -87,16 +87,6 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac */ protected $hidden = ['password', 'remember_token', 'totp_secret']; - /** - * Determines if a user has permissions. - * - * @return bool - */ - public function permissions() - { - return $this->hasMany(Permission::class); - } - /** * Enables or disables TOTP on an account if the token is valid. * @@ -176,4 +166,43 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac return $subuser->daemonSecret; } + + /** + * Returns all permissions that a user has. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function permissions() + { + return $this->hasMany(Permission::class); + } + + /** + * Returns an array of all servers a user is able to access. + * Note: does not account for user admin status. + * + * @return array + */ + public function serverAccessArray() + { + $union = Subuser::select('server_id')->where('user_id', $this->id); + + return Server::select('id')->where('owner_id', $this->id)->union($union)->pluck('id')->all(); + } + + /** + * Returns an array of all servers a user is able to access. + * Note: does not account for user admin status. + * + * @return Collection + */ + public function serverAccessCollection($paginate = null) + { + $query = Server::with('service', 'node'); + if (! $this->isRootAdmin()) { + $query->whereIn('id', $this->serverAccessArray()); + } + + return (is_numeric($paginate)) ? $query->paginate($paginate) : $query->get(); + } } diff --git a/resources/themes/pterodactyl/base/index.blade.php b/resources/themes/pterodactyl/base/index.blade.php index d029a37a9..71efda93f 100644 --- a/resources/themes/pterodactyl/base/index.blade.php +++ b/resources/themes/pterodactyl/base/index.blade.php @@ -62,8 +62,8 @@ {{ $server->uuidShort }} {{ $server->name }} - {{ $server->node_idName }} - @if(!is_null($server->ip_alias)){{ $server->ip_alias }}@else{{ $server->ip }}@endif:{{ $server->port }} + {{ $server->node->name }} + {{ $server->allocation->alias }}:{{ $server->allocation->port }} -- / {{ $server->memory === 0 ? '∞' : $server->memory }} MB -- % diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index 57c7383e0..d478bd372 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -245,7 +245,7 @@
      - @if(count($databases) > 0) + @if(count($server->databases) > 0)
      @@ -426,12 +432,12 @@ - @foreach($databases as $database) + @foreach($server->databases as $database) - + @endforeach @@ -568,7 +574,7 @@ $(document).ready(function () { 'X-Access-Token': '{{ $server->daemonSecret }}', 'X-Access-Server': '{{ $server->uuid }}' }, - url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/server', + url: '{{ $server->node->scheme }}://{{ $server->node->fqdn }}:{{ $server->node->daemonListen }}/server', dataType: 'json', timeout: 5000, }).done(function (data) { diff --git a/resources/views/admin/users/view.blade.php b/resources/views/admin/users/view.blade.php index 314fc8ba7..3ba9ec035 100644 --- a/resources/views/admin/users/view.blade.php +++ b/resources/views/admin/users/view.blade.php @@ -39,7 +39,7 @@
      - +
      @@ -64,7 +64,7 @@
      {!! csrf_field() !!} - +
      @@ -72,7 +72,7 @@
      - +
      @@ -83,7 +83,7 @@
      - +
      {{ $database->database }} {{ $database->username }} ({{ $database->remote }}) {{ Crypt::decrypt($database->password) }} {{ $database->a_host }}:{{ $database->a_port }}{{ $database->host->host }}:{{ $database->host->port }}
      @@ -112,12 +112,12 @@ - @foreach($servers as $server) + @foreach($user->servers as $server) - + @@ -127,7 +127,7 @@ @else
      There are no servers associated with this account.
      @endif - +
      From c8f6c93d26445ef8bc366612c82d84514bc650b8 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 9 Feb 2017 18:44:07 -0500 Subject: [PATCH 210/599] Modify subusers model setup --- app/Models/Permission.php | 33 ++++++--- app/Models/Subuser.php | 10 +++ app/Models/User.php | 4 +- app/Policies/ServerPolicy.php | 34 ++++----- ...2_09_174834_SetupPermissionsPivotTable.php | 72 +++++++++++++++++++ 5 files changed, 124 insertions(+), 29 deletions(-) create mode 100644 database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php diff --git a/app/Models/Permission.php b/app/Models/Permission.php index 008473f3c..391f5e8d2 100644 --- a/app/Models/Permission.php +++ b/app/Models/Permission.php @@ -42,22 +42,35 @@ class Permission extends Model */ protected $guarded = ['id', 'created_at', 'updated_at']; - /** - * Cast values to correct type. - * - * @var array - */ - protected $casts = [ - 'user_id' => 'integer', - 'server_id' => 'integer', - ]; + /** + * Cast values to correct type. + * + * @var array + */ + protected $casts = [ + 'subuser_id' => 'integer', + ]; + /** + * Find permission by permission node. + * + * @param \Illuminate\Database\Query\Builder $query + * @param string $permission + * @return \Illuminate\Database\Query\Builder + */ public function scopePermission($query, $permission) { return $query->where('permission', $permission); } - public function scopeServer($query, $server) + /** + * Filter permission by server. + * + * @param \Illuminate\Database\Query\Builder $query + * @param \Pterodactyl\Models\Server $server + * @return \Illuminate\Database\Query\Builder + */ + public function scopeServer($query, Server $server) { return $query->where('server_id', $server->id); } diff --git a/app/Models/Subuser.php b/app/Models/Subuser.php index 826995d0c..6d390df95 100644 --- a/app/Models/Subuser.php +++ b/app/Models/Subuser.php @@ -79,4 +79,14 @@ class Subuser extends Model { return $this->belongsTo(User::class); } + + /** + * Gets the permissions associated with a subuser. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function permissions() + { + return $this->hasMany(Pemission::class); + } } diff --git a/app/Models/User.php b/app/Models/User.php index 6d1bfa19b..abcddf227 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -199,11 +199,11 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac /** * Returns all permissions that a user has. * - * @return \Illuminate\Database\Eloquent\Relations\HasMany + * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough */ public function permissions() { - return $this->hasMany(Permission::class); + return $this->hasManyThrough(Permission::class, Subuser::class); } /** diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php index 3ef54f436..d67f3aced 100644 --- a/app/Policies/ServerPolicy.php +++ b/app/Policies/ServerPolicy.php @@ -39,6 +39,23 @@ class ServerPolicy // } + /** + * Checks if the user has the given permission on/for the server. + * + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @param $permission + * @return bool + */ + private function checkPermission(User $user, Server $server, $permission) + { + if ($this->isOwner($user, $server)) { + return true; + } + + return $user->permissions()->server($server)->permission($permission)->exists(); + } + /** * Determine if current user is the owner of a server. * @@ -521,21 +538,4 @@ class ServerPolicy { return $this->checkPermission($user, $server, 'set-allocation'); } - - /** - * Checks if the user has the given permission on/for the server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @param $permission - * @return bool - */ - private function checkPermission(User $user, Server $server, $permission) - { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission($permission)->exists(); - } } diff --git a/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php b/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php new file mode 100644 index 000000000..fe87c4f77 --- /dev/null +++ b/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php @@ -0,0 +1,72 @@ +unsignedInteger('subuser_id')->after('id'); + }); + + DB::transaction(function () { + foreach(Subuser::all() as &$subuser) { + Permission::where('user_id', $subuser->user_id)->where('server_id', $subuser->server_id)->update([ + 'subuser_id' => $subuser->id, + ]); + } + }); + + Schema::table('permissions', function (Blueprint $table) { + $table->dropForeign('permissions_server_id_foreign'); + $table->dropIndex('permissions_server_id_foreign'); + $table->dropForeign('permissions_user_id_foreign'); + $table->dropIndex('permissions_user_id_foreign'); + + $table->dropColumn('server_id'); + $table->dropColumn('user_id'); + $table->foreign('subuser_id')->references('id')->on('subusers'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('permissions', function (Blueprint $table) { + $table->unsignedInteger('server_id')->after('subuser_id'); + $table->unsignedInteger('user_id')->after('server_id'); + }); + + DB::transaction(function () { + foreach(Subuser::all() as &$subuser) { + Permission::where('subuser_id', $subuser->id)->update([ + 'user_id' => $subuser->user_id, + 'server_id' => $subuser->server_id, + ]); + } + }); + + Schema::table('permissions', function (Blueprint $table) { + $table->dropForeign('permissions_subuser_id_foreign'); + $table->dropIndex('permissions_subuser_id_foreign'); + $table->dropColumn('subuser_id'); + + $table->foreign('server_id')->references('id')->on('servers'); + $table->foreign('user_id')->references('id')->on('users'); + }); + } +} From 99812b040731b90854598ce8c48c3a2fc0572b97 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 9 Feb 2017 19:38:54 -0500 Subject: [PATCH 211/599] More subuser Model updates. --- .../Controllers/Server/SubuserController.php | 45 +++++-------------- app/Models/Permission.php | 8 ++++ app/Models/Server.php | 10 +++++ app/Models/Subuser.php | 2 +- app/Repositories/SubuserRepository.php | 21 +++++---- ...2_09_174834_SetupPermissionsPivotTable.php | 3 ++ .../pterodactyl/server/users/index.blade.php | 16 +++---- .../pterodactyl/server/users/view.blade.php | 4 +- 8 files changed, 54 insertions(+), 55 deletions(-) diff --git a/app/Http/Controllers/Server/SubuserController.php b/app/Http/Controllers/Server/SubuserController.php index ed25d4a2c..76735e351 100644 --- a/app/Http/Controllers/Server/SubuserController.php +++ b/app/Http/Controllers/Server/SubuserController.php @@ -49,7 +49,7 @@ class SubuserController extends Controller public function getIndex(Request $request, $uuid) { - $server = Models\Server::byUuid($uuid); + $server = Models\Server::byUuid($uuid)->load('subusers.user'); $this->authorize('list-subusers', $server); $server->js(); @@ -57,35 +57,17 @@ class SubuserController extends Controller return view('server.users.index', [ 'server' => $server, 'node' => $server->node, - 'subusers' => Models\Subuser::select('subusers.*', 'users.email', 'users.username', 'users.use_totp') - ->join('users', 'users.id', '=', 'subusers.user_id') - ->where('server_id', $server->id) - ->get(), + 'subusers' => $server->subusers, ]); } public function getView(Request $request, $uuid, $id) { - $server = Models\Server::byUuid($uuid); + $server = Models\Server::byUuid($uuid)->load('node'); $this->authorize('view-subuser', $server); - $subuser = Models\Subuser::select('subusers.*', 'users.email as a_userEmail') - ->join('users', 'users.id', '=', 'subusers.user_id') - ->where(DB::raw('md5(subusers.id)'), $id)->where('subusers.server_id', $server->id) - ->first(); - - if (! $subuser) { - abort(404); - } - - $permissions = []; - $modelPermissions = Models\Permission::select('permission') - ->where('user_id', $subuser->user_id)->where('server_id', $server->id) - ->get(); - - foreach ($modelPermissions as &$perm) { - $permissions[$perm->permission] = true; - } + $subuser = Models\Subuser::with('permissions', 'user') + ->where('server_id', $server->id)->findOrFail($id); $server->js(); @@ -93,7 +75,9 @@ class SubuserController extends Controller 'server' => $server, 'node' => $server->node, 'subuser' => $subuser, - 'permissions' => $permissions, + 'permissions' => $subuser->permissions->mapWithKeys(function ($item, $key) { + return [$item->permission => true]; + }), ]); } @@ -102,12 +86,10 @@ class SubuserController extends Controller $server = Models\Server::byUuid($uuid); $this->authorize('edit-subuser', $server); - $subuser = Models\Subuser::where(DB::raw('md5(id)'), $id)->where('server_id', $server->id)->first(); + $subuser = Models\Subuser::where('server_id', $server->id)->findOrFail($id); try { - if (! $subuser) { - throw new DisplayException('Unable to locate a subuser by that ID.'); - } elseif ($subuser->user_id === Auth::user()->id) { + if ($subuser->user_id === Auth::user()->id) { throw new DisplayException('You are not authorized to edit you own account.'); } @@ -163,7 +145,7 @@ class SubuserController extends Controller return redirect()->route('server.subusers.view', [ 'uuid' => $uuid, - 'id' => md5($subuser->id), + 'id' => $subuser->id, ]); } catch (DisplayValidationException $ex) { return redirect()->route('server.subusers.new', $uuid)->withErrors(json_decode($ex->getMessage()))->withInput(); @@ -183,10 +165,7 @@ class SubuserController extends Controller $this->authorize('delete-subuser', $server); try { - $subuser = Models\Subuser::select('id')->where(DB::raw('md5(id)'), $id)->where('server_id', $server->id)->first(); - if (! $subuser) { - throw new DisplayException('No subuser by that ID was found on the system.'); - } + $subuser = Models\Subuser::where('server_id', $server->id)->findOrFail($id); $repo = new SubuserRepository; $repo->delete($subuser->id); diff --git a/app/Models/Permission.php b/app/Models/Permission.php index 391f5e8d2..fe7221719 100644 --- a/app/Models/Permission.php +++ b/app/Models/Permission.php @@ -28,6 +28,14 @@ use Illuminate\Database\Eloquent\Model; class Permission extends Model { + + /** + * Should timestamps be used on this model. + * + * @var boolean + */ + public $timestamps = false; + /** * The table associated with the model. * diff --git a/app/Models/Server.php b/app/Models/Server.php index 3ea72e2b9..1ce041ca7 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -196,6 +196,16 @@ class Server extends Model return $this->belongsTo(User::class, 'owner_id'); } + /** + * Gets the subusers associated with a server. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function subusers() + { + return $this->hasMany(Subuser::class); + } + /** * Gets the default allocation for a server. * diff --git a/app/Models/Subuser.php b/app/Models/Subuser.php index 6d390df95..25a82f615 100644 --- a/app/Models/Subuser.php +++ b/app/Models/Subuser.php @@ -87,6 +87,6 @@ class Subuser extends Model */ public function permissions() { - return $this->hasMany(Pemission::class); + return $this->hasMany(Permission::class); } } diff --git a/app/Repositories/SubuserRepository.php b/app/Repositories/SubuserRepository.php index 94a8ccecb..4e4691dda 100644 --- a/app/Repositories/SubuserRepository.php +++ b/app/Repositories/SubuserRepository.php @@ -167,8 +167,7 @@ class SubuserRepository } Models\Permission::create([ - 'user_id' => $user->id, - 'server_id' => $server->id, + 'subuser_id' => $subuser->id, 'permission' => $permission, ]); } @@ -213,14 +212,12 @@ class SubuserRepository */ public function delete($id) { - $subuser = Models\Subuser::with('server.node', 'permissions')->findOrFail($id); + $subuser = Models\Subuser::with('server.node')->findOrFail($id); $server = $subuser->server; DB::beginTransaction(); try { - Models\Permission::where('user_id', $subuser->user_id)->where('server_id', $subuser->server_id)->delete(); - $server->node->guzzleClient([ 'X-Access-Server' => $server->uuid, 'X-Access-Token' => $server->node->daemonSecret, @@ -232,6 +229,9 @@ class SubuserRepository ], ]); + foreach($subuser->permissions as &$permission) { + $permission->delete(); + } $subuser->delete(); DB::commit(); @@ -273,7 +273,9 @@ class SubuserRepository DB::beginTransaction(); try { - Models\Permission::where('user_id', $subuser->user_id)->where('server_id', $subuser->server_id)->delete(); + foreach($subuser->permissions as &$permission) { + $permission->delete(); + } $daemonPermissions = $this->coreDaemonPermissions; foreach ($data['permissions'] as $permission) { @@ -282,13 +284,10 @@ class SubuserRepository if (! is_null($this->permissions[$permission])) { array_push($daemonPermissions, $this->permissions[$permission]); } - $model = new Models\Permission; - $model->fill([ - 'user_id' => $data['user'], - 'server_id' => $data['server'], + Models\Permission::create([ + 'subuser_id' => $subuser->id, 'permission' => $permission, ]); - $model->save(); } } diff --git a/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php b/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php index fe87c4f77..ce5e3ae89 100644 --- a/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php +++ b/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php @@ -35,6 +35,8 @@ class SetupPermissionsPivotTable extends Migration $table->dropColumn('server_id'); $table->dropColumn('user_id'); + $table->dropColumn('created_at'); + $table->dropColumn('updated_at'); $table->foreign('subuser_id')->references('id')->on('subusers'); }); } @@ -49,6 +51,7 @@ class SetupPermissionsPivotTable extends Migration Schema::table('permissions', function (Blueprint $table) { $table->unsignedInteger('server_id')->after('subuser_id'); $table->unsignedInteger('user_id')->after('server_id'); + $table->timestamps(); }); DB::transaction(function () { diff --git a/resources/themes/pterodactyl/server/users/index.blade.php b/resources/themes/pterodactyl/server/users/index.blade.php index f44849758..daffcb611 100644 --- a/resources/themes/pterodactyl/server/users/index.blade.php +++ b/resources/themes/pterodactyl/server/users/index.blade.php @@ -51,29 +51,29 @@ @can('view-subuser', $server)
      @endcan @can('delete-subuser', $server)@endcan - @foreach($subusers as $user) + @foreach($subusers as $subuser) - - + + - + @can('view-subuser', $server) @endcan @can('delete-subuser', $server) diff --git a/resources/themes/pterodactyl/server/users/view.blade.php b/resources/themes/pterodactyl/server/users/view.blade.php index b697edc34..925fbdf05 100644 --- a/resources/themes/pterodactyl/server/users/view.blade.php +++ b/resources/themes/pterodactyl/server/users/view.blade.php @@ -35,7 +35,7 @@ @section('content') @can('edit-subuser', $server) - + @endcan
      @@ -45,7 +45,7 @@
      {!! csrf_field() !!} - +
      From 0720bfe62f4fad89158b00f0fecab3111b92e365 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 10 Feb 2017 17:03:58 -0500 Subject: [PATCH 212/599] Cleanup database query code. --- app/Http/Controllers/Admin/DatabaseController.php | 5 +---- resources/views/admin/databases/index.blade.php | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/Admin/DatabaseController.php b/app/Http/Controllers/Admin/DatabaseController.php index 6cfa73041..1b7dcb5a2 100644 --- a/app/Http/Controllers/Admin/DatabaseController.php +++ b/app/Http/Controllers/Admin/DatabaseController.php @@ -48,10 +48,7 @@ class DatabaseController extends Controller { return view('admin.databases.index', [ 'databases' => Models\Database::with('server')->paginate(50), - 'hosts' => Models\DatabaseServer::select( - 'database_servers.*', - DB::raw('(SELECT COUNT(*) FROM `databases` WHERE `databases`.`db_server` = database_servers.id) as c_databases') - )->with('node')->paginate(20), + 'hosts' => Models\DatabaseServer::withCount('databases')->with('node')->paginate(20), ]); } diff --git a/resources/views/admin/databases/index.blade.php b/resources/views/admin/databases/index.blade.php index bb7be1e3f..f1c2a4aac 100644 --- a/resources/views/admin/databases/index.blade.php +++ b/resources/views/admin/databases/index.blade.php @@ -92,7 +92,7 @@ - + From ba175e6b55348e0bf9b5bc81d979e6f247aa9019 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 10 Feb 2017 17:09:56 -0500 Subject: [PATCH 213/599] Cleanup location model and controller for Admin. --- .../Controllers/Admin/LocationsController.php | 24 ++++--------------- app/Models/Location.php | 20 ++++++++++++++++ .../views/admin/locations/index.blade.php | 4 ++-- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/app/Http/Controllers/Admin/LocationsController.php b/app/Http/Controllers/Admin/LocationsController.php index d74f05d18..4f6343e5f 100644 --- a/app/Http/Controllers/Admin/LocationsController.php +++ b/app/Http/Controllers/Admin/LocationsController.php @@ -43,35 +43,21 @@ class LocationsController extends Controller public function getIndex(Request $request) { return view('admin.locations.index', [ - 'locations' => Models\Location::select( - 'locations.*', - DB::raw('(SELECT COUNT(*) FROM nodes WHERE nodes.location_id = locations.id) as a_nodeCount'), - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id IN (SELECT nodes.id FROM nodes WHERE nodes.location_id = locations.id)) as a_serverCount') - )->paginate(20), + 'locations' => Models\Location::withCount('nodes', 'servers')->paginate(20), ]); } public function deleteLocation(Request $request, $id) { - $model = Models\Location::select( - 'locations.id', - DB::raw('(SELECT COUNT(*) FROM nodes WHERE nodes.location_id = locations.id) as a_nodeCount'), - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id IN (SELECT nodes.id FROM nodes WHERE nodes.location_id = locations.id)) as a_serverCount') - )->where('id', $id)->first(); + $location = Models\Location::withCount('nodes')->findOrFail($id); - if (! $model) { + if ($location->nodes_count > 0) { return response()->json([ - 'error' => 'No location with that ID exists on the system.', - ], 404); - } - - if ($model->a_nodeCount > 0 || $model->a_serverCount > 0) { - return response()->json([ - 'error' => 'You cannot remove a location that is currently assigned to a node or server.', + 'error' => 'You cannot remove a location that is currently assigned to a node.', ], 422); } - $model->delete(); + $location->delete(); return response('', 204); } diff --git a/app/Models/Location.php b/app/Models/Location.php index 5c8feb9fa..f9ceec767 100644 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -41,4 +41,24 @@ class Location extends Model * @var array */ protected $guarded = ['id', 'created_at', 'updated_at']; + + /** + * Gets the nodes in a specificed location. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function nodes() + { + return $this->hasMany(Node::class); + } + + /** + * Gets the servers within a given location. + * + * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough + */ + public function servers() + { + return $this->hasManyThrough(Server::class, Node::class); + } } diff --git a/resources/views/admin/locations/index.blade.php b/resources/views/admin/locations/index.blade.php index 9aaf49faa..2fbd4b05a 100644 --- a/resources/views/admin/locations/index.blade.php +++ b/resources/views/admin/locations/index.blade.php @@ -46,8 +46,8 @@ - - + + From efef3568706e77f71214c5ec4160c0e4d00ba6b4 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 10 Feb 2017 17:18:46 -0500 Subject: [PATCH 214/599] Assorted model code updates. --- .../Controllers/Admin/NodesController.php | 26 ++++-------- app/Http/Controllers/Admin/PackController.php | 16 ++----- .../Controllers/Admin/ServersController.php | 14 ++----- .../Controllers/Admin/ServiceController.php | 42 +++++-------------- app/Http/Controllers/Admin/UserController.php | 16 ++----- 5 files changed, 31 insertions(+), 83 deletions(-) diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index 9cfac1fde..fc32f3929 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -112,10 +112,8 @@ class NodesController extends Controller public function getView(Request $request, $id) { $node = Models\Node::with( - 'servers.user', - 'servers.service', - 'servers.allocations', - 'location' + 'servers.user', 'servers.service', + 'servers.allocations', 'location' )->findOrFail($id); $node->setRelation('allocations', $node->allocations()->paginate(40)); @@ -131,20 +129,12 @@ class NodesController extends Controller try { $node = new NodeRepository; $node->update($id, $request->only([ - 'name', - 'location', - 'public', - 'fqdn', - 'scheme', - 'memory', - 'memory_overallocate', - 'disk', - 'disk_overallocate', - 'upload_size', - 'daemonBase', - 'daemonSFTP', - 'daemonListen', - 'reset_secret', + 'name', 'location', 'public', + 'fqdn', 'scheme', 'memory', + 'memory_overallocate', 'disk', + 'disk_overallocate', 'upload_size', + 'daemonBase', 'daemonSFTP', + 'daemonListen', 'reset_secret', ])); Alert::success('Successfully update this node\'s information. If you changed any daemon settings you will need to restart it now.')->flash(); diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php index 3e6685f28..c86e2ada4 100644 --- a/app/Http/Controllers/Admin/PackController.php +++ b/app/Http/Controllers/Admin/PackController.php @@ -73,12 +73,8 @@ class PackController extends Controller try { $repo = new Pack; $pack = $repo->create($request->only([ - 'name', - 'version', - 'description', - 'option', - 'selectable', - 'visible', + 'name', 'version', 'description', + 'option', 'selectable', 'visible', 'file_upload', ])); Alert::success('Successfully created new service!')->flash(); @@ -128,12 +124,8 @@ class PackController extends Controller try { $repo = new Pack; $repo->update($id, $request->only([ - 'name', - 'version', - 'description', - 'option', - 'selectable', - 'visible', + 'name', 'version', 'description', + 'option', 'selectable', 'visible', ])); Alert::success('Service pack has been successfully updated.')->flash(); } catch (DisplayValidationException $ex) { diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index d287e7819..b68f8d01c 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -279,13 +279,9 @@ class ServersController extends Controller try { $server = new ServerRepository; $server->changeBuild($id, $request->only([ - 'default', - 'add_additional', - 'remove_additional', - 'memory', - 'swap', - 'io', - 'cpu', + 'default', 'add_additional', + 'remove_additional', 'memory', + 'swap', 'io', 'cpu', ])); Alert::success('Server details were successfully updated.')->flash(); } catch (DisplayValidationException $ex) { @@ -377,9 +373,7 @@ class ServersController extends Controller try { $repo = new DatabaseRepository; $repo->create($id, $request->only([ - 'db_server', - 'database', - 'remote', + 'db_server', 'database', 'remote', ])); Alert::success('Added new database to this server.')->flash(); } catch (DisplayValidationException $ex) { diff --git a/app/Http/Controllers/Admin/ServiceController.php b/app/Http/Controllers/Admin/ServiceController.php index f8951993a..5aad76fd3 100644 --- a/app/Http/Controllers/Admin/ServiceController.php +++ b/app/Http/Controllers/Admin/ServiceController.php @@ -59,11 +59,8 @@ class ServiceController extends Controller try { $repo = new ServiceRepository\Service; $service = $repo->create($request->only([ - 'name', - 'description', - 'file', - 'executable', - 'startup', + 'name', 'description', 'file', + 'executable', 'startup', ])); Alert::success('Successfully created new service!')->flash(); @@ -92,11 +89,8 @@ class ServiceController extends Controller try { $repo = new ServiceRepository\Service; $repo->update($service, $request->only([ - 'name', - 'description', - 'file', - 'executable', - 'startup', + 'name', 'description', 'file', + 'executable', 'startup', ])); Alert::success('Successfully updated this service.')->flash(); } catch (DisplayValidationException $ex) { @@ -134,9 +128,7 @@ class ServiceController extends Controller $option = Models\ServiceOptions::with('service', 'variables')->findOrFail($option); $option->setRelation('servers', $option->servers()->with('user')->paginate(25)); - return view('admin.services.options.view', [ - 'option' => $option, - ]); + return view('admin.services.options.view', ['option' => $option]); } public function postOption(Request $request, $service, $option) @@ -144,12 +136,8 @@ class ServiceController extends Controller try { $repo = new ServiceRepository\Option; $repo->update($option, $request->only([ - 'name', - 'description', - 'tag', - 'executable', - 'docker_image', - 'startup', + 'name', 'description', 'tag', + 'executable', 'docker_image', 'startup', ])); Alert::success('Option settings successfully updated.')->flash(); } catch (DisplayValidationException $ex) { @@ -227,14 +215,9 @@ class ServiceController extends Controller try { $repo = new ServiceRepository\Variable; $repo->create($option, $request->only([ - 'name', - 'description', - 'env_variable', - 'default_value', - 'user_viewable', - 'user_editable', - 'required', - 'regex', + 'name', 'description', 'env_variable', + 'default_value', 'user_viewable', + 'user_editable', 'required', 'regex', ])); Alert::success('Successfully added new variable to this option.')->flash(); @@ -311,10 +294,7 @@ class ServiceController extends Controller { try { $repo = new ServiceRepository\Service; - $repo->updateFile($serviceId, $request->only([ - 'file', - 'contents', - ])); + $repo->updateFile($serviceId, $request->only(['file', 'contents'])); return response('', 204); } catch (DisplayException $ex) { diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index eef57a895..5ebce1b42 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -88,12 +88,8 @@ class UserController extends Controller try { $user = new UserRepository; $userid = $user->create($request->only([ - 'email', - 'password', - 'name_first', - 'name_last', - 'username', - 'root_admin', + 'email', 'password', 'name_first', + 'name_last', 'username', 'root_admin', ])); Alert::success('Account has been successfully created.')->flash(); @@ -113,12 +109,8 @@ class UserController extends Controller try { $repo = new UserRepository; $repo->update($user, $request->only([ - 'email', - 'password', - 'name_first', - 'name_last', - 'username', - 'root_admin', + 'email', 'password', 'name_first', + 'name_last', 'username', 'root_admin', ])); Alert::success('User account was successfully updated.')->flash(); } catch (DisplayValidationException $ex) { From 3b3002b77a73375aee5f230d25e401632aeb2e46 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 10 Feb 2017 17:29:10 -0500 Subject: [PATCH 215/599] API Model updates. --- app/Http/Controllers/Base/APIController.php | 14 +++---- app/Models/APIKey.php | 10 +++++ app/Repositories/APIRepository.php | 4 +- ...7_02_10_171858_UpdateAPIKeyColumnNames.php | 38 +++++++++++++++++++ 4 files changed, 56 insertions(+), 10 deletions(-) create mode 100644 database/migrations/2017_02_10_171858_UpdateAPIKeyColumnNames.php diff --git a/app/Http/Controllers/Base/APIController.php b/app/Http/Controllers/Base/APIController.php index 611638c95..2130ee760 100644 --- a/app/Http/Controllers/Base/APIController.php +++ b/app/Http/Controllers/Base/APIController.php @@ -38,13 +38,8 @@ class APIController extends Controller { public function index(Request $request) { - $keys = Models\APIKey::where('user', $request->user()->id)->get(); - foreach ($keys as &$key) { - $key->permissions = Models\APIPermission::where('key_id', $key->id)->get(); - } - return view('base.api.index', [ - 'keys' => $keys, + 'keys' => Models\APIKey::where('user_id', $request->user()->id)->get(), ]); } @@ -57,8 +52,11 @@ class APIController extends Controller { try { $repo = new APIRepository($request->user()); - $secret = $repo->create($request->except(['_token'])); - Alert::success('An API Keypair has successfully been generated. The API secret for this public key is shown below and will not be shown again.

      ' . $secret . '')->flash(); + $secret = $repo->create($request->only([ + 'memo', 'allowed_ips', + 'adminPermissions', 'permissions', + ])); + Alert::success('An API Key-Pair has successfully been generated. The API secret for this public key is shown below and will not be shown again.

      ' . $secret . '')->flash(); return redirect()->route('account.api'); } catch (DisplayValidationException $ex) { diff --git a/app/Models/APIKey.php b/app/Models/APIKey.php index 4b94b6782..68e481712 100644 --- a/app/Models/APIKey.php +++ b/app/Models/APIKey.php @@ -48,4 +48,14 @@ class APIKey extends Model * @var array */ protected $guarded = ['id', 'created_at', 'updated_at']; + + /** + * Gets the permissions associated with a key. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function permissions() + { + return $this->hasMany(APIPermission::class, 'key_id'); + } } diff --git a/app/Repositories/APIRepository.php b/app/Repositories/APIRepository.php index 7ce94f34b..382e6a274 100644 --- a/app/Repositories/APIRepository.php +++ b/app/Repositories/APIRepository.php @@ -102,7 +102,7 @@ class APIRepository { $this->user = is_null($user) ? Auth::user() : $user; if (is_null($this->user)) { - throw new \Exception('Cannot access API Repository without passing a user to __construct().'); + throw new \Exception('Cannot access API Repository without passing a user to constructor.'); } } @@ -178,7 +178,7 @@ class APIRepository } } - if ($this->user->root_admin === 1 && isset($data['adminPermissions'])) { + if ($this->user->isRootAdmin() && isset($data['adminPermissions'])) { foreach ($data['adminPermissions'] as $permNode) { if (! strpos($permNode, ':')) { continue; diff --git a/database/migrations/2017_02_10_171858_UpdateAPIKeyColumnNames.php b/database/migrations/2017_02_10_171858_UpdateAPIKeyColumnNames.php new file mode 100644 index 000000000..358f9938d --- /dev/null +++ b/database/migrations/2017_02_10_171858_UpdateAPIKeyColumnNames.php @@ -0,0 +1,38 @@ +dropForeign('api_keys_user_foreign')->dropIndex('api_keys_user_foreign'); + + $table->renameColumn('user', 'user_id'); + $table->foreign('user_id')->references('id')->on('users'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('api_keys', function (Blueprint $table) { + $table->dropForeign('api_keys_user_id_foreign')->dropIndex('api_keys_user_id_foreign'); + + $table->renameColumn('user_id', 'user'); + $table->foreign('user')->references('id')->on('users'); + }); + } +} From c70d31c08f1f2d6c0bb95d7db790c8b064c6f0d1 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 10 Feb 2017 17:36:58 -0500 Subject: [PATCH 216/599] More model updates. --- .../Controllers/Base/SecurityController.php | 3 +-- .../Controllers/Remote/RemoteController.php | 17 ++++++----------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/app/Http/Controllers/Base/SecurityController.php b/app/Http/Controllers/Base/SecurityController.php index cf8bf2dc1..23b6f0d68 100644 --- a/app/Http/Controllers/Base/SecurityController.php +++ b/app/Http/Controllers/Base/SecurityController.php @@ -118,8 +118,7 @@ class SecurityController extends Controller public function revoke(Request $request, $id) { - $session = Session::where('id', $id)->where('user_id', $request->user()->id)->firstOrFail(); - $session->delete(); + Session::where('user_id', $request->user()->id)->findOrFail($id)->delete(); return redirect()->route('account.security'); } diff --git a/app/Http/Controllers/Remote/RemoteController.php b/app/Http/Controllers/Remote/RemoteController.php index 0f168c04b..95ff6ab3e 100644 --- a/app/Http/Controllers/Remote/RemoteController.php +++ b/app/Http/Controllers/Remote/RemoteController.php @@ -28,7 +28,6 @@ use Carbon\Carbon; use Pterodactyl\Models; use Illuminate\Http\Request; use Pterodactyl\Http\Controllers\Controller; -use Pterodactyl\Services\NotificationService; class RemoteController extends Controller { @@ -42,7 +41,7 @@ class RemoteController extends Controller public function postDownload(Request $request) { - $download = Models\Download::where('token', $request->input('token', '00'))->first(); + $download = Models\Download::where('token', $request->input('token'))->first(); if (! $download) { return response()->json([ 'error' => 'An invalid request token was recieved with this request.', @@ -59,18 +58,17 @@ class RemoteController extends Controller public function postInstall(Request $request) { - $server = Models\Server::where('uuid', $request->input('server'))->first(); + $server = Models\Server::where('uuid', $request->input('server'))->with('node')->first(); if (! $server) { return response()->json([ 'error' => 'No server by that ID was found on the system.', ], 422); } - $node = Models\Node::findOrFail($server->node_id); $hmac = $request->input('signed'); $status = $request->input('installed'); - if (base64_decode($hmac) !== hash_hmac('sha256', $server->uuid, $node->daemonSecret, true)) { + if (base64_decode($hmac) !== hash_hmac('sha256', $server->uuid, $server->node->daemonSecret, true)) { return response()->json([ 'error' => 'Signed HMAC was invalid.', ], 403); @@ -86,17 +84,15 @@ class RemoteController extends Controller public function event(Request $request) { - $server = Models\Server::where('uuid', $request->input('server'))->first(); + $server = Models\Server::where('uuid', $request->input('server'))->with('node')->first(); if (! $server) { return response()->json([ 'error' => 'No server by that ID was found on the system.', ], 422); } - $node = Models\Node::findOrFail($server->node_id); - $hmac = $request->input('signed'); - if (base64_decode($hmac) !== hash_hmac('sha256', $server->uuid, $node->daemonSecret, true)) { + if (base64_decode($hmac) !== hash_hmac('sha256', $server->uuid, $server->node->daemonSecret, true)) { return response()->json([ 'error' => 'Signed HMAC was invalid.', ], 403); @@ -130,7 +126,6 @@ class RemoteController extends Controller $token->delete(); // Manually as getConfigurationAsJson() returns it in correct format already - return response($node->getConfigurationAsJson(), 200) - ->header('Content-Type', 'application/json'); + return response()->json($node->getConfigurationAsJson(), 200); } } From 8dc1f41b73c7211b39e1dd8bbeacee01f1700641 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 10 Feb 2017 17:41:56 -0500 Subject: [PATCH 217/599] More code cleanup. --- app/Repositories/APIRepository.php | 2 +- app/Services/NotificationService.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/Repositories/APIRepository.php b/app/Repositories/APIRepository.php index 382e6a274..14348b2db 100644 --- a/app/Repositories/APIRepository.php +++ b/app/Repositories/APIRepository.php @@ -149,7 +149,7 @@ class APIRepository $secretKey = str_random(16) . '.' . str_random(7) . '.' . str_random(7); $key = new Models\APIKey; $key->fill([ - 'user' => $this->user->id, + 'user_id' => $this->user->id, 'public' => str_random(16), 'secret' => Crypt::encrypt($secretKey), 'allowed_ips' => empty($this->allowed) ? null : json_encode($this->allowed), diff --git a/app/Services/NotificationService.php b/app/Services/NotificationService.php index abd2155b1..53a6e0ff9 100644 --- a/app/Services/NotificationService.php +++ b/app/Services/NotificationService.php @@ -48,7 +48,6 @@ class NotificationService public function __construct(Server $server) { $this->server = $server; - $this->user = User::findOrFail($server->owner_id); } public function pass(array $notification) From 32a1dc17eddd8e1d69180607cbdad8ceb2670c62 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 10 Feb 2017 20:26:38 -0500 Subject: [PATCH 218/599] API model updates, as well as general model updates and code fixes. --- .../Controllers/API/LocationController.php | 13 +- app/Http/Controllers/API/NodeController.php | 118 +++++------------- app/Http/Controllers/API/ServerController.php | 81 +++++------- .../Controllers/API/ServiceController.php | 11 +- .../Controllers/API/User/InfoController.php | 15 +-- .../Controllers/API/User/ServerController.php | 21 ++-- app/Http/Controllers/API/UserController.php | 44 +++---- .../Controllers/Admin/ServersController.php | 13 +- app/Http/Middleware/APISecretToken.php | 2 +- app/Models/Node.php | 28 +---- app/Repositories/APIRepository.php | 2 +- app/Repositories/NodeRepository.php | 14 +-- app/Repositories/ServerRepository.php | 48 +++---- resources/views/admin/nodes/new.blade.php | 4 +- resources/views/admin/nodes/view.blade.php | 4 +- resources/views/admin/servers/new.blade.php | 16 +-- 16 files changed, 162 insertions(+), 272 deletions(-) diff --git a/app/Http/Controllers/API/LocationController.php b/app/Http/Controllers/API/LocationController.php index 3bae975d8..94ec5fe7d 100755 --- a/app/Http/Controllers/API/LocationController.php +++ b/app/Http/Controllers/API/LocationController.php @@ -49,11 +49,12 @@ class LocationController extends BaseController */ public function lists(Request $request) { - return Location::select('locations.*', DB::raw('GROUP_CONCAT(nodes.id) as nodes')) - ->join('nodes', 'locations.id', '=', 'nodes.location') - ->groupBy('locations.id') - ->get()->each(function ($location) { - $location->nodes = explode(',', $location->nodes); - })->all(); + return Location::with('nodes')->get()->map(function ($item) { + $item->nodes->transform(function ($item) { + return collect($item)->only(['id', 'name', 'fqdn', 'scheme', 'daemonListen', 'daemonSFTP']); + }); + + return $item; + })->toArray(); } } diff --git a/app/Http/Controllers/API/NodeController.php b/app/Http/Controllers/API/NodeController.php index 0eda949f4..fd87770f7 100755 --- a/app/Http/Controllers/API/NodeController.php +++ b/app/Http/Controllers/API/NodeController.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Http\Controllers\API; +use Log; use Pterodactyl\Models; use Illuminate\Http\Request; use Dingo\Api\Exception\ResourceException; @@ -96,15 +97,21 @@ class NodeController extends BaseController public function create(Request $request) { try { - $node = new NodeRepository; - $new = $node->create($request->all()); + $repo = new NodeRepository; + $node = $repo->create($request->only([ + 'name', 'location_id', 'public', 'fqdn', + 'scheme', 'memory', 'memory_overallocate', + 'disk', 'disk_overallocate', 'daemonBase', + 'daemonSFTP', 'daemonListen', + ])); - return ['id' => $new]; + return ['id' => $repo->id]; } catch (DisplayValidationException $ex) { throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); } catch (DisplayException $ex) { throw new ResourceException($ex->getMessage()); - } catch (\Exception $e) { + } catch (\Exception $ex) { + Log::error($ex); throw new BadRequestHttpException('There was an error while attempting to add this node to the system.'); } } @@ -124,88 +131,35 @@ class NodeController extends BaseController */ public function view(Request $request, $id, $fields = null) { - $node = Models\Node::where('id', $id); + $node = Models\Node::with('allocations')->where('id', $id)->first(); + if (! $node) { + throw new NotFoundHttpException('No node by that ID was found.'); + } + + $node->allocations->transform(function ($item) { + return collect($item)->only([ + 'id', 'ip', 'ip_alias', 'port', 'server_id' + ]); + }); if (! is_null($request->input('fields'))) { - foreach (explode(',', $request->input('fields')) as $field) { - if (! empty($field)) { - $node->addSelect($field); - } + $fields = explode(',', $request->input('fields')); + if (! empty($fields) && is_array($fields)) { + return collect($node)->only($fields); } } - try { - if (! $node->first()) { - throw new NotFoundHttpException('No node by that ID was found.'); - } - - return [ - 'node' => $node->first(), - 'allocations' => [ - 'assigned' => Models\Allocation::where('node', $id)->whereNotNull('assigned_to')->get(), - 'unassigned' => Models\Allocation::where('node', $id)->whereNull('assigned_to')->get(), - ], - ]; - } catch (NotFoundHttpException $ex) { - throw $ex; - } catch (\Exception $ex) { - throw new BadRequestHttpException('There was an issue with the fields passed in the request.'); - } + return $node; } public function config(Request $request, $id) { - if (! $request->secure()) { - throw new BadRequestHttpException('This API route can only be accessed using a secure connection.'); - } - $node = Models\Node::where('id', $id)->first(); if (! $node) { throw new NotFoundHttpException('No node by that ID was found.'); } - return [ - 'web' => [ - 'listen' => $node->daemonListen, - 'host' => '0.0.0.0', - 'ssl' => [ - 'enabled' => ($node->scheme === 'https'), - 'certificate' => '/etc/certs/' . $node->fqdn . '/fullchain.pem', - 'key' => '/etc/certs/' . $node->fqdn . '/privkey.pem', - ], - ], - 'docker' => [ - 'socket' => '/var/run/docker.sock', - 'autoupdate_images' => true, - ], - 'sftp' => [ - 'path' => $node->daemonBase, - 'port' => (int) $node->daemonSFTP, - 'container' => 'ptdl-sftp', - ], - 'query' => [ - 'kill_on_fail' => true, - 'fail_limit' => 5, - ], - 'logger' => [ - 'path' => 'logs/', - 'src' => false, - 'level' => 'info', - 'period' => '1d', - 'count' => 3, - ], - 'remote' => [ - 'base' => config('app.url'), - 'download' => route('remote.download'), - 'installed' => route('remote.install'), - ], - 'uploads' => [ - 'size_limit' => $node->upload_size, - ], - 'keys' => [ - $node->daemonSecret, - ], - ]; + return $node->getConfigurationAsJson(); } /** @@ -219,12 +173,7 @@ class NodeController extends BaseController */ public function allocations(Request $request) { - $allocations = Models\Allocation::all(); - if ($allocations->count() < 1) { - throw new NotFoundHttpException('No allocations have been created.'); - } - - return $allocations; + return Models\Allocation::all()->toArray(); } /** @@ -238,18 +187,7 @@ class NodeController extends BaseController */ public function allocationsView(Request $request, $id) { - $query = Models\Allocation::where('assigned_to', $id)->get(); - try { - if (empty($query)) { - throw new NotFoundHttpException('No allocations for that server were found.'); - } - - return $query; - } catch (NotFoundHttpException $ex) { - throw $ex; - } catch (\Exception $ex) { - throw new BadRequestHttpException('There was an issue with the fields passed in the request.'); - } + return Models\Allocation::where('assigned_to', $id)->get()->toArray(); } /** diff --git a/app/Http/Controllers/API/ServerController.php b/app/Http/Controllers/API/ServerController.php index 24a2bc00e..e6b2add2c 100755 --- a/app/Http/Controllers/API/ServerController.php +++ b/app/Http/Controllers/API/ServerController.php @@ -72,10 +72,10 @@ class ServerController extends BaseController public function create(Request $request) { try { - $server = new ServerRepository; - $new = $server->create($request->all()); + $repo = new ServerRepository; + $server = $repo->create($request->all()); - return ['id' => $new]; + return ['id' => $server->id]; } catch (DisplayValidationException $ex) { throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); } catch (DisplayException $ex) { @@ -101,58 +101,38 @@ class ServerController extends BaseController */ public function view(Request $request, $id) { - $query = Models\Server::where('id', $id); + $server = Models\Server::with('node', 'allocations', 'pack')->where('id', $id)->first(); + if (! $server) { + throw new NotFoundHttpException('No server by that ID was found.'); + } if (! is_null($request->input('fields'))) { - foreach (explode(',', $request->input('fields')) as $field) { - if (! empty($field)) { - $query->addSelect($field); - } + $fields = explode(',', $request->input('fields')); + if (! empty($fields) && is_array($fields)) { + return collect($server)->only($fields); } } - try { - if (! $query->first()) { - throw new NotFoundHttpException('No server by that ID was found.'); - } + if ($request->input('daemon') === 'true') { + try { + $response = $server->node->guzzleClient([ + 'X-Access-Token' => $server->node->daemonSecret, + ])->request('GET', '/servers'); - // Requested Daemon Stats - $server = $query->with( - 'allocations', - 'pack' - )->first(); - if ($request->input('daemon') === 'true') { - $node = Models\Node::findOrFail($server->node_id); - $client = Models\Node::guzzleRequest($node->id); - - $response = $client->request('GET', '/servers', [ - 'headers' => [ - 'X-Access-Token' => $node->daemonSecret, - ], - ]); - - // Only return the daemon token if the request is using HTTPS - if ($request->secure()) { - $server->daemon_token = $server->daemonSecret; - } $server->daemon = json_decode($response->getBody())->{$server->uuid}; - - return $server->toArray(); + } catch (\GuzzleHttp\Exception\TransferException $ex) { + // Couldn't hit the daemon, return what we have though. + $server->daemon = [ + 'error' => 'There was an error encountered while attempting to connect to the remote daemon.', + ]; } - - return $server->toArray(); - } catch (NotFoundHttpException $ex) { - throw $ex; - } catch (\GuzzleHttp\Exception\TransferException $ex) { - // Couldn't hit the daemon, return what we have though. - $server->daemon = [ - 'error' => 'There was an error encountered while attempting to connect to the remote daemon.', - ]; - - return $server->toArray(); - } catch (\Exception $ex) { - throw new BadRequestHttpException('There was an issue with the fields passed in the request.'); } + + $server->allocations->transform(function ($item) { + return collect($item)->except(['created_at', 'updated_at']); + }); + + return $server->toArray(); } /** @@ -179,7 +159,9 @@ class ServerController extends BaseController { try { $server = new ServerRepository; - $server->updateDetails($id, $request->all()); + $server->updateDetails($id, $request->only([ + 'owner', 'name', 'reset_token', + ])); return Models\Server::findOrFail($id); } catch (DisplayValidationException $ex) { @@ -224,7 +206,10 @@ class ServerController extends BaseController { try { $server = new ServerRepository; - $server->changeBuild($id, $request->all()); + $server->changeBuild($id, $request->only([ + 'default', 'add_additional', 'remove_additional', + 'memory', 'swap', 'io', 'cpu', 'disk', + ])); return Models\Server::findOrFail($id); } catch (DisplayValidationException $ex) { diff --git a/app/Http/Controllers/API/ServiceController.php b/app/Http/Controllers/API/ServiceController.php index 81d5a955d..b1c600e27 100755 --- a/app/Http/Controllers/API/ServiceController.php +++ b/app/Http/Controllers/API/ServiceController.php @@ -45,18 +45,11 @@ class ServiceController extends BaseController public function view(Request $request, $id) { - $service = Models\Service::find($id); + $service = Models\Service::with('options.variables', 'options.packs')->find($id); if (! $service) { throw new NotFoundHttpException('No service by that ID was found.'); } - return [ - 'service' => $service, - 'options' => Models\ServiceOptions::select('id', 'name', 'description', 'tag', 'docker_image') - ->where('service_id', $service->id) - ->with('variables') - ->with('packs') - ->get(), - ]; + return $service->toArray(); } } diff --git a/app/Http/Controllers/API/User/InfoController.php b/app/Http/Controllers/API/User/InfoController.php index 844e493dc..6ef84ce50 100644 --- a/app/Http/Controllers/API/User/InfoController.php +++ b/app/Http/Controllers/API/User/InfoController.php @@ -32,19 +32,16 @@ class InfoController extends BaseController { public function me(Request $request) { - return $request->user()->serverAccessCollection()->map(function ($server) { + return $request->user()->serverAccessCollection()->load('allocation', 'option')->map(function ($server) { return [ 'id' => $server->uuidShort, 'uuid' => $server->uuid, 'name' => $server->name, - 'node' => $server->node_idName, - 'ip' => [ - 'set' => $server->ip, - 'alias' => $server->ip_alias, - ], - 'port' => $server->port, - 'service' => $server->a_serviceName, - 'option' => $server->a_serviceOptionName, + 'node' => $server->node->name, + 'ip' => $server->allocation->alias, + 'port' => $server->allocation->port, + 'service' => $server->service->name, + 'option' => $server->option->name, ]; })->all(); } diff --git a/app/Http/Controllers/API/User/ServerController.php b/app/Http/Controllers/API/User/ServerController.php index c6091f0b1..465c7a345 100644 --- a/app/Http/Controllers/API/User/ServerController.php +++ b/app/Http/Controllers/API/User/ServerController.php @@ -25,7 +25,6 @@ namespace Pterodactyl\Http\Controllers\API\User; use Log; -use Auth; use Pterodactyl\Models; use Illuminate\Http\Request; use Pterodactyl\Http\Controllers\API\BaseController; @@ -43,20 +42,14 @@ class ServerController extends BaseController $daemon = [ 'status' => $json->status, 'stats' => $json->proc, - 'query' => $json->query, ]; } catch (\Exception $ex) { $daemon = [ - 'error' => 'An error was encountered while trying to connect to the daemon to collece information. It might be offline.', + 'error' => 'An error was encountered while trying to connect to the daemon to collect information. It might be offline.', ]; Log::error($ex); } - foreach ($server->allocations as &$allocation) { - $allocation->default = ($allocation->id === $server->allocation_id); - unset($allocation->id); - } - return [ 'uuidShort' => $server->uuidShort, 'uuid' => $server->uuid, @@ -70,12 +63,18 @@ class ServerController extends BaseController 'cpu' => $server->cpu, 'oom_disabled' => (bool) $server->oom_disabled, ], - 'allocations' => $server->allocations, + 'allocations' => $server->allocations->map(function ($item) use ($server) { + return [ + 'ip' => $item->alias, + 'port' => $item->port, + 'default' => ($item->id === $server->allocation_id), + ]; + }), 'sftp' => [ - 'username' => (Auth::user()->can('view-sftp', $server)) ? $server->username : null, + 'username' => ($request->user()->can('view-sftp', $server)) ? $server->username : null, ], 'daemon' => [ - 'token' => ($request->secure()) ? $server->daemonSecret : false, + 'token' => $server->daemonSecret, 'response' => $daemon, ], ]; diff --git a/app/Http/Controllers/API/UserController.php b/app/Http/Controllers/API/UserController.php index a330ef61c..14c212f77 100755 --- a/app/Http/Controllers/API/UserController.php +++ b/app/Http/Controllers/API/UserController.php @@ -75,31 +75,27 @@ class UserController extends BaseController */ public function view(Request $request, $id) { - $query = Models\User::where((is_numeric($id) ? 'id' : 'email'), $id); + $user = Models\User::with('servers')->where((is_numeric($id) ? 'id' : 'email'), $id)->first(); + if (! $user->first()) { + throw new NotFoundHttpException('No user by that ID was found.'); + } + + $user->servers->transform(function ($item) { + return collect($item)->only([ + 'id', 'node_id', 'uuidShort', + 'uuid', 'name', 'suspended', + 'owner_id', + ]); + }); if (! is_null($request->input('fields'))) { - foreach (explode(',', $request->input('fields')) as $field) { - if (! empty($field)) { - $query->addSelect($field); - } + $fields = explode(',', $request->input('fields')); + if (! empty($fields) && is_array($fields)) { + return collect($user)->only($fields); } } - try { - if (! $query->first()) { - throw new NotFoundHttpException('No user by that ID was found.'); - } - - $user = $query->first(); - $userArray = $user->toArray(); - $userArray['servers'] = Models\Server::select('id', 'uuid', 'node', 'suspended')->where('owner', $user->id)->get(); - - return $userArray; - } catch (NotFoundHttpException $ex) { - throw $ex; - } catch (\Exception $ex) { - throw new BadRequestHttpException('There was an issue with the fields passed in the request.'); - } + return $user->toArray(); } /** @@ -123,7 +119,9 @@ class UserController extends BaseController try { $user = new UserRepository; $create = $user->create($request->only([ - 'email', 'username', 'name_first', 'name_last', 'password', 'root_admin', 'custom_id', + 'email', 'username', 'name_first', + 'name_last', 'password', + 'root_admin', 'custom_id', ])); $create = $user->create($request->input('email'), $request->input('password'), $request->input('admin'), $request->input('custom_id')); @@ -160,7 +158,9 @@ class UserController extends BaseController try { $user = new UserRepository; $user->update($id, $request->only([ - 'username', 'email', 'name_first', 'name_last', 'password', 'root_admin', 'language', + 'username', 'email', 'name_first', + 'name_last', 'password', + 'root_admin', 'language', ])); return Models\User::findOrFail($id); diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index b68f8d01c..ab73937c4 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -86,16 +86,9 @@ class ServersController extends Controller { try { $server = new ServerRepository; - $response = $server->create($request->only([ - 'owner', 'name', 'memory', 'swap', - 'node', 'ip', 'port', 'allocation', - 'cpu', 'disk', 'service', - 'option', 'location', 'pack', - 'startup', 'custom_image_name', - 'auto_deploy', 'custom_id', - ])); + $response = $server->create($request->except('_token')); - return redirect()->route('admin.servers.view', ['id' => $response]); + return redirect()->route('admin.servers.view', ['id' => $response->id]); } catch (DisplayValidationException $ex) { return redirect()->route('admin.servers.new')->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { @@ -188,7 +181,7 @@ class ServersController extends Controller ], 500); } - $option = Models\ServiceOptions::with('variables', ['packs' => function ($query) { + $option = Models\ServiceOptions::with('variables')->with(['packs' => function ($query) { $query->where('selectable', true); }])->findOrFail($request->input('option')); diff --git a/app/Http/Middleware/APISecretToken.php b/app/Http/Middleware/APISecretToken.php index a1c203c9d..25bf891ba 100755 --- a/app/Http/Middleware/APISecretToken.php +++ b/app/Http/Middleware/APISecretToken.php @@ -121,7 +121,7 @@ class APISecretToken extends Authorization // Log the Route Access APILogService::log($request, null, true); - return Auth::loginUsingId($key->user); + return Auth::loginUsingId($key->user_id); } protected function _generateHMAC($body, $key) diff --git a/app/Models/Node.php b/app/Models/Node.php index 3da24531c..78e0828f7 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -66,28 +66,12 @@ class Node extends Model * @var array */ protected $fillable = [ - 'uuid', - 'uuidShort', - 'node_id', - 'name', - 'suspended', - 'owner_id', - 'memory', - 'swap', - 'disk', - 'io', - 'cpu', - 'oom_disabled', - 'allocation_id', - 'service_id', - 'option_id', - 'pack_id', - 'startup', - 'daemonSecret', - 'image', - 'username', - 'sftp_password', - 'installed', + 'public', 'name', 'location_id', + 'fqdn', 'scheme', 'memory', + 'memory_overallocate', 'disk', + 'disk_overallocate', 'upload_size', + 'daemonSecret', 'daemonBase', + 'daemonSFTP', 'daemonListen', ]; /** diff --git a/app/Repositories/APIRepository.php b/app/Repositories/APIRepository.php index 14348b2db..71fbb88b5 100644 --- a/app/Repositories/APIRepository.php +++ b/app/Repositories/APIRepository.php @@ -62,8 +62,8 @@ class APIRepository // Node Management Routes 'nodes.list', + 'nodes.view', 'nodes.create', - 'nodes.list', 'nodes.allocations', 'nodes.delete', diff --git a/app/Repositories/NodeRepository.php b/app/Repositories/NodeRepository.php index e409a011a..1af316b23 100644 --- a/app/Repositories/NodeRepository.php +++ b/app/Repositories/NodeRepository.php @@ -44,7 +44,7 @@ class NodeRepository // Validate Fields $validator = Validator::make($data, [ 'name' => 'required|regex:/^([\w .-]{1,100})$/', - 'location' => 'required|numeric|min:1|exists:locations,id', + 'location_id' => 'required|numeric|min:1|exists:locations,id', 'public' => 'required|numeric|between:0,1', 'fqdn' => 'required|string|unique:nodes,fqdn', 'scheme' => 'required|regex:/^(http(s)?)$/', @@ -91,7 +91,7 @@ class NodeRepository // Validate Fields $validator = $validator = Validator::make($data, [ 'name' => 'regex:/^([\w .-]{1,100})$/', - 'location' => 'numeric|min:1|exists:locations,id', + 'location_id' => 'numeric|min:1|exists:locations,id', 'public' => 'numeric|between:0,1', 'fqdn' => 'string|unique:nodes,fqdn,' . $id, 'scheme' => 'regex:/^(http(s)?)$/', @@ -210,13 +210,13 @@ class NodeRepository foreach ($portBlock as $assignPort) { $alloc = Models\Allocation::firstOrNew([ - 'node' => $node->id, + 'node_id' => $node->id, 'ip' => $ip, 'port' => $assignPort, ]); if (! $alloc->exists) { $alloc->fill([ - 'node' => $node->id, + 'node_id' => $node->id, 'ip' => $ip, 'port' => $assignPort, 'ip_alias' => $setAlias, @@ -227,13 +227,13 @@ class NodeRepository } } else { $alloc = Models\Allocation::firstOrNew([ - 'node' => $node->id, + 'node_id' => $node->id, 'ip' => $ip, 'port' => $port, ]); if (! $alloc->exists) { $alloc->fill([ - 'node' => $node->id, + 'node_id' => $node->id, 'ip' => $ip, 'port' => $port, 'ip_alias' => $setAlias, @@ -269,7 +269,7 @@ class NodeRepository ]); // Delete Allocations - Models\Allocation::where('node', $node->id)->delete(); + Models\Allocation::where('node_id', $node->id)->delete(); // Delete configure tokens Models\NodeConfigurationToken::where('node', $node->id)->delete(); diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 13caf0a5c..6e441666a 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -90,17 +90,17 @@ class ServerRepository 'io' => 'required|numeric|min:10|max:1000', 'cpu' => 'required|numeric|min:0', 'disk' => 'required|numeric|min:0', - 'service' => 'required|numeric|min:1|exists:services,id', - 'option' => 'required|numeric|min:1|exists:service_options,id', - 'location' => 'required|numeric|min:1|exists:locations,id', - 'pack' => 'sometimes|nullable|numeric|min:0', + 'service_id' => 'required|numeric|min:1|exists:services,id', + 'option_id' => 'required|numeric|min:1|exists:service_options,id', + 'location_id' => 'required|numeric|min:1|exists:locations,id', + 'pack_id' => 'sometimes|nullable|numeric|min:0', 'startup' => 'string', 'custom_image_name' => 'required_if:use_custom_image,on', 'auto_deploy' => 'sometimes|boolean', 'custom_id' => 'sometimes|required|numeric|unique:servers,id', ]); - $validator->sometimes('node', 'bail|required|numeric|min:1|exists:nodes,id', function ($input) { + $validator->sometimes('node_id', 'bail|required|numeric|min:1|exists:nodes,id', function ($input) { return ! ($input->auto_deploy); }); @@ -112,7 +112,7 @@ class ServerRepository return ! $input->auto_deploy && ! $input->allocation; }); - $validator->sometimes('allocation', 'numeric|exists:allocations,id', function ($input) { + $validator->sometimes('allocation_id', 'numeric|exists:allocations,id', function ($input) { return ! ($input->auto_deploy || ($input->port && $input->ip)); }); @@ -131,19 +131,19 @@ class ServerRepository if (isset($data['auto_deploy']) && in_array($data['auto_deploy'], [true, 1, '1'])) { // This is an auto-deployment situation // Ignore any other passed node data - unset($data['node'], $data['ip'], $data['port'], $data['allocation']); + unset($data['node_id'], $data['ip'], $data['port'], $data['allocation_id']); $autoDeployed = true; - $node = DeploymentService::smartRandomNode($data['memory'], $data['disk'], $data['location']); + $node = DeploymentService::smartRandomNode($data['memory'], $data['disk'], $data['location_id']); $allocation = DeploymentService::randomAllocation($node->id); } else { - $node = Models\Node::findOrFail($data['node']); + $node = Models\Node::findOrFail($data['node_id']); } // Verify IP & Port are a.) free and b.) assigned to the node. // We know the node exists because of 'exists:nodes,id' in the validation if (! $autoDeployed) { - if (! isset($data['allocation'])) { + if (! isset($data['allocation_id'])) { $allocation = Models\Allocation::where('ip', $data['ip'])->where('port', $data['port'])->where('node', $data['node'])->whereNull('assigned_to')->first(); } else { $allocation = Models\Allocation::where('id', $data['allocation'])->where('node', $data['node'])->whereNull('assigned_to')->first(); @@ -165,12 +165,12 @@ class ServerRepository } // Validate the Pack - if ($data['pack'] == 0) { - $data['pack'] = null; + if ($data['pack_id'] == 0) { + $data['pack_id'] = null; } - if (! is_null($data['pack'])) { - $pack = Models\ServicePack::where('id', $data['pack'])->where('option', $data['option'])->first(); + if (! is_null($data['pack_id'])) { + $pack = Models\ServicePack::where('id', $data['pack_id'])->where('option', $data['option_id'])->first(); if (! $pack) { throw new DisplayException('The requested service pack does not seem to exist for this combination.'); } @@ -180,7 +180,7 @@ class ServerRepository $service = Models\Service::find($option->service_id); // Check those Variables - $variables = Models\ServiceVariables::where('option_id', $data['option'])->get(); + $variables = Models\ServiceVariables::where('option_id', $data['option_id'])->get(); $variableList = []; if ($variables) { foreach ($variables as $variable) { @@ -254,10 +254,10 @@ class ServerRepository $server->fill([ 'uuid' => $genUuid, 'uuidShort' => $genShortUuid, - 'node' => $node->id, + 'node_id' => $node->id, 'name' => $data['name'], 'suspended' => 0, - 'owner' => $user->id, + 'owner_id' => $user->id, 'memory' => $data['memory'], 'swap' => $data['swap'], 'disk' => $data['disk'], @@ -265,9 +265,9 @@ class ServerRepository 'cpu' => $data['cpu'], 'oom_disabled' => (isset($data['oom_disabled'])) ? true : false, 'allocation' => $allocation->id, - 'service' => $data['service'], - 'option' => $data['option'], - 'pack' => $data['pack'], + 'service_id' => $data['service_id'], + 'option_id' => $data['option_id'], + 'pack_id' => $data['pack_id'], 'startup' => $data['startup'], 'daemonSecret' => $uuid->generate('servers', 'daemonSecret'), 'image' => (isset($data['custom_image_name'])) ? $data['custom_image_name'] : $option->docker_image, @@ -277,7 +277,7 @@ class ServerRepository $server->save(); // Mark Allocation in Use - $allocation->assigned_to = $server->id; + $allocation->server_id = $server->id; $allocation->save(); // Add Variables @@ -329,7 +329,7 @@ class ServerRepository DB::commit(); - return $server->id; + return $server; } catch (TransferException $ex) { DB::rollBack(); throw new DisplayException('There was an error while attempting to connect to the daemon to add this server.', $ex); @@ -782,8 +782,8 @@ class ServerRepository DB::beginTransaction(); try { // Unassign Allocations - Models\Allocation::where('assigned_to', $server->id)->update([ - 'assigned_to' => null, + Models\Allocation::where('server_id', $server->id)->update([ + 'server_id' => null, ]); // Remove Variables diff --git a/resources/views/admin/nodes/new.blade.php b/resources/views/admin/nodes/new.blade.php index 07227daa7..37add9812 100644 --- a/resources/views/admin/nodes/new.blade.php +++ b/resources/views/admin/nodes/new.blade.php @@ -44,9 +44,9 @@
      - @foreach($locations as $location) - + @endforeach
      diff --git a/resources/views/admin/nodes/view.blade.php b/resources/views/admin/nodes/view.blade.php index 5fa054703..9b569d5c8 100644 --- a/resources/views/admin/nodes/view.blade.php +++ b/resources/views/admin/nodes/view.blade.php @@ -138,9 +138,9 @@
      - @foreach($locations as $location) - + @endforeach
      diff --git a/resources/views/admin/servers/new.blade.php b/resources/views/admin/servers/new.blade.php index 2c3d655a2..2fe12b1dd 100644 --- a/resources/views/admin/servers/new.blade.php +++ b/resources/views/admin/servers/new.blade.php @@ -63,7 +63,7 @@
      - @foreach($locations as $location) @@ -75,7 +75,7 @@ @section('footer-scripts') diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index d478bd372..ad8644648 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -236,7 +236,7 @@ - Copyright © 2015 - {{ date('Y') }} Pterodactyl Software & Design. + Copyright © 2015 - {{ date('Y') }} Pterodactyl Software.
      - - + + - - + @if (isset($directory['first']) && $directory['first'] === true) - - - - + + + + @endif @if (isset($directory['show']) && $directory['show'] === true) - + - - + + @endif @@ -69,8 +69,8 @@ - - + - - + @@ -176,7 +176,7 @@ $style = [ From 397172de3b5f0dda7495565ec2bf2b0da89b9d3f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 19:26:02 -0500 Subject: [PATCH 263/599] Better notification for user creation, only add button if needed. --- app/Notifications/AccountCreated.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/Notifications/AccountCreated.php b/app/Notifications/AccountCreated.php index e7daff927..8e66a7485 100644 --- a/app/Notifications/AccountCreated.php +++ b/app/Notifications/AccountCreated.php @@ -69,11 +69,16 @@ class AccountCreated extends Notification implements ShouldQueue */ public function toMail($notifiable) { - return (new MailMessage) + $message = (new MailMessage) ->greeting('Hello ' . $this->user->name . '!') ->line('You are recieving this email because an account has been created for you on Pterodactyl Panel.') ->line('Username: ' . $this->user->username) - ->line('Email: ' . $notifiable->email) - ->action('Setup Your Account', url('/auth/password/reset/' . $this->user->token . '?email=' . $notifiable->email)); + ->line('Email: ' . $notifiable->email); + + if (! is_null($this->user->token)) { + return $message->action('Setup Your Account', url('/auth/password/reset/' . $this->user->token . '?email=' . $notifiable->email)); + } + + return $message; } } From 054e65b78fddb3bc37090882a62e8e49442f154f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 19:28:23 -0500 Subject: [PATCH 264/599] Fix user deletion --- app/Repositories/UserRepository.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index 5ab2edbbf..c59637783 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -165,7 +165,7 @@ class UserRepository */ public function delete($id) { - if (Models\Server::where('owner', $id)->count() > 0) { + if (Models\Server::where('owner_id', $id)->count() > 0) { throw new DisplayException('Cannot delete a user with active servers attached to thier account.'); } @@ -177,10 +177,15 @@ class UserRepository DB::beginTransaction(); try { - Models\Permission::where('user_id', $id)->delete(); - Models\Subuser::where('user_id', $id)->delete(); - Models\User::destroy($id); + foreach(Models\Subuser::with('permissions')->where('user_id', $id)->get() as &$subuser) { + foreach($subuser->permissions as &$permission) { + $permission->delete(); + } + $subuser->delete(); + } + + Models\User::destroy($id); DB::commit(); return true; From 6a996c7c0cf9ab1836d85d19a78fae734f432b71 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 19:35:26 -0500 Subject: [PATCH 265/599] Fix account creation email --- app/Notifications/AccountCreated.php | 2 +- app/Observers/UserObserver.php | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Notifications/AccountCreated.php b/app/Notifications/AccountCreated.php index 8e66a7485..b7f86361c 100644 --- a/app/Notifications/AccountCreated.php +++ b/app/Notifications/AccountCreated.php @@ -38,7 +38,7 @@ class AccountCreated extends Notification implements ShouldQueue * * @var string */ - public $token; + public $user; /** * Create a new notification instance. diff --git a/app/Observers/UserObserver.php b/app/Observers/UserObserver.php index 437a82a69..258174ffb 100644 --- a/app/Observers/UserObserver.php +++ b/app/Observers/UserObserver.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Observers; +use DB; use Pterodactyl\Events; use Pterodactyl\Models\User; use Pterodactyl\Notifications\AccountCreated; @@ -51,10 +52,11 @@ class UserObserver { event(new Events\User\Created($user)); + $token = DB::table('password_resets')->where('email', $user->email)->orderBy('created_at', 'desc')->first(); $user->notify((new AccountCreated([ 'name' => $user->name_first, 'username' => $user->username, - 'token' => DB::table('password_resets')->where('email', $user->email)->orderBy('created_at', 'desc')->first(), + 'token' => (! is_null($token)) ? $token->token : null, ]))); } From 5f8572fe1aa61321da1d1241c32e01a6614b49f3 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 19:37:35 -0500 Subject: [PATCH 266/599] Fix power button permissions checking --- resources/themes/pterodactyl/server/index.blade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/themes/pterodactyl/server/index.blade.php b/resources/themes/pterodactyl/server/index.blade.php index 8774b5284..14a099406 100644 --- a/resources/themes/pterodactyl/server/index.blade.php +++ b/resources/themes/pterodactyl/server/index.blade.php @@ -45,8 +45,8 @@ From 0f93ba2495132a3ff527c484625958e5112e5430 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 19:45:03 -0500 Subject: [PATCH 267/599] Add permissions checking to sidebar --- .../pterodactyl/layouts/master.blade.php | 132 ++++++++++-------- 1 file changed, 75 insertions(+), 57 deletions(-) diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index 9df07de6e..ce881ada5 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -116,63 +116,81 @@ @lang('navigation.server.console') -
    • - - - @lang('navigation.server.file_management') - - - - - -
    • -
    • - - Subusers - -
    • -
    • - - @lang('navigation.server.task_management') - - {{ \Pterodactyl\Models\Task::select('id')->where('server', $server->id)->where('active', 1)->count() }} - - -
    • -
    • - - - @lang('navigation.server.configuration') - - - - - -
    • + @can('list-files', $server) +
    • + + + @lang('navigation.server.file_management') + + + + + +
    • + @endcan + @can('list-subusers', $server) +
    • + + Subusers + +
    • + @endcan + @can('list-tasks', $server) +
    • + + @lang('navigation.server.task_management') + + {{ \Pterodactyl\Models\Task::select('id')->where('server', $server->id)->where('active', 1)->count() }} + + +
    • + @endcan + @if(Gate::allows('view-startup', $server) || Gate::allows('view-sftp', $server) || Gate::allows('view-databases', $server) || Gate::allows('view-allocation', $server)) +
    • + + + @lang('navigation.server.configuration') + + + + + +
    • + @endif @endif From 22da8d47c827c0b5a1a9f5fe970c89cd0cabfc57 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 19:45:14 -0500 Subject: [PATCH 268/599] Auto-fill emails when resetting password --- app/Notifications/SendPasswordReset.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Notifications/SendPasswordReset.php b/app/Notifications/SendPasswordReset.php index a3bddb825..0037fb7f3 100644 --- a/app/Notifications/SendPasswordReset.php +++ b/app/Notifications/SendPasswordReset.php @@ -72,7 +72,7 @@ class SendPasswordReset extends Notification implements ShouldQueue return (new MailMessage) ->subject('Reset Password') ->line('You are receiving this email because we received a password reset request for your account.') - ->action('Reset Password', url('auth/password/reset', $this->token)) + ->action('Reset Password', url('/auth/password/reset/' . $this->token . '?email=' . $notifiable->email)) ->line('If you did not request a password reset, no further action is required.'); } } From e9762b427705ff3a89f501580eecd4b26a3bb23a Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 19:59:40 -0500 Subject: [PATCH 269/599] Fixes port deletion for node allocations as well as server notes on allocations. closes #305 --- CHANGELOG.md | 4 ++++ app/Http/Controllers/Admin/NodesController.php | 4 ++-- app/Models/Allocation.php | 10 ++++++++++ resources/views/admin/nodes/view.blade.php | 10 +++++++--- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24a0972fb..1334a5e54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,15 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * `[pre.2]` — Fixes inability to edit a server due to owner_id issues. * `[pre.2]` — Fixes bug when trying to add new subusers. * Emails sending with 'Pterodactyl Panel' as the from name. Now configurable by using `php artisan pterodactyl:mail` to update. +* `[pre.2]` — Fixes inability to delete accounts due to SQL changes. +* `[pre.2]` — Fixes bug with checking power-permissions that showed the wrong buttons. Also adds check back to sidebar to only show options a user can use. +* `[pre.2]` — Fixes allocation listing on node allocations tab as well as bug preventing deletion of port. ### Changed * `[pre.2]` — File Manager now displays relevant information on all screen sizes, and includes better button clicking mechanics for dropdown menu. * Reduced the number of database queries being executed when viewing a specific server. This is done by caching the query for up to 60 minutes in memcached. * User creation emails include more information and are sent by the event listener rather than the repository. +* Account password reset emails now auto-fill the email when clicking the link. ### Added * Notifications when a user is added or removed as a subuser for a server. diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index f90cab991..f4a60b5b2 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -108,7 +108,7 @@ class NodesController extends Controller 'servers.user', 'servers.service', 'servers.allocations', 'location' )->findOrFail($id); - $node->setRelation('allocations', $node->allocations()->paginate(40)); + $node->setRelation('allocations', $node->allocations()->with('server')->paginate(40)); return view('admin.nodes.view', [ 'node' => $node, @@ -151,7 +151,7 @@ class NodesController extends Controller public function deallocateSingle(Request $request, $node, $allocation) { - $query = Models\Allocation::where('node', $node)->whereNull('server_id')->where('id', $allocation)->delete(); + $query = Models\Allocation::where('node_id', $node)->whereNull('server_id')->where('id', $allocation)->delete(); if ((int) $query === 0) { return response()->json([ 'error' => 'Unable to find an allocation matching those details to delete.', diff --git a/app/Models/Allocation.php b/app/Models/Allocation.php index aad98ac63..cdcf79782 100644 --- a/app/Models/Allocation.php +++ b/app/Models/Allocation.php @@ -74,4 +74,14 @@ class Allocation extends Model { return ! is_null($this->ip_alias); } + + /** + * Gets information for the server associated with this allocation. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function server() + { + return $this->belongsTo(Server::class); + } } diff --git a/resources/views/admin/nodes/view.blade.php b/resources/views/admin/nodes/view.blade.php index 9b569d5c8..5a0879b72 100644 --- a/resources/views/admin/nodes/view.blade.php +++ b/resources/views/admin/nodes/view.blade.php @@ -356,16 +356,20 @@
      @foreach($node->allocations as $allocation) - + - + - - - + + + From fd5b74c87383a9f41075afbce0c4b12140c13b1e Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 3 Mar 2017 17:53:35 -0500 Subject: [PATCH 292/599] Use usernames for @schrej --- app/Http/Controllers/Admin/NodesController.php | 2 +- .../themes/pterodactyl/admin/nodes/view/servers.blade.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index 8ee9e2df8..ee4a58066 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -211,7 +211,7 @@ class NodesController extends Controller */ public function viewServers(Request $request, $id) { - $node = Models\Node::with('servers.user', 'servers.service', 'servers.allocations')->findOrFail($id); + $node = Models\Node::with('servers.user', 'servers.service', 'servers.option')->findOrFail($id); Javascript::put([ 'node' => collect($node->makeVisible('daemonSecret'))->only(['scheme', 'fqdn', 'daemonListen', 'daemonSecret']), ]); diff --git a/resources/themes/pterodactyl/admin/nodes/view/servers.blade.php b/resources/themes/pterodactyl/admin/nodes/view/servers.blade.php index d7ebcbabe..519b5fbbe 100644 --- a/resources/themes/pterodactyl/admin/nodes/view/servers.blade.php +++ b/resources/themes/pterodactyl/admin/nodes/view/servers.blade.php @@ -70,8 +70,8 @@ - - + + From 6df573e50c5f44dd5e4920bee7bcc2a7ce502808 Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Sat, 4 Mar 2017 00:14:21 +0100 Subject: [PATCH 293/599] retheme admin users list --- app/Http/Controllers/Admin/UserController.php | 8 +- .../pterodactyl/admin/users/index.blade.php | 84 +++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 resources/themes/pterodactyl/admin/users/index.blade.php diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 1b1079143..0de02eca9 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -47,8 +47,14 @@ class UserController extends Controller // @TODO: implement nicolaslopezj/searchable to clean up this disaster. public function getIndex(Request $request) { + $users = User::withCount('servers'); + + if (! is_null($request->input('query'))) { + $users->search($request->input('query')); + } + return view('admin.users.index', [ - 'users' => User::paginate(25), + 'users' => $users->paginate(25), ]); } diff --git a/resources/themes/pterodactyl/admin/users/index.blade.php b/resources/themes/pterodactyl/admin/users/index.blade.php new file mode 100644 index 000000000..3832c0374 --- /dev/null +++ b/resources/themes/pterodactyl/admin/users/index.blade.php @@ -0,0 +1,84 @@ +{{-- 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') + List Users +@endsection + +@section('content-header') +

      UsersAll registered users on the system.

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

      User List

      +
      + +
      + +
      + + +
      +
      + +
      +
      +
      +
      {{ $server->uuidShort }} {{ $server->name }}{{ $server->node_idName }}{{ $server->node->name }} {{ $server->username }} @if($server->suspended === 0)Active@elseSuspended@endif
      User Image{{ $user->username }} - {{ $user->email }}User Image{{ $subuser->user->username }} + {{ $subuser->user->email }} - @if($user->use_totp) + @if($subuser->user->use_totp) @else @endif - + - +
      {{ $database->name }} {{ $database->host }}:{{ $database->port }} {{ $database->username }}{{ $database->c_databases }}{{ $database->databases_count }} @if(is_null($database->node))unlinked@else{{ $database->node->name }}@endif
      {{ $location->short }} {{ $location->long }}{{ $location->a_nodeCount }}{{ $location->a_serverCount }}{{ $location->nodes_count }}{{ $location->servers_count }}
      @lang('server.files.file_name')@lang('server.files.size')@lang('server.files.last_modified')
      + /home/container{{ $directory['header'] }} @@ -45,21 +45,21 @@
      ← {{ $directory['link_show'] }}
      {{ $folder['entry'] }} {{ $folder['size'] }} timezone(env('APP_TIMEZONE', 'America/New_York')); ?> @if($carbon->diffInMinutes(Carbon::now()) > 60) {{ $carbon->format('m/d/y H:i:s') }} @@ -146,8 +146,8 @@ {{ $file['entry'] }} @endif {{ $file['size'] }} timezone(env('APP_TIMEZONE', 'America/New_York')); ?> @if($carbon->diffInMinutes(Carbon::now()) > 60) {{ $carbon->format('m/d/y H:i:s') }} From ff9904227b66b0fb705ec09a1b9b55a8df64ecac Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 18:17:28 -0500 Subject: [PATCH 258/599] Fix server editing --- app/Repositories/ServerRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 33e446e36..b6047739d 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -376,7 +376,7 @@ class ServerRepository } // Update Server Owner if it was passed. - if (isset($data['owner']) && $data['owner'] !== $owner->email) { + if (isset($data['owner']) && $data['owner'] !== $server->user->email) { $newOwner = Models\User::select('id')->where('email', $data['owner'])->first(); $server->owner_id = $newOwner->id; } From 9af06b4b59b8cb3d6c0c0ea0cebe757638e6a90d Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 18:19:53 -0500 Subject: [PATCH 259/599] Add in query caching on server view --- .env.example | 2 +- CHANGELOG.md | 5 ++ app/Console/Commands/UpdateEnvironment.php | 4 ++ app/Events/Server/Saved.php | 45 +++++++++++++++++ app/Events/Server/Saving.php | 45 +++++++++++++++++ app/Events/Server/Updated.php | 45 +++++++++++++++++ app/Events/Server/Updating.php | 45 +++++++++++++++++ app/Http/Controllers/Base/IndexController.php | 2 +- app/Models/Server.php | 20 +++++--- app/Models/User.php | 4 +- app/Observers/ServerObserver.php | 49 +++++++++++++++++++ config/cache.php | 6 ++- config/debugbar.php | 8 +-- .../pterodactyl/layouts/master.blade.php | 2 +- 14 files changed, 263 insertions(+), 19 deletions(-) create mode 100644 app/Events/Server/Saved.php create mode 100644 app/Events/Server/Saving.php create mode 100644 app/Events/Server/Updated.php create mode 100644 app/Events/Server/Updating.php diff --git a/.env.example b/.env.example index fa7e20965..ed3a56b68 100644 --- a/.env.example +++ b/.env.example @@ -13,7 +13,7 @@ DB_DATABASE=homestead DB_USERNAME=homestead DB_PASSWORD=secret -CACHE_DRIVER=file +CACHE_DRIVER=memcached SESSION_DRIVER=database MAIL_DRIVER=smtp diff --git a/CHANGELOG.md b/CHANGELOG.md index e5f206283..12a23d724 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ## v0.6.0-pre.3 (Courageous Carniadactylus) ### Fixed * `[pre.2]` — Fixes bug where servers could not be manually deployed to nodes due to a broken SQL call. +* `[pre.2]` — Fixes inability to edit a server due to owner_id issues. + +### Changed +* `[pre.2]` — File Manager now displays relevant information on all screen sizes, and includes better button clicking mechanics for dropdown menu. +* Reduced the number of database queries being executed when viewing a specific server. This is done by caching the query for up to 60 minutes in memcached. ## v0.6.0-pre.2 (Courageous Carniadactylus) ### Fixed diff --git a/app/Console/Commands/UpdateEnvironment.php b/app/Console/Commands/UpdateEnvironment.php index 3805ffd51..aa3dcfe7f 100644 --- a/app/Console/Commands/UpdateEnvironment.php +++ b/app/Console/Commands/UpdateEnvironment.php @@ -134,6 +134,10 @@ class UpdateEnvironment extends Command $variables['APP_TIMEZONE'] = $this->option('timezone'); } + $variables['APP_THEME'] = 'pterodactyl'; + $variables['CACHE_DRIVER'] = 'memcached'; + $variables['SESSION_DRIVER'] = 'database'; + $bar = $this->output->createProgressBar(count($variables)); $this->line('Writing new environment configuration to file.'); diff --git a/app/Events/Server/Saved.php b/app/Events/Server/Saved.php new file mode 100644 index 000000000..08700e3cb --- /dev/null +++ b/app/Events/Server/Saved.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\Server; + +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; + +class Saved +{ + use SerializesModels; + + public $server; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } +} diff --git a/app/Events/Server/Saving.php b/app/Events/Server/Saving.php new file mode 100644 index 000000000..2c6d3cb4e --- /dev/null +++ b/app/Events/Server/Saving.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\Server; + +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; + +class Saving +{ + use SerializesModels; + + public $server; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } +} diff --git a/app/Events/Server/Updated.php b/app/Events/Server/Updated.php new file mode 100644 index 000000000..0310e20c6 --- /dev/null +++ b/app/Events/Server/Updated.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\Server; + +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; + +class Updated +{ + use SerializesModels; + + public $server; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } +} diff --git a/app/Events/Server/Updating.php b/app/Events/Server/Updating.php new file mode 100644 index 000000000..f333ede6b --- /dev/null +++ b/app/Events/Server/Updating.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\Server; + +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; + +class Updating +{ + use SerializesModels; + + public $server; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } +} diff --git a/app/Http/Controllers/Base/IndexController.php b/app/Http/Controllers/Base/IndexController.php index 6b0bd273e..f6abf4ea4 100644 --- a/app/Http/Controllers/Base/IndexController.php +++ b/app/Http/Controllers/Base/IndexController.php @@ -47,7 +47,7 @@ class IndexController extends Controller public function getIndex(Request $request) { return view('base.index', [ - 'servers' => $request->user()->serverAccessCollection(10)->load('node', 'allocation'), + 'servers' => $request->user()->serverAccessCollection(10), ]); } diff --git a/app/Models/Server.php b/app/Models/Server.php index 5dd5bb357..5e8179254 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -25,6 +25,7 @@ namespace Pterodactyl\Models; use Auth; +use Cache; use Javascript; use Illuminate\Database\Eloquent\Model; use Illuminate\Notifications\Notifiable; @@ -113,16 +114,19 @@ class Server extends Model */ public static function byUuid($uuid) { - $query = self::with('service', 'node')->where(function ($q) use ($uuid) { - $q->where('uuidShort', $uuid)->orWhere('uuid', $uuid); + // Results are cached because we call this functions a few times on page load. + $result = Cache::remember('Server.byUuid.' . $uuid, 60, function () use ($uuid) { + $query = self::with('service', 'node')->where(function ($q) use ($uuid) { + $q->where('uuidShort', $uuid)->orWhere('uuid', $uuid); + }); + + if (! Auth::user()->isRootAdmin()) { + $query->whereIn('id', Auth::user()->serverAccessArray()); + } + + return $query->first(); }); - if (! Auth::user()->isRootAdmin()) { - $query->whereIn('id', Auth::user()->serverAccessArray()); - } - - $result = $query->first(); - if (! is_null($result)) { $result->daemonSecret = Auth::user()->daemonToken($result); } diff --git a/app/Models/User.php b/app/Models/User.php index abcddf227..131192264 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -186,9 +186,9 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac * * @return Collection */ - public function serverAccessCollection($paginate = null) + public function serverAccessCollection($paginate = null, $load = ['service', 'node', 'allocation']) { - $query = Server::with('service', 'node'); + $query = Server::with($load); if (! $this->isRootAdmin()) { $query->whereIn('id', $this->serverAccessArray()); } diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php index 06778c674..556d1c165 100644 --- a/app/Observers/ServerObserver.php +++ b/app/Observers/ServerObserver.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Observers; +use Cache; use Carbon; use Pterodactyl\Events; use Pterodactyl\Models\Server; @@ -97,4 +98,52 @@ class ServerObserver ->onQueue(env('QUEUE_STANDARD', 'standard')) ); } + + /** + * Listen to the Server saving event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function saving(Server $server) + { + event(new Events\Server\Saving($server)); + } + + /** + * Listen to the Server saved event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function saved(Server $server) + { + event(new Events\Server\Saved($server)); + } + + /** + * Listen to the Server saving event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function updating(Server $server) + { + event(new Events\Server\Updating($server)); + } + + /** + * Listen to the Server saved event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function updated(Server $server) + { + // Clear Caches + Cache::forget('Server.byUuid.' . $server->uuid); + Cache::forget('Server.byUuid.' . $server->uuidShort); + + event(new Events\Server\Updated($server)); + } } diff --git a/config/cache.php b/config/cache.php index 379135b0e..cb4bbd25d 100644 --- a/config/cache.php +++ b/config/cache.php @@ -13,7 +13,7 @@ return [ | */ - 'default' => env('CACHE_DRIVER', 'file'), + 'default' => env('CACHE_DRIVER', 'memcached'), /* |-------------------------------------------------------------------------- @@ -51,7 +51,9 @@ return [ 'driver' => 'memcached', 'servers' => [ [ - 'host' => '127.0.0.1', 'port' => 11211, 'weight' => 100, + 'host' => env('MEMCACHE_DRIVER_HOST', '127.0.0.1'), + 'port' => env('MEMCACHE_DRIVER_PORT', 11211), + 'weight' => 100, ], ], ], diff --git a/config/debugbar.php b/config/debugbar.php index 4c1349b40..4d9d8c45e 100644 --- a/config/debugbar.php +++ b/config/debugbar.php @@ -92,7 +92,7 @@ return [ 'views' => true, // Views with their data 'route' => true, // Current route information 'laravel' => false, // Laravel version and environment - 'events' => false, // All events fired + 'events' => true, // All events fired 'default_request' => false, // Regular or special Symfony request logger 'symfony_request' => true, // Only one can be enabled.. 'mail' => true, // Catch mail messages @@ -119,11 +119,11 @@ return [ ], 'db' => [ 'with_params' => true, // Render SQL with the parameters substituted - 'timeline' => false, // Add the queries to the timeline - 'backtrace' => false, // EXPERIMENTAL: Use a backtrace to find the origin of the query in your files. + 'timeline' => true, // Add the queries to the timeline + 'backtrace' => true, // EXPERIMENTAL: Use a backtrace to find the origin of the query in your files. 'explain' => [ // EXPERIMENTAL: Show EXPLAIN output on queries 'enabled' => false, - 'types' => ['SELECT'], // array('SELECT', 'INSERT', 'UPDATE', 'DELETE'); for MySQL 5.6.3+ + 'types' => ['SELECT', 'INSERT', 'UPDATE', 'DELETE'], // array('SELECT', 'INSERT', 'UPDATE', 'DELETE'); for MySQL 5.6.3+ ], 'hints' => true, // Show hints for common mistakes ], diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index 6c6307367..9df07de6e 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -219,7 +219,7 @@
      - {{ Settings::get('company') }} + {{ Settings::get('company', 'Pterodactyl Panel') }}

      © {{ date('Y') }} - {{ Settings::get('company') }}. + {{ Settings::get('company', 'Pterodactyl Panel') }}. All rights reserved.

      {{ $allocation->ip }} {{ $allocation->port }}@if(!is_null($allocation->assigned_to)){{ $allocation->assigned_to_name }}@endif + @if(! is_null($allocation->server)) + {{ $allocation->server->name }} + @endif + - @if(is_null($allocation->assigned_to)) + @if(is_null($allocation->server_id)) @else From 99497adcb2a070d038695e9011b015cb97c17c2f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 20:34:57 -0500 Subject: [PATCH 270/599] Show proper server status when viewing listing. closes #308 --- app/Http/Controllers/Server/AjaxController.php | 8 ++++++++ app/Http/Routes/ServerRoutes.php | 13 +++++++------ public/themes/pterodactyl/js/frontend/serverlist.js | 9 ++++++++- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/app/Http/Controllers/Server/AjaxController.php b/app/Http/Controllers/Server/AjaxController.php index d18aee7bf..8f3736da7 100644 --- a/app/Http/Controllers/Server/AjaxController.php +++ b/app/Http/Controllers/Server/AjaxController.php @@ -73,6 +73,14 @@ class AjaxController extends Controller return response()->json([], 404); } + if (! $server->installed) { + return response()->json(['status' => 20]); + } + + if ($server->suspended) { + return response()->json(['status' => 30]); + } + try { $res = $server->guzzleClient()->request('GET', '/server'); if ($res->getStatusCode() === 200) { diff --git a/app/Http/Routes/ServerRoutes.php b/app/Http/Routes/ServerRoutes.php index 284822db4..36c95827b 100644 --- a/app/Http/Routes/ServerRoutes.php +++ b/app/Http/Routes/ServerRoutes.php @@ -30,6 +30,13 @@ class ServerRoutes { public function map(Router $router) { + // Returns Server Status + $router->get('/server/{server}/ajax/status', [ + 'middleware' => ['auth', 'csrf'], + 'as' => 'server.ajax.status', + 'uses' => 'Server\AjaxController@getStatus', + ]); + $router->group([ 'prefix' => 'server/{server}', 'middleware' => [ @@ -164,12 +171,6 @@ class ServerRoutes // Assorted AJAX Routes $router->group(['prefix' => 'ajax'], function ($server) use ($router) { - // Returns Server Status - $router->get('status', [ - 'as' => 'server.ajax.status', - 'uses' => 'Server\AjaxController@getStatus', - ]); - // Sets the Default Connection for the Server $router->post('set-primary', [ 'uses' => 'Server\AjaxController@postSetPrimary', diff --git a/public/themes/pterodactyl/js/frontend/serverlist.js b/public/themes/pterodactyl/js/frontend/serverlist.js index 605c33d2f..fc2ae0aff 100644 --- a/public/themes/pterodactyl/js/frontend/serverlist.js +++ b/public/themes/pterodactyl/js/frontend/serverlist.js @@ -28,6 +28,7 @@ var Status = { $('.dynamic-update').each(function (index, data) { var element = $(this); var serverShortUUID = $(this).data('server'); + $.ajax({ type: 'GET', url: Router.route('server.ajax.status', { server: serverShortUUID }), @@ -53,8 +54,14 @@ var Status = { case 3: element.find('[data-action="status"]').html('Stopping'); break; + case 20: + element.find('[data-action="status"]').html('Installing'); + break; + case 30: + element.find('[data-action="status"]').html('Suspended'); + break; } - if (data.status !== 0) { + if (data.status > 0 && data.status < 4) { var cpuMax = element.find('[data-action="cpu"]').data('cpumax'); var currentCpu = data.proc.cpu.total; if (cpuMax !== 0) { From 824041f6ca30defacf585cb7b37d01533eff3764 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 20:40:50 -0500 Subject: [PATCH 271/599] Fix service creation/updates, closes #306 --- CHANGELOG.md | 1 + app/Models/Service.php | 6 ++++-- app/Repositories/ServiceRepository/Service.php | 8 +++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1334a5e54..3c186e143 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * `[pre.2]` — Fixes inability to delete accounts due to SQL changes. * `[pre.2]` — Fixes bug with checking power-permissions that showed the wrong buttons. Also adds check back to sidebar to only show options a user can use. * `[pre.2]` — Fixes allocation listing on node allocations tab as well as bug preventing deletion of port. +* `[pre.2]` — Fixes bug in services that prevented saving updated settings or creating new services. ### Changed * `[pre.2]` — File Manager now displays relevant information on all screen sizes, and includes better button clicking mechanics for dropdown menu. diff --git a/app/Models/Service.php b/app/Models/Service.php index 39e74e5b8..83cdb70b0 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -36,11 +36,13 @@ class Service extends Model protected $table = 'services'; /** - * Fields that are not mass assignable. + * Fields that are mass assignable. * * @var array */ - protected $fillable = ['id', 'created_at', 'updated_at']; + protected $fillable = [ + 'name', 'description', 'file', 'executable', 'startup', + ]; /** * Gets all service options associated with this service. diff --git a/app/Repositories/ServiceRepository/Service.php b/app/Repositories/ServiceRepository/Service.php index 6ebb76142..206479a0a 100644 --- a/app/Repositories/ServiceRepository/Service.php +++ b/app/Repositories/ServiceRepository/Service.php @@ -53,11 +53,13 @@ class Service throw new DisplayValidationException($validator->errors()); } - $data['author'] = env('SERVICE_AUTHOR', (string) Uuid::generate(4)); - DB::beginTransaction(); try { - $service = Models\Service::create($data); + $service = new Models\Service; + $service->author = env('SERVICE_AUTHOR', (string) Uuid::generate(4)); + $service->fill($data); + $service->save(); + Storage::put('services/' . $service->file . '/main.json', '{}'); Storage::copy('services/.templates/index.js', 'services/' . $service->file . '/index.js'); DB::commit(); From 911434d033e4e8bd5a762ea6593e19ba7349b3be Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Feb 2017 12:47:49 -0500 Subject: [PATCH 272/599] Only apache could manage to do something this ridiculous --- public/.htaccess | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/.htaccess b/public/.htaccess index 8eb2dd0dd..342448645 100644 --- a/public/.htaccess +++ b/public/.htaccess @@ -8,6 +8,10 @@ # Redirect Trailing Slashes If Not A Folder... RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)/$ /$1 [L,R=301] + + # Prevent stripping authorization headers + RewriteCond %{HTTP:Authorization} ^(.*) + RewriteRule .* - [e=HTTP_AUTHORIZATION:%1] # Handle Front Controller... RewriteCond %{REQUEST_FILENAME} !-d From b926d432e8011fd540e02f398037dda4420dea4a Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Feb 2017 19:31:44 -0500 Subject: [PATCH 273/599] Thats enough re-theming for the day... --- .../Controllers/Admin/ServersController.php | 53 ++-- app/Http/Controllers/Admin/UserController.php | 8 +- app/Http/Middleware/AdminAuthenticate.php | 3 - app/Http/Routes/AdminRoutes.php | 4 + app/Models/Server.php | 19 +- app/Models/User.php | 13 +- composer.json | 3 +- composer.lock | 50 +++- public/js/laroute.js | 2 +- public/themes/pterodactyl/css/pterodactyl.css | 17 ++ .../themes/pterodactyl/admin/index.blade.php | 71 ++++++ .../pterodactyl/admin/servers/index.blade.php | 94 +++++++ .../pterodactyl/admin/servers/new.blade.php | 230 ++++++++++++++++++ .../pterodactyl/layouts/admin.blade.php | 198 +++++++++++++++ .../pterodactyl/layouts/master.blade.php | 6 +- 15 files changed, 733 insertions(+), 38 deletions(-) create mode 100644 resources/themes/pterodactyl/admin/index.blade.php create mode 100644 resources/themes/pterodactyl/admin/servers/index.blade.php create mode 100644 resources/themes/pterodactyl/admin/servers/new.blade.php create mode 100644 resources/themes/pterodactyl/layouts/admin.blade.php diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 0f5cf495d..daacc9f08 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -46,8 +46,16 @@ class ServersController extends Controller public function getIndex(Request $request) { + $servers = Models\Server::withTrashed()->with( + 'node', 'user', 'allocation' + ); + + if (! is_null($request->input('query'))) { + $servers->search($request->input('query')); + } + return view('admin.servers.index', [ - 'servers' => Models\Server::withTrashed()->with('node', 'user')->paginate(25), + 'servers' => $servers->paginate(25), ]); } @@ -109,13 +117,25 @@ class ServersController extends Controller */ public function postNewServerGetNodes(Request $request) { - if (! $request->input('location')) { - return response()->json([ - 'error' => 'Missing location in request.', - ], 500); - } + $nodes = Models\Node::with('allocations')->where('location_id', $request->input('location'))->get(); + return $nodes->map(function ($item) { + $filtered = $item->allocations->map(function($map) { + return collect($map)->only(['ip', 'port']); + }); - return response()->json(Models\Node::select('id', 'name', 'public')->where('location_id', $request->input('location'))->get()); + $item->ports = $filtered->unique('ip')->map(function ($map) use ($item) { + return [ + 'ip' => $map['ip'], + 'ports' => $item->allocations->where('ip', $map['ip'])->pluck('port')->all(), + ]; + })->values(); + + return [ + 'id' => $item->id, + 'text' => $item->name, + 'allocations' => $item->ports, + ]; + })->values(); } /** @@ -126,24 +146,7 @@ class ServersController extends Controller */ public function postNewServerGetIps(Request $request) { - if (! $request->input('node')) { - return response()->json([ - 'error' => 'Missing node in request.', - ], 500); - } - - $ips = Models\Allocation::where('node_id', $request->input('node'))->whereNull('server_id')->get(); - $listing = []; - - foreach ($ips as &$ip) { - if (array_key_exists($ip->ip, $listing)) { - $listing[$ip->ip] = array_merge($listing[$ip->ip], [$ip->port]); - } else { - $listing[$ip->ip] = [$ip->port]; - } - } - - return response()->json($listing); + return Models\Allocation::select('id', 'ip')->where('node_id', $request->input('node'))->whereNull('server_id')->get()->unique('ip')->values()->all(); } /** diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 8f90795c2..1b1079143 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -124,6 +124,12 @@ class UserController extends Controller public function getJson(Request $request) { - return User::select('email')->get()->pluck('email'); + return User::select('id', 'email', 'username', 'name_first', 'name_last') + ->search($request->input('q')) + ->get()->transform(function ($item) { + $item->md5 = md5(strtolower($item->email)); + + return $item; + }); } } diff --git a/app/Http/Middleware/AdminAuthenticate.php b/app/Http/Middleware/AdminAuthenticate.php index c0d74f262..ed286d0b9 100644 --- a/app/Http/Middleware/AdminAuthenticate.php +++ b/app/Http/Middleware/AdminAuthenticate.php @@ -69,9 +69,6 @@ class AdminAuthenticate return abort(403); } - // @TODO: eventually update admin themes - Theme::set('default'); - return $next($request); } } diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index 127055daa..3422088ac 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -136,18 +136,22 @@ class AdminRoutes // Assorted Page Helpers $router->post('/new/get-nodes', [ + 'as' => 'admin.servers.new.get-nodes', 'uses' => 'Admin\ServersController@postNewServerGetNodes', ]); $router->post('/new/get-ips', [ + 'as' => 'admin.servers.new.get-ips', 'uses' => 'Admin\ServersController@postNewServerGetIps', ]); $router->post('/new/service-options', [ + 'as' => 'admin.servers.new.service-options', 'uses' => 'Admin\ServersController@postNewServerServiceOption', ]); $router->post('/new/option-details', [ + 'as' => 'admin.servers.new.option-details', 'uses' => 'Admin\ServersController@postNewServerOptionDetails', ]); // End Assorted Page Helpers diff --git a/app/Models/Server.php b/app/Models/Server.php index 8527e6a14..fa19fda2e 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -29,11 +29,12 @@ use Cache; use Javascript; use Illuminate\Database\Eloquent\Model; use Illuminate\Notifications\Notifiable; +use Nicolaslopezj\Searchable\SearchableTrait; use Illuminate\Database\Eloquent\SoftDeletes; class Server extends Model { - use Notifiable, SoftDeletes; + use Notifiable, SearchableTrait, SoftDeletes; /** * The table associated with the model. @@ -85,6 +86,22 @@ class Server extends Model 'installed' => 'integer', ]; + protected $searchable = [ + 'columns' => [ + 'servers.name' => 10, + 'servers.username' => 10, + 'servers.uuidShort' => 9, + 'servers.uuid' => 8, + 'users.email' => 6, + 'users.username' => 6, + 'nodes.name' => 2, + ], + 'joins' => [ + 'users' => ['users.id', 'servers.owner_id'], + 'nodes' => ['nodes.id', 'servers.node_id'], + ], + ]; + /** * Returns a single server specified by UUID. * DO NOT USE THIS TO MODIFY SERVER DETAILS OR SAVE THOSE DETAILS. diff --git a/app/Models/User.php b/app/Models/User.php index 131192264..b660e304c 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -30,6 +30,7 @@ use Illuminate\Auth\Authenticatable; use Illuminate\Database\Eloquent\Model; use Illuminate\Notifications\Notifiable; use Pterodactyl\Exceptions\DisplayException; +use Nicolaslopezj\Searchable\SearchableTrait; use Illuminate\Auth\Passwords\CanResetPassword; use Illuminate\Foundation\Auth\Access\Authorizable; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; @@ -39,7 +40,7 @@ use Pterodactyl\Notifications\SendPasswordReset as ResetPasswordNotification; class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract { - use Authenticatable, Authorizable, CanResetPassword, Notifiable; + use Authenticatable, Authorizable, CanResetPassword, Notifiable, SearchableTrait; /** * The rules for user passwords. @@ -87,6 +88,16 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac */ protected $hidden = ['password', 'remember_token', 'totp_secret']; + protected $searchable = [ + 'columns' => [ + 'email' => 10, + 'username' => 9, + 'name_first' => 6, + 'name_last' => 6, + 'uuid' => 1, + ], + ]; + /** * Enables or disables TOTP on an account if the token is valid. * diff --git a/composer.json b/composer.json index 40bee8bcb..a95d82df1 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,8 @@ "predis/predis": "1.1.1", "fideloper/proxy": "3.2.0", "laracasts/utilities": "2.1.0", - "lord/laroute": "2.3.0" + "lord/laroute": "2.3.0", + "nicolaslopezj/searchable": "1.9.5" }, "require-dev": { "fzaninotto/faker": "~1.4", diff --git a/composer.lock b/composer.lock index 22e5c4e3b..535af7aa2 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "49714983a18ad2bba4759ccde45314c5", - "content-hash": "af8cd5b69f96dd17c1e02afc1ba8e467", + "hash": "6a9656aff0fb3809d27a2a093a810197", + "content-hash": "8affaad10f155172b5079a72015b8bc5", "packages": [ { "name": "aws/aws-sdk-php", @@ -2011,6 +2011,52 @@ ], "time": "2015-11-04 20:07:17" }, + { + "name": "nicolaslopezj/searchable", + "version": "1.9.5", + "source": { + "type": "git", + "url": "https://github.com/nicolaslopezj/searchable.git", + "reference": "1351b1b21ae9be9e0f49f375f56488df839723d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nicolaslopezj/searchable/zipball/1351b1b21ae9be9e0f49f375f56488df839723d4", + "reference": "1351b1b21ae9be9e0f49f375f56488df839723d4", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "illuminate/database": "4.2.x|~5.0", + "php": ">=5.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Nicolaslopezj\\Searchable\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Lopez", + "email": "nicolaslopezj@me.com" + } + ], + "description": "Eloquent model search trait.", + "keywords": [ + "database", + "eloquent", + "laravel", + "model", + "search", + "searchable" + ], + "time": "2016-12-16 21:23:34" + }, { "name": "nikic/php-parser", "version": "v2.1.1", diff --git a/public/js/laroute.js b/public/js/laroute.js index 633b139f9..350a0c621 100644 --- a/public/js/laroute.js +++ b/public/js/laroute.js @@ -6,7 +6,7 @@ absolute: false, rootUrl: 'http://pterodactyl.app', - routes : [{"host":null,"methods":["GET","HEAD"],"uri":"admin","name":"admin.index","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/settings","name":"admin.settings","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getSettings"},{"host":null,"methods":["POST"],"uri":"admin\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\BaseController@postSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users","name":"admin.users","action":"Pterodactyl\Http\Controllers\Admin\UserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/accounts.json","name":"admin.users.json","action":"Pterodactyl\Http\Controllers\Admin\UserController@getJson"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/view\/{id}","name":"admin.users.view","action":"Pterodactyl\Http\Controllers\Admin\UserController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@updateUser"},{"host":null,"methods":["DELETE"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@deleteUser"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/new","name":"admin.users.new","action":"Pterodactyl\Http\Controllers\Admin\UserController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers","name":"admin.servers","action":"Pterodactyl\Http\Controllers\Admin\ServersController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/new","name":"admin.servers.new","action":"Pterodactyl\Http\Controllers\Admin\ServersController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/get-nodes","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerGetNodes"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/get-ips","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerGetIps"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/service-options","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerServiceOption"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/option-details","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerOptionDetails"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}","name":"admin.servers.view","action":"Pterodactyl\Http\Controllers\Admin\ServersController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/database","name":"admin.servers.database","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postDatabase"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/container","name":"admin.servers.post.container","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateContainerDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/startup","name":"admin.servers.post.startup","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerStartup"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/rebuild","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerToggleBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/build","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerUpdateBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/suspend","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postSuspendServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/unsuspend","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUnsuspendServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/installed","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postToggleInstall"},{"host":null,"methods":["DELETE"],"uri":"admin\/servers\/view\/{id}\/{force?}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@deleteServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/queuedDeletion","name":"admin.servers.post.queuedDeletion","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postQueuedDeletionHandler"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes","name":"admin.nodes","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/new","name":"admin.nodes.new","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.view","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@postView"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/deallocate\/single\/{allocation}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@deallocateSingle"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/deallocate\/block","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@deallocateBlock"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/alias","name":"admin.nodes.alias","action":"Pterodactyl\Http\Controllers\Admin\NodesController@setAlias"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/allocations.json","name":"admin.nodes.view.allocations","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getAllocationsJson"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocations","name":"admin.nodes.post.allocations","action":"Pterodactyl\Http\Controllers\Admin\NodesController@postAllocations"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/deploy","name":"admin.nodes.deply","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getScript"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.delete","action":"Pterodactyl\Http\Controllers\Admin\NodesController@deleteNode"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/{id}\/configurationtoken","name":"admin.nodes.configuration-token","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getConfigurationToken"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/locations","name":"admin.locations","action":"Pterodactyl\Http\Controllers\Admin\LocationsController@getIndex"},{"host":null,"methods":["DELETE"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@deleteLocation"},{"host":null,"methods":["PATCH"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@patchLocation"},{"host":null,"methods":["POST"],"uri":"admin\/locations","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@postLocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases","name":"admin.databases","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases\/new","name":"admin.databases.new","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/databases\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@postNew"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete\/{id}","name":"admin.databases.delete","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteDatabase"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete-server\/{id}","name":"admin.databases.delete-server","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteServer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services","name":"admin.services","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/new","name":"admin.services.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/services\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}","name":"admin.services.service","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getService"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postService"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}\/configuration","name":"admin.services.service.config","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getConfiguration"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}\/configuration","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/new","name":"admin.services.option.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@newOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":"admin.services.option","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOption"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{service}\/option\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":"admin.services.option.variable.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}","name":"admin.services.option.variable","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOptionVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}\/delete","name":"admin.services.option.variable.delete","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/new\/{option?}","name":"admin.services.packs.new","action":"Pterodactyl\Http\Controllers\Admin\PackController@new"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/upload\/{option?}","name":"admin.services.packs.uploadForm","action":"Pterodactyl\Http\Controllers\Admin\PackController@uploadForm"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/upload","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@postUpload"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs","name":"admin.services.packs","action":"Pterodactyl\Http\Controllers\Admin\PackController@listAll"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/option\/{option}","name":"admin.services.packs.option","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/service\/{service}","name":"admin.services.packs.service","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}","name":"admin.services.packs.edit","action":"Pterodactyl\Http\Controllers\Admin\PackController@edit"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/edit\/{pack}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}\/export\/{archive?}","name":"admin.services.packs.export","action":"Pterodactyl\Http\Controllers\Admin\PackController@export"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login","name":"auth.login","action":"Pterodactyl\Http\Controllers\Auth\LoginController@showLoginForm"},{"host":null,"methods":["POST"],"uri":"auth\/login","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@login"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login\/totp","name":"auth.totp","action":"Pterodactyl\Http\Controllers\Auth\LoginController@totp"},{"host":null,"methods":["POST"],"uri":"auth\/login\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@totpCheckpoint"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password","name":"auth.password","action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm"},{"host":null,"methods":["POST"],"uri":"auth\/password","name":null,"action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password\/reset\/{token}","name":"auth.reset","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@showResetForm"},{"host":null,"methods":["POST"],"uri":"auth\/password\/reset","name":"auth.reset.post","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@reset"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/logout","name":"auth.logout","action":"Pterodactyl\Http\Controllers\Auth\LoginController@logout"},{"host":null,"methods":["GET","HEAD"],"uri":"\/","name":"index","action":"Pterodactyl\Http\Controllers\Base\IndexController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"index","name":null,"action":"Closure"},{"host":null,"methods":["GET","HEAD"],"uri":"password-gen\/{length}","name":"password-gen","action":"Pterodactyl\Http\Controllers\Base\IndexController@getPassword"},{"host":null,"methods":["GET","HEAD"],"uri":"account","name":"account","action":"Pterodactyl\Http\Controllers\Base\AccountController@index"},{"host":null,"methods":["POST"],"uri":"account","name":null,"action":"Pterodactyl\Http\Controllers\Base\AccountController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api","name":"account.api","action":"Pterodactyl\Http\Controllers\Base\APIController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api\/new","name":"account.api.new","action":"Pterodactyl\Http\Controllers\Base\APIController@create"},{"host":null,"methods":["POST"],"uri":"account\/api\/new","name":null,"action":"Pterodactyl\Http\Controllers\Base\APIController@save"},{"host":null,"methods":["DELETE"],"uri":"account\/api\/revoke\/{key}","name":"account.api.revoke","action":"Pterodactyl\Http\Controllers\Base\APIController@revoke"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security","name":"account.security","action":"Pterodactyl\Http\Controllers\Base\SecurityController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security\/revoke\/{id}","name":"account.security.revoke","action":"Pterodactyl\Http\Controllers\Base\SecurityController@revoke"},{"host":null,"methods":["PUT"],"uri":"account\/security\/totp","name":"account.security.totp","action":"Pterodactyl\Http\Controllers\Base\SecurityController@generateTotp"},{"host":null,"methods":["POST"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@setTotp"},{"host":null,"methods":["DELETE"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@disableTotp"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services","name":"daemon.services","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@list"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services\/pull\/{service}\/{file}","name":"remote.install","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}","name":"daemon.pack.pull","action":"Pterodactyl\Http\Controllers\Daemon\PackController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}\/hash","name":"daemon.pack.hash","action":"Pterodactyl\Http\Controllers\Daemon\PackController@hash"},{"host":null,"methods":["GET","HEAD"],"uri":"language\/{lang}","name":"langauge.set","action":"Pterodactyl\Http\Controllers\Base\LanguageController@setLanguage"},{"host":null,"methods":["POST"],"uri":"remote\/download","name":"remote.download","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postDownload"},{"host":null,"methods":["POST"],"uri":"remote\/install","name":"remote.install","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postInstall"},{"host":null,"methods":["GET","HEAD"],"uri":"remote\/configuration\/{token}","name":"remote.configuration","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@getConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}","name":"server.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/databases","name":"server.settings.databases","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDatabases"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/sftp","name":"server.settings.sftp","action":"Pterodactyl\Http\Controllers\Server\ServerController@getSFTP"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/sftp","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsSFTP"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/startup","name":"server.settings.startup","action":"Pterodactyl\Http\Controllers\Server\ServerController@getStartup"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/allocation","name":"server.settings.allocation","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files","name":"server.files.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getFiles"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/edit\/{file}","name":"server.files.edit","action":"Pterodactyl\Http\Controllers\Server\ServerController@getEditFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/download\/{file}","name":"server.files.download","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDownloadFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/add","name":"server.files.add","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAddFile"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/directory-list","name":"server.files.directory-list","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postDirectoryList"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/save","name":"server.files.save","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSaveFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users","name":"server.subusers","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/new","name":"server.subusers.new","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/view\/{id}","name":"server.subusers.view","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getView"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postView"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/users\/delete\/{id}","name":"server.subusers.delete","action":"Pterodactyl\Http\Controllers\Server\SubuserController@deleteSubuser"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks","name":"server.tasks","action":"Pterodactyl\Http\Controllers\Server\TaskController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/view\/{id}","name":"server.tasks.view","action":"Pterodactyl\Http\Controllers\Server\TaskController@getView"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/new","name":"server.tasks.new","action":"Pterodactyl\Http\Controllers\Server\TaskController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\TaskController@postNew"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/tasks\/delete\/{id}","name":"server.tasks.delete","action":"Pterodactyl\Http\Controllers\Server\TaskController@deleteTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/toggle\/{id}","name":"server.tasks.toggle","action":"Pterodactyl\Http\Controllers\Server\TaskController@toggleTask"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/ajax\/status","name":"server.ajax.status","action":"Pterodactyl\Http\Controllers\Server\AjaxController@getStatus"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/set-primary","name":null,"action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSetPrimary"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/settings\/reset-database-password","name":"server.ajax.reset-database-password","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postResetDatabasePassword"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/open","name":"debugbar.openhandler","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@handle"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/clockwork\/{id}","name":"debugbar.clockwork","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@clockwork"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/stylesheets","name":"debugbar.assets.css","action":"Barryvdh\Debugbar\Controllers\AssetController@css"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/javascript","name":"debugbar.assets.js","action":"Barryvdh\Debugbar\Controllers\AssetController@js"}], + routes : [{"host":null,"methods":["GET","HEAD"],"uri":"admin","name":"admin.index","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/settings","name":"admin.settings","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getSettings"},{"host":null,"methods":["POST"],"uri":"admin\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\BaseController@postSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users","name":"admin.users","action":"Pterodactyl\Http\Controllers\Admin\UserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/accounts.json","name":"admin.users.json","action":"Pterodactyl\Http\Controllers\Admin\UserController@getJson"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/view\/{id}","name":"admin.users.view","action":"Pterodactyl\Http\Controllers\Admin\UserController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@updateUser"},{"host":null,"methods":["DELETE"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@deleteUser"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/new","name":"admin.users.new","action":"Pterodactyl\Http\Controllers\Admin\UserController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers","name":"admin.servers","action":"Pterodactyl\Http\Controllers\Admin\ServersController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/new","name":"admin.servers.new","action":"Pterodactyl\Http\Controllers\Admin\ServersController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/get-nodes","name":"admin.servers.new.get-nodes","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerGetNodes"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/get-ips","name":"admin.servers.new.get-ips","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerGetIps"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/service-options","name":"admin.servers.new.service-options","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerServiceOption"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/option-details","name":"admin.servers.new.option-details","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerOptionDetails"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}","name":"admin.servers.view","action":"Pterodactyl\Http\Controllers\Admin\ServersController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/database","name":"admin.servers.database","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postDatabase"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/container","name":"admin.servers.post.container","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateContainerDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/startup","name":"admin.servers.post.startup","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerStartup"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/rebuild","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerToggleBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/build","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerUpdateBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/suspend","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postSuspendServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/unsuspend","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUnsuspendServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/installed","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postToggleInstall"},{"host":null,"methods":["DELETE"],"uri":"admin\/servers\/view\/{id}\/{force?}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@deleteServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/queuedDeletion","name":"admin.servers.post.queuedDeletion","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postQueuedDeletionHandler"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes","name":"admin.nodes","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/new","name":"admin.nodes.new","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.view","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@postView"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/deallocate\/single\/{allocation}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@deallocateSingle"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/deallocate\/block","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@deallocateBlock"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/alias","name":"admin.nodes.alias","action":"Pterodactyl\Http\Controllers\Admin\NodesController@setAlias"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/allocations.json","name":"admin.nodes.view.allocations","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getAllocationsJson"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocations","name":"admin.nodes.post.allocations","action":"Pterodactyl\Http\Controllers\Admin\NodesController@postAllocations"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/deploy","name":"admin.nodes.deply","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getScript"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.delete","action":"Pterodactyl\Http\Controllers\Admin\NodesController@deleteNode"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/{id}\/configurationtoken","name":"admin.nodes.configuration-token","action":"Pterodactyl\Http\Controllers\Admin\NodesController@getConfigurationToken"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/locations","name":"admin.locations","action":"Pterodactyl\Http\Controllers\Admin\LocationsController@getIndex"},{"host":null,"methods":["DELETE"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@deleteLocation"},{"host":null,"methods":["PATCH"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@patchLocation"},{"host":null,"methods":["POST"],"uri":"admin\/locations","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@postLocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases","name":"admin.databases","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases\/new","name":"admin.databases.new","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/databases\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@postNew"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete\/{id}","name":"admin.databases.delete","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteDatabase"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete-server\/{id}","name":"admin.databases.delete-server","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteServer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services","name":"admin.services","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/new","name":"admin.services.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/services\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}","name":"admin.services.service","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getService"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postService"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}\/configuration","name":"admin.services.service.config","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getConfiguration"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}\/configuration","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/new","name":"admin.services.option.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@newOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":"admin.services.option","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOption"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{service}\/option\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":"admin.services.option.variable.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}","name":"admin.services.option.variable","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOptionVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}\/delete","name":"admin.services.option.variable.delete","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/new\/{option?}","name":"admin.services.packs.new","action":"Pterodactyl\Http\Controllers\Admin\PackController@new"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/upload\/{option?}","name":"admin.services.packs.uploadForm","action":"Pterodactyl\Http\Controllers\Admin\PackController@uploadForm"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/upload","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@postUpload"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs","name":"admin.services.packs","action":"Pterodactyl\Http\Controllers\Admin\PackController@listAll"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/option\/{option}","name":"admin.services.packs.option","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/service\/{service}","name":"admin.services.packs.service","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}","name":"admin.services.packs.edit","action":"Pterodactyl\Http\Controllers\Admin\PackController@edit"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/edit\/{pack}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}\/export\/{archive?}","name":"admin.services.packs.export","action":"Pterodactyl\Http\Controllers\Admin\PackController@export"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login","name":"auth.login","action":"Pterodactyl\Http\Controllers\Auth\LoginController@showLoginForm"},{"host":null,"methods":["POST"],"uri":"auth\/login","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@login"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login\/totp","name":"auth.totp","action":"Pterodactyl\Http\Controllers\Auth\LoginController@totp"},{"host":null,"methods":["POST"],"uri":"auth\/login\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@totpCheckpoint"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password","name":"auth.password","action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm"},{"host":null,"methods":["POST"],"uri":"auth\/password","name":null,"action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password\/reset\/{token}","name":"auth.reset","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@showResetForm"},{"host":null,"methods":["POST"],"uri":"auth\/password\/reset","name":"auth.reset.post","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@reset"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/logout","name":"auth.logout","action":"Pterodactyl\Http\Controllers\Auth\LoginController@logout"},{"host":null,"methods":["GET","HEAD"],"uri":"\/","name":"index","action":"Pterodactyl\Http\Controllers\Base\IndexController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"index","name":null,"action":"Closure"},{"host":null,"methods":["GET","HEAD"],"uri":"password-gen\/{length}","name":"password-gen","action":"Pterodactyl\Http\Controllers\Base\IndexController@getPassword"},{"host":null,"methods":["GET","HEAD"],"uri":"account","name":"account","action":"Pterodactyl\Http\Controllers\Base\AccountController@index"},{"host":null,"methods":["POST"],"uri":"account","name":null,"action":"Pterodactyl\Http\Controllers\Base\AccountController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api","name":"account.api","action":"Pterodactyl\Http\Controllers\Base\APIController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api\/new","name":"account.api.new","action":"Pterodactyl\Http\Controllers\Base\APIController@create"},{"host":null,"methods":["POST"],"uri":"account\/api\/new","name":null,"action":"Pterodactyl\Http\Controllers\Base\APIController@save"},{"host":null,"methods":["DELETE"],"uri":"account\/api\/revoke\/{key}","name":"account.api.revoke","action":"Pterodactyl\Http\Controllers\Base\APIController@revoke"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security","name":"account.security","action":"Pterodactyl\Http\Controllers\Base\SecurityController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security\/revoke\/{id}","name":"account.security.revoke","action":"Pterodactyl\Http\Controllers\Base\SecurityController@revoke"},{"host":null,"methods":["PUT"],"uri":"account\/security\/totp","name":"account.security.totp","action":"Pterodactyl\Http\Controllers\Base\SecurityController@generateTotp"},{"host":null,"methods":["POST"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@setTotp"},{"host":null,"methods":["DELETE"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@disableTotp"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services","name":"daemon.services","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@list"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services\/pull\/{service}\/{file}","name":"remote.install","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}","name":"daemon.pack.pull","action":"Pterodactyl\Http\Controllers\Daemon\PackController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}\/hash","name":"daemon.pack.hash","action":"Pterodactyl\Http\Controllers\Daemon\PackController@hash"},{"host":null,"methods":["GET","HEAD"],"uri":"language\/{lang}","name":"langauge.set","action":"Pterodactyl\Http\Controllers\Base\LanguageController@setLanguage"},{"host":null,"methods":["POST"],"uri":"remote\/download","name":"remote.download","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postDownload"},{"host":null,"methods":["POST"],"uri":"remote\/install","name":"remote.install","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postInstall"},{"host":null,"methods":["GET","HEAD"],"uri":"remote\/configuration\/{token}","name":"remote.configuration","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@getConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/ajax\/status","name":"server.ajax.status","action":"Pterodactyl\Http\Controllers\Server\AjaxController@getStatus"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}","name":"server.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/databases","name":"server.settings.databases","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDatabases"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/sftp","name":"server.settings.sftp","action":"Pterodactyl\Http\Controllers\Server\ServerController@getSFTP"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/sftp","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsSFTP"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/startup","name":"server.settings.startup","action":"Pterodactyl\Http\Controllers\Server\ServerController@getStartup"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/allocation","name":"server.settings.allocation","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files","name":"server.files.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getFiles"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/edit\/{file}","name":"server.files.edit","action":"Pterodactyl\Http\Controllers\Server\ServerController@getEditFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/download\/{file}","name":"server.files.download","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDownloadFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/add","name":"server.files.add","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAddFile"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/directory-list","name":"server.files.directory-list","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postDirectoryList"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/save","name":"server.files.save","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSaveFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users","name":"server.subusers","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/new","name":"server.subusers.new","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/view\/{id}","name":"server.subusers.view","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getView"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postView"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/users\/delete\/{id}","name":"server.subusers.delete","action":"Pterodactyl\Http\Controllers\Server\SubuserController@deleteSubuser"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks","name":"server.tasks","action":"Pterodactyl\Http\Controllers\Server\TaskController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/view\/{id}","name":"server.tasks.view","action":"Pterodactyl\Http\Controllers\Server\TaskController@getView"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/new","name":"server.tasks.new","action":"Pterodactyl\Http\Controllers\Server\TaskController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\TaskController@postNew"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/tasks\/delete\/{id}","name":"server.tasks.delete","action":"Pterodactyl\Http\Controllers\Server\TaskController@deleteTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/toggle\/{id}","name":"server.tasks.toggle","action":"Pterodactyl\Http\Controllers\Server\TaskController@toggleTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/set-primary","name":null,"action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSetPrimary"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/settings\/reset-database-password","name":"server.ajax.reset-database-password","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postResetDatabasePassword"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/open","name":"debugbar.openhandler","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@handle"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/clockwork\/{id}","name":"debugbar.clockwork","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@clockwork"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/stylesheets","name":"debugbar.assets.css","action":"Barryvdh\Debugbar\Controllers\AssetController@css"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/javascript","name":"debugbar.assets.js","action":"Barryvdh\Debugbar\Controllers\AssetController@js"}], prefix: '', route : function (name, parameters, route) { diff --git a/public/themes/pterodactyl/css/pterodactyl.css b/public/themes/pterodactyl/css/pterodactyl.css index 342b993b9..13e50047b 100644 --- a/public/themes/pterodactyl/css/pterodactyl.css +++ b/public/themes/pterodactyl/css/pterodactyl.css @@ -132,3 +132,20 @@ td.has-progress { .no-margin { margin: 0 !important; } + +li.select2-results__option--highlighted[aria-selected="false"] > .user-block > .username > a { + color: #fff; +} + +li.select2-results__option--highlighted[aria-selected="false"] > .user-block > .description { + color: #eee; +} + +.img-bordered-xs { + border: 1px solid #d2d6de; + padding: 1px; +} + +span[aria-labelledby="select2-pOwner-container"] { + padding-left: 2px !important; +} diff --git a/resources/themes/pterodactyl/admin/index.blade.php b/resources/themes/pterodactyl/admin/index.blade.php new file mode 100644 index 000000000..0385837af --- /dev/null +++ b/resources/themes/pterodactyl/admin/index.blade.php @@ -0,0 +1,71 @@ +{{-- 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') + Administration +@endsection + +@section('content-header') +

      Administrative OverviewA quick glance at your system.

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

      System Information

      +
      +
      + @if (Version::isLatestPanel()) + You are running Pterodactyl Panel version {{ Version::getCurrentPanel() }}. Your panel is up-to-date! + @else + Your panel is not up-to-date! The latest version is {{ Version::getPanel() }} and you are currently running version {{ Version::getCurrentPanel() }}. + @endif +
      +
      +
      +
      + +@endsection diff --git a/resources/themes/pterodactyl/admin/servers/index.blade.php b/resources/themes/pterodactyl/admin/servers/index.blade.php new file mode 100644 index 000000000..a9c6deb83 --- /dev/null +++ b/resources/themes/pterodactyl/admin/servers/index.blade.php @@ -0,0 +1,94 @@ +{{-- 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') + List Servers +@endsection + +@section('content-header') +

      ServersAll servers available on the system.

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

      Server List

      +
      + +
      + +
      + + +
      +
      + +
      +
      +
      + + + + + + + + + + + @foreach ($servers as $server) + + + + + + + + + @endforeach + +
      IDServer NameOwnerNodeConnection
      {{ $server->uuidShort }}{{ $server->name }}{{ $server->user->email }}{{ $server->node->name }} + {{ $server->allocation->alias }}:{{ $server->allocation->port }} + + @if($server->suspended && ! $server->trashed()) + Suspended + @elseif($server->trashed()) + Pending Deletion + @elseif(! $server->installed) + Installing + @else + Active + @endif +
      +
      + +
      +
      +
      +@endsection diff --git a/resources/themes/pterodactyl/admin/servers/new.blade.php b/resources/themes/pterodactyl/admin/servers/new.blade.php new file mode 100644 index 000000000..84e45dfa9 --- /dev/null +++ b/resources/themes/pterodactyl/admin/servers/new.blade.php @@ -0,0 +1,230 @@ +{{-- 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') + 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] (max 200 characters).

      +
      +
      + + +
      +
      +
      +
      +
      +
      +
      +
      + +
      +

      Allocation Management

      +
      +
      +
      + + +

      The location in which this server will be deployed.

      +
      +
      + + +

      The node which this server will be deployed to.

      +
      +
      + + +

      The IP address that this server will be allocated to.

      +
      +
      + + +

      The port that this server will be allocated to.

      +
      +
      + +
      +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/themes/pterodactyl/layouts/admin.blade.php b/resources/themes/pterodactyl/layouts/admin.blade.php new file mode 100644 index 000000000..b3cff34e3 --- /dev/null +++ b/resources/themes/pterodactyl/layouts/admin.blade.php @@ -0,0 +1,198 @@ +{{-- 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. --}} + + + + + + {{ Settings::get('company', 'Pterodactyl') }} - @yield('title') + + + @section('scripts') + {!! Theme::css('vendor/select2/select2.min.css') !!} + {!! Theme::css('vendor/bootstrap/bootstrap.min.css') !!} + {!! Theme::css('vendor/adminlte/admin.min.css') !!} + {!! Theme::css('vendor/adminlte/colors/skin-blue.min.css') !!} + {!! Theme::css('vendor/sweetalert/sweetalert.min.css') !!} + {!! Theme::css('vendor/animate/animate.min.css') !!} + {!! Theme::css('css/pterodactyl.css') !!} + + + + + @show + + +
      +
      + + +
      + +
      +
      + @yield('content-header') +
      +
      +
      +
      + @if (count($errors) > 0) +
      + @lang('base.validation_error')

      +
        + @foreach ($errors->all() as $error) +
      • {{ $error }}
      • + @endforeach +
      +
      + @endif + @foreach (Alert::getMessages() as $type => $messages) + @foreach ($messages as $message) + + @endforeach + @endforeach +
      +
      + @yield('content') +
      +
      + + +
      +
      + @section('footer-scripts') + {!! Theme::js('js/laroute.js') !!} + {!! Theme::js('js/vendor/jquery/jquery.min.js') !!} + {!! Theme::js('vendor/sweetalert/sweetalert.min.js') !!} + {!! Theme::js('vendor/bootstrap/bootstrap.min.js') !!} + {!! Theme::js('vendor/slimscroll/jquery.slimscroll.min.js') !!} + {!! Theme::js('vendor/adminlte/app.min.js') !!} + {!! Theme::js('js/vendor/socketio/socket.io.min.js') !!} + {!! Theme::js('vendor/bootstrap-notify/bootstrap-notify.min.js') !!} + {!! Theme::js('vendor/select2/select2.full.min.js') !!} + @show + + diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index ce881ada5..b7a7696d1 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -62,14 +62,14 @@ +
    • + +
    • @if(Auth::user()->isRootAdmin())
    • @endif -
    • - -
    • From f91e4c511ec7061050f41997674d9d83dda11b1b Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Feb 2017 21:45:11 -0500 Subject: [PATCH 274/599] Attach user to cache to prevent showing servers they can't access. --- CHANGELOG.md | 4 ++++ app/Models/Server.php | 2 +- app/Observers/ServerObserver.php | 5 +++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c186e143..d90ec523e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ This file is a running track of new features and fixes to each version of the pa This project follows [Semantic Versioning](http://semver.org) guidelines. +## v0.6.0-pre.4 (Courageous Carniadactylus) +### Fixed +* `[pre.3]` — Fixes bug in cache handler that doesn't cache against the user making the request. Would have allowed for users to access servers not belonging to themselves in production. + ## v0.6.0-pre.3 (Courageous Carniadactylus) ### Fixed * `[pre.2]` — Fixes bug where servers could not be manually deployed to nodes due to a broken SQL call. diff --git a/app/Models/Server.php b/app/Models/Server.php index 8527e6a14..7c69c763f 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -96,7 +96,7 @@ class Server extends Model public static function byUuid($uuid) { // Results are cached because we call this functions a few times on page load. - $result = Cache::remember('Server.byUuid.' . $uuid, 60, function () use ($uuid) { + $result = Cache::remember('Server.byUuid.' . $uuid . Auth::user()->uuid, 60, function () use ($uuid) { $query = self::with('service', 'node')->where(function ($q) use ($uuid) { $q->where('uuidShort', $uuid)->orWhere('uuid', $uuid); }); diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php index 556d1c165..5d919a559 100644 --- a/app/Observers/ServerObserver.php +++ b/app/Observers/ServerObserver.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Observers; +use Auth; use Cache; use Carbon; use Pterodactyl\Events; @@ -141,8 +142,8 @@ class ServerObserver public function updated(Server $server) { // Clear Caches - Cache::forget('Server.byUuid.' . $server->uuid); - Cache::forget('Server.byUuid.' . $server->uuidShort); + Cache::forget('Server.byUuid.' . $server->uuid . Auth::user()->uuid); + Cache::forget('Server.byUuid.' . $server->uuidShort . Auth::user()->uuid); event(new Events\Server\Updated($server)); } From efdc3e6fd8f43165bb694cf8987b57baac0c3087 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Feb 2017 22:26:07 -0500 Subject: [PATCH 275/599] Add cache policy for ServerPolicy 10 second cache, just long enough to handle the page load without making more than one MySQL call. --- CHANGELOG.md | 3 +++ app/Policies/ServerPolicy.php | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d90ec523e..82fc3ecfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Fixed * `[pre.3]` — Fixes bug in cache handler that doesn't cache against the user making the request. Would have allowed for users to access servers not belonging to themselves in production. +### Added +* New cache policy for ServerPolicy to avoid making 15+ queries per page load when confirming if a user has permission to perform an action. + ## v0.6.0-pre.3 (Courageous Carniadactylus) ### Fixed * `[pre.2]` — Fixes bug where servers could not be manually deployed to nodes due to a broken SQL call. diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php index d67f3aced..adb4f3850 100644 --- a/app/Policies/ServerPolicy.php +++ b/app/Policies/ServerPolicy.php @@ -24,11 +24,14 @@ namespace Pterodactyl\Policies; +use Cache; +use Carbon; use Pterodactyl\Models\User; use Pterodactyl\Models\Server; class ServerPolicy { + /** * Create a new policy instance. * @@ -53,7 +56,13 @@ class ServerPolicy return true; } - return $user->permissions()->server($server)->permission($permission)->exists(); + $permissions = Cache::remember('ServerPolicy.' . $user->uuid . $server->uuid, Carbon::now()->addSeconds(10), function () use ($user, $server) { + return $user->permissions()->server($server)->get()->transform(function ($item) { + return $item->permission; + })->values(); + }); + + return ($permissions->search($permission, true) !== false); } /** From 644c07ea3a847747c3f121e10adeec9a1de2b706 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Feb 2017 22:32:16 -0500 Subject: [PATCH 276/599] Fix broken port deletion --- CHANGELOG.md | 1 + app/Http/Controllers/Admin/NodesController.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82fc3ecfe..e88c0ec6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ## v0.6.0-pre.4 (Courageous Carniadactylus) ### Fixed * `[pre.3]` — Fixes bug in cache handler that doesn't cache against the user making the request. Would have allowed for users to access servers not belonging to themselves in production. +* `[pre.3]` — Fixes misnamed MySQL column that was causing the inability to delete certain port ranges from the database. ### Added * New cache policy for ServerPolicy to avoid making 15+ queries per page load when confirming if a user has permission to perform an action. diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index f4a60b5b2..877c44995 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -163,7 +163,7 @@ class NodesController extends Controller public function deallocateBlock(Request $request, $node) { - $query = Models\Allocation::where('node', $node)->whereNull('server_id')->where('ip', $request->input('ip'))->delete(); + $query = Models\Allocation::where('node_id', $node)->whereNull('server_id')->where('ip', $request->input('ip'))->delete(); if ((int) $query === 0) { Alert::danger('There was an error while attempting to delete allocations on that IP.')->flash(); @@ -199,7 +199,7 @@ class NodesController extends Controller public function getAllocationsJson(Request $request, $id) { - $allocations = Models\Allocation::select('ip')->where('node', $id)->groupBy('ip')->get(); + $allocations = Models\Allocation::select('ip')->where('node_id', $id)->groupBy('ip')->get(); return response()->json($allocations); } From ed4068bdb9038d72e27158e5ba89cb62d837e5ed Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Feb 2017 22:33:15 -0500 Subject: [PATCH 277/599] Fix bug preventing server container rebuilds. --- CHANGELOG.md | 1 + app/Http/Controllers/Admin/ServersController.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e88c0ec6d..8b856fd7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Fixed * `[pre.3]` — Fixes bug in cache handler that doesn't cache against the user making the request. Would have allowed for users to access servers not belonging to themselves in production. * `[pre.3]` — Fixes misnamed MySQL column that was causing the inability to delete certain port ranges from the database. +* `[pre.3]` — Fixes bug preventing rebuilding server containers through the Admin CP. ### Added * New cache policy for ServerPolicy to avoid making 15+ queries per page load when confirming if a user has permission to perform an action. diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 0f5cf495d..017dc1fcc 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -251,7 +251,7 @@ class ServersController extends Controller try { $res = $server->node->guzzleClient([ 'X-Access-Server' => $server->uuid, - 'X-Access-Token' => $node->daemonSecret, + 'X-Access-Token' => $server->node->daemonSecret, ])->request('POST', '/server/rebuild'); Alert::success('A rebuild has been queued successfully. It will run the next time this server is booted.')->flash(); } catch (\GuzzleHttp\Exception\TransferException $ex) { From b11029a666b0491c600811f34fcd7deba6139cee Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Feb 2017 22:57:50 -0500 Subject: [PATCH 278/599] Apply fixes from StyleCI (#312) * Bump for release * Apply fixes from StyleCI --- app/Http/Controllers/Base/APIController.php | 1 + app/Policies/ServerPolicy.php | 3 +-- app/Repositories/APIRepository.php | 2 +- app/Repositories/Daemon/CommandRepository.php | 1 - app/Repositories/Daemon/PowerRepository.php | 1 - app/Repositories/ServerRepository.php | 4 ++-- app/Repositories/UserRepository.php | 5 ++--- config/app.php | 2 +- 8 files changed, 8 insertions(+), 11 deletions(-) diff --git a/app/Http/Controllers/Base/APIController.php b/app/Http/Controllers/Base/APIController.php index e80f07033..68045a722 100644 --- a/app/Http/Controllers/Base/APIController.php +++ b/app/Http/Controllers/Base/APIController.php @@ -80,6 +80,7 @@ class APIController extends Controller return response('', 204); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ 'error' => 'An error occured while attempting to remove this key.', ], 503); diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php index adb4f3850..767dec13c 100644 --- a/app/Policies/ServerPolicy.php +++ b/app/Policies/ServerPolicy.php @@ -31,7 +31,6 @@ use Pterodactyl\Models\Server; class ServerPolicy { - /** * Create a new policy instance. * @@ -62,7 +61,7 @@ class ServerPolicy })->values(); }); - return ($permissions->search($permission, true) !== false); + return $permissions->search($permission, true) !== false; } /** diff --git a/app/Repositories/APIRepository.php b/app/Repositories/APIRepository.php index c18f1f993..5f148eda6 100644 --- a/app/Repositories/APIRepository.php +++ b/app/Repositories/APIRepository.php @@ -225,7 +225,7 @@ class APIRepository try { $model = Models\APIKey::with('permissions')->where('public', $key)->where('user_id', $this->user->id)->firstOrFail(); - foreach($model->permissions as &$permission) { + foreach ($model->permissions as &$permission) { $permission->delete(); } diff --git a/app/Repositories/Daemon/CommandRepository.php b/app/Repositories/Daemon/CommandRepository.php index 1905478e7..76ac93178 100644 --- a/app/Repositories/Daemon/CommandRepository.php +++ b/app/Repositories/Daemon/CommandRepository.php @@ -24,7 +24,6 @@ namespace Pterodactyl\Repositories\Daemon; -use GuzzleHttp\Client; use Pterodactyl\Models; use GuzzleHttp\Exception\RequestException; use Pterodactyl\Exceptions\DisplayException; diff --git a/app/Repositories/Daemon/PowerRepository.php b/app/Repositories/Daemon/PowerRepository.php index d43ec1a7d..b31c0cda0 100644 --- a/app/Repositories/Daemon/PowerRepository.php +++ b/app/Repositories/Daemon/PowerRepository.php @@ -24,7 +24,6 @@ namespace Pterodactyl\Repositories\Daemon; -use GuzzleHttp\Client; use Pterodactyl\Models; use Pterodactyl\Exceptions\DisplayException; diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index b6047739d..4b5ed1f15 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -791,8 +791,8 @@ class ServerRepository Models\ServerVariable::where('server_id', $server->id)->delete(); // Remove SubUsers - foreach(Models\Subuser::with('permissions')->where('server_id', $server->id)->get() as &$subuser) { - foreach($subuser->permissions as &$permission) { + foreach (Models\Subuser::with('permissions')->where('server_id', $server->id)->get() as &$subuser) { + foreach ($subuser->permissions as &$permission) { $permission->delete(); } $subuser->delete(); diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index c59637783..e9cd8580f 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -34,7 +34,6 @@ use Validator; use Pterodactyl\Models; use Pterodactyl\Services\UuidService; use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Notifications\AccountCreated; use Pterodactyl\Exceptions\DisplayValidationException; class UserRepository @@ -177,8 +176,8 @@ class UserRepository DB::beginTransaction(); try { - foreach(Models\Subuser::with('permissions')->where('user_id', $id)->get() as &$subuser) { - foreach($subuser->permissions as &$permission) { + foreach (Models\Subuser::with('permissions')->where('user_id', $id)->get() as &$subuser) { + foreach ($subuser->permissions as &$permission) { $permission->delete(); } diff --git a/config/app.php b/config/app.php index 622098a9b..e6b955156 100644 --- a/config/app.php +++ b/config/app.php @@ -4,7 +4,7 @@ return [ 'env' => env('APP_ENV', 'production'), - 'version' => env('APP_VERSION', 'canary'), + 'version' => env('APP_VERSION', '0.6.0-pre.4'), 'phrase_in_context' => env('PHRASE_IN_CONTEXT', false), From b82c67424ff9ed510467cab546213146e1f348f3 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Feb 2017 22:59:08 -0500 Subject: [PATCH 279/599] Slow ya roll StyleCI... --- config/app.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/app.php b/config/app.php index e6b955156..622098a9b 100644 --- a/config/app.php +++ b/config/app.php @@ -4,7 +4,7 @@ return [ 'env' => env('APP_ENV', 'production'), - 'version' => env('APP_VERSION', '0.6.0-pre.4'), + 'version' => env('APP_VERSION', 'canary'), 'phrase_in_context' => env('PHRASE_IN_CONTEXT', false), From 58999913ba38b89ac9cb7c39ed3ba797abeb942d Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 23 Feb 2017 22:52:05 -0500 Subject: [PATCH 280/599] More improvements to add server page. --- .../Controllers/Admin/ServersController.php | 8 +- public/themes/pterodactyl/css/pterodactyl.css | 51 +++++- .../pterodactyl/admin/servers/new.blade.php | 165 ++++++++++++------ 3 files changed, 164 insertions(+), 60 deletions(-) diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 195a66314..ba4e5d1cb 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -120,13 +120,13 @@ class ServersController extends Controller $nodes = Models\Node::with('allocations')->where('location_id', $request->input('location'))->get(); return $nodes->map(function ($item) { $filtered = $item->allocations->map(function($map) { - return collect($map)->only(['ip', 'port']); + return collect($map)->only(['id', 'ip', 'port']); }); - $item->ports = $filtered->unique('ip')->map(function ($map) use ($item) { + $item->ports = $filtered->map(function ($map) use ($item) { return [ - 'ip' => $map['ip'], - 'ports' => $item->allocations->where('ip', $map['ip'])->pluck('port')->all(), + 'id' => $map['id'], + 'text' => $map['ip'] . ':' . $map['port'], ]; })->values(); diff --git a/public/themes/pterodactyl/css/pterodactyl.css b/public/themes/pterodactyl/css/pterodactyl.css index 13e50047b..4a3fe3bf2 100644 --- a/public/themes/pterodactyl/css/pterodactyl.css +++ b/public/themes/pterodactyl/css/pterodactyl.css @@ -141,11 +141,60 @@ li.select2-results__option--highlighted[aria-selected="false"] > .user-block > . color: #eee; } +.select2-search--inline .select2-search__field:focus { + outline: none; + border: 0 !important; +} + .img-bordered-xs { border: 1px solid #d2d6de; padding: 1px; } -span[aria-labelledby="select2-pOwner-container"] { +span[aria-labelledby="select2-pUserId-container"] { padding-left: 2px !important; } + +.callout-slim a { + color: #555 !important; +} + +.callout.callout-info.callout-slim { + border: 1px solid #0097bc !important; + border-left: 5px solid #0097bc !important; + border-right: 5px solid #0097bc !important; + color: #777 !important; + background: transparent !important; +} + +.callout.callout-danger.callout-slim { + border: 1px solid #c23321 !important; + border-left: 5px solid #c23321 !important; + border-right: 5px solid #c23321 !important; + color: #777 !important; + background: transparent !important; +} + +.callout.callout-warning.callout-slim { + border: 1px solid #c87f0a !important; + border-left: 5px solid #c87f0a !important; + border-right: 5px solid #c87f0a !important; + color: #777 !important; + background: transparent !important; +} + +.callout.callout-success.callout-slim { + border: 1px solid #00733e !important; + border-left: 5px solid #00733e !important; + border-right: 5px solid #00733e !important; + color: #777 !important; + background: transparent !important; +} + +.callout.callout-default.callout-slim { + border: 1px solid #eee !important; + border-left: 5px solid #eee !important; + border-right: 5px solid #eee !important; + color: #777 !important; + background: transparent !important; +} diff --git a/resources/themes/pterodactyl/admin/servers/new.blade.php b/resources/themes/pterodactyl/admin/servers/new.blade.php index 84e45dfa9..ad9256e33 100644 --- a/resources/themes/pterodactyl/admin/servers/new.blade.php +++ b/resources/themes/pterodactyl/admin/servers/new.blade.php @@ -36,7 +36,7 @@
      -
      +

      Core Details

      @@ -62,36 +62,29 @@

      Allocation Management

      -
      +

      The location in which this server will be deployed.

      -
      +
      - +

      The node which this server will be deployed to.

      -
      - - -

      The IP address that this server will be allocated to.

      +
      + + +

      The main allocation that will be assigned to this server.

      -
      - - -

      The port that this server will be allocated to.

      +
      + + +

      Additional allocations to assign to this server on creation.

      +
      +
      +
      +
      +

      Resource Management

      +
      +
      +
      + +
      + + MB +
      +
      +
      + +
      + + MB +
      +
      +
      + +
      + + + + +
      +
      +
      + +
      +
      + +
      + + GB +
      +
      +
      + +
      + + % +
      +
      +
      + +
      + + I/O +
      +
      +
      + +
      +
      +
      @endsection @@ -110,10 +170,18 @@ @parent + {!! Theme::js('vendor/lodash/lodash.js') !!} + {!! Theme::js('js/admin/new-server.js') !!} @endsection From bbf9fd12aef3b9f84fb39d2adfd42f3f9abdd476 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 24 Feb 2017 18:23:03 -0500 Subject: [PATCH 282/599] Apply fixes from StyleCI (#325) --- app/Http/Controllers/Admin/ServersController.php | 3 ++- app/Http/Middleware/AdminAuthenticate.php | 1 - app/Models/Server.php | 4 ++-- app/Repositories/ServerRepository.php | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index be96d3ea4..6372d042a 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -128,8 +128,9 @@ class ServersController extends Controller public function postNewServerGetNodes(Request $request) { $nodes = Models\Node::with('allocations')->where('location_id', $request->input('location'))->get(); + return $nodes->map(function ($item) { - $filtered = $item->allocations->where('server_id', null)->map(function($map) { + $filtered = $item->allocations->where('server_id', null)->map(function ($map) { return collect($map)->only(['id', 'ip', 'port']); }); diff --git a/app/Http/Middleware/AdminAuthenticate.php b/app/Http/Middleware/AdminAuthenticate.php index ed286d0b9..d533fc49d 100644 --- a/app/Http/Middleware/AdminAuthenticate.php +++ b/app/Http/Middleware/AdminAuthenticate.php @@ -24,7 +24,6 @@ namespace Pterodactyl\Http\Middleware; -use Theme; use Closure; use Illuminate\Contracts\Auth\Guard; diff --git a/app/Models/Server.php b/app/Models/Server.php index 106ae000f..252646ba9 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -29,8 +29,8 @@ use Cache; use Javascript; use Illuminate\Database\Eloquent\Model; use Illuminate\Notifications\Notifiable; -use Nicolaslopezj\Searchable\SearchableTrait; use Illuminate\Database\Eloquent\SoftDeletes; +use Nicolaslopezj\Searchable\SearchableTrait; class Server extends Model { @@ -86,7 +86,7 @@ class Server extends Model 'installed' => 'integer', ]; - protected $searchable = [ + protected $searchable = [ 'columns' => [ 'servers.name' => 10, 'servers.username' => 10, diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 9d40ecc35..9a2b4eac3 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -268,7 +268,7 @@ class ServerRepository // Add Additional Allocations if (isset($data['allocation_additional']) && is_array($data['allocation_additional'])) { - foreach($data['allocation_additional'] as $allocation) { + foreach ($data['allocation_additional'] as $allocation) { $model = Models\Allocation::where('id', $allocation)->where('node_id', $data['node_id'])->whereNull('server_id')->first(); if (! $model) { continue; From fb21bf9282753567d2645c71153299de7c23ade2 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 25 Feb 2017 00:48:12 -0500 Subject: [PATCH 283/599] Begin implementation of server admin view Currently completed tabs: About, Details, Build Configuration --- .../Controllers/Admin/ServersController.php | 72 +--- app/Http/Routes/AdminRoutes.php | 17 +- app/Repositories/ServerRepository.php | 104 ++--- public/themes/pterodactyl/css/pterodactyl.css | 26 ++ .../pterodactyl/admin/servers/view.blade.php | 390 ++++++++++++++++++ .../pterodactyl/layouts/admin.blade.php | 2 +- 6 files changed, 464 insertions(+), 147 deletions(-) create mode 100644 resources/themes/pterodactyl/admin/servers/view.blade.php diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 6372d042a..2f521804a 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -149,71 +149,13 @@ class ServersController extends Controller })->values(); } - /** - * Returns a JSON tree of all avaliable IPs and Ports on a given node. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Contracts\View\View - */ - public function postNewServerGetIps(Request $request) - { - return Models\Allocation::select('id', 'ip')->where('node_id', $request->input('node'))->whereNull('server_id')->get()->unique('ip')->values()->all(); - } - - /** - * Returns a JSON tree of all avaliable options for a given service. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Contracts\View\View - */ - public function postNewServerServiceOption(Request $request) - { - if (! $request->input('service')) { - return response()->json([ - 'error' => 'Missing service in request.', - ], 500); - } - - $service = Models\Service::select('executable', 'startup')->where('id', $request->input('service'))->first(); - - return response()->json(Models\ServiceOption::select('id', 'name', 'docker_image')->where('service_id', $request->input('service'))->orderBy('name', 'asc')->get()); - } - - /** - * Returns a JSON tree of all avaliable variables for a given service option. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Contracts\View\View - */ - public function postNewServerOptionDetails(Request $request) - { - if (! $request->input('option')) { - return response()->json([ - 'error' => 'Missing option in request.', - ], 500); - } - - $option = Models\ServiceOption::with('variables')->with(['packs' => function ($query) { - $query->where('selectable', true); - }])->findOrFail($request->input('option')); - - return response()->json([ - 'packs' => $option->packs, - 'variables' => $option->variables, - 'exec' => $option->display_executable, - 'startup' => $option->display_startup, - ]); - } - public function postUpdateServerDetails(Request $request, $id) { try { $server = new ServerRepository; - $server->updateDetails($id, [ - 'owner' => $request->input('owner'), - 'name' => $request->input('name'), - 'reset_token' => ($request->input('reset_token', false) === 'on') ? true : false, - ]); + $server->updateDetails($id, $request->intersect([ + 'owner_id', 'name', 'reset_token' + ])); Alert::success('Server details were successfully updated.')->flash(); } catch (DisplayValidationException $ex) { @@ -238,7 +180,7 @@ class ServersController extends Controller { try { $server = new ServerRepository; - $server->updateContainer($id, ['image' => $request->input('docker_image')]); + $server->updateContainer($id, $request->intersect('docker_image')); Alert::success('Successfully updated this server\'s docker image.')->flash(); } catch (DisplayValidationException $ex) { return redirect()->route('admin.servers.view', [ @@ -283,9 +225,9 @@ class ServersController extends Controller { try { $server = new ServerRepository; - $server->changeBuild($id, $request->only([ - 'default', 'add_additional', - 'remove_additional', 'memory', + $server->changeBuild($id, $request->intersect([ + 'allocation_id', 'add_allocations', + 'remove_allocations', 'memory', 'swap', 'io', 'cpu', ])); Alert::success('Server details were successfully updated.')->flash(); diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index 3422088ac..20c528478 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -140,22 +140,6 @@ class AdminRoutes 'uses' => 'Admin\ServersController@postNewServerGetNodes', ]); - $router->post('/new/get-ips', [ - 'as' => 'admin.servers.new.get-ips', - 'uses' => 'Admin\ServersController@postNewServerGetIps', - ]); - - $router->post('/new/service-options', [ - 'as' => 'admin.servers.new.service-options', - 'uses' => 'Admin\ServersController@postNewServerServiceOption', - ]); - - $router->post('/new/option-details', [ - 'as' => 'admin.servers.new.option-details', - 'uses' => 'Admin\ServersController@postNewServerOptionDetails', - ]); - // End Assorted Page Helpers - // View Specific Server $router->get('/view/{id}', [ 'as' => 'admin.servers.view', @@ -170,6 +154,7 @@ class AdminRoutes // Change Server Details $router->post('/view/{id}/details', [ + 'as' => 'admin.servers.view.details', 'uses' => 'Admin\ServersController@postUpdateServerDetails', ]); diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 9a2b4eac3..756979908 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -352,8 +352,9 @@ class ServerRepository // Validate Fields $validator = Validator::make($data, [ - 'owner' => 'email|exists:users,email', - 'name' => 'regex:([\w .-]{1,200})', + 'owner_id' => 'sometimes|required|numeric|exists:users,id', + 'name' => 'sometimes|required|regex:([\w .-]{1,200})', + 'reset_token' => 'sometimes|required|accepted' ]); // Run validator, throw catchable and displayable exception if it fails. @@ -368,16 +369,15 @@ class ServerRepository $server = Models\Server::with('user')->findOrFail($id); // Update daemon secret if it was passed. - if ((isset($data['reset_token']) && $data['reset_token'] === true) || (isset($data['owner']) && $data['owner'] !== $server->user->email)) { + if (isset($data['reset_token']) || (isset($data['owner_id']) && $data['owner_id'] !== $server->user->id)) { $oldDaemonKey = $server->daemonSecret; $server->daemonSecret = $uuid->generate('servers', 'daemonSecret'); $resetDaemonKey = true; } // Update Server Owner if it was passed. - if (isset($data['owner']) && $data['owner'] !== $server->user->email) { - $newOwner = Models\User::select('id')->where('email', $data['owner'])->first(); - $server->owner_id = $newOwner->id; + if (isset($data['owner_id']) && $data['owner_id'] !== $server->user->id) { + $server->owner_id = $data['owner_id']; } // Update Server Name if it was passed. @@ -431,7 +431,7 @@ class ServerRepository public function updateContainer($id, array $data) { $validator = Validator::make($data, [ - 'image' => 'required|string', + 'docker_image' => 'required|string', ]); // Run validator, throw catchable and displayable exception if it fails. @@ -444,7 +444,7 @@ class ServerRepository try { $server = Models\Server::findOrFail($id); - $server->image = $data['image']; + $server->image = $data['docker_image']; $server->save(); $server->node->guzzleClient([ @@ -479,17 +479,14 @@ class ServerRepository public function changeBuild($id, array $data) { $validator = Validator::make($data, [ - 'default' => [ - 'string', - 'regex:/^(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5])):(\d{1,5})$/', - ], - 'add_additional' => 'nullable|array', - 'remove_additional' => 'nullable|array', - 'memory' => 'integer|min:0', - 'swap' => 'integer|min:-1', - 'io' => 'integer|min:10|max:1000', - 'cpu' => 'integer|min:0', - 'disk' => 'integer|min:0', + 'allocation_id' => 'sometimes|required|exists:allocations,id', + 'add_allocations' => 'sometimes|required|array', + 'remove_allocations' => 'sometimes|required|array', + 'memory' => 'sometimes|required|integer|min:0', + 'swap' => 'sometimes|required|integer|min:-1', + 'io' => 'sometimes|required|integer|min:10|max:1000', + 'cpu' => 'sometimes|required|integer|min:0', + 'disk' => 'sometimes|required|integer|min:0', ]); // Run validator, throw catchable and displayable exception if it fails. @@ -503,43 +500,33 @@ class ServerRepository try { $server = Models\Server::with('allocation', 'allocations')->findOrFail($id); $newBuild = []; + $newAllocations = []; - if (isset($data['default'])) { - list($ip, $port) = explode(':', $data['default']); - if ($ip !== $server->allocation->ip || (int) $port !== $server->allocation->port) { - $selection = $server->allocations->where('ip', $ip)->where('port', $port)->first(); + if (isset($data['allocation_id'])) { + if ((int) $data['allocation_id'] !== $server->allocation_id) { + $selection = $server->allocations->where('id', $data['allocation_id'])->first(); if (! $selection) { - throw new DisplayException('The requested default connection (' . $ip . ':' . $port . ') is not allocated to this server.'); + throw new DisplayException('The requested default connection is not allocated to this server.'); } $server->allocation_id = $selection->id; - $newBuild['default'] = [ - 'ip' => $ip, - 'port' => (int) $port, - ]; + $newBuild['default'] = ['ip' => $selection->ip, 'port' => $selection->port]; - // Re-Run to keep updated for rest of function $server->load('allocation'); } } $newPorts = false; // Remove Assignments - if (isset($data['remove_additional'])) { - foreach ($data['remove_additional'] as $id => $combo) { - list($ip, $port) = explode(':', $combo); - // Invalid, not worth killing the whole thing, we'll just skip over it. - if (! filter_var($ip, FILTER_VALIDATE_IP) || ! preg_match('/^(\d{1,5})$/', $port)) { - break; - } - + if (isset($data['remove_allocations'])) { + foreach ($data['remove_allocations'] as $allocation) { // Can't remove the assigned IP/Port combo - if ($ip === $server->allocation->ip && (int) $port === (int) $server->allocation->port) { - break; + if ((int) $allocation === $server->allocation_id) { + continue; } $newPorts = true; - $server->allocations->where('ip', $ip)->where('port', $port)->update([ + Models\Allocation::where('id', $allocation)->where('server_id', $server->id)->update([ 'server_id' => null, ]); } @@ -548,21 +535,15 @@ class ServerRepository } // Add Assignments - if (isset($data['add_additional'])) { - foreach ($data['add_additional'] as $id => $combo) { - list($ip, $port) = explode(':', $combo); - // Invalid, not worth killing the whole thing, we'll just skip over it. - if (! filter_var($ip, FILTER_VALIDATE_IP) || ! preg_match('/^(\d{1,5})$/', $port)) { - break; - } - - // Don't allow double port assignments - if ($server->allocations->where('port', $port)->count() !== 0) { - break; + if (isset($data['add_allocations'])) { + foreach ($data['add_allocations'] as $allocation) { + $model = Models\Allocation::where('id', $allocation)->whereNull('server_id')->first(); + if (! $model) { + continue; } $newPorts = true; - Models\Allocation::where('ip', $ip)->where('port', $port)->whereNull('server_id')->update([ + $model->update([ 'server_id' => $server->id, ]); } @@ -570,18 +551,10 @@ class ServerRepository $server->load('allocations'); } - // Loop All Assignments - $additionalAssignments = []; - foreach ($server->allocations as &$assignment) { - if (array_key_exists((string) $assignment->ip, $additionalAssignments)) { - array_push($additionalAssignments[(string) $assignment->ip], (int) $assignment->port); - } else { - $additionalAssignments[(string) $assignment->ip] = [(int) $assignment->port]; - } - } - - if ($newPorts === true) { - $newBuild['ports|overwrite'] = $additionalAssignments; + if ($newPorts) { + $newBuild['ports|overwrite'] = $server->allocations->groupBy('ip')->map(function ($item) { + return $item->pluck('port'); + })->toArray(); } // @TODO: verify that server can be set to this much memory without @@ -617,6 +590,7 @@ class ServerRepository // This won't be committed unless the HTTP request succeedes anyways $server->save(); + dd($newBuild); if (! empty($newBuild)) { $server->node->guzzleClient([ 'X-Access-Server' => $server->uuid, @@ -630,7 +604,7 @@ class ServerRepository DB::commit(); - return true; + return $server; } catch (TransferException $ex) { DB::rollBack(); throw new DisplayException('An error occured while attempting to update the configuration.', $ex); diff --git a/public/themes/pterodactyl/css/pterodactyl.css b/public/themes/pterodactyl/css/pterodactyl.css index 4a3fe3bf2..497c49324 100644 --- a/public/themes/pterodactyl/css/pterodactyl.css +++ b/public/themes/pterodactyl/css/pterodactyl.css @@ -198,3 +198,29 @@ span[aria-labelledby="select2-pUserId-container"] { color: #777 !important; background: transparent !important; } + +.tab-pane .box-footer { + margin: 0 -10px -10px; +} + +.select2-container{ width: 100% !important; } + +.nav-tabs-custom > .nav-tabs > li:hover { + border-top-color:#3c8dbc; +} + +.nav-tabs-custom > .nav-tabs > li.active.tab-danger, .nav-tabs-custom > .nav-tabs > li.tab-danger:hover { + border-top-color: #c23321; +} + +.nav-tabs-custom > .nav-tabs > li.active.tab-success, .nav-tabs-custom > .nav-tabs > li.tab-success:hover { + border-top-color: #00733e; +} + +.nav-tabs-custom > .nav-tabs > li.active.tab-info, .nav-tabs-custom > .nav-tabs > li.tab-info:hover { + border-top-color: #0097bc; +} + +.nav-tabs-custom > .nav-tabs > li.active.tab-warning, .nav-tabs-custom > .nav-tabs > li.tab-warning:hover { + border-top-color: #c87f0a; +} diff --git a/resources/themes/pterodactyl/admin/servers/view.blade.php b/resources/themes/pterodactyl/admin/servers/view.blade.php new file mode 100644 index 000000000..85a74536c --- /dev/null +++ b/resources/themes/pterodactyl/admin/servers/view.blade.php @@ -0,0 +1,390 @@ +{{-- 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') + Manage Server: {{ $server->name }} +@endsection + +@section('content-header') +

      {{ $server->name }}{{ $server->uuid }}

      + +@endsection + +@section('content') + @if($server->suspended && ! $server->trashed()) +
      + This server is suspended and has no user access. Processes cannot be started and files cannot be modified. All API access is disabled unless using a master token. +
      + @elseif($server->trashed()) +
      + This server is marked for deletion {{ Carbon::parse($server->deleted_at)->addMinutes(env('APP_DELETE_MINUTES', 10))->diffForHumans() }}. If you want to cancel this action simply click the button below. +

      +
      + + + + {!! csrf_field() !!} +
      +
      + @endif + @if(! $server->installed) +
      + This server is still running through the install process and is not avaliable for use just yet. This message will disappear once this process is completed. +
      + @elseif($server->installed === 2) +
      + This server failed to install properly. You should delete it and try to create it again or check the daemon logs. +
      + @endif +
      +
      + +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/themes/pterodactyl/layouts/admin.blade.php b/resources/themes/pterodactyl/layouts/admin.blade.php index b3cff34e3..568b60acc 100644 --- a/resources/themes/pterodactyl/layouts/admin.blade.php +++ b/resources/themes/pterodactyl/layouts/admin.blade.php @@ -67,7 +67,7 @@
    • -
    • +
    • From 9f54ff236ae418650cc93798a5df258c2cb84570 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 25 Feb 2017 14:14:07 -0500 Subject: [PATCH 284/599] Add back manage and delete tabs to server view Will come back to deal with Startup and Database tabs at a later date. --- .../themes/pterodactyl/js/admin/functions.js | 23 ++++++ .../pterodactyl/admin/servers/view.blade.php | 75 ++++++++++++++++++- .../pterodactyl/layouts/admin.blade.php | 1 + resources/views/layouts/admin.blade.php | 4 - 4 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 public/themes/pterodactyl/js/admin/functions.js diff --git a/public/themes/pterodactyl/js/admin/functions.js b/public/themes/pterodactyl/js/admin/functions.js new file mode 100644 index 000000000..26115cd46 --- /dev/null +++ b/public/themes/pterodactyl/js/admin/functions.js @@ -0,0 +1,23 @@ +// 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. +$.urlParam=function(name){var results=new RegExp("[\\?&]"+name+"=([^&#]*)").exec(decodeURIComponent(window.location.href));if(results==null){return null}else{return results[1]||0}};function getPageName(url){var index=url.lastIndexOf("/")+1;var filenameWithExtension=url.substr(index);var filename=filenameWithExtension.split(".")[0];return filename} +// Remeber Active Tab and Navigate to it on Reload +for(var queryParameters={},queryString=location.search.substring(1),re=/([^&=]+)=([^&]*)/g,m;m=re.exec(queryString);)queryParameters[decodeURIComponent(m[1])]=decodeURIComponent(m[2]);$("a[data-toggle='tab']").click(function(){queryParameters.tab=$(this).attr("href").substring(1),window.history.pushState(null,null,location.pathname+"?"+$.param(queryParameters))}); +if($.urlParam('tab') != null){$('.nav.nav-tabs a[href="#' + $.urlParam('tab') + '"]').tab('show');} diff --git a/resources/themes/pterodactyl/admin/servers/view.blade.php b/resources/themes/pterodactyl/admin/servers/view.blade.php index 85a74536c..5818f9510 100644 --- a/resources/themes/pterodactyl/admin/servers/view.blade.php +++ b/resources/themes/pterodactyl/admin/servers/view.blade.php @@ -293,13 +293,70 @@ {{-- End Database / Start Manage --}} @if($server->installed !== 2)
      - Manage +
      +
      +
      + {!! csrf_field() !!} + +

      This will toggle the install status for the server.

      +
      +
      +
      +
      + {!! csrf_field() !!} + +

      This will trigger a rebuild of the server container when it next starts up. This is useful if you modified the server configuration file manually, or something just didn't work out correctly.

      +
      +
      +
      + @if(! $server->suspended) +
      + {!! csrf_field() !!} + +

      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 +
      + {!! csrf_field() !!} + +

      This will unsuspend the server and restore normal user access.

      +
      + @endif +
      +
      @endif {{-- End Manage / Start Delete --}} @if(! $server->trashed())
      - Delete +
      + @if($server->installed) +
      +
      + {!! csrf_field() !!} + {!! method_field('DELETE') !!} + +
      +

      +

      + Deleting a server is an irreversible action. All data will be immediately removed relating to this server. +
      +

      +
      + @endif +
      +
      + {!! csrf_field() !!} + {!! method_field('DELETE') !!} + +
      +

      +

      + This is the same as deleting a server, however, if an error is returned by the daemon it is ignored and the server is still removed from the panel. +
      +

      +
      +
      @endif {{-- End Delete --}} @@ -312,6 +369,20 @@ @section('footer-scripts') @parent +@endsection diff --git a/resources/themes/pterodactyl/admin/nodes/view/allocation.blade.php b/resources/themes/pterodactyl/admin/nodes/view/allocation.blade.php new file mode 100644 index 000000000..ac385e608 --- /dev/null +++ b/resources/themes/pterodactyl/admin/nodes/view/allocation.blade.php @@ -0,0 +1,245 @@ +{{-- 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') + {{ $node->name }}: Allocations +@endsection + +@section('content-header') +

      {{ $node->name }}Control allocations available for servers on this node.

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

      Existing Allocations

      +
      +
      + + + + + + + + + @foreach($node->allocations as $allocation) + + + + + + + + @endforeach +
      IP Address IP AliasPortAssigned To
      {{ $allocation->ip }} + + + {{ $allocation->port }} + @if(! is_null($allocation->server)) + {{ $allocation->server->name }} + @endif + + @if(is_null($allocation->server_id)) + + @else + + @endif +
      +
      + +
      +
      +
      +
      +
      +
      +

      Assign New Allocations

      +
      +
      +
      + +
      + +

      Enter an IP address to assign ports to here.

      +
      +
      +
      + +
      + +

      If you would like to assign a default alias to these allocations enter it here.

      +
      +
      +
      + +
      + +

      Enter individual ports or port ranges here separated by commas or spaces.

      +
      +
      +
      + +
      +
      +
      +
      + +@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/themes/pterodactyl/admin/nodes/view/configuration.blade.php b/resources/themes/pterodactyl/admin/nodes/view/configuration.blade.php new file mode 100644 index 000000000..daa42fd40 --- /dev/null +++ b/resources/themes/pterodactyl/admin/nodes/view/configuration.blade.php @@ -0,0 +1,102 @@ +{{-- 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') + {{ $node->name }}: Configuration +@endsection + +@section('content-header') +

      {{ $node->name }}Your daemon configuration file.

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

      Configuration File

      +
      +
      +
      {{ $node->getConfigurationAsJson(true) }}
      +
      + +
      +
      +
      +
      +
      +

      Auto-Deploy

      +
      +
      +

      To simplify the configuration of nodes it is possible to fetch the config from the panel. A token is required for this process. The button below will generate a token and provide you with the commands necessary for automatic configuration of the node. Tokens are only valid for 5 minutes.

      +
      + +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/themes/pterodactyl/admin/nodes/view/index.blade.php b/resources/themes/pterodactyl/admin/nodes/view/index.blade.php new file mode 100644 index 000000000..9af1e6fad --- /dev/null +++ b/resources/themes/pterodactyl/admin/nodes/view/index.blade.php @@ -0,0 +1,143 @@ +{{-- 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') + {{ $node->name }} +@endsection + +@section('content-header') +

      {{ $node->name }}A quick overview of your node.

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

      Information

      +
      +
      + + + + + + + + + + + + + +
      Daemon Version (Latest: {{ Version::getDaemon() }})
      System Information
      Total CPU Cores
      +
      +
      +
      +
      +
      +
      +

      At-a-Glance

      +
      +
      +
      +
      +
      + +
      + Disk Space Allocated + {{ $stats['disk']['value'] }} Mb +
      +
      +
      +
      +
      +
      +
      +
      + +
      + Memory Allocated + {{ $stats['memory']['value'] }} Mb +
      +
      +
      +
      +
      +
      +
      +
      + +
      + Total Servers + {{ $node->servers_count }} +
      +
      +
      +
      +
      +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/themes/pterodactyl/admin/nodes/view/servers.blade.php b/resources/themes/pterodactyl/admin/nodes/view/servers.blade.php new file mode 100644 index 000000000..d7ebcbabe --- /dev/null +++ b/resources/themes/pterodactyl/admin/nodes/view/servers.blade.php @@ -0,0 +1,91 @@ +{{-- 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') + {{ $node->name }}: Servers +@endsection + +@section('content-header') +

      {{ $node->name }}All servers currently assigned to this node.

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

      Process Manager

      +
      +
      + + + + + + + + + + + + @foreach($node->servers as $server) + + + + + + + + + + + @endforeach +
      IDServer NameOwnerServiceMemoryDiskCPUStatus
      {{ $server->uuidShort }}{{ $server->name }}{{ $server->user->email }}{{ $server->service->name }}NaN / {{ $server->memory === 0 ? '∞' : $server->memory }} MB{{ $server->disk }} MBNaN %NaN
      +
      +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/admin/node/view-servers.js') !!} +@endsection diff --git a/resources/themes/pterodactyl/admin/nodes/view/settings.blade.php b/resources/themes/pterodactyl/admin/nodes/view/settings.blade.php new file mode 100644 index 000000000..97261f991 --- /dev/null +++ b/resources/themes/pterodactyl/admin/nodes/view/settings.blade.php @@ -0,0 +1,224 @@ +{{-- 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') + {{ $node->name }}: Settings +@endsection + +@section('content-header') +

      {{ $node->name }}Configure your node settings.

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

      Settings

      +
      +
      +
      + +
      + +

      Character limits: a-zA-Z0-9_.- and [Space] (min 1, max 100 characters).

      +
      +
      +
      + +
      + +
      +
      +
      + +
      + public) === '1') ? 'checked' : '' }} id="public_1" checked>
      + public) === '0') ? 'checked' : '' }} id="public_0"> +
      +
      +
      + +
      + +
      +

      Please enter domain name (e.g node.example.com) to be used for connecting to the daemon. An IP address may only be used if you are not using SSL for this node. + Why? +

      +
      +
      + +
      +
      + scheme) === 'https') ? 'checked' : '' }}/> +
      +
      + scheme) === 'http') ? 'checked' : '' }}/> +
      +
      +

      You should always leave SSL enabled for nodes. Disabling SSL could allow a malicious user to intercept traffic between the panel and the daemon potentially exposing sensitive information.

      +
      + +
      +
      +
      +
      +
      +
      +

      Allocation Limits

      +
      +
      +
      +
      +
      + +
      + + MB +
      +
      +
      + +
      + + % +
      +
      +
      +

      Enter the total amount of memory available on this node for allocation to servers. You may also provide a percentage that can allow allocation of more than the defined memory.

      +
      +
      +
      +
      + +
      + + MB +
      +
      +
      + +
      + + % +
      +
      +
      +

      Enter the total amount of disk space available on this node for server allocation. You may also provide a percentage that will determine the amount of disk space over the set limit to allow.

      +
      +
      +
      +
      +
      +
      +
      +

      General Configuration

      +
      +
      +
      + +
      + + MB +
      +

      Enter the maximum size of files that can be uploaded through the web-based file manager.

      +
      +
      +
      +
      + +
      + +
      +
      +
      + +
      + +
      +
      +
      +
      +
      +

      The daemon runs its own SFTP management container and does not use the SSHd process on the main physical server. Do not use the same port that you have assigned for your physcial server's SSH process.

      +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      Save Settings

      +
      +
      +
      +
      + +
      +

      Resetting the daemon master key will void any request coming from the old key. This key is used for all sensitive operations on the daemon including server creation and deletion. We suggest changing this key regularly for security.

      +
      +
      + +
      +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/themes/pterodactyl/admin/servers/index.blade.php b/resources/themes/pterodactyl/admin/servers/index.blade.php index a9c6deb83..b311424f7 100644 --- a/resources/themes/pterodactyl/admin/servers/index.blade.php +++ b/resources/themes/pterodactyl/admin/servers/index.blade.php @@ -40,7 +40,7 @@
      - +
      diff --git a/resources/themes/pterodactyl/layouts/admin.blade.php b/resources/themes/pterodactyl/layouts/admin.blade.php index e44aeac1a..7016fdc5b 100644 --- a/resources/themes/pterodactyl/layouts/admin.blade.php +++ b/resources/themes/pterodactyl/layouts/admin.blade.php @@ -90,15 +90,15 @@ Settings -
    • SERVER MANAGEMENT
    • +
    • MANAGEMENT
    • List Servers
    • -
    • - - Create Server +
    • + + List Nodes
    • From 2efd6865e330b8b45fdf8865d9d16aa3f6d483cd Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Fri, 3 Mar 2017 23:25:34 +0100 Subject: [PATCH 289/599] fix rethemed settings title --- resources/themes/pterodactyl/admin/settings.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/themes/pterodactyl/admin/settings.blade.php b/resources/themes/pterodactyl/admin/settings.blade.php index 815779849..5bc8a2ad3 100644 --- a/resources/themes/pterodactyl/admin/settings.blade.php +++ b/resources/themes/pterodactyl/admin/settings.blade.php @@ -20,7 +20,7 @@ @extends('layouts.admin') @section('title') - Administration + Settings @endsection @section('content-header') From b91e3d95f87a72e3cfaad2befa23a659022eb858 Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Fri, 3 Mar 2017 23:42:58 +0100 Subject: [PATCH 290/599] fix revealing module and jquery3 of 2fa-modal --- public/themes/pterodactyl/js/frontend/2fa-modal.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/public/themes/pterodactyl/js/frontend/2fa-modal.js b/public/themes/pterodactyl/js/frontend/2fa-modal.js index 935bd0f59..022ece2ff 100644 --- a/public/themes/pterodactyl/js/frontend/2fa-modal.js +++ b/public/themes/pterodactyl/js/frontend/2fa-modal.js @@ -37,7 +37,7 @@ var TwoFactorModal = (function () { }).done(function (data) { var image = new Image(); image.src = data.qrImage; - $(image).load(function () { + $(image).on('load', function () { $('#hide_img_load').slideUp(function () { $('#qr_image_insert').attr('src', image.src).slideDown(); }); @@ -85,7 +85,6 @@ var TwoFactorModal = (function () { bindListeners(); } } - -}); +})(); TwoFactorModal.init(); From 2854a55aa2a191e77aa579bc0b1ce9686d8332bf Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 3 Mar 2017 17:50:45 -0500 Subject: [PATCH 291/599] Fix server view to use owner username and named route locations --- resources/themes/pterodactyl/admin/servers/index.blade.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/themes/pterodactyl/admin/servers/index.blade.php b/resources/themes/pterodactyl/admin/servers/index.blade.php index b311424f7..820ca47df 100644 --- a/resources/themes/pterodactyl/admin/servers/index.blade.php +++ b/resources/themes/pterodactyl/admin/servers/index.blade.php @@ -63,9 +63,9 @@ @foreach ($servers as $server)
      {{ $server->uuidShort }}{{ $server->name }}{{ $server->user->email }}{{ $server->node->name }}{{ $server->name }}{{ $server->user->username }}{{ $server->node->name }} {{ $server->allocation->alias }}:{{ $server->allocation->port }}
      {{ $server->uuidShort }} {{ $server->name }}{{ $server->user->email }}{{ $server->service->name }}{{ $server->user->username }}{{ $server->service->name }} ({{ $server->option->name }}) NaN / {{ $server->memory === 0 ? '∞' : $server->memory }} MB {{ $server->disk }} MB NaN %
      + + + + + + + + + + @foreach ($users as $user) + + + + + + + + + @endforeach + +
      ID + Email + Client NameUsernameServers
      {{ $user->id }}{{ $user->email }}{{ $user->name_last }}, {{ $user->name_first }}{{ $user->username }}{{ $user->servers_count }}
      +
      + +
      +
      +
      +@endsection From e331157f53ebac73b280a12083f00e977860180e Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Sat, 4 Mar 2017 00:20:17 +0100 Subject: [PATCH 294/599] add users menu link to new admin layout rename server list to servers rename node list to nodes --- resources/themes/pterodactyl/layouts/admin.blade.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/resources/themes/pterodactyl/layouts/admin.blade.php b/resources/themes/pterodactyl/layouts/admin.blade.php index 7016fdc5b..72238ce48 100644 --- a/resources/themes/pterodactyl/layouts/admin.blade.php +++ b/resources/themes/pterodactyl/layouts/admin.blade.php @@ -93,12 +93,17 @@
    • MANAGEMENT
    • - List Servers + Servers
    • - List Nodes + Nodes + +
    • +
    • + + Users
    • From ae980f90206b6971b6ecb04e141a40a2b864715b Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Sat, 4 Mar 2017 01:10:03 +0100 Subject: [PATCH 295/599] retheme admin user view --- .../pterodactyl/admin/users/view.blade.php | 197 ++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 resources/themes/pterodactyl/admin/users/view.blade.php diff --git a/resources/themes/pterodactyl/admin/users/view.blade.php b/resources/themes/pterodactyl/admin/users/view.blade.php new file mode 100644 index 000000000..7b1dbeefa --- /dev/null +++ b/resources/themes/pterodactyl/admin/users/view.blade.php @@ -0,0 +1,197 @@ +{{-- 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') + Manager User: {{ $user->username }} +@endsection + +@section('content-header') +

      {{ $user->name_first }} {{ $user->name_last}}{{ $user->username }}

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

      Identity

      +
      +
      +
      +
      + +
      + +
      +
      +
      + +
      + +
      +
      +
      + +
      + +
      +
      +
      + +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      Password

      +
      +
      +
      + +
      + +
      + +
      +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      Permissions

      +
      +
      +
      +
      + +
      + +

      Setting this to 'Yes' gives a user full administrative access.

      +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      Associated Servers

      +
      +
      + + + + + + + + + + + + @foreach($user->servers as $server) + + + + + + + + @endforeach + +
      IdentifierServer NameNode
      {{ $server->uuidShort }}{{ $server->name }}{{ $server->node->name }}@if($server->suspended === 0)Active@elseSuspended@endif
      +
      + +
      +
      +
      +
      +
      +

      Delete User

      +
      +
      +
      Warning! There most be no servers associated with this account in order for it to be deleted.
      +

      +
      + {!! method_field('DELETE') !!} + {!! csrf_field() !!} + +
      +
      + +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection From d1811822f36742b8d21b7d83765df97d9b6baf9a Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Sat, 4 Mar 2017 01:44:52 +0100 Subject: [PATCH 296/599] fix form on admin user view --- .../pterodactyl/admin/users/view.blade.php | 55 +++++++------------ 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/resources/themes/pterodactyl/admin/users/view.blade.php b/resources/themes/pterodactyl/admin/users/view.blade.php index 7b1dbeefa..146a8c664 100644 --- a/resources/themes/pterodactyl/admin/users/view.blade.php +++ b/resources/themes/pterodactyl/admin/users/view.blade.php @@ -34,12 +34,12 @@ @section('content')
      -
      -
      -
      -

      Identity

      -
      -
      + +
      +
      +
      +

      Identity

      +
      @@ -68,17 +68,15 @@
      - -
      -
      -
      -
      -
      -

      Password

      -
      +
      +
      +
      +
      +

      Password

      +
      @@ -91,19 +89,13 @@
      - - -
      -
      -
      -
      -
      -

      Permissions

      -
      +
      +
      +
      +
      +

      Permissions

      +
      @@ -116,13 +108,9 @@
      - - +
      -
      +
      @@ -169,7 +157,6 @@
      -
      From 23dfcbd7bc6f19b84fd3d4ac4f07a40fa198d726 Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Sat, 4 Mar 2017 01:45:03 +0100 Subject: [PATCH 297/599] retheme admin create user page --- .../pterodactyl/admin/users/new.blade.php | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 resources/themes/pterodactyl/admin/users/new.blade.php diff --git a/resources/themes/pterodactyl/admin/users/new.blade.php b/resources/themes/pterodactyl/admin/users/new.blade.php new file mode 100644 index 000000000..c10029127 --- /dev/null +++ b/resources/themes/pterodactyl/admin/users/new.blade.php @@ -0,0 +1,144 @@ +{{-- 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') + Create User +@endsection + +@section('content-header') +

      Create UserAdd a new user to the system.

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

      Identity

      +
      +
      +
      +
      + +
      + +
      +
      +
      + +
      + +
      +
      +
      +
      +
      + +
      + +
      +
      +
      + +
      + +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +

      Permissions

      +
      +
      +
      + +
      + +

      Setting this to 'Yes' gives a user full administrative access.

      +
      +
      +
      +
      +
      +
      +
      +
      +

      Password

      +
      +
      +
      +

      Providing a user password is optional. New user emails prompt users to create a password the first time they login. If a password is provided here you will need to find a different method of providing it to the user.

      +
      + +
      + +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection From 61d8332e934b454ae2e34100efa1989d802f89b7 Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Sat, 4 Mar 2017 01:47:39 +0100 Subject: [PATCH 298/599] make new user and view user consistent --- .../pterodactyl/admin/users/new.blade.php | 43 ++++++++----------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/resources/themes/pterodactyl/admin/users/new.blade.php b/resources/themes/pterodactyl/admin/users/new.blade.php index c10029127..ada012874 100644 --- a/resources/themes/pterodactyl/admin/users/new.blade.php +++ b/resources/themes/pterodactyl/admin/users/new.blade.php @@ -41,34 +41,29 @@

      Identity

      -
      -
      - -
      - -
      -
      -
      - -
      - -
      +
      + +
      +
      -
      -
      - -
      - -
      +
      + +
      +
      -
      - -
      - -
      +
      +
      + +
      + +
      +
      +
      + +
      +
      -
      diff --git a/resources/themes/pterodactyl/admin/nodes/view/configuration.blade.php b/resources/themes/pterodactyl/admin/nodes/view/configuration.blade.php index daa42fd40..536b3e384 100644 --- a/resources/themes/pterodactyl/admin/nodes/view/configuration.blade.php +++ b/resources/themes/pterodactyl/admin/nodes/view/configuration.blade.php @@ -43,7 +43,6 @@
    • Configuration
    • Allocation
    • Servers
    • -
    • Delete
    • diff --git a/resources/themes/pterodactyl/admin/nodes/view/index.blade.php b/resources/themes/pterodactyl/admin/nodes/view/index.blade.php index 9af1e6fad..de875c678 100644 --- a/resources/themes/pterodactyl/admin/nodes/view/index.blade.php +++ b/resources/themes/pterodactyl/admin/nodes/view/index.blade.php @@ -42,32 +42,52 @@
    • Configuration
    • Allocation
    • Servers
    • -
    • Delete
    • -
      -
      -

      Information

      +
      +
      +
      +
      +

      Information

      +
      +
      + + + + + + + + + + + + + +
      Daemon Version (Latest: {{ Version::getDaemon() }})
      System Information
      Total CPU Cores
      +
      +
      -
      - - - - - - - - - - - - - -
      Daemon Version (Latest: {{ Version::getDaemon() }})
      System Information
      Total CPU Cores
      +
      +
      +
      +

      Delete Node

      +
      +
      +

      Deleting a node is a irreversable action and will immediately remove this node from the panel. There must be no servers associated with this node in order to continue.

      +
      + +
      diff --git a/resources/themes/pterodactyl/admin/nodes/view/servers.blade.php b/resources/themes/pterodactyl/admin/nodes/view/servers.blade.php index 519b5fbbe..0033dac2e 100644 --- a/resources/themes/pterodactyl/admin/nodes/view/servers.blade.php +++ b/resources/themes/pterodactyl/admin/nodes/view/servers.blade.php @@ -43,7 +43,6 @@
    • Configuration
    • Allocation
    • Servers
    • -
    • Delete
    • diff --git a/resources/themes/pterodactyl/admin/nodes/view/settings.blade.php b/resources/themes/pterodactyl/admin/nodes/view/settings.blade.php index 97261f991..74e31a5c4 100644 --- a/resources/themes/pterodactyl/admin/nodes/view/settings.blade.php +++ b/resources/themes/pterodactyl/admin/nodes/view/settings.blade.php @@ -43,7 +43,6 @@
    • Configuration
    • Allocation
    • Servers
    • -
    • Delete
    • From d38f89a4685bb98076da865ba452b960ac04a2d6 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 3 Mar 2017 23:14:23 -0500 Subject: [PATCH 300/599] Cleanup node routes, cleanup remote token --- .../Controllers/Admin/NodesController.php | 125 ++++++++---------- .../Controllers/Remote/RemoteController.php | 13 +- app/Http/Routes/AdminRoutes.php | 53 +++----- app/Models/NodeConfigurationToken.php | 10 ++ ...3_224254_UpdateNodeConfigTokensColumns.php | 42 ++++++ .../admin/nodes/view/configuration.blade.php | 2 +- 6 files changed, 131 insertions(+), 114 deletions(-) create mode 100644 database/migrations/2017_03_03_224254_UpdateNodeConfigTokensColumns.php diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index ee4a58066..023c52e3e 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -26,6 +26,7 @@ namespace Pterodactyl\Http\Controllers\Admin; use DB; use Log; +use Hash; use Alert; use Carbon; use Validator; @@ -107,21 +108,6 @@ class NodesController extends Controller return redirect()->route('admin.nodes.new')->withInput(); } - public function getView(Request $request, $id) - { - $node = Models\Node::with( - 'servers.user', 'servers.service', - 'servers.allocations', 'location' - )->findOrFail($id); - $node->setRelation('allocations', $node->allocations()->with('server')->paginate(40)); - - return view('admin.nodes.view', [ - 'node' => $node, - 'stats' => Models\Server::select(DB::raw('SUM(memory) as memory, SUM(disk) as disk'))->where('node_id', $node->id)->first(), - 'locations' => Models\Location::all(), - ]); - } - /** * Shows the index overview page for a specific node. * @@ -221,36 +207,35 @@ class NodesController extends Controller ]); } - public function postView(Request $request, $id) + /** + * Updates settings for a node. + * + * @param Request $request + * @param integer $node + * @return \Illuminate\Http\RedirectResponse + */ + public function updateSettings(Request $request, $id) { + $repo = new NodeRepository; + try { - $node = new NodeRepository; - $node->update($id, $request->only([ - 'name', 'location_id', 'public', - 'fqdn', 'scheme', 'memory', - 'memory_overallocate', 'disk', - 'disk_overallocate', 'upload_size', + $repo->update($id, $request->intersect([ + 'name', 'location_id', 'public', 'fqdn', 'scheme', 'memory', + 'memory_overallocate', 'disk', 'disk_overallocate', 'upload_size', 'daemonSFTP', 'daemonListen', 'reset_secret', ])); - Alert::success('Successfully update this node\'s information. If you changed any daemon settings you will need to restart it now.')->flash(); - return redirect()->route('admin.nodes.view', [ - 'id' => $id, - 'tab' => 'tab_settings', - ]); - } catch (DisplayValidationException $e) { - return redirect()->route('admin.nodes.view', $id)->withErrors(json_decode($e->getMessage()))->withInput(); - } catch (DisplayException $e) { - Alert::danger($e->getMessage())->flash(); - } catch (\Exception $e) { - Log::error($e); + Alert::success('Successfully updated this node\'s information. If you changed any daemon settings you will need to restart it now.')->flash(); + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.nodes.view.settings', $id)->withErrors(json_decode($ex->getMessage()))->withInput(); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); Alert::danger('An unhandled exception occured while attempting to edit this node. Please try again.')->flash(); } - return redirect()->route('admin.nodes.view', [ - 'id' => $id, - 'tab' => 'tab_settings', - ])->withInput(); + return redirect()->route('admin.nodes.view.settings', $id)->withInput(); } /** @@ -259,7 +244,7 @@ class NodesController extends Controller * @param Request $request * @param integer $node * @param integer $allocation [description] - * @return mixed + * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse */ public function allocationRemoveSingle(Request $request, $node, $allocation) { @@ -278,7 +263,7 @@ class NodesController extends Controller * * @param Request $request * @param integer $node - * @return mixed + * @return \Illuminate\Http\RedirectResponse */ public function allocationRemoveBlock(Request $request, $node) { @@ -297,7 +282,8 @@ class NodesController extends Controller * * @param Request $request * @param integer $node - * @return mixed + * @return \Illuminate\Http\Response + * @throws \Exception */ public function allocationSetAlias(Request $request, $node) { @@ -342,51 +328,48 @@ class NodesController extends Controller return redirect()->route('admin.nodes.view.allocation', $node); } - public function getAllocationsJson(Request $request, $id) + /** + * Deletes a node from the system. + * + * @param Request $request + * @param integer $id + * @return \Illuminate\Http\RedirectResponse + */ + public function delete(Request $request, $id) { - $allocations = Models\Allocation::select('ip')->where('node_id', $id)->groupBy('ip')->get(); + $repo = new NodeRepository; - return response()->json($allocations); - } - - public function deleteNode(Request $request, $id) - { try { - $repo = new NodeRepository; $repo->delete($id); Alert::success('Successfully deleted the requested node from the panel.')->flash(); return redirect()->route('admin.nodes'); - } catch (DisplayException $e) { - Alert::danger($e->getMessage())->flash(); - } catch (\Exception $e) { - Log::error($e); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); Alert::danger('An unhandled exception occured while attempting to delete this node. Please try again.')->flash(); } - return redirect()->route('admin.nodes.view', [ - 'id' => $id, - 'tab' => 'tab_delete', - ]); + return redirect()->route('admin.nodes.view', $id); } - public function getConfigurationToken(Request $request, $id) + /** + * Returns the configuration token to auto-deploy a node. + * + * @param Request $request + * @param integer $id + * @return \Illuminate\Http\JsonResponse + */ + public function setToken(Request $request, $id) { - // Check if Node exists. Will lead to 404 if not. - Models\Node::findOrFail($id); + $node = Models\Node::findOrFail($id); - // Create a token - $token = new Models\NodeConfigurationToken(); - $token->node = $id; - $token->token = str_random(32); - $token->expires_at = Carbon::now()->addMinutes(5); // Expire in 5 Minutes - $token->save(); + $t = Models\NodeConfigurationToken::create([ + 'node_id' => $id, + 'token' => str_random(32), + ]); - $token_response = [ - 'token' => $token->token, - 'expires_at' => $token->expires_at->toDateTimeString(), - ]; - - return response()->json($token_response, 200); + return response()->json(['token' => $t->token]); } } diff --git a/app/Http/Controllers/Remote/RemoteController.php b/app/Http/Controllers/Remote/RemoteController.php index 23ae805b6..2e8b782a1 100644 --- a/app/Http/Controllers/Remote/RemoteController.php +++ b/app/Http/Controllers/Remote/RemoteController.php @@ -105,27 +105,26 @@ class RemoteController extends Controller return response('', 201); } - public function getConfiguration(Request $request, $tokenString) + public function getConfiguration(Request $request, $token) { // Try to query the token and the node from the database try { - $token = Models\NodeConfigurationToken::where('token', $tokenString)->firstOrFail(); - $node = Models\Node::findOrFail($token->node); + $model = Models\NodeConfigurationToken::with('node')->where('token', $token)->firstOrFail(); } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) { return response()->json(['error' => 'token_invalid'], 403); } // Check if token is expired - if ($token->expires_at->lt(Carbon::now())) { - $token->delete(); + if ($model->created_at->lt(Carbon::now())) { + $model->delete(); return response()->json(['error' => 'token_expired'], 403); } // Delete the token, it's one-time use - $token->delete(); + $model->delete(); // Manually as getConfigurationAsJson() returns it in correct format already - return response($node->getConfigurationAsJson())->header('Content-Type', 'text/json'); + return response($model->node->getConfigurationAsJson())->header('Content-Type', 'text/json'); } } diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index ae77928a0..ebfb29756 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -232,79 +232,62 @@ class AdminRoutes 'uses' => 'Admin\NodesController@postNew', ]); - $router->get('/view/{id}/do/index', [ + $router->get('/view/{id}', [ 'as' => 'admin.nodes.view', 'uses' => 'Admin\NodesController@viewIndex', ]); - $router->get('/view/{id}/do/settings', [ + $router->get('/view/{id}/settings', [ 'as' => 'admin.nodes.view.settings', 'uses' => 'Admin\NodesController@viewSettings', ]); - $router->get('/view/{id}/do/configuration', [ + $router->post('/view/{id}/settings', [ + 'uses' => 'Admin\NodesController@updateSettings', + ]); + + $router->get('/view/{id}/configuration', [ 'as' => 'admin.nodes.view.configuration', 'uses' => 'Admin\NodesController@viewConfiguration', ]); - $router->get('/view/{id}/do/allocation', [ + $router->get('/view/{id}/allocation', [ 'as' => 'admin.nodes.view.allocation', 'uses' => 'Admin\NodesController@viewAllocation', ]); - $router->post('/view/{id}/do/allocation', [ + $router->post('/view/{id}/allocation', [ 'uses' => 'Admin\NodesController@createAllocation', ]); - $router->get('/view/{id}/do/servers', [ + $router->get('/view/{id}/servers', [ 'as' => 'admin.nodes.view.servers', 'uses' => 'Admin\NodesController@viewServers', ]); - $router->get('/view/{id}/do/delete', [ + $router->delete('/view/{id}/delete', [ 'as' => 'admin.nodes.view.delete', - 'uses' => 'Admin\NodesController@viewDelete', + 'uses' => 'Admin\NodesController@delete', ]); - $router->delete('/view/{id}/do/allocation/remove/{allocation}', [ + $router->delete('/view/{id}/allocation/remove/{allocation}', [ 'as' => 'admin.nodes.view.allocation.removeSingle', 'uses' => 'Admin\NodesController@allocationRemoveSingle', ]); - $router->post('/view/{id}/do/allocation/remove', [ + $router->post('/view/{id}/allocation/remove', [ 'as' => 'admin.nodes.view.allocation.removeBlock', 'uses' => 'Admin\NodesController@allocationRemoveBlock', ]); - $router->post('/view/{id}/do/allocation/alias', [ + $router->post('/view/{id}/allocation/alias', [ 'as' => 'admin.nodes.view.allocation.setAlias', 'uses' => 'Admin\NodesController@allocationSetAlias', ]); - $router->get('/view/{id}/allocations.json', [ - 'as' => 'admin.nodes.view.allocations', - 'uses' => 'Admin\NodesController@getAllocationsJson', - ]); - - $router->post('/view/{id}/allocations', [ - 'as' => 'admin.nodes.post.allocations', - 'uses' => 'Admin\NodesController@postAllocations', - ]); - - // View Deploy - $router->get('/view/{id}/deploy', [ - 'as' => 'admin.nodes.deply', - 'uses' => 'Admin\NodesController@getScript', - ]); - - $router->delete('/view/{id}', [ - 'as' => 'admin.nodes.delete', - 'uses' => 'Admin\NodesController@deleteNode', - ]); - - $router->get('/{id}/configurationtoken', [ - 'as' => 'admin.nodes.configuration-token', - 'uses' => 'Admin\NodesController@getConfigurationToken', + $router->get('/view/{id}/settings/token', [ + 'as' => 'admin.nodes.view.configuration.token', + 'uses' => 'Admin\NodesController@setToken', ]); }); diff --git a/app/Models/NodeConfigurationToken.php b/app/Models/NodeConfigurationToken.php index dd029ec78..b09e096bd 100644 --- a/app/Models/NodeConfigurationToken.php +++ b/app/Models/NodeConfigurationToken.php @@ -48,4 +48,14 @@ class NodeConfigurationToken extends Model * @var array */ protected $dates = ['created_at', 'updated_at', 'expires_at']; + + /** + * Gets the node associated with a configuration token. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function node() + { + return $this->belongsTo(Node::class); + } } diff --git a/database/migrations/2017_03_03_224254_UpdateNodeConfigTokensColumns.php b/database/migrations/2017_03_03_224254_UpdateNodeConfigTokensColumns.php new file mode 100644 index 000000000..58dc78ba9 --- /dev/null +++ b/database/migrations/2017_03_03_224254_UpdateNodeConfigTokensColumns.php @@ -0,0 +1,42 @@ +dropForeign(['node']); + $table->dropColumn('expires_at'); + $table->renameColumn('node', 'node_id'); + + $table->foreign('node_id')->references('id')->on('nodes'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('node_configuration_tokens', function (Blueprint $table) { + $table->dropForeign(['node_id']); + $table->renameColumn('node_id', 'node'); + $table->timestamp('expires_at')->after('token'); + + $table->foreign('node')->references('id')->on('nodes'); + }); + } +} diff --git a/resources/themes/pterodactyl/admin/nodes/view/configuration.blade.php b/resources/themes/pterodactyl/admin/nodes/view/configuration.blade.php index 536b3e384..8193eaeb9 100644 --- a/resources/themes/pterodactyl/admin/nodes/view/configuration.blade.php +++ b/resources/themes/pterodactyl/admin/nodes/view/configuration.blade.php @@ -81,7 +81,7 @@ @parent -@endsection diff --git a/resources/views/admin/nodes/index.blade.php b/resources/views/admin/nodes/index.blade.php deleted file mode 100644 index de1687087..000000000 --- a/resources/views/admin/nodes/index.blade.php +++ /dev/null @@ -1,96 +0,0 @@ -{{-- 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') - Node List -@endsection - -@section('scripts') - @parent - {!! Theme::css('css/vendor/fontawesome/animation.min.css') !!} -@endsection - -@section('content') -
      - -

      All Nodes


      - - - - - - - - - - - - - - - @foreach ($nodes as $node) - - - - - - - - - - - @endforeach - -
      NameLocationSSL
      {{ $node->name }}{{ $node->location->short }}
      -
      -
      {!! $nodes->render() !!}
      -
      -
      - -@endsection diff --git a/resources/views/admin/nodes/new.blade.php b/resources/views/admin/nodes/new.blade.php deleted file mode 100644 index 37add9812..000000000 --- a/resources/views/admin/nodes/new.blade.php +++ /dev/null @@ -1,187 +0,0 @@ -{{-- 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') - Create Node -@endsection - -@section('content') -
      - -

      Create New Node


      -
      -
      -
      -
      - -
      - -

      Character limits: a-zA-Z0-9_.- and [Space] (min 1, max 100 characters).

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

      Please enter domain name (e.g node.example.com) to be used for connecting to the daemon. An IP address may only be used if you are not using SSL for this node. - Why? -

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

      You should always leave SSL enabled for nodes. Disabling SSL could allow a malicious user to intercept traffic between the panel and the daemon potentially exposing sensitive information.

      -
      -
      -
      -
      -
      -
      -
      -
      - -
      - - MB -
      -
      -
      - -
      - - % -
      -
      -
      -
      -
      -

      Enter the total amount of memory avaliable for new servers. If you would like to allow overallocation of memory enter the percentage that you want to allow. To disable checking for overallocation enter -1 into the field. Entering 0 will prevent creating new servers if it would put the node over the limit.

      -
      -
      -
      -
      -
      -
      -
      -
      - -
      - - MB -
      -
      -
      - -
      - - % -
      -
      -
      -
      -
      -

      Enter the total amount of disk space avaliable for new servers. If you would like to allow overallocation of disk space enter the percentage that you want to allow. To disable checking for overallocation enter -1 into the field. Entering 0 will prevent creating new servers if it would put the node over the limit.

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

      The location at which your server files will be stored. Most users do not need to change this.

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

      The daemon runs its own SFTP management container and does not use the SSHd process on the main physical server. Do not use the same port that you have assigned for your physcial server's SSH process.

      -
      -
      -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      - -@endsection diff --git a/resources/views/admin/nodes/remote/deploy.blade.php b/resources/views/admin/nodes/remote/deploy.blade.php deleted file mode 100644 index b7283fcfd..000000000 --- a/resources/views/admin/nodes/remote/deploy.blade.php +++ /dev/null @@ -1,292 +0,0 @@ -#!/bin/bash -#### - # Pterodactyl - Panel - # 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. -#### -set +e -export DEBIAN_FRONTEND=noninteractive - -INSTALL_DIR="/srv/daemon" -DATA_DIR="{{ $node->daemonBase }}" -CURRENT_SYSTEM_KERNEL="$(uname -r)" -DL_VERSION="0.0.1" - -command_exists() { - command -v "$@" > /dev/null 2>&1 -} - -error_message() { - echo -e "\e[1m\e[97m\e[41m$1\e[0m" - exit 1 -} - -warning_message() { - echo -e "\e[43m\e[30m$1\e[0m" -} - -success_message() { - echo -e "\e[32m$1\e[0m" -} - -running_command() { - echo -e " ;; \e[47m\e[30m$1\e[0m" -} - -for i in "$@" -do - case $i in - -d|--directory) - INSTALL_DIR="$2" - ;; - -a|--datadir) - DATA_DIR="$2" - ;; - -g|--git) - USE_GIT=true - ;; - -u|--unstable) - USE_UNSTABLE=true - USE_GIT=true - ;; - -v|--version) - DL_VERSION="$2" - ;; - -h|--help) - echo "./installer [opts]" - echo " -d | --directory The directory to install the daemon into. (default: /srv/daemon)" - echo " -a | --datadir The directory that daemon users will be stored in. (default: /srv/daemon-data)" - echo " -g | --git Use this flag to download the daemon using a git clone. (default: false)" - echo " -u | --unstable Install unstable version of the daemon, automatically uses --git flag. (default: false)" - echo " -v | --version The version of the daemon to download." - exit - ;; - esac -shift -done - -warning_message "This program will automatically configure your system to run the Pterodactyl Daemon." -warning_message " - Install Location: $INSTALL_DIR" -warning_message " - Data Location: $DATA_DIR" -warning_message "This script will continue in 10 seconds. Press CRTL+C to exit now." -sleep 10 - -# Super basic system detection -if command_exists apt-get; then - INSTALL_CMD="apt-get -y" -elif command_exists yum; then - INSTALL_CMD="yum -y" -else - error_message "No supported repository manager was found." -fi - -if ! command_exists curl; then - warning_message "No file retrieval method found, installing curl now..." - running_command "$INSTALL_CMD -y install curl" - $INSTALL_CMD -y install curl - if [ "$?" -ne "0" ]; then - error_message "Unable to install curl and no other method was found for retrieving files." - fi -fi - -# Determine if the kernel is high enough version. -if command_exists awk; then - PROCESSED_KERNEL_VERSION=$(awk -F. '{print $1$2}' <<< $CURRENT_SYSTEM_KERNEL) -elif command_exists cut; then - PROCESSED_KERNEL_VERSION=$(cut -d. -f1-2 --output-delimiter='' <<< $CURRENT_SYSTEM_KERNEL) -else - error_message "You seem to be missing some core tools that this script needs: awk (or) cut" -fi - -if [ "$PROCESSED_KERNEL_VERSION" -lt "310" ]; then - error_message "Your kernel version must be at least 3.10 or higher for the daemon to work. You are using $CURRENT_SYSTEM_KERNEL" -fi - -check_cgroups() { - # Check CGroups - CGROUP_DIRECTORY_LISTING="$(awk '/[, ](cpu|cpuacct|cpuset|devices|freezer|memory)[, ]/ && $3 == "cgroup" { print $2 }' /proc/mounts | head -n1)" - if [ ! -z $CGROUP_DIRECTORY_LISTING -a -d $CGROUP_DIRECTORY_LISTING ]; then - CGROUP_DIRECTORY="$(dirname $CGROUP_DIRECTORY_LISTING 2>&1)" - if [ -d "$CGROUP_DIRECTORY/cpu" -a -d "$CGROUP_DIRECTORY/cpuacct" -a -d "$CGROUP_DIRECTORY/cpuset" -a -d "$CGROUP_DIRECTORY/devices" -a -d "$CGROUP_DIRECTORY/freezer" -a -d "$CGROUP_DIRECTORY/memory" ]; then - success_message "cgroups enabled and are valid on this machine." - else - error_message "You appear to be missing some important cgroups on this machine." - fi - else - if [ ! -e "/proc/cgroups" ]; then - error_message "This kernel does not appear to support cgroups! Please see https://gist.github.com/DaneEveritt/0f071f481b4d3fa637d4 for more information." - elif [ ! -d "/sys/fs/cgroup" ]; then - error_message "This kernel does not appear to support cgroups! Please see https://gist.github.com/DaneEveritt/0f071f481b4d3fa637d4 for more information." - fi - - if [ ! -f "/tmp/mount_cgroup.sh" ]; then - # Try to enable cgroups - warning_message "Attempting to enable cgroups on this machine..." - running_command "curl -L https://raw.githubusercontent.com/tianon/cgroupfs-mount/master/cgroupfs-mount > /tmp/mount_cgroup.sh" - curl -L https://raw.githubusercontent.com/tianon/cgroupfs-mount/master/cgroupfs-mount > /tmp/mount_cgroup.sh - - running_command "chmod +x /tmp/mount_cgroup.sh" - chmod +x /tmp/mount_cgroup.sh - - running_command "bash /tmp/mount_cgroup.sh" - bash /tmp/mount_cgroup.sh - check_cgroups - else - rm -rf /tmp/mount_cgroup.sh > /dev/null 2>&1 - error_message "Failed to enable cgroups on this machine." - fi - fi -} - -# Check those groups. -check_cgroups - -# Lets install the dependencies. -$INSTALL_CMD install linux-image-extra-$CURRENT_SYSTEM_KERNEL -if [ "$?" -ne "0" ]; then - warning_message "You appear to have a non-generic kernel meaning we could not install extra kernel tools." - warning_message "We will continue to install, but some docker enhancements might not work as expected." - warning_message "Continuing in 10 seconds, press CTRL+C to cancel this script." - sleep 10 -fi - -success_message "Installing Docker..." -running_command "curl -L https://get.docker.com/ | sh" -curl -L https://get.docker.com/ | sh -if [ "$?" -ne "0" ]; then - error_message "Unable to install docker, an error occured!" -fi; - -success_message "Installing NodeJS 5.x..." -running_command "curl -L https://deb.nodesource.com/setup_5.x | sudo -E bash -" -curl -L https://deb.nodesource.com/setup_5.x | sudo -E bash - -if [ "$?" -ne "0" ]; then - error_message "Unable to configure NodeJS, an error occured!" -fi; - -running_command "$INSTALL_CMD install tar nodejs" -$INSTALL_CMD install tar nodejs -if [ "$?" -ne "0" ]; then - error_message "Unable to install NodeJS or Tar, an error occured!" -fi; - -running_command "mkdir -p $INSTALL_DIR $DATA_DIR" -mkdir -p $INSTALL_DIR $DATA_DIR -cd $INSTALL_DIR - -if [ -z $USE_UNSTABLE -a -z $USE_GIT ]; then - CLEANUP_PROGRAMS="nodejs docker-engine" - - running_command "curl -sI https://github.com/Pterodactyl/Daemon/archive/$DL_VERSION.tar.gz | head -n1 | cut -d$' ' -f2" - GITHUB_STATUS="$(curl -sI https://github.com/Pterodactyl/Daemon/archive/$DL_VERSION.tar.gz | head -n1 | cut -d$' ' -f2)" - if [ $GITHUB_STATUS -ne "200" ]; then - $INSTALL_CMD remove $CLEANUP_PROGRAMS 2>&1 - error_message "Github returned a non-200 response code ($GITHUB_STATUS)" - fi - - running_command "curl -L \"https://github.com/Pterodactyl/Daemon/archive/$DL_VERSION.tar.gz\" > daemon.tar.gz" - curl -L "https://github.com/Pterodactyl/Daemon/archive/$DL_VERSION.tar.gz" > daemon.tar.gz - - running_command "tar --strip-components=1 -xzvf daemon.tar.gz" - tar --strip-components=1 -xzvf daemon.tar.gz 2>&1 - if [ "$?" -ne "0" ]; then - $INSTALL_CMD remove $CLEANUP_PROGRAMS 2>&1 - cd ~ && rm -rf $INSTALL_DIR 2>&1 - error_message "Unable to install the daemon due to an error while attempting to unpack files." - fi -elif [ $USE_GIT ]; then - CLEANUP_PROGRAMS="nodejs docker-engine git" - running_command "$INSTALL_CMD install git" - $INSTALL_CMD install git - - running_command "git clone https://github.com/Pterodactyl/Daemon.git ." - git clone https://github.com/Pterodactyl/Daemon.git . - if [ -z $USE_UNSTABLE ]; then - running_command "git checkout tags/$DL_VERSION" - git checkout tags/$DL_VERSION - fi - if [ "$?" -ne "0" ]; then - $INSTALL_CMD remove $CLEANUP_PROGRAMS 2>&1 - cd ~ && rm -rf $INSTALL_DIR 2>&1 - error_message "Unable to install the daemon due to an error while attempting to clone files to the server." - fi -else - error_message "Could not match an install method!" -fi - -running_command "npm install --production" -npm install --production -if [ "$?" -ne "0" ]; then - $INSTALL_CMD remove $CLEANUP_PROGRAMS 2>&1 - cd ~ && rm -rf $INSTALL_DIR 2>&1 - error_message "Unable to install the daemon due to an error that occured while running npm install." -fi - -running_command "docker run -d --name ptdl-sftp -p 2022:22 -v $DATA_DIR:/sftp-root -v $INSTALL_DIR/config/credentials:/creds quay.io/pterodactyl/scrappy" -docker run -d --name ptdl-sftp -p 2022:22 -v $DATA_DIR:/sftp-root -v $INSTALL_DIR/config/credentials:/creds quay.io/pterodactyl/scrappy -if [ "$?" -ne "0" ]; then - $INSTALL_CMD remove $CLEANUP_PROGRAMS 2>&1 - cd ~ && rm -rf $INSTALL_DIR 2>&1 - error_message "Unable to install the daemon due to an error while creating a SFTP container." -fi - -echo '{ - "web": { - "listen": {{ $node->daemonListen }}, - "ssl": { - "enabled": {{ $node->sceheme === 'https' ? 'true' : 'false' }}, - "certificate": "/etc/letsencrypt/live/{{ $node->fqdn }}/fullchain.pem", - "key": "/etc/letsencrypt/live/{{ $node->fqdn }}/privkey.pem" - } - }, - "docker": { - "socket": "/var/run/docker.sock" - }, - "sftp": { - "path": "{{ $node->daemonBase }}", - "port": {{ $node->daemonSFTP }}, - "container": "ptdl-sftp" - }, - "logger": { - "path": "logs/", - "src": false, - "level": "info", - "period": "1d", - "count": 3 - }, - "remote": { - "download": "{{ route('remote.download') }}", - "installed": "{{ route('remote.install') }}" - }, - "uploads": { - "maximumSize": 100000000 - }, - "keys": [ - "{{ $node->daemonSecret }}" - ] -}' > config/core.json -if [ "$?" -ne "0" ]; then - $INSTALL_CMD remove $CLEANUP_PROGRAMS - cd ~ && rm -rf $INSTALL_DIR 2>&1 - error_message "An error occured while attempting to save the JSON file." -fi - -success_message "Congratulations, the daemon is now installed." -exit diff --git a/resources/views/admin/nodes/view.blade.php b/resources/views/admin/nodes/view.blade.php deleted file mode 100644 index 5a0879b72..000000000 --- a/resources/views/admin/nodes/view.blade.php +++ /dev/null @@ -1,814 +0,0 @@ -{{-- 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') - Managing Node: {{ $node->name }} -@endsection - -@section('scripts') - @parent - {!! Theme::js('js/vendor/socketio/socket.io.min.js') !!} - {!! Theme::js('js/bootstrap-notify.min.js') !!} - {!! Theme::js('js/vendor/chartjs/chart.min.js') !!} - {!! Theme::js('js/vendor/jquery/jquery-dateFormat.min.js') !!} - -@endsection - -@section('content') -
      - - -
      -
      -
      -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      Daemon Version (Latest: {{ Version::getDaemon() }})
      System Information
      Total CPU Cores
      Total Servers{{ count($node->servers) }}
      Memory Allocated{{ is_numeric($stats->memory) ? $stats->memory : 0 }} MB of - @if(!is_null($node->memory_overallocate)) - {{ $node->memory }} - @else - {{ $node->memory }} - @endif - MB -
      Disk Allocated{{ is_numeric($stats->disk) ? $stats->disk : 0 }} MB of - @if(!is_null($node->disk_overallocate)) - {{ $node->disk }} - @else - {{ $node->disk }} - @endif - MB -
      -
      -
      -
      -
      - - -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - Changing some details below may require that you change the configuration file on the node as well as restart the daemon. They have been marked with below. -
      -
      -
      - -
      - -

      Character limits: a-zA-Z0-9_.- and [Space] (min 1, max 100 characters).

      -
      -
      -
      - -
      - -
      -
      -
      - -
      - public) === '1') ? 'checked' : '' }} id="public_1" checked>
      - public) === '0') ? 'checked' : '' }} id="public_0"> -
      -
      -
      -
      -
      - -
      - -
      -

      Please enter domain name (e.g node.example.com) to be used for connecting to the daemon. An IP address may only be used if you are not using SSL for this node. - Why? -

      -
      -
      - -
      -
      - scheme) === 'https') ? 'checked' : '' }}/> -
      -
      - scheme) === 'http') ? 'checked' : '' }}/> -
      -
      -

      You should always leave SSL enabled for nodes. Disabling SSL could allow a malicious user to intercept traffic between the panel and the daemon potentially exposing sensitive information.

      -
      -
      -
      -
      -
      -
      -
      - -
      - - MB -
      -
      -
      - -
      - - % -
      -
      -
      - -
      - - MB -
      -
      -
      - -
      - - % -
      -
      -
      -
      -
      -

      Enter the total amount of disk space and memory avaliable for new servers. If you would like to allow overallocation of disk space or memory enter the percentage that you want to allow. To disable checking for overallocation enter -1 into the field. Entering 0 will prevent creating new servers if it would put the node over the limit.

      -
      -
      -
      -
      -
      -
      -
      - -
      - - MB -
      -

      Enter the maximum size of files that can be uploaded through the web-based file manager.

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

      The daemon runs its own SFTP management container and does not use the SSHd process on the main physical server. Do not use the same port that you have assigned for your physcial server's SSH process.

      -
      -
      -
      -
      -
      -
      - -
      - Reset Daemon Master Key -
      -
      -
      -

      Resetting the daemon master key will void any request coming from the old key. This key is used for all sensitive operations on the daemon including server creation and deletion. We suggest changing this key regularly for security.

      -
      -
      -
      -
      -
      -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -

      To simplify the configuration of nodes it is possible to fetch the config from the panel. A token is required for this process. The button below will generate a token and provide you with the commands necessary for automatic configuration of the node. Be aware that these tokens are only valid for 5 minutes.

      -
      -
      -

      -
      -
      -
      {{ $node->getConfigurationAsJson(true) }}
      -
      -
      -
      -
      -
      -
      -
      -
      -

      Allocate Additional Ports

      -
      -
      -
      - - -
      -
      - -
      -
        -
      • - -
      • -
      -
      -

      You must enter a comma (,) or press the enter key after each port or range that you enter. They should appear in a blue box.

      - -
      -
      - - -
      -
      -
      -
      -
      - {!! csrf_field() !!} - - -
      -
      -
      -
      -
      -
      -
      - - - - - - - - - - @foreach($node->allocations as $allocation) - - - - - - - - @endforeach - -
      IP Address IP AliasPortAssigned To
      {{ $allocation->ip }} - - - {{ $allocation->port }} - @if(! is_null($allocation->server)) - {{ $allocation->server->name }} - @endif - - @if(is_null($allocation->server_id)) - - @else - - @endif -
      -
      - {{ $node->allocations->appends(['tab' => 'tab_allocation'])->render() }} -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - The data below is live output from the daemon. CPU usage is displayed relative to the assigned CPU allocation. For example, if a server is assigned 10% and the CPU usage below displays 90% that means the server is using 9% of the total system CPU. -
      - - - - - - - - - - - - - - @foreach($node->servers as $server) - - - - - - - - - - @endforeach - -
      NameOwnerServiceMemoryDiskCPUStatus
      {{ $server->name }}{{ $server->user->email }}{{ $server->service->name }}-- / {{ $server->memory === 0 ? '∞' : $server->memory }} MB{{ $server->disk }} MB-- %--
      -
      -
      -
      - @if(count($node->servers) === 0) -
      -
      -
      -
      -
      -
      -
      - {!! method_field('DELETE') !!} - {!! csrf_field() !!} - -
      -
      -
      -
      Deleting this node is a permanent action, it cannot be undone.
      -
      -
      -
      -
      -
      - @endif -
      -
      -
      -
      -
      - - -@endsection diff --git a/resources/views/admin/servers/index.blade.php b/resources/views/admin/servers/index.blade.php deleted file mode 100644 index e2e5010f5..000000000 --- a/resources/views/admin/servers/index.blade.php +++ /dev/null @@ -1,83 +0,0 @@ -{{-- 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 List -@endsection - -@section('content') -
      - -

      All Servers


      -
      -
      - -
      - -
      -
      -
      - - - - - - - - - - - @foreach ($servers as $server) - suspended === 1 && !$server->trashed()) - class="warning" - @elseif($server->trashed()) - class="danger" - @endif - data-server="{{ $server->uuidShort }}"> - - - - - - @endforeach - -
      Server NameOwnerNode
      - {{ $server->name }} - @if($server->suspended === 1 && !$server->trashed()) - Suspended - @elseif($server->trashed()) - Pending Deletion - @endif - {{ $server->user->email }}{{ $server->node->name }}
      -
      -
      {!! $servers->render() !!}
      -
      -
      - -@endsection diff --git a/resources/views/admin/servers/new.blade.php b/resources/views/admin/servers/new.blade.php deleted file mode 100644 index dc1deef22..000000000 --- a/resources/views/admin/servers/new.blade.php +++ /dev/null @@ -1,511 +0,0 @@ -{{-- 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') - Create New Server -@endsection - -@section('scripts') - @parent - {!! Theme::js('js/vendor/typeahead/typeahead.min.js') !!} -@endsection - -@section('content') -
      - -

      Create New Server


      -
      -
      -
      -
      - -
      - -

      Character limits: a-z A-Z 0-9 _ - . and [Space] (max 200 characters).

      -
      -
      -
      - -
      - {{-- Hacky workaround to prevent Safari and Chrome from trying to suggest emails here --}} - - -
      -
      -
      -
      -
      -
      -
      - -
      - -
      - -

      The location in which this server will be deployed.

      -
      -
      - -
      -
      - - -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - -
      - - MB -
      -
      -
      - -
      - - MB -
      -
      -
      - -
      - - - - - Disable OOM Killer - -
      -
      -
      -
      -
      -

      If you do not want to assign swap space to a server simply put 0 for the value, or -1 to allow unlimited swap space. If you want to disable memory limiting on a server simply enter 0 into the memory field. We suggest leaving OOM Killer enabled unless you know what you are doing, disabling it could cause your server to hang unexpectedly.

      -

      -
      -
      -
      - -
      - - MB -
      -
      -
      - -
      - - % -
      -
      -
      - -
      - - I/O -
      -
      -
      -
      -
      -

      If you do not want to limit CPU usage set the value to 0. To determine a value, take the number physical cores and multiply it by 100. For example, on a quad core system (4 * 100 = 400) there is 400% available. To limit a server to using half of a single core, you would set the value to 50. To allow a server to use up to two physical cores, set the value to 200. BlockIO should be a value between 10 and 1000. Please see this documentation for more information about it.

      -

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

      Select the type of service that this server will be running.

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

      If you would like to use a custom docker image for this server please enter it here. Most users can ignore this option.

      -
      -
      -
      -
      -
      - -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      - -@endsection diff --git a/resources/views/admin/settings.blade.php b/resources/views/admin/settings.blade.php deleted file mode 100644 index 09e66d6fc..000000000 --- a/resources/views/admin/settings.blade.php +++ /dev/null @@ -1,97 +0,0 @@ -{{-- 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') - Administration -@endsection - -@section('content') -
      - -

      Panel Settings


      -
      -
      -
      - -
      - -

      This is the name that is used throughout the panel and in emails sent to clients.

      -
      -
      -
      - -
      - -

      This is the default language that all clients will use unless they manually change it.

      -
      -
      -
      -
      -
      -
      In order to modify your SMTP settings for sending mail you will need to edit the .env file in this project's root folder.
      -
      -
      -
      -
      - -
      - -

      The email address that panel emails will be sent from. Note that some SMTP services require this to match for a given API key.

      -
      -
      -
      - -
      - -

      The name that emails will appear to come from.

      -
      -
      -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      - -@endsection diff --git a/resources/views/admin/users/index.blade.php b/resources/views/admin/users/index.blade.php deleted file mode 100644 index 7e85c8fe9..000000000 --- a/resources/views/admin/users/index.blade.php +++ /dev/null @@ -1,73 +0,0 @@ -{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} -{{-- Some Modifications (c) 2015 Dylan Seidt --}} - -{{-- 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') - Account List -@endsection - -@section('content') -
      - -

      All Registered Users


      -
      -
      - -
      - -
      -
      -
      - - - - - - - - - - @foreach ($users as $user) - - - - - - - - @endforeach - -
      ID - Email - Client NameUsername
      #{{ $user->id }}{{ $user->email }}{{ $user->name_last }}, {{ $user->name_first }}{{ $user->username }}
      -
      -
      {!! $users->render() !!}
      -
      -
      - -@endsection diff --git a/resources/views/admin/users/new.blade.php b/resources/views/admin/users/new.blade.php deleted file mode 100644 index 8e0bf5f7a..000000000 --- a/resources/views/admin/users/new.blade.php +++ /dev/null @@ -1,132 +0,0 @@ -{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} -{{-- Some Modifications (c) 2015 Dylan Seidt --}} - -{{-- 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') - New Account -@endsection - -@section('content') -
      - -

      Create New Account


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

      Setting this to 'Yes' gives a user full administrative access.

      -
      -
      -
      -
      -
      -
      -
      -

      Providing a user password is optional. New user emails prompt users to create a password the first time they login. If a password is provided here you will need to find a different method of providing it to the user.

      -
      -
      -
      - -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      -
      -
      - {!! csrf_field() !!} - - -
      -
      -
      -
      -
      - -@endsection diff --git a/resources/views/admin/users/view.blade.php b/resources/views/admin/users/view.blade.php deleted file mode 100644 index 3ba9ec035..000000000 --- a/resources/views/admin/users/view.blade.php +++ /dev/null @@ -1,171 +0,0 @@ -{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} -{{-- Some Modifications (c) 2015 Dylan Seidt --}} - -{{-- 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') - Viewing User -@endsection - -@section('content') -
      - -

      Viewing User: {{ $user->email }}

      -

      Registered {{ (new Carbon($user->created_at))->toRfc1123String() }}

      -
      -
      -
      -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      - -
      - -
      - -
      -
      -
      - -
      -
      -
      -
      - -
      - -

      Setting this to 'Yes' gives a user full administrative access.

      -
      -
      -
      -
      -
      -
      -
      -
      -

      Associated Servers


      - @if($user->servers) - - - - - - - - - - - - - @foreach($user->servers as $server) - - - - - - - - - @endforeach - -
      IdentifierServer NameNodeUsername
      {{ $server->uuidShort }}{{ $server->name }}{{ $server->node->name }}{{ $server->username }}@if($server->suspended === 0)Active@elseSuspended@endif
      - @else -
      There are no servers associated with this account.
      - @endif - -
      -
      -
      -
      -

      Delete Account


      -
      Warning! There most be no servers associated with this account in order for it to be deleted.
      -
      - {!! method_field('DELETE') !!} - {!! csrf_field() !!} - -
      -
      -
      -
      - -@endsection From e68846892023c20177a6a2d3992d5e394f545aaf Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 4 Mar 2017 19:03:49 -0500 Subject: [PATCH 304/599] Push updated server views --- CHANGELOG.md | 5 + .../Controllers/Admin/ServersController.php | 587 +++++++++++------- app/Http/Routes/AdminRoutes.php | 104 ++-- app/Jobs/DeleteServer.php | 2 +- app/Observers/ServerObserver.php | 34 +- app/Repositories/ServerRepository.php | 21 +- public/js/laroute.js | 2 +- public/themes/pterodactyl/css/pterodactyl.css | 4 +- .../themes/pterodactyl/js/admin/new-server.js | 2 +- .../pterodactyl/admin/servers/view.blade.php | 461 -------------- .../admin/servers/view/build.blade.php | 158 +++++ .../admin/servers/view/database.blade.php | 0 .../admin/servers/view/delete.blade.php | 141 +++++ .../admin/servers/view/details.blade.php | 170 +++++ .../admin/servers/view/index.blade.php | 203 ++++++ .../admin/servers/view/manage.blade.php | 127 ++++ .../admin/servers/view/startup.blade.php | 0 17 files changed, 1245 insertions(+), 776 deletions(-) delete mode 100644 resources/themes/pterodactyl/admin/servers/view.blade.php create mode 100644 resources/themes/pterodactyl/admin/servers/view/build.blade.php create mode 100644 resources/themes/pterodactyl/admin/servers/view/database.blade.php create mode 100644 resources/themes/pterodactyl/admin/servers/view/delete.blade.php create mode 100644 resources/themes/pterodactyl/admin/servers/view/details.blade.php create mode 100644 resources/themes/pterodactyl/admin/servers/view/index.blade.php create mode 100644 resources/themes/pterodactyl/admin/servers/view/manage.blade.php create mode 100644 resources/themes/pterodactyl/admin/servers/view/startup.blade.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 1829e20dd..a47cee758 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,17 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Changed * New theme applied to Admin CP. Many graphical changes were made, some data was moved around and some display data changed. Too much was changed to feasibly log it all in here. Major breaking changes or notable new features will be logged. * New server creation page now makes significantly less AJAX calls and is much quicker to respond. +* Server and Node view pages wee modified to split tabs into individual pages to make re-themeing and modifications significantly easier, and reduce MySQL query loads on page. + +### Fixed +* Fixes potential bug with invalid CIDR notation (ex: `192.168.1.1/z`) when adding allocations that could cause over 4 million records to be created at once. ### Added * Ability to assign multiple allocations at once when creating a new server. ### Deprecated * Old API calls to `Server::create` will fail due to changed data structure. +* Many old routes were modified to reflect new standards in panel, and many of the controller functions being called were also modified. This shouldn't really impact anyone unless you have been digging into the code and modifying things. ## v0.6.0-pre.4 (Courageous Carniadactylus) ### Fixed diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 0e217dcc7..000d5c830 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -29,6 +29,7 @@ use Alert; use Javascript; use Pterodactyl\Models; use Illuminate\Http\Request; +use GuzzleHttp\Exception\TransferException; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Repositories\ServerRepository; @@ -38,14 +39,12 @@ use Pterodactyl\Exceptions\DisplayValidationException; class ServersController extends Controller { /** - * Controller Constructor. + * Display the index page with all servers currently on the system. + * + * @param Request $request + * @return \Illuminate\View\View */ - public function __construct() - { - // - } - - public function getIndex(Request $request) + public function index(Request $request) { $servers = Models\Server::withTrashed()->with( 'node', 'user', 'allocation' @@ -60,7 +59,13 @@ class ServersController extends Controller ]); } - public function getNew(Request $request) + /** + * Display create new server page. + * + * @param Request $request + * @return \Illuminate\View\View + */ + public function new(Request $request) { $services = Models\Service::with('options.packs', 'options.variables')->get(); Javascript::put([ @@ -77,55 +82,38 @@ class ServersController extends Controller ]); } - public function getView(Request $request, $id) - { - $server = Models\Server::withTrashed()->with( - 'user', 'option.variables', 'variables', - 'node.allocations', 'databases.host' - )->findOrFail($id); - - $server->option->variables->transform(function ($item, $key) use ($server) { - $item->server_value = $server->variables->where('variable_id', $item->id)->pluck('variable_value')->first(); - - return $item; - }); - - return view('admin.servers.view', [ - 'server' => $server, - 'assigned' => $server->node->allocations->where('server_id', $server->id)->sortBy('port')->sortBy('ip'), - 'unassigned' => $server->node->allocations->where('server_id', null)->sortBy('port')->sortBy('ip'), - 'db_servers' => Models\DatabaseServer::all(), - ]); - } - - public function postNewServer(Request $request) + /** + * Create server controller method. + * + * @param Request $request + * @return \Illuminate\Response\RedirectResponse + */ + public function create(Request $request) { try { - $server = new ServerRepository; - $response = $server->create($request->except('_token')); + $repo = new ServerRepository; + $server = $repo->create($request->except('_token')); - return redirect()->route('admin.servers.view', ['id' => $response->id]); + return redirect()->route('admin.servers.view', $server->id); } catch (DisplayValidationException $ex) { return redirect()->route('admin.servers.new')->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); - - return redirect()->route('admin.servers.new')->withInput(); } catch (\Exception $ex) { Log::error($ex); Alert::danger('An unhandled exception occured while attemping to add this server. Please try again.')->flash(); - - return redirect()->route('admin.servers.new')->withInput(); } + + return redirect()->route('admin.servers.new')->withInput(); } /** - * Returns a JSON tree of all avaliable nodes in a given location. + * Returns a tree of all avaliable nodes in a given location. * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Contracts\View\View + * @param Request $request + * @return array */ - public function postNewServerGetNodes(Request $request) + public function newServerNodes(Request $request) { $nodes = Models\Node::with('allocations')->where('location_id', $request->input('location'))->get(); @@ -149,263 +137,388 @@ class ServersController extends Controller })->values(); } - public function postUpdateServerDetails(Request $request, $id) + /** + * Display the index when viewing a specific server. + * + * @param Request $request + * @param int $id + * @return \Illuminate\View\View + */ + public function viewIndex(Request $request, $id) { + return view('admin.servers.view.index', ['server' => Models\Server::withTrashed()->findOrFail($id)]); + } + + /** + * Display the details page when viewing a specific server. + * + * @param Request $request + * @param int $id + * @return \Illuminate\View\View + */ + public function viewDetails(Request $request, $id) + { + $server = Models\Server::where('installed', 1)->findOrFail($id); + + return view('admin.servers.view.details', ['server' => $server]); + } + + /** + * Display the build details page when viewing a specific server. + * + * @param Request $request + * @param int $id + * @return \Illuminate\View\View + */ + public function viewBuild(Request $request, $id) + { + $server = Models\Server::where('installed', 1)->with('node.allocations')->findOrFail($id); + + return view('admin.servers.view.build', [ + 'server' => $server, + 'assigned' => $server->node->allocations->where('server_id', $server->id)->sortBy('port')->sortBy('ip'), + 'unassigned' => $server->node->allocations->where('server_id', null)->sortBy('port')->sortBy('ip'), + ]); + } + + /** + * Display startup configuration page for a server. + * + * @param Request $request + * @param int $id + * @return \Illuminate\View\View + */ + public function viewStartup(Request $request, $id) + { + $server = Models\Server::where('installed', 1)->with('option.variables', 'variables')->findOrFail($id); + $server->option->variables->transform(function ($item, $key) use ($server) { + $item->server_value = $server->variables->where('variable_id', $item->id)->pluck('variable_value')->first(); + + return $item; + }); + + return view('admin.servers.view.startup', ['server' => $server]); + } + + /** + * Display the database management page for a specific server. + * + * @param Request $request + * @param int $id + * @return \Illuminate\View\View + */ + public function viewDatabase(Request $request, $id) + { + $server = Models\Server::where('installed', 1)->with('databases.host')->findOrFail($id); + + return view('admin.servers.view.build', ['server' => $server]); + } + + /** + * Display the management page when viewing a specific server. + * + * @param Request $request + * @param int $id + * @return \Illuminate\View\View + */ + public function viewManage(Request $request, $id) + { + return view('admin.servers.view.manage', ['server' => Models\Server::findOrFail($id)]); + } + + /** + * Display the deletion page for a server. + * + * @param Request $request + * @param int $id + * @return \Illuminate\View\View + */ + public function viewDelete(Request $request, $id) + { + return view('admin.servers.view.delete', ['server' => Models\Server::withTrashed()->findOrFail($id)]); + } + + /** + * Update the details for a server. + * + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function setDetails(Request $request, $id) + { + $repo = new ServerRepository;; try { - $server = new ServerRepository; - $server->updateDetails($id, $request->intersect([ + $repo->updateDetails($id, $request->intersect([ 'owner_id', 'name', 'reset_token', ])); Alert::success('Server details were successfully updated.')->flash(); } catch (DisplayValidationException $ex) { - return redirect()->route('admin.servers.view', [ - 'id' => $id, - 'tab' => 'tab_details', - ])->withErrors(json_decode($ex->getMessage()))->withInput(); + return redirect()->route('admin.servers.view.details', $id)->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); } catch (\Exception $ex) { Log::error($ex); - Alert::danger('An unhandled exception occured while attemping to update this server. Please try again.')->flash(); + Alert::danger('An unhandled exception occured while attemping to update this server. This error has been logged.')->flash(); } - return redirect()->route('admin.servers.view', [ - 'id' => $id, - 'tab' => 'tab_details', - ])->withInput(); + return redirect()->route('admin.servers.view.details', $id)->withInput(); } - public function postUpdateContainerDetails(Request $request, $id) + /** + * Set the new docker container for a server. + * + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function setContainer(Request $request, $id) { + $repo = new ServerRepository; + try { - $server = new ServerRepository; - $server->updateContainer($id, $request->intersect('docker_image')); + $repo->updateContainer($id, $request->intersect('docker_image')); + Alert::success('Successfully updated this server\'s docker image.')->flash(); } catch (DisplayValidationException $ex) { - return redirect()->route('admin.servers.view', [ - 'id' => $id, - 'tab' => 'tab_details', - ])->withErrors(json_decode($ex->getMessage()))->withInput(); + return redirect()->route('admin.servers.view.details', $id)->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); } catch (\Exception $ex) { Log::error($ex); - Alert::danger('An unhandled exception occured while attemping to update this server\'s docker image. Please try again.')->flash(); + Alert::danger('An unhandled exception occured while attemping to update this server\'s docker image. This error has been logged.')->flash(); } - return redirect()->route('admin.servers.view', [ - 'id' => $id, - 'tab' => 'tab_details', - ]); + return redirect()->route('admin.servers.view.details', $id); } - public function postUpdateServerToggleBuild(Request $request, $id) + /** + * Toggles the install status for a server. + * + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function toggleInstall(Request $request, $id) + { + $repo = new ServerRepository; + try { + $repo->toggleInstall($id); + + Alert::success('Server install status was successfully toggled.')->flash(); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An unhandled exception occured while attemping to toggle this servers status. This error has been logged.')->flash(); + } + + return redirect()->route('admin.servers.view.manage', $id); + } + + /** + * Setup a server to have a container rebuild. + * + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function rebuildContainer(Request $request, $id) { $server = Models\Server::with('node')->findOrFail($id); try { - $res = $server->node->guzzleClient([ + $server->node->guzzleClient([ 'X-Access-Server' => $server->uuid, 'X-Access-Token' => $server->node->daemonSecret, ])->request('POST', '/server/rebuild'); + Alert::success('A rebuild has been queued successfully. It will run the next time this server is booted.')->flash(); - } catch (\GuzzleHttp\Exception\TransferException $ex) { + } catch (TransferException $ex) { Log::warning($ex); - Alert::danger('An error occured while attempting to toggle a rebuild.')->flash(); + Alert::danger('A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.')->flash(); } - return redirect()->route('admin.servers.view', [ - 'id' => $id, - 'tab' => 'tab_manage', - ]); + return redirect()->route('admin.servers.view.manage', $id); } - public function postUpdateServerUpdateBuild(Request $request, $id) + /** + * Manage the suspension status for a server. + * + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function manageSuspension(Request $request, $id) { + $repo = new ServerRepository; + $action = $request->input('action'); + + if (! in_array($action, ['suspend', 'unsuspend'])) { + Alert::danger('Invalid action was passed to function.')->flash(); + + return redirect()->route('admin.servers.view.manage', $id); + } + try { - $server = new ServerRepository; - $server->changeBuild($id, $request->intersect([ - 'allocation_id', 'add_allocations', - 'remove_allocations', 'memory', - 'swap', 'io', 'cpu', - ])); - Alert::success('Server details were successfully updated.')->flash(); - } catch (DisplayValidationException $ex) { - return redirect()->route('admin.servers.view', [ - 'id' => $id, - 'tab' => 'tab_build', - ])->withErrors(json_decode($ex->getMessage()))->withInput(); + $repo->$action($id); + + Alert::success('Server has been ' . $action . 'ed.'); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); - - return redirect()->route('admin.servers.view', [ - 'id' => $id, - 'tab' => 'tab_build', - ]); } catch (\Exception $ex) { Log::error($ex); - Alert::danger('An unhandled exception occured while attemping to add this server. Please try again.')->flash(); + Alert::danger('An unhandled exception occured while attemping to ' . $action . ' this server. This error has been logged.')->flash(); } - return redirect()->route('admin.servers.view', [ - 'id' => $id, - 'tab' => 'tab_build', - ]); + return redirect()->route('admin.servers.view.manage', $id); } - public function deleteServer(Request $request, $id, $force = null) + /** + * Update the build configuration for a server. + * + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function updateBuild(Request $request, $id) { + $repo = new ServerRepository; + try { - $server = new ServerRepository; - $server->deleteServer($id, $force); + $repo->changeBuild($id, $request->intersect([ + 'allocation_id', 'add_allocations', 'remove_allocations', + 'memory', 'swap', 'io', 'cpu', + ])); + + Alert::success('Server details were successfully updated.')->flash(); + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.servers.view.build', $id)->withErrors(json_decode($ex->getMessage()))->withInput(); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An unhandled exception occured while attemping to add this server. This error has been logged.')->flash(); + } + + return redirect()->route('admin.servers.view.build', $id); + } + + /** + * Start the server deletion process. + * + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function delete(Request $request, $id) + { + $repo = new ServerRepository; + + try { + $repo->queueDeletion($id, ($request->input('is_force') > 0)); Alert::success('Server has been marked for deletion on the system.')->flash(); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An unhandled exception occured while attemping to delete this server. This error has been logged.')->flash(); + } + + return redirect()->route('admin.servers.view.delete', $id); + } + + /** + * Cancels a pending server deletion request. + * + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function cancelDeletion(Request $request, $id) + { + $repo = new ServerRepository; + + $repo->cancelDeletion($id); + Alert::success('Server deletion has been cancelled. This server will remain suspended until you unsuspend it.')->flash(); + + return redirect()->route('admin.servers.view.delete', $id); + } + + /** + * Skips the queue and continues the server deletion process. + * + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function continueDeletion(Request $request, $id, $method) + { + $repo = new ServerRepository; + + try { + $repo->delete($id, (isset($method) && $method === 'force')); + Alert::success('Server was successfully deleted from the system.')->flash(); return redirect()->route('admin.servers'); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); + } catch (TransferException $ex) { + Log::warning($ex); + Alert::danger('A TransferException occurred while attempting to delete this server from the daemon, please ensure it is running. This error has been logged.')->flash(); } catch (\Exception $ex) { Log::error($ex); - Alert::danger('An unhandled exception occured while attemping to delete this server. Please try again.')->flash(); + Alert::danger('An unhandled exception occured while attemping to delete this server. This error has been logged.')->flash(); } - return redirect()->route('admin.servers.view', [ - 'id' => $id, - 'tab' => 'tab_delete', - ]); + return redirect()->route('admin.servers.view.delete', $id); } - public function postToggleInstall(Request $request, $id) - { - try { - $server = new ServerRepository; - $server->toggleInstall($id); - Alert::success('Server status was successfully toggled.')->flash(); - } catch (DisplayException $ex) { - Alert::danger($ex->getMessage())->flash(); - } catch (\Exception $ex) { - Log::error($ex); - Alert::danger('An unhandled exception occured while attemping to toggle this servers status.')->flash(); - } finally { - return redirect()->route('admin.servers.view', [ - 'id' => $id, - 'tab' => 'tab_manage', - ]); - } - } - - 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(); - } - } - - public function postDatabase(Request $request, $id) - { - try { - $repo = new DatabaseRepository; - $repo->create($id, $request->only([ - 'db_server', 'database', 'remote', - ])); - Alert::success('Added new database to this server.')->flash(); - } catch (DisplayValidationException $ex) { - return redirect()->route('admin.servers.view', [ - 'id' => $id, - 'tab' => 'tab_database', - ])->withInput()->withErrors(json_decode($ex->getMessage()))->withInput(); - } catch (\Exception $ex) { - Log::error($ex); - Alert::danger('An exception occured while attempting to add a new database for this server.')->flash(); - } - - return redirect()->route('admin.servers.view', [ - 'id' => $id, - 'tab' => 'tab_database', - ])->withInput(); - } - - public function postSuspendServer(Request $request, $id) - { - try { - $repo = new ServerRepository; - $repo->suspend($id); - Alert::success('Server has been suspended on the system. All running processes have been stopped and will not be startable until it is un-suspended.'); - } catch (DisplayException $e) { - Alert::danger($e->getMessage())->flash(); - } catch (\Exception $e) { - Log::error($e); - Alert::danger('An unhandled exception occured while attemping to suspend this server. Please try again.')->flash(); - } finally { - return redirect()->route('admin.servers.view', [ - 'id' => $id, - 'tab' => 'tab_manage', - ]); - } - } - - public function postUnsuspendServer(Request $request, $id) - { - try { - $repo = new ServerRepository; - $repo->unsuspend($id); - Alert::success('Server has been unsuspended on the system. Access has been re-enabled.'); - } catch (DisplayException $e) { - Alert::danger($e->getMessage())->flash(); - } catch (\Exception $e) { - Log::error($e); - Alert::danger('An unhandled exception occured while attemping to unsuspend this server. Please try again.')->flash(); - } finally { - return redirect()->route('admin.servers.view', [ - 'id' => $id, - 'tab' => 'tab_manage', - ]); - } - } - - public function postQueuedDeletionHandler(Request $request, $id) - { - try { - $repo = new ServerRepository; - if (! is_null($request->input('cancel'))) { - $repo->cancelDeletion($id); - Alert::success('Server deletion has been cancelled. This server will remain suspended until you unsuspend it.')->flash(); - - return redirect()->route('admin.servers.view', $id); - } elseif (! is_null($request->input('delete'))) { - $repo->deleteNow($id); - Alert::success('Server was successfully deleted from the system.')->flash(); - - return redirect()->route('admin.servers'); - } elseif (! is_null($request->input('force_delete'))) { - $repo->deleteNow($id, true); - Alert::success('Server was successfully force deleted from the system.')->flash(); - - return redirect()->route('admin.servers'); - } - } catch (DisplayException $ex) { - Alert::danger($ex->getMessage())->flash(); - - return redirect()->route('admin.servers.view', $id); - } catch (\Exception $ex) { - Log::error($ex); - Alert::danger('An unhandled error occured while attempting to perform this action.')->flash(); - - return redirect()->route('admin.servers.view', $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(); + // } + // } + // + // public function postDatabase(Request $request, $id) + // { + // try { + // $repo = new DatabaseRepository; + // $repo->create($id, $request->only([ + // 'db_server', 'database', 'remote', + // ])); + // Alert::success('Added new database to this server.')->flash(); + // } catch (DisplayValidationException $ex) { + // return redirect()->route('admin.servers.view', [ + // 'id' => $id, + // 'tab' => 'tab_database', + // ])->withInput()->withErrors(json_decode($ex->getMessage()))->withInput(); + // } catch (\Exception $ex) { + // Log::error($ex); + // Alert::danger('An exception occured while attempting to add a new database for this server.')->flash(); + // } + // + // return redirect()->route('admin.servers.view', [ + // 'id' => $id, + // 'tab' => 'tab_database', + // ])->withInput(); + // } + // // } diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index bf6b44bfa..6cdc18e4e 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -121,89 +121,103 @@ class AdminRoutes // View All Servers $router->get('/', [ 'as' => 'admin.servers', - 'uses' => 'Admin\ServersController@getIndex', ]); + 'uses' => 'Admin\ServersController@index', + ]); // View Create Server Page $router->get('/new', [ 'as' => 'admin.servers.new', - 'uses' => 'Admin\ServersController@getNew', + 'uses' => 'Admin\ServersController@new', ]); // Handle POST Request for Creating Server $router->post('/new', [ - 'uses' => 'Admin\ServersController@postNewServer', + 'uses' => 'Admin\ServersController@create', ]); // Assorted Page Helpers - $router->post('/new/get-nodes', [ - 'as' => 'admin.servers.new.get-nodes', - 'uses' => 'Admin\ServersController@postNewServerGetNodes', + $router->post('/new/nodes', [ + 'as' => 'admin.servers.new.nodes', + 'uses' => 'Admin\ServersController@newServerNodes', ]); - // View Specific Server $router->get('/view/{id}', [ 'as' => 'admin.servers.view', - 'uses' => 'Admin\ServersController@getView', + 'uses' => 'Admin\ServersController@viewIndex', ]); - // Database Stuffs - $router->post('/view/{id}/database', [ - 'as' => 'admin.servers.database', - 'uses' => 'Admin\ServersController@postDatabase', - ]); - - // Change Server Details - $router->post('/view/{id}/details', [ + $router->get('/view/{id}/details', [ 'as' => 'admin.servers.view.details', - 'uses' => 'Admin\ServersController@postUpdateServerDetails', + 'uses' => 'Admin\ServersController@viewDetails', ]); - // Change Server Details - $router->post('/view/{id}/container', [ - 'as' => 'admin.servers.post.container', - 'uses' => 'Admin\ServersController@postUpdateContainerDetails', + $router->post('/view/{id}/details', [ + 'uses' => 'Admin\ServersController@setDetails', ]); - // Change Server Details - $router->post('/view/{id}/startup', [ - 'as' => 'admin.servers.post.startup', - 'uses' => 'Admin\ServersController@postUpdateServerStartup', + $router->post('/view/{id}/details/container', [ + 'as' => 'admin.servers.view.details.container', + 'uses' => 'Admin\ServersController@setContainer', ]); - // Rebuild Server - $router->post('/view/{id}/rebuild', [ - 'uses' => 'Admin\ServersController@postUpdateServerToggleBuild', + $router->get('/view/{id}/build', [ + 'as' => 'admin.servers.view.build', + 'uses' => 'Admin\ServersController@viewBuild', ]); - // Change Build Details $router->post('/view/{id}/build', [ - 'uses' => 'Admin\ServersController@postUpdateServerUpdateBuild', + 'uses' => 'Admin\ServersController@updateBuild', ]); - // Suspend Server - $router->post('/view/{id}/suspend', [ - 'uses' => 'Admin\ServersController@postSuspendServer', + $router->get('/view/{id}/startup', [ + 'as' => 'admin.servers.view.startup', + 'uses' => 'Admin\ServersController@viewStartup', ]); - // Unsuspend Server - $router->post('/view/{id}/unsuspend', [ - 'uses' => 'Admin\ServersController@postUnsuspendServer', + $router->get('/view/{id}/database', [ + 'as' => 'admin.servers.view.database', + 'uses' => 'Admin\ServersController@viewDatabase', ]); - // Change Install Status - $router->post('/view/{id}/installed', [ - 'uses' => 'Admin\ServersController@postToggleInstall', + $router->get('/view/{id}/manage', [ + 'as' => 'admin.servers.view.manage', + 'uses' => 'Admin\ServersController@viewManage', ]); - // Delete [force delete] - $router->delete('/view/{id}/{force?}', [ - 'uses' => 'Admin\ServersController@deleteServer', + $router->post('/view/{id}/manage/toggle', [ + 'as' => 'admin.servers.view.manage.toggle', + 'uses' => 'Admin\ServersController@toggleInstall', ]); - $router->post('/view/{id}/queuedDeletion', [ - 'uses' => 'Admin\ServersController@postQueuedDeletionHandler', - 'as' => 'admin.servers.post.queuedDeletion', + $router->post('/view/{id}/manage/rebuild', [ + 'as' => 'admin.servers.view.manage.rebuild', + 'uses' => 'Admin\ServersController@rebuildContainer', ]); + + $router->post('/view/{id}/manage/suspension', [ + 'as' => 'admin.servers.view.manage.suspension', + 'uses' => 'Admin\ServersController@manageSuspension', + ]); + + $router->get('/view/{id}/delete', [ + 'as' => 'admin.servers.view.delete', + 'uses' => 'Admin\ServersController@viewDelete', + ]); + + $router->post('/view/{id}/delete', [ + 'uses' => 'Admin\ServersController@delete', + ]); + + $router->post('/view/{id}/delete/continue/{force?}', [ + 'as' => 'admin.servers.view.delete.continue', + 'uses' => 'Admin\ServersController@continueDeletion', + ]); + + $router->post('/view/{id}/delete/cancel', [ + 'as' => 'admin.servers.view.delete.cancel', + 'uses' => 'Admin\ServersController@cancelDeletion', + ]); + }); // Node Routes diff --git a/app/Jobs/DeleteServer.php b/app/Jobs/DeleteServer.php index a42637ff2..16d04b4ba 100644 --- a/app/Jobs/DeleteServer.php +++ b/app/Jobs/DeleteServer.php @@ -58,6 +58,6 @@ class DeleteServer extends Job implements ShouldQueue public function handle() { $repo = new ServerRepository; - $repo->deleteNow($this->id); + $repo->delete($this->id); } } diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php index 5d919a559..5b746a7b6 100644 --- a/app/Observers/ServerObserver.php +++ b/app/Observers/ServerObserver.php @@ -41,8 +41,8 @@ class ServerObserver /** * Listen to the Server creating event. * - * @param Server $server [description] - * @return [type] [description] + * @param Server $server The server model. + * @return void */ public function creating(Server $server) { @@ -52,8 +52,8 @@ class ServerObserver /** * Listen to the Server created event. * - * @param Server $server [description] - * @return [type] [description] + * @param Server $server The server model. + * @return void */ public function created(Server $server) { @@ -73,8 +73,8 @@ class ServerObserver /** * Listen to the Server deleting event. * - * @param Server $server [description] - * @return [type] [description] + * @param Server $server The server model. + * @return void */ public function deleting(Server $server) { @@ -86,8 +86,8 @@ class ServerObserver /** * Listen to the Server deleted event. * - * @param Server $server [description] - * @return [type] [description] + * @param Server $server The server model. + * @return void */ public function deleted(Server $server) { @@ -103,8 +103,8 @@ class ServerObserver /** * Listen to the Server saving event. * - * @param Server $server [description] - * @return [type] [description] + * @param Server $server The server model. + * @return void */ public function saving(Server $server) { @@ -114,8 +114,8 @@ class ServerObserver /** * Listen to the Server saved event. * - * @param Server $server [description] - * @return [type] [description] + * @param Server $server The server model. + * @return void */ public function saved(Server $server) { @@ -123,10 +123,10 @@ class ServerObserver } /** - * Listen to the Server saving event. + * Listen to the Server updating event. * - * @param Server $server [description] - * @return [type] [description] + * @param Server $server The server model. + * @return void */ public function updating(Server $server) { @@ -136,8 +136,8 @@ class ServerObserver /** * Listen to the Server saved event. * - * @param Server $server [description] - * @return [type] [description] + * @param Server $server The server model. + * @return void */ public function updated(Server $server) { diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 8d3bfa8dc..c8063b384 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -352,7 +352,7 @@ class ServerRepository // Validate Fields $validator = Validator::make($data, [ - 'owner_id' => 'sometimes|required|numeric|exists:users,id', + 'owner_id' => 'sometimes|required|integer|exists:users,id', 'name' => 'sometimes|required|regex:([\w .-]{1,200})', 'reset_token' => 'sometimes|required|accepted', ]); @@ -369,14 +369,14 @@ class ServerRepository $server = Models\Server::with('user')->findOrFail($id); // Update daemon secret if it was passed. - if (isset($data['reset_token']) || (isset($data['owner_id']) && $data['owner_id'] !== $server->user->id)) { + if (isset($data['reset_token']) || (isset($data['owner_id']) && (int) $data['owner_id'] !== $server->user->id)) { $oldDaemonKey = $server->daemonSecret; $server->daemonSecret = $uuid->generate('servers', 'daemonSecret'); $resetDaemonKey = true; } // Update Server Owner if it was passed. - if (isset($data['owner_id']) && $data['owner_id'] !== $server->user->id) { + if (isset($data['owner_id']) && (int) $data['owner_id'] !== $server->user->id) { $server->owner_id = $data['owner_id']; } @@ -463,7 +463,7 @@ class ServerRepository return true; } catch (TransferException $ex) { DB::rollBack(); - throw new DisplayException('An error occured while attempting to update the container image.', $ex); + throw new DisplayException('A TransferException occured while attempting to update the container image. Is the daemon online? This error has been logged.', $ex); } catch (\Exception $ex) { DB::rollBack(); throw $ex; @@ -590,7 +590,6 @@ class ServerRepository // This won't be committed unless the HTTP request succeedes anyways $server->save(); - dd($newBuild); if (! empty($newBuild)) { $server->node->guzzleClient([ 'X-Access-Server' => $server->uuid, @@ -607,7 +606,7 @@ class ServerRepository return $server; } catch (TransferException $ex) { DB::rollBack(); - throw new DisplayException('An error occured while attempting to update the configuration.', $ex); + throw new DisplayException('A TransferException occured while attempting to update the server configuration, check that the daemon is online. This error has been logged.', $ex); } catch (\Exception $ex) { DB::rollBack(); throw $ex; @@ -723,13 +722,13 @@ class ServerRepository } } - public function deleteServer($id, $force) + public function queueDeletion($id, $force = false) { $server = Models\Server::findOrFail($id); DB::beginTransaction(); try { - if ($force === 'force' || $force) { + if ($force) { $server->installed = 3; $server->save(); } @@ -743,7 +742,7 @@ class ServerRepository } } - public function deleteNow($id, $force = false) + public function delete($id, $force = false) { $server = Models\Server::withTrashed()->with('node')->findOrFail($id); @@ -819,8 +818,8 @@ class ServerRepository public function toggleInstall($id) { $server = Models\Server::findOrFail($id); - if ($server->installed === 2) { - throw new DisplayException('This server was marked as having a failed install, you cannot override this.'); + if ($server->installed > 1) { + throw new DisplayException('This server was marked as having a failed install or being deleted, you cannot override this.'); } $server->installed = ! $server->installed; diff --git a/public/js/laroute.js b/public/js/laroute.js index f074f2812..09ff8ad96 100644 --- a/public/js/laroute.js +++ b/public/js/laroute.js @@ -6,7 +6,7 @@ absolute: false, rootUrl: 'http://pterodactyl.app', - routes : [{"host":null,"methods":["GET","HEAD"],"uri":"admin","name":"admin.index","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/settings","name":"admin.settings","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getSettings"},{"host":null,"methods":["POST"],"uri":"admin\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\BaseController@postSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users","name":"admin.users","action":"Pterodactyl\Http\Controllers\Admin\UserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/accounts.json","name":"admin.users.json","action":"Pterodactyl\Http\Controllers\Admin\UserController@getJson"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/view\/{id}","name":"admin.users.view","action":"Pterodactyl\Http\Controllers\Admin\UserController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@updateUser"},{"host":null,"methods":["DELETE"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@deleteUser"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/new","name":"admin.users.new","action":"Pterodactyl\Http\Controllers\Admin\UserController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers","name":"admin.servers","action":"Pterodactyl\Http\Controllers\Admin\ServersController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/new","name":"admin.servers.new","action":"Pterodactyl\Http\Controllers\Admin\ServersController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/get-nodes","name":"admin.servers.new.get-nodes","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postNewServerGetNodes"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}","name":"admin.servers.view","action":"Pterodactyl\Http\Controllers\Admin\ServersController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/database","name":"admin.servers.database","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postDatabase"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details","name":"admin.servers.view.details","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/container","name":"admin.servers.post.container","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateContainerDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/startup","name":"admin.servers.post.startup","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerStartup"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/rebuild","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerToggleBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/build","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUpdateServerUpdateBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/suspend","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postSuspendServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/unsuspend","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postUnsuspendServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/installed","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@postToggleInstall"},{"host":null,"methods":["DELETE"],"uri":"admin\/servers\/view\/{id}\/{force?}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@deleteServer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/queuedDeletion","name":"admin.servers.post.queuedDeletion","action":"Pterodactyl\Http\Controllers\Admin\ServersController@postQueuedDeletionHandler"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes","name":"admin.nodes","action":"Pterodactyl\Http\Controllers\Admin\NodesController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/new","name":"admin.nodes.new","action":"Pterodactyl\Http\Controllers\Admin\NodesController@new"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.view","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings","name":"admin.nodes.view.settings","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewSettings"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@updateSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/configuration","name":"admin.nodes.view.configuration","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":"admin.nodes.view.allocation","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewAllocation"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@createAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/servers","name":"admin.nodes.view.servers","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewServers"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/delete","name":"admin.nodes.view.delete","action":"Pterodactyl\Http\Controllers\Admin\NodesController@delete"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove\/{allocation}","name":"admin.nodes.view.allocation.removeSingle","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveSingle"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove","name":"admin.nodes.view.allocation.removeBlock","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveBlock"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/alias","name":"admin.nodes.view.allocation.setAlias","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationSetAlias"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings\/token","name":"admin.nodes.view.configuration.token","action":"Pterodactyl\Http\Controllers\Admin\NodesController@setToken"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/locations","name":"admin.locations","action":"Pterodactyl\Http\Controllers\Admin\LocationsController@getIndex"},{"host":null,"methods":["DELETE"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@deleteLocation"},{"host":null,"methods":["PATCH"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@patchLocation"},{"host":null,"methods":["POST"],"uri":"admin\/locations","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@postLocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases","name":"admin.databases","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases\/new","name":"admin.databases.new","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/databases\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@postNew"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete\/{id}","name":"admin.databases.delete","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteDatabase"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete-server\/{id}","name":"admin.databases.delete-server","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteServer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services","name":"admin.services","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/new","name":"admin.services.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/services\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}","name":"admin.services.service","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getService"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postService"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}\/configuration","name":"admin.services.service.config","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getConfiguration"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}\/configuration","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/new","name":"admin.services.option.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@newOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":"admin.services.option","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOption"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{service}\/option\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":"admin.services.option.variable.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}","name":"admin.services.option.variable","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOptionVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}\/delete","name":"admin.services.option.variable.delete","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/new\/{option?}","name":"admin.services.packs.new","action":"Pterodactyl\Http\Controllers\Admin\PackController@new"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/upload\/{option?}","name":"admin.services.packs.uploadForm","action":"Pterodactyl\Http\Controllers\Admin\PackController@uploadForm"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/upload","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@postUpload"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs","name":"admin.services.packs","action":"Pterodactyl\Http\Controllers\Admin\PackController@listAll"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/option\/{option}","name":"admin.services.packs.option","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/service\/{service}","name":"admin.services.packs.service","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}","name":"admin.services.packs.edit","action":"Pterodactyl\Http\Controllers\Admin\PackController@edit"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/edit\/{pack}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}\/export\/{archive?}","name":"admin.services.packs.export","action":"Pterodactyl\Http\Controllers\Admin\PackController@export"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login","name":"auth.login","action":"Pterodactyl\Http\Controllers\Auth\LoginController@showLoginForm"},{"host":null,"methods":["POST"],"uri":"auth\/login","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@login"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login\/totp","name":"auth.totp","action":"Pterodactyl\Http\Controllers\Auth\LoginController@totp"},{"host":null,"methods":["POST"],"uri":"auth\/login\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@totpCheckpoint"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password","name":"auth.password","action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm"},{"host":null,"methods":["POST"],"uri":"auth\/password","name":null,"action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password\/reset\/{token}","name":"auth.reset","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@showResetForm"},{"host":null,"methods":["POST"],"uri":"auth\/password\/reset","name":"auth.reset.post","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@reset"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/logout","name":"auth.logout","action":"Pterodactyl\Http\Controllers\Auth\LoginController@logout"},{"host":null,"methods":["GET","HEAD"],"uri":"\/","name":"index","action":"Pterodactyl\Http\Controllers\Base\IndexController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"index","name":null,"action":"Closure"},{"host":null,"methods":["GET","HEAD"],"uri":"password-gen\/{length}","name":"password-gen","action":"Pterodactyl\Http\Controllers\Base\IndexController@getPassword"},{"host":null,"methods":["GET","HEAD"],"uri":"account","name":"account","action":"Pterodactyl\Http\Controllers\Base\AccountController@index"},{"host":null,"methods":["POST"],"uri":"account","name":null,"action":"Pterodactyl\Http\Controllers\Base\AccountController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api","name":"account.api","action":"Pterodactyl\Http\Controllers\Base\APIController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api\/new","name":"account.api.new","action":"Pterodactyl\Http\Controllers\Base\APIController@create"},{"host":null,"methods":["POST"],"uri":"account\/api\/new","name":null,"action":"Pterodactyl\Http\Controllers\Base\APIController@save"},{"host":null,"methods":["DELETE"],"uri":"account\/api\/revoke\/{key}","name":"account.api.revoke","action":"Pterodactyl\Http\Controllers\Base\APIController@revoke"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security","name":"account.security","action":"Pterodactyl\Http\Controllers\Base\SecurityController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security\/revoke\/{id}","name":"account.security.revoke","action":"Pterodactyl\Http\Controllers\Base\SecurityController@revoke"},{"host":null,"methods":["PUT"],"uri":"account\/security\/totp","name":"account.security.totp","action":"Pterodactyl\Http\Controllers\Base\SecurityController@generateTotp"},{"host":null,"methods":["POST"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@setTotp"},{"host":null,"methods":["DELETE"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@disableTotp"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services","name":"daemon.services","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@list"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services\/pull\/{service}\/{file}","name":"remote.install","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}","name":"daemon.pack.pull","action":"Pterodactyl\Http\Controllers\Daemon\PackController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}\/hash","name":"daemon.pack.hash","action":"Pterodactyl\Http\Controllers\Daemon\PackController@hash"},{"host":null,"methods":["GET","HEAD"],"uri":"language\/{lang}","name":"langauge.set","action":"Pterodactyl\Http\Controllers\Base\LanguageController@setLanguage"},{"host":null,"methods":["POST"],"uri":"remote\/download","name":"remote.download","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postDownload"},{"host":null,"methods":["POST"],"uri":"remote\/install","name":"remote.install","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postInstall"},{"host":null,"methods":["GET","HEAD"],"uri":"remote\/configuration\/{token}","name":"remote.configuration","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@getConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/ajax\/status","name":"server.ajax.status","action":"Pterodactyl\Http\Controllers\Server\AjaxController@getStatus"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}","name":"server.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/databases","name":"server.settings.databases","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDatabases"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/sftp","name":"server.settings.sftp","action":"Pterodactyl\Http\Controllers\Server\ServerController@getSFTP"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/sftp","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsSFTP"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/startup","name":"server.settings.startup","action":"Pterodactyl\Http\Controllers\Server\ServerController@getStartup"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/allocation","name":"server.settings.allocation","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files","name":"server.files.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getFiles"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/edit\/{file}","name":"server.files.edit","action":"Pterodactyl\Http\Controllers\Server\ServerController@getEditFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/download\/{file}","name":"server.files.download","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDownloadFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/add","name":"server.files.add","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAddFile"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/directory-list","name":"server.files.directory-list","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postDirectoryList"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/save","name":"server.files.save","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSaveFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users","name":"server.subusers","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/new","name":"server.subusers.new","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/view\/{id}","name":"server.subusers.view","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getView"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postView"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/users\/delete\/{id}","name":"server.subusers.delete","action":"Pterodactyl\Http\Controllers\Server\SubuserController@deleteSubuser"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks","name":"server.tasks","action":"Pterodactyl\Http\Controllers\Server\TaskController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/view\/{id}","name":"server.tasks.view","action":"Pterodactyl\Http\Controllers\Server\TaskController@getView"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/new","name":"server.tasks.new","action":"Pterodactyl\Http\Controllers\Server\TaskController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\TaskController@postNew"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/tasks\/delete\/{id}","name":"server.tasks.delete","action":"Pterodactyl\Http\Controllers\Server\TaskController@deleteTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/toggle\/{id}","name":"server.tasks.toggle","action":"Pterodactyl\Http\Controllers\Server\TaskController@toggleTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/set-primary","name":null,"action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSetPrimary"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/settings\/reset-database-password","name":"server.ajax.reset-database-password","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postResetDatabasePassword"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/open","name":"debugbar.openhandler","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@handle"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/clockwork\/{id}","name":"debugbar.clockwork","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@clockwork"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/stylesheets","name":"debugbar.assets.css","action":"Barryvdh\Debugbar\Controllers\AssetController@css"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/javascript","name":"debugbar.assets.js","action":"Barryvdh\Debugbar\Controllers\AssetController@js"}], + routes : [{"host":null,"methods":["GET","HEAD"],"uri":"admin","name":"admin.index","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/settings","name":"admin.settings","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getSettings"},{"host":null,"methods":["POST"],"uri":"admin\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\BaseController@postSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users","name":"admin.users","action":"Pterodactyl\Http\Controllers\Admin\UserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/accounts.json","name":"admin.users.json","action":"Pterodactyl\Http\Controllers\Admin\UserController@getJson"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/view\/{id}","name":"admin.users.view","action":"Pterodactyl\Http\Controllers\Admin\UserController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@updateUser"},{"host":null,"methods":["DELETE"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@deleteUser"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/new","name":"admin.users.new","action":"Pterodactyl\Http\Controllers\Admin\UserController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers","name":"admin.servers","action":"Pterodactyl\Http\Controllers\Admin\ServersController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/new","name":"admin.servers.new","action":"Pterodactyl\Http\Controllers\Admin\ServersController@new"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@create"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/nodes","name":"admin.servers.new.nodes","action":"Pterodactyl\Http\Controllers\Admin\ServersController@newServerNodes"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}","name":"admin.servers.view","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/details","name":"admin.servers.view.details","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@setDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details\/container","name":"admin.servers.view.details.container","action":"Pterodactyl\Http\Controllers\Admin\ServersController@setContainer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/build","name":"admin.servers.view.build","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/build","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@updateBuild"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/startup","name":"admin.servers.view.startup","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/database","name":"admin.servers.view.database","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDatabase"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/manage","name":"admin.servers.view.manage","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewManage"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/toggle","name":"admin.servers.view.manage.toggle","action":"Pterodactyl\Http\Controllers\Admin\ServersController@toggleInstall"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/rebuild","name":"admin.servers.view.manage.rebuild","action":"Pterodactyl\Http\Controllers\Admin\ServersController@rebuildContainer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/suspension","name":"admin.servers.view.manage.suspension","action":"Pterodactyl\Http\Controllers\Admin\ServersController@manageSuspension"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/delete","name":"admin.servers.view.delete","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDelete"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@delete"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete\/continue\/{force?}","name":"admin.servers.view.delete.continue","action":"Pterodactyl\Http\Controllers\Admin\ServersController@continueDeletion"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete\/cancel","name":"admin.servers.view.delete.cancel","action":"Pterodactyl\Http\Controllers\Admin\ServersController@cancelDeletion"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes","name":"admin.nodes","action":"Pterodactyl\Http\Controllers\Admin\NodesController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/new","name":"admin.nodes.new","action":"Pterodactyl\Http\Controllers\Admin\NodesController@new"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.view","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings","name":"admin.nodes.view.settings","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewSettings"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@updateSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/configuration","name":"admin.nodes.view.configuration","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":"admin.nodes.view.allocation","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewAllocation"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@createAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/servers","name":"admin.nodes.view.servers","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewServers"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/delete","name":"admin.nodes.view.delete","action":"Pterodactyl\Http\Controllers\Admin\NodesController@delete"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove\/{allocation}","name":"admin.nodes.view.allocation.removeSingle","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveSingle"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove","name":"admin.nodes.view.allocation.removeBlock","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveBlock"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/alias","name":"admin.nodes.view.allocation.setAlias","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationSetAlias"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings\/token","name":"admin.nodes.view.configuration.token","action":"Pterodactyl\Http\Controllers\Admin\NodesController@setToken"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/locations","name":"admin.locations","action":"Pterodactyl\Http\Controllers\Admin\LocationsController@getIndex"},{"host":null,"methods":["DELETE"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@deleteLocation"},{"host":null,"methods":["PATCH"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@patchLocation"},{"host":null,"methods":["POST"],"uri":"admin\/locations","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@postLocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases","name":"admin.databases","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases\/new","name":"admin.databases.new","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/databases\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@postNew"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete\/{id}","name":"admin.databases.delete","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteDatabase"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete-server\/{id}","name":"admin.databases.delete-server","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteServer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services","name":"admin.services","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/new","name":"admin.services.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/services\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}","name":"admin.services.service","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getService"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postService"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}\/configuration","name":"admin.services.service.config","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getConfiguration"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}\/configuration","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/new","name":"admin.services.option.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@newOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":"admin.services.option","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOption"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{service}\/option\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":"admin.services.option.variable.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}","name":"admin.services.option.variable","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOptionVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}\/delete","name":"admin.services.option.variable.delete","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/new\/{option?}","name":"admin.services.packs.new","action":"Pterodactyl\Http\Controllers\Admin\PackController@new"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/upload\/{option?}","name":"admin.services.packs.uploadForm","action":"Pterodactyl\Http\Controllers\Admin\PackController@uploadForm"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/upload","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@postUpload"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs","name":"admin.services.packs","action":"Pterodactyl\Http\Controllers\Admin\PackController@listAll"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/option\/{option}","name":"admin.services.packs.option","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/service\/{service}","name":"admin.services.packs.service","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}","name":"admin.services.packs.edit","action":"Pterodactyl\Http\Controllers\Admin\PackController@edit"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/edit\/{pack}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}\/export\/{archive?}","name":"admin.services.packs.export","action":"Pterodactyl\Http\Controllers\Admin\PackController@export"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login","name":"auth.login","action":"Pterodactyl\Http\Controllers\Auth\LoginController@showLoginForm"},{"host":null,"methods":["POST"],"uri":"auth\/login","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@login"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login\/totp","name":"auth.totp","action":"Pterodactyl\Http\Controllers\Auth\LoginController@totp"},{"host":null,"methods":["POST"],"uri":"auth\/login\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@totpCheckpoint"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password","name":"auth.password","action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm"},{"host":null,"methods":["POST"],"uri":"auth\/password","name":null,"action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password\/reset\/{token}","name":"auth.reset","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@showResetForm"},{"host":null,"methods":["POST"],"uri":"auth\/password\/reset","name":"auth.reset.post","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@reset"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/logout","name":"auth.logout","action":"Pterodactyl\Http\Controllers\Auth\LoginController@logout"},{"host":null,"methods":["GET","HEAD"],"uri":"\/","name":"index","action":"Pterodactyl\Http\Controllers\Base\IndexController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"index","name":null,"action":"Closure"},{"host":null,"methods":["GET","HEAD"],"uri":"password-gen\/{length}","name":"password-gen","action":"Pterodactyl\Http\Controllers\Base\IndexController@getPassword"},{"host":null,"methods":["GET","HEAD"],"uri":"account","name":"account","action":"Pterodactyl\Http\Controllers\Base\AccountController@index"},{"host":null,"methods":["POST"],"uri":"account","name":null,"action":"Pterodactyl\Http\Controllers\Base\AccountController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api","name":"account.api","action":"Pterodactyl\Http\Controllers\Base\APIController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api\/new","name":"account.api.new","action":"Pterodactyl\Http\Controllers\Base\APIController@create"},{"host":null,"methods":["POST"],"uri":"account\/api\/new","name":null,"action":"Pterodactyl\Http\Controllers\Base\APIController@save"},{"host":null,"methods":["DELETE"],"uri":"account\/api\/revoke\/{key}","name":"account.api.revoke","action":"Pterodactyl\Http\Controllers\Base\APIController@revoke"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security","name":"account.security","action":"Pterodactyl\Http\Controllers\Base\SecurityController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security\/revoke\/{id}","name":"account.security.revoke","action":"Pterodactyl\Http\Controllers\Base\SecurityController@revoke"},{"host":null,"methods":["PUT"],"uri":"account\/security\/totp","name":"account.security.totp","action":"Pterodactyl\Http\Controllers\Base\SecurityController@generateTotp"},{"host":null,"methods":["POST"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@setTotp"},{"host":null,"methods":["DELETE"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@disableTotp"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services","name":"daemon.services","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@list"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services\/pull\/{service}\/{file}","name":"remote.install","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}","name":"daemon.pack.pull","action":"Pterodactyl\Http\Controllers\Daemon\PackController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}\/hash","name":"daemon.pack.hash","action":"Pterodactyl\Http\Controllers\Daemon\PackController@hash"},{"host":null,"methods":["GET","HEAD"],"uri":"language\/{lang}","name":"langauge.set","action":"Pterodactyl\Http\Controllers\Base\LanguageController@setLanguage"},{"host":null,"methods":["POST"],"uri":"remote\/download","name":"remote.download","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postDownload"},{"host":null,"methods":["POST"],"uri":"remote\/install","name":"remote.install","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postInstall"},{"host":null,"methods":["GET","HEAD"],"uri":"remote\/configuration\/{token}","name":"remote.configuration","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@getConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/ajax\/status","name":"server.ajax.status","action":"Pterodactyl\Http\Controllers\Server\AjaxController@getStatus"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}","name":"server.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/databases","name":"server.settings.databases","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDatabases"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/sftp","name":"server.settings.sftp","action":"Pterodactyl\Http\Controllers\Server\ServerController@getSFTP"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/sftp","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsSFTP"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/startup","name":"server.settings.startup","action":"Pterodactyl\Http\Controllers\Server\ServerController@getStartup"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/allocation","name":"server.settings.allocation","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files","name":"server.files.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getFiles"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/edit\/{file}","name":"server.files.edit","action":"Pterodactyl\Http\Controllers\Server\ServerController@getEditFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/download\/{file}","name":"server.files.download","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDownloadFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/add","name":"server.files.add","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAddFile"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/directory-list","name":"server.files.directory-list","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postDirectoryList"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/save","name":"server.files.save","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSaveFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users","name":"server.subusers","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/new","name":"server.subusers.new","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/view\/{id}","name":"server.subusers.view","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getView"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postView"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/users\/delete\/{id}","name":"server.subusers.delete","action":"Pterodactyl\Http\Controllers\Server\SubuserController@deleteSubuser"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks","name":"server.tasks","action":"Pterodactyl\Http\Controllers\Server\TaskController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/view\/{id}","name":"server.tasks.view","action":"Pterodactyl\Http\Controllers\Server\TaskController@getView"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/new","name":"server.tasks.new","action":"Pterodactyl\Http\Controllers\Server\TaskController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\TaskController@postNew"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/tasks\/delete\/{id}","name":"server.tasks.delete","action":"Pterodactyl\Http\Controllers\Server\TaskController@deleteTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/toggle\/{id}","name":"server.tasks.toggle","action":"Pterodactyl\Http\Controllers\Server\TaskController@toggleTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/set-primary","name":null,"action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSetPrimary"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/settings\/reset-database-password","name":"server.ajax.reset-database-password","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postResetDatabasePassword"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/open","name":"debugbar.openhandler","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@handle"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/clockwork\/{id}","name":"debugbar.clockwork","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@clockwork"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/stylesheets","name":"debugbar.assets.css","action":"Barryvdh\Debugbar\Controllers\AssetController@css"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/javascript","name":"debugbar.assets.js","action":"Barryvdh\Debugbar\Controllers\AssetController@js"}], prefix: '', route : function (name, parameters, route) { diff --git a/public/themes/pterodactyl/css/pterodactyl.css b/public/themes/pterodactyl/css/pterodactyl.css index 07b16522b..c4b1cf256 100644 --- a/public/themes/pterodactyl/css/pterodactyl.css +++ b/public/themes/pterodactyl/css/pterodactyl.css @@ -141,8 +141,8 @@ li.select2-results__option--highlighted[aria-selected="false"] > .user-block > . color: #eee; } -.select2-container--default .select2-selection--multiple .select2-selection__choice { - margin: 2.5px; +.select2-selection.select2-selection--multiple { + min-height: 36px !important; } .select2-search--inline .select2-search__field:focus { diff --git a/public/themes/pterodactyl/js/admin/new-server.js b/public/themes/pterodactyl/js/admin/new-server.js index 2b6b1b8ba..3e82cb1ad 100644 --- a/public/themes/pterodactyl/js/admin/new-server.js +++ b/public/themes/pterodactyl/js/admin/new-server.js @@ -111,7 +111,7 @@ $('#pLocationId').on('change', function (event) { $.ajax({ method: 'POST', - url: Router.route('admin.servers.new.get-nodes'), + url: Router.route('admin.servers.new.nodes'), headers: { 'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content') }, data: { location: currentLocation }, }).done(function (data) { diff --git a/resources/themes/pterodactyl/admin/servers/view.blade.php b/resources/themes/pterodactyl/admin/servers/view.blade.php deleted file mode 100644 index 5818f9510..000000000 --- a/resources/themes/pterodactyl/admin/servers/view.blade.php +++ /dev/null @@ -1,461 +0,0 @@ -{{-- 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') - Manage Server: {{ $server->name }} -@endsection - -@section('content-header') -

      {{ $server->name }}{{ $server->uuid }}

      - -@endsection - -@section('content') - @if($server->suspended && ! $server->trashed()) -
      - This server is suspended and has no user access. Processes cannot be started and files cannot be modified. All API access is disabled unless using a master token. -
      - @elseif($server->trashed()) -
      - This server is marked for deletion {{ Carbon::parse($server->deleted_at)->addMinutes(env('APP_DELETE_MINUTES', 10))->diffForHumans() }}. If you want to cancel this action simply click the button below. -

      -
      - - - - {!! csrf_field() !!} -
      -
      - @endif - @if(! $server->installed) -
      - This server is still running through the install process and is not avaliable for use just yet. This message will disappear once this process is completed. -
      - @elseif($server->installed === 2) -
      - This server failed to install properly. You should delete it and try to create it again or check the daemon logs. -
      - @endif -
      -
      - -
      -
      -@endsection - -@section('footer-scripts') - @parent - -@endsection diff --git a/resources/themes/pterodactyl/admin/servers/view/build.blade.php b/resources/themes/pterodactyl/admin/servers/view/build.blade.php new file mode 100644 index 000000000..c01149d97 --- /dev/null +++ b/resources/themes/pterodactyl/admin/servers/view/build.blade.php @@ -0,0 +1,158 @@ +{{-- 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 }}: Build Details +@endsection + +@section('content-header') +

      {{ $server->name }}Control allocations and system resources for this server.

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

      System Resources

      +
      +
      +
      + +
      + + MB +
      +

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

      +
      +
      + +
      + + MB +
      +

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

      +
      +
      + +
      + + % +
      +

      Each physical core on the system is considered to be 100%. Setting this value to 0 will allow a server to use CPU time without restrictions.

      +
      +
      + +
      + +
      +

      Changing this value can have negative effects on all containers on the system. We strongly recommend leaving this value as 500.

      +
      + +
      +
      +
      +
      +
      +
      +

      Allocation Management

      +
      +
      +
      + + +

      The default connection address that will be used for this game server.

      +
      +
      + +
      + +
      +

      Please note that due to software limitations you cannot assign identical ports on different IPs to the same server.

      +
      +
      + +
      + +
      +

      Simply select which ports you would like to remove from the list above. If you want to assign a port on a different IP that is already in use you can select it from the left and delete it here.

      +
      +
      + +
      +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/themes/pterodactyl/admin/servers/view/database.blade.php b/resources/themes/pterodactyl/admin/servers/view/database.blade.php new file mode 100644 index 000000000..e69de29bb diff --git a/resources/themes/pterodactyl/admin/servers/view/delete.blade.php b/resources/themes/pterodactyl/admin/servers/view/delete.blade.php new file mode 100644 index 000000000..5a0cfe297 --- /dev/null +++ b/resources/themes/pterodactyl/admin/servers/view/delete.blade.php @@ -0,0 +1,141 @@ +{{-- 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 }}: Delete +@endsection + +@section('content-header') +

      {{ $server->name }}Delete this server from the panel.

      + +@endsection + +@section('content') +
      +
      + +
      +
      +
      + @if($server->trashed()) +
      +
      +
      +

      Marked for Deletion

      +
      +
      +

      This server is currently marked for deletion by the system {{ Carbon::parse($server->deleted_at)->addMinutes(env('APP_DELETE_MINUTES', 10))->diffForHumans() }}.

      +

      Deleting a server is an irreversible action. All server data (including files and users) will be removed from the system.

      +
      + +
      +
      + @endif +
      +
      +
      +

      Safely Delete Server

      +
      +
      +

      This action will attempt to delete the server from both the panel and daemon. If either one reports an error the action will be cancelled.

      +

      Deleting a server is an irreversible action. All server data (including files and users) will be removed from the system.

      +
      + +
      +
      +
      +
      +
      +

      Force Delete Server

      +
      +
      +

      This action will attempt to delete the server from both the panel and daemon. The the daemon does not respond, or reports an error the deletion will continue.

      +

      Deleting a server is an irreversible action. All server data (including files and users) will be removed from the system. This method may leave dangling files on your daemon if it reports an error.

      +
      + +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/themes/pterodactyl/admin/servers/view/details.blade.php b/resources/themes/pterodactyl/admin/servers/view/details.blade.php new file mode 100644 index 000000000..618533ae3 --- /dev/null +++ b/resources/themes/pterodactyl/admin/servers/view/details.blade.php @@ -0,0 +1,170 @@ +{{-- 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 }}: Details +@endsection + +@section('content-header') +

      {{ $server->name }}Edit details for this server including owner and container.

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

      Base Information

      +
      +
      +
      +
      + + +

      Character limits: a-zA-Z0-9_- and [Space] (max 35 characters).

      +
      +
      + + +

      You can change the owner of this server by changing this field to an email matching another use on this system. If you do this a new daemon security token will be generated automatically.

      +
      +
      + + +

      This token should not be shared with anyone as it has full control over this server.

      +
      +
      + +

      Resetting this token will cause any requests using the old token to fail.

      +
      +
      + +
      +
      +
      +
      +
      +
      +

      Container Setup

      +
      +
      +
      +
      + + +

      The docker image to use for this server. The default image for this service and option combination is {{ $server->option->docker_image }}.

      +
      +
      + +
      +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/themes/pterodactyl/admin/servers/view/index.blade.php b/resources/themes/pterodactyl/admin/servers/view/index.blade.php new file mode 100644 index 000000000..f582e4572 --- /dev/null +++ b/resources/themes/pterodactyl/admin/servers/view/index.blade.php @@ -0,0 +1,203 @@ +{{-- 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 }} +@endsection + +@section('content-header') +

      {{ $server->name }}{{ $server->uuid }}

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

      Information

      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      UUID{{ $server->uuid }}
      Docker Container ID
      Docker User ID
      Service{{ $server->option->service->name }} :: {{ $server->option->name }}
      Name{{ $server->name }}
      Memory{{ $server->memory }}MB / {{ $server->swap }}MB
      OOM Killer{!! ($server->oom_disabled === 0) ? 'Enabled' : 'Disabled' !!}
      Disk Space{{ $server->disk }}MB
      Block IO Weight{{ $server->io }}
      CPU Limit{{ $server->cpu }}%
      Default Connection{{ $server->allocation->ip }}:{{ $server->allocation->port }}
      Connection Alias + @if($server->allocation->alias !== $server->allocation->ip) + {{ $server->allocation->alias }}:{{ $server->allocation->port }} + @else + No Alias Assigned + @endif +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      + @if($server->suspended) +
      +
      +
      +

      Suspended

      +
      +
      +
      + @endif + @if($server->installed !== 1) +
      +
      +
      +

      {{ (! $server->installed) ? 'Installing' : 'Install Failed' }}

      +
      +
      +
      + @endif +
      +
      +
      +

      {{ str_limit($server->user->username, 8) }}

      +

      Server Owner

      +
      +
      + + More info + +
      +
      +
      +
      +
      +

      {{ str_limit($server->node->name, 8) }}

      +

      Server Node

      +
      +
      + + More info + +
      +
      +
      +
      +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/themes/pterodactyl/admin/servers/view/manage.blade.php b/resources/themes/pterodactyl/admin/servers/view/manage.blade.php new file mode 100644 index 000000000..4aee0000f --- /dev/null +++ b/resources/themes/pterodactyl/admin/servers/view/manage.blade.php @@ -0,0 +1,127 @@ +{{-- 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 }}: Manage +@endsection + +@section('content-header') +

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

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

      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.

      +
      + +
      +
      +
      +
      +
      +

      Rebuild Container

      +
      +
      +

      This will trigger a rebuild of the server container when it next starts up. This is useful if you modified the server configuration file manually, or something just didn't work out correctly.

      +
      + +
      +
      + @if(! $server->suspended) +
      +
      +
      +

      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 +
      +@endsection diff --git a/resources/themes/pterodactyl/admin/servers/view/startup.blade.php b/resources/themes/pterodactyl/admin/servers/view/startup.blade.php new file mode 100644 index 000000000..e69de29bb From 5d59d364f82c879b129c07a4872cb2bc53eab053 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 4 Mar 2017 19:04:11 -0500 Subject: [PATCH 305/599] Fixes bug preventing proper updating of caches and models due to undefined Auth::user() --- CHANGELOG.md | 1 + app/Observers/ServerObserver.php | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a47cee758..919efdcb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Fixed * Fixes potential bug with invalid CIDR notation (ex: `192.168.1.1/z`) when adding allocations that could cause over 4 million records to be created at once. +* `[pre.4]` — Fixes bug preventing server updates from occurring by the system due to undefined `Auth::user()` in the event listener. ### Added * Ability to assign multiple allocations at once when creating a new server. diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php index 5b746a7b6..973b276d2 100644 --- a/app/Observers/ServerObserver.php +++ b/app/Observers/ServerObserver.php @@ -142,8 +142,10 @@ class ServerObserver public function updated(Server $server) { // Clear Caches - Cache::forget('Server.byUuid.' . $server->uuid . Auth::user()->uuid); - Cache::forget('Server.byUuid.' . $server->uuidShort . Auth::user()->uuid); + if (Auth::user()) { + Cache::forget('Server.byUuid.' . $server->uuid . Auth::user()->uuid); + Cache::forget('Server.byUuid.' . $server->uuidShort . Auth::user()->uuid); + } event(new Events\Server\Updated($server)); } From cd0a45a7775e92d9603dbbf4f2fce6c4acb78cbf Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 4 Mar 2017 19:24:46 -0500 Subject: [PATCH 306/599] Fixes caching to actually clear the cache for *all* users, rather than the logged in user by using cache tags. --- CHANGELOG.md | 1 + app/Models/Server.php | 3 ++- app/Observers/ServerObserver.php | 15 +++++++++------ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 919efdcb8..bd7eee349 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Fixed * Fixes potential bug with invalid CIDR notation (ex: `192.168.1.1/z`) when adding allocations that could cause over 4 million records to be created at once. * `[pre.4]` — Fixes bug preventing server updates from occurring by the system due to undefined `Auth::user()` in the event listener. +* `[pre.4]` — Fixes `Server::byUuid()` caching to actually clear the cache for *all* users, rather than the logged in user by using cache tags. ### Added * Ability to assign multiple allocations at once when creating a new server. diff --git a/app/Models/Server.php b/app/Models/Server.php index 252646ba9..de85c45cc 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -26,6 +26,7 @@ namespace Pterodactyl\Models; use Auth; use Cache; +use Carbon; use Javascript; use Illuminate\Database\Eloquent\Model; use Illuminate\Notifications\Notifiable; @@ -113,7 +114,7 @@ class Server extends Model public static function byUuid($uuid) { // Results are cached because we call this functions a few times on page load. - $result = Cache::remember('Server.byUuid.' . $uuid . Auth::user()->uuid, 60, function () use ($uuid) { + $result = Cache::tags(['Model:Server', 'Model:Server:byUuid:' . $uuid])->remember('Model:Server:byUuid:' . $uuid . Auth::user()->uuid, Carbon::now()->addMinutes(15), function () use ($uuid) { $query = self::with('service', 'node')->where(function ($q) use ($uuid) { $q->where('uuidShort', $uuid)->orWhere('uuid', $uuid); }); diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php index 973b276d2..554e86a82 100644 --- a/app/Observers/ServerObserver.php +++ b/app/Observers/ServerObserver.php @@ -24,7 +24,6 @@ namespace Pterodactyl\Observers; -use Auth; use Cache; use Carbon; use Pterodactyl\Events; @@ -141,11 +140,15 @@ class ServerObserver */ public function updated(Server $server) { - // Clear Caches - if (Auth::user()) { - Cache::forget('Server.byUuid.' . $server->uuid . Auth::user()->uuid); - Cache::forget('Server.byUuid.' . $server->uuidShort . Auth::user()->uuid); - } + /** + * The cached byUuid model calls are tagged with Model:Server:byUuid: + * so that they can be accessed regardless of if there is an Auth::user() + * defined or not. + * + * We can also delete all cached byUuid items using the Model:Server tag. + */ + Cache::tags('Model:Server:byUuid:' . $server->uuid)->flush(); + Cache::tags('Model:Server:byUuid:' . $server->uuidShort)->flush(); event(new Events\Server\Updated($server)); } From cbbd3704fe459f0e475f304e5f0d64d076d7c955 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 4 Mar 2017 19:27:24 -0500 Subject: [PATCH 307/599] Add a second check here *just* to make sure someone doesn't break this. --- app/Models/Server.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Models/Server.php b/app/Models/Server.php index de85c45cc..524708cde 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -113,6 +113,10 @@ class Server extends Model */ public static function byUuid($uuid) { + if (! Auth::check()) { + throw new \Exception('You must call Server:byUuid as an authenticated user.'); + } + // Results are cached because we call this functions a few times on page load. $result = Cache::tags(['Model:Server', 'Model:Server:byUuid:' . $uuid])->remember('Model:Server:byUuid:' . $uuid . Auth::user()->uuid, Carbon::now()->addMinutes(15), function () use ($uuid) { $query = self::with('service', 'node')->where(function ($q) use ($uuid) { From d51ae5ec23be0036659436b090bee013d6dcd5d8 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 4 Mar 2017 19:28:23 -0500 Subject: [PATCH 308/599] Apply fixes from StyleCI (#332) --- app/Http/Controllers/Admin/ServersController.php | 2 +- app/Http/Routes/AdminRoutes.php | 1 - app/Observers/ServerObserver.php | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 000d5c830..c20a6de41 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -247,7 +247,7 @@ class ServersController extends Controller */ public function setDetails(Request $request, $id) { - $repo = new ServerRepository;; + $repo = new ServerRepository; try { $repo->updateDetails($id, $request->intersect([ 'owner_id', 'name', 'reset_token', diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index 6cdc18e4e..69e596a64 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -217,7 +217,6 @@ class AdminRoutes 'as' => 'admin.servers.view.delete.cancel', 'uses' => 'Admin\ServersController@cancelDeletion', ]); - }); // Node Routes diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php index 554e86a82..92d1b8f9a 100644 --- a/app/Observers/ServerObserver.php +++ b/app/Observers/ServerObserver.php @@ -140,7 +140,7 @@ class ServerObserver */ public function updated(Server $server) { - /** + /* * The cached byUuid model calls are tagged with Model:Server:byUuid: * so that they can be accessed regardless of if there is an Auth::user() * defined or not. From 349b36d38a31510a258783e7d416b9dc9fe484ca Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 4 Mar 2017 23:45:22 -0500 Subject: [PATCH 309/599] Added startup management, cleaned up code. Refactored entire startup repository code block to be more efficient and cleaner. Also includes modifications to front-end to make it match backend name and design. --- .../Controllers/Admin/ServersController.php | 49 ++++---- .../Controllers/Server/ServerController.php | 4 +- app/Http/Routes/AdminRoutes.php | 4 + app/Repositories/ServerRepository.php | 116 +++++++----------- resources/lang/en/server.php | 2 + resources/lang/en/strings.php | 2 + .../admin/servers/view/startup.blade.php | 115 +++++++++++++++++ .../server/settings/startup.blade.php | 106 +++++++++------- 8 files changed, 252 insertions(+), 146 deletions(-) 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 From 5c32a912001f5b76b06a330b5dcdee88501cf849 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 5 Mar 2017 00:04:26 -0500 Subject: [PATCH 310/599] JS code updates --- public/js/laroute.js | 2 +- .../pterodactyl/js/frontend/serverlist.js | 25 ++++++------------- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/public/js/laroute.js b/public/js/laroute.js index 09ff8ad96..eb550062a 100644 --- a/public/js/laroute.js +++ b/public/js/laroute.js @@ -6,7 +6,7 @@ absolute: false, rootUrl: 'http://pterodactyl.app', - routes : [{"host":null,"methods":["GET","HEAD"],"uri":"admin","name":"admin.index","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/settings","name":"admin.settings","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getSettings"},{"host":null,"methods":["POST"],"uri":"admin\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\BaseController@postSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users","name":"admin.users","action":"Pterodactyl\Http\Controllers\Admin\UserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/accounts.json","name":"admin.users.json","action":"Pterodactyl\Http\Controllers\Admin\UserController@getJson"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/view\/{id}","name":"admin.users.view","action":"Pterodactyl\Http\Controllers\Admin\UserController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@updateUser"},{"host":null,"methods":["DELETE"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@deleteUser"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/new","name":"admin.users.new","action":"Pterodactyl\Http\Controllers\Admin\UserController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers","name":"admin.servers","action":"Pterodactyl\Http\Controllers\Admin\ServersController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/new","name":"admin.servers.new","action":"Pterodactyl\Http\Controllers\Admin\ServersController@new"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@create"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/nodes","name":"admin.servers.new.nodes","action":"Pterodactyl\Http\Controllers\Admin\ServersController@newServerNodes"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}","name":"admin.servers.view","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/details","name":"admin.servers.view.details","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@setDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details\/container","name":"admin.servers.view.details.container","action":"Pterodactyl\Http\Controllers\Admin\ServersController@setContainer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/build","name":"admin.servers.view.build","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/build","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@updateBuild"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/startup","name":"admin.servers.view.startup","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/database","name":"admin.servers.view.database","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDatabase"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/manage","name":"admin.servers.view.manage","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewManage"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/toggle","name":"admin.servers.view.manage.toggle","action":"Pterodactyl\Http\Controllers\Admin\ServersController@toggleInstall"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/rebuild","name":"admin.servers.view.manage.rebuild","action":"Pterodactyl\Http\Controllers\Admin\ServersController@rebuildContainer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/suspension","name":"admin.servers.view.manage.suspension","action":"Pterodactyl\Http\Controllers\Admin\ServersController@manageSuspension"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/delete","name":"admin.servers.view.delete","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDelete"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@delete"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete\/continue\/{force?}","name":"admin.servers.view.delete.continue","action":"Pterodactyl\Http\Controllers\Admin\ServersController@continueDeletion"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete\/cancel","name":"admin.servers.view.delete.cancel","action":"Pterodactyl\Http\Controllers\Admin\ServersController@cancelDeletion"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes","name":"admin.nodes","action":"Pterodactyl\Http\Controllers\Admin\NodesController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/new","name":"admin.nodes.new","action":"Pterodactyl\Http\Controllers\Admin\NodesController@new"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.view","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings","name":"admin.nodes.view.settings","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewSettings"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@updateSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/configuration","name":"admin.nodes.view.configuration","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":"admin.nodes.view.allocation","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewAllocation"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@createAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/servers","name":"admin.nodes.view.servers","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewServers"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/delete","name":"admin.nodes.view.delete","action":"Pterodactyl\Http\Controllers\Admin\NodesController@delete"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove\/{allocation}","name":"admin.nodes.view.allocation.removeSingle","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveSingle"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove","name":"admin.nodes.view.allocation.removeBlock","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveBlock"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/alias","name":"admin.nodes.view.allocation.setAlias","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationSetAlias"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings\/token","name":"admin.nodes.view.configuration.token","action":"Pterodactyl\Http\Controllers\Admin\NodesController@setToken"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/locations","name":"admin.locations","action":"Pterodactyl\Http\Controllers\Admin\LocationsController@getIndex"},{"host":null,"methods":["DELETE"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@deleteLocation"},{"host":null,"methods":["PATCH"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@patchLocation"},{"host":null,"methods":["POST"],"uri":"admin\/locations","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@postLocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases","name":"admin.databases","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases\/new","name":"admin.databases.new","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/databases\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@postNew"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete\/{id}","name":"admin.databases.delete","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteDatabase"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete-server\/{id}","name":"admin.databases.delete-server","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteServer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services","name":"admin.services","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/new","name":"admin.services.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/services\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}","name":"admin.services.service","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getService"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postService"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}\/configuration","name":"admin.services.service.config","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getConfiguration"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}\/configuration","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/new","name":"admin.services.option.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@newOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":"admin.services.option","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOption"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{service}\/option\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":"admin.services.option.variable.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}","name":"admin.services.option.variable","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOptionVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}\/delete","name":"admin.services.option.variable.delete","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/new\/{option?}","name":"admin.services.packs.new","action":"Pterodactyl\Http\Controllers\Admin\PackController@new"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/upload\/{option?}","name":"admin.services.packs.uploadForm","action":"Pterodactyl\Http\Controllers\Admin\PackController@uploadForm"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/upload","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@postUpload"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs","name":"admin.services.packs","action":"Pterodactyl\Http\Controllers\Admin\PackController@listAll"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/option\/{option}","name":"admin.services.packs.option","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/service\/{service}","name":"admin.services.packs.service","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}","name":"admin.services.packs.edit","action":"Pterodactyl\Http\Controllers\Admin\PackController@edit"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/edit\/{pack}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}\/export\/{archive?}","name":"admin.services.packs.export","action":"Pterodactyl\Http\Controllers\Admin\PackController@export"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login","name":"auth.login","action":"Pterodactyl\Http\Controllers\Auth\LoginController@showLoginForm"},{"host":null,"methods":["POST"],"uri":"auth\/login","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@login"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login\/totp","name":"auth.totp","action":"Pterodactyl\Http\Controllers\Auth\LoginController@totp"},{"host":null,"methods":["POST"],"uri":"auth\/login\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@totpCheckpoint"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password","name":"auth.password","action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm"},{"host":null,"methods":["POST"],"uri":"auth\/password","name":null,"action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password\/reset\/{token}","name":"auth.reset","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@showResetForm"},{"host":null,"methods":["POST"],"uri":"auth\/password\/reset","name":"auth.reset.post","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@reset"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/logout","name":"auth.logout","action":"Pterodactyl\Http\Controllers\Auth\LoginController@logout"},{"host":null,"methods":["GET","HEAD"],"uri":"\/","name":"index","action":"Pterodactyl\Http\Controllers\Base\IndexController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"index","name":null,"action":"Closure"},{"host":null,"methods":["GET","HEAD"],"uri":"password-gen\/{length}","name":"password-gen","action":"Pterodactyl\Http\Controllers\Base\IndexController@getPassword"},{"host":null,"methods":["GET","HEAD"],"uri":"account","name":"account","action":"Pterodactyl\Http\Controllers\Base\AccountController@index"},{"host":null,"methods":["POST"],"uri":"account","name":null,"action":"Pterodactyl\Http\Controllers\Base\AccountController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api","name":"account.api","action":"Pterodactyl\Http\Controllers\Base\APIController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api\/new","name":"account.api.new","action":"Pterodactyl\Http\Controllers\Base\APIController@create"},{"host":null,"methods":["POST"],"uri":"account\/api\/new","name":null,"action":"Pterodactyl\Http\Controllers\Base\APIController@save"},{"host":null,"methods":["DELETE"],"uri":"account\/api\/revoke\/{key}","name":"account.api.revoke","action":"Pterodactyl\Http\Controllers\Base\APIController@revoke"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security","name":"account.security","action":"Pterodactyl\Http\Controllers\Base\SecurityController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security\/revoke\/{id}","name":"account.security.revoke","action":"Pterodactyl\Http\Controllers\Base\SecurityController@revoke"},{"host":null,"methods":["PUT"],"uri":"account\/security\/totp","name":"account.security.totp","action":"Pterodactyl\Http\Controllers\Base\SecurityController@generateTotp"},{"host":null,"methods":["POST"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@setTotp"},{"host":null,"methods":["DELETE"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@disableTotp"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services","name":"daemon.services","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@list"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services\/pull\/{service}\/{file}","name":"remote.install","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}","name":"daemon.pack.pull","action":"Pterodactyl\Http\Controllers\Daemon\PackController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}\/hash","name":"daemon.pack.hash","action":"Pterodactyl\Http\Controllers\Daemon\PackController@hash"},{"host":null,"methods":["GET","HEAD"],"uri":"language\/{lang}","name":"langauge.set","action":"Pterodactyl\Http\Controllers\Base\LanguageController@setLanguage"},{"host":null,"methods":["POST"],"uri":"remote\/download","name":"remote.download","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postDownload"},{"host":null,"methods":["POST"],"uri":"remote\/install","name":"remote.install","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postInstall"},{"host":null,"methods":["GET","HEAD"],"uri":"remote\/configuration\/{token}","name":"remote.configuration","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@getConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/ajax\/status","name":"server.ajax.status","action":"Pterodactyl\Http\Controllers\Server\AjaxController@getStatus"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}","name":"server.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/databases","name":"server.settings.databases","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDatabases"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/sftp","name":"server.settings.sftp","action":"Pterodactyl\Http\Controllers\Server\ServerController@getSFTP"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/sftp","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsSFTP"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/startup","name":"server.settings.startup","action":"Pterodactyl\Http\Controllers\Server\ServerController@getStartup"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/allocation","name":"server.settings.allocation","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files","name":"server.files.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getFiles"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/edit\/{file}","name":"server.files.edit","action":"Pterodactyl\Http\Controllers\Server\ServerController@getEditFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/download\/{file}","name":"server.files.download","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDownloadFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/add","name":"server.files.add","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAddFile"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/directory-list","name":"server.files.directory-list","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postDirectoryList"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/save","name":"server.files.save","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSaveFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users","name":"server.subusers","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/new","name":"server.subusers.new","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/view\/{id}","name":"server.subusers.view","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getView"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postView"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/users\/delete\/{id}","name":"server.subusers.delete","action":"Pterodactyl\Http\Controllers\Server\SubuserController@deleteSubuser"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks","name":"server.tasks","action":"Pterodactyl\Http\Controllers\Server\TaskController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/view\/{id}","name":"server.tasks.view","action":"Pterodactyl\Http\Controllers\Server\TaskController@getView"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/new","name":"server.tasks.new","action":"Pterodactyl\Http\Controllers\Server\TaskController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\TaskController@postNew"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/tasks\/delete\/{id}","name":"server.tasks.delete","action":"Pterodactyl\Http\Controllers\Server\TaskController@deleteTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/toggle\/{id}","name":"server.tasks.toggle","action":"Pterodactyl\Http\Controllers\Server\TaskController@toggleTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/set-primary","name":null,"action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSetPrimary"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/settings\/reset-database-password","name":"server.ajax.reset-database-password","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postResetDatabasePassword"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/open","name":"debugbar.openhandler","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@handle"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/clockwork\/{id}","name":"debugbar.clockwork","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@clockwork"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/stylesheets","name":"debugbar.assets.css","action":"Barryvdh\Debugbar\Controllers\AssetController@css"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/javascript","name":"debugbar.assets.js","action":"Barryvdh\Debugbar\Controllers\AssetController@js"}], + routes : [{"host":null,"methods":["GET","HEAD"],"uri":"admin","name":"admin.index","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/settings","name":"admin.settings","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getSettings"},{"host":null,"methods":["POST"],"uri":"admin\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\BaseController@postSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users","name":"admin.users","action":"Pterodactyl\Http\Controllers\Admin\UserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/accounts.json","name":"admin.users.json","action":"Pterodactyl\Http\Controllers\Admin\UserController@getJson"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/view\/{id}","name":"admin.users.view","action":"Pterodactyl\Http\Controllers\Admin\UserController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@updateUser"},{"host":null,"methods":["DELETE"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@deleteUser"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/new","name":"admin.users.new","action":"Pterodactyl\Http\Controllers\Admin\UserController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers","name":"admin.servers","action":"Pterodactyl\Http\Controllers\Admin\ServersController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/new","name":"admin.servers.new","action":"Pterodactyl\Http\Controllers\Admin\ServersController@new"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@create"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/nodes","name":"admin.servers.new.nodes","action":"Pterodactyl\Http\Controllers\Admin\ServersController@newServerNodes"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}","name":"admin.servers.view","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/details","name":"admin.servers.view.details","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@setDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details\/container","name":"admin.servers.view.details.container","action":"Pterodactyl\Http\Controllers\Admin\ServersController@setContainer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/build","name":"admin.servers.view.build","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/build","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@updateBuild"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/startup","name":"admin.servers.view.startup","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewStartup"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@saveStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/database","name":"admin.servers.view.database","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDatabase"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/manage","name":"admin.servers.view.manage","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewManage"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/toggle","name":"admin.servers.view.manage.toggle","action":"Pterodactyl\Http\Controllers\Admin\ServersController@toggleInstall"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/rebuild","name":"admin.servers.view.manage.rebuild","action":"Pterodactyl\Http\Controllers\Admin\ServersController@rebuildContainer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/suspension","name":"admin.servers.view.manage.suspension","action":"Pterodactyl\Http\Controllers\Admin\ServersController@manageSuspension"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/delete","name":"admin.servers.view.delete","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDelete"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@delete"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete\/continue\/{force?}","name":"admin.servers.view.delete.continue","action":"Pterodactyl\Http\Controllers\Admin\ServersController@continueDeletion"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete\/cancel","name":"admin.servers.view.delete.cancel","action":"Pterodactyl\Http\Controllers\Admin\ServersController@cancelDeletion"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes","name":"admin.nodes","action":"Pterodactyl\Http\Controllers\Admin\NodesController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/new","name":"admin.nodes.new","action":"Pterodactyl\Http\Controllers\Admin\NodesController@new"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.view","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings","name":"admin.nodes.view.settings","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewSettings"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@updateSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/configuration","name":"admin.nodes.view.configuration","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":"admin.nodes.view.allocation","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewAllocation"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@createAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/servers","name":"admin.nodes.view.servers","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewServers"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/delete","name":"admin.nodes.view.delete","action":"Pterodactyl\Http\Controllers\Admin\NodesController@delete"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove\/{allocation}","name":"admin.nodes.view.allocation.removeSingle","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveSingle"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove","name":"admin.nodes.view.allocation.removeBlock","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveBlock"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/alias","name":"admin.nodes.view.allocation.setAlias","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationSetAlias"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings\/token","name":"admin.nodes.view.configuration.token","action":"Pterodactyl\Http\Controllers\Admin\NodesController@setToken"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/locations","name":"admin.locations","action":"Pterodactyl\Http\Controllers\Admin\LocationsController@getIndex"},{"host":null,"methods":["DELETE"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@deleteLocation"},{"host":null,"methods":["PATCH"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@patchLocation"},{"host":null,"methods":["POST"],"uri":"admin\/locations","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@postLocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases","name":"admin.databases","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases\/new","name":"admin.databases.new","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/databases\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@postNew"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete\/{id}","name":"admin.databases.delete","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteDatabase"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete-server\/{id}","name":"admin.databases.delete-server","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteServer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services","name":"admin.services","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/new","name":"admin.services.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/services\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}","name":"admin.services.service","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getService"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postService"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}\/configuration","name":"admin.services.service.config","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getConfiguration"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}\/configuration","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/new","name":"admin.services.option.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@newOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":"admin.services.option","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOption"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{service}\/option\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":"admin.services.option.variable.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}","name":"admin.services.option.variable","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOptionVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}\/delete","name":"admin.services.option.variable.delete","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/new\/{option?}","name":"admin.services.packs.new","action":"Pterodactyl\Http\Controllers\Admin\PackController@new"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/upload\/{option?}","name":"admin.services.packs.uploadForm","action":"Pterodactyl\Http\Controllers\Admin\PackController@uploadForm"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/upload","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@postUpload"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs","name":"admin.services.packs","action":"Pterodactyl\Http\Controllers\Admin\PackController@listAll"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/option\/{option}","name":"admin.services.packs.option","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/service\/{service}","name":"admin.services.packs.service","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}","name":"admin.services.packs.edit","action":"Pterodactyl\Http\Controllers\Admin\PackController@edit"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/edit\/{pack}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}\/export\/{archive?}","name":"admin.services.packs.export","action":"Pterodactyl\Http\Controllers\Admin\PackController@export"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login","name":"auth.login","action":"Pterodactyl\Http\Controllers\Auth\LoginController@showLoginForm"},{"host":null,"methods":["POST"],"uri":"auth\/login","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@login"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login\/totp","name":"auth.totp","action":"Pterodactyl\Http\Controllers\Auth\LoginController@totp"},{"host":null,"methods":["POST"],"uri":"auth\/login\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@totpCheckpoint"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password","name":"auth.password","action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm"},{"host":null,"methods":["POST"],"uri":"auth\/password","name":null,"action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password\/reset\/{token}","name":"auth.reset","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@showResetForm"},{"host":null,"methods":["POST"],"uri":"auth\/password\/reset","name":"auth.reset.post","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@reset"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/logout","name":"auth.logout","action":"Pterodactyl\Http\Controllers\Auth\LoginController@logout"},{"host":null,"methods":["GET","HEAD"],"uri":"\/","name":"index","action":"Pterodactyl\Http\Controllers\Base\IndexController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"index","name":null,"action":"Closure"},{"host":null,"methods":["GET","HEAD"],"uri":"password-gen\/{length}","name":"password-gen","action":"Pterodactyl\Http\Controllers\Base\IndexController@getPassword"},{"host":null,"methods":["GET","HEAD"],"uri":"account","name":"account","action":"Pterodactyl\Http\Controllers\Base\AccountController@index"},{"host":null,"methods":["POST"],"uri":"account","name":null,"action":"Pterodactyl\Http\Controllers\Base\AccountController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api","name":"account.api","action":"Pterodactyl\Http\Controllers\Base\APIController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api\/new","name":"account.api.new","action":"Pterodactyl\Http\Controllers\Base\APIController@create"},{"host":null,"methods":["POST"],"uri":"account\/api\/new","name":null,"action":"Pterodactyl\Http\Controllers\Base\APIController@save"},{"host":null,"methods":["DELETE"],"uri":"account\/api\/revoke\/{key}","name":"account.api.revoke","action":"Pterodactyl\Http\Controllers\Base\APIController@revoke"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security","name":"account.security","action":"Pterodactyl\Http\Controllers\Base\SecurityController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security\/revoke\/{id}","name":"account.security.revoke","action":"Pterodactyl\Http\Controllers\Base\SecurityController@revoke"},{"host":null,"methods":["PUT"],"uri":"account\/security\/totp","name":"account.security.totp","action":"Pterodactyl\Http\Controllers\Base\SecurityController@generateTotp"},{"host":null,"methods":["POST"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@setTotp"},{"host":null,"methods":["DELETE"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@disableTotp"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services","name":"daemon.services","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@list"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services\/pull\/{service}\/{file}","name":"remote.install","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}","name":"daemon.pack.pull","action":"Pterodactyl\Http\Controllers\Daemon\PackController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}\/hash","name":"daemon.pack.hash","action":"Pterodactyl\Http\Controllers\Daemon\PackController@hash"},{"host":null,"methods":["GET","HEAD"],"uri":"language\/{lang}","name":"langauge.set","action":"Pterodactyl\Http\Controllers\Base\LanguageController@setLanguage"},{"host":null,"methods":["POST"],"uri":"remote\/download","name":"remote.download","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postDownload"},{"host":null,"methods":["POST"],"uri":"remote\/install","name":"remote.install","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postInstall"},{"host":null,"methods":["GET","HEAD"],"uri":"remote\/configuration\/{token}","name":"remote.configuration","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@getConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/ajax\/status","name":"server.ajax.status","action":"Pterodactyl\Http\Controllers\Server\AjaxController@getStatus"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}","name":"server.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/databases","name":"server.settings.databases","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDatabases"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/sftp","name":"server.settings.sftp","action":"Pterodactyl\Http\Controllers\Server\ServerController@getSFTP"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/sftp","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsSFTP"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/startup","name":"server.settings.startup","action":"Pterodactyl\Http\Controllers\Server\ServerController@getStartup"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/allocation","name":"server.settings.allocation","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files","name":"server.files.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getFiles"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/edit\/{file}","name":"server.files.edit","action":"Pterodactyl\Http\Controllers\Server\ServerController@getEditFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/download\/{file}","name":"server.files.download","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDownloadFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/add","name":"server.files.add","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAddFile"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/directory-list","name":"server.files.directory-list","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postDirectoryList"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/save","name":"server.files.save","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSaveFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users","name":"server.subusers","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/new","name":"server.subusers.new","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/view\/{id}","name":"server.subusers.view","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getView"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postView"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/users\/delete\/{id}","name":"server.subusers.delete","action":"Pterodactyl\Http\Controllers\Server\SubuserController@deleteSubuser"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks","name":"server.tasks","action":"Pterodactyl\Http\Controllers\Server\TaskController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/view\/{id}","name":"server.tasks.view","action":"Pterodactyl\Http\Controllers\Server\TaskController@getView"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/new","name":"server.tasks.new","action":"Pterodactyl\Http\Controllers\Server\TaskController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\TaskController@postNew"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/tasks\/delete\/{id}","name":"server.tasks.delete","action":"Pterodactyl\Http\Controllers\Server\TaskController@deleteTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/toggle\/{id}","name":"server.tasks.toggle","action":"Pterodactyl\Http\Controllers\Server\TaskController@toggleTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/set-primary","name":null,"action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSetPrimary"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/settings\/reset-database-password","name":"server.ajax.reset-database-password","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postResetDatabasePassword"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/open","name":"debugbar.openhandler","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@handle"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/clockwork\/{id}","name":"debugbar.clockwork","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@clockwork"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/stylesheets","name":"debugbar.assets.css","action":"Barryvdh\Debugbar\Controllers\AssetController@css"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/javascript","name":"debugbar.assets.js","action":"Barryvdh\Debugbar\Controllers\AssetController@js"}], prefix: '', route : function (name, parameters, route) { diff --git a/public/themes/pterodactyl/js/frontend/serverlist.js b/public/themes/pterodactyl/js/frontend/serverlist.js index 0490b7fbe..2a93a5a7c 100644 --- a/public/themes/pterodactyl/js/frontend/serverlist.js +++ b/public/themes/pterodactyl/js/frontend/serverlist.js @@ -17,16 +17,13 @@ // 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. - -var ServerList = (function () { - +(function updateServerStatus() { var Status = { 0: 'Offline', 1: 'Online', 2: 'Starting', 3: 'Stopping' }; - $('.dynamic-update').each(function (index, data) { var element = $(this); var serverShortUUID = $(this).data('server'); @@ -81,20 +78,12 @@ var ServerList = (function () { element.find('[data-action="memory"]').html('--'); element.find('[data-action="cpu"]').html('--'); } - }).fail(function (jqXHR) { - console.error(jqXHR); - element.find('[data-action="status"]').html('Error'); - }); + } + }).fail(function (jqXHR) { + console.error(jqXHR); + element.find('[data-action="status"]').html('Error'); }); + }).promise().done(function () { setTimeout(updateServerStatus, 10000); - } - - return { - init: function () { - updateServerStatus(); - } - }; - + }); })(); - -ServerList.init(); From 16aaf531d6dcb58006303f047c979e44f9cccb51 Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Sun, 5 Mar 2017 17:25:28 +0100 Subject: [PATCH 311/599] switch user delete box to the style from nodes for consistency --- .../themes/pterodactyl/admin/users/view.blade.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/resources/themes/pterodactyl/admin/users/view.blade.php b/resources/themes/pterodactyl/admin/users/view.blade.php index 146a8c664..facddb1f5 100644 --- a/resources/themes/pterodactyl/admin/users/view.blade.php +++ b/resources/themes/pterodactyl/admin/users/view.blade.php @@ -149,12 +149,13 @@

      Delete User

      -
      Warning! There most be no servers associated with this account in order for it to be deleted.
      -

      -
      - {!! method_field('DELETE') !!} +

      There most be no servers associated with this account in order for it to be deleted.

      +
      +
      From 32dec97e4620cd7d17e85bd04c368a269d231090 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 5 Mar 2017 16:37:38 -0500 Subject: [PATCH 312/599] Improved database mechanics in admin CP for server view --- .../Controllers/Admin/ServersController.php | 99 ++++++--- app/Http/Routes/AdminRoutes.php | 13 ++ app/Repositories/DatabaseRepository.php | 160 +++++++-------- app/Repositories/ServerRepository.php | 10 +- public/js/laroute.js | 2 +- .../admin/servers/view/database.blade.php | 192 ++++++++++++++++++ 6 files changed, 357 insertions(+), 119 deletions(-) diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 39e361dc3..2efd1f876 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -211,7 +211,10 @@ class ServersController extends Controller { $server = Models\Server::where('installed', 1)->with('databases.host')->findOrFail($id); - return view('admin.servers.view.build', ['server' => $server]); + return view('admin.servers.view.database', [ + 'hosts' => Models\DatabaseServer::all(), + 'server' => $server + ]); } /** @@ -503,29 +506,73 @@ class ServersController extends Controller return redirect()->route('admin.servers.view.startup', $id); } - // - // public function postDatabase(Request $request, $id) - // { - // try { - // $repo = new DatabaseRepository; - // $repo->create($id, $request->only([ - // 'db_server', 'database', 'remote', - // ])); - // Alert::success('Added new database to this server.')->flash(); - // } catch (DisplayValidationException $ex) { - // return redirect()->route('admin.servers.view', [ - // 'id' => $id, - // 'tab' => 'tab_database', - // ])->withInput()->withErrors(json_decode($ex->getMessage()))->withInput(); - // } catch (\Exception $ex) { - // Log::error($ex); - // Alert::danger('An exception occured while attempting to add a new database for this server.')->flash(); - // } - // - // return redirect()->route('admin.servers.view', [ - // 'id' => $id, - // 'tab' => 'tab_database', - // ])->withInput(); - // } - // // + /** + * Creates a new database assigned to a specific server. + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function newDatabase(Request $request, $id) + { + $repo = new DatabaseRepository; + + try { + $repo->create($id, $request->only(['host', 'database', 'connection'])); + + Alert::success('A new database was assigned to this server successfully.')->flash(); + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.servers.view.database', $id)->withInput()->withErrors(json_decode($ex->getMessage()))->withInput(); + } catch(DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An exception occured while attempting to add a new database for this server. This error has been logged.')->flash(); + } + + return redirect()->route('admin.servers.view.database', $id)->withInput(); + } + + /** + * Resets the database password for a specific database on this server. + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function resetDatabasePassword(Request $request, $id) + { + $database = Models\Database::where('server_id', $id)->findOrFail($request->input('database')); + $repo = new DatabaseRepository; + + try { + $repo->password($database->id, str_random(20)); + + return response('', 204); + } catch (\Exception $ex) { + Log::error($ex); + + return response()->json(['error' => 'A unhandled exception occurred while attempting to reset this password. This error has been logged.'], 503); + } + } + + /** + * Deletes a database from a server. + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function deleteDatabase(Request $request, $id, $database) + { + $database = Models\Database::where('server_id', $id)->findOrFail($database); + $repo = new DatabaseRepository; + + try { + $repo->drop($database->id); + + return response('', 204); + } catch (\Exception $ex) { + Log::error($ex); + + return response()->json(['error' => 'A unhandled exception occurred while attempting to drop this database. This error has been logged.'], 503); + } + } } diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index c40de6d18..c25cb91e3 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -183,6 +183,19 @@ class AdminRoutes 'uses' => 'Admin\ServersController@viewDatabase', ]); + $router->post('/view/{id}/database', [ + 'uses' => 'Admin\ServersController@newDatabase', + ]); + + $router->patch('/view/{id}/database', [ + 'uses' => 'Admin\ServersController@resetDatabasePassword', + ]); + + $router->delete('/view/{id}/database/{database}/delete', [ + 'as' => 'admin.servers.view.database.delete', + 'uses' => 'Admin\ServersController@deleteDatabase', + ]); + $router->get('/view/{id}/manage', [ 'as' => 'admin.servers.view.manage', 'uses' => 'Admin\ServersController@viewManage', diff --git a/app/Repositories/DatabaseRepository.php b/app/Repositories/DatabaseRepository.php index c605a32de..4fd01c240 100644 --- a/app/Repositories/DatabaseRepository.php +++ b/app/Repositories/DatabaseRepository.php @@ -26,89 +26,98 @@ namespace Pterodactyl\Repositories; use DB; use Crypt; +use Config; use Validator; use Pterodactyl\Models; use Pterodactyl\Exceptions\DisplayException; -use Illuminate\Database\Capsule\Manager as Capsule; use Pterodactyl\Exceptions\DisplayValidationException; class DatabaseRepository { /** - * Adds a new database to a given database server. + * Adds a new database to a specified database host server. + * * @param int $server Id of the server to add a database for. * @param array $options Array of options for creating that database. + * + * @throws \Pterodactyl\Exceptions\DisplayException + * @throws \Pterodactyl\Exceptions\DisplayValidationException + * @throws \Exception * @return void */ - public function create($server, $options) + public function create($server, $data) { $server = Models\Server::findOrFail($server); - $validator = Validator::make($options, [ - 'db_server' => 'required|exists:database_servers,id', + + $validator = Validator::make($data, [ + 'host' => 'required|exists:database_servers,id', 'database' => 'required|regex:/^\w{1,100}$/', - 'remote' => 'required|regex:/^[0-9%.]{1,15}$/', + 'connection' => 'required|regex:/^[0-9%.]{1,15}$/', ]); if ($validator->fails()) { throw new DisplayValidationException($validator->errors()); } + $host = Models\DatabaseServer::findOrFail($data['host']); DB::beginTransaction(); + try { - $db = new Models\Database; - $db->fill([ + $database = Models\Database::firstOrNew([ 'server_id' => $server->id, - 'db_server' => $options['db_server'], - 'database' => "s{$server->id}_{$options['database']}", - 'username' => $server->uuidShort . '_' . str_random(7), - 'remote' => $options['remote'], - 'password' => Crypt::encrypt(str_random(20)), - ]); - $db->save(); - - // Contact Remote - $dbr = Models\DatabaseServer::findOrFail($options['db_server']); - - $capsule = new Capsule; - $capsule->addConnection([ - 'driver' => 'mysql', - 'host' => $dbr->host, - 'port' => $dbr->port, - 'database' => 'mysql', - 'username' => $dbr->username, - 'password' => Crypt::decrypt($dbr->password), - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', - 'prefix' => '', - 'options' => [ - \PDO::ATTR_TIMEOUT => 3, - ], + 'db_server' => $data['host'], + 'database' => sprintf('s%d_%s', $server->id, $data['database']), ]); - $capsule->setAsGlobal(); + if ($database->exists) { + throw new DisplayException('A database with those details already exists in the system.'); + } + + $database->username = sprintf('s%d_%s', $server->id, str_random(10)); + $database->remote = $data['connection']; + $database->password = Crypt::encrypt(str_random(20)); + + $database->save(); } catch (\Exception $ex) { DB::rollBack(); - throw new DisplayException('There was an error while connecting to the Database Host Server. Please check the error logs.', $ex); + throw $ex; } + Config::set('database.connections.dynamic', [ + 'driver' => 'mysql', + 'host' => $host->host, + 'port' => $host->port, + 'database' => 'mysql', + 'username' => $host->username, + 'password' => Crypt::decrypt($host->password), + 'charset' => 'utf8', + 'collation' => 'utf8_unicode_ci', + ]); + try { - Capsule::statement('CREATE DATABASE `' . $db->database . '`'); - Capsule::statement('CREATE USER `' . $db->username . '`@`' . $db->remote . '` IDENTIFIED BY \'' . Crypt::decrypt($db->password) . '\''); - Capsule::statement('GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON `' . $db->database . '`.* TO `' . $db->username . '`@`' . $db->remote . '`'); - Capsule::statement('FLUSH PRIVILEGES'); + DB::connection('dynamic')->statement(sprintf('CREATE DATABASE IF NOT EXISTS `%s`', $database->database)); + DB::connection('dynamic')->statement(sprintf( + 'CREATE USER `%s`@`%s` IDENTIFIED BY \'%s\'', + $database->username, $database->remote, Crypt::decrypt($database->password) + )); + DB::connection('dynamic')->statement(sprintf( + 'GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON `%s`.* TO `%s`@`%s`', + $database->database, $database->username, $database->remote + )); + + DB::connection('dynamic')->statement('FLUSH PRIVILEGES'); + + // Save Everything DB::commit(); } catch (\Exception $ex) { try { - Capsule::statement('DROP DATABASE `' . $db->database . '`'); - Capsule::statement('DROP USER `' . $db->username . '`@`' . $db->remote . '`'); - } catch (\Exception $exi) { - // ignore it, if it fails its probably - // because we failed to ever make the DB - // or the user on the system. - } finally { - DB::rollBack(); - throw $ex; - } + DB::connection('dynamic')->statement(sprintf('DROP DATABASE IF EXISTS `%s`', $database->database)); + DB::connection('dynamic')->statement(sprintf('DROP USER IF EXISTS `%s`@`%s`', $database->username, $database->remote)); + DB::connection('dynamic')->statement('FLUSH PRIVILEGES'); + } catch (\Exception $ex) {} + + DB::rollBack(); + throw $ex; } } @@ -118,7 +127,7 @@ class DatabaseRepository * @param string $password The new password to use for the database. * @return bool */ - public function modifyPassword($id, $password) + public function password($id, $password) { $database = Models\Database::with('host')->findOrFail($id); @@ -127,33 +136,25 @@ class DatabaseRepository $database->password = Crypt::encrypt($password); $database->save(); - $capsule = new Capsule; - $capsule->addConnection([ + Config::set('database.connections.dynamic', [ 'driver' => 'mysql', 'host' => $database->host->host, 'port' => $database->host->port, 'database' => 'mysql', 'username' => $database->host->username, 'password' => Crypt::decrypt($database->host->password), - 'charset' => 'utf8', + 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', - 'prefix' => '', - 'options' => [ - \PDO::ATTR_TIMEOUT => 3, - ], ]); - $capsule->setAsGlobal(); - Capsule::statement(sprintf( + DB::connection('dynamic')->statement(sprintf( 'SET PASSWORD FOR `%s`@`%s` = PASSWORD(\'%s\')', - $database->username, - $database->remote, - $password + $database->username, $database->remote, $password )); DB::commit(); } catch (\Exception $ex) { - DB::rollback(); + DB::rollBack(); throw $ex; } } @@ -168,34 +169,25 @@ class DatabaseRepository $database = Models\Database::with('host')->findOrFail($id); DB::beginTransaction(); - try { - $capsule = new Capsule; - $capsule->addConnection([ + Config::set('database.connections.dynamic', [ 'driver' => 'mysql', 'host' => $database->host->host, 'port' => $database->host->port, 'database' => 'mysql', 'username' => $database->host->username, 'password' => Crypt::decrypt($database->host->password), - 'charset' => 'utf8', + 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', - 'prefix' => '', - 'options' => [ - \PDO::ATTR_TIMEOUT => 3, - ], ]); - $capsule->setAsGlobal(); - - Capsule::statement('DROP USER `' . $database->username . '`@`' . $database->remote . '`'); - Capsule::statement('DROP DATABASE `' . $database->database . '`'); + DB::connection('dynamic')->statement(sprintf('DROP DATABASE IF EXISTS `%s`', $database->database)); + DB::connection('dynamic')->statement(sprintf('DROP USER IF EXISTS `%s`@`%s`', $database->username, $database->remote)); + DB::connection('dynamic')->statement('FLUSH PRIVILEGES'); $database->delete(); DB::commit(); - - return true; } catch (\Exception $ex) { DB::rollback(); throw $ex; @@ -243,28 +235,20 @@ class DatabaseRepository } DB::beginTransaction(); - try { - $capsule = new Capsule; - $capsule->addConnection([ + Config::set('database.connections.dynamic', [ 'driver' => 'mysql', 'host' => $data['host'], 'port' => $data['port'], 'database' => 'mysql', 'username' => $data['username'], 'password' => $data['password'], - 'charset' => 'utf8', + 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', - 'prefix' => '', - 'options' => [ - \PDO::ATTR_TIMEOUT => 3, - ], ]); - $capsule->setAsGlobal(); - // Allows us to check that we can connect to things. - Capsule::select('SELECT 1 FROM dual'); + DB::connection('dynamic')->select('SELECT 1 FROM dual'); Models\DatabaseServer::create([ 'name' => $data['name'], diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 377450f66..d911140a6 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -745,10 +745,12 @@ class ServerRepository // Delete Databases // This is the one un-recoverable point where // transactions will not save us. - $repository = new DatabaseRepository; - foreach (Models\Database::select('id')->where('server_id', $server->id)->get() as &$database) { - $repository->drop($database->id); - } + // + // @TODO: move to post-deletion event as a queued task! + // $repository = new DatabaseRepository; + // foreach (Models\Database::select('id')->where('server_id', $server->id)->get() as &$database) { + // $repository->drop($database->id); + // } $server->node->guzzleClient([ 'X-Access-Token' => $server->node->daemonSecret, diff --git a/public/js/laroute.js b/public/js/laroute.js index eb550062a..b4f553912 100644 --- a/public/js/laroute.js +++ b/public/js/laroute.js @@ -6,7 +6,7 @@ absolute: false, rootUrl: 'http://pterodactyl.app', - routes : [{"host":null,"methods":["GET","HEAD"],"uri":"admin","name":"admin.index","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/settings","name":"admin.settings","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getSettings"},{"host":null,"methods":["POST"],"uri":"admin\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\BaseController@postSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users","name":"admin.users","action":"Pterodactyl\Http\Controllers\Admin\UserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/accounts.json","name":"admin.users.json","action":"Pterodactyl\Http\Controllers\Admin\UserController@getJson"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/view\/{id}","name":"admin.users.view","action":"Pterodactyl\Http\Controllers\Admin\UserController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@updateUser"},{"host":null,"methods":["DELETE"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@deleteUser"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/new","name":"admin.users.new","action":"Pterodactyl\Http\Controllers\Admin\UserController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers","name":"admin.servers","action":"Pterodactyl\Http\Controllers\Admin\ServersController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/new","name":"admin.servers.new","action":"Pterodactyl\Http\Controllers\Admin\ServersController@new"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@create"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/nodes","name":"admin.servers.new.nodes","action":"Pterodactyl\Http\Controllers\Admin\ServersController@newServerNodes"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}","name":"admin.servers.view","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/details","name":"admin.servers.view.details","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@setDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details\/container","name":"admin.servers.view.details.container","action":"Pterodactyl\Http\Controllers\Admin\ServersController@setContainer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/build","name":"admin.servers.view.build","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/build","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@updateBuild"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/startup","name":"admin.servers.view.startup","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewStartup"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@saveStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/database","name":"admin.servers.view.database","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDatabase"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/manage","name":"admin.servers.view.manage","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewManage"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/toggle","name":"admin.servers.view.manage.toggle","action":"Pterodactyl\Http\Controllers\Admin\ServersController@toggleInstall"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/rebuild","name":"admin.servers.view.manage.rebuild","action":"Pterodactyl\Http\Controllers\Admin\ServersController@rebuildContainer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/suspension","name":"admin.servers.view.manage.suspension","action":"Pterodactyl\Http\Controllers\Admin\ServersController@manageSuspension"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/delete","name":"admin.servers.view.delete","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDelete"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@delete"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete\/continue\/{force?}","name":"admin.servers.view.delete.continue","action":"Pterodactyl\Http\Controllers\Admin\ServersController@continueDeletion"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete\/cancel","name":"admin.servers.view.delete.cancel","action":"Pterodactyl\Http\Controllers\Admin\ServersController@cancelDeletion"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes","name":"admin.nodes","action":"Pterodactyl\Http\Controllers\Admin\NodesController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/new","name":"admin.nodes.new","action":"Pterodactyl\Http\Controllers\Admin\NodesController@new"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.view","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings","name":"admin.nodes.view.settings","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewSettings"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@updateSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/configuration","name":"admin.nodes.view.configuration","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":"admin.nodes.view.allocation","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewAllocation"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@createAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/servers","name":"admin.nodes.view.servers","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewServers"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/delete","name":"admin.nodes.view.delete","action":"Pterodactyl\Http\Controllers\Admin\NodesController@delete"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove\/{allocation}","name":"admin.nodes.view.allocation.removeSingle","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveSingle"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove","name":"admin.nodes.view.allocation.removeBlock","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveBlock"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/alias","name":"admin.nodes.view.allocation.setAlias","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationSetAlias"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings\/token","name":"admin.nodes.view.configuration.token","action":"Pterodactyl\Http\Controllers\Admin\NodesController@setToken"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/locations","name":"admin.locations","action":"Pterodactyl\Http\Controllers\Admin\LocationsController@getIndex"},{"host":null,"methods":["DELETE"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@deleteLocation"},{"host":null,"methods":["PATCH"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@patchLocation"},{"host":null,"methods":["POST"],"uri":"admin\/locations","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@postLocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases","name":"admin.databases","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases\/new","name":"admin.databases.new","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/databases\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@postNew"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete\/{id}","name":"admin.databases.delete","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteDatabase"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete-server\/{id}","name":"admin.databases.delete-server","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteServer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services","name":"admin.services","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/new","name":"admin.services.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/services\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}","name":"admin.services.service","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getService"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postService"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}\/configuration","name":"admin.services.service.config","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getConfiguration"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}\/configuration","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/new","name":"admin.services.option.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@newOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":"admin.services.option","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOption"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{service}\/option\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":"admin.services.option.variable.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}","name":"admin.services.option.variable","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOptionVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}\/delete","name":"admin.services.option.variable.delete","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/new\/{option?}","name":"admin.services.packs.new","action":"Pterodactyl\Http\Controllers\Admin\PackController@new"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/upload\/{option?}","name":"admin.services.packs.uploadForm","action":"Pterodactyl\Http\Controllers\Admin\PackController@uploadForm"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/upload","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@postUpload"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs","name":"admin.services.packs","action":"Pterodactyl\Http\Controllers\Admin\PackController@listAll"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/option\/{option}","name":"admin.services.packs.option","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/service\/{service}","name":"admin.services.packs.service","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}","name":"admin.services.packs.edit","action":"Pterodactyl\Http\Controllers\Admin\PackController@edit"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/edit\/{pack}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}\/export\/{archive?}","name":"admin.services.packs.export","action":"Pterodactyl\Http\Controllers\Admin\PackController@export"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login","name":"auth.login","action":"Pterodactyl\Http\Controllers\Auth\LoginController@showLoginForm"},{"host":null,"methods":["POST"],"uri":"auth\/login","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@login"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login\/totp","name":"auth.totp","action":"Pterodactyl\Http\Controllers\Auth\LoginController@totp"},{"host":null,"methods":["POST"],"uri":"auth\/login\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@totpCheckpoint"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password","name":"auth.password","action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm"},{"host":null,"methods":["POST"],"uri":"auth\/password","name":null,"action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password\/reset\/{token}","name":"auth.reset","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@showResetForm"},{"host":null,"methods":["POST"],"uri":"auth\/password\/reset","name":"auth.reset.post","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@reset"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/logout","name":"auth.logout","action":"Pterodactyl\Http\Controllers\Auth\LoginController@logout"},{"host":null,"methods":["GET","HEAD"],"uri":"\/","name":"index","action":"Pterodactyl\Http\Controllers\Base\IndexController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"index","name":null,"action":"Closure"},{"host":null,"methods":["GET","HEAD"],"uri":"password-gen\/{length}","name":"password-gen","action":"Pterodactyl\Http\Controllers\Base\IndexController@getPassword"},{"host":null,"methods":["GET","HEAD"],"uri":"account","name":"account","action":"Pterodactyl\Http\Controllers\Base\AccountController@index"},{"host":null,"methods":["POST"],"uri":"account","name":null,"action":"Pterodactyl\Http\Controllers\Base\AccountController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api","name":"account.api","action":"Pterodactyl\Http\Controllers\Base\APIController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api\/new","name":"account.api.new","action":"Pterodactyl\Http\Controllers\Base\APIController@create"},{"host":null,"methods":["POST"],"uri":"account\/api\/new","name":null,"action":"Pterodactyl\Http\Controllers\Base\APIController@save"},{"host":null,"methods":["DELETE"],"uri":"account\/api\/revoke\/{key}","name":"account.api.revoke","action":"Pterodactyl\Http\Controllers\Base\APIController@revoke"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security","name":"account.security","action":"Pterodactyl\Http\Controllers\Base\SecurityController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security\/revoke\/{id}","name":"account.security.revoke","action":"Pterodactyl\Http\Controllers\Base\SecurityController@revoke"},{"host":null,"methods":["PUT"],"uri":"account\/security\/totp","name":"account.security.totp","action":"Pterodactyl\Http\Controllers\Base\SecurityController@generateTotp"},{"host":null,"methods":["POST"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@setTotp"},{"host":null,"methods":["DELETE"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@disableTotp"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services","name":"daemon.services","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@list"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services\/pull\/{service}\/{file}","name":"remote.install","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}","name":"daemon.pack.pull","action":"Pterodactyl\Http\Controllers\Daemon\PackController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}\/hash","name":"daemon.pack.hash","action":"Pterodactyl\Http\Controllers\Daemon\PackController@hash"},{"host":null,"methods":["GET","HEAD"],"uri":"language\/{lang}","name":"langauge.set","action":"Pterodactyl\Http\Controllers\Base\LanguageController@setLanguage"},{"host":null,"methods":["POST"],"uri":"remote\/download","name":"remote.download","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postDownload"},{"host":null,"methods":["POST"],"uri":"remote\/install","name":"remote.install","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postInstall"},{"host":null,"methods":["GET","HEAD"],"uri":"remote\/configuration\/{token}","name":"remote.configuration","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@getConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/ajax\/status","name":"server.ajax.status","action":"Pterodactyl\Http\Controllers\Server\AjaxController@getStatus"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}","name":"server.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/databases","name":"server.settings.databases","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDatabases"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/sftp","name":"server.settings.sftp","action":"Pterodactyl\Http\Controllers\Server\ServerController@getSFTP"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/sftp","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsSFTP"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/startup","name":"server.settings.startup","action":"Pterodactyl\Http\Controllers\Server\ServerController@getStartup"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/allocation","name":"server.settings.allocation","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files","name":"server.files.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getFiles"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/edit\/{file}","name":"server.files.edit","action":"Pterodactyl\Http\Controllers\Server\ServerController@getEditFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/download\/{file}","name":"server.files.download","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDownloadFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/add","name":"server.files.add","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAddFile"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/directory-list","name":"server.files.directory-list","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postDirectoryList"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/save","name":"server.files.save","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSaveFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users","name":"server.subusers","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/new","name":"server.subusers.new","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/view\/{id}","name":"server.subusers.view","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getView"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postView"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/users\/delete\/{id}","name":"server.subusers.delete","action":"Pterodactyl\Http\Controllers\Server\SubuserController@deleteSubuser"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks","name":"server.tasks","action":"Pterodactyl\Http\Controllers\Server\TaskController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/view\/{id}","name":"server.tasks.view","action":"Pterodactyl\Http\Controllers\Server\TaskController@getView"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/new","name":"server.tasks.new","action":"Pterodactyl\Http\Controllers\Server\TaskController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\TaskController@postNew"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/tasks\/delete\/{id}","name":"server.tasks.delete","action":"Pterodactyl\Http\Controllers\Server\TaskController@deleteTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/toggle\/{id}","name":"server.tasks.toggle","action":"Pterodactyl\Http\Controllers\Server\TaskController@toggleTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/set-primary","name":null,"action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSetPrimary"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/settings\/reset-database-password","name":"server.ajax.reset-database-password","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postResetDatabasePassword"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/open","name":"debugbar.openhandler","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@handle"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/clockwork\/{id}","name":"debugbar.clockwork","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@clockwork"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/stylesheets","name":"debugbar.assets.css","action":"Barryvdh\Debugbar\Controllers\AssetController@css"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/javascript","name":"debugbar.assets.js","action":"Barryvdh\Debugbar\Controllers\AssetController@js"}], + routes : [{"host":null,"methods":["GET","HEAD"],"uri":"admin","name":"admin.index","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/settings","name":"admin.settings","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getSettings"},{"host":null,"methods":["POST"],"uri":"admin\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\BaseController@postSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users","name":"admin.users","action":"Pterodactyl\Http\Controllers\Admin\UserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/accounts.json","name":"admin.users.json","action":"Pterodactyl\Http\Controllers\Admin\UserController@getJson"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/view\/{id}","name":"admin.users.view","action":"Pterodactyl\Http\Controllers\Admin\UserController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@updateUser"},{"host":null,"methods":["DELETE"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@deleteUser"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/new","name":"admin.users.new","action":"Pterodactyl\Http\Controllers\Admin\UserController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers","name":"admin.servers","action":"Pterodactyl\Http\Controllers\Admin\ServersController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/new","name":"admin.servers.new","action":"Pterodactyl\Http\Controllers\Admin\ServersController@new"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@create"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/nodes","name":"admin.servers.new.nodes","action":"Pterodactyl\Http\Controllers\Admin\ServersController@newServerNodes"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}","name":"admin.servers.view","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/details","name":"admin.servers.view.details","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@setDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details\/container","name":"admin.servers.view.details.container","action":"Pterodactyl\Http\Controllers\Admin\ServersController@setContainer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/build","name":"admin.servers.view.build","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/build","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@updateBuild"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/startup","name":"admin.servers.view.startup","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewStartup"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@saveStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/database","name":"admin.servers.view.database","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDatabase"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/database","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@newDatabase"},{"host":null,"methods":["PATCH"],"uri":"admin\/servers\/view\/{id}\/database","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@resetDatabasePassword"},{"host":null,"methods":["DELETE"],"uri":"admin\/servers\/view\/{id}\/database\/{database}\/delete","name":"admin.servers.view.database.delete","action":"Pterodactyl\Http\Controllers\Admin\ServersController@deleteDatabase"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/manage","name":"admin.servers.view.manage","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewManage"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/toggle","name":"admin.servers.view.manage.toggle","action":"Pterodactyl\Http\Controllers\Admin\ServersController@toggleInstall"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/rebuild","name":"admin.servers.view.manage.rebuild","action":"Pterodactyl\Http\Controllers\Admin\ServersController@rebuildContainer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/suspension","name":"admin.servers.view.manage.suspension","action":"Pterodactyl\Http\Controllers\Admin\ServersController@manageSuspension"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/delete","name":"admin.servers.view.delete","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDelete"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@delete"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete\/continue\/{force?}","name":"admin.servers.view.delete.continue","action":"Pterodactyl\Http\Controllers\Admin\ServersController@continueDeletion"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete\/cancel","name":"admin.servers.view.delete.cancel","action":"Pterodactyl\Http\Controllers\Admin\ServersController@cancelDeletion"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes","name":"admin.nodes","action":"Pterodactyl\Http\Controllers\Admin\NodesController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/new","name":"admin.nodes.new","action":"Pterodactyl\Http\Controllers\Admin\NodesController@new"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.view","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings","name":"admin.nodes.view.settings","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewSettings"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@updateSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/configuration","name":"admin.nodes.view.configuration","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":"admin.nodes.view.allocation","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewAllocation"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@createAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/servers","name":"admin.nodes.view.servers","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewServers"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/delete","name":"admin.nodes.view.delete","action":"Pterodactyl\Http\Controllers\Admin\NodesController@delete"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove\/{allocation}","name":"admin.nodes.view.allocation.removeSingle","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveSingle"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove","name":"admin.nodes.view.allocation.removeBlock","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveBlock"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/alias","name":"admin.nodes.view.allocation.setAlias","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationSetAlias"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings\/token","name":"admin.nodes.view.configuration.token","action":"Pterodactyl\Http\Controllers\Admin\NodesController@setToken"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/locations","name":"admin.locations","action":"Pterodactyl\Http\Controllers\Admin\LocationsController@getIndex"},{"host":null,"methods":["DELETE"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@deleteLocation"},{"host":null,"methods":["PATCH"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@patchLocation"},{"host":null,"methods":["POST"],"uri":"admin\/locations","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@postLocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases","name":"admin.databases","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases\/new","name":"admin.databases.new","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/databases\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@postNew"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete\/{id}","name":"admin.databases.delete","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteDatabase"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete-server\/{id}","name":"admin.databases.delete-server","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteServer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services","name":"admin.services","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/new","name":"admin.services.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/services\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}","name":"admin.services.service","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getService"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postService"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}\/configuration","name":"admin.services.service.config","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getConfiguration"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}\/configuration","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/new","name":"admin.services.option.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@newOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":"admin.services.option","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOption"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{service}\/option\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":"admin.services.option.variable.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}","name":"admin.services.option.variable","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOptionVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}\/delete","name":"admin.services.option.variable.delete","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/new\/{option?}","name":"admin.services.packs.new","action":"Pterodactyl\Http\Controllers\Admin\PackController@new"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/upload\/{option?}","name":"admin.services.packs.uploadForm","action":"Pterodactyl\Http\Controllers\Admin\PackController@uploadForm"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/upload","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@postUpload"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs","name":"admin.services.packs","action":"Pterodactyl\Http\Controllers\Admin\PackController@listAll"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/option\/{option}","name":"admin.services.packs.option","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/service\/{service}","name":"admin.services.packs.service","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}","name":"admin.services.packs.edit","action":"Pterodactyl\Http\Controllers\Admin\PackController@edit"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/edit\/{pack}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}\/export\/{archive?}","name":"admin.services.packs.export","action":"Pterodactyl\Http\Controllers\Admin\PackController@export"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login","name":"auth.login","action":"Pterodactyl\Http\Controllers\Auth\LoginController@showLoginForm"},{"host":null,"methods":["POST"],"uri":"auth\/login","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@login"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login\/totp","name":"auth.totp","action":"Pterodactyl\Http\Controllers\Auth\LoginController@totp"},{"host":null,"methods":["POST"],"uri":"auth\/login\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@totpCheckpoint"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password","name":"auth.password","action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm"},{"host":null,"methods":["POST"],"uri":"auth\/password","name":null,"action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password\/reset\/{token}","name":"auth.reset","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@showResetForm"},{"host":null,"methods":["POST"],"uri":"auth\/password\/reset","name":"auth.reset.post","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@reset"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/logout","name":"auth.logout","action":"Pterodactyl\Http\Controllers\Auth\LoginController@logout"},{"host":null,"methods":["GET","HEAD"],"uri":"\/","name":"index","action":"Pterodactyl\Http\Controllers\Base\IndexController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"index","name":null,"action":"Closure"},{"host":null,"methods":["GET","HEAD"],"uri":"password-gen\/{length}","name":"password-gen","action":"Pterodactyl\Http\Controllers\Base\IndexController@getPassword"},{"host":null,"methods":["GET","HEAD"],"uri":"account","name":"account","action":"Pterodactyl\Http\Controllers\Base\AccountController@index"},{"host":null,"methods":["POST"],"uri":"account","name":null,"action":"Pterodactyl\Http\Controllers\Base\AccountController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api","name":"account.api","action":"Pterodactyl\Http\Controllers\Base\APIController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api\/new","name":"account.api.new","action":"Pterodactyl\Http\Controllers\Base\APIController@create"},{"host":null,"methods":["POST"],"uri":"account\/api\/new","name":null,"action":"Pterodactyl\Http\Controllers\Base\APIController@save"},{"host":null,"methods":["DELETE"],"uri":"account\/api\/revoke\/{key}","name":"account.api.revoke","action":"Pterodactyl\Http\Controllers\Base\APIController@revoke"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security","name":"account.security","action":"Pterodactyl\Http\Controllers\Base\SecurityController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security\/revoke\/{id}","name":"account.security.revoke","action":"Pterodactyl\Http\Controllers\Base\SecurityController@revoke"},{"host":null,"methods":["PUT"],"uri":"account\/security\/totp","name":"account.security.totp","action":"Pterodactyl\Http\Controllers\Base\SecurityController@generateTotp"},{"host":null,"methods":["POST"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@setTotp"},{"host":null,"methods":["DELETE"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@disableTotp"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services","name":"daemon.services","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@list"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services\/pull\/{service}\/{file}","name":"remote.install","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}","name":"daemon.pack.pull","action":"Pterodactyl\Http\Controllers\Daemon\PackController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}\/hash","name":"daemon.pack.hash","action":"Pterodactyl\Http\Controllers\Daemon\PackController@hash"},{"host":null,"methods":["GET","HEAD"],"uri":"language\/{lang}","name":"langauge.set","action":"Pterodactyl\Http\Controllers\Base\LanguageController@setLanguage"},{"host":null,"methods":["POST"],"uri":"remote\/download","name":"remote.download","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postDownload"},{"host":null,"methods":["POST"],"uri":"remote\/install","name":"remote.install","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postInstall"},{"host":null,"methods":["GET","HEAD"],"uri":"remote\/configuration\/{token}","name":"remote.configuration","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@getConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/ajax\/status","name":"server.ajax.status","action":"Pterodactyl\Http\Controllers\Server\AjaxController@getStatus"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}","name":"server.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/databases","name":"server.settings.databases","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDatabases"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/sftp","name":"server.settings.sftp","action":"Pterodactyl\Http\Controllers\Server\ServerController@getSFTP"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/sftp","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsSFTP"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/startup","name":"server.settings.startup","action":"Pterodactyl\Http\Controllers\Server\ServerController@getStartup"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/allocation","name":"server.settings.allocation","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files","name":"server.files.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getFiles"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/edit\/{file}","name":"server.files.edit","action":"Pterodactyl\Http\Controllers\Server\ServerController@getEditFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/download\/{file}","name":"server.files.download","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDownloadFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/add","name":"server.files.add","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAddFile"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/directory-list","name":"server.files.directory-list","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postDirectoryList"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/save","name":"server.files.save","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSaveFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users","name":"server.subusers","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/new","name":"server.subusers.new","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/view\/{id}","name":"server.subusers.view","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getView"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postView"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/users\/delete\/{id}","name":"server.subusers.delete","action":"Pterodactyl\Http\Controllers\Server\SubuserController@deleteSubuser"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks","name":"server.tasks","action":"Pterodactyl\Http\Controllers\Server\TaskController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/view\/{id}","name":"server.tasks.view","action":"Pterodactyl\Http\Controllers\Server\TaskController@getView"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/new","name":"server.tasks.new","action":"Pterodactyl\Http\Controllers\Server\TaskController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\TaskController@postNew"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/tasks\/delete\/{id}","name":"server.tasks.delete","action":"Pterodactyl\Http\Controllers\Server\TaskController@deleteTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/toggle\/{id}","name":"server.tasks.toggle","action":"Pterodactyl\Http\Controllers\Server\TaskController@toggleTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/set-primary","name":null,"action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSetPrimary"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/settings\/reset-database-password","name":"server.ajax.reset-database-password","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postResetDatabasePassword"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/open","name":"debugbar.openhandler","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@handle"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/clockwork\/{id}","name":"debugbar.clockwork","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@clockwork"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/stylesheets","name":"debugbar.assets.css","action":"Barryvdh\Debugbar\Controllers\AssetController@css"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/javascript","name":"debugbar.assets.js","action":"Barryvdh\Debugbar\Controllers\AssetController@js"}], prefix: '', route : function (name, parameters, route) { diff --git a/resources/themes/pterodactyl/admin/servers/view/database.blade.php b/resources/themes/pterodactyl/admin/servers/view/database.blade.php index e69de29bb..c9ebf506e 100644 --- a/resources/themes/pterodactyl/admin/servers/view/database.blade.php +++ b/resources/themes/pterodactyl/admin/servers/view/database.blade.php @@ -0,0 +1,192 @@ +{{-- 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 }}: Databases +@endsection + +@section('content-header') +

      {{ $server->name }}Manage server databases.

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

      Active Databases

      +
      +
      + + + + + + + + + @foreach($server->databases as $database) + + + + + + + + @endforeach +
      DatabaseUsernameConnections FromHost
      {{ $database->database }}{{ $database->username }}{{ $database->remote }}{{ $database->host->host }}:{{ $database->host->port }} + + +
      +
      +
      +
      +
      +
      +
      +

      Create New Database

      +
      +
      +
      +
      + + +

      Select the host database server that this database should be created on.

      +
      +
      + +
      + s{{ $server->id }}_ + +
      +
      +
      + + +

      This should reflect the IP address that connections are allowed from. Uses standard MySQL notation. If unsure leave as %.

      +
      +
      + +
      +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection From 33555547048ade331f44af1f128183951f1e9a82 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 5 Mar 2017 16:46:44 -0500 Subject: [PATCH 313/599] Fix frontend database password reset --- .../Controllers/Server/AjaxController.php | 15 +++++----- public/themes/pterodactyl/css/pterodactyl.css | 2 +- .../server/settings/databases.blade.php | 28 ++++++++++--------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/app/Http/Controllers/Server/AjaxController.php b/app/Http/Controllers/Server/AjaxController.php index 8f3736da7..4609ae270 100644 --- a/app/Http/Controllers/Server/AjaxController.php +++ b/app/Http/Controllers/Server/AjaxController.php @@ -224,17 +224,16 @@ class AjaxController extends Controller $server = Models\Server::byUuid($uuid); $this->authorize('reset-db-password', $server); - $database = Models\Database::where('id', $request->input('database'))->where('server_id', $server->id)->firstOrFail(); + $database = Models\Database::where('server_id', $server->id)->findOrFail($request->input('database')); + $repo = new Repositories\DatabaseRepository; + try { - $repo = new Repositories\DatabaseRepository; - $password = str_random(16); - $repo->modifyPassword($request->input('database'), $password); + $password = str_random(20); + $repo->password($database->id, $password); return response($password); - } catch (\Pterodactyl\Exceptions\DisplayException $ex) { - return response()->json([ - 'error' => $ex->getMessage(), - ], 503); + } catch (DisplayException $ex) { + return response()->json(['error' => $ex->getMessage()], 503); } catch (\Exception $ex) { Log::error($ex); diff --git a/public/themes/pterodactyl/css/pterodactyl.css b/public/themes/pterodactyl/css/pterodactyl.css index c4b1cf256..ca34e46a5 100644 --- a/public/themes/pterodactyl/css/pterodactyl.css +++ b/public/themes/pterodactyl/css/pterodactyl.css @@ -65,7 +65,7 @@ code { font-size: 14px !important; } -.middle { +.middle, .align-middle { vertical-align: middle !important; } diff --git a/resources/themes/pterodactyl/server/settings/databases.blade.php b/resources/themes/pterodactyl/server/settings/databases.blade.php index b69b0f36d..5e90be84f 100644 --- a/resources/themes/pterodactyl/server/settings/databases.blade.php +++ b/resources/themes/pterodactyl/server/settings/databases.blade.php @@ -49,17 +49,19 @@ @lang('strings.username') @lang('strings.password') @lang('server.config.database.host') + @can('reset-db-password', $server)@endcan @foreach($databases as $database) - {{ $database->database }} - {{ $database->username }} - {{ Crypt::decrypt($database->password) }} - @can('reset-db-password', $server) - - @endcan - - {{ $database->a_host }}:{{ $database->a_port }} + {{ $database->database }} + {{ $database->username }} + {{ Crypt::decrypt($database->password) }} + {{ $database->a_host }}:{{ $database->a_port }} + @can('reset-db-password', $server) + + + + @endcan @endforeach @@ -88,10 +90,10 @@ {!! Theme::js('js/frontend/server.socket.js') !!} +@endsection diff --git a/resources/themes/pterodactyl/admin/services/view.blade.php b/resources/themes/pterodactyl/admin/services/view.blade.php new file mode 100644 index 000000000..42d151539 --- /dev/null +++ b/resources/themes/pterodactyl/admin/services/view.blade.php @@ -0,0 +1,113 @@ +{{-- 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') + Services: {{ $service->name }} +@endsection + +@section('content-header') +

      {{ $service->name }}{{ str_limit($service->description, 50) }}

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

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

      +
      +
      +
      + +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      + +
      + +

      Services are downloaded by the daemon and stored in a folder using this name. The storage location is /srv/daemon/services/{NAME} by default.

      +
      +
      +
      + +
      + +

      The default start command to use when running options under this service. This command can be modified per-option and should include the executable to be called in the container.

      +
      +
      +
      + +
      +
      +
      +
      +
      +
      +
      +
      +

      Configured Options

      +
      +
      + + + + + + + + @foreach($service->options as $option) + + + + + + + @endforeach +
      NameDescriptionTagServers
      {{ $option->name }}{!! $option->description !!}{{ $option->tag }}{{ $option->servers->count() }}
      +
      + +
      +
      +
      +@endsection diff --git a/resources/themes/pterodactyl/layouts/admin.blade.php b/resources/themes/pterodactyl/layouts/admin.blade.php index 96b8c0e98..a6c735c60 100644 --- a/resources/themes/pterodactyl/layouts/admin.blade.php +++ b/resources/themes/pterodactyl/layouts/admin.blade.php @@ -106,6 +106,17 @@ Users +
    • SERVICE MANAGEMENT
    • +
    • + + Services + +
    • +
    • + + Packs + +
    • From 871b7354649f40acba7205fc8315c9a3e6fb0f3f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 11 Mar 2017 14:44:18 -0500 Subject: [PATCH 318/599] Ignore VSCode files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a30c114f5..9f02de4ca 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.DS_Store* .env .vagrant/* +.vscode/* composer.lock From bccbb309b2da37aa222db7b2308edd0d1a1f492f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 11 Mar 2017 15:02:04 -0500 Subject: [PATCH 319/599] Fix broken descriptors --- app/Models/User.php | 2 +- app/Repositories/DatabaseRepository.php | 2 +- app/Services/DeploymentService.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Models/User.php b/app/Models/User.php index b660e304c..cb78ad4a8 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -66,7 +66,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac /** * A list of mass-assignable variables. * - * @var [type] + * @var array */ protected $fillable = ['username', 'email', 'name_first', 'name_last', 'password', 'language', 'use_totp', 'totp_secret', 'gravatar', 'root_admin']; diff --git a/app/Repositories/DatabaseRepository.php b/app/Repositories/DatabaseRepository.php index b0d85b60f..5397fc5c7 100644 --- a/app/Repositories/DatabaseRepository.php +++ b/app/Repositories/DatabaseRepository.php @@ -199,7 +199,7 @@ class DatabaseRepository * Deletes a database server from the system if it is empty. * * @param int $server The ID of the Database Server. - * @return + * @return bool */ public function delete($server) { diff --git a/app/Services/DeploymentService.php b/app/Services/DeploymentService.php index af1ede940..d4d28e9a9 100644 --- a/app/Services/DeploymentService.php +++ b/app/Services/DeploymentService.php @@ -79,7 +79,7 @@ class DeploymentService * @param int $memory * @param int $disk * @param int $location - * @return \Pterodactyl\Models\Node; + * @return \Pterodactyl\Models\Node * * @throws \Pterodactyl\Exceptions\DisplayException */ @@ -103,7 +103,7 @@ class DeploymentService /** * Returns a random allocation for a node. * @param int $node - * @return \Models\Pterodactyl\Allocation; + * @return \Models\Pterodactyl\Allocation */ public static function randomAllocation($node) { From d7682bb7c91ff73b8d42b54ae12bd40bd02d8442 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 12 Mar 2017 00:00:06 -0500 Subject: [PATCH 320/599] Complete new service, option, and variable management interface in Admin CP --- .../Controllers/Admin/OptionController.php | 126 +++- .../Controllers/Admin/ServiceController.php | 41 +- app/Http/Routes/AdminRoutes.php | 11 +- app/Models/Service.php | 2 +- app/Repositories/OptionRepository.php | 84 +++ app/Repositories/ServiceRepository.php | 21 +- app/Repositories/VariableRepository.php | 140 ++-- config/pterodactyl.php | 1 + ..._ChangeServiceVariablesValidationRules.php | 47 ++ .../admin/services/options/new.blade.php | 170 +++++ .../services/options/variables.blade.php | 114 +++ .../admin/services/options/view.blade.php | 14 +- .../pterodactyl/admin/services/view.blade.php | 12 + resources/views/admin/servers/view.blade.php | 687 ------------------ .../admin/services/options/variable.blade.php | 122 ---- storage/app/services/index.js | 31 + 16 files changed, 698 insertions(+), 925 deletions(-) create mode 100644 database/migrations/2017_03_11_215455_ChangeServiceVariablesValidationRules.php create mode 100644 resources/themes/pterodactyl/admin/services/options/new.blade.php create mode 100644 resources/themes/pterodactyl/admin/services/options/variables.blade.php delete mode 100644 resources/views/admin/servers/view.blade.php delete mode 100644 resources/views/admin/services/options/variable.blade.php create mode 100644 storage/app/services/index.js diff --git a/app/Http/Controllers/Admin/OptionController.php b/app/Http/Controllers/Admin/OptionController.php index 3dc9b24ff..b60c0df7b 100644 --- a/app/Http/Controllers/Admin/OptionController.php +++ b/app/Http/Controllers/Admin/OptionController.php @@ -27,15 +27,63 @@ namespace Pterodactyl\Http\Controllers\Admin; use Log; use Alert; use Storage; -use Pterodactyl\Models; +use Javascript; use Illuminate\Http\Request; +use Pterodactyl\Models\Service; +use Pterodactyl\Models\ServiceOption; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Repositories\OptionRepository; +use Pterodactyl\Repositories\VariableRepository; use Pterodactyl\Exceptions\DisplayValidationException; class OptionController extends Controller { + /** + * Handles request to view page for adding new option. + * + * @param Request $request + * @return \Illuminate\View\View + */ + public function new(Request $request) + { + $services = Service::with('options')->get(); + Javascript::put(['services' => $services->keyBy('id')]); + + return view('admin.services.options.new', ['services' => $services]); + } + + /** + * Handles POST request to create a new option. + + * @param Request $request + * @return \Illuminate\Response\RedirectResponse + */ + public function create(Request $request) + { + $repo = new OptionRepository; + + try { + $option = $repo->create($request->intersect([ + 'service_id', 'name', 'description', 'tag', + 'docker_image', 'startup', 'config_from', 'config_startup', + 'config_logs', 'config_files', 'config_stop' + ])); + Alert::success('Successfully created new service option.')->flash(); + + return redirect()->route('admin.services.option.view', $option->id); + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.services.option.new')->withErrors(json_decode($ex->getMessage()))->withInput(); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An unhandled exception occurred while attempting to create this service. This error has been logged.')->flash(); + } + + return redirect()->route('admin.services.option.new')->withInput(); + } + /** * Display option overview page. * @@ -45,27 +93,89 @@ class OptionController extends Controller */ public function viewConfiguration(Request $request, $id) { - return view('admin.services.options.view', ['option' => Models\ServiceOption::findOrFail($id)]); + return view('admin.services.options.view', ['option' => ServiceOption::findOrFail($id)]); } + /** + * Display variable overview page for a service option. + * + * @param Request $request + * @param int $id + * @return \Illuminate\View\View + */ + public function viewVariables(Request $request, $id) + { + return view('admin.services.options.variables', ['option' => ServiceOption::with('variables')->findOrFail($id)]); + } + + /** + * Handles POST when editing a configration for a service option. + * + * @param Request $request + * @return \Illuminate\Response\RedirectResponse + */ public function editConfiguration(Request $request, $id) { $repo = new OptionRepository; try { - $repo->update($id, $request->intersect([ - 'name', 'description', 'tag', 'docker_image', 'startup', - 'config_from', 'config_stop', 'config_logs', 'config_files', 'config_startup', - ])); + if ($request->input('action') !== 'delete') { + $repo->update($id, $request->intersect([ + 'name', 'description', 'tag', 'docker_image', 'startup', + 'config_from', 'config_stop', 'config_logs', 'config_files', 'config_startup', + ])); + Alert::success('Service option configuration has been successfully updated.')->flash(); + } else { + $option = ServiceOption::with('service')->where('id', $id)->first(); + $repo->delete($id); + Alert::success('Successfully deleted service option from the system.')->flash(); - Alert::success('Service option configuration has been successfully updated.')->flash(); + return redirect()->route('admin.services.view', $option->service_id); + } } catch (DisplayValidationException $ex) { return redirect()->route('admin.services.option.view', $id)->withErrors(json_decode($ex->getMessage())); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); } catch (\Exception $ex) { Log::error($ex); - Alert::danger('An unhandled exception occurred while attempting to update this service option. This error has been logged.')->flash(); + Alert::danger('An unhandled exception occurred while attempting to perform that action. This error has been logged.')->flash(); } return redirect()->route('admin.services.option.view', $id); } + + /** + * Handles POST when editing a configration for a service option. + * + * @param Request $request + * @param int $option + * @param int $variable + * @return \Illuminate\Response\RedirectResponse + */ + public function editVariable(Request $request, $option, $variable) + { + $repo = new VariableRepository; + + try { + if ($request->input('action') !== 'delete') { + $variable = $repo->update($variable, $request->only([ + 'name', 'description', 'env_variable', + 'default_value', 'options', 'rules', + ])); + Alert::success("The service variable '{$variable->name}' has been updated.")->flash(); + } else { + $repo->delete($variable); + Alert::success("That service variable has been deleted.")->flash(); + } + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.services.option.variables', $option)->withErrors(json_decode($ex->getMessage())); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An unhandled exception was encountered while attempting to process that request. This error has been logged.')->flash(); + } + + return redirect()->route('admin.services.option.variables', $option); + } } diff --git a/app/Http/Controllers/Admin/ServiceController.php b/app/Http/Controllers/Admin/ServiceController.php index 81ca528b8..60450ab28 100644 --- a/app/Http/Controllers/Admin/ServiceController.php +++ b/app/Http/Controllers/Admin/ServiceController.php @@ -103,32 +103,6 @@ class ServiceController extends Controller return redirect()->route('admin.services.new')->withInput(); } - /** - * Delete a service from the system. - * - * @param Request $request - * @param int $id - * @return \Illuminate\Response\RedirectResponse - */ - public function delete(Request $request, $id) - { - $repo = new ServiceRepository; - - try { - $repo->delete($id); - Alert::success('Successfully deleted service.')->flash(); - - return redirect()->route('admin.services'); - } catch (DisplayException $ex) { - Alert::danger($ex->getMessage())->flash(); - } catch (\Exception $ex) { - Log::error($ex); - Alert::danger('An error was encountered while attempting to delete that service. This error has been logged')->flash(); - } - - return redirect()->route('admin.services.view', $id); - } - /** * Edits configuration for a specific service. * @@ -141,10 +115,17 @@ class ServiceController extends Controller $repo = new ServiceRepository; try { - $repo->update($id, $request->intersect([ - 'name', 'description', 'folder', 'startup', - ])); - Alert::success('Service has been updated successfully.')->flash(); + if ($request->input('action') !== 'delete') { + $repo->update($id, $request->intersect([ + 'name', 'description', 'folder', 'startup', + ])); + Alert::success('Service has been updated successfully.')->flash(); + } else { + $repo->delete($id); + Alert::success('Successfully deleted service from the system.')->flash(); + + return redirect()->route('admin.services'); + } } catch (DisplayValidationException $ex) { return redirect()->route('admin.services.view', $id)->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index edf8fdc91..5cec94b55 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -419,20 +419,25 @@ class AdminRoutes 'uses' => 'Admin\OptionController@new', ]); + $router->post('/option/new', 'Admin\OptionController@create'); + $router->get('/option/{id}', [ 'as' => 'admin.services.option.view', 'uses' => 'Admin\OptionController@viewConfiguration', ]); $router->get('/option/{id}/variables', [ - 'as' => 'admin.services.option.view.variables', + 'as' => 'admin.services.option.variables', 'uses' => 'Admin\OptionController@viewVariables', ]); - $router->post('/option/{id}', [ - 'uses' => 'Admin\OptionController@editConfiguration', + $router->post('/option/{id}/variables/{variable}', [ + 'as' => 'admin.services.option.variables.edit', + 'uses' => 'Admin\OptionController@editVariable', ]); + $router->post('/option/{id}', 'Admin\OptionController@editConfiguration'); + }); // Service Packs diff --git a/app/Models/Service.php b/app/Models/Service.php index 83cdb70b0..50679633e 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -41,7 +41,7 @@ class Service extends Model * @var array */ protected $fillable = [ - 'name', 'description', 'file', 'executable', 'startup', + 'name', 'description', 'folder', 'startup', ]; /** diff --git a/app/Repositories/OptionRepository.php b/app/Repositories/OptionRepository.php index 7ded09689..e33eb652c 100644 --- a/app/Repositories/OptionRepository.php +++ b/app/Repositories/OptionRepository.php @@ -28,10 +28,74 @@ use DB; use Validator; use Pterodactyl\Models\ServiceOption; use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Repositories\VariableRepository; use Pterodactyl\Exceptions\DisplayValidationException; class OptionRepository { + /** + * Creates a new service option on the system. + * + * @param array $data + * @return \Pterodactyl\Models\ServiceOption + * + * @throws \Pterodactyl\Exceptions\DisplayException + * @throws \Pterodactyl\Exceptions\DisplayValidationException + */ + public function create(array $data) + { + $validator = Validator::make($data, [ + 'service_id' => 'required|numeric|exists:services,id', + 'name' => 'required|string|max:255', + 'description' => 'required|string', + 'tag' => 'required|string|max:255|unique:service_options,tag', + 'docker_image' => 'required|string|max:255', + 'startup' => 'required|string', + 'config_from' => 'sometimes|required|numeric|exists:service_options,id', + 'config_startup' => 'required_without:config_from|json', + 'config_stop' => 'required_without:config_from|string|max:255', + 'config_logs' => 'required_without:config_from|json', + 'config_files' => 'required_without:config_from|json', + ]); + + if ($validator->fails()) { + throw new DisplayValidationException($validator->errors()); + } + + if (isset($data['config_from'])) { + if (! ServiceOption::where('service_id', $data['service_id'])->where('id', $data['config_from'])->first()) { + throw new DisplayException('The `configuration from` directive must be a child of the assigned service.'); + } + } + + return ServiceOption::create($data); + } + + /** + * Deletes a service option from the system. + * + * @param int $id + * @return void + * + * @throws \Pterodactyl\Exceptions\DisplayException + */ + public function delete($id) + { + $option = ServiceOption::with('variables')->withCount('servers')->findOrFail($id); + + if ($option->servers_count > 0) { + throw new DisplayException('You cannot delete a service option that has servers associated with it.'); + } + + DB::transaction(function () use ($option) { + foreach($option->variables as $variable) { + (new VariableRepository)->delete($variable->id); + } + + $option->delete(); + }); + } + /** * Updates a service option in the database which can then be used * on nodes. @@ -39,11 +103,25 @@ class OptionRepository * @param int $id * @param array $data * @return \Pterodactyl\Models\ServiceOption + * + * @throws \Pterodactyl\Exceptions\DisplayException + * @throws \Pterodactyl\Exceptions\DisplayValidationException */ public function update($id, array $data) { $option = ServiceOption::findOrFail($id); + // Due to code limitations (at least when I am writing this currently) + // we have to make an assumption that if config_from is not passed + // that we should be telling it that no config is wanted anymore. + // + // This really is only an issue if we open API access to this function, + // in which case users will always need to pass `config_from` in order + // to keep it assigned. + if (! isset($data['config_from']) && ! is_null($option->config_from)) { + $option->config_from = null; + } + $validator = Validator::make($data, [ 'name' => 'sometimes|required|string|max:255', 'description' => 'sometimes|required|string', @@ -73,6 +151,12 @@ class OptionRepository throw new DisplayValidationException($validator->errors()); } + if (isset($data['config_from'])) { + if (! ServiceOption::where('service_id', $option->service_id)->where('id', $data['config_from'])->first()) { + throw new DisplayException('The `configuration from` directive must be a child of the assigned service.'); + } + } + $option->fill($data)->save(); return $option; diff --git a/app/Repositories/ServiceRepository.php b/app/Repositories/ServiceRepository.php index ed9dbf03d..a82c80b3f 100644 --- a/app/Repositories/ServiceRepository.php +++ b/app/Repositories/ServiceRepository.php @@ -31,6 +31,7 @@ use Validator; use Pterodactyl\Models\Service; use Pterodactyl\Models\ServiceVariable; use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Repositories\OptionRepository; use Pterodactyl\Exceptions\DisplayValidationException; class ServiceRepository @@ -55,13 +56,14 @@ class ServiceRepository } $service = DB::transaction(function () use ($data) { - $service = Service::create([ - 'author' => config('pterodactyl.service.author'), + $service = new Service; + $service->author = config('pterodactyl.service.author'); + $service->fill([ 'name' => $data['name'], 'description' => (isset($data['description'])) ? $data['description'] : null, 'folder' => $data['folder'], 'startup' => (isset($data['startup'])) ? $data['startup'] : null, - ]); + ])->save(); // It is possible for an event to return false or throw an exception // which won't necessarily be detected by this transaction. @@ -105,8 +107,7 @@ class ServiceRepository $moveFiles = (isset($data['folder']) && $data['folder'] !== $service->folder); $oldFolder = $service->folder; - $service->fill($data); - $service->save(); + $service->fill($data)->save(); if ($moveFiles) { Storage::move(sprintf('services/%s/index.js', $oldFolder), sprintf('services/%s/index.js', $service->folder)); @@ -124,18 +125,16 @@ class ServiceRepository */ public function delete($id) { - $service = Service::withCount('servers', 'options')->findOrFail($id); + $service = Service::withCount('servers')->with('options')->findOrFail($id); if ($service->servers_count > 0) { throw new DisplayException('You cannot delete a service that has servers associated with it.'); } DB::transaction(function () use ($service) { - ServiceVariable::whereIn('option_id', $service->options->pluck('id')->all())->delete(); - - $service->options->each(function ($item) { - $item->delete(); - }); + foreach($service->options as $option) { + (new OptionRepository)->delete($option->id); + } $service->delete(); Storage::deleteDirectory('services/' . $service->folder); diff --git a/app/Repositories/VariableRepository.php b/app/Repositories/VariableRepository.php index 744cb8bc7..b9421897b 100644 --- a/app/Repositories/VariableRepository.php +++ b/app/Repositories/VariableRepository.php @@ -26,7 +26,7 @@ namespace Pterodactyl\Repositories; use DB; use Validator; -use Pterodactyl\Models; +use Pterodactyl\Models\ServiceVariable; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayValidationException; @@ -37,108 +37,126 @@ class VariableRepository // } - public function create($id, array $data) + public function create(array $data) { - $option = Models\ServiceOption::select('id')->findOrFail($id); - $validator = Validator::make($data, [ + 'option_id' => 'required|numeric|exists:service_options,id', 'name' => 'required|string|min:1|max:255', - 'description' => 'required|string', + 'description' => 'sometimes|nullable|string', 'env_variable' => 'required|regex:/^[\w]{1,255}$/', - 'default_value' => 'string|max:255', - 'user_viewable' => 'sometimes|required|nullable|boolean', - 'user_editable' => 'sometimes|required|nullable|boolean', - 'required' => 'sometimes|required|nullable|boolean', - 'regex' => 'required|string|min:1', + 'default_value' => 'string', + 'options' => 'sometimes|required|array', + 'rules' => 'bail|required|string|min:1', ]); + // Ensure the default value is allowed by the rules provided. + $rules = (isset($data['rules'])) ? $data['rules'] : $variable->rules; + $validator->sometimes('default_value', $rules, function ($input) { + return $input->default_value; + }); + if ($validator->fails()) { throw new DisplayValidationException($validator->errors()); } - if ($data['default_value'] !== '' && ! preg_match($data['regex'], $data['default_value'])) { - throw new DisplayException('The default value you entered cannot violate the regex requirements.'); + if (isset($data['env_variable'])) { + $search = ServiceVariable::where('env_variable', $data['env_variable']) + ->where('option_id', $variable->option_id) + ->where('id', '!=', $variable->id); + if ($search->first()) { + throw new DisplayException('The envionment variable name assigned to this variable must be unique for this service option.'); + } } - if (Models\ServiceVariable::where('env_variable', $data['env_variable'])->where('option_id', $option->id)->first()) { - throw new DisplayException('An environment variable with that name already exists for this option.'); + if (! isset($data['options']) || ! is_array($data['options'])) { + $data['options'] = []; } - $data['user_viewable'] = (isset($data['user_viewable']) && in_array((int) $data['user_viewable'], [0, 1])) ? $data['user_viewable'] : 0; - $data['user_editable'] = (isset($data['user_editable']) && in_array((int) $data['user_editable'], [0, 1])) ? $data['user_editable'] : 0; - $data['required'] = (isset($data['required']) && in_array((int) $data['required'], [0, 1])) ? $data['required'] : 0; - $data['option_id'] = $option->id; + $data['user_viewable'] = (in_array('user_viewable', $data['options'])); + $data['user_editable'] = (in_array('user_editable', $data['options'])); + $data['required'] = (in_array('required', $data['options'])); - $variable = Models\ServiceVariable::create($data); + // Remove field that isn't used. + unset($data['options']); - return $variable; + return ServiceVariable::create($data); } + /** + * Deletes a specified option variable as well as all server + * variables currently assigned. + * + * @param int $id + * @return void + */ public function delete($id) { - $variable = Models\ServiceVariable::with('serverVariable')->findOrFail($id); + $variable = ServiceVariable::with('serverVariable')->findOrFail($id); - DB::beginTransaction(); - try { - foreach ($variable->serverVariable as $svar) { - $svar->delete(); + DB::transaction(function () use ($variable) { + foreach ($variable->serverVariable as $v) { + $v->delete(); } - $variable->delete(); - DB::commit(); - } catch (\Exception $ex) { - DB::rollBack(); - throw $ex; - } + $variable->delete(); + }); } + /** + * Updates a given service variable. + * + * @param int $id + * @param array $data + * @return \Pterodactyl\Models\ServiceVariable + * + * @throws \Pterodactyl\Exceptions\DisplayException + * @throws \Pterodactyl\Exceptions\DisplayValidationException + */ public function update($id, array $data) { - $variable = Models\ServiceVariable::findOrFail($id); + $variable = ServiceVariable::findOrFail($id); $validator = Validator::make($data, [ 'name' => 'sometimes|required|string|min:1|max:255', - 'description' => 'sometimes|required|string', + 'description' => 'sometimes|nullable|string', 'env_variable' => 'sometimes|required|regex:/^[\w]{1,255}$/', - 'default_value' => 'sometimes|string|max:255', - 'user_viewable' => 'sometimes|required|nullable|boolean', - 'user_editable' => 'sometimes|required|nullable|boolean', - 'required' => 'sometimes|required|nullable|boolean', - 'regex' => 'sometimes|required|string|min:1', + 'default_value' => 'string', + 'options' => 'sometimes|required|array', + 'rules' => 'bail|sometimes|required|string|min:1', ]); + // Ensure the default value is allowed by the rules provided. + $rules = (isset($data['rules'])) ? $data['rules'] : $variable->rules; + $validator->sometimes('default_value', $rules, function ($input) { + return $input->default_value; + }); + 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 ($data['default_value'] !== '' && ! preg_match($data['regex'], $data['default_value'])) { - throw new DisplayException('The default value you entered cannot violate the regex requirements.'); + if (isset($data['env_variable'])) { + $search = ServiceVariable::where('env_variable', $data['env_variable']) + ->where('option_id', $variable->option_id) + ->where('id', '!=', $variable->id); + if ($search->first()) { + throw new DisplayException('The envionment variable name assigned to this variable must be unique for this service option.'); + } } - if (Models\ServiceVariable::where('id', '!=', $variable->id)->where('env_variable', $data['env_variable'])->where('option_id', $variable->option_id)->first()) { - throw new DisplayException('An environment variable with that name already exists for this option.'); + if (! isset($data['options']) || ! is_array($data['options'])) { + $data['options'] = []; } - $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; + $data['user_viewable'] = (in_array('user_viewable', $data['options'])); + $data['user_editable'] = (in_array('user_editable', $data['options'])); + $data['required'] = (in_array('required', $data['options'])); - // Not using $data because the function that passes into this function - // can't do $requst->only() due to the page setup. - $variable->fill([ - 'name' => $data['name'], - 'description' => $data['description'], - 'env_variable' => $data['env_variable'], - 'default_value' => $data['default_value'], - 'user_viewable' => $data['user_viewable'], - 'user_editable' => $data['user_editable'], - 'required' => $data['required'], - 'regex' => $data['regex'], - ]); + // Remove field that isn't used. + unset($data['options']); - return $variable->save(); + $variable->fill($data)->save(); + + return $variable; } } diff --git a/config/pterodactyl.php b/config/pterodactyl.php index ec0e430cd..30ea7ef97 100644 --- a/config/pterodactyl.php +++ b/config/pterodactyl.php @@ -12,6 +12,7 @@ return [ | standard Pterodactyl shipped services. */ 'service' => [ + 'core' => 'ptrdctyl-v040-11e6-8b77-86f30ca893d3', 'author' => env('SERVICE_AUTHOR'), ], diff --git a/database/migrations/2017_03_11_215455_ChangeServiceVariablesValidationRules.php b/database/migrations/2017_03_11_215455_ChangeServiceVariablesValidationRules.php new file mode 100644 index 000000000..1ade5b53e --- /dev/null +++ b/database/migrations/2017_03_11_215455_ChangeServiceVariablesValidationRules.php @@ -0,0 +1,47 @@ +renameColumn('regex', 'rules'); + }); + + DB::transaction(function () { + foreach(ServiceVariable::all() as $variable) { + $variable->rules = ($variable->required) ? 'required|regex:' . $variable->rules : 'regex:' . $variable->regex; + $variable->save(); + } + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('service_variables', function (Blueprint $table) { + $table->renameColumn('rules', 'regex'); + }); + + DB::transaction(function () { + foreach(ServiceVariable::all() as $variable) { + $variable->regex = str_replace(['required|regex:', 'regex:'], '', $variable->regex); + $variable->save(); + } + }); + } +} diff --git a/resources/themes/pterodactyl/admin/services/options/new.blade.php b/resources/themes/pterodactyl/admin/services/options/new.blade.php new file mode 100644 index 000000000..763e6096c --- /dev/null +++ b/resources/themes/pterodactyl/admin/services/options/new.blade.php @@ -0,0 +1,170 @@ +{{-- 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') + Services → New Option +@endsection + +@section('content-header') +

      New OptionCreate a new service option to assign to servers.

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

      Configuration

      +
      +
      +
      +
      +
      + + +
      +
      + + +

      A simple, human-readable name to use as an identifier for this service.

      +
      +
      + + +

      A description of this service that will be displayed throughout the panel as needed.

      +
      +
      +
      +
      + + +

      This should be a unique identifer for this service option that is not used for any other service options.

      +
      +
      + + +

      The default docker image that should be used for new servers under this service option. This can be left blank to use the parent service's defined image, and can also be changed per-server.

      +
      +
      + + +

      The default statup command that should be used for new servers under this service option. This can be left blank to use the parent service's startup, and can also be changed per-server.

      +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      Process Management

      +
      +
      +
      +
      +
      +

      All fields are required unless you select a seperate option from the 'Copy Settings From' dropdown, in which case fields may be left blank to use the values from that option.

      +
      +
      +
      +
      + + +

      If you would like to default to settings from another option select the option from the menu above.

      +
      +
      + + +

      The command that should be sent to server processes to stop them gracefully. If you need to send a SIGINT you should enter ^C here.

      +
      +
      + + +

      This should be a JSON representation of where log files are stored, and wether or not the daemon should be creating custom logs.

      +
      +
      +
      +
      + + +

      This should be a JSON representation of configuration files to modify and what parts should be changed.

      +
      +
      + + +

      This should be a JSON representation of what values the daemon should be looking for when booting a server to determine completion.

      +
      +
      +
      + +
      +
      +
      + +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('vendor/lodash/lodash.js') !!} + +@endsection diff --git a/resources/themes/pterodactyl/admin/services/options/variables.blade.php b/resources/themes/pterodactyl/admin/services/options/variables.blade.php new file mode 100644 index 000000000..c1870d3ee --- /dev/null +++ b/resources/themes/pterodactyl/admin/services/options/variables.blade.php @@ -0,0 +1,114 @@ +{{-- 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') + Service Options → {{ $option->name }} → Variables +@endsection + +@section('content-header') +

      {{ $option->name }}Managing variables for this service option.

      + +@endsection + +@section('content') +
      +
      + +
      +
      +
      + @foreach($option->variables as $variable) +
      +
      +
      +

      {{ $variable->name }}

      +
      +
      +
      +
      + + +
      +
      + + +
      +
      +
      + + +
      +
      + + +
      +
      +

      This variable can be accessed in the statup command by using {{ $variable->env_variable }}.

      +
      +
      +
      + + +
      +
      + + +

      These rules are defined using standard Laravel Framework validation rules.

      +
      +
      + +
      +
      +
      + @endforeach +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/themes/pterodactyl/admin/services/options/view.blade.php b/resources/themes/pterodactyl/admin/services/options/view.blade.php index 01965d4ee..6450fdef3 100644 --- a/resources/themes/pterodactyl/admin/services/options/view.blade.php +++ b/resources/themes/pterodactyl/admin/services/options/view.blade.php @@ -39,7 +39,7 @@
      @@ -131,12 +131,16 @@

      This should be a JSON representation of what values the daemon should be looking for when booting a server to determine completion.

      +
      @@ -147,6 +151,12 @@ @section('footer-scripts') @parent +@endsection diff --git a/resources/views/admin/servers/view.blade.php b/resources/views/admin/servers/view.blade.php deleted file mode 100644 index 3f65dbd11..000000000 --- a/resources/views/admin/servers/view.blade.php +++ /dev/null @@ -1,687 +0,0 @@ -{{-- 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') - Managing Server: {{ $server->name }} ({{ $server->uuidShort}}) -@endsection - -@section('content') -
      - - @if($server->suspended === 1 && !$server->trashed()) -
      - This server is suspended and has no user access. Processes cannot be started and files cannot be modified. All API access is disabled unless using a master token. -
      - @elseif($server->trashed()) -
      - This server is marked for deletion {{ Carbon::parse($server->deleted_at)->addMinutes(env('APP_DELETE_MINUTES', 10))->diffForHumans() }}. If you want to cancel this action simply click the button below. -

      -
      - - - - {!! csrf_field() !!} -
      -
      - @endif - @if($server->installed === 0) -
      - This server is still running through the install process and is not avaliable for use just yet. This message will disappear once this process is completed. -
      - @elseif($server->installed === 2) -
      - This server failed to install properly. You should delete it and try to create it again or check the daemon logs. -
      - @endif - -
      -
      -
      -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      UUID{{ $server->uuid }}
      Docker Container ID
      Docker User ID
      Owner{{ $server->user->email }}
      Location{{ $server->node->location->short }}
      Node{{ $server->node->name }}
      Service{{ $server->option->service->name }} :: {{ $server->option->name }}
      Name{{ $server->name }}
      Memory{{ $server->memory }}MB / {{ $server->swap }}MB
      OOM Killer{!! ($server->oom_disabled === 0) ? 'Enabled' : 'Disabled' !!}
      Disk Space{{ $server->disk }}MB
      Block IO Weight{{ $server->io }}
      CPU Limit{{ $server->cpu }}%
      Default Connection{{ $server->allocation->ip }}:{{ $server->allocation->port }}
      Connection Alias - @if($server->allocation->alias !== $server->allocation->ip) - {{ $server->allocation->alias }}:{{ $server->allocation->port }} - @else - No Alias Assigned - @endif -
      Installed{!! ($server->installed === 1) ? 'Yes' : 'No' !!}
      Suspended{!! ($server->suspended === 1) ? 'Suspended' : 'No' !!}
      -
      -
      -
      - @if($server->installed === 1) -
      -
      -
      -
      -
      -
      - -
      - -

      Character limits: a-zA-Z0-9_- and [Space] (max 35 characters).

      -
      -
      -
      - -
      - -

      You can change the owner of this server by changing this field to an email matching another use on this system. If you do this a new daemon security token will be generated automatically.

      -
      -
      -
      - -
      - -

      This token should not be shared with anyone as it has full control over this server.

      -
      -
      -
      -
      - Yes, Reset Daemon Token -

      Resetting this token will cause any requests using the old token to fail.

      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      -
      -
      -
      -
      - -
      - -

      The docker image to use for this server. The default image for this service and option combination is {{ $server->docker_image }}.

      -
      -
      -
      -
      -
      - -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - After editing any of the options below you will need to restart the server for changes to take effect. If the server is currently off, you just need to start it and the container will be rebuilt with the new settings. -
      -
      -
      -
      -
      -
      - -
      - - MB -
      -
      -
      - -
      - - MB -
      -

      Setting this to 0 will disable swap space on this server.

      -
      -
      -
      -
      - -
      - - % -
      -

      Each physical core on the system is considered to be 100%. Setting this value to 0 will allow a server to use CPU time without restrictions.

      -
      -
      - -
      - -
      -

      Changing this value can have negative effects on all containers on the system. We strongly recommend leaving this value as 500.

      -
      -
      -
      -
      -
      -
      - Additional IPs and Ports can be assigned to this server for use by plugins or other software. The game port is what will show up for the user to use to connect to thier server, and what their configuration files will be forced to use for binding. -
      -
      -
      - - @foreach ($assigned as $assignment) -
      - - id === $server->allocation_id) checked="checked" @endif - name="default" value="{{ $assignment->ip }}:{{ $assignment->port }}"/> - - has_alias) - data-toggle="tooltip" data-placement="left" title="{{ $assignment->ip }}:{{ $assignment->port }}" - @endif - /> -
      - @endforeach -
      -
      -
      -
      - -
      - -
      -

      Please note that due to software limitations you cannot assign identical ports on different IPs to the same server. For example, you cannot assign both 192.168.0.5:25565 and 192.168.10.5:25565 to the same server.

      -
      -
      -
      -
      - -
      - -
      -

      Simply select which ports you would like to remove from the list above. If you want to assign a port on a different IP that is already in use you can select it above and delete it down here.

      -
      -
      -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      Changing any of the values below will require a restart for them to take effect.
      - -
      - {{ $server->option->display_executable }} - -
      -

      The following data replacers are avaliable 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.

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

      {!! $variable->description !!}
      Regex: {{ $variable->regex }}
      Access as: {{{{ $variable->env_variable }}}}

      -
      - @endforeach -
      -
      -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -

      Add New Database

      -
      -
      -
      - -
      -
      s{{ $server->id }}_
      - -
      -
      -
      - -
      - -
      -

      Which IP to allow connections from. Standard MySQL wildcard notation allowed (e.g. 192.168.%.%).

      -
      -
      -
      -
      - - -
      -
      - -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      - @if(count($server->databases) > 0) -
      -
      - - - - - - - - - - - - @foreach($server->databases as $database) - - - - - - - - @endforeach - -
      DatabaseUser (Connections From)PasswordDB Server
      {{ $database->database }}{{ $database->username }} ({{ $database->remote }}){{ Crypt::decrypt($database->password) }} {{ $database->host->host }}:{{ $database->host->port }}
      -
      - @endif -
      -
      - @endif - @if($server->installed !== 2) -
      -
      -
      -
      -
      - -
      -

      This will take you to the server management page that users normally see and allow you to manage server files as well as check the console and data usage.

      -
      -
      -
      -
      -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -

      This will toggle the install status for the server.

      -
      If you have just created this server it is ill advised to perform this action as the daemon will contact the panel when finished which could cause the install status to be wrongly set.
      -
      -
      -
      - @if($server->installed === 1) -
      -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -

      This will trigger a rebuild of the server container when it next starts up. This is useful if you modified the server configuration file manually, or something just didn't work out correctly.

      -
      A rebuild will automatically occur whenever you edit build configuration settings for the server.
      -
      -
      -
      - @endif -
      -
      -
      - @if($server->suspended === 0) -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -

      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 -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -

      This will unsuspend the server and restore normal user access.

      -
      - @endif -
      -
      -
      -
      - @endif -
      -
      -
      - @if($server->installed === 1) -
      -
      -
      -
      - {!! csrf_field() !!} - {!! method_field('DELETE') !!} - -
      -
      -
      -
      Deleting a server is an irreversible action. All data will be immediately removed relating to this server.
      -
      -
      -
      -
      - @endif -
      -
      -
      -
      - {!! csrf_field() !!} - {!! method_field('DELETE') !!} - -
      -
      -
      -
      This is the same as deleting a server, however, if an error is returned by the daemon it is ignored and the server is still removed from the panel.
      -
      -
      -
      -
      -
      -
      -
      - -@endsection diff --git a/resources/views/admin/services/options/variable.blade.php b/resources/views/admin/services/options/variable.blade.php deleted file mode 100644 index 5ed9540c3..000000000 --- a/resources/views/admin/services/options/variable.blade.php +++ /dev/null @@ -1,122 +0,0 @@ -{{-- 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') - New Variable for {{ $option->name }} -@endsection - -@section('content') -
      - -

      New Option Variable


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

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

      -
      -
      -
      -
      -
      - -
      - -

      Accessed in startup by using {{}} parameter.

      -
      -
      -
      - -
      - -

      The default value to use for this field.

      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      - -@endsection diff --git a/storage/app/services/index.js b/storage/app/services/index.js new file mode 100644 index 000000000..f6b6695d0 --- /dev/null +++ b/storage/app/services/index.js @@ -0,0 +1,31 @@ +'use strict'; + +/** + * Pterodactyl - Daemon + * 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. + */ +const rfr = require('rfr'); + +const Core = rfr('src/services/index.js'); + +class Service extends Core {} + +module.exports = Service; From d58529428974db27ff0f3eab55ae5174c0608b32 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 12 Mar 2017 00:03:04 -0500 Subject: [PATCH 321/599] Misc. file removal and migration cleanup --- ...03_10_173607_MigrateToNewServiceSystem.php | 2 +- storage/app/services/index.js | 31 -------- storage/app/services/minecraft/main.json | 74 ------------------- storage/app/services/srcds/main.json | 23 ------ storage/app/services/terraria/main.json | 23 ------ storage/app/services/voice/main.json | 50 ------------- 6 files changed, 1 insertion(+), 202 deletions(-) delete mode 100644 storage/app/services/index.js delete mode 100644 storage/app/services/minecraft/main.json delete mode 100644 storage/app/services/srcds/main.json delete mode 100644 storage/app/services/terraria/main.json delete mode 100644 storage/app/services/voice/main.json diff --git a/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php b/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php index afa9f6ee1..c22954150 100644 --- a/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php +++ b/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php @@ -125,7 +125,7 @@ class MigrateToNewServiceSystem extends Migration switch($item->tag) { case 'source': - $item->config_startup = '{"done": "Assigned anonymous gameserver Steam ID", "userInteraction": []}'; + $item->config_startup = '{"done": "Assigned anonymous gameserver", "userInteraction": []}'; $item->config_files = '{}'; $item->config_logs = '{"custom": true, "location": "logs/latest.log"}'; $item->config_stop = 'quit'; diff --git a/storage/app/services/index.js b/storage/app/services/index.js deleted file mode 100644 index f6b6695d0..000000000 --- a/storage/app/services/index.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -/** - * Pterodactyl - Daemon - * 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. - */ -const rfr = require('rfr'); - -const Core = rfr('src/services/index.js'); - -class Service extends Core {} - -module.exports = Service; diff --git a/storage/app/services/minecraft/main.json b/storage/app/services/minecraft/main.json deleted file mode 100644 index 48a490cb3..000000000 --- a/storage/app/services/minecraft/main.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "vanilla": { - "startup": { - "done": ")! For help, type ", - "userInteraction": [ - "Go to eula.txt for more info." - ] - }, - "stop": "stop", - "configs": { - "server.properties": { - "parser": "properties", - "find": { - "server-ip": "0.0.0.0", - "enable-query": "true", - "server-port": "{{ server.build.default.port }}", - "query.port": "{{ server.build.default.port }}" - } - } - }, - "log": { - "custom": false, - "location": "logs/latest.log" - }, - "query": "minecraftping" - }, - "spigot": { - "symlink": "vanilla", - "configs": { - "spigot.yml": { - "parser": "yaml", - "find": { - "settings.restart-on-crash": "false" - } - } - } - }, - "bungeecord": { - "startup": { - "done": "Listening on ", - "userInteraction": [ - "Listening on /0.0.0.0:25577" - ] - }, - "stop": "end", - "configs": { - "config.yml": { - "parser": "yaml", - "find": { - "listeners[0].query_enabled": true, - "listeners[0].query_port": "{{ server.build.default.port }}", - "listeners[0].host": "0.0.0.0:{{ server.build.default.port }}", - "servers.*.address": { - "127.0.0.1": "{{ config.docker.interface }}", - "localhost": "{{ config.docker.interface }}" - } - } - } - }, - "log": { - "custom": false, - "location": "proxy.log.0" - }, - "query": "minecraftping" - }, - "sponge": { - "symlink": "vanilla", - "startup": { - "userInteraction": [ - "You need to agree to the EULA" - ] - } - } -} diff --git a/storage/app/services/srcds/main.json b/storage/app/services/srcds/main.json deleted file mode 100644 index 989a67537..000000000 --- a/storage/app/services/srcds/main.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "srcds": { - "startup": { - "done": "Assigned anonymous gameserver Steam ID", - "userInteraction": [] - }, - "stop": "quit", - "configs": {}, - "log": { - "custom": true, - "location": "logs/latest.log" - }, - "query": "protocol-valve" - }, - "ark": { - "symlink": "srcds", - "startup": { - "done": "Setting breakpad minidump AppID" - }, - "stop": "^C", - "query": "none" - } -} diff --git a/storage/app/services/terraria/main.json b/storage/app/services/terraria/main.json deleted file mode 100644 index 78f1b5bc0..000000000 --- a/storage/app/services/terraria/main.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "tshock": { - "startup": { - "done": "Type 'help' for a list of commands", - "userInteraction": [] - }, - "stop": "exit", - "configs": { - "tshock/config.json": { - "parser": "json", - "find": { - "ServerPort": "{{ server.build.default.port }}", - "MaxSlots": "{{ server.build.env.MAX_SLOTS }}" - } - } - }, - "log": { - "custom": false, - "location": "ServerLog.txt" - }, - "query": "none" - } -} diff --git a/storage/app/services/voice/main.json b/storage/app/services/voice/main.json deleted file mode 100644 index bc7232f46..000000000 --- a/storage/app/services/voice/main.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "mumble": { - "startup": { - "done": "Server listening on", - "userInteraction": [ - "Generating new server certificate" - ] - }, - "stop": "^C", - "configs": { - "murmur.ini": { - "parser": "ini", - "find": { - "logfile": "murmur.log", - "port": "{{ server.build.default.port }}", - "host": "0.0.0.0", - "users": "{{ server.build.env.MAX_USERS }}" - } - } - }, - "log": { - "custom": true, - "location": "logs/murmur.log" - }, - "query": "mumbleping" - }, - "ts3": { - "startup": { - "done": "listening on 0.0.0.0:", - "userInteraction": [] - }, - "stop": "^C", - "configs": { - "ts3server.ini": { - "parser": "ini", - "find": { - "default_voice_port": "{{ server.build.default.port }}", - "voice_ip": "0.0.0.0", - "query_port": "{{ server.build.default.port }}", - "query_ip": "0.0.0.0" - } - } - }, - "log": { - "custom": true, - "location": "logs/ts3.log" - }, - "query": "none" - } -} From 419031e0cd469364f56f6f045c274f3d83ac0234 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 12 Mar 2017 15:59:17 -0400 Subject: [PATCH 322/599] Add function file editing, and move all service file items into database --- .../Controllers/Admin/ServiceController.php | 217 +++--------------- app/Http/Routes/AdminRoutes.php | 7 +- app/Models/Service.php | 45 +++- app/Repositories/ServiceRepository.php | 51 +--- ...150648_MoveFunctionsFromFileToDatabase.php | 120 ++++++++++ .../admin/services/functions.blade.php | 88 +++++++ .../pterodactyl/admin/services/view.blade.php | 12 +- storage/app/services/.templates/index.js | 31 --- storage/app/services/minecraft/index.js | 38 --- storage/app/services/srcds/index.js | 31 --- storage/app/services/terraria/index.js | 31 --- storage/app/services/voice/index.js | 31 --- 12 files changed, 298 insertions(+), 404 deletions(-) create mode 100644 database/migrations/2017_03_12_150648_MoveFunctionsFromFileToDatabase.php create mode 100644 resources/themes/pterodactyl/admin/services/functions.blade.php delete mode 100644 storage/app/services/.templates/index.js delete mode 100644 storage/app/services/minecraft/index.js delete mode 100644 storage/app/services/srcds/index.js delete mode 100644 storage/app/services/terraria/index.js delete mode 100644 storage/app/services/voice/index.js diff --git a/app/Http/Controllers/Admin/ServiceController.php b/app/Http/Controllers/Admin/ServiceController.php index 60450ab28..523e6bb14 100644 --- a/app/Http/Controllers/Admin/ServiceController.php +++ b/app/Http/Controllers/Admin/ServiceController.php @@ -26,7 +26,6 @@ namespace Pterodactyl\Http\Controllers\Admin; use Log; use Alert; -use Storage; use Pterodactyl\Models; use Illuminate\Http\Request; use Pterodactyl\Exceptions\DisplayException; @@ -74,6 +73,18 @@ class ServiceController extends Controller ]); } + /** + * Return function editing view for a service. + * + * @param Request $request + * @param int $id + * @return \Illuminate\View\View + */ + public function viewFunctions(Request $request, $id) + { + return view('admin.services.functions', ['service' => Models\Service::findOrFail($id)]); + } + /** * Handle post action for new service. * @@ -113,11 +124,12 @@ class ServiceController extends Controller public function edit(Request $request, $id) { $repo = new ServiceRepository; + $redirectTo = ($request->input('redirect_to')) ? 'admin.services.view.functions' : 'admin.services.view'; try { if ($request->input('action') !== 'delete') { $repo->update($id, $request->intersect([ - 'name', 'description', 'folder', 'startup', + 'name', 'description', 'folder', 'startup', 'index_file', ])); Alert::success('Service has been updated successfully.')->flash(); } else { @@ -127,7 +139,7 @@ class ServiceController extends Controller return redirect()->route('admin.services'); } } catch (DisplayValidationException $ex) { - return redirect()->route('admin.services.view', $id)->withErrors(json_decode($ex->getMessage()))->withInput(); + return redirect()->route($redirectTo, $id)->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); } catch (\Exception $ex) { @@ -135,193 +147,18 @@ class ServiceController extends Controller Alert::danger('An error occurred while attempting to update this service. This error has been logged.')->flash(); } - return redirect()->route('admin.services.view', $id); + return redirect()->route($redirectTo, $id); } - // public function getOption(Request $request, $service, $option) - // { - // $option = Models\ServiceOption::with('service', 'variables')->findOrFail($option); - // $option->setRelation('servers', $option->servers()->with('user')->paginate(25)); - // - // return view('admin.services.options.view', ['option' => $option]); - // } - // - // public function postOption(Request $request, $service, $option) - // { - // try { - // $repo = new ServiceRepository\Option; - // $repo->update($option, $request->only([ - // 'name', 'description', 'tag', - // 'executable', 'docker_image', 'startup', - // ])); - // Alert::success('Option settings successfully updated.')->flash(); - // } catch (DisplayValidationException $ex) { - // return redirect()->route('admin.services.option', [$service, $option])->withErrors(json_decode($ex->getMessage()))->withInput(); - // } catch (\Exception $ex) { - // Log::error($ex); - // Alert::danger('An error occured while attempting to modify this option.')->flash(); - // } - // - // return redirect()->route('admin.services.option', [$service, $option])->withInput(); - // } - // - // public function deleteOption(Request $request, $service, $option) - // { - // try { - // $repo = new ServiceRepository\Option; - // $repo->delete($option); - // - // Alert::success('Successfully deleted that option.')->flash(); - // - // return redirect()->route('admin.services.service', $service); - // } catch (DisplayException $ex) { - // Alert::danger($ex->getMessage())->flash(); - // } catch (\Exception $ex) { - // Log::error($ex); - // Alert::danger('An error was encountered while attempting to delete this option.')->flash(); - // } - // - // return redirect()->route('admin.services.option', [$service, $option]); - // } - // - // public function postOptionVariable(Request $request, $service, $option, $variable) - // { - // 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 = [ - // 'user_viewable' => '0', - // 'user_editable' => '0', - // 'required' => '0', - // ]; - // 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', [$service, $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', [$service, $option])->withInput(); - // } - // - // public function getNewVariable(Request $request, $service, $option) - // { - // return view('admin.services.options.variable', [ - // 'option' => Models\ServiceOption::with('service')->findOrFail($option), - // ]); - // } - // - // public function postNewVariable(Request $request, $service, $option) - // { - // try { - // $repo = new ServiceRepository\Variable; - // $repo->create($option, $request->only([ - // 'name', 'description', 'env_variable', - // 'default_value', 'user_viewable', - // 'user_editable', 'required', 'regex', - // ])); - // Alert::success('Successfully added new variable to this option.')->flash(); - // - // return redirect()->route('admin.services.option', [$service, $option]); - // } catch (DisplayValidationException $ex) { - // return redirect()->route('admin.services.option.variable.new', [$service, $option])->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 add this variable.')->flash(); - // } - // - // return redirect()->route('admin.services.option.variable.new', [$service, $option])->withInput(); - // } - // - // public function newOption(Request $request, $service) - // { - // return view('admin.services.options.new', [ - // 'service' => Models\Service::findOrFail($service), - // ]); - // } - // - // public function postNewOption(Request $request, $service) - // { - // try { - // $repo = new ServiceRepository\Option; - // $id = $repo->create($service, $request->except([ - // '_token', - // ])); - // Alert::success('Successfully created new service option.')->flash(); - // - // return redirect()->route('admin.services.option', [$service, $id]); - // } catch (DisplayValidationException $ex) { - // return redirect()->route('admin.services.option.new', $service)->withErrors(json_decode($ex->getMessage()))->withInput(); - // } catch (\Exception $ex) { - // Log::error($ex); - // Alert::danger('An error occured while attempting to add this service option.')->flash(); - // } - // - // return redirect()->route('admin.services.option.new', $service)->withInput(); - // } - // - // public function deleteVariable(Request $request, $service, $option, $variable) - // { - // try { - // $repo = new ServiceRepository\Variable; - // $repo->delete($variable); - // Alert::success('Deleted variable.')->flash(); - // } catch (DisplayException $ex) { - // Alert::danger($ex->getMessage())->flash(); - // } catch (\Exception $ex) { - // Log::error($ex); - // Alert::danger('An error occured while attempting to delete that variable.')->flash(); - // } - // - // return redirect()->route('admin.services.option', [$service, $option]); - // } - // - // public function getConfiguration(Request $request, $serviceId) - // { - // $service = Models\Service::findOrFail($serviceId); - // - // return view('admin.services.config', [ - // 'service' => $service, - // 'contents' => [ - // 'json' => Storage::get('services/' . $service->file . '/main.json'), - // 'index' => Storage::get('services/' . $service->file . '/index.js'), - // ], - // ]); - // } - // - // public function postConfiguration(Request $request, $serviceId) - // { - // try { - // $repo = new ServiceRepository\Service; - // $repo->updateFile($serviceId, $request->only(['file', 'contents'])); - // - // return response('', 204); - // } catch (DisplayException $ex) { - // return response()->json([ - // 'error' => $ex->getMessage(), - // ], 503); - // } catch (\Exception $ex) { - // Log::error($ex); - // - // return response()->json([ - // 'error' => 'An error occured while attempting to save the file.', - // ], 503); - // } - // } + /** + * Edits function file for a service. + * + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function editFunctions(Request $request, $id) + { + + } } diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index 5cec94b55..60a6cb8ed 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -403,8 +403,11 @@ class AdminRoutes 'uses' => 'Admin\ServiceController@view', ]); - $router->post('/view/{id}', [ - 'uses' => 'Admin\ServiceController@edit', + $router->post('/view/{id}', 'Admin\ServiceController@edit'); + + $router->get('/view/{id}/functions', [ + 'as' => 'admin.services.view.functions', + 'uses' => 'Admin\ServiceController@viewFunctions', ]); $router->delete('/view/{id}', [ diff --git a/app/Models/Service.php b/app/Models/Service.php index 50679633e..c521b8035 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -41,9 +41,52 @@ class Service extends Model * @var array */ protected $fillable = [ - 'name', 'description', 'folder', 'startup', + 'name', 'description', 'folder', 'startup', 'index_file', ]; + /** + * Returns the default contents of the index.js file for a service. + * + * @return string + */ + public function defaultIndexFile() + { + return << + * + * 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. + */ +const rfr = require('rfr'); +const _ = require('lodash'); + +const Core = rfr('src/services/index.js'); + +class Service extends Core {} + +module.exports = Service; +EOF; + } + /** * Gets all service options associated with this service. * diff --git a/app/Repositories/ServiceRepository.php b/app/Repositories/ServiceRepository.php index a82c80b3f..801a29deb 100644 --- a/app/Repositories/ServiceRepository.php +++ b/app/Repositories/ServiceRepository.php @@ -26,7 +26,6 @@ namespace Pterodactyl\Repositories; use DB; use Uuid; -use Storage; use Validator; use Pterodactyl\Models\Service; use Pterodactyl\Models\ServiceVariable; @@ -55,7 +54,7 @@ class ServiceRepository throw new DisplayValidationException($validator->errors()); } - $service = DB::transaction(function () use ($data) { + return DB::transaction(function () use ($data) { $service = new Service; $service->author = config('pterodactyl.service.author'); $service->fill([ @@ -63,6 +62,7 @@ class ServiceRepository 'description' => (isset($data['description'])) ? $data['description'] : null, 'folder' => $data['folder'], 'startup' => (isset($data['startup'])) ? $data['startup'] : null, + 'index_file' => $service->defaultIndexFile(), ])->save(); // It is possible for an event to return false or throw an exception @@ -73,12 +73,8 @@ class ServiceRepository throw new \Exception('Service model was created however the response appears to be invalid. Did an event fire wrongly?'); } - Storage::copy('services/.templates/index.js', 'services/' . $service->folder . '/index.js'); - return $service; }); - - return $service; } /** @@ -97,6 +93,7 @@ class ServiceRepository 'description' => 'sometimes|required|nullable|string', 'folder' => 'sometimes|required|regex:/^[\w.-]{1,50}$/', 'startup' => 'sometimes|required|nullable|string', + 'index_file' => 'sometimes|required|string', ]); if ($validator->fails()) { @@ -104,15 +101,8 @@ class ServiceRepository } return DB::transaction(function () use ($data, $service) { - $moveFiles = (isset($data['folder']) && $data['folder'] !== $service->folder); - $oldFolder = $service->folder; - $service->fill($data)->save(); - if ($moveFiles) { - Storage::move(sprintf('services/%s/index.js', $oldFolder), sprintf('services/%s/index.js', $service->folder)); - } - return $service; }); } @@ -137,41 +127,6 @@ class ServiceRepository } $service->delete(); - Storage::deleteDirectory('services/' . $service->folder); }); } - - /** - * Updates a service file on the system. - * - * @param int $id - * @param array $data - * @return void - * - * @deprecated - */ - // public function updateFile($id, array $data) - // { - // $service = Service::findOrFail($id); - // - // $validator = Validator::make($data, [ - // 'file' => 'required|in:index', - // 'contents' => 'required|string', - // ]); - // - // if ($validator->fails()) { - // throw new DisplayValidationException($validator->errors()); - // } - // - // $filepath = 'services/' . $service->folder . '/' . $filename; - // $backup = 'services/.bak/' . str_random(12) . '.bak'; - // - // try { - // Storage::move($filepath, $backup); - // Storage::put($filepath, $data['contents']); - // } catch (\Exception $ex) { - // Storage::move($backup, $filepath); - // throw $ex; - // } - // } } diff --git a/database/migrations/2017_03_12_150648_MoveFunctionsFromFileToDatabase.php b/database/migrations/2017_03_12_150648_MoveFunctionsFromFileToDatabase.php new file mode 100644 index 000000000..bb37afd9a --- /dev/null +++ b/database/migrations/2017_03_12_150648_MoveFunctionsFromFileToDatabase.php @@ -0,0 +1,120 @@ + + * + * 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. + */ +const rfr = require('rfr'); +const _ = require('lodash'); + +const Core = rfr('src/services/index.js'); + +class Service extends Core {} + +module.exports = Service; +EOF; + + private $default_mc = << + * + * 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. + */ +const rfr = require('rfr'); +const _ = require('lodash'); + +const Core = rfr('src/services/index.js'); + +class Service extends Core { + onConsole(data) { + // Hide the output spam from Bungeecord getting pinged. + if (_.endsWith(data, '<-> InitialHandler has connected')) return; + return super.onConsole(data); + } +} + +module.exports = Service; +EOF; + + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('services', function (Blueprint $table) { + $table->text('index_file')->after('startup'); + }); + + DB::transaction(function () { + Service::where('author', 'ptrdctyl-v040-11e6-8b77-86f30ca893d3')->where('folder', '!=', 'minecraft')->update([ + 'index_file' => $this->default, + ]); + + Service::where('author', 'ptrdctyl-v040-11e6-8b77-86f30ca893d3')->where('folder', 'minecraft')->update([ + 'index_file' => $this->default_mc, + ]); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('services', function (Blueprint $table) { + $table->dropColumn('index_file'); + }); + } +} diff --git a/resources/themes/pterodactyl/admin/services/functions.blade.php b/resources/themes/pterodactyl/admin/services/functions.blade.php new file mode 100644 index 000000000..634f38b72 --- /dev/null +++ b/resources/themes/pterodactyl/admin/services/functions.blade.php @@ -0,0 +1,88 @@ +{{-- 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') + Services → {{ $service->name }} → Functions +@endsection + +@section('content-header') +

      {{ $service->name }}Extend the default daemon functions using this service file.

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

      Functions Control

      +
      +
      +
      +
      {{ $service->index_file }}
      + +
      + +
      +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/vendor/ace/ace.js') !!} + {!! Theme::js('js/vendor/ace/ext-modelist.js') !!} + +@endsection diff --git a/resources/themes/pterodactyl/admin/services/view.blade.php b/resources/themes/pterodactyl/admin/services/view.blade.php index 49d6b727a..ab31abe0d 100644 --- a/resources/themes/pterodactyl/admin/services/view.blade.php +++ b/resources/themes/pterodactyl/admin/services/view.blade.php @@ -20,7 +20,7 @@ @extends('layouts.admin') @section('title') - Services: {{ $service->name }} + Services → {{ $service->name }} @endsection @section('content-header') @@ -33,6 +33,16 @@ @endsection @section('content') +
      +
      + +
      +
      diff --git a/storage/app/services/.templates/index.js b/storage/app/services/.templates/index.js deleted file mode 100644 index f6b6695d0..000000000 --- a/storage/app/services/.templates/index.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -/** - * Pterodactyl - Daemon - * 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. - */ -const rfr = require('rfr'); - -const Core = rfr('src/services/index.js'); - -class Service extends Core {} - -module.exports = Service; diff --git a/storage/app/services/minecraft/index.js b/storage/app/services/minecraft/index.js deleted file mode 100644 index b53364bec..000000000 --- a/storage/app/services/minecraft/index.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -/** - * Pterodactyl - Daemon - * 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. - */ -const rfr = require('rfr'); -const _ = require('lodash'); - -const Core = rfr('src/services/index.js'); - -class Service extends Core { - onConsole(data) { - // Hide the output spam from Bungeecord getting pinged. - if (_.endsWith(data, '<-> InitialHandler has connected')) return; - return super.onConsole(data); - } -} - -module.exports = Service; diff --git a/storage/app/services/srcds/index.js b/storage/app/services/srcds/index.js deleted file mode 100644 index f6b6695d0..000000000 --- a/storage/app/services/srcds/index.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -/** - * Pterodactyl - Daemon - * 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. - */ -const rfr = require('rfr'); - -const Core = rfr('src/services/index.js'); - -class Service extends Core {} - -module.exports = Service; diff --git a/storage/app/services/terraria/index.js b/storage/app/services/terraria/index.js deleted file mode 100644 index f6b6695d0..000000000 --- a/storage/app/services/terraria/index.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -/** - * Pterodactyl - Daemon - * 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. - */ -const rfr = require('rfr'); - -const Core = rfr('src/services/index.js'); - -class Service extends Core {} - -module.exports = Service; diff --git a/storage/app/services/voice/index.js b/storage/app/services/voice/index.js deleted file mode 100644 index f6b6695d0..000000000 --- a/storage/app/services/voice/index.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -/** - * Pterodactyl - Daemon - * 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. - */ -const rfr = require('rfr'); - -const Core = rfr('src/services/index.js'); - -class Service extends Core {} - -module.exports = Service; From b1b1f448e9d3fb7154f4c2ca6cd192f1647a33e8 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 12 Mar 2017 16:04:47 -0400 Subject: [PATCH 323/599] Send the correct information to daemon for new index.js setup --- app/Http/Controllers/Daemon/ServiceController.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Daemon/ServiceController.php b/app/Http/Controllers/Daemon/ServiceController.php index fbbad9b4e..6638f30d6 100644 --- a/app/Http/Controllers/Daemon/ServiceController.php +++ b/app/Http/Controllers/Daemon/ServiceController.php @@ -24,7 +24,6 @@ namespace Pterodactyl\Http\Controllers\Daemon; -use Storage; use Illuminate\Http\Request; use Pterodactyl\Models\Service; use Pterodactyl\Models\ServiceOption; @@ -46,7 +45,7 @@ class ServiceController extends Controller foreach (Service::all() as $service) { $response[$service->folder] = [ 'main.json' => sha1($this->getConfiguration($service->id)->toJson()), - 'index.js' => sha1_file(storage_path('app/services/' . $service->folder . '/index.js')), + 'index.js' => sha1($service->index_file), ]; } @@ -66,7 +65,7 @@ class ServiceController extends Controller $service = Service::where('folder', $folder)->firstOrFail(); if ($file === 'index.js') { - return response()->file(storage_path('app/services/' . $service->folder . '/index.js')); + return response($service->index_file)->header('Content-Type', 'text/plain'); } else if ($file === 'main.json') { return response()->json($this->getConfiguration($service->id)); } From f5a4ec981d7badacffde737011e9830be852e7dc Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 12 Mar 2017 16:28:38 -0400 Subject: [PATCH 324/599] Add ability to create new service variable. --- .../Controllers/Admin/OptionController.php | 32 ++++++++++- app/Http/Routes/AdminRoutes.php | 7 +-- app/Repositories/VariableRepository.php | 24 +++++---- .../services/options/variables.blade.php | 54 +++++++++++++++++++ 4 files changed, 104 insertions(+), 13 deletions(-) diff --git a/app/Http/Controllers/Admin/OptionController.php b/app/Http/Controllers/Admin/OptionController.php index b60c0df7b..837e5a8aa 100644 --- a/app/Http/Controllers/Admin/OptionController.php +++ b/app/Http/Controllers/Admin/OptionController.php @@ -55,7 +55,7 @@ class OptionController extends Controller /** * Handles POST request to create a new option. - + * * @param Request $request * @return \Illuminate\Response\RedirectResponse */ @@ -84,6 +84,36 @@ class OptionController extends Controller return redirect()->route('admin.services.option.new')->withInput(); } + /** + * Handles POST request to create a new option variable. + * + * @param Request $request + * @param int $id The ID of the service option to assign this variable to. + * @return \Illuminate\Response\RedirectResponse + */ + public function createVariable(Request $request, $id) + { + $repo = new VariableRepository; + + try { + $variable = $repo->create($id, $request->only([ + 'name', 'description', 'env_variable', + 'default_value', 'options', 'rules', + ])); + + Alert::success('New variable successfully assigned to this service option.')->flash(); + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.services.option.variables', $id)->withErrors(json_decode($ex->getMessage())); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An unhandled exception was encountered while attempting to process that request. This error has been logged.')->flash(); + } + + return redirect()->route('admin.services.option.variables', $id); + } + /** * Display option overview page. * diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index 60a6cb8ed..634568728 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -429,18 +429,19 @@ class AdminRoutes 'uses' => 'Admin\OptionController@viewConfiguration', ]); + $router->post('/option/{id}', 'Admin\OptionController@editConfiguration'); + $router->get('/option/{id}/variables', [ 'as' => 'admin.services.option.variables', 'uses' => 'Admin\OptionController@viewVariables', ]); + $router->post('/option/{id}/variables', 'Admin\OptionController@createVariable'); + $router->post('/option/{id}/variables/{variable}', [ 'as' => 'admin.services.option.variables.edit', 'uses' => 'Admin\OptionController@editVariable', ]); - - $router->post('/option/{id}', 'Admin\OptionController@editConfiguration'); - }); // Service Packs diff --git a/app/Repositories/VariableRepository.php b/app/Repositories/VariableRepository.php index b9421897b..91490b4b1 100644 --- a/app/Repositories/VariableRepository.php +++ b/app/Repositories/VariableRepository.php @@ -26,21 +26,28 @@ namespace Pterodactyl\Repositories; use DB; use Validator; +use Pterodactyl\Models\ServiceOption; use Pterodactyl\Models\ServiceVariable; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayValidationException; class VariableRepository { - public function __construct() + /** + * Create a new service variable. + * + * @param int $option + * @param array $data + * @return \Pterodactyl\Models\ServiceVariable + * + * @throws \Pterodactyl\Exceptions\DisplayException + * @throws \Pterodactyl\Exceptions\DisplayValidationException + */ + public function create($option, array $data) { - // - } + $option = ServiceOption::select('id')->findOrFail($option); - public function create(array $data) - { $validator = Validator::make($data, [ - 'option_id' => 'required|numeric|exists:service_options,id', 'name' => 'required|string|min:1|max:255', 'description' => 'sometimes|nullable|string', 'env_variable' => 'required|regex:/^[\w]{1,255}$/', @@ -60,9 +67,7 @@ class VariableRepository } if (isset($data['env_variable'])) { - $search = ServiceVariable::where('env_variable', $data['env_variable']) - ->where('option_id', $variable->option_id) - ->where('id', '!=', $variable->id); + $search = ServiceVariable::where('env_variable', $data['env_variable'])->where('option_id', $option->id); if ($search->first()) { throw new DisplayException('The envionment variable name assigned to this variable must be unique for this service option.'); } @@ -72,6 +77,7 @@ class VariableRepository $data['options'] = []; } + $data['option_id'] = $option->id; $data['user_viewable'] = (in_array('user_viewable', $data['options'])); $data['user_editable'] = (in_array('user_editable', $data['options'])); $data['required'] = (in_array('required', $data['options'])); diff --git a/resources/themes/pterodactyl/admin/services/options/variables.blade.php b/resources/themes/pterodactyl/admin/services/options/variables.blade.php index c1870d3ee..c763e6cee 100644 --- a/resources/themes/pterodactyl/admin/services/options/variables.blade.php +++ b/resources/themes/pterodactyl/admin/services/options/variables.blade.php @@ -41,6 +41,7 @@
      @@ -99,6 +100,59 @@
      @endforeach
      + @endsection @section('footer-scripts') From 37a723aa580819995ddc3eaefb0bb34bd41ced89 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 12 Mar 2017 16:29:04 -0400 Subject: [PATCH 325/599] Remove old views no longer in use. --- .../views/admin/services/config.blade.php | 180 -------------- .../views/admin/services/index.blade.php | 65 ----- resources/views/admin/services/new.blade.php | 95 -------- .../admin/services/options/new.blade.php | 98 -------- .../admin/services/options/view.blade.php | 211 ---------------- resources/views/admin/services/view.blade.php | 135 ----------- resources/views/errors/403.blade.php | 37 --- resources/views/errors/404.blade.php | 37 --- resources/views/layouts/admin.blade.php | 226 ------------------ 9 files changed, 1084 deletions(-) delete mode 100644 resources/views/admin/services/config.blade.php delete mode 100644 resources/views/admin/services/index.blade.php delete mode 100644 resources/views/admin/services/new.blade.php delete mode 100644 resources/views/admin/services/options/new.blade.php delete mode 100644 resources/views/admin/services/options/view.blade.php delete mode 100644 resources/views/admin/services/view.blade.php delete mode 100644 resources/views/errors/403.blade.php delete mode 100644 resources/views/errors/404.blade.php delete mode 100644 resources/views/layouts/admin.blade.php diff --git a/resources/views/admin/services/config.blade.php b/resources/views/admin/services/config.blade.php deleted file mode 100644 index 2aa814428..000000000 --- a/resources/views/admin/services/config.blade.php +++ /dev/null @@ -1,180 +0,0 @@ -{{-- 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') - Manage Service Configuration -@endsection - -@section('content') -
      - -

      Service Configuration


      - -
      -
      -
      -
      -
      -
      -
      -
      {{ $contents['json'] }}
      -
      -
      -
      -
      - -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      {{ $contents['index'] }}
      -
      -
      -
      -
      - -
      -
      -
      -
      -
      -
      -
      -{!! Theme::js('js/vendor/ace/ace.js') !!} -{!! Theme::js('js/vendor/ace/ext-modelist.js') !!} - -@endsection diff --git a/resources/views/admin/services/index.blade.php b/resources/views/admin/services/index.blade.php deleted file mode 100644 index c97df4cf1..000000000 --- a/resources/views/admin/services/index.blade.php +++ /dev/null @@ -1,65 +0,0 @@ -{{-- 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') - Manage Services -@endsection - -@section('content') -
      - -

      Server Services


      - - - - - - - - - - - @foreach ($services as $service) - - - - - - - @endforeach - - - - - - - -
      Service TypeDescriptionServers
      {{ $service->name }}{!! $service->description !!}{{ $service->servers_count }}
      -
      - -@endsection diff --git a/resources/views/admin/services/new.blade.php b/resources/views/admin/services/new.blade.php deleted file mode 100644 index 1bb829e00..000000000 --- a/resources/views/admin/services/new.blade.php +++ /dev/null @@ -1,95 +0,0 @@ -{{-- 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') - New Service -@endsection - -@section('content') -
      - -

      Add New Service


      -
      -
      -
      - -
      - -

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

      -
      -
      -
      - -
      - -
      -
      -
      -
      -
      - -
      - /src/services/ - - /index.js -
      -

      This should be a unique alpha-numeric (a-z) name used to identify the service.

      -
      -
      - -
      - -
      -

      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.

      -
      -
      -
      -
      - -
      - - -
      -

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

      -
      -
      -
      -
      -
      You will be able to add service options and variables once the service is created.
      - {!! csrf_field() !!} - -
      -
      -
      -
      - -@endsection diff --git a/resources/views/admin/services/options/new.blade.php b/resources/views/admin/services/options/new.blade.php deleted file mode 100644 index 5585fad0f..000000000 --- a/resources/views/admin/services/options/new.blade.php +++ /dev/null @@ -1,98 +0,0 @@ -{{-- 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') - New Service Option for {{ $service->name }} -@endsection - -@section('content') -
      - -

      Service Option Settings


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

      Leave blank to use parent executable.

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

      To use the default startup of the parent service simply leave this field blank.

      -
      -
      -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      - -@endsection diff --git a/resources/views/admin/services/options/view.blade.php b/resources/views/admin/services/options/view.blade.php deleted file mode 100644 index f40bc8154..000000000 --- a/resources/views/admin/services/options/view.blade.php +++ /dev/null @@ -1,211 +0,0 @@ -{{-- 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') - Manage Service Option {{ $option->name }} -@endsection - -@section('content') -
      - -
      Warning! This page contains advanced settings that the panel and daemon use to control servers. Modifying information on this page is not recommended unless you are absolutely sure of what you are doing.
      -

      Settings


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

      Leave blank to use parent executable.

      -
      -
      -
      - -
      - -

      Changing the docker image will only effect servers created or modified after this point.

      -
      -
      -
      -
      -
      - -
      - -

      To use the default startup of the parent service simply leave this field blank.

      -
      -
      -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -

      Variables


      - @foreach($option->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 -

      Servers


      - - - - - - - - - - @foreach ($option->servers as $server) - - - - - - @endforeach - -
      NameOwnerUpdated
      {{ $server->name }}{{ $server->user->email }}{{ $server->updated_at }}
      -
      - {!! $option->servers->render() !!} -
      -
      -
      -
      -
      - Deleting an option is an irreversible action. An option can only be deleted if no servers are associated with it. -
      - {!! csrf_field() !!} - {!! method_field('DELETE') !!} - -
      -
      -
      -
      - -@endsection diff --git a/resources/views/admin/services/view.blade.php b/resources/views/admin/services/view.blade.php deleted file mode 100644 index 6b660a5ac..000000000 --- a/resources/views/admin/services/view.blade.php +++ /dev/null @@ -1,135 +0,0 @@ -{{-- 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') - Manage Service -@endsection - -@section('content') -
      - -

      Service Options


      - - - - - - - - - - - @foreach($service->options as $option) - - - - - - - @endforeach - - - - - - - -
      Option NameDescriptionTagServers
      {{ $option->name }}{!! $option->description !!}{{ $option->tag }}{{ $option->servers->count() }}
      -
      -
      -
      -
      - -
      - -

      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() !!} - - -
      -
      -
      -
      -
      -
      -
      -
      - Deleting a service is an irreversible action. A service can only be deleted if no servers are associated with it. -
      - {!! csrf_field() !!} - {!! method_field('DELETE') !!} - -
      -
      -
      -
      - -@endsection diff --git a/resources/views/errors/403.blade.php b/resources/views/errors/403.blade.php deleted file mode 100644 index bc83eb24a..000000000 --- a/resources/views/errors/403.blade.php +++ /dev/null @@ -1,37 +0,0 @@ -{{-- 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.master') - -@section('title', '403: Forbidden') - -@section('content') -
      -
      -
      -

      HTTP 403: Access Denied

      -
      -
      -

      You do not have permission to access that function. Please contact your server administrator to request permission.

      -
      -
      -

      -

      Take me back or go home.

      -
      -@endsection diff --git a/resources/views/errors/404.blade.php b/resources/views/errors/404.blade.php deleted file mode 100644 index bdaec2cd4..000000000 --- a/resources/views/errors/404.blade.php +++ /dev/null @@ -1,37 +0,0 @@ -{{-- 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.master') - -@section('title', '404: Not Found') - - -@section('right-nav') -@endsection - -@section('sidebar') -@endsection - -@section('content') -
      -

      404 - File Not Found

      -

      -

      Take me back or go home.

      -
      -@endsection diff --git a/resources/views/layouts/admin.blade.php b/resources/views/layouts/admin.blade.php deleted file mode 100644 index f800c1ac5..000000000 --- a/resources/views/layouts/admin.blade.php +++ /dev/null @@ -1,226 +0,0 @@ -{{-- 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. --}} - - - - @section('scripts') - - - - {!! Theme::css('css/vendor/bootstrap/bootstrap.css') !!} - {!! Theme::css('css/pterodactyl.css') !!} - {!! Theme::css('css/animate.css') !!} - {!! Theme::css('css/vendor/fontawesome/font-awesome.min.css') !!} - {!! Theme::css('css/vendor/sweetalert/sweetalert.min.css') !!} - {!! Theme::css('css/vendor/fuelux/fuelux.min.css') !!} - {!! Theme::js('js/vendor/jquery/jquery.min.js') !!} - {!! Theme::js('js/vendor/bootstrap/bootstrap.min.js') !!} - {!! Theme::js('js/vendor/sweetalert/sweetalert.min.js') !!} - {!! Theme::js('js/vendor/fuelux/fuelux.min.js') !!} - {!! Theme::js('js/admin.min.js') !!} - {!! Theme::js('js/bootstrap-notify.min.js') !!} - - @show - {{ Settings::get('company') }} - @yield('title') - - -
      - - -
      - -
      -
      -
      - @section('resp-errors') - @if (count($errors) > 0) -
      - - {{ trans('strings.whoops') }}! {{ trans('auth.errorencountered') }}

      -
        - @foreach ($errors->all() as $error) -
      • {{ $error }}
      • - @endforeach -
      -
      - @endif - @show - @section('resp-alerts') - @foreach (Alert::getMessages() as $type => $messages) - @foreach ($messages as $message) - - @endforeach - @endforeach - @show -
      -
      -
      - @yield('content') -
      -
      -
      - -
      - - - From 1897741381ea95301024489211cbc48061bdc6f0 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 12 Mar 2017 16:34:43 -0400 Subject: [PATCH 326/599] StyleCI cleanup --- app/Http/Controllers/Admin/OptionController.php | 5 ++--- app/Http/Controllers/Admin/ServiceController.php | 12 ------------ app/Http/Controllers/Daemon/ServiceController.php | 2 +- app/Models/Service.php | 2 +- app/Repositories/OptionRepository.php | 1 - app/Repositories/ServiceRepository.php | 5 +---- ...17_03_10_162934_AddNewServiceOptionsColumns.php | 4 ++-- ...2017_03_10_173607_MigrateToNewServiceSystem.php | 14 ++++++-------- ...15455_ChangeServiceVariablesValidationRules.php | 4 ++-- ...3_12_150648_MoveFunctionsFromFileToDatabase.php | 4 ++-- 10 files changed, 17 insertions(+), 36 deletions(-) diff --git a/app/Http/Controllers/Admin/OptionController.php b/app/Http/Controllers/Admin/OptionController.php index 837e5a8aa..68ddfaf9e 100644 --- a/app/Http/Controllers/Admin/OptionController.php +++ b/app/Http/Controllers/Admin/OptionController.php @@ -26,7 +26,6 @@ namespace Pterodactyl\Http\Controllers\Admin; use Log; use Alert; -use Storage; use Javascript; use Illuminate\Http\Request; use Pterodactyl\Models\Service; @@ -67,7 +66,7 @@ class OptionController extends Controller $option = $repo->create($request->intersect([ 'service_id', 'name', 'description', 'tag', 'docker_image', 'startup', 'config_from', 'config_startup', - 'config_logs', 'config_files', 'config_stop' + 'config_logs', 'config_files', 'config_stop', ])); Alert::success('Successfully created new service option.')->flash(); @@ -195,7 +194,7 @@ class OptionController extends Controller Alert::success("The service variable '{$variable->name}' has been updated.")->flash(); } else { $repo->delete($variable); - Alert::success("That service variable has been deleted.")->flash(); + Alert::success('That service variable has been deleted.')->flash(); } } catch (DisplayValidationException $ex) { return redirect()->route('admin.services.option.variables', $option)->withErrors(json_decode($ex->getMessage())); diff --git a/app/Http/Controllers/Admin/ServiceController.php b/app/Http/Controllers/Admin/ServiceController.php index 523e6bb14..bcf4d9008 100644 --- a/app/Http/Controllers/Admin/ServiceController.php +++ b/app/Http/Controllers/Admin/ServiceController.php @@ -149,16 +149,4 @@ class ServiceController extends Controller return redirect()->route($redirectTo, $id); } - - /** - * Edits function file for a service. - * - * @param Request $request - * @param int $id - * @return \Illuminate\Response\RedirectResponse - */ - public function editFunctions(Request $request, $id) - { - - } } diff --git a/app/Http/Controllers/Daemon/ServiceController.php b/app/Http/Controllers/Daemon/ServiceController.php index 6638f30d6..99d69cf02 100644 --- a/app/Http/Controllers/Daemon/ServiceController.php +++ b/app/Http/Controllers/Daemon/ServiceController.php @@ -66,7 +66,7 @@ class ServiceController extends Controller if ($file === 'index.js') { return response($service->index_file)->header('Content-Type', 'text/plain'); - } else if ($file === 'main.json') { + } elseif ($file === 'main.json') { return response()->json($this->getConfiguration($service->id)); } diff --git a/app/Models/Service.php b/app/Models/Service.php index c521b8035..96798f94c 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -51,7 +51,7 @@ class Service extends Model */ public function defaultIndexFile() { - return <<options as $option) { + foreach ($service->options as $option) { (new OptionRepository)->delete($option->id); } diff --git a/database/migrations/2017_03_10_162934_AddNewServiceOptionsColumns.php b/database/migrations/2017_03_10_162934_AddNewServiceOptionsColumns.php index 535c3b477..71af419b0 100644 --- a/database/migrations/2017_03_10_162934_AddNewServiceOptionsColumns.php +++ b/database/migrations/2017_03_10_162934_AddNewServiceOptionsColumns.php @@ -13,7 +13,7 @@ class AddNewServiceOptionsColumns extends Migration */ public function up() { - DB::transaction(function() { + DB::transaction(function () { Schema::table('service_options', function (Blueprint $table) { $table->dropColumn('executable'); @@ -35,7 +35,7 @@ class AddNewServiceOptionsColumns extends Migration */ public function down() { - DB::transaction(function() { + DB::transaction(function () { Schema::table('service_options', function (Blueprint $table) { $table->dropForeign('config_from'); diff --git a/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php b/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php index c22954150..75d775185 100644 --- a/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php +++ b/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php @@ -23,8 +23,6 @@ */ use Pterodactyl\Models\Service; use Pterodactyl\Models\ServiceOption; -use Illuminate\Support\Facades\Schema; -use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class MigrateToNewServiceSystem extends Migration @@ -69,7 +67,7 @@ class MigrateToNewServiceSystem extends Migration DB::transaction(function () use ($service) { $options = ServiceOption::where('service_id', $service->id)->get(); $options->each(function ($item) use ($options) { - switch($item->tag) { + switch ($item->tag) { case 'vanilla': $item->config_startup = '{"done": ")! For help, type ", "userInteraction": [ "Go to eula.txt for more info."]}'; $item->config_files = '{"server.properties":{"parser": "properties", "find":{"server-ip": "0.0.0.0", "enable-query": "true", "server-port": "{{server.build.default.port}}", "query.port": "{{server.build.default.port}}"}}}'; @@ -117,13 +115,13 @@ class MigrateToNewServiceSystem extends Migration $options->each(function ($item) use ($options) { if ($item->tag === 'srcds' && $item->name === 'Insurgency') { $item->tag = 'insurgency'; - } else if ($item->tag === 'srcds' && $item->name === 'Team Fortress 2') { + } elseif ($item->tag === 'srcds' && $item->name === 'Team Fortress 2') { $item->tag = 'tf2'; - } else if ($item->tag === 'srcds' && $item->name === 'Custom Source Engine Game') { + } elseif ($item->tag === 'srcds' && $item->name === 'Custom Source Engine Game') { $item->tag = 'source'; } - switch($item->tag) { + switch ($item->tag) { case 'source': $item->config_startup = '{"done": "Assigned anonymous gameserver", "userInteraction": []}'; $item->config_files = '{}'; @@ -164,7 +162,7 @@ class MigrateToNewServiceSystem extends Migration DB::transaction(function () use ($service) { $options = ServiceOption::where('service_id', $service->id)->get(); $options->each(function ($item) use ($options) { - switch($item->tag) { + switch ($item->tag) { case 'tshock': $item->startup = null; $item->config_startup = '{"done": "Type \'help\' for a list of commands", "userInteraction": []}'; @@ -195,7 +193,7 @@ class MigrateToNewServiceSystem extends Migration DB::transaction(function () use ($service) { $options = ServiceOption::where('service_id', $service->id)->get(); $options->each(function ($item) use ($options) { - switch($item->tag) { + switch ($item->tag) { case 'mumble': $item->startup = './murmur.x86 -fg'; $item->config_startup = '{"done": "Server listening on", "userInteraction": [ "Generating new server certificate"]}'; diff --git a/database/migrations/2017_03_11_215455_ChangeServiceVariablesValidationRules.php b/database/migrations/2017_03_11_215455_ChangeServiceVariablesValidationRules.php index 1ade5b53e..a9c1dae84 100644 --- a/database/migrations/2017_03_11_215455_ChangeServiceVariablesValidationRules.php +++ b/database/migrations/2017_03_11_215455_ChangeServiceVariablesValidationRules.php @@ -19,7 +19,7 @@ class ChangeServiceVariablesValidationRules extends Migration }); DB::transaction(function () { - foreach(ServiceVariable::all() as $variable) { + foreach (ServiceVariable::all() as $variable) { $variable->rules = ($variable->required) ? 'required|regex:' . $variable->rules : 'regex:' . $variable->regex; $variable->save(); } @@ -38,7 +38,7 @@ class ChangeServiceVariablesValidationRules extends Migration }); DB::transaction(function () { - foreach(ServiceVariable::all() as $variable) { + foreach (ServiceVariable::all() as $variable) { $variable->regex = str_replace(['required|regex:', 'regex:'], '', $variable->regex); $variable->save(); } diff --git a/database/migrations/2017_03_12_150648_MoveFunctionsFromFileToDatabase.php b/database/migrations/2017_03_12_150648_MoveFunctionsFromFileToDatabase.php index bb37afd9a..b58051736 100644 --- a/database/migrations/2017_03_12_150648_MoveFunctionsFromFileToDatabase.php +++ b/database/migrations/2017_03_12_150648_MoveFunctionsFromFileToDatabase.php @@ -8,7 +8,7 @@ use Illuminate\Database\Migrations\Migration; class MoveFunctionsFromFileToDatabase extends Migration { - private $default = << Date: Sun, 12 Mar 2017 16:35:25 -0400 Subject: [PATCH 327/599] More StyleCI... --- app/Repositories/OptionRepository.php | 2 +- .../2017_03_12_150648_MoveFunctionsFromFileToDatabase.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/Repositories/OptionRepository.php b/app/Repositories/OptionRepository.php index e700f98bf..b5e9510c1 100644 --- a/app/Repositories/OptionRepository.php +++ b/app/Repositories/OptionRepository.php @@ -87,7 +87,7 @@ class OptionRepository } DB::transaction(function () use ($option) { - foreach($option->variables as $variable) { + foreach ($option->variables as $variable) { (new VariableRepository)->delete($variable->id); } diff --git a/database/migrations/2017_03_12_150648_MoveFunctionsFromFileToDatabase.php b/database/migrations/2017_03_12_150648_MoveFunctionsFromFileToDatabase.php index b58051736..bbd5fda42 100644 --- a/database/migrations/2017_03_12_150648_MoveFunctionsFromFileToDatabase.php +++ b/database/migrations/2017_03_12_150648_MoveFunctionsFromFileToDatabase.php @@ -7,7 +7,6 @@ use Illuminate\Database\Migrations\Migration; class MoveFunctionsFromFileToDatabase extends Migration { - private $default = <<<'EOF' 'use strict'; From 97cad1d55e234c9cf8c27184b47678d7ba244591 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 12 Mar 2017 18:02:15 -0400 Subject: [PATCH 328/599] Update seeders to not error out and allow updating values quickly. --- app/Models/Service.php | 2 +- app/Repositories/ServiceRepository.php | 2 +- .../seeds/MinecraftServiceTableSeeder.php | 181 +++++++++++------ database/seeds/SourceServiceTableSeeder.php | 182 +++++++++++------- database/seeds/TerrariaServiceTableSeeder.php | 45 +++-- database/seeds/VoiceServiceTableSeeder.php | 67 ++++--- 6 files changed, 305 insertions(+), 174 deletions(-) diff --git a/app/Models/Service.php b/app/Models/Service.php index 96798f94c..245587afd 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -49,7 +49,7 @@ class Service extends Model * * @return string */ - public function defaultIndexFile() + public static function defaultIndexFile() { return <<<'EOF' 'use strict'; diff --git a/app/Repositories/ServiceRepository.php b/app/Repositories/ServiceRepository.php index 56bfd5148..e8d606ffc 100644 --- a/app/Repositories/ServiceRepository.php +++ b/app/Repositories/ServiceRepository.php @@ -59,7 +59,7 @@ class ServiceRepository 'description' => (isset($data['description'])) ? $data['description'] : null, 'folder' => $data['folder'], 'startup' => (isset($data['startup'])) ? $data['startup'] : null, - 'index_file' => $service->defaultIndexFile(), + 'index_file' => Service::defaultIndexFile(), ])->save(); // It is possible for an event to return false or throw an exception diff --git a/database/seeds/MinecraftServiceTableSeeder.php b/database/seeds/MinecraftServiceTableSeeder.php index 45f251ebd..7595f64bc 100644 --- a/database/seeds/MinecraftServiceTableSeeder.php +++ b/database/seeds/MinecraftServiceTableSeeder.php @@ -21,15 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -use Pterodactyl\Models; use Illuminate\Database\Seeder; +use Pterodactyl\Models\Service; +use Pterodactyl\Models\ServiceOption; +use Pterodactyl\Models\ServiceVariable; class MinecraftServiceTableSeeder extends Seeder { /** * The core service ID. * - * @var Models\Service + * @var \Pterodactyl\Models\Service */ protected $service; @@ -40,6 +42,47 @@ class MinecraftServiceTableSeeder extends Seeder */ protected $option = []; + private $default_mc = <<<'EOF' +'use strict'; + +/** + * Pterodactyl - Daemon + * 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. + */ +const rfr = require('rfr'); +const _ = require('lodash'); + +const Core = rfr('src/services/index.js'); + +class Service extends Core { + onConsole(data) { + // Hide the output spam from Bungeecord getting pinged. + if (_.endsWith(data, '<-> InitialHandler has connected')) return; + return super.onConsole(data); + } +} + +module.exports = Service; +EOF; + /** * Run the database seeds. * @@ -54,55 +97,76 @@ class MinecraftServiceTableSeeder extends Seeder private function addCoreService() { - $this->service = Models\Service::create([ - 'author' => 'ptrdctyl-v040-11e6-8b77-86f30ca893d3', + $this->service = Service::updateOrCreate([ + 'author' => config('pterodactyl.service.core'), + 'folder' => 'minecraft', + ], [ 'name' => 'Minecraft', 'description' => 'Minecraft - the classic game from Mojang. With support for Vanilla MC, Spigot, and many others!', - 'file' => 'minecraft', - 'executable' => 'java', - 'startup' => '-Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}', + 'startup' => 'java -Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}', + 'index_file' => $this->default_mc, ]); } private function addCoreOptions() { - $this->option['vanilla'] = Models\ServiceOption::create([ + $this->option['vanilla'] = ServiceOption::updateOrCreate([ 'service_id' => $this->service->id, + 'tag' => 'vanilla', + ], [ 'name' => 'Vanilla Minecraft', 'description' => 'Minecraft is a game about placing blocks and going on adventures. Explore randomly generated worlds and build amazing things from the simplest of homes to the grandest of castles. Play in Creative Mode with unlimited resources or mine deep in Survival Mode, crafting weapons and armor to fend off dangerous mobs. Do all this alone or with friends.', - 'tag' => 'vanilla', 'docker_image' => 'quay.io/pterodactyl/minecraft', - 'executable' => null, + 'config_startup' => '{"done": ")! For help, type ", "userInteraction": [ "Go to eula.txt for more info."]}', + 'config_logs' => '{"custom": false, "location": "logs/latest.log"}', + 'config_files' => '{"server.properties":{"parser": "properties", "find":{"server-ip": "0.0.0.0", "enable-query": "true", "server-port": "{{server.build.default.port}}", "query.port": "{{server.build.default.port}}"}}}', + 'config_stop' => 'stop', + 'config_from' => null, 'startup' => null, ]); - $this->option['spigot'] = Models\ServiceOption::create([ + $this->option['spigot'] = ServiceOption::updateOrCreate([ 'service_id' => $this->service->id, + 'tag' => 'spigot', + ], [ 'name' => 'Spigot', 'description' => 'Spigot is the most widely-used modded Minecraft server software in the world. It powers many of the top Minecraft server networks around to ensure they can cope with their huge player base and ensure the satisfaction of their players. Spigot works by reducing and eliminating many causes of lag, as well as adding in handy features and settings that help make your job of server administration easier.', - 'tag' => 'spigot', 'docker_image' => 'quay.io/pterodactyl/minecraft:spigot', - 'executable' => null, - 'startup' => '-Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}', - ]); - - $this->option['sponge'] = Models\ServiceOption::create([ - 'service_id' => $this->service->id, - 'name' => 'Sponge (SpongeVanilla)', - 'description' => 'SpongeVanilla is the SpongeAPI implementation for Vanilla Minecraft.', - 'tag' => 'sponge', - 'docker_image' => 'quay.io/pterodactyl/minecraft:sponge', - 'executable' => null, + 'config_startup' => null, + 'config_files' => '{"spigot.yml":{"parser": "yaml", "find":{"settings.restart-on-crash": "false"}}}', + 'config_logs' => null, + 'config_stop' => null, + 'config_from' => $this->option['vanilla']->id, 'startup' => null, ]); - $this->option['bungeecord'] = Models\ServiceOption::create([ + $this->option['sponge'] = ServiceOption::updateOrCreate([ 'service_id' => $this->service->id, + 'tag' => 'sponge', + ], [ + 'name' => 'Sponge (SpongeVanilla)', + 'description' => 'SpongeVanilla is the SpongeAPI implementation for Vanilla Minecraft.', + 'docker_image' => 'quay.io/pterodactyl/minecraft:sponge', + 'config_startup' => '{"userInteraction": [ "You need to agree to the EULA"]}', + 'config_files' => null, + 'config_logs' => null, + 'config_stop' => null, + 'config_from' => $this->option['vanilla']->id, + 'startup' => null, + ]); + + $this->option['bungeecord'] = ServiceOption::updateOrCreate([ + 'service_id' => $this->service->id, + 'tag' => 'bungeecord', + ], [ 'name' => 'Bungeecord', 'description' => 'For a long time, Minecraft server owners have had a dream that encompasses a free, easy, and reliable way to connect multiple Minecraft servers together. BungeeCord is the answer to said dream. Whether you are a small server wishing to string multiple game-modes together, or the owner of the ShotBow Network, BungeeCord is the ideal solution for you. With the help of BungeeCord, you will be able to unlock your community\'s full potential.', - 'tag' => 'bungeecord', 'docker_image' => 'quay.io/pterodactyl/minecraft:bungeecord', - 'executable' => null, + 'config_startup' => '{"done": "Listening on ", "userInteraction": [ "Listening on /0.0.0.0:25577"]}', + 'config_files' => '{"config.yml":{"parser": "yaml", "find":{"listeners[0].query_enabled": true, "listeners[0].query_port": "{{server.build.default.port}}", "listeners[0].host": "0.0.0.0:{{server.build.default.port}}", "servers.*.address":{"127.0.0.1": "{{config.docker.interface}}", "localhost": "{{config.docker.interface}}"}}}}', + 'config_logs' => '{"custom": false, "location": "proxy.log.0"}', + 'config_stop' => 'end', + 'config_from' => null, 'startup' => null, ]); } @@ -117,121 +181,130 @@ class MinecraftServiceTableSeeder extends Seeder private function addVanillaVariables() { - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['vanilla']->id, + 'env_variable' => 'SERVER_JARFILE', + ], [ 'name' => 'Server Jar File', 'description' => 'The name of the server jarfile to run the server with.', - 'env_variable' => 'SERVER_JARFILE', 'default_value' => 'server.jar', 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^([\w\d._-]+)(\.jar)$/', + 'rules' => 'required|regex:/^([\w\d._-]+)(\.jar)$/', ]); - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['vanilla']->id, + 'env_variable' => 'VANILLA_VERSION', + ], [ 'name' => 'Server Version', 'description' => 'The version of Minecraft Vanilla to install. Use "latest" to install the latest version.', - 'env_variable' => 'VANILLA_VERSION', 'default_value' => 'latest', 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^(latest|[a-zA-Z0-9_\.-]{3,7})$/', + 'rules' => 'required|string|between:3,7', ]); } private function addSpigotVariables() { - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['spigot']->id, + 'env_variable' => 'SERVER_JARFILE', + ], [ 'name' => 'Server Jar File', 'description' => 'The name of the server jarfile to run the server with.', - 'env_variable' => 'SERVER_JARFILE', 'default_value' => 'server.jar', 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^([\w\d._-]+)(\.jar)$/', + 'rules' => 'required|regex:/^([\w\d._-]+)(\.jar)$/', ]); - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['spigot']->id, + 'env_variable' => 'DL_VERSION', + ], [ 'name' => 'Spigot Version', 'description' => 'The version of Spigot to download (using the --rev tag). Use "latest" for latest.', - 'env_variable' => 'DL_VERSION', 'default_value' => 'latest', 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^(latest|[a-zA-Z0-9_\.-]{3,7})$/', + 'rules' => 'required|string|between:3,7', ]); - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['spigot']->id, + 'env_variable' => 'DL_PATH', + ], [ 'name' => 'Download Path', 'description' => 'A URL to use to download Spigot rather than building it on the server. This is not user viewable. Use {{DL_VERSION}} in the URL to automatically insert the assigned version into the URL. If you do not enter a URL Spigot will build directly in the container (this will fail on low memory containers).', - 'env_variable' => 'DL_PATH', 'default_value' => '', 'user_viewable' => 0, 'user_editable' => 0, 'required' => 0, - 'regex' => '/^(.*)$/', + 'rules' => 'required|string', ]); } private function addSpongeVariables() { - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['sponge']->id, + 'env_variable' => 'SPONGE_VERSION', + ], [ 'name' => 'Sponge Version', 'description' => 'The version of SpongeVanilla to download and use.', - 'env_variable' => 'SPONGE_VERSION', - 'default_value' => '1.10.2-5.1.0-BETA-359', + 'default_value' => '1.10.2-5.2.0-BETA-381', 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^([a-zA-Z0-9.\-_]+)$/', + 'rules' => 'required|regex:/^([a-zA-Z0-9.\-_]+)$/', ]); - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['sponge']->id, + 'env_variable' => 'SERVER_JARFILE', + ], [ 'name' => 'Server Jar File', 'description' => 'The name of the Jarfile to use when running SpongeVanilla.', - 'env_variable' => 'SERVER_JARFILE', 'default_value' => 'server.jar', 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^([\w\d._-]+)(\.jar)$/', + 'rules' => 'required|regex:/^([\w\d._-]+)(\.jar)$/', ]); } private function addBungeecordVariables() { - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['bungeecord']->id, + 'env_variable' => 'BUNGEE_VERSION', + ], [ 'name' => 'Bungeecord Version', 'description' => 'The version of Bungeecord to download and use.', - 'env_variable' => 'BUNGEE_VERSION', 'default_value' => 'latest', 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^(latest|[\d]{1,6})$/', + 'rules' => 'required|alpha_num|between:1,6', ]); - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['bungeecord']->id, + 'env_variable' => 'SERVER_JARFILE', + ], [ 'name' => 'Bungeecord Jar File', 'description' => 'The name of the Jarfile to use when running Bungeecord.', - 'env_variable' => 'SERVER_JARFILE', 'default_value' => 'bungeecord.jar', 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^([\w\d._-]+)(\.jar)$/', + 'rules' => 'required|regex:/^([\w\d._-]+)(\.jar)$/', ]); } } diff --git a/database/seeds/SourceServiceTableSeeder.php b/database/seeds/SourceServiceTableSeeder.php index 87623335c..d565d27d6 100644 --- a/database/seeds/SourceServiceTableSeeder.php +++ b/database/seeds/SourceServiceTableSeeder.php @@ -21,8 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -use Pterodactyl\Models; use Illuminate\Database\Seeder; +use Pterodactyl\Models\Service; +use Pterodactyl\Models\ServiceOption; +use Pterodactyl\Models\ServiceVariable; class SourceServiceTableSeeder extends Seeder { @@ -54,57 +56,78 @@ class SourceServiceTableSeeder extends Seeder private function addCoreService() { - $this->service = Models\Service::create([ - 'author' => 'ptrdctyl-v040-11e6-8b77-86f30ca893d3', + $this->service = Service::updateOrCreate([ + 'author' => config('pterodactyl.service.core'), + 'folder' => 'srcds', + ], [ 'name' => 'Source Engine', 'description' => 'Includes support for most Source Dedicated Server games.', - 'file' => 'srcds', - 'executable' => './srcds_run', - 'startup' => '-game {{SRCDS_GAME}} -console -port {{SERVER_PORT}} -strictportbind -norestart', + 'startup' => './srcds_run -game {{SRCDS_GAME}} -console -port {{SERVER_PORT}} +ip 0.0.0.0 -strictportbind -norestart', + 'index_file' => Service::defaultIndexFile(), ]); } private function addCoreOptions() { - $this->option['insurgency'] = Models\ServiceOption::create([ - 'service_id' => $this->service->id, - 'name' => 'Insurgency', - 'description' => 'Take to the streets for intense close quarters combat, where a team\'s survival depends upon securing crucial strongholds and destroying enemy supply in this multiplayer and cooperative Source Engine based experience.', - 'tag' => 'srcds', - 'docker_image' => 'quay.io/pterodactyl/srcds', - 'executable' => null, - 'startup' => '-game {{SRCDS_GAME}} -console -port {{SERVER_PORT}} +map {{SRCDS_MAP}} -strictportbind -norestart', - ]); - - $this->option['tf2'] = Models\ServiceOption::create([ - 'service_id' => $this->service->id, - 'name' => 'Team Fortress 2', - 'description' => 'Team Fortress 2 is a team-based first-person shooter multiplayer video game developed and published by Valve Corporation. It is the sequel to the 1996 mod Team Fortress for Quake and its 1999 remake.', - 'tag' => 'srcds', - 'docker_image' => 'quay.io/pterodactyl/srcds', - 'executable' => null, - 'startup' => '-game {{SRCDS_GAME}} -console -port {{SERVER_PORT}} +map {{SRCDS_MAP}} -strictportbind -norestart', - ]); - - $this->option['ark'] = Models\ServiceOption::create([ - 'service_id' => $this->service->id, - 'name' => 'Ark: Survival Evolved', - 'description' => 'As a man or woman stranded, naked, freezing, and starving on the unforgiving shores of a mysterious island called ARK, use your skill and cunning to kill or tame and ride the plethora of leviathan dinosaurs and other primeval creatures roaming the land. Hunt, harvest resources, craft items, grow crops, research technologies, and build shelters to withstand the elements and store valuables, all while teaming up with (or preying upon) hundreds of other players to survive, dominate... and escape! — Gamepedia: ARK', - 'tag' => 'ark', - 'docker_image' => 'quay.io/pterodactyl/srcds:ark', - 'executable' => './ShooterGameServer', - 'startup' => 'TheIsland?listen?ServerPassword={{ARK_PASSWORD}}?ServerAdminPassword={{ARK_ADMIN_PASSWORD}}?Port={{SERVER_PORT}}?MaxPlayers={{SERVER_MAX_PLAYERS}}', - ]); - - $this->option['custom'] = Models\ServiceOption::create([ + $this->option['source'] = ServiceOption::updateOrCreate([ 'service_id' => $this->service->id, + 'tag' => 'source', + ], [ 'name' => 'Custom Source Engine Game', 'description' => 'This option allows modifying the startup arguments and other details to run a custo SRCDS based game on the panel.', - 'tag' => 'srcds', 'docker_image' => 'quay.io/pterodactyl/srcds', - 'executable' => null, + 'config_startup' => '{"done": "Assigned anonymous gameserver", "userInteraction": []}', + 'config_files' => '{}', + 'config_logs' => '{"custom": true, "location": "logs/latest.log"}', + 'config_stop' => 'quit', + 'config_from' => null, 'startup' => null, ]); + + $this->option['insurgency'] = ServiceOption::updateOrCreate([ + 'service_id' => $this->service->id, + 'tag' => 'insurgency', + ], [ + 'name' => 'Insurgency', + 'description' => 'Take to the streets for intense close quarters combat, where a team\'s survival depends upon securing crucial strongholds and destroying enemy supply in this multiplayer and cooperative Source Engine based experience.', + 'docker_image' => 'quay.io/pterodactyl/srcds', + 'config_startup' => null, + 'config_files' => null, + 'config_logs' => null, + 'config_stop' => null, + 'config_from' => $this->option['source']->id, + 'startup' => './srcds_run -game {{SRCDS_GAME}} -console -port {{SERVER_PORT}} +map {{SRCDS_MAP}} +ip 0.0.0.0 -strictportbind -norestart', + ]); + + $this->option['tf2'] = ServiceOption::updateOrCreate([ + 'service_id' => $this->service->id, + 'tag' => 'tf2', + ], [ + 'name' => 'Team Fortress 2', + 'description' => 'Team Fortress 2 is a team-based first-person shooter multiplayer video game developed and published by Valve Corporation. It is the sequel to the 1996 mod Team Fortress for Quake and its 1999 remake.', + 'docker_image' => 'quay.io/pterodactyl/srcds', + 'config_startup' => null, + 'config_files' => null, + 'config_logs' => null, + 'config_stop' => null, + 'config_from' => $this->option['source']->id, + 'startup' => './srcds_run -game {{SRCDS_GAME}} -console -port {{SERVER_PORT}} +map {{SRCDS_MAP}} +ip 0.0.0.0 -strictportbind -norestart', + ]); + + $this->option['ark'] = ServiceOption::updateOrCreate([ + 'service_id' => $this->service->id, + 'tag' => 'ark', + ], [ + 'name' => 'Ark: Survival Evolved', + 'description' => 'As a man or woman stranded, naked, freezing, and starving on the unforgiving shores of a mysterious island called ARK, use your skill and cunning to kill or tame and ride the plethora of leviathan dinosaurs and other primeval creatures roaming the land. Hunt, harvest resources, craft items, grow crops, research technologies, and build shelters to withstand the elements and store valuables, all while teaming up with (or preying upon) hundreds of other players to survive, dominate... and escape! — Gamepedia: ARK', + 'docker_image' => 'quay.io/pterodactyl/srcds:ark', + 'config_startup' => '{"done": "Setting breakpad minidump AppID"}', + 'config_files' => null, + 'config_logs' => null, + 'config_stop' => '^C', + 'config_from' => $this->option['source']->id, + 'startup' => './ShooterGame/Binaries/Linux/ShooterGameServer TheIsland?listen?ServerPassword={{ARK_PASSWORD}}?ServerAdminPassword={{ARK_ADMIN_PASSWORD}}?Port={{SERVER_PORT}}?MaxPlayers={{SERVER_MAX_PLAYERS}}', + ]); } private function addVariables() @@ -117,145 +140,156 @@ class SourceServiceTableSeeder extends Seeder private function addInsurgencyVariables() { - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['insurgency']->id, + 'env_variable' => 'SRCDS_APPID', + ], [ 'name' => 'Game ID', 'description' => 'The ID corresponding to the game to download and run using SRCDS.', - 'env_variable' => 'SRCDS_APPID', 'default_value' => '17705', 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(17705)$/', + 'rules' => 'required|regex:/^(17705)$/', ]); - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['insurgency']->id, + 'env_variable' => 'SRCDS_GAME', + ], [ 'name' => 'Game Name', 'description' => 'The name corresponding to the game to download and run using SRCDS.', - 'env_variable' => 'SRCDS_GAME', 'default_value' => 'insurgency', 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(insurgency)$/', + 'rules' => 'required|regex:/^(insurgency)$/', ]); - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['insurgency']->id, + 'env_variable' => 'SRCDS_MAP', + ], [ 'name' => 'Default Map', 'description' => 'The default map to use when starting the server.', - 'env_variable' => 'SRCDS_MAP', 'default_value' => 'sinjar', 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^(\w{1,20})$/', + 'rules' => 'required|regex:/^(\w{1,20})$/', ]); } private function addTF2Variables() { - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['tf2']->id, + 'env_variable' => 'SRCDS_APPID', + ], [ 'name' => 'Game ID', 'description' => 'The ID corresponding to the game to download and run using SRCDS.', - 'env_variable' => 'SRCDS_APPID', 'default_value' => '232250', 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(232250)$/', + 'rules' => 'required|regex:/^(232250)$/', ]); - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['tf2']->id, + 'env_variable' => 'SRCDS_GAME', + ], [ 'name' => 'Game Name', 'description' => 'The name corresponding to the game to download and run using SRCDS.', - 'env_variable' => 'SRCDS_GAME', 'default_value' => 'tf', 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(tf)$/', + 'rules' => 'required|regex:/^(tf)$/', ]); - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['tf2']->id, + 'env_variable' => 'SRCDS_MAP', + ], [ 'name' => 'Default Map', 'description' => 'The default map to use when starting the server.', - 'env_variable' => 'SRCDS_MAP', 'default_value' => 'cp_dustbowl', 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^(\w{1,20})$/', + 'rules' => 'required|regex:/^(\w{1,20})$/', ]); } private function addArkVariables() { - DB::table('service_variables')->insert([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['ark']->id, + 'env_variable' => 'ARK_PASSWORD', + ], [ 'name' => 'Server Password', 'description' => 'If specified, players must provide this password to join the server.', - 'env_variable' => 'ARK_PASSWORD', 'default_value' => '', 'user_viewable' => 1, 'user_editable' => 1, 'required' => 0, - 'regex' => '/^(\w\.*)$/', + 'rules' => 'alpha_dash|between:1,100', ]); - DB::table('service_variables')->insert([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['ark']->id, + 'env_variable' => 'ARK_ADMIN_PASSWORD', + ], [ 'name' => 'Admin Password', 'description' => 'If specified, players must provide this password (via the in-game console) to gain access to administrator commands on the server.', - 'env_variable' => 'ARK_ADMIN_PASSWORD', 'default_value' => '', 'user_viewable' => 1, 'user_editable' => 1, 'required' => 0, - 'regex' => '/^(\w\.*)$/', + 'rules' => 'alpha_dash|between:1,100', ]); - DB::table('service_variables')->insert([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['ark']->id, + 'env_variable' => 'SERVER_MAX_PLAYERS', + ], [ 'name' => 'Maximum Players', 'description' => 'Specifies the maximum number of players that can play on the server simultaneously.', - 'env_variable' => 'SERVER_MAX_PLAYERS', 'default_value' => 20, 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^(\d{1,4})$/', + 'rules' => 'required|numeric|digits_between:1,4', ]); } private function addCustomVariables() { - Models\ServiceVariable::create([ - 'option_id' => $this->option['custom']->id, + ServiceVariable::updateOrCreate([ + 'option_id' => $this->option['source']->id, + 'env_variable' => 'SRCDS_APPID', + ], [ 'name' => 'Game ID', 'description' => 'The ID corresponding to the game to download and run using SRCDS.', - 'env_variable' => 'SRCDS_APPID', 'default_value' => '', 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(\d){1,6}$/', + 'rules' => 'required|numeric|digits_between:1,6', ]); - Models\ServiceVariable::create([ - 'option_id' => $this->option['custom']->id, + ServiceVariable::updateOrCreate([ + 'option_id' => $this->option['source']->id, + 'env_variable' => 'SRCDS_GAME', + ], [ 'name' => 'Game Name', 'description' => 'The name corresponding to the game to download and run using SRCDS.', - 'env_variable' => 'SRCDS_GAME', 'default_value' => '', 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(.*)$/', + 'rules' => 'required|alpha_dash|between:1,100', ]); } } diff --git a/database/seeds/TerrariaServiceTableSeeder.php b/database/seeds/TerrariaServiceTableSeeder.php index 59fd1e519..9bc442738 100644 --- a/database/seeds/TerrariaServiceTableSeeder.php +++ b/database/seeds/TerrariaServiceTableSeeder.php @@ -21,8 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -use Pterodactyl\Models; use Illuminate\Database\Seeder; +use Pterodactyl\Models\Service; +use Pterodactyl\Models\ServiceOption; +use Pterodactyl\Models\ServiceVariable; class TerrariaServiceTableSeeder extends Seeder { @@ -54,53 +56,60 @@ class TerrariaServiceTableSeeder extends Seeder private function addCoreService() { - $this->service = Models\Service::create([ - 'author' => 'ptrdctyl-v040-11e6-8b77-86f30ca893d3', + $this->service = Service::updateOrCreate([ + 'author' => config('pterodactyl.service.core'), + 'folder' => 'terraria', + ], [ 'name' => 'Terraria', 'description' => 'Terraria is a land of adventure! A land of mystery! A land that\'s yours to shape, defend, and enjoy. Your options in Terraria are limitless. Are you an action gamer with an itchy trigger finger? A master builder? A collector? An explorer? There\'s something for everyone.', - 'file' => 'terraria', - 'executable' => 'TerrariaServer.exe', - 'startup' => '-port {{SERVER_PORT}} -autocreate 2 -worldname World', + 'startup' => 'mono TerrariaServer.exe -port {{SERVER_PORT}} -autocreate 2 -worldname World', ]); } private function addCoreOptions() { - $this->option['tshock'] = Models\ServiceOption::create([ + $this->option['tshock'] = ServiceOption::updateOrCreate([ 'service_id' => $this->service->id, + 'tag' => 'tshock', + ], [ 'name' => 'Terraria Server (TShock)', 'description' => 'TShock is a server modification for Terraria, written in C#, and based upon the Terraria Server API. It uses JSON for configuration management, and offers several features not present in the Terraria Server normally.', - 'tag' => 'tshock', 'docker_image' => 'quay.io/pterodactyl/terraria:tshock', - 'executable' => '', - 'startup' => '', + 'config_startup' => '{"userInteraction": [ "You need to agree to the EULA"]}', + 'config_startup' => '{"done": "Type \'help\' for a list of commands", "userInteraction": []}', + 'config_files' => '{"tshock/config.json":{"parser": "json", "find":{"ServerPort": "{{server.build.default.port}}", "MaxSlots": "{{server.build.env.MAX_SLOTS}}"}}}', + 'config_logs' => '{"custom": false, "location": "ServerLog.txt"}', + 'config_stop' => 'exit', + 'startup' => null, ]); } private function addVariables() { - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['tshock']->id, + 'env_variable' => 'T_VERSION', + ], [ 'name' => 'TShock Version', 'description' => 'Which version of TShock to install and use.', - 'env_variable' => 'T_VERSION', - 'default_value' => '4.3.17', + 'default_value' => '4.3.22', 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^([0-9_\.-]{5,10})$/', + 'rules' => 'required|regex:/^([0-9_\.-]{5,10})$/', ]); - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['tshock']->id, + 'env_variable' => 'MAX_SLOTS', + ], [ 'name' => 'Maximum Slots', 'description' => 'Total number of slots to allow on the server.', - 'env_variable' => 'MAX_SLOTS', - 'default_value' => '20', + 'default_value' => 20, 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(\d){1,3}$/', + 'rules' => 'required|numeric|digits_between:1,3', ]); } } diff --git a/database/seeds/VoiceServiceTableSeeder.php b/database/seeds/VoiceServiceTableSeeder.php index 3856ac76a..22b02b95e 100644 --- a/database/seeds/VoiceServiceTableSeeder.php +++ b/database/seeds/VoiceServiceTableSeeder.php @@ -21,15 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -use Pterodactyl\Models; use Illuminate\Database\Seeder; +use Pterodactyl\Models\Service; +use Pterodactyl\Models\ServiceOption; +use Pterodactyl\Models\ServiceVariable; class VoiceServiceTableSeeder extends Seeder { /** * The core service ID. * - * @var Models\Service + * @var Service */ protected $service; @@ -54,75 +56,88 @@ class VoiceServiceTableSeeder extends Seeder private function addCoreService() { - $this->service = Models\Service::create([ - 'author' => 'ptrdctyl-v040-11e6-8b77-86f30ca893d3', + $this->service = Service::updateOrCreate([ + 'author' => config('pterodactyl.service.core'), + 'folder' => 'voice', + ], [ 'name' => 'Voice Servers', 'description' => 'Voice servers such as Mumble and Teamspeak 3.', - 'file' => 'voice', - 'executable' => '', 'startup' => '', ]); } private function addCoreOptions() { - $this->option['mumble'] = Models\ServiceOption::create([ + $this->option['mumble'] = ServiceOption::updateOrCreate([ 'service_id' => $this->service->id, + 'tag' => 'mumble', + ], [ 'name' => 'Mumble Server', 'description' => 'Mumble is an open source, low-latency, high quality voice chat software primarily intended for use while gaming.', - 'tag' => 'mumble', 'docker_image' => 'quay.io/pterodactyl/voice:mumble', - 'executable' => './murmur.x86', - 'startup' => '-fg', + 'config_startup' => '{"done": "Server listening on", "userInteraction": [ "Generating new server certificate"]}', + 'config_files' => '{"murmur.ini":{"parser": "ini", "find":{"logfile": "murmur.log", "port": "{{server.build.default.port}}", "host": "0.0.0.0", "users": "{{server.build.env.MAX_USERS}}"}}}', + 'config_logs' => '{"custom": true, "location": "logs/murmur.log"}', + 'config_stop' => '^C', + 'config_from' => null, + 'startup' => './murmur.x86 -fg', ]); - $this->option['ts3'] = Models\ServiceOption::create([ + $this->option['ts3'] = ServiceOption::updateOrCreate([ 'service_id' => $this->service->id, + 'tag' => 'ts3', + ], [ 'name' => 'Teamspeak3 Server', 'description' => 'VoIP software designed with security in mind, featuring crystal clear voice quality, endless customization options, and scalabilty up to thousands of simultaneous users.', - 'tag' => 'ts3', 'docker_image' => 'quay.io/pterodactyl/voice:ts3', - 'executable' => './ts3server_minimal_runscript.sh', - 'startup' => 'default_voice_port={{SERVER_PORT}} query_port={{SERVER_PORT}}', + 'config_startup' => '{"done": "listening on 0.0.0.0:", "userInteraction": []}', + 'config_files' => '{"ts3server.ini":{"parser": "ini", "find":{"default_voice_port": "{{server.build.default.port}}", "voice_ip": "0.0.0.0", "query_port": "{{server.build.default.port}}", "query_ip": "0.0.0.0"}}}', + 'config_logs' => '{"custom": true, "location": "logs/ts3.log"}', + 'config_stop' => '^C', + 'config_from' => null, + 'startup' => './ts3server_minimal_runscript.sh default_voice_port={{SERVER_PORT}} query_port={{SERVER_PORT}}', ]); } private function addVariables() { - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['mumble']->id, + 'env_variable' => 'MAX_USERS', + ], [ 'name' => 'Maximum Users', 'description' => 'Maximum concurrent users on the mumble server.', - 'env_variable' => 'MAX_USERS', - 'default_value' => '100', + 'default_value' => 100, 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(\d){1,6}$/', + 'rules' => 'required|numeric|digits_between:1,5', ]); - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['mumble']->id, + 'env_variable' => 'MUMBLE_VERSION', + ], [ 'name' => 'Server Version', 'description' => 'Version of Mumble Server to download and use.', - 'env_variable' => 'MUMBLE_VERSION', - 'default_value' => '1.2.16', + 'default_value' => '1.2.19', 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^([0-9_\.-]{5,8})$/', + 'rules' => 'required|regex:/^([0-9_\.-]{5,8})$/', ]); - Models\ServiceVariable::create([ + ServiceVariable::updateOrCreate([ 'option_id' => $this->option['ts3']->id, + 'env_variable' => 'T_VERSION', + ], [ 'name' => 'Server Version', 'description' => 'The version of Teamspeak 3 to use when running the server.', - 'env_variable' => 'T_VERSION', - 'default_value' => '3.0.13.4', + 'default_value' => '3.1.1.1', 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^([0-9_\.-]{5,10})$/', + 'rules' => 'required|regex:/^([0-9_\.-]{5,10})$/', ]); } } From 63029bb39694b5bf36d3dd174a1ff7b5a2a6a5c4 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 12 Mar 2017 18:05:30 -0400 Subject: [PATCH 329/599] Clean old migration. New seeder method allows most all of this migration to occur in the seeder, aside from renaming a few duplicate keys. --- ...03_10_173607_MigrateToNewServiceSystem.php | 186 ++---------------- 1 file changed, 14 insertions(+), 172 deletions(-) diff --git a/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php b/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php index 75d775185..471ad8078 100644 --- a/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php +++ b/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php @@ -27,8 +27,6 @@ use Illuminate\Database\Migrations\Migration; class MigrateToNewServiceSystem extends Migration { - protected $services; - /** * Run the migrations. * @@ -36,12 +34,21 @@ class MigrateToNewServiceSystem extends Migration */ public function up() { - $this->services = Service::where('author', 'ptrdctyl-v040-11e6-8b77-86f30ca893d3')->get(); + $service = Service::where('author', config('pterodactyl.service.core'))->where('folder', 'srcds')->first(); + if (! $service) { + return; + } - $this->minecraft(); - $this->srcds(); - $this->terraria(); - $this->voice(); + $options = ServiceOption::where('service_id', $service->id)->get(); + $options->each(function ($item) use ($options) { + if ($item->tag === 'srcds' && $item->name === 'Insurgency') { + $item->tag = 'insurgency'; + } elseif ($item->tag === 'srcds' && $item->name === 'Team Fortress 2') { + $item->tag = 'tf2'; + } elseif ($item->tag === 'srcds' && $item->name === 'Custom Source Engine Game') { + $item->tag = 'source'; + } + }); } /** @@ -53,169 +60,4 @@ class MigrateToNewServiceSystem extends Migration { // Not doing reversals right now... } - - public function minecraft() - { - $service = $this->services->where('folder', 'minecraft')->first(); - if (! $service) { - return; - } - - // Set New Default Startup - $service->startup = 'java -Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}'; - - DB::transaction(function () use ($service) { - $options = ServiceOption::where('service_id', $service->id)->get(); - $options->each(function ($item) use ($options) { - switch ($item->tag) { - case 'vanilla': - $item->config_startup = '{"done": ")! For help, type ", "userInteraction": [ "Go to eula.txt for more info."]}'; - $item->config_files = '{"server.properties":{"parser": "properties", "find":{"server-ip": "0.0.0.0", "enable-query": "true", "server-port": "{{server.build.default.port}}", "query.port": "{{server.build.default.port}}"}}}'; - $item->config_logs = '{"custom": false, "location": "logs/latest.log"}'; - $item->config_stop = 'stop'; - break; - case 'spigot': - $item->startup = null; - $item->config_from = $options->where('tag', 'vanilla')->pluck('id')->pop(); - $item->config_files = '{"spigot.yml":{"parser": "yaml", "find":{"settings.restart-on-crash": "false"}}}'; - break; - case 'bungeecord': - $item->config_startup = '{"done": "Listening on ", "userInteraction": [ "Listening on /0.0.0.0:25577"]}'; - $item->config_files = '{"config.yml":{"parser": "yaml", "find":{"listeners[0].query_enabled": true, "listeners[0].query_port": "{{server.build.default.port}}", "listeners[0].host": "0.0.0.0:{{server.build.default.port}}", "servers.*.address":{"127.0.0.1": "{{config.docker.interface}}", "localhost": "{{config.docker.interface}}"}}}}'; - $item->config_logs = '{"custom": false, "location": "proxy.log.0"}'; - $item->config_stop = 'end'; - break; - case 'sponge': - $item->startup = null; - $item->config_from = $options->where('tag', 'vanilla')->pluck('id')->pop(); - $item->config_startup = '{"userInteraction": [ "You need to agree to the EULA"]}'; - break; - default: - break; - } - - $item->save(); - }); - - $service->save(); - }); - } - - public function srcds() - { - $service = $this->services->where('folder', 'srcds')->first(); - if (! $service) { - return; - } - - $service->startup = './srcds_run -game {{SRCDS_GAME}} -console -port {{SERVER_PORT}} +ip 0.0.0.0 -strictportbind -norestart'; - - DB::transaction(function () use ($service) { - $options = ServiceOption::where('service_id', $service->id)->get(); - $options->each(function ($item) use ($options) { - if ($item->tag === 'srcds' && $item->name === 'Insurgency') { - $item->tag = 'insurgency'; - } elseif ($item->tag === 'srcds' && $item->name === 'Team Fortress 2') { - $item->tag = 'tf2'; - } elseif ($item->tag === 'srcds' && $item->name === 'Custom Source Engine Game') { - $item->tag = 'source'; - } - - switch ($item->tag) { - case 'source': - $item->config_startup = '{"done": "Assigned anonymous gameserver", "userInteraction": []}'; - $item->config_files = '{}'; - $item->config_logs = '{"custom": true, "location": "logs/latest.log"}'; - $item->config_stop = 'quit'; - break; - case 'insurgency': - case 'tf2': - $item->startup = './srcds_run -game {{SRCDS_GAME}} -console -port {{SERVER_PORT}} +map {{SRCDS_MAP}} +ip 0.0.0.0 -strictportbind -norestart'; - $item->config_from = $options->where('name', 'Custom Source Engine Game')->pluck('id')->pop(); - break; - case 'ark': - $item->startup = './ShooterGame/Binaries/Linux/ShooterGameServer TheIsland?listen?ServerPassword={{ARK_PASSWORD}}?ServerAdminPassword={{ARK_ADMIN_PASSWORD}}?Port={{SERVER_PORT}}?MaxPlayers={{SERVER_MAX_PLAYERS}}'; - $item->config_from = $options->where('name', 'Custom Source Engine Game')->pluck('id')->pop(); - $item->config_startup = '{"done": "Setting breakpad minidump AppID"}'; - $item->config_stop = '^C'; - break; - default: - break; - } - - $item->save(); - }); - - $service->save(); - }); - } - - public function terraria() - { - $service = $this->services->where('folder', 'terraria')->first(); - if (! $service) { - return; - } - - $service->startup = 'mono TerrariaServer.exe -port {{SERVER_PORT}} -autocreate 2 -worldname World'; - - DB::transaction(function () use ($service) { - $options = ServiceOption::where('service_id', $service->id)->get(); - $options->each(function ($item) use ($options) { - switch ($item->tag) { - case 'tshock': - $item->startup = null; - $item->config_startup = '{"done": "Type \'help\' for a list of commands", "userInteraction": []}'; - $item->config_files = '{"tshock/config.json":{"parser": "json", "find":{"ServerPort": "{{server.build.default.port}}", "MaxSlots": "{{server.build.env.MAX_SLOTS}}"}}}'; - $item->config_logs = '{"custom": false, "location": "ServerLog.txt"}'; - $item->config_stop = 'exit'; - break; - default: - break; - } - - $item->save(); - }); - - $service->save(); - }); - } - - public function voice() - { - $service = $this->services->where('folder', 'voice')->first(); - if (! $service) { - return; - } - - $service->startup = null; - - DB::transaction(function () use ($service) { - $options = ServiceOption::where('service_id', $service->id)->get(); - $options->each(function ($item) use ($options) { - switch ($item->tag) { - case 'mumble': - $item->startup = './murmur.x86 -fg'; - $item->config_startup = '{"done": "Server listening on", "userInteraction": [ "Generating new server certificate"]}'; - $item->config_files = '{"murmur.ini":{"parser": "ini", "find":{"logfile": "murmur.log", "port": "{{server.build.default.port}}", "host": "0.0.0.0", "users": "{{server.build.env.MAX_USERS}}"}}}'; - $item->config_logs = '{"custom": true, "location": "logs/murmur.log"}'; - $item->config_stop = '^C'; - break; - case 'ts3': - $item->startup = './ts3server_minimal_runscript.sh default_voice_port={{SERVER_PORT}} query_port={{SERVER_PORT}}'; - $item->config_startup = '{"done": "listening on 0.0.0.0:", "userInteraction": []}'; - $item->config_files = '{"ts3server.ini":{"parser": "ini", "find":{"default_voice_port": "{{server.build.default.port}}", "voice_ip": "0.0.0.0", "query_port": "{{server.build.default.port}}", "query_ip": "0.0.0.0"}}}'; - $item->config_logs = '{"custom": true, "location": "logs/ts3.log"}'; - $item->config_stop = '^C'; - break; - default: - break; - } - - $item->save(); - }); - - $service->save(); - }); - } } From d67f65bb71067584f86a230f6f743559d7301828 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 12 Mar 2017 18:26:36 -0400 Subject: [PATCH 330/599] Attempt to properly handle new start lines on servers for migration --- ...5_212803_DeleteServiceExecutableOption.php | 28 ++++++++++++--- ..._10_162934_AddNewServiceOptionsColumns.php | 36 +++++++++---------- ...03_10_173607_MigrateToNewServiceSystem.php | 28 ++++++++------- 3 files changed, 54 insertions(+), 38 deletions(-) diff --git a/database/migrations/2017_03_05_212803_DeleteServiceExecutableOption.php b/database/migrations/2017_03_05_212803_DeleteServiceExecutableOption.php index 374219539..5a1df2afb 100644 --- a/database/migrations/2017_03_05_212803_DeleteServiceExecutableOption.php +++ b/database/migrations/2017_03_05_212803_DeleteServiceExecutableOption.php @@ -13,11 +13,29 @@ class DeleteServiceExecutableOption extends Migration */ public function up() { - Schema::table('services', function (Blueprint $table) { - $table->dropColumn('executable'); - $table->renameColumn('file', 'folder'); - $table->text('description')->nullable()->change(); - $table->text('startup')->nullable()->change(); + DB::transaction(function () { + Schema::table('services', function (Blueprint $table) { + $table->renameColumn('file', 'folder'); + $table->text('description')->nullable()->change(); + $table->text('startup')->nullable()->change(); + }); + + // Attempt to fix any startup commands for servers + // that we possibly can. + foreach (ServiceOption::with('servers')->get() as $option) { + $option->servers->each(function ($s) use ($option) { + $prepend = $option->display_executable; + $prepend = ($prepend === './ShooterGameServer') ? './ShooterGame/Binaries/Linux/ShooterGameServer' : $prepend; + $prepend = ($prepend === 'TerrariaServer.exe') ? 'mono TerrariaServer.exe' : $prepend; + + $s->startup = $prepend . ' ' . $s->startup; + $s->save(); + }); + } + + Schema::table('services', function (Blueprint $table) { + $table->dropColumn('executable'); + }); }); } diff --git a/database/migrations/2017_03_10_162934_AddNewServiceOptionsColumns.php b/database/migrations/2017_03_10_162934_AddNewServiceOptionsColumns.php index 71af419b0..f2c50cdd7 100644 --- a/database/migrations/2017_03_10_162934_AddNewServiceOptionsColumns.php +++ b/database/migrations/2017_03_10_162934_AddNewServiceOptionsColumns.php @@ -13,18 +13,16 @@ class AddNewServiceOptionsColumns extends Migration */ public function up() { - DB::transaction(function () { - Schema::table('service_options', function (Blueprint $table) { - $table->dropColumn('executable'); + Schema::table('service_options', function (Blueprint $table) { + $table->dropColumn('executable'); - $table->unsignedInteger('config_from')->nullable()->after('docker_image'); - $table->string('config_stop')->nullable()->after('docker_image'); - $table->text('config_logs')->nullable()->after('docker_image'); - $table->text('config_startup')->nullable()->after('docker_image'); - $table->text('config_files')->nullable()->after('docker_image'); + $table->unsignedInteger('config_from')->nullable()->after('docker_image'); + $table->string('config_stop')->nullable()->after('docker_image'); + $table->text('config_logs')->nullable()->after('docker_image'); + $table->text('config_startup')->nullable()->after('docker_image'); + $table->text('config_files')->nullable()->after('docker_image'); - $table->foreign('config_from')->references('id')->on('service_options'); - }); + $table->foreign('config_from')->references('id')->on('service_options'); }); } @@ -35,18 +33,16 @@ class AddNewServiceOptionsColumns extends Migration */ public function down() { - DB::transaction(function () { - Schema::table('service_options', function (Blueprint $table) { - $table->dropForeign('config_from'); + Schema::table('service_options', function (Blueprint $table) { + $table->dropForeign('config_from'); - $table->dropColumn('config_from'); - $table->dropColumn('config_stop'); - $table->dropColumn('config_logs'); - $table->dropColumn('config_startup'); - $table->dropColumn('config_files'); + $table->dropColumn('config_from'); + $table->dropColumn('config_stop'); + $table->dropColumn('config_logs'); + $table->dropColumn('config_startup'); + $table->dropColumn('config_files'); - $table->string('executable')->after('docker_image')->nullable(); - }); + $table->string('executable')->after('docker_image')->nullable(); }); } } diff --git a/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php b/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php index 471ad8078..9f935fff8 100644 --- a/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php +++ b/database/migrations/2017_03_10_173607_MigrateToNewServiceSystem.php @@ -34,20 +34,22 @@ class MigrateToNewServiceSystem extends Migration */ public function up() { - $service = Service::where('author', config('pterodactyl.service.core'))->where('folder', 'srcds')->first(); - if (! $service) { - return; - } - - $options = ServiceOption::where('service_id', $service->id)->get(); - $options->each(function ($item) use ($options) { - if ($item->tag === 'srcds' && $item->name === 'Insurgency') { - $item->tag = 'insurgency'; - } elseif ($item->tag === 'srcds' && $item->name === 'Team Fortress 2') { - $item->tag = 'tf2'; - } elseif ($item->tag === 'srcds' && $item->name === 'Custom Source Engine Game') { - $item->tag = 'source'; + DB::transaction(function () { + $service = Service::where('author', config('pterodactyl.service.core'))->where('folder', 'srcds')->first(); + if (! $service) { + return; } + + $options = ServiceOption::where('service_id', $service->id)->get(); + $options->each(function ($item) use ($options) { + if ($item->tag === 'srcds' && $item->name === 'Insurgency') { + $item->tag = 'insurgency'; + } elseif ($item->tag === 'srcds' && $item->name === 'Team Fortress 2') { + $item->tag = 'tf2'; + } elseif ($item->tag === 'srcds' && $item->name === 'Custom Source Engine Game') { + $item->tag = 'source'; + } + }); }); } From 66e94dd7c04b369b958236a8eac0302384075b26 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 12 Mar 2017 18:31:56 -0400 Subject: [PATCH 331/599] combine validation --- app/Repositories/OptionRepository.php | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/app/Repositories/OptionRepository.php b/app/Repositories/OptionRepository.php index b5e9510c1..80a0a52a7 100644 --- a/app/Repositories/OptionRepository.php +++ b/app/Repositories/OptionRepository.php @@ -130,7 +130,9 @@ class OptionRepository 'config_from' => 'sometimes|required|numeric|exists:service_options,id', ]); - $validator->sometimes('config_startup', 'required_without:config_from|json', function ($input) use ($option) { + $validator->sometimes([ + 'config_startup', 'config_logs', 'config_files', + ], 'required_without:config_from|json', function ($input) use ($option) { return ! (! $input->config_from && ! is_null($option->config_from)); }); @@ -138,14 +140,6 @@ class OptionRepository return ! (! $input->config_from && ! is_null($option->config_from)); }); - $validator->sometimes('config_logs', 'required_without:config_from|json', function ($input) use ($option) { - return ! (! $input->config_from && ! is_null($option->config_from)); - }); - - $validator->sometimes('config_files', 'required_without:config_from|json', function ($input) use ($option) { - return ! (! $input->config_from && ! is_null($option->config_from)); - }); - if ($validator->fails()) { throw new DisplayValidationException($validator->errors()); } From fcadee7e673f68aa1c36b0f5a55bb6aeb92f475e Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 12 Mar 2017 19:34:06 -0400 Subject: [PATCH 332/599] Fix front and backend views with new service variable setups --- .../Controllers/Admin/ServersController.php | 2 + .../Controllers/Server/ServerController.php | 41 ++++++------------- app/Models/Server.php | 2 +- app/Models/ServerVariable.php | 30 ++++++++++++++ app/Models/ServiceOption.php | 11 ----- app/Models/ServiceVariable.php | 28 ++++++++++--- app/Repositories/ServerRepository.php | 24 ++++++----- app/Repositories/VariableRepository.php | 2 - ..._ChangeServiceVariablesValidationRules.php | 5 +++ .../seeds/MinecraftServiceTableSeeder.php | 2 +- resources/lang/en/server.php | 2 +- .../admin/servers/view/startup.blade.php | 7 +--- .../services/options/variables.blade.php | 2 - .../server/settings/startup.blade.php | 39 +++++++----------- 14 files changed, 104 insertions(+), 93 deletions(-) diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 6b1808516..56dfdbad3 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -493,6 +493,8 @@ class ServersController extends Controller $repo->updateStartup($id, $request->except('_token'), true); Alert::success('Startup variables were successfully modified and assigned for this server.')->flash(); + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.servers.view.startup', $id)->withErrors(json_decode($ex->getMessage())); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); } catch (TransferException $ex) { diff --git a/app/Http/Controllers/Server/ServerController.php b/app/Http/Controllers/Server/ServerController.php index 7be93ff61..c2a597928 100644 --- a/app/Http/Controllers/Server/ServerController.php +++ b/app/Http/Controllers/Server/ServerController.php @@ -209,37 +209,20 @@ class ServerController extends Controller public function getStartup(Request $request, $uuid) { $server = Models\Server::byUuid($uuid); - $server->load(['allocations' => function ($query) use ($server) { - $query->where('id', $server->allocation_id); - }]); + $server->load(['node', 'allocation', 'variables.variable']); + $this->authorize('view-startup', $server); - $variables = Models\ServiceVariable::select( - 'service_variables.*', - DB::raw('COALESCE(server_variables.variable_value, service_variables.default_value) as a_serverValue') - )->leftJoin('server_variables', 'server_variables.variable_id', '=', 'service_variables.id') - ->where('service_variables.option_id', $server->option_id) - ->where('server_variables.server_id', $server->id) - ->get(); - - $service = Models\Service::select( - DB::raw('IFNULL(service_options.executable, services.executable) as executable') - )->leftJoin('service_options', 'service_options.service_id', '=', 'services.id') - ->where('service_options.id', $server->option_id) - ->where('services.id', $server->service_id) - ->first(); - - $allocation = $server->allocations->pop(); - $ServerVariable = [ + $replacements = [ '{{SERVER_MEMORY}}' => $server->memory, - '{{SERVER_IP}}' => $allocation->ip, - '{{SERVER_PORT}}' => $allocation->port, + '{{SERVER_IP}}' => $server->allocation->ip, + '{{SERVER_PORT}}' => $server->allocation->port, ]; - $processed = str_replace(array_keys($ServerVariable), array_values($ServerVariable), $server->startup); - foreach ($variables as &$variable) { - $replace = ($variable->user_viewable === 1) ? $variable->a_serverValue : '[hidden]'; - $processed = str_replace('{{' . $variable->env_variable . '}}', $replace, $processed); + $processed = str_replace(array_keys($replacements), array_values($replacements), $server->startup); + foreach ($server->variables as $v) { + $replace = ($v->user_can_view) ? $v->variable_value : '[hidden]'; + $processed = str_replace('{{' . $v->variable->env_variable . '}}', $replace, $processed); } $server->js(); @@ -247,8 +230,8 @@ class ServerController extends Controller return view('server.settings.startup', [ 'server' => $server, 'node' => $server->node, - 'variables' => $variables->where('user_viewable', 1), - 'service' => $service, + 'variables' => $server->variables->where('user_can_view', true), + 'service' => $server->service, 'processedStartup' => $processed, ]); } @@ -311,6 +294,8 @@ class ServerController extends Controller $repo = new ServerRepository; $repo->updateStartup($server->id, $request->except('_token')); Alert::success('Server startup variables were successfully updated.')->flash(); + } catch (DisplayValidationException $ex) { + return redirect()->route('server.settings.startup', $uuid)->withErrors(json_decode($ex->getMessage())); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); } catch (\Exception $ex) { diff --git a/app/Models/Server.php b/app/Models/Server.php index 524708cde..4e0ae9e2c 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -111,7 +111,7 @@ class Server extends Model * @param string $uuid The Short-UUID of the server to return an object about. * @return \Illuminate\Database\Eloquent\Collection */ - public static function byUuid($uuid) + public static function byUuid($uuid, array $with = [], array $withCount = []) { if (! Auth::check()) { throw new \Exception('You must call Server:byUuid as an authenticated user.'); diff --git a/app/Models/ServerVariable.php b/app/Models/ServerVariable.php index e92c5caf2..165d5b3df 100644 --- a/app/Models/ServerVariable.php +++ b/app/Models/ServerVariable.php @@ -52,6 +52,36 @@ class ServerVariable extends Model 'variable_id' => 'integer', ]; + /** + * Determine if variable is viewable by users. + * + * @return bool + */ + public function getUserCanViewAttribute() + { + return (bool) $this->variable->user_viewable; + } + + /** + * Determine if variable is editable by users. + * + * @return bool + */ + public function getUserCanEditAttribute() + { + return (bool) $this->variable->user_editable; + } + + /** + * Determine if variable is required. + * + * @return bool + */ + public function getRequiredAttribute() + { + return $this->variable->required; + } + /** * Returns information about a given variables parent. * diff --git a/app/Models/ServiceOption.php b/app/Models/ServiceOption.php index adf646d88..521efef39 100644 --- a/app/Models/ServiceOption.php +++ b/app/Models/ServiceOption.php @@ -51,17 +51,6 @@ class ServiceOption extends Model 'service_id' => 'integer', ]; - /** - * Returns the display executable for the option and will use the parent - * service one if the option does not have one defined. - * - * @return string - */ - public function getDisplayExecutableAttribute($value) - { - return (is_null($this->executable)) ? $this->service->executable : $this->executable; - } - /** * Returns the display startup string for the option and will use the parent * service one if the option does not have one defined. diff --git a/app/Models/ServiceVariable.php b/app/Models/ServiceVariable.php index aedfc6351..7e35e48dc 100644 --- a/app/Models/ServiceVariable.php +++ b/app/Models/ServiceVariable.php @@ -47,13 +47,29 @@ class ServiceVariable extends Model * * @var array */ - protected $casts = [ - 'option_id' => 'integer', - 'user_viewable' => 'integer', - 'user_editable' => 'integer', - 'required' => 'integer', - ]; + protected $casts = [ + 'option_id' => 'integer', + 'user_viewable' => 'integer', + 'user_editable' => 'integer', + 'required' => 'integer', + ]; + /** + * Returns the display executable for the option and will use the parent + * service one if the option does not have one defined. + * + * @return string + */ + public function getRequiredAttribute($value) + { + return ($this->rules === 'required' || str_contains($this->rules, ['required|', '|required'])); + } + + /** + * Return server variables associated with this variable. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function serverVariable() { return $this->hasMany(ServerVariable::class, 'variable_id'); diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 0e4e0f099..478bddc11 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -627,23 +627,25 @@ class ServerRepository 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; } - // 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 . ').'); - } + // Perform Field Validation + $validator = Validator::make([ + 'variable_value' => ($set) ? $data['env_' . $variable->id] : null, + ], [ + 'variable_value' => $variable->rules, + ]); + + if ($validator->fails()) { + throw new DisplayValidationException(json_encode( + collect([ + 'notice' => ['There was a validation error with the `' . $variable->name . '` variable.'] + ])->merge($validator->errors()->toArray()) + )); } $svar = Models\ServerVariable::firstOrNew([ diff --git a/app/Repositories/VariableRepository.php b/app/Repositories/VariableRepository.php index 91490b4b1..c707788d3 100644 --- a/app/Repositories/VariableRepository.php +++ b/app/Repositories/VariableRepository.php @@ -80,7 +80,6 @@ class VariableRepository $data['option_id'] = $option->id; $data['user_viewable'] = (in_array('user_viewable', $data['options'])); $data['user_editable'] = (in_array('user_editable', $data['options'])); - $data['required'] = (in_array('required', $data['options'])); // Remove field that isn't used. unset($data['options']); @@ -156,7 +155,6 @@ class VariableRepository $data['user_viewable'] = (in_array('user_viewable', $data['options'])); $data['user_editable'] = (in_array('user_editable', $data['options'])); - $data['required'] = (in_array('required', $data['options'])); // Remove field that isn't used. unset($data['options']); diff --git a/database/migrations/2017_03_11_215455_ChangeServiceVariablesValidationRules.php b/database/migrations/2017_03_11_215455_ChangeServiceVariablesValidationRules.php index a9c1dae84..225a1edc0 100644 --- a/database/migrations/2017_03_11_215455_ChangeServiceVariablesValidationRules.php +++ b/database/migrations/2017_03_11_215455_ChangeServiceVariablesValidationRules.php @@ -24,6 +24,10 @@ class ChangeServiceVariablesValidationRules extends Migration $variable->save(); } }); + + Schema::table('service_variables', function (Blueprint $table) { + $table->dropColumn('required'); + }); } /** @@ -35,6 +39,7 @@ class ChangeServiceVariablesValidationRules extends Migration { Schema::table('service_variables', function (Blueprint $table) { $table->renameColumn('rules', 'regex'); + $table->boolean('required')->default(true)->before('regex'); }); DB::transaction(function () { diff --git a/database/seeds/MinecraftServiceTableSeeder.php b/database/seeds/MinecraftServiceTableSeeder.php index 7595f64bc..0a004947a 100644 --- a/database/seeds/MinecraftServiceTableSeeder.php +++ b/database/seeds/MinecraftServiceTableSeeder.php @@ -246,7 +246,7 @@ EOF; 'user_viewable' => 0, 'user_editable' => 0, 'required' => 0, - 'rules' => 'required|string', + 'rules' => 'string', ]); } diff --git a/resources/lang/en/server.php b/resources/lang/en/server.php index d8cae3ae2..43913b64e 100644 --- a/resources/lang/en/server.php +++ b/resources/lang/en/server.php @@ -234,7 +234,7 @@ return [ 'edit_params' => 'Edit Parameters', 'update' => 'Update Startup Parameters', 'startup_var' => 'Startup Command Variable', - 'startup_regex' => 'Verification Regex', + 'startup_regex' => 'Input Rules', ], 'sftp' => [ 'header' => 'SFTP Configuration', diff --git a/resources/themes/pterodactyl/admin/servers/view/startup.blade.php b/resources/themes/pterodactyl/admin/servers/view/startup.blade.php index 5e4175ad2..61cb650f3 100644 --- a/resources/themes/pterodactyl/admin/servers/view/startup.blade.php +++ b/resources/themes/pterodactyl/admin/servers/view/startup.blade.php @@ -62,10 +62,7 @@
      -
      - {{ $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}}.

      diff --git a/resources/themes/pterodactyl/admin/services/options/variables.blade.php b/resources/themes/pterodactyl/admin/services/options/variables.blade.php index c763e6cee..830bec458 100644 --- a/resources/themes/pterodactyl/admin/services/options/variables.blade.php +++ b/resources/themes/pterodactyl/admin/services/options/variables.blade.php @@ -81,7 +81,6 @@
      @@ -135,7 +134,6 @@
      diff --git a/resources/themes/pterodactyl/server/settings/startup.blade.php b/resources/themes/pterodactyl/server/settings/startup.blade.php index 981d8e60c..b9377fa6e 100644 --- a/resources/themes/pterodactyl/server/settings/startup.blade.php +++ b/resources/themes/pterodactyl/server/settings/startup.blade.php @@ -42,9 +42,8 @@

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

      -
      - {{ $service->executable }} - +
      +
      @can('edit-startup', $server) @@ -56,35 +55,35 @@
      @can('edit-startup', $server) - @foreach($variables as $variable) + @foreach($variables as $v)
      -

      {{ $variable->name }}

      +

      {{ $v->variable->name }}

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

      {{ $variable->description }}

      + class="form-control" type="text" value="{{ old('env_' . $v->id, $v->variable_value) }}" /> +

      {{ $v->variable->description }}

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

      @@ -97,14 +96,4 @@ @section('footer-scripts') @parent {!! Theme::js('js/frontend/server.socket.js') !!} - @endsection From 668dc9216a682fab45e3e504d5a88bf4bc3df857 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 12 Mar 2017 19:36:13 -0400 Subject: [PATCH 333/599] Update seeders to reflect removed table column --- database/seeds/MinecraftServiceTableSeeder.php | 9 --------- database/seeds/SourceServiceTableSeeder.php | 11 ----------- database/seeds/TerrariaServiceTableSeeder.php | 2 -- database/seeds/VoiceServiceTableSeeder.php | 3 --- 4 files changed, 25 deletions(-) diff --git a/database/seeds/MinecraftServiceTableSeeder.php b/database/seeds/MinecraftServiceTableSeeder.php index 0a004947a..d1e7b844a 100644 --- a/database/seeds/MinecraftServiceTableSeeder.php +++ b/database/seeds/MinecraftServiceTableSeeder.php @@ -190,7 +190,6 @@ EOF; 'default_value' => 'server.jar', 'user_viewable' => 1, 'user_editable' => 1, - 'required' => 1, 'rules' => 'required|regex:/^([\w\d._-]+)(\.jar)$/', ]); @@ -203,7 +202,6 @@ EOF; 'default_value' => 'latest', 'user_viewable' => 1, 'user_editable' => 1, - 'required' => 1, 'rules' => 'required|string|between:3,7', ]); } @@ -219,7 +217,6 @@ EOF; 'default_value' => 'server.jar', 'user_viewable' => 1, 'user_editable' => 1, - 'required' => 1, 'rules' => 'required|regex:/^([\w\d._-]+)(\.jar)$/', ]); @@ -232,7 +229,6 @@ EOF; 'default_value' => 'latest', 'user_viewable' => 1, 'user_editable' => 1, - 'required' => 1, 'rules' => 'required|string|between:3,7', ]); @@ -245,7 +241,6 @@ EOF; 'default_value' => '', 'user_viewable' => 0, 'user_editable' => 0, - 'required' => 0, 'rules' => 'string', ]); } @@ -261,7 +256,6 @@ EOF; 'default_value' => '1.10.2-5.2.0-BETA-381', 'user_viewable' => 1, 'user_editable' => 0, - 'required' => 1, 'rules' => 'required|regex:/^([a-zA-Z0-9.\-_]+)$/', ]); @@ -274,7 +268,6 @@ EOF; 'default_value' => 'server.jar', 'user_viewable' => 1, 'user_editable' => 1, - 'required' => 1, 'rules' => 'required|regex:/^([\w\d._-]+)(\.jar)$/', ]); } @@ -290,7 +283,6 @@ EOF; 'default_value' => 'latest', 'user_viewable' => 1, 'user_editable' => 1, - 'required' => 1, 'rules' => 'required|alpha_num|between:1,6', ]); @@ -303,7 +295,6 @@ EOF; 'default_value' => 'bungeecord.jar', 'user_viewable' => 1, 'user_editable' => 1, - 'required' => 1, 'rules' => 'required|regex:/^([\w\d._-]+)(\.jar)$/', ]); } diff --git a/database/seeds/SourceServiceTableSeeder.php b/database/seeds/SourceServiceTableSeeder.php index d565d27d6..08e941ed5 100644 --- a/database/seeds/SourceServiceTableSeeder.php +++ b/database/seeds/SourceServiceTableSeeder.php @@ -149,7 +149,6 @@ class SourceServiceTableSeeder extends Seeder 'default_value' => '17705', 'user_viewable' => 1, 'user_editable' => 0, - 'required' => 1, 'rules' => 'required|regex:/^(17705)$/', ]); @@ -162,7 +161,6 @@ class SourceServiceTableSeeder extends Seeder 'default_value' => 'insurgency', 'user_viewable' => 1, 'user_editable' => 0, - 'required' => 1, 'rules' => 'required|regex:/^(insurgency)$/', ]); @@ -175,7 +173,6 @@ class SourceServiceTableSeeder extends Seeder 'default_value' => 'sinjar', 'user_viewable' => 1, 'user_editable' => 1, - 'required' => 1, 'rules' => 'required|regex:/^(\w{1,20})$/', ]); } @@ -191,7 +188,6 @@ class SourceServiceTableSeeder extends Seeder 'default_value' => '232250', 'user_viewable' => 1, 'user_editable' => 0, - 'required' => 1, 'rules' => 'required|regex:/^(232250)$/', ]); @@ -204,7 +200,6 @@ class SourceServiceTableSeeder extends Seeder 'default_value' => 'tf', 'user_viewable' => 1, 'user_editable' => 0, - 'required' => 1, 'rules' => 'required|regex:/^(tf)$/', ]); @@ -217,7 +212,6 @@ class SourceServiceTableSeeder extends Seeder 'default_value' => 'cp_dustbowl', 'user_viewable' => 1, 'user_editable' => 1, - 'required' => 1, 'rules' => 'required|regex:/^(\w{1,20})$/', ]); } @@ -233,7 +227,6 @@ class SourceServiceTableSeeder extends Seeder 'default_value' => '', 'user_viewable' => 1, 'user_editable' => 1, - 'required' => 0, 'rules' => 'alpha_dash|between:1,100', ]); @@ -246,7 +239,6 @@ class SourceServiceTableSeeder extends Seeder 'default_value' => '', 'user_viewable' => 1, 'user_editable' => 1, - 'required' => 0, 'rules' => 'alpha_dash|between:1,100', ]); @@ -259,7 +251,6 @@ class SourceServiceTableSeeder extends Seeder 'default_value' => 20, 'user_viewable' => 1, 'user_editable' => 1, - 'required' => 1, 'rules' => 'required|numeric|digits_between:1,4', ]); } @@ -275,7 +266,6 @@ class SourceServiceTableSeeder extends Seeder 'default_value' => '', 'user_viewable' => 1, 'user_editable' => 0, - 'required' => 1, 'rules' => 'required|numeric|digits_between:1,6', ]); @@ -288,7 +278,6 @@ class SourceServiceTableSeeder extends Seeder 'default_value' => '', 'user_viewable' => 1, 'user_editable' => 0, - 'required' => 1, 'rules' => 'required|alpha_dash|between:1,100', ]); } diff --git a/database/seeds/TerrariaServiceTableSeeder.php b/database/seeds/TerrariaServiceTableSeeder.php index 9bc442738..036e42e0e 100644 --- a/database/seeds/TerrariaServiceTableSeeder.php +++ b/database/seeds/TerrariaServiceTableSeeder.php @@ -95,7 +95,6 @@ class TerrariaServiceTableSeeder extends Seeder 'default_value' => '4.3.22', 'user_viewable' => 1, 'user_editable' => 1, - 'required' => 1, 'rules' => 'required|regex:/^([0-9_\.-]{5,10})$/', ]); @@ -108,7 +107,6 @@ class TerrariaServiceTableSeeder extends Seeder 'default_value' => 20, 'user_viewable' => 1, 'user_editable' => 0, - 'required' => 1, 'rules' => 'required|numeric|digits_between:1,3', ]); } diff --git a/database/seeds/VoiceServiceTableSeeder.php b/database/seeds/VoiceServiceTableSeeder.php index 22b02b95e..2e1c26a8b 100644 --- a/database/seeds/VoiceServiceTableSeeder.php +++ b/database/seeds/VoiceServiceTableSeeder.php @@ -110,7 +110,6 @@ class VoiceServiceTableSeeder extends Seeder 'default_value' => 100, 'user_viewable' => 1, 'user_editable' => 0, - 'required' => 1, 'rules' => 'required|numeric|digits_between:1,5', ]); @@ -123,7 +122,6 @@ class VoiceServiceTableSeeder extends Seeder 'default_value' => '1.2.19', 'user_viewable' => 1, 'user_editable' => 1, - 'required' => 1, 'rules' => 'required|regex:/^([0-9_\.-]{5,8})$/', ]); @@ -136,7 +134,6 @@ class VoiceServiceTableSeeder extends Seeder 'default_value' => '3.1.1.1', 'user_viewable' => 1, 'user_editable' => 1, - 'required' => 1, 'rules' => 'required|regex:/^([0-9_\.-]{5,10})$/', ]); } From 2d90187c83b77b4d38ffd02cec7b11f9421dfba8 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 12 Mar 2017 19:38:50 -0400 Subject: [PATCH 334/599] StyleCI fixes --- app/Http/Controllers/Server/ServerController.php | 1 - app/Models/ServiceVariable.php | 13 ++++++------- app/Repositories/ServerRepository.php | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/Server/ServerController.php b/app/Http/Controllers/Server/ServerController.php index c2a597928..c1514e334 100644 --- a/app/Http/Controllers/Server/ServerController.php +++ b/app/Http/Controllers/Server/ServerController.php @@ -24,7 +24,6 @@ namespace Pterodactyl\Http\Controllers\Server; -use DB; use Log; use Uuid; use Alert; diff --git a/app/Models/ServiceVariable.php b/app/Models/ServiceVariable.php index 7e35e48dc..0e7746312 100644 --- a/app/Models/ServiceVariable.php +++ b/app/Models/ServiceVariable.php @@ -42,16 +42,15 @@ class ServiceVariable extends Model */ protected $guarded = ['id', 'created_at', 'updated_at']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'option_id' => 'integer', 'user_viewable' => 'integer', 'user_editable' => 'integer', - 'required' => 'integer', ]; /** @@ -62,7 +61,7 @@ class ServiceVariable extends Model */ public function getRequiredAttribute($value) { - return ($this->rules === 'required' || str_contains($this->rules, ['required|', '|required'])); + return $this->rules === 'required' || str_contains($this->rules, ['required|', '|required']); } /** diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 478bddc11..51806042c 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -643,7 +643,7 @@ class ServerRepository if ($validator->fails()) { throw new DisplayValidationException(json_encode( collect([ - 'notice' => ['There was a validation error with the `' . $variable->name . '` variable.'] + 'notice' => ['There was a validation error with the `' . $variable->name . '` variable.'], ])->merge($validator->errors()->toArray()) )); } From 50558db7c3a1d9d7ba25ebc3e72cba1dd53ba7d8 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 14 Mar 2017 21:18:36 -0400 Subject: [PATCH 335/599] Add initial pack creation and overview pages --- app/Http/Controllers/Admin/PackController.php | 233 +++++++----------- .../Controllers/Daemon/PackController.php | 4 +- app/Http/Routes/AdminRoutes.php | 52 ++-- app/Models/Pack.php | 100 ++++++++ app/Models/Server.php | 77 +++--- app/Models/Service.php | 2 +- app/Models/ServiceOption.php | 2 +- app/Models/ServicePack.php | 69 ------ app/Models/User.php | 5 + app/Repositories/PackRepository.php | 124 ++++++---- app/Repositories/ServerRepository.php | 2 +- ...5631_RenameServicePacksToSingluarPacks.php | 44 ++++ ...17_03_14_200326_AddLockedStatusToTable.php | 32 +++ public/js/laroute.js | 2 +- public/themes/pterodactyl/css/checkbox.css | 231 +++++++++++++++++ public/themes/pterodactyl/css/pterodactyl.css | 6 + .../pterodactyl/admin/packs/index.blade.php | 84 +++++++ .../pterodactyl/admin/packs/modal.blade.php | 47 ++++ .../pterodactyl/admin/packs/new.blade.php | 158 ++++++++++++ .../admin/services/packs/byoption.blade.php | 90 ------- .../admin/services/packs/byservice.blade.php | 67 ----- 21 files changed, 944 insertions(+), 487 deletions(-) create mode 100644 app/Models/Pack.php delete mode 100644 app/Models/ServicePack.php create mode 100644 database/migrations/2017_03_14_175631_RenameServicePacksToSingluarPacks.php create mode 100644 database/migrations/2017_03_14_200326_AddLockedStatusToTable.php create mode 100644 public/themes/pterodactyl/css/checkbox.css create mode 100644 resources/themes/pterodactyl/admin/packs/index.blade.php create mode 100644 resources/themes/pterodactyl/admin/packs/modal.blade.php create mode 100644 resources/themes/pterodactyl/admin/packs/new.blade.php delete mode 100644 resources/views/admin/services/packs/byoption.blade.php delete mode 100644 resources/views/admin/services/packs/byservice.blade.php diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php index f4e577d0e..1ef60b8c8 100644 --- a/app/Http/Controllers/Admin/PackController.php +++ b/app/Http/Controllers/Admin/PackController.php @@ -27,179 +27,124 @@ namespace Pterodactyl\Http\Controllers\Admin; use Log; use Alert; use Storage; -use Pterodactyl\Models; use Illuminate\Http\Request; +use Pterodactyl\Models\Pack; +use Pterodactyl\Models\Service; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Http\Controllers\Controller; -use Pterodactyl\Repositories\ServiceRepository\Pack; +use Pterodactyl\Repositories\PackRepository; use Pterodactyl\Exceptions\DisplayValidationException; class PackController extends Controller { - public function __construct() + /** + * Display listing of all packs on the system. + * + * @param Request $request + * @return \Illuminate\View\View + */ + public function index(Request $request) { - // + $packs = Pack::with('option')->withCount('servers'); + + if (! is_null($request->input('query'))) { + $packs->search($request->input('query')); + } + + return view('admin.packs.index', ['packs' => $packs->paginate(50)]); } - public function listAll(Request $request) + /** + * Display new pack creation form. + * + * @param Request $request + * @return \Illuminate\View\View + */ + public function new(Request $request) { - return view('admin.services.packs.index', ['services' => Models\Service::all()]); - } - - public function listByOption(Request $request, $id) - { - return view('admin.services.packs.byoption', [ - 'option' => Models\ServiceOption::with('service', 'packs')->findOrFail($id), + return view('admin.packs.new', [ + 'services' => Service::with('options')->get(), ]); } - public function listByService(Request $request, $id) + /** + * Display new pack creation modal for use with template upload. + * + * @param Request $request + * @return \Illuminate\View\View + */ + public function newTemplate(Request $request) { - return view('admin.services.packs.byservice', [ - 'service' => Models\Service::with('options', 'options.packs')->findOrFail($id), - ]); - } - - public function new(Request $request, $opt = null) - { - return view('admin.services.packs.new', [ - 'services' => Models\Service::with('options')->get(), + return view('admin.packs.modal', [ + 'services' => Service::with('options')->get(), ]); } public function create(Request $request) { + $repo = new PackRepository; + try { - $repo = new Pack; - $pack = $repo->create($request->only([ - 'name', 'version', 'description', - 'option', 'selectable', 'visible', - 'file_upload', - ])); - Alert::success('Successfully created new service!')->flash(); - - return redirect()->route('admin.services.packs.edit', $pack->id)->withInput(); - } catch (DisplayValidationException $ex) { - return redirect()->route('admin.services.packs.new', $request->input('option'))->withErrors(json_decode($ex->getMessage()))->withInput(); - } catch (DisplayException $ex) { - Alert::danger($ex->getMessage())->flash(); - } catch (\Exception $ex) { - Log::error($ex); - Alert::danger('An error occured while attempting to add a new service pack.')->flash(); - } - - return redirect()->route('admin.services.packs.new', $request->input('option'))->withInput(); - } - - public function edit(Request $request, $id) - { - $pack = Models\ServicePack::with('option.service')->findOrFail($id); - - return view('admin.services.packs.edit', [ - 'pack' => $pack, - 'services' => Models\Service::all()->load('options'), - 'files' => Storage::files('packs/' . $pack->uuid), - ]); - } - - public function update(Request $request, $id) - { - if (! is_null($request->input('action_delete'))) { - try { - $repo = new Pack; - $repo->delete($id); - Alert::success('The requested service pack has been deleted from the system.')->flash(); - - return redirect()->route('admin.services.packs'); - } catch (DisplayException $ex) { - Alert::danger($ex->getMessage())->flash(); - } catch (\Exception $ex) { - Log::error($ex); - Alert::danger('An error occured while attempting to delete this pack.')->flash(); - } - - return redirect()->route('admin.services.packs.edit', $id); - } else { - try { - $repo = new Pack; - $repo->update($id, $request->only([ - 'name', 'version', 'description', - 'option', 'selectable', 'visible', + if ($request->input('action') === 'from_template') { + $pack = $repo->createWithTemplate($request->intersect(['option_id', 'file_upload'])); + } else { + $pack = $repo->create($request->intersect([ + 'name', 'description', 'version', 'option_id', + 'selectable', 'visible', 'locked', 'file_upload', ])); - Alert::success('Service pack has been successfully updated.')->flash(); - } catch (DisplayValidationException $ex) { - return redirect()->route('admin.services.packs.edit', $id)->withErrors(json_decode($ex->getMessage()))->withInput(); - } catch (\Exception $ex) { - Log::error($ex); - Alert::danger('An error occured while attempting to add edit this pack.')->flash(); } + Alert::success('Pack successfully created on the system.')->flash(); - return redirect()->route('admin.services.packs.edit', $id); - } - } - - public function export(Request $request, $id, $files = false) - { - $pack = Models\ServicePack::findOrFail($id); - $json = [ - 'name' => $pack->name, - 'version' => $pack->version, - 'description' => $pack->dscription, - 'selectable' => (bool) $pack->selectable, - 'visible' => (bool) $pack->visible, - ]; - - $filename = tempnam(sys_get_temp_dir(), 'pterodactyl_'); - if ((bool) $files) { - $zip = new \ZipArchive; - if (! $zip->open($filename, \ZipArchive::CREATE)) { - abort(503, 'Unable to open file for writing.'); - } - - $files = Storage::files('packs/' . $pack->uuid); - foreach ($files as $file) { - $zip->addFile(storage_path('app/' . $file), basename(storage_path('app/' . $file))); - } - - $zip->addFromString('import.json', json_encode($json, JSON_PRETTY_PRINT)); - $zip->close(); - - return response()->download($filename, 'pack-' . $pack->name . '.zip')->deleteFileAfterSend(true); - } else { - $fp = fopen($filename, 'a+'); - fwrite($fp, json_encode($json, JSON_PRETTY_PRINT)); - fclose($fp); - - return response()->download($filename, 'pack-' . $pack->name . '.json', [ - 'Content-Type' => 'application/json', - ])->deleteFileAfterSend(true); - } - } - - public function uploadForm(Request $request, $for = null) - { - return view('admin.services.packs.upload', [ - 'services' => Models\Service::all()->load('options'), - ]); - } - - public function postUpload(Request $request) - { - try { - $repo = new Pack; - $pack = $repo->createWithTemplate($request->only(['option', 'file_upload'])); - Alert::success('Successfully created new service!')->flash(); - - return redirect()->route('admin.services.packs.edit', $pack->id)->withInput(); - } catch (DisplayValidationException $ex) { - return redirect()->back()->withErrors(json_decode($ex->getMessage()))->withInput(); + return redirect()->route('admin.packs.view', $pack->id); + } catch(DisplayValidationException $ex) { + return redirect()->route('admin.packs.new')->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); } catch (\Exception $ex) { Log::error($ex); - Alert::danger('An error occured while attempting to add a new service pack.')->flash(); + Alert::danger('An error occured while attempting to add a new service pack. This error has been logged.')->flash(); } - return redirect()->back(); + return redirect()->route('admin.packs.new')->withInput(); } + + + // public function export(Request $request, $id, $files = false) + // { + // $pack = Models\Pack::findOrFail($id); + // $json = [ + // 'name' => $pack->name, + // 'version' => $pack->version, + // 'description' => $pack->dscription, + // 'selectable' => (bool) $pack->selectable, + // 'visible' => (bool) $pack->visible, + // ]; + + // $filename = tempnam(sys_get_temp_dir(), 'pterodactyl_'); + // if ((bool) $files) { + // $zip = new \ZipArchive; + // if (! $zip->open($filename, \ZipArchive::CREATE)) { + // abort(503, 'Unable to open file for writing.'); + // } + + // $files = Storage::files('packs/' . $pack->uuid); + // foreach ($files as $file) { + // $zip->addFile(storage_path('app/' . $file), basename(storage_path('app/' . $file))); + // } + + // $zip->addFromString('import.json', json_encode($json, JSON_PRETTY_PRINT)); + // $zip->close(); + + // return response()->download($filename, 'pack-' . $pack->name . '.zip')->deleteFileAfterSend(true); + // } else { + // $fp = fopen($filename, 'a+'); + // fwrite($fp, json_encode($json, JSON_PRETTY_PRINT)); + // fclose($fp); + + // return response()->download($filename, 'pack-' . $pack->name . '.json', [ + // 'Content-Type' => 'application/json', + // ])->deleteFileAfterSend(true); + // } + // } + } diff --git a/app/Http/Controllers/Daemon/PackController.php b/app/Http/Controllers/Daemon/PackController.php index e96aa6ee5..4d35f6d77 100644 --- a/app/Http/Controllers/Daemon/PackController.php +++ b/app/Http/Controllers/Daemon/PackController.php @@ -47,7 +47,7 @@ class PackController extends Controller */ public function pull(Request $request, $uuid) { - $pack = Models\ServicePack::where('uuid', $uuid)->first(); + $pack = Models\Pack::where('uuid', $uuid)->first(); if (! $pack) { return response()->json(['error' => 'No such pack.'], 404); @@ -68,7 +68,7 @@ class PackController extends Controller */ public function hash(Request $request, $uuid) { - $pack = Models\ServicePack::where('uuid', $uuid)->first(); + $pack = Models\Pack::where('uuid', $uuid)->first(); if (! $pack) { return response()->json(['error' => 'No such pack.'], 404); diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index 634568728..f714f632d 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -453,43 +453,27 @@ class AdminRoutes 'csrf', ], ], function () use ($router) { - // $router->get('/new/{option?}', [ - // 'as' => 'admin.packs.new', - // 'uses' => 'Admin\PackController@new', - // ]); - // $router->post('/new', [ - // 'uses' => 'Admin\PackController@create', - // ]); - // $router->get('/upload/{option?}', [ - // 'as' => 'admin.packs.uploadForm', - // 'uses' => 'Admin\PackController@uploadForm', - // ]); - // $router->post('/upload', [ - // 'uses' => 'Admin\PackController@postUpload', - // ]); $router->get('/', [ 'as' => 'admin.packs', - 'uses' => 'Admin\PackController@listAll', + 'uses' => 'Admin\PackController@index', + ]); + + $router->get('/new', [ + 'as' => 'admin.packs.new', + 'uses' => 'Admin\PackController@new', + ]); + + $router->post('/new', 'Admin\PackController@create'); + + $router->get('/new/template', [ + 'as' => 'admin.packs.new.template', + 'uses' => 'Admin\PackController@newTemplate', + ]); + + $router->get('/view/{id}', [ + 'as' => 'admin.packs.view', + 'uses' => 'Admin\PackController@view', ]); - // $router->get('/for/option/{option}', [ - // 'as' => 'admin.packs.option', - // 'uses' => 'Admin\PackController@listByOption', - // ]); - // $router->get('/for/service/{service}', [ - // 'as' => 'admin.packs.service', - // 'uses' => 'Admin\PackController@listByService', - // ]); - // $router->get('/edit/{pack}', [ - // 'as' => 'admin.packs.edit', - // 'uses' => 'Admin\PackController@edit', - // ]); - // $router->post('/edit/{pack}', [ - // 'uses' => 'Admin\PackController@update', - // ]); - // $router->get('/edit/{pack}/export/{archive?}', [ - // 'as' => 'admin.packs.export', - // 'uses' => 'Admin\PackController@export', - // ]); }); } } diff --git a/app/Models/Pack.php b/app/Models/Pack.php new file mode 100644 index 000000000..5675fb25a --- /dev/null +++ b/app/Models/Pack.php @@ -0,0 +1,100 @@ +. + * + * 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\Models; + +use Illuminate\Database\Eloquent\Model; +use Nicolaslopezj\Searchable\SearchableTrait; + +class Pack extends Model +{ + use SearchableTrait; + + /** + * The table associated with the model. + * + * @var string + */ + protected $table = 'packs'; + + /** + * Fields that are mass assignable. + * + * @var array + */ + protected $fillable = [ + 'option_id', 'name', 'version', 'description', 'selectable', 'visible', 'locked', + ]; + + /** + * Cast values to correct type. + * + * @var array + */ + protected $casts = [ + 'option_id' => 'integer', + 'selectable' => 'boolean', + 'visible' => 'boolean', + 'locked' => 'boolean', + ]; + + /** + * Parameters for search querying. + * + * @var array + */ + protected $searchable = [ + 'columns' => [ + 'packs.name' => 10, + 'packs.uuid' => 8, + 'service_options.name' => 6, + 'service_options.tag' => 5, + 'service_options.docker_image' => 5, + 'packs.version' => 2, + ], + 'joins' => [ + 'service_options' => ['packs.option_id', 'service_options.id'], + ], + ]; + + /** + * Gets option associated with a service pack. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function option() + { + return $this->belongsTo(ServiceOption::class); + } + + /** + * Gets servers associated with a pack. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function servers() + { + return $this->hasMany(Server::class); + } +} diff --git a/app/Models/Server.php b/app/Models/Server.php index 4e0ae9e2c..c341aad70 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -65,43 +65,50 @@ class Server extends Model */ protected $guarded = ['id', 'installed', 'created_at', 'updated_at', 'deleted_at']; - /** - * Cast values to correct type. - * - * @var array - */ - protected $casts = [ - 'node_id' => 'integer', - 'suspended' => 'integer', - 'owner_id' => 'integer', - 'memory' => 'integer', - 'swap' => 'integer', - 'disk' => 'integer', - 'io' => 'integer', - 'cpu' => 'integer', - 'oom_disabled' => 'integer', - 'allocation_id' => 'integer', - 'service_id' => 'integer', - 'option_id' => 'integer', - 'pack_id' => 'integer', - 'installed' => 'integer', - ]; + /** + * Cast values to correct type. + * + * @var array + */ + protected $casts = [ + 'node_id' => 'integer', + 'suspended' => 'integer', + 'owner_id' => 'integer', + 'memory' => 'integer', + 'swap' => 'integer', + 'disk' => 'integer', + 'io' => 'integer', + 'cpu' => 'integer', + 'oom_disabled' => 'integer', + 'allocation_id' => 'integer', + 'service_id' => 'integer', + 'option_id' => 'integer', + 'pack_id' => 'integer', + 'installed' => 'integer', + ]; + /** + * Parameters for search querying. + * + * @var array + */ protected $searchable = [ - 'columns' => [ - 'servers.name' => 10, - 'servers.username' => 10, - 'servers.uuidShort' => 9, - 'servers.uuid' => 8, - 'users.email' => 6, - 'users.username' => 6, - 'nodes.name' => 2, - ], - 'joins' => [ + 'columns' => [ + 'servers.name' => 10, + 'servers.username' => 10, + 'servers.uuidShort' => 9, + 'servers.uuid' => 8, + 'packs.name' => 7, + 'users.email' => 6, + 'users.username' => 6, + 'nodes.name' => 2, + ], + 'joins' => [ + 'packs' => ['packs.id', 'servers.pack_id'], 'users' => ['users.id', 'servers.owner_id'], 'nodes' => ['nodes.id', 'servers.node_id'], - ], - ]; + ], + ]; /** * Returns a single server specified by UUID. @@ -236,11 +243,11 @@ class Server extends Model /** * Gets information for the pack associated with this server. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function pack() { - return $this->hasOne(ServicePack::class, 'id', 'pack_id'); + return $this->belongsTo(Pack::class); } /** diff --git a/app/Models/Service.php b/app/Models/Service.php index 245587afd..b05366882 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -105,7 +105,7 @@ EOF; public function packs() { return $this->hasManyThrough( - 'Pterodactyl\Models\ServicePack', 'Pterodactyl\Models\ServiceOption', + 'Pterodactyl\Models\Pack', 'Pterodactyl\Models\ServiceOption', 'service_id', 'option_id' ); } diff --git a/app/Models/ServiceOption.php b/app/Models/ServiceOption.php index 521efef39..a0f76df23 100644 --- a/app/Models/ServiceOption.php +++ b/app/Models/ServiceOption.php @@ -99,6 +99,6 @@ class ServiceOption extends Model */ public function packs() { - return $this->hasMany(ServicePack::class, 'option_id'); + return $this->hasMany(Pack::class, 'option_id'); } } diff --git a/app/Models/ServicePack.php b/app/Models/ServicePack.php deleted file mode 100644 index e82f72411..000000000 --- a/app/Models/ServicePack.php +++ /dev/null @@ -1,69 +0,0 @@ -. - * - * 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\Models; - -use Illuminate\Database\Eloquent\Model; - -class ServicePack extends Model -{ - /** - * The table associated with the model. - * - * @var string - */ - protected $table = 'service_packs'; - - /** - * Fields that are not mass assignable. - * - * @var array - */ - protected $guarded = ['id', 'created_at', 'updated_at']; - - /** - * Cast values to correct type. - * - * @var array - */ - protected $casts = [ - 'option' => 'integer', - 'build_memory' => 'integer', - 'build_swap' => 'integer', - 'build_cpu' => 'integer', - 'build_io' => 'integer', - 'selectable' => 'boolean', - 'visible' => 'boolean', - ]; - - /** - * Gets option associated with a service pack. - * - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function option() - { - return $this->belongsTo(ServiceOption::class); - } -} diff --git a/app/Models/User.php b/app/Models/User.php index cb78ad4a8..62ced4e72 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -88,6 +88,11 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac */ protected $hidden = ['password', 'remember_token', 'totp_secret']; + /** + * Parameters for search querying. + * + * @var array + */ protected $searchable = [ 'columns' => [ 'email' => 10, diff --git a/app/Repositories/PackRepository.php b/app/Repositories/PackRepository.php index 842bfdac6..3fc6b2571 100644 --- a/app/Repositories/PackRepository.php +++ b/app/Repositories/PackRepository.php @@ -28,31 +28,36 @@ use DB; use Uuid; use Storage; use Validator; -use Pterodactyl\Models; +use Pterodactyl\Models\Pack; use Pterodactyl\Services\UuidService; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayValidationException; class PackRepository { - public function __construct() - { - // - } - + /** + * Creates a new pack on the system. + * + * @param array $data + * @return \Pterodactyl\Models\Pack + * + * @throws \Pterodactyl\Exceptions\DisplayException + * @throws \Pterodactyl\Exceptions\DisplayValidationException + */ public function create(array $data) { $validator = Validator::make($data, [ 'name' => 'required|string', 'version' => 'required|string', 'description' => 'sometimes|nullable|string', - 'option' => 'required|exists:service_options,id', - 'selectable' => 'sometimes|boolean', - 'visible' => 'sometimes|boolean', + 'selectable' => 'sometimes|required|boolean', + 'visible' => 'sometimes|required|boolean', + 'locked' => 'sometimes|required|boolean', + 'option_id' => 'required|exists:service_options,id', ]); if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } if (isset($data['file_upload'])) { @@ -65,33 +70,42 @@ class PackRepository } } - DB::beginTransaction(); - try { - $uuid = new UuidService; - $pack = Models\ServicePack::create([ - 'option_id' => $data['option'], - 'uuid' => $uuid->generate('service_packs', 'uuid'), + return DB::transaction(function () use ($data) { + $uuid = new UuidService(); + + $pack = new Pack; + $pack->uuid = $uuid->generate('packs', 'uuid'); + $pack->fill([ + 'option_id' => $data['option_id'], 'name' => $data['name'], 'version' => $data['version'], 'description' => (empty($data['description'])) ? null : $data['description'], 'selectable' => isset($data['selectable']), 'visible' => isset($data['visible']), - ]); + 'locked' => isset($data['locked']), + ])->save(); + + if (! $pack->exists) { + throw new DisplayException('Model does not exist after creation. Did an event prevent it from saving?'); + } Storage::makeDirectory('packs/' . $pack->uuid); if (isset($data['file_upload'])) { $data['file_upload']->storeAs('packs/' . $pack->uuid, 'archive.tar.gz'); } - DB::commit(); - } catch (\Exception $ex) { - DB::rollBack(); - throw $ex; - } - - return $pack; + return $pack; + }); } + /** + * Creates a new pack on the system given a template file. + * + * @param array $data + * @return \Pterodactyl\Models\Pack + * + * @throws \Pterodactyl\Exceptions\DisplayException + */ public function createWithTemplate(array $data) { if (! isset($data['file_upload'])) { @@ -127,9 +141,10 @@ class PackRepository 'name' => $json->name, 'version' => $json->version, 'description' => $json->description, - 'option' => $data['option'], + 'option_id' => $data['option_id'], 'selectable' => $json->selectable, 'visible' => $json->visible, + 'locked' => $json->locked, ]); if (! $zip->extractTo(storage_path('app/packs/' . $pack->uuid), 'archive.tar.gz')) { @@ -147,42 +162,67 @@ class PackRepository 'name' => $json->name, 'version' => $json->version, 'description' => $json->description, - 'option' => $data['option'], + 'option_id' => $data['option_id'], 'selectable' => $json->selectable, 'visible' => $json->visible, + 'locked' => $json->locked, ]); } } + /** + * Updates a pack on the system. + * + * @param int $id + * @param array $data + * @return \Pterodactyl\Models\Pack + * + * @throws \Pterodactyl\Exceptions\DisplayValidationException + */ public function update($id, array $data) { $validator = Validator::make($data, [ - 'name' => 'required|string', - 'version' => 'required|string', - 'description' => 'string', - 'option' => 'required|exists:service_options,id', - 'selectable' => 'sometimes|boolean', - 'visible' => 'sometimes|boolean', + 'name' => 'sometimes|required|string', + 'version' => 'sometimes|required|string', + 'description' => 'sometimes|string', + 'selectable' => 'sometimes|required|boolean', + 'visible' => 'sometimes|required|boolean', + 'locked' => 'sometimes|required|boolean', ]); if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } - Models\ServicePack::findOrFail($id)->update([ - 'option_id' => $data['option'], - 'name' => $data['name'], - 'version' => $data['version'], + $pack = Pack::findOrFail($id); + $pack->fill([ + 'name' => isset($data['name']) ? $data['name'] : $pack->name, + 'version' => isset($data['version']) ? $data['version'] : $pack->version, 'description' => (empty($data['description'])) ? null : $data['description'], - 'selectable' => isset($data['selectable']), - 'visible' => isset($data['visible']), - ]); + 'selectable' => isset($data['selectable']) ? $data['selectable'] : $data->selectable, + 'visible' => isset($data['visible']) ? $data['visible'] : $data->visible, + 'locked' => isset($data['locked']) ? $data['locked'] : $data->locked, + ])->save(); + + return $pack; } + /** + * Deletes a pack and files from the system. + * + * @param int $id + * @return void + * + * @throws \Pterodactyl\Exceptions\DisplayException + */ public function delete($id) { - $pack = Models\ServicePack::findOrFail($id); - // @TODO Check for linked servers; foreign key should block this. + $pack = Models\Pack::withCount('servers')->findOrFail($id); + + if ($pack->servers_count > 0) { + throw new DisplayException('Cannot delete a pack from the system if servers are assocaited with it.'); + } + DB::transaction(function () use ($pack) { $pack->delete(); Storage::deleteDirectory('packs/' . $pack->uuid); diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 51806042c..f95d45431 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -156,7 +156,7 @@ class ServerRepository if (! isset($data['pack_id']) || (int) $data['pack_id'] < 1) { $data['pack_id'] = null; } else { - $pack = Models\ServicePack::where('id', $data['pack_id'])->where('option_id', $data['option_id'])->first(); + $pack = Models\Pack::where('id', $data['pack_id'])->where('option_id', $data['option_id'])->first(); if (! $pack) { throw new DisplayException('The requested service pack does not seem to exist for this combination.'); } diff --git a/database/migrations/2017_03_14_175631_RenameServicePacksToSingluarPacks.php b/database/migrations/2017_03_14_175631_RenameServicePacksToSingluarPacks.php new file mode 100644 index 000000000..910fb79df --- /dev/null +++ b/database/migrations/2017_03_14_175631_RenameServicePacksToSingluarPacks.php @@ -0,0 +1,44 @@ +dropForeign(['option_id']); + }); + + Schema::rename('service_packs', 'packs'); + + Schema::table('packs', function (Blueprint $table) { + $table->foreign('option_id')->references('id')->on('service_options'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('packs', function (Blueprint $table) { + $table->dropForeign(['option_id']); + }); + + Schema::rename('packs', 'service_packs'); + + Schema::table('service_packs', function (Blueprint $table) { + $table->foreign('option_id')->references('id')->on('service_options'); + }); + } +} diff --git a/database/migrations/2017_03_14_200326_AddLockedStatusToTable.php b/database/migrations/2017_03_14_200326_AddLockedStatusToTable.php new file mode 100644 index 000000000..4916cd028 --- /dev/null +++ b/database/migrations/2017_03_14_200326_AddLockedStatusToTable.php @@ -0,0 +1,32 @@ +boolean('locked')->default(false)->after('visible'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('packs', function (Blueprint $table) { + $table->dropColumn('locked'); + }); + } +} diff --git a/public/js/laroute.js b/public/js/laroute.js index b4f553912..dde3acaf8 100644 --- a/public/js/laroute.js +++ b/public/js/laroute.js @@ -6,7 +6,7 @@ absolute: false, rootUrl: 'http://pterodactyl.app', - routes : [{"host":null,"methods":["GET","HEAD"],"uri":"admin","name":"admin.index","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/settings","name":"admin.settings","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getSettings"},{"host":null,"methods":["POST"],"uri":"admin\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\BaseController@postSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users","name":"admin.users","action":"Pterodactyl\Http\Controllers\Admin\UserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/accounts.json","name":"admin.users.json","action":"Pterodactyl\Http\Controllers\Admin\UserController@getJson"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/view\/{id}","name":"admin.users.view","action":"Pterodactyl\Http\Controllers\Admin\UserController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@updateUser"},{"host":null,"methods":["DELETE"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@deleteUser"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/new","name":"admin.users.new","action":"Pterodactyl\Http\Controllers\Admin\UserController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers","name":"admin.servers","action":"Pterodactyl\Http\Controllers\Admin\ServersController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/new","name":"admin.servers.new","action":"Pterodactyl\Http\Controllers\Admin\ServersController@new"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@create"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/nodes","name":"admin.servers.new.nodes","action":"Pterodactyl\Http\Controllers\Admin\ServersController@newServerNodes"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}","name":"admin.servers.view","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/details","name":"admin.servers.view.details","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@setDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details\/container","name":"admin.servers.view.details.container","action":"Pterodactyl\Http\Controllers\Admin\ServersController@setContainer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/build","name":"admin.servers.view.build","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/build","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@updateBuild"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/startup","name":"admin.servers.view.startup","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewStartup"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@saveStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/database","name":"admin.servers.view.database","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDatabase"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/database","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@newDatabase"},{"host":null,"methods":["PATCH"],"uri":"admin\/servers\/view\/{id}\/database","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@resetDatabasePassword"},{"host":null,"methods":["DELETE"],"uri":"admin\/servers\/view\/{id}\/database\/{database}\/delete","name":"admin.servers.view.database.delete","action":"Pterodactyl\Http\Controllers\Admin\ServersController@deleteDatabase"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/manage","name":"admin.servers.view.manage","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewManage"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/toggle","name":"admin.servers.view.manage.toggle","action":"Pterodactyl\Http\Controllers\Admin\ServersController@toggleInstall"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/rebuild","name":"admin.servers.view.manage.rebuild","action":"Pterodactyl\Http\Controllers\Admin\ServersController@rebuildContainer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/suspension","name":"admin.servers.view.manage.suspension","action":"Pterodactyl\Http\Controllers\Admin\ServersController@manageSuspension"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/delete","name":"admin.servers.view.delete","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDelete"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@delete"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete\/continue\/{force?}","name":"admin.servers.view.delete.continue","action":"Pterodactyl\Http\Controllers\Admin\ServersController@continueDeletion"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete\/cancel","name":"admin.servers.view.delete.cancel","action":"Pterodactyl\Http\Controllers\Admin\ServersController@cancelDeletion"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes","name":"admin.nodes","action":"Pterodactyl\Http\Controllers\Admin\NodesController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/new","name":"admin.nodes.new","action":"Pterodactyl\Http\Controllers\Admin\NodesController@new"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.view","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings","name":"admin.nodes.view.settings","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewSettings"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@updateSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/configuration","name":"admin.nodes.view.configuration","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":"admin.nodes.view.allocation","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewAllocation"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@createAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/servers","name":"admin.nodes.view.servers","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewServers"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/delete","name":"admin.nodes.view.delete","action":"Pterodactyl\Http\Controllers\Admin\NodesController@delete"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove\/{allocation}","name":"admin.nodes.view.allocation.removeSingle","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveSingle"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove","name":"admin.nodes.view.allocation.removeBlock","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveBlock"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/alias","name":"admin.nodes.view.allocation.setAlias","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationSetAlias"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings\/token","name":"admin.nodes.view.configuration.token","action":"Pterodactyl\Http\Controllers\Admin\NodesController@setToken"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/locations","name":"admin.locations","action":"Pterodactyl\Http\Controllers\Admin\LocationsController@getIndex"},{"host":null,"methods":["DELETE"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@deleteLocation"},{"host":null,"methods":["PATCH"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@patchLocation"},{"host":null,"methods":["POST"],"uri":"admin\/locations","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@postLocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases","name":"admin.databases","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases\/new","name":"admin.databases.new","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/databases\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@postNew"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete\/{id}","name":"admin.databases.delete","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteDatabase"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete-server\/{id}","name":"admin.databases.delete-server","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteServer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services","name":"admin.services","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/new","name":"admin.services.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/services\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}","name":"admin.services.service","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getService"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postService"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{id}\/configuration","name":"admin.services.service.config","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getConfiguration"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{id}\/configuration","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/new","name":"admin.services.option.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@newOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":"admin.services.option","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getOption"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOption"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/service\/{service}\/option\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":"admin.services.option.variable.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@getNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postNewVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}","name":"admin.services.option.variable","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@postOptionVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/service\/{service}\/option\/{option}\/variable\/{variable}\/delete","name":"admin.services.option.variable.delete","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@deleteVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/new\/{option?}","name":"admin.services.packs.new","action":"Pterodactyl\Http\Controllers\Admin\PackController@new"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/upload\/{option?}","name":"admin.services.packs.uploadForm","action":"Pterodactyl\Http\Controllers\Admin\PackController@uploadForm"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/upload","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@postUpload"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs","name":"admin.services.packs","action":"Pterodactyl\Http\Controllers\Admin\PackController@listAll"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/option\/{option}","name":"admin.services.packs.option","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByOption"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/for\/service\/{service}","name":"admin.services.packs.service","action":"Pterodactyl\Http\Controllers\Admin\PackController@listByService"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}","name":"admin.services.packs.edit","action":"Pterodactyl\Http\Controllers\Admin\PackController@edit"},{"host":null,"methods":["POST"],"uri":"admin\/services\/packs\/edit\/{pack}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/packs\/edit\/{pack}\/export\/{archive?}","name":"admin.services.packs.export","action":"Pterodactyl\Http\Controllers\Admin\PackController@export"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login","name":"auth.login","action":"Pterodactyl\Http\Controllers\Auth\LoginController@showLoginForm"},{"host":null,"methods":["POST"],"uri":"auth\/login","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@login"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login\/totp","name":"auth.totp","action":"Pterodactyl\Http\Controllers\Auth\LoginController@totp"},{"host":null,"methods":["POST"],"uri":"auth\/login\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@totpCheckpoint"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password","name":"auth.password","action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm"},{"host":null,"methods":["POST"],"uri":"auth\/password","name":null,"action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password\/reset\/{token}","name":"auth.reset","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@showResetForm"},{"host":null,"methods":["POST"],"uri":"auth\/password\/reset","name":"auth.reset.post","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@reset"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/logout","name":"auth.logout","action":"Pterodactyl\Http\Controllers\Auth\LoginController@logout"},{"host":null,"methods":["GET","HEAD"],"uri":"\/","name":"index","action":"Pterodactyl\Http\Controllers\Base\IndexController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"index","name":null,"action":"Closure"},{"host":null,"methods":["GET","HEAD"],"uri":"password-gen\/{length}","name":"password-gen","action":"Pterodactyl\Http\Controllers\Base\IndexController@getPassword"},{"host":null,"methods":["GET","HEAD"],"uri":"account","name":"account","action":"Pterodactyl\Http\Controllers\Base\AccountController@index"},{"host":null,"methods":["POST"],"uri":"account","name":null,"action":"Pterodactyl\Http\Controllers\Base\AccountController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api","name":"account.api","action":"Pterodactyl\Http\Controllers\Base\APIController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api\/new","name":"account.api.new","action":"Pterodactyl\Http\Controllers\Base\APIController@create"},{"host":null,"methods":["POST"],"uri":"account\/api\/new","name":null,"action":"Pterodactyl\Http\Controllers\Base\APIController@save"},{"host":null,"methods":["DELETE"],"uri":"account\/api\/revoke\/{key}","name":"account.api.revoke","action":"Pterodactyl\Http\Controllers\Base\APIController@revoke"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security","name":"account.security","action":"Pterodactyl\Http\Controllers\Base\SecurityController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security\/revoke\/{id}","name":"account.security.revoke","action":"Pterodactyl\Http\Controllers\Base\SecurityController@revoke"},{"host":null,"methods":["PUT"],"uri":"account\/security\/totp","name":"account.security.totp","action":"Pterodactyl\Http\Controllers\Base\SecurityController@generateTotp"},{"host":null,"methods":["POST"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@setTotp"},{"host":null,"methods":["DELETE"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@disableTotp"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services","name":"daemon.services","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@list"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services\/pull\/{service}\/{file}","name":"remote.install","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}","name":"daemon.pack.pull","action":"Pterodactyl\Http\Controllers\Daemon\PackController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}\/hash","name":"daemon.pack.hash","action":"Pterodactyl\Http\Controllers\Daemon\PackController@hash"},{"host":null,"methods":["GET","HEAD"],"uri":"language\/{lang}","name":"langauge.set","action":"Pterodactyl\Http\Controllers\Base\LanguageController@setLanguage"},{"host":null,"methods":["POST"],"uri":"remote\/download","name":"remote.download","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postDownload"},{"host":null,"methods":["POST"],"uri":"remote\/install","name":"remote.install","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postInstall"},{"host":null,"methods":["GET","HEAD"],"uri":"remote\/configuration\/{token}","name":"remote.configuration","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@getConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/ajax\/status","name":"server.ajax.status","action":"Pterodactyl\Http\Controllers\Server\AjaxController@getStatus"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}","name":"server.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/databases","name":"server.settings.databases","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDatabases"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/sftp","name":"server.settings.sftp","action":"Pterodactyl\Http\Controllers\Server\ServerController@getSFTP"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/sftp","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsSFTP"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/startup","name":"server.settings.startup","action":"Pterodactyl\Http\Controllers\Server\ServerController@getStartup"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/allocation","name":"server.settings.allocation","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files","name":"server.files.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getFiles"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/edit\/{file}","name":"server.files.edit","action":"Pterodactyl\Http\Controllers\Server\ServerController@getEditFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/download\/{file}","name":"server.files.download","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDownloadFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/add","name":"server.files.add","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAddFile"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/directory-list","name":"server.files.directory-list","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postDirectoryList"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/save","name":"server.files.save","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSaveFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users","name":"server.subusers","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/new","name":"server.subusers.new","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/view\/{id}","name":"server.subusers.view","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getView"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postView"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/users\/delete\/{id}","name":"server.subusers.delete","action":"Pterodactyl\Http\Controllers\Server\SubuserController@deleteSubuser"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks","name":"server.tasks","action":"Pterodactyl\Http\Controllers\Server\TaskController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/view\/{id}","name":"server.tasks.view","action":"Pterodactyl\Http\Controllers\Server\TaskController@getView"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/new","name":"server.tasks.new","action":"Pterodactyl\Http\Controllers\Server\TaskController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\TaskController@postNew"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/tasks\/delete\/{id}","name":"server.tasks.delete","action":"Pterodactyl\Http\Controllers\Server\TaskController@deleteTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/toggle\/{id}","name":"server.tasks.toggle","action":"Pterodactyl\Http\Controllers\Server\TaskController@toggleTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/set-primary","name":null,"action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSetPrimary"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/settings\/reset-database-password","name":"server.ajax.reset-database-password","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postResetDatabasePassword"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/open","name":"debugbar.openhandler","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@handle"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/clockwork\/{id}","name":"debugbar.clockwork","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@clockwork"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/stylesheets","name":"debugbar.assets.css","action":"Barryvdh\Debugbar\Controllers\AssetController@css"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/javascript","name":"debugbar.assets.js","action":"Barryvdh\Debugbar\Controllers\AssetController@js"}], + routes : [{"host":null,"methods":["GET","HEAD"],"uri":"admin","name":"admin.index","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/settings","name":"admin.settings","action":"Pterodactyl\Http\Controllers\Admin\BaseController@getSettings"},{"host":null,"methods":["POST"],"uri":"admin\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\BaseController@postSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users","name":"admin.users","action":"Pterodactyl\Http\Controllers\Admin\UserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/accounts.json","name":"admin.users.json","action":"Pterodactyl\Http\Controllers\Admin\UserController@getJson"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/view\/{id}","name":"admin.users.view","action":"Pterodactyl\Http\Controllers\Admin\UserController@getView"},{"host":null,"methods":["POST"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@updateUser"},{"host":null,"methods":["DELETE"],"uri":"admin\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@deleteUser"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/users\/new","name":"admin.users.new","action":"Pterodactyl\Http\Controllers\Admin\UserController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\UserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers","name":"admin.servers","action":"Pterodactyl\Http\Controllers\Admin\ServersController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/new","name":"admin.servers.new","action":"Pterodactyl\Http\Controllers\Admin\ServersController@new"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@create"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/new\/nodes","name":"admin.servers.new.nodes","action":"Pterodactyl\Http\Controllers\Admin\ServersController@newServerNodes"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}","name":"admin.servers.view","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/details","name":"admin.servers.view.details","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@setDetails"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/details\/container","name":"admin.servers.view.details.container","action":"Pterodactyl\Http\Controllers\Admin\ServersController@setContainer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/build","name":"admin.servers.view.build","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewBuild"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/build","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@updateBuild"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/startup","name":"admin.servers.view.startup","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewStartup"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@saveStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/database","name":"admin.servers.view.database","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDatabase"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/database","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@newDatabase"},{"host":null,"methods":["PATCH"],"uri":"admin\/servers\/view\/{id}\/database","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@resetDatabasePassword"},{"host":null,"methods":["DELETE"],"uri":"admin\/servers\/view\/{id}\/database\/{database}\/delete","name":"admin.servers.view.database.delete","action":"Pterodactyl\Http\Controllers\Admin\ServersController@deleteDatabase"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/manage","name":"admin.servers.view.manage","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewManage"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/toggle","name":"admin.servers.view.manage.toggle","action":"Pterodactyl\Http\Controllers\Admin\ServersController@toggleInstall"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/rebuild","name":"admin.servers.view.manage.rebuild","action":"Pterodactyl\Http\Controllers\Admin\ServersController@rebuildContainer"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/manage\/suspension","name":"admin.servers.view.manage.suspension","action":"Pterodactyl\Http\Controllers\Admin\ServersController@manageSuspension"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/servers\/view\/{id}\/delete","name":"admin.servers.view.delete","action":"Pterodactyl\Http\Controllers\Admin\ServersController@viewDelete"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServersController@delete"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete\/continue\/{force?}","name":"admin.servers.view.delete.continue","action":"Pterodactyl\Http\Controllers\Admin\ServersController@continueDeletion"},{"host":null,"methods":["POST"],"uri":"admin\/servers\/view\/{id}\/delete\/cancel","name":"admin.servers.view.delete.cancel","action":"Pterodactyl\Http\Controllers\Admin\ServersController@cancelDeletion"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes","name":"admin.nodes","action":"Pterodactyl\Http\Controllers\Admin\NodesController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/new","name":"admin.nodes.new","action":"Pterodactyl\Http\Controllers\Admin\NodesController@new"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}","name":"admin.nodes.view","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings","name":"admin.nodes.view.settings","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewSettings"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/settings","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@updateSettings"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/configuration","name":"admin.nodes.view.configuration","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":"admin.nodes.view.allocation","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewAllocation"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation","name":null,"action":"Pterodactyl\Http\Controllers\Admin\NodesController@createAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/servers","name":"admin.nodes.view.servers","action":"Pterodactyl\Http\Controllers\Admin\NodesController@viewServers"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/delete","name":"admin.nodes.view.delete","action":"Pterodactyl\Http\Controllers\Admin\NodesController@delete"},{"host":null,"methods":["DELETE"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove\/{allocation}","name":"admin.nodes.view.allocation.removeSingle","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveSingle"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/remove","name":"admin.nodes.view.allocation.removeBlock","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationRemoveBlock"},{"host":null,"methods":["POST"],"uri":"admin\/nodes\/view\/{id}\/allocation\/alias","name":"admin.nodes.view.allocation.setAlias","action":"Pterodactyl\Http\Controllers\Admin\NodesController@allocationSetAlias"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/nodes\/view\/{id}\/settings\/token","name":"admin.nodes.view.configuration.token","action":"Pterodactyl\Http\Controllers\Admin\NodesController@setToken"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/locations","name":"admin.locations","action":"Pterodactyl\Http\Controllers\Admin\LocationsController@getIndex"},{"host":null,"methods":["DELETE"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@deleteLocation"},{"host":null,"methods":["PATCH"],"uri":"admin\/locations\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@patchLocation"},{"host":null,"methods":["POST"],"uri":"admin\/locations","name":null,"action":"Pterodactyl\Http\Controllers\Admin\LocationsController@postLocation"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases","name":"admin.databases","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/databases\/new","name":"admin.databases.new","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@getNew"},{"host":null,"methods":["POST"],"uri":"admin\/databases\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@postNew"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete\/{id}","name":"admin.databases.delete","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteDatabase"},{"host":null,"methods":["DELETE"],"uri":"admin\/databases\/delete-server\/{id}","name":"admin.databases.delete-server","action":"Pterodactyl\Http\Controllers\Admin\DatabaseController@deleteServer"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services","name":"admin.services","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/new","name":"admin.services.new","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@new"},{"host":null,"methods":["POST"],"uri":"admin\/services\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/view\/{id}","name":"admin.services.view","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@view"},{"host":null,"methods":["POST"],"uri":"admin\/services\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@edit"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/view\/{id}\/functions","name":"admin.services.view.functions","action":"Pterodactyl\Http\Controllers\Admin\ServiceController@viewFunctions"},{"host":null,"methods":["DELETE"],"uri":"admin\/services\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\ServiceController@delete"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/option\/new","name":"admin.services.option.new","action":"Pterodactyl\Http\Controllers\Admin\OptionController@new"},{"host":null,"methods":["POST"],"uri":"admin\/services\/option\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\OptionController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/option\/{id}","name":"admin.services.option.view","action":"Pterodactyl\Http\Controllers\Admin\OptionController@viewConfiguration"},{"host":null,"methods":["POST"],"uri":"admin\/services\/option\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Admin\OptionController@editConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/services\/option\/{id}\/variables","name":"admin.services.option.variables","action":"Pterodactyl\Http\Controllers\Admin\OptionController@viewVariables"},{"host":null,"methods":["POST"],"uri":"admin\/services\/option\/{id}\/variables","name":null,"action":"Pterodactyl\Http\Controllers\Admin\OptionController@createVariable"},{"host":null,"methods":["POST"],"uri":"admin\/services\/option\/{id}\/variables\/{variable}","name":"admin.services.option.variables.edit","action":"Pterodactyl\Http\Controllers\Admin\OptionController@editVariable"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/packs","name":"admin.packs","action":"Pterodactyl\Http\Controllers\Admin\PackController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/packs\/new","name":"admin.packs.new","action":"Pterodactyl\Http\Controllers\Admin\PackController@new"},{"host":null,"methods":["POST"],"uri":"admin\/packs\/new","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@create"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/packs\/new\/template","name":"admin.packs.new.template","action":"Pterodactyl\Http\Controllers\Admin\PackController@newTemplate"},{"host":null,"methods":["POST"],"uri":"admin\/packs\/new\/template","name":null,"action":"Pterodactyl\Http\Controllers\Admin\PackController@createTemplate"},{"host":null,"methods":["GET","HEAD"],"uri":"admin\/packs\/view\/{id}","name":"admin.packs.view","action":"Pterodactyl\Http\Controllers\Admin\PackController@view"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login","name":"auth.login","action":"Pterodactyl\Http\Controllers\Auth\LoginController@showLoginForm"},{"host":null,"methods":["POST"],"uri":"auth\/login","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@login"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/login\/totp","name":"auth.totp","action":"Pterodactyl\Http\Controllers\Auth\LoginController@totp"},{"host":null,"methods":["POST"],"uri":"auth\/login\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Auth\LoginController@totpCheckpoint"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password","name":"auth.password","action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm"},{"host":null,"methods":["POST"],"uri":"auth\/password","name":null,"action":"Pterodactyl\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/password\/reset\/{token}","name":"auth.reset","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@showResetForm"},{"host":null,"methods":["POST"],"uri":"auth\/password\/reset","name":"auth.reset.post","action":"Pterodactyl\Http\Controllers\Auth\ResetPasswordController@reset"},{"host":null,"methods":["GET","HEAD"],"uri":"auth\/logout","name":"auth.logout","action":"Pterodactyl\Http\Controllers\Auth\LoginController@logout"},{"host":null,"methods":["GET","HEAD"],"uri":"\/","name":"index","action":"Pterodactyl\Http\Controllers\Base\IndexController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"index","name":null,"action":"Closure"},{"host":null,"methods":["GET","HEAD"],"uri":"password-gen\/{length}","name":"password-gen","action":"Pterodactyl\Http\Controllers\Base\IndexController@getPassword"},{"host":null,"methods":["GET","HEAD"],"uri":"account","name":"account","action":"Pterodactyl\Http\Controllers\Base\AccountController@index"},{"host":null,"methods":["POST"],"uri":"account","name":null,"action":"Pterodactyl\Http\Controllers\Base\AccountController@update"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api","name":"account.api","action":"Pterodactyl\Http\Controllers\Base\APIController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/api\/new","name":"account.api.new","action":"Pterodactyl\Http\Controllers\Base\APIController@create"},{"host":null,"methods":["POST"],"uri":"account\/api\/new","name":null,"action":"Pterodactyl\Http\Controllers\Base\APIController@save"},{"host":null,"methods":["DELETE"],"uri":"account\/api\/revoke\/{key}","name":"account.api.revoke","action":"Pterodactyl\Http\Controllers\Base\APIController@revoke"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security","name":"account.security","action":"Pterodactyl\Http\Controllers\Base\SecurityController@index"},{"host":null,"methods":["GET","HEAD"],"uri":"account\/security\/revoke\/{id}","name":"account.security.revoke","action":"Pterodactyl\Http\Controllers\Base\SecurityController@revoke"},{"host":null,"methods":["PUT"],"uri":"account\/security\/totp","name":"account.security.totp","action":"Pterodactyl\Http\Controllers\Base\SecurityController@generateTotp"},{"host":null,"methods":["POST"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@setTotp"},{"host":null,"methods":["DELETE"],"uri":"account\/security\/totp","name":null,"action":"Pterodactyl\Http\Controllers\Base\SecurityController@disableTotp"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services","name":"daemon.services","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@list"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/services\/pull\/{service}\/{file}","name":"remote.install","action":"Pterodactyl\Http\Controllers\Daemon\ServiceController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}","name":"daemon.pack.pull","action":"Pterodactyl\Http\Controllers\Daemon\PackController@pull"},{"host":null,"methods":["GET","HEAD"],"uri":"daemon\/packs\/pull\/{uuid}\/hash","name":"daemon.pack.hash","action":"Pterodactyl\Http\Controllers\Daemon\PackController@hash"},{"host":null,"methods":["GET","HEAD"],"uri":"language\/{lang}","name":"langauge.set","action":"Pterodactyl\Http\Controllers\Base\LanguageController@setLanguage"},{"host":null,"methods":["POST"],"uri":"remote\/download","name":"remote.download","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postDownload"},{"host":null,"methods":["POST"],"uri":"remote\/install","name":"remote.install","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@postInstall"},{"host":null,"methods":["GET","HEAD"],"uri":"remote\/configuration\/{token}","name":"remote.configuration","action":"Pterodactyl\Http\Controllers\Remote\RemoteController@getConfiguration"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/ajax\/status","name":"server.ajax.status","action":"Pterodactyl\Http\Controllers\Server\AjaxController@getStatus"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}","name":"server.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/databases","name":"server.settings.databases","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDatabases"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/sftp","name":"server.settings.sftp","action":"Pterodactyl\Http\Controllers\Server\ServerController@getSFTP"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/sftp","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsSFTP"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/startup","name":"server.settings.startup","action":"Pterodactyl\Http\Controllers\Server\ServerController@getStartup"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/settings\/startup","name":null,"action":"Pterodactyl\Http\Controllers\Server\ServerController@postSettingsStartup"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/settings\/allocation","name":"server.settings.allocation","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAllocation"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files","name":"server.files.index","action":"Pterodactyl\Http\Controllers\Server\ServerController@getFiles"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/edit\/{file}","name":"server.files.edit","action":"Pterodactyl\Http\Controllers\Server\ServerController@getEditFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/download\/{file}","name":"server.files.download","action":"Pterodactyl\Http\Controllers\Server\ServerController@getDownloadFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/files\/add","name":"server.files.add","action":"Pterodactyl\Http\Controllers\Server\ServerController@getAddFile"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/directory-list","name":"server.files.directory-list","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postDirectoryList"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/files\/save","name":"server.files.save","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSaveFile"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users","name":"server.subusers","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/new","name":"server.subusers.new","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postNew"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/users\/view\/{id}","name":"server.subusers.view","action":"Pterodactyl\Http\Controllers\Server\SubuserController@getView"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/users\/view\/{id}","name":null,"action":"Pterodactyl\Http\Controllers\Server\SubuserController@postView"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/users\/delete\/{id}","name":"server.subusers.delete","action":"Pterodactyl\Http\Controllers\Server\SubuserController@deleteSubuser"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks","name":"server.tasks","action":"Pterodactyl\Http\Controllers\Server\TaskController@getIndex"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/view\/{id}","name":"server.tasks.view","action":"Pterodactyl\Http\Controllers\Server\TaskController@getView"},{"host":null,"methods":["GET","HEAD"],"uri":"server\/{server}\/tasks\/new","name":"server.tasks.new","action":"Pterodactyl\Http\Controllers\Server\TaskController@getNew"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/new","name":null,"action":"Pterodactyl\Http\Controllers\Server\TaskController@postNew"},{"host":null,"methods":["DELETE"],"uri":"server\/{server}\/tasks\/delete\/{id}","name":"server.tasks.delete","action":"Pterodactyl\Http\Controllers\Server\TaskController@deleteTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/tasks\/toggle\/{id}","name":"server.tasks.toggle","action":"Pterodactyl\Http\Controllers\Server\TaskController@toggleTask"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/set-primary","name":null,"action":"Pterodactyl\Http\Controllers\Server\AjaxController@postSetPrimary"},{"host":null,"methods":["POST"],"uri":"server\/{server}\/ajax\/settings\/reset-database-password","name":"server.ajax.reset-database-password","action":"Pterodactyl\Http\Controllers\Server\AjaxController@postResetDatabasePassword"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/open","name":"debugbar.openhandler","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@handle"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/clockwork\/{id}","name":"debugbar.clockwork","action":"Barryvdh\Debugbar\Controllers\OpenHandlerController@clockwork"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/stylesheets","name":"debugbar.assets.css","action":"Barryvdh\Debugbar\Controllers\AssetController@css"},{"host":null,"methods":["GET","HEAD"],"uri":"_debugbar\/assets\/javascript","name":"debugbar.assets.js","action":"Barryvdh\Debugbar\Controllers\AssetController@js"}], prefix: '', route : function (name, parameters, route) { diff --git a/public/themes/pterodactyl/css/checkbox.css b/public/themes/pterodactyl/css/checkbox.css new file mode 100644 index 000000000..fd4a855ac --- /dev/null +++ b/public/themes/pterodactyl/css/checkbox.css @@ -0,0 +1,231 @@ +/** + * Bootsnip - "Bootstrap Checkboxes/Radios" + * Bootstrap 3.2.0 Snippet by i-heart-php + * + * Copyright (c) 2013 Bootsnipp.com + * + * 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. + */ + .checkbox { + padding-left: 20px; +} +.checkbox label { + display: inline-block; + position: relative; + padding-left: 5px; +} +.checkbox label::before { + content: ""; + display: inline-block; + position: absolute; + width: 17px; + height: 17px; + left: 0; + margin-left: -20px; + border: 1px solid #cccccc; + border-radius: 3px; + background-color: #fff; + -webkit-transition: border 0.15s ease-in-out, color 0.15s ease-in-out; + -o-transition: border 0.15s ease-in-out, color 0.15s ease-in-out; + transition: border 0.15s ease-in-out, color 0.15s ease-in-out; +} +.checkbox label::after { + display: inline-block; + position: absolute; + width: 16px; + height: 16px; + left: 0; + top: 0; + margin-left: -20px; + padding-left: 3px; + padding-top: 1px; + font-size: 11px; + color: #555555; +} +.checkbox input[type="checkbox"] { + opacity: 0; +} +.checkbox input[type="checkbox"]:focus + label::before { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.checkbox input[type="checkbox"]:checked + label::after { + font-family: 'FontAwesome'; + content: "\f00c"; +} +.checkbox input[type="checkbox"]:disabled + label { + opacity: 0.65; +} +.checkbox input[type="checkbox"]:disabled + label::before { + background-color: #eeeeee; + cursor: not-allowed; +} +.checkbox.checkbox-circle label::before { + border-radius: 50%; +} +.checkbox.checkbox-inline { + margin-top: 0; +} +.checkbox-primary input[type="checkbox"]:checked + label::before { + background-color: #428bca; + border-color: #428bca; +} +.checkbox-primary input[type="checkbox"]:checked + label::after { + color: #fff; +} +.checkbox-danger input[type="checkbox"]:checked + label::before { + background-color: #d9534f; + border-color: #d9534f; +} +.checkbox-danger input[type="checkbox"]:checked + label::after { + color: #fff; +} +.checkbox-info input[type="checkbox"]:checked + label::before { + background-color: #5bc0de; + border-color: #5bc0de; +} +.checkbox-info input[type="checkbox"]:checked + label::after { + color: #fff; +} +.checkbox-warning input[type="checkbox"]:checked + label::before { + background-color: #f0ad4e; + border-color: #f0ad4e; +} +.checkbox-warning input[type="checkbox"]:checked + label::after { + color: #fff; +} +.checkbox-success input[type="checkbox"]:checked + label::before { + background-color: #5cb85c; + border-color: #5cb85c; +} +.checkbox-success input[type="checkbox"]:checked + label::after { + color: #fff; +} +.radio { + padding-left: 20px; +} +.radio label { + display: inline-block; + position: relative; + padding-left: 5px; +} +.radio label::before { + content: ""; + display: inline-block; + position: absolute; + width: 17px; + height: 17px; + left: 0; + margin-left: -20px; + border: 1px solid #cccccc; + border-radius: 50%; + background-color: #fff; + -webkit-transition: border 0.15s ease-in-out; + -o-transition: border 0.15s ease-in-out; + transition: border 0.15s ease-in-out; +} +.radio label::after { + display: inline-block; + position: absolute; + content: " "; + width: 11px; + height: 11px; + left: 3px; + top: 3px; + margin-left: -20px; + border-radius: 50%; + background-color: #555555; + -webkit-transform: scale(0, 0); + -ms-transform: scale(0, 0); + -o-transform: scale(0, 0); + transform: scale(0, 0); + -webkit-transition: -webkit-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33); + -moz-transition: -moz-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33); + -o-transition: -o-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33); + transition: transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33); +} +.radio input[type="radio"] { + opacity: 0; +} +.radio input[type="radio"]:focus + label::before { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.radio input[type="radio"]:checked + label::after { + -webkit-transform: scale(1, 1); + -ms-transform: scale(1, 1); + -o-transform: scale(1, 1); + transform: scale(1, 1); +} +.radio input[type="radio"]:disabled + label { + opacity: 0.65; +} +.radio input[type="radio"]:disabled + label::before { + cursor: not-allowed; +} +.radio.radio-inline { + margin-top: 0; +} +.radio-primary input[type="radio"] + label::after { + background-color: #428bca; +} +.radio-primary input[type="radio"]:checked + label::before { + border-color: #428bca; +} +.radio-primary input[type="radio"]:checked + label::after { + background-color: #428bca; +} +.radio-danger input[type="radio"] + label::after { + background-color: #d9534f; +} +.radio-danger input[type="radio"]:checked + label::before { + border-color: #d9534f; +} +.radio-danger input[type="radio"]:checked + label::after { + background-color: #d9534f; +} +.radio-info input[type="radio"] + label::after { + background-color: #5bc0de; +} +.radio-info input[type="radio"]:checked + label::before { + border-color: #5bc0de; +} +.radio-info input[type="radio"]:checked + label::after { + background-color: #5bc0de; +} +.radio-warning input[type="radio"] + label::after { + background-color: #f0ad4e; +} +.radio-warning input[type="radio"]:checked + label::before { + border-color: #f0ad4e; +} +.radio-warning input[type="radio"]:checked + label::after { + background-color: #f0ad4e; +} +.radio-success input[type="radio"] + label::after { + background-color: #5cb85c; +} +.radio-success input[type="radio"]:checked + label::before { + border-color: #5cb85c; +} +.radio-success input[type="radio"]:checked + label::after { + background-color: #5cb85c; +} diff --git a/public/themes/pterodactyl/css/pterodactyl.css b/public/themes/pterodactyl/css/pterodactyl.css index ca34e46a5..9d91c3192 100644 --- a/public/themes/pterodactyl/css/pterodactyl.css +++ b/public/themes/pterodactyl/css/pterodactyl.css @@ -20,6 +20,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + @import 'checkbox.css'; + .login-box, .register-box { width: 40%; margin: 7% auto @@ -266,3 +268,7 @@ span[aria-labelledby="select2-pUserId-container"] { .terminal-notify:hover { opacity: .9; } + +.no-margin-bottom { + margin-bottom: 0 !important; +} diff --git a/resources/themes/pterodactyl/admin/packs/index.blade.php b/resources/themes/pterodactyl/admin/packs/index.blade.php new file mode 100644 index 000000000..a4da22809 --- /dev/null +++ b/resources/themes/pterodactyl/admin/packs/index.blade.php @@ -0,0 +1,84 @@ +{{-- 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') + List Packs +@endsection + +@section('content-header') +

      PacksAll service packs available on the system.

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

      Pack List

      +
      +
      +
      + +
      + + +
      +
      +
      +
      +
      +
      + + + + + + + + + + @foreach ($packs as $pack) + + + + + + + + + @endforeach + +
      IDPack NameVersionDescriptionOption + Servers
      {{ $pack->id }}{{ $pack->name }}{{ $pack->version }}{{ str_limit($pack->description, 150) }}{{ $pack->option->name }}{{ $pack->servers_count }}
      +
      + @if ($packs->hasPages()) + + @endif +
      +
      +
      +@endsection diff --git a/resources/themes/pterodactyl/admin/packs/modal.blade.php b/resources/themes/pterodactyl/admin/packs/modal.blade.php new file mode 100644 index 000000000..fd4263575 --- /dev/null +++ b/resources/themes/pterodactyl/admin/packs/modal.blade.php @@ -0,0 +1,47 @@ + diff --git a/resources/themes/pterodactyl/admin/packs/new.blade.php b/resources/themes/pterodactyl/admin/packs/new.blade.php new file mode 100644 index 000000000..540717ef4 --- /dev/null +++ b/resources/themes/pterodactyl/admin/packs/new.blade.php @@ -0,0 +1,158 @@ +{{-- 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') + Packs → New +@endsection + +@section('content-header') +

      New PackCreate a new pack on the system.

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

      Pack Details

      +
      +
      +
      + + +

      A short but descriptive name of what this pack is. For example, Counter Strike: Source if it is a Counter Strike package.

      +
      +
      + + +
      +
      + + +

      The version of this package, or the version of the files contained within the package.

      +
      +
      + + +

      The option that this pack is assocaited with. Only servers that are assigned this option will be able to access this pack.

      +
      +
      +
      +
      +
      +
      +
      +

      Pack Configuration

      +
      +
      +
      +
      + + +
      +

      Check this box if user should be able to select this pack to install on their servers.

      +
      +
      +
      + + +
      +

      Check this box if this pack is visible in the dropdown menu. If this pack is assigned to a server it will be visible regardless of this setting.

      +
      +
      +
      + + +
      +

      Check this box if servers assigned this pack should not be able to switch to a different pack.

      +
      +
      +
      + + +

      This package file must be a .tar.gz archive of pack files to be decompressed into the server folder.

      +

      If your file is larger than 50MB it is recommended to upload it using SFTP. Once you have added this pack to the system, a path will be provided where you should upload the file.

      +
      +

      This server is currently configured with the following limits:
      upload_max_filesize={{ ini_get('upload_max_filesize') }}
      post_max_size={{ ini_get('post_max_size') }}

      If your file is larger than either of those values this request will fail.

      +
      +
      +
      + +
      +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/views/admin/services/packs/byoption.blade.php b/resources/views/admin/services/packs/byoption.blade.php deleted file mode 100644 index f781a3a3c..000000000 --- a/resources/views/admin/services/packs/byoption.blade.php +++ /dev/null @@ -1,90 +0,0 @@ -{{-- 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') - Service Packs for {{ $option->name }} -@endsection - -@section('content') -
      - -

      Service Packs


      - - - - - - - - - - - - @foreach ($option->packs as $pack) - - - - - - - - @endforeach - - - - -
      Pack NameVersionUUIDSelectableVisible
      {{ $pack->name }}{{ $pack->version }}{{ $pack->uuid }}@if($pack->selectable)@else@endif@if($pack->visible)@else@endif
      - - - - - - -
      -
      - -@endsection diff --git a/resources/views/admin/services/packs/byservice.blade.php b/resources/views/admin/services/packs/byservice.blade.php deleted file mode 100644 index f36ce4e4c..000000000 --- a/resources/views/admin/services/packs/byservice.blade.php +++ /dev/null @@ -1,67 +0,0 @@ -{{-- 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') - Service Packs for {{ $service->name }} -@endsection - -@section('content') -
      - -

      Service Packs


      - - - - - - - - - @foreach ($service->options as $option) - - - - - @endforeach - - - - -
      Service OptionTotal Packs
      {{ $option->name }}{{ $option->packs->count() }}
      - - - - - - -
      -
      - -@endsection From 47303095897a87b9b260084c8baeb4885a693f3c Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 15 Mar 2017 19:47:44 -0400 Subject: [PATCH 336/599] Add IDE helper for all functions --- .gitignore | 4 + app/Providers/AppServiceProvider.php | 4 +- composer.json | 3 +- composer.lock | 175 ++++++++++++++++++++++++++- 4 files changed, 182 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 9f02de4ca..efbbccdcf 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,7 @@ Vagrantfile node_modules yarn.lock node_modules + +_ide_helper_models.php + +_ide_helper.php diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index a1181fb10..5a9a0d925 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -49,6 +49,8 @@ class AppServiceProvider extends ServiceProvider */ public function register() { - // + if ($this->app->environment() !== 'production') { + $this->app->register(\Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class); + } } } diff --git a/composer.json b/composer.json index a95d82df1..a58fc7f82 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,8 @@ "phpunit/phpunit": "~5.0", "symfony/css-selector": "3.1.*", "symfony/dom-crawler": "3.1.*", - "laravel/homestead": "3.0.*" + "laravel/homestead": "3.0.*", + "barryvdh/laravel-ide-helper": "^2.3" }, "autoload": { "classmap": [ diff --git a/composer.lock b/composer.lock index 535af7aa2..8975e85a0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "6a9656aff0fb3809d27a2a093a810197", - "content-hash": "8affaad10f155172b5079a72015b8bc5", + "hash": "7c01d337ebab3d47ae3479360c63e68f", + "content-hash": "c2addd888e0a4fd26518ea7c691f6f25", "packages": [ { "name": "aws/aws-sdk-php", @@ -3747,6 +3747,121 @@ } ], "packages-dev": [ + { + "name": "barryvdh/laravel-ide-helper", + "version": "v2.3.2", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-ide-helper.git", + "reference": "e82de98cef0d6597b1b686be0b5813a3a4bb53c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/e82de98cef0d6597b1b686be0b5813a3a4bb53c5", + "reference": "e82de98cef0d6597b1b686be0b5813a3a4bb53c5", + "shasum": "" + }, + "require": { + "barryvdh/reflection-docblock": "^2.0.4", + "illuminate/console": "^5.0,<5.5", + "illuminate/filesystem": "^5.0,<5.5", + "illuminate/support": "^5.0,<5.5", + "php": ">=5.4.0", + "symfony/class-loader": "^2.3|^3.0" + }, + "require-dev": { + "doctrine/dbal": "~2.3", + "phpunit/phpunit": "4.*", + "scrutinizer/ocular": "~1.1", + "squizlabs/php_codesniffer": "~2.3" + }, + "suggest": { + "doctrine/dbal": "Load information from the database about models for phpdocs (~2.3)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Barryvdh\\LaravelIdeHelper\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.", + "keywords": [ + "autocomplete", + "codeintel", + "helper", + "ide", + "laravel", + "netbeans", + "phpdoc", + "phpstorm", + "sublime" + ], + "time": "2017-02-22 12:27:33" + }, + { + "name": "barryvdh/reflection-docblock", + "version": "v2.0.4", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/ReflectionDocBlock.git", + "reference": "3dcbd98b5d9384a5357266efba8fd29884458e5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/3dcbd98b5d9384a5357266efba8fd29884458e5c", + "reference": "3dcbd98b5d9384a5357266efba8fd29884458e5c", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0,<4.5" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Barryvdh": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2016-06-13 19:28:20" + }, { "name": "doctrine/instantiator", "version": "1.0.5", @@ -5008,6 +5123,62 @@ "homepage": "https://github.com/sebastianbergmann/version", "time": "2016-10-03 07:35:21" }, + { + "name": "symfony/class-loader", + "version": "v3.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/class-loader.git", + "reference": "c29a5bc6ca14cfff1f5e3d7781ed74b6e898d2b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/class-loader/zipball/c29a5bc6ca14cfff1f5e3d7781ed74b6e898d2b9", + "reference": "c29a5bc6ca14cfff1f5e3d7781ed74b6e898d2b9", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "require-dev": { + "symfony/finder": "~2.8|~3.0", + "symfony/polyfill-apcu": "~1.1" + }, + "suggest": { + "symfony/polyfill-apcu": "For using ApcClassLoader on HHVM" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\ClassLoader\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony ClassLoader Component", + "homepage": "https://symfony.com", + "time": "2017-02-18 17:28:00" + }, { "name": "symfony/css-selector", "version": "v3.1.10", From 1c47b2ed5551b7c29d66766d4846497edc3eda9c Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 15 Mar 2017 20:52:37 -0400 Subject: [PATCH 337/599] Finish pack management in Admin CP --- app/Http/Controllers/Admin/PackController.php | 129 +++++++++--- .../Controllers/Remote/RemoteController.php | 4 - app/Http/Routes/AdminRoutes.php | 7 + app/Models/Pack.php | 25 +++ .../MacroServiceProvider.php} | 46 ++--- app/Repositories/PackRepository.php | 16 +- app/Services/FileService.php | 0 config/app.php | 1 + .../pterodactyl/admin/packs/view.blade.php | 192 ++++++++++++++++++ .../views/admin/services/packs/edit.blade.php | 160 --------------- .../admin/services/packs/index.blade.php | 47 ----- .../views/admin/services/packs/new.blade.php | 135 ------------ .../admin/services/packs/upload.blade.php | 45 ---- 13 files changed, 352 insertions(+), 455 deletions(-) rename app/{Services/NotificationService.php => Providers/MacroServiceProvider.php} (58%) create mode 100644 app/Services/FileService.php create mode 100644 resources/themes/pterodactyl/admin/packs/view.blade.php delete mode 100644 resources/views/admin/services/packs/edit.blade.php delete mode 100644 resources/views/admin/services/packs/index.blade.php delete mode 100644 resources/views/admin/services/packs/new.blade.php delete mode 100644 resources/views/admin/services/packs/upload.blade.php diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php index 1ef60b8c8..675ccc738 100644 --- a/app/Http/Controllers/Admin/PackController.php +++ b/app/Http/Controllers/Admin/PackController.php @@ -80,6 +80,12 @@ class PackController extends Controller ]); } + /** + * Handle create pack request and route user to location. + * + * @param Request $request + * @return \Illuminate\View\View + */ public function create(Request $request) { $repo = new PackRepository; @@ -108,43 +114,102 @@ class PackController extends Controller return redirect()->route('admin.packs.new')->withInput(); } + /** + * Display pack view template to user. + * + * @param Request $request + * @param int $id + * @return \Illuminate\View\View + */ + public function view(Request $request, $id) + { + return view('admin.packs.view', [ + 'pack' => Pack::with('servers.node', 'servers.user')->findOrFail($id), + 'services' => Service::with('options')->get(), + ]); + } - // public function export(Request $request, $id, $files = false) - // { - // $pack = Models\Pack::findOrFail($id); - // $json = [ - // 'name' => $pack->name, - // 'version' => $pack->version, - // 'description' => $pack->dscription, - // 'selectable' => (bool) $pack->selectable, - // 'visible' => (bool) $pack->visible, - // ]; + /** + * Handle updating or deleting pack information. + * + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function update(Request $request, $id) + { + $repo = new PackRepository; - // $filename = tempnam(sys_get_temp_dir(), 'pterodactyl_'); - // if ((bool) $files) { - // $zip = new \ZipArchive; - // if (! $zip->open($filename, \ZipArchive::CREATE)) { - // abort(503, 'Unable to open file for writing.'); - // } + try { + if ($request->input('action') !== 'delete') { + $pack = $repo->update($id, $request->intersect([ + 'name', 'description', 'version', + 'option_id', 'selectable', 'visible', 'locked' + ])); + Alert::success('Pack successfully updated.')->flash(); + } else { + $repo->delete($id); + Alert::success('Pack was successfully deleted from the system.')->flash(); - // $files = Storage::files('packs/' . $pack->uuid); - // foreach ($files as $file) { - // $zip->addFile(storage_path('app/' . $file), basename(storage_path('app/' . $file))); - // } + return redirect()->route('admin.packs'); + } + } catch(DisplayValidationException $ex) { + return redirect()->route('admin.packs.view', $id)->withErrors(json_decode($ex->getMessage())); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An error occured while attempting to edit this service pack. This error has been logged.')->flash(); + } - // $zip->addFromString('import.json', json_encode($json, JSON_PRETTY_PRINT)); - // $zip->close(); + return redirect()->route('admin.packs.view', $id); + } - // return response()->download($filename, 'pack-' . $pack->name . '.zip')->deleteFileAfterSend(true); - // } else { - // $fp = fopen($filename, 'a+'); - // fwrite($fp, json_encode($json, JSON_PRETTY_PRINT)); - // fclose($fp); + /** + * Creates an archive of the pack and downloads it to the browser. + * + * @param Request $request + * @param int $id + * @param bool $files + * @return \Illuminate\Response\BinaryFileResponse + */ + public function export(Request $request, $id, $files = false) + { + $pack = Pack::findOrFail($id); + $json = [ + 'name' => $pack->name, + 'version' => $pack->version, + 'description' => $pack->description, + 'selectable' => $pack->selectable, + 'visible' => $pack->visible, + 'locked' => $pack->locked, + ]; - // return response()->download($filename, 'pack-' . $pack->name . '.json', [ - // 'Content-Type' => 'application/json', - // ])->deleteFileAfterSend(true); - // } - // } + $filename = tempnam(sys_get_temp_dir(), 'pterodactyl_'); + if ($files === 'with-files') { + $zip = new \ZipArchive; + if (! $zip->open($filename, \ZipArchive::CREATE)) { + abort(503, 'Unable to open file for writing.'); + } + + $files = Storage::files('packs/' . $pack->uuid); + foreach ($files as $file) { + $zip->addFile(storage_path('app/' . $file), basename(storage_path('app/' . $file))); + } + + $zip->addFromString('import.json', json_encode($json, JSON_PRETTY_PRINT)); + $zip->close(); + + return response()->download($filename, 'pack-' . $pack->name . '.zip')->deleteFileAfterSend(true); + } else { + $fp = fopen($filename, 'a+'); + fwrite($fp, json_encode($json, JSON_PRETTY_PRINT)); + fclose($fp); + + return response()->download($filename, 'pack-' . $pack->name . '.json', [ + 'Content-Type' => 'application/json', + ])->deleteFileAfterSend(true); + } + } } diff --git a/app/Http/Controllers/Remote/RemoteController.php b/app/Http/Controllers/Remote/RemoteController.php index 2e8b782a1..93dd672e1 100644 --- a/app/Http/Controllers/Remote/RemoteController.php +++ b/app/Http/Controllers/Remote/RemoteController.php @@ -98,10 +98,6 @@ class RemoteController extends Controller ], 403); } - // Passes Validation, Setup Notifications - $notify = new NotificationService($server); - $notify->pass($request->input('notification')); - return response('', 201); } diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index f714f632d..f8cbc17fa 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -474,6 +474,13 @@ class AdminRoutes 'as' => 'admin.packs.view', 'uses' => 'Admin\PackController@view', ]); + + $router->post('/view/{id}', 'Admin\PackController@update'); + + $router->post('/view/{id}/export/{files?}', [ + 'as' => 'admin.packs.view.export', + 'uses' => 'Admin\PackController@export', + ]); }); } } diff --git a/app/Models/Pack.php b/app/Models/Pack.php index 5675fb25a..0a6310660 100644 --- a/app/Models/Pack.php +++ b/app/Models/Pack.php @@ -24,6 +24,8 @@ namespace Pterodactyl\Models; +use File; +use Storage; use Illuminate\Database\Eloquent\Model; use Nicolaslopezj\Searchable\SearchableTrait; @@ -78,6 +80,29 @@ class Pack extends Model ], ]; + /** + * Returns all of the archived files for a given pack. + * + * @param bool $collection + * @return \Illuminate\Support\Collection|object + */ + public function files($collection = false) + { + $files = collect(Storage::files('packs/' . $this->uuid)); + + $files = $files->map(function ($item) { + $path = storage_path('app/' . $item); + + return (object) [ + 'name' => basename($item), + 'hash' => sha1_file($path), + 'size' => File::humanReadableSize($path), + ]; + }); + + return ($collection) ? $files : (object) $files->all(); + } + /** * Gets option associated with a service pack. * diff --git a/app/Services/NotificationService.php b/app/Providers/MacroServiceProvider.php similarity index 58% rename from app/Services/NotificationService.php rename to app/Providers/MacroServiceProvider.php index 7912cf65d..ad23aaf74 100644 --- a/app/Services/NotificationService.php +++ b/app/Providers/MacroServiceProvider.php @@ -22,41 +22,31 @@ * SOFTWARE. */ -namespace Pterodactyl\Services; +namespace Pterodactyl\Providers; -use Pterodactyl\Models\Server; -use Pterodactyl\Notifications\Daemon; +use File; +use Illuminate\Support\ServiceProvider; -class NotificationService +class MacroServiceProvider extends ServiceProvider { - protected $server; - - protected $user; - /** - * Daemon will pass an event name, this matches that event name with the notification to send. - * @var array + * Bootstrap the application services. + * + * @return void */ - protected $types = [ - // 'crashed' => 'CrashNotification', - // 'started' => 'StartNotification', - // 'stopped' => 'StopNotification', - // 'rebuild' => 'RebuildNotification' - ]; - - public function __construct(Server $server) + public function boot() { - $this->server = $server; - } + File::macro('humanReadableSize', function ($path, $precision = 2) { + $size = File::size($path); + static $units = ['B', 'kB', 'MB', 'GB', 'TB']; - public function pass(array $notification) - { - if (! $notification->type) { - return; - } + $i = 0; + while (($size / 1024) > 0.9) { + $size = $size / 1024; + $i++; + } - if (class_exists($this->types[$notification->type]::class)) { - $user->notify(new $this->types[$notification->type]($notification->payload)); - } + return round($size, ($i < 2) ? 0 : $precision) . ' ' . $units[$i]; + }); } } diff --git a/app/Repositories/PackRepository.php b/app/Repositories/PackRepository.php index 3fc6b2571..fdc5fbd5d 100644 --- a/app/Repositories/PackRepository.php +++ b/app/Repositories/PackRepository.php @@ -177,12 +177,14 @@ class PackRepository * @param array $data * @return \Pterodactyl\Models\Pack * + * @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\DisplayValidationException */ public function update($id, array $data) { $validator = Validator::make($data, [ 'name' => 'sometimes|required|string', + 'option_id' => 'sometimes|required|exists:service_options,id', 'version' => 'sometimes|required|string', 'description' => 'sometimes|string', 'selectable' => 'sometimes|required|boolean', @@ -194,14 +196,20 @@ class PackRepository throw new DisplayValidationException(json_encode($validator->errors())); } - $pack = Pack::findOrFail($id); + $pack = Pack::withCount('servers')->findOrFail($id); + + if ($pack->servers_count > 0 && (isset($data['option_id']) && (int) $data['option_id'] !== $pack->option_id)) { + throw new DisplayException('You cannot modify the associated option if servers are attached to a pack.'); + } + $pack->fill([ 'name' => isset($data['name']) ? $data['name'] : $pack->name, + 'option_id' => isset($data['option_id']) ? $data['option_id'] : $pack->option_id, 'version' => isset($data['version']) ? $data['version'] : $pack->version, 'description' => (empty($data['description'])) ? null : $data['description'], - 'selectable' => isset($data['selectable']) ? $data['selectable'] : $data->selectable, - 'visible' => isset($data['visible']) ? $data['visible'] : $data->visible, - 'locked' => isset($data['locked']) ? $data['locked'] : $data->locked, + 'selectable' => isset($data['selectable']), + 'visible' => isset($data['visible']), + 'locked' => isset($data['locked']), ])->save(); return $pack; diff --git a/app/Services/FileService.php b/app/Services/FileService.php new file mode 100644 index 000000000..e69de29bb diff --git a/config/app.php b/config/app.php index 622098a9b..4721bb3d2 100644 --- a/config/app.php +++ b/config/app.php @@ -150,6 +150,7 @@ return [ Pterodactyl\Providers\AuthServiceProvider::class, Pterodactyl\Providers\EventServiceProvider::class, Pterodactyl\Providers\RouteServiceProvider::class, + Pterodactyl\Providers\MacroServiceProvider::class, Pterodactyl\Providers\PhraseAppTranslationProvider::class, /* diff --git a/resources/themes/pterodactyl/admin/packs/view.blade.php b/resources/themes/pterodactyl/admin/packs/view.blade.php new file mode 100644 index 000000000..03b331bee --- /dev/null +++ b/resources/themes/pterodactyl/admin/packs/view.blade.php @@ -0,0 +1,192 @@ +{{-- 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') + Packs → View → {{ $pack->name }} +@endsection + +@section('content-header') +

      {{ $pack->name }}{{ str_limit($pack->description, 60) }}

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

      Pack Details

      +
      +
      +
      + + +

      A short but descriptive name of what this pack is. For example, Counter Strike: Source if it is a Counter Strike package.

      +
      +
      + + +
      +
      + + +

      The version of this package, or the version of the files contained within the package.

      +
      +
      +
      +
      +
      +
      +
      +

      Pack Configuration

      +
      +
      +
      + + +

      The option that this pack is assocaited with. Only servers that are assigned this option will be able to access this pack. This assigned option cannot be changed if servers are attached to this pack.

      +
      +
      +
      + selectable ?: 'checked' }}/> + +
      +

      Check this box if user should be able to select this pack to install on their servers.

      +
      +
      +
      + visible ?: 'checked' }}/> + +
      +

      Check this box if this pack is visible in the dropdown menu. If this pack is assigned to a server it will be visible regardless of this setting.

      +
      +
      +
      + locked ?: 'checked' }}/> + +
      +

      Check this box if servers assigned this pack should not be able to switch to a different pack.

      +
      +
      + +
      +
      +
      +
      +
      +
      +
      +
      +

      Stored Files

      +
      +
      + + + + + + + @foreach($pack->files() as $file) + + + + + + @endforeach +
      NameSHA1 HashFile Size
      {{ $file->name }}{{ $file->hash }}{{ $file->size }}
      +
      + +
      +
      +
      +
      +
      +
      +
      +

      Servers Using This Pack

      +
      +
      + + + + + + + + @foreach($pack->servers as $server) + + + + + + + @endforeach +
      IDServer NameNodeOwner
      {{ $server->uuidShort }}{{ $server->name }}{{ $server->node->name }}{{ $server->user->email }}
      +
      +
      +
      +
      +
      +
      +
      + {!! csrf_field() !!} + +
      +
      + {!! csrf_field() !!} + +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/views/admin/services/packs/edit.blade.php b/resources/views/admin/services/packs/edit.blade.php deleted file mode 100644 index cc6470b3b..000000000 --- a/resources/views/admin/services/packs/edit.blade.php +++ /dev/null @@ -1,160 +0,0 @@ -{{-- 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') - Add New Service Pack -@endsection - -@section('content') -
      - -

      Manage Service Pack


      -
      -
      -
      - -
      - -

      The name of the pack which will be seen in dropdown menus and to users.

      -
      -
      -
      - -
      - -

      The version of the program included in this pack.

      -
      -
      -
      - -
      - -

      Provide a description of the pack which will be shown to users.

      -
      -
      -
      -
      -
      - - -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      -
      -
      -
      -
      Package Archive
      -
      -
      -
      - @if(count($files) > 1) -
      Warning! Service packs should only contain a single pack archive in .tar.gz format. We've detected more than one file for this pack.
      - @endif - - - - - - - - - - - @foreach($files as &$file) - - - - - - - @endforeach - -
      FilenameFile SizeSHA1 HashLast Modified
      {{ basename($file) }}{{ Storage::size($file) }} Bytes{{ sha1_file(storage_path('app/' . $file)) }}{{ Carbon::createFromTimestamp(Storage::lastModified($file))->toDateTimeString() }}
      -

      If you wish to modify or upload a new file it should be uploaded to {{ storage_path('app/packs/' . $pack->uuid) }} as archive.tar.gz.

      -
      -
      -
      -
      -
      -
      -
      -
      -
      - {!! csrf_field() !!} - - - - -
      -
      - -
      -{!! Theme::js('js/vendor/ace/ace.js') !!} -{!! Theme::js('js/vendor/ace/ext-modelist.js') !!} - -@endsection diff --git a/resources/views/admin/services/packs/index.blade.php b/resources/views/admin/services/packs/index.blade.php deleted file mode 100644 index 6456ca317..000000000 --- a/resources/views/admin/services/packs/index.blade.php +++ /dev/null @@ -1,47 +0,0 @@ -{{-- 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') - Service Packs -@endsection - -@section('content') -
      - -

      Service Packs


      -
      - @foreach ($services as $service) - - @endforeach -
      -
      - -@endsection diff --git a/resources/views/admin/services/packs/new.blade.php b/resources/views/admin/services/packs/new.blade.php deleted file mode 100644 index d5b0440da..000000000 --- a/resources/views/admin/services/packs/new.blade.php +++ /dev/null @@ -1,135 +0,0 @@ -{{-- 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') - Add New Service Pack -@endsection - -@section('content') -
      - -

      New Service Pack


      -
      -
      -
      - -
      - -

      The name of the pack which will be seen in dropdown menus and to users.

      -
      -
      -
      - -
      - -

      The version of the program included in this pack.

      -
      -
      -
      - -
      - -

      Provide a description of the pack which will be shown to users.

      -
      -
      -
      -
      -
      - - -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      -
      -
      -
      -
      File Upload
      -
      -
      -
      - - -

      This package file must be a .tar.gz archive of files to use for either building or running this pack.

      If your file is larger than 20MB we recommend uploading it using SFTP. Once you have added this pack to the system, a path will be provided where you should upload the file. - This server is currently configured with the following limits: upload_max_filesize={{ ini_get('upload_max_filesize') }} and post_max_size={{ ini_get('post_max_size') }}. If your file is larger than either of those values this request will fail.

      -
      -
      -
      -
      -
      -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      - -
      -{!! Theme::js('js/vendor/ace/ace.js') !!} -{!! Theme::js('js/vendor/ace/ext-modelist.js') !!} - -@endsection diff --git a/resources/views/admin/services/packs/upload.blade.php b/resources/views/admin/services/packs/upload.blade.php deleted file mode 100644 index cb5e548d8..000000000 --- a/resources/views/admin/services/packs/upload.blade.php +++ /dev/null @@ -1,45 +0,0 @@ - From 436ba814a999df0bc99e8eb82509939a86cfabc1 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 15 Mar 2017 20:53:49 -0400 Subject: [PATCH 338/599] Apply fixes from StyleCI (#351) --- app/Http/Controllers/Admin/PackController.php | 7 +++---- app/Models/ServiceVariable.php | 8 ++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php index 675ccc738..46674ae02 100644 --- a/app/Http/Controllers/Admin/PackController.php +++ b/app/Http/Controllers/Admin/PackController.php @@ -102,7 +102,7 @@ class PackController extends Controller Alert::success('Pack successfully created on the system.')->flash(); return redirect()->route('admin.packs.view', $pack->id); - } catch(DisplayValidationException $ex) { + } catch (DisplayValidationException $ex) { return redirect()->route('admin.packs.new')->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); @@ -144,7 +144,7 @@ class PackController extends Controller if ($request->input('action') !== 'delete') { $pack = $repo->update($id, $request->intersect([ 'name', 'description', 'version', - 'option_id', 'selectable', 'visible', 'locked' + 'option_id', 'selectable', 'visible', 'locked', ])); Alert::success('Pack successfully updated.')->flash(); } else { @@ -153,7 +153,7 @@ class PackController extends Controller return redirect()->route('admin.packs'); } - } catch(DisplayValidationException $ex) { + } catch (DisplayValidationException $ex) { return redirect()->route('admin.packs.view', $id)->withErrors(json_decode($ex->getMessage())); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); @@ -211,5 +211,4 @@ class PackController extends Controller ])->deleteFileAfterSend(true); } } - } diff --git a/app/Models/ServiceVariable.php b/app/Models/ServiceVariable.php index 0e7746312..3d4647583 100644 --- a/app/Models/ServiceVariable.php +++ b/app/Models/ServiceVariable.php @@ -43,10 +43,10 @@ class ServiceVariable extends Model protected $guarded = ['id', 'created_at', 'updated_at']; /** - * Cast values to correct type. - * - * @var array - */ + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'option_id' => 'integer', 'user_viewable' => 'integer', From 4094a49e9c2f8b1470ea2c593dc1a78a92642af9 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 15 Mar 2017 20:59:16 -0400 Subject: [PATCH 339/599] Update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd7eee349..2aaf6b6dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * New theme applied to Admin CP. Many graphical changes were made, some data was moved around and some display data changed. Too much was changed to feasibly log it all in here. Major breaking changes or notable new features will be logged. * New server creation page now makes significantly less AJAX calls and is much quicker to respond. * Server and Node view pages wee modified to split tabs into individual pages to make re-themeing and modifications significantly easier, and reduce MySQL query loads on page. +* `[pre.4]` — Services and Pack magement overhauled to be faster, cleaner, and more extensible in the future. +* Most of the backend `UnhandledException` display errors now include a clearer error that directs admins to the program's logs. +* Table seeders for services now can be run during upgrades and will attempt to locate and update, or create new if not found in the database. +* Many structural changes to the database and `Pterodactyl\Models` classes that would flood this changelog if they were all included. All required migrations included to handle database changes. +* `[pre.4]` — Service pack files are now stored in the database rather than on the host system to make updates easier. ### Fixed * Fixes potential bug with invalid CIDR notation (ex: `192.168.1.1/z`) when adding allocations that could cause over 4 million records to be created at once. @@ -16,6 +21,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Added * Ability to assign multiple allocations at once when creating a new server. +* New `humanReadable` macro on `File` facade that accepts a file path and returns a human readable size. (`File::humanReadable(path, precision)`) ### Deprecated * Old API calls to `Server::create` will fail due to changed data structure. From 1852018397cf7512d5802d76b0da219fa02b11c7 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 15 Mar 2017 21:38:09 -0400 Subject: [PATCH 340/599] Add back missing node creation page. --- .gitignore | 2 +- .../Controllers/Admin/NodesController.php | 31 ++-- .../pterodactyl/admin/nodes/new.blade.php | 171 ++++++++++++++++++ 3 files changed, 192 insertions(+), 12 deletions(-) create mode 100644 resources/themes/pterodactyl/admin/nodes/new.blade.php diff --git a/.gitignore b/.gitignore index efbbccdcf..0826a5ebe 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .env .vagrant/* .vscode/* +storage/framework/* composer.lock @@ -15,5 +16,4 @@ yarn.lock node_modules _ide_helper_models.php - _ide_helper.php diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index 4bb08c52f..cbf3ff6ce 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -82,11 +82,16 @@ class NodesController extends Controller { try { $repo = new NodeRepository; - $node = $repo->create($request->intersect([ - 'name', 'location_id', 'public', 'fqdn', 'scheme', 'memory', - 'memory_overallocate', 'disk', 'disk_overallocate', - 'daemonBase', 'daemonSFTP', 'daemonListen', - ])); + $node = $repo->create(array_merge( + $request->only([ + 'public', 'disk_overallocate', 'memory_overallocate', + ]), + $request->intersect([ + 'name', 'location_id', 'fqdn', + 'scheme', 'memory', 'disk', + 'daemonBase', 'daemonSFTP', 'daemonListen', + ]) + )); Alert::success('Successfully created new node that can be configured automatically on your remote machine by visiting the configuration tab. Before you can add any servers you need to first assign some IP addresses and ports.')->flash(); return redirect()->route('admin.nodes.view', $node->id); @@ -213,12 +218,16 @@ class NodesController extends Controller $repo = new NodeRepository; try { - $repo->update($id, $request->intersect([ - 'name', 'location_id', 'public', 'fqdn', 'scheme', 'memory', - 'memory_overallocate', 'disk', 'disk_overallocate', 'upload_size', - 'daemonSFTP', 'daemonListen', 'reset_secret', - ])); - + $node = $repo->update($id, array_merge( + $request->only([ + 'public', 'disk_overallocate', 'memory_overallocate', + ]), + $request->intersect([ + 'name', 'location_id', 'fqdn', + 'scheme', 'memory', 'disk', 'upload_size', + 'reset_secret', 'daemonSFTP', 'daemonListen', + ]) + )); Alert::success('Successfully updated this node\'s information. If you changed any daemon settings you will need to restart it now.')->flash(); } catch (DisplayValidationException $ex) { return redirect()->route('admin.nodes.view.settings', $id)->withErrors(json_decode($ex->getMessage()))->withInput(); diff --git a/resources/themes/pterodactyl/admin/nodes/new.blade.php b/resources/themes/pterodactyl/admin/nodes/new.blade.php new file mode 100644 index 000000000..eb58e32fa --- /dev/null +++ b/resources/themes/pterodactyl/admin/nodes/new.blade.php @@ -0,0 +1,171 @@ +{{-- 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') + Nodes → New +@endsection + +@section('content-header') +

      New NodeCreate a new local or remote node for servers to be installed to.

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

      Basic Details

      +
      +
      +
      + + +

      Character limits: a-zA-Z0-9_.- and [Space] (min 1, max 100 characters).

      +
      +
      + + +
      +
      + +
      +
      + + +
      +
      + + +
      +
      +

      By setting a node to private you will be denying the ability to auto-deploy to this node. +

      +
      + + +

      Please enter domain name (e.g node.example.com) to be used for connecting to the daemon. An IP address may be used only if you are not using SSL for this node.

      +
      +
      + +
      +
      + + +
      +
      + + +
      +
      +

      SSL should only be disabled if this node is assigned an IP address as the FQDN and not an actual FQDN. Disabling SSL could allow a malicious user to intercept traffic between the panel and the daemon potentially exposing sensitive information.

      +
      +
      + + +

      Enter the directory where server files should be stored. If you use OVH you should check your partition scheme. You may need to use /home/daemon-data to have enough space.

      +
      +
      +
      +
      +
      +
      +
      +

      Configuration

      +
      +
      +
      +
      + +
      + + MB +
      +
      +
      + +
      + + % +
      +
      +
      +

      Enter the total amount of memory avaliable for new servers. If you would like to allow overallocation of memory enter the percentage that you want to allow. To disable checking for overallocation enter -1 into the field. Entering 0 will prevent creating new servers if it would put the node over the limit.

      +
      +
      +
      +
      + +
      + + MB +
      +
      +
      + +
      + + % +
      +
      +
      +

      Enter the total amount of disk space avaliable for new servers. If you would like to allow overallocation of disk space enter the percentage that you want to allow. To disable checking for overallocation enter -1 into the field. Entering 0 will prevent creating new servers if it would put the node over the limit.

      +
      +
      +
      +
      + + +
      +
      + + +
      +
      +

      The daemon runs its own SFTP management container and does not use the SSHd process on the main physical server. Do not use the same port that you have assigned for your physcial server's SSH process. If you will be running the daemon behind CloudFlare® you should set the daemon port to 8443 to allow websocket proxying over SSL.

      +
      +
      +
      + +
      +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection From db072025d4671abd29f9cac765da5d40f09f2cd8 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 15 Mar 2017 21:39:50 -0400 Subject: [PATCH 341/599] Reference the correct column in the DB --- app/Repositories/NodeRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Repositories/NodeRepository.php b/app/Repositories/NodeRepository.php index 32b206991..2975da4e1 100644 --- a/app/Repositories/NodeRepository.php +++ b/app/Repositories/NodeRepository.php @@ -262,7 +262,7 @@ class NodeRepository Models\Allocation::where('node_id', $node->id)->delete(); // Delete configure tokens - Models\NodeConfigurationToken::where('node', $node->id)->delete(); + Models\NodeConfigurationToken::where('node_id', $node->id)->delete(); // Delete Node $node->delete(); From 05d2a6d370111328e70abb3c6bce364d26ca9272 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 16 Mar 2017 18:09:02 -0400 Subject: [PATCH 342/599] Add back locations with new theme --- .../Controllers/Admin/LocationController.php | 119 ++++++++++++++++++ .../Controllers/Admin/LocationsController.php | 100 --------------- app/Http/Routes/AdminRoutes.php | 77 ++++-------- app/Repositories/LocationRepository.php | 73 ++++++----- .../admin/locations/index.blade.php | 100 +++++++++++++++ .../admin/locations/view.blade.php | 87 +++++++++++++ .../pterodactyl/layouts/admin.blade.php | 14 ++- 7 files changed, 383 insertions(+), 187 deletions(-) create mode 100644 app/Http/Controllers/Admin/LocationController.php delete mode 100644 app/Http/Controllers/Admin/LocationsController.php create mode 100644 resources/themes/pterodactyl/admin/locations/index.blade.php create mode 100644 resources/themes/pterodactyl/admin/locations/view.blade.php diff --git a/app/Http/Controllers/Admin/LocationController.php b/app/Http/Controllers/Admin/LocationController.php new file mode 100644 index 000000000..6ceae16e7 --- /dev/null +++ b/app/Http/Controllers/Admin/LocationController.php @@ -0,0 +1,119 @@ +. + * + * 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 Log; +use Alert; +use Illuminate\Http\Request; +use Pterodactyl\Models\Location; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Repositories\LocationRepository; +use Pterodactyl\Exceptions\DisplayValidationException; + +class LocationController extends Controller +{ + /** + * Return the location overview page. + * + * @param Request $request + * @return \Illuminate\View\View + */ + public function index(Request $request) + { + return view('admin.locations.index', [ + 'locations' => Location::withCount('nodes', 'servers')->get(), + ]); + } + + /** + * Return the location view page. + * + * @param Request $request + * @param int $id + * @return \Illuminate\View\View + */ + public function view(Request $request, $id) + { + return view('admin.locations.view', ['location' => Location::with('nodes.servers')->findOrFail($id)]); + } + + /** + * Handle request to create new location. + * + * @param Request $request + * @return \Illuminate\Response\RedirectResponse + */ + public function create(Request $request) + { + $repo = new LocationRepository; + + try { + $location = $repo->create($request->intersect(['short', 'long'])); + Alert::success('Location was created successfully.')->flash(); + + return redirect()->route('admin.locations.view', $location->id); + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.locations')->withErrors(json_decode($ex->getMessage())); + } catch (\Exception $ex) { + Log::error($ex); + Alert::error('An unhandled exception occurred while processing this request. This error has been logged.')->flash(); + } + + return redirect()->route('admin.locations'); + } + + /** + * Handle request to update or delete location. + * + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function update(Request $request, $id) + { + $repo = new LocationRepository; + + try { + if ($request->input('action') !== 'delete') { + $location = $repo->update($id, $request->intersect(['short', 'long'])); + Alert::success('Location was updated successfully.')->flash(); + } else { + $repo->delete($id); + + return redirect()->route('admin.locations'); + } + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.locations.view', $id)->withErrors(json_decode($ex->getMessage())); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::error('An unhandled exception occurred while processing this request. This error has been logged.')->flash(); + } + + return redirect()->route('admin.locations.view', $id); + } +} diff --git a/app/Http/Controllers/Admin/LocationsController.php b/app/Http/Controllers/Admin/LocationsController.php deleted file mode 100644 index 94c9ebf59..000000000 --- a/app/Http/Controllers/Admin/LocationsController.php +++ /dev/null @@ -1,100 +0,0 @@ -. - * - * 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 Pterodactyl\Models; -use Illuminate\Http\Request; -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Http\Controllers\Controller; -use Pterodactyl\Repositories\LocationRepository; -use Pterodactyl\Exceptions\DisplayValidationException; - -class LocationsController extends Controller -{ - public function __construct() - { - // - } - - public function getIndex(Request $request) - { - return view('admin.locations.index', [ - 'locations' => Models\Location::withCount('nodes', 'servers')->paginate(20), - ]); - } - - public function deleteLocation(Request $request, $id) - { - $location = Models\Location::withCount('nodes')->findOrFail($id); - - if ($location->nodes_count > 0) { - return response()->json([ - 'error' => 'You cannot remove a location that is currently assigned to a node.', - ], 422); - } - - $location->delete(); - - return response('', 204); - } - - public function patchLocation(Request $request, $id) - { - try { - $location = new LocationRepository; - $location->edit($id, $request->only(['long', 'short'])); - - return response('', 204); - } catch (DisplayValidationException $ex) { - return response()->json([ - 'error' => 'There was a validation error while processing this request. Location descriptions must be between 1 and 255 characters, and the location code must be between 1 and 20 characters with no spaces or special characters.', - ], 422); - } catch (\Exception $ex) { - // This gets caught and processed into JSON anyways. - throw $ex; - } - } - - public function postLocation(Request $request) - { - try { - $location = new LocationRepository; - $location->create($request->only(['long', 'short'])); - Alert::success('New location successfully added.')->flash(); - - return redirect()->route('admin.locations'); - } catch (DisplayValidationException $ex) { - return redirect()->route('admin.locations')->withErrors(json_decode($ex->getMessage()))->withInput(); - } catch (DisplayException $ex) { - Alert::danger($ex->getMessage())->flash(); - } catch (\Exception $ex) { - Log::error($ex); - Alert::danger('An unhandled exception occured while attempting to add this location. Please try again.')->flash(); - } - - return redirect()->route('admin.locations')->withInput(); - } -} diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index f8cbc17fa..8649e789f 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -43,6 +43,29 @@ class AdminRoutes 'uses' => 'Admin\BaseController@getIndex', ]); + $router->group([ + 'prefix' => 'admin/locations', + 'middleware' => [ + 'auth', + 'admin', + 'csrf', + ], + ], function () use ($router) { + $router->get('/', [ + 'as' => 'admin.locations', + 'uses' => 'Admin\LocationController@index', + ]); + + $router->post('/', 'Admin\LocationController@create'); + + $router->get('/view/{id}', [ + 'as' => 'admin.locations.view', + 'uses' => 'Admin\LocationController@view', + ]); + + $router->post('/view/{id}', 'Admin\LocationController@update'); + }); + $router->group([ 'prefix' => 'admin/settings', 'middleware' => [ @@ -321,60 +344,6 @@ class AdminRoutes ]); }); - // Location Routes - $router->group([ - 'prefix' => 'admin/locations', - 'middleware' => [ - 'auth', - 'admin', - 'csrf', - ], - ], function () use ($router) { - $router->get('/', [ - 'as' => 'admin.locations', - 'uses' => 'Admin\LocationsController@getIndex', - ]); - $router->delete('/{id}', [ - 'uses' => 'Admin\LocationsController@deleteLocation', - ]); - $router->patch('/{id}', [ - 'uses' => 'Admin\LocationsController@patchLocation', - ]); - $router->post('/', [ - 'uses' => 'Admin\LocationsController@postLocation', - ]); - }); - - // Database Routes - $router->group([ - 'prefix' => 'admin/databases', - 'middleware' => [ - 'auth', - 'admin', - 'csrf', - ], - ], function () use ($router) { - $router->get('/', [ - 'as' => 'admin.databases', - 'uses' => 'Admin\DatabaseController@getIndex', - ]); - $router->get('/new', [ - 'as' => 'admin.databases.new', - 'uses' => 'Admin\DatabaseController@getNew', - ]); - $router->post('/new', [ - 'uses' => 'Admin\DatabaseController@postNew', - ]); - $router->delete('/delete/{id}', [ - 'as' => 'admin.databases.delete', - 'uses' => 'Admin\DatabaseController@deleteDatabase', - ]); - $router->delete('/delete-server/{id}', [ - 'as' => 'admin.databases.delete-server', - 'uses' => 'Admin\DatabaseController@deleteServer', - ]); - }); - // Service Routes $router->group([ 'prefix' => 'admin/services', diff --git a/app/Repositories/LocationRepository.php b/app/Repositories/LocationRepository.php index 1b6f50613..d3efb5d25 100644 --- a/app/Repositories/LocationRepository.php +++ b/app/Repositories/LocationRepository.php @@ -25,16 +25,12 @@ namespace Pterodactyl\Repositories; use Validator; -use Pterodactyl\Models; +use Pterodactyl\Models\Location; +use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayValidationException; class LocationRepository { - public function __construct() - { - // - } - /** * Creates a new location on the system. * @@ -45,48 +41,63 @@ class LocationRepository public function create(array $data) { $validator = Validator::make($data, [ - 'short' => 'required|regex:/^[\w.-]{1,20}$/i|unique:locations,short', - 'long' => 'required|string|min:1|max:255', + 'short' => 'required|string|between:1,60|unique:locations,short', + 'long' => 'required|string|between:1,255', ]); - // Run validator, throw catchable and displayable exception if it fails. - // Exception includes a JSON result of failed validation rules. if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } - $location = Models\Location::create([ + return Location::create([ 'long' => $data['long'], 'short' => $data['short'], ]); + } + + /** + * Modifies a location. + * + * @param int $id + * @param array $data + * @return \Pterodactyl\Models\Location + * + * @throws Pterodactyl\Exceptions\DisplayValidationException + */ + public function update($id, array $data) + { + $location = Location::findOrFail($id); + + $validator = Validator::make($data, [ + 'short' => 'sometimes|required|string|between:1,60|unique:locations,short,' . $location->id, + 'long' => 'sometimes|required|string|between:1,255', + ]); + + if ($validator->fails()) { + throw new DisplayValidationException(json_encode($validator->errors())); + } + + $location->fill($data)->save(); return $location; } /** - * Modifies a location based on the fields passed in $data. - * @param int $id - * @param array $data - * @throws Pterodactyl\Exceptions\DisplayValidationException - * @return bool + * Deletes a location from the system. + * + * @param int $id + * @return void + * + * @throws Pterodactyl\Exceptions\DisplayException */ - public function edit($id, array $data) + public function delete($id) { - $location = Models\Location::findOrFail($id); + $location = Location::withCount('nodes')->findOrFail($id); - $validator = Validator::make($data, [ - 'short' => 'required|regex:/^[\w.-]{1,20}$/i|unique:locations,short,' . $location->id, - 'long' => 'required|string|min:1|max:255', - ]); - - // Run validator, throw catchable and displayable exception if it fails. - // Exception includes a JSON result of failed validation rules. - if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + if ($location->nodes_count > 0) { + throw new DisplayException('Cannot delete a location that has nodes assigned to it.'); } - $location->fill($data); - - return $location->save(); + $location->delete(); } } diff --git a/resources/themes/pterodactyl/admin/locations/index.blade.php b/resources/themes/pterodactyl/admin/locations/index.blade.php new file mode 100644 index 000000000..e2b8578a0 --- /dev/null +++ b/resources/themes/pterodactyl/admin/locations/index.blade.php @@ -0,0 +1,100 @@ +{{-- 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') + Locations +@endsection + +@section('content-header') +

      LocationsAll locations that nodes can be assigned to for easier categorization.

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

      Location List

      +
      +
      + + + + + + + + + + @foreach ($locations as $location) + + + + + + + + @endforeach + +
      IDShort CodeDescriptionNodesServers
      {{ $location->id }}{{ $location->short }}{{ $location->long }}{{ $location->nodes_count }}{{ $location->servers_count }}
      +
      + +
      +
      +
      + +@endsection diff --git a/resources/themes/pterodactyl/admin/locations/view.blade.php b/resources/themes/pterodactyl/admin/locations/view.blade.php new file mode 100644 index 000000000..41490f4b9 --- /dev/null +++ b/resources/themes/pterodactyl/admin/locations/view.blade.php @@ -0,0 +1,87 @@ +{{-- 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') + Locations → View → {{ $location->short }} +@endsection + +@section('content-header') +

      {{ $location->short }}{{ str_limit($location->long, 75) }}

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

      Location Details

      +
      +
      +
      +
      + + +
      +
      + + +
      +
      + +
      +
      +
      +
      +
      +
      +

      Nodes

      +
      +
      + + + + + + + + @foreach($location->nodes as $node) + + + + + + + @endforeach +
      IDNameFQDNServers
      {{ $node->id }}{{ $node->name }}{{ $node->fqdn }}{{ $node->servers->count() }}
      +
      +
      +
      +
      +@endsection diff --git a/resources/themes/pterodactyl/layouts/admin.blade.php b/resources/themes/pterodactyl/layouts/admin.blade.php index a6c735c60..85ac74160 100644 --- a/resources/themes/pterodactyl/layouts/admin.blade.php +++ b/resources/themes/pterodactyl/layouts/admin.blade.php @@ -91,9 +91,14 @@
    • MANAGEMENT
    • -
    • +
    • - Servers + Databases + +
    • +
    • + + Locations
    • @@ -101,6 +106,11 @@ Nodes
    • +
    • + + Servers + +
    • Users From 5bbded2c034f152a37301612b51737b5b87aeace Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 16 Mar 2017 19:30:04 -0400 Subject: [PATCH 343/599] Correctly json_encode validation errors. --- app/Repositories/APIRepository.php | 2 +- app/Repositories/NodeRepository.php | 6 +++--- app/Repositories/OptionRepository.php | 4 ++-- app/Repositories/ServerRepository.php | 8 ++++---- app/Repositories/ServiceRepository.php | 4 ++-- app/Repositories/UserRepository.php | 4 ++-- app/Repositories/VariableRepository.php | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/Repositories/APIRepository.php b/app/Repositories/APIRepository.php index 5f148eda6..dc856e188 100644 --- a/app/Repositories/APIRepository.php +++ b/app/Repositories/APIRepository.php @@ -141,7 +141,7 @@ class APIRepository // Run validator, throw catchable and displayable exception if it fails. // Exception includes a JSON result of failed validation rules. if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } DB::beginTransaction(); diff --git a/app/Repositories/NodeRepository.php b/app/Repositories/NodeRepository.php index 2975da4e1..0c2c455c1 100644 --- a/app/Repositories/NodeRepository.php +++ b/app/Repositories/NodeRepository.php @@ -60,7 +60,7 @@ class NodeRepository // Run validator, throw catchable and displayable exception if it fails. // Exception includes a JSON result of failed validation rules. if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } // Verify the FQDN if using SSL @@ -109,7 +109,7 @@ class NodeRepository // Run validator, throw catchable and displayable exception if it fails. // Exception includes a JSON result of failed validation rules. if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } // Verify the FQDN @@ -193,7 +193,7 @@ class NodeRepository ]); if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } $explode = explode('/', $data['allocation_ip']); diff --git a/app/Repositories/OptionRepository.php b/app/Repositories/OptionRepository.php index 80a0a52a7..d0535b575 100644 --- a/app/Repositories/OptionRepository.php +++ b/app/Repositories/OptionRepository.php @@ -58,7 +58,7 @@ class OptionRepository ]); if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } if (isset($data['config_from'])) { @@ -141,7 +141,7 @@ class OptionRepository }); if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } if (isset($data['config_from'])) { diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index f95d45431..adf05a293 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -114,7 +114,7 @@ class ServerRepository // Run validator, throw catchable and displayable exception if it fails. // Exception includes a JSON result of failed validation rules. if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } $user = Models\User::findOrFail($data['user_id']); @@ -360,7 +360,7 @@ class ServerRepository // Run validator, throw catchable and displayable exception if it fails. // Exception includes a JSON result of failed validation rules. if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } DB::beginTransaction(); @@ -437,7 +437,7 @@ class ServerRepository // Run validator, throw catchable and displayable exception if it fails. // Exception includes a JSON result of failed validation rules. if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } DB::beginTransaction(); @@ -492,7 +492,7 @@ class ServerRepository // Run validator, throw catchable and displayable exception if it fails. // Exception includes a JSON result of failed validation rules. if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } DB::beginTransaction(); diff --git a/app/Repositories/ServiceRepository.php b/app/Repositories/ServiceRepository.php index e8d606ffc..126feb647 100644 --- a/app/Repositories/ServiceRepository.php +++ b/app/Repositories/ServiceRepository.php @@ -48,7 +48,7 @@ class ServiceRepository ]); if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } return DB::transaction(function () use ($data) { @@ -94,7 +94,7 @@ class ServiceRepository ]); if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } return DB::transaction(function () use ($data, $service) { diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index e9cd8580f..714718cbd 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -67,7 +67,7 @@ class UserRepository // Run validator, throw catchable and displayable exception if it fails. // Exception includes a JSON result of failed validation rules. if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } DB::beginTransaction(); @@ -141,7 +141,7 @@ class UserRepository // Run validator, throw catchable and displayable exception if it fails. // Exception includes a JSON result of failed validation rules. if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } // The password and root_admin fields are not mass assignable. diff --git a/app/Repositories/VariableRepository.php b/app/Repositories/VariableRepository.php index c707788d3..ee6885280 100644 --- a/app/Repositories/VariableRepository.php +++ b/app/Repositories/VariableRepository.php @@ -63,7 +63,7 @@ class VariableRepository }); if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } if (isset($data['env_variable'])) { @@ -137,7 +137,7 @@ class VariableRepository }); if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } if (isset($data['env_variable'])) { From 198a021a9748b2cff5b290b712abb1c7cb1b2400 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 16 Mar 2017 19:35:29 -0400 Subject: [PATCH 344/599] Add database host management to panel. --- CHANGELOG.md | 2 + .../Controllers/Admin/DatabaseController.php | 130 ++++++++------ .../Controllers/Admin/ServersController.php | 2 +- app/Http/Routes/AdminRoutes.php | 23 +++ app/Models/Database.php | 10 +- .../{DatabaseServer.php => DatabaseHost.php} | 18 +- app/Repositories/DatabaseRepository.php | 163 ++++++++++++------ ...eOrganizeDatabaseServersToDatabaseHost.php | 48 ++++++ ..._03_16_181515_CleanupDatabasesDatabase.php | 40 +++++ .../admin/databases/index.blade.php | 149 ++++++++++++++++ .../admin/databases/view.blade.php | 143 +++++++++++++++ .../pterodactyl/layouts/admin.blade.php | 2 +- 12 files changed, 605 insertions(+), 125 deletions(-) rename app/Models/{DatabaseServer.php => DatabaseHost.php} (84%) create mode 100644 database/migrations/2017_03_16_181109_ReOrganizeDatabaseServersToDatabaseHost.php create mode 100644 database/migrations/2017_03_16_181515_CleanupDatabasesDatabase.php create mode 100644 resources/themes/pterodactyl/admin/databases/index.blade.php create mode 100644 resources/themes/pterodactyl/admin/databases/view.blade.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 2aaf6b6dc..c6de40f1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Table seeders for services now can be run during upgrades and will attempt to locate and update, or create new if not found in the database. * Many structural changes to the database and `Pterodactyl\Models` classes that would flood this changelog if they were all included. All required migrations included to handle database changes. * `[pre.4]` — Service pack files are now stored in the database rather than on the host system to make updates easier. +* Clarified details for database hosts to prevent users entering invalid account details, as well as renamed tables and columns relating to it to keep things clearer. ### Fixed * Fixes potential bug with invalid CIDR notation (ex: `192.168.1.1/z`) when adding allocations that could cause over 4 million records to be created at once. @@ -22,6 +23,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Added * Ability to assign multiple allocations at once when creating a new server. * New `humanReadable` macro on `File` facade that accepts a file path and returns a human readable size. (`File::humanReadable(path, precision)`) +* Added ability to edit database host details after creation on the system. ### Deprecated * Old API calls to `Server::create` will fail due to changed data structure. diff --git a/app/Http/Controllers/Admin/DatabaseController.php b/app/Http/Controllers/Admin/DatabaseController.php index 7014c321b..e41575458 100644 --- a/app/Http/Controllers/Admin/DatabaseController.php +++ b/app/Http/Controllers/Admin/DatabaseController.php @@ -26,8 +26,10 @@ namespace Pterodactyl\Http\Controllers\Admin; use Log; use Alert; -use Pterodactyl\Models; use Illuminate\Http\Request; +use Pterodactyl\Models\Database; +use Pterodactyl\Models\Location; +use Pterodactyl\Models\DatabaseHost; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Repositories\DatabaseRepository; @@ -36,82 +38,98 @@ use Pterodactyl\Exceptions\DisplayValidationException; class DatabaseController extends Controller { /** - * Controller Constructor. + * Display database host index. + * + * @param Request $request + * @return \Illuminate\View\View */ - public function __construct() - { - // - } - - public function getIndex(Request $request) + public function index(Request $request) { return view('admin.databases.index', [ - 'databases' => Models\Database::with('server')->paginate(50), - 'hosts' => Models\DatabaseServer::withCount('databases')->with('node')->paginate(20), + 'locations' => Location::with('nodes')->get(), + 'hosts' => DatabaseHost::withCount('databases')->with('node')->get(), ]); } - public function getNew(Request $request) + /** + * Display database host to user. + * + * @param Request $request + * @param int $id + * @return \Illuminate\View\View + */ + public function view(Request $request, $id) { - return view('admin.databases.new', [ - 'nodes' => Models\Node::all()->load('location'), + return view('admin.databases.view', [ + 'locations' => Location::with('nodes')->get(), + 'host' => DatabaseHost::with('databases.server')->findOrFail($id), ]); } - public function postNew(Request $request) + /** + * Handle post request to create database host. + * + * @param Request $request + * @return \Illuminate\Response\RedirectResponse + */ + public function create(Request $request) { + $repo = new DatabaseRepository; + try { - $repo = new DatabaseRepository; - $repo->add($request->only([ - 'name', - 'host', - 'port', - 'username', - 'password', - 'linked_node', + $host = $repo->add($request->intersect([ + 'name', 'username', 'password', + 'host', 'port', 'node_id', ])); - Alert::success('Successfully added a new database server to the system.')->flash(); + Alert::success('Successfully created new database host on the system.')->flash(); - return redirect()->route('admin.databases', ['tab' => 'tab_dbservers']); + return redirect()->route('admin.databases.view', $host->id); + } catch (\PDOException $ex) { + Alert::danger($ex->getMessage())->flash(); } catch (DisplayValidationException $ex) { - return redirect()->route('admin.databases.new')->withErrors(json_decode($ex->getMessage()))->withInput(); + return redirect()->route('admin.databases')->withErrors(json_decode($ex->getMessage())); } catch (\Exception $ex) { - if ($ex instanceof DisplayException || $ex instanceof \PDOException) { - Alert::danger($ex->getMessage())->flash(); + Log::error($ex); + Alert::danger('An error was encountered while trying to process this request. This error has been logged.')->flash(); + } + + return redirect()->route('admin.databases'); + } + + /** + * Handle post request to update a database host. + * + * @param Request $request + * @param int $id + * @return \Illuminate\Response\RedirectResponse + */ + public function update(Request $request, $id) + { + $repo = new DatabaseRepository; + + try { + if ($request->input('action') !== 'delete') { + $host = $repo->update($id, $request->intersect([ + 'name', 'username', 'password', + 'host', 'port', 'node_id', + ])); + Alert::success('Database host was updated successfully.')->flash(); } else { - Log::error($ex); - Alert::danger('An error occurred while attempting to delete this database server from the system.')->flash(); + $repo->delete($id); + + return redirect()->route('admin.databases'); } - - return redirect()->route('admin.databases.new')->withInput(); - } - } - - public function deleteDatabase(Request $request, $id) - { - try { - $repo = new DatabaseRepository; - $repo->drop($id); + } catch (\PDOException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.databases.view', $id)->withErrors(json_decode($ex->getMessage())); } catch (\Exception $ex) { Log::error($ex); - - return response()->json([ - 'error' => ($ex instanceof DisplayException) ? $ex->getMessage() : 'An error occurred while attempting to delete this database from the system.', - ], 500); + Alert::danger('An error was encountered while trying to process this request. This error has been logged.')->flash(); } - } - public function deleteServer(Request $request, $id) - { - try { - $repo = new DatabaseRepository; - $repo->delete($id); - } catch (\Exception $ex) { - Log::error($ex); - - return response()->json([ - 'error' => ($ex instanceof DisplayException) ? $ex->getMessage() : 'An error occurred while attempting to delete this database server from the system.', - ], 500); - } + return redirect()->route('admin.databases.view', $id); } } diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 56dfdbad3..5ac430865 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -212,7 +212,7 @@ class ServersController extends Controller $server = Models\Server::where('installed', 1)->with('databases.host')->findOrFail($id); return view('admin.servers.view.database', [ - 'hosts' => Models\DatabaseServer::all(), + 'hosts' => Models\DatabaseHost::all(), 'server' => $server, ]); } diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index 8649e789f..41ab22482 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -43,6 +43,29 @@ class AdminRoutes 'uses' => 'Admin\BaseController@getIndex', ]); + $router->group([ + 'prefix' => 'admin/databases', + 'middleware' => [ + 'auth', + 'admin', + 'csrf', + ], + ], function () use ($router) { + $router->get('/', [ + 'as' => 'admin.databases', + 'uses' => 'Admin\DatabaseController@index', + ]); + + $router->post('/', 'Admin\DatabaseController@create'); + + $router->get('/view/{id}', [ + 'as' => 'admin.databases.view', + 'uses' => 'Admin\DatabaseController@view', + ]); + + $router->post('/view/{id}', 'Admin\DatabaseController@update'); + }); + $router->group([ 'prefix' => 'admin/locations', 'middleware' => [ diff --git a/app/Models/Database.php b/app/Models/Database.php index b5e9d39ad..e7f543466 100644 --- a/app/Models/Database.php +++ b/app/Models/Database.php @@ -43,11 +43,13 @@ class Database extends Model protected $hidden = ['password']; /** - * Fields that are not mass assignable. + * Fields that are mass assignable. * * @var array */ - protected $guarded = ['id', 'created_at', 'updated_at']; + protected $fillable = [ + 'server_id', 'database_host_id', 'database', 'username', 'remote', + ]; /** * Cast values to correct type. @@ -56,7 +58,7 @@ class Database extends Model */ protected $casts = [ 'server_id' => 'integer', - 'db_server' => 'integer', + 'database_host_id' => 'integer', ]; /** @@ -66,7 +68,7 @@ class Database extends Model */ public function host() { - return $this->belongsTo(DatabaseServer::class, 'db_server'); + return $this->belongsTo(DatabaseHost::class); } /** diff --git a/app/Models/DatabaseServer.php b/app/Models/DatabaseHost.php similarity index 84% rename from app/Models/DatabaseServer.php rename to app/Models/DatabaseHost.php index 1ebb7546f..0d5eaf30a 100644 --- a/app/Models/DatabaseServer.php +++ b/app/Models/DatabaseHost.php @@ -26,14 +26,14 @@ namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; -class DatabaseServer extends Model +class DatabaseHost extends Model { /** * The table associated with the model. * * @var string */ - protected $table = 'database_servers'; + protected $table = 'database_hosts'; /** * The attributes excluded from the model's JSON form. @@ -43,11 +43,13 @@ class DatabaseServer extends Model protected $hidden = ['password']; /** - * Fields that are not mass assignable. + * Fields that are mass assignable. * * @var array */ - protected $guarded = ['id', 'created_at', 'updated_at']; + protected $fillable = [ + 'name', 'host', 'port', 'username', 'max_databases', 'node_id', + ]; /** * Cast values to correct type. @@ -56,8 +58,8 @@ class DatabaseServer extends Model */ protected $casts = [ 'id' => 'integer', - 'server_id' => 'integer', - 'db_server' => 'integer', + 'max_databases' => 'integer', + 'node_id' => 'integer', ]; /** @@ -67,7 +69,7 @@ class DatabaseServer extends Model */ public function node() { - return $this->belongsTo(Node::class, 'linked_node'); + return $this->belongsTo(Node::class); } /** @@ -77,6 +79,6 @@ class DatabaseServer extends Model */ public function databases() { - return $this->hasMany(Database::class, 'db_server'); + return $this->hasMany(Database::class); } } diff --git a/app/Repositories/DatabaseRepository.php b/app/Repositories/DatabaseRepository.php index 5397fc5c7..7e1760b63 100644 --- a/app/Repositories/DatabaseRepository.php +++ b/app/Repositories/DatabaseRepository.php @@ -28,7 +28,9 @@ use DB; use Crypt; use Config; use Validator; -use Pterodactyl\Models; +use Pterodactyl\Models\Server; +use Pterodactyl\Models\Database; +use Pterodactyl\Models\DatabaseHost; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayValidationException; @@ -37,17 +39,16 @@ class DatabaseRepository /** * Adds a new database to a specified database host server. * - * @param int $server Id of the server to add a database for. - * @param array $options Array of options for creating that database. + * @param int $id + * @param array $data + * @return \Pterodactyl\Models\Database * * @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\DisplayValidationException - * @throws \Exception - * @return void */ - public function create($server, $data) + public function create($id, array $data) { - $server = Models\Server::findOrFail($server); + $server = Server::findOrFail($server); $validator = Validator::make($data, [ 'host' => 'required|exists:database_servers,id', @@ -56,16 +57,16 @@ class DatabaseRepository ]); if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } - $host = Models\DatabaseServer::findOrFail($data['host']); + $host = DatabaseHost::findOrFail($data['host']); DB::beginTransaction(); try { $database = Models\Database::firstOrNew([ 'server_id' => $server->id, - 'db_server' => $data['host'], + 'database_host_id' => $data['host'], 'database' => sprintf('s%d_%s', $server->id, $data['database']), ]); @@ -109,6 +110,8 @@ class DatabaseRepository // Save Everything DB::commit(); + + return $database; } catch (\Exception $ex) { try { DB::connection('dynamic')->statement(sprintf('DROP DATABASE IF EXISTS `%s`', $database->database)); @@ -124,18 +127,17 @@ class DatabaseRepository /** * Updates the password for a given database. - * @param int $id The ID of the database to modify. - * @param string $password The new password to use for the database. - * @return bool + * + * @param int $id + * @param string $password + * @return void */ public function password($id, $password) { $database = Models\Database::with('host')->findOrFail($id); - DB::beginTransaction(); - try { + DB::transaction(function () use ($database, $password) { $database->password = Crypt::encrypt($password); - $database->save(); Config::set('database.connections.dynamic', [ 'driver' => 'mysql', @@ -153,24 +155,21 @@ class DatabaseRepository $database->username, $database->remote, $password )); - DB::commit(); - } catch (\Exception $ex) { - DB::rollBack(); - throw $ex; - } + $database->save(); + }); } /** - * Drops a database from the associated MySQL Server. - * @param int $id The ID of the database to drop. - * @return bool + * Drops a database from the associated database host. + * + * @param int $id + * @return void */ public function drop($id) { - $database = Models\Database::with('host')->findOrFail($id); + $database = Database::with('host')->findOrFail($id); - DB::beginTransaction(); - try { + DB::transaction(function () use ($database) { Config::set('database.connections.dynamic', [ 'driver' => 'mysql', 'host' => $database->host->host, @@ -187,34 +186,35 @@ class DatabaseRepository DB::connection('dynamic')->statement('FLUSH PRIVILEGES'); $database->delete(); - - DB::commit(); - } catch (\Exception $ex) { - DB::rollback(); - throw $ex; - } + }); } /** - * Deletes a database server from the system if it is empty. + * Deletes a database host from the system if it has no associated databases. * - * @param int $server The ID of the Database Server. - * @return bool + * @param int $server + * @return void + * + * @throws \Pterodactyl\Exceptions\DisplayException */ - public function delete($server) + public function delete($id) { - $host = Models\DatabaseServer::withCount('databases')->findOrFail($server); + $host = DatabaseHost::withCount('databases')->findOrFail($id); if ($host->databases_count > 0) { - throw new DisplayException('You cannot delete a database server that has active databases attached to it.'); + throw new DisplayException('You cannot delete a database host that has active databases attached to it.'); } - return $host->delete(); + $host->delete(); } /** - * Adds a new Database Server to the system. - * @param array $data + * Adds a new Database Host to the system. + * + * @param array $data + * @return \Pterodactyl\Models\DatabaseHost + * + * @throws \Pterodactyl\Exceptions\DisplayValidationException */ public function add(array $data) { @@ -224,19 +224,18 @@ class DatabaseRepository $validator = Validator::make($data, [ 'name' => 'required|string|max:255', - 'host' => 'required|ip|unique:database_servers,host', + 'host' => 'required|ip|unique:database_hosts,host', 'port' => 'required|numeric|between:1,65535', 'username' => 'required|string|max:32', 'password' => 'required|string', - 'linked_node' => 'sometimes', + 'node_id' => 'sometimes|required|exists:nodes,id', ]); if ($validator->fails()) { - throw new DisplayValidationException($validator->errors()); + throw new DisplayValidationException(json_encode($validator->errors())); } - DB::beginTransaction(); - try { + return DB::transaction(function () use ($data) { Config::set('database.connections.dynamic', [ 'driver' => 'mysql', 'host' => $data['host'], @@ -251,20 +250,74 @@ class DatabaseRepository // Allows us to check that we can connect to things. DB::connection('dynamic')->select('SELECT 1 FROM dual'); - Models\DatabaseServer::create([ + $host = new DatabaseHost; + $host->password = Crypt::encrypt($data['password']); + + $host->fill([ 'name' => $data['name'], 'host' => $data['host'], 'port' => $data['port'], 'username' => $data['username'], - 'password' => Crypt::encrypt($data['password']), 'max_databases' => null, - 'linked_node' => (! empty($data['linked_node']) && $data['linked_node'] > 0) ? $data['linked_node'] : null, + 'node_id' => (isset($data['node_id'])) ? $data['node_id'] : null, + ])->save(); + + return $host; + }); + } + + /** + * Updates a Database Host on the system. + * + * @param int $id + * @param array $data + * @return \Pterodactyl\Models\DatabaseHost + * + * @throws \Pterodactyl\Exceptions\DisplayValidationException + */ + public function update($id, array $data) + { + $host = DatabaseHost::findOrFail($id); + + if (isset($data['host'])) { + $data['host'] = gethostbyname($data['host']); + } + + $validator = Validator::make($data, [ + 'name' => 'sometimes|required|string|max:255', + 'host' => 'sometimes|required|ip|unique:database_hosts,host,' . $host->id, + 'port' => 'sometimes|required|numeric|between:1,65535', + 'username' => 'sometimes|required|string|max:32', + 'password' => 'sometimes|required|string', + 'node_id' => 'sometimes|required|exists:nodes,id', + ]); + + if ($validator->fails()) { + throw new DisplayValidationException(json_encode($validator->errors())); + } + + return DB::transaction(function () use ($data, $host) { + if (isset($data['password'])) { + $host->password = Crypt::encrypt($data['password']); + } + $host->fill($data)->save(); + + // Check that we can still connect with these details. + Config::set('database.connections.dynamic', [ + 'driver' => 'mysql', + 'host' => $host->host, + 'port' => $host->port, + 'database' => 'mysql', + 'username' => $host->username, + 'password' => Crypt::decrypt($host->password), + 'charset' => 'utf8', + 'collation' => 'utf8_unicode_ci', ]); - DB::commit(); - } catch (\Exception $ex) { - DB::rollBack(); - throw $ex; - } + // Allows us to check that we can connect to things. + DB::connection('dynamic')->select('SELECT 1 FROM dual'); + + return $host; + }); } } diff --git a/database/migrations/2017_03_16_181109_ReOrganizeDatabaseServersToDatabaseHost.php b/database/migrations/2017_03_16_181109_ReOrganizeDatabaseServersToDatabaseHost.php new file mode 100644 index 000000000..50699a688 --- /dev/null +++ b/database/migrations/2017_03_16_181109_ReOrganizeDatabaseServersToDatabaseHost.php @@ -0,0 +1,48 @@ +dropForeign(['linked_node']); + }); + + Schema::rename('database_servers', 'database_hosts'); + + Schema::table('database_hosts', function (Blueprint $table) { + $table->renameColumn('linked_node', 'node_id'); + + $table->foreign('node_id')->references('id')->on('nodes'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('database_hosts', function (Blueprint $table) { + $table->dropForeign(['node_id']); + }); + + Schema::rename('database_hosts', 'database_servers'); + + Schema::table('database_servers', function (Blueprint $table) { + $table->renameColumn('node_id', 'linked_node'); + + $table->foreign('linked_node')->references('id')->on('nodes'); + }); + } +} diff --git a/database/migrations/2017_03_16_181515_CleanupDatabasesDatabase.php b/database/migrations/2017_03_16_181515_CleanupDatabasesDatabase.php new file mode 100644 index 000000000..07192f898 --- /dev/null +++ b/database/migrations/2017_03_16_181515_CleanupDatabasesDatabase.php @@ -0,0 +1,40 @@ +dropForeign(['db_server']); + + $table->renameColumn('db_server', 'database_host_id'); + + $table->foreign('database_host_id')->references('id')->on('database_hosts'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('databases', function (Blueprint $table) { + $table->dropForeign(['database_host_id']); + + $table->renameColumn('database_host_id', 'db_server'); + + $table->foreign('db_server')->references('id')->on('database_hosts'); + }); + } +} diff --git a/resources/themes/pterodactyl/admin/databases/index.blade.php b/resources/themes/pterodactyl/admin/databases/index.blade.php new file mode 100644 index 000000000..b2735849a --- /dev/null +++ b/resources/themes/pterodactyl/admin/databases/index.blade.php @@ -0,0 +1,149 @@ +{{-- 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') + Database Hosts +@endsection + +@section('content-header') +

      Database HostsDatabase hosts that servers can have databases created on.

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

      Host List

      +
      +
      + + + + + + + + + + + + @foreach ($hosts as $host) + + + + + + + + + + @endforeach + +
      IDNameHostPortUsernameDatabasesNode
      {{ $host->id }}{{ $host->name }}{{ $host->host }}{{ $host->port }}{{ $host->username }}{{ $host->databases_count }} + @if(! is_null($host->node)) + {{ $host->node->name }} + @else + None + @endif +
      +
      + +
      +
      +
      + +@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/themes/pterodactyl/admin/databases/view.blade.php b/resources/themes/pterodactyl/admin/databases/view.blade.php new file mode 100644 index 000000000..ab331921c --- /dev/null +++ b/resources/themes/pterodactyl/admin/databases/view.blade.php @@ -0,0 +1,143 @@ +{{-- 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') + Database Hosts → View → {{ $host->name }} +@endsection + +@section('content-header') +

      {{ $host->name }}Viewing associated databases and details for this database host.

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

      Host Details

      +
      +
      +
      + + +
      +
      + + +

      The IP address or FQDN that should be used when attempting to connect to this MySQL host from the panel to add new databases.

      +
      +
      + + +

      The port that MySQL is running on for this host.

      +
      +
      + + +

      This setting does nothing other than default to this database host when adding a database to a server on the selected node.

      +
      +
      +
      +
      +
      +
      +
      +

      User Details

      +
      +
      +
      + + +

      The username of an account that has enough permissions to create new users and databases on the system.

      +
      +
      + + +

      The password to the account defined. Leave blank to continue using the assigned password.

      +
      +
      +

      The account defined for this database host must have the WITH GRANT OPTION permission. If the defined account does not have this permission requests to create databases will fail. Do not use the same account details for MySQL that you have defined for this panel.

      +
      + +
      +
      +
      +
      +
      +
      +
      +
      +

      Databases

      +
      +
      + + + + + + + + + @foreach($host->databases as $database) + + + + + + + + @endforeach +
      ServerDatabase NameUsernameConnections From
      {{ $database->server->name }}{{ $database->database }}{{ $database->username }}{{ $database->remote }} + + + +
      +
      +
      +
      +
      +@endsection + +@section('footer-scripts') + @parent + +@endsection diff --git a/resources/themes/pterodactyl/layouts/admin.blade.php b/resources/themes/pterodactyl/layouts/admin.blade.php index 85ac74160..9a17d3119 100644 --- a/resources/themes/pterodactyl/layouts/admin.blade.php +++ b/resources/themes/pterodactyl/layouts/admin.blade.php @@ -92,7 +92,7 @@
    • MANAGEMENT
    • - + Databases
    • From 955d89c0c61481381d741415bdda6fdf03c251a7 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 16 Mar 2017 19:48:24 -0400 Subject: [PATCH 345/599] Move everything over to pterodactyl theme --- resources/lang/en/base.php | 8 + .../themes/pterodactyl/errors/403.blade.php | 1 - .../pterodactyl}/errors/503.blade.php | 2 +- .../pterodactyl}/errors/installing.blade.php | 30 ++- .../pterodactyl}/errors/suspended.blade.php | 28 ++- .../views/admin/databases/index.blade.php | 150 ------------- resources/views/admin/databases/new.blade.php | 103 --------- .../views/admin/locations/index.blade.php | 211 ------------------ resources/views/vendor/.gitkeep | 0 .../notifications/email-plain.blade.php | 22 -- .../vendor/notifications/email.blade.php | 192 ---------------- .../vendor/pagination/bootstrap-4.blade.php | 36 --- .../views/vendor/pagination/default.blade.php | 36 --- .../pagination/simple-bootstrap-4.blade.php | 17 -- .../pagination/simple-default.blade.php | 17 -- 15 files changed, 45 insertions(+), 808 deletions(-) rename resources/{views => themes/pterodactyl}/errors/503.blade.php (94%) rename resources/{views => themes/pterodactyl}/errors/installing.blade.php (63%) rename resources/{views => themes/pterodactyl}/errors/suspended.blade.php (61%) delete mode 100644 resources/views/admin/databases/index.blade.php delete mode 100644 resources/views/admin/databases/new.blade.php delete mode 100644 resources/views/admin/locations/index.blade.php delete mode 100644 resources/views/vendor/.gitkeep delete mode 100644 resources/views/vendor/notifications/email-plain.blade.php delete mode 100644 resources/views/vendor/notifications/email.blade.php delete mode 100644 resources/views/vendor/pagination/bootstrap-4.blade.php delete mode 100644 resources/views/vendor/pagination/default.blade.php delete mode 100644 resources/views/vendor/pagination/simple-bootstrap-4.blade.php delete mode 100644 resources/views/vendor/pagination/simple-default.blade.php diff --git a/resources/lang/en/base.php b/resources/lang/en/base.php index c71f04578..52ad3f144 100644 --- a/resources/lang/en/base.php +++ b/resources/lang/en/base.php @@ -13,6 +13,14 @@ return [ 'header' => 'File Not Found', 'desc' => 'We were unable to locate the requested resource on the server.', ], + 'installing' => [ + 'header' => 'Server Installing', + 'desc' => 'The requested server is still completing the install process. Please check back in a few minutes, you should recieve an email as soon as this process is completed.', + ], + 'suspended' => [ + 'header' => 'Server Suspended', + 'desc' => 'This server has been suspended and cannot be accessed.', + ], ], 'index' => [ 'header' => 'Your Servers', diff --git a/resources/themes/pterodactyl/errors/403.blade.php b/resources/themes/pterodactyl/errors/403.blade.php index 225852a15..43aa58e1e 100644 --- a/resources/themes/pterodactyl/errors/403.blade.php +++ b/resources/themes/pterodactyl/errors/403.blade.php @@ -27,7 +27,6 @@ @endsection @section('content') -
      diff --git a/resources/views/errors/503.blade.php b/resources/themes/pterodactyl/errors/503.blade.php similarity index 94% rename from resources/views/errors/503.blade.php rename to resources/themes/pterodactyl/errors/503.blade.php index 4a4150592..7d55e46ad 100644 --- a/resources/views/errors/503.blade.php +++ b/resources/themes/pterodactyl/errors/503.blade.php @@ -40,7 +40,7 @@
      -
      Be right back.
      +
      Be right back!
      diff --git a/resources/views/errors/installing.blade.php b/resources/themes/pterodactyl/errors/installing.blade.php similarity index 63% rename from resources/views/errors/installing.blade.php rename to resources/themes/pterodactyl/errors/installing.blade.php index 8a8d5c292..dea162251 100644 --- a/resources/views/errors/installing.blade.php +++ b/resources/themes/pterodactyl/errors/installing.blade.php @@ -17,24 +17,30 @@ {{-- 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.master') +@extends('layouts.error') -@section('title', '503: Server Temporarily Unavaliable') +@section('title') + @lang('base.errors.installing.header') +@endsection + +@section('content-header') +@endsection @section('content') -
      -
      -
      -

      HTTP 503: Temporarily Unavaliable

      -
      -
      -

      The requested server is still completing the install process. Please check back in a few minutes, you should recieve an email as soon as this process is completed.

      -

      +
      +
      +
      -
      +
      +
      +
      +

      @lang('base.errors.installing.desc')

      +
      +
      -

      Take me back or go home.

      @endsection diff --git a/resources/views/errors/suspended.blade.php b/resources/themes/pterodactyl/errors/suspended.blade.php similarity index 61% rename from resources/views/errors/suspended.blade.php rename to resources/themes/pterodactyl/errors/suspended.blade.php index f96f13d60..e5cfebb35 100644 --- a/resources/views/errors/suspended.blade.php +++ b/resources/themes/pterodactyl/errors/suspended.blade.php @@ -17,20 +17,28 @@ {{-- 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.master') +@extends('layouts.error') -@section('title', '503: Server Temporarily Unavaliable') +@section('title') + @lang('base.errors.suspended.header') +@endsection + +@section('content-header') +@endsection @section('content') -
      -
      -
      -

      HTTP 403: Access Denied

      -
      -
      -

      This server has been suspended and cannot be accessed.

      +
      +
      +
      +
      +

      401

      +

      @lang('base.errors.suspended.desc')

      +
      +
      -

      Take me back or go home.

      @endsection diff --git a/resources/views/admin/databases/index.blade.php b/resources/views/admin/databases/index.blade.php deleted file mode 100644 index f1c2a4aac..000000000 --- a/resources/views/admin/databases/index.blade.php +++ /dev/null @@ -1,150 +0,0 @@ -{{-- 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') - Database Management -@endsection - -@section('content') -
      - -

      Manage Databases


      - -
      -
      -
      -
      -
      - - - - - - - - - - - - - @foreach($databases as $database) - - - - - where('id', $database->db_server)->first(); ?> - - - - - @endforeach - -
      ServerDatabaseUsernameConnection
      {{ $database->server->name }}{{ $database->database }}{{ $database->username }} ({{ $database->remote }}){{ $host->host }}:{{ $host->port }}
      -
      - {{ $databases->appends(['tab' => 'tab_databases'])->links() }} -
      -
      -
      -
      -
      -
      -
      -
      - - - - - - - - - - - - - @foreach($hosts as $database) - - - - - - - - - @endforeach - -
      NameConnectionUsernameDatabasesLinked Node
      {{ $database->name }}{{ $database->host }}:{{ $database->port }}{{ $database->username }}{{ $database->databases_count }}@if(is_null($database->node))unlinked@else{{ $database->node->name }}@endif
      -
      - {{ $hosts->appends('tab', 'tab_dbservers')->render() }} -
      -
      -
      -
      -
      -
      - -@endsection diff --git a/resources/views/admin/databases/new.blade.php b/resources/views/admin/databases/new.blade.php deleted file mode 100644 index c9625cd75..000000000 --- a/resources/views/admin/databases/new.blade.php +++ /dev/null @@ -1,103 +0,0 @@ -{{-- 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') - Add New Database Server -@endsection - -@section('content') -
      - -

      New Database Server


      -
      If you are trying to add a new database to an existing server please visit that server's control page and visit the 'Databases' tab. This page is for adding a new database server that individual per-server databases can be deployed to.
      -
      -
      -
      - -
      - -

      Enter a descriptive name for this database server.

      -
      -
      -
      - -
      - -

      A linked node implies that this Database Server is running on that node and it will be auto-selected when adding a database to servers on that node.

      -
      -
      -
      -
      -
      -
      - -
      - -

      Enter the IP address that this database server is listening on.

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

      The panel must be able to access this database, you may need to allow access from {{ Request::server('SERVER_ADDR') }} for this user.

      -
      -
      -
      - -
      - -
      -
      -
      -
      -
      -
      - {!! csrf_field() !!} - -
      -
      -
      -
      -
      - -@endsection diff --git a/resources/views/admin/locations/index.blade.php b/resources/views/admin/locations/index.blade.php deleted file mode 100644 index 2fbd4b05a..000000000 --- a/resources/views/admin/locations/index.blade.php +++ /dev/null @@ -1,211 +0,0 @@ -{{-- 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') - Location List -@endsection - -@section('content') -
      - -

      All Locations


      - - - - - - - - - - - - - @foreach ($locations as $location) - - - - - - - - - @endforeach - -
      LocationDescriptionNodesServers
      {{ $location->short }}{{ $location->long }}{{ $location->nodes_count }}{{ $location->servers_count }}
      -
      -
      {!! $locations->render() !!}
      -
      -
      -
      -
      - -
      -
      -
      -
      - - - -@endsection diff --git a/resources/views/vendor/.gitkeep b/resources/views/vendor/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/resources/views/vendor/notifications/email-plain.blade.php b/resources/views/vendor/notifications/email-plain.blade.php deleted file mode 100644 index 7bd992481..000000000 --- a/resources/views/vendor/notifications/email-plain.blade.php +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - 'margin: 0; padding: 0; width: 100%; background-color: #F2F4F6;', - 'email-wrapper' => 'width: 100%; margin: 0; padding: 0; background-color: #F2F4F6;', - - /* Masthead ----------------------- */ - - 'email-masthead' => 'padding: 25px 0; text-align: center;', - 'email-masthead_name' => 'font-size: 16px; font-weight: bold; color: #2F3133; text-decoration: none; text-shadow: 0 1px 0 white;', - - 'email-body' => 'width: 100%; margin: 0; padding: 0; border-top: 1px solid #EDEFF2; border-bottom: 1px solid #EDEFF2; background-color: #FFF;', - 'email-body_inner' => 'width: auto; max-width: 570px; margin: 0 auto; padding: 0;', - 'email-body_cell' => 'padding: 35px;', - - 'email-footer' => 'width: auto; max-width: 570px; margin: 0 auto; padding: 0; text-align: center;', - 'email-footer_cell' => 'color: #AEAEAE; padding: 35px; text-align: center;', - - /* Body ------------------------------ */ - - 'body_action' => 'width: 100%; margin: 30px auto; padding: 0; text-align: center;', - 'body_sub' => 'margin-top: 25px; padding-top: 25px; border-top: 1px solid #EDEFF2;', - - /* Type ------------------------------ */ - - 'anchor' => 'color: #3869D4;', - 'header-1' => 'margin-top: 0; color: #2F3133; font-size: 19px; font-weight: bold; text-align: left;', - 'paragraph' => 'margin-top: 0; color: #74787E; font-size: 16px; line-height: 1.5em;', - 'paragraph-sub' => 'margin-top: 0; color: #74787E; font-size: 12px; line-height: 1.5em;', - 'paragraph-center' => 'text-align: center;', - - /* Buttons ------------------------------ */ - - 'button' => 'display: block; display: inline-block; width: 200px; min-height: 20px; padding: 10px; - background-color: #3869D4; border-radius: 3px; color: #ffffff; font-size: 15px; line-height: 25px; - text-align: center; text-decoration: none; -webkit-text-size-adjust: none;', - - 'button--green' => 'background-color: #22BC66;', - 'button--red' => 'background-color: #dc4d2f;', - 'button--blue' => 'background-color: #3869D4;', -]; -?> - - - - - - - - -
      - - - - - - - - - - - - - - - -
      - - {{ Settings::get('company', 'Pterodactyl Panel') }} - -
      - - - - -
      - -

      - @if (! empty($greeting)) - {{ $greeting }} - @else - @if ($level == 'error') - Whoops! - @else - Hello! - @endif - @endif -

      - - - @foreach ($introLines as $line) -

      - {{ $line }} -

      - @endforeach - - - @if (isset($actionText)) - - - - -
      - - - - {{ $actionText }} - -
      - @endif - - - @foreach ($outroLines as $line) -

      - {{ $line }} -

      - @endforeach - - -

      - Regards,
      {{ Settings::get('company') }} -

      - - - @if (isset($actionText)) - - - - -
      -

      - If you’re having trouble clicking the "{{ $actionText }}" button, - copy and paste the URL below into your web browser: -

      - -

      - - {{ $actionUrl }} - -

      -
      - @endif -
      -
      - - - - -
      -

      - © {{ date('Y') }} - {{ Settings::get('company', 'Pterodactyl Panel') }}. - All rights reserved. -

      -
      -
      -
      - - diff --git a/resources/views/vendor/pagination/bootstrap-4.blade.php b/resources/views/vendor/pagination/bootstrap-4.blade.php deleted file mode 100644 index 9d80428cc..000000000 --- a/resources/views/vendor/pagination/bootstrap-4.blade.php +++ /dev/null @@ -1,36 +0,0 @@ -@if ($paginator->count() > 1) -
        - - @if ($paginator->onFirstPage()) -
      • «
      • - @else -
      • - @endif - - - @foreach ($elements as $element) - - @if (is_string($element)) -
      • {{ $element }}
      • - @endif - - - @if (is_array($element)) - @foreach ($element as $page => $url) - @if ($page == $paginator->currentPage()) -
      • {{ $page }}
      • - @else -
      • {{ $page }}
      • - @endif - @endforeach - @endif - @endforeach - - - @if ($paginator->hasMorePages()) -
      • - @else -
      • »
      • - @endif -
      -@endif diff --git a/resources/views/vendor/pagination/default.blade.php b/resources/views/vendor/pagination/default.blade.php deleted file mode 100644 index 26e56994f..000000000 --- a/resources/views/vendor/pagination/default.blade.php +++ /dev/null @@ -1,36 +0,0 @@ -@if ($paginator->lastPage() > 1) -
        - - @if ($paginator->onFirstPage()) - {{--
      • «
      • --}} - @else -
      • - @endif - - - @foreach ($elements as $element) - - @if (is_string($element)) -
      • {{ $element }}
      • - @endif - - - @if (is_array($element)) - @foreach ($element as $page => $url) - @if ($page == $paginator->currentPage()) -
      • {{ $page }}
      • - @else -
      • {{ $page }}
      • - @endif - @endforeach - @endif - @endforeach - - - @if ($paginator->hasMorePages()) -
      • - @else - {{--
      • »
      • --}} - @endif -
      -@endif diff --git a/resources/views/vendor/pagination/simple-bootstrap-4.blade.php b/resources/views/vendor/pagination/simple-bootstrap-4.blade.php deleted file mode 100644 index 4b14efeb5..000000000 --- a/resources/views/vendor/pagination/simple-bootstrap-4.blade.php +++ /dev/null @@ -1,17 +0,0 @@ -@if ($paginator->count() > 1) -
        - - @if ($paginator->onFirstPage()) -
      • «
      • - @else -
      • - @endif - - - @if ($paginator->hasMorePages()) -
      • - @else -
      • »
      • - @endif -
      -@endif diff --git a/resources/views/vendor/pagination/simple-default.blade.php b/resources/views/vendor/pagination/simple-default.blade.php deleted file mode 100644 index a45097ee2..000000000 --- a/resources/views/vendor/pagination/simple-default.blade.php +++ /dev/null @@ -1,17 +0,0 @@ -@if ($paginator->count() > 1) -
        - - @if ($paginator->onFirstPage()) -
      • «
      • - @else -
      • - @endif - - - @if ($paginator->hasMorePages()) -
      • - @else -
      • »
      • - @endif -
      -@endif From 1aa191210a37382f7c658f789362e24a7f1fb2a5 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 16 Mar 2017 19:54:31 -0400 Subject: [PATCH 346/599] closes #344 --- CHANGELOG.md | 1 + app/Http/Controllers/Base/IndexController.php | 2 +- config/pterodactyl.php | 14 ++++++++++++++ resources/themes/pterodactyl/base/index.blade.php | 5 +++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6de40f1b..e655bbe97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Fixes potential bug with invalid CIDR notation (ex: `192.168.1.1/z`) when adding allocations that could cause over 4 million records to be created at once. * `[pre.4]` — Fixes bug preventing server updates from occurring by the system due to undefined `Auth::user()` in the event listener. * `[pre.4]` — Fixes `Server::byUuid()` caching to actually clear the cache for *all* users, rather than the logged in user by using cache tags. +* `[pre.4]` — Fixes server listing on frontend not displaying a page selector when more than 10 servers exist. ### Added * Ability to assign multiple allocations at once when creating a new server. diff --git a/app/Http/Controllers/Base/IndexController.php b/app/Http/Controllers/Base/IndexController.php index f6abf4ea4..5b6fab3a7 100644 --- a/app/Http/Controllers/Base/IndexController.php +++ b/app/Http/Controllers/Base/IndexController.php @@ -47,7 +47,7 @@ class IndexController extends Controller public function getIndex(Request $request) { return view('base.index', [ - 'servers' => $request->user()->serverAccessCollection(10), + 'servers' => $request->user()->serverAccessCollection(config('pterodactyl.paginate.frontend.servers')), ]); } diff --git a/config/pterodactyl.php b/config/pterodactyl.php index 30ea7ef97..77a946adb 100644 --- a/config/pterodactyl.php +++ b/config/pterodactyl.php @@ -16,4 +16,18 @@ return [ 'author' => env('SERVICE_AUTHOR'), ], + /* + |-------------------------------------------------------------------------- + | Pagination + |-------------------------------------------------------------------------- + | + | Certain pagination result counts can be configured here and will take + | effect globally. + */ + 'paginate' => [ + 'frontend' => [ + 'servers' => 15, + ], + ], + ]; diff --git a/resources/themes/pterodactyl/base/index.blade.php b/resources/themes/pterodactyl/base/index.blade.php index 71efda93f..8ce413888 100644 --- a/resources/themes/pterodactyl/base/index.blade.php +++ b/resources/themes/pterodactyl/base/index.blade.php @@ -78,6 +78,11 @@
      + @if($servers->hasPages()) + + @endif
      From b8c3ab6960c1eb513d8e941edbfff445349333f9 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 16 Mar 2017 19:56:58 -0400 Subject: [PATCH 347/599] closes #339 --- CHANGELOG.md | 1 + app/Http/Controllers/Base/APIController.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e655bbe97..b2841bb7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * `[pre.4]` — Fixes bug preventing server updates from occurring by the system due to undefined `Auth::user()` in the event listener. * `[pre.4]` — Fixes `Server::byUuid()` caching to actually clear the cache for *all* users, rather than the logged in user by using cache tags. * `[pre.4]` — Fixes server listing on frontend not displaying a page selector when more than 10 servers exist. +* `[pre.4]` — Fixes non-admin users being unable to create personal API keys. ### Added * Ability to assign multiple allocations at once when creating a new server. diff --git a/app/Http/Controllers/Base/APIController.php b/app/Http/Controllers/Base/APIController.php index 68045a722..f4133bc7f 100644 --- a/app/Http/Controllers/Base/APIController.php +++ b/app/Http/Controllers/Base/APIController.php @@ -52,7 +52,7 @@ class APIController extends Controller { try { $repo = new APIRepository($request->user()); - $secret = $repo->create($request->only([ + $secret = $repo->create($request->intersect([ 'memo', 'allowed_ips', 'adminPermissions', 'permissions', ])); From 48e261bb91333e5522553d126f0a03a4ae1487ac Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 16 Mar 2017 19:59:24 -0400 Subject: [PATCH 348/599] closes #288 --- CHANGELOG.md | 1 + database/seeds/SourceServiceTableSeeder.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2841bb7f..5e2a117db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * `[pre.4]` — Fixes `Server::byUuid()` caching to actually clear the cache for *all* users, rather than the logged in user by using cache tags. * `[pre.4]` — Fixes server listing on frontend not displaying a page selector when more than 10 servers exist. * `[pre.4]` — Fixes non-admin users being unable to create personal API keys. +* Fixes bug where daemon was unable to register that certain games had fully booted and were ready to play on. ### Added * Ability to assign multiple allocations at once when creating a new server. diff --git a/database/seeds/SourceServiceTableSeeder.php b/database/seeds/SourceServiceTableSeeder.php index 08e941ed5..226387c1c 100644 --- a/database/seeds/SourceServiceTableSeeder.php +++ b/database/seeds/SourceServiceTableSeeder.php @@ -76,7 +76,7 @@ class SourceServiceTableSeeder extends Seeder 'name' => 'Custom Source Engine Game', 'description' => 'This option allows modifying the startup arguments and other details to run a custo SRCDS based game on the panel.', 'docker_image' => 'quay.io/pterodactyl/srcds', - 'config_startup' => '{"done": "Assigned anonymous gameserver", "userInteraction": []}', + 'config_startup' => '{"done": "gameserver Steam ID", "userInteraction": []}', 'config_files' => '{}', 'config_logs' => '{"custom": true, "location": "logs/latest.log"}', 'config_stop' => 'quit', From 34d5e81b7a195a73d102652cb3f49bcbace78724 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 16 Mar 2017 20:29:48 -0400 Subject: [PATCH 349/599] Fix new server page display --- public/themes/pterodactyl/js/admin/new-server.js | 9 ++------- resources/themes/pterodactyl/admin/servers/new.blade.php | 9 +++------ 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/public/themes/pterodactyl/js/admin/new-server.js b/public/themes/pterodactyl/js/admin/new-server.js index 3e82cb1ad..f3de55bee 100644 --- a/public/themes/pterodactyl/js/admin/new-server.js +++ b/public/themes/pterodactyl/js/admin/new-server.js @@ -162,11 +162,6 @@ $('#pOptionId').on('change', function (event) { $('#pStartup').val(_.get(objectChain, 'startup')); } - if (!_.get(objectChain, 'executable', false)) { - $('#pStartupExecutable').html(_.get(parentChain, 'executable', 'ERROR: Exec Not Defined!')); - } else { - $('#pStartupExecutable').html(_.get(objectChain, 'executable')); - } $('#pPackId').html('').select2({ data: [{ id: 0, text: 'No Service Pack' }].concat( $.map(_.get(objectChain, 'packs', []), function (item, i) { @@ -186,8 +181,8 @@ $('#pOptionId').on('change', function (event) { \ \

      ' + item.description + '
      \ - Access in Startup: @{{' + item.env_variable + '}}
      \ - Validation Regex: ' + item.regex + '

      \ + Access in Startup: {{' + item.env_variable + '}}
      \ + Validation Rules: ' + item.rules + '

      \
      \ '; $('#appendVariablesTo').append(dataAppend); diff --git a/resources/themes/pterodactyl/admin/servers/new.blade.php b/resources/themes/pterodactyl/admin/servers/new.blade.php index fbb0868d6..55c6c6cad 100644 --- a/resources/themes/pterodactyl/admin/servers/new.blade.php +++ b/resources/themes/pterodactyl/admin/servers/new.blade.php @@ -147,14 +147,14 @@
      - + %
      - + I/O
      @@ -229,10 +229,7 @@
      -
      - - -
      +

      The following data replacers are avaliable 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.

      From be60299089efe112a1deaa4551254ae2ca0553c1 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 16 Mar 2017 20:49:11 -0400 Subject: [PATCH 350/599] Send correct container to daemon --- app/Repositories/ServerRepository.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index adf05a293..5ffbe65c2 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -94,6 +94,7 @@ class ServerRepository 'option_id' => 'required|numeric|min:1|exists:service_options,id', 'location_id' => 'required|numeric|min:1|exists:locations,id', 'pack_id' => 'sometimes|nullable|numeric|min:0', + 'custom_container' => 'string', 'startup' => 'string', 'auto_deploy' => 'sometimes|boolean', 'custom_id' => 'sometimes|required|numeric|unique:servers,id', @@ -256,7 +257,7 @@ class ServerRepository 'pack_id' => $data['pack_id'], 'startup' => $data['startup'], 'daemonSecret' => $uuid->generate('servers', 'daemonSecret'), - 'image' => (isset($data['custom_container'])) ? $data['custom_container'] : $option->docker_image, + 'image' => (isset($data['custom_container']) && ! empty($data['custom_container'])) ? $data['custom_container'] : $option->docker_image, 'username' => $this->generateSFTPUsername($data['name'], $genShortUuid), 'sftp_password' => Crypt::encrypt('not set'), ]); From 4ad09c5435e12a9ab216ca0e8a882e597ad3ed84 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 16 Mar 2017 21:11:15 -0400 Subject: [PATCH 351/599] Fixes bug introduced during admin rewrite that broke server creation --- .../Controllers/Admin/ServersController.php | 3 +- app/Models/Node.php | 4 +- app/Repositories/ServerRepository.php | 73 +++++++++---------- config/pterodactyl.php | 30 +++++--- 4 files changed, 60 insertions(+), 50 deletions(-) diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 5ac430865..3de8d0c9f 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -454,9 +454,10 @@ class ServersController extends Controller * * @param Request $request * @param int $id + * @param string $method * @return \Illuminate\Response\RedirectResponse */ - public function continueDeletion(Request $request, $id, $method) + public function continueDeletion(Request $request, $id, $method = 'safe') { $repo = new ServerRepository; diff --git a/app/Models/Node.php b/app/Models/Node.php index 928633095..f1a3159be 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -97,8 +97,8 @@ class Node extends Model { return new Client([ 'base_uri' => sprintf('%s://%s:%s/', $this->scheme, $this->fqdn, $this->daemonListen), - 'timeout' => env('GUZZLE_TIMEOUT', 5.0), - 'connect_timeout' => env('GUZZLE_CONNECT_TIMEOUT', 3.0), + 'timeout' => config('pterodactyl.guzzle.timeout'), + 'connect_timeout' => config('pterodactyl.guzzle.connect_timeout'), 'headers' => $headers, ]); } diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 5ffbe65c2..223659fcd 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -314,10 +314,10 @@ class ServerRepository 'io' => (int) $server->io, 'cpu' => (int) $server->cpu, 'disk' => (int) $server->disk, - 'image' => (isset($data['custom_container'])) ? $data['custom_container'] : $option->docker_image, + 'image' => $server->image, ], 'service' => [ - 'type' => $service->file, + 'type' => $service->folder, 'option' => $option->tag, 'pack' => (isset($pack)) ? $pack->uuid : null, ], @@ -701,7 +701,6 @@ class ServerRepository $server->installed = 3; $server->save(); } - $server->delete(); return DB::commit(); @@ -713,7 +712,7 @@ class ServerRepository public function delete($id, $force = false) { - $server = Models\Server::withTrashed()->with('node')->findOrFail($id); + $server = Models\Server::withTrashed()->with('node', 'allocations', 'variables')->findOrFail($id); // Handle server being restored previously or // an accidental queue. @@ -721,17 +720,34 @@ class ServerRepository return; } - DB::beginTransaction(); + // Due to MySQL lockouts if the daemon response fails, we need to + // delete the server from the daemon first. If it succeedes and then + // MySQL fails, users just need to force delete the server. + // + // If this is a force delete, continue anyways. try { - // Unassign Allocations - Models\Allocation::where('server_id', $server->id)->update([ - 'server_id' => null, - ]); + $server->node->guzzleClient([ + 'X-Access-Token' => $server->node->daemonSecret, + 'X-Access-Server' => $server->uuid, + ])->request('DELETE', '/servers'); + } catch (TransferException $ex) { + if ($server->installed !== 3 && ! $force) { + throw new DisplayException($ex->getMessage()); + } + } catch (\Exception $ex) { + throw $ex; + } - // Remove Variables - Models\ServerVariable::where('server_id', $server->id)->delete(); + DB::transaction(function () use ($server) { + $server->allocations->each(function ($item) { + $item->server_id = null; + $item->save(); + }); + + $server->variables->each(function ($item) { + $item->delete(); + }); - // Remove SubUsers foreach (Models\Subuser::with('permissions')->where('server_id', $server->id)->get() as &$subuser) { foreach ($subuser->permissions as &$permission) { $permission->delete(); @@ -748,33 +764,14 @@ class ServerRepository // Delete Databases // This is the one un-recoverable point where // transactions will not save us. - // - // @TODO: move to post-deletion event as a queued task! - // $repository = new DatabaseRepository; - // foreach (Models\Database::select('id')->where('server_id', $server->id)->get() as &$database) { - // $repository->drop($database->id); - // } - - $server->node->guzzleClient([ - 'X-Access-Token' => $server->node->daemonSecret, - 'X-Access-Server' => $server->uuid, - ])->request('DELETE', '/servers'); - - $server->forceDelete(); - DB::commit(); - } catch (TransferException $ex) { - // Set installed is set to 3 when force deleting. - if ($server->installed === 3 || $force) { - $server->forceDelete(); - DB::commit(); - } else { - DB::rollBack(); - throw $ex; + $repository = new DatabaseRepository; + foreach (Models\Database::select('id')->where('server_id', $server->id)->get() as $database) { + $repository->drop($database->id); } - } catch (\Exception $ex) { - DB::rollBack(); - throw $ex; - } + + // Fully delete the server. + $server->forceDelete(); + }); } public function cancelDeletion($id) diff --git a/config/pterodactyl.php b/config/pterodactyl.php index 77a946adb..1b946c6a3 100644 --- a/config/pterodactyl.php +++ b/config/pterodactyl.php @@ -11,10 +11,10 @@ return [ | author of custom services, and make upgrades easier by identifying | standard Pterodactyl shipped services. */ - 'service' => [ - 'core' => 'ptrdctyl-v040-11e6-8b77-86f30ca893d3', - 'author' => env('SERVICE_AUTHOR'), - ], + 'service' => [ + 'core' => 'ptrdctyl-v040-11e6-8b77-86f30ca893d3', + 'author' => env('SERVICE_AUTHOR'), + ], /* |-------------------------------------------------------------------------- @@ -24,10 +24,22 @@ return [ | Certain pagination result counts can be configured here and will take | effect globally. */ - 'paginate' => [ - 'frontend' => [ - 'servers' => 15, - ], - ], + 'paginate' => [ + 'frontend' => [ + 'servers' => 15, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Guzzle Connections + |-------------------------------------------------------------------------- + | + | Configure the timeout to be used for Guzzle connections here. + */ + 'guzzle' => [ + 'timeout' => env('GUZZLE_TIMEOUT', 5), + 'connect_timeout' => env('GUZZLE_CONNECT_TIMEOUT', 3), + ], ]; From a5902bf39cc56ec7df2712f58652a18960244799 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Mar 2017 15:34:29 -0400 Subject: [PATCH 352/599] Show indicator of user permissions on server when listing --- resources/lang/en/strings.php | 4 ++++ resources/themes/pterodactyl/base/index.blade.php | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/resources/lang/en/strings.php b/resources/lang/en/strings.php index b3abb2bc1..2ceb4d2cf 100644 --- a/resources/lang/en/strings.php +++ b/resources/lang/en/strings.php @@ -65,4 +65,8 @@ return [ 'admin_cp' => 'Admin Control Panel', 'optional' => 'Optional', 'read_only' => 'Read Only', + 'relation' => 'Relation', + 'owner' => 'Owner', + 'admin' => 'Admin', + 'subuser' => 'Subuser', ]; diff --git a/resources/themes/pterodactyl/base/index.blade.php b/resources/themes/pterodactyl/base/index.blade.php index 8ce413888..b7d51e6ce 100644 --- a/resources/themes/pterodactyl/base/index.blade.php +++ b/resources/themes/pterodactyl/base/index.blade.php @@ -56,6 +56,7 @@ @lang('strings.connection') @lang('strings.memory') @lang('strings.cpu') + @lang('strings.relation') @lang('strings.status') @foreach($servers as $server) @@ -66,6 +67,15 @@ {{ $server->allocation->alias }}:{{ $server->allocation->port }} -- / {{ $server->memory === 0 ? '∞' : $server->memory }} MB -- % + + @if($server->user->id === Auth::user()->id) + @lang('strings.owner') + @elseif(Auth::user()->isRootAdmin()) + @lang('strings.admin') + @else + @lang('strings.subuser') + @endif + @if($server->suspended === 1) @lang('strings.suspended') From 7e45f917c7cd563753ade5095e1aabdee748371a Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Mar 2017 16:19:45 -0400 Subject: [PATCH 353/599] Fix subuser permissions in file manager --- .../Controllers/Server/ServerController.php | 2 +- app/Policies/ServerPolicy.php | 6 +- app/Repositories/SubuserRepository.php | 2 +- .../pterodactyl/server/users/view.blade.php | 146 +++++------------- 4 files changed, 43 insertions(+), 113 deletions(-) diff --git a/app/Http/Controllers/Server/ServerController.php b/app/Http/Controllers/Server/ServerController.php index c1514e334..751f36093 100644 --- a/app/Http/Controllers/Server/ServerController.php +++ b/app/Http/Controllers/Server/ServerController.php @@ -112,7 +112,7 @@ class ServerController extends Controller public function getAddFile(Request $request, $uuid) { $server = Models\Server::byUuid($uuid); - $this->authorize('add-files', $server); + $this->authorize('create-files', $server); $server->js(); diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php index 767dec13c..7079aaa19 100644 --- a/app/Policies/ServerPolicy.php +++ b/app/Policies/ServerPolicy.php @@ -253,14 +253,14 @@ class ServerPolicy * @param \Pterodactyl\Models\Server $server * @return bool */ - public function addFiles(User $user, Server $server) + public function createFiles(User $user, Server $server) { - return $this->checkPermission($user, $server, 'add-files'); + return $this->checkPermission($user, $server, 'create-files'); } /** * Check if user has permission to upload files to a server. - * This permission relies on the user having the 'add-files' permission as well due to page authorization. + * This permission relies on the user having the 'create-files' permission as well due to page authorization. * * @param \Pterodactyl\Models\User $user * @param \Pterodactyl\Models\Server $server diff --git a/app/Repositories/SubuserRepository.php b/app/Repositories/SubuserRepository.php index 2d9da4b29..a6e0123ce 100644 --- a/app/Repositories/SubuserRepository.php +++ b/app/Repositories/SubuserRepository.php @@ -62,7 +62,7 @@ class SubuserRepository 'list-files' => 's:files:get', 'edit-files' => 's:files:read', 'save-files' => 's:files:post', - 'create-files' => 's:files:post', + 'create-files' => 's:files:create', 'download-files' => null, 'upload-files' => 's:files:upload', 'delete-files' => 's:files:delete', diff --git a/resources/themes/pterodactyl/server/users/view.blade.php b/resources/themes/pterodactyl/server/users/view.blade.php index 925fbdf05..fdb4e0c0d 100644 --- a/resources/themes/pterodactyl/server/users/view.blade.php +++ b/resources/themes/pterodactyl/server/users/view.blade.php @@ -71,40 +71,30 @@

      @lang('server.users.new.power_header')

      -
      - +
      + + +

      @lang('server.users.new.start.description')

      -
      -