Add phpstan for static analysis (#3718)

This commit is contained in:
Dane Everitt 2021-10-30 13:41:38 -07:00 committed by GitHub
parent 871d0bdd1c
commit cdd8eabcc0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
103 changed files with 1286 additions and 877 deletions

View file

@ -5,6 +5,7 @@ APP_THEME=pterodactyl
APP_TIMEZONE=America/Los_Angeles APP_TIMEZONE=America/Los_Angeles
APP_URL=http://localhost/ APP_URL=http://localhost/
DB_CONNECTION=testing
TESTING_DB_HOST=127.0.0.1 TESTING_DB_HOST=127.0.0.1
TESTING_DB_DATABASE=panel_test TESTING_DB_DATABASE=panel_test
TESTING_DB_USERNAME=root TESTING_DB_USERNAME=root

View file

@ -37,9 +37,7 @@ jobs:
path: | path: |
~/.php_cs.cache ~/.php_cs.cache
${{ steps.composer-cache.outputs.dir }} ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-cache-${{ matrix.php }}-${{ hashFiles('**.composer.lock') }} key: ${{ runner.os }}-cache-${{ matrix.php }}-${{ hashFiles('composer.lock') }}
restore-keys: |
${{ runner.os }}-cache-${{ matrix.php }}-
- name: Setup PHP - name: Setup PHP
uses: shivammathur/setup-php@v2 uses: shivammathur/setup-php@v2
with: with:
@ -52,16 +50,22 @@ jobs:
- name: composer install - name: composer install
run: composer install --prefer-dist --no-interaction --no-progress run: composer install --prefer-dist --no-interaction --no-progress
- name: Run cs-fixer - name: Run cs-fixer
run: vendor/bin/php-cs-fixer fix --dry-run --diff --diff-format=udiff --config .php-cs-fixer.dist.php run: vendor/bin/php-cs-fixer fix --dry-run --diff --format=txt --config .php-cs-fixer.dist.php
continue-on-error: true continue-on-error: true
- name: Static Analysis
if: ${{ matrix.php }} == '8.0'
run: |
php artisan ide-helper:models -N
./vendor/bin/phpstan analyse --memory-limit=2G
env:
TESTING_DB_PORT: ${{ job.services.database.ports[3306] }}
- name: Execute Unit Tests - name: Execute Unit Tests
run: php artisan test tests/Unit run: php artisan test tests/Unit
if: ${{ always() }} if: ${{ always() }}
env: env:
TESTING_DB_PORT: ${{ job.services.database.ports[3306] }} TESTING_DB_PORT: ${{ job.services.database.ports[3306] }}
TESTING_DB_USERNAME: root
- name: Execute Integration Tests - name: Execute Integration Tests
run: php artisan test tests/Integration run: php artisan test tests/Integration
if: ${{ always() }}
env: env:
TESTING_DB_PORT: ${{ job.services.database.ports[3306] }} TESTING_DB_PORT: ${{ job.services.database.ports[3306] }}
TESTING_DB_USERNAME: root

View file

@ -10,6 +10,9 @@ $finder = (new Finder())
'node_modules', 'node_modules',
'storage', 'storage',
'bootstrap/cache', 'bootstrap/cache',
'.phpstorm.meta.php',
'_ide_helper.php',
'_ide_helper_models.php',
]) ])
->notName(['_ide_helper*']); ->notName(['_ide_helper*']);

View file

@ -54,15 +54,15 @@ class InfoCommand extends Command
$this->output->title('Version Information'); $this->output->title('Version Information');
$this->table([], [ $this->table([], [
['Panel Version', $this->config->get('app.version')], ['Panel Version', $this->config->get('app.version')],
['Latest Version', $this->versionService->getPanel()], ['Latest Version', $this->versionService->getLatestPanel()],
['Up-to-Date', $this->versionService->isLatestPanel() ? 'Yes' : $this->formatText('No', 'bg=red')], ['Up-to-Date', $this->versionService->isLatestPanel() ? 'Yes' : $this->formatText('No', 'bg=red')],
['Unique Identifier', $this->config->get('pterodactyl.service.author')], ['Unique Identifier', $this->config->get('pterodactyl.service.author')],
], 'compact'); ], 'compact');
$this->output->title('Application Configuration'); $this->output->title('Application Configuration');
$this->table([], [ $this->table([], [
['Environment', $this->formatText($this->config->get('app.env'), $this->config->get('app.env') === 'production' ?: 'bg=red')], ['Environment', $this->formatText($this->config->get('app.env'), $this->config->get('app.env') === 'production' ? '' : 'bg=red')],
['Debug Mode', $this->formatText($this->config->get('app.debug') ? 'Yes' : 'No', !$this->config->get('app.debug') ?: 'bg=red')], ['Debug Mode', $this->formatText($this->config->get('app.debug') ? 'Yes' : 'No', !$this->config->get('app.debug') ? '' : 'bg=red')],
['Installation URL', $this->config->get('app.url')], ['Installation URL', $this->config->get('app.url')],
['Installation Directory', base_path()], ['Installation Directory', base_path()],
['Timezone', $this->config->get('app.timezone')], ['Timezone', $this->config->get('app.timezone')],

View file

@ -1,11 +1,4 @@
<?php <?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Console\Commands\Location; namespace Pterodactyl\Console\Commands\Location;
@ -26,9 +19,9 @@ class DeleteLocationCommand extends Command
protected $description = 'Deletes a location from the Panel.'; protected $description = 'Deletes a location from the Panel.';
/** /**
* @var \Illuminate\Support\Collection * @var \Illuminate\Support\Collection|null
*/ */
protected $locations; protected $locations = null;
/** /**
* @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface * @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface

View file

@ -13,14 +13,14 @@ class SeedCommand extends BaseSeedCommand
* Block someone from running this seed command if they have not completed * Block someone from running this seed command if they have not completed
* the migration process. * the migration process.
*/ */
public function handle() public function handle(): int
{ {
if (!$this->hasCompletedMigrations()) { if (!$this->hasCompletedMigrations()) {
$this->showMigrationWarning(); $this->showMigrationWarning();
return; return 1;
} }
parent::handle(); return parent::handle();
} }
} }

View file

@ -13,14 +13,14 @@ class UpCommand extends BaseUpCommand
* Block someone from running this up command if they have not completed * Block someone from running this up command if they have not completed
* the migration process. * the migration process.
*/ */
public function handle() public function handle(): int
{ {
if (!$this->hasCompletedMigrations()) { if (!$this->hasCompletedMigrations()) {
$this->showMigrationWarning(); $this->showMigrationWarning();
return; return 1;
} }
parent::handle(); return parent::handle();
} }
} }

View file

@ -24,7 +24,7 @@ class ProcessRunnableCommand extends Command
/** /**
* Handle command execution. * Handle command execution.
*/ */
public function handle() public function handle(): int
{ {
$schedules = Schedule::query()->with('tasks') $schedules = Schedule::query()->with('tasks')
->where('is_active', true) ->where('is_active', true)
@ -35,7 +35,7 @@ class ProcessRunnableCommand extends Command
if ($schedules->count() < 1) { if ($schedules->count() < 1) {
$this->line('There are no scheduled tasks for servers that need to be run.'); $this->line('There are no scheduled tasks for servers that need to be run.');
return; return 0;
} }
$bar = $this->output->createProgressBar(count($schedules)); $bar = $this->output->createProgressBar(count($schedules));
@ -47,6 +47,8 @@ class ProcessRunnableCommand extends Command
} }
$this->line(''); $this->line('');
return 0;
} }
/** /**
@ -69,7 +71,7 @@ class ProcessRunnableCommand extends Command
'schedule' => $schedule->name, 'schedule' => $schedule->name,
'hash' => $schedule->hashid, 'hash' => $schedule->hashid,
])); ]));
} catch (Throwable | Exception $exception) { } catch (Throwable|Exception $exception) {
Log::error($exception, ['schedule_id' => $schedule->id]); Log::error($exception, ['schedule_id' => $schedule->id]);
$this->error("An error was encountered while processing Schedule #{$schedule->id}: " . $exception->getMessage()); $this->error("An error was encountered while processing Schedule #{$schedule->id}: " . $exception->getMessage());

View file

@ -87,11 +87,12 @@ class UpgradeCommand extends Command
if (!$this->confirm('Are you sure you want to run the upgrade process for your Panel?')) { if (!$this->confirm('Are you sure you want to run the upgrade process for your Panel?')) {
$this->warn('Upgrade process terminated by user.'); $this->warn('Upgrade process terminated by user.');
return; return;
} }
} }
ini_set('output_buffering', 0); ini_set('output_buffering', '0');
$bar = $this->output->createProgressBar($skipDownload ? 9 : 10); $bar = $this->output->createProgressBar($skipDownload ? 9 : 10);
$bar->start(); $bar->start();

View file

@ -1,11 +1,4 @@
<?php <?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Console\Commands\User; namespace Pterodactyl\Console\Commands\User;
@ -47,11 +40,9 @@ class DeleteUserCommand extends Command
} }
/** /**
* @return bool
*
* @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\DisplayException
*/ */
public function handle() public function handle(): int
{ {
$search = $this->option('user') ?? $this->ask(trans('command/messages.user.search_users')); $search = $this->option('user') ?? $this->ask(trans('command/messages.user.search_users'));
Assert::notEmpty($search, 'Search term should be an email address, got: %s.'); Assert::notEmpty($search, 'Search term should be an email address, got: %s.');
@ -68,13 +59,13 @@ class DeleteUserCommand extends Command
return $this->handle(); return $this->handle();
} }
return false; return 1;
} }
if ($this->input->isInteractive()) { if ($this->input->isInteractive()) {
$tableValues = []; $tableValues = [];
foreach ($results as $user) { foreach ($results as $user) {
$tableValues[] = [$user->id, $user->email, $user->name]; $tableValues[] = [$user->id, $user->email, $user->name_first];
} }
$this->table(['User ID', 'Email', 'Name'], $tableValues); $this->table(['User ID', 'Email', 'Name'], $tableValues);
@ -85,7 +76,7 @@ class DeleteUserCommand extends Command
if (count($results) > 1) { if (count($results) > 1) {
$this->error(trans('command/messages.user.multiple_found')); $this->error(trans('command/messages.user.multiple_found'));
return false; return 1;
} }
$deleteUser = $results->first(); $deleteUser = $results->first();
@ -95,5 +86,7 @@ class DeleteUserCommand extends Command
$this->deletionService->handle($deleteUser); $this->deletionService->handle($deleteUser);
$this->info(trans('command/messages.user.deleted')); $this->info(trans('command/messages.user.deleted'));
} }
return 0;
} }
} }

View file

@ -62,7 +62,7 @@ class MakeUserCommand extends Command
['UUID', $user->uuid], ['UUID', $user->uuid],
['Email', $user->email], ['Email', $user->email],
['Username', $user->username], ['Username', $user->username],
['Name', $user->name], ['Name', $user->name_first],
['Admin', $user->root_admin ? 'Yes' : 'No'], ['Admin', $user->root_admin ? 'Yes' : 'No'],
]); ]);
} }

View file

@ -39,10 +39,8 @@ interface DatabaseRepositoryInterface extends RepositoryInterface
/** /**
* Create a new database user on a given connection. * Create a new database user on a given connection.
*
* @param $max_connections
*/ */
public function createUser(string $username, string $remote, string $password, string $max_connections): bool; public function createUser(string $username, string $remote, string $password, int $max_connections): bool;
/** /**
* Give a specific user access to a given database. * Give a specific user access to a given database.
@ -61,8 +59,6 @@ interface DatabaseRepositoryInterface extends RepositoryInterface
/** /**
* Drop a given user on a specific connection. * Drop a given user on a specific connection.
*
* @return mixed
*/ */
public function dropUser(string $username, string $remote): bool; public function dropUser(string $username, string $remote): bool;
} }

View file

@ -20,8 +20,6 @@ interface LocationRepositoryInterface extends RepositoryInterface
/** /**
* Return all of the nodes and their respective count of servers for a location. * Return all of the nodes and their respective count of servers for a location.
* *
* @return mixed
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function getWithNodes(int $id): Location; public function getWithNodes(int $id): Location;
@ -29,8 +27,6 @@ interface LocationRepositoryInterface extends RepositoryInterface
/** /**
* Return a location and the count of nodes in that location. * Return a location and the count of nodes in that location.
* *
* @return mixed
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function getWithNodeCount(int $id): Location; public function getWithNodeCount(int $id): Location;

View file

@ -1,11 +1,4 @@
<?php <?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Contracts\Repository; namespace Pterodactyl\Contracts\Repository;
@ -16,27 +9,7 @@ interface NestRepositoryInterface extends RepositoryInterface
/** /**
* Return a nest or all nests with their associated eggs and variables. * Return a nest or all nests with their associated eggs and variables.
* *
* @param int $id
*
* @return \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\Nest
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function getWithEggs(int $id = null); public function getWithEggs(int $id = null): Nest;
/**
* Return a nest or all nests and the count of eggs and servers for that nest.
*
* @return \Pterodactyl\Models\Nest|\Illuminate\Database\Eloquent\Collection
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithCounts(int $id = null);
/**
* Return a nest along with its associated eggs and the servers relation on those eggs.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithEggServers(int $id): Nest;
} }

View file

@ -21,20 +21,20 @@ class Fractal extends SpatieFractal
public function createData() public function createData()
{ {
// Set the serializer by default. // Set the serializer by default.
if (is_null($this->serializer)) { if (is_null($this->serializer)) { // @phpstan-ignore-line
$this->serializer = new PterodactylSerializer(); $this->serializer = new PterodactylSerializer();
} }
// Automatically set the paginator on the response object if the // Automatically set the paginator on the response object if the
// data being provided implements a paginator. // data being provided implements a paginator.
if (is_null($this->paginator) && $this->data instanceof LengthAwarePaginator) { if (is_null($this->paginator) && $this->data instanceof LengthAwarePaginator) { // @phpstan-ignore-line
$this->paginator = new IlluminatePaginatorAdapter($this->data); $this->paginator = new IlluminatePaginatorAdapter($this->data);
} }
// If the resource name is not set attempt to pull it off the transformer // If the resource name is not set attempt to pull it off the transformer
// itself and set it automatically. // itself and set it automatically.
$class = is_string($this->transformer) ? new $this->transformer() : $this->transformer; $class = is_string($this->transformer) ? new $this->transformer() : $this->transformer;
if (is_null($this->resourceName) && $class instanceof Transformer) { if (is_null($this->resourceName) && $class instanceof Transformer) { // @phpstan-ignore-line
$this->resourceName = $class->getResourceName(); $this->resourceName = $class->getResourceName();
} }

View file

@ -17,6 +17,6 @@ final class Time
{ {
$offset = round(CarbonImmutable::now($timezone)->getTimezone()->getOffset(CarbonImmutable::now('UTC')) / 3600); $offset = round(CarbonImmutable::now($timezone)->getTimezone()->getOffset(CarbonImmutable::now('UTC')) / 3600);
return sprintf('%s%s:00', $offset > 0 ? '+' : '-', str_pad(abs($offset), 2, '0', STR_PAD_LEFT)); return sprintf('%s%s:00', $offset > 0 ? '+' : '-', str_pad((string) abs($offset), 2, '0', STR_PAD_LEFT));
} }
} }

View file

@ -40,7 +40,7 @@ class DatabaseController extends ApplicationApiController
*/ */
public function index(GetDatabasesRequest $request): array public function index(GetDatabasesRequest $request): array
{ {
$perPage = $request->query('per_page', 10); $perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) { if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100); throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
} }

View file

@ -36,11 +36,12 @@ class EggController extends ApplicationApiController
*/ */
public function index(GetEggsRequest $request, Nest $nest): array public function index(GetEggsRequest $request, Nest $nest): array
{ {
$perPage = $request->query('per_page', 10); $perPage = (int) $request->query('per_page', '10');
if ($perPage > 100) { if ($perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100); throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
} }
// @phpstan-ignore-next-line
$eggs = QueryBuilder::for(Egg::query()) $eggs = QueryBuilder::for(Egg::query())
->where('nest_id', '=', $nest->id) ->where('nest_id', '=', $nest->id)
->allowedFilters(['id', 'name', 'author']) ->allowedFilters(['id', 'name', 'author'])

View file

@ -55,7 +55,7 @@ class EggVariableController extends ApplicationApiController
{ {
$validated = $request->validated(); $validated = $request->validated();
$this->connection->transaction(function () use($egg, $validated) { $this->connection->transaction(function () use ($egg, $validated) {
foreach ($validated as $data) { foreach ($validated as $data) {
$this->variableUpdateService->handle($egg, $data); $this->variableUpdateService->handle($egg, $data);
} }

View file

@ -46,7 +46,7 @@ class LocationController extends ApplicationApiController
*/ */
public function index(GetLocationsRequest $request): array public function index(GetLocationsRequest $request): array
{ {
$perPage = $request->query('per_page', 10); $perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) { if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100); throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
} }

View file

@ -34,7 +34,7 @@ class MountController extends ApplicationApiController
*/ */
public function index(GetMountsRequest $request): array public function index(GetMountsRequest $request): array
{ {
$perPage = $request->query('per_page', 10); $perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) { if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100); throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
} }

View file

@ -13,8 +13,8 @@ use Pterodactyl\Transformers\Api\Application\EggTransformer;
use Pterodactyl\Transformers\Api\Application\NestTransformer; use Pterodactyl\Transformers\Api\Application\NestTransformer;
use Pterodactyl\Exceptions\Http\QueryValueOutOfRangeHttpException; use Pterodactyl\Exceptions\Http\QueryValueOutOfRangeHttpException;
use Pterodactyl\Http\Requests\Api\Application\Nests\GetNestRequest; use Pterodactyl\Http\Requests\Api\Application\Nests\GetNestRequest;
use Pterodactyl\Http\Requests\Api\Application\Nests\GetNestsRequest;
use Pterodactyl\Http\Requests\Api\Application\Eggs\ImportEggRequest; use Pterodactyl\Http\Requests\Api\Application\Eggs\ImportEggRequest;
use Pterodactyl\Http\Requests\Api\Application\Nests\GetNestsRequest;
use Pterodactyl\Http\Requests\Api\Application\Nests\StoreNestRequest; use Pterodactyl\Http\Requests\Api\Application\Nests\StoreNestRequest;
use Pterodactyl\Http\Requests\Api\Application\Nests\DeleteNestRequest; use Pterodactyl\Http\Requests\Api\Application\Nests\DeleteNestRequest;
use Pterodactyl\Http\Requests\Api\Application\Nests\UpdateNestRequest; use Pterodactyl\Http\Requests\Api\Application\Nests\UpdateNestRequest;
@ -51,7 +51,7 @@ class NestController extends ApplicationApiController
*/ */
public function index(GetNestsRequest $request): array public function index(GetNestsRequest $request): array
{ {
$perPage = $request->query('per_page', 10); $perPage = (int) $request->query('per_page', '10');
if ($perPage > 100) { if ($perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100); throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
} }

View file

@ -42,7 +42,7 @@ class AllocationController extends ApplicationApiController
*/ */
public function index(GetAllocationsRequest $request, Node $node): array public function index(GetAllocationsRequest $request, Node $node): array
{ {
$perPage = $request->query('per_page', 10); $perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) { if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100); throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
} }

View file

@ -50,7 +50,7 @@ class NodeController extends ApplicationApiController
*/ */
public function index(GetNodesRequest $request): array public function index(GetNodesRequest $request): array
{ {
$perPage = $request->query('per_page', 10); $perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) { if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100); throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
} }

View file

@ -35,7 +35,7 @@ class NodeDeploymentController extends ApplicationApiController
$nodes = $this->viableNodesService->setLocations($data['location_ids'] ?? []) $nodes = $this->viableNodesService->setLocations($data['location_ids'] ?? [])
->setMemory($data['memory']) ->setMemory($data['memory'])
->setDisk($data['disk']) ->setDisk($data['disk'])
->handle($request->query('per_page'), $request->query('page')); ->handle($request->query('per_page'), $request->query('page')); // @phpstan-ignore-line
return $this->fractal->collection($nodes) return $this->fractal->collection($nodes)
->transformWith(NodeTransformer::class) ->transformWith(NodeTransformer::class)

View file

@ -32,7 +32,7 @@ class RoleController extends ApplicationApiController
*/ */
public function index(GetRolesRequest $request): array public function index(GetRolesRequest $request): array
{ {
$perPage = $request->query('per_page', 10); $perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) { if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100); throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
} }

View file

@ -52,7 +52,7 @@ class ServerController extends ApplicationApiController
*/ */
public function index(GetServersRequest $request): array public function index(GetServersRequest $request): array
{ {
$perPage = $request->query('per_page', 10); $perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) { if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100); throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
} }

View file

@ -52,7 +52,7 @@ class UserController extends ApplicationApiController
*/ */
public function index(GetUsersRequest $request): array public function index(GetUsersRequest $request): array
{ {
$perPage = $request->query('per_page', 10); $perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) { if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100); throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
} }

View file

@ -15,7 +15,7 @@ class AccountController extends ClientApiController
private UserUpdateService $updateService; private UserUpdateService $updateService;
/** /**
* @var \Illuminate\Auth\SessionGuard * @var \Illuminate\Auth\AuthManager
*/ */
private $sessionGuard; private $sessionGuard;
@ -64,7 +64,9 @@ class AccountController extends ClientApiController
// cached copy of the user that does not include the updated password. Do this // cached copy of the user that does not include the updated password. Do this
// to correctly store the new user details in the guard and allow the logout // to correctly store the new user details in the guard and allow the logout
// other devices functionality to work. // other devices functionality to work.
$this->sessionGuard->setUser($user); if (method_exists($this->sessionGuard, 'setUser')) {
$this->sessionGuard->setUser($user);
}
// TODO: Find another way to do this, function doesn't exist due to API changes. // TODO: Find another way to do this, function doesn't exist due to API changes.
//$this->sessionGuard->logoutOtherDevices($request->input('password')); //$this->sessionGuard->logoutOtherDevices($request->input('password'));

View file

@ -66,7 +66,7 @@ class ClientController extends ClientApiController
$builder = $builder->whereIn('servers.id', $user->accessibleServers()->pluck('id')->all()); $builder = $builder->whereIn('servers.id', $user->accessibleServers()->pluck('id')->all());
} }
$servers = $builder->paginate(min($request->query('per_page', 50), 100))->appends($request->query()); $servers = $builder->paginate(min((int) $request->query('per_page', '50'), 100))->appends($request->query());
return $this->fractal->transformWith(new ServerTransformer())->collection($servers)->toArray(); return $this->fractal->transformWith(new ServerTransformer())->collection($servers)->toArray();
} }

View file

@ -61,7 +61,6 @@ class StartupController extends ClientApiController
*/ */
public function update(UpdateStartupVariableRequest $request, Server $server): array public function update(UpdateStartupVariableRequest $request, Server $server): array
{ {
/** @var \Pterodactyl\Models\EggVariable $variable */
$variable = $server->variables()->where('env_variable', $request->input('key'))->first(); $variable = $server->variables()->where('env_variable', $request->input('key'))->first();
if (is_null($variable) || !$variable->user_viewable) { if (is_null($variable) || !$variable->user_viewable) {

View file

@ -87,8 +87,6 @@ class WebauthnController extends ClientApiController
$request->input('name'), $request->input('name'),
); );
return $this->fractal->item($webauthnKey) return $this->fractal->item($webauthnKey)
->transformWith(WebauthnKeyTransformer::class) ->transformWith(WebauthnKeyTransformer::class)
->toArray(); ->toArray();

View file

@ -91,9 +91,6 @@ abstract class AbstractLoginController extends Controller
/** /**
* Determine if the user is logging in using an email or username,. * Determine if the user is logging in using an email or username,.
*
* @param string|null $input
* @return string
*/ */
protected function getField(string $input = null): string protected function getField(string $input = null): string
{ {

View file

@ -16,7 +16,6 @@ class ForgotPasswordController extends Controller
/** /**
* Get the response for a failed password reset link. * Get the response for a failed password reset link.
* *
* @param \Illuminate\Http\Request
* @param string $response * @param string $response
*/ */
protected function sendResetLinkFailedResponse(Request $request, $response): JsonResponse protected function sendResetLinkFailedResponse(Request $request, $response): JsonResponse

View file

@ -2,8 +2,8 @@
namespace Pterodactyl\Http\Controllers\Auth; namespace Pterodactyl\Http\Controllers\Auth;
use Carbon\CarbonInterface;
use Carbon\CarbonImmutable; use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use Pterodactyl\Models\User; use Pterodactyl\Models\User;
use PragmaRX\Google2FA\Google2FA; use PragmaRX\Google2FA\Google2FA;
use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Contracts\Encryption\Encrypter;
@ -50,17 +50,20 @@ class LoginCheckpointController extends AbstractLoginController
{ {
if ($this->hasTooManyLoginAttempts($request)) { if ($this->hasTooManyLoginAttempts($request)) {
$this->sendLockoutResponse($request); $this->sendLockoutResponse($request);
return; return;
} }
$details = $request->session()->get('auth_confirmation_token'); $details = $request->session()->get('auth_confirmation_token');
if (!$this->hasValidSessionData($details)) { if (!$this->hasValidSessionData($details)) {
$this->sendFailedLoginResponse($request, null, self::TOKEN_EXPIRED_MESSAGE); $this->sendFailedLoginResponse($request, null, self::TOKEN_EXPIRED_MESSAGE);
return; return;
} }
if (!hash_equals($request->input('confirmation_token') ?? '', $details['token_value'])) { if (!hash_equals($request->input('confirmation_token') ?? '', $details['token_value'])) {
$this->sendFailedLoginResponse($request); $this->sendFailedLoginResponse($request);
return; return;
} }
@ -69,6 +72,7 @@ class LoginCheckpointController extends AbstractLoginController
$user = User::query()->findOrFail($details['user_id']); $user = User::query()->findOrFail($details['user_id']);
} catch (ModelNotFoundException $exception) { } catch (ModelNotFoundException $exception) {
$this->sendFailedLoginResponse($request, null, self::TOKEN_EXPIRED_MESSAGE); $this->sendFailedLoginResponse($request, null, self::TOKEN_EXPIRED_MESSAGE);
return; return;
} }
@ -91,8 +95,6 @@ class LoginCheckpointController extends AbstractLoginController
/** /**
* Determines if a given recovery token is valid for the user account. If we find a matching token * Determines if a given recovery token is valid for the user account. If we find a matching token
* it will be deleted from the database. * it will be deleted from the database.
*
* @return bool
*/ */
protected function isValidRecoveryToken(User $user, string $value): bool protected function isValidRecoveryToken(User $user, string $value): bool
{ {
@ -116,9 +118,6 @@ class LoginCheckpointController extends AbstractLoginController
* Determines if the data provided from the session is valid or not. This * Determines if the data provided from the session is valid or not. This
* will return false if the data is invalid, or if more time has passed than * will return false if the data is invalid, or if more time has passed than
* was configured when the session was written. * was configured when the session was written.
*
* @param array $data
* @return bool
*/ */
public static function isValidSessionData(ValidationFactory $validation, array $data): bool public static function isValidSessionData(ValidationFactory $validation, array $data): bool
{ {

View file

@ -10,7 +10,6 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use LaravelWebauthn\Facades\Webauthn; use LaravelWebauthn\Facades\Webauthn;
use Illuminate\Contracts\View\Factory as ViewFactory; use Illuminate\Contracts\View\Factory as ViewFactory;
use Illuminate\Database\Eloquent\ModelNotFoundException;
class LoginController extends AbstractLoginController class LoginController extends AbstractLoginController
{ {
@ -24,7 +23,8 @@ class LoginController extends AbstractLoginController
/** /**
* LoginController constructor. * LoginController constructor.
*/ */
public function __construct(ViewFactory $view) { public function __construct(ViewFactory $view)
{
parent::__construct(); parent::__construct();
$this->view = $view; $this->view = $view;
@ -57,12 +57,11 @@ class LoginController extends AbstractLoginController
return; return;
} }
try { $username = $request->input('user');
$username = $request->input('user');
/** @var \Pterodactyl\Models\User $user */ /** @var \Pterodactyl\Models\User|null $user */
$user = User::query()->where($this->getField($username), $username)->firstOrFail(); $user = User::query()->where($this->getField($username), $username)->first();
} catch (ModelNotFoundException $exception) { if (is_null($user)) {
$this->sendFailedLoginResponse($request); $this->sendFailedLoginResponse($request);
} }

View file

@ -87,7 +87,7 @@ class ResetPasswordController extends Controller
* account do not automatically log them in. In those cases, send the user back to the login * 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. * 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 \Pterodactyl\Models\User $user
* @param string $password * @param string $password
* *
* @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Model\DataValidationException

View file

@ -38,17 +38,20 @@ class WebauthnController extends AbstractLoginController
{ {
if ($this->hasTooManyLoginAttempts($request)) { if ($this->hasTooManyLoginAttempts($request)) {
$this->sendLockoutResponse($request); $this->sendLockoutResponse($request);
return; return;
} }
$details = $request->session()->get('auth_confirmation_token'); $details = $request->session()->get('auth_confirmation_token');
if (!LoginCheckpointController::isValidSessionData($this->validation, $details)) { if (!LoginCheckpointController::isValidSessionData($this->validation, $details)) {
$this->sendFailedLoginResponse($request, null, LoginCheckpointController::TOKEN_EXPIRED_MESSAGE); $this->sendFailedLoginResponse($request, null, LoginCheckpointController::TOKEN_EXPIRED_MESSAGE);
return; return;
} }
if (!hash_equals($request->input('confirmation_token') ?? '', $details['token_value'])) { if (!hash_equals($request->input('confirmation_token') ?? '', $details['token_value'])) {
$this->sendFailedLoginResponse($request); $this->sendFailedLoginResponse($request);
return; return;
} }
@ -57,6 +60,7 @@ class WebauthnController extends AbstractLoginController
$user = User::query()->findOrFail($details['user_id']); $user = User::query()->findOrFail($details['user_id']);
} catch (ModelNotFoundException $exception) { } catch (ModelNotFoundException $exception) {
$this->sendFailedLoginResponse($request, null, LoginCheckpointController::TOKEN_EXPIRED_MESSAGE); $this->sendFailedLoginResponse($request, null, LoginCheckpointController::TOKEN_EXPIRED_MESSAGE);
return; return;
} }

View file

@ -109,7 +109,5 @@ class Kernel extends HttpKernel
'bindings' => SubstituteBindings::class, 'bindings' => SubstituteBindings::class,
'recaptcha' => VerifyReCaptcha::class, 'recaptcha' => VerifyReCaptcha::class,
'node.maintenance' => MaintenanceMiddleware::class, 'node.maintenance' => MaintenanceMiddleware::class,
// API Specific Middleware
'api..key' => AuthenticateKey::class,
]; ];
} }

View file

@ -54,7 +54,7 @@ class SubstituteApplicationApiBindings
try { try {
$this->router->substituteImplicitBindings($route = $request->route()); $this->router->substituteImplicitBindings($route = $request->route());
} catch (ModelNotFoundException $exception) { } catch (ModelNotFoundException $exception) {
if (isset($route) && $route->getMissing()) { if (!empty($route) && $route->getMissing()) {
$route->getMissing()($request); $route->getMissing()($request);
} }

View file

@ -25,7 +25,7 @@ class SubstituteClientApiBindings
/** /**
* Perform substitution of route parameters for the Client API. * Perform substitution of route parameters for the Client API.
* *
* @param \Illuminate\Http\Request * @param \Illuminate\Http\Request $request
* *
* @return mixed * @return mixed
*/ */
@ -76,7 +76,7 @@ class SubstituteClientApiBindings
/* @var \Illuminate\Routing\Route $route */ /* @var \Illuminate\Routing\Route $route */
$this->router->substituteBindings($route = $request->route()); $this->router->substituteBindings($route = $request->route());
} catch (ModelNotFoundException $exception) { } catch (ModelNotFoundException $exception) {
if (isset($route) && $route->getMissing()) { if (!empty($route) && $route->getMissing()) {
$route->getMissing()($request); $route->getMissing()($request);
} }

View file

@ -41,7 +41,7 @@ class RequireTwoFactorAuthentication
*/ */
public function handle(Request $request, Closure $next) public function handle(Request $request, Closure $next)
{ {
/** @var \Pterodactyl\Models\User $user */ /** @var \Pterodactyl\Models\User|null $user */
$user = $request->user(); $user = $request->user();
$uri = rtrim($request->getRequestUri(), '/') . '/'; $uri = rtrim($request->getRequestUri(), '/') . '/';
$current = $request->route()->getName(); $current = $request->route()->getName();
@ -66,6 +66,7 @@ class RequireTwoFactorAuthentication
throw new TwoFactorAuthRequiredException(); throw new TwoFactorAuthRequiredException();
} }
// @phpstan-ignore-next-line
$this->alert->danger(trans('auth.2fa_must_be_enabled'))->flash(); $this->alert->danger(trans('auth.2fa_must_be_enabled'))->flash();
return redirect()->to($this->redirectRoute); return redirect()->to($this->redirectRoute);

View file

@ -3,7 +3,6 @@
namespace Pterodactyl\Http\Requests\Api\Application\Eggs\Variables; namespace Pterodactyl\Http\Requests\Api\Application\Eggs\Variables;
use Pterodactyl\Models\EggVariable; use Pterodactyl\Models\EggVariable;
use Illuminate\Validation\Validator;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class UpdateEggVariablesRequest extends ApplicationApiRequest class UpdateEggVariablesRequest extends ApplicationApiRequest

View file

@ -3,9 +3,6 @@
namespace Pterodactyl\Http\Requests\Api\Application\Servers; namespace Pterodactyl\Http\Requests\Api\Application\Servers;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Illuminate\Validation\Rule;
use Illuminate\Contracts\Validation\Validator;
use Pterodactyl\Models\Objects\DeploymentObject;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class StoreServerRequest extends ApplicationApiRequest class StoreServerRequest extends ApplicationApiRequest

View file

@ -65,8 +65,6 @@ abstract class SubuserRequest extends ClientApiRequest
// Otherwise, get the current subuser's permission set, and ensure that the // 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 // permissions they are trying to assign are not _more_ than the ones they
// already have. // already have.
/** @var \Pterodactyl\Models\Subuser|null $subuser */
/** @var \Pterodactyl\Services\Servers\GetUserPermissionsService $service */
$service = $this->container->make(GetUserPermissionsService::class); $service = $this->container->make(GetUserPermissionsService::class);
if (count(array_diff($permissions, $service->handle($server, $user))) > 0) { if (count(array_diff($permissions, $service->handle($server, $user))) > 0) {

View file

@ -101,7 +101,7 @@ class AuditLog extends Model
* currently authenticated user if available. This model is not saved at this point, so * currently authenticated user if available. This model is not saved at this point, so
* you can always make modifications to it as needed before saving. * you can always make modifications to it as needed before saving.
* *
* @return $this * @return self
*/ */
public static function instance(string $action, array $metadata, bool $isSystem = false) public static function instance(string $action, array $metadata, bool $isSystem = false)
{ {

View file

@ -2,17 +2,6 @@
namespace Pterodactyl\Models; namespace Pterodactyl\Models;
/**
* @property int $id
* @property string $name
* @property string $host
* @property int $port
* @property string $username
* @property string $password
* @property int|null $max_databases
* @property \Carbon\CarbonImmutable $created_at
* @property \Carbon\CarbonImmutable $updated_at
*/
class DatabaseHost extends Model class DatabaseHost extends Model
{ {
/** /**

View file

@ -2,44 +2,6 @@
namespace Pterodactyl\Models; namespace Pterodactyl\Models;
/**
* @property int $id
* @property string $uuid
* @property int $nest_id
* @property string $author
* @property string $name
* @property string|null $description
* @property array|null $features
* @property string $docker_image -- deprecated, use $docker_images
* @property string $update_url
* @property array $docker_images
* @property array|null $file_denylist
* @property string|null $config_files
* @property string|null $config_startup
* @property string|null $config_stop
* @property int|null $config_from
* @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 \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property string|null $copy_script_install
* @property string $copy_script_entry
* @property string $copy_script_container
* @property string|null $inherit_config_files
* @property string|null $inherit_config_startup
* @property string|null $inherit_config_stop
* @property string $inherit_file_denylist
* @property array|null $inherit_features
* @property \Pterodactyl\Models\Nest $nest
* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\Server[] $servers
* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\EggVariable[] $variables
* @property \Pterodactyl\Models\Egg|null $scriptFrom
* @property \Pterodactyl\Models\Egg|null $configFrom
*/
class Egg extends Model class Egg extends Model
{ {
/** /**
@ -162,10 +124,12 @@ class Egg extends Model
*/ */
public function getCopyScriptEntryAttribute() public function getCopyScriptEntryAttribute()
{ {
// @phpstan-ignore-next-line
if (!is_null($this->script_entry) || is_null($this->copy_script_from)) { if (!is_null($this->script_entry) || is_null($this->copy_script_from)) {
return $this->script_entry; return $this->script_entry;
} }
// @phpstan-ignore-next-line
return $this->scriptFrom->script_entry; return $this->scriptFrom->script_entry;
} }
@ -177,10 +141,12 @@ class Egg extends Model
*/ */
public function getCopyScriptContainerAttribute() public function getCopyScriptContainerAttribute()
{ {
// @phpstan-ignore-next-line
if (!is_null($this->script_container) || is_null($this->copy_script_from)) { if (!is_null($this->script_container) || is_null($this->copy_script_from)) {
return $this->script_container; return $this->script_container;
} }
// @phpstan-ignore-next-line
return $this->scriptFrom->script_container; return $this->scriptFrom->script_container;
} }

View file

@ -2,25 +2,6 @@
namespace Pterodactyl\Models; namespace Pterodactyl\Models;
/**
* @property int $id
* @property int $egg_id
* @property string $name
* @property string $description
* @property string $env_variable
* @property string $default_value
* @property bool $user_viewable
* @property bool $user_editable
* @property string $rules
* @property \Carbon\CarbonImmutable $created_at
* @property \Carbon\CarbonImmutable $updated_at
* @property \Pterodactyl\Models\Egg $egg
* @property \Pterodactyl\Models\ServerVariable $serverVariable
*
* The "server_value" variable is only present on the object if you've loaded this model
* using the server relationship.
* @property string|null $server_value
*/
class EggVariable extends Model class EggVariable extends Model
{ {
/** /**

View file

@ -48,6 +48,7 @@ class MultiFieldServerFilter implements Filter
} }
}, },
// Otherwise, just try to search for that specific port in the allocations. // Otherwise, just try to search for that specific port in the allocations.
// @phpstan-ignore-next-line
function (Builder $builder) use ($value) { function (Builder $builder) use ($value) {
$builder->orWhere('allocations.port', 'LIKE', substr($value, 1) . '%'); $builder->orWhere('allocations.port', 'LIKE', substr($value, 1) . '%');
} }

View file

@ -23,22 +23,15 @@ abstract class Model extends IlluminateModel
/** /**
* Determines if the model should undergo data validation before it is saved * Determines if the model should undergo data validation before it is saved
* to the database. * to the database.
*
* @var bool
*/ */
protected $skipValidation = false; protected bool $skipValidation = false;
/** /**
* The validator instance used by this model. * The validator instance used by this model.
*
* @var \Illuminate\Validation\Validator
*/ */
protected $validator; protected ?Validator $validator = null;
/** protected static Factory $validatorFactory;
* @var \Illuminate\Contracts\Validation\Factory
*/
protected static $validatorFactory;
public static array $validationRules = []; public static array $validationRules = [];
@ -82,6 +75,7 @@ abstract class Model extends IlluminateModel
{ {
$rules = $this->getKey() ? static::getRulesForUpdate($this) : static::getRules(); $rules = $this->getKey() ? static::getRulesForUpdate($this) : static::getRules();
// @phpstan-ignore-next-line
return $this->validator ?: $this->validator = static::$validatorFactory->make( return $this->validator ?: $this->validator = static::$validatorFactory->make(
[], [],
$rules, $rules,

View file

@ -8,38 +8,6 @@ use Illuminate\Container\Container;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Contracts\Encryption\Encrypter;
/**
* @property int $id
* @property string $uuid
* @property bool $public
* @property string $name
* @property string|null $description
* @property int $location_id
* @property int|null $database_host_id
* @property string $fqdn
* @property int $listen_port_http
* @property int $public_port_http
* @property int $listen_port_sftp
* @property int $public_port_sftp
* @property string $scheme
* @property bool $behind_proxy
* @property bool $maintenance_mode
* @property int $memory
* @property int $memory_overallocate
* @property int $disk
* @property int $disk_overallocate
* @property int $upload_size
* @property string $daemon_token_id
* @property string $daemon_token
* @property string $daemon_base
* @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 \Pterodactyl\Models\DatabaseHost $databaseHost
*/
class Node extends Model class Node extends Model
{ {
use Notifiable; use Notifiable;
@ -275,6 +243,7 @@ class Node extends Model
$memoryLimit = $this->memory * (1 + ($this->memory_overallocate / 100)); $memoryLimit = $this->memory * (1 + ($this->memory_overallocate / 100));
$diskLimit = $this->disk * (1 + ($this->disk_overallocate / 100)); $diskLimit = $this->disk * (1 + ($this->disk_overallocate / 100));
// @phpstan-ignore-next-line
return ($this->sum_memory + $memory) <= $memoryLimit && ($this->sum_disk + $disk) <= $diskLimit; return ($this->sum_memory + $memory) <= $memoryLimit && ($this->sum_disk + $disk) <= $diskLimit;
} }
} }

View file

@ -213,7 +213,7 @@ class Permission extends Model
* Returns all of the permissions available on the system for a user to * Returns all of the permissions available on the system for a user to
* have when controlling a server. * have when controlling a server.
* *
* @return \Illuminate\Database\Eloquent\Collection * @phpstan-return \Illuminate\Support\Collection<string, array{description: string, keys: array<string, string>}>
*/ */
public static function permissions(): Collection public static function permissions(): Collection
{ {

View file

@ -8,50 +8,6 @@ use Illuminate\Database\Query\JoinClause;
use Znck\Eloquent\Traits\BelongsToThrough; use Znck\Eloquent\Traits\BelongsToThrough;
use Pterodactyl\Exceptions\Http\Server\ServerStateConflictException; use Pterodactyl\Exceptions\Http\Server\ServerStateConflictException;
/**
* @property int $id
* @property string|null $external_id
* @property string $uuid
* @property string $uuidShort
* @property int $node_id
* @property string $name
* @property string $description
* @property string|null $status
* @property bool $skip_scripts
* @property int $owner_id
* @property int $memory
* @property int $swap
* @property int $disk
* @property int $io
* @property int $cpu
* @property string $threads
* @property bool $oom_disabled
* @property int $allocation_id
* @property int $nest_id
* @property int $egg_id
* @property string $startup
* @property string $image
* @property int $allocation_limit
* @property int $database_limit
* @property int $backup_limit
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Pterodactyl\Models\User $user
* @property \Pterodactyl\Models\Subuser[]|\Illuminate\Database\Eloquent\Collection $subusers
* @property \Pterodactyl\Models\Allocation $allocation
* @property \Pterodactyl\Models\Allocation[]|\Illuminate\Database\Eloquent\Collection $allocations
* @property \Pterodactyl\Models\Node $node
* @property \Pterodactyl\Models\Nest $nest
* @property \Pterodactyl\Models\Egg $egg
* @property \Pterodactyl\Models\EggVariable[]|\Illuminate\Database\Eloquent\Collection $variables
* @property \Pterodactyl\Models\Schedule[]|\Illuminate\Database\Eloquent\Collection $schedule
* @property \Pterodactyl\Models\Database[]|\Illuminate\Database\Eloquent\Collection $databases
* @property \Pterodactyl\Models\Location $location
* @property \Pterodactyl\Models\ServerTransfer $transfer
* @property \Pterodactyl\Models\Backup[]|\Illuminate\Database\Eloquent\Collection $backups
* @property \Pterodactyl\Models\Mount[]|\Illuminate\Database\Eloquent\Collection $mounts
* @property \Pterodactyl\Models\AuditLog[] $audits
*/
class Server extends Model class Server extends Model
{ {
use BelongsToThrough; use BelongsToThrough;
@ -239,6 +195,7 @@ class Server extends Model
* Gets information for the service variables associated with this server. * Gets information for the service variables associated with this server.
* *
* @return \Illuminate\Database\Eloquent\Relations\HasMany * @return \Illuminate\Database\Eloquent\Relations\HasMany
* @phpstan-return \Illuminate\Database\Eloquent\Relations\HasMany<\Pterodactyl\Models\EggVariable>
*/ */
public function variables() public function variables()
{ {

View file

@ -58,7 +58,7 @@ class AccountCreated extends Notification implements ShouldQueue
public function toMail($notifiable) public function toMail($notifiable)
{ {
$message = (new MailMessage()) $message = (new MailMessage())
->greeting('Hello ' . $this->user->name . '!') ->greeting('Hello ' . $this->user->name_first . '!')
->line('You are receiving this email because an account has been created for you on ' . config('app.name') . '.') ->line('You are receiving this email because an account has been created for you on ' . config('app.name') . '.')
->line('Username: ' . $this->user->username) ->line('Username: ' . $this->user->username)
->line('Email: ' . $this->user->email); ->line('Email: ' . $this->user->email);

View file

@ -27,7 +27,7 @@ class MailTested extends Notification
{ {
return (new MailMessage()) return (new MailMessage())
->subject('Pterodactyl Test Message') ->subject('Pterodactyl Test Message')
->greeting('Hello ' . $this->user->name . '!') ->greeting('Hello ' . $this->user->name_first . '!')
->line('This is a test of the Pterodactyl mail system. You\'re good to go!'); ->line('This is a test of the Pterodactyl mail system. You\'re good to go!');
} }
} }

View file

@ -2,6 +2,7 @@
namespace Pterodactyl\Notifications; namespace Pterodactyl\Notifications;
use Webmozart\Assert\Assert;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Pterodactyl\Events\Event; use Pterodactyl\Events\Event;
use Illuminate\Container\Container; use Illuminate\Container\Container;
@ -33,6 +34,8 @@ class ServerInstalled extends Notification implements ShouldQueue, ReceivesEvent
*/ */
public function handle(Event $event): void public function handle(Event $event): void
{ {
Assert::propertyExists($event, 'server');
$event->server->loadMissing('user'); $event->server->loadMissing('user');
$this->server = $event->server; $this->server = $event->server;

View file

@ -20,10 +20,12 @@ class BackupRepository extends EloquentRepository
/** /**
* Determines if too many backups have been generated by the server. * Determines if too many backups have been generated by the server.
* *
* @return \Pterodactyl\Models\Backup[]|\Illuminate\Support\Collection * @return \Illuminate\Support\Collection
* @phpstan-return \Illuminate\Support\Collection<\Pterodactyl\Models\Backup>
*/ */
public function getBackupsGeneratedDuringTimespan(int $server, int $seconds = 600) public function getBackupsGeneratedDuringTimespan(int $server, int $seconds = 600)
{ {
// @phpstan-ignore-next-line
return $this->getBuilder() return $this->getBuilder()
->withTrashed() ->withTrashed()
->where('server_id', $server) ->where('server_id', $server)

View file

@ -89,10 +89,8 @@ class DatabaseRepository extends EloquentRepository implements DatabaseRepositor
/** /**
* Create a new database user on a given connection. * Create a new database user on a given connection.
*
* @param $max_connections
*/ */
public function createUser(string $username, string $remote, string $password, $max_connections): bool public function createUser(string $username, string $remote, string $password, int $max_connections): bool
{ {
if (!$max_connections) { if (!$max_connections) {
return $this->run(sprintf('CREATE USER `%s`@`%s` IDENTIFIED BY \'%s\'', $username, $remote, $password)); return $this->run(sprintf('CREATE USER `%s`@`%s` IDENTIFIED BY \'%s\'', $username, $remote, $password));
@ -132,8 +130,6 @@ class DatabaseRepository extends EloquentRepository implements DatabaseRepositor
/** /**
* Drop a given user on a specific connection. * Drop a given user on a specific connection.
*
* @return mixed
*/ */
public function dropUser(string $username, string $remote): bool public function dropUser(string $username, string $remote): bool
{ {

View file

@ -29,6 +29,8 @@ class EggRepository extends EloquentRepository implements EggRepositoryInterface
public function getWithVariables(int $id): Egg public function getWithVariables(int $id): Egg
{ {
try { try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('variables')->findOrFail($id, $this->getColumns()); return $this->getBuilder()->with('variables')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) { } catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException(); throw new RecordNotFoundException();
@ -55,6 +57,8 @@ class EggRepository extends EloquentRepository implements EggRepositoryInterface
Assert::true((is_digit($value) || is_string($value)), 'First argument passed to getWithCopyAttributes must be an integer or string, received %s.'); Assert::true((is_digit($value) || is_string($value)), 'First argument passed to getWithCopyAttributes must be an integer or string, received %s.');
try { try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('scriptFrom', 'configFrom')->where($column, '=', $value)->firstOrFail($this->getColumns()); return $this->getBuilder()->with('scriptFrom', 'configFrom')->where($column, '=', $value)->firstOrFail($this->getColumns());
} catch (ModelNotFoundException $exception) { } catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException(); throw new RecordNotFoundException();
@ -69,6 +73,8 @@ class EggRepository extends EloquentRepository implements EggRepositoryInterface
public function getWithExportAttributes(int $id): Egg public function getWithExportAttributes(int $id): Egg
{ {
try { try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('scriptFrom', 'configFrom', 'variables')->findOrFail($id, $this->getColumns()); return $this->getBuilder()->with('scriptFrom', 'configFrom', 'variables')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) { } catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException(); throw new RecordNotFoundException();

View file

@ -4,6 +4,7 @@ namespace Pterodactyl\Repositories\Eloquent;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Webmozart\Assert\Assert; use Webmozart\Assert\Assert;
use Pterodactyl\Models\Model;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Pterodactyl\Repositories\Repository; use Pterodactyl\Repositories\Repository;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
@ -25,12 +26,8 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
* Determines if the repository function should use filters off the request object * Determines if the repository function should use filters off the request object
* present when returning results. This allows repository methods to be called in API * present when returning results. This allows repository methods to be called in API
* context's such that we can pass through ?filter[name]=Dane&sort=desc for example. * context's such that we can pass through ?filter[name]=Dane&sort=desc for example.
*
* @param bool $usingFilters
*
* @return $this
*/ */
public function usingRequestFilters($usingFilters = true) public function usingRequestFilters(bool $usingFilters = true): self
{ {
$this->useRequestFilters = $usingFilters; $this->useRequestFilters = $usingFilters;
@ -39,26 +36,22 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
/** /**
* Returns the request instance. * Returns the request instance.
*
* @return \Illuminate\Http\Request
*/ */
protected function request() protected function request(): Request
{ {
return $this->app->make(Request::class); return $this->app->make(Request::class);
} }
/** /**
* Paginate the response data based on the page para. * Paginate the response data based on the page para.
*
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/ */
protected function paginate(Builder $instance, int $default = 50) protected function paginate(Builder $instance, int $default = 50): LengthAwarePaginator
{ {
if (!$this->useRequestFilters) { if (!$this->useRequestFilters) {
return $instance->paginate($default); return $instance->paginate($default);
} }
return $instance->paginate($this->request()->query('per_page', $default)); return $instance->paginate((int) $this->request()->query('per_page', (string) $default));
} }
/** /**
@ -91,15 +84,20 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
*/ */
public function create(array $fields, bool $validate = true, bool $force = false) public function create(array $fields, bool $validate = true, bool $force = false)
{ {
/** @phpstan-var \Illuminate\Database\Eloquent\Model $instance */
$instance = $this->getBuilder()->newModelInstance(); $instance = $this->getBuilder()->newModelInstance();
($force) ? $instance->forceFill($fields) : $instance->fill($fields); ($force) ? $instance->forceFill($fields) : $instance->fill($fields);
if (!$validate) { if ($instance instanceof Model) {
$saved = $instance->skipValidation()->save(); if (!$validate) {
} else { $saved = $instance->skipValidation()->save();
if (!$saved = $instance->save()) { } else {
throw new DataValidationException($instance->getValidator()); if (!$saved = $instance->save()) {
throw new DataValidationException($instance->getValidator());
}
} }
} else {
$saved = $instance->save();
} }
return ($this->withFresh) ? $instance->fresh() : $saved; return ($this->withFresh) ? $instance->fresh() : $saved;
@ -150,6 +148,7 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
*/ */
public function findCountWhere(array $fields): int public function findCountWhere(array $fields): int
{ {
// @phpstan-ignore-next-line
return $this->getBuilder()->where($fields)->count($this->getColumns()); return $this->getBuilder()->where($fields)->count($this->getColumns());
} }
@ -191,12 +190,16 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
($force) ? $instance->forceFill($fields) : $instance->fill($fields); ($force) ? $instance->forceFill($fields) : $instance->fill($fields);
if (!$validate) { if ($instance instanceof Model) {
$saved = $instance->skipValidation()->save(); if (!$validate) {
} else { $saved = $instance->skipValidation()->save();
if (!$saved = $instance->save()) { } else {
throw new DataValidationException($instance->getValidator()); if (!$saved = $instance->save()) {
throw new DataValidationException($instance->getValidator());
}
} }
} else {
$saved = $instance->save();
} }
return ($this->withFresh) ? $instance->fresh() : $saved; return ($this->withFresh) ? $instance->fresh() : $saved;
@ -245,6 +248,7 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
return $this->create(array_merge($where, $fields), $validate, $force); return $this->create(array_merge($where, $fields), $validate, $force);
} }
// @phpstan-ignore-next-line
return $this->update($instance->id, $fields, $validate, $force); return $this->update($instance->id, $fields, $validate, $force);
} }

View file

@ -39,13 +39,13 @@ class LocationRepository extends EloquentRepository implements LocationRepositor
/** /**
* Return all of the nodes and their respective count of servers for a location. * Return all of the nodes and their respective count of servers for a location.
* *
* @return mixed
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function getWithNodes(int $id): Location public function getWithNodes(int $id): Location
{ {
try { try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('nodes.servers')->findOrFail($id, $this->getColumns()); return $this->getBuilder()->with('nodes.servers')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) { } catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException(); throw new RecordNotFoundException();
@ -55,13 +55,13 @@ class LocationRepository extends EloquentRepository implements LocationRepositor
/** /**
* Return a location and the count of nodes in that location. * Return a location and the count of nodes in that location.
* *
* @return mixed
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function getWithNodeCount(int $id): Location public function getWithNodeCount(int $id): Location
{ {
try { try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->withCount('nodes')->findOrFail($id, $this->getColumns()); return $this->getBuilder()->withCount('nodes')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) { } catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException(); throw new RecordNotFoundException();

View file

@ -31,13 +31,13 @@ class MountRepository extends EloquentRepository
/** /**
* Return all of the mounts and their respective relations. * Return all of the mounts and their respective relations.
* *
* @return mixed
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function getWithRelations(string $id): Mount public function getWithRelations(string $id): Mount
{ {
try { try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('eggs', 'nodes')->findOrFail($id, $this->getColumns()); return $this->getBuilder()->with('eggs', 'nodes')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) { } catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException(); throw new RecordNotFoundException();

View file

@ -28,15 +28,14 @@ class NestRepository extends EloquentRepository implements NestRepositoryInterfa
/** /**
* Return a nest or all nests with their associated eggs and variables. * Return a nest or all nests with their associated eggs and variables.
* *
* @return \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\Nest
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function getWithEggs(int $id = null) public function getWithEggs(int $id = null): Nest
{ {
$instance = $this->getBuilder()->with('eggs', 'eggs.variables'); $instance = $this->getBuilder()->with('eggs', 'eggs.variables');
if (!is_null($id)) { if (!is_null($id)) {
/** @var \Pterodactyl\Models\Nest|null $instance */
$instance = $instance->find($id, $this->getColumns()); $instance = $instance->find($id, $this->getColumns());
if (!$instance) { if (!$instance) {
throw new RecordNotFoundException(); throw new RecordNotFoundException();
@ -45,45 +44,8 @@ class NestRepository extends EloquentRepository implements NestRepositoryInterfa
return $instance; return $instance;
} }
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $instance->get($this->getColumns()); return $instance->get($this->getColumns());
} }
/**
* Return a nest or all nests and the count of eggs and servers for that nest.
*
* @return \Pterodactyl\Models\Nest|\Illuminate\Database\Eloquent\Collection
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithCounts(int $id = null)
{
$instance = $this->getBuilder()->withCount(['eggs', 'servers']);
if (!is_null($id)) {
$instance = $instance->find($id, $this->getColumns());
if (!$instance) {
throw new RecordNotFoundException();
}
return $instance;
}
return $instance->get($this->getColumns());
}
/**
* Return a nest along with its associated eggs and the servers relation on those eggs.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithEggServers(int $id): Nest
{
$instance = $this->getBuilder()->with('eggs.servers')->find($id, $this->getColumns());
if (!$instance) {
throw new RecordNotFoundException();
}
/* @var Nest $instance */
return $instance;
}
} }

View file

@ -59,7 +59,10 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
$this->getBuilder()->raw('IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk') $this->getBuilder()->raw('IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk')
)->join('servers', 'servers.node_id', '=', 'nodes.id')->where('node_id', $node->id)->first(); )->join('servers', 'servers.node_id', '=', 'nodes.id')->where('node_id', $node->id)->first();
return collect(['disk' => $stats->sum_disk, 'memory' => $stats->sum_memory])->mapWithKeys(function ($value, $key) use ($node) { return collect([
'disk' => $stats->sum_disk,
'memory' => $stats->sum_memory,
])->mapWithKeys(function ($value, $key) use ($node) {
$maxUsage = $node->{$key}; $maxUsage = $node->{$key};
if ($node->{$key . '_overallocate'} > 0) { if ($node->{$key . '_overallocate'} > 0) {
$maxUsage = $node->{$key} * (1 + ($node->{$key . '_overallocate'} / 100)); $maxUsage = $node->{$key} * (1 + ($node->{$key . '_overallocate'} / 100));
@ -85,6 +88,7 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
// This is quite ugly and can probably be improved down the road. // This is quite ugly and can probably be improved down the road.
// And by probably, I mean it should. // And by probably, I mean it should.
// @phpstan-ignore-next-line
if (is_null($node->servers_count) || $refresh) { if (is_null($node->servers_count) || $refresh) {
$node->load('servers'); $node->load('servers');
$node->setRelation('servers_count', count($node->getRelation('servers'))); $node->setRelation('servers_count', count($node->getRelation('servers')));
@ -118,22 +122,28 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
*/ */
public function getNodesForServerCreation(): Collection public function getNodesForServerCreation(): Collection
{ {
return $this->getBuilder()->with('allocations')->get()->map(function (Node $item) { /** @phpstan-var \Illuminate\Database\Eloquent\Collection<\Pterodactyl\Models\Node> $collection */
$collection = $this->getBuilder()->with('allocations')->get();
return $collection->map(function (Node $item) {
/** @phpstan-var \Illuminate\Support\Collection<array{id: string, ip: string, port: string|int}> $filtered */
$filtered = $item->getRelation('allocations')->where('server_id', null)->map(function ($map) { $filtered = $item->getRelation('allocations')->where('server_id', null)->map(function ($map) {
return collect($map)->only(['id', 'ip', 'port']); return collect($map)->only(['id', 'ip', 'port']);
}); });
$item->ports = $filtered->map(function ($map) { $ports = $filtered->map(function ($map) {
return [ return [
'id' => $map['id'], 'id' => $map['id'],
'text' => sprintf('%s:%s', $map['ip'], $map['port']), 'text' => sprintf('%s:%s', $map['ip'], $map['port']),
]; ];
})->values(); })->values();
$item->setAttribute('ports', $ports);
return [ return [
'id' => $item->id, 'id' => $item->id,
'text' => $item->name, 'text' => $item->name,
'allocations' => $item->ports, 'allocations' => $ports,
]; ];
})->values(); })->values();
} }
@ -144,11 +154,22 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
public function getNodeWithResourceUsage(int $node_id): Node public function getNodeWithResourceUsage(int $node_id): Node
{ {
$instance = $this->getBuilder() $instance = $this->getBuilder()
->select(['nodes.id', 'nodes.fqdn', 'nodes.public_port_http', 'nodes.scheme', 'nodes.daemon_token', 'nodes.memory', 'nodes.disk', 'nodes.memory_overallocate', 'nodes.disk_overallocate']) ->select([
'nodes.id',
'nodes.fqdn',
'nodes.public_port_http',
'nodes.scheme',
'nodes.daemon_token',
'nodes.memory',
'nodes.disk',
'nodes.memory_overallocate',
'nodes.disk_overallocate',
])
->selectRaw('IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk') ->selectRaw('IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk')
->leftJoin('servers', 'servers.node_id', '=', 'nodes.id') ->leftJoin('servers', 'servers.node_id', '=', 'nodes.id')
->where('nodes.id', $node_id); ->where('nodes.id', $node_id);
/* @noinspection PhpIncompatibleReturnTypeInspection */
return $instance->first(); return $instance->first();
} }
} }

View file

@ -36,6 +36,8 @@ class ScheduleRepository extends EloquentRepository implements ScheduleRepositor
public function getScheduleWithTasks(int $schedule): Schedule public function getScheduleWithTasks(int $schedule): Schedule
{ {
try { try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('tasks')->findOrFail($schedule, $this->getColumns()); return $this->getBuilder()->with('tasks')->findOrFail($schedule, $this->getColumns());
} catch (ModelNotFoundException $exception) { } catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException(); throw new RecordNotFoundException();

View file

@ -74,6 +74,8 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
public function findWithVariables(int $id): Server public function findWithVariables(int $id): Server
{ {
try { try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('egg.variables', 'variables') return $this->getBuilder()->with('egg.variables', 'variables')
->where($this->getModel()->getKeyName(), '=', $id) ->where($this->getModel()->getKeyName(), '=', $id)
->firstOrFail($this->getColumns()); ->firstOrFail($this->getColumns());

View file

@ -27,6 +27,8 @@ class TaskRepository extends EloquentRepository implements TaskRepositoryInterfa
public function getTaskForJobProcess(int $id): Task public function getTaskForJobProcess(int $id): Task
{ {
try { try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('server.user', 'schedule')->findOrFail($id, $this->getColumns()); return $this->getBuilder()->with('server.user', 'schedule')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) { } catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException(); throw new RecordNotFoundException();

View file

@ -118,7 +118,8 @@ abstract class Repository implements RepositoryInterface
/** /**
* Take the provided model and make it accessible to the rest of the repository. * Take the provided model and make it accessible to the rest of the repository.
* *
* @param array $model * @param string[] $model
* @phpstan-param class-string<\Illuminate\Database\Eloquent\Model> $model
* *
* @return mixed * @return mixed
*/ */
@ -128,6 +129,7 @@ abstract class Repository implements RepositoryInterface
case 1: case 1:
return $this->model = $this->app->make($model[0]); return $this->model = $this->app->make($model[0]);
case 2: case 2:
// @phpstan-ignore-next-line
return $this->model = call_user_func([$this->app->make($model[0]), $model[1]]); return $this->model = call_user_func([$this->app->make($model[0]), $model[1]]);
default: default:
throw new InvalidArgumentException('Model must be a FQDN or an array with a count of two.'); throw new InvalidArgumentException('Model must be a FQDN or an array with a count of two.');

View file

@ -22,7 +22,7 @@ class Username implements Rule
*/ */
public function passes($attribute, $value): bool public function passes($attribute, $value): bool
{ {
return preg_match(self::VALIDATION_REGEX, mb_strtolower($value)); return preg_match(self::VALIDATION_REGEX, mb_strtolower($value)) === 1;
} }
/** /**

View file

@ -64,6 +64,7 @@ class AssignmentService
$parsed = Network::parse($underlying); $parsed = Network::parse($underlying);
} catch (Exception $exception) { } catch (Exception $exception) {
/* @noinspection PhpUndefinedVariableInspection */ /* @noinspection PhpUndefinedVariableInspection */
// @phpstan-ignore-next-line
throw new DisplayException("Could not parse provided allocation IP address ({$underlying}): {$exception->getMessage()}", $exception); throw new DisplayException("Could not parse provided allocation IP address ({$underlying}): {$exception->getMessage()}", $exception);
} }

View file

@ -102,6 +102,7 @@ class DeleteBackupService
/** @var \League\Flysystem\AwsS3v3\AwsS3Adapter $adapter */ /** @var \League\Flysystem\AwsS3v3\AwsS3Adapter $adapter */
$adapter = $this->manager->adapter(Backup::ADAPTER_AWS_S3); $adapter = $this->manager->adapter(Backup::ADAPTER_AWS_S3);
// @phpstan-ignore-next-line this is defined on the actual S3Client class, just not on the interface.
$adapter->getClient()->deleteObject([ $adapter->getClient()->deleteObject([
'Bucket' => $adapter->getBucket(), 'Bucket' => $adapter->getBucket(),
'Key' => sprintf('%s/%s.tar.gz', $backup->server->uuid, $backup->uuid), 'Key' => sprintf('%s/%s.tar.gz', $backup->server->uuid, $backup->uuid),

View file

@ -9,6 +9,7 @@ use Pterodactyl\Models\Backup;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Illuminate\Database\ConnectionInterface; use Illuminate\Database\ConnectionInterface;
use Pterodactyl\Extensions\Backups\BackupManager; use Pterodactyl\Extensions\Backups\BackupManager;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Pterodactyl\Repositories\Eloquent\BackupRepository; use Pterodactyl\Repositories\Eloquent\BackupRepository;
use Pterodactyl\Repositories\Wings\DaemonBackupRepository; use Pterodactyl\Repositories\Wings\DaemonBackupRepository;
use Pterodactyl\Exceptions\Service\Backup\TooManyBackupsException; use Pterodactyl\Exceptions\Service\Backup\TooManyBackupsException;
@ -53,8 +54,6 @@ class InitiateBackupService
/** /**
* InitiateBackupService constructor. * InitiateBackupService constructor.
*
* @param \Pterodactyl\Services\Backups\DeleteBackupService $deleteBackupService
*/ */
public function __construct( public function __construct(
BackupRepository $repository, BackupRepository $repository,
@ -140,7 +139,7 @@ class InitiateBackupService
// Get the oldest backup the server has that is not "locked" (indicating a backup that should // 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 // 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. // this process. If no backup is found that can be used an exception is thrown.
/** @var \Pterodactyl\Models\Backup $oldest */ /** @var \Pterodactyl\Models\Backup|null $oldest */
$oldest = $successful->where('is_locked', false)->orderBy('created_at')->first(); $oldest = $successful->where('is_locked', false)->orderBy('created_at')->first();
if (!$oldest) { if (!$oldest) {
throw new TooManyBackupsException($server->backup_limit); throw new TooManyBackupsException($server->backup_limit);

View file

@ -152,6 +152,7 @@ class DatabaseManagementService
}); });
} catch (Exception $exception) { } catch (Exception $exception) {
try { try {
// @phpstan-ignore-next-line doesn't understand the pass-by-reference above
if ($database instanceof Database) { if ($database instanceof Database) {
$this->repository->dropDatabase($database->database); $this->repository->dropDatabase($database->database);
$this->repository->dropUser($database->username, $database->remote); $this->repository->dropUser($database->username, $database->remote);

View file

@ -49,8 +49,6 @@ class DatabasePasswordService
/** /**
* Updates a password for a given database. * Updates a password for a given database.
* *
* @param \Pterodactyl\Models\Database|int $database
*
* @throws \Throwable * @throws \Throwable
*/ */
public function handle(Database $database): string public function handle(Database $database): string

View file

@ -205,6 +205,7 @@ class EggConfigurationService
// Replace anything starting with "server." with the value out of the server configuration // Replace anything starting with "server." with the value out of the server configuration
// array that used to be created for the old daemon. // array that used to be created for the old daemon.
if (Str::startsWith($key, 'server.')) { if (Str::startsWith($key, 'server.')) {
// @phpstan-ignore-next-line
$plucked = Arr::get($structure, preg_replace('/^server\./', '', $key), ''); $plucked = Arr::get($structure, preg_replace('/^server\./', '', $key), '');
$value = str_replace("{{{$key}}}", $plucked, $value); $value = str_replace("{{{$key}}}", $plucked, $value);
@ -215,6 +216,7 @@ class EggConfigurationService
// variable from the server configuration. // variable from the server configuration.
$plucked = Arr::get( $plucked = Arr::get(
$structure, $structure,
// @phpstan-ignore-next-line
preg_replace('/^env\./', 'build.env.', $key), preg_replace('/^env\./', 'build.env.', $key),
'' ''
); );

View file

@ -24,13 +24,11 @@ class InstallScriptService
/** /**
* Modify the install script for a given Egg. * Modify the install script for a given Egg.
* *
* @param int|\Pterodactyl\Models\Egg $egg
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Service\Egg\InvalidCopyFromException * @throws \Pterodactyl\Exceptions\Service\Egg\InvalidCopyFromException
*/ */
public function handle(Egg $egg, array $data) public function handle(Egg $egg, array $data): void
{ {
if (!is_null(array_get($data, 'copy_script_from'))) { if (!is_null(array_get($data, 'copy_script_from'))) {
if (!$this->repository->isCopyableScript(array_get($data, 'copy_script_from'), $egg->nest_id)) { if (!$this->repository->isCopyableScript(array_get($data, 'copy_script_from'), $egg->nest_id)) {

View file

@ -14,8 +14,8 @@ use Symfony\Component\Yaml\Exception\ParseException;
use Pterodactyl\Contracts\Repository\EggRepositoryInterface; use Pterodactyl\Contracts\Repository\EggRepositoryInterface;
use Pterodactyl\Contracts\Repository\NestRepositoryInterface; use Pterodactyl\Contracts\Repository\NestRepositoryInterface;
use Pterodactyl\Exceptions\Service\Egg\BadJsonFormatException; use Pterodactyl\Exceptions\Service\Egg\BadJsonFormatException;
use Pterodactyl\Exceptions\Service\InvalidFileUploadException;
use Pterodactyl\Exceptions\Service\Egg\BadYamlFormatException; use Pterodactyl\Exceptions\Service\Egg\BadYamlFormatException;
use Pterodactyl\Exceptions\Service\InvalidFileUploadException;
use Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface; use Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface;
class EggImporterService class EggImporterService
@ -58,7 +58,7 @@ class EggImporterService
/** /**
* Take an uploaded JSON file and parse it into a new egg. * Take an uploaded JSON file and parse it into a new egg.
* *
* @deprecated Use `handleFile` or `handleContent` instead. * @deprecated use `handleFile` or `handleContent` instead
* *
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Service\Egg\BadJsonFormatException * @throws \Pterodactyl\Exceptions\Service\Egg\BadJsonFormatException

View file

@ -59,6 +59,7 @@ class VariableCreationService
'user_editable' => in_array('user_editable', $options), 'user_editable' => in_array('user_editable', $options),
'rules' => $data['rules'] ?? '', 'rules' => $data['rules'] ?? '',
]); ]);
return $model; return $model;
} }
} }

View file

@ -8,7 +8,6 @@ use Pterodactyl\Models\EggVariable;
use Illuminate\Contracts\Validation\Factory; use Illuminate\Contracts\Validation\Factory;
use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Traits\Services\ValidatesValidationRules; use Pterodactyl\Traits\Services\ValidatesValidationRules;
use Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface;
use Pterodactyl\Exceptions\Service\Egg\Variable\ReservedVariableNameException; use Pterodactyl\Exceptions\Service\Egg\Variable\ReservedVariableNameException;
class VariableUpdateService class VariableUpdateService
@ -51,7 +50,7 @@ class VariableUpdateService
} }
$count = $egg->variables() $count = $egg->variables()
->where('egg_variables.env_variable',$data['env_variable']) ->where('egg_variables.env_variable', $data['env_variable'])
->where('egg_variables.id', '!=', $data['id']) ->where('egg_variables.id', '!=', $data['id'])
->count(); ->count();

View file

@ -6,6 +6,7 @@ use Exception;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use Carbon\CarbonImmutable; use Carbon\CarbonImmutable;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Contracts\Cache\Repository as CacheRepository; use Illuminate\Contracts\Cache\Repository as CacheRepository;
use Pterodactyl\Exceptions\Service\Helper\CdnVersionFetchingException; use Pterodactyl\Exceptions\Service\Helper\CdnVersionFetchingException;

View file

@ -1,11 +1,4 @@
<?php <?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Services\Nodes; namespace Pterodactyl\Services\Nodes;
@ -48,23 +41,15 @@ class NodeDeletionService
/** /**
* Delete a node from the panel if no servers are attached to it. * Delete a node from the panel if no servers are attached to it.
* *
* @param int|\Pterodactyl\Models\Node $node
*
* @return bool|null
*
* @throws \Pterodactyl\Exceptions\Service\HasActiveServersException * @throws \Pterodactyl\Exceptions\Service\HasActiveServersException
*/ */
public function handle($node) public function handle(Node $node): void
{ {
if ($node instanceof Node) { $servers = $this->serverRepository->setColumns('id')->findCountWhere([['node_id', '=', $node->id]]);
$node = $node->id;
}
$servers = $this->serverRepository->setColumns('id')->findCountWhere([['node_id', '=', $node]]);
if ($servers > 0) { if ($servers > 0) {
throw new HasActiveServersException($this->translator->trans('exceptions.node.servers_attached')); throw new HasActiveServersException($this->translator->get('exceptions.node.servers_attached'));
} }
return $this->repository->delete($node); $this->repository->delete($node->id);
} }
} }

View file

@ -63,8 +63,6 @@ class NodeJWTService
/** /**
* Generate a new JWT for a given node. * Generate a new JWT for a given node.
* *
* @param string|null $identifiedBy
*
* @return \Lcobucci\JWT\Token\Plain * @return \Lcobucci\JWT\Token\Plain
*/ */
public function handle(Node $node, string $identifiedBy, string $algo = 'md5') public function handle(Node $node, string $identifiedBy, string $algo = 'md5')

View file

@ -45,7 +45,7 @@ class ProcessScheduleService
*/ */
public function handle(Schedule $schedule, bool $now = false) public function handle(Schedule $schedule, bool $now = false)
{ {
/** @var \Pterodactyl\Models\Task $task */ /** @var \Pterodactyl\Models\Task|null $task */
$task = $schedule->tasks()->orderBy('sequence_id')->first(); $task = $schedule->tasks()->orderBy('sequence_id')->first();
if (is_null($task)) { if (is_null($task)) {

View file

@ -33,8 +33,6 @@ class BuildModificationService
* BuildModificationService constructor. * BuildModificationService constructor.
* *
* @param \Pterodactyl\Services\Servers\ServerConfigurationStructureService $structureService * @param \Pterodactyl\Services\Servers\ServerConfigurationStructureService $structureService
* @param \Illuminate\Database\ConnectionInterface $connection
* @param \Pterodactyl\Repositories\Wings\DaemonServerRepository $daemonServerRepository
*/ */
public function __construct( public function __construct(
ServerConfigurationStructureService $structureService, ServerConfigurationStructureService $structureService,
@ -57,7 +55,7 @@ class BuildModificationService
public function handle(Server $server, array $data) public function handle(Server $server, array $data)
{ {
/** @var \Pterodactyl\Models\Server $server */ /** @var \Pterodactyl\Models\Server $server */
$server = $this->connection->transaction(function() use ($server, $data) { $server = $this->connection->transaction(function () use ($server, $data) {
$this->processAllocations($server, $data); $this->processAllocations($server, $data);
if (isset($data['allocation_id']) && $data['allocation_id'] != $server->allocation_id) { if (isset($data['allocation_id']) && $data['allocation_id'] != $server->allocation_id) {
@ -115,11 +113,12 @@ class BuildModificationService
$query = Allocation::query() $query = Allocation::query()
->where('node_id', $server->node_id) ->where('node_id', $server->node_id)
->whereIn('id', $data['add_allocations']) ->whereIn('id', $data['add_allocations'])
->whereNull('server_id'); ->whereNull('server_id')
->first();
// Keep track of all the allocations we're just now adding so that we can use the first // 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. // one to reset the default allocation to.
$freshlyAllocated = $query->pluck('id')->first(); $freshlyAllocated = optional($query)->id;
$query->update(['server_id' => $server->id, 'notes' => null]); $query->update(['server_id' => $server->id, 'notes' => null]);
} }

View file

@ -36,6 +36,7 @@ class EnvironmentService
public function handle(Server $server): array public function handle(Server $server): array
{ {
$variables = $server->variables->toBase()->mapWithKeys(function (EggVariable $variable) { $variables = $server->variables->toBase()->mapWithKeys(function (EggVariable $variable) {
// @phpstan-ignore-next-line
return [$variable->env_variable => $variable->server_value ?? $variable->default_value]; return [$variable->env_variable => $variable->server_value ?? $variable->default_value];
}); });

View file

@ -16,6 +16,7 @@ class StartupCommandService
foreach ($server->variables as $variable) { foreach ($server->variables as $variable) {
$find[] = '{{' . $variable->env_variable . '}}'; $find[] = '{{' . $variable->env_variable . '}}';
// @phpstan-ignore-next-line
$replace[] = ($variable->user_viewable && !$hideAllValues) ? ($variable->server_value ?? $variable->default_value) : '[hidden]'; $replace[] = ($variable->user_viewable && !$hideAllValues) ? ($variable->server_value ?? $variable->default_value) : '[hidden]';
} }

View file

@ -4,15 +4,9 @@ namespace Pterodactyl\Services\Servers;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Pterodactyl\Repositories\Wings\DaemonServerRepository; use Pterodactyl\Repositories\Wings\DaemonServerRepository;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
class TransferService class TransferService
{ {
/**
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
*/
private $repository;
/** /**
* @var \Pterodactyl\Repositories\Wings\DaemonServerRepository * @var \Pterodactyl\Repositories\Wings\DaemonServerRepository
*/ */
@ -21,19 +15,14 @@ class TransferService
/** /**
* TransferService constructor. * TransferService constructor.
*/ */
public function __construct( public function __construct(DaemonServerRepository $daemonServerRepository)
DaemonServerRepository $daemonServerRepository, {
ServerRepositoryInterface $repository
) {
$this->repository = $repository;
$this->daemonServerRepository = $daemonServerRepository; $this->daemonServerRepository = $daemonServerRepository;
} }
/** /**
* Requests an archive from the daemon. * Requests an archive from the daemon.
* *
* @param int|\Pterodactyl\Models\Server $server
*
* @throws \Throwable * @throws \Throwable
*/ */
public function requestArchive(Server $server) public function requestArchive(Server $server)

View file

@ -1,11 +1,4 @@
<?php <?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Services\Users; namespace Pterodactyl\Services\Users;
@ -48,23 +41,15 @@ class UserDeletionService
/** /**
* Delete a user from the panel only if they have no servers attached to their account. * Delete a user from the panel only if they have no servers attached to their account.
* *
* @param int|\Pterodactyl\Models\User $user
*
* @return bool|null
*
* @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\DisplayException
*/ */
public function handle($user) public function handle(User $user): void
{ {
if ($user instanceof User) { $servers = $this->serverRepository->setColumns('id')->findCountWhere([['owner_id', '=', $user->id]]);
$user = $user->id;
}
$servers = $this->serverRepository->setColumns('id')->findCountWhere([['owner_id', '=', $user]]);
if ($servers > 0) { if ($servers > 0) {
throw new DisplayException($this->translator->trans('admin/user.exceptions.user_has_servers')); throw new DisplayException($this->translator->get('admin/user.exceptions.user_has_servers'));
} }
return $this->repository->delete($user); $this->repository->delete($user->id);
} }
} }

View file

@ -8,14 +8,14 @@ use Illuminate\Filesystem\Filesystem;
trait AvailableLanguages trait AvailableLanguages
{ {
/** /**
* @var \Illuminate\Filesystem\Filesystem * @var \Illuminate\Filesystem\Filesystem|null;
*/ */
private $filesystem; private $filesystem = null;
/** /**
* @var \Matriphe\ISO639\ISO639 * @var \Matriphe\ISO639\ISO639|null
*/ */
private $iso639; private $iso639 = null;
/** /**
* Return all of the available languages on the Panel based on those * Return all of the available languages on the Panel based on those

View file

@ -28,6 +28,7 @@ class DatabaseHostTransformer extends Transformer
'host' => $model->host, 'host' => $model->host,
'port' => $model->port, 'port' => $model->port,
'username' => $model->username, 'username' => $model->username,
// @phpstan-ignore-next-line no clue why it can't find this.
'node' => $model->node_id, 'node' => $model->node_id,
'created_at' => self::formatTimestamp($model->created_at), 'created_at' => self::formatTimestamp($model->created_at),
'updated_at' => self::formatTimestamp($model->updated_at), 'updated_at' => self::formatTimestamp($model->updated_at),

View file

@ -40,6 +40,8 @@ class ServerVariableTransformer extends Transformer
return $this->null(); return $this->null();
} }
// TODO: confirm this code?
// @phpstan-ignore-next-line This might actually be wrong, not sure?
return $this->item($variable->variable, new EggVariableTransformer()); return $this->item($variable->variable, new EggVariableTransformer());
} }
} }

View file

@ -27,7 +27,7 @@ class EggVariableTransformer extends Transformer
'description' => $variable->description, 'description' => $variable->description,
'env_variable' => $variable->env_variable, 'env_variable' => $variable->env_variable,
'default_value' => $variable->default_value, 'default_value' => $variable->default_value,
'server_value' => $variable->server_value, 'server_value' => property_exists($variable, 'server_value') ? $variable->server_value : null,
'is_editable' => $variable->user_editable, 'is_editable' => $variable->user_editable,
'rules' => $variable->rules, 'rules' => $variable->rules,
]; ];

View file

@ -5,6 +5,7 @@ namespace Pterodactyl\Transformers\Api;
use Closure; use Closure;
use DateTimeInterface; use DateTimeInterface;
use Carbon\CarbonImmutable; use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Pterodactyl\Models\User; use Pterodactyl\Models\User;
use Webmozart\Assert\Assert; use Webmozart\Assert\Assert;
@ -64,7 +65,7 @@ abstract class Transformer extends TransformerAbstract
* *
* @param mixed $data * @param mixed $data
* @param callable|\League\Fractal\TransformerAbstract $transformer * @param callable|\League\Fractal\TransformerAbstract $transformer
* @param null $resourceKey * @param string|null $resourceKey
* *
* @return \League\Fractal\Resource\Item * @return \League\Fractal\Resource\Item
*/ */
@ -76,7 +77,7 @@ abstract class Transformer extends TransformerAbstract
$item = parent::item($data, $transformer, $resourceKey); $item = parent::item($data, $transformer, $resourceKey);
if (!$item->getResourceKey()) { if (!$item->getResourceKey() && method_exists($transformer, 'getResourceName')) {
$item->setResourceKey($transformer->getResourceName()); $item->setResourceKey($transformer->getResourceName());
} }
@ -88,7 +89,7 @@ abstract class Transformer extends TransformerAbstract
* *
* @param mixed $data * @param mixed $data
* @param callable|\League\Fractal\TransformerAbstract $transformer * @param callable|\League\Fractal\TransformerAbstract $transformer
* @param null $resourceKey * @param string|null $resourceKey
* *
* @return \League\Fractal\Resource\Collection * @return \League\Fractal\Resource\Collection
*/ */
@ -100,7 +101,7 @@ abstract class Transformer extends TransformerAbstract
$collection = parent::collection($data, $transformer, $resourceKey); $collection = parent::collection($data, $transformer, $resourceKey);
if (!$collection->getResourceKey()) { if (!$collection->getResourceKey() && method_exists($transformer, 'getResourceName')) {
$collection->setResourceKey($transformer->getResourceName()); $collection->setResourceKey($transformer->getResourceName());
} }
@ -151,7 +152,7 @@ abstract class Transformer extends TransformerAbstract
if ($timestamp instanceof DateTimeInterface) { if ($timestamp instanceof DateTimeInterface) {
$value = CarbonImmutable::instance($timestamp); $value = CarbonImmutable::instance($timestamp);
} else { } else {
$value = CarbonImmutable::createFromFormat(CarbonImmutable::DEFAULT_TO_STRING_FORMAT, $timestamp); $value = CarbonImmutable::createFromFormat(CarbonInterface::DEFAULT_TO_STRING_FORMAT, $timestamp);
} }
return $value->setTimezone($tz ?? self::$timezone)->toIso8601String(); return $value->setTimezone($tz ?? self::$timezone)->toIso8601String();

View file

@ -21,8 +21,8 @@ if (!function_exists('object_get_strict')) {
* and will not trigger the response of a default value (unlike object_get). * and will not trigger the response of a default value (unlike object_get).
* *
* @param object $object * @param object $object
* @param string $key * @param string|null $key
* @param null $default * @param mixed|null $default
* *
* @return mixed * @return mixed
*/ */

View file

@ -24,7 +24,7 @@
"guzzlehttp/guzzle": "^7.3", "guzzlehttp/guzzle": "^7.3",
"hashids/hashids": "^4.1", "hashids/hashids": "^4.1",
"laracasts/utilities": "^3.2", "laracasts/utilities": "^3.2",
"laravel/framework": "^8.58", "laravel/framework": "^8.68",
"laravel/helpers": "^1.4", "laravel/helpers": "^1.4",
"laravel/sanctum": "^2.11", "laravel/sanctum": "^2.11",
"laravel/tinker": "^2.6", "laravel/tinker": "^2.6",
@ -53,7 +53,9 @@
"laravel/dusk": "^6.18", "laravel/dusk": "^6.18",
"mockery/mockery": "^1.4", "mockery/mockery": "^1.4",
"nunomaduro/collision": "^5.9", "nunomaduro/collision": "^5.9",
"nunomaduro/larastan": "^0.7.15",
"php-mock/php-mock-phpunit": "^2.6", "php-mock/php-mock-phpunit": "^2.6",
"phpstan/phpstan-webmozart-assert": "^0.12.16",
"phpunit/phpunit": "^9.5" "phpunit/phpunit": "^9.5"
}, },
"autoload": { "autoload": {

1193
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
<?php <?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class UpdateDefaultValuesForEggs extends Migration class UpdateDefaultValuesForEggs extends Migration
{ {

257
phpstan-baseline.neon Normal file
View file

@ -0,0 +1,257 @@
parameters:
ignoreErrors:
-
message: "#^Parameter \\#1 \\$string of function strtoupper expects string, int\\|string given\\.$#"
count: 1
path: app/Console/Commands/Environment/AppSettingsCommand.php
-
message: "#^Parameter \\#2 \\$subject of function preg_match_all expects string, string\\|false\\|null given\\.$#"
count: 1
path: app/Console/Commands/Environment/AppSettingsCommand.php
-
message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|false\\|null given\\.$#"
count: 1
path: app/Console/Commands/Environment/AppSettingsCommand.php
-
message: "#^Parameter \\#1 \\$string of function strtoupper expects string, int\\|string given\\.$#"
count: 1
path: app/Console/Commands/Environment/DatabaseSettingsCommand.php
-
message: "#^Parameter \\#2 \\$subject of function preg_match_all expects string, string\\|false\\|null given\\.$#"
count: 1
path: app/Console/Commands/Environment/DatabaseSettingsCommand.php
-
message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|false\\|null given\\.$#"
count: 1
path: app/Console/Commands/Environment/DatabaseSettingsCommand.php
-
message: "#^Parameter \\#1 \\$string of function strtoupper expects string, int\\|string given\\.$#"
count: 1
path: app/Console/Commands/Environment/EmailSettingsCommand.php
-
message: "#^Parameter \\#1 \\$value of function studly_case expects string, array\\|bool\\|string given\\.$#"
count: 1
path: app/Console/Commands/Environment/EmailSettingsCommand.php
-
message: "#^Parameter \\#2 \\$subject of function preg_match_all expects string, string\\|false\\|null given\\.$#"
count: 1
path: app/Console/Commands/Environment/EmailSettingsCommand.php
-
message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|false\\|null given\\.$#"
count: 1
path: app/Console/Commands/Environment/EmailSettingsCommand.php
-
message: "#^Parameter \\#1 \\$action of method Pterodactyl\\\\Repositories\\\\Wings\\\\DaemonPowerRepository\\:\\:send\\(\\) expects string, array\\|string\\|null given\\.$#"
count: 1
path: app/Console/Commands/Server/BulkPowerActionCommand.php
-
message: "#^Parameter \\#2 \\$string of function explode expects string, array\\|bool\\|string given\\.$#"
count: 2
path: app/Console/Commands/Server/BulkPowerActionCommand.php
-
message: "#^Binary operation \"\\.\" between 'download/v' and array\\|bool\\|string\\|null results in an error\\.$#"
count: 1
path: app/Console/Commands/UpgradeCommand.php
-
message: "#^Cannot access offset 'name' on array\\|false\\.$#"
count: 2
path: app/Console/Commands/UpgradeCommand.php
-
message: "#^Method Pterodactyl\\\\Console\\\\Commands\\\\UpgradeCommand\\:\\:getUrl\\(\\) should return string but returns array\\|bool\\|string\\|null\\.$#"
count: 1
path: app/Console/Commands/UpgradeCommand.php
-
message: "#^Parameter \\#1 \\$group_id of function posix_getgrgid expects int, int\\|false given\\.$#"
count: 1
path: app/Console/Commands/UpgradeCommand.php
-
message: "#^Parameter \\#1 \\$user_id of function posix_getpwuid expects int, int\\|false given\\.$#"
count: 1
path: app/Console/Commands/UpgradeCommand.php
-
message: "#^Binary operation \"\\.\" between array\\|string and '\\.' results in an error\\.$#"
count: 1
path: app/Exceptions/Handler.php
-
message: "#^Possibly invalid array key type array\\|string\\.$#"
count: 1
path: app/Exceptions/Handler.php
-
message: "#^Unable to resolve the template type TReturn in call to method Illuminate\\\\Support\\\\Collection\\<mixed,array\\<int, mixed\\>\\>\\:\\:flatMap\\(\\)$#"
count: 1
path: app/Exceptions/Handler.php
-
message: "#^Possibly invalid array key type array\\<string\\>\\|string\\.$#"
count: 1
path: app/Extensions/Backups/BackupManager.php
-
message: "#^Parameter \\#1 \\$message of static method Illuminate\\\\Log\\\\Logger\\:\\:info\\(\\) expects string, string\\|false given\\.$#"
count: 2
path: app/Http/Controllers/Api/Application/Eggs/EggController.php
-
message: "#^Parameter \\#2 \\$content of method Pterodactyl\\\\Services\\\\Eggs\\\\Sharing\\\\EggImporterService\\:\\:handleContent\\(\\) expects string, resource\\|string given\\.$#"
count: 1
path: app/Http/Controllers/Api/Application/Nests/NestController.php
-
message: "#^Parameter \\#1 \\$perPage of method Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\HasMany\\<Pterodactyl\\\\Models\\\\Backup\\>\\:\\:paginate\\(\\) expects int\\|null, array\\|int\\|string given\\.$#"
count: 1
path: app/Http/Controllers/Api/Client/Servers/BackupController.php
-
message: "#^Parameter \\#2 \\$content of method Pterodactyl\\\\Repositories\\\\Wings\\\\DaemonFileRepository\\:\\:putContent\\(\\) expects string, resource\\|string given\\.$#"
count: 1
path: app/Http/Controllers/Api/Client/Servers/FileController.php
-
message: "#^Parameter \\#1 \\$string of function md5 expects string, string\\|false given\\.$#"
count: 1
path: app/Http/Controllers/Base/LocaleController.php
-
message: "#^Parameter \\#1 \\$key of method Illuminate\\\\Routing\\\\Router\\:\\:bind\\(\\) expects string, int\\|string given\\.$#"
count: 1
path: app/Http/Middleware/Api/Application/SubstituteApplicationApiBindings.php
-
message: "#^Parameter \\#1 \\$json of function json_decode expects string, resource\\|string given\\.$#"
count: 1
path: app/Http/Middleware/Api/IsValidJson.php
-
message: "#^Parameter \\#1 \\$array of function array_get expects array\\|ArrayAccess, array\\<string, int\\|string\\>\\|false given\\.$#"
count: 1
path: app/Http/Middleware/VerifyReCaptcha.php
-
message: "#^Parameter \\#1 \\$value of function snake_case expects string, int\\|string given\\.$#"
count: 1
path: app/Http/Requests/Api/Application/Nodes/StoreNodeRequest.php
-
message: "#^Method Pterodactyl\\\\Jobs\\\\Schedule\\\\RunTaskJob\\:\\:__construct\\(\\) has parameter \\$manualRun with no typehint specified\\.$#"
count: 1
path: app/Jobs/Schedule/RunTaskJob.php
-
message: "#^Parameter \\#2 \\$column of static method Illuminate\\\\Validation\\\\Rule\\:\\:unique\\(\\) expects string, int\\|string given\\.$#"
count: 1
path: app/Models/Model.php
-
message: "#^Method Pterodactyl\\\\Models\\\\Node\\:\\:getJsonConfiguration\\(\\) should return string but returns string\\|false\\.$#"
count: 1
path: app/Models/Node.php
-
message: "#^Method Pterodactyl\\\\Repositories\\\\Eloquent\\\\EloquentRepository\\:\\:updateOrCreate\\(\\) should return Illuminate\\\\Database\\\\Eloquent\\\\Model but returns bool\\|Illuminate\\\\Database\\\\Eloquent\\\\Model\\.$#"
count: 1
path: app/Repositories/Eloquent/EloquentRepository.php
-
message: "#^Parameter \\#1 \\.\\.\\.\\$model of method Pterodactyl\\\\Repositories\\\\Repository\\:\\:initializeModel\\(\\) expects class\\-string\\<Illuminate\\\\Database\\\\Eloquent\\\\Model\\>, mixed given\\.$#"
count: 1
path: app/Repositories/Repository.php
-
message: "#^Parameter \\#2 \\$content of method Pterodactyl\\\\Services\\\\Eggs\\\\Sharing\\\\EggImporterService\\:\\:handleContent\\(\\) expects string, string\\|false given\\.$#"
count: 1
path: app/Services/Eggs/Sharing/EggImporterService.php
-
message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#"
count: 1
path: app/Services/Eggs/Sharing/EggUpdateImporterService.php
-
message: "#^Parameter \\#1 \\$value of static method Illuminate\\\\Support\\\\Str\\:\\:snake\\(\\) expects string, array\\|string given\\.$#"
count: 1
path: app/Services/Eggs/Variables/VariableCreationService.php
-
message: "#^Parameter \\#1 \\$value of static method Illuminate\\\\Support\\\\Str\\:\\:snake\\(\\) expects string, array\\|string given\\.$#"
count: 1
path: app/Services/Eggs/Variables/VariableUpdateService.php
-
message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|false given\\.$#"
count: 1
path: app/Services/Helpers/SoftwareVersionService.php
-
message: "#^Parameter \\#2 \\$string of function explode expects string, string\\|false given\\.$#"
count: 1
path: app/Services/Helpers/SoftwareVersionService.php
-
message: "#^Parameter \\#1 \\$id of method Lcobucci\\\\JWT\\\\Builder\\:\\:identifiedBy\\(\\) expects string, string\\|false given\\.$#"
count: 1
path: app/Services/Nodes/NodeJWTService.php
-
message: "#^Parameter \\#1 \\$name of method Lcobucci\\\\JWT\\\\Builder\\:\\:withClaim\\(\\) expects string, int\\|string given\\.$#"
count: 1
path: app/Services/Nodes/NodeJWTService.php
-
message: "#^Parameter \\#1 \\$key of method Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:setAttribute\\(\\) expects string, int\\|string given\\.$#"
count: 1
path: app/Services/Servers/ServerConfigurationStructureService.php
-
message: "#^Access to an undefined property Illuminate\\\\Database\\\\Eloquent\\\\Collection\\<Pterodactyl\\\\Models\\\\Allocation\\>\\|Pterodactyl\\\\Models\\\\Allocation\\:\\:\\$node_id\\.$#"
count: 1
path: app/Services/Servers/ServerCreationService.php
-
message: "#^Access to an undefined property Illuminate\\\\Database\\\\Eloquent\\\\Collection\\<Pterodactyl\\\\Models\\\\Egg\\>\\|Pterodactyl\\\\Models\\\\Egg\\:\\:\\$nest_id\\.$#"
count: 1
path: app/Services/Servers/ServerCreationService.php
-
message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|false given\\.$#"
count: 1
path: app/Services/Subusers/SubuserCreationService.php
-
message: "#^Parameter \\#1 \\$string of function urlencode expects string, array\\|string\\|null given\\.$#"
count: 1
path: app/Services/Users/TwoFactorSetupService.php
-
message: "#^Cannot call method getResourceName\\(\\) on \\(callable&class\\-string\\)\\|\\(callable&object\\)\\|League\\\\Fractal\\\\TransformerAbstract\\.$#"
count: 2
path: app/Transformers/Api/Transformer.php
-
message: "#^Cannot call method setTimezone\\(\\) on Carbon\\\\CarbonImmutable\\|false\\.$#"
count: 1
path: app/Transformers/Api/Transformer.php
-
message: "#^Parameter \\#1 \\$object_or_class of function method_exists expects object\\|string, \\(callable\\)\\|League\\\\Fractal\\\\TransformerAbstract given\\.$#"
count: 2
path: app/Transformers/Api/Transformer.php

15
phpstan.neon Normal file
View file

@ -0,0 +1,15 @@
includes:
- ./phpstan-baseline.neon
- ./vendor/nunomaduro/larastan/extension.neon
- ./vendor/phpstan/phpstan-webmozart-assert/extension.neon
parameters:
paths:
- app
- database/Seeders
level: 7
ignoreErrors:
- '#Unsafe usage of new static#'
- '#has no return typehint specified.#'
- '#has no typehint specified.#'
checkMissingIterableValueType: false

Some files were not shown because too many files have changed in this diff Show more