Browse Source

Merge remote-tracking branch 'origin/product_links' into development

AVMG20 3 years ago
parent
commit
75622d3958

+ 41 - 3
app/Http/Controllers/Admin/ProductController.php

@@ -3,6 +3,10 @@
 namespace App\Http\Controllers\Admin;
 namespace App\Http\Controllers\Admin;
 
 
 use App\Http\Controllers\Controller;
 use App\Http\Controllers\Controller;
+use App\Models\Egg;
+use App\Models\Location;
+use App\Models\Nest;
+use App\Models\Node;
 use App\Models\Configuration;
 use App\Models\Configuration;
 use App\Models\Product;
 use App\Models\Product;
 use Exception;
 use Exception;
@@ -33,7 +37,18 @@ class ProductController extends Controller
      */
      */
     public function create()
     public function create()
     {
     {
-        return view('admin.products.create');
+        return view('admin.products.create' , [
+            'locations' => Location::with('nodes')->get(),
+            'nests' => Nest::with('eggs')->get(),
+        ]);
+    }
+
+    public function clone(Request $request , Product $product){
+        return view('admin.products.create' , [
+            'product' => $product,
+            'locations' => Location::with('nodes')->get(),
+            'nests' => Nest::with('eggs')->get(),
+        ]);
     }
     }
 
 
     /**
     /**
@@ -57,11 +72,17 @@ class ProductController extends Controller
             "databases" => "required|numeric|max:1000000|min:0",
             "databases" => "required|numeric|max:1000000|min:0",
             "backups" => "required|numeric|max:1000000|min:0",
             "backups" => "required|numeric|max:1000000|min:0",
             "allocations" => "required|numeric|max:1000000|min:0",
             "allocations" => "required|numeric|max:1000000|min:0",
+            "nodes.*" => "required|exists:nodes,id",
+            "eggs.*" => "required|exists:eggs,id",
             "disabled" => "nullable",
             "disabled" => "nullable",
         ]);
         ]);
 
 
         $disabled = !is_null($request->input('disabled'));
         $disabled = !is_null($request->input('disabled'));
-        Product::create(array_merge($request->all(), ['disabled' => $disabled]));
+        $product = Product::create(array_merge($request->all(), ['disabled' => $disabled]));
+
+        #link nodes and eggs
+        $product->eggs()->attach($request->input('eggs'));
+        $product->nodes()->attach($request->input('nodes'));
 
 
         return redirect()->route('admin.products.index')->with('success', 'product has been created!');
         return redirect()->route('admin.products.index')->with('success', 'product has been created!');
     }
     }
@@ -89,7 +110,9 @@ class ProductController extends Controller
     public function edit(Product $product)
     public function edit(Product $product)
     {
     {
         return view('admin.products.edit', [
         return view('admin.products.edit', [
-            'product' => $product
+            'product' => $product,
+            'locations' => Location::with('nodes')->get(),
+            'nests' => Nest::with('eggs')->get(),
         ]);
         ]);
     }
     }
 
 
@@ -115,12 +138,20 @@ class ProductController extends Controller
             "databases" => "required|numeric|max:1000000|min:0",
             "databases" => "required|numeric|max:1000000|min:0",
             "backups" => "required|numeric|max:1000000|min:0",
             "backups" => "required|numeric|max:1000000|min:0",
             "allocations" => "required|numeric|max:1000000|min:0",
             "allocations" => "required|numeric|max:1000000|min:0",
+            "nodes.*" => "required|exists:nodes,id",
+            "eggs.*" => "required|exists:eggs,id",
             "disabled" => "nullable",
             "disabled" => "nullable",
         ]);
         ]);
 
 
         $disabled = !is_null($request->input('disabled'));
         $disabled = !is_null($request->input('disabled'));
         $product->update(array_merge($request->all(), ['disabled' => $disabled]));
         $product->update(array_merge($request->all(), ['disabled' => $disabled]));
 
 
+        #link nodes and eggs
+        $product->eggs()->detach();
+        $product->nodes()->detach();
+        $product->eggs()->attach($request->input('eggs'));
+        $product->nodes()->attach($request->input('nodes'));
+
         return redirect()->route('admin.products.index')->with('success', 'product has been updated!');
         return redirect()->route('admin.products.index')->with('success', 'product has been updated!');
     }
     }
 
 
@@ -166,6 +197,7 @@ class ProductController extends Controller
             ->addColumn('actions', function (Product $product) {
             ->addColumn('actions', function (Product $product) {
                 return '
                 return '
                             <a data-content="Show" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.products.show', $product->id) . '" class="btn btn-sm text-white btn-warning mr-1"><i class="fas fa-eye"></i></a>
                             <a data-content="Show" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.products.show', $product->id) . '" class="btn btn-sm text-white btn-warning mr-1"><i class="fas fa-eye"></i></a>
+                            <a data-content="Clone" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.products.clone', $product->id) . '" class="btn btn-sm text-white btn-primary mr-1"><i class="fas fa-clone"></i></a>
                             <a data-content="Edit" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.products.edit', $product->id) . '" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a>
                             <a data-content="Edit" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.products.edit', $product->id) . '" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a>
 
 
                            <form class="d-inline" onsubmit="return submitResult();" method="post" action="' . route('admin.products.destroy', $product->id) . '">
                            <form class="d-inline" onsubmit="return submitResult();" method="post" action="' . route('admin.products.destroy', $product->id) . '">
@@ -179,6 +211,12 @@ class ProductController extends Controller
             ->addColumn('servers', function (Product $product) {
             ->addColumn('servers', function (Product $product) {
                 return $product->servers()->count();
                 return $product->servers()->count();
             })
             })
+            ->addColumn('nodes', function (Product $product) {
+                return $product->nodes()->count();
+            })
+            ->addColumn('eggs', function (Product $product) {
+                return $product->eggs()->count();
+            })
             ->addColumn('disabled', function (Product $product) {
             ->addColumn('disabled', function (Product $product) {
                 $checked = $product->disabled == false ? "checked" : "";
                 $checked = $product->disabled == false ? "checked" : "";
                 return '
                 return '

+ 2 - 0
app/Http/Controllers/HomeController.php

@@ -1,6 +1,8 @@
 <?php
 <?php
 namespace App\Http\Controllers;
 namespace App\Http\Controllers;
 
 
+use App\Models\Egg;
+use App\Models\Product;
 use App\Models\UsefulLink;
 use App\Models\UsefulLink;
 use App\Models\Configuration;
 use App\Models\Configuration;
 use Illuminate\Http\Request;
 use Illuminate\Http\Request;

+ 23 - 14
app/Models/Egg.php

@@ -6,6 +6,7 @@ use App\Classes\Pterodactyl;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\Relations\BelongsToMany;
 
 
 class Egg extends Model
 class Egg extends Model
 {
 {
@@ -23,14 +24,6 @@ class Egg extends Model
         'environment',
         'environment',
     ];
     ];
 
 
-    /**
-     * @return BelongsTo
-     */
-    public function nest()
-    {
-        return $this->belongsTo(Nest::class, 'id', 'nest_id');
-    }
-
     /**
     /**
      * @return array
      * @return array
      */
      */
@@ -39,7 +32,7 @@ class Egg extends Model
         $array = [];
         $array = [];
 
 
         foreach (json_decode($this->environment) as $variable) {
         foreach (json_decode($this->environment) as $variable) {
-            foreach ($variable as $key => $value){
+            foreach ($variable as $key => $value) {
                 $array[$key] = $value;
                 $array[$key] = $value;
             }
             }
         }
         }
@@ -47,12 +40,13 @@ class Egg extends Model
         return $array;
         return $array;
     }
     }
 
 
-    public static function syncEggs(){
+    public static function syncEggs()
+    {
 
 
-         Nest::all()->each(function (Nest $nest) {
+        Nest::all()->each(function (Nest $nest) {
             $eggs = Pterodactyl::getEggs($nest);
             $eggs = Pterodactyl::getEggs($nest);
 
 
-            foreach ($eggs as $egg){
+            foreach ($eggs as $egg) {
                 $array = [];
                 $array = [];
                 $environment = [];
                 $environment = [];
 
 
@@ -64,17 +58,32 @@ class Egg extends Model
                 $array['startup'] = $egg['attributes']['startup'];
                 $array['startup'] = $egg['attributes']['startup'];
 
 
                 //get environment variables
                 //get environment variables
-                foreach ($egg['attributes']['relationships']['variables']['data'] as $variable){
+                foreach ($egg['attributes']['relationships']['variables']['data'] as $variable) {
                     $environment[$variable['attributes']['env_variable']] = $variable['attributes']['default_value'];
                     $environment[$variable['attributes']['env_variable']] = $variable['attributes']['default_value'];
                 }
                 }
 
 
                 $array['environment'] = json_encode([$environment]);
                 $array['environment'] = json_encode([$environment]);
 
 
-                self::firstOrCreate(['id' => $array['id']] , $array);
+                self::firstOrCreate(['id' => $array['id']], $array);
             }
             }
 
 
         });
         });
+    }
 
 
+    /**
+     * @return BelongsTo
+     */
+    public function nest()
+    {
+        return $this->belongsTo(Nest::class, 'id', 'nest_id');
+    }
 
 
+    /**
+     * @return BelongsToMany
+     */
+    public function products()
+    {
+        return $this->belongsToMany(Product::class);
     }
     }
+
 }
 }

+ 9 - 0
app/Models/Node.php

@@ -7,6 +7,7 @@ use Exception;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\Relations\BelongsToMany;
 
 
 class Node extends Model
 class Node extends Model
 {
 {
@@ -48,4 +49,12 @@ class Node extends Model
         }
         }
 
 
     }
     }
+
+    /**
+     * @return BelongsToMany
+     */
+    public function products()
+    {
+        return $this->belongsToMany(Product::class);
+    }
 }
 }

+ 22 - 1
app/Models/Product.php

@@ -6,6 +6,8 @@ use Hidehalo\Nanoid\Client;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\Relations\BelongsToMany;
+use Illuminate\Database\Eloquent\Relations\HasMany;
 use Spatie\Activitylog\Traits\LogsActivity;
 use Spatie\Activitylog\Traits\LogsActivity;
 
 
 class Product extends Model
 class Product extends Model
@@ -25,6 +27,11 @@ class Product extends Model
 
 
             $product->{$product->getKeyName()} = $client->generateId($size = 21);
             $product->{$product->getKeyName()} = $client->generateId($size = 21);
         });
         });
+
+        static::deleting(function(Product $product) {
+            $product->nodes()->detach();
+            $product->eggs()->detach();
+        });
     }
     }
 
 
     public function getHourlyPrice()
     public function getHourlyPrice()
@@ -45,8 +52,22 @@ class Product extends Model
     /**
     /**
      * @return BelongsTo
      * @return BelongsTo
      */
      */
-    public function servers(): BelongsTo
+    public function servers()
     {
     {
         return $this->belongsTo(Server::class, 'id', 'product_id');
         return $this->belongsTo(Server::class, 'id', 'product_id');
     }
     }
+
+    /**
+     * @return BelongsToMany
+     */
+    public function eggs() {
+        return $this->belongsToMany(Egg::class);
+    }
+
+    /**
+     * @return BelongsToMany
+     */
+    public function nodes() {
+        return $this->belongsToMany(Node::class);
+    }
 }
 }

+ 32 - 0
database/migrations/2021_07_06_152319_create_egg_product_table.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateEggProductTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('egg_product', function (Blueprint $table) {
+            $table->foreignId('egg_id')->constrained();
+            $table->foreignUuid('product_id')->constrained();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('egg_product');
+    }
+}

+ 32 - 0
database/migrations/2021_07_06_154314_create_node_product_table.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateNodeProductTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('node_product', function (Blueprint $table) {
+            $table->foreignId('node_id')->constrained();
+            $table->foreignUuid('product_id')->constrained();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('node_product');
+    }
+}

+ 32 - 0
database/migrations/2021_07_06_154658_add_disabled_to_eggs_table.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddDisabledToEggsTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('eggs', function (Blueprint $table) {
+            $table->boolean('disabled')->default(false);
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('eggs', function (Blueprint $table) {
+            $table->dropColumn('disabled');
+        });
+    }
+}

+ 131 - 47
resources/views/admin/products/create.blade.php

@@ -25,19 +25,22 @@
     <!-- MAIN CONTENT -->
     <!-- MAIN CONTENT -->
     <section class="content">
     <section class="content">
         <div class="container-fluid">
         <div class="container-fluid">
+            <form action="{{route('admin.products.store')}}" method="POST">
+                @csrf
+                <div class="row">
+                    <div class="col-lg-6">
+                        <div class="card">
+                            <div class="card-header">
+                                <h5 class="card-title">Product Details</h5>
+                            </div>
+                            <div class="card-body">
 
 
-            <div class="row">
-                <div class="col-lg-6">
-                    <div class="card">
-                        <div class="card-body">
-                            <form action="{{ route('admin.products.store') }}" method="POST">
-                                @csrf
                                 <div class="d-flex flex-row-reverse">
                                 <div class="d-flex flex-row-reverse">
                                     <div class="custom-control custom-switch">
                                     <div class="custom-control custom-switch">
                                         <input type="checkbox" name="disabled"
                                         <input type="checkbox" name="disabled"
-                                            class="custom-control-input custom-control-input-danger" id="switch1">
-                                        <label class="custom-control-label" for="switch1">Disabled <i data-toggle="popover"
-                                                data-trigger="hover"
+                                               class="custom-control-input custom-control-input-danger" id="switch1">
+                                        <label class="custom-control-label" for="switch1">Disabled <i
+                                                data-toggle="popover" data-trigger="hover"
                                                 data-content="Will hide this option from being selected"
                                                 data-content="Will hide this option from being selected"
                                                 class="fas fa-info-circle"></i></label>
                                                 class="fas fa-info-circle"></i></label>
                                     </div>
                                     </div>
@@ -47,9 +50,9 @@
                                     <div class="col-lg-6">
                                     <div class="col-lg-6">
                                         <div class="form-group">
                                         <div class="form-group">
                                             <label for="name">Name</label>
                                             <label for="name">Name</label>
-                                            <input value="{{ old('name') }}" id="name" name="name" type="text"
-                                                class="form-control @error('name') is-invalid @enderror"
-                                                required="required">
+                                            <input value="{{$product->name ?? old('name')}}" id="name" name="name" type="text"
+                                                   class="form-control @error('name') is-invalid @enderror"
+                                                   required="required">
                                             @error('name')
                                             @error('name')
                                                 <div class="invalid-feedback">
                                                 <div class="invalid-feedback">
                                                     {{ $message }}
                                                     {{ $message }}
@@ -58,10 +61,11 @@
                                         </div>
                                         </div>
 
 
                                         <div class="form-group">
                                         <div class="form-group">
-                                            <label for="price">Price in {{ CREDITS_DISPLAY_NAME }}</label>
-                                            <input value="{{ old('price') }}" id="price" name="price" type="number"
-                                                class="form-control @error('price') is-invalid @enderror"
-                                                required="required">
+                                            <label for="price">Price in credits</label>
+                                            <input value="{{$product->price ??  old('price')}}" id="price" name="price"
+                                                   type="number"
+                                                   class="form-control @error('price') is-invalid @enderror"
+                                                   required="required">
                                             @error('price')
                                             @error('price')
                                                 <div class="invalid-feedback">
                                                 <div class="invalid-feedback">
                                                     {{ $message }}
                                                     {{ $message }}
@@ -72,9 +76,10 @@
 
 
                                         <div class="form-group">
                                         <div class="form-group">
                                             <label for="memory">Memory</label>
                                             <label for="memory">Memory</label>
-                                            <input value="{{ old('memory') }}" id="memory" name="memory" type="number"
-                                                class="form-control @error('memory') is-invalid @enderror"
-                                                required="required">
+                                            <input value="{{$product->memory ?? old('memory')}}" id="memory" name="memory"
+                                                   type="number"
+                                                   class="form-control @error('memory') is-invalid @enderror"
+                                                   required="required">
                                             @error('memory')
                                             @error('memory')
                                                 <div class="invalid-feedback">
                                                 <div class="invalid-feedback">
                                                     {{ $message }}
                                                     {{ $message }}
@@ -84,8 +89,10 @@
 
 
                                         <div class="form-group">
                                         <div class="form-group">
                                             <label for="cpu">Cpu</label>
                                             <label for="cpu">Cpu</label>
-                                            <input value="{{ old('cpu') }}" id="cpu" name="cpu" type="number"
-                                                class="form-control @error('cpu') is-invalid @enderror" required="required">
+                                            <input value="{{$product->cpu ?? old('cpu')}}" id="cpu" name="cpu"
+                                                   type="number"
+                                                   class="form-control @error('cpu') is-invalid @enderror"
+                                                   required="required">
                                             @error('cpu')
                                             @error('cpu')
                                                 <div class="invalid-feedback">
                                                 <div class="invalid-feedback">
                                                     {{ $message }}
                                                     {{ $message }}
@@ -95,9 +102,10 @@
 
 
                                         <div class="form-group">
                                         <div class="form-group">
                                             <label for="swap">Swap</label>
                                             <label for="swap">Swap</label>
-                                            <input value="{{ old('swap') }}" id="swap" name="swap" type="number"
-                                                class="form-control @error('swap') is-invalid @enderror"
-                                                required="required">
+                                            <input value="{{$product->swap ?? old('swap')}}" id="swap" name="swap"
+                                                   type="number"
+                                                   class="form-control @error('swap') is-invalid @enderror"
+                                                   required="required">
                                             @error('swap')
                                             @error('swap')
                                                 <div class="invalid-feedback">
                                                 <div class="invalid-feedback">
                                                     {{ $message }}
                                                     {{ $message }}
@@ -107,11 +115,13 @@
 
 
                                         <div class="form-group">
                                         <div class="form-group">
                                             <label for="description">Description <i data-toggle="popover"
                                             <label for="description">Description <i data-toggle="popover"
-                                                    data-trigger="hover" data-content="This is what the users sees"
-                                                    class="fas fa-info-circle"></i></label>
-                                            <textarea id="description" name="description" type="text"
-                                                class="form-control @error('description') is-invalid @enderror"
-                                                required="required">{{ old('description') }}</textarea>
+                                                                                    data-trigger="hover"
+                                                                                    data-content="This is what the users sees"
+                                                                                    class="fas fa-info-circle"></i></label>
+                                            <textarea id="description" name="description"
+                                                      type="text"
+                                                      class="form-control @error('description') is-invalid @enderror"
+                                                      required="required">{{$product->description ?? old('description')}}</textarea>
                                             @error('description')
                                             @error('description')
                                                 <div class="invalid-feedback">
                                                 <div class="invalid-feedback">
                                                     {{ $message }}
                                                     {{ $message }}
@@ -123,9 +133,10 @@
                                     <div class="col-lg-6">
                                     <div class="col-lg-6">
                                         <div class="form-group">
                                         <div class="form-group">
                                             <label for="disk">Disk</label>
                                             <label for="disk">Disk</label>
-                                            <input value="{{ old('disk') ?? 1000 }}" id="disk" name="disk" type="number"
-                                                class="form-control @error('disk') is-invalid @enderror"
-                                                required="required">
+                                            <input value="{{$product->disk ?? old('disk') ?? 1000}}" id="disk" name="disk"
+                                                   type="number"
+                                                   class="form-control @error('disk') is-invalid @enderror"
+                                                   required="required">
                                             @error('disk')
                                             @error('disk')
                                                 <div class="invalid-feedback">
                                                 <div class="invalid-feedback">
                                                     {{ $message }}
                                                     {{ $message }}
@@ -151,8 +162,10 @@
 
 
                                         <div class="form-group">
                                         <div class="form-group">
                                             <label for="io">IO</label>
                                             <label for="io">IO</label>
-                                            <input value="{{ old('io') ?? 500 }}" id="io" name="io" type="number"
-                                                class="form-control @error('io') is-invalid @enderror" required="required">
+                                            <input value="{{$product->io ?? old('io') ?? 500}}" id="io" name="io"
+                                                   type="number"
+                                                   class="form-control @error('io') is-invalid @enderror"
+                                                   required="required">
                                             @error('io')
                                             @error('io')
                                                 <div class="invalid-feedback">
                                                 <div class="invalid-feedback">
                                                     {{ $message }}
                                                     {{ $message }}
@@ -161,9 +174,11 @@
                                         </div>
                                         </div>
                                         <div class="form-group">
                                         <div class="form-group">
                                             <label for="databases">Databases</label>
                                             <label for="databases">Databases</label>
-                                            <input value="{{ old('databases') ?? 1 }}" id="databases" name="databases"
-                                                type="number" class="form-control @error('databases') is-invalid @enderror"
-                                                required="required">
+                                            <input value="{{$product->databases ?? old('databases') ?? 1}}" id="databases"
+                                                   name="databases"
+                                                   type="number"
+                                                   class="form-control @error('databases') is-invalid @enderror"
+                                                   required="required">
                                             @error('databases')
                                             @error('databases')
                                                 <div class="invalid-feedback">
                                                 <div class="invalid-feedback">
                                                     {{ $message }}
                                                     {{ $message }}
@@ -172,9 +187,11 @@
                                         </div>
                                         </div>
                                         <div class="form-group">
                                         <div class="form-group">
                                             <label for="backups">Backups</label>
                                             <label for="backups">Backups</label>
-                                            <input value="{{ old('backups') ?? 1 }}" id="backups" name="backups"
-                                                type="number" class="form-control @error('backups') is-invalid @enderror"
-                                                required="required">
+                                            <input value="{{$product->backups ?? old('backups') ?? 1}}" id="backups"
+                                                   name="backups"
+                                                   type="number"
+                                                   class="form-control @error('backups') is-invalid @enderror"
+                                                   required="required">
                                             @error('backups')
                                             @error('backups')
                                                 <div class="invalid-feedback">
                                                 <div class="invalid-feedback">
                                                     {{ $message }}
                                                     {{ $message }}
@@ -183,10 +200,11 @@
                                         </div>
                                         </div>
                                         <div class="form-group">
                                         <div class="form-group">
                                             <label for="allocations">Allocations</label>
                                             <label for="allocations">Allocations</label>
-                                            <input value="{{ old('allocations') ?? 0 }}" id="allocations"
-                                                name="allocations" type="number"
-                                                class="form-control @error('allocations') is-invalid @enderror"
-                                                required="required">
+                                            <input value="{{$product->allocations ?? old('allocations') ?? 0}}"
+                                                   id="allocations" name="allocations"
+                                                   type="number"
+                                                   class="form-control @error('allocations') is-invalid @enderror"
+                                                   required="required">
                                             @error('allocations')
                                             @error('allocations')
                                                 <div class="invalid-feedback">
                                                 <div class="invalid-feedback">
                                                     {{ $message }}
                                                     {{ $message }}
@@ -201,11 +219,73 @@
                                         Submit
                                         Submit
                                     </button>
                                     </button>
                                 </div>
                                 </div>
-                            </form>
+
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="col-lg-6">
+                        <div class="card">
+                            <div class="card-header">
+                                <h5 class="card-title">Product Linking <i data-toggle="popover" data-trigger="hover"
+                                                                          data-content="Linked products will only be available when the user has selected the linked node and/or egg"
+                                                                          class="fas fa-info-circle"></i></h5>
+                            </div>
+                            <div class="card-body">
+
+                                <div class="form-group">
+                                    <label for="nodes">Nodes</label>
+                                    <select id="nodes" style="width:100%" class="custom-select @error('nodes') is-invalid @enderror"
+                                            name="nodes[]" multiple="multiple" autocomplete="off">
+                                        @foreach($locations as $location)
+                                            <optgroup label="{{$location->name}}">
+                                                @foreach($location->nodes as $node)
+                                                    <option @if(isset($product)) @if($product->nodes->contains('id' , $node->id)) selected
+                                                            @endif @endif value="{{$node->id}}">{{$node->name}}</option>
+                                                @endforeach
+                                            </optgroup>
+                                        @endforeach
+                                    </select>
+                                    @error('nodes')
+                                    <div class="text-danger">
+                                        {{$message}}
+                                    </div>
+                                    @enderror
+                                    <div class="text-muted">
+                                        This product will only be available for these nodes
+                                    </div>
+                                </div>
+
+
+                                <div class="form-group">
+                                    <label for="eggs">Eggs</label>
+                                    <select id="eggs" style="width:100%" class="custom-select @error('eggs') is-invalid @enderror"
+                                            name="eggs[]" multiple="multiple" autocomplete="off">
+                                        @foreach($nests as $nest)
+                                            <optgroup label="{{$nest->name}}">
+                                                @foreach($nest->eggs as $egg)
+                                                    <option @if(isset($product)) @if($product->eggs->contains('id' , $egg->id)) selected
+                                                            @endif @endif  value="{{$egg->id}}">{{$egg->name}}</option>
+                                                @endforeach
+                                            </optgroup>
+                                        @endforeach
+                                    </select>
+                                    @error('eggs')
+                                    <div class="text-danger">
+                                        {{$message}}
+                                    </div>
+                                    @enderror
+                                    <div class="text-muted">
+                                        This product will only be available for these eggs
+                                    </div>
+                                </div>
+
+                            </div>
                         </div>
                         </div>
                     </div>
                     </div>
+
                 </div>
                 </div>
-            </div>
+            </form>
 
 
         </div>
         </div>
     </section>
     </section>
@@ -216,6 +296,10 @@
             $('[data-toggle="popover"]').popover();
             $('[data-toggle="popover"]').popover();
         });
         });
     </script>
     </script>
-
+    <script>
+        document.addEventListener('DOMContentLoaded', (event) => {
+        })
+    </script>
+            $('.custom-select').select2();
 
 
 @endsection
 @endsection

+ 103 - 31
resources/views/admin/products/edit.blade.php

@@ -10,10 +10,10 @@
                 </div>
                 </div>
                 <div class="col-sm-6">
                 <div class="col-sm-6">
                     <ol class="breadcrumb float-sm-right">
                     <ol class="breadcrumb float-sm-right">
-                        <li class="breadcrumb-item"><a href="{{ route('home') }}">Dashboard</a></li>
-                        <li class="breadcrumb-item"><a href="{{ route('admin.products.index') }}">Products</a></li>
+                        <li class="breadcrumb-item"><a href="{{route('home')}}">Dashboard</a></li>
+                        <li class="breadcrumb-item"><a href="{{route('admin.products.index')}}">Products</a></li>
                         <li class="breadcrumb-item"><a class="text-muted"
                         <li class="breadcrumb-item"><a class="text-muted"
-                                href="{{ route('admin.products.edit', $product->id) }}">Edit</a>
+                                                       href="{{route('admin.products.edit' , $product->id)}}">Edit</a>
                         </li>
                         </li>
                     </ol>
                     </ol>
                 </div>
                 </div>
@@ -25,31 +25,34 @@
     <!-- MAIN CONTENT -->
     <!-- MAIN CONTENT -->
     <section class="content">
     <section class="content">
         <div class="container-fluid">
         <div class="container-fluid">
+            <form action="{{route('admin.products.update' , $product->id)}}" method="POST">
+                @csrf
+                @method('PATCH')
 
 
+                <div class="row">
+                    <div class="col-lg-6">
 
 
-            <div class="row">
-                <div class="col-lg-6">
+                        @if($product->servers()->count() > 0)
+                            <div class="callout callout-danger">
+                                <h4>Editing the resource options will not automatically update the servers on
+                                    pterodactyl's side!</h4>
+                                <p class="text-muted">Automatically updating resource options on pterodactyl side is on
+                                    my todo list :)</p>
+                            </div>
+                        @endif
 
 
-                    @if ($product->servers()->count() > 0)
-                        <div class="callout callout-danger">
-                            <h4>Editing the resource options will not automatically update the servers on pterodactyl's
-                                side!</h4>
-                            <p class="text-muted">Automatically updating resource options on pterodactyl side is on my
-                                todo list :)</p>
-                        </div>
-                    @endif
+                        <div class="card">
+                            <div class="card-header">
+                                <h5 class="card-title">Product Details</h5>
+                            </div>
+                            <div class="card-body">
 
 
-                    <div class="card">
-                        <div class="card-body">
-                            <form action="{{ route('admin.products.update', $product->id) }}" method="POST">
-                                @csrf
-                                @method('PATCH')
                                 <div class="d-flex flex-row-reverse">
                                 <div class="d-flex flex-row-reverse">
                                     <div class="custom-control custom-switch">
                                     <div class="custom-control custom-switch">
-                                        <input type="checkbox" @if ($product->disabled) checked @endif name="disabled"
-                                            class="custom-control-input custom-control-input-danger" id="switch1">
-                                        <label class="custom-control-label" for="switch1">Disabled <i data-toggle="popover"
-                                                data-trigger="hover"
+                                        <input type="checkbox" @if($product->disabled) checked @endif name="disabled"
+                                               class="custom-control-input custom-control-input-danger" id="switch1">
+                                        <label class="custom-control-label" for="switch1">Disabled <i
+                                                data-toggle="popover" data-trigger="hover"
                                                 data-content="Will hide this option from being selected"
                                                 data-content="Will hide this option from being selected"
                                                 class="fas fa-info-circle"></i></label>
                                                 class="fas fa-info-circle"></i></label>
                                     </div>
                                     </div>
@@ -57,6 +60,7 @@
 
 
                                 <div class="row">
                                 <div class="row">
                                     <div class="col-lg-6">
                                     <div class="col-lg-6">
+
                                         <div class="form-group">
                                         <div class="form-group">
                                             <label for="name">Name</label>
                                             <label for="name">Name</label>
                                             <input value="{{ $product->name }}" id="name" name="name" type="text"
                                             <input value="{{ $product->name }}" id="name" name="name" type="text"
@@ -118,11 +122,13 @@
 
 
                                         <div class="form-group">
                                         <div class="form-group">
                                             <label for="description">Description <i data-toggle="popover"
                                             <label for="description">Description <i data-toggle="popover"
-                                                    data-trigger="hover" data-content="This is what the users sees"
-                                                    class="fas fa-info-circle"></i></label>
-                                            <textarea id="description" name="description" type="text"
-                                                class="form-control @error('description') is-invalid @enderror"
-                                                required="required">{{ $product->description }}</textarea>
+                                                                                    data-trigger="hover"
+                                                                                    data-content="This is what the users sees"
+                                                                                    class="fas fa-info-circle"></i></label>
+                                            <textarea id="description" name="description"
+                                                      type="text"
+                                                      class="form-control @error('description') is-invalid @enderror"
+                                                      required="required">{{$product->description}}</textarea>
                                             @error('description')
                                             @error('description')
                                                 <div class="invalid-feedback">
                                                 <div class="invalid-feedback">
                                                     {{ $message }}
                                                     {{ $message }}
@@ -210,21 +216,87 @@
                                         Submit
                                         Submit
                                     </button>
                                     </button>
                                 </div>
                                 </div>
-                            </form>
+
+                            </div>
                         </div>
                         </div>
                     </div>
                     </div>
-                </div>
-            </div>
 
 
+                    <div class="col-lg-6">
+                        <div class="card">
+                            <div class="card-header">
+                                <h5 class="card-title">Product Linking <i data-toggle="popover" data-trigger="hover"
+                                                                          data-content="Linked products will only be available when the user has selected the linked node and/or egg"
+                                                                          class="fas fa-info-circle"></i></h5>
+                            </div>
+                            <div class="card-body">
+
+                                <div class="form-group">
+                                    <label for="nodes">Nodes</label>
+                                    <select id="nodes" style="width:100%"
+                                            class="custom-select @error('nodes') is-invalid @enderror" name="nodes[]"
+                                            multiple="multiple" autocomplete="off">
+                                        @foreach($locations as $location)
+                                            <optgroup label="{{$location->name}}">
+                                                @foreach($location->nodes as $node)
+                                                    <option @if($product->nodes->contains('id' , $node->id)) selected
+                                                            @endif value="{{$node->id}}">{{$node->name}}</option>
+                                                @endforeach
+                                            </optgroup>
+                                        @endforeach
+                                    </select>
+                                    @error('nodes')
+                                    <div class="text-danger">
+                                        {{$message}}
+                                    </div>
+                                    @enderror
+                                    <div class="text-muted">
+                                        This product will only be available for these nodes
+                                    </div>
+                                </div>
+
+                                <div class="form-group">
+                                    <label for="eggs">Eggs</label>
+                                    <select id="eggs" style="width:100%"
+                                            class="custom-select @error('eggs') is-invalid @enderror" name="eggs[]"
+                                            multiple="multiple" autocomplete="off">
+                                        @foreach($nests as $nest)
+                                            <optgroup label="{{$nest->name}}">
+                                                @foreach($nest->eggs as $egg)
+                                                    <option @if($product->eggs->contains('id' , $egg->id)) selected
+                                                            @endif value="{{$egg->id}}">{{$egg->name}}</option>
+                                                @endforeach
+                                            </optgroup>
+                                        @endforeach
+                                    </select>
+                                    @error('eggs')
+                                    <div class="text-danger">
+                                        {{$message}}
+                                    </div>
+                                    @enderror
+                                    <div class="text-muted">
+                                        This product will only be available for these eggs
+                                    </div>
+                                </div>
+
+                            </div>
+                        </div>
+                    </div>
+
+                </div>
+            </form>
         </div>
         </div>
     </section>
     </section>
     <!-- END CONTENT -->
     <!-- END CONTENT -->
 
 
+    <script>
+        document.addEventListener('DOMContentLoaded', (event) => {
+            $('.custom-select').select2();
+        })
+    </script>
     <script>
     <script>
         document.addEventListener('DOMContentLoaded', function() {
         document.addEventListener('DOMContentLoaded', function() {
             $('[data-toggle="popover"]').popover();
             $('[data-toggle="popover"]').popover();
         });
         });
     </script>
     </script>
 
 
-
 @endsection
 @endsection

+ 5 - 4
resources/views/admin/products/index.blade.php

@@ -46,10 +46,10 @@
                             <th>Cpu</th>
                             <th>Cpu</th>
                             <th>Swap</th>
                             <th>Swap</th>
                             <th>Disk</th>
                             <th>Disk</th>
-                            <th>IO</th>
                             <th>Databases</th>
                             <th>Databases</th>
                             <th>Backups</th>
                             <th>Backups</th>
-                            <th>Allocations</th>
+                            <th>Eggs</th>
+                            <th>Nodes</th>
                             <th>Servers</th>
                             <th>Servers</th>
                             <th>Created at</th>
                             <th>Created at</th>
                             <th></th>
                             <th></th>
@@ -79,6 +79,7 @@
                 processing: true,
                 processing: true,
                 serverSide: true,
                 serverSide: true,
                 stateSave: true,
                 stateSave: true,
+                order: [[ 2, "asc" ]],
                 ajax: "{{route('admin.products.datatable')}}",
                 ajax: "{{route('admin.products.datatable')}}",
                 columns: [
                 columns: [
                     {data: 'disabled'},
                     {data: 'disabled'},
@@ -88,10 +89,10 @@
                     {data: 'cpu'},
                     {data: 'cpu'},
                     {data: 'swap'},
                     {data: 'swap'},
                     {data: 'disk'},
                     {data: 'disk'},
-                    {data: 'io'},
                     {data: 'databases'},
                     {data: 'databases'},
                     {data: 'backups'},
                     {data: 'backups'},
-                    {data: 'allocations'},
+                    {data: 'nodes', sortable: false},
+                    {data: 'eggs', sortable: false},
                     {data: 'servers', sortable: false},
                     {data: 'servers', sortable: false},
                     {data: 'created_at'},
                     {data: 'created_at'},
                     {data: 'actions', sortable: false},
                     {data: 'actions', sortable: false},

+ 2 - 0
resources/views/layouts/main.blade.php

@@ -340,6 +340,8 @@
 <script type="text/javascript" src="https://cdn.datatables.net/v/bs4/dt-1.10.24/datatables.min.js"></script>
 <script type="text/javascript" src="https://cdn.datatables.net/v/bs4/dt-1.10.24/datatables.min.js"></script>
 <!-- Summernote -->
 <!-- Summernote -->
 <script src="{{asset('plugins/summernote/summernote-bs4.min.js')}}"></script>
 <script src="{{asset('plugins/summernote/summernote-bs4.min.js')}}"></script>
+<!-- select2 -->
+<script src="{{asset('plugins/select2/js/select2.min.js')}}"></script>
 
 
 <!-- Moment.js -->
 <!-- Moment.js -->
 <script src="{{asset('plugins/moment/moment.min.js')}}"></script>
 <script src="{{asset('plugins/moment/moment.min.js')}}"></script>

+ 1 - 0
routes/web.php

@@ -87,6 +87,7 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () {
         Route::resource('servers', AdminServerController::class);
         Route::resource('servers', AdminServerController::class);
 
 
         Route::get('products/datatable', [ProductController::class, 'datatable'])->name('products.datatable');
         Route::get('products/datatable', [ProductController::class, 'datatable'])->name('products.datatable');
+        Route::get('products/clone/{product}', [ProductController::class, 'clone'])->name('products.clone');
         Route::patch('products/disable/{product}', [ProductController::class, 'disable'])->name('products.disable');
         Route::patch('products/disable/{product}', [ProductController::class, 'disable'])->name('products.disable');
         Route::resource('products', ProductController::class);
         Route::resource('products', ProductController::class);