From 8c7c938c6a526bcede58e264dd41d8b7529fc294 Mon Sep 17 00:00:00 2001 From: AVMG20 Date: Sun, 7 Nov 2021 12:07:30 +0100 Subject: [PATCH] fine tuning :) --- app/Classes/Pterodactyl.php | 1 - .../Controllers/Admin/OverViewController.php | 25 +++++ app/Http/Controllers/ServerController.php | 30 ++++-- app/Models/Egg.php | 95 ++++++++++++------- app/Models/Location.php | 54 +++++++++-- app/Models/Nest.php | 53 ++++++++++- app/Models/Node.php | 82 +++++++++++----- .../views/admin/overview/index.blade.php | 40 ++++---- resources/views/layouts/main.blade.php | 29 ++++-- resources/views/servers/create.blade.php | 36 +++++-- routes/web.php | 9 +- 11 files changed, 342 insertions(+), 112 deletions(-) diff --git a/app/Classes/Pterodactyl.php b/app/Classes/Pterodactyl.php index dd86f914..c245651b 100644 --- a/app/Classes/Pterodactyl.php +++ b/app/Classes/Pterodactyl.php @@ -67,7 +67,6 @@ class Pterodactyl { $response = self::client()->get('/application/nodes'); if ($response->failed()) throw self::getException(); - dd($response->json()); return $response->json()['data']; } diff --git a/app/Http/Controllers/Admin/OverViewController.php b/app/Http/Controllers/Admin/OverViewController.php index 34a774bc..5745e513 100644 --- a/app/Http/Controllers/Admin/OverViewController.php +++ b/app/Http/Controllers/Admin/OverViewController.php @@ -3,6 +3,10 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; +use App\Models\Egg; +use App\Models\Location; +use App\Models\Nest; +use App\Models\Node; use App\Models\Payment; use App\Models\Server; use App\Models\User; @@ -30,11 +34,32 @@ class OverViewController extends Controller return Server::query()->count(); }); + $lastEgg = Egg::query()->latest('updated_at')->first(); + $syncLastUpdate = $lastEgg ? $lastEgg->updated_at->isoFormat('LLL') : __('unknown'); + return view('admin.overview.index', [ 'serverCount' => $serverCount, 'userCount' => $userCount, 'paymentCount' => $paymentCount, 'creditCount' => number_format($creditCount, 2, '.', ''), + + 'locationCount' => Location::query()->count(), + 'nodeCount' => Node::query()->count(), + 'nestCount' => Nest::query()->count(), + 'eggCount' => Egg::query()->count(), + 'syncLastUpdate' => $syncLastUpdate ]); } + + + /** + * @description Sync locations,nodes,nests,eggs with the linked pterodactyl panel + */ + public function syncPterodactyl() + { + Node::syncNodes(); + Egg::syncEggs(); + + return redirect()->back()->with('success', __('Pterodactyl synced')); + } } diff --git a/app/Http/Controllers/ServerController.php b/app/Http/Controllers/ServerController.php index 209f982c..0e319f7c 100644 --- a/app/Http/Controllers/ServerController.php +++ b/app/Http/Controllers/ServerController.php @@ -11,6 +11,7 @@ use App\Models\Product; use App\Models\Server; use App\Notifications\ServerCreationError; use Exception; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\Client\Response; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; @@ -32,12 +33,22 @@ class ServerController extends Controller { if (!is_null($this->validateConfigurationRules())) return $this->validateConfigurationRules(); + $productCount = Product::query()->where('disabled', '=', false)->count(); + + $nodeCount = Node::query()->has('products')->count(); + + $eggs = Egg::query()->has('products')->get(); + + $nests = Nest::query()->whereHas('eggs', function (Builder $builder) { + $builder->has('products'); + })->get(); + return view('servers.create')->with([ - 'productCount' => Product::query()->where('disabled', '=', false)->count(), - 'nodeCount' => Node::query()->where('disabled', '=', false)->count(), - 'nests' => Nest::query()->where('disabled', '=', false)->get(), - 'eggs' => Egg::query()->where('disabled', '=', false)->get(), - 'minimum_credits' => Configuration::getValueByKey('MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER', 50) + 'productCount' => $productCount, + 'nodeCount' => $nodeCount, + 'nests' => $nests, + 'eggs' => $eggs, + 'user' => Auth::user(), ]); } @@ -80,6 +91,10 @@ class ServerController extends Controller /** Store a newly created resource in storage. */ public function store(Request $request) { + /** @var Node $node */ + /** @var Egg $egg */ + /** @var Product $product */ + if (!is_null($this->validateConfigurationRules())) return $this->validateConfigurationRules(); $request->validate([ @@ -90,8 +105,9 @@ class ServerController extends Controller ]); //get required resources - $egg = Egg::findOrFail($request->input('egg')); - $node = Node::findOrFail($request->input('node')); + $product = Product::query()->findOrFail($request->input('product')); + $egg = $product->eggs()->findOrFail($request->input('egg')); + $node = $product->nodes()->findOrFail($request->input('node')); $server = $request->user()->servers()->create([ 'name' => $request->input('name'), diff --git a/app/Models/Egg.php b/app/Models/Egg.php index 49589378..435b8cb0 100644 --- a/app/Models/Egg.php +++ b/app/Models/Egg.php @@ -7,7 +7,6 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Database\Eloquent\Relations\HasManyThrough; class Egg extends Model { @@ -23,8 +22,70 @@ class Egg extends Model 'docker_image', 'startup', 'environment', + 'updated_at', ]; + public static function boot() + { + parent::boot(); // TODO: Change the autogenerated stub + + static::deleting(function (Egg $egg) { + $egg->products()->detach(); + }); + } + + public static function syncEggs() + { + Nest::syncNests(); + + Nest::all()->each(function (Nest $nest) { + $eggs = Pterodactyl::getEggs($nest); + + foreach ($eggs as $egg) { + $array = []; + $environment = []; + + $array['id'] = $egg['attributes']['id']; + $array['nest_id'] = $egg['attributes']['nest']; + $array['name'] = $egg['attributes']['name']; + $array['description'] = $egg['attributes']['description']; + $array['docker_image'] = $egg['attributes']['docker_image']; + $array['startup'] = $egg['attributes']['startup']; + $array['updated_at'] = now(); + + //get environment variables + foreach ($egg['attributes']['relationships']['variables']['data'] as $variable) { + $environment[$variable['attributes']['env_variable']] = $variable['attributes']['default_value']; + } + + $array['environment'] = json_encode([$environment]); + + self::query()->updateOrCreate([ + 'id' => $array['id'] + ], array_diff_key($array, array_flip(["id"])) + ); + } + + self::removeDeletedEggs($nest, $eggs); + }); + } + + /** + * @description remove eggs that have been deleted on pterodactyl + * @param Nest $nest + * @param array $eggs + */ + private static function removeDeletedEggs(Nest $nest, array $eggs): void + { + $ids = array_map(function ($data) { + return $data['attributes']['id']; + }, $eggs); + + $nest->eggs()->each(function (Egg $egg) use ($ids) { + if (!in_array($egg->id, $ids)) $egg->delete(); + }); + } + /** * @return array */ @@ -41,42 +102,12 @@ class Egg extends Model return $array; } - public static function syncEggs() - { - - Nest::all()->each(function (Nest $nest) { - $eggs = Pterodactyl::getEggs($nest); - - foreach ($eggs as $egg) { - $array = []; - $environment = []; - - $array['id'] = $egg['attributes']['id']; - $array['nest_id'] = $egg['attributes']['nest']; - $array['name'] = $egg['attributes']['name']; - $array['description'] = $egg['attributes']['description']; - $array['docker_image'] = $egg['attributes']['docker_image']; - $array['startup'] = $egg['attributes']['startup']; - - //get environment variables - foreach ($egg['attributes']['relationships']['variables']['data'] as $variable) { - $environment[$variable['attributes']['env_variable']] = $variable['attributes']['default_value']; - } - - $array['environment'] = json_encode([$environment]); - - self::firstOrCreate(['id' => $array['id']], $array); - } - - }); - } - /** * @return BelongsTo */ public function nest() { - return $this->belongsTo(Nest::class, 'id', 'nest_id'); + return $this->belongsTo(Nest::class); } /** diff --git a/app/Models/Location.php b/app/Models/Location.php index f3f4f79e..9066a4d4 100644 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -15,28 +15,68 @@ class Location extends Model public $guarded = []; - public function nodes(){ - return $this->hasMany(Node::class , 'location_id' , 'id'); + public static function boot() + { + parent::boot(); // TODO: Change the autogenerated stub + + static::deleting(function (Location $location) { + $location->nodes()->each(function (Node $node) { + $node->delete(); + }); + }); } /** * Sync locations with pterodactyl panel * @throws Exception */ - public static function syncLocations(){ + public static function syncLocations() + { $locations = Pterodactyl::getLocations(); - $locations = array_map(function($val) { + //map response + $locations = array_map(function ($val) { return array( - 'id' => $val['attributes']['id'], - 'name' => $val['attributes']['short'], + 'id' => $val['attributes']['id'], + 'name' => $val['attributes']['short'], 'description' => $val['attributes']['long'] ); }, $locations); + //update or create foreach ($locations as $location) { - self::firstOrCreate(['id' => $location['id']] , $location); + self::query()->updateOrCreate( + [ + 'id' => $location['id'] + ], + [ + 'name' => $location['name'], + 'description' => $location['name'], + ] + ); } + + self::removeDeletedLocation($locations); + } + + /** + * @description remove locations that have been deleted on pterodactyl + * @param array $locations + */ + private static function removeDeletedLocation(array $locations): void + { + $ids = array_map(function ($data) { + return $data['id']; + }, $locations); + + self::all()->each(function (Location $location) use ($ids) { + if (!in_array($location->id, $ids)) $location->delete(); + }); + } + + public function nodes() + { + return $this->hasMany(Node::class, 'location_id', 'id'); } } diff --git a/app/Models/Nest.php b/app/Models/Nest.php index 0906b002..fdc36a94 100644 --- a/app/Models/Nest.php +++ b/app/Models/Nest.php @@ -19,17 +19,60 @@ class Nest extends Model 'disabled', ]; + public static function boot() + { + parent::boot(); // TODO: Change the autogenerated stub - public function eggs(){ - return $this->hasMany(Egg::class); + static::deleting(function (Nest $nest) { + $nest->eggs()->each(function (Egg $egg) { + $egg->delete(); + }); + }); } - public static function syncNests(){ - self::query()->delete(); + public static function syncNests() + { $nests = Pterodactyl::getNests(); + //map response + $nests = array_map(function ($nest) { + return array( + 'id' => $nest['attributes']['id'], + 'name' => $nest['attributes']['name'], + 'description' => $nest['attributes']['description'], + ); + }, $nests); + foreach ($nests as $nest) { - self::firstOrCreate(['id' => $nest['attributes']['id']] , array_merge($nest['attributes'] , ['disabled' => '1'])); + self::query()->updateOrCreate([ + 'id' => $nest['id'] + ], [ + 'name' => $nest['name'], + 'description' => $nest['description'], + 'disabled' => false + ]); } + + self::removeDeletedNests($nests); + } + + /** + * @description remove nests that have been deleted on pterodactyl + * @param array $nests + */ + private static function removeDeletedNests(array $nests): void + { + $ids = array_map(function ($data) { + return $data['id']; + }, $nests); + + self::all()->each(function (Nest $nest) use ($ids) { + if (!in_array($nest->id, $ids)) $nest->delete(); + }); + } + + public function eggs() + { + return $this->hasMany(Egg::class); } } diff --git a/app/Models/Node.php b/app/Models/Node.php index 680ba44a..c0d1ab3e 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -17,6 +17,65 @@ class Node extends Model public $guarded = []; + public static function boot() + { + parent::boot(); // TODO: Change the autogenerated stub + + static::deleting(function (Node $node) { + $node->products()->detach(); + }); + } + + + /** + * @throws Exception + */ + public static function syncNodes() + { + Location::syncLocations(); + $nodes = Pterodactyl::getNodes(); + + //map response + $nodes = array_map(function ($node) { + return array( + 'id' => $node['attributes']['id'], + 'location_id' => $node['attributes']['location_id'], + 'name' => $node['attributes']['name'], + 'description' => $node['attributes']['description'], + ); + }, $nodes); + + //update or create + foreach ($nodes as $node) { + self::query()->updateOrCreate( + [ + 'id' => $node['id'] + ], + [ + 'name' => $node['name'], + 'description' => $node['description'], + 'location_id' => $node['location_id'], + 'disabled' => false + ]); + } + + self::removeDeletedNodes($nodes); + } + + /** + * @description remove nodes that have been deleted on pterodactyl + * @param array $nodes + */ + private static function removeDeletedNodes(array $nodes): void + { + $ids = array_map(function ($data) { + return $data['id']; + }, $nodes); + + self::all()->each(function (Node $node) use ($ids) { + if (!in_array($node->id, $ids)) $node->delete(); + }); + } /** * @return BelongsTo @@ -26,29 +85,6 @@ class Node extends Model return $this->belongsTo(Location::class); } - /** - * @throws Exception - */ - public static function syncNodes(){ - Location::syncLocations(); - $nodes = Pterodactyl::getNodes(); - - $nodes = array_map(function($node) { - return array( - 'id' => $node['attributes']['id'], - 'location_id' => $node['attributes']['location_id'], - 'name' => $node['attributes']['name'], - 'description' => $node['attributes']['description'], - 'disabled' => '1' - ); - }, $nodes); - - foreach ($nodes as $node) { - self::firstOrCreate(['id' => $node['id']] , $node); - } - - } - /** * @return BelongsToMany */ diff --git a/resources/views/admin/overview/index.blade.php b/resources/views/admin/overview/index.blade.php index ef4a355b..0c491a55 100644 --- a/resources/views/admin/overview/index.blade.php +++ b/resources/views/admin/overview/index.blade.php @@ -26,16 +26,20 @@
@@ -68,7 +72,8 @@
- +
{{__('Total')}} {{CREDITS_DISPLAY_NAME}} @@ -101,39 +106,40 @@
{{__('Pterodactyl')}}
- + {{__('Sync')}}
- - - - - - + + + + + + - + - + - + - +
{{__('Resources')}}{{__('Count')}}
{{__('Resources')}}{{__('Count')}}
{{__('Locations')}}1{{$locationCount}}
{{__('Nodes')}}1{{$nodeCount}}
{{__('Nests')}}1{{$nestCount}}
{{__('Eggs')}}1{{$eggCount}}
diff --git a/resources/views/layouts/main.blade.php b/resources/views/layouts/main.blade.php index d0c756ee..266fc9db 100644 --- a/resources/views/layouts/main.blade.php +++ b/resources/views/layouts/main.blade.php @@ -78,11 +78,33 @@ + + - @@ -258,6 +265,7 @@ selectedProductObject: {}, //values + user: {!! $user !!}, nests: {!! $nests !!}, eggsSave:{!! $eggs !!}, //store back-end eggs eggs: [], @@ -374,6 +382,16 @@ return '{{__('Please select a configuration...')}}'; } return '{{__('---')}}'; + }, + + getProductOptionText(product){ + let text = product.name + ' (' + product.description + ')'; + + if (product.minimum_credits > this.user.credits){ + return '{{__('Not enough credits!')}} | ' + text; + } + + return text; } } } diff --git a/routes/web.php b/routes/web.php index 799d9e34..43a415a9 100644 --- a/routes/web.php +++ b/routes/web.php @@ -3,8 +3,6 @@ use App\Http\Controllers\Admin\ActivityLogController; use App\Http\Controllers\Admin\ApplicationApiController; use App\Http\Controllers\Admin\ConfigurationController; -use App\Http\Controllers\Admin\NestsController; -use App\Http\Controllers\Admin\NodeController; use App\Http\Controllers\Admin\OverViewController; use App\Http\Controllers\Admin\PaymentController; use App\Http\Controllers\Admin\PaypalProductController; @@ -58,8 +56,8 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () { #server create utility routes (product) #routes made for server create page to fetch product info - Route::get('/products/nodes/egg/{egg?}' , [FrontProductController::class , 'getNodesBasedOnEgg'])->name('products.nodes.egg'); - Route::get('/products/products/node/{node?}' , [FrontProductController::class , 'getProductsBasedOnNode'])->name('products.products.node'); + Route::get('/products/nodes/egg/{egg?}', [FrontProductController::class, 'getNodesBasedOnEgg'])->name('products.nodes.egg'); + Route::get('/products/products/node/{node?}', [FrontProductController::class, 'getProductsBasedOnNode'])->name('products.products.node'); #payments Route::get('checkout/{paypalProduct}', [PaymentController::class, 'checkOut'])->name('checkout'); @@ -79,7 +77,8 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () { #admin Route::prefix('admin')->name('admin.')->middleware('admin')->group(function () { - Route::get('overview', [OverViewController::class , 'index'])->name('overview.index'); + Route::get('overview', [OverViewController::class, 'index'])->name('overview.index'); + Route::get('overview/sync', [OverViewController::class, 'syncPterodactyl'])->name('overview.sync'); Route::resource('activitylogs', ActivityLogController::class);