From 130a3b308b80fb06548ac2c65464e3a4ff0248b6 Mon Sep 17 00:00:00 2001 From: AGuyNamedJens Date: Wed, 22 May 2024 14:26:18 +0200 Subject: [PATCH] [Feature] Addon implemented --- app/Http/Controllers/ProductController.php | 31 +++++++--- app/Http/Controllers/ServerController.php | 59 +++++++++++++----- lang/en.json | 2 +- routes/web.php | 2 +- themes/default/views/servers/create.blade.php | 61 ++++++++----------- 5 files changed, 95 insertions(+), 60 deletions(-) diff --git a/app/Http/Controllers/ProductController.php b/app/Http/Controllers/ProductController.php index 5f3d94dc..ae9c1548 100644 --- a/app/Http/Controllers/ProductController.php +++ b/app/Http/Controllers/ProductController.php @@ -14,7 +14,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Collection; class ProductController extends Controller -{ +{ private $pterodactyl; public function __construct(PterodactylSettings $ptero_settings) @@ -97,30 +97,41 @@ class ProductController extends Controller } /** - * @param Node $node + * @param Int $location * @param Egg $egg * @return Collection|JsonResponse */ - public function getProductsBasedOnNode(Egg $egg, Node $node) + public function getProductsBasedOnLocation(Egg $egg, Int $location) { - if (is_null($egg->id) || is_null($node->id)) { - return response()->json('node and egg id is required', '400'); + if (is_null($egg->id) || is_null($location)) { + return response()->json('location and egg id is required', '400'); } + // Get all nodes in this location + $nodes = Node::query() + ->where('location_id', '=', $location) + ->get(); + $products = Product::query() ->where('disabled', '=', false) - ->whereHas('nodes', function (Builder $builder) use ($node) { - $builder->where('id', '=', $node->id); + ->whereHas('nodes', function (Builder $builder) use ($nodes) { + $builder->whereIn('id', $nodes->map(function ($node) { + return $node->id; + })); }) ->whereHas('eggs', function (Builder $builder) use ($egg) { $builder->where('id', '=', $egg->id); }) ->get(); - $pteroNode = $this->pterodactyl->getNode($node->id); + // Instead of the old node check, we will check if the product fits in any given node in the location foreach ($products as $key => $product) { - if ($product->memory > ($pteroNode['memory'] * ($pteroNode['memory_overallocate'] + 100) / 100) - $pteroNode['allocated_resources']['memory'] || $product->disk > ($pteroNode['disk'] * ($pteroNode['disk_overallocate'] + 100) / 100) - $pteroNode['allocated_resources']['disk']) { - $product->doesNotFit = true; + $product->doesNotFit = false; + foreach ($nodes as $node) { + $pteroNode = $this->pterodactyl->getNode($node->id); + if ($product->memory > ($pteroNode['memory'] * ($pteroNode['memory_overallocate'] + 100) / 100) - $pteroNode['allocated_resources']['memory'] || $product->disk > ($pteroNode['disk'] * ($pteroNode['disk_overallocate'] + 100) / 100) - $pteroNode['allocated_resources']['disk']) { + $product->doesNotFit = true; + } } } diff --git a/app/Http/Controllers/ServerController.php b/app/Http/Controllers/ServerController.php index 0c18a508..a6cd1b9a 100644 --- a/app/Http/Controllers/ServerController.php +++ b/app/Http/Controllers/ServerController.php @@ -141,13 +141,10 @@ class ServerController extends Controller $product = Product::findOrFail(FacadesRequest::input('product')); // Get node resource allocation info - $node = $product->nodes()->findOrFail(FacadesRequest::input('node')); - $nodeName = $node->name; - - // Check if node has enough memory and disk space - $checkResponse = $this->pterodactyl->checkNodeResources($node, $product->memory, $product->disk); - if ($checkResponse == false) { - return redirect()->route('servers.index')->with('error', __("The node '" . $nodeName . "' doesn't have the required memory or disk left to allocate this product.")); + $location = FacadesRequest::input('location'); + $availableNode = $this->getAvailableNode($location, $product); + if (!$availableNode) { + return redirect()->route('servers.index')->with('error', __("The chosen location doesn't have the required memory or disk left to allocate this product.")); } // Min. Credits @@ -179,7 +176,7 @@ class ServerController extends Controller /** Store a newly created resource in storage. */ public function store(Request $request, UserSettings $user_settings, ServerSettings $server_settings, GeneralSettings $generalSettings) { - /** @var Node $node */ + /** @var Location $location */ /** @var Egg $egg */ /** @var Product $product */ $validate_configuration = $this->validateConfigurationRules($user_settings, $server_settings, $generalSettings); @@ -190,15 +187,23 @@ class ServerController extends Controller $request->validate([ 'name' => 'required|max:191', - 'node' => 'required|exists:nodes,id', + 'location' => 'required|exists:locations,id', 'egg' => 'required|exists:eggs,id', 'product' => 'required|exists:products,id', ]); - //get required resources + // Get the product and egg $product = Product::query()->findOrFail($request->input('product')); $egg = $product->eggs()->findOrFail($request->input('egg')); - $node = $product->nodes()->findOrFail($request->input('node')); + + // Get an available node + $location = $request->input('location'); + $availableNode = $this->getAvailableNode($location, $product); + $node = Node::query()->find($availableNode); + + if(!$node) { + return redirect()->route('servers.index')->with('error', __("No nodes satisfying the requirements for automatic deployment on this location were found.")); + } $server = $request->user()->servers()->create([ 'name' => $request->input('name'), @@ -316,7 +321,7 @@ class ServerController extends Controller }) ->get(); - // Set the each product eggs array to just contain the eggs name + // Set each product eggs array to just contain the eggs name foreach ($products as $product) { $product->eggs = $product->eggs->pluck('name')->toArray(); if ($product->memory - $currentProduct->memory > ($pteroNode['memory'] * ($pteroNode['memory_overallocate'] + 100) / 100) - $pteroNode['allocated_resources']['memory'] || $product->disk - $currentProduct->disk > ($pteroNode['disk'] * ($pteroNode['disk_overallocate'] + 100) / 100) - $pteroNode['allocated_resources']['disk']) { @@ -356,8 +361,8 @@ class ServerController extends Controller // Check if node has enough memory and disk space $requireMemory = $newProduct->memory - $oldProduct->memory; $requiredisk = $newProduct->disk - $oldProduct->disk; - $checkResponse = $this->pterodactyl->checkNodeResources($node, $requireMemory, $requiredisk); - if ($checkResponse == false) { + $nodeFree = $this->pterodactyl->checkNodeResources($node, $requireMemory, $requiredisk); + if (!$nodeFree) { return redirect()->route('servers.index')->with('error', __("The node '" . $nodeName . "' doesn't have the required memory or disk left to upgrade the server.")); } @@ -412,4 +417,30 @@ class ServerController extends Controller return redirect()->route('servers.show', ['server' => $server->id])->with('error', __('Not Enough Balance for Upgrade')); } } + + /** + * @param string $location + * @param Product $product + * @return int | null Node ID + */ + private function getAvailableNode(string $location, Product $product) + { + $collection = Node::query()->where('location_id', $location)->get(); + + // loop through nodes and check if the node has enough resources + foreach ($collection as $node) { + // Check if the node has enough memory and disk space + $freeNode = $this->pterodactyl->checkNodeResources($node, $product->memory, $product->disk); + // Remove the node from the collection if it doesn't have enough resources + if (!$freeNode) { + $collection->forget($node['id']); + } + } + + if($collection->isEmpty()) { + return null; + } + + return $collection->first()['id']; + } } diff --git a/lang/en.json b/lang/en.json index 633a4ec2..91da6df3 100644 --- a/lang/en.json +++ b/lang/en.json @@ -71,7 +71,7 @@ "Change Status": "Change Status", "Profile updated": "Profile updated", "Server limit reached!": "Server limit reached!", - "The node '\" . $nodeName . \"' doesn't have the required memory or disk left to allocate this product.": "The node '\" . $nodeName . \"' doesn't have the required memory or disk left to allocate this product.", + "The chosen location doesn't have the required memory or disk left to allocate this product.": "The chosen location doesn't have the required memory or disk left to allocate this product.", "You are required to verify your email address before you can create a server.": "You are required to verify your email address before you can create a server.", "You are required to link your discord account before you can create a server.": "You are required to link your discord account before you can create a server.", "Server created": "Server created", diff --git a/routes/web.php b/routes/web.php index c575ea98..444d9485 100644 --- a/routes/web.php +++ b/routes/web.php @@ -95,7 +95,7 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () { //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/locations/egg/{egg?}', [FrontProductController::class, 'getLocationsBasedOnEgg'])->name('products.locations.egg'); - Route::get('/products/products/{egg?}/{node?}', [FrontProductController::class, 'getProductsBasedOnNode'])->name('products.products.node'); + Route::get('/products/products/{egg?}/{location?}', [FrontProductController::class, 'getProductsBasedOnLocation'])->name('products.products.location'); //payments Route::get('checkout/{shopProduct}', [PaymentController::class, 'checkOut'])->name('checkout'); diff --git a/themes/default/views/servers/create.blade.php b/themes/default/views/servers/create.blade.php index 588da5a4..4dfadea5 100644 --- a/themes/default/views/servers/create.blade.php +++ b/themes/default/views/servers/create.blade.php @@ -133,32 +133,25 @@ -
- - + + + -
+
-
+