diff --git a/.github/docker/default.conf b/.github/docker/default.conf deleted file mode 100644 index a6bd58d720..0000000000 --- a/.github/docker/default.conf +++ /dev/null @@ -1,75 +0,0 @@ -# If using Ubuntu this file should be placed in: -# /etc/nginx/sites-available/ -# -# If using CentOS this file should be placed in: -# /etc/nginx/conf.d/ -# - -# The MIT License (MIT) -# -# Pterodactyl® -# Copyright © Dane Everitt and contributors -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -server { - listen 80; - server_name _; - - root /app/public; - index index.html index.htm index.php; - charset utf-8; - - location / { - try_files $uri $uri/ /index.php?$query_string; - } - - location = /favicon.ico { access_log off; log_not_found off; } - location = /robots.txt { access_log off; log_not_found off; } - - access_log off; - error_log /var/log/nginx/panel.app-error.log error; - - # allow larger file uploads and longer script runtimes - client_max_body_size 100m; - client_body_timeout 120s; - - sendfile off; - - location ~ \.php$ { - fastcgi_split_path_info ^(.+\.php)(/.+)$; - # the fastcgi_pass path needs to be changed accordingly when using CentOS - fastcgi_pass 127.0.0.1:9000; - fastcgi_index index.php; - include fastcgi_params; - fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M"; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param HTTP_PROXY ""; - fastcgi_intercept_errors off; - fastcgi_buffer_size 16k; - fastcgi_buffers 4 16k; - fastcgi_connect_timeout 300; - fastcgi_send_timeout 300; - fastcgi_read_timeout 300; - } - - location ~ /\.ht { - deny all; - } -} diff --git a/.github/docker/default_ssl.conf b/.github/docker/default_ssl.conf deleted file mode 100644 index 930a38daa6..0000000000 --- a/.github/docker/default_ssl.conf +++ /dev/null @@ -1,70 +0,0 @@ -# If using Ubuntu this file should be placed in: -# /etc/nginx/sites-available/ -# -server { - listen 80; - server_name ; - return 301 https://$server_name$request_uri; -} - -server { - listen 443 ssl http2; - server_name ; - - root /app/public; - index index.php; - - access_log /var/log/nginx/panel.app-access.log; - error_log /var/log/nginx/panel.app-error.log error; - - # allow larger file uploads and longer script runtimes - client_max_body_size 100m; - client_body_timeout 120s; - - sendfile off; - - # strengthen ssl security - ssl_certificate /etc/letsencrypt/live//fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live//privkey.pem; - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_prefer_server_ciphers on; - ssl_session_cache shared:SSL:10m; - ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; - - # See the link below for more SSL information: - # https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html - # - # ssl_dhparam /etc/ssl/certs/dhparam.pem; - - # Add headers to serve security related headers - add_header Strict-Transport-Security "max-age=15768000; preload;"; - add_header X-Content-Type-Options nosniff; - add_header X-XSS-Protection "1; mode=block"; - add_header X-Robots-Tag none; - add_header Content-Security-Policy "frame-ancestors 'self'"; - - location / { - try_files $uri $uri/ /index.php?$query_string; - } - - location ~ \.php$ { - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_pass 127.0.0.1:9000; - fastcgi_index index.php; - include fastcgi_params; - fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M"; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param HTTP_PROXY ""; - fastcgi_intercept_errors off; - fastcgi_buffer_size 16k; - fastcgi_buffers 4 16k; - fastcgi_connect_timeout 300; - fastcgi_send_timeout 300; - fastcgi_read_timeout 300; - include /etc/nginx/fastcgi_params; - } - - location ~ /\.ht { - deny all; - } -} diff --git a/.github/docker/www.conf b/.github/docker/www.conf deleted file mode 100644 index c0c17903f3..0000000000 --- a/.github/docker/www.conf +++ /dev/null @@ -1,16 +0,0 @@ -[www] - -user = nginx -group = nginx - -listen = 127.0.0.1:9000 -listen.owner = nginx -listen.group = nginx -listen.mode = 0750 - -pm = ondemand -pm.max_children = 9 -pm.process_idle_timeout = 10s -pm.max_requests = 200 - -clear_env = no \ No newline at end of file diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 41b2cdd424..1d540975d0 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -1,6 +1,5 @@ name: Docker - on: push: branches: @@ -15,17 +14,23 @@ env: jobs: build-and-push: - name: Build and Push - runs-on: ubuntu-latest + name: Build and Push ${{ matrix.os }} + runs-on: ${{ matrix.os }} permissions: contents: read packages: write + + strategy: + fail-fast: false + matrix: + os: [ubuntu-24.04, ubuntu-24.04-arm] # Always run against a tag, even if the commit into the tag has [docker skip] within the commit message. if: "!contains(github.ref, 'main') || (!contains(github.event.head_commit.message, 'skip docker') && !contains(github.event.head_commit.message, 'docker skip'))" + steps: - name: Code checkout uses: actions/checkout@v4 - + - name: Docker metadata id: docker_meta uses: docker/metadata-action@v5 @@ -38,9 +43,6 @@ jobs: type=ref,event=tag type=ref,event=branch - - name: Setup QEMU - uses: docker/setup-qemu-action@v3 - - name: Setup Docker buildx uses: docker/setup-buildx-action@v3 @@ -58,26 +60,26 @@ jobs: echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - name: Build and Push (tag) - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 if: "github.event_name == 'release' && github.event.action == 'published'" with: context: . file: ./Dockerfile push: true - platforms: linux/amd64,linux/arm64 + platforms: ${{ matrix.os == 'ubuntu-24.04' && 'linux/amd64' || 'linux/arm64' }} build-args: | VERSION=${{ steps.build_info.outputs.version_tag }} labels: ${{ steps.docker_meta.outputs.labels }} tags: ${{ steps.docker_meta.outputs.tags }} - name: Build and Push (main) - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 if: "github.event_name == 'push' && contains(github.ref, 'main')" with: context: . file: ./Dockerfile push: ${{ github.event_name != 'pull_request' }} - platforms: linux/amd64,linux/arm64 + platforms: ${{ matrix.os == 'ubuntu-24.04' && 'linux/amd64' || 'linux/arm64' }} build-args: | VERSION=dev-${{ steps.build_info.outputs.short_sha }} labels: ${{ steps.docker_meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile index 3e2da64825..2bc0f23e3d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,50 +1,67 @@ # Pelican Production Dockerfile -FROM node:20-alpine AS yarn -#FROM --platform=$TARGETOS/$TARGETARCH node:20-alpine AS yarn +# ================================ +# Stage 1: Build PHP Dependencies +# ================================ +FROM --platform=$TARGETOS/$TARGETARCH php:8.3-fpm-alpine AS composer WORKDIR /build COPY . ./ +COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer + +# Install required libraries and PHP extensions +RUN apk update && apk add --no-cache \ + libpng-dev libjpeg-turbo-dev freetype-dev libzip-dev icu-dev \ + zip unzip curl \ + && docker-php-ext-install bcmath gd intl zip opcache pcntl posix pdo_mysql + +RUN composer install --no-dev --optimize-autoloader + +# ================================ +# Stage 2: Build Frontend Assets +# ================================ +FROM --platform=$TARGETOS/$TARGETARCH node:20-alpine AS yarn + +WORKDIR /build + +COPY --from=composer /build . RUN yarn config set network-timeout 300000 \ && yarn install --frozen-lockfile \ - && yarn run build:production + && yarn run build -FROM php:8.3-fpm-alpine -# FROM --platform=$TARGETOS/$TARGETARCH php:8.3-fpm-alpine - -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +# ================================ +# Stage 3: Build Final Application Image +# ================================ +FROM --platform=$TARGETOS/$TARGETARCH php:8.3-fpm-alpine WORKDIR /var/www/html -# Install dependencies +COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer + +# Install additional required libraries RUN apk update && apk add --no-cache \ libpng-dev libjpeg-turbo-dev freetype-dev libzip-dev icu-dev \ - zip unzip curl \ - caddy ca-certificates supervisor \ - && docker-php-ext-install bcmath gd intl zip opcache pcntl posix pdo_mysql + zip unzip curl caddy ca-certificates supervisor -# Copy the Caddyfile to the container -COPY Caddyfile /etc/caddy/Caddyfile - -# Copy the application code to the container -COPY . . +# Copy PHP extensions and configuration from Composer stage +COPY --from=composer /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/ +COPY --from=composer /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/ -COPY --from=yarn /build/public/assets ./public/assets +COPY Caddyfile /etc/caddy/Caddyfile +COPY --from=yarn /build . RUN touch .env -RUN composer install --no-dev --optimize-autoloader - -# Set file permissions +# Set permissions for Laravel directories RUN chmod -R 755 storage bootstrap/cache \ && chown -R www-data:www-data ./ -# Add scheduler to cron +# Add Laravel scheduler to crontab RUN echo "* * * * * php /var/www/html/artisan schedule:run >> /dev/null 2>&1" | crontab -u www-data - -## supervisord config and log dir +# Configure Supervisor RUN cp .github/docker/supervisord.conf /etc/supervisord.conf && \ mkdir /var/log/supervisord/ diff --git a/app/Console/Commands/Schedule/ProcessRunnableCommand.php b/app/Console/Commands/Schedule/ProcessRunnableCommand.php index d773cb2b2f..57a8bb48b8 100644 --- a/app/Console/Commands/Schedule/ProcessRunnableCommand.php +++ b/app/Console/Commands/Schedule/ProcessRunnableCommand.php @@ -6,6 +6,7 @@ use App\Models\Schedule; use Illuminate\Database\Eloquent\Builder; use App\Services\Schedules\ProcessScheduleService; +use Throwable; class ProcessRunnableCommand extends Command { @@ -13,10 +14,7 @@ class ProcessRunnableCommand extends Command protected $description = 'Process schedules in the database and determine which are ready to run.'; - /** - * Handle command execution. - */ - public function handle(): int + public function handle(ProcessScheduleService $processScheduleService): int { $schedules = Schedule::query() ->with('tasks') @@ -35,7 +33,7 @@ public function handle(): int $bar = $this->output->createProgressBar(count($schedules)); foreach ($schedules as $schedule) { $bar->clear(); - $this->processSchedule($schedule); + $this->processSchedule($processScheduleService, $schedule); $bar->advance(); $bar->display(); } @@ -50,20 +48,20 @@ public function handle(): int * never throw an exception out, otherwise you'll end up killing the entire run group causing * any other schedules to not process correctly. */ - protected function processSchedule(Schedule $schedule): void + protected function processSchedule(ProcessScheduleService $processScheduleService, Schedule $schedule): void { if ($schedule->tasks->isEmpty()) { return; } try { - $this->getLaravel()->make(ProcessScheduleService::class)->handle($schedule); + $processScheduleService->handle($schedule); $this->line(trans('command/messages.schedule.output_line', [ 'schedule' => $schedule->name, 'id' => $schedule->id, ])); - } catch (\Throwable|\Exception $exception) { + } catch (Throwable $exception) { logger()->error($exception, ['schedule_id' => $schedule->id]); $this->error(__('commands.schedule.process.no_tasks') . " #$schedule->id: " . $exception->getMessage()); diff --git a/app/Console/Commands/Server/BulkPowerActionCommand.php b/app/Console/Commands/Server/BulkPowerActionCommand.php index 52bcb3e428..1aae626850 100644 --- a/app/Console/Commands/Server/BulkPowerActionCommand.php +++ b/app/Console/Commands/Server/BulkPowerActionCommand.php @@ -19,26 +19,13 @@ class BulkPowerActionCommand extends Command protected $description = 'Perform bulk power management on large groupings of servers or nodes at once.'; - /** - * BulkPowerActionCommand constructor. - */ - public function __construct(private DaemonPowerRepository $powerRepository, private ValidatorFactory $validator) - { - parent::__construct(); - } - - /** - * Handle the bulk power request. - * - * @throws \Illuminate\Validation\ValidationException - */ - public function handle(): void + public function handle(DaemonPowerRepository $powerRepository, ValidatorFactory $validator): void { $action = $this->argument('action'); $nodes = empty($this->option('nodes')) ? [] : explode(',', $this->option('nodes')); $servers = empty($this->option('servers')) ? [] : explode(',', $this->option('servers')); - $validator = $this->validator->make([ + $validator = $validator->make([ 'action' => $action, 'nodes' => $nodes, 'servers' => $servers, @@ -64,11 +51,14 @@ public function handle(): void } $bar = $this->output->createProgressBar($count); - $powerRepository = $this->powerRepository; - // @phpstan-ignore-next-line - $this->getQueryBuilder($servers, $nodes)->each(function (Server $server) use ($action, $powerRepository, &$bar) { + + $this->getQueryBuilder($servers, $nodes)->get()->each(function ($server, int $index) use ($action, $powerRepository, &$bar): mixed { $bar->clear(); + if (!$server instanceof Server) { + return null; + } + try { $powerRepository->setServer($server)->send($action); } catch (Exception $exception) { @@ -82,6 +72,8 @@ public function handle(): void $bar->advance(); $bar->display(); + + return null; }); $this->line(''); diff --git a/app/Console/Commands/UpgradeCommand.php b/app/Console/Commands/UpgradeCommand.php index 145e6e0c6f..e464eb0a10 100644 --- a/app/Console/Commands/UpgradeCommand.php +++ b/app/Console/Commands/UpgradeCommand.php @@ -39,10 +39,6 @@ public function handle(): void $this->line($this->getUrl()); } - if (version_compare(PHP_VERSION, '7.4.0') < 0) { - $this->error(__('commands.upgrade.php_version') . ' [' . PHP_VERSION . '].'); - } - $user = 'www-data'; $group = 'www-data'; if ($this->input->isInteractive()) { diff --git a/app/Eloquent/BackupQueryBuilder.php b/app/Eloquent/BackupQueryBuilder.php new file mode 100644 index 0000000000..53f10a28f4 --- /dev/null +++ b/app/Eloquent/BackupQueryBuilder.php @@ -0,0 +1,24 @@ + + */ +class BackupQueryBuilder extends Builder +{ + public function nonFailed(): self + { + $this->where(function (Builder $query) { + $query + ->whereNull('completed_at') + ->orWhere('is_successful', true); + }); + + return $this; + } +} diff --git a/app/Enums/EditorLanguages.php b/app/Enums/EditorLanguages.php index 26f4520d93..91dcaebe78 100644 --- a/app/Enums/EditorLanguages.php +++ b/app/Enums/EditorLanguages.php @@ -91,7 +91,7 @@ enum EditorLanguages: string implements HasLabel case yaml = 'yaml'; case json = 'json'; - public function getLabel(): ?string + public function getLabel(): string { return $this->name; } diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 5fc4fe5e86..685aa0a553 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -20,6 +20,7 @@ use Symfony\Component\Mailer\Exception\TransportException; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; +use Throwable; class Handler extends ExceptionHandler { @@ -179,10 +180,7 @@ public function invalidJson($request, ValidationException $exception): JsonRespo return response()->json(['errors' => $errors], $exception->status); } - /** - * Return the exception as a JSONAPI representation for use on API requests. - */ - protected function convertExceptionToArray(\Throwable $e, array $override = []): array + public static function exceptionToArray(Throwable $e, array $override = []): array { $match = self::$exceptionResponseCodes[get_class($e)] ?? null; @@ -214,7 +212,7 @@ protected function convertExceptionToArray(\Throwable $e, array $override = []): 'trace' => Collection::make($e->getTrace()) ->map(fn ($trace) => Arr::except($trace, ['args'])) ->all(), - 'previous' => Collection::make($this->extractPrevious($e)) + 'previous' => Collection::make(self::extractPrevious($e)) ->map(fn ($exception) => $exception->getTrace()) ->map(fn ($trace) => Arr::except($trace, ['args'])) ->all(), @@ -225,6 +223,14 @@ protected function convertExceptionToArray(\Throwable $e, array $override = []): return ['errors' => [array_merge($error, $override)]]; } + /** + * Return the exception as a JSONAPI representation for use on API requests. + */ + protected function convertExceptionToArray(Throwable $e, array $override = []): array + { + return self::exceptionToArray($e, $override); + } + /** * Return an array of exceptions that should not be reported. */ @@ -251,15 +257,12 @@ protected function unauthenticated($request, AuthenticationException $exception) * Extracts all the previous exceptions that lead to the one passed into this * function being thrown. * - * @return \Throwable[] + * @return Throwable[] */ - protected function extractPrevious(\Throwable $e): array + public static function extractPrevious(Throwable $e): array { $previous = []; while ($value = $e->getPrevious()) { - if (!$value instanceof \Throwable) { - break; - } $previous[] = $value; $e = $value; } @@ -273,7 +276,6 @@ protected function extractPrevious(\Throwable $e): array */ public static function toArray(\Throwable $e): array { - // @phpstan-ignore-next-line - return (new self(app()))->convertExceptionToArray($e); + return self::exceptionToArray($e); } } diff --git a/app/Extensions/Filesystem/S3Filesystem.php b/app/Extensions/Filesystem/S3Filesystem.php index 6ce793b996..6535dc6f31 100644 --- a/app/Extensions/Filesystem/S3Filesystem.php +++ b/app/Extensions/Filesystem/S3Filesystem.php @@ -1,28 +1,5 @@ and contributors - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. */ - namespace App\Extensions\Filesystem; use Aws\S3\S3ClientInterface; diff --git a/app/Filament/Admin/Resources/NodeResource/Pages/EditNode.php b/app/Filament/Admin/Resources/NodeResource/Pages/EditNode.php index d5e1c4e2b9..7078b15b55 100644 --- a/app/Filament/Admin/Resources/NodeResource/Pages/EditNode.php +++ b/app/Filament/Admin/Resources/NodeResource/Pages/EditNode.php @@ -7,6 +7,7 @@ use App\Services\Helpers\SoftwareVersionService; use App\Services\Nodes\NodeAutoDeployService; use App\Services\Nodes\NodeUpdateService; +use Exception; use Filament\Actions; use Filament\Forms; use Filament\Forms\Components\Actions as FormActions; @@ -25,6 +26,7 @@ use Filament\Notifications\Notification; use Filament\Resources\Pages\EditRecord; use Filament\Support\Enums\Alignment; +use Illuminate\Database\Eloquent\Model; use Illuminate\Support\HtmlString; use Webbingbrasil\FilamentCopyActions\Forms\Actions\CopyAction; @@ -32,6 +34,15 @@ class EditNode extends EditRecord { protected static string $resource = NodeResource::class; + private bool $errored = false; + + private NodeUpdateService $nodeUpdateService; + + public function boot(NodeUpdateService $nodeUpdateService): void + { + $this->nodeUpdateService = $nodeUpdateService; + } + public function form(Forms\Form $form): Forms\Form { return $form->schema([ @@ -552,8 +563,8 @@ public function form(Forms\Form $form): Forms\Form ->requiresConfirmation() ->modalHeading('Reset Daemon Token?') ->modalDescription('Resetting the daemon token will void any request coming from the old token. This token is used for all sensitive operations on the daemon including server creation and deletion. We suggest changing this token regularly for security.') - ->action(function (NodeUpdateService $nodeUpdateService, Node $node) { - $nodeUpdateService->handle($node, [], true); + ->action(function (Node $node) { + $this->nodeUpdateService->handle($node, [], true); Notification::make()->success()->title('Daemon Key Reset')->send(); $this->fillForm(); }), @@ -583,6 +594,39 @@ protected function mutateFormDataBeforeFill(array $data): array return $data; } + protected function handleRecordUpdate(Model $record, array $data): Model + { + if (!$record instanceof Node) { + return $record; + } + + try { + unset($data['unlimited_mem'], $data['unlimited_disk'], $data['unlimited_cpu']); + + return $this->nodeUpdateService->handle($record, $data); + } catch (Exception $exception) { + $this->errored = true; + Notification::make() + ->title('Error connecting to the node') + ->body('The configuration could not be automatically updated on Wings, you will need to manually update the configuration file.') + ->color('warning') + ->icon('tabler-database') + ->warning() + ->send(); + + return parent::handleRecordUpdate($record, $data); + } + } + + protected function getSavedNotification(): ?Notification + { + if ($this->errored) { + return null; + } + + return parent::getSavedNotification(); + } + protected function getFormActions(): array { return []; diff --git a/app/Filament/Admin/Resources/UserResource/Pages/EditUser.php b/app/Filament/Admin/Resources/UserResource/Pages/EditUser.php index 40c0f2957e..b17707b534 100644 --- a/app/Filament/Admin/Resources/UserResource/Pages/EditUser.php +++ b/app/Filament/Admin/Resources/UserResource/Pages/EditUser.php @@ -5,6 +5,7 @@ use App\Filament\Admin\Resources\UserResource; use App\Models\Role; use App\Models\User; +use App\Services\Helpers\LanguageService; use Filament\Actions\DeleteAction; use Filament\Forms\Components\CheckboxList; use Filament\Forms\Components\Hidden; @@ -40,7 +41,7 @@ public function form(Form $form): Form ->required() ->hidden() ->default('en') - ->options(fn (User $user) => $user->getAvailableLanguages()), + ->options(fn (LanguageService $languageService) => $languageService->getAvailableLanguages()), Hidden::make('skipValidation') ->default(true), CheckboxList::make('roles') diff --git a/app/Filament/Admin/Resources/UserResource/RelationManagers/ServersRelationManager.php b/app/Filament/Admin/Resources/UserResource/RelationManagers/ServersRelationManager.php index 83c8bf7af5..4ebb743e29 100644 --- a/app/Filament/Admin/Resources/UserResource/RelationManagers/ServersRelationManager.php +++ b/app/Filament/Admin/Resources/UserResource/RelationManagers/ServersRelationManager.php @@ -34,7 +34,7 @@ public function table(Table $table): Table ->label('Suspend All Servers') ->color('warning') ->action(function (SuspensionService $suspensionService) use ($user) { - collect($user->servers()->get())->filter(fn ($server) => !$server->isSuspended()) + collect($user->servers)->filter(fn ($server) => !$server->isSuspended()) ->each(fn ($server) => $suspensionService->handle($server, SuspendAction::Suspend)); }), Actions\Action::make('toggleUnsuspend') diff --git a/app/Filament/Components/Actions/ImportEggAction.php b/app/Filament/Components/Actions/ImportEggAction.php index 44748e42ac..70cab62c20 100644 --- a/app/Filament/Components/Actions/ImportEggAction.php +++ b/app/Filament/Components/Actions/ImportEggAction.php @@ -10,7 +10,6 @@ use Filament\Forms\Components\Tabs\Tab; use Filament\Forms\Components\TextInput; use Filament\Notifications\Notification; -use Livewire\Features\SupportFileUploads\TemporaryUploadedFile; class ImportEggAction extends Action { @@ -55,7 +54,6 @@ protected function setUp(): void $this->action(function (array $data, EggImporterService $eggImportService): void { try { if (!empty($data['egg'])) { - /** @var TemporaryUploadedFile[] $eggFile */ $eggFile = $data['egg']; foreach ($eggFile as $file) { diff --git a/app/Filament/Components/Tables/Actions/ImportEggAction.php b/app/Filament/Components/Tables/Actions/ImportEggAction.php index e8a82a3013..ae2fe68b4a 100644 --- a/app/Filament/Components/Tables/Actions/ImportEggAction.php +++ b/app/Filament/Components/Tables/Actions/ImportEggAction.php @@ -10,7 +10,6 @@ use Filament\Forms\Components\TextInput; use Filament\Notifications\Notification; use Filament\Tables\Actions\Action; -use Livewire\Features\SupportFileUploads\TemporaryUploadedFile; class ImportEggAction extends Action { @@ -55,7 +54,6 @@ protected function setUp(): void $this->action(function (array $data, EggImporterService $eggImportService): void { try { if (!empty($data['egg'])) { - /** @var TemporaryUploadedFile[] $eggFile */ $eggFile = $data['egg']; foreach ($eggFile as $file) { diff --git a/app/Filament/Components/Tables/Columns/DateTimeColumn.php b/app/Filament/Components/Tables/Columns/DateTimeColumn.php index 33dc08ec79..05793276e6 100644 --- a/app/Filament/Components/Tables/Columns/DateTimeColumn.php +++ b/app/Filament/Components/Tables/Columns/DateTimeColumn.php @@ -23,6 +23,6 @@ public function since(?string $timezone = null): static public function getTimezone(): string { - return auth()->user()?->timezone ?? config('app.timezone', 'UTC'); + return auth()->user()->timezone ?? config('app.timezone', 'UTC'); } } diff --git a/app/Filament/Pages/Auth/EditProfile.php b/app/Filament/Pages/Auth/EditProfile.php index 4146312731..f328fdeb48 100644 --- a/app/Filament/Pages/Auth/EditProfile.php +++ b/app/Filament/Pages/Auth/EditProfile.php @@ -8,6 +8,7 @@ use App\Models\ActivityLog; use App\Models\ApiKey; use App\Models\User; +use App\Services\Helpers\LanguageService; use App\Services\Users\ToggleTwoFactorService; use App\Services\Users\TwoFactorSetupService; use App\Services\Users\UserUpdateService; @@ -115,13 +116,12 @@ protected function getForms(): array ->prefixIcon('tabler-flag') ->live() ->default('en') - ->helperText(fn (User $user, $state) => new HtmlString($user->isLanguageTranslated($state) ? '' : " + ->helperText(fn ($state, LanguageService $languageService) => new HtmlString($languageService->isLanguageTranslated($state) ? '' : " Your language ($state) has not been translated yet! But never fear, you can help fix that by contributing directly here. - ") - ) - ->options(fn (User $user) => $user->getAvailableLanguages()), + ")) + ->options(fn (LanguageService $languageService) => $languageService->getAvailableLanguages()), ]), Tab::make('OAuth') @@ -208,38 +208,30 @@ protected function getForms(): array 'addLogoSpace' => true, 'logoSpaceWidth' => 13, 'logoSpaceHeight' => 13, + 'version' => Version::AUTO, + // 'outputInterface' => QRSvgWithLogo::class, + 'outputBase64' => false, + 'eccLevel' => EccLevel::H, // ECC level H is necessary when using logos + 'addQuietzone' => true, + // 'drawLightModules' => true, + 'connectPaths' => true, + 'drawCircularModules' => true, + // 'circleRadius' => 0.45, + 'svgDefs' => ' + + + + + + + ', ]); // https://github.com/chillerlan/php-qrcode/blob/main/examples/svgWithLogo.php - // QROptions - // @phpstan-ignore property.protected - $options->version = Version::AUTO; - // $options->outputInterface = QRSvgWithLogo::class; - // @phpstan-ignore property.protected - $options->outputBase64 = false; - // @phpstan-ignore property.protected - $options->eccLevel = EccLevel::H; // ECC level H is necessary when using logos - // @phpstan-ignore property.protected - $options->addQuietzone = true; - // $options->drawLightModules = true; - // @phpstan-ignore property.protected - $options->connectPaths = true; - // @phpstan-ignore property.protected - $options->drawCircularModules = true; - // $options->circleRadius = 0.45; - - // @phpstan-ignore property.protected - $options->svgDefs = ' - - - - - '; - $image = (new QRCode($options))->render($url); return [ diff --git a/app/Filament/Server/Resources/DatabaseResource/Pages/ListDatabases.php b/app/Filament/Server/Resources/DatabaseResource/Pages/ListDatabases.php index ab4b418e73..bce64b791f 100644 --- a/app/Filament/Server/Resources/DatabaseResource/Pages/ListDatabases.php +++ b/app/Filament/Server/Resources/DatabaseResource/Pages/ListDatabases.php @@ -6,7 +6,6 @@ use App\Filament\Components\Tables\Columns\DateTimeColumn; use App\Filament\Server\Resources\DatabaseResource; use App\Models\Database; -use App\Models\DatabaseHost; use App\Models\Permission; use App\Models\Server; use App\Services\Databases\DatabaseManagementService; @@ -99,7 +98,7 @@ protected function getHeaderActions(): array ->columnSpan(2) ->required() ->placeholder('Select Database Host') - ->options(fn () => $server->node->databaseHosts->mapWithKeys(fn (DatabaseHost $databaseHost) => [$databaseHost->id => $databaseHost->name])), + ->options(fn () => $server->node->databaseHosts->mapWithKeys(fn ($databaseHost) => [$databaseHost->id => $databaseHost->name])), TextInput::make('database') ->columnSpan(1) ->label('Database Name') diff --git a/app/Filament/Server/Resources/FileResource/Pages/ListFiles.php b/app/Filament/Server/Resources/FileResource/Pages/ListFiles.php index 7bafed8cae..87e087b42d 100644 --- a/app/Filament/Server/Resources/FileResource/Pages/ListFiles.php +++ b/app/Filament/Server/Resources/FileResource/Pages/ListFiles.php @@ -355,8 +355,7 @@ public function table(Table $table): Table ->action(function (Collection $files, $data, DaemonFileRepository $fileRepository) use ($server) { $location = resolve_path(join_paths($this->path, $data['location'])); - // @phpstan-ignore-next-line - $files = $files->map(fn ($file) => ['to' => $location, 'from' => $file->name])->toArray(); + $files = $files->map(fn ($file) => ['to' => $location, 'from' => $file['name']])->toArray(); $fileRepository ->setServer($server) ->renameFiles($this->path, $files); @@ -374,8 +373,7 @@ public function table(Table $table): Table BulkAction::make('archive') ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_ARCHIVE, $server)) ->action(function (Collection $files, DaemonFileRepository $fileRepository) use ($server) { - // @phpstan-ignore-next-line - $files = $files->map(fn ($file) => $file->name)->toArray(); + $files = $files->map(fn ($file) => $file['name'])->toArray(); $fileRepository ->setServer($server) @@ -396,8 +394,7 @@ public function table(Table $table): Table DeleteBulkAction::make() ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_DELETE, $server)) ->action(function (Collection $files, DaemonFileRepository $fileRepository) use ($server) { - // @phpstan-ignore-next-line - $files = $files->map(fn ($file) => $file->name)->toArray(); + $files = $files->map(fn ($file) => $file['name'])->toArray(); $fileRepository ->setServer($server) ->deleteFiles($this->path, $files); diff --git a/app/Filament/Server/Widgets/ServerConsole.php b/app/Filament/Server/Widgets/ServerConsole.php index 851b4b3a30..f1ca9f3709 100644 --- a/app/Filament/Server/Widgets/ServerConsole.php +++ b/app/Filament/Server/Widgets/ServerConsole.php @@ -30,16 +30,25 @@ class ServerConsole extends Widget public string $input = ''; + private GetUserPermissionsService $getUserPermissionsService; + + private NodeJWTService $nodeJWTService; + + public function boot(GetUserPermissionsService $getUserPermissionsService, NodeJWTService $nodeJWTService): void + { + $this->getUserPermissionsService = $getUserPermissionsService; + $this->nodeJWTService = $nodeJWTService; + } + protected function getToken(): string { if (!$this->user || !$this->server || $this->user->cannot(Permission::ACTION_WEBSOCKET_CONNECT, $this->server)) { throw new HttpForbiddenException('You do not have permission to connect to this server\'s websocket.'); } - // @phpstan-ignore-next-line - $permissions = app(GetUserPermissionsService::class)->handle($this->server, $this->user); - // @phpstan-ignore-next-line - return app(NodeJWTService::class) + $permissions = $this->getUserPermissionsService->handle($this->server, $this->user); + + return $this->nodeJWTService ->setExpiresAt(now()->addMinutes(10)->toImmutable()) ->setUser($this->user) ->setClaims([ diff --git a/app/Http/Controllers/Api/Client/AccountController.php b/app/Http/Controllers/Api/Client/AccountController.php index 6a0862d6b5..eb1303539d 100644 --- a/app/Http/Controllers/Api/Client/AccountController.php +++ b/app/Http/Controllers/Api/Client/AccountController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Client; +use Illuminate\Auth\SessionGuard; use Illuminate\Http\Request; use Illuminate\Http\Response; use Illuminate\Auth\AuthManager; @@ -63,8 +64,7 @@ public function updatePassword(UpdatePasswordRequest $request): JsonResponse // other devices functionality to work. $guard->setUser($user); - // This method doesn't exist in the stateless Sanctum world. - if (method_exists($guard, 'logoutOtherDevices')) { + if ($guard instanceof SessionGuard) { $guard->logoutOtherDevices($request->input('password')); } diff --git a/app/Http/Controllers/Api/Client/Servers/BackupController.php b/app/Http/Controllers/Api/Client/Servers/BackupController.php index ab1e441e24..9fc96e36d0 100644 --- a/app/Http/Controllers/Api/Client/Servers/BackupController.php +++ b/app/Http/Controllers/Api/Client/Servers/BackupController.php @@ -22,14 +22,11 @@ class BackupController extends ClientApiController { - /** - * BackupController constructor. - */ public function __construct( - private DaemonBackupRepository $daemonRepository, - private DeleteBackupService $deleteBackupService, - private InitiateBackupService $initiateBackupService, - private DownloadLinkService $downloadLinkService, + private readonly DaemonBackupRepository $daemonRepository, + private readonly DeleteBackupService $deleteBackupService, + private readonly InitiateBackupService $initiateBackupService, + private readonly DownloadLinkService $downloadLinkService, ) { parent::__construct(); } @@ -38,7 +35,7 @@ public function __construct( * Returns all the backups for a given server instance in a paginated * result set. * - * @throws \Illuminate\Auth\Access\AuthorizationException + * @throws AuthorizationException */ public function index(Request $request, Server $server): array { diff --git a/app/Http/Controllers/Api/Client/Servers/CommandController.php b/app/Http/Controllers/Api/Client/Servers/CommandController.php index f367c204d6..1591f38186 100644 --- a/app/Http/Controllers/Api/Client/Servers/CommandController.php +++ b/app/Http/Controllers/Api/Client/Servers/CommandController.php @@ -5,7 +5,6 @@ use Illuminate\Http\Response; use App\Models\Server; use App\Facades\Activity; -use Psr\Http\Message\ResponseInterface; use GuzzleHttp\Exception\BadResponseException; use Symfony\Component\HttpKernel\Exception\HttpException; use App\Http\Controllers\Api\Client\ClientApiController; @@ -28,7 +27,7 @@ public function index(SendCommandRequest $request, Server $server): Response $previous = $exception->getPrevious(); if ($previous instanceof BadResponseException) { - if ($previous->getResponse() instanceof ResponseInterface && $previous->getResponse()->getStatusCode() === Response::HTTP_BAD_GATEWAY) { + if ($previous->getResponse()->getStatusCode() === Response::HTTP_BAD_GATEWAY) { throw new HttpException(Response::HTTP_BAD_GATEWAY, 'Server must be online in order to send commands.', $exception); } } diff --git a/app/Http/Controllers/Api/Remote/SftpAuthenticationController.php b/app/Http/Controllers/Api/Remote/SftpAuthenticationController.php index 04d5ca29d8..73d9eef430 100644 --- a/app/Http/Controllers/Api/Remote/SftpAuthenticationController.php +++ b/app/Http/Controllers/Api/Remote/SftpAuthenticationController.php @@ -158,6 +158,6 @@ protected function throttleKey(Request $request): string { $username = explode('.', strrev($request->input('username', ''))); - return strtolower(strrev($username[0] ?? '') . '|' . $request->ip()); + return strtolower(strrev($username[0]) . '|' . $request->ip()); } } diff --git a/app/Http/Controllers/Auth/AbstractLoginController.php b/app/Http/Controllers/Auth/AbstractLoginController.php deleted file mode 100644 index 4a6fa719f1..0000000000 --- a/app/Http/Controllers/Auth/AbstractLoginController.php +++ /dev/null @@ -1,106 +0,0 @@ -lockoutTime = config('auth.lockout.time'); - $this->maxLoginAttempts = config('auth.lockout.attempts'); - $this->auth = Container::getInstance()->make(AuthManager::class); - } - - /** - * Get the failed login response instance. - * - * @throws \App\Exceptions\DisplayException - */ - protected function sendFailedLoginResponse(Request $request, ?Authenticatable $user = null, ?string $message = null): never - { - $this->incrementLoginAttempts($request); - $this->fireFailedLoginEvent($user, [ - $this->getField($request->input('user')) => $request->input('user'), - ]); - - if ($request->route()->named('auth.login-checkpoint')) { - throw new DisplayException($message ?? trans('auth.two_factor.checkpoint_failed')); - } - - throw new DisplayException(trans('auth.failed')); - } - - /** - * Send the response after the user was authenticated. - */ - protected function sendLoginResponse(User $user, Request $request): JsonResponse - { - $request->session()->remove('auth_confirmation_token'); - $request->session()->regenerate(); - - $this->clearLoginAttempts($request); - - $this->auth->guard()->login($user, true); - - Event::dispatch(new DirectLogin($user, true)); - - return new JsonResponse([ - 'data' => [ - 'complete' => true, - 'intended' => $this->redirectPath(), - 'user' => $user->toReactObject(), - ], - ]); - } - - /** - * Determine if the user is logging in using an email or username. - */ - protected function getField(?string $input = null): string - { - return ($input && str_contains($input, '@')) ? 'email' : 'username'; - } - - /** - * Fire a failed login event. - */ - protected function fireFailedLoginEvent(?Authenticatable $user = null, array $credentials = []): void - { - Event::dispatch(new Failed('auth', $user, $credentials)); - } -} diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php deleted file mode 100644 index f58aded823..0000000000 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ /dev/null @@ -1,38 +0,0 @@ -ip(), $request->input('email'))); - - return $this->sendResetLinkResponse($request, Password::RESET_LINK_SENT); - } - - /** - * Get the response for a successful password reset link. - */ - protected function sendResetLinkResponse(Request $request, string $response): JsonResponse - { - return response()->json([ - 'status' => trans($response), - ]); - } -} diff --git a/app/Http/Controllers/Auth/LoginCheckpointController.php b/app/Http/Controllers/Auth/LoginCheckpointController.php deleted file mode 100644 index 8797f533be..0000000000 --- a/app/Http/Controllers/Auth/LoginCheckpointController.php +++ /dev/null @@ -1,124 +0,0 @@ -hasTooManyLoginAttempts($request)) { - $this->sendLockoutResponse($request); - } - - $details = $request->session()->get('auth_confirmation_token'); - if (!$this->hasValidSessionData($details)) { - $this->sendFailedLoginResponse($request, null, self::TOKEN_EXPIRED_MESSAGE); - } - - if (!hash_equals($request->input('confirmation_token') ?? '', $details['token_value'])) { - $this->sendFailedLoginResponse($request); - } - - $user = User::query()->find($details['user_id']); - if (!$user) { - $this->sendFailedLoginResponse($request, null, self::TOKEN_EXPIRED_MESSAGE); - } - - // Recovery tokens go through a slightly different pathway for usage. - if (!is_null($recoveryToken = $request->input('recovery_token'))) { - if ($this->isValidRecoveryToken($user, $recoveryToken)) { - Event::dispatch(new ProvidedAuthenticationToken($user, true)); - - return $this->sendLoginResponse($user, $request); - } - } else { - if ($this->google2FA->verifyKey($user->totp_secret, (string) $request->input('authentication_code'), config('panel.auth.2fa.window'))) { - Event::dispatch(new ProvidedAuthenticationToken($user)); - - return $this->sendLoginResponse($user, $request); - } - } - - $this->sendFailedLoginResponse($request, $user, !empty($recoveryToken) ? 'The recovery token provided is not valid.' : null); - } - - /** - * Determines if a given recovery token is valid for the user account. If we find a matching token - * it will be deleted from the database. - * - * @throws \Exception - */ - protected function isValidRecoveryToken(User $user, string $value): bool - { - foreach ($user->recoveryTokens as $token) { - if (password_verify($value, $token->token)) { - $token->delete(); - - return true; - } - } - - return false; - } - - /** - * Determines if the data provided from the session is valid or not. This - * will return false if the data is invalid, or if more time has passed than - * was configured when the session was written. - */ - protected function hasValidSessionData(array $data): bool - { - $validator = $this->validation->make($data, [ - 'user_id' => 'required|integer|min:1', - 'token_value' => 'required|string', - 'expires_at' => 'required', - ]); - - if ($validator->fails()) { - return false; - } - - if (!$data['expires_at'] instanceof CarbonInterface) { - return false; - } - - if ($data['expires_at']->isBefore(CarbonImmutable::now())) { - return false; - } - - return true; - } -} diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php deleted file mode 100644 index 1501b6d66a..0000000000 --- a/app/Http/Controllers/Auth/LoginController.php +++ /dev/null @@ -1,77 +0,0 @@ -hasTooManyLoginAttempts($request)) { - $this->fireLockoutEvent($request); - $this->sendLockoutResponse($request); - } - - $username = $request->input('user'); - $user = User::query()->where($this->getField($username), $username)->first(); - if (!$user) { - $this->sendFailedLoginResponse($request); - } - - // Ensure that the account is using a valid username and password before trying to - // continue. Previously this was handled in the 2FA checkpoint, however that has - // a flaw in which you can discover if an account exists simply by seeing if you - // can proceed to the next step in the login process. - if (!password_verify($request->input('password'), $user->password)) { - $this->sendFailedLoginResponse($request, $user); - } - - if (!$user->use_totp) { - return $this->sendLoginResponse($user, $request); - } - - Activity::event('auth:checkpoint')->withRequestMetadata()->subject($user)->log(); - - $request->session()->put('auth_confirmation_token', [ - 'user_id' => $user->id, - 'token_value' => $token = Str::random(64), - 'expires_at' => CarbonImmutable::now()->addMinutes(5), - ]); - - return new JsonResponse([ - 'data' => [ - 'complete' => false, - 'confirmation_token' => $token, - ], - ]); - } -} diff --git a/app/Http/Controllers/Auth/OAuthController.php b/app/Http/Controllers/Auth/OAuthController.php index 40a72a5dc4..829e40cf21 100644 --- a/app/Http/Controllers/Auth/OAuthController.php +++ b/app/Http/Controllers/Auth/OAuthController.php @@ -16,12 +16,9 @@ class OAuthController extends Controller { - /** - * OAuthController constructor. - */ public function __construct( - private AuthManager $auth, - private UserUpdateService $updateService + private readonly AuthManager $auth, + private readonly UserUpdateService $updateService ) {} /** diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php deleted file mode 100644 index 8cceb714e1..0000000000 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ /dev/null @@ -1,100 +0,0 @@ -broker()->reset( - $this->credentials($request), - function ($user, $password) { - $this->resetPassword($user, $password); - } - ); - - // If the password was successfully reset, we will redirect the user back to - // the application's home authenticated view. If there is an error we can - // redirect them back to where they came from with their error message. - if ($response === Password::PASSWORD_RESET) { - return $this->sendResetResponse(); - } - - throw new DisplayException(trans($response)); - } - - /** - * Reset the given user's password. If the user has two-factor authentication enabled on their - * account do not automatically log them in. In those cases, send the user back to the login - * form with a note telling them their password was changed and to log back in. - * - * @param \Illuminate\Contracts\Auth\CanResetPassword|\App\Models\User $user - * @param string $password - * - * @throws \App\Exceptions\Model\DataValidationException - */ - protected function resetPassword($user, $password): void - { - /** @var User $user */ - $user->password = $this->hasher->make($password); - $user->setRememberToken(Str::random(60)); - $user->save(); - - event(new PasswordReset($user)); - - // If the user is not using 2FA log them in, otherwise skip this step and force a - // fresh login where they'll be prompted to enter a token. - if (!$user->use_totp) { - $this->guard()->login($user); - } - - $this->hasTwoFactor = $user->use_totp; - } - - /** - * Send a successful password reset response back to the callee. - */ - protected function sendResetResponse(): JsonResponse - { - return response()->json([ - 'success' => true, - 'redirect_to' => $this->redirectTo, - 'send_to_login' => $this->hasTwoFactor, - ]); - } -} diff --git a/app/Http/Controllers/Base/IndexController.php b/app/Http/Controllers/Base/IndexController.php deleted file mode 100644 index 397dbd4a66..0000000000 --- a/app/Http/Controllers/Base/IndexController.php +++ /dev/null @@ -1,23 +0,0 @@ -loader = $translator->getLoader(); - } - - /** - * Returns translation data given a specific locale and namespace. - */ - public function __invoke(Request $request): JsonResponse - { - $locales = explode(' ', $request->input('locale') ?? ''); - $namespaces = explode(' ', $request->input('namespace') ?? ''); - - $response = []; - foreach ($locales as $locale) { - $response[$locale] = []; - foreach ($namespaces as $namespace) { - $response[$locale][$namespace] = $this->i18n( - $this->loader->load($locale, str_replace('.', '/', $namespace)) - ); - } - } - - return new JsonResponse($response, 200, [ - // Cache this in the browser for an hour, and allow the browser to use a stale - // cache for up to a day after it was created while it fetches an updated set - // of translation keys. - 'Cache-Control' => 'public, max-age=3600, stale-while-revalidate=86400', - 'ETag' => md5(json_encode($response, JSON_THROW_ON_ERROR)), - ]); - } - - /** - * Convert standard Laravel translation keys that look like ":foo" - * into key structures that are supported by the front-end i18n - * library, like "{{foo}}". - */ - protected function i18n(array $data): array - { - foreach ($data as $key => $value) { - if (is_array($value)) { - $data[$key] = $this->i18n($value); - } else { - // Find a Laravel style translation replacement in the string and replace it with - // one that the front-end is able to use. This won't always be present, especially - // for complex strings or things where we'd never have a backend component anyways. - // - // For example: - // "Hello :name, the :notifications.0.title notification needs :count actions :foo.0.bar." - // - // Becomes: - // "Hello {{name}}, the {{notifications.0.title}} notification needs {{count}} actions {{foo.0.bar}}." - $data[$key] = preg_replace('/:([\w.-]+\w)([^\w:]?|$)/m', '{{$1}}$2', $value); - } - } - - return $data; - } -} diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php index 91d25ff850..06b064c59f 100644 --- a/app/Http/Middleware/RedirectIfAuthenticated.php +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -2,24 +2,17 @@ namespace App\Http\Middleware; -use App\Filament\App\Resources\ServerResource\Pages\ListServers; use Illuminate\Http\Request; use Illuminate\Auth\AuthManager; -class RedirectIfAuthenticated +readonly class RedirectIfAuthenticated { - /** - * RedirectIfAuthenticated constructor. - */ public function __construct(private AuthManager $authManager) {} - /** - * Handle an incoming request. - */ public function handle(Request $request, \Closure $next, ?string $guard = null): mixed { if ($this->authManager->guard($guard)->check()) { - return redirect(ListServers::getUrl()); + return redirect('/'); } return $next($request); diff --git a/app/Livewire/Installer/PanelInstaller.php b/app/Livewire/Installer/PanelInstaller.php index c55b2e8c4f..9a14685e81 100644 --- a/app/Livewire/Installer/PanelInstaller.php +++ b/app/Livewire/Installer/PanelInstaller.php @@ -47,8 +47,7 @@ public function getMaxWidth(): MaxWidth|string public static function isInstalled(): bool { - // This defaults to true so existing panels count as "installed" - return env('APP_INSTALLED', true); + return config('app.installed'); } public function mount(): void diff --git a/app/Livewire/Installer/Steps/RequirementsStep.php b/app/Livewire/Installer/Steps/RequirementsStep.php index 258f76cab5..0ba9bc518f 100644 --- a/app/Livewire/Installer/Steps/RequirementsStep.php +++ b/app/Livewire/Installer/Steps/RequirementsStep.php @@ -14,7 +14,8 @@ class RequirementsStep public static function make(): Step { - $correctPhpVersion = version_compare(PHP_VERSION, self::MIN_PHP_VERSION) >= 0; + $compare = version_compare(phpversion(), self::MIN_PHP_VERSION); + $correctPhpVersion = $compare >= 0; $fields = [ Section::make('PHP Version') diff --git a/app/Models/ActivityLog.php b/app/Models/ActivityLog.php index 94df56848c..83daf066c0 100644 --- a/app/Models/ActivityLog.php +++ b/app/Models/ActivityLog.php @@ -85,12 +85,7 @@ protected function casts(): array public function actor(): MorphTo { - $morph = $this->morphTo(); - if (method_exists($morph, 'withTrashed')) { - return $morph->withTrashed(); - } - - return $morph; + return $this->morphTo()->withTrashed(); } public function subjects(): HasMany diff --git a/app/Models/AuditLog.php b/app/Models/AuditLog.php index d091773eae..4529336731 100644 --- a/app/Models/AuditLog.php +++ b/app/Models/AuditLog.php @@ -60,7 +60,7 @@ public function server(): BelongsTo */ public static function instance(string $action, array $metadata, bool $isSystem = false): self { - /** @var \Illuminate\Http\Request $request */ + /** @var ?Request $request */ $request = Container::getInstance()->make('request'); if ($isSystem || !$request instanceof Request) { $request = null; diff --git a/app/Models/Backup.php b/app/Models/Backup.php index d6e4be65a2..e214f8bd00 100644 --- a/app/Models/Backup.php +++ b/app/Models/Backup.php @@ -2,7 +2,7 @@ namespace App\Models; -use Illuminate\Database\Eloquent\Builder; +use App\Eloquent\BackupQueryBuilder; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -81,10 +81,11 @@ public function server(): BelongsTo } /** - * Returns a query filtering only non-failed backups for a specific server. + * @param \Illuminate\Database\Query\Builder $query + * @return BackupQueryBuilder<\Illuminate\Database\Eloquent\Model> */ - public function scopeNonFailed(Builder $query): void + public function newEloquentBuilder($query): BackupQueryBuilder { - $query->whereNull('completed_at')->orWhere('is_successful', true); + return new BackupQueryBuilder($query); } } diff --git a/app/Models/File.php b/app/Models/File.php index e4f96bef2d..bb582884cb 100644 --- a/app/Models/File.php +++ b/app/Models/File.php @@ -130,8 +130,7 @@ public function getSchema(): array public function getRows(): array { try { - /** @var DaemonFileRepository $fileRepository */ - $fileRepository = app(DaemonFileRepository::class)->setServer(self::$server); // @phpstan-ignore-line + $fileRepository = (new DaemonFileRepository())->setServer(self::$server); if (!is_null(self::$searchTerm)) { $contents = cache()->remember('file_search_' . self::$path . '_' . self::$searchTerm, now()->addMinute(), fn () => $fileRepository->search(self::$searchTerm, self::$path)); diff --git a/app/Models/Node.php b/app/Models/Node.php index 3a1cb4ce33..d8dbab90d0 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -307,8 +307,7 @@ public function systemInformation(): array { return once(function () { try { - // @phpstan-ignore-next-line - return resolve(DaemonConfigurationRepository::class) + return (new DaemonConfigurationRepository()) ->setNode($this) ->getSystemInformation(); } catch (Exception $exception) { diff --git a/app/Models/Server.php b/app/Models/Server.php index 109eaaf776..39e1ef3be9 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -342,6 +342,9 @@ public function transfer(): HasOne return $this->hasOne(ServerTransfer::class)->whereNull('successful')->orderByDesc('id'); } + /** + * @return HasMany + */ public function backups(): HasMany { return $this->hasMany(Backup::class); @@ -487,7 +490,7 @@ public function formatResource(string $resourceKey, bool $limit = false, ServerR public function condition(): Attribute { return Attribute::make( - get: fn () => $this->isSuspended() ? ServerState::Suspended : $this->status?->value ?? $this->retrieveStatus(), + get: fn () => $this->isSuspended() ? ServerState::Suspended->value : $this->status->value ?? $this->retrieveStatus(), ); } diff --git a/app/Models/User.php b/app/Models/User.php index 9e7fd435a2..f71db79b68 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -20,7 +20,6 @@ use Illuminate\Database\Eloquent\Builder; use App\Models\Traits\HasAccessTokens; use Illuminate\Auth\Passwords\CanResetPassword; -use App\Traits\Helpers\AvailableLanguages; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Foundation\Auth\Access\Authorizable; use Illuminate\Database\Eloquent\Relations\MorphToMany; @@ -30,6 +29,7 @@ use App\Notifications\SendPasswordReset as ResetPasswordNotification; use Filament\Facades\Filament; use Illuminate\Database\Eloquent\Model as IlluminateModel; +use ResourceBundle; use Spatie\Permission\Traits\HasRoles; /** @@ -89,7 +89,6 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac { use Authenticatable; use Authorizable {can as protected canned; } - use AvailableLanguages; use CanResetPassword; use HasAccessTokens; use HasRoles; @@ -179,9 +178,8 @@ protected function casts(): array protected static function booted(): void { static::creating(function (self $user) { - $user->uuid = Str::uuid()->toString(); - - $user->timezone = env('APP_TIMEZONE', 'UTC'); + $user->uuid ??= Str::uuid()->toString(); + $user->timezone ??= config('app.timezone'); return true; }); @@ -206,8 +204,8 @@ public static function getRules(): array { $rules = parent::getRules(); - $rules['language'][] = new In(array_keys((new self())->getAvailableLanguages())); - $rules['timezone'][] = new In(array_values(DateTimeZone::listIdentifiers())); + $rules['language'][] = new In(array_values(array_filter(ResourceBundle::getLocales(''), fn ($lang) => preg_match('/^[a-z]{2}$/', $lang)))); + $rules['timezone'][] = new In(DateTimeZone::listIdentifiers()); $rules['username'][] = new Username(); return $rules; @@ -257,6 +255,8 @@ public function setEmailAttribute(string $value): void /** * Returns all servers that a user owns. + * + * @return HasMany */ public function servers(): HasMany { diff --git a/app/PHPStan/ForbiddenGlobalFunctionsRule.php b/app/PHPStan/ForbiddenGlobalFunctionsRule.php index 545cc60fb7..b9c5cb6abf 100644 --- a/app/PHPStan/ForbiddenGlobalFunctionsRule.php +++ b/app/PHPStan/ForbiddenGlobalFunctionsRule.php @@ -6,6 +6,7 @@ use PhpParser\Node\Expr\FuncCall; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; class ForbiddenGlobalFunctionsRule implements Rule { @@ -28,7 +29,10 @@ public function processNode(Node $node, Scope $scope): array $functionName = (string) $node->name; if (in_array($functionName, $this->forbiddenFunctions, true)) { return [ - sprintf('Usage of global function "%s" is forbidden.', $functionName), + RuleErrorBuilder::message(sprintf( + 'Usage of global function "%s" is forbidden.', + $functionName, + ))->identifier('myCustomRules.forbiddenGlobalFunctions')->build(), ]; } } diff --git a/app/Services/Activity/ActivityLogService.php b/app/Services/Activity/ActivityLogService.php index 621800a4e0..243edb62d8 100644 --- a/app/Services/Activity/ActivityLogService.php +++ b/app/Services/Activity/ActivityLogService.php @@ -3,6 +3,7 @@ namespace App\Services\Activity; use Illuminate\Support\Arr; +use Throwable; use Webmozart\Assert\Assert; use Illuminate\Support\Collection; use App\Models\ActivityLog; @@ -141,9 +142,8 @@ public function log(?string $description = null): ActivityLog try { return $this->save(); - } catch (\Throwable|\Exception $exception) { + } catch (Throwable $exception) { if (config('app.env') !== 'production') { - /* @noinspection PhpUnhandledExceptionInspection */ throw $exception; } @@ -216,9 +216,7 @@ protected function getActivity(): ActivityLog if ($actor = $this->targetable->actor()) { $this->actor($actor); } elseif ($user = $this->manager->guard()->user()) { - if ($user instanceof Model) { - $this->actor($user); - } + $this->actor($user); } return $this->activity; diff --git a/app/Services/Backups/InitiateBackupService.php b/app/Services/Backups/InitiateBackupService.php index b00fd9c4d9..506448d256 100644 --- a/app/Services/Backups/InitiateBackupService.php +++ b/app/Services/Backups/InitiateBackupService.php @@ -14,7 +14,7 @@ class InitiateBackupService { - private ?array $ignoredFiles; + private array $ignoredFiles; private bool $isLocked = false; @@ -22,10 +22,10 @@ class InitiateBackupService * InitiateBackupService constructor. */ public function __construct( - private ConnectionInterface $connection, - private DaemonBackupRepository $daemonBackupRepository, - private DeleteBackupService $deleteBackupService, - private BackupManager $backupManager + private readonly ConnectionInterface $connection, + private readonly DaemonBackupRepository $daemonBackupRepository, + private readonly DeleteBackupService $deleteBackupService, + private readonly BackupManager $backupManager ) {} /** diff --git a/app/Services/Databases/DeployServerDatabaseService.php b/app/Services/Databases/DeployServerDatabaseService.php index 6cf60fb190..c4aa2988a6 100644 --- a/app/Services/Databases/DeployServerDatabaseService.php +++ b/app/Services/Databases/DeployServerDatabaseService.php @@ -8,18 +8,10 @@ use App\Models\DatabaseHost; use App\Exceptions\Service\Database\NoSuitableDatabaseHostException; -class DeployServerDatabaseService +readonly class DeployServerDatabaseService { - /** - * DeployServerDatabaseService constructor. - */ public function __construct(private DatabaseManagementService $managementService) {} - /** - * @throws \Throwable - * @throws \App\Exceptions\Service\Database\TooManyDatabasesException - * @throws \App\Exceptions\Service\Database\DatabaseClientFeatureNotEnabledException - */ public function handle(Server $server, array $data): Database { Assert::notEmpty($data['database'] ?? null); diff --git a/app/Services/Helpers/LanguageService.php b/app/Services/Helpers/LanguageService.php new file mode 100644 index 0000000000..1a4d86444d --- /dev/null +++ b/app/Services/Helpers/LanguageService.php @@ -0,0 +1,40 @@ +mapWithKeys(function ($path) { + $code = basename($path); + + return [$code => title_case(Locale::getDisplayName($code, $code))]; + })->toArray(); + } +} diff --git a/app/Services/Nodes/NodeJWTService.php b/app/Services/Nodes/NodeJWTService.php index 325fe04c08..2a5b1a3ffd 100644 --- a/app/Services/Nodes/NodeJWTService.php +++ b/app/Services/Nodes/NodeJWTService.php @@ -3,6 +3,7 @@ namespace App\Services\Nodes; use Carbon\CarbonImmutable; +use DateTimeImmutable; use Illuminate\Support\Str; use App\Models\Node; use App\Models\User; @@ -18,7 +19,7 @@ class NodeJWTService private ?User $user = null; - private ?\DateTimeImmutable $expiresAt; + private DateTimeImmutable $expiresAt; private ?string $subject = null; @@ -73,9 +74,7 @@ public function handle(Node $node, ?string $identifiedBy, string $algo = 'md5'): ->issuedAt(CarbonImmutable::now()) ->canOnlyBeUsedAfter(CarbonImmutable::now()->subMinutes(5)); - if ($this->expiresAt) { - $builder = $builder->expiresAt($this->expiresAt); - } + $builder = $builder->expiresAt($this->expiresAt); if (!empty($this->subject)) { $builder = $builder->relatedTo($this->subject)->withHeader('sub', $this->subject); diff --git a/app/Services/Schedules/ProcessScheduleService.php b/app/Services/Schedules/ProcessScheduleService.php index 601e1b0c3d..4d24f63fff 100644 --- a/app/Services/Schedules/ProcessScheduleService.php +++ b/app/Services/Schedules/ProcessScheduleService.php @@ -2,6 +2,7 @@ namespace App\Services\Schedules; +use App\Models\Task; use Exception; use App\Models\Schedule; use Illuminate\Contracts\Bus\Dispatcher; @@ -12,18 +13,14 @@ class ProcessScheduleService { - /** - * ProcessScheduleService constructor. - */ public function __construct(private ConnectionInterface $connection, private Dispatcher $dispatcher, private DaemonServerRepository $serverRepository) {} /** * Process a schedule and push the first task onto the queue worker. - * - * @throws \Throwable */ public function handle(Schedule $schedule, bool $now = false): void { + /** @var ?Task $task */ $task = $schedule->tasks()->orderBy('sequence_id')->first(); if (!$task) { diff --git a/app/Traits/Helpers/AvailableLanguages.php b/app/Traits/Helpers/AvailableLanguages.php deleted file mode 100644 index aafffbbab1..0000000000 --- a/app/Traits/Helpers/AvailableLanguages.php +++ /dev/null @@ -1,57 +0,0 @@ -getFilesystemInstance()->directories(base_path('lang')))->mapWithKeys(function ($path) { - $code = basename($path); - - $value = Locale::getDisplayName($code, $code); - - return [$code => title_case($value)]; - })->toArray(); - } - - public function isLanguageTranslated(string $countryCode = 'en'): bool - { - return in_array($countryCode, self::TRANSLATED, true); - } - - /** - * Return an instance of the filesystem for getting a folder listing. - */ - private function getFilesystemInstance(): Filesystem - { - // @phpstan-ignore-next-line - return $this->filesystem = $this->filesystem ?: app()->make(Filesystem::class); - } -} diff --git a/app/Transformers/Api/Application/BaseTransformer.php b/app/Transformers/Api/Application/BaseTransformer.php index baf8c76cb0..397158a138 100644 --- a/app/Transformers/Api/Application/BaseTransformer.php +++ b/app/Transformers/Api/Application/BaseTransformer.php @@ -24,7 +24,7 @@ abstract class BaseTransformer extends TransformerAbstract /** * BaseTransformer constructor. */ - public function __construct() + final public function __construct() { // Transformers allow for dependency injection on the handle method. if (method_exists($this, 'handle')) { @@ -40,7 +40,7 @@ abstract public function getResourceName(): string; /** * Sets the request on the instance. */ - public function setRequest(Request $request): self + public function setRequest(Request $request): static { $this->request = $request; @@ -49,13 +49,10 @@ public function setRequest(Request $request): self /** * Returns a new transformer instance with the request set on the instance. - * - * @return static */ - public static function fromRequest(Request $request): self + public static function fromRequest(Request $request): static { - // @phpstan-ignore-next-line - return app(static::class)->setRequest($request); + return (new static())->setRequest($request); } /** diff --git a/app/helpers.php b/app/helpers.php index 3bf7aaf307..f1033bdfc0 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -49,8 +49,7 @@ function join_paths(string $base, string ...$paths): string if (!function_exists('resolve_path')) { function resolve_path(string $path): string { - // @phpstan-ignore-next-line - $parts = array_filter(explode('/', $path), 'strlen'); + $parts = array_filter(explode('/', $path), fn (string $p) => strlen($p) > 0); $absolutes = []; foreach ($parts as $part) { diff --git a/composer.json b/composer.json index 508e263742..b2d2fec92f 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,7 @@ "require-dev": { "barryvdh/laravel-ide-helper": "^3.0", "fakerphp/faker": "^1.23.1", - "larastan/larastan": "^2.9.6", + "larastan/larastan": "^3.0", "laravel/pint": "^1.15.3", "laravel/sail": "^1.29.1", "mockery/mockery": "^1.6.11", diff --git a/composer.lock b/composer.lock index 1b2f590efe..2b63b57a53 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4c83ce23eb3e0fab5738cdd7212e4fe3", + "content-hash": "3605a7db1271bc67e1f1ce1bf0d80b18", "packages": [ { "name": "abdelhamiderrahmouni/filament-monaco-editor", @@ -1413,29 +1413,27 @@ }, { "name": "doctrine/deprecations", - "version": "1.1.3", + "version": "1.1.4", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" + "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", - "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/31610dbb31faa98e6b5447b62340826f54fbc4e9", + "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^9", - "phpstan/phpstan": "1.4.10 || 1.10.15", - "phpstan/phpstan-phpunit": "^1.0", + "doctrine/coding-standard": "^9 || ^12", + "phpstan/phpstan": "1.4.10 || 2.0.3", + "phpstan/phpstan-phpunit": "^1.0 || ^2", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psalm/plugin-phpunit": "0.18.4", - "psr/log": "^1 || ^2 || ^3", - "vimeo/psalm": "4.30.0 || 5.12.0" + "psr/log": "^1 || ^2 || ^3" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" @@ -1443,7 +1441,7 @@ "type": "library", "autoload": { "psr-4": { - "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + "Doctrine\\Deprecations\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1454,9 +1452,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.3" + "source": "https://github.com/doctrine/deprecations/tree/1.1.4" }, - "time": "2024-01-30T19:34:25+00:00" + "time": "2024-12-07T21:18:45+00:00" }, { "name": "doctrine/event-manager", @@ -1784,16 +1782,16 @@ }, { "name": "egulias/email-validator", - "version": "4.0.2", + "version": "4.0.3", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e" + "reference": "b115554301161fa21467629f1e1391c1936de517" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ebaaf5be6c0286928352e054f2d5125608e5405e", - "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/b115554301161fa21467629f1e1391c1936de517", + "reference": "b115554301161fa21467629f1e1391c1936de517", "shasum": "" }, "require": { @@ -1839,7 +1837,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/4.0.2" + "source": "https://github.com/egulias/EmailValidator/tree/4.0.3" }, "funding": [ { @@ -1847,7 +1845,7 @@ "type": "github" } ], - "time": "2023-10-06T06:47:41+00:00" + "time": "2024-12-27T00:36:43+00:00" }, { "name": "filament/actions", @@ -2953,23 +2951,23 @@ }, { "name": "laravel/framework", - "version": "v11.31.0", + "version": "v11.37.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "365090ed2c68244e3141cdb5e247cdf3dfba2c40" + "reference": "6cb103d2024b087eae207654b3f4b26646119ba5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/365090ed2c68244e3141cdb5e247cdf3dfba2c40", - "reference": "365090ed2c68244e3141cdb5e247cdf3dfba2c40", + "url": "https://api.github.com/repos/laravel/framework/zipball/6cb103d2024b087eae207654b3f4b26646119ba5", + "reference": "6cb103d2024b087eae207654b3f4b26646119ba5", "shasum": "" }, "require": { "brick/math": "^0.9.3|^0.10.2|^0.11|^0.12", "composer-runtime-api": "^2.2", "doctrine/inflector": "^2.0.5", - "dragonmantank/cron-expression": "^3.3.2", + "dragonmantank/cron-expression": "^3.4", "egulias/email-validator": "^3.2.1|^4.0", "ext-ctype": "*", "ext-filter": "*", @@ -2979,38 +2977,39 @@ "ext-session": "*", "ext-tokenizer": "*", "fruitcake/php-cors": "^1.3", - "guzzlehttp/guzzle": "^7.8", + "guzzlehttp/guzzle": "^7.8.2", "guzzlehttp/uri-template": "^1.0", "laravel/prompts": "^0.1.18|^0.2.0|^0.3.0", - "laravel/serializable-closure": "^1.3", - "league/commonmark": "^2.2.1", - "league/flysystem": "^3.8.0", + "laravel/serializable-closure": "^1.3|^2.0", + "league/commonmark": "^2.6", + "league/flysystem": "^3.25.1", + "league/flysystem-local": "^3.25.1", + "league/uri": "^7.5.1", "monolog/monolog": "^3.0", - "nesbot/carbon": "^2.72.2|^3.0", + "nesbot/carbon": "^2.72.2|^3.4", "nunomaduro/termwind": "^2.0", "php": "^8.2", "psr/container": "^1.1.1|^2.0.1", "psr/log": "^1.0|^2.0|^3.0", "psr/simple-cache": "^1.0|^2.0|^3.0", "ramsey/uuid": "^4.7", - "symfony/console": "^7.0", - "symfony/error-handler": "^7.0", - "symfony/finder": "^7.0", - "symfony/http-foundation": "^7.0", - "symfony/http-kernel": "^7.0", - "symfony/mailer": "^7.0", - "symfony/mime": "^7.0", - "symfony/polyfill-php83": "^1.28", - "symfony/process": "^7.0", - "symfony/routing": "^7.0", - "symfony/uid": "^7.0", - "symfony/var-dumper": "^7.0", + "symfony/console": "^7.0.3", + "symfony/error-handler": "^7.0.3", + "symfony/finder": "^7.0.3", + "symfony/http-foundation": "^7.2.0", + "symfony/http-kernel": "^7.0.3", + "symfony/mailer": "^7.0.3", + "symfony/mime": "^7.0.3", + "symfony/polyfill-php83": "^1.31", + "symfony/process": "^7.0.3", + "symfony/routing": "^7.0.3", + "symfony/uid": "^7.0.3", + "symfony/var-dumper": "^7.0.3", "tijsverkoyen/css-to-inline-styles": "^2.2.5", - "vlucas/phpdotenv": "^5.4.1", - "voku/portable-ascii": "^2.0" + "vlucas/phpdotenv": "^5.6.1", + "voku/portable-ascii": "^2.0.2" }, "conflict": { - "mockery/mockery": "1.6.8", "tightenco/collect": "<5.5.33" }, "provide": { @@ -3057,29 +3056,32 @@ }, "require-dev": { "ably/ably-php": "^1.0", - "aws/aws-sdk-php": "^3.235.5", + "aws/aws-sdk-php": "^3.322.9", "ext-gmp": "*", - "fakerphp/faker": "^1.23", - "league/flysystem-aws-s3-v3": "^3.0", - "league/flysystem-ftp": "^3.0", - "league/flysystem-path-prefixing": "^3.3", - "league/flysystem-read-only": "^3.3", - "league/flysystem-sftp-v3": "^3.0", - "mockery/mockery": "^1.6", - "nyholm/psr7": "^1.2", - "orchestra/testbench-core": "^9.5", - "pda/pheanstalk": "^5.0", + "fakerphp/faker": "^1.24", + "guzzlehttp/promises": "^2.0.3", + "guzzlehttp/psr7": "^2.4", + "league/flysystem-aws-s3-v3": "^3.25.1", + "league/flysystem-ftp": "^3.25.1", + "league/flysystem-path-prefixing": "^3.25.1", + "league/flysystem-read-only": "^3.25.1", + "league/flysystem-sftp-v3": "^3.25.1", + "mockery/mockery": "^1.6.10", + "orchestra/testbench-core": "^9.6", + "pda/pheanstalk": "^5.0.6", + "php-http/discovery": "^1.15", "phpstan/phpstan": "^1.11.5", - "phpunit/phpunit": "^10.5|^11.0", - "predis/predis": "^2.0.2", + "phpunit/phpunit": "^10.5.35|^11.3.6", + "predis/predis": "^2.3", "resend/resend-php": "^0.10.0", - "symfony/cache": "^7.0", - "symfony/http-client": "^7.0", - "symfony/psr-http-message-bridge": "^7.0" + "symfony/cache": "^7.0.3", + "symfony/http-client": "^7.0.3", + "symfony/psr-http-message-bridge": "^7.0.3", + "symfony/translation": "^7.0.3" }, "suggest": { "ably/ably-php": "Required to use the Ably broadcast driver (^1.0).", - "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage, and SES mail driver (^3.235.5).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage, and SES mail driver (^3.322.9).", "brianium/paratest": "Required to run tests in parallel (^7.0|^8.0).", "ext-apcu": "Required to use the APC cache driver.", "ext-fileinfo": "Required to use the Filesystem class.", @@ -3093,16 +3095,16 @@ "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", "filp/whoops": "Required for friendly error pages in development (^2.14.3).", "laravel/tinker": "Required to use the tinker console command (^2.0).", - "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.0).", - "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.0).", - "league/flysystem-path-prefixing": "Required to use the scoped driver (^3.3).", - "league/flysystem-read-only": "Required to use read-only disks (^3.3)", - "league/flysystem-sftp-v3": "Required to use the Flysystem SFTP driver (^3.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.25.1).", + "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.25.1).", + "league/flysystem-path-prefixing": "Required to use the scoped driver (^3.25.1).", + "league/flysystem-read-only": "Required to use read-only disks (^3.25.1)", + "league/flysystem-sftp-v3": "Required to use the Flysystem SFTP driver (^3.25.1).", "mockery/mockery": "Required to use mocking (^1.6).", - "nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).", "pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).", + "php-http/discovery": "Required to use PSR-7 bridging features (^1.15).", "phpunit/phpunit": "Required to use assertions and run tests (^10.5|^11.0).", - "predis/predis": "Required to use the predis connector (^2.0.2).", + "predis/predis": "Required to use the predis connector (^2.3).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).", "resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0).", @@ -3121,6 +3123,7 @@ }, "autoload": { "files": [ + "src/Illuminate/Collections/functions.php", "src/Illuminate/Collections/helpers.php", "src/Illuminate/Events/functions.php", "src/Illuminate/Filesystem/functions.php", @@ -3158,7 +3161,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-11-12T15:36:15+00:00" + "time": "2025-01-02T20:10:21+00:00" }, { "name": "laravel/helpers", @@ -3342,16 +3345,16 @@ }, { "name": "laravel/serializable-closure", - "version": "v1.3.6", + "version": "v1.3.7", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "f865a58ea3a0107c336b7045104c75243fa59d96" + "reference": "4f48ade902b94323ca3be7646db16209ec76be3d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f865a58ea3a0107c336b7045104c75243fa59d96", - "reference": "f865a58ea3a0107c336b7045104c75243fa59d96", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/4f48ade902b94323ca3be7646db16209ec76be3d", + "reference": "4f48ade902b94323ca3be7646db16209ec76be3d", "shasum": "" }, "require": { @@ -3399,7 +3402,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2024-11-11T17:06:04+00:00" + "time": "2024-11-14T18:34:49+00:00" }, { "name": "laravel/socialite", @@ -3742,16 +3745,16 @@ }, { "name": "league/commonmark", - "version": "2.5.3", + "version": "2.6.1", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "b650144166dfa7703e62a22e493b853b58d874b0" + "reference": "d990688c91cedfb69753ffc2512727ec646df2ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/b650144166dfa7703e62a22e493b853b58d874b0", - "reference": "b650144166dfa7703e62a22e493b853b58d874b0", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d990688c91cedfb69753ffc2512727ec646df2ad", + "reference": "d990688c91cedfb69753ffc2512727ec646df2ad", "shasum": "" }, "require": { @@ -3776,8 +3779,9 @@ "phpstan/phpstan": "^1.8.2", "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", "scrutinizer/ocular": "^1.8.1", - "symfony/finder": "^5.3 | ^6.0 || ^7.0", - "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 || ^7.0", + "symfony/finder": "^5.3 | ^6.0 | ^7.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", "unleashedtech/php-coding-standard": "^3.1.1", "vimeo/psalm": "^4.24.0 || ^5.0.0" }, @@ -3787,7 +3791,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.6-dev" + "dev-main": "2.7-dev" } }, "autoload": { @@ -3844,7 +3848,7 @@ "type": "tidelift" } ], - "time": "2024-08-16T11:46:16+00:00" + "time": "2024-12-29T14:10:59+00:00" }, { "name": "league/config", @@ -4484,20 +4488,20 @@ }, { "name": "league/uri", - "version": "7.4.1", + "version": "7.5.1", "source": { "type": "git", "url": "https://github.com/thephpleague/uri.git", - "reference": "bedb6e55eff0c933668addaa7efa1e1f2c417cc4" + "reference": "81fb5145d2644324614cc532b28efd0215bda430" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/bedb6e55eff0c933668addaa7efa1e1f2c417cc4", - "reference": "bedb6e55eff0c933668addaa7efa1e1f2c417cc4", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", + "reference": "81fb5145d2644324614cc532b28efd0215bda430", "shasum": "" }, "require": { - "league/uri-interfaces": "^7.3", + "league/uri-interfaces": "^7.5", "php": "^8.1" }, "conflict": { @@ -4562,7 +4566,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri/tree/7.4.1" + "source": "https://github.com/thephpleague/uri/tree/7.5.1" }, "funding": [ { @@ -4570,20 +4574,20 @@ "type": "github" } ], - "time": "2024-03-23T07:42:40+00:00" + "time": "2024-12-08T08:40:02+00:00" }, { "name": "league/uri-interfaces", - "version": "7.4.1", + "version": "7.5.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-interfaces.git", - "reference": "8d43ef5c841032c87e2de015972c06f3865ef718" + "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/8d43ef5c841032c87e2de015972c06f3865ef718", - "reference": "8d43ef5c841032c87e2de015972c06f3865ef718", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", "shasum": "" }, "require": { @@ -4646,7 +4650,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-interfaces/tree/7.4.1" + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0" }, "funding": [ { @@ -4654,7 +4658,7 @@ "type": "github" } ], - "time": "2024-03-23T07:42:40+00:00" + "time": "2024-12-08T08:18:47+00:00" }, { "name": "livewire/livewire", @@ -4801,16 +4805,16 @@ }, { "name": "monolog/monolog", - "version": "3.8.0", + "version": "3.8.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "32e515fdc02cdafbe4593e30a9350d486b125b67" + "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/32e515fdc02cdafbe4593e30a9350d486b125b67", - "reference": "32e515fdc02cdafbe4593e30a9350d486b125b67", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/aef6ee73a77a66e404dd6540934a9ef1b3c855b4", + "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4", "shasum": "" }, "require": { @@ -4888,7 +4892,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.8.0" + "source": "https://github.com/Seldaek/monolog/tree/3.8.1" }, "funding": [ { @@ -4900,7 +4904,7 @@ "type": "tidelift" } ], - "time": "2024-11-12T13:57:08+00:00" + "time": "2024-12-05T17:15:07+00:00" }, { "name": "mtdowling/jmespath.php", @@ -4970,16 +4974,16 @@ }, { "name": "nesbot/carbon", - "version": "3.8.2", + "version": "3.8.4", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "e1268cdbc486d97ce23fef2c666dc3c6b6de9947" + "reference": "129700ed449b1f02d70272d2ac802357c8c30c58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/e1268cdbc486d97ce23fef2c666dc3c6b6de9947", - "reference": "e1268cdbc486d97ce23fef2c666dc3c6b6de9947", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/129700ed449b1f02d70272d2ac802357c8c30c58", + "reference": "129700ed449b1f02d70272d2ac802357c8c30c58", "shasum": "" }, "require": { @@ -5011,10 +5015,6 @@ ], "type": "library", "extra": { - "branch-alias": { - "dev-master": "3.x-dev", - "dev-2.x": "2.x-dev" - }, "laravel": { "providers": [ "Carbon\\Laravel\\ServiceProvider" @@ -5024,6 +5024,10 @@ "includes": [ "extension.neon" ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev", + "dev-master": "3.x-dev" } }, "autoload": { @@ -5072,7 +5076,7 @@ "type": "tidelift" } ], - "time": "2024-11-07T17:46:48+00:00" + "time": "2024-12-27T09:25:35+00:00" }, { "name": "nette/schema", @@ -5282,31 +5286,31 @@ }, { "name": "nunomaduro/termwind", - "version": "v2.2.0", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/termwind.git", - "reference": "42c84e4e8090766bbd6445d06cd6e57650626ea3" + "reference": "52915afe6a1044e8b9cee1bcff836fb63acf9cda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/42c84e4e8090766bbd6445d06cd6e57650626ea3", - "reference": "42c84e4e8090766bbd6445d06cd6e57650626ea3", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/52915afe6a1044e8b9cee1bcff836fb63acf9cda", + "reference": "52915afe6a1044e8b9cee1bcff836fb63acf9cda", "shasum": "" }, "require": { "ext-mbstring": "*", "php": "^8.2", - "symfony/console": "^7.1.5" + "symfony/console": "^7.1.8" }, "require-dev": { - "illuminate/console": "^11.28.0", - "laravel/pint": "^1.18.1", + "illuminate/console": "^11.33.2", + "laravel/pint": "^1.18.2", "mockery/mockery": "^1.6.12", "pestphp/pest": "^2.36.0", - "phpstan/phpstan": "^1.12.6", + "phpstan/phpstan": "^1.12.11", "phpstan/phpstan-strict-rules": "^1.6.1", - "symfony/var-dumper": "^7.1.5", + "symfony/var-dumper": "^7.1.8", "thecodingmachine/phpstan-strict-rules": "^1.0.0" }, "type": "library", @@ -5349,7 +5353,7 @@ ], "support": { "issues": "https://github.com/nunomaduro/termwind/issues", - "source": "https://github.com/nunomaduro/termwind/tree/v2.2.0" + "source": "https://github.com/nunomaduro/termwind/tree/v2.3.0" }, "funding": [ { @@ -5365,7 +5369,7 @@ "type": "github" } ], - "time": "2024-10-15T16:15:16+00:00" + "time": "2024-11-21T10:39:51+00:00" }, { "name": "openspout/openspout", @@ -7871,16 +7875,16 @@ }, { "name": "symfony/clock", - "version": "v7.1.6", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "97bebc53548684c17ed696bc8af016880f0f098d" + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/97bebc53548684c17ed696bc8af016880f0f098d", - "reference": "97bebc53548684c17ed696bc8af016880f0f098d", + "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", "shasum": "" }, "require": { @@ -7925,7 +7929,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v7.1.6" + "source": "https://github.com/symfony/clock/tree/v7.2.0" }, "funding": [ { @@ -7941,20 +7945,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/console", - "version": "v7.1.8", + "version": "v7.2.1", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "ff04e5b5ba043d2badfb308197b9e6b42883fcd5" + "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/ff04e5b5ba043d2badfb308197b9e6b42883fcd5", - "reference": "ff04e5b5ba043d2badfb308197b9e6b42883fcd5", + "url": "https://api.github.com/repos/symfony/console/zipball/fefcc18c0f5d0efe3ab3152f15857298868dc2c3", + "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3", "shasum": "" }, "require": { @@ -8018,7 +8022,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.1.8" + "source": "https://github.com/symfony/console/tree/v7.2.1" }, "funding": [ { @@ -8034,20 +8038,20 @@ "type": "tidelift" } ], - "time": "2024-11-06T14:23:19+00:00" + "time": "2024-12-11T03:49:26+00:00" }, { "name": "symfony/css-selector", - "version": "v7.1.6", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "4aa4f6b3d6749c14d3aa815eef8226632e7bbc66" + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/4aa4f6b3d6749c14d3aa815eef8226632e7bbc66", - "reference": "4aa4f6b3d6749c14d3aa815eef8226632e7bbc66", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2", "shasum": "" }, "require": { @@ -8083,7 +8087,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v7.1.6" + "source": "https://github.com/symfony/css-selector/tree/v7.2.0" }, "funding": [ { @@ -8099,20 +8103,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", "shasum": "" }, "require": { @@ -8120,12 +8124,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -8150,7 +8154,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" }, "funding": [ { @@ -8166,20 +8170,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/error-handler", - "version": "v7.1.7", + "version": "v7.2.1", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "010e44661f4c6babaf8c4862fe68c24a53903342" + "reference": "6150b89186573046167796fa5f3f76601d5145f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/010e44661f4c6babaf8c4862fe68c24a53903342", - "reference": "010e44661f4c6babaf8c4862fe68c24a53903342", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/6150b89186573046167796fa5f3f76601d5145f8", + "reference": "6150b89186573046167796fa5f3f76601d5145f8", "shasum": "" }, "require": { @@ -8225,7 +8229,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.1.7" + "source": "https://github.com/symfony/error-handler/tree/v7.2.1" }, "funding": [ { @@ -8241,20 +8245,20 @@ "type": "tidelift" } ], - "time": "2024-11-05T15:34:55+00:00" + "time": "2024-12-07T08:50:44+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.1.6", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "87254c78dd50721cfd015b62277a8281c5589702" + "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/87254c78dd50721cfd015b62277a8281c5589702", - "reference": "87254c78dd50721cfd015b62277a8281c5589702", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/910c5db85a5356d0fea57680defec4e99eb9c8c1", + "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1", "shasum": "" }, "require": { @@ -8305,7 +8309,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.1.6" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.2.0" }, "funding": [ { @@ -8321,20 +8325,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50" + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/8f93aec25d41b72493c6ddff14e916177c9efc50", - "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f", + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f", "shasum": "" }, "require": { @@ -8343,12 +8347,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -8381,7 +8385,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1" }, "funding": [ { @@ -8397,20 +8401,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/finder", - "version": "v7.1.6", + "version": "v7.2.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "2cb89664897be33f78c65d3d2845954c8d7a43b8" + "reference": "87a71856f2f56e4100373e92529eed3171695cfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/2cb89664897be33f78c65d3d2845954c8d7a43b8", - "reference": "2cb89664897be33f78c65d3d2845954c8d7a43b8", + "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb", "shasum": "" }, "require": { @@ -8445,7 +8449,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.1.6" + "source": "https://github.com/symfony/finder/tree/v7.2.2" }, "funding": [ { @@ -8461,7 +8465,7 @@ "type": "tidelift" } ], - "time": "2024-10-01T08:31:23+00:00" + "time": "2024-12-30T19:00:17+00:00" }, { "name": "symfony/html-sanitizer", @@ -8628,16 +8632,16 @@ }, { "name": "symfony/http-client-contracts", - "version": "v3.5.0", + "version": "v3.5.2", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "20414d96f391677bf80078aa55baece78b82647d" + "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d", - "reference": "20414d96f391677bf80078aa55baece78b82647d", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645", + "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645", "shasum": "" }, "require": { @@ -8645,12 +8649,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -8686,7 +8690,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.2" }, "funding": [ { @@ -8702,24 +8706,25 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-12-07T08:49:48+00:00" }, { "name": "symfony/http-foundation", - "version": "v7.1.8", + "version": "v7.2.2", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "f4419ec69ccfc3f725a4de7c20e4e57626d10112" + "reference": "62d1a43796ca3fea3f83a8470dfe63a4af3bc588" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f4419ec69ccfc3f725a4de7c20e4e57626d10112", - "reference": "f4419ec69ccfc3f725a4de7c20e4e57626d10112", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/62d1a43796ca3fea3f83a8470dfe63a4af3bc588", + "reference": "62d1a43796ca3fea3f83a8470dfe63a4af3bc588", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", "symfony/polyfill-mbstring": "~1.1", "symfony/polyfill-php83": "^1.27" }, @@ -8763,7 +8768,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.1.8" + "source": "https://github.com/symfony/http-foundation/tree/v7.2.2" }, "funding": [ { @@ -8779,20 +8784,20 @@ "type": "tidelift" } ], - "time": "2024-11-09T09:16:45+00:00" + "time": "2024-12-30T19:00:17+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.1.8", + "version": "v7.2.2", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "33fef24e3dc79d6d30bf4936531f2f4bd2ca189e" + "reference": "3c432966bd8c7ec7429663105f5a02d7e75b4306" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/33fef24e3dc79d6d30bf4936531f2f4bd2ca189e", - "reference": "33fef24e3dc79d6d30bf4936531f2f4bd2ca189e", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/3c432966bd8c7ec7429663105f5a02d7e75b4306", + "reference": "3c432966bd8c7ec7429663105f5a02d7e75b4306", "shasum": "" }, "require": { @@ -8821,7 +8826,7 @@ "symfony/twig-bridge": "<6.4", "symfony/validator": "<6.4", "symfony/var-dumper": "<6.4", - "twig/twig": "<3.0.4" + "twig/twig": "<3.12" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" @@ -8849,7 +8854,7 @@ "symfony/validator": "^6.4|^7.0", "symfony/var-dumper": "^6.4|^7.0", "symfony/var-exporter": "^6.4|^7.0", - "twig/twig": "^3.0.4" + "twig/twig": "^3.12" }, "type": "library", "autoload": { @@ -8877,7 +8882,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.1.8" + "source": "https://github.com/symfony/http-kernel/tree/v7.2.2" }, "funding": [ { @@ -8893,20 +8898,20 @@ "type": "tidelift" } ], - "time": "2024-11-13T14:25:32+00:00" + "time": "2024-12-31T14:59:40+00:00" }, { "name": "symfony/mailer", - "version": "v7.1.6", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "69c9948451fb3a6a4d47dc8261d1794734e76cdd" + "reference": "e4d358702fb66e4c8a2af08e90e7271a62de39cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/69c9948451fb3a6a4d47dc8261d1794734e76cdd", - "reference": "69c9948451fb3a6a4d47dc8261d1794734e76cdd", + "url": "https://api.github.com/repos/symfony/mailer/zipball/e4d358702fb66e4c8a2af08e90e7271a62de39cc", + "reference": "e4d358702fb66e4c8a2af08e90e7271a62de39cc", "shasum": "" }, "require": { @@ -8915,7 +8920,7 @@ "psr/event-dispatcher": "^1", "psr/log": "^1|^2|^3", "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/mime": "^6.4|^7.0", + "symfony/mime": "^7.2", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -8957,7 +8962,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.1.6" + "source": "https://github.com/symfony/mailer/tree/v7.2.0" }, "funding": [ { @@ -8973,7 +8978,7 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-11-25T15:21:05+00:00" }, { "name": "symfony/mailgun-mailer", @@ -9046,16 +9051,16 @@ }, { "name": "symfony/mime", - "version": "v7.1.6", + "version": "v7.2.1", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "caa1e521edb2650b8470918dfe51708c237f0598" + "reference": "7f9617fcf15cb61be30f8b252695ed5e2bfac283" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/caa1e521edb2650b8470918dfe51708c237f0598", - "reference": "caa1e521edb2650b8470918dfe51708c237f0598", + "url": "https://api.github.com/repos/symfony/mime/zipball/7f9617fcf15cb61be30f8b252695ed5e2bfac283", + "reference": "7f9617fcf15cb61be30f8b252695ed5e2bfac283", "shasum": "" }, "require": { @@ -9110,7 +9115,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.1.6" + "source": "https://github.com/symfony/mime/tree/v7.2.1" }, "funding": [ { @@ -9126,7 +9131,7 @@ "type": "tidelift" } ], - "time": "2024-10-25T15:11:02+00:00" + "time": "2024-12-07T08:50:44+00:00" }, { "name": "symfony/polyfill-ctype", @@ -9154,8 +9159,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -9230,8 +9235,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -9309,8 +9314,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -9391,8 +9396,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -9475,8 +9480,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -9549,8 +9554,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -9629,8 +9634,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -9711,8 +9716,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -9836,16 +9841,16 @@ }, { "name": "symfony/process", - "version": "v7.1.8", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892" + "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/42783370fda6e538771f7c7a36e9fa2ee3a84892", - "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892", + "url": "https://api.github.com/repos/symfony/process/zipball/d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", + "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", "shasum": "" }, "require": { @@ -9877,7 +9882,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.1.8" + "source": "https://github.com/symfony/process/tree/v7.2.0" }, "funding": [ { @@ -9893,20 +9898,20 @@ "type": "tidelift" } ], - "time": "2024-11-06T14:23:19+00:00" + "time": "2024-11-06T14:24:19+00:00" }, { "name": "symfony/routing", - "version": "v7.1.6", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "66a2c469f6c22d08603235c46a20007c0701ea0a" + "reference": "e10a2450fa957af6c448b9b93c9010a4e4c0725e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/66a2c469f6c22d08603235c46a20007c0701ea0a", - "reference": "66a2c469f6c22d08603235c46a20007c0701ea0a", + "url": "https://api.github.com/repos/symfony/routing/zipball/e10a2450fa957af6c448b9b93c9010a4e4c0725e", + "reference": "e10a2450fa957af6c448b9b93c9010a4e4c0725e", "shasum": "" }, "require": { @@ -9958,7 +9963,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.1.6" + "source": "https://github.com/symfony/routing/tree/v7.2.0" }, "funding": [ { @@ -9974,20 +9979,20 @@ "type": "tidelift" } ], - "time": "2024-10-01T08:31:23+00:00" + "time": "2024-11-25T11:08:51+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", - "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", "shasum": "" }, "require": { @@ -10000,12 +10005,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -10041,7 +10046,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" }, "funding": [ { @@ -10057,20 +10062,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/string", - "version": "v7.1.8", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "591ebd41565f356fcd8b090fe64dbb5878f50281" + "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/591ebd41565f356fcd8b090fe64dbb5878f50281", - "reference": "591ebd41565f356fcd8b090fe64dbb5878f50281", + "url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82", + "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82", "shasum": "" }, "require": { @@ -10128,7 +10133,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.1.8" + "source": "https://github.com/symfony/string/tree/v7.2.0" }, "funding": [ { @@ -10144,24 +10149,25 @@ "type": "tidelift" } ], - "time": "2024-11-13T13:31:21+00:00" + "time": "2024-11-13T13:31:26+00:00" }, { "name": "symfony/translation", - "version": "v7.1.6", + "version": "v7.2.2", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "b9f72ab14efdb6b772f85041fa12f820dee8d55f" + "reference": "e2674a30132b7cc4d74540d6c2573aa363f05923" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/b9f72ab14efdb6b772f85041fa12f820dee8d55f", - "reference": "b9f72ab14efdb6b772f85041fa12f820dee8d55f", + "url": "https://api.github.com/repos/symfony/translation/zipball/e2674a30132b7cc4d74540d6c2573aa363f05923", + "reference": "e2674a30132b7cc4d74540d6c2573aa363f05923", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/translation-contracts": "^2.5|^3.0" }, @@ -10222,7 +10228,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.1.6" + "source": "https://github.com/symfony/translation/tree/v7.2.2" }, "funding": [ { @@ -10238,20 +10244,20 @@ "type": "tidelift" } ], - "time": "2024-09-28T12:35:13+00:00" + "time": "2024-12-07T08:18:10+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a" + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", - "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", "shasum": "" }, "require": { @@ -10259,12 +10265,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -10300,7 +10306,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" }, "funding": [ { @@ -10316,20 +10322,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/uid", - "version": "v7.1.6", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "65befb3bb2d503bbffbd08c815aa38b472999917" + "reference": "2d294d0c48df244c71c105a169d0190bfb080426" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/65befb3bb2d503bbffbd08c815aa38b472999917", - "reference": "65befb3bb2d503bbffbd08c815aa38b472999917", + "url": "https://api.github.com/repos/symfony/uid/zipball/2d294d0c48df244c71c105a169d0190bfb080426", + "reference": "2d294d0c48df244c71c105a169d0190bfb080426", "shasum": "" }, "require": { @@ -10374,7 +10380,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.1.6" + "source": "https://github.com/symfony/uid/tree/v7.2.0" }, "funding": [ { @@ -10390,20 +10396,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.1.8", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "7bb01a47b1b00428d32b5e7b4d3b2d1aa58d3db8" + "reference": "c6a22929407dec8765d6e2b6ff85b800b245879c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/7bb01a47b1b00428d32b5e7b4d3b2d1aa58d3db8", - "reference": "7bb01a47b1b00428d32b5e7b4d3b2d1aa58d3db8", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c6a22929407dec8765d6e2b6ff85b800b245879c", + "reference": "c6a22929407dec8765d6e2b6ff85b800b245879c", "shasum": "" }, "require": { @@ -10419,7 +10425,7 @@ "symfony/http-kernel": "^6.4|^7.0", "symfony/process": "^6.4|^7.0", "symfony/uid": "^6.4|^7.0", - "twig/twig": "^3.0.4" + "twig/twig": "^3.12" }, "bin": [ "Resources/bin/var-dump-server" @@ -10457,7 +10463,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.1.8" + "source": "https://github.com/symfony/var-dumper/tree/v7.2.0" }, "funding": [ { @@ -10473,7 +10479,7 @@ "type": "tidelift" } ], - "time": "2024-11-08T15:46:42+00:00" + "time": "2024-11-08T15:48:14+00:00" }, { "name": "symfony/yaml", @@ -10548,31 +10554,33 @@ }, { "name": "tijsverkoyen/css-to-inline-styles", - "version": "v2.2.7", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "83ee6f38df0a63106a9e4536e3060458b74ccedb" + "reference": "0d72ac1c00084279c1816675284073c5a337c20d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/83ee6f38df0a63106a9e4536e3060458b74ccedb", - "reference": "83ee6f38df0a63106a9e4536e3060458b74ccedb", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0d72ac1c00084279c1816675284073c5a337c20d", + "reference": "0d72ac1c00084279c1816675284073c5a337c20d", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", - "php": "^5.5 || ^7.0 || ^8.0", - "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0" + "php": "^7.4 || ^8.0", + "symfony/css-selector": "^5.4 || ^6.0 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^7.5 || ^8.5.21 || ^9.5.10" + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^8.5.21 || ^9.5.10" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { @@ -10595,9 +10603,9 @@ "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", "support": { "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", - "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.2.7" + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.3.0" }, - "time": "2023-12-08T13:03:43+00:00" + "time": "2024-12-21T16:25:41+00:00" }, { "name": "vlucas/phpdotenv", @@ -10685,16 +10693,16 @@ }, { "name": "voku/portable-ascii", - "version": "2.0.1", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/voku/portable-ascii.git", - "reference": "b56450eed252f6801410d810c8e1727224ae0743" + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b56450eed252f6801410d810c8e1727224ae0743", - "reference": "b56450eed252f6801410d810c8e1727224ae0743", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", "shasum": "" }, "require": { @@ -10719,7 +10727,7 @@ "authors": [ { "name": "Lars Moelleken", - "homepage": "http://www.moelleken.org/" + "homepage": "https://www.moelleken.org/" } ], "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", @@ -10731,7 +10739,7 @@ ], "support": { "issues": "https://github.com/voku/portable-ascii/issues", - "source": "https://github.com/voku/portable-ascii/tree/2.0.1" + "source": "https://github.com/voku/portable-ascii/tree/2.0.3" }, "funding": [ { @@ -10755,7 +10763,7 @@ "type": "tidelift" } ], - "time": "2022-03-08T17:03:00+00:00" + "time": "2024-11-21T01:49:47+00:00" }, { "name": "webbingbrasil/filament-copyactions", @@ -11356,53 +11364,53 @@ }, { "name": "larastan/larastan", - "version": "v2.9.11", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/larastan/larastan.git", - "reference": "54eccd35d1732b9ee4392c25aec606a6a9c521e7" + "reference": "b2e24e1605cff1d1097ccb6fb8af3bbd1dfe1c6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/larastan/larastan/zipball/54eccd35d1732b9ee4392c25aec606a6a9c521e7", - "reference": "54eccd35d1732b9ee4392c25aec606a6a9c521e7", + "url": "https://api.github.com/repos/larastan/larastan/zipball/b2e24e1605cff1d1097ccb6fb8af3bbd1dfe1c6f", + "reference": "b2e24e1605cff1d1097ccb6fb8af3bbd1dfe1c6f", "shasum": "" }, "require": { "ext-json": "*", - "illuminate/console": "^9.52.16 || ^10.28.0 || ^11.16", - "illuminate/container": "^9.52.16 || ^10.28.0 || ^11.16", - "illuminate/contracts": "^9.52.16 || ^10.28.0 || ^11.16", - "illuminate/database": "^9.52.16 || ^10.28.0 || ^11.16", - "illuminate/http": "^9.52.16 || ^10.28.0 || ^11.16", - "illuminate/pipeline": "^9.52.16 || ^10.28.0 || ^11.16", - "illuminate/support": "^9.52.16 || ^10.28.0 || ^11.16", - "php": "^8.0.2", + "illuminate/console": "^11.15.0", + "illuminate/container": "^11.15.0", + "illuminate/contracts": "^11.15.0", + "illuminate/database": "^11.15.0", + "illuminate/http": "^11.15.0", + "illuminate/pipeline": "^11.15.0", + "illuminate/support": "^11.15.0", + "php": "^8.2", "phpmyadmin/sql-parser": "^5.9.0", - "phpstan/phpstan": "^1.12.5" + "phpstan/phpstan": "^2.0.2" }, "require-dev": { "doctrine/coding-standard": "^12.0", - "laravel/framework": "^9.52.16 || ^10.28.0 || ^11.16", - "mockery/mockery": "^1.5.1", - "nikic/php-parser": "^4.19.1", - "orchestra/canvas": "^7.11.1 || ^8.11.0 || ^9.0.2", - "orchestra/testbench-core": "^7.33.0 || ^8.13.0 || ^9.0.9", - "phpstan/phpstan-deprecation-rules": "^1.2", - "phpunit/phpunit": "^9.6.13 || ^10.5.16" + "laravel/framework": "^11.15.0", + "mockery/mockery": "^1.6", + "nikic/php-parser": "^5.3", + "orchestra/canvas": "^v9.1.3", + "orchestra/testbench-core": "^9.5.2", + "phpstan/phpstan-deprecation-rules": "^2.0.0", + "phpunit/phpunit": "^10.5.16" }, "suggest": { "orchestra/testbench": "Using Larastan for analysing a package needs Testbench" }, "type": "phpstan-extension", "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - }, "phpstan": { "includes": [ "extension.neon" ] + }, + "branch-alias": { + "dev-master": "2.0-dev" } }, "autoload": { @@ -11437,27 +11445,15 @@ ], "support": { "issues": "https://github.com/larastan/larastan/issues", - "source": "https://github.com/larastan/larastan/tree/v2.9.11" + "source": "https://github.com/larastan/larastan/tree/v3.0.2" }, "funding": [ - { - "url": "https://www.paypal.com/paypalme/enunomaduro", - "type": "custom" - }, { "url": "https://github.com/canvural", "type": "github" - }, - { - "url": "https://github.com/nunomaduro", - "type": "github" - }, - { - "url": "https://www.patreon.com/nunomaduro", - "type": "patreon" } ], - "time": "2024-11-11T23:11:00+00:00" + "time": "2024-11-26T23:15:21+00:00" }, { "name": "laravel/pint", @@ -12059,16 +12055,16 @@ }, { "name": "phpmyadmin/sql-parser", - "version": "5.10.1", + "version": "5.10.2", "source": { "type": "git", "url": "https://github.com/phpmyadmin/sql-parser.git", - "reference": "b14fd66496a22d8dd7f7e2791edd9e8674422f17" + "reference": "72afbce7e4b421593b60d2eb7281e37a50734df8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmyadmin/sql-parser/zipball/b14fd66496a22d8dd7f7e2791edd9e8674422f17", - "reference": "b14fd66496a22d8dd7f7e2791edd9e8674422f17", + "url": "https://api.github.com/repos/phpmyadmin/sql-parser/zipball/72afbce7e4b421593b60d2eb7281e37a50734df8", + "reference": "72afbce7e4b421593b60d2eb7281e37a50734df8", "shasum": "" }, "require": { @@ -12142,24 +12138,24 @@ "type": "other" } ], - "time": "2024-11-10T04:10:31+00:00" + "time": "2024-12-05T15:04:09+00:00" }, { "name": "phpstan/phpstan", - "version": "1.12.10", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "fc463b5d0fe906dcf19689be692c65c50406a071" + "reference": "2392d360fdf54ea253aa6c68cad1d4ba2e54e927" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fc463b5d0fe906dcf19689be692c65c50406a071", - "reference": "fc463b5d0fe906dcf19689be692c65c50406a071", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2392d360fdf54ea253aa6c68cad1d4ba2e54e927", + "reference": "2392d360fdf54ea253aa6c68cad1d4ba2e54e927", "shasum": "" }, "require": { - "php": "^7.2|^8.0" + "php": "^7.4|^8.0" }, "conflict": { "phpstan/phpstan-shim": "*" @@ -12200,7 +12196,7 @@ "type": "github" } ], - "time": "2024-11-11T15:37:09+00:00" + "time": "2024-12-31T07:30:03+00:00" }, { "name": "phpunit/php-code-coverage", diff --git a/config/app.php b/config/app.php index e673f72690..58e4e544ff 100644 --- a/config/app.php +++ b/config/app.php @@ -10,6 +10,8 @@ 'timezone' => 'UTC', + 'installed' => env('APP_INSTALLED', true), + 'exceptions' => [ 'report_all' => env('APP_REPORT_ALL_EXCEPTIONS', false), ], diff --git a/phpstan.neon b/phpstan.neon index 3731172cea..e66afe111f 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -12,6 +12,15 @@ parameters: level: 6 ignoreErrors: - - '#no value type specified in iterable#' - - '#Unable to resolve the template type#' - - '#does not specify its types#' + - identifier: argument.templateType + - identifier: missingType.generics + - identifier: missingType.iterableValue + - identifier: property.notFound + + # We are getting and setting environment variables directly + - + identifier: larastan.noEnvCallsOutsideOfConfig + paths: + - app/Console/Commands/Environment/*.php + - app/Extensions/OAuth/Providers/*.php + - app/Filament/Admin/Pages/Settings.php diff --git a/routes/auth.php b/routes/auth.php index 9f43a95be3..8b3196a8d0 100644 --- a/routes/auth.php +++ b/routes/auth.php @@ -3,5 +3,7 @@ use Illuminate\Support\Facades\Route; use App\Http\Controllers\Auth; +Route::redirect('/login', '/login')->name('auth.login'); + Route::get('/oauth/redirect/{driver}', [Auth\OAuthController::class, 'redirect'])->name('auth.oauth.redirect'); Route::get('/oauth/callback/{driver}', [Auth\OAuthController::class, 'callback'])->name('auth.oauth.callback')->withoutMiddleware('guest');