浏览代码

[FEATURE] Server owner transfer

[FEATURE] Server owner transfer
Dennis 2 年之前
父节点
当前提交
e978cb9914

+ 35 - 19
app/Classes/Pterodactyl.php

@@ -7,6 +7,7 @@ use App\Models\Nest;
 use App\Models\Node;
 use App\Models\Product;
 use App\Models\Server;
+use App\Models\User;
 use Exception;
 use Illuminate\Http\Client\PendingRequest;
 use Illuminate\Http\Client\Response;
@@ -22,19 +23,19 @@ class Pterodactyl
     public static function client()
     {
         return Http::withHeaders([
-            'Authorization' => 'Bearer '.config('SETTINGS::SYSTEM:PTERODACTYL:TOKEN'),
+            'Authorization' => 'Bearer ' . config('SETTINGS::SYSTEM:PTERODACTYL:TOKEN'),
             'Content-type' => 'application/json',
             'Accept' => 'Application/vnd.pterodactyl.v1+json',
-        ])->baseUrl(config('SETTINGS::SYSTEM:PTERODACTYL:URL').'/api');
+        ])->baseUrl(config('SETTINGS::SYSTEM:PTERODACTYL:URL') . '/api');
     }
 
     public static function clientAdmin()
     {
         return Http::withHeaders([
-            'Authorization' => 'Bearer '.config('SETTINGS::SYSTEM:PTERODACTYL:ADMIN_USER_TOKEN'),
+            'Authorization' => 'Bearer ' . config('SETTINGS::SYSTEM:PTERODACTYL:ADMIN_USER_TOKEN'),
             'Content-type' => 'application/json',
             'Accept' => 'Application/vnd.pterodactyl.v1+json',
-        ])->baseUrl(config('SETTINGS::SYSTEM:PTERODACTYL:URL').'/api');
+        ])->baseUrl(config('SETTINGS::SYSTEM:PTERODACTYL:URL') . '/api');
     }
 
     /**
@@ -43,22 +44,22 @@ class Pterodactyl
     private static function getException(string $message = '', int $status = 0): Exception
     {
         if ($status == 404) {
-            return new Exception('Ressource does not exist on pterodactyl - '.$message, 404);
+            return new Exception('Ressource does not exist on pterodactyl - ' . $message, 404);
         }
 
         if ($status == 403) {
-            return new Exception('No permission on pterodactyl, check pterodactyl token and permissions - '.$message, 403);
+            return new Exception('No permission on pterodactyl, check pterodactyl token and permissions - ' . $message, 403);
         }
 
         if ($status == 401) {
-            return new Exception('No pterodactyl token set - '.$message, 401);
+            return new Exception('No pterodactyl token set - ' . $message, 401);
         }
 
         if ($status == 500) {
-            return new Exception('Pterodactyl server error - '.$message, 500);
+            return new Exception('Pterodactyl server error - ' . $message, 500);
         }
 
-        return new Exception('Request Failed, is pterodactyl set-up correctly? - '.$message);
+        return new Exception('Request Failed, is pterodactyl set-up correctly? - ' . $message);
     }
 
     /**
@@ -70,7 +71,7 @@ class Pterodactyl
     public static function getEggs(Nest $nest)
     {
         try {
-            $response = self::client()->get("/application/nests/{$nest->id}/eggs?include=nest,variables&per_page=".config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
+            $response = self::client()->get("/application/nests/{$nest->id}/eggs?include=nest,variables&per_page=" . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
         } catch (Exception $e) {
             throw self::getException($e->getMessage());
         }
@@ -89,7 +90,7 @@ class Pterodactyl
     public static function getNodes()
     {
         try {
-            $response = self::client()->get('/application/nodes?per_page='.config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
+            $response = self::client()->get('/application/nodes?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
         } catch (Exception $e) {
             throw self::getException($e->getMessage());
         }
@@ -109,12 +110,12 @@ class Pterodactyl
     public static function getNode($id)
     {
         try {
-            $response = self::client()->get('/application/nodes/'.$id);
+            $response = self::client()->get('/application/nodes/' . $id);
         } catch (Exception $e) {
             throw self::getException($e->getMessage());
         }
         if ($response->failed()) {
-            throw self::getException('Failed to get node id '.$id.' - '.$response->status());
+            throw self::getException('Failed to get node id ' . $id . ' - ' . $response->status());
         }
 
         return $response->json()['attributes'];
@@ -123,7 +124,7 @@ class Pterodactyl
     public static function getServers()
     {
         try {
-            $response = self::client()->get('/application/servers?per_page='.config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
+            $response = self::client()->get('/application/servers?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
         } catch (Exception $e) {
             throw self::getException($e->getMessage());
         }
@@ -142,7 +143,7 @@ class Pterodactyl
     public static function getNests()
     {
         try {
-            $response = self::client()->get('/application/nests?per_page='.config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
+            $response = self::client()->get('/application/nests?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
         } catch (Exception $e) {
             throw self::getException($e->getMessage());
         }
@@ -161,7 +162,7 @@ class Pterodactyl
     public static function getLocations()
     {
         try {
-            $response = self::client()->get('/application/locations?per_page='.config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
+            $response = self::client()->get('/application/locations?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
         } catch (Exception $e) {
             throw self::getException($e->getMessage());
         }
@@ -195,9 +196,9 @@ class Pterodactyl
         $freeAllocations = [];
 
         if (isset($response['data'])) {
-            if (! empty($response['data'])) {
+            if (!empty($response['data'])) {
                 foreach ($response['data'] as $allocation) {
-                    if (! $allocation['attributes']['assigned']) {
+                    if (!$allocation['attributes']['assigned']) {
                         array_push($freeAllocations, $allocation);
                     }
                 }
@@ -234,7 +235,7 @@ class Pterodactyl
      */
     public static function url(string $route): string
     {
-        return config('SETTINGS::SYSTEM:PTERODACTYL:URL').$route;
+        return config('SETTINGS::SYSTEM:PTERODACTYL:URL') . $route;
     }
 
     /**
@@ -373,6 +374,21 @@ class Pterodactyl
         ]);
     }
 
+    /**
+     * Update the owner of a server
+     *
+     * @param  int  $userId
+     * @param  Server  $server
+     * @return mixed
+     */
+    public static function updateServerOwner(Server $server, int $userId)
+    {
+        return self::client()->patch("/application/servers/{$server->pterodactyl_id}/details", [
+            'name' => $server->name,
+            'user' => $userId,
+        ]);
+    }
+
     /**
      * Power Action Specific Server
      *

+ 47 - 21
app/Http/Controllers/Admin/ServerController.php

@@ -5,6 +5,7 @@ namespace App\Http\Controllers\Admin;
 use App\Classes\Pterodactyl;
 use App\Http\Controllers\Controller;
 use App\Models\Server;
+use App\Models\User;
 use Exception;
 use Illuminate\Contracts\Foundation\Application;
 use Illuminate\Contracts\View\Factory;
@@ -66,8 +67,12 @@ class ServerController extends Controller
      */
     public function edit(Server $server)
     {
+        // get all users from the database
+        $users = User::all();
+
         return view('admin.servers.edit')->with([
             'server' => $server,
+            'users' => $users,
         ]);
     }
 
@@ -76,15 +81,36 @@ class ServerController extends Controller
      *
      * @param  Request  $request
      * @param  Server  $server
-     * @return Response
      */
     public function update(Request $request, Server $server)
     {
         $request->validate([
             'identifier' => 'required|string',
+            'user_id' => 'required|integer',
         ]);
 
-        $server->update($request->all());
+
+        if ($request->get('user_id') != $server->user_id) {
+            // find the user
+            $user = User::findOrFail($request->get('user_id'));
+
+            // try to update the owner on pterodactyl
+            try {
+                $response = Pterodactyl::updateServerOwner($server, $user->pterodactyl_id);
+                if ($response->getStatusCode() != 200) {
+                    return redirect()->back()->with('error', 'Failed to update server owner on pterodactyl');
+                }
+
+                // update the owner on the database
+                $server->user_id = $user->id;
+            } catch (Exception $e) {
+                return redirect()->back()->with('error', 'Internal Server Error');
+            }
+        }
+
+        // update the identifier
+        $server->identifier = $request->get('identifier');
+        $server->save();
 
         return redirect()->route('admin.servers.index')->with('success', 'Server updated!');
     }
@@ -102,7 +128,7 @@ class ServerController extends Controller
 
             return redirect()->route('admin.servers.index')->with('success', __('Server removed'));
         } catch (Exception $e) {
-            return redirect()->route('admin.servers.index')->with('error', __('An exception has occurred while trying to remove a resource "').$e->getMessage().'"');
+            return redirect()->route('admin.servers.index')->with('error', __('An exception has occurred while trying to remove a resource "') . $e->getMessage() . '"');
         }
     }
 
@@ -128,17 +154,17 @@ class ServerController extends Controller
 
         $CPIDArray = [];
         $renameCount = 0;
-        foreach ($CPServers as $CPServer) {//go thru all CP servers and make array with IDs as keys. All values are false.
+        foreach ($CPServers as $CPServer) { //go thru all CP servers and make array with IDs as keys. All values are false.
             if ($CPServer->pterodactyl_id) {
                 $CPIDArray[$CPServer->pterodactyl_id] = false;
             }
         }
 
-        foreach ($pteroServers as $server) {//go thru all ptero servers, if server exists, change value to true in array.
+        foreach ($pteroServers as $server) { //go thru all ptero servers, if server exists, change value to true in array.
             if (isset($CPIDArray[$server['attributes']['id']])) {
                 $CPIDArray[$server['attributes']['id']] = true;
 
-                if (isset($server['attributes']['name'])) {//failsafe
+                if (isset($server['attributes']['name'])) { //failsafe
                     //Check if a server got renamed
                     $savedServer = Server::query()->where('pterodactyl_id', $server['attributes']['id'])->first();
                     if ($savedServer->name != $server['attributes']['name']) {
@@ -150,16 +176,16 @@ class ServerController extends Controller
             }
         }
         $filteredArray = array_filter($CPIDArray, function ($v, $k) {
-        return $v == false;
+            return $v == false;
         }, ARRAY_FILTER_USE_BOTH); //Array of servers, that dont exist on ptero (value == false)
         $deleteCount = 0;
-        foreach ($filteredArray as $key => $CPID) {//delete servers that dont exist on ptero anymore
-            if (! Pterodactyl::getServerAttributes($key, true)) {
+        foreach ($filteredArray as $key => $CPID) { //delete servers that dont exist on ptero anymore
+            if (!Pterodactyl::getServerAttributes($key, true)) {
                 $deleteCount++;
             }
         }
 
-        return redirect()->back()->with('success', __('Servers synced successfully'.(($renameCount) ? (',\n'.__('renamed').' '.$renameCount.' '.__('servers')) : '').((count($filteredArray)) ? (',\n'.__('deleted').' '.$deleteCount.'/'.count($filteredArray).' '.__('old servers')) : ''))).'.';
+        return redirect()->back()->with('success', __('Servers synced successfully' . (($renameCount) ? (',\n' . __('renamed') . ' ' . $renameCount . ' ' . __('servers')) : '') . ((count($filteredArray)) ? (',\n' . __('deleted') . ' ' . $deleteCount . '/' . count($filteredArray) . ' ' . __('old servers')) : ''))) . '.';
     }
 
     /**
@@ -180,7 +206,7 @@ class ServerController extends Controller
 
         return datatables($query)
             ->addColumn('user', function (Server $server) {
-                return '<a href="'.route('admin.users.show', $server->user->id).'">'.$server->user->name.'</a>';
+                return '<a href="' . route('admin.users.show', $server->user->id) . '">' . $server->user->name . '</a>';
             })
             ->addColumn('resources', function (Server $server) {
                 return $server->product->description;
@@ -191,16 +217,16 @@ class ServerController extends Controller
                 $suspendText = $server->isSuspended() ? __('Unsuspend') : __('Suspend');
 
                 return '
-                         <a data-content="'.__('Edit').'" data-toggle="popover" data-trigger="hover" data-placement="top"  href="'.route('admin.servers.edit', $server->id).'" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a>
-                        <form class="d-inline" method="post" action="'.route('admin.servers.togglesuspend', $server->id).'">
-                            '.csrf_field().'
-                           <button data-content="'.$suspendText.'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm '.$suspendColor.' text-white mr-1"><i class="far '.$suspendIcon.'"></i></button>
+                         <a data-content="' . __('Edit') . '" data-toggle="popover" data-trigger="hover" data-placement="top"  href="' . route('admin.servers.edit', $server->id) . '" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a>
+                        <form class="d-inline" method="post" action="' . route('admin.servers.togglesuspend', $server->id) . '">
+                            ' . csrf_field() . '
+                           <button data-content="' . $suspendText . '" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm ' . $suspendColor . ' text-white mr-1"><i class="far ' . $suspendIcon . '"></i></button>
                        </form>
 
-                       <form class="d-inline" onsubmit="return submitResult();" method="post" action="'.route('admin.servers.destroy', $server->id).'">
-                            '.csrf_field().'
-                            '.method_field('DELETE').'
-                           <button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm btn-danger mr-1"><i class="fas fa-trash"></i></button>
+                       <form class="d-inline" onsubmit="return submitResult();" method="post" action="' . route('admin.servers.destroy', $server->id) . '">
+                            ' . csrf_field() . '
+                            ' . method_field('DELETE') . '
+                           <button data-content="' . __('Delete') . '" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm btn-danger mr-1"><i class="fas fa-trash"></i></button>
                        </form>
 
                 ';
@@ -208,7 +234,7 @@ class ServerController extends Controller
             ->addColumn('status', function (Server $server) {
                 $labelColor = $server->isSuspended() ? 'text-danger' : 'text-success';
 
-                return '<i class="fas '.$labelColor.' fa-circle mr-2"></i>';
+                return '<i class="fas ' . $labelColor . ' fa-circle mr-2"></i>';
             })
             ->editColumn('created_at', function (Server $server) {
                 return $server->created_at ? $server->created_at->diffForHumans() : '';
@@ -217,7 +243,7 @@ class ServerController extends Controller
                 return $server->suspended ? $server->suspended->diffForHumans() : '';
             })
             ->editColumn('name', function (Server $server) {
-                return '<a class="text-info" target="_blank" href="'.config('SETTINGS::SYSTEM:PTERODACTYL:URL').'/admin/servers/view/'.$server->pterodactyl_id.'">'.strip_tags($server->name).'</a>';
+                return '<a class="text-info" target="_blank" href="' . config('SETTINGS::SYSTEM:PTERODACTYL:URL') . '/admin/servers/view/' . $server->pterodactyl_id . '">' . strip_tags($server->name) . '</a>';
             })
             ->rawColumns(['user', 'actions', 'status', 'name'])
             ->make();

+ 41 - 15
themes/default/views/admin/servers/edit.blade.php

@@ -6,21 +6,22 @@
         <div class="container-fluid">
             <div class="alert alert-danger p-2 m-2">
                 <h5><i class="icon fas fa-exclamation-circle"></i> {{ __('ATTENTION!') }}</h5>
-                {{ __('Only edit these settings if you know exactly what you are doing ')}}
+                {{ __('Only edit these settings if you know exactly what you are doing ') }}
                 <br>
                 {{ __('You usually do not need to change anything here') }}
             </div>
             <div class="row mb-2">
                 <div class="col-sm-6">
 
-                    <h1>{{__('Edit Server')}}</h1>
+                    <h1>{{ __('Edit Server') }}</h1>
                 </div>
                 <div class="col-sm-6">
                     <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.servers.index')}}">{{__('Servers')}}</a></li>
+                        <li class="breadcrumb-item"><a href="{{ route('home') }}">{{ __('Dashboard') }}</a></li>
+                        <li class="breadcrumb-item"><a href="{{ route('admin.servers.index') }}">{{ __('Servers') }}</a>
+                        </li>
                         <li class="breadcrumb-item"><a class="text-muted"
-                                                       href="{{route('admin.servers.edit' , $server->id)}}">{{__('Edit')}}</a></li>
+                                href="{{ route('admin.servers.edit', $server->id) }}">{{ __('Edit') }}</a></li>
                     </ol>
                 </div>
             </div>
@@ -36,23 +37,49 @@
                 <div class="col-lg-6">
                     <div class="card">
                         <div class="card-body">
-                            <form action="{{route('admin.servers.update', $server->id)}}" method="POST">
+                            <form action="{{ route('admin.servers.update', $server->id) }}" method="POST">
                                 @csrf
                                 @method('PATCH')
                                 <div class="form-group">
-                                    <label for="name">{{__('Server identifier')}}</label>
-                                    <input value="{{$server->identifier}}" id="identifier" name="identifier" type="text"
-                                           class="form-control @error('identifier') is-invalid @enderror" required="required">
+                                    <label for="identifier">{{ __('Server identifier') }}
+                                        <i data-toggle="popover" data-trigger="hover"
+                                            data-content="{{ __('Change the server identifier on controlpanel to match a pterodactyl server.') }}"
+                                            class="fas fa-info-circle"></i>
+                                    </label>
+                                    <input value="{{ $server->identifier }}" id="identifier" name="identifier"
+                                        type="text" class="form-control @error('identifier') is-invalid @enderror"
+                                        required="required">
                                     @error('identifier')
-                                    <div class="invalid-feedback">
-                                        {{$message}}
-                                    </div>
+                                        <div class="invalid-feedback">
+                                            {{ $message }}
+                                        </div>
                                     @enderror
                                 </div>
 
-                                <div class="form-group text-right">
-                                    <button type="submit" class="btn btn-primary">{{__('Submit')}}</button>
+                                <div class="form-group">
+                                    <label for="user_id">{{ __('Server owner') }}
+                                        <i data-toggle="popover" data-trigger="hover"
+                                            data-content="{{ __('Change the current server owner on controlpanel and pterodactyl.') }}"
+                                            class="fas fa-info-circle"></i>
+                                    </label>
+                                    <select name="user_id" id="user_id" class="form-control">
+                                        @foreach ($users as $user)
+                                            <option value="{{ $user->id }}"
+                                                @if ($user->id == $server->user_id) selected @endif>{{ $user->name }}
+                                                ({{ $user->email }})
+                                                ({{ $user->id }})
+                                            </option>
+                                        @endforeach
+                                    </select>
+                                    @error('user_id')
+                                        <div class="invalid-feedback">
+                                            {{ $message }}
+                                        </div>
+                                    @enderror
                                 </div>
+
+                                <button type="submit" class="btn btn-primary">{{ __('Submit') }}</button>
+
                         </div>
                     </div>
                 </div>
@@ -63,5 +90,4 @@
 
     </section>
     <!-- END CONTENT -->
-
 @endsection