diff --git a/app/Classes/Pterodactyl/PterodactylClient.php b/app/Classes/Pterodactyl/PterodactylClient.php index 1bb6dc5..dfa39ab 100755 --- a/app/Classes/Pterodactyl/PterodactylClient.php +++ b/app/Classes/Pterodactyl/PterodactylClient.php @@ -71,6 +71,16 @@ public function getNests(): PromiseInterface|Response return $this->handleResponse($response); } + /** + * @return mixed + * @throws Exception + * @description Returns the infos of a single node + */ + public function getNode($id) { + $response = $this->client->get('application/nodes/' . $id); + return $this->handleResponse($response); + } + /** * @throws PterodactylRequestException */ @@ -178,6 +188,18 @@ public function updateServerDetails(int $pterodactyl_id, array $data): PromiseIn return $this->handleResponse($response); } + /** + * Get Servers from Pterodactyl + * + * @return PromiseInterface|Response + * @throws PterodactylRequestException + */ + public function getServers(): PromiseInterface|Response + { + $response = $this->client->get('application/servers?per_page=' . self::PER_PAGE); + return $this->handleResponse($response); + } + /** * Delete server * diff --git a/app/Http/Controllers/Admin/OverviewController.php b/app/Http/Controllers/Admin/OverviewController.php new file mode 100644 index 0000000..b9060c8 --- /dev/null +++ b/app/Http/Controllers/Admin/OverviewController.php @@ -0,0 +1,130 @@ +latest('updated_at')->first(); + $syncLastUpdate = $lastEgg ? $lastEgg->updated_at->isoFormat('LLL') : __('unknown'); + + //Generate the Counters used on the Overview + $counters = $this->constructNodeInfo()["counters"]; + $nodes = $this->constructNodeInfo()["nodes"]; + + return view('admin.overview.index', [ + 'counters' => $counters, + 'nodeCounters' => $nodes, + 'lastPteroSync' => $syncLastUpdate, + 'settings' => $settings + ]); + + + } + + + /** + * @return \Illuminate\Support\Collection + */ + private function constructCounters() + { + + $userCount = User::query()->count(); + $creditCount = User::query()->sum('credits'); + $creditCount = number_format($creditCount, 2, '.', ''); + //Get counters + $counters = collect(); + //Set basic variables in the collection + $counters->put('users', $userCount); + $counters->put('credits', $creditCount); + // $counters->put('payments', Payment::all()->count()); + $counters->put('eggs', Egg::all()->count()); + $counters->put('nests', Nest::all()->count()); + $counters->put('locations', Location::all()->count()); + + //Prepare for counting + $counters->put('servers', collect()); + $counters['servers']->active = 0; + $counters['servers']->total = 0; + $counters->put('earnings', collect()); + $counters['earnings']->active = 0; + $counters['earnings']->total = 0; + $counters->put('totalUsagePercent', 0); + + return $counters; + } + + + /** + * @return array + */ + private function constructNodeInfo() + { + $pterosettings = new PterodactylSettings(); + $pterodactylClient = new PterodactylClient($pterosettings); + $counters = $this->constructCounters(); + + //Get node information + $nodes = collect(); + foreach ($DBnodes = Node::all() as $DBnode) { //gets all node information and prepares the structure + $nodeId = $DBnode['id']; + $nodes->put($nodeId, collect()); + $nodes[$nodeId]->id = $nodeId; + $nodes[$nodeId]->name = $DBnode['name']; + $pteroNode = $pterodactylClient->getNode($nodeId)->json()["attributes"]; + $nodes[$nodeId]->usagePercent = round(max($pteroNode['allocated_resources']['memory'] / ($pteroNode['memory'] * ($pteroNode['memory_overallocate'] + 100) / 100), $pteroNode['allocated_resources']['disk'] / ($pteroNode['disk'] * ($pteroNode['disk_overallocate'] + 100) / 100)) * 100, 2); + $counters['totalUsagePercent'] += $nodes[$nodeId]->usagePercent; + + $nodes[$nodeId]->totalServers = 0; + $nodes[$nodeId]->activeServers = 0; + $nodes[$nodeId]->totalEarnings = 0; + $nodes[$nodeId]->activeEarnings = 0; + } + $counters['totalUsagePercent'] = ($DBnodes->count()) ? round($counters['totalUsagePercent'] / $DBnodes->count(), 2) : 0; + + $response = ($pterodactylClient->getServers()->json()); + foreach ($response["data"] as $server) { //gets all servers from Pterodactyl and calculates total of credit usage for each node separately + total + + $serverId = $server['attributes']['id']; + $nodeId = $server['attributes']['node']; + + $CPServer = Server::query()->where('pterodactyl_id', $serverId)->first(); + + if ($CPServer) { + $price = Server::query()->where('id', $CPServer->product_id)->first()->price; + if (!$CPServer->suspended) { + $counters['earnings']->active += $price; + $counters['servers']->active++; + $nodes[$nodeId]->activeEarnings += $price; + $nodes[$nodeId]->activeServers++; + } + $counters['earnings']->total += $price; + $counters['servers']->total++; + $nodes[$nodeId]->totalEarnings += $price; + $nodes[$nodeId]->totalServers++; + } + } + return [ + 'counters' => $counters, + 'nodes' => $nodes + ]; + } + + +} diff --git a/resources/views/admin/overview/index.blade.php b/resources/views/admin/overview/index.blade.php new file mode 100644 index 0000000..68b990e --- /dev/null +++ b/resources/views/admin/overview/index.blade.php @@ -0,0 +1,156 @@ +@extends('layouts.dashboard') + +@section('content') +
+ +
+ +
+
+
+
+
+ Total servers + {{$counters['servers']->total}} +
+
+
+ +
+
+
+
+
+
+ + + +
+
+
+
+
+ {{__("Total users")}} + {{$counters['users']}} +
+
+
+ +
+
+
+
+
+
+ + + +
+
+
+
+
+ {{__('Total :credits ', ['credits' => $settings->credits_display_name])}} + + {{$counters['credits']}} +
+
+
+ +
+
+
+
+
+
+ + + +
+
+
+
+
+ {{__('Total :credits earnings', ['credits' => $settings->credits_display_name])}} + + {{$counters['earnings']->active}} +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+
+
+ {{__('Last Sync from Pterodactyl')}} + + {{$lastPteroSync}} +
+
+
+ +
+
+
+
+
+
+ + + +
+
+
+ {{__("Nodes Info")}} +
+ + + + + + + + + + + + + + @foreach($nodeCounters as $node) + + + + + + + + + + @endforeach + + + +
#NameUsage-%Total ServersActive ServersActive Earnings
{{$node->id}}{{$node->name}}{{$node->usagePercent}}{{$node->totalServers}}{{$node->activeServers}}{{$node->activeEarnings}}
+
+
+
+
+ +
+ + + +
+@endsection + + diff --git a/resources/views/layouts/parts/navigation/sidebar/350-overview.blade.php b/resources/views/layouts/parts/navigation/sidebar/350-overview.blade.php new file mode 100644 index 0000000..4ba495c --- /dev/null +++ b/resources/views/layouts/parts/navigation/sidebar/350-overview.blade.php @@ -0,0 +1,10 @@ +@can('admin.overview.read') + +@endcan diff --git a/routes/web.php b/routes/web.php index 0fb9a64..b77345d 100755 --- a/routes/web.php +++ b/routes/web.php @@ -2,6 +2,7 @@ use App\Http\Controllers\Admin\ConfigurationController; use App\Http\Controllers\Admin\NotificationTemplateController; +use App\Http\Controllers\Admin\OverviewController; use App\Http\Controllers\Admin\RoleController; use App\Http\Controllers\Admin\ServerController as AdminServerController; use App\Http\Controllers\Admin\UserController; @@ -55,6 +56,7 @@ Route::resource('roles', RoleController::class); Route::resource('users', UserController::class); Route::resource('servers', AdminServerController::class); + Route::get('overview', [OverviewController::class, 'index'])->name('overview.index'); Route::get('/configurations/sync', [ConfigurationController::class, 'syncPterodactyl'])->name('configurations.sync'); Route::get('/configurations/{configuration}/clone', [ConfigurationController::class, 'clone'])->name('configurations.clone'); Route::resource('configurations', ConfigurationController::class);