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")}}
+
+
+
+
+ | # |
+ Name |
+ Usage-% |
+ Total Servers |
+ Active Servers |
+ Active Earnings |
+
+
+
+
+ @foreach($nodeCounters as $node)
+
+
+ | {{$node->id}} |
+ {{$node->name}} |
+ {{$node->usagePercent}} |
+ {{$node->totalServers}} |
+ {{$node->activeServers}} |
+ {{$node->activeEarnings}} |
+
+ @endforeach
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@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);