mirror of
https://github.com/pelican-dev/panel.git
synced 2025-05-19 22:14:45 +02:00
Merge branch 'main' into lance/phpstan-return-types
This commit is contained in:
commit
81c75f7966
@ -11,11 +11,8 @@ class CheckEggUpdatesCommand extends Command
|
||||
{
|
||||
protected $signature = 'p:egg:check-updates';
|
||||
|
||||
public function handle(): void
|
||||
public function handle(EggExporterService $exporterService): void
|
||||
{
|
||||
/** @var EggExporterService $exporterService */
|
||||
$exporterService = app(EggExporterService::class);
|
||||
|
||||
$eggs = Egg::all();
|
||||
foreach ($eggs as $egg) {
|
||||
try {
|
||||
|
@ -64,6 +64,7 @@ class DisplayException extends PanelException implements HttpExceptionInterface
|
||||
return response()->json(Handler::toArray($this), $this->getStatusCode(), $this->getHeaders());
|
||||
}
|
||||
|
||||
// @phpstan-ignore-next-line
|
||||
app(AlertsMessageBag::class)->danger($this->getMessage())->flash();
|
||||
|
||||
return redirect()->back()->withInput();
|
||||
|
@ -273,6 +273,7 @@ class Handler extends ExceptionHandler
|
||||
*/
|
||||
public static function toArray(\Throwable $e): array
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return (new self(app()))->convertExceptionToArray($e);
|
||||
}
|
||||
}
|
||||
|
@ -28,16 +28,20 @@ class Dashboard extends Page
|
||||
|
||||
public string $activeTab = 'nodes';
|
||||
|
||||
private SoftwareVersionService $softwareVersionService;
|
||||
|
||||
public function mount(SoftwareVersionService $softwareVersionService): void
|
||||
{
|
||||
$this->softwareVersionService = $softwareVersionService;
|
||||
}
|
||||
|
||||
public function getViewData(): array
|
||||
{
|
||||
/** @var SoftwareVersionService $softwareVersionService */
|
||||
$softwareVersionService = app(SoftwareVersionService::class);
|
||||
|
||||
return [
|
||||
'inDevelopment' => config('app.version') === 'canary',
|
||||
'version' => $softwareVersionService->versionData()['version'],
|
||||
'latestVersion' => $softwareVersionService->getPanel(),
|
||||
'isLatest' => $softwareVersionService->isLatestPanel(),
|
||||
'version' => $this->softwareVersionService->versionData()['version'],
|
||||
'latestVersion' => $this->softwareVersionService->getPanel(),
|
||||
'isLatest' => $this->softwareVersionService->isLatestPanel(),
|
||||
'eggsCount' => Egg::query()->count(),
|
||||
'nodesList' => ListNodes::getUrl(),
|
||||
'nodesCount' => Node::query()->count(),
|
||||
@ -67,7 +71,7 @@ class Dashboard extends Page
|
||||
CreateAction::make()
|
||||
->label(trans('dashboard/index.sections.intro-support.button_donate'))
|
||||
->icon('tabler-cash')
|
||||
->url($softwareVersionService->getDonations(), true)
|
||||
->url($this->softwareVersionService->getDonations(), true)
|
||||
->color('success'),
|
||||
],
|
||||
'helpActions' => [
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Filament\Pages\Installer;
|
||||
|
||||
use App\Filament\Pages\Dashboard;
|
||||
use App\Filament\Pages\Installer\Steps\AdminUserStep;
|
||||
use App\Filament\Pages\Installer\Steps\CompletedStep;
|
||||
use App\Filament\Pages\Installer\Steps\DatabaseStep;
|
||||
@ -13,7 +14,6 @@ use App\Services\Users\UserCreationService;
|
||||
use App\Traits\CheckMigrationsTrait;
|
||||
use App\Traits\EnvironmentWriterTrait;
|
||||
use Exception;
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Forms\Components\Actions\Action;
|
||||
use Filament\Forms\Components\Wizard;
|
||||
use Filament\Forms\Concerns\InteractsWithForms;
|
||||
@ -104,7 +104,7 @@ class PanelInstaller extends SimplePage implements HasForms
|
||||
auth()->guard()->login($this->user, true);
|
||||
|
||||
// Redirect to admin panel
|
||||
return redirect(Filament::getPanel('admin')->getUrl());
|
||||
return redirect(Dashboard::getUrl());
|
||||
}
|
||||
|
||||
public function writeToEnv(string $key): void
|
||||
@ -160,12 +160,12 @@ class PanelInstaller extends SimplePage implements HasForms
|
||||
}
|
||||
}
|
||||
|
||||
public function createAdminUser(): void
|
||||
public function createAdminUser(UserCreationService $userCreationService): void
|
||||
{
|
||||
try {
|
||||
$userData = array_get($this->data, 'user');
|
||||
$userData['root_admin'] = true;
|
||||
$this->user = app(UserCreationService::class)->handle($userData);
|
||||
$this->user = $userCreationService->handle($userData);
|
||||
} catch (Exception $exception) {
|
||||
report($exception);
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Filament\Pages\Installer\Steps;
|
||||
|
||||
use App\Filament\Pages\Installer\PanelInstaller;
|
||||
use App\Services\Users\UserCreationService;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Wizard\Step;
|
||||
|
||||
@ -28,6 +29,6 @@ class AdminUserStep
|
||||
->password()
|
||||
->revealable(),
|
||||
])
|
||||
->afterValidation(fn () => $installer->createAdminUser());
|
||||
->afterValidation(fn (UserCreationService $service) => $installer->createAdminUser($service));
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ use PDOException;
|
||||
|
||||
class CreateDatabaseHost extends CreateRecord
|
||||
{
|
||||
private HostCreationService $service;
|
||||
|
||||
protected static string $resource = DatabaseHostResource::class;
|
||||
|
||||
protected ?string $heading = 'Database Hosts';
|
||||
@ -26,6 +28,11 @@ class CreateDatabaseHost extends CreateRecord
|
||||
|
||||
protected ?string $subheading = '(database servers that can have individual databases)';
|
||||
|
||||
public function boot(HostCreationService $service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
public function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
@ -96,7 +103,7 @@ class CreateDatabaseHost extends CreateRecord
|
||||
|
||||
protected function handleRecordCreation(array $data): Model
|
||||
{
|
||||
return resolve(HostCreationService::class)->handle($data);
|
||||
return $this->service->handle($data);
|
||||
}
|
||||
|
||||
public function exception(Exception $e, Closure $stopPropagation): void
|
||||
|
@ -23,6 +23,13 @@ class EditDatabaseHost extends EditRecord
|
||||
{
|
||||
protected static string $resource = DatabaseHostResource::class;
|
||||
|
||||
private HostUpdateService $hostUpdateService;
|
||||
|
||||
public function boot(HostUpdateService $hostUpdateService)
|
||||
{
|
||||
$this->hostUpdateService = $hostUpdateService;
|
||||
}
|
||||
|
||||
public function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
@ -105,7 +112,7 @@ class EditDatabaseHost extends EditRecord
|
||||
return $record;
|
||||
}
|
||||
|
||||
return resolve(HostUpdateService::class)->handle($record, $data);
|
||||
return $this->hostUpdateService->handle($record, $data);
|
||||
}
|
||||
|
||||
public function exception(Exception $e, Closure $stopPropagation): void
|
||||
|
@ -280,10 +280,7 @@ class EditEgg extends EditRecord
|
||||
->contained(false),
|
||||
|
||||
])
|
||||
->action(function (array $data, Egg $egg): void {
|
||||
/** @var EggImporterService $eggImportService */
|
||||
$eggImportService = resolve(EggImporterService::class);
|
||||
|
||||
->action(function (array $data, Egg $egg, EggImporterService $eggImportService): void {
|
||||
if (!empty($data['egg'])) {
|
||||
try {
|
||||
$eggImportService->fromFile($data['egg'], $egg);
|
||||
|
@ -66,9 +66,10 @@ class ListEggs extends ListRecords
|
||||
->modalDescription('If you made any changes to the egg they will be overwritten!')
|
||||
->modalIconColor('danger')
|
||||
->modalSubmitAction(fn (Actions\StaticAction $action) => $action->color('danger'))
|
||||
->action(function (Egg $egg) {
|
||||
->action(function (Egg $egg, EggImporterService $eggImporterService) {
|
||||
try {
|
||||
app(EggImporterService::class)->fromUrl($egg->update_url, $egg);
|
||||
$eggImporterService->fromUrl($egg->update_url, $egg);
|
||||
|
||||
cache()->forget("eggs.{$egg->uuid}.update");
|
||||
} catch (Exception $exception) {
|
||||
Notification::make()
|
||||
@ -129,10 +130,7 @@ class ListEggs extends ListRecords
|
||||
->contained(false),
|
||||
|
||||
])
|
||||
->action(function (array $data): void {
|
||||
/** @var EggImporterService $eggImportService */
|
||||
$eggImportService = resolve(EggImporterService::class);
|
||||
|
||||
->action(function (array $data, EggImporterService $eggImportService): void {
|
||||
if (!empty($data['egg'])) {
|
||||
/** @var TemporaryUploadedFile[] $eggFile */
|
||||
$eggFile = $data['egg'];
|
||||
|
@ -398,7 +398,7 @@ class CreateNode extends CreateRecord
|
||||
protected function getRedirectUrlParameters(): array
|
||||
{
|
||||
return [
|
||||
'tab' => '-configuration-tab',
|
||||
'tab' => '-configuration-file-tab',
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -148,7 +148,7 @@ class AllocationsRelationManager extends RelationManager
|
||||
->splitKeys(['Tab', ' ', ','])
|
||||
->required(),
|
||||
])
|
||||
->action(fn (array $data) => resolve(AssignmentService::class)->handle($this->getOwnerRecord(), $data)),
|
||||
->action(fn (array $data, AssignmentService $service) => $service->handle($this->getOwnerRecord(), $data)),
|
||||
])
|
||||
->bulkActions([
|
||||
BulkActionGroup::make([
|
||||
|
@ -49,6 +49,13 @@ class CreateServer extends CreateRecord
|
||||
|
||||
public ?Node $node = null;
|
||||
|
||||
private ServerCreationService $serverCreationService;
|
||||
|
||||
public function boot(ServerCreationService $serverCreationService)
|
||||
{
|
||||
$this->serverCreationService = $serverCreationService;
|
||||
}
|
||||
|
||||
public function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
@ -118,8 +125,9 @@ class CreateServer extends CreateRecord
|
||||
->hintIconTooltip('Providing a user password is optional. New user email will prompt users to create a password the first time they login.')
|
||||
->password(),
|
||||
])
|
||||
->createOptionUsing(function ($data) {
|
||||
resolve(UserCreationService::class)->handle($data);
|
||||
->createOptionUsing(function ($data, UserCreationService $service) {
|
||||
$service->handle($data);
|
||||
|
||||
$this->refreshForm();
|
||||
})
|
||||
->required(),
|
||||
@ -262,9 +270,9 @@ class CreateServer extends CreateRecord
|
||||
->splitKeys(['Tab', ' ', ','])
|
||||
->required(),
|
||||
])
|
||||
->createOptionUsing(function (array $data, Get $get): int {
|
||||
->createOptionUsing(function (array $data, Get $get, AssignmentService $assignmentService): int {
|
||||
return collect(
|
||||
resolve(AssignmentService::class)->handle(Node::find($get('node_id')), $data)
|
||||
$assignmentService->handle(Node::find($get('node_id')), $data)
|
||||
)->first();
|
||||
})
|
||||
->required(),
|
||||
@ -825,10 +833,7 @@ class CreateServer extends CreateRecord
|
||||
{
|
||||
$data['allocation_additional'] = collect($data['allocation_additional'])->filter()->all();
|
||||
|
||||
/** @var ServerCreationService $service */
|
||||
$service = resolve(ServerCreationService::class);
|
||||
|
||||
return $service->handle($data);
|
||||
return $this->serverCreationService->handle($data);
|
||||
}
|
||||
|
||||
private function shouldHideComponent(Get $get, Component $component): bool
|
||||
|
@ -749,8 +749,8 @@ class EditServer extends EditRecord
|
||||
->color('danger')
|
||||
->label('Delete')
|
||||
->requiresConfirmation()
|
||||
->action(function (Server $server) {
|
||||
resolve(ServerDeletionService::class)->handle($server);
|
||||
->action(function (Server $server, ServerDeletionService $service) {
|
||||
$service->handle($server);
|
||||
|
||||
return redirect(ListServers::getUrl());
|
||||
})
|
||||
|
@ -144,7 +144,7 @@ class AllocationsRelationManager extends RelationManager
|
||||
->splitKeys(['Tab', ' ', ','])
|
||||
->required(),
|
||||
])
|
||||
->action(fn (array $data) => resolve(AssignmentService::class)->handle($this->getOwnerRecord()->node, $data, $this->getOwnerRecord())),
|
||||
->action(fn (array $data, AssignmentService $service) => $service->handle($this->getOwnerRecord()->node, $data, $this->getOwnerRecord())),
|
||||
AssociateAction::make()
|
||||
->multiple()
|
||||
->associateAnother(false)
|
||||
|
@ -40,6 +40,13 @@ use Illuminate\Validation\Rules\Password;
|
||||
*/
|
||||
class EditProfile extends \Filament\Pages\Auth\EditProfile
|
||||
{
|
||||
private ToggleTwoFactorService $toggleTwoFactorService;
|
||||
|
||||
public function boot(ToggleTwoFactorService $toggleTwoFactorService): void
|
||||
{
|
||||
$this->toggleTwoFactorService = $toggleTwoFactorService;
|
||||
}
|
||||
|
||||
protected function getForms(): array
|
||||
{
|
||||
return [
|
||||
@ -108,7 +115,7 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile
|
||||
|
||||
Tab::make('2FA')
|
||||
->icon('tabler-shield-lock')
|
||||
->schema(function () {
|
||||
->schema(function (TwoFactorSetupService $setupService) {
|
||||
if ($this->getUser()->use_totp) {
|
||||
return [
|
||||
Placeholder::make('2fa-already-enabled')
|
||||
@ -126,8 +133,6 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile
|
||||
->helperText('Enter your current 2FA code to disable Two Factor Authentication'),
|
||||
];
|
||||
}
|
||||
/** @var TwoFactorSetupService */
|
||||
$setupService = app(TwoFactorSetupService::class);
|
||||
|
||||
['image_url_data' => $url, 'secret' => $secret] = cache()->remember(
|
||||
"users.{$this->getUser()->id}.2fa.state",
|
||||
@ -283,20 +288,14 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile
|
||||
}
|
||||
|
||||
if ($token = $data['2facode'] ?? null) {
|
||||
/** @var ToggleTwoFactorService $service */
|
||||
$service = resolve(ToggleTwoFactorService::class);
|
||||
|
||||
$tokens = $service->handle($record, $token, true);
|
||||
$tokens = $this->toggleTwoFactorService->handle($record, $token, true);
|
||||
cache()->set("users.$record->id.2fa.tokens", implode("\n", $tokens), now()->addSeconds(15));
|
||||
|
||||
$this->redirectRoute('filament.admin.auth.profile', ['tab' => '-2fa-tab']);
|
||||
}
|
||||
|
||||
if ($token = $data['2fa-disable-code'] ?? null) {
|
||||
/** @var ToggleTwoFactorService $service */
|
||||
$service = resolve(ToggleTwoFactorService::class);
|
||||
|
||||
$service->handle($record, $token, false);
|
||||
$this->toggleTwoFactorService->handle($record, $token, false);
|
||||
|
||||
cache()->forget("users.$record->id.2fa.state");
|
||||
}
|
||||
|
@ -110,13 +110,11 @@ class ListUsers extends ListRecords
|
||||
]),
|
||||
])
|
||||
->successRedirectUrl(route('filament.admin.resources.users.index'))
|
||||
->action(function (array $data) {
|
||||
->action(function (array $data, UserCreationService $creationService) {
|
||||
$roles = $data['roles'];
|
||||
$roles = collect($roles)->map(fn ($role) => Role::findById($role));
|
||||
unset($data['roles']);
|
||||
|
||||
/** @var UserCreationService $creationService */
|
||||
$creationService = resolve(UserCreationService::class);
|
||||
$user = $creationService->handle($data);
|
||||
|
||||
$user->syncRoles($roles);
|
||||
|
@ -32,18 +32,18 @@ class ServersRelationManager extends RelationManager
|
||||
)
|
||||
->label('Suspend All Servers')
|
||||
->color('warning')
|
||||
->action(function () use ($user) {
|
||||
->action(function (SuspensionService $suspensionService) use ($user) {
|
||||
foreach ($user->servers()->whereNot('status', ServerState::Suspended)->get() as $server) {
|
||||
resolve(SuspensionService::class)->toggle($server);
|
||||
$suspensionService->toggle($server);
|
||||
}
|
||||
}),
|
||||
Actions\Action::make('toggleUnsuspend')
|
||||
->hidden(fn () => $user->servers()->where('status', ServerState::Suspended)->count() === 0)
|
||||
->label('Unsuspend All Servers')
|
||||
->color('primary')
|
||||
->action(function () use ($user) {
|
||||
->action(function (SuspensionService $suspensionService) use ($user) {
|
||||
foreach ($user->servers()->where('status', ServerState::Suspended)->get() as $server) {
|
||||
resolve(SuspensionService::class)->toggle($server, SuspensionService::ACTION_UNSUSPEND);
|
||||
$suspensionService->toggle($server, SuspensionService::ACTION_UNSUSPEND);
|
||||
}
|
||||
}),
|
||||
])
|
||||
|
@ -3,23 +3,26 @@
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use App\Events\Auth\FailedCaptcha;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class VerifyReCaptcha
|
||||
readonly class VerifyReCaptcha
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*/
|
||||
public function __construct(private Application $app)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function handle(Request $request, \Closure $next): mixed
|
||||
{
|
||||
if (!config('recaptcha.enabled')) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
if (app()->isLocal()) {
|
||||
if ($this->app->isLocal()) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
|
@ -295,6 +295,7 @@ class Node extends Model
|
||||
{
|
||||
return once(function () {
|
||||
try {
|
||||
// @phpstan-ignore-next-line
|
||||
return resolve(DaemonConfigurationRepository::class)
|
||||
->setNode($this)
|
||||
->getSystemInformation(connectTimeout: 3);
|
||||
|
38
app/PHPStan/ForbiddenGlobalFunctionsRule.php
Normal file
38
app/PHPStan/ForbiddenGlobalFunctionsRule.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\PHPStan;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Rules\Rule;
|
||||
|
||||
class ForbiddenGlobalFunctionsRule implements Rule
|
||||
{
|
||||
private array $forbiddenFunctions;
|
||||
|
||||
public function __construct(array $forbiddenFunctions = ['app', 'resolve'])
|
||||
{
|
||||
$this->forbiddenFunctions = $forbiddenFunctions;
|
||||
}
|
||||
|
||||
public function getNodeType(): string
|
||||
{
|
||||
return FuncCall::class;
|
||||
}
|
||||
|
||||
public function processNode(Node $node, Scope $scope): array
|
||||
{
|
||||
/** @var FuncCall $node */
|
||||
if ($node->name instanceof Node\Name) {
|
||||
$functionName = (string) $node->name;
|
||||
if (in_array($functionName, $this->forbiddenFunctions, true)) {
|
||||
return [
|
||||
sprintf('Usage of global function "%s" is forbidden.', $functionName),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ use Dedoc\Scramble\Support\Generator\SecurityScheme;
|
||||
use Filament\Support\Colors\Color;
|
||||
use Filament\Support\Facades\FilamentColor;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Pagination\Paginator;
|
||||
use Illuminate\Support\Facades\Broadcast;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
@ -29,7 +30,7 @@ class AppServiceProvider extends ServiceProvider
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*/
|
||||
public function boot(): void
|
||||
public function boot(Application $app): void
|
||||
{
|
||||
// TODO: remove when old admin area gets yeeted
|
||||
View::share('appVersion', config('app.version'));
|
||||
@ -64,7 +65,7 @@ class AppServiceProvider extends ServiceProvider
|
||||
->asJson()
|
||||
->withToken($node->daemon_token)
|
||||
->withHeaders($headers)
|
||||
->withOptions(['verify' => (bool) app()->environment('production')])
|
||||
->withOptions(['verify' => (bool) $app->environment('production')])
|
||||
->timeout(config('panel.guzzle.timeout'))
|
||||
->connectTimeout(config('panel.guzzle.connect_timeout'))
|
||||
->baseUrl($node->getConnectionAddress())
|
||||
|
@ -12,7 +12,7 @@ trait CheckMigrationsTrait
|
||||
protected function hasCompletedMigrations(): bool
|
||||
{
|
||||
/** @var Migrator $migrator */
|
||||
$migrator = app()->make('migrator');
|
||||
$migrator = app()->make('migrator'); // @phpstan-ignore-line
|
||||
|
||||
$files = $migrator->getMigrationFiles(database_path('migrations'));
|
||||
|
||||
|
@ -51,6 +51,7 @@ trait AvailableLanguages
|
||||
*/
|
||||
private function getFilesystemInstance(): Filesystem
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->filesystem = $this->filesystem ?: app()->make(Filesystem::class);
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ abstract class BaseTransformer extends TransformerAbstract
|
||||
*/
|
||||
public static function fromRequest(Request $request): self
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return app(static::class)->setRequest($request);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
includes:
|
||||
- vendor/larastan/larastan/extension.neon
|
||||
|
||||
rules:
|
||||
- App\PHPStan\ForbiddenGlobalFunctionsRule
|
||||
|
||||
parameters:
|
||||
|
||||
paths:
|
||||
|
Loading…
x
Reference in New Issue
Block a user