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
-
+
* [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!
+
+
+
+
+
## 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 ab5c7424a..3f76a2e3c 100644
--- a/app/Actions/CoolifyTask/PrepareCoolifyTask.php
+++ b/app/Actions/CoolifyTask/PrepareCoolifyTask.php
@@ -46,7 +46,7 @@ class PrepareCoolifyTask
call_event_on_finish: $this->remoteProcessArgs->call_event_on_finish,
call_event_data: $this->remoteProcessArgs->call_event_data,
);
- dispatch($job)->onQueue('high');
+ 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/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/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..5c6aa26b3 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;
}
@@ -198,7 +199,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
$databasesToBackup = data_get($this->backup, 'databases_to_backup');
}
- if (is_null($databasesToBackup)) {
+ if (filled($databasesToBackup)) {
if (str($databaseType)->contains('postgres')) {
$databasesToBackup = [$this->database->postgres_db];
} elseif (str($databaseType)->contains('mongodb')) {
@@ -319,12 +320,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..6c581e1d3 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.
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/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/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..3edb21974 100644
--- a/app/Livewire/Project/Application/Heading.php
+++ b/app/Livewire/Project/Application/Heading.php
@@ -45,13 +45,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/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 242980e00..fae8951fd 100644
--- a/app/Notifications/Application/DeploymentFailed.php
+++ b/app/Notifications/Application/DeploymentFailed.php
@@ -34,6 +34,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 946a622ca..bfdef9f25 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 852c6b526..3b062effb 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 182a1f5fc..90dae63d4 100644
--- a/app/Notifications/Container/ContainerRestarted.php
+++ b/app/Notifications/Container/ContainerRestarted.php
@@ -15,7 +15,10 @@ class ContainerRestarted extends Notification implements ShouldQueue
public $tries = 1;
- public function __construct(public string $name, public Server $server, public ?string $url = null) {}
+ 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 33a55c65a..3c8103568 100644
--- a/app/Notifications/Container/ContainerStopped.php
+++ b/app/Notifications/Container/ContainerStopped.php
@@ -15,7 +15,10 @@ class ContainerStopped extends Notification implements ShouldQueue
public $tries = 1;
- public function __construct(public string $name, public Server $server, public ?string $url = null) {}
+ 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 8e2733339..ba67db4ae 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 5128c8ed6..669a8a034 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 48e7d8340..dcfde7b5b 100644
--- a/app/Notifications/Internal/GeneralNotification.php
+++ b/app/Notifications/Internal/GeneralNotification.php
@@ -15,7 +15,10 @@ class GeneralNotification extends Notification implements ShouldQueue
public $tries = 1;
- public function __construct(public string $message) {}
+ 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 c3501a8eb..efdb8dccf 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 7ea1b84c2..7e9425bb3 100644
--- a/app/Notifications/Server/DockerCleanup.php
+++ b/app/Notifications/Server/DockerCleanup.php
@@ -16,7 +16,10 @@ class DockerCleanup extends Notification implements ShouldQueue
public $tries = 1;
- public function __construct(public Server $server, public string $message) {}
+ 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 a26c803ee..0008e3ed7 100644
--- a/app/Notifications/Server/ForceDisabled.php
+++ b/app/Notifications/Server/ForceDisabled.php
@@ -18,7 +18,10 @@ class ForceDisabled extends Notification implements ShouldQueue
public $tries = 1;
- public function __construct(public Server $server) {}
+ 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 65b65a10c..15288ddcf 100644
--- a/app/Notifications/Server/ForceEnabled.php
+++ b/app/Notifications/Server/ForceEnabled.php
@@ -18,7 +18,10 @@ class ForceEnabled extends Notification implements ShouldQueue
public $tries = 1;
- public function __construct(public Server $server) {}
+ 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 e373abc03..d07af0f24 100644
--- a/app/Notifications/Server/HighDiskUsage.php
+++ b/app/Notifications/Server/HighDiskUsage.php
@@ -15,7 +15,10 @@ class HighDiskUsage extends Notification implements ShouldQueue
public $tries = 1;
- public function __construct(public Server $server, public int $disk_usage, public int $server_disk_usage_notification_threshold) {}
+ 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 9b54501d9..dc8ff6bad 100644
--- a/app/Notifications/Server/Reachable.php
+++ b/app/Notifications/Server/Reachable.php
@@ -22,6 +22,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 5bc568e82..c28877aa0 100644
--- a/app/Notifications/Server/Unreachable.php
+++ b/app/Notifications/Server/Unreachable.php
@@ -22,6 +22,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 a43b1e153..64f9bb0a5 100644
--- a/app/Notifications/Test.php
+++ b/app/Notifications/Test.php
@@ -15,7 +15,10 @@ class Test extends Notification implements ShouldQueue
public $tries = 5;
- public function __construct(public ?string $emails = null) {}
+ 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/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/config/constants.php b/config/constants.php
index dcd49b177..b29adfff3 100644
--- a/config/constants.php
+++ b/config/constants.php
@@ -2,7 +2,7 @@
return [
'coolify' => [
- 'version' => '4.0.0-beta.371',
+ 'version' => '4.0.0-beta.372',
'self_hosted' => env('SELF_HOSTED', true),
'autoupdate' => env('AUTOUPDATE'),
'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),
diff --git a/config/version.php b/config/version.php
index fcda1b4ac..21119de4a 100644
--- a/config/version.php
+++ b/config/version.php
@@ -1,3 +1,3 @@
getMessage());
+ }
}
public function down()
{
- DB::statement('DROP INDEX IF EXISTS idx_activity_type_uuid');
- DB::statement('ALTER TABLE activity_log ALTER COLUMN properties TYPE json USING properties::json');
-
+ 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/resources/views/livewire/notifications/email.blade.php b/resources/views/livewire/notifications/email.blade.php
index a2e5326c6..182c73d6a 100644
--- a/resources/views/livewire/notifications/email.blade.php
+++ b/resources/views/livewire/notifications/email.blade.php
@@ -16,9 +16,9 @@
@endif
@if (isEmailEnabled($team) && auth()->user()->isAdminFromSession() && isTestEmailEnabled($team))
-