chore: add phpstan static analysis minimum (#4511)

This commit is contained in:
Lance Pioch 2022-11-28 11:56:03 -05:00 committed by GitHub
parent 3f7e2a565f
commit a1a52754ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
67 changed files with 561 additions and 279 deletions

View file

@ -25,7 +25,7 @@ use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
class Handler extends ExceptionHandler
final class Handler extends ExceptionHandler
{
/**
* The validation parser in Laravel formats custom rules using the class name

View file

@ -9,7 +9,6 @@ use Pterodactyl\Models\ApiKey;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Api\KeyCreationService;
use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface;
@ -23,8 +22,7 @@ class ApiController extends Controller
public function __construct(
private AlertsMessageBag $alert,
private ApiKeyRepositoryInterface $repository,
private KeyCreationService $keyCreationService,
private ViewFactory $view,
private KeyCreationService $keyCreationService
) {
}
@ -33,7 +31,7 @@ class ApiController extends Controller
*/
public function index(Request $request): View
{
return $this->view->make('admin.api.index', [
return view('admin.api.index', [
'keys' => $this->repository->getApplicationKeys($request->user()),
]);
}
@ -48,7 +46,7 @@ class ApiController extends Controller
$resources = AdminAcl::getResourceList();
sort($resources);
return $this->view->make('admin.api.new', [
return view('admin.api.new', [
'resources' => $resources,
'permissions' => [
'r' => AdminAcl::READ,

View file

@ -3,7 +3,6 @@
namespace Pterodactyl\Http\Controllers\Admin;
use Illuminate\View\View;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Helpers\SoftwareVersionService;
@ -12,7 +11,7 @@ class BaseController extends Controller
/**
* BaseController constructor.
*/
public function __construct(private SoftwareVersionService $version, private ViewFactory $view)
public function __construct(private SoftwareVersionService $version)
{
}
@ -21,6 +20,6 @@ class BaseController extends Controller
*/
public function index(): View
{
return $this->view->make('admin.index', ['version' => $this->version]);
return view('admin.index', ['version' => $this->version]);
}
}

View file

@ -8,7 +8,6 @@ use Illuminate\View\View;
use Pterodactyl\Models\DatabaseHost;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Databases\Hosts\HostUpdateService;
use Pterodactyl\Http\Requests\Admin\DatabaseHostFormRequest;
@ -30,8 +29,7 @@ class DatabaseController extends Controller
private HostCreationService $creationService,
private HostDeletionService $deletionService,
private HostUpdateService $updateService,
private LocationRepositoryInterface $locationRepository,
private ViewFactory $view
private LocationRepositoryInterface $locationRepository
) {
}
@ -40,7 +38,7 @@ class DatabaseController extends Controller
*/
public function index(): View
{
return $this->view->make('admin.databases.index', [
return view('admin.databases.index', [
'locations' => $this->locationRepository->getAllWithNodes(),
'hosts' => $this->repository->getWithViewDetails(),
]);
@ -53,7 +51,7 @@ class DatabaseController extends Controller
*/
public function view(int $host): View
{
return $this->view->make('admin.databases.view', [
return view('admin.databases.view', [
'locations' => $this->locationRepository->getAllWithNodes(),
'host' => $this->repository->find($host),
'databases' => $this->databaseRepository->getDatabasesForHost($host),

View file

@ -35,7 +35,7 @@ class LocationController extends Controller
*/
public function index(): View
{
return $this->view->make('admin.locations.index', [
return view('admin.locations.index', [
'locations' => $this->repository->getAllWithDetails(),
]);
}
@ -47,7 +47,7 @@ class LocationController extends Controller
*/
public function view(int $id): View
{
return $this->view->make('admin.locations.view', [
return view('admin.locations.view', [
'location' => $this->repository->getWithNodes($id),
]);
}

View file

@ -37,7 +37,7 @@ class MountController extends Controller
*/
public function index(): View
{
return $this->view->make('admin.mounts.index', [
return view('admin.mounts.index', [
'mounts' => $this->repository->getAllWithDetails(),
]);
}
@ -52,7 +52,7 @@ class MountController extends Controller
$nests = Nest::query()->with('eggs')->get();
$locations = Location::query()->with('nodes')->get();
return $this->view->make('admin.mounts.view', [
return view('admin.mounts.view', [
'mount' => $this->repository->getWithRelations($id),
'nests' => $nests,
'locations' => $locations,

View file

@ -42,7 +42,7 @@ class EggController extends Controller
$nests = $this->nestRepository->getWithEggs();
JavaScript::put(['nests' => $nests->keyBy('id')]);
return $this->view->make('admin.eggs.new', ['nests' => $nests]);
return view('admin.eggs.new', ['nests' => $nests]);
}
/**
@ -67,7 +67,7 @@ class EggController extends Controller
*/
public function view(Egg $egg): View
{
return $this->view->make('admin.eggs.view', [
return view('admin.eggs.view', [
'egg' => $egg,
'images' => array_map(
fn ($key, $value) => $key === $value ? $value : "$key|$value",

View file

@ -41,7 +41,7 @@ class EggScriptController extends Controller
['copy_script_from', '=', $egg->id],
]);
return $this->view->make('admin.eggs.scripts', [
return view('admin.eggs.scripts', [
'copyFromOptions' => $copy,
'relyOnScript' => $rely,
'egg' => $egg,

View file

@ -39,7 +39,7 @@ class EggVariableController extends Controller
{
$egg = $this->repository->getWithVariables($egg);
return $this->view->make('admin.eggs.variables', ['egg' => $egg]);
return view('admin.eggs.variables', ['egg' => $egg]);
}
/**

View file

@ -35,7 +35,7 @@ class NestController extends Controller
*/
public function index(): View
{
return $this->view->make('admin.nests.index', [
return view('admin.nests.index', [
'nests' => $this->repository->getWithCounts(),
]);
}
@ -45,7 +45,7 @@ class NestController extends Controller
*/
public function create(): View
{
return $this->view->make('admin.nests.new');
return view('admin.nests.new');
}
/**
@ -68,7 +68,7 @@ class NestController extends Controller
*/
public function view(int $nest): View
{
return $this->view->make('admin.nests.view', [
return view('admin.nests.view', [
'nest' => $this->repository->getWithEggServers($nest),
]);
}

View file

@ -7,17 +7,9 @@ use Illuminate\Http\Request;
use Pterodactyl\Models\Node;
use Spatie\QueryBuilder\QueryBuilder;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Contracts\View\Factory as ViewFactory;
class NodeController extends Controller
{
/**
* NodeController constructor.
*/
public function __construct(private ViewFactory $view)
{
}
/**
* Returns a listing of nodes on the system.
*/
@ -30,6 +22,6 @@ class NodeController extends Controller
->allowedSorts(['id'])
->paginate(25);
return $this->view->make('admin.nodes.index', ['nodes' => $nodes]);
return view('admin.nodes.index', ['nodes' => $nodes]);
}
}

View file

@ -8,13 +8,11 @@ use Pterodactyl\Models\Node;
use Illuminate\Support\Collection;
use Pterodactyl\Models\Allocation;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Contracts\View\Factory as ViewFactory;
use Pterodactyl\Repositories\Eloquent\NodeRepository;
use Pterodactyl\Repositories\Eloquent\ServerRepository;
use Pterodactyl\Traits\Controllers\JavascriptInjection;
use Pterodactyl\Services\Helpers\SoftwareVersionService;
use Pterodactyl\Repositories\Eloquent\LocationRepository;
use Pterodactyl\Repositories\Eloquent\AllocationRepository;
class NodeViewController extends Controller
{
@ -24,12 +22,10 @@ class NodeViewController extends Controller
* NodeViewController constructor.
*/
public function __construct(
private AllocationRepository $allocationRepository,
private LocationRepository $locationRepository,
private NodeRepository $repository,
private ServerRepository $serverRepository,
private SoftwareVersionService $versionService,
private ViewFactory $view
private SoftwareVersionService $versionService
) {
}
@ -40,7 +36,7 @@ class NodeViewController extends Controller
{
$node = $this->repository->loadLocationAndServerCount($node);
return $this->view->make('admin.nodes.view.index', [
return view('admin.nodes.view.index', [
'node' => $node,
'stats' => $this->repository->getUsageStats($node),
'version' => $this->versionService,
@ -52,7 +48,7 @@ class NodeViewController extends Controller
*/
public function settings(Request $request, Node $node): View
{
return $this->view->make('admin.nodes.view.settings', [
return view('admin.nodes.view.settings', [
'node' => $node,
'locations' => $this->locationRepository->all(),
]);
@ -63,7 +59,7 @@ class NodeViewController extends Controller
*/
public function configuration(Request $request, Node $node): View
{
return $this->view->make('admin.nodes.view.configuration', compact('node'));
return view('admin.nodes.view.configuration', compact('node'));
}
/**
@ -75,7 +71,7 @@ class NodeViewController extends Controller
$this->plainInject(['node' => Collection::wrap($node)->only(['id'])]);
return $this->view->make('admin.nodes.view.allocation', [
return view('admin.nodes.view.allocation', [
'node' => $node,
'allocations' => Allocation::query()->where('node_id', $node->id)
->groupBy('ip')
@ -94,7 +90,7 @@ class NodeViewController extends Controller
->only(['scheme', 'fqdn', 'daemonListen', 'daemon_token_id', 'daemon_token']),
]);
return $this->view->make('admin.nodes.view.servers', [
return view('admin.nodes.view.servers', [
'node' => $node,
'servers' => $this->serverRepository->loadAllServersForNode($node->id, 25),
]);

View file

@ -60,7 +60,7 @@ class NodesController extends Controller
return redirect()->route('admin.locations');
}
return $this->view->make('admin.nodes.new', ['locations' => $locations]);
return view('admin.nodes.new', ['locations' => $locations]);
}
/**

View file

@ -4,11 +4,11 @@ namespace Pterodactyl\Http\Controllers\Admin\Servers;
use JavaScript;
use Illuminate\View\View;
use Pterodactyl\Models\Nest;
use Pterodactyl\Models\Node;
use Pterodactyl\Models\Location;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Repositories\Eloquent\NestRepository;
use Pterodactyl\Repositories\Eloquent\NodeRepository;
@ -24,8 +24,7 @@ class CreateServerController extends Controller
private AlertsMessageBag $alert,
private NestRepository $nestRepository,
private NodeRepository $nodeRepository,
private ServerCreationService $creationService,
private ViewFactory $view
private ServerCreationService $creationService
) {
}
@ -47,14 +46,14 @@ class CreateServerController extends Controller
JavaScript::put([
'nodeData' => $this->nodeRepository->getNodesForServerCreation(),
'nests' => $nests->map(function ($item) {
'nests' => $nests->map(function (Nest $item) {
return array_merge($item->toArray(), [
'eggs' => $item->eggs->keyBy('id')->toArray(),
]);
})->keyBy('id'),
]);
return $this->view->make('admin.servers.new', [
return view('admin.servers.new', [
'locations' => Location::all(),
'nests' => $nests,
]);

View file

@ -9,17 +9,9 @@ use Spatie\QueryBuilder\QueryBuilder;
use Spatie\QueryBuilder\AllowedFilter;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Models\Filters\AdminServerFilter;
use Illuminate\Contracts\View\Factory as ViewFactory;
class ServerController extends Controller
{
/**
* ServerController constructor.
*/
public function __construct(private ViewFactory $view)
{
}
/**
* Returns all the servers that exist on the system using a paginated result set. If
* a query is passed along in the request it is also passed to the repository function.
@ -33,6 +25,6 @@ class ServerController extends Controller
])
->paginate(config()->get('pterodactyl.paginate.admin.servers'));
return $this->view->make('admin.servers.index', ['servers' => $servers]);
return view('admin.servers.index', ['servers' => $servers]);
}
}

View file

@ -4,6 +4,7 @@ namespace Pterodactyl\Http\Controllers\Admin\Servers;
use Carbon\CarbonImmutable;
use Illuminate\Http\Request;
use Pterodactyl\Models\Node;
use Pterodactyl\Models\Server;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
@ -11,7 +12,6 @@ use Pterodactyl\Models\ServerTransfer;
use Illuminate\Database\ConnectionInterface;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Nodes\NodeJWTService;
use Pterodactyl\Repositories\Eloquent\NodeRepository;
use Pterodactyl\Repositories\Wings\DaemonTransferRepository;
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
@ -25,8 +25,7 @@ class ServerTransferController extends Controller
private AllocationRepositoryInterface $allocationRepository,
private ConnectionInterface $connection,
private DaemonTransferRepository $daemonTransferRepository,
private NodeJWTService $nodeJWTService,
private NodeRepository $nodeRepository
private NodeJWTService $nodeJWTService
) {
}
@ -48,7 +47,7 @@ class ServerTransferController extends Controller
$additional_allocations = array_map('intval', $validatedData['allocation_additional'] ?? []);
// Check if the node is viable for the transfer.
$node = $this->nodeRepository->getNodeWithResourceUsage($node_id);
$node = Node::query()->findOrFail($node_id);
if (!$node->isViable($server->memory, $server->disk)) {
$this->alert->danger(trans('admin/server.alerts.transfer_not_viable'))->flash();
@ -58,7 +57,6 @@ class ServerTransferController extends Controller
$server->validateTransferState();
$this->connection->transaction(function () use ($server, $node_id, $allocation_id, $additional_allocations) {
// Create a new ServerTransfer entry.
$transfer = new ServerTransfer();
$transfer->server_id = $server->id;
@ -66,7 +64,7 @@ class ServerTransferController extends Controller
$transfer->new_node = $node_id;
$transfer->old_allocation = $server->allocation_id;
$transfer->new_allocation = $allocation_id;
$transfer->old_additional_allocations = $server->allocations->where('id', '!=', $server->allocation_id)->pluck('id');
$transfer->old_additional_allocations = $server->allocations->where('id', '!=', $server->allocation_id)->pluck('id')->all();
$transfer->new_additional_allocations = $additional_allocations;
$transfer->save();

View file

@ -10,11 +10,9 @@ use Pterodactyl\Models\Server;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Servers\EnvironmentService;
use Illuminate\Contracts\View\Factory as ViewFactory;
use Pterodactyl\Repositories\Eloquent\NestRepository;
use Pterodactyl\Repositories\Eloquent\NodeRepository;
use Pterodactyl\Repositories\Eloquent\MountRepository;
use Pterodactyl\Repositories\Eloquent\ServerRepository;
use Pterodactyl\Traits\Controllers\JavascriptInjection;
use Pterodactyl\Repositories\Eloquent\LocationRepository;
use Pterodactyl\Repositories\Eloquent\DatabaseHostRepository;
@ -32,9 +30,7 @@ class ServerViewController extends Controller
private MountRepository $mountRepository,
private NestRepository $nestRepository,
private NodeRepository $nodeRepository,
private ServerRepository $repository,
private EnvironmentService $environmentService,
private ViewFactory $view
private EnvironmentService $environmentService
) {
}
@ -43,7 +39,7 @@ class ServerViewController extends Controller
*/
public function index(Request $request, Server $server): View
{
return $this->view->make('admin.servers.view.index', compact('server'));
return view('admin.servers.view.index', compact('server'));
}
/**
@ -51,7 +47,7 @@ class ServerViewController extends Controller
*/
public function details(Request $request, Server $server): View
{
return $this->view->make('admin.servers.view.details', compact('server'));
return view('admin.servers.view.details', compact('server'));
}
/**
@ -61,7 +57,7 @@ class ServerViewController extends Controller
{
$allocations = $server->node->allocations->toBase();
return $this->view->make('admin.servers.view.build', [
return view('admin.servers.view.build', [
'server' => $server,
'assigned' => $allocations->where('server_id', $server->id)->sortBy('port')->sortBy('ip'),
'unassigned' => $allocations->where('server_id', null)->sortBy('port')->sortBy('ip'),
@ -88,7 +84,7 @@ class ServerViewController extends Controller
})->keyBy('id'),
]);
return $this->view->make('admin.servers.view.startup', compact('server', 'nests'));
return view('admin.servers.view.startup', compact('server', 'nests'));
}
/**
@ -96,7 +92,7 @@ class ServerViewController extends Controller
*/
public function database(Request $request, Server $server): View
{
return $this->view->make('admin.servers.view.database', [
return view('admin.servers.view.database', [
'hosts' => $this->databaseHostRepository->all(),
'server' => $server,
]);
@ -109,7 +105,7 @@ class ServerViewController extends Controller
{
$server->load('mounts');
return $this->view->make('admin.servers.view.mounts', [
return view('admin.servers.view.mounts', [
'mounts' => $this->mountRepository->getMountListForServer($server),
'server' => $server,
]);
@ -138,7 +134,7 @@ class ServerViewController extends Controller
'nodeData' => $this->nodeRepository->getNodesForServerCreation(),
]);
return $this->view->make('admin.servers.view.manage', [
return view('admin.servers.view.manage', [
'server' => $server,
'locations' => $this->locationRepository->all(),
'canTransfer' => $canTransfer,
@ -150,6 +146,6 @@ class ServerViewController extends Controller
*/
public function delete(Request $request, Server $server): View
{
return $this->view->make('admin.servers.view.delete', compact('server'));
return view('admin.servers.view.delete', compact('server'));
}
}

View file

@ -6,7 +6,6 @@ use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Contracts\Config\Repository as ConfigRepository;
use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface;
@ -21,8 +20,7 @@ class AdvancedController extends Controller
private AlertsMessageBag $alert,
private ConfigRepository $config,
private Kernel $kernel,
private SettingsRepositoryInterface $settings,
private ViewFactory $view
private SettingsRepositoryInterface $settings
) {
}
@ -39,7 +37,7 @@ class AdvancedController extends Controller
$showRecaptchaWarning = true;
}
return $this->view->make('admin.settings.advanced', [
return view('admin.settings.advanced', [
'showRecaptchaWarning' => $showRecaptchaWarning,
]);
}

View file

@ -6,7 +6,6 @@ use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Traits\Helpers\AvailableLanguages;
use Pterodactyl\Services\Helpers\SoftwareVersionService;
@ -24,8 +23,7 @@ class IndexController extends Controller
private AlertsMessageBag $alert,
private Kernel $kernel,
private SettingsRepositoryInterface $settings,
private SoftwareVersionService $versionService,
private ViewFactory $view
private SoftwareVersionService $versionService
) {
}
@ -34,7 +32,7 @@ class IndexController extends Controller
*/
public function index(): View
{
return $this->view->make('admin.settings.index', [
return view('admin.settings.index', [
'version' => $this->versionService,
'languages' => $this->getAvailableLanguages(true),
]);

View file

@ -8,7 +8,6 @@ use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Contracts\Console\Kernel;
use Pterodactyl\Notifications\MailTested;
use Illuminate\View\Factory as ViewFactory;
use Illuminate\Support\Facades\Notification;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller;
@ -27,8 +26,7 @@ class MailController extends Controller
private ConfigRepository $config,
private Encrypter $encrypter,
private Kernel $kernel,
private SettingsRepositoryInterface $settings,
private ViewFactory $view
private SettingsRepositoryInterface $settings
) {
}
@ -38,7 +36,7 @@ class MailController extends Controller
*/
public function index(): View
{
return $this->view->make('admin.settings.mail', [
return view('admin.settings.mail', [
'disabled' => $this->config->get('mail.default') !== 'smtp',
]);
}

View file

@ -6,13 +6,13 @@ use Illuminate\View\View;
use Illuminate\Http\Request;
use Pterodactyl\Models\User;
use Pterodactyl\Models\Model;
use Illuminate\Support\Collection;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Spatie\QueryBuilder\QueryBuilder;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Contracts\Translation\Translator;
use Pterodactyl\Services\Users\UserUpdateService;
use Pterodactyl\Traits\Helpers\AvailableLanguages;
@ -57,7 +57,7 @@ class UserController extends Controller
->allowedSorts(['id', 'uuid'])
->paginate(50);
return $this->view->make('admin.users.index', ['users' => $users]);
return view('admin.users.index', ['users' => $users]);
}
/**
@ -65,7 +65,7 @@ class UserController extends Controller
*/
public function create(): View
{
return $this->view->make('admin.users.new', [
return view('admin.users.new', [
'languages' => $this->getAvailableLanguages(true),
]);
}
@ -75,7 +75,7 @@ class UserController extends Controller
*/
public function view(User $user): View
{
return $this->view->make('admin.users.view', [
return view('admin.users.view', [
'user' => $user,
'languages' => $this->getAvailableLanguages(true),
]);
@ -132,22 +132,13 @@ class UserController extends Controller
/**
* Get a JSON response of users on the system.
*/
public function json(Request $request): Model|Collection
public function json(Request $request): Model|LengthAwarePaginator
{
$users = QueryBuilder::for(User::query())->allowedFilters(['email'])->paginate(25);
// Handle single user requests.
if ($request->query('user_id')) {
$user = User::query()->findOrFail($request->input('user_id'));
$user->md5 = md5(strtolower($user->email));
return $user;
return User::query()->findOrFail($request->input('user_id'));
}
return $users->map(function ($item) {
$item->md5 = md5(strtolower($item->email));
return $item;
});
return QueryBuilder::for(User::query())->allowedFilters(['email'])->paginate(25);
}
}

View file

@ -52,7 +52,6 @@ class StartupController extends ClientApiController
*/
public function update(UpdateStartupVariableRequest $request, Server $server): array
{
/** @var \Pterodactyl\Models\EggVariable $variable */
$variable = $server->variables()->where('env_variable', $request->input('key'))->first();
$original = $variable->server_value;
@ -62,6 +61,8 @@ class StartupController extends ClientApiController
throw new BadRequestHttpException('The environment variable you are trying to edit is read-only.');
}
/* @var \Pterodactyl\Models\EggVariable $variable */
// Revalidate the variable value using the egg variable specific validation rules for it.
$this->validate($request, ['value' => $variable->rules]);

View file

@ -3,6 +3,7 @@
namespace Pterodactyl\Http\Controllers\Api\Remote\Servers;
use Illuminate\Http\Request;
use Pterodactyl\Models\Backup;
use Pterodactyl\Models\Server;
use Illuminate\Http\JsonResponse;
use Pterodactyl\Facades\Activity;
@ -98,9 +99,11 @@ class ServerDetailsController extends Controller
if ($subject = $activity->subjects->where('subject_type', 'backup')->first()) {
// Just create a new audit entry for this event and update the server state
// so that power actions, file management, and backups can resume as normal.
/** @var Backup $actualSubject */
$actualSubject = $subject->subject;
Activity::event('server:backup.restore-failed')
->subject($server, $subject->subject)
->property('name', $subject->subject->name)
->subject($server, $actualSubject)
->property('name', $actualSubject->name)
->log();
}
}

View file

@ -49,7 +49,9 @@ abstract class AbstractLoginController extends Controller
/**
* Get the failed login response instance.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @return never
*
* @throws DisplayException
*/
protected function sendFailedLoginResponse(Request $request, Authenticatable $user = null, string $message = null)
{

View file

@ -72,7 +72,7 @@ class LoginCheckpointController extends AbstractLoginController
} else {
$decrypted = $this->encrypter->decrypt($user->totp_secret);
if ($this->google2FA->verifyKey($decrypted, (string) $request->input('authentication_code') ?? '', config('pterodactyl.auth.2fa.window'))) {
if ($this->google2FA->verifyKey($decrypted, $request->input('authentication_code') ?? '', config('pterodactyl.auth.2fa.window'))) {
Event::dispatch(new ProvidedAuthenticationToken($user));
return $this->sendLoginResponse($user, $request);

View file

@ -9,19 +9,10 @@ use Pterodactyl\Models\User;
use Illuminate\Http\JsonResponse;
use Pterodactyl\Facades\Activity;
use Illuminate\Contracts\View\View;
use Illuminate\Contracts\View\Factory as ViewFactory;
use Illuminate\Database\Eloquent\ModelNotFoundException;
class LoginController extends AbstractLoginController
{
/**
* LoginController constructor.
*/
public function __construct(private ViewFactory $view)
{
parent::__construct();
}
/**
* Handle all incoming requests for the authentication routes and render the
* base authentication view component. React will take over at this point and
@ -29,7 +20,7 @@ class LoginController extends AbstractLoginController
*/
public function index(): View
{
return $this->view->make('templates/auth.core');
return view('templates/auth.core');
}
/**

View file

@ -3,6 +3,7 @@
namespace Pterodactyl\Http\Controllers\Auth;
use Illuminate\Support\Str;
use Pterodactyl\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Contracts\Hashing\Hasher;
use Illuminate\Support\Facades\Password;
@ -67,13 +68,12 @@ class ResetPasswordController extends Controller
* account do not automatically log them in. In those cases, send the user back to the login
* form with a note telling them their password was changed and to log back in.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword|\Pterodactyl\Models\User $user
* @param string $password
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
protected function resetPassword($user, $password)
protected function resetPassword(User $user, $password)
{
$user = $this->userRepository->update($user->id, [
'password' => $this->hasher->make($password),

View file

@ -23,6 +23,6 @@ class IndexController extends Controller
*/
public function index(): View
{
return $this->view->make('templates/base.core');
return view('templates/base.core');
}
}

View file

@ -29,11 +29,11 @@ class ResourceBelongsToServer
public function handle(Request $request, Closure $next): mixed
{
$params = $request->route()->parameters();
if (is_null($params) || !$params['server'] instanceof Server) {
if (!$params['server'] instanceof Server) {
throw new InvalidArgumentException('This middleware cannot be used in a context that is missing a server in the parameters.');
}
/** @var \Pterodactyl\Models\Server $server */
/** @var Server $server */
$server = $request->route()->parameter('server');
$exception = new NotFoundHttpException('The requested resource was not found for this server.');
foreach ($params as $key => $model) {
@ -45,6 +45,7 @@ class ResourceBelongsToServer
continue;
}
/** @var Allocation|Backup|Database|Schedule|Subuser $model */
switch (get_class($model)) {
// All of these models use "server_id" as the field key for the server
// they are assigned to, so the logic is identical for them all.
@ -71,6 +72,7 @@ class ResourceBelongsToServer
// Tasks are special since they're (currently) the only item in the API
// that requires something in addition to the server in order to be accessed.
case Task::class:
/** @var Schedule $schedule */
$schedule = $request->route()->parameter('schedule');
if ($model->schedule_id !== $schedule->id || $schedule->server_id !== $server->id) {
throw $exception;

View file

@ -5,6 +5,7 @@ namespace Pterodactyl\Http\Middleware;
use Closure;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Pterodactyl\Models\User;
use Prologue\Alerts\AlertsMessageBag;
use Pterodactyl\Exceptions\Http\TwoFactorAuthRequiredException;
@ -36,12 +37,17 @@ class RequireTwoFactorAuthentication
*/
public function handle(Request $request, Closure $next): mixed
{
/** @var \Pterodactyl\Models\User $user */
/** @var User $user */
$user = $request->user();
$uri = rtrim($request->getRequestUri(), '/') . '/';
$current = $request->route()->getName();
if (!$user || Str::startsWith($uri, ['/auth/']) || Str::startsWith($current, ['auth.', 'account.'])) {
// Must be logged in
if (!$user instanceof User) {
return $next($request);
}
if (Str::startsWith($uri, ['/auth/']) || Str::startsWith($current, ['auth.', 'account.'])) {
return $next($request);
}

View file

@ -12,7 +12,10 @@ class LocationFormRequest extends AdminFormRequest
public function rules(): array
{
if ($this->method() === 'PATCH') {
return Location::getRulesForUpdate($this->route()->parameter('location')->id);
/** @var Location $location */
$location = $this->route()->parameter('location');
return Location::getRulesForUpdate($location->id);
}
return Location::getRules();

View file

@ -12,7 +12,10 @@ class MountFormRequest extends AdminFormRequest
public function rules(): array
{
if ($this->method() === 'PATCH') {
return Mount::getRulesForUpdate($this->route()->parameter('mount')->id);
/** @var Mount $mount */
$mount = $this->route()->parameter('mount');
return Mount::getRulesForUpdate($mount->id);
}
return Mount::getRules();

View file

@ -29,7 +29,7 @@ abstract class ApplicationApiRequest extends FormRequest
* Determine if the current user is authorized to perform
* the requested action against the API.
*
* @throws \Pterodactyl\Exceptions\PterodactylException
* @throws PterodactylException
*/
public function authorize(): bool
{
@ -42,6 +42,7 @@ abstract class ApplicationApiRequest extends FormRequest
return true;
}
/** @var ApiKey $token */
if ($token->key_type === ApiKey::TYPE_ACCOUNT) {
return true;
}
@ -81,6 +82,7 @@ abstract class ApplicationApiRequest extends FormRequest
*/
public function parameter(string $key, string $expect)
{
/** @var ApiKey $value */
$value = $this->route()->parameter($key);
Assert::isInstanceOf($value, $expect);

View file

@ -11,7 +11,9 @@ class UpdateLocationRequest extends StoreLocationRequest
*/
public function rules(): array
{
$locationId = $this->route()->parameter('location')->id;
/** @var Location $location */
$location = $this->route()->parameter('location');
$locationId = $location->id;
return collect(Location::getRulesForUpdate($locationId))->only([
'short',

View file

@ -12,8 +12,9 @@ class UpdateNodeRequest extends StoreNodeRequest
*/
public function rules(array $rules = null): array
{
$node = $this->route()->parameter('node')->id;
/** @var Node $node */
$node = $this->route()->parameter('node');
return parent::rules(Node::getRulesForUpdate($node));
return parent::rules(Node::getRulesForUpdate($node->id));
}
}

View file

@ -21,6 +21,7 @@ class StoreServerDatabaseRequest extends ApplicationApiRequest
*/
public function rules(): array
{
/** @var Server $server */
$server = $this->route()->parameter('server');
return [
@ -67,6 +68,7 @@ class StoreServerDatabaseRequest extends ApplicationApiRequest
*/
public function databaseName(): string
{
/** @var Server $server */
$server = $this->route()->parameter('server');
Assert::isInstanceOf($server, Server::class);

View file

@ -21,6 +21,7 @@ class StoreDatabaseRequest extends ClientApiRequest implements ClientPermissions
public function rules(): array
{
/** @var Server $server */
$server = $this->route()->parameter('server');
Assert::isInstanceOf($server, Server::class);

View file

@ -63,7 +63,6 @@ abstract class SubuserRequest extends ClientApiRequest
// Otherwise, get the current subuser's permission set, and ensure that the
// permissions they are trying to assign are not _more_ than the ones they
// already have.
/** @var \Pterodactyl\Models\Subuser|null $subuser */
/** @var \Pterodactyl\Services\Servers\GetUserPermissionsService $service */
$service = $this->container->make(GetUserPermissionsService::class);

View file

@ -26,9 +26,9 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
* @property string|null $startup
* @property bool $script_is_privileged
* @property string|null $script_install
* @property string $script_entry
* @property string $script_container
* @property int|null $copy_script_from
* @property ?string $script_entry
* @property ?string $script_container
* @property ?int $copy_script_from
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property string|null $copy_script_install

View file

@ -18,8 +18,9 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
* @property \Carbon\CarbonImmutable $created_at
* @property \Carbon\CarbonImmutable $updated_at
* @property bool $required
* @property \Pterodactyl\Models\Egg $egg
* @property \Pterodactyl\Models\ServerVariable $serverVariable
* @property Egg $egg
* @property ServerVariable $serverVariable
* @property string $field_type
*
* The "server_value" variable is only present on the object if you've loaded this model
* using the server relationship.

View file

@ -155,6 +155,7 @@ abstract class Model extends IlluminateModel
return;
}
/** @var \Illuminate\Validation\Validator $validator */
$validator = $this->getValidator();
$validator->setData(
// Trying to do self::toArray() here will leave out keys based on the whitelist/blacklist

View file

@ -6,6 +6,7 @@ use Illuminate\Support\Str;
use Symfony\Component\Yaml\Yaml;
use Illuminate\Container\Container;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Contracts\Encryption\Encrypter;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -24,20 +25,24 @@ use Illuminate\Database\Eloquent\Relations\HasManyThrough;
* @property bool $maintenance_mode
* @property int $memory
* @property int $memory_overallocate
* @property int $sum_memory
* @property int $disk
* @property int $disk_overallocate
* @property int $sum_disk
* @property int $upload_size
* @property string $daemon_token_id
* @property string $daemon_token
* @property int $daemonListen
* @property int $daemonSFTP
* @property string $daemonBase
* @property int $servers_count
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Pterodactyl\Models\Location $location
* @property \Pterodactyl\Models\Mount[]|\Illuminate\Database\Eloquent\Collection $mounts
* @property \Pterodactyl\Models\Server[]|\Illuminate\Database\Eloquent\Collection $servers
* @property \Pterodactyl\Models\Allocation[]|\Illuminate\Database\Eloquent\Collection $allocations
* @property Location $location
* @property int[]|\Illuminate\Support\Collection $ports
* @property Mount[]|Collection $mounts
* @property Server[]|Collection $servers
* @property Allocation[]|Collection $allocations
*/
class Node extends Model
{
@ -220,11 +225,21 @@ class Node extends Model
return $this->hasMany(Allocation::class);
}
public function loadServerSums(): self
{
$this->loadSum('servers as sum_memory', 'memory');
$this->loadSum('servers as sum_disk', 'disk');
return $this;
}
/**
* Returns a boolean if the node is viable for an additional server to be placed on it.
*/
public function isViable(int $memory, int $disk): bool
public function isViable(int $memory = 0, int $disk = 0): bool
{
$this->loadServerSums();
$memoryLimit = $this->memory * (1.0 + ($this->memory_overallocate / 100.0));
$diskLimit = $this->disk * (1.0 + ($this->disk_overallocate / 100.0));

View file

@ -2,6 +2,7 @@
namespace Pterodactyl\Models;
/** @property string $value */
class Setting extends Model
{
/**

View file

@ -11,6 +11,7 @@ use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Builder;
use Pterodactyl\Models\Traits\HasAccessTokens;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Pterodactyl\Traits\Helpers\AvailableLanguages;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\Access\Authorizable;
@ -129,6 +130,10 @@ class User extends Model implements
'root_admin',
];
protected $appends = [
'md5',
];
/**
* Cast values to correct type.
*/
@ -259,6 +264,13 @@ class User extends Model implements
return $this->morphToMany(ActivityLog::class, 'subject', 'activity_log_subjects');
}
public function md5(): Attribute
{
return Attribute::make(
get: fn () => md5(strtolower($this->email)),
);
}
/**
* Returns all the servers that a user can access by way of being the owner of the
* server, or because they are assigned as a subuser for that server.

View file

@ -26,12 +26,14 @@ class ServerInstalled extends Notification implements ShouldQueue, ReceivesEvent
* Handle a direct call to this notification from the server installed event. This is configured
* in the event service provider.
*/
public function handle(Event|Installed $event): void
public function handle(Event|Installed $notification): void
{
$event->server->loadMissing('user');
abort_unless($notification instanceof Installed, 500);
/* @var Installed $notification */
$notification->server->loadMissing('user');
$this->server = $event->server;
$this->user = $event->server->user;
$this->server = $notification->server;
$this->user = $notification->server->user;
// Since we are calling this notification directly from an event listener we need to fire off the dispatcher
// to send the email now. Don't use send() or you'll end up firing off two different events.

View file

@ -78,6 +78,7 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
*/
public function create(array $fields, bool $validate = true, bool $force = false): Model|bool
{
/** @var \Pterodactyl\Models\Model $instance */
$instance = $this->getBuilder()->newModelInstance();
($force) ? $instance->forceFill($fields) : $instance->fill($fields);
@ -163,6 +164,7 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
public function update(int $id, array $fields, bool $validate = true, bool $force = false): Model|bool
{
try {
/** @var \Pterodactyl\Models\Model $instance */
$instance = $this->getBuilder()->where('id', $id)->firstOrFail();
} catch (ModelNotFoundException) {
throw new RecordNotFoundException();

View file

@ -21,11 +21,7 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
*/
public function getUsageStats(Node $node): array
{
$stats = $this->getBuilder()
->selectRaw('COALESCE(SUM(servers.memory), 0) as sum_memory, COALESCE(SUM(servers.disk), 0) as sum_disk')
->join('servers', 'servers.node_id', '=', 'nodes.id')
->where('node_id', '=', $node->id)
->first();
$stats = $node->loadServerSums();
return Collection::make(['disk' => $stats->sum_disk, 'memory' => $stats->sum_memory])
->mapWithKeys(function ($value, $key) use ($node) {
@ -53,9 +49,7 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
*/
public function getUsageStatsRaw(Node $node): array
{
$stats = $this->getBuilder()->select(
$this->getBuilder()->raw('COALESCE(SUM(servers.memory), 0) as sum_memory, COALESCE(SUM(servers.disk), 0) as sum_disk')
)->join('servers', 'servers.node_id', '=', 'nodes.id')->where('node_id', $node->id)->first();
$stats = $node->loadServerSums();
return collect(['disk' => $stats->sum_disk, 'memory' => $stats->sum_memory])->mapWithKeys(function ($value, $key) use ($node) {
$maxUsage = $node->{$key};
@ -84,9 +78,7 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
// This is quite ugly and can probably be improved down the road.
// And by probably, I mean it should.
if (is_null($node->servers_count) || $refresh) {
$node->load('servers');
$node->setRelation('servers_count', count($node->getRelation('servers')));
unset($node->servers);
$node->loadCount('servers');
}
return $node;
@ -135,18 +127,4 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
];
})->values();
}
/**
* Returns a node with the given id with the Node's resource usage.
*/
public function getNodeWithResourceUsage(int $node_id): Node
{
$instance = $this->getBuilder()
->select(['nodes.id', 'nodes.fqdn', 'nodes.scheme', 'nodes.daemon_token', 'nodes.daemonListen', 'nodes.memory', 'nodes.disk', 'nodes.memory_overallocate', 'nodes.disk_overallocate'])
->selectRaw('COALESCE(SUM(servers.memory), 0) as sum_memory, COALESCE(SUM(servers.disk), 0) as sum_disk')
->leftJoin('servers', 'servers.node_id', '=', 'nodes.id')
->where('nodes.id', $node_id);
return $instance->first();
}
}

View file

@ -46,6 +46,7 @@ class SettingsRepository extends EloquentRepository implements SettingsRepositor
return value($default);
}
/** @var Setting $instance */
$instance = $this->getBuilder()->where('key', $key)->first();
if (is_null($instance)) {
self::$databaseMiss[$key] = true;

View file

@ -6,11 +6,11 @@ use Illuminate\Support\Arr;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Contracts\Validation\DataAwareRule;
class Fqdn implements Rule, DataAwareRule
final class Fqdn implements Rule, DataAwareRule
{
protected array $data = [];
protected string $message = '';
protected ?string $schemeField = null;
private array $data = [];
private string $message = '';
private ?string $schemeField = null;
/**
* @param array $data

View file

@ -40,23 +40,24 @@ class AssignmentService
*/
public function handle(Node $node, array $data): void
{
$explode = explode('/', $data['allocation_ip']);
$allocationIp = $data['allocation_ip'];
$explode = explode('/', $allocationIp);
if (count($explode) !== 1) {
if (!ctype_digit($explode[1]) || ($explode[1] > self::CIDR_MIN_BITS || $explode[1] < self::CIDR_MAX_BITS)) {
throw new CidrOutOfRangeException();
}
}
$underlying = 'Unknown IP';
try {
// TODO: how should we approach supporting IPv6 with this?
// gethostbyname only supports IPv4, but the alternative (dns_get_record) returns
// an array of records, which is not ideal for this use case, we need a SINGLE
// IP to use, not multiple.
$underlying = gethostbyname($data['allocation_ip']);
$underlying = gethostbyname($allocationIp);
$parsed = Network::parse($underlying);
} catch (Exception $exception) {
/* @noinspection PhpUndefinedVariableInspection */
throw new DisplayException("Could not parse provided allocation IP address ({$underlying}): {$exception->getMessage()}", $exception);
throw new DisplayException("Could not parse provided allocation IP address for $allocationIp ($underlying): {$exception->getMessage()}", $exception);
}
$this->connection->beginTransaction();

View file

@ -73,7 +73,10 @@ class DeleteBackupService
/** @var \Pterodactyl\Extensions\Filesystem\S3Filesystem $adapter */
$adapter = $this->manager->adapter(Backup::ADAPTER_AWS_S3);
$adapter->getClient()->deleteObject([
/** @var \Aws\S3\S3Client $client */
$client = $adapter->getClient();
$client->deleteObject([
'Bucket' => $adapter->getBucket(),
'Key' => sprintf('%s/%s.tar.gz', $backup->server->uuid, $backup->uuid),
]);

View file

@ -98,17 +98,17 @@ class InitiateBackupService
// Get the oldest backup the server has that is not "locked" (indicating a backup that should
// never be automatically purged). If we find a backup we will delete it and then continue with
// this process. If no backup is found that can be used an exception is thrown.
/** @var \Pterodactyl\Models\Backup $oldest */
$oldest = $successful->where('is_locked', false)->orderBy('created_at')->first();
if (!$oldest) {
throw new TooManyBackupsException($server->backup_limit);
}
/* @var Backup $oldest */
$this->deleteBackupService->handle($oldest);
}
return $this->connection->transaction(function () use ($server, $name) {
/** @var \Pterodactyl\Models\Backup $backup */
/** @var Backup $backup */
$backup = $this->repository->create([
'server_id' => $server->id,
'uuid' => Uuid::uuid4()->toString(),

View file

@ -119,6 +119,7 @@ class DatabaseManagementService
});
} catch (Exception $exception) {
try {
/** @var ?Database $database */
if ($database instanceof Database) {
$this->repository->dropDatabase($database->database);
$this->repository->dropUser($database->username, $database->remote);

View file

@ -78,7 +78,7 @@ class FindViableNodesService
->where('nodes.public', 1);
if (!empty($this->locations)) {
$query = $query->whereIn('nodes.location_id', $this->locations);
$query = $query->whereIn('location_id', $this->locations);
}
$results = $query->groupBy('nodes.id')

View file

@ -27,13 +27,13 @@ class ProcessScheduleService
*/
public function handle(Schedule $schedule, bool $now = false): void
{
/** @var \Pterodactyl\Models\Task $task */
$task = $schedule->tasks()->orderBy('sequence_id')->first();
if (is_null($task)) {
throw new DisplayException('Cannot process schedule for task execution: no tasks are registered.');
}
/* @var \Pterodactyl\Models\Task $task */
$this->connection->transaction(function () use ($schedule, $task) {
$schedule->forceFill([
'is_processing' => true,

View file

@ -88,14 +88,13 @@ class BuildModificationService
// Handle the addition of allocations to this server. Only assign allocations that are not currently
// assigned to a different server, and only allocations on the same node as the server.
if (!empty($data['add_allocations'])) {
$query = Allocation::query()
->where('node_id', $server->node_id)
$query = $server->node->allocations()
->whereIn('id', $data['add_allocations'])
->whereNull('server_id');
// Keep track of all the allocations we're just now adding so that we can use the first
// one to reset the default allocation to.
$freshlyAllocated = $query->pluck('id')->first();
$freshlyAllocated = $query->first()->id ?? null;
$query->update(['server_id' => $server->id, 'notes' => null]);
}

View file

@ -82,7 +82,7 @@ class ServerCreationService
//
// If that connection fails out we will attempt to perform a cleanup by just
// deleting the server itself from the system.
/** @var \Pterodactyl\Models\Server $server */
/** @var Server $server */
$server = $this->connection->transaction(function () use ($data, $eggVariableData) {
// Create the server and assign any additional allocations to it.
$server = $this->createModel($data);
@ -115,7 +115,7 @@ class ServerCreationService
*/
private function configureDeployment(array $data, DeploymentObject $deployment): Allocation
{
/** @var \Illuminate\Support\Collection $nodes */
/** @var Collection $nodes */
$nodes = $this->findViableNodesService->setLocations($deployment->getLocations())
->setDisk(Arr::get($data, 'disk'))
->setMemory(Arr::get($data, 'memory'))
@ -136,7 +136,7 @@ class ServerCreationService
{
$uuid = $this->generateUniqueUuidCombo();
/** @var \Pterodactyl\Models\Server $model */
/** @var Server $model */
$model = $this->repository->create([
'external_id' => Arr::get($data, 'external_id'),
'uuid' => $uuid,

View file

@ -25,7 +25,7 @@ class UserDeletionService
*
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function handle(int|User $user): ?bool
public function handle(int|User $user): void
{
if ($user instanceof User) {
$user = $user->id;
@ -36,6 +36,6 @@ class UserDeletionService
throw new DisplayException($this->translator->get('admin/user.exceptions.user_has_servers'));
}
return $this->repository->delete($user);
$this->repository->delete($user);
}
}

View file

@ -4,6 +4,7 @@ namespace Pterodactyl\Transformers\Api\Application;
use League\Fractal\Resource\Item;
use Pterodactyl\Models\EggVariable;
use Pterodactyl\Models\ServerVariable;
use League\Fractal\Resource\NullResource;
use Pterodactyl\Services\Acl\Api\AdminAcl;