[FEATURE] Server owner transfer

[FEATURE] Server owner transfer
This commit is contained in:
Dennis 2023-01-19 11:29:42 +01:00 committed by GitHub
commit e978cb9914
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 123 additions and 55 deletions

View file

@ -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
*

View file

@ -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();

View file

@ -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