浏览代码

fine tuning :)

AVMG20 3 年之前
父节点
当前提交
8c7c938c6a

+ 0 - 1
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'];
     }
 

+ 25 - 0
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'));
+    }
 }

+ 23 - 7
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'),

+ 46 - 15
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,26 +22,21 @@ class Egg extends Model
         'docker_image',
         'startup',
         'environment',
+        'updated_at',
     ];
 
-    /**
-     * @return array
-     */
-    public function getEnvironmentVariables()
+    public static function boot()
     {
-        $array = [];
-
-        foreach (json_decode($this->environment) as $variable) {
-            foreach ($variable as $key => $value) {
-                $array[$key] = $value;
-            }
-        }
+        parent::boot(); // TODO: Change the autogenerated stub
 
-        return $array;
+        static::deleting(function (Egg $egg) {
+            $egg->products()->detach();
+        });
     }
 
     public static function syncEggs()
     {
+        Nest::syncNests();
 
         Nest::all()->each(function (Nest $nest) {
             $eggs = Pterodactyl::getEggs($nest);
@@ -57,6 +51,7 @@ class Egg extends Model
                 $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) {
@@ -65,18 +60,54 @@ class Egg extends Model
 
                 $array['environment'] = json_encode([$environment]);
 
-                self::firstOrCreate(['id' => $array['id']], $array);
+                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
+     */
+    public function getEnvironmentVariables()
+    {
+        $array = [];
+
+        foreach (json_decode($this->environment) as $variable) {
+            foreach ($variable as $key => $value) {
+                $array[$key] = $value;
+            }
+        }
+
+        return $array;
+    }
+
     /**
      * @return BelongsTo
      */
     public function nest()
     {
-        return $this->belongsTo(Nest::class, 'id', 'nest_id');
+        return $this->belongsTo(Nest::class);
     }
 
     /**

+ 47 - 7
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');
     }
 
 }

+ 48 - 5
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);
     }
 }

+ 48 - 12
app/Models/Node.php

@@ -17,36 +17,72 @@ class Node extends Model
 
     public $guarded = [];
 
-
-    /**
-     * @return BelongsTo
-     */
-    public function location(): BelongsTo
+    public static function boot()
     {
-        return $this->belongsTo(Location::class);
+        parent::boot(); // TODO: Change the autogenerated stub
+
+        static::deleting(function (Node $node) {
+            $node->products()->detach();
+        });
     }
 
+
     /**
      * @throws Exception
      */
-    public static function syncNodes(){
+    public static function syncNodes()
+    {
         Location::syncLocations();
         $nodes = Pterodactyl::getNodes();
 
-        $nodes = array_map(function($node) {
+        //map response
+        $nodes = array_map(function ($node) {
             return array(
-                'id' => $node['attributes']['id'],
+                'id'          => $node['attributes']['id'],
                 'location_id' => $node['attributes']['location_id'],
-                'name' => $node['attributes']['name'],
+                'name'        => $node['attributes']['name'],
                 'description' => $node['attributes']['description'],
-                'disabled' => '1'
             );
         }, $nodes);
 
+        //update or create
         foreach ($nodes as $node) {
-            self::firstOrCreate(['id' => $node['id']] , $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
+     */
+    public function location(): BelongsTo
+    {
+        return $this->belongsTo(Location::class);
     }
 
     /**

+ 23 - 17
resources/views/admin/overview/index.blade.php

@@ -26,16 +26,20 @@
 
             <div class="row mb-3">
                 <div class="col-md-3">
-                    <a href="https://discord.gg/4Y6HjD2uyU" class="btn btn-dark btn-block px-3"><i class="fab fa-discord mr-2"></i> {{__('Support server')}}</a>
+                    <a href="https://discord.gg/4Y6HjD2uyU" class="btn btn-dark btn-block px-3"><i
+                            class="fab fa-discord mr-2"></i> {{__('Support server')}}</a>
                 </div>
                 <div class="col-md-3">
-                    <a href="https://controlpanel.gg/docs/intro" class="btn btn-dark btn-block px-3"><i class="fas fa-link mr-2"></i> {{__('Documentation')}}</a>
+                    <a href="https://controlpanel.gg/docs/intro" class="btn btn-dark btn-block px-3"><i
+                            class="fas fa-link mr-2"></i> {{__('Documentation')}}</a>
                 </div>
                 <div class="col-md-3">
-                    <a href="https://github.com/ControlPanel-gg/dashboard" class="btn btn-dark btn-block px-3"><i class="fab fa-github mr-2"></i> {{__('Github')}}</a>
+                    <a href="https://github.com/ControlPanel-gg/dashboard" class="btn btn-dark btn-block px-3"><i
+                            class="fab fa-github mr-2"></i> {{__('Github')}}</a>
                 </div>
                 <div class="col-md-3">
-                    <a href="https://controlpanel.gg/docs/Contributing/donating" class="btn btn-dark btn-block px-3"><i class="fas fa-money-bill mr-2"></i> {{__('Support ControlPanel')}}</a>
+                    <a href="https://controlpanel.gg/docs/Contributing/donating" class="btn btn-dark btn-block px-3"><i
+                            class="fas fa-money-bill mr-2"></i> {{__('Support ControlPanel')}}</a>
                 </div>
             </div>
 
@@ -68,7 +72,8 @@
 
                 <div class="col-12 col-sm-6 col-md-3">
                     <div class="info-box">
-                        <span class="info-box-icon bg-warning elevation-1"><i class="fas fa-coins text-white"></i></span>
+                        <span class="info-box-icon bg-warning elevation-1"><i
+                                class="fas fa-coins text-white"></i></span>
 
                         <div class="info-box-content">
                             <span class="info-box-text">{{__('Total')}} {{CREDITS_DISPLAY_NAME}}</span>
@@ -101,39 +106,40 @@
                                 <div class="card-title ">
                                     <span><i class="fas fa-kiwi-bird mr-2"></i>{{__('Pterodactyl')}}</span>
                                 </div>
-                                <button class="btn btn-primary"><i class="fas fa-sync mr-2"></i>{{__('Sync')}}</button>
+                                <a href="{{route('admin.overview.sync')}}" class="btn btn-primary btn-sm"><i
+                                        class="fas fa-sync mr-2"></i>{{__('Sync')}}</a>
                             </div>
                         </div>
                         <div class="card-body py-1">
                             <table class="table">
-                               <thead>
-                               <tr>
-                                   <th>{{__('Resources')}}</th>
-                                   <th>{{__('Count')}}</th>
-                               </tr>
-                               </thead>
+                                <thead>
+                                <tr>
+                                    <th>{{__('Resources')}}</th>
+                                    <th>{{__('Count')}}</th>
+                                </tr>
+                                </thead>
                                 <tbody>
                                 <tr>
                                     <td>{{__('Locations')}}</td>
-                                    <td>1</td>
+                                    <td>{{$locationCount}}</td>
                                 </tr>
                                 <tr>
                                     <td>{{__('Nodes')}}</td>
-                                    <td>1</td>
+                                    <td>{{$nodeCount}}</td>
                                 </tr>
                                 <tr>
                                     <td>{{__('Nests')}}</td>
-                                    <td>1</td>
+                                    <td>{{$nestCount}}</td>
                                 </tr>
                                 <tr>
                                     <td>{{__('Eggs')}}</td>
-                                    <td>1</td>
+                                    <td>{{$eggCount}}</td>
                                 </tr>
                                 </tbody>
                             </table>
                         </div>
                         <div class="card-footer">
-                            <span><i class="fas fa-sync mr-2"></i>{{__('Last updated :date', ['date' => now()])}}</span>
+                            <span><i class="fas fa-sync mr-2"></i>{{__('Last updated :date', ['date' => $syncLastUpdate])}}</span>
                         </div>
                     </div>
                 </div>

+ 23 - 6
resources/views/layouts/main.blade.php

@@ -78,11 +78,33 @@
                 </div>
             </li>
 
+            <li class="nav-item dropdown">
+                <a class="nav-link" href="#" id="userDropdown" role="button" data-toggle="dropdown"
+                   aria-haspopup="true"
+                   aria-expanded="false">
+                    <span class="mr-1 d-lg-inline text-gray-600">
+                        <small><i class="fas fa-coins mr-2"></i></small>{{Auth::user()->credits()}}
+                    </span>
+                </a>
+                <div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
+                    <a class="dropdown-item" href="{{route('store.index')}}">
+                        <i class="fas fa-coins fa-sm fa-fw mr-2 text-gray-400"></i>
+                        {{__('Store')}}
+                    </a>
+                    <div class="dropdown-divider"></div>
+                    <a class="dropdown-item" data-toggle="modal" data-target="#redeemVoucherModal"
+                       href="javascript:void(0)">
+                        <i class="fas fa-money-check-alt fa-sm fa-fw mr-2 text-gray-400"></i>
+                        {{__('Redeem code')}}
+                    </a>
+                </div>
+            </li>
+
             <li class="nav-item dropdown no-arrow">
                 <a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-toggle="dropdown"
                    aria-haspopup="true"
                    aria-expanded="false">
-                    <span class="mr-1 d-none d-lg-inline text-gray-600 small">
+                    <span class="mr-1 d-lg-inline text-gray-600 small">
                         {{Auth::user()->name}}
                         <img width="28px" height="28px" class="rounded-circle ml-1" src="{{Auth::user()->getAvatar()}}">
                     </span>
@@ -104,11 +126,6 @@
                             Log back in
                         </a>
                     @endif
-                    <a class="dropdown-item" data-toggle="modal" data-target="#redeemVoucherModal"
-                       href="javascript:void(0)">
-                        <i class="fas fa-money-check-alt fa-sm fa-fw mr-2 text-gray-400"></i>
-                        Redeem code
-                    </a>
                     <div class="dropdown-divider"></div>
                     <form method="post" action="{{route('logout')}}">
                         @csrf

+ 27 - 9
resources/views/servers/create.blade.php

@@ -37,14 +37,18 @@
 
                         @if($productCount === 0 || $nodeCount === 0 || count($nests) === 0 || count($eggs) === 0 )
                             <div class="alert alert-danger p-2 m-2">
-                                <h5><i class="icon fas fa-exclamation-circle"></i>Error!</h5>
+                                <h5><i class="icon fas fa-exclamation-circle"></i>{{__('Error!')}}</h5>
+                                <p class="pl-4">
+                                    {{__('Make sure to link your products to nodes and eggs.')}} <br>
+                                    {{__('There has to be at least 1 valid product for server creation')}}
+                                </p>
                                 <ul>
                                     @if($productCount === 0 )
                                         <li> {{__('No products available!')}}</li>
                                     @endif
 
                                     @if($nodeCount === 0 )
-                                        <li>{{__('No nodes available!')}}</li>
+                                        <li>{{__('No nodes have been linked!')}}</li>
                                     @endif
 
                                     @if(count($nests) === 0 )
@@ -52,7 +56,7 @@
                                     @endif
 
                                     @if(count($eggs) === 0 )
-                                        <li>{{__('No eggs available!')}}</li>
+                                        <li>{{__('No eggs have been linked!')}}</li>
                                     @endif
                                 </ul>
                             </div>
@@ -96,7 +100,7 @@
                                                 id="nest"
                                                 x-model="selectedNest"
                                                 @change="setNests();">
-                                            <option selected disabled
+                                            <option selected disabled hidden
                                                     value="null">{{count($nests) > 0 ? __('Please select software..') : __('---')}}</option>
                                             @foreach ($nests as $nest)
                                                 <option value="{{ $nest->id }}">{{ $nest->name }}</option>
@@ -140,7 +144,7 @@
                                         class="custom-select">
                                     <option
                                         x-text="getNodeInputText()"
-                                        disabled selected value="null"></option>
+                                        disabled selected hidden value="null"></option>
                                     <template x-for="node in nodes" :key="node.id">
                                         <option x-text="node.name" :value="node.id"></option>
                                     </template>
@@ -159,10 +163,12 @@
                                         class="custom-select">
                                     <option
                                         x-text="getProductInputText()"
-                                        disabled selected value="null"></option>
+                                        disabled selected hidden value="null"></option>
                                     <template x-for="product in products" :key="product.id">
-                                        <option x-text="product.name + ' (' + product.description + ')'"
-                                                :value="product.id"></option>
+                                        <option :disabled="product.minimum_credits > user.credits"
+                                                x-text="getProductOptionText(product)"
+                                                :value="product.id">
+                                        </option>
                                     </template>
                                 </select>
                             </div>
@@ -222,7 +228,8 @@
                                     </strong>
                                 </li>
                             </ul>
-                            <button :disabled="!isFormValid()" :class="isFormValid() ? '' : 'disabled'" class="btn btn-primary btn-block">
+                            <button :disabled="!isFormValid()" :class="isFormValid() ? '' : 'disabled'"
+                                    class="btn btn-primary btn-block">
                                 {{__('Create server')}}
                             </button>
                         </div>
@@ -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;
                 }
             }
         }

+ 4 - 5
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);