mirror of
				https://github.com/pelican-dev/panel.git
				synced 2025-10-31 00:26:51 +01:00 
			
		
		
		
	Merge branch 'main' into issue/68
# Conflicts: # app/Filament/Resources/NodeResource/RelationManagers/AllocationsRelationManager.php # app/Filament/Resources/ServerResource/Pages/CreateServer.php # app/Filament/Resources/ServerResource/Pages/EditServer.php # app/Filament/Resources/ServerResource/RelationManagers/AllocationsRelationManager.php # app/Filament/Resources/UserResource/Pages/EditProfile.php # app/Models/Node.php # app/Models/Objects/DeploymentObject.php # app/Services/Allocations/AssignmentService.php # app/Services/Servers/ServerCreationService.php # app/Services/Servers/TransferServerService.php # pint.json
This commit is contained in:
		
						commit
						4f5e9a6c30
					
				| @ -11,11 +11,8 @@ class CheckEggUpdatesCommand extends Command | |||||||
| { | { | ||||||
|     protected $signature = 'p:egg:check-updates'; |     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(); |         $eggs = Egg::all(); | ||||||
|         foreach ($eggs as $egg) { |         foreach ($eggs as $egg) { | ||||||
|             try { |             try { | ||||||
|  | |||||||
| @ -70,7 +70,7 @@ class EmailSettingsCommand extends Command | |||||||
|     /** |     /** | ||||||
|      * Handle variables for SMTP driver. |      * Handle variables for SMTP driver. | ||||||
|      */ |      */ | ||||||
|     private function setupSmtpDriverVariables() |     private function setupSmtpDriverVariables(): void | ||||||
|     { |     { | ||||||
|         $this->variables['MAIL_HOST'] = $this->option('host') ?? $this->ask( |         $this->variables['MAIL_HOST'] = $this->option('host') ?? $this->ask( | ||||||
|             trans('command/messages.environment.mail.ask_smtp_host'), |             trans('command/messages.environment.mail.ask_smtp_host'), | ||||||
| @ -101,7 +101,7 @@ class EmailSettingsCommand extends Command | |||||||
|     /** |     /** | ||||||
|      * Handle variables for mailgun driver. |      * Handle variables for mailgun driver. | ||||||
|      */ |      */ | ||||||
|     private function setupMailgunDriverVariables() |     private function setupMailgunDriverVariables(): void | ||||||
|     { |     { | ||||||
|         $this->variables['MAILGUN_DOMAIN'] = $this->option('host') ?? $this->ask( |         $this->variables['MAILGUN_DOMAIN'] = $this->option('host') ?? $this->ask( | ||||||
|             trans('command/messages.environment.mail.ask_mailgun_domain'), |             trans('command/messages.environment.mail.ask_mailgun_domain'), | ||||||
| @ -122,7 +122,7 @@ class EmailSettingsCommand extends Command | |||||||
|     /** |     /** | ||||||
|      * Handle variables for mandrill driver. |      * Handle variables for mandrill driver. | ||||||
|      */ |      */ | ||||||
|     private function setupMandrillDriverVariables() |     private function setupMandrillDriverVariables(): void | ||||||
|     { |     { | ||||||
|         $this->variables['MANDRILL_SECRET'] = $this->option('password') ?? $this->ask( |         $this->variables['MANDRILL_SECRET'] = $this->option('password') ?? $this->ask( | ||||||
|             trans('command/messages.environment.mail.ask_mandrill_secret'), |             trans('command/messages.environment.mail.ask_mandrill_secret'), | ||||||
| @ -133,7 +133,7 @@ class EmailSettingsCommand extends Command | |||||||
|     /** |     /** | ||||||
|      * Handle variables for postmark driver. |      * Handle variables for postmark driver. | ||||||
|      */ |      */ | ||||||
|     private function setupPostmarkDriverVariables() |     private function setupPostmarkDriverVariables(): void | ||||||
|     { |     { | ||||||
|         $this->variables['MAIL_DRIVER'] = 'smtp'; |         $this->variables['MAIL_DRIVER'] = 'smtp'; | ||||||
|         $this->variables['MAIL_HOST'] = 'smtp.postmarkapp.com'; |         $this->variables['MAIL_HOST'] = 'smtp.postmarkapp.com'; | ||||||
|  | |||||||
| @ -51,7 +51,7 @@ class ProcessRunnableCommand extends Command | |||||||
|      * never throw an exception out, otherwise you'll end up killing the entire run group causing |      * never throw an exception out, otherwise you'll end up killing the entire run group causing | ||||||
|      * any other schedules to not process correctly. |      * any other schedules to not process correctly. | ||||||
|      */ |      */ | ||||||
|     protected function processSchedule(Schedule $schedule) |     protected function processSchedule(Schedule $schedule): void | ||||||
|     { |     { | ||||||
|         if ($schedule->tasks->isEmpty()) { |         if ($schedule->tasks->isEmpty()) { | ||||||
|             return; |             return; | ||||||
|  | |||||||
| @ -178,7 +178,7 @@ class UpgradeCommand extends Command | |||||||
|         $this->info(__('commands.upgrade.success')); |         $this->info(__('commands.upgrade.success')); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function withProgress(ProgressBar $bar, \Closure $callback) |     protected function withProgress(ProgressBar $bar, \Closure $callback): void | ||||||
|     { |     { | ||||||
|         $bar->clear(); |         $bar->clear(); | ||||||
|         $callback(); |         $callback(); | ||||||
|  | |||||||
| @ -4,6 +4,8 @@ namespace App\Exceptions; | |||||||
| 
 | 
 | ||||||
| use Exception; | use Exception; | ||||||
| use Filament\Notifications\Notification; | use Filament\Notifications\Notification; | ||||||
|  | use Illuminate\Http\JsonResponse; | ||||||
|  | use Illuminate\Http\RedirectResponse; | ||||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||||
| use Psr\Log\LoggerInterface; | use Psr\Log\LoggerInterface; | ||||||
| use Illuminate\Http\Response; | use Illuminate\Http\Response; | ||||||
| @ -14,8 +16,11 @@ use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; | |||||||
| class DisplayException extends PanelException implements HttpExceptionInterface | class DisplayException extends PanelException implements HttpExceptionInterface | ||||||
| { | { | ||||||
|     public const LEVEL_DEBUG = 'debug'; |     public const LEVEL_DEBUG = 'debug'; | ||||||
|  | 
 | ||||||
|     public const LEVEL_INFO = 'info'; |     public const LEVEL_INFO = 'info'; | ||||||
|  | 
 | ||||||
|     public const LEVEL_WARNING = 'warning'; |     public const LEVEL_WARNING = 'warning'; | ||||||
|  | 
 | ||||||
|     public const LEVEL_ERROR = 'error'; |     public const LEVEL_ERROR = 'error'; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -46,7 +51,7 @@ class DisplayException extends PanelException implements HttpExceptionInterface | |||||||
|      * and then redirecting them back to the page that they came from. If the |      * and then redirecting them back to the page that they came from. If the | ||||||
|      * request originated from an API hit, return the error in JSONAPI spec format. |      * request originated from an API hit, return the error in JSONAPI spec format. | ||||||
|      */ |      */ | ||||||
|     public function render(Request $request) |     public function render(Request $request): bool|RedirectResponse|JsonResponse | ||||||
|     { |     { | ||||||
|         if ($request->is('livewire/update')) { |         if ($request->is('livewire/update')) { | ||||||
|             Notification::make() |             Notification::make() | ||||||
| @ -55,13 +60,14 @@ class DisplayException extends PanelException implements HttpExceptionInterface | |||||||
|                 ->danger() |                 ->danger() | ||||||
|                 ->send(); |                 ->send(); | ||||||
| 
 | 
 | ||||||
|             return; |             return false; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if ($request->expectsJson()) { |         if ($request->expectsJson()) { | ||||||
|             return response()->json(Handler::toArray($this), $this->getStatusCode(), $this->getHeaders()); |             return response()->json(Handler::toArray($this), $this->getStatusCode(), $this->getHeaders()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         // @phpstan-ignore-next-line
 | ||||||
|         app(AlertsMessageBag::class)->danger($this->getMessage())->flash(); |         app(AlertsMessageBag::class)->danger($this->getMessage())->flash(); | ||||||
| 
 | 
 | ||||||
|         return redirect()->back()->withInput(); |         return redirect()->back()->withInput(); | ||||||
| @ -73,10 +79,10 @@ class DisplayException extends PanelException implements HttpExceptionInterface | |||||||
|      * |      * | ||||||
|      * @throws \Throwable |      * @throws \Throwable | ||||||
|      */ |      */ | ||||||
|     public function report() |     public function report(): void | ||||||
|     { |     { | ||||||
|         if (!$this->getPrevious() instanceof \Exception || !Handler::isReportable($this->getPrevious())) { |         if (!$this->getPrevious() instanceof \Exception || !Handler::isReportable($this->getPrevious())) { | ||||||
|             return null; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
| @ -85,6 +91,6 @@ class DisplayException extends PanelException implements HttpExceptionInterface | |||||||
|             throw $this->getPrevious(); |             throw $this->getPrevious(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return $logger->{$this->getErrorLevel()}($this->getPrevious()); |         $logger->{$this->getErrorLevel()}($this->getPrevious()); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -273,6 +273,7 @@ class Handler extends ExceptionHandler | |||||||
|      */ |      */ | ||||||
|     public static function toArray(\Throwable $e): array |     public static function toArray(\Throwable $e): array | ||||||
|     { |     { | ||||||
|  |         // @phpstan-ignore-next-line
 | ||||||
|         return (new self(app()))->convertExceptionToArray($e); |         return (new self(app()))->convertExceptionToArray($e); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ class HttpForbiddenException extends HttpException | |||||||
|     /** |     /** | ||||||
|      * HttpForbiddenException constructor. |      * HttpForbiddenException constructor. | ||||||
|      */ |      */ | ||||||
|     public function __construct(string $message = null, \Throwable $previous = null) |     public function __construct(?string $message = null, ?\Throwable $previous = null) | ||||||
|     { |     { | ||||||
|         parent::__construct(Response::HTTP_FORBIDDEN, $message, $previous); |         parent::__construct(Response::HTTP_FORBIDDEN, $message, $previous); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -12,7 +12,7 @@ class ServerStateConflictException extends ConflictHttpException | |||||||
|      * Exception thrown when the server is in an unsupported state for API access or |      * Exception thrown when the server is in an unsupported state for API access or | ||||||
|      * certain operations within the codebase. |      * certain operations within the codebase. | ||||||
|      */ |      */ | ||||||
|     public function __construct(Server $server, \Throwable $previous = null) |     public function __construct(Server $server, ?\Throwable $previous = null) | ||||||
|     { |     { | ||||||
|         $message = 'This server is currently in an unsupported state, please try again later.'; |         $message = 'This server is currently in an unsupported state, please try again later.'; | ||||||
|         if ($server->isSuspended()) { |         if ($server->isSuspended()) { | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ class TwoFactorAuthRequiredException extends HttpException implements HttpExcept | |||||||
|     /** |     /** | ||||||
|      * TwoFactorAuthRequiredException constructor. |      * TwoFactorAuthRequiredException constructor. | ||||||
|      */ |      */ | ||||||
|     public function __construct(\Throwable $previous = null) |     public function __construct(?\Throwable $previous = null) | ||||||
|     { |     { | ||||||
|         parent::__construct(Response::HTTP_BAD_REQUEST, 'Two-factor authentication is required on this account in order to access this endpoint.', $previous); |         parent::__construct(Response::HTTP_BAD_REQUEST, 'Two-factor authentication is required on this account in order to access this endpoint.', $previous); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ class ServiceLimitExceededException extends DisplayException | |||||||
|      * Exception thrown when something goes over a defined limit, such as allocated |      * Exception thrown when something goes over a defined limit, such as allocated | ||||||
|      * ports, tasks, databases, etc. |      * ports, tasks, databases, etc. | ||||||
|      */ |      */ | ||||||
|     public function __construct(string $message, \Throwable $previous = null) |     public function __construct(string $message, ?\Throwable $previous = null) | ||||||
|     { |     { | ||||||
|         parent::__construct($message, $previous, self::LEVEL_WARNING); |         parent::__construct($message, $previous, self::LEVEL_WARNING); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ use App\Exceptions\DisplayException; | |||||||
| class TwoFactorAuthenticationTokenInvalid extends DisplayException | class TwoFactorAuthenticationTokenInvalid extends DisplayException | ||||||
| { | { | ||||||
|     public string $title = 'Invalid 2FA Code'; |     public string $title = 'Invalid 2FA Code'; | ||||||
|  | 
 | ||||||
|     public string $icon = 'tabler-2fa'; |     public string $icon = 'tabler-2fa'; | ||||||
| 
 | 
 | ||||||
|     public function __construct() |     public function __construct() | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ class BackupManager | |||||||
|     /** |     /** | ||||||
|      * Returns a backup adapter instance. |      * Returns a backup adapter instance. | ||||||
|      */ |      */ | ||||||
|     public function adapter(string $name = null): FilesystemAdapter |     public function adapter(?string $name = null): FilesystemAdapter | ||||||
|     { |     { | ||||||
|         return $this->get($name ?: $this->getDefaultAdapter()); |         return $this->get($name ?: $this->getDefaultAdapter()); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -7,7 +7,9 @@ use App\Models\DatabaseHost; | |||||||
| class DynamicDatabaseConnection | class DynamicDatabaseConnection | ||||||
| { | { | ||||||
|     public const DB_CHARSET = 'utf8'; |     public const DB_CHARSET = 'utf8'; | ||||||
|  | 
 | ||||||
|     public const DB_COLLATION = 'utf8_unicode_ci'; |     public const DB_COLLATION = 'utf8_unicode_ci'; | ||||||
|  | 
 | ||||||
|     public const DB_DRIVER = 'mysql'; |     public const DB_DRIVER = 'mysql'; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -4,17 +4,17 @@ namespace App\Extensions\Themes; | |||||||
| 
 | 
 | ||||||
| class Theme | class Theme | ||||||
| { | { | ||||||
|     public function js($path): string |     public function js(string $path): string | ||||||
|     { |     { | ||||||
|         return sprintf('<script src="%s"></script>' . PHP_EOL, $this->getUrl($path)); |         return sprintf('<script src="%s"></script>' . PHP_EOL, $this->getUrl($path)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function css($path): string |     public function css(string $path): string | ||||||
|     { |     { | ||||||
|         return sprintf('<link media="all" type="text/css" rel="stylesheet" href="%s"/>' . PHP_EOL, $this->getUrl($path)); |         return sprintf('<link media="all" type="text/css" rel="stylesheet" href="%s"/>' . PHP_EOL, $this->getUrl($path)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function getUrl($path): string |     protected function getUrl(string $path): string | ||||||
|     { |     { | ||||||
|         return '/themes/panel/' . ltrim($path, '/'); |         return '/themes/panel/' . ltrim($path, '/'); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -28,16 +28,20 @@ class Dashboard extends Page | |||||||
| 
 | 
 | ||||||
|     public string $activeTab = 'nodes'; |     public string $activeTab = 'nodes'; | ||||||
| 
 | 
 | ||||||
|  |     private SoftwareVersionService $softwareVersionService; | ||||||
|  | 
 | ||||||
|  |     public function mount(SoftwareVersionService $softwareVersionService): void | ||||||
|  |     { | ||||||
|  |         $this->softwareVersionService = $softwareVersionService; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function getViewData(): array |     public function getViewData(): array | ||||||
|     { |     { | ||||||
|         /** @var SoftwareVersionService $softwareVersionService */ |  | ||||||
|         $softwareVersionService = app(SoftwareVersionService::class); |  | ||||||
| 
 |  | ||||||
|         return [ |         return [ | ||||||
|             'inDevelopment' => config('app.version') === 'canary', |             'inDevelopment' => config('app.version') === 'canary', | ||||||
|             'version' => $softwareVersionService->versionData()['version'], |             'version' => $this->softwareVersionService->versionData()['version'], | ||||||
|             'latestVersion' => $softwareVersionService->getPanel(), |             'latestVersion' => $this->softwareVersionService->getPanel(), | ||||||
|             'isLatest' => $softwareVersionService->isLatestPanel(), |             'isLatest' => $this->softwareVersionService->isLatestPanel(), | ||||||
|             'eggsCount' => Egg::query()->count(), |             'eggsCount' => Egg::query()->count(), | ||||||
|             'nodesList' => ListNodes::getUrl(), |             'nodesList' => ListNodes::getUrl(), | ||||||
|             'nodesCount' => Node::query()->count(), |             'nodesCount' => Node::query()->count(), | ||||||
| @ -67,7 +71,7 @@ class Dashboard extends Page | |||||||
|                 CreateAction::make() |                 CreateAction::make() | ||||||
|                     ->label(trans('dashboard/index.sections.intro-support.button_donate')) |                     ->label(trans('dashboard/index.sections.intro-support.button_donate')) | ||||||
|                     ->icon('tabler-cash') |                     ->icon('tabler-cash') | ||||||
|                     ->url($softwareVersionService->getDonations(), true) |                     ->url($this->softwareVersionService->getDonations(), true) | ||||||
|                     ->color('success'), |                     ->color('success'), | ||||||
|             ], |             ], | ||||||
|             'helpActions' => [ |             'helpActions' => [ | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filament\Pages\Installer; | namespace App\Filament\Pages\Installer; | ||||||
| 
 | 
 | ||||||
|  | use App\Filament\Pages\Dashboard; | ||||||
| use App\Filament\Pages\Installer\Steps\AdminUserStep; | use App\Filament\Pages\Installer\Steps\AdminUserStep; | ||||||
| use App\Filament\Pages\Installer\Steps\CompletedStep; | use App\Filament\Pages\Installer\Steps\CompletedStep; | ||||||
| use App\Filament\Pages\Installer\Steps\DatabaseStep; | use App\Filament\Pages\Installer\Steps\DatabaseStep; | ||||||
| @ -13,7 +14,6 @@ use App\Services\Users\UserCreationService; | |||||||
| use App\Traits\CheckMigrationsTrait; | use App\Traits\CheckMigrationsTrait; | ||||||
| use App\Traits\EnvironmentWriterTrait; | use App\Traits\EnvironmentWriterTrait; | ||||||
| use Exception; | use Exception; | ||||||
| use Filament\Facades\Filament; |  | ||||||
| use Filament\Forms\Components\Actions\Action; | use Filament\Forms\Components\Actions\Action; | ||||||
| use Filament\Forms\Components\Wizard; | use Filament\Forms\Components\Wizard; | ||||||
| use Filament\Forms\Concerns\InteractsWithForms; | use Filament\Forms\Concerns\InteractsWithForms; | ||||||
| @ -24,6 +24,7 @@ use Filament\Notifications\Notification; | |||||||
| use Filament\Pages\SimplePage; | use Filament\Pages\SimplePage; | ||||||
| use Filament\Support\Enums\MaxWidth; | use Filament\Support\Enums\MaxWidth; | ||||||
| use Filament\Support\Exceptions\Halt; | use Filament\Support\Exceptions\Halt; | ||||||
|  | use Illuminate\Http\RedirectResponse; | ||||||
| use Illuminate\Support\Facades\Artisan; | use Illuminate\Support\Facades\Artisan; | ||||||
| use Illuminate\Support\Facades\Blade; | use Illuminate\Support\Facades\Blade; | ||||||
| use Illuminate\Support\HtmlString; | use Illuminate\Support\HtmlString; | ||||||
| @ -37,7 +38,7 @@ class PanelInstaller extends SimplePage implements HasForms | |||||||
|     use EnvironmentWriterTrait; |     use EnvironmentWriterTrait; | ||||||
|     use InteractsWithForms; |     use InteractsWithForms; | ||||||
| 
 | 
 | ||||||
|     public $data = []; |     public array $data = []; | ||||||
| 
 | 
 | ||||||
|     protected static string $view = 'filament.pages.installer'; |     protected static string $view = 'filament.pages.installer'; | ||||||
| 
 | 
 | ||||||
| @ -54,7 +55,7 @@ class PanelInstaller extends SimplePage implements HasForms | |||||||
|         return env('APP_INSTALLED', true); |         return env('APP_INSTALLED', true); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function mount() |     public function mount(): void | ||||||
|     { |     { | ||||||
|         abort_if(self::isInstalled(), 404); |         abort_if(self::isInstalled(), 404); | ||||||
| 
 | 
 | ||||||
| @ -93,7 +94,7 @@ class PanelInstaller extends SimplePage implements HasForms | |||||||
|         return 'data'; |         return 'data'; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function submit() |     public function submit(): RedirectResponse | ||||||
|     { |     { | ||||||
|         // Disable installer
 |         // Disable installer
 | ||||||
|         $this->writeToEnvironment(['APP_INSTALLED' => 'true']); |         $this->writeToEnvironment(['APP_INSTALLED' => 'true']); | ||||||
| @ -103,7 +104,7 @@ class PanelInstaller extends SimplePage implements HasForms | |||||||
|         auth()->guard()->login($this->user, true); |         auth()->guard()->login($this->user, true); | ||||||
| 
 | 
 | ||||||
|         // Redirect to admin panel
 |         // Redirect to admin panel
 | ||||||
|         return redirect(Filament::getPanel('admin')->getUrl()); |         return redirect(Dashboard::getUrl()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function writeToEnv(string $key): void |     public function writeToEnv(string $key): void | ||||||
| @ -159,12 +160,12 @@ class PanelInstaller extends SimplePage implements HasForms | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function createAdminUser(): void |     public function createAdminUser(UserCreationService $userCreationService): void | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             $userData = array_get($this->data, 'user'); |             $userData = array_get($this->data, 'user'); | ||||||
|             $userData['root_admin'] = true; |             $userData['root_admin'] = true; | ||||||
|             $this->user = app(UserCreationService::class)->handle($userData); |             $this->user = $userCreationService->handle($userData); | ||||||
|         } catch (Exception $exception) { |         } catch (Exception $exception) { | ||||||
|             report($exception); |             report($exception); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ | |||||||
| namespace App\Filament\Pages\Installer\Steps; | namespace App\Filament\Pages\Installer\Steps; | ||||||
| 
 | 
 | ||||||
| use App\Filament\Pages\Installer\PanelInstaller; | use App\Filament\Pages\Installer\PanelInstaller; | ||||||
|  | use App\Services\Users\UserCreationService; | ||||||
| use Filament\Forms\Components\TextInput; | use Filament\Forms\Components\TextInput; | ||||||
| use Filament\Forms\Components\Wizard\Step; | use Filament\Forms\Components\Wizard\Step; | ||||||
| 
 | 
 | ||||||
| @ -28,6 +29,6 @@ class AdminUserStep | |||||||
|                     ->password() |                     ->password() | ||||||
|                     ->revealable(), |                     ->revealable(), | ||||||
|             ]) |             ]) | ||||||
|             ->afterValidation(fn () => $installer->createAdminUser()); |             ->afterValidation(fn (UserCreationService $service) => $installer->createAdminUser($service)); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -72,7 +72,7 @@ class DatabaseStep | |||||||
|             }); |             }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static function testConnection(string $driver, $host, $port, $database, $username, $password): bool |     private static function testConnection(string $driver, string $host, string $port, string $database, string $username, string $password): bool | ||||||
|     { |     { | ||||||
|         if ($driver === 'sqlite') { |         if ($driver === 'sqlite') { | ||||||
|             return true; |             return true; | ||||||
|  | |||||||
| @ -56,7 +56,7 @@ class RedisStep | |||||||
|             }); |             }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static function testConnection($host, $port, $username, $password): bool |     private static function testConnection(string $host, string $port, string $username, string $password): bool | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             config()->set('database.redis._panel_install_test', [ |             config()->set('database.redis._panel_install_test', [ | ||||||
|  | |||||||
| @ -38,6 +38,7 @@ class Settings extends Page implements HasForms | |||||||
|     use InteractsWithHeaderActions; |     use InteractsWithHeaderActions; | ||||||
| 
 | 
 | ||||||
|     protected static ?string $navigationIcon = 'tabler-settings'; |     protected static ?string $navigationIcon = 'tabler-settings'; | ||||||
|  | 
 | ||||||
|     protected static ?string $navigationGroup = 'Advanced'; |     protected static ?string $navigationGroup = 'Advanced'; | ||||||
| 
 | 
 | ||||||
|     protected static string $view = 'filament.pages.settings'; |     protected static string $view = 'filament.pages.settings'; | ||||||
|  | |||||||
| @ -5,12 +5,16 @@ namespace App\Filament\Resources; | |||||||
| use App\Filament\Resources\ApiKeyResource\Pages; | use App\Filament\Resources\ApiKeyResource\Pages; | ||||||
| use App\Models\ApiKey; | use App\Models\ApiKey; | ||||||
| use Filament\Resources\Resource; | use Filament\Resources\Resource; | ||||||
|  | use Illuminate\Database\Eloquent\Model; | ||||||
| 
 | 
 | ||||||
| class ApiKeyResource extends Resource | class ApiKeyResource extends Resource | ||||||
| { | { | ||||||
|     protected static ?string $model = ApiKey::class; |     protected static ?string $model = ApiKey::class; | ||||||
|  | 
 | ||||||
|     protected static ?string $label = 'API Key'; |     protected static ?string $label = 'API Key'; | ||||||
|  | 
 | ||||||
|     protected static ?string $navigationIcon = 'tabler-key'; |     protected static ?string $navigationIcon = 'tabler-key'; | ||||||
|  | 
 | ||||||
|     protected static ?string $navigationGroup = 'Advanced'; |     protected static ?string $navigationGroup = 'Advanced'; | ||||||
| 
 | 
 | ||||||
|     public static function getNavigationBadge(): ?string |     public static function getNavigationBadge(): ?string | ||||||
| @ -18,7 +22,7 @@ class ApiKeyResource extends Resource | |||||||
|         return static::getModel()::where('key_type', '2')->count() ?: null; |         return static::getModel()::where('key_type', '2')->count() ?: null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static function canEdit($record): bool |     public static function canEdit(Model $record): bool | ||||||
|     { |     { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ class DatabaseHostResource extends Resource | |||||||
|     protected static ?string $label = 'Database Host'; |     protected static ?string $label = 'Database Host'; | ||||||
| 
 | 
 | ||||||
|     protected static ?string $navigationIcon = 'tabler-database'; |     protected static ?string $navigationIcon = 'tabler-database'; | ||||||
|  | 
 | ||||||
|     protected static ?string $navigationGroup = 'Advanced'; |     protected static ?string $navigationGroup = 'Advanced'; | ||||||
| 
 | 
 | ||||||
|     public static function getNavigationBadge(): ?string |     public static function getNavigationBadge(): ?string | ||||||
|  | |||||||
| @ -5,6 +5,8 @@ namespace App\Filament\Resources\DatabaseHostResource\Pages; | |||||||
| use App\Filament\Resources\DatabaseHostResource; | use App\Filament\Resources\DatabaseHostResource; | ||||||
| use App\Models\Objects\Endpoint; | use App\Models\Objects\Endpoint; | ||||||
| use App\Services\Databases\Hosts\HostCreationService; | use App\Services\Databases\Hosts\HostCreationService; | ||||||
|  | use Closure; | ||||||
|  | use Exception; | ||||||
| use Filament\Forms; | use Filament\Forms; | ||||||
| use Filament\Forms\Components\Section; | use Filament\Forms\Components\Section; | ||||||
| use Filament\Forms\Components\Select; | use Filament\Forms\Components\Select; | ||||||
| @ -17,6 +19,8 @@ use PDOException; | |||||||
| 
 | 
 | ||||||
| class CreateDatabaseHost extends CreateRecord | class CreateDatabaseHost extends CreateRecord | ||||||
| { | { | ||||||
|  |     private HostCreationService $service; | ||||||
|  | 
 | ||||||
|     protected static string $resource = DatabaseHostResource::class; |     protected static string $resource = DatabaseHostResource::class; | ||||||
| 
 | 
 | ||||||
|     protected ?string $heading = 'Database Hosts'; |     protected ?string $heading = 'Database Hosts'; | ||||||
| @ -25,6 +29,11 @@ class CreateDatabaseHost extends CreateRecord | |||||||
| 
 | 
 | ||||||
|     protected ?string $subheading = '(database servers that can have individual databases)'; |     protected ?string $subheading = '(database servers that can have individual databases)'; | ||||||
| 
 | 
 | ||||||
|  |     public function boot(HostCreationService $service): void | ||||||
|  |     { | ||||||
|  |         $this->service = $service; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function form(Form $form): Form |     public function form(Form $form): Form | ||||||
|     { |     { | ||||||
|         return $form |         return $form | ||||||
| @ -95,10 +104,10 @@ class CreateDatabaseHost extends CreateRecord | |||||||
| 
 | 
 | ||||||
|     protected function handleRecordCreation(array $data): Model |     protected function handleRecordCreation(array $data): Model | ||||||
|     { |     { | ||||||
|         return resolve(HostCreationService::class)->handle($data); |         return $this->service->handle($data); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function exception($e, $stopPropagation): void |     public function exception(Exception $e, Closure $stopPropagation): void | ||||||
|     { |     { | ||||||
|         if ($e instanceof PDOException) { |         if ($e instanceof PDOException) { | ||||||
|             Notification::make() |             Notification::make() | ||||||
|  | |||||||
| @ -7,6 +7,8 @@ use App\Filament\Resources\DatabaseHostResource\RelationManagers\DatabasesRelati | |||||||
| use App\Models\DatabaseHost; | use App\Models\DatabaseHost; | ||||||
| use App\Models\Objects\Endpoint; | use App\Models\Objects\Endpoint; | ||||||
| use App\Services\Databases\Hosts\HostUpdateService; | use App\Services\Databases\Hosts\HostUpdateService; | ||||||
|  | use Closure; | ||||||
|  | use Exception; | ||||||
| use Filament\Actions; | use Filament\Actions; | ||||||
| use Filament\Forms; | use Filament\Forms; | ||||||
| use Filament\Forms\Components\Section; | use Filament\Forms\Components\Section; | ||||||
| @ -22,6 +24,13 @@ class EditDatabaseHost extends EditRecord | |||||||
| { | { | ||||||
|     protected static string $resource = DatabaseHostResource::class; |     protected static string $resource = DatabaseHostResource::class; | ||||||
| 
 | 
 | ||||||
|  |     private HostUpdateService $hostUpdateService; | ||||||
|  | 
 | ||||||
|  |     public function boot(HostUpdateService $hostUpdateService): void | ||||||
|  |     { | ||||||
|  |         $this->hostUpdateService = $hostUpdateService; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function form(Form $form): Form |     public function form(Form $form): Form | ||||||
|     { |     { | ||||||
|         return $form |         return $form | ||||||
| @ -98,12 +107,16 @@ class EditDatabaseHost extends EditRecord | |||||||
|         ]; |         ]; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function handleRecordUpdate($record, array $data): Model |     protected function handleRecordUpdate(Model $record, array $data): Model | ||||||
|     { |     { | ||||||
|         return resolve(HostUpdateService::class)->handle($record->id, $data); |         if (!$record instanceof DatabaseHost) { | ||||||
|  |             return $record; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     public function exception($e, $stopPropagation): void |         return $this->hostUpdateService->handle($record, $data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function exception(Exception $e, Closure $stopPropagation): void | ||||||
|     { |     { | ||||||
|         if ($e instanceof PDOException) { |         if ($e instanceof PDOException) { | ||||||
|             Notification::make() |             Notification::make() | ||||||
|  | |||||||
| @ -32,13 +32,16 @@ class ListDatabaseHosts extends ListRecords | |||||||
|                     ->sortable(), |                     ->sortable(), | ||||||
|                 TextColumn::make('username') |                 TextColumn::make('username') | ||||||
|                     ->searchable(), |                     ->searchable(), | ||||||
|                 TextColumn::make('max_databases') |                 TextColumn::make('databases_count') | ||||||
|                     ->numeric() |                     ->counts('databases') | ||||||
|                     ->sortable(), |                     ->icon('tabler-database') | ||||||
|  |                     ->label('Databases'), | ||||||
|                 TextColumn::make('node.name') |                 TextColumn::make('node.name') | ||||||
|                     ->numeric() |                     ->icon('tabler-server-2') | ||||||
|  |                     ->placeholder('No Nodes') | ||||||
|                     ->sortable(), |                     ->sortable(), | ||||||
|             ]) |             ]) | ||||||
|  |             ->checkIfRecordIsSelectableUsing(fn (DatabaseHost $databaseHost) => !$databaseHost->databases_count) | ||||||
|             ->actions([ |             ->actions([ | ||||||
|                 EditAction::make(), |                 EditAction::make(), | ||||||
|             ]) |             ]) | ||||||
|  | |||||||
| @ -8,6 +8,7 @@ use Filament\Forms\Components\Actions\Action; | |||||||
| use Filament\Forms\Components\TextInput; | use Filament\Forms\Components\TextInput; | ||||||
| use Filament\Forms\Form; | use Filament\Forms\Form; | ||||||
| use Filament\Forms\Get; | use Filament\Forms\Get; | ||||||
|  | use Filament\Forms\Set; | ||||||
| use Filament\Resources\RelationManagers\RelationManager; | use Filament\Resources\RelationManagers\RelationManager; | ||||||
| use Filament\Tables\Actions\DeleteAction; | use Filament\Tables\Actions\DeleteAction; | ||||||
| use Filament\Tables\Actions\ViewAction; | use Filament\Tables\Actions\ViewAction; | ||||||
| @ -40,6 +41,7 @@ class DatabasesRelationManager extends RelationManager | |||||||
|                     ->formatStateUsing(fn (Get $get, Database $database) => 'jdbc:mysql://' . $get('username') . ':' . urlencode($database->password) . '@' . $database->host->host . ':' . $database->host->port . '/' . $get('database')), |                     ->formatStateUsing(fn (Get $get, Database $database) => 'jdbc:mysql://' . $get('username') . ':' . urlencode($database->password) . '@' . $database->host->host . ':' . $database->host->port . '/' . $get('database')), | ||||||
|             ]); |             ]); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function table(Table $table): Table |     public function table(Table $table): Table | ||||||
|     { |     { | ||||||
|         return $table |         return $table | ||||||
| @ -60,7 +62,7 @@ class DatabasesRelationManager extends RelationManager | |||||||
|             ]); |             ]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function rotatePassword(DatabasePasswordService $service, Database $database, $set, $get): void |     protected function rotatePassword(DatabasePasswordService $service, Database $database, Set $set, Get $get): void | ||||||
|     { |     { | ||||||
|         $newPassword = $service->handle($database); |         $newPassword = $service->handle($database); | ||||||
|         $jdbcString = 'jdbc:mysql://' . $get('username') . ':' . urlencode($newPassword) . '@' . $database->host->host . ':' . $database->host->port . '/' . $get('database'); |         $jdbcString = 'jdbc:mysql://' . $get('username') . ':' . urlencode($newPassword) . '@' . $database->host->host . ':' . $database->host->port . '/' . $get('database'); | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ class DatabaseResource extends Resource | |||||||
|     protected static ?string $navigationIcon = 'tabler-database'; |     protected static ?string $navigationIcon = 'tabler-database'; | ||||||
| 
 | 
 | ||||||
|     protected static bool $shouldRegisterNavigation = false; |     protected static bool $shouldRegisterNavigation = false; | ||||||
|  | 
 | ||||||
|     protected static ?string $navigationGroup = 'Advanced'; |     protected static ?string $navigationGroup = 'Advanced'; | ||||||
| 
 | 
 | ||||||
|     public static function getNavigationBadge(): ?string |     public static function getNavigationBadge(): ?string | ||||||
|  | |||||||
| @ -21,9 +21,12 @@ class CreateDatabase extends CreateRecord | |||||||
|                     ->searchable() |                     ->searchable() | ||||||
|                     ->preload() |                     ->preload() | ||||||
|                     ->required(), |                     ->required(), | ||||||
|                 TextInput::make('database_host_id') |                 Select::make('database_host_id') | ||||||
|                     ->required() |                     ->relationship('host', 'name') | ||||||
|                     ->numeric(), |                     ->searchable() | ||||||
|  |                     ->selectablePlaceholder(false) | ||||||
|  |                     ->preload() | ||||||
|  |                     ->required(), | ||||||
|                 TextInput::make('database') |                 TextInput::make('database') | ||||||
|                     ->required() |                     ->required() | ||||||
|                     ->maxLength(255), |                     ->maxLength(255), | ||||||
|  | |||||||
| @ -27,6 +27,7 @@ class CreateEgg extends CreateRecord | |||||||
|     protected static string $resource = EggResource::class; |     protected static string $resource = EggResource::class; | ||||||
| 
 | 
 | ||||||
|     protected static bool $canCreateAnother = false; |     protected static bool $canCreateAnother = false; | ||||||
|  | 
 | ||||||
|     public function form(Form $form): Form |     public function form(Form $form): Form | ||||||
|     { |     { | ||||||
|         return $form |         return $form | ||||||
|  | |||||||
| @ -280,10 +280,7 @@ class EditEgg extends EditRecord | |||||||
|                         ->contained(false), |                         ->contained(false), | ||||||
| 
 | 
 | ||||||
|                 ]) |                 ]) | ||||||
|                 ->action(function (array $data, Egg $egg): void { |                 ->action(function (array $data, Egg $egg, EggImporterService $eggImportService): void { | ||||||
|                     /** @var EggImporterService $eggImportService */ |  | ||||||
|                     $eggImportService = resolve(EggImporterService::class); |  | ||||||
| 
 |  | ||||||
|                     if (!empty($data['egg'])) { |                     if (!empty($data['egg'])) { | ||||||
|                         try { |                         try { | ||||||
|                             $eggImportService->fromFile($data['egg'], $egg); |                             $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!') |                     ->modalDescription('If you made any changes to the egg they will be overwritten!') | ||||||
|                     ->modalIconColor('danger') |                     ->modalIconColor('danger') | ||||||
|                     ->modalSubmitAction(fn (Actions\StaticAction $action) => $action->color('danger')) |                     ->modalSubmitAction(fn (Actions\StaticAction $action) => $action->color('danger')) | ||||||
|                     ->action(function (Egg $egg) { |                     ->action(function (Egg $egg, EggImporterService $eggImporterService) { | ||||||
|                         try { |                         try { | ||||||
|                             app(EggImporterService::class)->fromUrl($egg->update_url, $egg); |                             $eggImporterService->fromUrl($egg->update_url, $egg); | ||||||
|  | 
 | ||||||
|                             cache()->forget("eggs.{$egg->uuid}.update"); |                             cache()->forget("eggs.{$egg->uuid}.update"); | ||||||
|                         } catch (Exception $exception) { |                         } catch (Exception $exception) { | ||||||
|                             Notification::make() |                             Notification::make() | ||||||
| @ -97,6 +98,7 @@ class ListEggs extends ListRecords | |||||||
|                 ]), |                 ]), | ||||||
|             ]); |             ]); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     protected function getHeaderActions(): array |     protected function getHeaderActions(): array | ||||||
|     { |     { | ||||||
|         return [ |         return [ | ||||||
| @ -129,10 +131,7 @@ class ListEggs extends ListRecords | |||||||
|                         ->contained(false), |                         ->contained(false), | ||||||
| 
 | 
 | ||||||
|                 ]) |                 ]) | ||||||
|                 ->action(function (array $data): void { |                 ->action(function (array $data, EggImporterService $eggImportService): void { | ||||||
|                     /** @var EggImporterService $eggImportService */ |  | ||||||
|                     $eggImportService = resolve(EggImporterService::class); |  | ||||||
| 
 |  | ||||||
|                     if (!empty($data['egg'])) { |                     if (!empty($data['egg'])) { | ||||||
|                         /** @var TemporaryUploadedFile[] $eggFile */ |                         /** @var TemporaryUploadedFile[] $eggFile */ | ||||||
|                         $eggFile = $data['egg']; |                         $eggFile = $data['egg']; | ||||||
|  | |||||||
| @ -11,6 +11,7 @@ class MountResource extends Resource | |||||||
|     protected static ?string $model = Mount::class; |     protected static ?string $model = Mount::class; | ||||||
| 
 | 
 | ||||||
|     protected static ?string $navigationIcon = 'tabler-layers-linked'; |     protected static ?string $navigationIcon = 'tabler-layers-linked'; | ||||||
|  | 
 | ||||||
|     protected static ?string $navigationGroup = 'Advanced'; |     protected static ?string $navigationGroup = 'Advanced'; | ||||||
| 
 | 
 | ||||||
|     public static function getNavigationBadge(): ?string |     public static function getNavigationBadge(): ?string | ||||||
|  | |||||||
| @ -96,6 +96,7 @@ class EditMount extends EditRecord | |||||||
|                 'lg' => 2, |                 'lg' => 2, | ||||||
|             ]); |             ]); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     protected function getHeaderActions(): array |     protected function getHeaderActions(): array | ||||||
|     { |     { | ||||||
|         return [ |         return [ | ||||||
|  | |||||||
| @ -17,6 +17,7 @@ use Filament\Tables\Table; | |||||||
| class ListMounts extends ListRecords | class ListMounts extends ListRecords | ||||||
| { | { | ||||||
|     protected static string $resource = MountResource::class; |     protected static string $resource = MountResource::class; | ||||||
|  | 
 | ||||||
|     public function table(Table $table): Table |     public function table(Table $table): Table | ||||||
|     { |     { | ||||||
|         return $table |         return $table | ||||||
| @ -56,6 +57,7 @@ class ListMounts extends ListRecords | |||||||
|                     ->button(), |                     ->button(), | ||||||
|             ]); |             ]); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     protected function getHeaderActions(): array |     protected function getHeaderActions(): array | ||||||
|     { |     { | ||||||
|         return [ |         return [ | ||||||
|  | |||||||
| @ -399,7 +399,7 @@ class CreateNode extends CreateRecord | |||||||
|     protected function getRedirectUrlParameters(): array |     protected function getRedirectUrlParameters(): array | ||||||
|     { |     { | ||||||
|         return [ |         return [ | ||||||
|             'tab' => '-configuration-tab', |             'tab' => '-configuration-file-tab', | ||||||
|         ]; |         ]; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -470,12 +470,12 @@ class EditNode extends EditRecord | |||||||
|         $this->fillForm(); |         $this->fillForm(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function getColumnSpan() |     protected function getColumnSpan(): ?int | ||||||
|     { |     { | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function getColumnStart() |     protected function getColumnStart(): ?int | ||||||
|     { |     { | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -12,6 +12,7 @@ use Illuminate\Support\Number; | |||||||
| class NodeCpuChart extends ChartWidget | class NodeCpuChart extends ChartWidget | ||||||
| { | { | ||||||
|     protected static ?string $pollingInterval = '5s'; |     protected static ?string $pollingInterval = '5s'; | ||||||
|  | 
 | ||||||
|     protected static ?string $maxHeight = '300px'; |     protected static ?string $maxHeight = '300px'; | ||||||
| 
 | 
 | ||||||
|     public ?Model $record = null; |     public ?Model $record = null; | ||||||
|  | |||||||
| @ -12,6 +12,7 @@ use Illuminate\Support\Number; | |||||||
| class NodeMemoryChart extends ChartWidget | class NodeMemoryChart extends ChartWidget | ||||||
| { | { | ||||||
|     protected static ?string $pollingInterval = '5s'; |     protected static ?string $pollingInterval = '5s'; | ||||||
|  | 
 | ||||||
|     protected static ?string $maxHeight = '300px'; |     protected static ?string $maxHeight = '300px'; | ||||||
| 
 | 
 | ||||||
|     public ?Model $record = null; |     public ?Model $record = null; | ||||||
|  | |||||||
| @ -9,7 +9,9 @@ use Illuminate\Database\Eloquent\Model; | |||||||
| class NodeStorageChart extends ChartWidget | class NodeStorageChart extends ChartWidget | ||||||
| { | { | ||||||
|     protected static ?string $heading = 'Storage'; |     protected static ?string $heading = 'Storage'; | ||||||
|  | 
 | ||||||
|     protected static ?string $pollingInterval = '60s'; |     protected static ?string $pollingInterval = '60s'; | ||||||
|  | 
 | ||||||
|     protected static ?string $maxHeight = '300px'; |     protected static ?string $maxHeight = '300px'; | ||||||
| 
 | 
 | ||||||
|     public ?Model $record = null; |     public ?Model $record = null; | ||||||
|  | |||||||
| @ -42,6 +42,7 @@ use LogicException; | |||||||
| class CreateServer extends CreateRecord | class CreateServer extends CreateRecord | ||||||
| { | { | ||||||
|     protected static string $resource = ServerResource::class; |     protected static string $resource = ServerResource::class; | ||||||
|  | 
 | ||||||
|     protected static bool $canCreateAnother = false; |     protected static bool $canCreateAnother = false; | ||||||
| 
 | 
 | ||||||
|     public ?Node $node = null; |     public ?Node $node = null; | ||||||
| @ -49,6 +50,13 @@ class CreateServer extends CreateRecord | |||||||
|     public array $ports = []; |     public array $ports = []; | ||||||
|     public array $eggDefaultPorts = []; |     public array $eggDefaultPorts = []; | ||||||
| 
 | 
 | ||||||
|  |     private ServerCreationService $serverCreationService; | ||||||
|  | 
 | ||||||
|  |     public function boot(ServerCreationService $serverCreationService): void | ||||||
|  |     { | ||||||
|  |         $this->serverCreationService = $serverCreationService; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function form(Form $form): Form |     public function form(Form $form): Form | ||||||
|     { |     { | ||||||
|         return $form |         return $form | ||||||
| @ -118,8 +126,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.') |                                         ->hintIconTooltip('Providing a user password is optional. New user email will prompt users to create a password the first time they login.') | ||||||
|                                         ->password(), |                                         ->password(), | ||||||
|                                 ]) |                                 ]) | ||||||
|                                 ->createOptionUsing(function ($data) { |                                 ->createOptionUsing(function ($data, UserCreationService $service) { | ||||||
|                                     resolve(UserCreationService::class)->handle($data); |                                     $service->handle($data); | ||||||
|  | 
 | ||||||
|                                     $this->refreshForm(); |                                     $this->refreshForm(); | ||||||
|                                 }) |                                 }) | ||||||
|                                 ->required(), |                                 ->required(), | ||||||
| @ -726,10 +735,7 @@ class CreateServer extends CreateRecord | |||||||
|             $data['environment'][$env] = $data['ports'][$data['assignments'][$i]]; |             $data['environment'][$env] = $data['ports'][$data['assignments'][$i]]; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         /** @var ServerCreationService $service */ |         return $this->serverCreationService->handle($data, validateVariables: false); | ||||||
|         $service = resolve(ServerCreationService::class); |  | ||||||
| 
 |  | ||||||
|         return $service->handle($data, validateVariables: false); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private function shouldHideComponent(Get $get, Component $component): bool |     private function shouldHideComponent(Get $get, Component $component): bool | ||||||
|  | |||||||
| @ -830,6 +830,7 @@ class EditServer extends EditRecord | |||||||
|             ]); |             ]); | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     protected function getHeaderActions(): array |     protected function getHeaderActions(): array | ||||||
|     { |     { | ||||||
|         return [ |         return [ | ||||||
| @ -838,8 +839,8 @@ class EditServer extends EditRecord | |||||||
|                 ->color('danger') |                 ->color('danger') | ||||||
|                 ->label('Delete') |                 ->label('Delete') | ||||||
|                 ->requiresConfirmation() |                 ->requiresConfirmation() | ||||||
|                 ->action(function (Server $server) { |                 ->action(function (Server $server, ServerDeletionService $service) { | ||||||
|                     resolve(ServerDeletionService::class)->handle($server); |                     $service->handle($server); | ||||||
| 
 | 
 | ||||||
|                     return redirect(ListServers::getUrl()); |                     return redirect(ListServers::getUrl()); | ||||||
|                 }) |                 }) | ||||||
| @ -852,6 +853,7 @@ class EditServer extends EditRecord | |||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     protected function getFormActions(): array |     protected function getFormActions(): array | ||||||
|     { |     { | ||||||
|         return []; |         return []; | ||||||
| @ -969,7 +971,7 @@ class EditServer extends EditRecord | |||||||
|         return $options; |         return $options; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function rotatePassword(DatabasePasswordService $service, $record, $set, $get): void |     protected function rotatePassword(DatabasePasswordService $service, Database $record, Set $set, Get $get): void | ||||||
|     { |     { | ||||||
|         $newPassword = $service->handle($record); |         $newPassword = $service->handle($record); | ||||||
|         $jdbcString = 'jdbc:mysql://' . $get('username') . ':' . urlencode($newPassword) . '@' . $record->host->host . ':' . $record->host->port . '/' . $get('database'); |         $jdbcString = 'jdbc:mysql://' . $get('username') . ':' . urlencode($newPassword) . '@' . $record->host->host . ':' . $record->host->port . '/' . $get('database'); | ||||||
|  | |||||||
| @ -88,6 +88,7 @@ class ListServers extends ListRecords | |||||||
|                     ->button(), |                     ->button(), | ||||||
|             ]); |             ]); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     protected function getHeaderActions(): array |     protected function getHeaderActions(): array | ||||||
|     { |     { | ||||||
|         return [ |         return [ | ||||||
|  | |||||||
| @ -13,7 +13,9 @@ use chillerlan\QRCode\Common\EccLevel; | |||||||
| use chillerlan\QRCode\Common\Version; | use chillerlan\QRCode\Common\Version; | ||||||
| use chillerlan\QRCode\QRCode; | use chillerlan\QRCode\QRCode; | ||||||
| use chillerlan\QRCode\QROptions; | use chillerlan\QRCode\QROptions; | ||||||
|  | use Closure; | ||||||
| use DateTimeZone; | use DateTimeZone; | ||||||
|  | use Exception; | ||||||
| use Filament\Forms\Components\Actions\Action; | use Filament\Forms\Components\Actions\Action; | ||||||
| use Filament\Forms\Components\Grid; | use Filament\Forms\Components\Grid; | ||||||
| use Filament\Forms\Components\Placeholder; | use Filament\Forms\Components\Placeholder; | ||||||
| @ -38,6 +40,13 @@ use Illuminate\Validation\Rules\Password; | |||||||
|  */ |  */ | ||||||
| class EditProfile extends \Filament\Pages\Auth\EditProfile | class EditProfile extends \Filament\Pages\Auth\EditProfile | ||||||
| { | { | ||||||
|  |     private ToggleTwoFactorService $toggleTwoFactorService; | ||||||
|  | 
 | ||||||
|  |     public function boot(ToggleTwoFactorService $toggleTwoFactorService): void | ||||||
|  |     { | ||||||
|  |         $this->toggleTwoFactorService = $toggleTwoFactorService; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     protected function getForms(): array |     protected function getForms(): array | ||||||
|     { |     { | ||||||
|         return [ |         return [ | ||||||
| @ -106,7 +115,7 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile | |||||||
| 
 | 
 | ||||||
|                                 Tab::make('2FA') |                                 Tab::make('2FA') | ||||||
|                                     ->icon('tabler-shield-lock') |                                     ->icon('tabler-shield-lock') | ||||||
|                                     ->schema(function () { |                                     ->schema(function (TwoFactorSetupService $setupService) { | ||||||
|                                         if ($this->getUser()->use_totp) { |                                         if ($this->getUser()->use_totp) { | ||||||
|                                             return [ |                                             return [ | ||||||
|                                                 Placeholder::make('2fa-already-enabled') |                                                 Placeholder::make('2fa-already-enabled') | ||||||
| @ -124,8 +133,6 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile | |||||||
|                                                     ->helperText('Enter your current 2FA code to disable Two Factor Authentication'), |                                                     ->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( |                                         ['image_url_data' => $url, 'secret' => $secret] = cache()->remember( | ||||||
|                                             "users.{$this->getUser()->id}.2fa.state", |                                             "users.{$this->getUser()->id}.2fa.state", | ||||||
| @ -274,23 +281,21 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile | |||||||
|         ]; |         ]; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function handleRecordUpdate($record, $data): Model |     protected function handleRecordUpdate(Model $record, array $data): Model | ||||||
|     { |     { | ||||||
|         if ($token = $data['2facode'] ?? null) { |         if (!$record instanceof User) { | ||||||
|             /** @var ToggleTwoFactorService $service */ |             return $record; | ||||||
|             $service = resolve(ToggleTwoFactorService::class); |         } | ||||||
| 
 | 
 | ||||||
|             $tokens = $service->handle($record, $token, true); |         if ($token = $data['2facode'] ?? null) { | ||||||
|             cache()->set("users.$record->id.2fa.tokens", implode("\n", $tokens), 15); |             $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']); |             $this->redirectRoute('filament.admin.auth.profile', ['tab' => '-2fa-tab']); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if ($token = $data['2fa-disable-code'] ?? null) { |         if ($token = $data['2fa-disable-code'] ?? null) { | ||||||
|             /** @var ToggleTwoFactorService $service */ |             $this->toggleTwoFactorService->handle($record, $token, false); | ||||||
|             $service = resolve(ToggleTwoFactorService::class); |  | ||||||
| 
 |  | ||||||
|             $service->handle($record, $token, false); |  | ||||||
| 
 | 
 | ||||||
|             cache()->forget("users.$record->id.2fa.state"); |             cache()->forget("users.$record->id.2fa.state"); | ||||||
|         } |         } | ||||||
| @ -298,7 +303,7 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile | |||||||
|         return parent::handleRecordUpdate($record, $data); |         return parent::handleRecordUpdate($record, $data); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function exception($e, $stopPropagation): void |     public function exception(Exception $e, Closure $stopPropagation): void | ||||||
|     { |     { | ||||||
|         if ($e instanceof TwoFactorAuthenticationTokenInvalid) { |         if ($e instanceof TwoFactorAuthenticationTokenInvalid) { | ||||||
|             Notification::make() |             Notification::make() | ||||||
|  | |||||||
| @ -18,6 +18,7 @@ use Illuminate\Support\Facades\Hash; | |||||||
| class EditUser extends EditRecord | class EditUser extends EditRecord | ||||||
| { | { | ||||||
|     protected static string $resource = UserResource::class; |     protected static string $resource = UserResource::class; | ||||||
|  | 
 | ||||||
|     public function form(Form $form): Form |     public function form(Form $form): Form | ||||||
|     { |     { | ||||||
|         return $form |         return $form | ||||||
| @ -46,6 +47,7 @@ class EditUser extends EditRecord | |||||||
|                 ])->columns(), |                 ])->columns(), | ||||||
|             ]); |             ]); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     protected function getHeaderActions(): array |     protected function getHeaderActions(): array | ||||||
|     { |     { | ||||||
|         return [ |         return [ | ||||||
|  | |||||||
| @ -78,6 +78,7 @@ class ListUsers extends ListRecords | |||||||
|                 ]), |                 ]), | ||||||
|             ]); |             ]); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     protected function getHeaderActions(): array |     protected function getHeaderActions(): array | ||||||
|     { |     { | ||||||
|         return [ |         return [ | ||||||
| @ -110,13 +111,11 @@ class ListUsers extends ListRecords | |||||||
|                         ]), |                         ]), | ||||||
|                 ]) |                 ]) | ||||||
|                 ->successRedirectUrl(route('filament.admin.resources.users.index')) |                 ->successRedirectUrl(route('filament.admin.resources.users.index')) | ||||||
|                 ->action(function (array $data) { |                 ->action(function (array $data, UserCreationService $creationService) { | ||||||
|                     $roles = $data['roles']; |                     $roles = $data['roles']; | ||||||
|                     $roles = collect($roles)->map(fn ($role) => Role::findById($role)); |                     $roles = collect($roles)->map(fn ($role) => Role::findById($role)); | ||||||
|                     unset($data['roles']); |                     unset($data['roles']); | ||||||
| 
 | 
 | ||||||
|                     /** @var UserCreationService $creationService */ |  | ||||||
|                     $creationService = resolve(UserCreationService::class); |  | ||||||
|                     $user = $creationService->handle($data); |                     $user = $creationService->handle($data); | ||||||
| 
 | 
 | ||||||
|                     $user->syncRoles($roles); |                     $user->syncRoles($roles); | ||||||
|  | |||||||
| @ -31,18 +31,18 @@ class ServersRelationManager extends RelationManager | |||||||
|                     ) |                     ) | ||||||
|                     ->label('Suspend All Servers') |                     ->label('Suspend All Servers') | ||||||
|                     ->color('warning') |                     ->color('warning') | ||||||
|                     ->action(function () use ($user) { |                     ->action(function (SuspensionService $suspensionService) use ($user) { | ||||||
|                         foreach ($user->servers()->whereNot('status', ServerState::Suspended)->get() as $server) { |                         foreach ($user->servers()->whereNot('status', ServerState::Suspended)->get() as $server) { | ||||||
|                             resolve(SuspensionService::class)->toggle($server); |                             $suspensionService->toggle($server); | ||||||
|                         } |                         } | ||||||
|                     }), |                     }), | ||||||
|                 Actions\Action::make('toggleUnsuspend') |                 Actions\Action::make('toggleUnsuspend') | ||||||
|                     ->hidden(fn () => $user->servers()->where('status', ServerState::Suspended)->count() === 0) |                     ->hidden(fn () => $user->servers()->where('status', ServerState::Suspended)->count() === 0) | ||||||
|                     ->label('Unsuspend All Servers') |                     ->label('Unsuspend All Servers') | ||||||
|                     ->color('primary') |                     ->color('primary') | ||||||
|                     ->action(function () use ($user) { |                     ->action(function (SuspensionService $suspensionService) use ($user) { | ||||||
|                         foreach ($user->servers()->where('status', ServerState::Suspended)->get() as $server) { |                         foreach ($user->servers()->where('status', ServerState::Suspended)->get() as $server) { | ||||||
|                             resolve(SuspensionService::class)->toggle($server, SuspensionService::ACTION_UNSUSPEND); |                             $suspensionService->toggle($server, SuspensionService::ACTION_UNSUSPEND); | ||||||
|                         } |                         } | ||||||
|                     }), |                     }), | ||||||
|             ]) |             ]) | ||||||
|  | |||||||
| @ -127,7 +127,7 @@ class EggController extends Controller | |||||||
|     /** |     /** | ||||||
|      * Normalizes a string of docker image data into the expected egg format. |      * Normalizes a string of docker image data into the expected egg format. | ||||||
|      */ |      */ | ||||||
|     protected function normalizeDockerImages(string $input = null): array |     protected function normalizeDockerImages(?string $input = null): array | ||||||
|     { |     { | ||||||
|         $data = array_map(fn ($value) => trim($value), explode("\n", $input ?? '')); |         $data = array_map(fn ($value) => trim($value), explode("\n", $input ?? '')); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ class NodeViewController extends Controller | |||||||
|     use JavascriptInjection; |     use JavascriptInjection; | ||||||
| 
 | 
 | ||||||
|     public const THRESHOLD_PERCENTAGE_LOW = 75; |     public const THRESHOLD_PERCENTAGE_LOW = 75; | ||||||
|  | 
 | ||||||
|     public const THRESHOLD_PERCENTAGE_MEDIUM = 90; |     public const THRESHOLD_PERCENTAGE_MEDIUM = 90; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -70,7 +70,7 @@ class ServersController extends Controller | |||||||
|      * @throws \App\Exceptions\DisplayException |      * @throws \App\Exceptions\DisplayException | ||||||
|      * @throws \App\Exceptions\Model\DataValidationException |      * @throws \App\Exceptions\Model\DataValidationException | ||||||
|      */ |      */ | ||||||
|     public function toggleInstall(Server $server) |     public function toggleInstall(Server $server): void | ||||||
|     { |     { | ||||||
|         if ($server->status === ServerState::InstallFailed) { |         if ($server->status === ServerState::InstallFailed) { | ||||||
|             throw new DisplayException(trans('admin/server.exceptions.marked_as_failed')); |             throw new DisplayException(trans('admin/server.exceptions.marked_as_failed')); | ||||||
| @ -84,8 +84,6 @@ class ServersController extends Controller | |||||||
|             ->body(trans('admin/server.alerts.install_toggled')) |             ->body(trans('admin/server.alerts.install_toggled')) | ||||||
|             ->success() |             ->success() | ||||||
|             ->send(); |             ->send(); | ||||||
| 
 |  | ||||||
|         return null; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -94,7 +92,7 @@ class ServersController extends Controller | |||||||
|      * @throws \App\Exceptions\DisplayException |      * @throws \App\Exceptions\DisplayException | ||||||
|      * @throws \App\Exceptions\Model\DataValidationException |      * @throws \App\Exceptions\Model\DataValidationException | ||||||
|      */ |      */ | ||||||
|     public function reinstallServer(Server $server) |     public function reinstallServer(Server $server): void | ||||||
|     { |     { | ||||||
|         $this->reinstallService->handle($server); |         $this->reinstallService->handle($server); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -40,7 +40,7 @@ abstract class ApplicationApiController extends Controller | |||||||
|      * Perform dependency injection of certain classes needed for core functionality |      * Perform dependency injection of certain classes needed for core functionality | ||||||
|      * without littering the constructors of classes that extend this abstract. |      * without littering the constructors of classes that extend this abstract. | ||||||
|      */ |      */ | ||||||
|     public function loadDependencies(Fractal $fractal, Request $request) |     public function loadDependencies(Fractal $fractal, Request $request): void | ||||||
|     { |     { | ||||||
|         $this->fractal = $fractal; |         $this->fractal = $fractal; | ||||||
|         $this->request = $request; |         $this->request = $request; | ||||||
| @ -52,7 +52,6 @@ abstract class ApplicationApiController extends Controller | |||||||
|      * @template T of \App\Transformers\Api\Application\BaseTransformer |      * @template T of \App\Transformers\Api\Application\BaseTransformer | ||||||
|      * |      * | ||||||
|      * @param  class-string<T>  $abstract |      * @param  class-string<T>  $abstract | ||||||
|      * |  | ||||||
|      * @return T |      * @return T | ||||||
|      * |      * | ||||||
|      * @noinspection PhpDocSignatureInspection |      * @noinspection PhpDocSignatureInspection | ||||||
|  | |||||||
| @ -42,7 +42,6 @@ abstract class ClientApiController extends ApplicationApiController | |||||||
|      * @template T of \App\Transformers\Api\Client\BaseClientTransformer |      * @template T of \App\Transformers\Api\Client\BaseClientTransformer | ||||||
|      * |      * | ||||||
|      * @param  class-string<T>  $abstract |      * @param  class-string<T>  $abstract | ||||||
|      * |  | ||||||
|      * @return T |      * @return T | ||||||
|      * |      * | ||||||
|      * @noinspection PhpDocSignatureInspection |      * @noinspection PhpDocSignatureInspection | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ use App\Http\Requests\Api\Remote\ActivityEventRequest; | |||||||
| 
 | 
 | ||||||
| class ActivityProcessingController extends Controller | class ActivityProcessingController extends Controller | ||||||
| { | { | ||||||
|     public function __invoke(ActivityEventRequest $request) |     public function __invoke(ActivityEventRequest $request): void | ||||||
|     { |     { | ||||||
|         $tz = Carbon::now()->getTimezone(); |         $tz = Carbon::now()->getTimezone(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -51,7 +51,7 @@ abstract class AbstractLoginController extends Controller | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\DisplayException |      * @throws \App\Exceptions\DisplayException | ||||||
|      */ |      */ | ||||||
|     protected function sendFailedLoginResponse(Request $request, Authenticatable $user = null, string $message = null) |     protected function sendFailedLoginResponse(Request $request, ?Authenticatable $user = null, ?string $message = null): never | ||||||
|     { |     { | ||||||
|         $this->incrementLoginAttempts($request); |         $this->incrementLoginAttempts($request); | ||||||
|         $this->fireFailedLoginEvent($user, [ |         $this->fireFailedLoginEvent($user, [ | ||||||
| @ -91,7 +91,7 @@ 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. | ||||||
|      */ |      */ | ||||||
|     protected function getField(string $input = null): string |     protected function getField(?string $input = null): string | ||||||
|     { |     { | ||||||
|         return ($input && str_contains($input, '@')) ? 'email' : 'username'; |         return ($input && str_contains($input, '@')) ? 'email' : 'username'; | ||||||
|     } |     } | ||||||
| @ -99,7 +99,7 @@ abstract class AbstractLoginController extends Controller | |||||||
|     /** |     /** | ||||||
|      * Fire a failed login event. |      * Fire a failed login event. | ||||||
|      */ |      */ | ||||||
|     protected function fireFailedLoginEvent(Authenticatable $user = null, array $credentials = []) |     protected function fireFailedLoginEvent(?Authenticatable $user = null, array $credentials = []): void | ||||||
|     { |     { | ||||||
|         Event::dispatch(new Failed('auth', $user, $credentials)); |         Event::dispatch(new Failed('auth', $user, $credentials)); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ class ForgotPasswordController extends Controller | |||||||
|     /** |     /** | ||||||
|      * Get the response for a failed password reset link. |      * Get the response for a failed password reset link. | ||||||
|      */ |      */ | ||||||
|     protected function sendResetLinkFailedResponse(Request $request, $response): JsonResponse |     protected function sendResetLinkFailedResponse(Request $request, string $response): JsonResponse | ||||||
|     { |     { | ||||||
|         // As noted in #358 we will return success even if it failed
 |         // As noted in #358 we will return success even if it failed
 | ||||||
|         // to avoid pointing out that an account does or does not
 |         // to avoid pointing out that an account does or does not
 | ||||||
| @ -28,10 +28,8 @@ class ForgotPasswordController extends Controller | |||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Get the response for a successful password reset link. |      * Get the response for a successful password reset link. | ||||||
|      * |  | ||||||
|      * @param string $response |  | ||||||
|      */ |      */ | ||||||
|     protected function sendResetLinkResponse(Request $request, $response): JsonResponse |     protected function sendResetLinkResponse(Request $request, string $response): JsonResponse | ||||||
|     { |     { | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'status' => trans($response), |             'status' => trans($response), | ||||||
|  | |||||||
| @ -72,7 +72,7 @@ class LoginCheckpointController extends AbstractLoginController | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return $this->sendFailedLoginResponse($request, $user, !empty($recoveryToken) ? 'The recovery token provided is not valid.' : null); |         $this->sendFailedLoginResponse($request, $user, !empty($recoveryToken) ? 'The recovery token provided is not valid.' : null); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -4,11 +4,13 @@ namespace App\Http\Controllers\Auth; | |||||||
| 
 | 
 | ||||||
| use App\Filament\Pages\Installer\PanelInstaller; | use App\Filament\Pages\Installer\PanelInstaller; | ||||||
| use Carbon\CarbonImmutable; | use Carbon\CarbonImmutable; | ||||||
|  | use Illuminate\Http\RedirectResponse; | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||||
| use App\Models\User; | use App\Models\User; | ||||||
| use Illuminate\Http\JsonResponse; | use Illuminate\Http\JsonResponse; | ||||||
| use App\Facades\Activity; | use App\Facades\Activity; | ||||||
|  | use Illuminate\View\View; | ||||||
| 
 | 
 | ||||||
| class LoginController extends AbstractLoginController | class LoginController extends AbstractLoginController | ||||||
| { | { | ||||||
| @ -17,7 +19,7 @@ class LoginController extends AbstractLoginController | |||||||
|      * base authentication view component. React will take over at this point and |      * base authentication view component. React will take over at this point and | ||||||
|      * turn the login area into an SPA. |      * turn the login area into an SPA. | ||||||
|      */ |      */ | ||||||
|     public function index() |     public function index(): View|RedirectResponse | ||||||
|     { |     { | ||||||
|         if (!PanelInstaller::isInstalled()) { |         if (!PanelInstaller::isInstalled()) { | ||||||
|             return redirect('/installer'); |             return redirect('/installer'); | ||||||
|  | |||||||
| @ -69,7 +69,7 @@ class ResetPasswordController extends Controller | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\Model\DataValidationException |      * @throws \App\Exceptions\Model\DataValidationException | ||||||
|      */ |      */ | ||||||
|     protected function resetPassword($user, $password) |     protected function resetPassword($user, $password): void | ||||||
|     { |     { | ||||||
|         /** @var User $user */ |         /** @var User $user */ | ||||||
|         $user->password = $this->hasher->make($password); |         $user->password = $this->hasher->make($password); | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ class EnsureStatefulRequests extends EnsureFrontendRequestsAreStateful | |||||||
|      * We don't want to support API usage using the cookies, except for requests stemming |      * We don't want to support API usage using the cookies, except for requests stemming | ||||||
|      * from the front-end we control. |      * from the front-end we control. | ||||||
|      */ |      */ | ||||||
|     public static function fromFrontend($request) |     public static function fromFrontend($request): bool | ||||||
|     { |     { | ||||||
|         if (parent::fromFrontend($request)) { |         if (parent::fromFrontend($request)) { | ||||||
|             return true; |             return true; | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ class RedirectIfAuthenticated | |||||||
|     /** |     /** | ||||||
|      * Handle an incoming request. |      * Handle an incoming request. | ||||||
|      */ |      */ | ||||||
|     public function handle(Request $request, \Closure $next, string $guard = null): mixed |     public function handle(Request $request, \Closure $next, ?string $guard = null): mixed | ||||||
|     { |     { | ||||||
|         if ($this->authManager->guard($guard)->check()) { |         if ($this->authManager->guard($guard)->check()) { | ||||||
|             return redirect()->route('index'); |             return redirect()->route('index'); | ||||||
|  | |||||||
| @ -10,7 +10,9 @@ use App\Exceptions\Http\TwoFactorAuthRequiredException; | |||||||
| class RequireTwoFactorAuthentication | class RequireTwoFactorAuthentication | ||||||
| { | { | ||||||
|     public const LEVEL_NONE = 0; |     public const LEVEL_NONE = 0; | ||||||
|  | 
 | ||||||
|     public const LEVEL_ADMIN = 1; |     public const LEVEL_ADMIN = 1; | ||||||
|  | 
 | ||||||
|     public const LEVEL_ALL = 2; |     public const LEVEL_ALL = 2; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -3,23 +3,26 @@ | |||||||
| namespace App\Http\Middleware; | namespace App\Http\Middleware; | ||||||
| 
 | 
 | ||||||
| use GuzzleHttp\Client; | use GuzzleHttp\Client; | ||||||
|  | use Illuminate\Foundation\Application; | ||||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||||
| use Illuminate\Http\Response; | use Illuminate\Http\Response; | ||||||
| use App\Events\Auth\FailedCaptcha; | use App\Events\Auth\FailedCaptcha; | ||||||
| use Symfony\Component\HttpKernel\Exception\HttpException; | use Symfony\Component\HttpKernel\Exception\HttpException; | ||||||
| 
 | 
 | ||||||
| class VerifyReCaptcha | readonly class VerifyReCaptcha | ||||||
| { | { | ||||||
|     /** |     public function __construct(private Application $app) | ||||||
|      * Handle an incoming request. |     { | ||||||
|      */ | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function handle(Request $request, \Closure $next): mixed |     public function handle(Request $request, \Closure $next): mixed | ||||||
|     { |     { | ||||||
|         if (!config('recaptcha.enabled')) { |         if (!config('recaptcha.enabled')) { | ||||||
|             return $next($request); |             return $next($request); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (app()->isLocal()) { |         if ($this->app->isLocal()) { | ||||||
|             return $next($request); |             return $next($request); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ abstract class AdminFormRequest extends FormRequest | |||||||
|      * Return only the fields that we are interested in from the request. |      * Return only the fields that we are interested in from the request. | ||||||
|      * This will include empty fields as a null value. |      * This will include empty fields as a null value. | ||||||
|      */ |      */ | ||||||
|     public function normalize(array $only = null): array |     public function normalize(?array $only = null): array | ||||||
|     { |     { | ||||||
|         return $this->only($only ?? array_keys($this->rules())); |         return $this->only($only ?? array_keys($this->rules())); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ | |||||||
| namespace App\Http\Requests\Admin\Egg; | namespace App\Http\Requests\Admin\Egg; | ||||||
| 
 | 
 | ||||||
| use App\Http\Requests\Admin\AdminFormRequest; | use App\Http\Requests\Admin\AdminFormRequest; | ||||||
|  | use Illuminate\Validation\Validator; | ||||||
| 
 | 
 | ||||||
| class EggFormRequest extends AdminFormRequest | class EggFormRequest extends AdminFormRequest | ||||||
| { | { | ||||||
| @ -25,7 +26,7 @@ class EggFormRequest extends AdminFormRequest | |||||||
|         return $rules; |         return $rules; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function withValidator($validator) |     public function withValidator(Validator $validator): void | ||||||
|     { |     { | ||||||
|         $validator->sometimes('config_from', 'exists:eggs,id', function () { |         $validator->sometimes('config_from', 'exists:eggs,id', function () { | ||||||
|             return (int) $this->input('config_from') !== 0; |             return (int) $this->input('config_from') !== 0; | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ class MailSettingsFormRequest extends AdminFormRequest | |||||||
|      * Override the default normalization function for this type of request |      * Override the default normalization function for this type of request | ||||||
|      * as we need to accept empty values on the keys. |      * as we need to accept empty values on the keys. | ||||||
|      */ |      */ | ||||||
|     public function normalize(array $only = null): array |     public function normalize(?array $only = null): array | ||||||
|     { |     { | ||||||
|         $keys = array_flip(array_keys($this->rules())); |         $keys = array_flip(array_keys($this->rules())); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -75,7 +75,6 @@ abstract class ApplicationApiRequest extends FormRequest | |||||||
|      * @template T of \Illuminate\Database\Eloquent\Model |      * @template T of \Illuminate\Database\Eloquent\Model | ||||||
|      * |      * | ||||||
|      * @param  class-string<T>  $expect |      * @param  class-string<T>  $expect | ||||||
|      * |  | ||||||
|      * @return T |      * @return T | ||||||
|      * |      * | ||||||
|      * @noinspection PhpDocSignatureInspection |      * @noinspection PhpDocSignatureInspection | ||||||
|  | |||||||
| @ -12,7 +12,7 @@ class StoreDatabaseHostRequest extends ApplicationApiRequest | |||||||
| 
 | 
 | ||||||
|     protected int $permission = AdminAcl::WRITE; |     protected int $permission = AdminAcl::WRITE; | ||||||
| 
 | 
 | ||||||
|     public function rules(array $rules = null): array |     public function rules(?array $rules = null): array | ||||||
|     { |     { | ||||||
|         return $rules ?? DatabaseHost::getRules(); |         return $rules ?? DatabaseHost::getRules(); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -6,11 +6,11 @@ use App\Models\DatabaseHost; | |||||||
| 
 | 
 | ||||||
| class UpdateDatabaseHostRequest extends StoreDatabaseHostRequest | class UpdateDatabaseHostRequest extends StoreDatabaseHostRequest | ||||||
| { | { | ||||||
|     public function rules(array $rules = null): array |     public function rules(?array $rules = null): array | ||||||
|     { |     { | ||||||
|         /** @var DatabaseHost $databaseHost */ |         /** @var DatabaseHost $databaseHost */ | ||||||
|         $databaseHost = $this->route()->parameter('database_host'); |         $databaseHost = $this->route()->parameter('database_host'); | ||||||
| 
 | 
 | ||||||
|         return $rules ?? DatabaseHost::getRulesForUpdate($databaseHost->id); |         return $rules ?? DatabaseHost::getRulesForUpdate($databaseHost); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,11 +9,11 @@ class UpdateMountRequest extends StoreMountRequest | |||||||
|     /** |     /** | ||||||
|      * Apply validation rules to this request. |      * Apply validation rules to this request. | ||||||
|      */ |      */ | ||||||
|     public function rules(array $rules = null): array |     public function rules(?array $rules = null): array | ||||||
|     { |     { | ||||||
|         /** @var Mount $mount */ |         /** @var Mount $mount */ | ||||||
|         $mount = $this->route()->parameter('mount'); |         $mount = $this->route()->parameter('mount'); | ||||||
| 
 | 
 | ||||||
|         return Mount::getRulesForUpdate($mount->id); |         return Mount::getRulesForUpdate($mount); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ class StoreNodeRequest extends ApplicationApiRequest | |||||||
|     /** |     /** | ||||||
|      * Validation rules to apply to this request. |      * Validation rules to apply to this request. | ||||||
|      */ |      */ | ||||||
|     public function rules(array $rules = null): array |     public function rules(?array $rules = null): array | ||||||
|     { |     { | ||||||
|         return collect($rules ?? Node::getRules())->only([ |         return collect($rules ?? Node::getRules())->only([ | ||||||
|             'public', |             'public', | ||||||
|  | |||||||
| @ -10,11 +10,11 @@ class UpdateNodeRequest extends StoreNodeRequest | |||||||
|      * Apply validation rules to this request. Uses the parent class rules() |      * Apply validation rules to this request. Uses the parent class rules() | ||||||
|      * function but passes in the rules for updating rather than creating. |      * function but passes in the rules for updating rather than creating. | ||||||
|      */ |      */ | ||||||
|     public function rules(array $rules = null): array |     public function rules(?array $rules = null): array | ||||||
|     { |     { | ||||||
|         /** @var Node $node */ |         /** @var Node $node */ | ||||||
|         $node = $this->route()->parameter('node'); |         $node = $this->route()->parameter('node'); | ||||||
| 
 | 
 | ||||||
|         return parent::rules(Node::getRulesForUpdate($node->id)); |         return parent::rules(Node::getRulesForUpdate($node)); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ class StoreRoleRequest extends ApplicationApiRequest | |||||||
| 
 | 
 | ||||||
|     protected int $permission = AdminAcl::WRITE; |     protected int $permission = AdminAcl::WRITE; | ||||||
| 
 | 
 | ||||||
|     public function rules(array $rules = null): array |     public function rules(?array $rules = null): array | ||||||
|     { |     { | ||||||
|         return [ |         return [ | ||||||
|             'name' => 'required|string', |             'name' => 'required|string', | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ class AssignUserRolesRequest extends StoreUserRequest | |||||||
|     /** |     /** | ||||||
|      * Return the validation rules for this request. |      * Return the validation rules for this request. | ||||||
|      */ |      */ | ||||||
|     public function rules(array $rules = null): array |     public function rules(?array $rules = null): array | ||||||
|     { |     { | ||||||
|         return [ |         return [ | ||||||
|             'roles' => 'array', |             'roles' => 'array', | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ class StoreUserRequest extends ApplicationApiRequest | |||||||
|     /** |     /** | ||||||
|      * Return the validation rules for this request. |      * Return the validation rules for this request. | ||||||
|      */ |      */ | ||||||
|     public function rules(array $rules = null): array |     public function rules(?array $rules = null): array | ||||||
|     { |     { | ||||||
|         $rules = $rules ?? User::getRules(); |         $rules = $rules ?? User::getRules(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -9,10 +9,10 @@ class UpdateUserRequest extends StoreUserRequest | |||||||
|     /** |     /** | ||||||
|      * Return the validation rules for this request. |      * Return the validation rules for this request. | ||||||
|      */ |      */ | ||||||
|     public function rules(array $rules = null): array |     public function rules(?array $rules = null): array | ||||||
|     { |     { | ||||||
|         $userId = $this->parameter('user', User::class)->id; |         $user = $this->parameter('user', User::class); | ||||||
| 
 | 
 | ||||||
|         return parent::rules(User::getRulesForUpdate($userId)); |         return parent::rules(User::getRulesForUpdate($user)); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -49,7 +49,7 @@ abstract class SubuserRequest extends ClientApiRequest | |||||||
|      * |      * | ||||||
|      * @throws \Illuminate\Contracts\Container\BindingResolutionException |      * @throws \Illuminate\Contracts\Container\BindingResolutionException | ||||||
|      */ |      */ | ||||||
|     protected function validatePermissionsCanBeAssigned(array $permissions) |     protected function validatePermissionsCanBeAssigned(array $permissions): void | ||||||
|     { |     { | ||||||
|         $user = $this->user(); |         $user = $this->user(); | ||||||
|         /** @var \App\Models\Server $server */ |         /** @var \App\Models\Server $server */ | ||||||
|  | |||||||
| @ -42,5 +42,4 @@ class NodeStatistics implements ShouldQueue | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -90,7 +90,7 @@ class RunTaskJob extends Job implements ShouldQueue | |||||||
|     /** |     /** | ||||||
|      * Handle a failure while sending the action to the daemon or otherwise processing the job. |      * Handle a failure while sending the action to the daemon or otherwise processing the job. | ||||||
|      */ |      */ | ||||||
|     public function failed(\Exception $exception = null) |     public function failed(?\Exception $exception = null): void | ||||||
|     { |     { | ||||||
|         $this->markTaskNotQueued(); |         $this->markTaskNotQueued(); | ||||||
|         $this->markScheduleComplete(); |         $this->markScheduleComplete(); | ||||||
| @ -99,7 +99,7 @@ class RunTaskJob extends Job implements ShouldQueue | |||||||
|     /** |     /** | ||||||
|      * Get the next task in the schedule and queue it for running after the defined period of wait time. |      * Get the next task in the schedule and queue it for running after the defined period of wait time. | ||||||
|      */ |      */ | ||||||
|     private function queueNextTask() |     private function queueNextTask(): void | ||||||
|     { |     { | ||||||
|         /** @var \App\Models\Task|null $nextTask */ |         /** @var \App\Models\Task|null $nextTask */ | ||||||
|         $nextTask = Task::query()->where('schedule_id', $this->task->schedule_id) |         $nextTask = Task::query()->where('schedule_id', $this->task->schedule_id) | ||||||
| @ -121,7 +121,7 @@ class RunTaskJob extends Job implements ShouldQueue | |||||||
|     /** |     /** | ||||||
|      * Marks the parent schedule as being complete. |      * Marks the parent schedule as being complete. | ||||||
|      */ |      */ | ||||||
|     private function markScheduleComplete() |     private function markScheduleComplete(): void | ||||||
|     { |     { | ||||||
|         $this->task->schedule()->update([ |         $this->task->schedule()->update([ | ||||||
|             'is_processing' => false, |             'is_processing' => false, | ||||||
| @ -132,7 +132,7 @@ class RunTaskJob extends Job implements ShouldQueue | |||||||
|     /** |     /** | ||||||
|      * Mark a specific task as no longer being queued. |      * Mark a specific task as no longer being queued. | ||||||
|      */ |      */ | ||||||
|     private function markTaskNotQueued() |     private function markTaskNotQueued(): void | ||||||
|     { |     { | ||||||
|         $this->task->update(['is_queued' => false]); |         $this->task->update(['is_queued' => false]); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -3,19 +3,21 @@ | |||||||
| namespace App\Livewire; | namespace App\Livewire; | ||||||
| 
 | 
 | ||||||
| use App\Models\Node; | use App\Models\Node; | ||||||
|  | use Illuminate\View\View; | ||||||
| use Livewire\Component; | use Livewire\Component; | ||||||
| 
 | 
 | ||||||
| class NodeSystemInformation extends Component | class NodeSystemInformation extends Component | ||||||
| { | { | ||||||
|     public Node $node; |     public Node $node; | ||||||
|  | 
 | ||||||
|     public string $sizeClasses; |     public string $sizeClasses; | ||||||
| 
 | 
 | ||||||
|     public function render() |     public function render(): View | ||||||
|     { |     { | ||||||
|         return view('livewire.node-system-information'); |         return view('livewire.node-system-information'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function placeholder() |     public function placeholder(): string | ||||||
|     { |     { | ||||||
|         return <<<'HTML' |         return <<<'HTML' | ||||||
|         <div> |         <div> | ||||||
|  | |||||||
| @ -123,7 +123,7 @@ class ActivityLog extends Model | |||||||
|      * |      * | ||||||
|      * @see https://laravel.com/docs/9.x/eloquent#pruning-models
 |      * @see https://laravel.com/docs/9.x/eloquent#pruning-models
 | ||||||
|      */ |      */ | ||||||
|     public function prunable() |     public function prunable(): Builder | ||||||
|     { |     { | ||||||
|         if (is_null(config('activity.prune_days'))) { |         if (is_null(config('activity.prune_days'))) { | ||||||
|             throw new \LogicException('Cannot prune activity logs: no "prune_days" configuration value is set.'); |             throw new \LogicException('Cannot prune activity logs: no "prune_days" configuration value is set.'); | ||||||
| @ -136,7 +136,7 @@ class ActivityLog extends Model | |||||||
|      * Boots the model event listeners. This will trigger an activity log event every |      * Boots the model event listeners. This will trigger an activity log event every | ||||||
|      * time a new model is inserted which can then be captured and worked with as needed. |      * time a new model is inserted which can then be captured and worked with as needed. | ||||||
|      */ |      */ | ||||||
|     protected static function boot() |     protected static function boot(): void | ||||||
|     { |     { | ||||||
|         parent::boot(); |         parent::boot(); | ||||||
| 
 | 
 | ||||||
| @ -149,7 +149,7 @@ class ActivityLog extends Model | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function htmlable() |     public function htmlable(): string | ||||||
|     { |     { | ||||||
|         $user = $this->actor; |         $user = $this->actor; | ||||||
|         if (!$user instanceof User) { |         if (!$user instanceof User) { | ||||||
|  | |||||||
| @ -3,8 +3,9 @@ | |||||||
| namespace App\Models; | namespace App\Models; | ||||||
| 
 | 
 | ||||||
| use Illuminate\Database\Eloquent\Relations\BelongsTo; | use Illuminate\Database\Eloquent\Relations\BelongsTo; | ||||||
|  | use Illuminate\Database\Eloquent\Relations\MorphTo; | ||||||
| use Illuminate\Database\Eloquent\Relations\Pivot; | use Illuminate\Database\Eloquent\Relations\Pivot; | ||||||
| use Illuminate\Database\Eloquent\SoftDeletes; | use Illuminate\Database\Eloquent\SoftDeletingScope; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * \App\Models\ActivityLogSubject. |  * \App\Models\ActivityLogSubject. | ||||||
| @ -25,6 +26,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; | |||||||
| class ActivityLogSubject extends Pivot | class ActivityLogSubject extends Pivot | ||||||
| { | { | ||||||
|     public $incrementing = true; |     public $incrementing = true; | ||||||
|  | 
 | ||||||
|     public $timestamps = false; |     public $timestamps = false; | ||||||
| 
 | 
 | ||||||
|     protected $table = 'activity_log_subjects'; |     protected $table = 'activity_log_subjects'; | ||||||
| @ -36,15 +38,8 @@ class ActivityLogSubject extends Pivot | |||||||
|         return $this->belongsTo(ActivityLog::class); |         return $this->belongsTo(ActivityLog::class); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function subject() |     public function subject(): MorphTo | ||||||
|     { |     { | ||||||
|         $morph = $this->morphTo(); |         return $this->morphTo()->withoutGlobalScope(SoftDeletingScope::class); | ||||||
| 
 |  | ||||||
|         if (in_array(SoftDeletes::class, class_uses_recursive($morph::class))) { |  | ||||||
|             /** @var self|Backup|UserSSHKey $morph - cannot use traits in doc blocks */ |  | ||||||
|             return $morph->withTrashed(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return $morph; |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -63,21 +63,28 @@ class ApiKey extends Model | |||||||
|      * API representation using fractal. |      * API representation using fractal. | ||||||
|      */ |      */ | ||||||
|     public const RESOURCE_NAME = 'api_key'; |     public const RESOURCE_NAME = 'api_key'; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Different API keys that can exist on the system. |      * Different API keys that can exist on the system. | ||||||
|      */ |      */ | ||||||
|     public const TYPE_NONE = 0; |     public const TYPE_NONE = 0; | ||||||
|  | 
 | ||||||
|     public const TYPE_ACCOUNT = 1; |     public const TYPE_ACCOUNT = 1; | ||||||
|  | 
 | ||||||
|     /* @deprecated */ |     /* @deprecated */ | ||||||
|     public const TYPE_APPLICATION = 2; |     public const TYPE_APPLICATION = 2; | ||||||
|  | 
 | ||||||
|     /* @deprecated */ |     /* @deprecated */ | ||||||
|     public const TYPE_DAEMON_USER = 3; |     public const TYPE_DAEMON_USER = 3; | ||||||
|  | 
 | ||||||
|     /* @deprecated */ |     /* @deprecated */ | ||||||
|     public const TYPE_DAEMON_APPLICATION = 4; |     public const TYPE_DAEMON_APPLICATION = 4; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * The length of API key identifiers. |      * The length of API key identifiers. | ||||||
|      */ |      */ | ||||||
|     public const IDENTIFIER_LENGTH = 16; |     public const IDENTIFIER_LENGTH = 16; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * The length of the actual API key that is encrypted and stored |      * The length of the actual API key that is encrypted and stored | ||||||
|      * in the database. |      * in the database. | ||||||
|  | |||||||
| @ -31,6 +31,7 @@ class Backup extends Model | |||||||
|     public const RESOURCE_NAME = 'backup'; |     public const RESOURCE_NAME = 'backup'; | ||||||
| 
 | 
 | ||||||
|     public const ADAPTER_DAEMON = 'wings'; |     public const ADAPTER_DAEMON = 'wings'; | ||||||
|  | 
 | ||||||
|     public const ADAPTER_AWS_S3 = 's3'; |     public const ADAPTER_AWS_S3 = 's3'; | ||||||
| 
 | 
 | ||||||
|     protected $table = 'backups'; |     protected $table = 'backups'; | ||||||
|  | |||||||
| @ -70,6 +70,7 @@ class Egg extends Model | |||||||
|      * than leaving it null. |      * than leaving it null. | ||||||
|      */ |      */ | ||||||
|     public const FEATURE_EULA_POPUP = 'eula'; |     public const FEATURE_EULA_POPUP = 'eula'; | ||||||
|  | 
 | ||||||
|     public const FEATURE_FASTDL = 'fastdl'; |     public const FEATURE_FASTDL = 'fastdl'; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -13,7 +13,7 @@ class AdminServerFilter implements Filter | |||||||
|      * |      * | ||||||
|      * @param  string  $value |      * @param  string  $value | ||||||
|      */ |      */ | ||||||
|     public function __invoke(Builder $query, $value, string $property) |     public function __invoke(Builder $query, $value, string $property): void | ||||||
|     { |     { | ||||||
|         if ($query->getQuery()->from !== 'servers') { |         if ($query->getQuery()->from !== 'servers') { | ||||||
|             throw new \BadMethodCallException('Cannot use the AdminServerFilter against a non-server model.'); |             throw new \BadMethodCallException('Cannot use the AdminServerFilter against a non-server model.'); | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ class MultiFieldServerFilter implements Filter | |||||||
|      * |      * | ||||||
|      * @param  string  $value |      * @param  string  $value | ||||||
|      */ |      */ | ||||||
|     public function __invoke(Builder $query, $value, string $property) |     public function __invoke(Builder $query, $value, string $property): void | ||||||
|     { |     { | ||||||
|         if ($query->getQuery()->from !== 'servers') { |         if ($query->getQuery()->from !== 'servers') { | ||||||
|             throw new \BadMethodCallException('Cannot use the MultiFieldServerFilter against a non-server model.'); |             throw new \BadMethodCallException('Cannot use the MultiFieldServerFilter against a non-server model.'); | ||||||
|  | |||||||
| @ -38,7 +38,7 @@ abstract class Model extends IlluminateModel | |||||||
|      * |      * | ||||||
|      * @throws \Illuminate\Contracts\Container\BindingResolutionException |      * @throws \Illuminate\Contracts\Container\BindingResolutionException | ||||||
|      */ |      */ | ||||||
|     protected static function boot() |     protected static function boot(): void | ||||||
|     { |     { | ||||||
|         parent::boot(); |         parent::boot(); | ||||||
| 
 | 
 | ||||||
| @ -69,7 +69,7 @@ abstract class Model extends IlluminateModel | |||||||
|         return 'uuid'; |         return 'uuid'; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function asDateTime($value) |     protected function asDateTime($value): Carbon | ||||||
|     { |     { | ||||||
|         $timezone = auth()->user()?->timezone ?? config('app.timezone', 'UTC'); |         $timezone = auth()->user()?->timezone ?? config('app.timezone', 'UTC'); | ||||||
| 
 | 
 | ||||||
| @ -135,11 +135,9 @@ abstract class Model extends IlluminateModel | |||||||
|      * Returns the rules associated with the model, specifically for updating the given model |      * Returns the rules associated with the model, specifically for updating the given model | ||||||
|      * rather than just creating it. |      * rather than just creating it. | ||||||
|      */ |      */ | ||||||
|     public static function getRulesForUpdate($model, string $column = 'id'): array |     public static function getRulesForUpdate(self $model): array | ||||||
|     { |     { | ||||||
|         if ($model instanceof Model) { |  | ||||||
|         [$id, $column] = [$model->getKey(), $model->getKeyName()]; |         [$id, $column] = [$model->getKey(), $model->getKeyName()]; | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         $rules = static::getRules(); |         $rules = static::getRules(); | ||||||
|         foreach ($rules as $key => &$data) { |         foreach ($rules as $key => &$data) { | ||||||
|  | |||||||
| @ -70,7 +70,7 @@ class Mount extends Model | |||||||
|     /** |     /** | ||||||
|      * Blacklisted source paths. |      * Blacklisted source paths. | ||||||
|      */ |      */ | ||||||
|     public static $invalidSourcePaths = [ |     public static array $invalidSourcePaths = [ | ||||||
|         '/etc/pelican', |         '/etc/pelican', | ||||||
|         '/var/lib/pelican/volumes', |         '/var/lib/pelican/volumes', | ||||||
|         '/srv/daemon-data', |         '/srv/daemon-data', | ||||||
| @ -79,7 +79,7 @@ class Mount extends Model | |||||||
|     /** |     /** | ||||||
|      * Blacklisted target paths. |      * Blacklisted target paths. | ||||||
|      */ |      */ | ||||||
|     public static $invalidTargetPaths = [ |     public static array $invalidTargetPaths = [ | ||||||
|         '/home/container', |         '/home/container', | ||||||
|     ]; |     ]; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -16,51 +16,81 @@ class Permission extends Model | |||||||
|      * Constants defining different permissions available. |      * Constants defining different permissions available. | ||||||
|      */ |      */ | ||||||
|     public const ACTION_WEBSOCKET_CONNECT = 'websocket.connect'; |     public const ACTION_WEBSOCKET_CONNECT = 'websocket.connect'; | ||||||
|  | 
 | ||||||
|     public const ACTION_CONTROL_CONSOLE = 'control.console'; |     public const ACTION_CONTROL_CONSOLE = 'control.console'; | ||||||
|  | 
 | ||||||
|     public const ACTION_CONTROL_START = 'control.start'; |     public const ACTION_CONTROL_START = 'control.start'; | ||||||
|  | 
 | ||||||
|     public const ACTION_CONTROL_STOP = 'control.stop'; |     public const ACTION_CONTROL_STOP = 'control.stop'; | ||||||
|  | 
 | ||||||
|     public const ACTION_CONTROL_RESTART = 'control.restart'; |     public const ACTION_CONTROL_RESTART = 'control.restart'; | ||||||
| 
 | 
 | ||||||
|     public const ACTION_DATABASE_READ = 'database.read'; |     public const ACTION_DATABASE_READ = 'database.read'; | ||||||
|  | 
 | ||||||
|     public const ACTION_DATABASE_CREATE = 'database.create'; |     public const ACTION_DATABASE_CREATE = 'database.create'; | ||||||
|  | 
 | ||||||
|     public const ACTION_DATABASE_UPDATE = 'database.update'; |     public const ACTION_DATABASE_UPDATE = 'database.update'; | ||||||
|  | 
 | ||||||
|     public const ACTION_DATABASE_DELETE = 'database.delete'; |     public const ACTION_DATABASE_DELETE = 'database.delete'; | ||||||
|  | 
 | ||||||
|     public const ACTION_DATABASE_VIEW_PASSWORD = 'database.view_password'; |     public const ACTION_DATABASE_VIEW_PASSWORD = 'database.view_password'; | ||||||
| 
 | 
 | ||||||
|     public const ACTION_SCHEDULE_READ = 'schedule.read'; |     public const ACTION_SCHEDULE_READ = 'schedule.read'; | ||||||
|  | 
 | ||||||
|     public const ACTION_SCHEDULE_CREATE = 'schedule.create'; |     public const ACTION_SCHEDULE_CREATE = 'schedule.create'; | ||||||
|  | 
 | ||||||
|     public const ACTION_SCHEDULE_UPDATE = 'schedule.update'; |     public const ACTION_SCHEDULE_UPDATE = 'schedule.update'; | ||||||
|  | 
 | ||||||
|     public const ACTION_SCHEDULE_DELETE = 'schedule.delete'; |     public const ACTION_SCHEDULE_DELETE = 'schedule.delete'; | ||||||
| 
 | 
 | ||||||
|     public const ACTION_USER_READ = 'user.read'; |     public const ACTION_USER_READ = 'user.read'; | ||||||
|  | 
 | ||||||
|     public const ACTION_USER_CREATE = 'user.create'; |     public const ACTION_USER_CREATE = 'user.create'; | ||||||
|  | 
 | ||||||
|     public const ACTION_USER_UPDATE = 'user.update'; |     public const ACTION_USER_UPDATE = 'user.update'; | ||||||
|  | 
 | ||||||
|     public const ACTION_USER_DELETE = 'user.delete'; |     public const ACTION_USER_DELETE = 'user.delete'; | ||||||
| 
 | 
 | ||||||
|     public const ACTION_BACKUP_READ = 'backup.read'; |     public const ACTION_BACKUP_READ = 'backup.read'; | ||||||
|  | 
 | ||||||
|     public const ACTION_BACKUP_CREATE = 'backup.create'; |     public const ACTION_BACKUP_CREATE = 'backup.create'; | ||||||
|  | 
 | ||||||
|     public const ACTION_BACKUP_DELETE = 'backup.delete'; |     public const ACTION_BACKUP_DELETE = 'backup.delete'; | ||||||
|  | 
 | ||||||
|     public const ACTION_BACKUP_DOWNLOAD = 'backup.download'; |     public const ACTION_BACKUP_DOWNLOAD = 'backup.download'; | ||||||
|  | 
 | ||||||
|     public const ACTION_BACKUP_RESTORE = 'backup.restore'; |     public const ACTION_BACKUP_RESTORE = 'backup.restore'; | ||||||
| 
 | 
 | ||||||
|     public const ACTION_ALLOCATION_READ = 'allocation.read'; |     public const ACTION_ALLOCATION_READ = 'allocation.read'; | ||||||
|  | 
 | ||||||
|     public const ACTION_ALLOCATION_CREATE = 'allocation.create'; |     public const ACTION_ALLOCATION_CREATE = 'allocation.create'; | ||||||
|  | 
 | ||||||
|     public const ACTION_ALLOCATION_UPDATE = 'allocation.update'; |     public const ACTION_ALLOCATION_UPDATE = 'allocation.update'; | ||||||
|  | 
 | ||||||
|     public const ACTION_ALLOCATION_DELETE = 'allocation.delete'; |     public const ACTION_ALLOCATION_DELETE = 'allocation.delete'; | ||||||
| 
 | 
 | ||||||
|     public const ACTION_FILE_READ = 'file.read'; |     public const ACTION_FILE_READ = 'file.read'; | ||||||
|  | 
 | ||||||
|     public const ACTION_FILE_READ_CONTENT = 'file.read-content'; |     public const ACTION_FILE_READ_CONTENT = 'file.read-content'; | ||||||
|  | 
 | ||||||
|     public const ACTION_FILE_CREATE = 'file.create'; |     public const ACTION_FILE_CREATE = 'file.create'; | ||||||
|  | 
 | ||||||
|     public const ACTION_FILE_UPDATE = 'file.update'; |     public const ACTION_FILE_UPDATE = 'file.update'; | ||||||
|  | 
 | ||||||
|     public const ACTION_FILE_DELETE = 'file.delete'; |     public const ACTION_FILE_DELETE = 'file.delete'; | ||||||
|  | 
 | ||||||
|     public const ACTION_FILE_ARCHIVE = 'file.archive'; |     public const ACTION_FILE_ARCHIVE = 'file.archive'; | ||||||
|  | 
 | ||||||
|     public const ACTION_FILE_SFTP = 'file.sftp'; |     public const ACTION_FILE_SFTP = 'file.sftp'; | ||||||
| 
 | 
 | ||||||
|     public const ACTION_STARTUP_READ = 'startup.read'; |     public const ACTION_STARTUP_READ = 'startup.read'; | ||||||
|  | 
 | ||||||
|     public const ACTION_STARTUP_UPDATE = 'startup.update'; |     public const ACTION_STARTUP_UPDATE = 'startup.update'; | ||||||
|  | 
 | ||||||
|     public const ACTION_STARTUP_DOCKER_IMAGE = 'startup.docker-image'; |     public const ACTION_STARTUP_DOCKER_IMAGE = 'startup.docker-image'; | ||||||
| 
 | 
 | ||||||
|     public const ACTION_SETTINGS_RENAME = 'settings.rename'; |     public const ACTION_SETTINGS_RENAME = 'settings.rename'; | ||||||
|  | 
 | ||||||
|     public const ACTION_SETTINGS_REINSTALL = 'settings.reinstall'; |     public const ACTION_SETTINGS_REINSTALL = 'settings.reinstall'; | ||||||
| 
 | 
 | ||||||
|     public const ACTION_ACTIVITY_READ = 'activity.read'; |     public const ACTION_ACTIVITY_READ = 'activity.read'; | ||||||
|  | |||||||
| @ -74,6 +74,7 @@ use App\Exceptions\Http\Server\ServerStateConflictException; | |||||||
|  * @property \App\Models\User $user |  * @property \App\Models\User $user | ||||||
|  * @property \Illuminate\Database\Eloquent\Collection|\App\Models\EggVariable[] $variables |  * @property \Illuminate\Database\Eloquent\Collection|\App\Models\EggVariable[] $variables | ||||||
|  * @property int|null $variables_count |  * @property int|null $variables_count | ||||||
|  |  * | ||||||
|  * @method static \Database\Factories\ServerFactory factory(...$parameters) |  * @method static \Database\Factories\ServerFactory factory(...$parameters) | ||||||
|  * @method static \Illuminate\Database\Eloquent\Builder|Server newModelQuery() |  * @method static \Illuminate\Database\Eloquent\Builder|Server newModelQuery() | ||||||
|  * @method static \Illuminate\Database\Eloquent\Builder|Server newQuery() |  * @method static \Illuminate\Database\Eloquent\Builder|Server newQuery() | ||||||
| @ -104,6 +105,7 @@ use App\Exceptions\Http\Server\ServerStateConflictException; | |||||||
|  * @method static \Illuminate\Database\Eloquent\Builder|Server whereUpdatedAt($value) |  * @method static \Illuminate\Database\Eloquent\Builder|Server whereUpdatedAt($value) | ||||||
|  * @method static \Illuminate\Database\Eloquent\Builder|Server whereUuid($value) |  * @method static \Illuminate\Database\Eloquent\Builder|Server whereUuid($value) | ||||||
|  * @method static \Illuminate\Database\Eloquent\Builder|Server whereuuid_short($value) |  * @method static \Illuminate\Database\Eloquent\Builder|Server whereuuid_short($value) | ||||||
|  |  * | ||||||
|  * @property array|null $docker_labels |  * @property array|null $docker_labels | ||||||
|  * @property Collection<Endpoint>|null $ports |  * @property Collection<Endpoint>|null $ports | ||||||
|  * @property-read mixed $condition |  * @property-read mixed $condition | ||||||
| @ -111,10 +113,12 @@ use App\Exceptions\Http\Server\ServerStateConflictException; | |||||||
|  * @property-read int|null $egg_variables_count |  * @property-read int|null $egg_variables_count | ||||||
|  * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ServerVariable> $serverVariables |  * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ServerVariable> $serverVariables | ||||||
|  * @property-read int|null $server_variables_count |  * @property-read int|null $server_variables_count | ||||||
|  |  * | ||||||
|  * @method static \Illuminate\Database\Eloquent\Builder|Server whereDockerLabels($value) |  * @method static \Illuminate\Database\Eloquent\Builder|Server whereDockerLabels($value) | ||||||
|  * @method static \Illuminate\Database\Eloquent\Builder|Server whereInstalledAt($value) |  * @method static \Illuminate\Database\Eloquent\Builder|Server whereInstalledAt($value) | ||||||
|  * @method static \Illuminate\Database\Eloquent\Builder|Server wherePorts($value) |  * @method static \Illuminate\Database\Eloquent\Builder|Server wherePorts($value) | ||||||
|  * @method static \Illuminate\Database\Eloquent\Builder|Server whereUuidShort($value) |  * @method static \Illuminate\Database\Eloquent\Builder|Server whereUuidShort($value) | ||||||
|  |  * | ||||||
|  * @mixin \Eloquent |  * @mixin \Eloquent | ||||||
|  */ |  */ | ||||||
| class Server extends Model | class Server extends Model | ||||||
| @ -342,7 +346,7 @@ class Server extends Model | |||||||
|      * |      * | ||||||
|      * @throws ServerStateConflictException |      * @throws ServerStateConflictException | ||||||
|      */ |      */ | ||||||
|     public function validateCurrentState() |     public function validateCurrentState(): void | ||||||
|     { |     { | ||||||
|         if ( |         if ( | ||||||
|             $this->isSuspended() || |             $this->isSuspended() || | ||||||
| @ -361,7 +365,7 @@ class Server extends Model | |||||||
|      * sure the server can be transferred and is not currently being transferred |      * sure the server can be transferred and is not currently being transferred | ||||||
|      * or installed. |      * or installed. | ||||||
|      */ |      */ | ||||||
|     public function validateTransferState() |     public function validateTransferState(): void | ||||||
|     { |     { | ||||||
|         if ( |         if ( | ||||||
|             !$this->isInstalled() || |             !$this->isInstalled() || | ||||||
|  | |||||||
| @ -31,8 +31,11 @@ class Task extends Model | |||||||
|      * The default actions that can exist for a task |      * The default actions that can exist for a task | ||||||
|      */ |      */ | ||||||
|     public const ACTION_POWER = 'power'; |     public const ACTION_POWER = 'power'; | ||||||
|  | 
 | ||||||
|     public const ACTION_COMMAND = 'command'; |     public const ACTION_COMMAND = 'command'; | ||||||
|  | 
 | ||||||
|     public const ACTION_BACKUP = 'backup'; |     public const ACTION_BACKUP = 'backup'; | ||||||
|  | 
 | ||||||
|     public const ACTION_DELETE_FILES = 'delete_files'; |     public const ACTION_DELETE_FILES = 'delete_files'; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -99,6 +99,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac | |||||||
|     use Notifiable; |     use Notifiable; | ||||||
| 
 | 
 | ||||||
|     public const USER_LEVEL_USER = 0; |     public const USER_LEVEL_USER = 0; | ||||||
|  | 
 | ||||||
|     public const USER_LEVEL_ADMIN = 1; |     public const USER_LEVEL_ADMIN = 1; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -235,7 +236,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac | |||||||
|      * |      * | ||||||
|      * @param  string  $token |      * @param  string  $token | ||||||
|      */ |      */ | ||||||
|     public function sendPasswordResetNotification($token) |     public function sendPasswordResetNotification($token): void | ||||||
|     { |     { | ||||||
|         Activity::event('auth:reset-password') |         Activity::event('auth:reset-password') | ||||||
|             ->withRequestMetadata() |             ->withRequestMetadata() | ||||||
| @ -248,7 +249,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac | |||||||
|     /** |     /** | ||||||
|      * Store the username as a lowercase string. |      * Store the username as a lowercase string. | ||||||
|      */ |      */ | ||||||
|     public function setUsernameAttribute(string $value) |     public function setUsernameAttribute(string $value): void | ||||||
|     { |     { | ||||||
|         $this->attributes['username'] = mb_strtolower($value); |         $this->attributes['username'] = mb_strtolower($value); | ||||||
|     } |     } | ||||||
|  | |||||||
							
								
								
									
										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 []; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -41,7 +41,7 @@ class ServerPolicy | |||||||
|      * not call the before() function if there isn't a function matching the |      * not call the before() function if there isn't a function matching the | ||||||
|      * policy permission. |      * policy permission. | ||||||
|      */ |      */ | ||||||
|     public function __call(string $name, mixed $arguments) |     public function __call(string $name, mixed $arguments): void | ||||||
|     { |     { | ||||||
|         // do nothing
 |         // do nothing
 | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ use Dedoc\Scramble\Support\Generator\SecurityScheme; | |||||||
| use Filament\Support\Colors\Color; | use Filament\Support\Colors\Color; | ||||||
| use Filament\Support\Facades\FilamentColor; | use Filament\Support\Facades\FilamentColor; | ||||||
| use Illuminate\Database\Eloquent\Relations\Relation; | use Illuminate\Database\Eloquent\Relations\Relation; | ||||||
|  | use Illuminate\Foundation\Application; | ||||||
| use Illuminate\Pagination\Paginator; | use Illuminate\Pagination\Paginator; | ||||||
| use Illuminate\Support\Facades\Broadcast; | use Illuminate\Support\Facades\Broadcast; | ||||||
| use Illuminate\Support\Facades\Event; | use Illuminate\Support\Facades\Event; | ||||||
| @ -34,7 +35,7 @@ class AppServiceProvider extends ServiceProvider | |||||||
|     /** |     /** | ||||||
|      * Bootstrap any application services. |      * Bootstrap any application services. | ||||||
|      */ |      */ | ||||||
|     public function boot(): void |     public function boot(Application $app): void | ||||||
|     { |     { | ||||||
|         // TODO: remove when old admin area gets yeeted
 |         // TODO: remove when old admin area gets yeeted
 | ||||||
|         View::share('appVersion', config('app.version')); |         View::share('appVersion', config('app.version')); | ||||||
| @ -68,7 +69,7 @@ class AppServiceProvider extends ServiceProvider | |||||||
|                 ->asJson() |                 ->asJson() | ||||||
|                 ->withToken($node->daemon_token) |                 ->withToken($node->daemon_token) | ||||||
|                 ->withHeaders($headers) |                 ->withHeaders($headers) | ||||||
|                 ->withOptions(['verify' => (bool) app()->environment('production')]) |                 ->withOptions(['verify' => (bool) $app->environment('production')]) | ||||||
|                 ->timeout(config('panel.guzzle.timeout')) |                 ->timeout(config('panel.guzzle.timeout')) | ||||||
|                 ->connectTimeout(config('panel.guzzle.connect_timeout')) |                 ->connectTimeout(config('panel.guzzle.connect_timeout')) | ||||||
|                 ->baseUrl($node->getConnectionAddress()) |                 ->baseUrl($node->getConnectionAddress()) | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ use Filament\Http\Middleware\DisableBladeIconComponents; | |||||||
| use Filament\Http\Middleware\DispatchServingFilamentEvent; | use Filament\Http\Middleware\DispatchServingFilamentEvent; | ||||||
| use Filament\Panel; | use Filament\Panel; | ||||||
| use Filament\PanelProvider; | use Filament\PanelProvider; | ||||||
|  | use Filament\Support\Enums\MaxWidth; | ||||||
| use Filament\Support\Facades\FilamentAsset; | use Filament\Support\Facades\FilamentAsset; | ||||||
| use Filament\Widgets; | use Filament\Widgets; | ||||||
| use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; | use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; | ||||||
| @ -21,7 +22,7 @@ use Illuminate\View\Middleware\ShareErrorsFromSession; | |||||||
| 
 | 
 | ||||||
| class AdminPanelProvider extends PanelProvider | class AdminPanelProvider extends PanelProvider | ||||||
| { | { | ||||||
|     public function boot() |     public function boot(): void | ||||||
|     { |     { | ||||||
|         FilamentAsset::registerCssVariables([ |         FilamentAsset::registerCssVariables([ | ||||||
|             'sidebar-width' => '16rem !important', |             'sidebar-width' => '16rem !important', | ||||||
| @ -43,6 +44,8 @@ class AdminPanelProvider extends PanelProvider | |||||||
|             ->brandLogo(config('app.logo')) |             ->brandLogo(config('app.logo')) | ||||||
|             ->brandLogoHeight('2rem') |             ->brandLogoHeight('2rem') | ||||||
|             ->profile(EditProfile::class, false) |             ->profile(EditProfile::class, false) | ||||||
|  |             ->maxContentWidth(MaxWidth::ScreenTwoExtraLarge) | ||||||
|  |             ->spa() | ||||||
|             ->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources') |             ->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources') | ||||||
|             ->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages') |             ->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages') | ||||||
|             ->discoverClusters(in: app_path('Filament/Clusters'), for: 'App\\Filament\\Clusters') |             ->discoverClusters(in: app_path('Filament/Clusters'), for: 'App\\Filament\\Clusters') | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Repositories\Daemon; | namespace App\Repositories\Daemon; | ||||||
| 
 | 
 | ||||||
|  | use Illuminate\Http\Client\Response; | ||||||
| use Webmozart\Assert\Assert; | use Webmozart\Assert\Assert; | ||||||
| use App\Models\Backup; | use App\Models\Backup; | ||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
| @ -27,7 +28,7 @@ class DaemonBackupRepository extends DaemonRepository | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException |      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException | ||||||
|      */ |      */ | ||||||
|     public function backup(Backup $backup) |     public function backup(Backup $backup): Response | ||||||
|     { |     { | ||||||
|         Assert::isInstanceOf($this->server, Server::class); |         Assert::isInstanceOf($this->server, Server::class); | ||||||
| 
 | 
 | ||||||
| @ -50,7 +51,7 @@ class DaemonBackupRepository extends DaemonRepository | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException |      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException | ||||||
|      */ |      */ | ||||||
|     public function restore(Backup $backup, string $url = null, bool $truncate = false) |     public function restore(Backup $backup, ?string $url = null, bool $truncate = false): Response | ||||||
|     { |     { | ||||||
|         Assert::isInstanceOf($this->server, Server::class); |         Assert::isInstanceOf($this->server, Server::class); | ||||||
| 
 | 
 | ||||||
| @ -73,7 +74,7 @@ class DaemonBackupRepository extends DaemonRepository | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException |      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException | ||||||
|      */ |      */ | ||||||
|     public function delete(Backup $backup) |     public function delete(Backup $backup): Response | ||||||
|     { |     { | ||||||
|         Assert::isInstanceOf($this->server, Server::class); |         Assert::isInstanceOf($this->server, Server::class); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ namespace App\Repositories\Daemon; | |||||||
| use App\Models\Node; | use App\Models\Node; | ||||||
| use GuzzleHttp\Exception\TransferException; | use GuzzleHttp\Exception\TransferException; | ||||||
| use App\Exceptions\Http\Connection\DaemonConnectionException; | use App\Exceptions\Http\Connection\DaemonConnectionException; | ||||||
|  | use Illuminate\Http\Client\Response; | ||||||
| 
 | 
 | ||||||
| class DaemonConfigurationRepository extends DaemonRepository | class DaemonConfigurationRepository extends DaemonRepository | ||||||
| { | { | ||||||
| @ -13,7 +14,7 @@ class DaemonConfigurationRepository extends DaemonRepository | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException |      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException | ||||||
|      */ |      */ | ||||||
|     public function getSystemInformation(?int $version = null, $connectTimeout = 5): array |     public function getSystemInformation(?int $version = null, int $connectTimeout = 5): array | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             $response = $this |             $response = $this | ||||||
| @ -34,7 +35,7 @@ class DaemonConfigurationRepository extends DaemonRepository | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException |      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException | ||||||
|      */ |      */ | ||||||
|     public function update(Node $node) |     public function update(Node $node): Response | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             return $this->getHttpClient()->post( |             return $this->getHttpClient()->post( | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ | |||||||
| namespace App\Repositories\Daemon; | namespace App\Repositories\Daemon; | ||||||
| 
 | 
 | ||||||
| use Carbon\CarbonInterval; | use Carbon\CarbonInterval; | ||||||
|  | use Illuminate\Http\Client\Response; | ||||||
| use Webmozart\Assert\Assert; | use Webmozart\Assert\Assert; | ||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
| use GuzzleHttp\Exception\ClientException; | use GuzzleHttp\Exception\ClientException; | ||||||
| @ -21,7 +22,7 @@ class DaemonFileRepository extends DaemonRepository | |||||||
|      * @throws \App\Exceptions\Http\Server\FileSizeTooLargeException |      * @throws \App\Exceptions\Http\Server\FileSizeTooLargeException | ||||||
|      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException |      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException | ||||||
|      */ |      */ | ||||||
|     public function getContent(string $path, int $notLargerThan = null): string |     public function getContent(string $path, ?int $notLargerThan = null): string | ||||||
|     { |     { | ||||||
|         Assert::isInstanceOf($this->server, Server::class); |         Assert::isInstanceOf($this->server, Server::class); | ||||||
| 
 | 
 | ||||||
| @ -48,7 +49,7 @@ class DaemonFileRepository extends DaemonRepository | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException |      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException | ||||||
|      */ |      */ | ||||||
|     public function putContent(string $path, string $content) |     public function putContent(string $path, string $content): Response | ||||||
|     { |     { | ||||||
|         Assert::isInstanceOf($this->server, Server::class); |         Assert::isInstanceOf($this->server, Server::class); | ||||||
| 
 | 
 | ||||||
| @ -88,7 +89,7 @@ class DaemonFileRepository extends DaemonRepository | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException |      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException | ||||||
|      */ |      */ | ||||||
|     public function createDirectory(string $name, string $path) |     public function createDirectory(string $name, string $path): Response | ||||||
|     { |     { | ||||||
|         Assert::isInstanceOf($this->server, Server::class); |         Assert::isInstanceOf($this->server, Server::class); | ||||||
| 
 | 
 | ||||||
| @ -110,7 +111,7 @@ class DaemonFileRepository extends DaemonRepository | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException |      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException | ||||||
|      */ |      */ | ||||||
|     public function renameFiles(?string $root, array $files) |     public function renameFiles(?string $root, array $files): Response | ||||||
|     { |     { | ||||||
|         Assert::isInstanceOf($this->server, Server::class); |         Assert::isInstanceOf($this->server, Server::class); | ||||||
| 
 | 
 | ||||||
| @ -132,7 +133,7 @@ class DaemonFileRepository extends DaemonRepository | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException |      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException | ||||||
|      */ |      */ | ||||||
|     public function copyFile(string $location) |     public function copyFile(string $location): Response | ||||||
|     { |     { | ||||||
|         Assert::isInstanceOf($this->server, Server::class); |         Assert::isInstanceOf($this->server, Server::class); | ||||||
| 
 | 
 | ||||||
| @ -153,7 +154,7 @@ class DaemonFileRepository extends DaemonRepository | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException |      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException | ||||||
|      */ |      */ | ||||||
|     public function deleteFiles(?string $root, array $files) |     public function deleteFiles(?string $root, array $files): Response | ||||||
|     { |     { | ||||||
|         Assert::isInstanceOf($this->server, Server::class); |         Assert::isInstanceOf($this->server, Server::class); | ||||||
| 
 | 
 | ||||||
| @ -203,7 +204,7 @@ class DaemonFileRepository extends DaemonRepository | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException |      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException | ||||||
|      */ |      */ | ||||||
|     public function decompressFile(?string $root, string $file) |     public function decompressFile(?string $root, string $file): Response | ||||||
|     { |     { | ||||||
|         Assert::isInstanceOf($this->server, Server::class); |         Assert::isInstanceOf($this->server, Server::class); | ||||||
| 
 | 
 | ||||||
| @ -229,7 +230,7 @@ class DaemonFileRepository extends DaemonRepository | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException |      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException | ||||||
|      */ |      */ | ||||||
|     public function chmodFiles(?string $root, array $files) |     public function chmodFiles(?string $root, array $files): Response | ||||||
|     { |     { | ||||||
|         Assert::isInstanceOf($this->server, Server::class); |         Assert::isInstanceOf($this->server, Server::class); | ||||||
| 
 | 
 | ||||||
| @ -251,7 +252,7 @@ class DaemonFileRepository extends DaemonRepository | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException |      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException | ||||||
|      */ |      */ | ||||||
|     public function pull(string $url, ?string $directory, array $params = []) |     public function pull(string $url, ?string $directory, array $params = []): Response | ||||||
|     { |     { | ||||||
|         Assert::isInstanceOf($this->server, Server::class); |         Assert::isInstanceOf($this->server, Server::class); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Repositories\Daemon; | namespace App\Repositories\Daemon; | ||||||
| 
 | 
 | ||||||
|  | use Illuminate\Http\Client\Response; | ||||||
| use Webmozart\Assert\Assert; | use Webmozart\Assert\Assert; | ||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
| use GuzzleHttp\Exception\TransferException; | use GuzzleHttp\Exception\TransferException; | ||||||
| @ -14,7 +15,7 @@ class DaemonPowerRepository extends DaemonRepository | |||||||
|      * |      * | ||||||
|      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException |      * @throws \App\Exceptions\Http\Connection\DaemonConnectionException | ||||||
|      */ |      */ | ||||||
|     public function send(string $action) |     public function send(string $action): Response | ||||||
|     { |     { | ||||||
|         Assert::isInstanceOf($this->server, Server::class); |         Assert::isInstanceOf($this->server, Server::class); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -17,7 +17,9 @@ class AdminAcl | |||||||
|      * implements a read/write/none permissions scheme for all endpoints. |      * implements a read/write/none permissions scheme for all endpoints. | ||||||
|      */ |      */ | ||||||
|     public const NONE = 0; |     public const NONE = 0; | ||||||
|  | 
 | ||||||
|     public const READ = 1; |     public const READ = 1; | ||||||
|  | 
 | ||||||
|     public const WRITE = 2; |     public const WRITE = 2; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -25,13 +27,21 @@ class AdminAcl | |||||||
|      * set for each key. These are stored in the database as r_{resource}. |      * set for each key. These are stored in the database as r_{resource}. | ||||||
|      */ |      */ | ||||||
|     public const RESOURCE_SERVERS = 'servers'; |     public const RESOURCE_SERVERS = 'servers'; | ||||||
|  | 
 | ||||||
|     public const RESOURCE_NODES = 'nodes'; |     public const RESOURCE_NODES = 'nodes'; | ||||||
|  | 
 | ||||||
|     public const RESOURCE_ALLOCATIONS = 'allocations'; |     public const RESOURCE_ALLOCATIONS = 'allocations'; | ||||||
|  | 
 | ||||||
|     public const RESOURCE_USERS = 'users'; |     public const RESOURCE_USERS = 'users'; | ||||||
|  | 
 | ||||||
|     public const RESOURCE_EGGS = 'eggs'; |     public const RESOURCE_EGGS = 'eggs'; | ||||||
|  | 
 | ||||||
|     public const RESOURCE_DATABASE_HOSTS = 'database_hosts'; |     public const RESOURCE_DATABASE_HOSTS = 'database_hosts'; | ||||||
|  | 
 | ||||||
|     public const RESOURCE_SERVER_DATABASES = 'server_databases'; |     public const RESOURCE_SERVER_DATABASES = 'server_databases'; | ||||||
|  | 
 | ||||||
|     public const RESOURCE_MOUNTS = 'mounts'; |     public const RESOURCE_MOUNTS = 'mounts'; | ||||||
|  | 
 | ||||||
|     public const RESOURCE_ROLES = 'roles'; |     public const RESOURCE_ROLES = 'roles'; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Lance Pioch
						Lance Pioch