From 86c8ecdcdf1520729ab48e37e310faf38bef18d6 Mon Sep 17 00:00:00 2001 From: stanjg Date: Fri, 4 May 2018 15:02:51 +0200 Subject: [PATCH 01/66] Added the actual logic --- app/Http/Kernel.php | 2 ++ app/Http/Middleware/MaintenanceMiddleware.php | 27 ++++++++++++++++ app/Models/Node.php | 5 ++- app/Providers/RouteServiceProvider.php | 2 +- ..._05_04_123826_add_maintenance_to_nodes.php | 32 +++++++++++++++++++ resources/lang/en/base.php | 5 +++ .../pterodactyl/errors/maintenance.blade.php | 30 +++++++++++++++++ 7 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 app/Http/Middleware/MaintenanceMiddleware.php create mode 100644 database/migrations/2018_05_04_123826_add_maintenance_to_nodes.php create mode 100644 resources/themes/pterodactyl/errors/maintenance.blade.php diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index b6d44530..db01e70c 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -2,6 +2,7 @@ namespace Pterodactyl\Http; +use Pterodactyl\Http\Middleware\MaintenanceMiddleware; use Pterodactyl\Models\ApiKey; use Illuminate\Auth\Middleware\Authorize; use Illuminate\Auth\Middleware\Authenticate; @@ -108,6 +109,7 @@ class Kernel extends HttpKernel 'can' => Authorize::class, 'bindings' => SubstituteBindings::class, 'recaptcha' => VerifyReCaptcha::class, + 'maintenance' => MaintenanceMiddleware::class, // Server specific middleware (used for authenticating access to resources) // diff --git a/app/Http/Middleware/MaintenanceMiddleware.php b/app/Http/Middleware/MaintenanceMiddleware.php new file mode 100644 index 00000000..49358280 --- /dev/null +++ b/app/Http/Middleware/MaintenanceMiddleware.php @@ -0,0 +1,27 @@ +attributes->get('server'); + $node = $server->node; + + if ($node->maintenance) { + return response(view('errors.maintenance')); + } + + return $next($request); + } +} diff --git a/app/Models/Node.php b/app/Models/Node.php index 26d9eb44..ea0258e8 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -48,6 +48,7 @@ class Node extends Model implements CleansAttributes, ValidableContract 'daemonSFTP' => 'integer', 'behind_proxy' => 'boolean', 'public' => 'boolean', + 'maintenance' => 'boolean', ]; /** @@ -62,7 +63,7 @@ class Node extends Model implements CleansAttributes, ValidableContract 'disk_overallocate', 'upload_size', 'daemonSecret', 'daemonBase', 'daemonSFTP', 'daemonListen', - 'description', + 'description', 'maintenance', ]; /** @@ -111,6 +112,7 @@ class Node extends Model implements CleansAttributes, ValidableContract 'daemonBase' => 'regex:/^([\/][\d\w.\-\/]+)$/', 'daemonSFTP' => 'numeric|between:1024,65535', 'daemonListen' => 'numeric|between:1024,65535', + 'maintenance' => 'boolean', ]; /** @@ -126,6 +128,7 @@ class Node extends Model implements CleansAttributes, ValidableContract 'daemonBase' => '/srv/daemon-data', 'daemonSFTP' => 2022, 'daemonListen' => 8080, + 'maintenance' => false, ]; /** diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 3de307d9..3604b3d7 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -33,7 +33,7 @@ class RouteServiceProvider extends ServiceProvider ->namespace($this->namespace . '\Auth') ->group(base_path('routes/auth.php')); - Route::middleware(['web', 'csrf', 'auth', 'server', 'subuser.auth'])->prefix('/server/{server}') + Route::middleware(['web', 'csrf', 'auth', 'server', 'subuser.auth', 'maintenance'])->prefix('/server/{server}') ->namespace($this->namespace . '\Server') ->group(base_path('routes/server.php')); diff --git a/database/migrations/2018_05_04_123826_add_maintenance_to_nodes.php b/database/migrations/2018_05_04_123826_add_maintenance_to_nodes.php new file mode 100644 index 00000000..6c55912a --- /dev/null +++ b/database/migrations/2018_05_04_123826_add_maintenance_to_nodes.php @@ -0,0 +1,32 @@ +boolean('maintenance')->after('behind_proxy')->default(false); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('nodes', function (Blueprint $table) { + $table->dropColumn('maintenance'); + }); + } +} diff --git a/resources/lang/en/base.php b/resources/lang/en/base.php index ee3fb1f3..1603f4a1 100644 --- a/resources/lang/en/base.php +++ b/resources/lang/en/base.php @@ -21,6 +21,11 @@ return [ 'header' => 'Server Suspended', 'desc' => 'This server has been suspended and cannot be accessed.', ], + 'maintenance' => [ + 'header' => 'Node Under Maintenance', + 'title' => 'Maintenance', + 'desc' => 'This node is under maintenance, therefore your server can temporarily not be accessed.' + ], ], 'index' => [ 'header' => 'Your Servers', diff --git a/resources/themes/pterodactyl/errors/maintenance.blade.php b/resources/themes/pterodactyl/errors/maintenance.blade.php new file mode 100644 index 00000000..97bb810e --- /dev/null +++ b/resources/themes/pterodactyl/errors/maintenance.blade.php @@ -0,0 +1,30 @@ +{{-- Pterodactyl - Panel --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- This software is licensed under the terms of the MIT license. --}} +{{-- https://opensource.org/licenses/MIT --}} +@extends('layouts.error') + +@section('title') + @lang('base.errors.maintenance.header') +@endsection + +@section('content-header') +@endsection + +@section('content') +
+
+
+
+

@lang('base.errors.maintenance.title')

+

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

+
+ +
+
+
+@endsection From baea1d61912d16ae76bc0841142d820cb706e6a9 Mon Sep 17 00:00:00 2001 From: stanjg Date: Fri, 4 May 2018 15:13:34 +0200 Subject: [PATCH 02/66] Added the option to toggle, and made it display on the details page --- .../pterodactyl/admin/nodes/view/index.blade.php | 11 +++++++++++ .../admin/nodes/view/settings.blade.php | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/resources/themes/pterodactyl/admin/nodes/view/index.blade.php b/resources/themes/pterodactyl/admin/nodes/view/index.blade.php index 76a2ca62..2880fba5 100644 --- a/resources/themes/pterodactyl/admin/nodes/view/index.blade.php +++ b/resources/themes/pterodactyl/admin/nodes/view/index.blade.php @@ -96,6 +96,17 @@
+ @if($node->maintenance) +
+
+ +
+ This node is under + Maintenance +
+
+
+ @endif
diff --git a/resources/themes/pterodactyl/admin/nodes/view/settings.blade.php b/resources/themes/pterodactyl/admin/nodes/view/settings.blade.php index 919ad958..ba9a952b 100644 --- a/resources/themes/pterodactyl/admin/nodes/view/settings.blade.php +++ b/resources/themes/pterodactyl/admin/nodes/view/settings.blade.php @@ -108,6 +108,20 @@

If you are running the daemon behind a proxy such as Cloudflare, select this to have the daemon skip looking for certificates on boot.

+
+ +
+
+ maintenance) == false) ? 'checked' : '' }}> + +
+
+ maintenance) == true) ? 'checked' : '' }}> + +
+
+

If the node is marked as 'Under Maintenance' users won't be able to access servers that are on this node.

+
From f39720f15db760e05a49c691d8b545d196e6592b Mon Sep 17 00:00:00 2001 From: stanjg Date: Fri, 4 May 2018 15:16:14 +0200 Subject: [PATCH 03/66] Made it display 'maintenance' on the index page --- resources/themes/pterodactyl/base/index.blade.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/resources/themes/pterodactyl/base/index.blade.php b/resources/themes/pterodactyl/base/index.blade.php index 95cce612..09596298 100644 --- a/resources/themes/pterodactyl/base/index.blade.php +++ b/resources/themes/pterodactyl/base/index.blade.php @@ -64,9 +64,15 @@ @lang('strings.subuser') @endif - - - + @if($server->node->maintenance) + + Maintenance + + @else + + + + @endif @if (! empty($server->description)) From 93a7d11c28d8423741b6d01d57e6dfaf5de97e0e Mon Sep 17 00:00:00 2001 From: stanjg Date: Fri, 4 May 2018 18:45:37 +0200 Subject: [PATCH 04/66] Made a base --- .../Admin/StatisticsController.php | 59 ++++++++++ public/themes/pterodactyl/css/pterodactyl.css | 4 + .../themes/pterodactyl/js/admin/statistics.js | 101 +++++++++++++++++ .../pterodactyl/admin/statistics.blade.php | 103 ++++++++++++++++++ .../pterodactyl/layouts/admin.blade.php | 5 + routes/admin.php | 1 + 6 files changed, 273 insertions(+) create mode 100644 app/Http/Controllers/Admin/StatisticsController.php create mode 100644 public/themes/pterodactyl/js/admin/statistics.js create mode 100644 resources/themes/pterodactyl/admin/statistics.blade.php diff --git a/app/Http/Controllers/Admin/StatisticsController.php b/app/Http/Controllers/Admin/StatisticsController.php new file mode 100644 index 00000000..499b52cd --- /dev/null +++ b/app/Http/Controllers/Admin/StatisticsController.php @@ -0,0 +1,59 @@ +sum('memory'); + $totalNodeRam = DB::table('nodes')->sum('memory'); + $totalServerDisk = DB::table('servers')->sum('disk'); + $totalNodeDisk = DB::table('nodes')->sum('disk'); + $totalAllocations = Allocation::count(); + + $suspendedServersCount = Server::where('suspended', true)->count(); + + Javascript::put([ + 'servers' => Server::all(), + 'serverCount' => $serversCount, + 'suspendedServers' => $suspendedServersCount, + 'totalServerRam' => $totalServerRam, + 'totalNodeRam' => $totalNodeRam, + 'totalServerDisk' => $totalServerDisk, + 'totalNodeDisk' => $totalNodeDisk, + ]); + + return view('admin.statistics', [ + 'serversCount' => $serversCount, + 'nodesCount' => $nodesCount, + 'usersCount' => $usersCount, + 'eggsCount' => $eggsCount, + 'totalServerRam' => $totalServerRam, + 'databasesCount' => $databasesCount, + 'totalNodeRam' => $totalNodeRam, + 'totalNodeDisk' => $totalNodeDisk, + 'totalServerDisk' => $totalServerDisk, + 'totalAllocations' => $totalAllocations, + ]); + } + +} diff --git a/public/themes/pterodactyl/css/pterodactyl.css b/public/themes/pterodactyl/css/pterodactyl.css index 9e7e6a82..41f163f3 100644 --- a/public/themes/pterodactyl/css/pterodactyl.css +++ b/public/themes/pterodactyl/css/pterodactyl.css @@ -473,3 +473,7 @@ label.control-label > span.field-optional:before { height: 42px; width: auto; } + +.number-info-box-content { + padding: 15px 10px 0; +} diff --git a/public/themes/pterodactyl/js/admin/statistics.js b/public/themes/pterodactyl/js/admin/statistics.js new file mode 100644 index 00000000..b5bdbe4a --- /dev/null +++ b/public/themes/pterodactyl/js/admin/statistics.js @@ -0,0 +1,101 @@ +var freeDisk = Pterodactyl.totalNodeDisk - Pterodactyl.totalServerDisk; +let diskChart = new Chart($('#disk_chart'), { + type: 'pie', + data: { + labels: ['Free Disk', 'Used Disk'], + datasets: [ + { + label: 'Disk in MBs', + backgroundColor: ['#51B060', '#ff0000'], + data: [freeDisk, Pterodactyl.totalServerDisk] + } + ] + } +}); + +var freeRam = Pterodactyl.totalNodeRam - Pterodactyl.totalServerRam; +let ramChart = new Chart($('#ram_chart'), { + type: 'pie', + data: { + labels: ['Free RAM', 'Used RAM'], + datasets: [ + { + label: 'RAM in MBs', + backgroundColor: ['#51B060', '#ff0000'], + data: [freeRam, Pterodactyl.totalServerRam] + } + ] + } +}); + +var activeServers = Pterodactyl.serverCount - Pterodactyl.suspendedServers; +let serversChart = new Chart($('#servers_chart'), { + type: 'pie', + data: { + labels: ['Active', 'Suspended'], + datasets: [ + { + label: 'Servers', + backgroundColor: ['#51B060', '#E08E0B'], + data: [activeServers, Pterodactyl.suspendedServers] + } + ] + } +}); + +let statusChart = new Chart($('#status_chart'), { + type: 'pie', + data: { + labels: ['Online', 'Offline', 'Installing', 'Error'], + datasets: [ + { + label: '', + backgroundColor: ['#51B060', '#b7b7b7', '#E08E0B', '#ff0000'], + data: [0,0,0,0] + } + ] + } +}); + +var servers = Pterodactyl.servers; +servers.forEach(function (server) { + $.ajax({ + type: 'GET', + url: Router.route('index.status', { server: server.uuidShort}), + timeout: 5000, + headers: { + 'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content'), + } + }).done(function (data) { + + if (typeof data.status === 'undefined') { + // Error + statusChart.data.datasets[0].data[3]++; + return; + } + + switch (data.status) { + case 0: + case 3: + case 30: + // Offline + statusChart.data.datasets[0].data[1]++; + break; + case 1: + case 2: + // Online + console.log('online'); + statusChart.data.datasets[0].data[0]++; + break; + case 20: + // Installing + statusChart.data.datasets[0].data[2]++; + break; + } + statusChart.update(); + }).fail(function (jqXHR) { + // Error + statusChart.data.datasets[0].data[3]++; + statusChart.update(); + }); +}); \ No newline at end of file diff --git a/resources/themes/pterodactyl/admin/statistics.blade.php b/resources/themes/pterodactyl/admin/statistics.blade.php new file mode 100644 index 00000000..0579093a --- /dev/null +++ b/resources/themes/pterodactyl/admin/statistics.blade.php @@ -0,0 +1,103 @@ +@extends('layouts.admin') +@include('partials/admin.settings.nav', ['activeTab' => 'basic']) + +@section('title') + Statistics Overview +@endsection + +@section('content-header') +

Statistics OverviewMonitor your panel usage.

+ +@endsection + +@section('content') +
+
+
+
+ Servers +
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+ Servers + {{ $serversCount }} +
+
+
+ +
+ Total used RAM + {{ $totalServerRam }}MB +
+
+
+ +
+ Total used disk space + {{ $totalServerDisk }}MB +
+
+
+
+
+
+
+
+ Nodes +
+ +
+ +
+
+ +
+
+
+
+
+
+ +
+ Total RAM + {{ $totalNodeRam }}MB +
+
+
+ +
+ Total Disk Space + {{ $totalNodeDisk }}MB +
+
+
+ +
+ Total Allocations + {{ $totalAllocations }} +
+
+
+
+@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('vendor/chartjs/chart.min.js') !!} + {!! Theme::js('js/admin/statistics.js') !!} +@endsection \ No newline at end of file diff --git a/resources/themes/pterodactyl/layouts/admin.blade.php b/resources/themes/pterodactyl/layouts/admin.blade.php index d67eb6b4..aaf8f4ca 100644 --- a/resources/themes/pterodactyl/layouts/admin.blade.php +++ b/resources/themes/pterodactyl/layouts/admin.blade.php @@ -80,6 +80,11 @@ Overview +
  • + + Statistics + +
  • Settings diff --git a/routes/admin.php b/routes/admin.php index 7dfa94f0..70ba7e3d 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -1,6 +1,7 @@ name('admin.index'); +Route::get('/statistics', 'StatisticsController@index')->name('admin.statistics'); /* |-------------------------------------------------------------------------- From 28a97fea54351d8d00f64220483688202b9efd07 Mon Sep 17 00:00:00 2001 From: stanjg Date: Fri, 4 May 2018 22:48:43 +0200 Subject: [PATCH 05/66] Polished it up --- .../Admin/StatisticsController.php | 22 ++++++++++- .../themes/pterodactyl/js/admin/statistics.js | 30 ++++++++++++--- .../pterodactyl/admin/statistics.blade.php | 38 +++++++++++++++++++ 3 files changed, 84 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/Admin/StatisticsController.php b/app/Http/Controllers/Admin/StatisticsController.php index 499b52cd..119adb08 100644 --- a/app/Http/Controllers/Admin/StatisticsController.php +++ b/app/Http/Controllers/Admin/StatisticsController.php @@ -12,13 +12,22 @@ use Pterodactyl\Models\Server; use Pterodactyl\Models\User; use JavaScript; use Illuminate\Support\Facades\DB; +use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService; class StatisticsController extends Controller { + private $keyProviderService; + + function __construct(DaemonKeyProviderService $keyProviderService) + { + $this->keyProviderService = $keyProviderService; + } + public function index(Request $request) { $servers = Server::all(); + $nodes = Node::all(); $serversCount = count($servers); $nodesCount = Node::count(); $usersCount = User::count(); @@ -29,17 +38,26 @@ class StatisticsController extends Controller $totalServerDisk = DB::table('servers')->sum('disk'); $totalNodeDisk = DB::table('nodes')->sum('disk'); $totalAllocations = Allocation::count(); + $totalUsersCount = User::count(); + $totalDBCount = Database::count(); $suspendedServersCount = Server::where('suspended', true)->count(); + $tokens = []; + foreach ($nodes as $node) { + $tokens[$node->id] = $this->keyProviderService->handle($node->servers->get(0), $request->user()); + } + Javascript::put([ - 'servers' => Server::all(), + 'servers' => $servers, 'serverCount' => $serversCount, 'suspendedServers' => $suspendedServersCount, 'totalServerRam' => $totalServerRam, 'totalNodeRam' => $totalNodeRam, 'totalServerDisk' => $totalServerDisk, 'totalNodeDisk' => $totalNodeDisk, + 'nodes' => $nodes, + 'tokens' => $tokens, ]); return view('admin.statistics', [ @@ -53,6 +71,8 @@ class StatisticsController extends Controller 'totalNodeDisk' => $totalNodeDisk, 'totalServerDisk' => $totalServerDisk, 'totalAllocations' => $totalAllocations, + 'totalUsersCount' => $totalUsersCount, + 'totalDBCount' => $totalDBCount, ]); } diff --git a/public/themes/pterodactyl/js/admin/statistics.js b/public/themes/pterodactyl/js/admin/statistics.js index b5bdbe4a..f2c1c13d 100644 --- a/public/themes/pterodactyl/js/admin/statistics.js +++ b/public/themes/pterodactyl/js/admin/statistics.js @@ -58,13 +58,25 @@ let statusChart = new Chart($('#status_chart'), { }); var servers = Pterodactyl.servers; -servers.forEach(function (server) { +var nodes = Pterodactyl.nodes; + +for (let i = 0; i < servers.length; i++) { + setTimeout(getStatus, 200 * i); +} + +var index = 0; +function getStatus() { + var server = servers[index]; + var uuid = server.uuid; + var node = getNodeByID(server.node_id); + $.ajax({ type: 'GET', - url: Router.route('index.status', { server: server.uuidShort}), + url: node.scheme + '://' + node.fqdn + ':'+node.daemonListen+'/v1/server', timeout: 5000, headers: { - 'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content'), + 'X-Access-Server': uuid, + 'X-Access-Token': Pterodactyl.tokens[node.id], } }).done(function (data) { @@ -84,7 +96,6 @@ servers.forEach(function (server) { case 1: case 2: // Online - console.log('online'); statusChart.data.datasets[0].data[0]++; break; case 20: @@ -98,4 +109,13 @@ servers.forEach(function (server) { statusChart.data.datasets[0].data[3]++; statusChart.update(); }); -}); \ No newline at end of file + + index++; +} + +function getNodeByID(id) { + for (var i = 0; i < nodes.length; i++) { + if (nodes[i].id === id) + return nodes[i]; + } +} \ No newline at end of file diff --git a/resources/themes/pterodactyl/admin/statistics.blade.php b/resources/themes/pterodactyl/admin/statistics.blade.php index 0579093a..e8e7cc25 100644 --- a/resources/themes/pterodactyl/admin/statistics.blade.php +++ b/resources/themes/pterodactyl/admin/statistics.blade.php @@ -94,6 +94,44 @@ +
    +
    +
    + +
    + Total Eggs + {{ $eggsCount }} +
    +
    +
    +
    +
    + +
    + Total Users + {{ $totalUsersCount }} +
    +
    +
    +
    +
    + +
    + Total Nodes + {{ $nodesCount }} +
    +
    +
    +
    +
    + +
    + Total Databases + {{ $totalDBCount }} +
    +
    +
    +
    @endsection @section('footer-scripts') From ee50da0a7c2538fa7ed337424833b431d54280b3 Mon Sep 17 00:00:00 2001 From: stanjg Date: Fri, 4 May 2018 23:35:45 +0200 Subject: [PATCH 06/66] Fixed a typo --- resources/themes/pterodactyl/admin/statistics.blade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/themes/pterodactyl/admin/statistics.blade.php b/resources/themes/pterodactyl/admin/statistics.blade.php index e8e7cc25..dff5019e 100644 --- a/resources/themes/pterodactyl/admin/statistics.blade.php +++ b/resources/themes/pterodactyl/admin/statistics.blade.php @@ -60,14 +60,14 @@
    Nodes
    - +
    - +
    From 06a67bb4bb2a786132f4731a14168446eb403356 Mon Sep 17 00:00:00 2001 From: stanjg Date: Sat, 5 May 2018 10:39:20 +0200 Subject: [PATCH 07/66] Cleaned up some duplicate code --- app/Http/Controllers/Admin/StatisticsController.php | 4 ---- resources/themes/pterodactyl/admin/statistics.blade.php | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/Admin/StatisticsController.php b/app/Http/Controllers/Admin/StatisticsController.php index 119adb08..a3777e4e 100644 --- a/app/Http/Controllers/Admin/StatisticsController.php +++ b/app/Http/Controllers/Admin/StatisticsController.php @@ -38,8 +38,6 @@ class StatisticsController extends Controller $totalServerDisk = DB::table('servers')->sum('disk'); $totalNodeDisk = DB::table('nodes')->sum('disk'); $totalAllocations = Allocation::count(); - $totalUsersCount = User::count(); - $totalDBCount = Database::count(); $suspendedServersCount = Server::where('suspended', true)->count(); @@ -71,8 +69,6 @@ class StatisticsController extends Controller 'totalNodeDisk' => $totalNodeDisk, 'totalServerDisk' => $totalServerDisk, 'totalAllocations' => $totalAllocations, - 'totalUsersCount' => $totalUsersCount, - 'totalDBCount' => $totalDBCount, ]); } diff --git a/resources/themes/pterodactyl/admin/statistics.blade.php b/resources/themes/pterodactyl/admin/statistics.blade.php index dff5019e..46e11233 100644 --- a/resources/themes/pterodactyl/admin/statistics.blade.php +++ b/resources/themes/pterodactyl/admin/statistics.blade.php @@ -109,7 +109,7 @@
    Total Users - {{ $totalUsersCount }} + {{ $usersCount }}
    @@ -127,7 +127,7 @@
    Total Databases - {{ $totalDBCount }} + {{ $databasesCount }}
    From 095d85bb60cb283596ff7879bcc567924157da53 Mon Sep 17 00:00:00 2001 From: stanjg Date: Sun, 6 May 2018 17:59:11 +0200 Subject: [PATCH 08/66] Added the server as argument, and improved the bug fix --- app/Http/Controllers/Admin/StatisticsController.php | 12 ++++++++---- public/themes/pterodactyl/js/admin/statistics.js | 11 ++++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/app/Http/Controllers/Admin/StatisticsController.php b/app/Http/Controllers/Admin/StatisticsController.php index a3777e4e..aedca3d6 100644 --- a/app/Http/Controllers/Admin/StatisticsController.php +++ b/app/Http/Controllers/Admin/StatisticsController.php @@ -3,6 +3,8 @@ namespace Pterodactyl\Http\Controllers\Admin; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; +use JavaScript; use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Models\Allocation; use Pterodactyl\Models\Database; @@ -10,8 +12,6 @@ use Pterodactyl\Models\Egg; use Pterodactyl\Models\Node; use Pterodactyl\Models\Server; use Pterodactyl\Models\User; -use JavaScript; -use Illuminate\Support\Facades\DB; use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService; class StatisticsController extends Controller @@ -29,7 +29,7 @@ class StatisticsController extends Controller $servers = Server::all(); $nodes = Node::all(); $serversCount = count($servers); - $nodesCount = Node::count(); + $nodesCount = count($nodes); $usersCount = User::count(); $eggsCount = Egg::count(); $databasesCount = Database::count(); @@ -43,7 +43,11 @@ class StatisticsController extends Controller $tokens = []; foreach ($nodes as $node) { - $tokens[$node->id] = $this->keyProviderService->handle($node->servers->get(0), $request->user()); + $server = Server::where('node_id', $node->id)->first(); + if ($server == null) + continue; + + $tokens[$node->id] = $this->keyProviderService->handle($server, $request->user()); } Javascript::put([ diff --git a/public/themes/pterodactyl/js/admin/statistics.js b/public/themes/pterodactyl/js/admin/statistics.js index f2c1c13d..12f4277b 100644 --- a/public/themes/pterodactyl/js/admin/statistics.js +++ b/public/themes/pterodactyl/js/admin/statistics.js @@ -61,12 +61,10 @@ var servers = Pterodactyl.servers; var nodes = Pterodactyl.nodes; for (let i = 0; i < servers.length; i++) { - setTimeout(getStatus, 200 * i); + setTimeout(getStatus, 200 * i, servers[i]); } -var index = 0; -function getStatus() { - var server = servers[index]; +function getStatus(server) { var uuid = server.uuid; var node = getNodeByID(server.node_id); @@ -109,13 +107,12 @@ function getStatus() { statusChart.data.datasets[0].data[3]++; statusChart.update(); }); - - index++; } function getNodeByID(id) { for (var i = 0; i < nodes.length; i++) { - if (nodes[i].id === id) + if (nodes[i].id === id) { return nodes[i]; + } } } \ No newline at end of file From 5f6ee45f445aaf784d50e7996e2da9c6cedafcf1 Mon Sep 17 00:00:00 2001 From: Xander Smeets Date: Sun, 6 May 2018 20:22:30 +0200 Subject: [PATCH 09/66] Fixed typo (#1134) --- app/Notifications/AccountCreated.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Notifications/AccountCreated.php b/app/Notifications/AccountCreated.php index 8312c3bd..29b084d5 100644 --- a/app/Notifications/AccountCreated.php +++ b/app/Notifications/AccountCreated.php @@ -60,7 +60,7 @@ class AccountCreated extends Notification implements ShouldQueue { $message = (new MailMessage) ->greeting('Hello ' . $this->user->name . '!') - ->line('You are recieving this email because an account has been created for you on ' . config('app.name') . '.') + ->line('You are receiving this email because an account has been created for you on ' . config('app.name') . '.') ->line('Username: ' . $this->user->username) ->line('Email: ' . $this->user->email); From ba96829d13fcd5818941dca63f97d2182c96afbe Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 13 May 2018 00:41:56 -0400 Subject: [PATCH 10/66] Fix cron jobs by removing the extra unusable argument --- app/Services/Schedules/ProcessScheduleService.php | 2 +- app/Services/Schedules/ScheduleCreationService.php | 2 +- app/Services/Schedules/ScheduleUpdateService.php | 2 +- tests/Unit/Services/Schedules/ProcessScheduleServiceTest.php | 2 +- tests/Unit/Services/Schedules/ScheduleCreationServiceTest.php | 4 ++-- tests/Unit/Services/Schedules/ScheduleUpdateServiceTest.php | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/Services/Schedules/ProcessScheduleService.php b/app/Services/Schedules/ProcessScheduleService.php index ec6ea5f1..b134caa3 100644 --- a/app/Services/Schedules/ProcessScheduleService.php +++ b/app/Services/Schedules/ProcessScheduleService.php @@ -63,7 +63,7 @@ class ProcessScheduleService { $this->repository->loadTasks($schedule); - $formattedCron = sprintf('%s %s %s * %s *', + $formattedCron = sprintf('%s %s %s * %s', $schedule->cron_minute, $schedule->cron_hour, $schedule->cron_day_of_month, diff --git a/app/Services/Schedules/ScheduleCreationService.php b/app/Services/Schedules/ScheduleCreationService.php index 9f676e24..c8cbd7fb 100644 --- a/app/Services/Schedules/ScheduleCreationService.php +++ b/app/Services/Schedules/ScheduleCreationService.php @@ -86,7 +86,7 @@ class ScheduleCreationService */ private function getCronTimestamp(array $data) { - $formattedCron = sprintf('%s %s %s * %s *', + $formattedCron = sprintf('%s %s %s * %s', array_get($data, 'cron_minute', '*'), array_get($data, 'cron_hour', '*'), array_get($data, 'cron_day_of_month', '*'), diff --git a/app/Services/Schedules/ScheduleUpdateService.php b/app/Services/Schedules/ScheduleUpdateService.php index 96da1b10..1ddbbd24 100644 --- a/app/Services/Schedules/ScheduleUpdateService.php +++ b/app/Services/Schedules/ScheduleUpdateService.php @@ -98,7 +98,7 @@ class ScheduleUpdateService */ private function getCronTimestamp(array $data) { - $formattedCron = sprintf('%s %s %s * %s *', + $formattedCron = sprintf('%s %s %s * %s', array_get($data, 'cron_minute', '*'), array_get($data, 'cron_hour', '*'), array_get($data, 'cron_day_of_month', '*'), diff --git a/tests/Unit/Services/Schedules/ProcessScheduleServiceTest.php b/tests/Unit/Services/Schedules/ProcessScheduleServiceTest.php index 67db3b62..27e20082 100644 --- a/tests/Unit/Services/Schedules/ProcessScheduleServiceTest.php +++ b/tests/Unit/Services/Schedules/ProcessScheduleServiceTest.php @@ -60,7 +60,7 @@ class ProcessScheduleServiceTest extends TestCase $this->repository->shouldReceive('loadTasks')->with($model)->once()->andReturn($model); - $formatted = sprintf('%s %s %s * %s *', $model->cron_minute, $model->cron_hour, $model->cron_day_of_month, $model->cron_day_of_week); + $formatted = sprintf('%s %s %s * %s', $model->cron_minute, $model->cron_hour, $model->cron_day_of_month, $model->cron_day_of_week); $this->repository->shouldReceive('update')->with($model->id, [ 'is_processing' => true, 'next_run_at' => CronExpression::factory($formatted)->getNextRunDate(), diff --git a/tests/Unit/Services/Schedules/ScheduleCreationServiceTest.php b/tests/Unit/Services/Schedules/ScheduleCreationServiceTest.php index 62d875fc..117d4a86 100644 --- a/tests/Unit/Services/Schedules/ScheduleCreationServiceTest.php +++ b/tests/Unit/Services/Schedules/ScheduleCreationServiceTest.php @@ -64,7 +64,7 @@ class ScheduleCreationServiceTest extends TestCase $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); $this->repository->shouldReceive('create')->with([ 'server_id' => $server->id, - 'next_run_at' => CronExpression::factory('* * * * * *')->getNextRunDate(), + 'next_run_at' => CronExpression::factory('* * * * *')->getNextRunDate(), 'test_key' => 'value', ])->once()->andReturn($schedule); $this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull(); @@ -85,7 +85,7 @@ class ScheduleCreationServiceTest extends TestCase $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); $this->repository->shouldReceive('create')->with([ 'server_id' => $server->id, - 'next_run_at' => CronExpression::factory('* * * * * *')->getNextRunDate(), + 'next_run_at' => CronExpression::factory('* * * * *')->getNextRunDate(), 'test_key' => 'value', ])->once()->andReturn($schedule); diff --git a/tests/Unit/Services/Schedules/ScheduleUpdateServiceTest.php b/tests/Unit/Services/Schedules/ScheduleUpdateServiceTest.php index 3f26f69b..4a4dc20d 100644 --- a/tests/Unit/Services/Schedules/ScheduleUpdateServiceTest.php +++ b/tests/Unit/Services/Schedules/ScheduleUpdateServiceTest.php @@ -64,7 +64,7 @@ class ScheduleUpdateServiceTest extends TestCase $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs(); $this->repository->shouldReceive('update')->once()->with($schedule->id, array_merge($data, [ - 'next_run_at' => CronExpression::factory('1 2 3 * 4 *')->getNextRunDate(), + 'next_run_at' => CronExpression::factory('1 2 3 * 4')->getNextRunDate(), ]))->andReturn($schedule); $this->taskRepository->shouldReceive('deleteWhere')->once()->with([['schedule_id', '=', $schedule->id]]); From 351099ccf512f23e7936d4125d6a71051cf74ef3 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 13 May 2018 10:13:51 -0400 Subject: [PATCH 11/66] Rename identitity to identity --- resources/lang/de/base.php | 2 +- resources/lang/en/base.php | 2 +- resources/lang/es/base.php | 2 +- resources/themes/pterodactyl/base/account.blade.php | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/lang/de/base.php b/resources/lang/de/base.php index b482e9af..6d547def 100644 --- a/resources/lang/de/base.php +++ b/resources/lang/de/base.php @@ -220,7 +220,7 @@ return [ 'new_email' => 'Neue Email Adresse', 'first_name' => 'Vornahme', 'last_name' => 'Nachname', - 'update_identitity' => 'Account bearbeiten', + 'update_identity' => 'Account bearbeiten', 'username_help' => 'Dein Username darf nicht bereits vergeben sein oder folgende Zeichen enthakten: :requirements.', ], 'security' => [ diff --git a/resources/lang/en/base.php b/resources/lang/en/base.php index ee3fb1f3..51b18546 100644 --- a/resources/lang/en/base.php +++ b/resources/lang/en/base.php @@ -62,7 +62,7 @@ return [ 'new_email' => 'New Email Address', 'first_name' => 'First Name', 'last_name' => 'Last Name', - 'update_identitity' => 'Update Identity', + 'update_identity' => 'Update Identity', 'username_help' => 'Your username must be unique to your account, and may only contain the following characters: :requirements.', ], 'security' => [ diff --git a/resources/lang/es/base.php b/resources/lang/es/base.php index 0593be07..93dca11b 100644 --- a/resources/lang/es/base.php +++ b/resources/lang/es/base.php @@ -220,7 +220,7 @@ return [ 'new_email' => 'Nueva Dirección De Correo Electrónico', 'first_name' => 'Primer Nombre', 'last_name' => 'Apellido', - 'update_identitity' => 'Actualización De La Identidad', + 'update_identity' => 'Actualización De La Identidad', 'username_help' => 'Su nombre de usuario debe ser único a su cuenta, y sólo pueden contener los siguientes caracteres: :requirements.', ], 'security' => [ diff --git a/resources/themes/pterodactyl/base/account.blade.php b/resources/themes/pterodactyl/base/account.blade.php index 3c202f57..2fd8294e 100644 --- a/resources/themes/pterodactyl/base/account.blade.php +++ b/resources/themes/pterodactyl/base/account.blade.php @@ -64,7 +64,7 @@
    -

    @lang('base.account.update_identitity')

    +

    @lang('base.account.update_identity')

    @@ -94,7 +94,7 @@
    From 84edec632329729020fbf5c234d0b8169a5a917b Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 13 May 2018 10:18:30 -0400 Subject: [PATCH 12/66] Spelling fixes in the english translation --- resources/lang/en/admin/server.php | 2 +- resources/lang/en/base.php | 8 ++++---- resources/lang/en/command/messages.php | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/resources/lang/en/admin/server.php b/resources/lang/en/admin/server.php index e0ccdba7..fa254c8d 100644 --- a/resources/lang/en/admin/server.php +++ b/resources/lang/en/admin/server.php @@ -16,7 +16,7 @@ return [ 'default_allocation_not_found' => 'The requested default allocation was not found in this server\'s allocations.', ], 'alerts' => [ - 'startup_changed' => 'The startup configuration for this server has been updated. If this server\'s nest or egg was changed a reinstall will be occuring now.', + 'startup_changed' => 'The startup configuration for this server has been updated. If this server\'s nest or egg was changed a reinstall will be occurring now.', 'server_deleted' => 'Server has successfully been deleted from the system.', 'server_created' => 'Server was successfully created on the panel. Please allow the daemon a few minutes to completely install this server.', 'build_updated' => 'The build details for this server have been updated. Some changes may require a restart to take effect.', diff --git a/resources/lang/en/base.php b/resources/lang/en/base.php index 51b18546..2c0f6c62 100644 --- a/resources/lang/en/base.php +++ b/resources/lang/en/base.php @@ -31,7 +31,7 @@ return [ 'index' => [ 'list' => 'Your Keys', 'header' => 'Account API', - 'header_sub' => 'Manage access keys that allow you to perform actions aganist the panel.', + 'header_sub' => 'Manage access keys that allow you to perform actions against the panel.', 'create_new' => 'Create New API key', 'keypair_created' => 'An API key has been successfully generated and is listed below.', ], @@ -45,7 +45,7 @@ return [ ], '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 delimited list of IPs that are allowed to access the API using this key. CIDR notation is allowed. Leave blank to allow any IP.', ], ], ], @@ -71,12 +71,12 @@ return [ 'header_sub' => 'Control active sessions and 2-Factor Authentication.', 'sessions' => 'Active Sessions', '2fa_header' => '2-Factor Authentication', - '2fa_token_help' => 'Enter the 2FA Token generated by your app (Google Authenticatior, Authy, etc.).', + '2fa_token_help' => 'Enter the 2FA Token generated by your app (Google Authenticator, Authy, etc.).', 'disable_2fa' => 'Disable 2-Factor Authentication', '2fa_enabled' => '2-Factor Authentication is enabled on this account and will be required in order to login to the panel. If you would like to disable 2FA, simply enter a valid token below and submit the form.', '2fa_disabled' => '2-Factor Authentication is disabled on your account! You should enable 2FA in order to add an extra level of protection on your account.', 'enable_2fa' => 'Enable 2-Factor Authentication', - '2fa_qr' => 'Confgure 2FA on Your Device', + '2fa_qr' => 'Configure 2FA on Your Device', '2fa_checkpoint_help' => 'Use the 2FA application on your phone to take a picture of the QR code to the left, or manually enter the code under it. Once you have done so, generate a token and enter it below.', '2fa_disable_error' => 'The 2FA token provided was not valid. Protection has not been disabled for this account.', ], diff --git a/resources/lang/en/command/messages.php b/resources/lang/en/command/messages.php index 1fd706a8..68d17289 100644 --- a/resources/lang/en/command/messages.php +++ b/resources/lang/en/command/messages.php @@ -43,7 +43,7 @@ return [ 'server' => [ 'rebuild_failed' => 'Rebuild request for ":name" (#:id) on node ":node" failed with error: :message', 'power' => [ - 'confirm' => 'You are about to perform a :action aganist :count servers. Do you wish to continue?', + 'confirm' => 'You are about to perform a :action against :count servers. Do you wish to continue?', 'action_failed' => 'Power action request for ":name" (#:id) on node ":node" failed with error: :message', ], ], @@ -89,7 +89,7 @@ return [ 'using_redis' => 'You\'ve selected the Redis driver for one or more options, please provide valid connection information below. In most cases you can use the defaults provided unless you have modified your setup.', 'redis_host' => 'Redis Host', 'redis_password' => 'Redis Password', - 'redis_pass_help' => 'By default a Redis server instance has no password as it is running locally and inaccessable to the outside world. If this is the case, simply hit enter without entering a value.', + 'redis_pass_help' => 'By default a Redis server instance has no password as it is running locally and inaccessible to the outside world. If this is the case, simply hit enter without entering a value.', 'redis_port' => 'Redis Port', 'redis_pass_defined' => 'It seems a password is already defined for Redis, would you like to change it?', ], From c6c37e1b88439c34287cf3cf37fcdf6385fab0ca Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 13 May 2018 10:24:07 -0400 Subject: [PATCH 13/66] occurred --- .../themes/pterodactyl/js/frontend/2fa-modal.js | 2 +- .../pterodactyl/js/frontend/files/src/actions.js | 16 ++++++++-------- .../pterodactyl/js/frontend/files/src/index.js | 2 +- .../js/frontend/tasks/management-actions.js | 6 +++--- .../themes/pterodactyl/admin/api/index.blade.php | 2 +- .../admin/servers/view/database.blade.php | 4 ++-- .../themes/pterodactyl/base/api/index.blade.php | 2 +- .../pterodactyl/server/databases/index.blade.php | 4 ++-- .../server/settings/allocation.blade.php | 2 +- .../pterodactyl/server/users/index.blade.php | 2 +- 10 files changed, 21 insertions(+), 21 deletions(-) diff --git a/public/themes/pterodactyl/js/frontend/2fa-modal.js b/public/themes/pterodactyl/js/frontend/2fa-modal.js index d542b377..8de4ee53 100644 --- a/public/themes/pterodactyl/js/frontend/2fa-modal.js +++ b/public/themes/pterodactyl/js/frontend/2fa-modal.js @@ -44,7 +44,7 @@ var TwoFactorModal = (function () { }); $('#open2fa').modal('show'); }).fail(function (jqXHR) { - alert('An error occured while attempting to load the 2FA setup modal. Please try again.'); + alert('An error occurred while attempting to load the 2FA setup modal. Please try again.'); console.error(jqXHR); }); diff --git a/public/themes/pterodactyl/js/frontend/files/src/actions.js b/public/themes/pterodactyl/js/frontend/files/src/actions.js index 83db5cfa..d2d6f42e 100644 --- a/public/themes/pterodactyl/js/frontend/files/src/actions.js +++ b/public/themes/pterodactyl/js/frontend/files/src/actions.js @@ -72,7 +72,7 @@ class ActionsClass { Files.list(); }).fail(jqXHR => { console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; + var error = 'An error occurred while trying to process this request.'; if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { error = jqXHR.responseJSON.error; } @@ -118,7 +118,7 @@ class ActionsClass { swal.close(); }).fail(jqXHR => { console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; + var error = 'An error occurred while trying to process this request.'; if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { error = jqXHR.responseJSON.error; } @@ -198,7 +198,7 @@ class ActionsClass { inputField.remove(); }).fail(jqXHR => { console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; + var error = 'An error occurred while trying to process this request.'; if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { error = jqXHR.responseJSON.error; } @@ -255,7 +255,7 @@ class ActionsClass { Files.list(); }).fail(jqXHR => { console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; + var error = 'An error occurred while trying to process this request.'; if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { error = jqXHR.responseJSON.error; } @@ -315,7 +315,7 @@ class ActionsClass { type: 'error', title: 'Whoops!', html: true, - text: 'An error occured while attempting to delete this file. Please try again.', + text: 'An error occurred while attempting to delete this file. Please try again.', }); }); }); @@ -433,7 +433,7 @@ class ActionsClass { type: 'error', title: 'Whoops!', html: true, - text: 'An error occured while attempting to delete these files. Please try again.', + text: 'An error occurred while attempting to delete these files. Please try again.', }); }); }); @@ -476,7 +476,7 @@ class ActionsClass { Files.list(compPath); }).fail(jqXHR => { console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; + var error = 'An error occurred while trying to process this request.'; if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { error = jqXHR.responseJSON.error; } @@ -516,7 +516,7 @@ class ActionsClass { }); }).fail(jqXHR => { console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; + var error = 'An error occurred while trying to process this request.'; if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { error = jqXHR.responseJSON.error; } diff --git a/public/themes/pterodactyl/js/frontend/files/src/index.js b/public/themes/pterodactyl/js/frontend/files/src/index.js index b407c0f0..a27d4030 100644 --- a/public/themes/pterodactyl/js/frontend/files/src/index.js +++ b/public/themes/pterodactyl/js/frontend/files/src/index.js @@ -71,7 +71,7 @@ class FileManager { swal({ type: 'error', title: 'File Error', - text: jqXHR.responseJSON.errors[0].detail || 'An error occured while attempting to process this request. Please try again.', + text: jqXHR.responseJSON.errors[0].detail || 'An error occurred while attempting to process this request. Please try again.', }); console.error(jqXHR); }); diff --git a/public/themes/pterodactyl/js/frontend/tasks/management-actions.js b/public/themes/pterodactyl/js/frontend/tasks/management-actions.js index 3c344a97..857c32cf 100644 --- a/public/themes/pterodactyl/js/frontend/tasks/management-actions.js +++ b/public/themes/pterodactyl/js/frontend/tasks/management-actions.js @@ -54,7 +54,7 @@ $(document).ready(function () { swal({ type: 'error', title: 'Whoops!', - text: 'An error occured while attempting to delete this schedule.' + text: 'An error occurred while attempting to delete this schedule.' }); }); }); @@ -93,7 +93,7 @@ $(document).ready(function () { swal({ type: 'error', title: 'Whoops!', - text: 'An error occured while attempting to trigger this schedule.' + text: 'An error occurred while attempting to trigger this schedule.' }); }); }); @@ -136,7 +136,7 @@ $(document).ready(function () { swal({ type: 'error', title: 'Whoops!', - text: 'An error occured while attempting to toggle this schedule.' + text: 'An error occurred while attempting to toggle this schedule.' }); }); }); diff --git a/resources/themes/pterodactyl/admin/api/index.blade.php b/resources/themes/pterodactyl/admin/api/index.blade.php index ece51699..9abcc200 100644 --- a/resources/themes/pterodactyl/admin/api/index.blade.php +++ b/resources/themes/pterodactyl/admin/api/index.blade.php @@ -93,7 +93,7 @@ swal({ type: 'error', title: 'Whoops!', - text: 'An error occured while attempting to revoke this key.' + text: 'An error occurred while attempting to revoke this key.' }); }); }); diff --git a/resources/themes/pterodactyl/admin/servers/view/database.blade.php b/resources/themes/pterodactyl/admin/servers/view/database.blade.php index 6c556137..9b7c8107 100644 --- a/resources/themes/pterodactyl/admin/servers/view/database.blade.php +++ b/resources/themes/pterodactyl/admin/servers/view/database.blade.php @@ -141,7 +141,7 @@ swal({ type: 'error', title: 'Whoops!', - text: (typeof jqXHR.responseJSON.error !== 'undefined') ? jqXHR.responseJSON.error : 'An error occured while processing this request.' + text: (typeof jqXHR.responseJSON.error !== 'undefined') ? jqXHR.responseJSON.error : 'An error occurred while processing this request.' }); }); }); @@ -163,7 +163,7 @@ }); }).fail(function(jqXHR, textStatus, errorThrown) { console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; + var error = 'An error occurred while trying to process this request.'; if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { error = jqXHR.responseJSON.error; } diff --git a/resources/themes/pterodactyl/base/api/index.blade.php b/resources/themes/pterodactyl/base/api/index.blade.php index 24a71734..99e5a1ca 100644 --- a/resources/themes/pterodactyl/base/api/index.blade.php +++ b/resources/themes/pterodactyl/base/api/index.blade.php @@ -113,7 +113,7 @@ swal({ type: 'error', title: 'Whoops!', - text: 'An error occured while attempting to revoke this key.' + text: 'An error occurred while attempting to revoke this key.' }); }); }); diff --git a/resources/themes/pterodactyl/server/databases/index.blade.php b/resources/themes/pterodactyl/server/databases/index.blade.php index fb618b64..d7b475ac 100644 --- a/resources/themes/pterodactyl/server/databases/index.blade.php +++ b/resources/themes/pterodactyl/server/databases/index.blade.php @@ -148,7 +148,7 @@ block.parent().parent().find('[data-attr="set-password"]').html(data.password); }).fail(function(jqXHR) { console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; + var error = 'An error occurred while trying to process this request.'; if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { error = jqXHR.responseJSON.error; } @@ -188,7 +188,7 @@ swal({ type: 'error', title: 'Whoops!', - text: (typeof jqXHR.responseJSON.error !== 'undefined') ? jqXHR.responseJSON.error : 'An error occured while processing this request.' + text: (typeof jqXHR.responseJSON.error !== 'undefined') ? jqXHR.responseJSON.error : 'An error occurred while processing this request.' }); }); }); diff --git a/resources/themes/pterodactyl/server/settings/allocation.blade.php b/resources/themes/pterodactyl/server/settings/allocation.blade.php index 4c7d7661..cc195240 100644 --- a/resources/themes/pterodactyl/server/settings/allocation.blade.php +++ b/resources/themes/pterodactyl/server/settings/allocation.blade.php @@ -103,7 +103,7 @@ self.removeClass('btn-default').addClass('btn-success disabled').html('{{ trans('strings.primary') }}'); }).fail(function(jqXHR) { console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; + var error = 'An error occurred while trying to process this request.'; if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { error = jqXHR.responseJSON.error; } diff --git a/resources/themes/pterodactyl/server/users/index.blade.php b/resources/themes/pterodactyl/server/users/index.blade.php index 1cb88233..3d08e590 100644 --- a/resources/themes/pterodactyl/server/users/index.blade.php +++ b/resources/themes/pterodactyl/server/users/index.blade.php @@ -114,7 +114,7 @@ }); }).fail(function (jqXHR) { console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; + var error = 'An error occurred while trying to process this request.'; if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { error = jqXHR.responseJSON.error; } From 608ad33d319a60150ff0a637f4483b46a5aa0122 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 13 May 2018 10:34:09 -0400 Subject: [PATCH 14/66] Spellcheck themes --- resources/themes/pterodactyl/admin/eggs/new.blade.php | 8 ++++---- resources/themes/pterodactyl/admin/eggs/scripts.blade.php | 2 +- .../themes/pterodactyl/admin/eggs/variables.blade.php | 4 ++-- resources/themes/pterodactyl/admin/eggs/view.blade.php | 4 ++-- resources/themes/pterodactyl/admin/nests/index.blade.php | 2 +- resources/themes/pterodactyl/admin/nests/new.blade.php | 2 +- resources/themes/pterodactyl/admin/nests/view.blade.php | 2 +- resources/themes/pterodactyl/admin/nodes/new.blade.php | 6 +++--- .../themes/pterodactyl/admin/nodes/view/index.blade.php | 2 +- .../pterodactyl/admin/nodes/view/settings.blade.php | 2 +- resources/themes/pterodactyl/admin/packs/modal.blade.php | 2 +- resources/themes/pterodactyl/admin/packs/new.blade.php | 2 +- resources/themes/pterodactyl/admin/packs/view.blade.php | 2 +- resources/themes/pterodactyl/admin/servers/new.blade.php | 2 +- .../themes/pterodactyl/admin/servers/view/build.blade.php | 2 +- .../pterodactyl/admin/servers/view/startup.blade.php | 6 +++--- .../themes/pterodactyl/admin/settings/index.blade.php | 2 +- resources/themes/pterodactyl/admin/users/new.blade.php | 2 +- resources/themes/pterodactyl/admin/users/view.blade.php | 2 +- 19 files changed, 28 insertions(+), 28 deletions(-) diff --git a/resources/themes/pterodactyl/admin/eggs/new.blade.php b/resources/themes/pterodactyl/admin/eggs/new.blade.php index 8059363f..474d989a 100644 --- a/resources/themes/pterodactyl/admin/eggs/new.blade.php +++ b/resources/themes/pterodactyl/admin/eggs/new.blade.php @@ -37,13 +37,13 @@ @endforeach -

    Think of a Nest as a category. You can put multiple Eggs in a nest, but consider putting only Eggs that are related to eachother in each Nest.

    +

    Think of a Nest as a category. You can put multiple Eggs in a nest, but consider putting only Eggs that are related to each other in each Nest.

    -

    A simple, human-readable name to use as an identifier for this Egg. This is what users will see as thier gameserver type.

    +

    A simple, human-readable name to use as an identifier for this Egg. This is what users will see as their game server type.

    @@ -60,7 +60,7 @@
    -

    The default statup command that should be used for new servers created with this Egg. You can change this per-server as needed.

    +

    The default startup command that should be used for new servers created with this Egg. You can change this per-server as needed.

    @@ -76,7 +76,7 @@
    -

    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.

    +

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

    diff --git a/resources/themes/pterodactyl/admin/eggs/scripts.blade.php b/resources/themes/pterodactyl/admin/eggs/scripts.blade.php index 44252b26..55c6f1b9 100644 --- a/resources/themes/pterodactyl/admin/eggs/scripts.blade.php +++ b/resources/themes/pterodactyl/admin/eggs/scripts.blade.php @@ -41,7 +41,7 @@ @if(! is_null($egg->copyFrom))
    - This service option is copying installation scripts and containe options from {{ $egg->copyFrom->name }}. Any changes you make to this script will not apply unless you select "None" from the dropdown box below. + This service option is copying installation scripts and container options from {{ $egg->copyFrom->name }}. Any changes you make to this script will not apply unless you select "None" from the dropdown box below.
    @endif diff --git a/resources/themes/pterodactyl/admin/eggs/variables.blade.php b/resources/themes/pterodactyl/admin/eggs/variables.blade.php index baf72f53..f49886ee 100644 --- a/resources/themes/pterodactyl/admin/eggs/variables.blade.php +++ b/resources/themes/pterodactyl/admin/eggs/variables.blade.php @@ -68,7 +68,7 @@
    -

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

    +

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

    @@ -121,7 +121,7 @@
    -

    This variable can be accessed in the statup command by entering @{{environment variable value}}.

    +

    This variable can be accessed in the startup command by entering @{{environment variable value}}.

    diff --git a/resources/themes/pterodactyl/admin/eggs/view.blade.php b/resources/themes/pterodactyl/admin/eggs/view.blade.php index 9c91627e..715f749e 100644 --- a/resources/themes/pterodactyl/admin/eggs/view.blade.php +++ b/resources/themes/pterodactyl/admin/eggs/view.blade.php @@ -101,7 +101,7 @@
    -

    The default statup command that should be used for new servers using this Egg.

    +

    The default startup command that should be used for new servers using this Egg.

    @@ -118,7 +118,7 @@

    The following configuration options should not be edited unless you understand how this system works. If wrongly modified it is possible for the daemon to break.

    -

    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 Egg.

    +

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

    diff --git a/resources/themes/pterodactyl/admin/nests/index.blade.php b/resources/themes/pterodactyl/admin/nests/index.blade.php index 9f9c1531..3c726964 100644 --- a/resources/themes/pterodactyl/admin/nests/index.blade.php +++ b/resources/themes/pterodactyl/admin/nests/index.blade.php @@ -21,7 +21,7 @@
    - Eggs are a powerful feature of Pterodactyl Panel that allow for extreme flexibility and configuration. Please note that while powerful, modifing an egg wrongly can very easily brick your servers and cause more problems. Please avoid editing our default eggs — those provided by support@pterodactyl.io — unless you are absolutely sure of what you are doing. + Eggs are a powerful feature of Pterodactyl Panel that allow for extreme flexibility and configuration. Please note that while powerful, modifying an egg wrongly can very easily brick your servers and cause more problems. Please avoid editing our default eggs — those provided by support@pterodactyl.io — unless you are absolutely sure of what you are doing.
    diff --git a/resources/themes/pterodactyl/admin/nests/new.blade.php b/resources/themes/pterodactyl/admin/nests/new.blade.php index ed7fa3cd..a93911be 100644 --- a/resources/themes/pterodactyl/admin/nests/new.blade.php +++ b/resources/themes/pterodactyl/admin/nests/new.blade.php @@ -31,7 +31,7 @@
    -

    This should be a descriptive category name that emcompasses all of the eggs within the nest.

    +

    This should be a descriptive category name that encompasses all of the eggs within the nest.

    diff --git a/resources/themes/pterodactyl/admin/nests/view.blade.php b/resources/themes/pterodactyl/admin/nests/view.blade.php index fe1e4946..d54155e5 100644 --- a/resources/themes/pterodactyl/admin/nests/view.blade.php +++ b/resources/themes/pterodactyl/admin/nests/view.blade.php @@ -28,7 +28,7 @@
    -

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

    +

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

    diff --git a/resources/themes/pterodactyl/admin/nodes/new.blade.php b/resources/themes/pterodactyl/admin/nodes/new.blade.php index 0064ed89..94ecb609 100644 --- a/resources/themes/pterodactyl/admin/nodes/new.blade.php +++ b/resources/themes/pterodactyl/admin/nodes/new.blade.php @@ -126,7 +126,7 @@
    -

    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.

    +

    Enter the total amount of memory available 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.

    @@ -145,7 +145,7 @@
    -

    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.

    +

    Enter the total amount of disk space available 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.

    @@ -158,7 +158,7 @@
    -

    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.

    +

    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 physical 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.

    diff --git a/resources/themes/pterodactyl/admin/nodes/view/index.blade.php b/resources/themes/pterodactyl/admin/nodes/view/index.blade.php index 76a2ca62..9f385c9d 100644 --- a/resources/themes/pterodactyl/admin/nodes/view/index.blade.php +++ b/resources/themes/pterodactyl/admin/nodes/view/index.blade.php @@ -76,7 +76,7 @@

    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.

    +

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

    -

    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.

    +

    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 physical server's SSH process.

    diff --git a/resources/themes/pterodactyl/admin/packs/modal.blade.php b/resources/themes/pterodactyl/admin/packs/modal.blade.php index dbf2044e..551e6fde 100644 --- a/resources/themes/pterodactyl/admin/packs/modal.blade.php +++ b/resources/themes/pterodactyl/admin/packs/modal.blade.php @@ -20,7 +20,7 @@ @endforeach -

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

    +

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

    diff --git a/resources/themes/pterodactyl/admin/packs/new.blade.php b/resources/themes/pterodactyl/admin/packs/new.blade.php index 35acdb54..1595083e 100644 --- a/resources/themes/pterodactyl/admin/packs/new.blade.php +++ b/resources/themes/pterodactyl/admin/packs/new.blade.php @@ -62,7 +62,7 @@ @endforeach -

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

    +

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

    diff --git a/resources/themes/pterodactyl/admin/packs/view.blade.php b/resources/themes/pterodactyl/admin/packs/view.blade.php index e530bc9c..cba76304 100644 --- a/resources/themes/pterodactyl/admin/packs/view.blade.php +++ b/resources/themes/pterodactyl/admin/packs/view.blade.php @@ -66,7 +66,7 @@ @endforeach -

    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.

    +

    The option that this pack is associated 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.

    diff --git a/resources/themes/pterodactyl/admin/servers/new.blade.php b/resources/themes/pterodactyl/admin/servers/new.blade.php index c4a39f9c..39d7ee32 100644 --- a/resources/themes/pterodactyl/admin/servers/new.blade.php +++ b/resources/themes/pterodactyl/admin/servers/new.blade.php @@ -239,7 +239,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.

    +

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

    diff --git a/resources/themes/pterodactyl/admin/servers/view/build.blade.php b/resources/themes/pterodactyl/admin/servers/view/build.blade.php index 8900bf90..2c5a45b6 100644 --- a/resources/themes/pterodactyl/admin/servers/view/build.blade.php +++ b/resources/themes/pterodactyl/admin/servers/view/build.blade.php @@ -102,7 +102,7 @@
    -

    The total number of databases a user is allowed to create for this server. Leave blank to allow unlimmited.

    +

    The total number of databases a user is allowed to create for this server. Leave blank to allow unlimited.

    diff --git a/resources/themes/pterodactyl/admin/servers/view/startup.blade.php b/resources/themes/pterodactyl/admin/servers/view/startup.blade.php index 60bc6d53..6bb7a5cd 100644 --- a/resources/themes/pterodactyl/admin/servers/view/startup.blade.php +++ b/resources/themes/pterodactyl/admin/servers/view/startup.blade.php @@ -70,11 +70,11 @@

    - Changing any of the below values will result in the server processing a re-install command. The server will be stopped and will then proceede. - If you are changing the pack, exisiting data may be overwritten. If you would like the service scripts to not run, ensure the box is checked at the bottom. + Changing any of the below values will result in the server processing a re-install command. The server will be stopped and will then proceed. + If you are changing the pack, existing data may be overwritten. If you would like the service scripts to not run, ensure the box is checked at the bottom.

    - This is a destructive operation in many cases. This server will be stopped immediately in order for this action to proceede. + This is a destructive operation in many cases. This server will be stopped immediately in order for this action to proceed.

    diff --git a/resources/themes/pterodactyl/admin/settings/index.blade.php b/resources/themes/pterodactyl/admin/settings/index.blade.php index 62ef0963..489646dc 100644 --- a/resources/themes/pterodactyl/admin/settings/index.blade.php +++ b/resources/themes/pterodactyl/admin/settings/index.blade.php @@ -52,7 +52,7 @@
    - +
    @foreach($languages as $key => $value) diff --git a/resources/themes/pterodactyl/admin/users/view.blade.php b/resources/themes/pterodactyl/admin/users/view.blade.php index fa3b333d..125719d9 100644 --- a/resources/themes/pterodactyl/admin/users/view.blade.php +++ b/resources/themes/pterodactyl/admin/users/view.blade.php @@ -52,7 +52,7 @@
    - +
    \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}/v1/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}/v1/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: '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}/v1/server/file/delete`,\n timeout: 10000,\n data: JSON.stringify({\n items: [`${delPath}${delName}`]\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 toggleMassActions() {\n if ($('#file_listing input[type=\"checkbox\"]:checked').length) {\n $('#mass_actions').removeClass('disabled');\n } else {\n $('#mass_actions').addClass('disabled');\n }\n }\n\n toggleHighlight(event) {\n const parent = $(event.currentTarget);\n const item = $(event.currentTarget).find('input');\n\n if($(item).is(':checked')) {\n $(item).prop('checked', false);\n parent.removeClass('warning').delay(200);\n } else {\n $(item).prop('checked', true);\n parent.addClass('warning').delay(200);\n }\n }\n\n highlightAll(event) {\n let parent;\n const item = $(event.currentTarget).find('input');\n\n if($(item).is(':checked')) {\n $('#file_listing input[type=checkbox]').prop('checked', false);\n $('#file_listing input[data-action=\"addSelection\"]').each(function() {\n parent = $(this).closest('tr');\n parent.removeClass('warning').delay(200);\n });\n } else {\n $('#file_listing input[type=checkbox]').prop('checked', true);\n $('#file_listing input[data-action=\"addSelection\"]').each(function() {\n parent = $(this).closest('tr');\n parent.addClass('warning').delay(200);\n });\n }\n }\n\n deleteSelected() {\n let selectedItems = [];\n let selectedItemsElements = [];\n let parent;\n let nameBlock;\n let delLocation;\n\n $('#file_listing input[data-action=\"addSelection\"]:checked').each(function() {\n parent = $(this).closest('tr');\n nameBlock = $(parent).find('td[data-identifier=\"name\"]');\n delLocation = decodeURIComponent(nameBlock.data('path')) + decodeURIComponent(nameBlock.data('name'));\n\n selectedItems.push(delLocation);\n selectedItemsElements.push(parent);\n });\n\n if (selectedItems.length != 0)\n {\n let formattedItems = \"\";\n $.each(selectedItems, function(key, value) {\n formattedItems += (\"\" + value + \", \");\n })\n\n formattedItems = formattedItems.slice(0, -2);\n\n swal({\n type: 'warning',\n title: '',\n text: 'Are you sure you want to delete:' + formattedItems + '? 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: '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}/v1/server/file/delete`,\n timeout: 10000,\n data: JSON.stringify({\n items: selectedItems\n }),\n }).done(data => {\n $('#file_listing input:checked').each(function() {\n $(this).prop('checked', false);\n });\n\n $.each(selectedItemsElements, function() {\n $(this).addClass('warning').delay(200).fadeOut();\n })\n\n swal({\n type: 'success',\n title: 'Files 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 these files. Please try again.',\n });\n });\n });\n } else {\n swal({\n type: 'warning',\n title: '',\n text: 'Please select files/folders to delete.',\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}/v1/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}/v1/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 = $('#file_listing').data('current-dir');\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 if ($(document).find('#fileOptionMenu').is(':visible')) {\n $('body').trigger('click');\n return;\n }\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 this.addFolderButton();\n this.selectItem();\n this.selectAll();\n this.selectiveDeletion();\n this.selectRow();\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\n if ((path !== '' && path !== '/') && jqXHR.status === 404) {\n return this.list('', next);\n }\n\n swal({\n type: 'error',\n title: 'File Error',\n text: jqXHR.responseJSON.errors[0].detail || '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 selectItem() {\n $('[data-action=\"addSelection\"]').on('click', event => {\n event.preventDefault();\n });\n }\n\n selectAll() {\n $('[data-action=\"selectAll\"]').on('click', event => {\n event.preventDefault();\n });\n }\n\n selectiveDeletion() {\n $('[data-action=\"selective-deletion\"]').on('mousedown', event => {\n new ActionsClass().deleteSelected();\n });\n }\n\n addFolderButton() {\n $('[data-action=\"add-folder\"]').unbind().on('click', () => {\n new ActionsClass().folder($('#file_listing').data('current-dir') || '/');\n })\n }\n\n selectRow() {\n $('#file_listing tr').on('mousedown', event => {\n if (event.which === 1) {\n if ($(event.target).is('th') || $(event.target).is('input[data-action=\"selectAll\"]')) {\n new ActionsClass().highlightAll(event);\n } else if ($(event.target).is('td') || $(event.target).is('input[data-action=\"addSelection\"]')) {\n new ActionsClass().toggleHighlight(event);\n }\n\n new ActionsClass().toggleMassActions();\n }\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":"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","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(path) {\n let inputValue\n if (path) {\n inputValue = path\n } else {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.data('name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n if ($(this.element).data('type') === 'file') {\n inputValue = currentPath;\n } else {\n inputValue = `${currentPath}${currentName}/`;\n }\n }\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}/v1/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 occurred 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}/v1/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 occurred 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}/v1/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 occurred 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}/v1/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 occurred 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 + '?',\n html: true,\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true\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}/v1/server/file/delete`,\n timeout: 10000,\n data: JSON.stringify({\n items: [`${delPath}${delName}`]\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 occurred while attempting to delete this file. Please try again.',\n });\n });\n });\n }\n\n toggleMassActions() {\n if ($('#file_listing input[type=\"checkbox\"]:checked').length) {\n $('#mass_actions').removeClass('disabled');\n } else {\n $('#mass_actions').addClass('disabled');\n }\n }\n\n toggleHighlight(event) {\n const parent = $(event.currentTarget);\n const item = $(event.currentTarget).find('input');\n\n if($(item).is(':checked')) {\n $(item).prop('checked', false);\n parent.removeClass('warning').delay(200);\n } else {\n $(item).prop('checked', true);\n parent.addClass('warning').delay(200);\n }\n }\n\n highlightAll(event) {\n let parent;\n const item = $(event.currentTarget).find('input');\n\n if($(item).is(':checked')) {\n $('#file_listing input[type=checkbox]').prop('checked', false);\n $('#file_listing input[data-action=\"addSelection\"]').each(function() {\n parent = $(this).closest('tr');\n parent.removeClass('warning').delay(200);\n });\n } else {\n $('#file_listing input[type=checkbox]').prop('checked', true);\n $('#file_listing input[data-action=\"addSelection\"]').each(function() {\n parent = $(this).closest('tr');\n parent.addClass('warning').delay(200);\n });\n }\n }\n\n deleteSelected() {\n let selectedItems = [];\n let selectedItemsElements = [];\n let parent;\n let nameBlock;\n let delLocation;\n\n $('#file_listing input[data-action=\"addSelection\"]:checked').each(function() {\n parent = $(this).closest('tr');\n nameBlock = $(parent).find('td[data-identifier=\"name\"]');\n delLocation = decodeURIComponent(nameBlock.data('path')) + decodeURIComponent(nameBlock.data('name'));\n\n selectedItems.push(delLocation);\n selectedItemsElements.push(parent);\n });\n\n if (selectedItems.length != 0)\n {\n let formattedItems = \"\";\n let i = 0;\n $.each(selectedItems, function(key, value) {\n formattedItems += (\"\" + value + \", \");\n i++;\n return i < 5;\n });\n\n formattedItems = formattedItems.slice(0, -2);\n if (selectedItems.length > 5) {\n formattedItems += ', and ' + (selectedItems.length - 5) + ' other(s)';\n }\n\n swal({\n type: 'warning',\n title: '',\n text: 'Are you sure you want to delete the following files: ' + formattedItems + '?',\n html: true,\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true\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}/v1/server/file/delete`,\n timeout: 10000,\n data: JSON.stringify({\n items: selectedItems\n }),\n }).done(data => {\n $('#file_listing input:checked').each(function() {\n $(this).prop('checked', false);\n });\n\n $.each(selectedItemsElements, function() {\n $(this).addClass('warning').delay(200).fadeOut();\n })\n\n swal({\n type: 'success',\n title: 'Files Deleted'\n });\n }).fail(jqXHR => {\n console.error(jqXHR);\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: 'An error occurred while attempting to delete these files. Please try again.',\n });\n });\n });\n } else {\n swal({\n type: 'warning',\n title: '',\n text: 'Please select files/folders to delete.',\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}/v1/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 occurred 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}/v1/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 occurred 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 = $('#file_listing').data('current-dir');\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 if ($(document).find('#fileOptionMenu').is(':visible')) {\n $('body').trigger('click');\n return;\n }\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 this.addFolderButton();\n this.selectItem();\n this.selectAll();\n this.selectiveDeletion();\n this.selectRow();\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\n if ((path !== '' && path !== '/') && jqXHR.status === 404) {\n return this.list('', next);\n }\n\n swal({\n type: 'error',\n title: 'File Error',\n text: jqXHR.responseJSON.errors[0].detail || 'An error occurred 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 selectItem() {\n $('[data-action=\"addSelection\"]').on('click', event => {\n event.preventDefault();\n });\n }\n\n selectAll() {\n $('[data-action=\"selectAll\"]').on('click', event => {\n event.preventDefault();\n });\n }\n\n selectiveDeletion() {\n $('[data-action=\"selective-deletion\"]').on('mousedown', event => {\n new ActionsClass().deleteSelected();\n });\n }\n\n addFolderButton() {\n $('[data-action=\"add-folder\"]').unbind().on('click', () => {\n new ActionsClass().folder($('#file_listing').data('current-dir') || '/');\n })\n }\n\n selectRow() {\n $('#file_listing tr').on('mousedown', event => {\n if (event.which === 1) {\n if ($(event.target).is('th') || $(event.target).is('input[data-action=\"selectAll\"]')) {\n new ActionsClass().highlightAll(event);\n } else if ($(event.target).is('td') || $(event.target).is('input[data-action=\"addSelection\"]')) {\n new ActionsClass().toggleHighlight(event);\n }\n\n new ActionsClass().toggleMassActions();\n }\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 4e2eafe73f13152e198f4f62e5fcd5a1587803e4 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 May 2018 11:42:13 -0700 Subject: [PATCH 57/66] Update dependencies --- composer.lock | 314 ++++++++++++++++++++++++++------------------------ 1 file changed, 164 insertions(+), 150 deletions(-) diff --git a/composer.lock b/composer.lock index cca82308..ea58eb51 100644 --- a/composer.lock +++ b/composer.lock @@ -1,10 +1,10 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "146950cbea496a5c754d3b441ebf0118", + "content-hash": "36fe7d95a4e28ceee9aeb6e63e2187a0", "packages": [ { "name": "appstract/laravel-blade-directives", @@ -61,16 +61,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.55.11", + "version": "3.57.1", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "237f2acff17238ac723845e0f302d5672d0bf0a1" + "reference": "795332f5f3a81474e85653e62d1d7b306bd4eeae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/237f2acff17238ac723845e0f302d5672d0bf0a1", - "reference": "237f2acff17238ac723845e0f302d5672d0bf0a1", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/795332f5f3a81474e85653e62d1d7b306bd4eeae", + "reference": "795332f5f3a81474e85653e62d1d7b306bd4eeae", "shasum": "" }, "require": { @@ -137,7 +137,7 @@ "s3", "sdk" ], - "time": "2018-05-10T19:27:13+00:00" + "time": "2018-05-25T21:34:30+00:00" }, { "name": "cakephp/chronos", @@ -1162,16 +1162,16 @@ }, { "name": "igaster/laravel-theme", - "version": "v2.0.7", + "version": "v2.0.8", "source": { "type": "git", "url": "https://github.com/igaster/laravel-theme.git", - "reference": "b37c53021e1f523e7448a1c41e09a9d7ade11f18" + "reference": "697548f755d81175bef8c0f37c1f189a62e205bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/igaster/laravel-theme/zipball/b37c53021e1f523e7448a1c41e09a9d7ade11f18", - "reference": "b37c53021e1f523e7448a1c41e09a9d7ade11f18", + "url": "https://api.github.com/repos/igaster/laravel-theme/zipball/697548f755d81175bef8c0f37c1f189a62e205bd", + "reference": "697548f755d81175bef8c0f37c1f189a62e205bd", "shasum": "" }, "require": { @@ -1221,7 +1221,7 @@ "themes", "views" ], - "time": "2018-04-27T12:29:41+00:00" + "time": "2018-05-24T08:05:30+00:00" }, { "name": "jakub-onderka/php-console-color", @@ -1369,16 +1369,16 @@ }, { "name": "laravel/framework", - "version": "v5.6.21", + "version": "v5.6.23", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "458a89b1c5ff73072c27308566f444c790f76f28" + "reference": "f547f0a71a12763d1adb8493237d541c9e3a5d10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/458a89b1c5ff73072c27308566f444c790f76f28", - "reference": "458a89b1c5ff73072c27308566f444c790f76f28", + "url": "https://api.github.com/repos/laravel/framework/zipball/f547f0a71a12763d1adb8493237d541c9e3a5d10", + "reference": "f547f0a71a12763d1adb8493237d541c9e3a5d10", "shasum": "" }, "require": { @@ -1504,20 +1504,20 @@ "framework", "laravel" ], - "time": "2018-05-08T13:30:15+00:00" + "time": "2018-05-22T14:55:57+00:00" }, { "name": "laravel/tinker", - "version": "v1.0.6", + "version": "v1.0.7", "source": { "type": "git", "url": "https://github.com/laravel/tinker.git", - "reference": "b22fe905fcefdffae76b011e27c7ac09e07e052b" + "reference": "e3086ee8cb1f54a39ae8dcb72d1c37d10128997d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/tinker/zipball/b22fe905fcefdffae76b011e27c7ac09e07e052b", - "reference": "b22fe905fcefdffae76b011e27c7ac09e07e052b", + "url": "https://api.github.com/repos/laravel/tinker/zipball/e3086ee8cb1f54a39ae8dcb72d1c37d10128997d", + "reference": "e3086ee8cb1f54a39ae8dcb72d1c37d10128997d", "shasum": "" }, "require": { @@ -1567,7 +1567,7 @@ "laravel", "psysh" ], - "time": "2018-04-16T12:10:37+00:00" + "time": "2018-05-17T13:42:07+00:00" }, { "name": "league/flysystem", @@ -1890,50 +1890,6 @@ ], "time": "2017-06-19T01:22:40+00:00" }, - { - "name": "mtdowling/cron-expression", - "version": "v1.2.1", - "source": { - "type": "git", - "url": "https://github.com/mtdowling/cron-expression.git", - "reference": "9504fa9ea681b586028adaaa0877db4aecf32bad" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/9504fa9ea681b586028adaaa0877db4aecf32bad", - "reference": "9504fa9ea681b586028adaaa0877db4aecf32bad", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.0|~5.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Cron\\": "src/Cron/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", - "keywords": [ - "cron", - "schedule" - ], - "time": "2017-01-23T04:29:33+00:00" - }, { "name": "mtdowling/jmespath.php", "version": "2.4.0", @@ -2570,16 +2526,16 @@ }, { "name": "psy/psysh", - "version": "v0.9.3", + "version": "v0.9.4", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "79c280013cf0b30fa23f3ba8bd3649218075adf4" + "reference": "4d969a0e08e1e05e7207c07cb4207017ecc9a331" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/79c280013cf0b30fa23f3ba8bd3649218075adf4", - "reference": "79c280013cf0b30fa23f3ba8bd3649218075adf4", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/4d969a0e08e1e05e7207c07cb4207017ecc9a331", + "reference": "4d969a0e08e1e05e7207c07cb4207017ecc9a331", "shasum": "" }, "require": { @@ -2591,9 +2547,9 @@ "symfony/var-dumper": "~2.7|~3.0|~4.0" }, "require-dev": { + "bamarni/composer-bin-plugin": "^1.2", "hoa/console": "~2.15|~3.16", - "phpunit/phpunit": "~4.8.35|~5.0|~6.0|~7.0", - "symfony/finder": "~2.1|~3.0|~4.0" + "phpunit/phpunit": "~4.8.35|~5.0|~6.0|~7.0" }, "suggest": { "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", @@ -2638,7 +2594,7 @@ "interactive", "shell" ], - "time": "2018-04-18T12:32:50+00:00" + "time": "2018-05-22T06:48:07+00:00" }, { "name": "ramsey/uuid", @@ -3107,16 +3063,16 @@ }, { "name": "symfony/console", - "version": "v4.0.9", + "version": "v4.0.11", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "3e820bc2c520a87ca209ad8fa961c97f42e0b4ae" + "reference": "058f120b8e06ebcd7b211de5ffae07b2db00fbdd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/3e820bc2c520a87ca209ad8fa961c97f42e0b4ae", - "reference": "3e820bc2c520a87ca209ad8fa961c97f42e0b4ae", + "url": "https://api.github.com/repos/symfony/console/zipball/058f120b8e06ebcd7b211de5ffae07b2db00fbdd", + "reference": "058f120b8e06ebcd7b211de5ffae07b2db00fbdd", "shasum": "" }, "require": { @@ -3171,20 +3127,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-04-30T01:23:47+00:00" + "time": "2018-05-16T09:05:32+00:00" }, { "name": "symfony/css-selector", - "version": "v4.0.9", + "version": "v4.0.11", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "03f965583147957f1ecbad7ea1c9d6fd5e525ec2" + "reference": "0383a1a4eb1ffcac28719975d3e01bfa14be8ab3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/03f965583147957f1ecbad7ea1c9d6fd5e525ec2", - "reference": "03f965583147957f1ecbad7ea1c9d6fd5e525ec2", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/0383a1a4eb1ffcac28719975d3e01bfa14be8ab3", + "reference": "0383a1a4eb1ffcac28719975d3e01bfa14be8ab3", "shasum": "" }, "require": { @@ -3224,20 +3180,20 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2018-03-19T22:35:49+00:00" + "time": "2018-05-11T15:58:37+00:00" }, { "name": "symfony/debug", - "version": "v4.0.9", + "version": "v4.0.11", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "e1d57cdb357e5b10f5fdacbb0b86689c0a435e6e" + "reference": "4e7c98de67cc4171d4c986554e09a511da40f3d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/e1d57cdb357e5b10f5fdacbb0b86689c0a435e6e", - "reference": "e1d57cdb357e5b10f5fdacbb0b86689c0a435e6e", + "url": "https://api.github.com/repos/symfony/debug/zipball/4e7c98de67cc4171d4c986554e09a511da40f3d8", + "reference": "4e7c98de67cc4171d4c986554e09a511da40f3d8", "shasum": "" }, "require": { @@ -3280,11 +3236,11 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2018-04-30T16:59:37+00:00" + "time": "2018-05-16T09:05:32+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.0.9", + "version": "v4.0.11", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -3347,16 +3303,16 @@ }, { "name": "symfony/finder", - "version": "v4.0.9", + "version": "v4.0.11", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49" + "reference": "8c633f5a815903a1fe6e3fc135f207267a8a79af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ca27c02b7a3fef4828c998c2ff9ba7aae1641c49", - "reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49", + "url": "https://api.github.com/repos/symfony/finder/zipball/8c633f5a815903a1fe6e3fc135f207267a8a79af", + "reference": "8c633f5a815903a1fe6e3fc135f207267a8a79af", "shasum": "" }, "require": { @@ -3392,20 +3348,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-04-04T05:10:37+00:00" + "time": "2018-05-16T09:05:32+00:00" }, { "name": "symfony/http-foundation", - "version": "v4.0.9", + "version": "v4.0.11", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "014487772c22d893168e5d628a13e882009fea29" + "reference": "277b757a2d3960170d99d372e171a8a18916467a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/014487772c22d893168e5d628a13e882009fea29", - "reference": "014487772c22d893168e5d628a13e882009fea29", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/277b757a2d3960170d99d372e171a8a18916467a", + "reference": "277b757a2d3960170d99d372e171a8a18916467a", "shasum": "" }, "require": { @@ -3445,20 +3401,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2018-04-30T01:05:59+00:00" + "time": "2018-05-25T11:08:56+00:00" }, { "name": "symfony/http-kernel", - "version": "v4.0.9", + "version": "v4.0.11", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "8333264b6de323ea27a08627d5396aa564fb9c25" + "reference": "450a1bda817f2dce25a9e13f0f011336743f2a48" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/8333264b6de323ea27a08627d5396aa564fb9c25", - "reference": "8333264b6de323ea27a08627d5396aa564fb9c25", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/450a1bda817f2dce25a9e13f0f011336743f2a48", + "reference": "450a1bda817f2dce25a9e13f0f011336743f2a48", "shasum": "" }, "require": { @@ -3466,7 +3422,8 @@ "psr/log": "~1.0", "symfony/debug": "~3.4|~4.0", "symfony/event-dispatcher": "~3.4|~4.0", - "symfony/http-foundation": "~3.4.4|~4.0.4" + "symfony/http-foundation": "~3.4.4|~4.0.4", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { "symfony/config": "<3.4", @@ -3531,7 +3488,62 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2018-04-30T19:45:57+00:00" + "time": "2018-05-25T13:32:52+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/7cc359f1b7b80fc25ed7796be7d96adc9b354bae", + "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + }, + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2018-04-30T19:57:29+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -3757,16 +3769,16 @@ }, { "name": "symfony/process", - "version": "v4.0.9", + "version": "v4.0.11", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "d7dc1ee5dfe9f732cb1bba7310f5b99f2b7a6d25" + "reference": "3621fa74d0576a6f89d63bc44fabd376711bd0b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d7dc1ee5dfe9f732cb1bba7310f5b99f2b7a6d25", - "reference": "d7dc1ee5dfe9f732cb1bba7310f5b99f2b7a6d25", + "url": "https://api.github.com/repos/symfony/process/zipball/3621fa74d0576a6f89d63bc44fabd376711bd0b0", + "reference": "3621fa74d0576a6f89d63bc44fabd376711bd0b0", "shasum": "" }, "require": { @@ -3802,20 +3814,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-04-03T05:24:00+00:00" + "time": "2018-05-16T09:05:32+00:00" }, { "name": "symfony/routing", - "version": "v4.0.9", + "version": "v4.0.11", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "1dfbfdf060bbc80da8dedc062050052e694cd027" + "reference": "e8833b64b139926cbe1610d53722185e55c18e44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/1dfbfdf060bbc80da8dedc062050052e694cd027", - "reference": "1dfbfdf060bbc80da8dedc062050052e694cd027", + "url": "https://api.github.com/repos/symfony/routing/zipball/e8833b64b139926cbe1610d53722185e55c18e44", + "reference": "e8833b64b139926cbe1610d53722185e55c18e44", "shasum": "" }, "require": { @@ -3880,20 +3892,20 @@ "uri", "url" ], - "time": "2018-04-20T06:20:23+00:00" + "time": "2018-05-16T14:21:07+00:00" }, { "name": "symfony/translation", - "version": "v4.0.9", + "version": "v4.0.11", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "ad3abf08eb3450491d8d76513100ef58194cd13e" + "reference": "e1f5863d0a9e79cfec7f031421ced3fe1d403e66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/ad3abf08eb3450491d8d76513100ef58194cd13e", - "reference": "ad3abf08eb3450491d8d76513100ef58194cd13e", + "url": "https://api.github.com/repos/symfony/translation/zipball/e1f5863d0a9e79cfec7f031421ced3fe1d403e66", + "reference": "e1f5863d0a9e79cfec7f031421ced3fe1d403e66", "shasum": "" }, "require": { @@ -3948,11 +3960,11 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2018-04-30T01:23:47+00:00" + "time": "2018-05-21T10:09:47+00:00" }, { "name": "symfony/var-dumper", - "version": "v4.0.9", + "version": "v4.0.11", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", @@ -4222,16 +4234,16 @@ "packages-dev": [ { "name": "barryvdh/laravel-debugbar", - "version": "v3.1.4", + "version": "v3.1.5", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-debugbar.git", - "reference": "7a91480cc6e597caed5117a3c5d685f06d35c5a1" + "reference": "d3cdca2ad6cc6e67735b4a63e7551c690a497f5f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/7a91480cc6e597caed5117a3c5d685f06d35c5a1", - "reference": "7a91480cc6e597caed5117a3c5d685f06d35c5a1", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/d3cdca2ad6cc6e67735b4a63e7551c690a497f5f", + "reference": "d3cdca2ad6cc6e67735b4a63e7551c690a497f5f", "shasum": "" }, "require": { @@ -4286,7 +4298,7 @@ "profiler", "webprofiler" ], - "time": "2018-03-06T08:35:31+00:00" + "time": "2018-05-03T18:27:04+00:00" }, { "name": "barryvdh/laravel-ide-helper", @@ -4412,16 +4424,16 @@ }, { "name": "codedungeon/php-cli-colors", - "version": "1.10.3", + "version": "1.10.7", "source": { "type": "git", "url": "https://github.com/mikeerickson/php-cli-colors.git", - "reference": "1beb5c21b21b2c125aff26a75caf02fcec12571f" + "reference": "5649ef76ec0c9ed626e95bf40fdfaf4b8efcf79b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mikeerickson/php-cli-colors/zipball/1beb5c21b21b2c125aff26a75caf02fcec12571f", - "reference": "1beb5c21b21b2c125aff26a75caf02fcec12571f", + "url": "https://api.github.com/repos/mikeerickson/php-cli-colors/zipball/5649ef76ec0c9ed626e95bf40fdfaf4b8efcf79b", + "reference": "5649ef76ec0c9ed626e95bf40fdfaf4b8efcf79b", "shasum": "" }, "require-dev": { @@ -4452,7 +4464,7 @@ "package", "php" ], - "time": "2017-09-12T17:12:52+00:00" + "time": "2018-05-17T01:34:14+00:00" }, { "name": "codedungeon/phpunit-result-printer", @@ -6652,7 +6664,7 @@ }, { "name": "symfony/class-loader", - "version": "v3.4.9", + "version": "v3.4.11", "source": { "type": "git", "url": "https://github.com/symfony/class-loader.git", @@ -6708,20 +6720,21 @@ }, { "name": "symfony/filesystem", - "version": "v4.0.9", + "version": "v4.0.11", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "5d2d655b2c72fc4d9bf7e9bf14f72a447b940f21" + "reference": "7a69e728e9f0044958c2fd7d72bfe5e7bd1a4d04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/5d2d655b2c72fc4d9bf7e9bf14f72a447b940f21", - "reference": "5d2d655b2c72fc4d9bf7e9bf14f72a447b940f21", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/7a69e728e9f0044958c2fd7d72bfe5e7bd1a4d04", + "reference": "7a69e728e9f0044958c2fd7d72bfe5e7bd1a4d04", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8" }, "type": "library", "extra": { @@ -6753,20 +6766,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2018-02-22T10:50:29+00:00" + "time": "2018-05-16T09:05:32+00:00" }, { "name": "symfony/options-resolver", - "version": "v4.0.9", + "version": "v4.0.11", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "371532a2cfe932f7a3766dd4c45364566def1dd0" + "reference": "ac1c3a814ddcad9d0cc2d0382e215d3bff8ae2d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/371532a2cfe932f7a3766dd4c45364566def1dd0", - "reference": "371532a2cfe932f7a3766dd4c45364566def1dd0", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/ac1c3a814ddcad9d0cc2d0382e215d3bff8ae2d2", + "reference": "ac1c3a814ddcad9d0cc2d0382e215d3bff8ae2d2", "shasum": "" }, "require": { @@ -6807,7 +6820,7 @@ "configuration", "options" ], - "time": "2018-01-18T22:19:33+00:00" + "time": "2018-05-11T15:58:37+00:00" }, { "name": "symfony/polyfill-php70", @@ -6870,7 +6883,7 @@ }, { "name": "symfony/stopwatch", - "version": "v4.0.9", + "version": "v4.0.11", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", @@ -6919,20 +6932,21 @@ }, { "name": "symfony/yaml", - "version": "v4.0.9", + "version": "v4.0.11", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "275ad099e4cbe612a2acbca14a16dd1c5311324d" + "reference": "048b1be5fb96e73ff1d065f5e7e23f84415ac907" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/275ad099e4cbe612a2acbca14a16dd1c5311324d", - "reference": "275ad099e4cbe612a2acbca14a16dd1c5311324d", + "url": "https://api.github.com/repos/symfony/yaml/zipball/048b1be5fb96e73ff1d065f5e7e23f84415ac907", + "reference": "048b1be5fb96e73ff1d065f5e7e23f84415ac907", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { "symfony/console": "<3.4" @@ -6973,7 +6987,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2018-04-08T08:49:08+00:00" + "time": "2018-05-07T07:12:24+00:00" }, { "name": "theseer/tokenizer", From 86e70853960f89dd308aa475834deabcff44f661 Mon Sep 17 00:00:00 2001 From: stanjg Date: Sat, 26 May 2018 20:58:49 +0200 Subject: [PATCH 58/66] Cleaned up the controller and prepared for tests --- .../Repository/RepositoryInterface.php | 7 ++ .../Admin/StatisticsController.php | 65 +++++++++++++------ .../Eloquent/EloquentRepository.php | 10 +++ .../JavascriptStatisticsInjection.php | 24 +++++++ 4 files changed, 85 insertions(+), 21 deletions(-) create mode 100644 app/Traits/Controllers/JavascriptStatisticsInjection.php diff --git a/app/Contracts/Repository/RepositoryInterface.php b/app/Contracts/Repository/RepositoryInterface.php index 4a098c34..3da9da00 100644 --- a/app/Contracts/Repository/RepositoryInterface.php +++ b/app/Contracts/Repository/RepositoryInterface.php @@ -200,4 +200,11 @@ interface RepositoryInterface * @return bool */ public function insertIgnore(array $values): bool; + + /** + * Get the amount of entries in the database + * + * @return int + */ + public function count(): int; } diff --git a/app/Http/Controllers/Admin/StatisticsController.php b/app/Http/Controllers/Admin/StatisticsController.php index aedca3d6..984b6de2 100644 --- a/app/Http/Controllers/Admin/StatisticsController.php +++ b/app/Http/Controllers/Admin/StatisticsController.php @@ -5,52 +5,75 @@ namespace Pterodactyl\Http\Controllers\Admin; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use JavaScript; +use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface; +use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface; +use Pterodactyl\Contracts\Repository\EggRepositoryInterface; +use Pterodactyl\Contracts\Repository\NodeRepositoryInterface; +use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; +use Pterodactyl\Contracts\Repository\UserRepositoryInterface; use Pterodactyl\Http\Controllers\Controller; -use Pterodactyl\Models\Allocation; -use Pterodactyl\Models\Database; -use Pterodactyl\Models\Egg; -use Pterodactyl\Models\Node; -use Pterodactyl\Models\Server; -use Pterodactyl\Models\User; use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService; +use Pterodactyl\Traits\Controllers\JavascriptInjection; class StatisticsController extends Controller { + use JavascriptInjection; + + private $allocationRepository; + + private $databaseRepository; private $keyProviderService; - function __construct(DaemonKeyProviderService $keyProviderService) + private $eggRepository; + + private $nodeRepository; + + private $serverRepository; + + private $userRepository; + + function __construct( + AllocationRepositoryInterface $allocationRepository, + DatabaseRepositoryInterface $databaseRepository, + DaemonKeyProviderService $keyProviderService, + EggRepositoryInterface $eggRepository, + NodeRepositoryInterface $nodeRepository, + ServerRepositoryInterface $serverRepository, + UserRepositoryInterface $userRepository + ) { + $this->allocationRepository = $allocationRepository; + $this->databaseRepository = $databaseRepository; $this->keyProviderService = $keyProviderService; + $this->eggRepository = $eggRepository; + $this->nodeRepository = $nodeRepository; + $this->serverRepository = $serverRepository; + $this->userRepository = $userRepository; } public function index(Request $request) { - $servers = Server::all(); - $nodes = Node::all(); + $servers = $this->serverRepository->all(); $serversCount = count($servers); + $nodes = $this->nodeRepository->all(); $nodesCount = count($nodes); - $usersCount = User::count(); - $eggsCount = Egg::count(); - $databasesCount = Database::count(); + $usersCount = $this->userRepository->count(); + $eggsCount = $this->eggRepository->count(); + $databasesCount = $this->databaseRepository->count(); $totalServerRam = DB::table('servers')->sum('memory'); $totalNodeRam = DB::table('nodes')->sum('memory'); $totalServerDisk = DB::table('servers')->sum('disk'); $totalNodeDisk = DB::table('nodes')->sum('disk'); - $totalAllocations = Allocation::count(); - - $suspendedServersCount = Server::where('suspended', true)->count(); + $totalAllocations = $this->allocationRepository->count(); + $suspendedServersCount = $this->serverRepository->getBuilder()->where('suspended', true)->count(); $tokens = []; foreach ($nodes as $node) { - $server = Server::where('node_id', $node->id)->first(); - if ($server == null) - continue; - - $tokens[$node->id] = $this->keyProviderService->handle($server, $request->user()); + $tokens[$node->id] = $node->daemonSecret; } - Javascript::put([ + $this->injectJavascript([ 'servers' => $servers, 'serverCount' => $serversCount, 'suspendedServers' => $suspendedServersCount, diff --git a/app/Repositories/Eloquent/EloquentRepository.php b/app/Repositories/Eloquent/EloquentRepository.php index 74ec809f..64e7cfb6 100644 --- a/app/Repositories/Eloquent/EloquentRepository.php +++ b/app/Repositories/Eloquent/EloquentRepository.php @@ -296,4 +296,14 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf return $this->getBuilder()->getConnection()->statement($statement, $bindings); } + + /** + * Get the amount of entries in the database + * + * @return int + */ + public function count(): int + { + return $this->getBuilder()->count(); + } } diff --git a/app/Traits/Controllers/JavascriptStatisticsInjection.php b/app/Traits/Controllers/JavascriptStatisticsInjection.php new file mode 100644 index 00000000..77976423 --- /dev/null +++ b/app/Traits/Controllers/JavascriptStatisticsInjection.php @@ -0,0 +1,24 @@ + Date: Sat, 26 May 2018 21:02:47 +0200 Subject: [PATCH 59/66] Wording changes and fix of major fail last commit --- app/Http/Controllers/Admin/StatisticsController.php | 5 ++--- app/Traits/Controllers/JavascriptStatisticsInjection.php | 2 +- public/themes/pterodactyl/js/admin/statistics.js | 4 ++-- resources/themes/pterodactyl/admin/statistics.blade.php | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/Http/Controllers/Admin/StatisticsController.php b/app/Http/Controllers/Admin/StatisticsController.php index 984b6de2..07124e4b 100644 --- a/app/Http/Controllers/Admin/StatisticsController.php +++ b/app/Http/Controllers/Admin/StatisticsController.php @@ -4,7 +4,6 @@ namespace Pterodactyl\Http\Controllers\Admin; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; -use JavaScript; use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface; use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface; use Pterodactyl\Contracts\Repository\EggRepositoryInterface; @@ -13,11 +12,11 @@ use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; use Pterodactyl\Contracts\Repository\UserRepositoryInterface; use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService; -use Pterodactyl\Traits\Controllers\JavascriptInjection; +use Pterodactyl\Traits\Controllers\JavascriptStatisticsInjection; class StatisticsController extends Controller { - use JavascriptInjection; + use JavascriptStatisticsInjection; private $allocationRepository; diff --git a/app/Traits/Controllers/JavascriptStatisticsInjection.php b/app/Traits/Controllers/JavascriptStatisticsInjection.php index 77976423..3b4e52d0 100644 --- a/app/Traits/Controllers/JavascriptStatisticsInjection.php +++ b/app/Traits/Controllers/JavascriptStatisticsInjection.php @@ -10,7 +10,7 @@ namespace Pterodactyl\Traits\Controllers; use JavaScript; -class JavascriptStatisticsInjection +trait JavascriptStatisticsInjection { /** diff --git a/public/themes/pterodactyl/js/admin/statistics.js b/public/themes/pterodactyl/js/admin/statistics.js index 12f4277b..59034a8d 100644 --- a/public/themes/pterodactyl/js/admin/statistics.js +++ b/public/themes/pterodactyl/js/admin/statistics.js @@ -5,7 +5,7 @@ let diskChart = new Chart($('#disk_chart'), { labels: ['Free Disk', 'Used Disk'], datasets: [ { - label: 'Disk in MBs', + label: 'Disk (in MB)', backgroundColor: ['#51B060', '#ff0000'], data: [freeDisk, Pterodactyl.totalServerDisk] } @@ -20,7 +20,7 @@ let ramChart = new Chart($('#ram_chart'), { labels: ['Free RAM', 'Used RAM'], datasets: [ { - label: 'RAM in MBs', + label: 'Memory (in MB)', backgroundColor: ['#51B060', '#ff0000'], data: [freeRam, Pterodactyl.totalServerRam] } diff --git a/resources/themes/pterodactyl/admin/statistics.blade.php b/resources/themes/pterodactyl/admin/statistics.blade.php index 46e11233..036ad937 100644 --- a/resources/themes/pterodactyl/admin/statistics.blade.php +++ b/resources/themes/pterodactyl/admin/statistics.blade.php @@ -41,14 +41,14 @@
    - Total used RAM + Total used Memory (in MB) {{ $totalServerRam }}MB
    - Total used disk space + Total used Disk (in MB) {{ $totalServerDisk }}MB
    From 60e1ffa56497e5fe9bee8da8a06e74e54b328e60 Mon Sep 17 00:00:00 2001 From: stanjg Date: Sun, 27 May 2018 00:16:13 +0200 Subject: [PATCH 60/66] Added a test for the controller and cleaned up the controller --- .../Repository/NodeRepositoryInterface.php | 8 ++ .../Repository/ServerRepositoryInterface.php | 7 ++ .../Admin/StatisticsController.php | 38 +++--- app/Repositories/Eloquent/NodeRepository.php | 27 +++++ .../Eloquent/ServerRepository.php | 10 ++ ...ction.php => PlainJavascriptInjection.php} | 2 +- .../themes/pterodactyl/js/admin/statistics.js | 2 +- .../pterodactyl/admin/statistics.blade.php | 4 +- .../Admin/StatisticsControllerTest.php | 113 ++++++++++++++++++ 9 files changed, 188 insertions(+), 23 deletions(-) rename app/Traits/Controllers/{JavascriptStatisticsInjection.php => PlainJavascriptInjection.php} (89%) create mode 100644 tests/Unit/Http/Controllers/Admin/StatisticsControllerTest.php diff --git a/app/Contracts/Repository/NodeRepositoryInterface.php b/app/Contracts/Repository/NodeRepositoryInterface.php index 0ebcbe3a..c533032c 100644 --- a/app/Contracts/Repository/NodeRepositoryInterface.php +++ b/app/Contracts/Repository/NodeRepositoryInterface.php @@ -21,6 +21,14 @@ interface NodeRepositoryInterface extends RepositoryInterface, SearchableInterfa */ public function getUsageStats(Node $node): array; + /** + * Return the usage stats for a single node. + * + * @param \Pterodactyl\Models\Node $node + * @return array + */ + public function getUsageStatsRaw(Node $node): array; + /** * Return all available nodes with a searchable interface. * diff --git a/app/Contracts/Repository/ServerRepositoryInterface.php b/app/Contracts/Repository/ServerRepositoryInterface.php index dc677fba..9fb712e2 100644 --- a/app/Contracts/Repository/ServerRepositoryInterface.php +++ b/app/Contracts/Repository/ServerRepositoryInterface.php @@ -145,4 +145,11 @@ interface ServerRepositoryInterface extends RepositoryInterface, SearchableInter * @return bool */ public function isUniqueUuidCombo(string $uuid, string $short): bool; + + /** + * Get the amount of servers that are suspended + * + * @return int + */ + public function getSuspendedServersCount(): int; } diff --git a/app/Http/Controllers/Admin/StatisticsController.php b/app/Http/Controllers/Admin/StatisticsController.php index 07124e4b..2327fd88 100644 --- a/app/Http/Controllers/Admin/StatisticsController.php +++ b/app/Http/Controllers/Admin/StatisticsController.php @@ -11,19 +11,16 @@ use Pterodactyl\Contracts\Repository\NodeRepositoryInterface; use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; use Pterodactyl\Contracts\Repository\UserRepositoryInterface; use Pterodactyl\Http\Controllers\Controller; -use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService; -use Pterodactyl\Traits\Controllers\JavascriptStatisticsInjection; +use Pterodactyl\Traits\Controllers\PlainJavascriptInjection; class StatisticsController extends Controller { - use JavascriptStatisticsInjection; + use PlainJavascriptInjection; private $allocationRepository; private $databaseRepository; - private $keyProviderService; - private $eggRepository; private $nodeRepository; @@ -35,7 +32,6 @@ class StatisticsController extends Controller function __construct( AllocationRepositoryInterface $allocationRepository, DatabaseRepositoryInterface $databaseRepository, - DaemonKeyProviderService $keyProviderService, EggRepositoryInterface $eggRepository, NodeRepositoryInterface $nodeRepository, ServerRepositoryInterface $serverRepository, @@ -44,28 +40,33 @@ class StatisticsController extends Controller { $this->allocationRepository = $allocationRepository; $this->databaseRepository = $databaseRepository; - $this->keyProviderService = $keyProviderService; $this->eggRepository = $eggRepository; $this->nodeRepository = $nodeRepository; $this->serverRepository = $serverRepository; $this->userRepository = $userRepository; } - public function index(Request $request) + public function index() { $servers = $this->serverRepository->all(); - $serversCount = count($servers); $nodes = $this->nodeRepository->all(); - $nodesCount = count($nodes); $usersCount = $this->userRepository->count(); $eggsCount = $this->eggRepository->count(); $databasesCount = $this->databaseRepository->count(); - $totalServerRam = DB::table('servers')->sum('memory'); - $totalNodeRam = DB::table('nodes')->sum('memory'); - $totalServerDisk = DB::table('servers')->sum('disk'); - $totalNodeDisk = DB::table('nodes')->sum('disk'); $totalAllocations = $this->allocationRepository->count(); - $suspendedServersCount = $this->serverRepository->getBuilder()->where('suspended', true)->count(); + $suspendedServersCount = $this->serverRepository->getSuspendedServersCount(); + + $totalServerRam = 0; + $totalNodeRam = 0; + $totalServerDisk = 0; + $totalNodeDisk = 0; + foreach ($nodes as $node) { + $stats = $this->nodeRepository->getUsageStatsRaw($node); + $totalServerRam += $stats['memory']['value']; + $totalNodeRam += $stats['memory']['max']; + $totalServerDisk += $stats['disk']['value']; + $totalNodeDisk += $stats['disk']['max']; + } $tokens = []; foreach ($nodes as $node) { @@ -74,7 +75,6 @@ class StatisticsController extends Controller $this->injectJavascript([ 'servers' => $servers, - 'serverCount' => $serversCount, 'suspendedServers' => $suspendedServersCount, 'totalServerRam' => $totalServerRam, 'totalNodeRam' => $totalNodeRam, @@ -83,10 +83,10 @@ class StatisticsController extends Controller 'nodes' => $nodes, 'tokens' => $tokens, ]); - + return view('admin.statistics', [ - 'serversCount' => $serversCount, - 'nodesCount' => $nodesCount, + 'servers' => $servers, + 'nodes' => $nodes, 'usersCount' => $usersCount, 'eggsCount' => $eggsCount, 'totalServerRam' => $totalServerRam, diff --git a/app/Repositories/Eloquent/NodeRepository.php b/app/Repositories/Eloquent/NodeRepository.php index b4d6ba6b..4f59fddc 100644 --- a/app/Repositories/Eloquent/NodeRepository.php +++ b/app/Repositories/Eloquent/NodeRepository.php @@ -56,6 +56,33 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa })->toArray(); } + /** + * Return the usage stats for a single node. + * + * @param \Pterodactyl\Models\Node $node + * @return array + */ + public function getUsageStatsRaw(Node $node): array + { + $stats = $this->getBuilder()->select( + $this->getBuilder()->raw('IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk') + )->join('servers', 'servers.node_id', '=', 'nodes.id')->where('node_id', $node->id)->first(); + + return collect(['disk' => $stats->sum_disk, 'memory' => $stats->sum_memory])->mapWithKeys(function ($value, $key) use ($node) { + $maxUsage = $node->{$key}; + if ($node->{$key . '_overallocate'} > 0) { + $maxUsage = $node->{$key} * (1 + ($node->{$key . '_overallocate'} / 100)); + } + + return [ + $key => [ + 'value' => $value, + 'max' => $maxUsage, + ], + ]; + })->toArray(); + } + /** * Return all available nodes with a searchable interface. * diff --git a/app/Repositories/Eloquent/ServerRepository.php b/app/Repositories/Eloquent/ServerRepository.php index 2fc5f878..c2c6e1e3 100644 --- a/app/Repositories/Eloquent/ServerRepository.php +++ b/app/Repositories/Eloquent/ServerRepository.php @@ -328,4 +328,14 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt $this->app->make(SubuserRepository::class)->getBuilder()->select('server_id')->where('user_id', $user) )->pluck('id')->all(); } + + /** + * Get the amount of servers that are suspended + * + * @return int + */ + public function getSuspendedServersCount(): int + { + return $this->getBuilder()->where('suspended', true)->count(); + } } diff --git a/app/Traits/Controllers/JavascriptStatisticsInjection.php b/app/Traits/Controllers/PlainJavascriptInjection.php similarity index 89% rename from app/Traits/Controllers/JavascriptStatisticsInjection.php rename to app/Traits/Controllers/PlainJavascriptInjection.php index 3b4e52d0..eae53bfb 100644 --- a/app/Traits/Controllers/JavascriptStatisticsInjection.php +++ b/app/Traits/Controllers/PlainJavascriptInjection.php @@ -10,7 +10,7 @@ namespace Pterodactyl\Traits\Controllers; use JavaScript; -trait JavascriptStatisticsInjection +trait PlainJavascriptInjection { /** diff --git a/public/themes/pterodactyl/js/admin/statistics.js b/public/themes/pterodactyl/js/admin/statistics.js index 59034a8d..7433f322 100644 --- a/public/themes/pterodactyl/js/admin/statistics.js +++ b/public/themes/pterodactyl/js/admin/statistics.js @@ -28,7 +28,7 @@ let ramChart = new Chart($('#ram_chart'), { } }); -var activeServers = Pterodactyl.serverCount - Pterodactyl.suspendedServers; +var activeServers = Pterodactyl.servers.length - Pterodactyl.suspendedServers; let serversChart = new Chart($('#servers_chart'), { type: 'pie', data: { diff --git a/resources/themes/pterodactyl/admin/statistics.blade.php b/resources/themes/pterodactyl/admin/statistics.blade.php index 036ad937..529107bb 100644 --- a/resources/themes/pterodactyl/admin/statistics.blade.php +++ b/resources/themes/pterodactyl/admin/statistics.blade.php @@ -35,7 +35,7 @@
    Servers - {{ $serversCount }} + {{ count($servers) }}
    @@ -118,7 +118,7 @@
    Total Nodes - {{ $nodesCount }} + {{ count($nodes) }}
    diff --git a/tests/Unit/Http/Controllers/Admin/StatisticsControllerTest.php b/tests/Unit/Http/Controllers/Admin/StatisticsControllerTest.php new file mode 100644 index 00000000..f3a20f8a --- /dev/null +++ b/tests/Unit/Http/Controllers/Admin/StatisticsControllerTest.php @@ -0,0 +1,113 @@ +allocationRepository = m::mock(AllocationRepositoryInterface::class); + $this->databaseRepository = m::mock(DatabaseRepositoryInterface::class); + $this->eggRepository = m::mock(EggRepositoryInterface::class); + $this->nodeRepository = m::mock(NodeRepositoryInterface::class); + $this->serverRepository = m::mock(ServerRepositoryInterface::class); + $this->userRepository = m::mock(UserRepositoryInterface::class); + } + + public function testIndexController() + { + $controller = $this->getController(); + + $this->serverRepository->shouldReceive('all')->withNoArgs(); + $this->nodeRepository->shouldReceive('all')->withNoArgs()->andReturn(collect([factory(Node::class)->make(), factory(Node::class)->make()])); + $this->userRepository->shouldReceive('count')->withNoArgs(); + $this->eggRepository->shouldReceive('count')->withNoArgs(); + $this->databaseRepository->shouldReceive('count')->withNoArgs(); + $this->allocationRepository->shouldReceive('count')->withNoArgs(); + $this->serverRepository->shouldReceive('getSuspendedServersCount')->withNoArgs(); + + $this->nodeRepository->shouldReceive('getUsageStatsRaw')->twice()->andReturn([ + 'memory' => [ + 'value' => 1024, + 'max' => 512, + ], + 'disk' => [ + 'value' => 1024, + 'max' => 512, + ] + ]); + + $controller->shouldReceive('injectJavascript')->once(); + + $response = $controller->index(); + + $this->assertIsViewResponse($response); + $this->assertViewNameEquals('admin.statistics', $response); + } + + private function getController() + { + return $this->buildMockedController(StatisticsController::class, [$this->allocationRepository, + $this->databaseRepository, + $this->eggRepository, + $this->nodeRepository, + $this->serverRepository, + $this->userRepository] + ); + } + +} \ No newline at end of file From 013dde75ae237422cddc8abbe9183b8274b6e44a Mon Sep 17 00:00:00 2001 From: stanjg Date: Thu, 31 May 2018 16:34:35 +0200 Subject: [PATCH 61/66] Renamed the field and made some improvements --- app/Http/Middleware/MaintenanceMiddleware.php | 2 +- app/Models/Node.php | 8 ++++---- .../2018_05_04_123826_add_maintenance_to_nodes.php | 4 ++-- resources/lang/en/strings.php | 1 + .../themes/pterodactyl/admin/nodes/index.blade.php | 2 +- .../pterodactyl/admin/nodes/view/index.blade.php | 2 +- .../pterodactyl/admin/nodes/view/settings.blade.php | 10 +++++----- resources/themes/pterodactyl/base/index.blade.php | 4 ++-- 8 files changed, 17 insertions(+), 16 deletions(-) diff --git a/app/Http/Middleware/MaintenanceMiddleware.php b/app/Http/Middleware/MaintenanceMiddleware.php index 39f26059..c67a3f05 100644 --- a/app/Http/Middleware/MaintenanceMiddleware.php +++ b/app/Http/Middleware/MaintenanceMiddleware.php @@ -35,7 +35,7 @@ class MaintenanceMiddleware $server = $request->attributes->get('server'); $node = $server->getRelation('node'); - if ($node->maintenance) { + if ($node->maintenance_mode) { return $this->response->view('errors.maintenance'); } diff --git a/app/Models/Node.php b/app/Models/Node.php index ea0258e8..2643d062 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -48,7 +48,7 @@ class Node extends Model implements CleansAttributes, ValidableContract 'daemonSFTP' => 'integer', 'behind_proxy' => 'boolean', 'public' => 'boolean', - 'maintenance' => 'boolean', + 'maintenance_mode' => 'boolean', ]; /** @@ -63,7 +63,7 @@ class Node extends Model implements CleansAttributes, ValidableContract 'disk_overallocate', 'upload_size', 'daemonSecret', 'daemonBase', 'daemonSFTP', 'daemonListen', - 'description', 'maintenance', + 'description', 'maintenance_mode', ]; /** @@ -112,7 +112,7 @@ class Node extends Model implements CleansAttributes, ValidableContract 'daemonBase' => 'regex:/^([\/][\d\w.\-\/]+)$/', 'daemonSFTP' => 'numeric|between:1024,65535', 'daemonListen' => 'numeric|between:1024,65535', - 'maintenance' => 'boolean', + 'maintenance_mode' => 'boolean', ]; /** @@ -128,7 +128,7 @@ class Node extends Model implements CleansAttributes, ValidableContract 'daemonBase' => '/srv/daemon-data', 'daemonSFTP' => 2022, 'daemonListen' => 8080, - 'maintenance' => false, + 'maintenance_mode' => false, ]; /** diff --git a/database/migrations/2018_05_04_123826_add_maintenance_to_nodes.php b/database/migrations/2018_05_04_123826_add_maintenance_to_nodes.php index 6c55912a..799f1df2 100644 --- a/database/migrations/2018_05_04_123826_add_maintenance_to_nodes.php +++ b/database/migrations/2018_05_04_123826_add_maintenance_to_nodes.php @@ -14,7 +14,7 @@ class AddMaintenanceToNodes extends Migration public function up() { Schema::table('nodes', function (Blueprint $table) { - $table->boolean('maintenance')->after('behind_proxy')->default(false); + $table->boolean('maintenance_mode')->after('behind_proxy')->default(false); }); } @@ -26,7 +26,7 @@ class AddMaintenanceToNodes extends Migration public function down() { Schema::table('nodes', function (Blueprint $table) { - $table->dropColumn('maintenance'); + $table->dropColumn('maintenance_mode'); }); } } diff --git a/resources/lang/en/strings.php b/resources/lang/en/strings.php index 5b917386..c0bf3f41 100644 --- a/resources/lang/en/strings.php +++ b/resources/lang/en/strings.php @@ -74,6 +74,7 @@ return [ 'tasks' => 'Tasks', 'seconds' => 'Seconds', 'minutes' => 'Minutes', + 'under_maintenance' => 'Under Maintenance', 'days' => [ 'sun' => 'Sunday', 'mon' => 'Monday', diff --git a/resources/themes/pterodactyl/admin/nodes/index.blade.php b/resources/themes/pterodactyl/admin/nodes/index.blade.php index abaf25e5..b4ea579a 100644 --- a/resources/themes/pterodactyl/admin/nodes/index.blade.php +++ b/resources/themes/pterodactyl/admin/nodes/index.blade.php @@ -56,7 +56,7 @@ @foreach ($nodes as $node) - {{ $node->name }} + {!! $node->maintenance_mode ? ' ' : '' !!}{{ $node->name }} {{ $node->location->short }} {{ $node->memory }} MB {{ $node->disk }} MB diff --git a/resources/themes/pterodactyl/admin/nodes/view/index.blade.php b/resources/themes/pterodactyl/admin/nodes/view/index.blade.php index 5ee0a88f..71eb346d 100644 --- a/resources/themes/pterodactyl/admin/nodes/view/index.blade.php +++ b/resources/themes/pterodactyl/admin/nodes/view/index.blade.php @@ -96,7 +96,7 @@
    - @if($node->maintenance) + @if($node->maintenance_mode)
    diff --git a/resources/themes/pterodactyl/admin/nodes/view/settings.blade.php b/resources/themes/pterodactyl/admin/nodes/view/settings.blade.php index 0e042fab..5afd65ed 100644 --- a/resources/themes/pterodactyl/admin/nodes/view/settings.blade.php +++ b/resources/themes/pterodactyl/admin/nodes/view/settings.blade.php @@ -109,15 +109,15 @@

    If you are running the daemon behind a proxy such as Cloudflare, select this to have the daemon skip looking for certificates on boot.

    - +
    - maintenance) == false) ? 'checked' : '' }}> - + maintenance_mode) == false) ? 'checked' : '' }}> +
    - maintenance) == true) ? 'checked' : '' }}> - + maintenance_mode) == true) ? 'checked' : '' }}> +

    If the node is marked as 'Under Maintenance' users won't be able to access servers that are on this node.

    diff --git a/resources/themes/pterodactyl/base/index.blade.php b/resources/themes/pterodactyl/base/index.blade.php index 09596298..28f4c4d5 100644 --- a/resources/themes/pterodactyl/base/index.blade.php +++ b/resources/themes/pterodactyl/base/index.blade.php @@ -64,9 +64,9 @@ @lang('strings.subuser') @endif - @if($server->node->maintenance) + @if($server->node->maintenance_mode) - Maintenance + @lang('strings.under_maintenance') @else From ccf3e3511f6344239dcc49ed7dbcb667c7f0461a Mon Sep 17 00:00:00 2001 From: stanjg Date: Thu, 31 May 2018 16:40:18 +0200 Subject: [PATCH 62/66] Renamed middleware, and fixed the test --- app/Http/Kernel.php | 2 +- app/Providers/RouteServiceProvider.php | 2 +- tests/Unit/Http/Middleware/MaintenanceMiddlewareTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 4221672e..d21c8d3c 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -109,7 +109,7 @@ class Kernel extends HttpKernel 'can' => Authorize::class, 'bindings' => SubstituteBindings::class, 'recaptcha' => VerifyReCaptcha::class, - 'maintenance' => MaintenanceMiddleware::class, + 'node.maintenance' => MaintenanceMiddleware::class, // Server specific middleware (used for authenticating access to resources) // diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 3604b3d7..f0e97811 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -33,7 +33,7 @@ class RouteServiceProvider extends ServiceProvider ->namespace($this->namespace . '\Auth') ->group(base_path('routes/auth.php')); - Route::middleware(['web', 'csrf', 'auth', 'server', 'subuser.auth', 'maintenance'])->prefix('/server/{server}') + Route::middleware(['web', 'csrf', 'auth', 'server', 'subuser.auth', 'node.maintenance'])->prefix('/server/{server}') ->namespace($this->namespace . '\Server') ->group(base_path('routes/server.php')); diff --git a/tests/Unit/Http/Middleware/MaintenanceMiddlewareTest.php b/tests/Unit/Http/Middleware/MaintenanceMiddlewareTest.php index 6b7380f3..fedeaa0c 100644 --- a/tests/Unit/Http/Middleware/MaintenanceMiddlewareTest.php +++ b/tests/Unit/Http/Middleware/MaintenanceMiddlewareTest.php @@ -46,7 +46,7 @@ class MaintenanceMiddlewareTest extends MiddlewareTestCase public function testHandleInMaintenanceMode() { $server = factory(Server::class)->make(); - $node = factory(Node::class)->make(['maintenance' => 1]); + $node = factory(Node::class)->make(['maintenance_mode' => 1]); $server->setRelation('node', $node); $this->setRequestAttribute('server', $server); From 6e6ce652b24d23a0050e500e326a1141a78e761e Mon Sep 17 00:00:00 2001 From: Matthew Penner Date: Thu, 31 May 2018 21:35:24 -0600 Subject: [PATCH 63/66] Fix logo-mini image (#1183) --- resources/themes/pterodactyl/layouts/master.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index c46db68b..644cb5bc 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -44,7 +44,7 @@