diff --git a/README.md b/README.md index 8868bcea6..0a3ce0132 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ # About the Project -Coolify is an open-source & self-hostable alternative to Heroku / Netlify / Vercel / etc. +Coolify is an open-source & self-hostable alternative to Heroku / Netlify / Vercel / etc. It helps you manage your servers, applications, and databases on your own hardware; you only need an SSH connection. You can manage VPS, Bare Metal, Raspberry PIs, and anything else. @@ -40,21 +40,20 @@ Special thanks to our biggest sponsors! ### Special Sponsors -![image](https://github.com/user-attachments/assets/c95a07df-7c5a-4e77-a35a-81f25fcbece1) +![image](https://github.com/user-attachments/assets/152bd1e0-e0c1-4d47-8a4f-0eb3700d2e61) * [CCCareers](https://cccareers.org/) - A career development platform connecting coding bootcamp graduates with job opportunities in the tech industry. * [Hetzner](http://htznr.li/CoolifyXHetzner) - A German web hosting company offering affordable dedicated servers, cloud services, and web hosting solutions. * [Logto](https://logto.io/?ref=coolify) - An open-source authentication and authorization solution for building secure login systems and managing user identities. +* [Tolgee](https://tolgee.io/?ref=coolify) - Developer & translator friendly web-based localization platform. * [BC Direct](https://bc.direct/?ref=coolify.io) - A digital marketing agency specializing in e-commerce solutions and online business growth strategies. * [QuantCDN](https://www.quantcdn.io/?ref=coolify.io) - A content delivery network (CDN) optimizing website performance through global content distribution. * [Arcjet](https://arcjet.com/?ref=coolify.io) - A cloud-based platform providing real-time protection against API abuse and bot attacks. * [SupaGuide](https://supa.guide/?ref=coolify.io) - A comprehensive resource hub offering guides and tutorials for web development using Supabase. * [Tigris](https://tigrisdata.com/?ref=coolify.io) - A fully managed serverless object storage service compatible with Amazon S3 API. Offers high performance, scalability, and built-in search capabilities for efficient data management. -* [Fractal Networks](https://fractalnetworks.co/?ref=coolify.io) - A decentralized network infrastructure company focusing on secure and private communication solutions. * [Advin](https://coolify.ad.vin/?ref=coolify.io) - A digital advertising agency specializing in programmatic advertising and data-driven marketing strategies. * [Treive](https://trieve.ai/?ref=coolify.io) - An AI-powered search and discovery platform for enhancing information retrieval in large datasets. * [Blacksmith](https://blacksmith.sh/?ref=coolify.io) - A cloud-native platform for automating infrastructure provisioning and management across multiple cloud providers. -* [Latitude](https://latitude.sh/?ref=coolify.io) - A cloud computing platform offering bare metal servers and cloud instances for developers and businesses. * [Brand Dev](https://brand.dev/?ref=coolify.io) - A web development agency specializing in creating custom digital experiences and brand identities. * [Jobscollider](https://jobscollider.com/remote-jobs?ref=coolify.io) - A job search platform connecting professionals with remote work opportunities across various industries. * [Hostinger](https://www.hostinger.com/vps/coolify-hosting?ref=coolify.io) - A web hosting provider offering affordable hosting solutions, domain registration, and website building tools. @@ -63,6 +62,7 @@ Special thanks to our biggest sponsors! * [Juxtdigital](https://juxtdigital.dev/?ref=coolify.io) - A digital agency offering web development, design, and digital marketing services for businesses. * [Saasykit](https://saasykit.com/?ref=coolify.io) - A Laravel-based boilerplate providing essential components and features for building SaaS applications quickly. * [Massivegrid](https://massivegrid.com/?ref=coolify.io) - A cloud hosting provider offering scalable infrastructure solutions for businesses of all sizes. +* [LiquidWeb](https://liquidweb.com/?utm_source=coolify.io) - Fast web hosting provider. ## Github Sponsors ($40+) @@ -91,6 +91,11 @@ Special thanks to our biggest sponsors! Michael Mazurczak Formbricks Adith Suhas +StartupFame +Jonas Jaeger +JP +Evercam +Web3 Career ## Organizations diff --git a/app/Actions/Application/StopApplication.php b/app/Actions/Application/StopApplication.php index cab7e45f0..642b4ba45 100644 --- a/app/Actions/Application/StopApplication.php +++ b/app/Actions/Application/StopApplication.php @@ -10,6 +10,8 @@ class StopApplication { use AsAction; + public string $jobQueue = 'high'; + public function handle(Application $application, bool $previewDeployments = false, bool $dockerCleanup = true) { try { diff --git a/app/Actions/CoolifyTask/PrepareCoolifyTask.php b/app/Actions/CoolifyTask/PrepareCoolifyTask.php index 6676b7937..3f76a2e3c 100644 --- a/app/Actions/CoolifyTask/PrepareCoolifyTask.php +++ b/app/Actions/CoolifyTask/PrepareCoolifyTask.php @@ -3,7 +3,6 @@ namespace App\Actions\CoolifyTask; use App\Data\CoolifyTaskArgs; -use App\Enums\ActivityTypes; use App\Jobs\CoolifyTask; use Spatie\Activitylog\Models\Activity; @@ -47,11 +46,7 @@ class PrepareCoolifyTask call_event_on_finish: $this->remoteProcessArgs->call_event_on_finish, call_event_data: $this->remoteProcessArgs->call_event_data, ); - if ($this->remoteProcessArgs->type === ActivityTypes::COMMAND->value) { - dispatch($job)->onQueue('high'); - } else { - dispatch($job); - } + dispatch($job); $this->activity->refresh(); return $this->activity; diff --git a/app/Actions/Database/StartDatabase.php b/app/Actions/Database/StartDatabase.php index 869a88521..e2fa6fc87 100644 --- a/app/Actions/Database/StartDatabase.php +++ b/app/Actions/Database/StartDatabase.php @@ -16,6 +16,8 @@ class StartDatabase { use AsAction; + public string $jobQueue = 'high'; + public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse $database) { $server = $database->destination->server; @@ -49,7 +51,7 @@ class StartDatabase break; } if ($database->is_public && $database->public_port) { - StartDatabaseProxy::dispatch($database)->onQueue('high'); + StartDatabaseProxy::dispatch($database); } return $activity; diff --git a/app/Actions/Database/StartDatabaseProxy.php b/app/Actions/Database/StartDatabaseProxy.php index d7a3bc697..3ddf6c036 100644 --- a/app/Actions/Database/StartDatabaseProxy.php +++ b/app/Actions/Database/StartDatabaseProxy.php @@ -18,6 +18,8 @@ class StartDatabaseProxy { use AsAction; + public string $jobQueue = 'high'; + public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse|ServiceDatabase $database) { $internalPort = null; diff --git a/app/Actions/Database/StopDatabaseProxy.php b/app/Actions/Database/StopDatabaseProxy.php index 0a166d24a..9ee794351 100644 --- a/app/Actions/Database/StopDatabaseProxy.php +++ b/app/Actions/Database/StopDatabaseProxy.php @@ -18,6 +18,8 @@ class StopDatabaseProxy { use AsAction; + public string $jobQueue = 'high'; + public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|ServiceDatabase|StandaloneDragonfly|StandaloneClickhouse $database) { $server = data_get($database, 'destination.server'); diff --git a/app/Actions/Docker/GetContainersStatus.php b/app/Actions/Docker/GetContainersStatus.php index a08056837..8aae910a9 100644 --- a/app/Actions/Docker/GetContainersStatus.php +++ b/app/Actions/Docker/GetContainersStatus.php @@ -7,7 +7,6 @@ use App\Actions\Shared\ComplexStatusCheck; use App\Models\ApplicationPreview; use App\Models\Server; use App\Models\ServiceDatabase; -use App\Notifications\Container\ContainerRestarted; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Lorisleiva\Actions\Concerns\AsAction; @@ -16,6 +15,8 @@ class GetContainersStatus { use AsAction; + public string $jobQueue = 'high'; + public $applications; public ?Collection $containers; diff --git a/app/Actions/Proxy/CheckProxy.php b/app/Actions/Proxy/CheckProxy.php index 51303d87a..6c8dd5234 100644 --- a/app/Actions/Proxy/CheckProxy.php +++ b/app/Actions/Proxy/CheckProxy.php @@ -30,7 +30,7 @@ class CheckProxy if (is_null($proxyType) || $proxyType === 'NONE' || $server->proxy->force_stop) { return false; } - ['uptime' => $uptime, 'error' => $error] = $server->validateConnection(false); + ['uptime' => $uptime, 'error' => $error] = $server->validateConnection(); if (! $uptime) { throw new \Exception($error); } diff --git a/app/Actions/Server/CleanupDocker.php b/app/Actions/Server/CleanupDocker.php index 1b8e6c9a6..0349ead89 100644 --- a/app/Actions/Server/CleanupDocker.php +++ b/app/Actions/Server/CleanupDocker.php @@ -9,6 +9,8 @@ class CleanupDocker { use AsAction; + public string $jobQueue = 'high'; + public function handle(Server $server) { $settings = instanceSettings(); diff --git a/app/Actions/Server/ServerCheck.php b/app/Actions/Server/ServerCheck.php index 1dae03fd9..5f9a1e357 100644 --- a/app/Actions/Server/ServerCheck.php +++ b/app/Actions/Server/ServerCheck.php @@ -130,10 +130,10 @@ class ServerCheck if ($foundLogDrainContainer) { $status = data_get($foundLogDrainContainer, 'State.Status'); if ($status !== 'running') { - StartLogDrain::dispatch($this->server)->onQueue('high'); + StartLogDrain::dispatch($this->server); } } else { - StartLogDrain::dispatch($this->server)->onQueue('high'); + StartLogDrain::dispatch($this->server); } } diff --git a/app/Actions/Server/StartLogDrain.php b/app/Actions/Server/StartLogDrain.php index 1997b58d6..0d28a0099 100644 --- a/app/Actions/Server/StartLogDrain.php +++ b/app/Actions/Server/StartLogDrain.php @@ -9,6 +9,8 @@ class StartLogDrain { use AsAction; + public string $jobQueue = 'high'; + public function handle(Server $server) { if ($server->settings->is_logdrain_newrelic_enabled) { diff --git a/app/Actions/Server/UpdateCoolify.php b/app/Actions/Server/UpdateCoolify.php index d57a4fe46..53c443778 100644 --- a/app/Actions/Server/UpdateCoolify.php +++ b/app/Actions/Server/UpdateCoolify.php @@ -29,7 +29,7 @@ class UpdateCoolify if (! $this->server) { return; } - CleanupDocker::dispatch($this->server)->onQueue('high'); + CleanupDocker::dispatch($this->server); $this->latestVersion = get_latest_version_of_coolify(); $this->currentVersion = config('version'); if (! $manual_update) { diff --git a/app/Actions/Server/ValidateServer.php b/app/Actions/Server/ValidateServer.php index d0a4cd6be..55b37a77c 100644 --- a/app/Actions/Server/ValidateServer.php +++ b/app/Actions/Server/ValidateServer.php @@ -9,6 +9,8 @@ class ValidateServer { use AsAction; + public string $jobQueue = 'high'; + public ?string $uptime = null; public ?string $error = null; diff --git a/app/Actions/Service/RestartService.php b/app/Actions/Service/RestartService.php index 1b6a5c32c..4151ea947 100644 --- a/app/Actions/Service/RestartService.php +++ b/app/Actions/Service/RestartService.php @@ -9,6 +9,8 @@ class RestartService { use AsAction; + public string $jobQueue = 'high'; + public function handle(Service $service) { StopService::run($service); diff --git a/app/Actions/Service/StartService.php b/app/Actions/Service/StartService.php index 82de066d7..1dfaf6c49 100644 --- a/app/Actions/Service/StartService.php +++ b/app/Actions/Service/StartService.php @@ -10,6 +10,8 @@ class StartService { use AsAction; + public string $jobQueue = 'high'; + public function handle(Service $service) { $service->saveComposeConfigs(); diff --git a/app/Actions/Service/StopService.php b/app/Actions/Service/StopService.php index 046d94ced..95b08b437 100644 --- a/app/Actions/Service/StopService.php +++ b/app/Actions/Service/StopService.php @@ -10,6 +10,8 @@ class StopService { use AsAction; + public string $jobQueue = 'high'; + public function handle(Service $service, bool $isDeleteOperation = false, bool $dockerCleanup = true) { try { diff --git a/app/Console/Commands/CleanupRedis.php b/app/Console/Commands/CleanupRedis.php index 5fc2b4e61..e16a82be4 100644 --- a/app/Console/Commands/CleanupRedis.php +++ b/app/Console/Commands/CleanupRedis.php @@ -13,7 +13,6 @@ class CleanupRedis extends Command public function handle() { - echo "Cleanup Redis keys.\n"; $prefix = config('database.redis.options.prefix'); $keys = Redis::connection()->keys('*:laravel*'); diff --git a/app/Console/Commands/CleanupStuckedResources.php b/app/Console/Commands/CleanupStuckedResources.php index 9d36ce9b8..def3d5a2c 100644 --- a/app/Console/Commands/CleanupStuckedResources.php +++ b/app/Console/Commands/CleanupStuckedResources.php @@ -30,7 +30,6 @@ class CleanupStuckedResources extends Command public function handle() { - echo "Running cleanup stucked resources.\n"; $this->cleanup_stucked_resources(); } diff --git a/app/Console/Commands/Horizon.php b/app/Console/Commands/Horizon.php index 8ae165c59..655729ec9 100644 --- a/app/Console/Commands/Horizon.php +++ b/app/Console/Commands/Horizon.php @@ -13,7 +13,7 @@ class Horizon extends Command public function handle() { if (config('constants.horizon.is_horizon_enabled')) { - $this->info('Horizon is enabled. Starting.'); + $this->info('[x]: Horizon is enabled. Starting.'); $this->call('horizon'); exit(0); } else { diff --git a/app/Console/Commands/Init.php b/app/Console/Commands/Init.php index bbf1dc093..57bbe896b 100644 --- a/app/Console/Commands/Init.php +++ b/app/Console/Commands/Init.php @@ -2,9 +2,9 @@ namespace App\Console\Commands; -use App\Actions\Server\StopSentinel; use App\Enums\ActivityTypes; use App\Enums\ApplicationDeploymentStatus; +use App\Jobs\CheckHelperImageJob; use App\Models\ApplicationDeploymentQueue; use App\Models\Environment; use App\Models\ScheduledDatabaseBackup; @@ -12,6 +12,7 @@ use App\Models\Server; use App\Models\StandalonePostgresql; use App\Models\User; use Illuminate\Console\Command; +use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Http; @@ -25,6 +26,8 @@ class Init extends Command public function handle() { + $this->optimize(); + if (isCloud() && ! $this->option('force-cloud')) { echo "Skipping init as we are on cloud and --force-cloud option is not set\n"; @@ -39,7 +42,6 @@ class Init extends Command } // Backward compatibility - // $this->disable_metrics(); $this->replace_slash_in_environment_name(); $this->restore_coolify_db_backup(); $this->update_user_emails(); @@ -53,9 +55,18 @@ class Init extends Command } else { $this->cleanup_in_progress_application_deployments(); } + echo "[3]: Cleanup Redis keys.\n"; $this->call('cleanup:redis'); + + echo "[4]: Cleanup stucked resources.\n"; $this->call('cleanup:stucked-resources'); + try { + $this->pullHelperImage(); + } catch (\Throwable $e) { + // + } + if (isCloud()) { try { $this->pullTemplatesFromCDN(); @@ -87,6 +98,11 @@ class Init extends Command } } + private function pullHelperImage() + { + CheckHelperImageJob::dispatch(); + } + private function pullTemplatesFromCDN() { $response = Http::retry(3, 1000)->get(config('constants.services.official')); @@ -95,19 +111,13 @@ class Init extends Command File::put(base_path('templates/service-templates.json'), json_encode($services)); } } - // private function disable_metrics() - // { - // if (version_compare('4.0.0-beta.312', config('version'), '<=')) { - // foreach ($this->servers as $server) { - // if ($server->settings->is_metrics_enabled === true) { - // $server->settings->update(['is_metrics_enabled' => false]); - // } - // if ($server->isFunctional()) { - // StopSentinel::dispatch($server)->onQueue('high'); - // } - // } - // } - // } + + private function optimize() + { + echo "[1]: Optimizing Laravel (caching config, routes, views).\n"; + Artisan::call('optimize:clear'); + Artisan::call('optimize'); + } private function update_user_emails() { @@ -222,15 +232,15 @@ class Init extends Command $settings = instanceSettings(); $do_not_track = data_get($settings, 'do_not_track'); if ($do_not_track == true) { - echo "Skipping alive as do_not_track is enabled\n"; + echo "[2]: Skipping sending live signal as do_not_track is enabled\n"; return; } try { Http::get("https://undead.coolify.io/v4/alive?appId=$id&version=$version"); - echo "I am alive!\n"; + echo "[2]: Sending live signal!\n"; } catch (\Throwable $e) { - echo "Error in alive: {$e->getMessage()}\n"; + echo "[2]: Error in sending live signal: {$e->getMessage()}\n"; } } diff --git a/app/Console/Commands/Scheduler.php b/app/Console/Commands/Scheduler.php index 9b6ca5324..9ee7b06e6 100644 --- a/app/Console/Commands/Scheduler.php +++ b/app/Console/Commands/Scheduler.php @@ -13,7 +13,7 @@ class Scheduler extends Command public function handle() { if (config('constants.horizon.is_scheduler_enabled')) { - $this->info('Scheduler is enabled. Starting.'); + $this->info('[x]: Scheduler is enabled. Starting.'); $this->call('schedule:work'); exit(0); } else { diff --git a/app/Console/Commands/ServicesDelete.php b/app/Console/Commands/ServicesDelete.php index 1e5d5808c..b5a74166a 100644 --- a/app/Console/Commands/ServicesDelete.php +++ b/app/Console/Commands/ServicesDelete.php @@ -96,7 +96,7 @@ class ServicesDelete extends Command if (! $confirmed) { break; } - DeleteResourceJob::dispatch($toDelete)->onQueue('high'); + DeleteResourceJob::dispatch($toDelete); } } } @@ -122,7 +122,7 @@ class ServicesDelete extends Command if (! $confirmed) { return; } - DeleteResourceJob::dispatch($toDelete)->onQueue('high'); + DeleteResourceJob::dispatch($toDelete); } } } @@ -148,7 +148,7 @@ class ServicesDelete extends Command if (! $confirmed) { return; } - DeleteResourceJob::dispatch($toDelete)->onQueue('high'); + DeleteResourceJob::dispatch($toDelete); } } } diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index e113dbe9a..832dcf58b 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -50,7 +50,7 @@ class Kernel extends ConsoleKernel $this->instanceTimezone = config('app.timezone'); } - $this->scheduleInstance->job(new CleanupStaleMultiplexedConnections)->hourly(); + // $this->scheduleInstance->job(new CleanupStaleMultiplexedConnections)->hourly(); if (isDev()) { // Instance Jobs @@ -154,7 +154,7 @@ class Kernel extends ConsoleKernel } // Cleanup multiplexed connections every hour - $this->scheduleInstance->job(new ServerCleanupMux($server))->hourly()->onOneServer(); + // $this->scheduleInstance->job(new ServerCleanupMux($server))->hourly()->onOneServer(); // Temporary solution until we have better memory management for Sentinel if ($server->isSentinelEnabled()) { diff --git a/app/Helpers/SshMultiplexingHelper.php b/app/Helpers/SshMultiplexingHelper.php index 0e840c3ce..8da476b9e 100644 --- a/app/Helpers/SshMultiplexingHelper.php +++ b/app/Helpers/SshMultiplexingHelper.php @@ -21,17 +21,14 @@ class SshMultiplexingHelper ]; } - public static function ensureMultiplexedConnection(Server $server) + public static function ensureMultiplexedConnection(Server $server): bool { if (! self::isMultiplexingEnabled()) { - return; + return false; } $sshConfig = self::serverSshConfiguration($server); $muxSocket = $sshConfig['muxFilename']; - $sshKeyLocation = $sshConfig['sshKeyLocation']; - - self::validateSshKey($sshKeyLocation); $checkCommand = "ssh -O check -o ControlPath=$muxSocket "; if (data_get($server, 'settings.is_cloudflare_tunnel')) { @@ -41,16 +38,17 @@ class SshMultiplexingHelper $process = Process::run($checkCommand); if ($process->exitCode() !== 0) { - self::establishNewMultiplexedConnection($server); + return self::establishNewMultiplexedConnection($server); } + + return true; } - public static function establishNewMultiplexedConnection(Server $server) + public static function establishNewMultiplexedConnection(Server $server): bool { $sshConfig = self::serverSshConfiguration($server); $sshKeyLocation = $sshConfig['sshKeyLocation']; $muxSocket = $sshConfig['muxFilename']; - $connectionTimeout = config('constants.ssh.connection_timeout'); $serverInterval = config('constants.ssh.server_interval'); $muxPersistTime = config('constants.ssh.mux_persist_time'); @@ -60,15 +58,14 @@ class SshMultiplexingHelper if (data_get($server, 'settings.is_cloudflare_tunnel')) { $establishCommand .= ' -o ProxyCommand="cloudflared access ssh --hostname %h" '; } - $establishCommand .= self::getCommonSshOptions($server, $sshKeyLocation, $connectionTimeout, $serverInterval); $establishCommand .= "{$server->user}@{$server->ip}"; - $establishProcess = Process::run($establishCommand); - if ($establishProcess->exitCode() !== 0) { - throw new \RuntimeException('Failed to establish multiplexed connection: '.$establishProcess->errorOutput()); + return false; } + + return true; } public static function removeMuxFile(Server $server) @@ -97,9 +94,8 @@ class SshMultiplexingHelper if ($server->isIpv6()) { $scp_command .= '-6 '; } - if (self::isMultiplexingEnabled()) { + if (self::isMultiplexingEnabled() && self::ensureMultiplexedConnection($server)) { $scp_command .= "-o ControlMaster=auto -o ControlPath=$muxSocket -o ControlPersist={$muxPersistTime} "; - self::ensureMultiplexedConnection($server); } if (data_get($server, 'settings.is_cloudflare_tunnel')) { @@ -120,6 +116,9 @@ class SshMultiplexingHelper $sshConfig = self::serverSshConfiguration($server); $sshKeyLocation = $sshConfig['sshKeyLocation']; + + self::validateSshKey($server->privateKey); + $muxSocket = $sshConfig['muxFilename']; $timeout = config('constants.ssh.command_timeout'); @@ -127,9 +126,8 @@ class SshMultiplexingHelper $ssh_command = "timeout $timeout ssh "; - if (self::isMultiplexingEnabled()) { + if (self::isMultiplexingEnabled() && self::ensureMultiplexedConnection($server)) { $ssh_command .= "-o ControlMaster=auto -o ControlPath=$muxSocket -o ControlPersist={$muxPersistTime} "; - self::ensureMultiplexedConnection($server); } if (data_get($server, 'settings.is_cloudflare_tunnel')) { @@ -154,13 +152,14 @@ class SshMultiplexingHelper return config('constants.ssh.mux_enabled') && ! config('constants.coolify.is_windows_docker_desktop'); } - private static function validateSshKey(string $sshKeyLocation): void + private static function validateSshKey(PrivateKey $privateKey): void { - $checkKeyCommand = "ls $sshKeyLocation 2>/dev/null"; + $keyLocation = $privateKey->getKeyLocation(); + $checkKeyCommand = "ls $keyLocation 2>/dev/null"; $keyCheckProcess = Process::run($checkKeyCommand); if ($keyCheckProcess->exitCode() !== 0) { - throw new \RuntimeException("SSH key file not accessible: $sshKeyLocation"); + $privateKey->storeInFileSystem(); } } diff --git a/app/Http/Controllers/Api/ApplicationsController.php b/app/Http/Controllers/Api/ApplicationsController.php index 500db3922..c69640970 100644 --- a/app/Http/Controllers/Api/ApplicationsController.php +++ b/app/Http/Controllers/Api/ApplicationsController.php @@ -1224,7 +1224,7 @@ class ApplicationsController extends Controller $service->name = "service-$service->uuid"; $service->parse(isNew: true); if ($instantDeploy) { - StartService::dispatch($service)->onQueue('high'); + StartService::dispatch($service); } return response()->json(serializeApiResponse([ @@ -1379,7 +1379,7 @@ class ApplicationsController extends Controller deleteVolumes: $request->query->get('delete_volumes', true), dockerCleanup: $request->query->get('docker_cleanup', true), deleteConnectedNetworks: $request->query->get('delete_connected_networks', true) - )->onQueue('high'); + ); return response()->json([ 'message' => 'Application deletion request queued.', @@ -2523,7 +2523,7 @@ class ApplicationsController extends Controller if (! $application) { return response()->json(['message' => 'Application not found.'], 404); } - StopApplication::dispatch($application)->onQueue('high'); + StopApplication::dispatch($application); return response()->json( [ diff --git a/app/Http/Controllers/Api/DatabasesController.php b/app/Http/Controllers/Api/DatabasesController.php index eaa542a83..ce658d2a2 100644 --- a/app/Http/Controllers/Api/DatabasesController.php +++ b/app/Http/Controllers/Api/DatabasesController.php @@ -497,9 +497,9 @@ class DatabasesController extends Controller $database->update($request->all()); if ($whatToDoWithDatabaseProxy === 'start') { - StartDatabaseProxy::dispatch($database)->onQueue('high'); + StartDatabaseProxy::dispatch($database); } elseif ($whatToDoWithDatabaseProxy === 'stop') { - StopDatabaseProxy::dispatch($database)->onQueue('high'); + StopDatabaseProxy::dispatch($database); } return response()->json([ @@ -1151,7 +1151,7 @@ class DatabasesController extends Controller } $database = create_standalone_postgresql($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } $database->refresh(); $payload = [ @@ -1206,7 +1206,7 @@ class DatabasesController extends Controller } $database = create_standalone_mariadb($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } $database->refresh(); @@ -1264,7 +1264,7 @@ class DatabasesController extends Controller } $database = create_standalone_mysql($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } $database->refresh(); @@ -1320,7 +1320,7 @@ class DatabasesController extends Controller } $database = create_standalone_redis($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } $database->refresh(); @@ -1357,7 +1357,7 @@ class DatabasesController extends Controller removeUnnecessaryFieldsFromRequest($request); $database = create_standalone_dragonfly($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } return response()->json(serializeApiResponse([ @@ -1406,7 +1406,7 @@ class DatabasesController extends Controller } $database = create_standalone_keydb($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } $database->refresh(); @@ -1442,7 +1442,7 @@ class DatabasesController extends Controller removeUnnecessaryFieldsFromRequest($request); $database = create_standalone_clickhouse($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } $database->refresh(); @@ -1500,7 +1500,7 @@ class DatabasesController extends Controller } $database = create_standalone_mongodb($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } $database->refresh(); @@ -1593,7 +1593,7 @@ class DatabasesController extends Controller deleteVolumes: $request->query->get('delete_volumes', true), dockerCleanup: $request->query->get('docker_cleanup', true), deleteConnectedNetworks: $request->query->get('delete_connected_networks', true) - )->onQueue('high'); + ); return response()->json([ 'message' => 'Database deletion request queued.', @@ -1666,7 +1666,7 @@ class DatabasesController extends Controller if (str($database->status)->contains('running')) { return response()->json(['message' => 'Database is already running.'], 400); } - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); return response()->json( [ @@ -1742,7 +1742,7 @@ class DatabasesController extends Controller if (str($database->status)->contains('stopped') || str($database->status)->contains('exited')) { return response()->json(['message' => 'Database is already stopped.'], 400); } - StopDatabase::dispatch($database)->onQueue('high'); + StopDatabase::dispatch($database); return response()->json( [ @@ -1815,7 +1815,7 @@ class DatabasesController extends Controller if (! $database) { return response()->json(['message' => 'Database not found.'], 404); } - RestartDatabase::dispatch($database)->onQueue('high'); + RestartDatabase::dispatch($database); return response()->json( [ diff --git a/app/Http/Controllers/Api/DeployController.php b/app/Http/Controllers/Api/DeployController.php index 59b199d87..666dc55a5 100644 --- a/app/Http/Controllers/Api/DeployController.php +++ b/app/Http/Controllers/Api/DeployController.php @@ -307,7 +307,7 @@ class DeployController extends Controller break; default: // Database resource - StartDatabase::dispatch($resource)->onQueue('high'); + StartDatabase::dispatch($resource); $resource->update([ 'started_at' => now(), ]); diff --git a/app/Http/Controllers/Api/ServersController.php b/app/Http/Controllers/Api/ServersController.php index cbee00642..3f0f4d2c3 100644 --- a/app/Http/Controllers/Api/ServersController.php +++ b/app/Http/Controllers/Api/ServersController.php @@ -550,7 +550,7 @@ class ServersController extends Controller 'is_build_server' => $request->is_build_server, ]); if ($request->instant_validate) { - ValidateServer::dispatch($server)->onQueue('high'); + ValidateServer::dispatch($server); } return response()->json([ @@ -675,7 +675,7 @@ class ServersController extends Controller ]); } if ($request->instant_validate) { - ValidateServer::dispatch($server)->onQueue('high'); + ValidateServer::dispatch($server); } return response()->json([ @@ -813,7 +813,7 @@ class ServersController extends Controller if (! $server) { return response()->json(['message' => 'Server not found.'], 404); } - ValidateServer::dispatch($server)->onQueue('high'); + ValidateServer::dispatch($server); return response()->json(['message' => 'Validation started.']); } diff --git a/app/Http/Controllers/Api/ServicesController.php b/app/Http/Controllers/Api/ServicesController.php index bdb5612ad..bf90322e2 100644 --- a/app/Http/Controllers/Api/ServicesController.php +++ b/app/Http/Controllers/Api/ServicesController.php @@ -342,7 +342,7 @@ class ServicesController extends Controller } $service->parse(isNew: true); if ($instantDeploy) { - StartService::dispatch($service)->onQueue('high'); + StartService::dispatch($service); } $domains = $service->applications()->get()->pluck('fqdn')->sort(); $domains = $domains->map(function ($domain) { @@ -487,7 +487,7 @@ class ServicesController extends Controller deleteVolumes: $request->query->get('delete_volumes', true), dockerCleanup: $request->query->get('docker_cleanup', true), deleteConnectedNetworks: $request->query->get('delete_connected_networks', true) - )->onQueue('high'); + ); return response()->json([ 'message' => 'Service deletion request queued.', @@ -1076,7 +1076,7 @@ class ServicesController extends Controller if (str($service->status())->contains('running')) { return response()->json(['message' => 'Service is already running.'], 400); } - StartService::dispatch($service)->onQueue('high'); + StartService::dispatch($service); return response()->json( [ @@ -1154,7 +1154,7 @@ class ServicesController extends Controller if (str($service->status())->contains('stopped') || str($service->status())->contains('exited')) { return response()->json(['message' => 'Service is already stopped.'], 400); } - StopService::dispatch($service)->onQueue('high'); + StopService::dispatch($service); return response()->json( [ @@ -1229,7 +1229,7 @@ class ServicesController extends Controller if (! $service) { return response()->json(['message' => 'Service not found.'], 404); } - RestartService::dispatch($service)->onQueue('high'); + RestartService::dispatch($service); return response()->json( [ diff --git a/app/Http/Controllers/Webhook/Stripe.php b/app/Http/Controllers/Webhook/Stripe.php index e94209b23..83ba16699 100644 --- a/app/Http/Controllers/Webhook/Stripe.php +++ b/app/Http/Controllers/Webhook/Stripe.php @@ -3,21 +3,26 @@ namespace App\Http\Controllers\Webhook; use App\Http\Controllers\Controller; -use App\Jobs\ServerLimitCheckJob; -use App\Jobs\SubscriptionInvoiceFailedJob; -use App\Models\Subscription; -use App\Models\Team; +use App\Jobs\StripeProcessJob; use App\Models\Webhook; use Exception; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; -use Illuminate\Support\Str; class Stripe extends Controller { + protected $webhook; + public function events(Request $request) { try { + $webhookSecret = config('subscription.stripe_webhook_secret'); + $signature = $request->header('Stripe-Signature'); + $event = \Stripe\Webhook::constructEvent( + $request->getContent(), + $signature, + $webhookSecret + ); if (app()->isDownForMaintenance()) { $epoch = now()->valueOf(); $data = [ @@ -33,241 +38,17 @@ class Stripe extends Controller $json = json_encode($data); Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Stripe::events_stripe", $json); - return; + return response('Webhook received. Cool cool cool cool cool.', 200); } - $webhookSecret = config('subscription.stripe_webhook_secret'); - $signature = $request->header('Stripe-Signature'); - $excludedPlans = config('subscription.stripe_excluded_plans'); - $event = \Stripe\Webhook::constructEvent( - $request->getContent(), - $signature, - $webhookSecret - ); - $webhook = Webhook::create([ + $this->webhook = Webhook::create([ 'type' => 'stripe', 'payload' => $request->getContent(), ]); - $type = data_get($event, 'type'); - $data = data_get($event, 'data.object'); - switch ($type) { - case 'radar.early_fraud_warning.created': - $stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key')); - $id = data_get($data, 'id'); - $charge = data_get($data, 'charge'); - if ($charge) { - $stripe->refunds->create(['charge' => $charge]); - } - $pi = data_get($data, 'payment_intent'); - $piData = $stripe->paymentIntents->retrieve($pi, []); - $customerId = data_get($piData, 'customer'); - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if ($subscription) { - $subscriptionId = data_get($subscription, 'stripe_subscription_id'); - $stripe->subscriptions->cancel($subscriptionId, []); - $subscription->update([ - 'stripe_invoice_paid' => false, - ]); - send_internal_notification("Early fraud warning created Refunded, subscription canceled. Charge: {$charge}, id: {$id}, pi: {$pi}"); - } else { - send_internal_notification("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}"); + StripeProcessJob::dispatch($event); - return response("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}", 400); - } - break; - case 'checkout.session.completed': - $clientReferenceId = data_get($data, 'client_reference_id'); - if (is_null($clientReferenceId)) { - send_internal_notification('Checkout session completed without client reference id.'); - break; - } - $userId = Str::before($clientReferenceId, ':'); - $teamId = Str::after($clientReferenceId, ':'); - $subscriptionId = data_get($data, 'subscription'); - $customerId = data_get($data, 'customer'); - $team = Team::find($teamId); - $found = $team->members->where('id', $userId)->first(); - if (! $found->isAdmin()) { - send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}."); - - return response("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.", 400); - } - $subscription = Subscription::where('team_id', $teamId)->first(); - if ($subscription) { - // send_internal_notification('Old subscription activated for team: '.$teamId); - $subscription->update([ - 'stripe_subscription_id' => $subscriptionId, - 'stripe_customer_id' => $customerId, - 'stripe_invoice_paid' => true, - ]); - } else { - // send_internal_notification('New subscription for team: '.$teamId); - Subscription::create([ - 'team_id' => $teamId, - 'stripe_subscription_id' => $subscriptionId, - 'stripe_customer_id' => $customerId, - 'stripe_invoice_paid' => true, - ]); - } - break; - case 'invoice.paid': - $customerId = data_get($data, 'customer'); - $planId = data_get($data, 'lines.data.0.plan.id'); - if (Str::contains($excludedPlans, $planId)) { - // send_internal_notification('Subscription excluded.'); - break; - } - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if ($subscription) { - $subscription->update([ - 'stripe_invoice_paid' => true, - ]); - } else { - return response("No subscription found for customer: {$customerId}", 400); - } - break; - case 'invoice.payment_failed': - $customerId = data_get($data, 'customer'); - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if (! $subscription) { - // send_internal_notification('invoice.payment_failed failed but no subscription found in Coolify for customer: '.$customerId); - - return response('No subscription found in Coolify.'); - } - $team = data_get($subscription, 'team'); - if (! $team) { - // send_internal_notification('invoice.payment_failed failed but no team found in Coolify for customer: '.$customerId); - - return response('No team found in Coolify.'); - } - if (! $subscription->stripe_invoice_paid) { - SubscriptionInvoiceFailedJob::dispatch($team); - // send_internal_notification('Invoice payment failed: '.$customerId); - } else { - // send_internal_notification('Invoice payment failed but already paid: '.$customerId); - } - break; - case 'payment_intent.payment_failed': - $customerId = data_get($data, 'customer'); - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if (! $subscription) { - // send_internal_notification('payment_intent.payment_failed, no subscription found in Coolify for customer: '.$customerId); - - return response('No subscription found in Coolify.'); - } - if ($subscription->stripe_invoice_paid) { - // send_internal_notification('payment_intent.payment_failed but invoice is active for customer: '.$customerId); - - return; - } - send_internal_notification('Subscription payment failed for customer: '.$customerId); - break; - case 'customer.subscription.created': - $customerId = data_get($data, 'customer'); - $subscriptionId = data_get($data, 'id'); - $teamId = data_get($data, 'metadata.team_id'); - $userId = data_get($data, 'metadata.user_id'); - if (! $teamId || ! $userId) { - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if ($subscription) { - return response("Subscription already exists for customer: {$customerId}", 200); - } - - return response('No team id or user id found', 400); - } - $team = Team::find($teamId); - $found = $team->members->where('id', $userId)->first(); - if (! $found->isAdmin()) { - send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}."); - - return response("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}.", 400); - } - $subscription = Subscription::where('team_id', $teamId)->first(); - if ($subscription) { - return response("Subscription already exists for team: {$teamId}", 200); - } else { - Subscription::create([ - 'team_id' => $teamId, - 'stripe_subscription_id' => $subscriptionId, - 'stripe_customer_id' => $customerId, - 'stripe_invoice_paid' => false, - ]); - - return response('Subscription created'); - } - case 'customer.subscription.updated': - $teamId = data_get($data, 'metadata.team_id'); - $userId = data_get($data, 'metadata.user_id'); - $customerId = data_get($data, 'customer'); - $status = data_get($data, 'status'); - $subscriptionId = data_get($data, 'items.data.0.subscription'); - $planId = data_get($data, 'items.data.0.plan.id'); - if (Str::contains($excludedPlans, $planId)) { - // send_internal_notification('Subscription excluded.'); - break; - } - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if (! $subscription) { - if ($status === 'incomplete_expired') { - return response('Subscription incomplete expired', 200); - } - if ($teamId) { - $subscription = Subscription::create([ - 'team_id' => $teamId, - 'stripe_subscription_id' => $subscriptionId, - 'stripe_customer_id' => $customerId, - 'stripe_invoice_paid' => false, - ]); - } else { - return response('No subscription and team id found', 400); - } - } - $cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end'); - $feedback = data_get($data, 'cancellation_details.feedback'); - $comment = data_get($data, 'cancellation_details.comment'); - $lookup_key = data_get($data, 'items.data.0.price.lookup_key'); - if (str($lookup_key)->contains('dynamic')) { - $quantity = data_get($data, 'items.data.0.quantity', 2); - $team = data_get($subscription, 'team'); - if ($team) { - $team->update([ - 'custom_server_limit' => $quantity, - ]); - } - ServerLimitCheckJob::dispatch($team); - } - $subscription->update([ - 'stripe_feedback' => $feedback, - 'stripe_comment' => $comment, - 'stripe_plan_id' => $planId, - 'stripe_cancel_at_period_end' => $cancelAtPeriodEnd, - ]); - if ($status === 'paused' || $status === 'incomplete_expired') { - $subscription->update([ - 'stripe_invoice_paid' => false, - ]); - } - if ($feedback) { - $reason = "Cancellation feedback for {$customerId}: '".$feedback."'"; - if ($comment) { - $reason .= ' with comment: \''.$comment."'"; - } - } - break; - case 'customer.subscription.deleted': - // End subscription - $customerId = data_get($data, 'customer'); - $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); - $team = data_get($subscription, 'team'); - $team?->subscriptionEnded(); - break; - default: - // Unhandled event type - } + return response('Webhook received. Cool cool cool cool cool.', 200); } catch (Exception $e) { - if ($type !== 'payment_intent.payment_failed') { - send_internal_notification("Subscription webhook ($type) failed: ".$e->getMessage()); - } - $webhook->update([ + $this->webhook->update([ 'status' => 'failed', 'failure_reason' => $e->getMessage(), ]); diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index cd89f55f3..270243eaf 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -166,6 +166,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue public function __construct(int $application_deployment_queue_id) { + $this->onQueue('high'); + $this->application_deployment_queue = ApplicationDeploymentQueue::find($application_deployment_queue_id); $this->application = Application::find($this->application_deployment_queue->application_id); $this->build_pack = data_get($this->application, 'build_pack'); @@ -349,8 +351,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue private function post_deployment() { if ($this->server->isProxyShouldRun()) { - GetContainersStatus::dispatch($this->server)->onQueue('high'); - // dispatch(new ContainerStatusJob($this->server)); + GetContainersStatus::dispatch($this->server); } $this->next(ApplicationDeploymentStatus::FINISHED->value); if ($this->pull_request_id !== 0) { diff --git a/app/Jobs/ApplicationPullRequestUpdateJob.php b/app/Jobs/ApplicationPullRequestUpdateJob.php index 2eefc4dd2..ef8e6efb6 100755 --- a/app/Jobs/ApplicationPullRequestUpdateJob.php +++ b/app/Jobs/ApplicationPullRequestUpdateJob.php @@ -25,7 +25,9 @@ class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue public ApplicationPreview $preview, public ProcessStatus $status, public ?string $deployment_uuid = null - ) {} + ) { + $this->onQueue('high'); + } public function handle() { diff --git a/app/Jobs/CoolifyTask.php b/app/Jobs/CoolifyTask.php index c3692c30b..49a5ba8dd 100755 --- a/app/Jobs/CoolifyTask.php +++ b/app/Jobs/CoolifyTask.php @@ -23,7 +23,10 @@ class CoolifyTask implements ShouldBeEncrypted, ShouldQueue public bool $ignore_errors, public $call_event_on_finish, public $call_event_data, - ) {} + ) { + + $this->onQueue('high'); + } /** * Execute the job. diff --git a/app/Jobs/DatabaseBackupJob.php b/app/Jobs/DatabaseBackupJob.php index 94f185882..d213959e4 100644 --- a/app/Jobs/DatabaseBackupJob.php +++ b/app/Jobs/DatabaseBackupJob.php @@ -60,6 +60,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue public function __construct($backup) { + $this->onQueue('high'); $this->backup = $backup; } @@ -197,8 +198,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue $databaseType = $this->database->type(); $databasesToBackup = data_get($this->backup, 'databases_to_backup'); } - - if (is_null($databasesToBackup)) { + if (blank($databasesToBackup)) { if (str($databaseType)->contains('postgres')) { $databasesToBackup = [$this->database->postgres_db]; } elseif (str($databaseType)->contains('mongodb')) { @@ -319,12 +319,10 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue 'filename' => null, ]); } - send_internal_notification('DatabaseBackupJob failed with: '.$e->getMessage()); $this->team?->notify(new BackupFailed($this->backup, $this->database, $this->backup_output, $database)); } } } catch (\Throwable $e) { - send_internal_notification('DatabaseBackupJob failed with: '.$e->getMessage()); throw $e; } finally { if ($this->team) { diff --git a/app/Jobs/DeleteResourceJob.php b/app/Jobs/DeleteResourceJob.php index 2442d5b06..8b9228e5f 100644 --- a/app/Jobs/DeleteResourceJob.php +++ b/app/Jobs/DeleteResourceJob.php @@ -35,7 +35,9 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue public bool $deleteVolumes = true, public bool $dockerCleanup = true, public bool $deleteConnectedNetworks = true - ) {} + ) { + $this->onQueue('high'); + } public function handle() { @@ -87,7 +89,6 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue $this->resource?->delete_connected_networks($this->resource->uuid); } } catch (\Throwable $e) { - send_internal_notification('ContainerStoppingJob failed with: '.$e->getMessage()); throw $e; } finally { $this->resource->forceDelete(); diff --git a/app/Jobs/PullHelperImageJob.php b/app/Jobs/PullHelperImageJob.php index cfc0c5a94..b92886d38 100644 --- a/app/Jobs/PullHelperImageJob.php +++ b/app/Jobs/PullHelperImageJob.php @@ -16,7 +16,10 @@ class PullHelperImageJob implements ShouldBeEncrypted, ShouldQueue public $timeout = 1000; - public function __construct(public Server $server) {} + public function __construct(public Server $server) + { + $this->onQueue('high'); + } public function handle(): void { diff --git a/app/Jobs/PullTemplatesFromCDN.php b/app/Jobs/PullTemplatesFromCDN.php index bde5e6c7a..45c536e06 100644 --- a/app/Jobs/PullTemplatesFromCDN.php +++ b/app/Jobs/PullTemplatesFromCDN.php @@ -17,7 +17,10 @@ class PullTemplatesFromCDN implements ShouldBeEncrypted, ShouldQueue public $timeout = 10; - public function __construct() {} + public function __construct() + { + $this->onQueue('high'); + } public function handle(): void { diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index 9822ca071..24f8d1e6b 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -360,7 +360,7 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue private function checkLogDrainContainer() { if ($this->server->isLogDrainEnabled() && $this->foundLogDrainContainer === false) { - StartLogDrain::dispatch($this->server)->onQueue('high'); + StartLogDrain::dispatch($this->server); } } } diff --git a/app/Jobs/ScheduledTaskJob.php b/app/Jobs/ScheduledTaskJob.php index 7bfc29af3..00575e187 100644 --- a/app/Jobs/ScheduledTaskJob.php +++ b/app/Jobs/ScheduledTaskJob.php @@ -40,6 +40,8 @@ class ScheduledTaskJob implements ShouldQueue public function __construct($task) { + $this->onQueue('high'); + $this->task = $task; if ($service = $task->service()->first()) { $this->resource = $service; diff --git a/app/Jobs/SendMessageToDiscordJob.php b/app/Jobs/SendMessageToDiscordJob.php index 5b406f50f..99aeaeea2 100644 --- a/app/Jobs/SendMessageToDiscordJob.php +++ b/app/Jobs/SendMessageToDiscordJob.php @@ -32,7 +32,9 @@ class SendMessageToDiscordJob implements ShouldBeEncrypted, ShouldQueue public function __construct( public DiscordMessage $message, public string $webhookUrl - ) {} + ) { + $this->onQueue('high'); + } /** * Execute the job. diff --git a/app/Jobs/SendMessageToTelegramJob.php b/app/Jobs/SendMessageToTelegramJob.php index bf52b782f..85f4fc934 100644 --- a/app/Jobs/SendMessageToTelegramJob.php +++ b/app/Jobs/SendMessageToTelegramJob.php @@ -33,7 +33,9 @@ class SendMessageToTelegramJob implements ShouldBeEncrypted, ShouldQueue public string $token, public string $chatId, public ?string $topicId = null, - ) {} + ) { + $this->onQueue('high'); + } /** * Execute the job. @@ -70,7 +72,7 @@ class SendMessageToTelegramJob implements ShouldBeEncrypted, ShouldQueue } $response = Http::post($url, $payload); if ($response->failed()) { - throw new \Exception('Telegram notification failed with '.$response->status().' status code.'.$response->body()); + throw new \RuntimeException('Telegram notification failed with '.$response->status().' status code.'.$response->body()); } } } diff --git a/app/Jobs/ServerCheckJob.php b/app/Jobs/ServerCheckJob.php index 0d5e2fd36..9818d5c6a 100644 --- a/app/Jobs/ServerCheckJob.php +++ b/app/Jobs/ServerCheckJob.php @@ -94,10 +94,10 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue if ($foundLogDrainContainer) { $status = data_get($foundLogDrainContainer, 'State.Status'); if ($status !== 'running') { - StartLogDrain::dispatch($this->server)->onQueue('high'); + StartLogDrain::dispatch($this->server); } } else { - StartLogDrain::dispatch($this->server)->onQueue('high'); + StartLogDrain::dispatch($this->server); } } } diff --git a/app/Jobs/ServerFilesFromServerJob.php b/app/Jobs/ServerFilesFromServerJob.php index 769dfc004..58455df2f 100644 --- a/app/Jobs/ServerFilesFromServerJob.php +++ b/app/Jobs/ServerFilesFromServerJob.php @@ -16,7 +16,10 @@ class ServerFilesFromServerJob implements ShouldBeEncrypted, ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - public function __construct(public ServiceApplication|ServiceDatabase|Application $resource) {} + public function __construct(public ServiceApplication|ServiceDatabase|Application $resource) + { + $this->onQueue('high'); + } public function handle() { diff --git a/app/Jobs/ServerStorageCheckJob.php b/app/Jobs/ServerStorageCheckJob.php index 0723ffcee..9a8d86be1 100644 --- a/app/Jobs/ServerStorageCheckJob.php +++ b/app/Jobs/ServerStorageCheckJob.php @@ -25,7 +25,7 @@ class ServerStorageCheckJob implements ShouldBeEncrypted, ShouldQueue return isDev() ? 1 : 3; } - public function __construct(public Server $server, public ?int $percentage = null) {} + public function __construct(public Server $server, public int|string|null $percentage = null) {} public function handle() { diff --git a/app/Jobs/ServerStorageSaveJob.php b/app/Jobs/ServerStorageSaveJob.php index 526cd5375..17a293f94 100644 --- a/app/Jobs/ServerStorageSaveJob.php +++ b/app/Jobs/ServerStorageSaveJob.php @@ -14,7 +14,10 @@ class ServerStorageSaveJob implements ShouldBeEncrypted, ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - public function __construct(public LocalFileVolume $localFileVolume) {} + public function __construct(public LocalFileVolume $localFileVolume) + { + $this->onQueue('high'); + } public function handle() { diff --git a/app/Jobs/StripeProcessJob.php b/app/Jobs/StripeProcessJob.php new file mode 100644 index 000000000..2a1a5313c --- /dev/null +++ b/app/Jobs/StripeProcessJob.php @@ -0,0 +1,242 @@ +onQueue('high'); + } + + public function handle(): void + { + $excludedPlans = config('subscription.stripe_excluded_plans'); + + $type = data_get($this->event, 'type'); + $this->type = $type; + $data = data_get($this->event, 'data.object'); + switch ($type) { + case 'radar.early_fraud_warning.created': + $stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key')); + $id = data_get($data, 'id'); + $charge = data_get($data, 'charge'); + if ($charge) { + $stripe->refunds->create(['charge' => $charge]); + } + $pi = data_get($data, 'payment_intent'); + $piData = $stripe->paymentIntents->retrieve($pi, []); + $customerId = data_get($piData, 'customer'); + $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); + if ($subscription) { + $subscriptionId = data_get($subscription, 'stripe_subscription_id'); + $stripe->subscriptions->cancel($subscriptionId, []); + $subscription->update([ + 'stripe_invoice_paid' => false, + ]); + send_internal_notification("Early fraud warning created Refunded, subscription canceled. Charge: {$charge}, id: {$id}, pi: {$pi}"); + } else { + send_internal_notification("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}"); + throw new \Exception("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}"); + } + break; + case 'checkout.session.completed': + $clientReferenceId = data_get($data, 'client_reference_id'); + if (is_null($clientReferenceId)) { + send_internal_notification('Checkout session completed without client reference id.'); + break; + } + $userId = Str::before($clientReferenceId, ':'); + $teamId = Str::after($clientReferenceId, ':'); + $subscriptionId = data_get($data, 'subscription'); + $customerId = data_get($data, 'customer'); + $team = Team::find($teamId); + $found = $team->members->where('id', $userId)->first(); + if (! $found->isAdmin()) { + send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}."); + throw new \Exception("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}."); + } + $subscription = Subscription::where('team_id', $teamId)->first(); + if ($subscription) { + send_internal_notification('Old subscription activated for team: '.$teamId); + $subscription->update([ + 'stripe_subscription_id' => $subscriptionId, + 'stripe_customer_id' => $customerId, + 'stripe_invoice_paid' => true, + ]); + } else { + send_internal_notification('New subscription for team: '.$teamId); + Subscription::create([ + 'team_id' => $teamId, + 'stripe_subscription_id' => $subscriptionId, + 'stripe_customer_id' => $customerId, + 'stripe_invoice_paid' => true, + ]); + } + break; + case 'invoice.paid': + $customerId = data_get($data, 'customer'); + $planId = data_get($data, 'lines.data.0.plan.id'); + if (Str::contains($excludedPlans, $planId)) { + send_internal_notification('Subscription excluded.'); + break; + } + $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); + if ($subscription) { + $subscription->update([ + 'stripe_invoice_paid' => true, + ]); + } else { + throw new \Exception("No subscription found for customer: {$customerId}"); + } + break; + case 'invoice.payment_failed': + $customerId = data_get($data, 'customer'); + $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); + if (! $subscription) { + send_internal_notification('invoice.payment_failed failed but no subscription found in Coolify for customer: '.$customerId); + throw new \Exception("No subscription found for customer: {$customerId}"); + } + $team = data_get($subscription, 'team'); + if (! $team) { + send_internal_notification('invoice.payment_failed failed but no team found in Coolify for customer: '.$customerId); + throw new \Exception("No team found in Coolify for customer: {$customerId}"); + } + if (! $subscription->stripe_invoice_paid) { + SubscriptionInvoiceFailedJob::dispatch($team); + send_internal_notification('Invoice payment failed: '.$customerId); + } else { + send_internal_notification('Invoice payment failed but already paid: '.$customerId); + } + break; + case 'payment_intent.payment_failed': + $customerId = data_get($data, 'customer'); + $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); + if (! $subscription) { + send_internal_notification('payment_intent.payment_failed, no subscription found in Coolify for customer: '.$customerId); + throw new \Exception("No subscription found in Coolify for customer: {$customerId}"); + } + if ($subscription->stripe_invoice_paid) { + send_internal_notification('payment_intent.payment_failed but invoice is active for customer: '.$customerId); + + return; + } + send_internal_notification('Subscription payment failed for customer: '.$customerId); + break; + case 'customer.subscription.created': + $customerId = data_get($data, 'customer'); + $subscriptionId = data_get($data, 'id'); + $teamId = data_get($data, 'metadata.team_id'); + $userId = data_get($data, 'metadata.user_id'); + if (! $teamId || ! $userId) { + $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); + if ($subscription) { + throw new \Exception("Subscription already exists for customer: {$customerId}"); + } + throw new \Exception('No team id or user id found'); + } + $team = Team::find($teamId); + $found = $team->members->where('id', $userId)->first(); + if (! $found->isAdmin()) { + send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}."); + throw new \Exception("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}."); + } + $subscription = Subscription::where('team_id', $teamId)->first(); + if ($subscription) { + send_internal_notification("Subscription already exists for team: {$teamId}"); + throw new \Exception("Subscription already exists for team: {$teamId}"); + } else { + Subscription::create([ + 'team_id' => $teamId, + 'stripe_subscription_id' => $subscriptionId, + 'stripe_customer_id' => $customerId, + 'stripe_invoice_paid' => false, + ]); + } + case 'customer.subscription.updated': + $teamId = data_get($data, 'metadata.team_id'); + $userId = data_get($data, 'metadata.user_id'); + $customerId = data_get($data, 'customer'); + $status = data_get($data, 'status'); + $subscriptionId = data_get($data, 'items.data.0.subscription'); + $planId = data_get($data, 'items.data.0.plan.id'); + if (Str::contains($excludedPlans, $planId)) { + send_internal_notification('Subscription excluded.'); + break; + } + $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); + if (! $subscription) { + if ($status === 'incomplete_expired') { + send_internal_notification('Subscription incomplete expired'); + throw new \Exception('Subscription incomplete expired'); + } + if ($teamId) { + $subscription = Subscription::create([ + 'team_id' => $teamId, + 'stripe_subscription_id' => $subscriptionId, + 'stripe_customer_id' => $customerId, + 'stripe_invoice_paid' => false, + ]); + } else { + send_internal_notification('No subscription and team id found'); + throw new \Exception('No subscription and team id found'); + } + } + $cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end'); + $feedback = data_get($data, 'cancellation_details.feedback'); + $comment = data_get($data, 'cancellation_details.comment'); + $lookup_key = data_get($data, 'items.data.0.price.lookup_key'); + if (str($lookup_key)->contains('dynamic')) { + $quantity = data_get($data, 'items.data.0.quantity', 2); + $team = data_get($subscription, 'team'); + if ($team) { + $team->update([ + 'custom_server_limit' => $quantity, + ]); + } + ServerLimitCheckJob::dispatch($team); + } + $subscription->update([ + 'stripe_feedback' => $feedback, + 'stripe_comment' => $comment, + 'stripe_plan_id' => $planId, + 'stripe_cancel_at_period_end' => $cancelAtPeriodEnd, + ]); + if ($status === 'paused' || $status === 'incomplete_expired') { + $subscription->update([ + 'stripe_invoice_paid' => false, + ]); + } + if ($feedback) { + $reason = "Cancellation feedback for {$customerId}: '".$feedback."'"; + if ($comment) { + $reason .= ' with comment: \''.$comment."'"; + } + } + break; + case 'customer.subscription.deleted': + // End subscription + $customerId = data_get($data, 'customer'); + $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); + $team = data_get($subscription, 'team'); + $team?->subscriptionEnded(); + break; + default: + // Unhandled event type + } + } +} diff --git a/app/Jobs/SubscriptionInvoiceFailedJob.php b/app/Jobs/SubscriptionInvoiceFailedJob.php index aabeecef5..dc511f445 100755 --- a/app/Jobs/SubscriptionInvoiceFailedJob.php +++ b/app/Jobs/SubscriptionInvoiceFailedJob.php @@ -15,7 +15,10 @@ class SubscriptionInvoiceFailedJob implements ShouldBeEncrypted, ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - public function __construct(protected Team $team) {} + public function __construct(protected Team $team) + { + $this->onQueue('high'); + } public function handle() { diff --git a/app/Jobs/UpdateCoolifyJob.php b/app/Jobs/UpdateCoolifyJob.php index 1e5197b6f..f0e43cbc0 100644 --- a/app/Jobs/UpdateCoolifyJob.php +++ b/app/Jobs/UpdateCoolifyJob.php @@ -18,6 +18,11 @@ class UpdateCoolifyJob implements ShouldBeEncrypted, ShouldQueue public $timeout = 600; + public function __construct() + { + $this->onQueue('high'); + } + public function handle(): void { try { diff --git a/app/Livewire/NavbarDeleteTeam.php b/app/Livewire/NavbarDeleteTeam.php index cc5d78f60..e97cceb0d 100644 --- a/app/Livewire/NavbarDeleteTeam.php +++ b/app/Livewire/NavbarDeleteTeam.php @@ -3,7 +3,6 @@ namespace App\Livewire; use App\Models\InstanceSettings; -use Illuminate\Container\Attributes\Auth as AttributesAuth; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash; @@ -32,7 +31,7 @@ class NavbarDeleteTeam extends Component $currentTeam->delete(); $currentTeam->members->each(function ($user) use ($currentTeam) { - if ($user->id === AttributesAuth::id()) { + if ($user->id === Auth::id()) { return; } $user->teams()->detach($currentTeam); diff --git a/app/Livewire/Notifications/Email.php b/app/Livewire/Notifications/Email.php index 56f07f3a9..fcedf1305 100644 --- a/app/Livewire/Notifications/Email.php +++ b/app/Livewire/Notifications/Email.php @@ -73,6 +73,9 @@ class Email extends Component #[Validate(['nullable', 'string'])] public ?string $resendApiKey = null; + #[Validate(['required', 'email'])] + public string $testEmailAddress = ''; + public function mount() { try { @@ -132,14 +135,21 @@ class Email extends Component } } - public function sendTestNotification() + public function sendTestEmail() { try { + $this->validate([ + 'testEmailAddress' => 'required|email', + ], [ + 'testEmailAddress.required' => 'Test email address is required.', + 'testEmailAddress.email' => 'Please enter a valid email address.', + ]); + $executed = RateLimiter::attempt( 'test-email:'.$this->team->id, $perMinute = 0, function () { - $this->team?->notify(new Test($this->emails)); + $this->team?->notify(new Test($this->testEmailAddress)); $this->dispatch('success', 'Test Email sent.'); }, $decaySeconds = 10, diff --git a/app/Livewire/Project/Application/Heading.php b/app/Livewire/Project/Application/Heading.php index 1082b48cd..19a6145b7 100644 --- a/app/Livewire/Project/Application/Heading.php +++ b/app/Livewire/Project/Application/Heading.php @@ -36,7 +36,11 @@ class Heading extends Component public function mount() { - $this->parameters = get_route_parameters(); + $this->parameters = [ + 'project_uuid' => $this->application->project()->uuid, + 'environment_name' => $this->application->environment->name, + 'application_uuid' => $this->application->uuid, + ]; $lastDeployment = $this->application->get_last_successful_deployment(); $this->lastDeploymentInfo = data_get_str($lastDeployment, 'commit')->limit(7).' '.data_get($lastDeployment, 'commit_message'); $this->lastDeploymentLink = $this->application->gitCommitLink(data_get($lastDeployment, 'commit')); @@ -45,13 +49,11 @@ class Heading extends Component public function check_status($showNotification = false) { if ($this->application->destination->server->isFunctional()) { - GetContainersStatus::dispatch($this->application->destination->server)->onQueue('high'); + GetContainersStatus::dispatch($this->application->destination->server); } if ($showNotification) { $this->dispatch('success', 'Success', 'Application status updated.'); } - // Removed because it caused flickering - // $this->dispatch('configurationChanged'); } public function force_deploy_without_cache() diff --git a/app/Livewire/Project/Database/CreateScheduledBackup.php b/app/Livewire/Project/Database/CreateScheduledBackup.php index 0903efdfd..01108c290 100644 --- a/app/Livewire/Project/Database/CreateScheduledBackup.php +++ b/app/Livewire/Project/Database/CreateScheduledBackup.php @@ -21,8 +21,8 @@ class CreateScheduledBackup extends Component public bool $enabled = true; - #[Validate(['required', 'integer'])] - public int $s3StorageId; + #[Validate(['nullable', 'integer'])] + public ?int $s3StorageId = null; public Collection $definedS3s; @@ -49,6 +49,7 @@ class CreateScheduledBackup extends Component return; } + $payload = [ 'enabled' => true, 'frequency' => $this->frequency, @@ -58,6 +59,7 @@ class CreateScheduledBackup extends Component 'database_type' => $this->database->getMorphClass(), 'team_id' => currentTeam()->id, ]; + if ($this->database->type() === 'standalone-postgresql') { $payload['databases_to_backup'] = $this->database->postgres_db; } elseif ($this->database->type() === 'standalone-mysql') { @@ -72,11 +74,11 @@ class CreateScheduledBackup extends Component } else { $this->dispatch('refreshScheduledBackups'); } + } catch (\Throwable $e) { return handleError($e, $this); } finally { $this->frequency = ''; - $this->saveToS3 = true; } } } diff --git a/app/Livewire/Project/New/Select.php b/app/Livewire/Project/New/Select.php index 2dc9abbf1..3dedc11af 100644 --- a/app/Livewire/Project/New/Select.php +++ b/app/Livewire/Project/New/Select.php @@ -91,9 +91,12 @@ class Select extends Component { $services = get_service_templates(true); $services = collect($services)->map(function ($service, $key) { + $logo = data_get($service, 'logo', 'svgs/coolify.png'); + return [ 'name' => str($key)->headline(), - 'logo' => asset(data_get($service, 'logo', 'svgs/coolify.png')), + 'logo' => asset($logo), + 'logo_github_url' => 'https://raw.githubusercontent.com/coollabsio/coolify/refs/heads/main/public/a'.$logo, ] + (array) $service; })->all(); $gitBasedApplications = [ diff --git a/app/Livewire/Project/Shared/Tags.php b/app/Livewire/Project/Shared/Tags.php index dca6180ff..811859cb8 100644 --- a/app/Livewire/Project/Shared/Tags.php +++ b/app/Livewire/Project/Shared/Tags.php @@ -37,6 +37,7 @@ class Tags extends Component $this->validate(); $tags = str($this->newTags)->trim()->explode(' '); foreach ($tags as $tag) { + $tag = strip_tags($tag); if (strlen($tag) < 2) { $this->dispatch('error', 'Invalid tag.', "Tag $tag is invalid. Min length is 2."); @@ -65,6 +66,7 @@ class Tags extends Component public function addTag(string $id, string $name) { try { + $name = strip_tags($name); if ($this->resource->tags()->where('id', $id)->exists()) { $this->dispatch('error', 'Duplicate tags.', "Tag $name already added."); diff --git a/app/Livewire/Server/New/ByIp.php b/app/Livewire/Server/New/ByIp.php index f80152435..5f60c5db5 100644 --- a/app/Livewire/Server/New/ByIp.php +++ b/app/Livewire/Server/New/ByIp.php @@ -6,64 +6,60 @@ use App\Enums\ProxyTypes; use App\Models\Server; use App\Models\Team; use Illuminate\Support\Collection; +use Livewire\Attributes\Locked; +use Livewire\Attributes\Validate; use Livewire\Component; class ByIp extends Component { + #[Locked] public $private_keys; + #[Locked] public $limit_reached; + #[Validate('nullable|integer', as: 'Private Key')] public ?int $private_key_id = null; + #[Validate('nullable|string', as: 'Private Key Name')] public $new_private_key_name; + #[Validate('nullable|string', as: 'Private Key Description')] public $new_private_key_description; + #[Validate('nullable|string', as: 'Private Key Value')] public $new_private_key_value; + #[Validate('required|string', as: 'Name')] public string $name; + #[Validate('nullable|string', as: 'Description')] public ?string $description = null; + #[Validate('required|string', as: 'IP Address/Domain')] public string $ip; + #[Validate('required|string', as: 'User')] public string $user = 'root'; + #[Validate('required|integer|between:1,65535', as: 'Port')] public int $port = 22; + #[Validate('required|boolean', as: 'Swarm Manager')] public bool $is_swarm_manager = false; + #[Validate('required|boolean', as: 'Swarm Worker')] public bool $is_swarm_worker = false; + #[Validate('nullable|integer', as: 'Swarm Cluster')] public $selected_swarm_cluster = null; + #[Validate('required|boolean', as: 'Build Server')] public bool $is_build_server = false; + #[Locked] public Collection $swarm_managers; - protected $rules = [ - 'name' => 'required|string', - 'description' => 'nullable|string', - 'ip' => 'required', - 'user' => 'required|string', - 'port' => 'required|integer', - 'is_swarm_manager' => 'required|boolean', - 'is_swarm_worker' => 'required|boolean', - 'is_build_server' => 'required|boolean', - ]; - - protected $validationAttributes = [ - 'name' => 'Name', - 'description' => 'Description', - 'ip' => 'IP Address/Domain', - 'user' => 'User', - 'port' => 'Port', - 'is_swarm_manager' => 'Swarm Manager', - 'is_swarm_worker' => 'Swarm Worker', - 'is_build_server' => 'Build Server', - ]; - public function mount() { $this->name = generate_random_name(); @@ -88,6 +84,12 @@ class ByIp extends Component { $this->validate(); try { + if (Server::where('team_id', currentTeam()->id) + ->where('ip', $this->ip) + ->exists()) { + return $this->dispatch('error', 'This IP/Domain is already in use by another server in your team.'); + } + if (is_null($this->private_key_id)) { return $this->dispatch('error', 'You must select a private key'); } diff --git a/app/Livewire/Server/Show.php b/app/Livewire/Server/Show.php index 5a1743f96..a5544489d 100644 --- a/app/Livewire/Server/Show.php +++ b/app/Livewire/Server/Show.php @@ -107,6 +107,15 @@ class Show extends Component { if ($toModel) { $this->validate(); + + if (Server::where('team_id', currentTeam()->id) + ->where('ip', $this->ip) + ->where('id', '!=', $this->server->id) + ->exists()) { + $this->ip = $this->server->ip; + throw new \Exception('This IP/Domain is already in use by another server in your team.'); + } + $this->server->name = $this->name; $this->server->description = $this->description; $this->server->ip = $this->ip; diff --git a/app/Models/PrivateKey.php b/app/Models/PrivateKey.php index 065746ede..80015d87f 100644 --- a/app/Models/PrivateKey.php +++ b/app/Models/PrivateKey.php @@ -218,10 +218,12 @@ class PrivateKey extends BaseModel private static function fingerprintExists($fingerprint, $excludeId = null) { - $query = self::where('fingerprint', $fingerprint); + $query = self::query() + ->where('fingerprint', $fingerprint) + ->where('id', '!=', $excludeId); - if (! is_null($excludeId)) { - $query->where('id', '!=', $excludeId); + if (currentTeam()) { + $query->where('team_id', currentTeam()->id); } return $query->exists(); diff --git a/app/Models/Server.php b/app/Models/Server.php index 3df156a78..e6e2ffbe1 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -988,7 +988,7 @@ $schema://$host { public function status(): bool { - ['uptime' => $uptime] = $this->validateConnection(false); + ['uptime' => $uptime] = $this->validateConnection(); if ($uptime === false) { foreach ($this->applications() as $application) { $application->status = 'exited'; @@ -1051,18 +1051,14 @@ $schema://$host { $this->team->notify(new Unreachable($this)); } - public function validateConnection(bool $isManualCheck = true, bool $justCheckingNewKey = false) + public function validateConnection(bool $justCheckingNewKey = false) { - config()->set('constants.ssh.mux_enabled', ! $isManualCheck); + config()->set('constants.ssh.mux_enabled', false); if ($this->skipServer()) { return ['uptime' => false, 'error' => 'Server skipped.']; } try { - // Make sure the private key is stored - if ($this->privateKey) { - $this->privateKey->storeInFileSystem(); - } instant_remote_process(['ls /'], $this); if ($this->settings->is_reachable === false) { $this->settings->is_reachable = true; diff --git a/app/Notifications/Application/DeploymentFailed.php b/app/Notifications/Application/DeploymentFailed.php index dc6b93aad..12bcce626 100644 --- a/app/Notifications/Application/DeploymentFailed.php +++ b/app/Notifications/Application/DeploymentFailed.php @@ -35,6 +35,7 @@ class DeploymentFailed extends Notification implements ShouldQueue public function __construct(Application $application, string $deployment_uuid, ?ApplicationPreview $preview = null) { + $this->onQueue('high'); $this->application = $application; $this->deployment_uuid = $deployment_uuid; $this->preview = $preview; diff --git a/app/Notifications/Application/DeploymentSuccess.php b/app/Notifications/Application/DeploymentSuccess.php index e11d6db1c..29934dab1 100644 --- a/app/Notifications/Application/DeploymentSuccess.php +++ b/app/Notifications/Application/DeploymentSuccess.php @@ -34,6 +34,7 @@ class DeploymentSuccess extends Notification implements ShouldQueue public function __construct(Application $application, string $deployment_uuid, ?ApplicationPreview $preview = null) { + $this->onQueue('high'); $this->application = $application; $this->deployment_uuid = $deployment_uuid; $this->preview = $preview; diff --git a/app/Notifications/Application/StatusChanged.php b/app/Notifications/Application/StatusChanged.php index c7445cb70..1f57aeeda 100644 --- a/app/Notifications/Application/StatusChanged.php +++ b/app/Notifications/Application/StatusChanged.php @@ -27,6 +27,7 @@ class StatusChanged extends Notification implements ShouldQueue public function __construct(public Application $resource) { + $this->onQueue('high'); $this->resource_name = data_get($resource, 'name'); $this->project_uuid = data_get($resource, 'environment.project.uuid'); $this->environment_name = data_get($resource, 'environment.name'); diff --git a/app/Notifications/Channels/DiscordChannel.php b/app/Notifications/Channels/DiscordChannel.php index 86276fec9..df7040f8f 100644 --- a/app/Notifications/Channels/DiscordChannel.php +++ b/app/Notifications/Channels/DiscordChannel.php @@ -17,6 +17,6 @@ class DiscordChannel if (! $webhookUrl) { return; } - dispatch(new SendMessageToDiscordJob($message, $webhookUrl))->onQueue('high'); + SendMessageToDiscordJob::dispatch($message, $webhookUrl); } } diff --git a/app/Notifications/Channels/TelegramChannel.php b/app/Notifications/Channels/TelegramChannel.php index b3d4e384b..958c46c21 100644 --- a/app/Notifications/Channels/TelegramChannel.php +++ b/app/Notifications/Channels/TelegramChannel.php @@ -41,6 +41,6 @@ class TelegramChannel if (! $telegramToken || ! $chatId || ! $message) { return; } - dispatch(new SendMessageToTelegramJob($message, $buttons, $telegramToken, $chatId, $topicId))->onQueue('high'); + SendMessageToTelegramJob::dispatch($message, $buttons, $telegramToken, $chatId, $topicId); } } diff --git a/app/Notifications/Container/ContainerRestarted.php b/app/Notifications/Container/ContainerRestarted.php index 40bd9b7ee..d1642bc5d 100644 --- a/app/Notifications/Container/ContainerRestarted.php +++ b/app/Notifications/Container/ContainerRestarted.php @@ -17,6 +17,7 @@ class ContainerRestarted extends Notification implements ShouldQueue public function __construct(public string $name, public Server $server, public ?string $url = null) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/Container/ContainerStopped.php b/app/Notifications/Container/ContainerStopped.php index 9b3824624..a5d812bf1 100644 --- a/app/Notifications/Container/ContainerStopped.php +++ b/app/Notifications/Container/ContainerStopped.php @@ -17,6 +17,7 @@ class ContainerStopped extends Notification implements ShouldQueue public function __construct(public string $name, public Server $server, public ?string $url = null) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/Database/BackupFailed.php b/app/Notifications/Database/BackupFailed.php index 137a6d730..22e5cea25 100644 --- a/app/Notifications/Database/BackupFailed.php +++ b/app/Notifications/Database/BackupFailed.php @@ -23,6 +23,7 @@ class BackupFailed extends Notification implements ShouldQueue public function __construct(ScheduledDatabaseBackup $backup, public $database, public $output, public $database_name) { + $this->onQueue('high'); $this->name = $database->name; $this->frequency = $backup->frequency; } diff --git a/app/Notifications/Database/BackupSuccess.php b/app/Notifications/Database/BackupSuccess.php index 76ddc9221..6f7b32b42 100644 --- a/app/Notifications/Database/BackupSuccess.php +++ b/app/Notifications/Database/BackupSuccess.php @@ -23,6 +23,7 @@ class BackupSuccess extends Notification implements ShouldQueue public function __construct(ScheduledDatabaseBackup $backup, public $database, public $database_name) { + $this->onQueue('high'); $this->name = $database->name; $this->frequency = $backup->frequency; } diff --git a/app/Notifications/Internal/GeneralNotification.php b/app/Notifications/Internal/GeneralNotification.php index 4dd925159..699291d16 100644 --- a/app/Notifications/Internal/GeneralNotification.php +++ b/app/Notifications/Internal/GeneralNotification.php @@ -19,6 +19,7 @@ class GeneralNotification extends Notification implements ShouldQueue public function __construct(public string $message) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/ScheduledTask/TaskFailed.php b/app/Notifications/ScheduledTask/TaskFailed.php index 99d83fdf6..67f77ff71 100644 --- a/app/Notifications/ScheduledTask/TaskFailed.php +++ b/app/Notifications/ScheduledTask/TaskFailed.php @@ -21,6 +21,7 @@ class TaskFailed extends Notification implements ShouldQueue public function __construct(public ScheduledTask $task, public string $output) { + $this->onQueue('high'); if ($task->application) { $this->url = $task->application->failedTaskLink($task->uuid); } elseif ($task->service) { diff --git a/app/Notifications/Server/DockerCleanup.php b/app/Notifications/Server/DockerCleanup.php index eb4498835..979672cfd 100644 --- a/app/Notifications/Server/DockerCleanup.php +++ b/app/Notifications/Server/DockerCleanup.php @@ -19,6 +19,7 @@ class DockerCleanup extends Notification implements ShouldQueue public function __construct(public Server $server, public string $message) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/Server/ForceDisabled.php b/app/Notifications/Server/ForceDisabled.php index 969f60d79..053ea6e7f 100644 --- a/app/Notifications/Server/ForceDisabled.php +++ b/app/Notifications/Server/ForceDisabled.php @@ -22,6 +22,7 @@ class ForceDisabled extends Notification implements ShouldQueue public function __construct(public Server $server) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/Server/ForceEnabled.php b/app/Notifications/Server/ForceEnabled.php index e24136c81..1c7086dfd 100644 --- a/app/Notifications/Server/ForceEnabled.php +++ b/app/Notifications/Server/ForceEnabled.php @@ -22,6 +22,7 @@ class ForceEnabled extends Notification implements ShouldQueue public function __construct(public Server $server) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/Server/HighDiskUsage.php b/app/Notifications/Server/HighDiskUsage.php index a780d9d15..6c38b8418 100644 --- a/app/Notifications/Server/HighDiskUsage.php +++ b/app/Notifications/Server/HighDiskUsage.php @@ -18,6 +18,7 @@ class HighDiskUsage extends Notification implements ShouldQueue public function __construct(public Server $server, public int $disk_usage, public int $server_disk_usage_notification_threshold) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/Server/Reachable.php b/app/Notifications/Server/Reachable.php index 6ca4170f5..3e49fea8d 100644 --- a/app/Notifications/Server/Reachable.php +++ b/app/Notifications/Server/Reachable.php @@ -24,6 +24,7 @@ class Reachable extends Notification implements ShouldQueue public function __construct(public Server $server) { + $this->onQueue('high'); $this->isRateLimited = isEmailRateLimited( limiterKey: 'server-reachable:' . $this->server->id, ); diff --git a/app/Notifications/Server/Unreachable.php b/app/Notifications/Server/Unreachable.php index cdb18b1bd..e0f58787d 100644 --- a/app/Notifications/Server/Unreachable.php +++ b/app/Notifications/Server/Unreachable.php @@ -24,6 +24,7 @@ class Unreachable extends Notification implements ShouldQueue public function __construct(public Server $server) { + $this->onQueue('high'); $this->isRateLimited = isEmailRateLimited( limiterKey: 'server-unreachable:' . $this->server->id, ); diff --git a/app/Notifications/Test.php b/app/Notifications/Test.php index 6aae641c4..ce998d9f6 100644 --- a/app/Notifications/Test.php +++ b/app/Notifications/Test.php @@ -18,6 +18,7 @@ class Test extends Notification implements ShouldQueue public function __construct(public ?string $emails = null) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/TransactionalEmails/InvitationLink.php b/app/Notifications/TransactionalEmails/InvitationLink.php index 6da2a6fcc..eef7ba0e5 100644 --- a/app/Notifications/TransactionalEmails/InvitationLink.php +++ b/app/Notifications/TransactionalEmails/InvitationLink.php @@ -22,7 +22,10 @@ class InvitationLink extends Notification implements ShouldQueue return [TransactionalEmailChannel::class]; } - public function __construct(public User $user) {} + public function __construct(public User $user) + { + $this->onQueue('high'); + } public function toMail(): MailMessage { diff --git a/app/Notifications/TransactionalEmails/Test.php b/app/Notifications/TransactionalEmails/Test.php index 64883a58e..b3cc79604 100644 --- a/app/Notifications/TransactionalEmails/Test.php +++ b/app/Notifications/TransactionalEmails/Test.php @@ -14,7 +14,10 @@ class Test extends Notification implements ShouldQueue public $tries = 5; - public function __construct(public string $emails) {} + public function __construct(public string $emails) + { + $this->onQueue('high'); + } public function via(): array { diff --git a/app/View/Components/Forms/Checkbox.php b/app/View/Components/Forms/Checkbox.php index 414dbf2ae..0bdebe7e4 100644 --- a/app/View/Components/Forms/Checkbox.php +++ b/app/View/Components/Forms/Checkbox.php @@ -17,11 +17,14 @@ class Checkbox extends Component public ?string $value = null, public ?string $label = null, public ?string $helper = null, + public string|bool|null $checked = false, public string|bool $instantSave = false, public bool $disabled = false, public string $defaultClass = 'dark:border-neutral-700 text-coolgray-400 focus:ring-warning dark:bg-coolgray-100 rounded cursor-pointer dark:disabled:bg-base dark:disabled:cursor-not-allowed', ) { - // + if ($this->disabled) { + $this->defaultClass .= ' opacity-40'; + } } /** diff --git a/bootstrap/helpers/applications.php b/bootstrap/helpers/applications.php index eb331f8c2..73d5389ae 100644 --- a/bootstrap/helpers/applications.php +++ b/bootstrap/helpers/applications.php @@ -44,13 +44,13 @@ function queue_application_deployment(Application $application, string $deployme ]); if ($no_questions_asked) { - dispatch(new ApplicationDeploymentJob( + ApplicationDeploymentJob::dispatch( application_deployment_queue_id: $deployment->id, - ))->onQueue('high'); + ); } elseif (next_queuable($server_id, $application_id)) { - dispatch(new ApplicationDeploymentJob( + ApplicationDeploymentJob::dispatch( application_deployment_queue_id: $deployment->id, - ))->onQueue('high'); + ); } } function force_start_deployment(ApplicationDeploymentQueue $deployment) @@ -59,9 +59,9 @@ function force_start_deployment(ApplicationDeploymentQueue $deployment) 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value, ]); - dispatch(new ApplicationDeploymentJob( + ApplicationDeploymentJob::dispatch( application_deployment_queue_id: $deployment->id, - ))->onQueue('high'); + ); } function queue_next_deployment(Application $application) { @@ -72,9 +72,9 @@ function queue_next_deployment(Application $application) 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value, ]); - dispatch(new ApplicationDeploymentJob( + ApplicationDeploymentJob::dispatch( application_deployment_queue_id: $next_found->id, - ))->onQueue('high'); + ); } } @@ -113,9 +113,9 @@ function next_after_cancel(?Server $server = null) 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value, ]); - dispatch(new ApplicationDeploymentJob( + ApplicationDeploymentJob::dispatch( application_deployment_queue_id: $next->id, - ))->onQueue('high'); + ); } break; } diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php index 302193131..da99c5cbd 100644 --- a/bootstrap/helpers/docker.php +++ b/bootstrap/helpers/docker.php @@ -227,13 +227,17 @@ function generateServiceSpecificFqdns(ServiceApplication|Application $resource) $MINIO_BROWSER_REDIRECT_URL = $variables->where('key', 'MINIO_BROWSER_REDIRECT_URL')->first(); $MINIO_SERVER_URL = $variables->where('key', 'MINIO_SERVER_URL')->first(); - if (str($MINIO_BROWSER_REDIRECT_URL->value)->isEmpty()) { - $MINIO_BROWSER_REDIRECT_URL?->update([ + if (is_null($MINIO_BROWSER_REDIRECT_URL) || is_null($MINIO_SERVER_URL)) { + return collect([]); + } + + if (str($MINIO_BROWSER_REDIRECT_URL->value ?? '')->isEmpty()) { + $MINIO_BROWSER_REDIRECT_URL->update([ 'value' => generateFqdn($server, 'console-'.$uuid, true), ]); } - if (str($MINIO_SERVER_URL->value)->isEmpty()) { - $MINIO_SERVER_URL?->update([ + if (str($MINIO_SERVER_URL->value ?? '')->isEmpty()) { + $MINIO_SERVER_URL->update([ 'value' => generateFqdn($server, 'minio-'.$uuid, true), ]); } @@ -246,13 +250,17 @@ function generateServiceSpecificFqdns(ServiceApplication|Application $resource) $LOGTO_ENDPOINT = $variables->where('key', 'LOGTO_ENDPOINT')->first(); $LOGTO_ADMIN_ENDPOINT = $variables->where('key', 'LOGTO_ADMIN_ENDPOINT')->first(); - if (str($LOGTO_ENDPOINT?->value)->isEmpty()) { - $LOGTO_ENDPOINT?->update([ + if (is_null($LOGTO_ENDPOINT) || is_null($LOGTO_ADMIN_ENDPOINT)) { + return collect([]); + } + + if (str($LOGTO_ENDPOINT->value ?? '')->isEmpty()) { + $LOGTO_ENDPOINT->update([ 'value' => generateFqdn($server, 'logto-'.$uuid), ]); } - if (str($LOGTO_ADMIN_ENDPOINT?->value)->isEmpty()) { - $LOGTO_ADMIN_ENDPOINT?->update([ + if (str($LOGTO_ADMIN_ENDPOINT->value ?? '')->isEmpty()) { + $LOGTO_ADMIN_ENDPOINT->update([ 'value' => generateFqdn($server, 'logto-admin-'.$uuid), ]); } diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 7602d3066..7fb9b6e08 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -4081,7 +4081,7 @@ function defaultNginxConfiguration(): string location / { root /usr/share/nginx/html; index index.html index.htm; - try_files $uri $uri/index.html =404; + try_files $uri $uri.html $uri/index.html $uri/index.htm $uri/ /index.html /index.htm =404; } error_page 500 502 503 504 /50x.html; diff --git a/composer.json b/composer.json index 9e34e8b23..694bad882 100644 --- a/composer.json +++ b/composer.json @@ -42,6 +42,7 @@ "socialiteproviders/microsoft-azure": "^5.1", "spatie/laravel-activitylog": "^4.7.3", "spatie/laravel-data": "^4.11", + "spatie/laravel-ray": "^1.37", "spatie/laravel-schemaless-attributes": "^2.4", "spatie/url": "^2.2", "stripe/stripe-php": "^16.2.0", @@ -63,7 +64,6 @@ "phpunit/phpunit": "^11.4", "serversideup/spin": "^2.3", "spatie/laravel-ignition": "^2.1.0", - "spatie/laravel-ray": "^1.37", "symfony/http-client": "^7.1" }, "minimum-stability": "stable", diff --git a/composer.lock b/composer.lock index 63d070405..8ea0d9a5a 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": "c19f791a42f2d1458409e399ff7d28ec", + "content-hash": "f50de759f43a3eefb58ce9ebbb02d33b", "packages": [ { "name": "3sidedcube/laravel-redoc", @@ -979,16 +979,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.325.7", + "version": "3.327.1", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "55852104253172e66c3358bf4c35281bbd8622b2" + "reference": "3d52ec587989b136e486f94eff3dd316465aeb42" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/55852104253172e66c3358bf4c35281bbd8622b2", - "reference": "55852104253172e66c3358bf4c35281bbd8622b2", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3d52ec587989b136e486f94eff3dd316465aeb42", + "reference": "3d52ec587989b136e486f94eff3dd316465aeb42", "shasum": "" }, "require": { @@ -1071,9 +1071,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.325.7" + "source": "https://github.com/aws/aws-sdk-php/tree/3.327.1" }, - "time": "2024-11-12T19:27:31+00:00" + "time": "2024-11-15T01:53:30+00:00" }, { "name": "bacon/bacon-qr-code", @@ -5473,6 +5473,134 @@ }, "time": "2024-09-04T12:51:01+00:00" }, + { + "name": "php-di/invoker", + "version": "2.3.4", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/Invoker.git", + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/33234b32dafa8eb69202f950a1fc92055ed76a86", + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "psr/container": "^1.0|^2.0" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Invoker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Generic and extensible callable invoker", + "homepage": "https://github.com/PHP-DI/Invoker", + "keywords": [ + "callable", + "dependency", + "dependency-injection", + "injection", + "invoke", + "invoker" + ], + "support": { + "issues": "https://github.com/PHP-DI/Invoker/issues", + "source": "https://github.com/PHP-DI/Invoker/tree/2.3.4" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + } + ], + "time": "2023-09-08T09:24:21+00:00" + }, + { + "name": "php-di/php-di", + "version": "7.0.7", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PHP-DI.git", + "reference": "e87435e3c0e8f22977adc5af0d5cdcc467e15cf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/e87435e3c0e8f22977adc5af0d5cdcc467e15cf1", + "reference": "e87435e3c0e8f22977adc5af0d5cdcc467e15cf1", + "shasum": "" + }, + "require": { + "laravel/serializable-closure": "^1.0", + "php": ">=8.0", + "php-di/invoker": "^2.0", + "psr/container": "^1.1 || ^2.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3", + "friendsofphp/proxy-manager-lts": "^1", + "mnapoli/phpunit-easymock": "^1.3", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^4.6" + }, + "suggest": { + "friendsofphp/proxy-manager-lts": "Install it if you want to use lazy injection (version ^1)" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "DI\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The dependency injection container for humans", + "homepage": "https://php-di.org/", + "keywords": [ + "PSR-11", + "container", + "container-interop", + "dependency injection", + "di", + "ioc", + "psr11" + ], + "support": { + "issues": "https://github.com/PHP-DI/PHP-DI/issues", + "source": "https://github.com/PHP-DI/PHP-DI/tree/7.0.7" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", + "type": "tidelift" + } + ], + "time": "2024-07-21T15:55:45+00:00" + }, { "name": "phpdocumentor/reflection", "version": "6.0.0", @@ -5947,6 +6075,64 @@ }, "time": "2024-10-13T11:29:49+00:00" }, + { + "name": "phpstan/phpstan", + "version": "1.12.10", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "fc463b5d0fe906dcf19689be692c65c50406a071" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fc463b5d0fe906dcf19689be692c65c50406a071", + "reference": "fc463b5d0fe906dcf19689be692c65c50406a071", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2024-11-11T15:37:09+00:00" + }, { "name": "pion/laravel-chunk-upload", "version": "v1.5.4", @@ -6983,6 +7169,65 @@ ], "time": "2024-04-27T21:32:50+00:00" }, + { + "name": "rector/rector", + "version": "1.2.10", + "source": { + "type": "git", + "url": "https://github.com/rectorphp/rector.git", + "reference": "40f9cf38c05296bd32f444121336a521a293fa61" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/40f9cf38c05296bd32f444121336a521a293fa61", + "reference": "40f9cf38c05296bd32f444121336a521a293fa61", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0", + "phpstan/phpstan": "^1.12.5" + }, + "conflict": { + "rector/rector-doctrine": "*", + "rector/rector-downgrade-php": "*", + "rector/rector-phpunit": "*", + "rector/rector-symfony": "*" + }, + "suggest": { + "ext-dom": "To manipulate phpunit.xml via the custom-rule command" + }, + "bin": [ + "bin/rector" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "keywords": [ + "automation", + "dev", + "migration", + "refactoring" + ], + "support": { + "issues": "https://github.com/rectorphp/rector/issues", + "source": "https://github.com/rectorphp/rector/tree/1.2.10" + }, + "funding": [ + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2024-11-08T13:59:10+00:00" + }, { "name": "resend/resend-laravel", "version": "v0.15.0", @@ -7484,6 +7729,69 @@ }, "time": "2024-03-15T03:02:10+00:00" }, + { + "name": "spatie/backtrace", + "version": "1.6.2", + "source": { + "type": "git", + "url": "https://github.com/spatie/backtrace.git", + "reference": "1a9a145b044677ae3424693f7b06479fc8c137a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/backtrace/zipball/1a9a145b044677ae3424693f7b06479fc8c137a9", + "reference": "1a9a145b044677ae3424693f7b06479fc8c137a9", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "ext-json": "*", + "laravel/serializable-closure": "^1.3", + "phpunit/phpunit": "^9.3", + "spatie/phpunit-snapshot-assertions": "^4.2", + "symfony/var-dumper": "^5.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\Backtrace\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van de Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "A better backtrace", + "homepage": "https://github.com/spatie/backtrace", + "keywords": [ + "Backtrace", + "spatie" + ], + "support": { + "source": "https://github.com/spatie/backtrace/tree/1.6.2" + }, + "funding": [ + { + "url": "https://github.com/sponsors/spatie", + "type": "github" + }, + { + "url": "https://spatie.be/open-source/support-us", + "type": "other" + } + ], + "time": "2024-07-22T08:21:24+00:00" + }, { "name": "spatie/laravel-activitylog", "version": "4.9.0", @@ -7719,6 +8027,93 @@ ], "time": "2024-08-27T18:56:10+00:00" }, + { + "name": "spatie/laravel-ray", + "version": "1.37.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-ray.git", + "reference": "c2bedfd1172648df2c80aaceb2541d70f1d9a5b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-ray/zipball/c2bedfd1172648df2c80aaceb2541d70f1d9a5b9", + "reference": "c2bedfd1172648df2c80aaceb2541d70f1d9a5b9", + "shasum": "" + }, + "require": { + "ext-json": "*", + "illuminate/contracts": "^7.20|^8.19|^9.0|^10.0|^11.0", + "illuminate/database": "^7.20|^8.19|^9.0|^10.0|^11.0", + "illuminate/queue": "^7.20|^8.19|^9.0|^10.0|^11.0", + "illuminate/support": "^7.20|^8.19|^9.0|^10.0|^11.0", + "php": "^7.4|^8.0", + "rector/rector": "^0.19.2|^1.0", + "spatie/backtrace": "^1.0", + "spatie/ray": "^1.41.1", + "symfony/stopwatch": "4.2|^5.1|^6.0|^7.0", + "zbateson/mail-mime-parser": "^1.3.1|^2.0|^3.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.3", + "laravel/framework": "^7.20|^8.19|^9.0|^10.0|^11.0", + "orchestra/testbench-core": "^5.0|^6.0|^7.0|^8.0|^9.0", + "pestphp/pest": "^1.22|^2.0", + "phpstan/phpstan": "^1.10.57", + "phpunit/phpunit": "^9.3|^10.1", + "spatie/pest-plugin-snapshots": "^1.1|^2.0", + "symfony/var-dumper": "^4.2|^5.1|^6.0|^7.0.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + }, + "laravel": { + "providers": [ + "Spatie\\LaravelRay\\RayServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Spatie\\LaravelRay\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Easily debug Laravel apps", + "homepage": "https://github.com/spatie/laravel-ray", + "keywords": [ + "laravel-ray", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-ray/issues", + "source": "https://github.com/spatie/laravel-ray/tree/1.37.1" + }, + "funding": [ + { + "url": "https://github.com/sponsors/spatie", + "type": "github" + }, + { + "url": "https://spatie.be/open-source/support-us", + "type": "other" + } + ], + "time": "2024-07-12T12:35:17+00:00" + }, { "name": "spatie/laravel-schemaless-attributes", "version": "2.5.0", @@ -7925,6 +8320,91 @@ ], "time": "2024-08-29T10:43:45+00:00" }, + { + "name": "spatie/ray", + "version": "1.41.2", + "source": { + "type": "git", + "url": "https://github.com/spatie/ray.git", + "reference": "c44f8cfbf82c69909b505de61d8d3f2d324e93fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/ray/zipball/c44f8cfbf82c69909b505de61d8d3f2d324e93fc", + "reference": "c44f8cfbf82c69909b505de61d8d3f2d324e93fc", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "php": "^7.3|^8.0", + "ramsey/uuid": "^3.0|^4.1", + "spatie/backtrace": "^1.1", + "spatie/macroable": "^1.0|^2.0", + "symfony/stopwatch": "^4.0|^5.1|^6.0|^7.0", + "symfony/var-dumper": "^4.2|^5.1|^6.0|^7.0.3" + }, + "require-dev": { + "illuminate/support": "6.x|^8.18|^9.0", + "nesbot/carbon": "^2.63", + "pestphp/pest": "^1.22", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.19.2", + "spatie/phpunit-snapshot-assertions": "^4.2", + "spatie/test-time": "^1.2" + }, + "bin": [ + "bin/remove-ray.sh" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Spatie\\Ray\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Debug with Ray to fix problems faster", + "homepage": "https://github.com/spatie/ray", + "keywords": [ + "ray", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/ray/issues", + "source": "https://github.com/spatie/ray/tree/1.41.2" + }, + "funding": [ + { + "url": "https://github.com/sponsors/spatie", + "type": "github" + }, + { + "url": "https://spatie.be/open-source/support-us", + "type": "other" + } + ], + "time": "2024-04-24T14:21:46+00:00" + }, { "name": "spatie/url", "version": "2.4.0", @@ -9141,6 +9621,86 @@ ], "time": "2024-09-09T11:45:10+00:00" }, + { + "name": "symfony/polyfill-iconv", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-iconv.git", + "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/48becf00c920479ca2e910c22a5a39e5d47ca956", + "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-iconv": "*" + }, + "suggest": { + "ext-iconv": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Iconv\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Iconv extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "iconv", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, { "name": "symfony/polyfill-intl-grapheme", "version": "v1.31.0", @@ -10006,6 +10566,68 @@ ], "time": "2024-04-18T09:32:20+00:00" }, + { + "name": "symfony/stopwatch", + "version": "v7.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "8b4a434e6e7faf6adedffb48783a5c75409a1a05" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/8b4a434e6e7faf6adedffb48783a5c75409a1a05", + "reference": "8b4a434e6e7faf6adedffb48783a5c75409a1a05", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/service-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a way to profile code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v7.1.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, { "name": "symfony/string", "version": "v7.1.8", @@ -10930,6 +11552,214 @@ }, "time": "2018-08-08T15:08:14+00:00" }, + { + "name": "zbateson/mail-mime-parser", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/zbateson/mail-mime-parser.git", + "reference": "e0d4423fe27850c9dd301190767dbc421acc2f19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zbateson/mail-mime-parser/zipball/e0d4423fe27850c9dd301190767dbc421acc2f19", + "reference": "e0d4423fe27850c9dd301190767dbc421acc2f19", + "shasum": "" + }, + "require": { + "guzzlehttp/psr7": "^2.5", + "php": ">=8.0", + "php-di/php-di": "^6.0|^7.0", + "psr/log": "^1|^2|^3", + "zbateson/mb-wrapper": "^2.0", + "zbateson/stream-decorators": "^2.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "*", + "monolog/monolog": "^2|^3", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^9.6" + }, + "suggest": { + "ext-iconv": "For best support/performance", + "ext-mbstring": "For best support/performance" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZBateson\\MailMimeParser\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Zaahid Bateson" + }, + { + "name": "Contributors", + "homepage": "https://github.com/zbateson/mail-mime-parser/graphs/contributors" + } + ], + "description": "MIME email message parser", + "homepage": "https://mail-mime-parser.org", + "keywords": [ + "MimeMailParser", + "email", + "mail", + "mailparse", + "mime", + "mimeparse", + "parser", + "php-imap" + ], + "support": { + "docs": "https://mail-mime-parser.org/#usage-guide", + "issues": "https://github.com/zbateson/mail-mime-parser/issues", + "source": "https://github.com/zbateson/mail-mime-parser" + }, + "funding": [ + { + "url": "https://github.com/zbateson", + "type": "github" + } + ], + "time": "2024-08-10T18:44:09+00:00" + }, + { + "name": "zbateson/mb-wrapper", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/zbateson/mb-wrapper.git", + "reference": "9e4373a153585d12b6c621ac4a6bb143264d4619" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zbateson/mb-wrapper/zipball/9e4373a153585d12b6c621ac4a6bb143264d4619", + "reference": "9e4373a153585d12b6c621ac4a6bb143264d4619", + "shasum": "" + }, + "require": { + "php": ">=8.0", + "symfony/polyfill-iconv": "^1.9", + "symfony/polyfill-mbstring": "^1.9" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "<10.0" + }, + "suggest": { + "ext-iconv": "For best support/performance", + "ext-mbstring": "For best support/performance" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZBateson\\MbWrapper\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Zaahid Bateson" + } + ], + "description": "Wrapper for mbstring with fallback to iconv for encoding conversion and string manipulation", + "keywords": [ + "charset", + "encoding", + "http", + "iconv", + "mail", + "mb", + "mb_convert_encoding", + "mbstring", + "mime", + "multibyte", + "string" + ], + "support": { + "issues": "https://github.com/zbateson/mb-wrapper/issues", + "source": "https://github.com/zbateson/mb-wrapper/tree/2.0.0" + }, + "funding": [ + { + "url": "https://github.com/zbateson", + "type": "github" + } + ], + "time": "2024-03-20T01:38:07+00:00" + }, + { + "name": "zbateson/stream-decorators", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/zbateson/stream-decorators.git", + "reference": "32a2a62fb0f26313395c996ebd658d33c3f9c4e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zbateson/stream-decorators/zipball/32a2a62fb0f26313395c996ebd658d33c3f9c4e5", + "reference": "32a2a62fb0f26313395c996ebd658d33c3f9c4e5", + "shasum": "" + }, + "require": { + "guzzlehttp/psr7": "^2.5", + "php": ">=8.0", + "zbateson/mb-wrapper": "^2.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^9.6|^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZBateson\\StreamDecorators\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Zaahid Bateson" + } + ], + "description": "PHP psr7 stream decorators for mime message part streams", + "keywords": [ + "base64", + "charset", + "decorators", + "mail", + "mime", + "psr7", + "quoted-printable", + "stream", + "uuencode" + ], + "support": { + "issues": "https://github.com/zbateson/stream-decorators/issues", + "source": "https://github.com/zbateson/stream-decorators/tree/2.1.1" + }, + "funding": [ + { + "url": "https://github.com/zbateson", + "type": "github" + } + ], + "time": "2024-04-29T21:42:39+00:00" + }, { "name": "zircote/swagger-php", "version": "4.11.1", @@ -11015,16 +11845,16 @@ "packages-dev": [ { "name": "barryvdh/laravel-debugbar", - "version": "v3.14.6", + "version": "v3.14.7", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-debugbar.git", - "reference": "14e4517bd49130d6119228107eb21ae47ae120ab" + "reference": "f484b8c9124de0b163da39958331098ffcd4a65e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/14e4517bd49130d6119228107eb21ae47ae120ab", - "reference": "14e4517bd49130d6119228107eb21ae47ae120ab", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/f484b8c9124de0b163da39958331098ffcd4a65e", + "reference": "f484b8c9124de0b163da39958331098ffcd4a65e", "shasum": "" }, "require": { @@ -11083,7 +11913,7 @@ ], "support": { "issues": "https://github.com/barryvdh/laravel-debugbar/issues", - "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.14.6" + "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.14.7" }, "funding": [ { @@ -11095,7 +11925,7 @@ "type": "github" } ], - "time": "2024-10-18T13:15:12+00:00" + "time": "2024-11-14T09:12:35+00:00" }, { "name": "brianium/paratest", @@ -12393,134 +13223,6 @@ }, "time": "2022-02-21T01:04:05+00:00" }, - { - "name": "php-di/invoker", - "version": "2.3.4", - "source": { - "type": "git", - "url": "https://github.com/PHP-DI/Invoker.git", - "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/33234b32dafa8eb69202f950a1fc92055ed76a86", - "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "psr/container": "^1.0|^2.0" - }, - "require-dev": { - "athletic/athletic": "~0.1.8", - "mnapoli/hard-mode": "~0.3.0", - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Invoker\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Generic and extensible callable invoker", - "homepage": "https://github.com/PHP-DI/Invoker", - "keywords": [ - "callable", - "dependency", - "dependency-injection", - "injection", - "invoke", - "invoker" - ], - "support": { - "issues": "https://github.com/PHP-DI/Invoker/issues", - "source": "https://github.com/PHP-DI/Invoker/tree/2.3.4" - }, - "funding": [ - { - "url": "https://github.com/mnapoli", - "type": "github" - } - ], - "time": "2023-09-08T09:24:21+00:00" - }, - { - "name": "php-di/php-di", - "version": "7.0.7", - "source": { - "type": "git", - "url": "https://github.com/PHP-DI/PHP-DI.git", - "reference": "e87435e3c0e8f22977adc5af0d5cdcc467e15cf1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/e87435e3c0e8f22977adc5af0d5cdcc467e15cf1", - "reference": "e87435e3c0e8f22977adc5af0d5cdcc467e15cf1", - "shasum": "" - }, - "require": { - "laravel/serializable-closure": "^1.0", - "php": ">=8.0", - "php-di/invoker": "^2.0", - "psr/container": "^1.1 || ^2.0" - }, - "provide": { - "psr/container-implementation": "^1.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3", - "friendsofphp/proxy-manager-lts": "^1", - "mnapoli/phpunit-easymock": "^1.3", - "phpunit/phpunit": "^9.5", - "vimeo/psalm": "^4.6" - }, - "suggest": { - "friendsofphp/proxy-manager-lts": "Install it if you want to use lazy injection (version ^1)" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "DI\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "The dependency injection container for humans", - "homepage": "https://php-di.org/", - "keywords": [ - "PSR-11", - "container", - "container-interop", - "dependency injection", - "di", - "ioc", - "psr11" - ], - "support": { - "issues": "https://github.com/PHP-DI/PHP-DI/issues", - "source": "https://github.com/PHP-DI/PHP-DI/tree/7.0.7" - }, - "funding": [ - { - "url": "https://github.com/mnapoli", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", - "type": "tidelift" - } - ], - "time": "2024-07-21T15:55:45+00:00" - }, { "name": "php-webdriver/webdriver", "version": "1.15.1", @@ -12587,64 +13289,6 @@ }, "time": "2023-10-20T12:21:20+00:00" }, - { - "name": "phpstan/phpstan", - "version": "1.12.10", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "fc463b5d0fe906dcf19689be692c65c50406a071" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fc463b5d0fe906dcf19689be692c65c50406a071", - "reference": "fc463b5d0fe906dcf19689be692c65c50406a071", - "shasum": "" - }, - "require": { - "php": "^7.2|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" - }, - "bin": [ - "phpstan", - "phpstan.phar" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPStan - PHP Static Analysis Tool", - "keywords": [ - "dev", - "static analysis" - ], - "support": { - "docs": "https://phpstan.org/user-guide/getting-started", - "forum": "https://github.com/phpstan/phpstan/discussions", - "issues": "https://github.com/phpstan/phpstan/issues", - "security": "https://github.com/phpstan/phpstan/security/policy", - "source": "https://github.com/phpstan/phpstan-src" - }, - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://github.com/phpstan", - "type": "github" - } - ], - "time": "2024-11-11T15:37:09+00:00" - }, { "name": "phpunit/php-code-coverage", "version": "11.0.7", @@ -13068,65 +13712,6 @@ ], "time": "2024-10-28T13:07:50+00:00" }, - { - "name": "rector/rector", - "version": "1.2.10", - "source": { - "type": "git", - "url": "https://github.com/rectorphp/rector.git", - "reference": "40f9cf38c05296bd32f444121336a521a293fa61" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/40f9cf38c05296bd32f444121336a521a293fa61", - "reference": "40f9cf38c05296bd32f444121336a521a293fa61", - "shasum": "" - }, - "require": { - "php": "^7.2|^8.0", - "phpstan/phpstan": "^1.12.5" - }, - "conflict": { - "rector/rector-doctrine": "*", - "rector/rector-downgrade-php": "*", - "rector/rector-phpunit": "*", - "rector/rector-symfony": "*" - }, - "suggest": { - "ext-dom": "To manipulate phpunit.xml via the custom-rule command" - }, - "bin": [ - "bin/rector" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Instant Upgrade and Automated Refactoring of any PHP code", - "keywords": [ - "automation", - "dev", - "migration", - "refactoring" - ], - "support": { - "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/1.2.10" - }, - "funding": [ - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2024-11-08T13:59:10+00:00" - }, { "name": "sebastian/cli-parser", "version": "3.0.2", @@ -14095,69 +14680,6 @@ ], "time": "2024-10-15T15:12:28+00:00" }, - { - "name": "spatie/backtrace", - "version": "1.6.2", - "source": { - "type": "git", - "url": "https://github.com/spatie/backtrace.git", - "reference": "1a9a145b044677ae3424693f7b06479fc8c137a9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spatie/backtrace/zipball/1a9a145b044677ae3424693f7b06479fc8c137a9", - "reference": "1a9a145b044677ae3424693f7b06479fc8c137a9", - "shasum": "" - }, - "require": { - "php": "^7.3|^8.0" - }, - "require-dev": { - "ext-json": "*", - "laravel/serializable-closure": "^1.3", - "phpunit/phpunit": "^9.3", - "spatie/phpunit-snapshot-assertions": "^4.2", - "symfony/var-dumper": "^5.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "Spatie\\Backtrace\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van de Herten", - "email": "freek@spatie.be", - "homepage": "https://spatie.be", - "role": "Developer" - } - ], - "description": "A better backtrace", - "homepage": "https://github.com/spatie/backtrace", - "keywords": [ - "Backtrace", - "spatie" - ], - "support": { - "source": "https://github.com/spatie/backtrace/tree/1.6.2" - }, - "funding": [ - { - "url": "https://github.com/sponsors/spatie", - "type": "github" - }, - { - "url": "https://spatie.be/open-source/support-us", - "type": "other" - } - ], - "time": "2024-07-22T08:21:24+00:00" - }, { "name": "spatie/error-solutions", "version": "1.1.1", @@ -14475,178 +14997,6 @@ ], "time": "2024-06-12T15:01:18+00:00" }, - { - "name": "spatie/laravel-ray", - "version": "1.37.1", - "source": { - "type": "git", - "url": "https://github.com/spatie/laravel-ray.git", - "reference": "c2bedfd1172648df2c80aaceb2541d70f1d9a5b9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-ray/zipball/c2bedfd1172648df2c80aaceb2541d70f1d9a5b9", - "reference": "c2bedfd1172648df2c80aaceb2541d70f1d9a5b9", - "shasum": "" - }, - "require": { - "ext-json": "*", - "illuminate/contracts": "^7.20|^8.19|^9.0|^10.0|^11.0", - "illuminate/database": "^7.20|^8.19|^9.0|^10.0|^11.0", - "illuminate/queue": "^7.20|^8.19|^9.0|^10.0|^11.0", - "illuminate/support": "^7.20|^8.19|^9.0|^10.0|^11.0", - "php": "^7.4|^8.0", - "rector/rector": "^0.19.2|^1.0", - "spatie/backtrace": "^1.0", - "spatie/ray": "^1.41.1", - "symfony/stopwatch": "4.2|^5.1|^6.0|^7.0", - "zbateson/mail-mime-parser": "^1.3.1|^2.0|^3.0" - }, - "require-dev": { - "guzzlehttp/guzzle": "^7.3", - "laravel/framework": "^7.20|^8.19|^9.0|^10.0|^11.0", - "orchestra/testbench-core": "^5.0|^6.0|^7.0|^8.0|^9.0", - "pestphp/pest": "^1.22|^2.0", - "phpstan/phpstan": "^1.10.57", - "phpunit/phpunit": "^9.3|^10.1", - "spatie/pest-plugin-snapshots": "^1.1|^2.0", - "symfony/var-dumper": "^4.2|^5.1|^6.0|^7.0.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - }, - "laravel": { - "providers": [ - "Spatie\\LaravelRay\\RayServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "Spatie\\LaravelRay\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "homepage": "https://spatie.be", - "role": "Developer" - } - ], - "description": "Easily debug Laravel apps", - "homepage": "https://github.com/spatie/laravel-ray", - "keywords": [ - "laravel-ray", - "spatie" - ], - "support": { - "issues": "https://github.com/spatie/laravel-ray/issues", - "source": "https://github.com/spatie/laravel-ray/tree/1.37.1" - }, - "funding": [ - { - "url": "https://github.com/sponsors/spatie", - "type": "github" - }, - { - "url": "https://spatie.be/open-source/support-us", - "type": "other" - } - ], - "time": "2024-07-12T12:35:17+00:00" - }, - { - "name": "spatie/ray", - "version": "1.41.2", - "source": { - "type": "git", - "url": "https://github.com/spatie/ray.git", - "reference": "c44f8cfbf82c69909b505de61d8d3f2d324e93fc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spatie/ray/zipball/c44f8cfbf82c69909b505de61d8d3f2d324e93fc", - "reference": "c44f8cfbf82c69909b505de61d8d3f2d324e93fc", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "ext-json": "*", - "php": "^7.3|^8.0", - "ramsey/uuid": "^3.0|^4.1", - "spatie/backtrace": "^1.1", - "spatie/macroable": "^1.0|^2.0", - "symfony/stopwatch": "^4.0|^5.1|^6.0|^7.0", - "symfony/var-dumper": "^4.2|^5.1|^6.0|^7.0.3" - }, - "require-dev": { - "illuminate/support": "6.x|^8.18|^9.0", - "nesbot/carbon": "^2.63", - "pestphp/pest": "^1.22", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^9.5", - "rector/rector": "^0.19.2", - "spatie/phpunit-snapshot-assertions": "^4.2", - "spatie/test-time": "^1.2" - }, - "bin": [ - "bin/remove-ray.sh" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - } - }, - "autoload": { - "files": [ - "src/helpers.php" - ], - "psr-4": { - "Spatie\\Ray\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "homepage": "https://spatie.be", - "role": "Developer" - } - ], - "description": "Debug with Ray to fix problems faster", - "homepage": "https://github.com/spatie/ray", - "keywords": [ - "ray", - "spatie" - ], - "support": { - "issues": "https://github.com/spatie/ray/issues", - "source": "https://github.com/spatie/ray/tree/1.41.2" - }, - "funding": [ - { - "url": "https://github.com/sponsors/spatie", - "type": "github" - }, - { - "url": "https://spatie.be/open-source/support-us", - "type": "other" - } - ], - "time": "2024-04-24T14:21:46+00:00" - }, { "name": "symfony/http-client", "version": "v7.1.8", @@ -14819,148 +15169,6 @@ ], "time": "2024-04-18T09:32:20+00:00" }, - { - "name": "symfony/polyfill-iconv", - "version": "v1.31.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/48becf00c920479ca2e910c22a5a39e5d47ca956", - "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "provide": { - "ext-iconv": "*" - }, - "suggest": { - "ext-iconv": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Iconv\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Iconv extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "iconv", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.31.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-09-09T11:45:10+00:00" - }, - { - "name": "symfony/stopwatch", - "version": "v7.1.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/stopwatch.git", - "reference": "8b4a434e6e7faf6adedffb48783a5c75409a1a05" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/8b4a434e6e7faf6adedffb48783a5c75409a1a05", - "reference": "8b4a434e6e7faf6adedffb48783a5c75409a1a05", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/service-contracts": "^2.5|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Stopwatch\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides a way to profile code", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.1.6" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-09-25T14:20:29+00:00" - }, { "name": "ta-tikoma/phpunit-architecture-test", "version": "0.8.4", @@ -15069,214 +15277,6 @@ } ], "time": "2024-03-03T12:36:25+00:00" - }, - { - "name": "zbateson/mail-mime-parser", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/zbateson/mail-mime-parser.git", - "reference": "e0d4423fe27850c9dd301190767dbc421acc2f19" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zbateson/mail-mime-parser/zipball/e0d4423fe27850c9dd301190767dbc421acc2f19", - "reference": "e0d4423fe27850c9dd301190767dbc421acc2f19", - "shasum": "" - }, - "require": { - "guzzlehttp/psr7": "^2.5", - "php": ">=8.0", - "php-di/php-di": "^6.0|^7.0", - "psr/log": "^1|^2|^3", - "zbateson/mb-wrapper": "^2.0", - "zbateson/stream-decorators": "^2.1" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "*", - "monolog/monolog": "^2|^3", - "phpstan/phpstan": "*", - "phpunit/phpunit": "^9.6" - }, - "suggest": { - "ext-iconv": "For best support/performance", - "ext-mbstring": "For best support/performance" - }, - "type": "library", - "autoload": { - "psr-4": { - "ZBateson\\MailMimeParser\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Zaahid Bateson" - }, - { - "name": "Contributors", - "homepage": "https://github.com/zbateson/mail-mime-parser/graphs/contributors" - } - ], - "description": "MIME email message parser", - "homepage": "https://mail-mime-parser.org", - "keywords": [ - "MimeMailParser", - "email", - "mail", - "mailparse", - "mime", - "mimeparse", - "parser", - "php-imap" - ], - "support": { - "docs": "https://mail-mime-parser.org/#usage-guide", - "issues": "https://github.com/zbateson/mail-mime-parser/issues", - "source": "https://github.com/zbateson/mail-mime-parser" - }, - "funding": [ - { - "url": "https://github.com/zbateson", - "type": "github" - } - ], - "time": "2024-08-10T18:44:09+00:00" - }, - { - "name": "zbateson/mb-wrapper", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/zbateson/mb-wrapper.git", - "reference": "9e4373a153585d12b6c621ac4a6bb143264d4619" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zbateson/mb-wrapper/zipball/9e4373a153585d12b6c621ac4a6bb143264d4619", - "reference": "9e4373a153585d12b6c621ac4a6bb143264d4619", - "shasum": "" - }, - "require": { - "php": ">=8.0", - "symfony/polyfill-iconv": "^1.9", - "symfony/polyfill-mbstring": "^1.9" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "*", - "phpstan/phpstan": "*", - "phpunit/phpunit": "<10.0" - }, - "suggest": { - "ext-iconv": "For best support/performance", - "ext-mbstring": "For best support/performance" - }, - "type": "library", - "autoload": { - "psr-4": { - "ZBateson\\MbWrapper\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Zaahid Bateson" - } - ], - "description": "Wrapper for mbstring with fallback to iconv for encoding conversion and string manipulation", - "keywords": [ - "charset", - "encoding", - "http", - "iconv", - "mail", - "mb", - "mb_convert_encoding", - "mbstring", - "mime", - "multibyte", - "string" - ], - "support": { - "issues": "https://github.com/zbateson/mb-wrapper/issues", - "source": "https://github.com/zbateson/mb-wrapper/tree/2.0.0" - }, - "funding": [ - { - "url": "https://github.com/zbateson", - "type": "github" - } - ], - "time": "2024-03-20T01:38:07+00:00" - }, - { - "name": "zbateson/stream-decorators", - "version": "2.1.1", - "source": { - "type": "git", - "url": "https://github.com/zbateson/stream-decorators.git", - "reference": "32a2a62fb0f26313395c996ebd658d33c3f9c4e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zbateson/stream-decorators/zipball/32a2a62fb0f26313395c996ebd658d33c3f9c4e5", - "reference": "32a2a62fb0f26313395c996ebd658d33c3f9c4e5", - "shasum": "" - }, - "require": { - "guzzlehttp/psr7": "^2.5", - "php": ">=8.0", - "zbateson/mb-wrapper": "^2.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "*", - "phpstan/phpstan": "*", - "phpunit/phpunit": "^9.6|^10.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "ZBateson\\StreamDecorators\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Zaahid Bateson" - } - ], - "description": "PHP psr7 stream decorators for mime message part streams", - "keywords": [ - "base64", - "charset", - "decorators", - "mail", - "mime", - "psr7", - "quoted-printable", - "stream", - "uuencode" - ], - "support": { - "issues": "https://github.com/zbateson/stream-decorators/issues", - "source": "https://github.com/zbateson/stream-decorators/tree/2.1.1" - }, - "funding": [ - { - "url": "https://github.com/zbateson", - "type": "github" - } - ], - "time": "2024-04-29T21:42:39+00:00" } ], "aliases": [], diff --git a/config/constants.php b/config/constants.php index 532feb56c..b29adfff3 100644 --- a/config/constants.php +++ b/config/constants.php @@ -2,9 +2,9 @@ return [ 'coolify' => [ - 'version' => '4.0.0-beta.368', + 'version' => '4.0.0-beta.372', 'self_hosted' => env('SELF_HOSTED', true), - 'autoupdate' => env('AUTOUPDATE', false), + 'autoupdate' => env('AUTOUPDATE'), 'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'), 'helper_image' => env('HELPER_IMAGE', 'ghcr.io/coollabsio/coolify-helper'), 'is_windows_docker_desktop' => env('IS_WINDOWS_DOCKER_DESKTOP', false), diff --git a/config/version.php b/config/version.php index ddb1cb354..21119de4a 100644 --- a/config/version.php +++ b/config/version.php @@ -1,3 +1,3 @@ getMessage()); + } + } + + public function down() + { + try { + DB::statement('DROP INDEX IF EXISTS idx_activity_type_uuid'); + DB::statement('ALTER TABLE activity_log ALTER COLUMN properties TYPE json USING properties::json'); + } catch (\Exception $e) { + Log::error('Error dropping index from activity_log: '.$e->getMessage()); + } + } +} diff --git a/database/seeders/ProductionSeeder.php b/database/seeders/ProductionSeeder.php index 8144a8b1a..7acdef548 100644 --- a/database/seeders/ProductionSeeder.php +++ b/database/seeders/ProductionSeeder.php @@ -22,9 +22,9 @@ class ProductionSeeder extends Seeder public function run(): void { if (isCloud()) { - echo "Running in cloud mode.\n"; + echo "[x]: Running in cloud mode.\n"; } else { - echo "Running in self-hosted mode.\n"; + echo "[x]: Running in self-hosted mode.\n"; } // Fix for 4.0.0-beta.37 diff --git a/docker/coolify-helper/Dockerfile b/docker/coolify-helper/Dockerfile index c375db5f8..741fff764 100644 --- a/docker/coolify-helper/Dockerfile +++ b/docker/coolify-helper/Dockerfile @@ -1,4 +1,5 @@ # Versions + # https://hub.docker.com/_/alpine ARG BASE_IMAGE=alpine:3.20 # https://download.docker.com/linux/static/stable/ diff --git a/docker/coolify-realtime/Dockerfile b/docker/coolify-realtime/Dockerfile index 9f94518f5..b9f3c1e62 100644 --- a/docker/coolify-realtime/Dockerfile +++ b/docker/coolify-realtime/Dockerfile @@ -1,5 +1,6 @@ FROM quay.io/soketi/soketi:1.6-16-alpine + ARG TARGETPLATFORM # https://github.com/cloudflare/cloudflared/releases ARG CLOUDFLARED_VERSION=2024.4.1 diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile index ca34bb05b..36be6cf06 100644 --- a/docker/prod/Dockerfile +++ b/docker/prod/Dockerfile @@ -57,13 +57,6 @@ RUN composer dump-autoload COPY --from=static-assets --chown=9999:9999 /app/public/build ./public/build COPY --chmod=755 docker/prod/etc/s6-overlay/ /etc/s6-overlay/ -RUN php artisan route:clear -RUN php artisan view:clear -RUN php artisan config:clear -RUN php artisan route:cache -RUN php artisan view:cache -RUN php artisan config:cache - RUN echo "alias ll='ls -al'" >>/etc/bash.bashrc RUN echo "alias a='php artisan'" >>/etc/bash.bashrc RUN echo "alias logs='tail -f storage/logs/laravel.log'" >>/etc/bash.bashrc @@ -86,4 +79,4 @@ RUN { \ } > /etc/php/current_version/cli/conf.d/upload-limits.ini COPY --from=minio-client /usr/bin/mc /usr/bin/mc -RUN chmod +x /usr/bin/mc \ No newline at end of file +RUN chmod +x /usr/bin/mc diff --git a/other/nightly/install.sh b/other/nightly/install.sh index 876e8c6e2..4a03a5c98 100755 --- a/other/nightly/install.sh +++ b/other/nightly/install.sh @@ -9,7 +9,7 @@ CDN="https://cdn.coollabs.io/coolify-nightly" DATE=$(date +"%Y%m%d-%H%M%S") VERSION="1.6" -DOCKER_VERSION="27.3" +DOCKER_VERSION="27.0" # TODO: Ask for a user CURRENT_USER=$USER diff --git a/resources/views/components/forms/checkbox.blade.php b/resources/views/components/forms/checkbox.blade.php index ef4d5a7f3..fb244962d 100644 --- a/resources/views/components/forms/checkbox.blade.php +++ b/resources/views/components/forms/checkbox.blade.php @@ -5,6 +5,7 @@ 'disabled' => false, 'instantSave' => false, 'value' => null, + 'checked' => false, 'hideLabel' => false, 'fullWidth' => false, ]) @@ -14,7 +15,9 @@ 'w-full' => $fullWidth, ])> @if (!$hideLabel) -