diff --git a/.github/workflows/coolify-production-build.yml b/.github/workflows/coolify-production-build.yml index 771687d4b..7017b4897 100644 --- a/.github/workflows/coolify-production-build.yml +++ b/.github/workflows/coolify-production-build.yml @@ -53,8 +53,6 @@ jobs: tags: | ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} - labels: | - coolify.managed=true aarch64: runs-on: [self-hosted, arm64] @@ -90,8 +88,6 @@ jobs: tags: | ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 - labels: | - coolify.managed=true merge-manifest: runs-on: ubuntu-latest diff --git a/.github/workflows/coolify-staging-build.yml b/.github/workflows/coolify-staging-build.yml index dd5e6ebd6..6e4d4adc3 100644 --- a/.github/workflows/coolify-staging-build.yml +++ b/.github/workflows/coolify-staging-build.yml @@ -48,8 +48,6 @@ jobs: tags: | ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} - labels: | - coolify.managed=true aarch64: runs-on: [self-hosted, arm64] @@ -83,8 +81,6 @@ jobs: tags: | ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 - labels: | - coolify.managed=true merge-manifest: runs-on: ubuntu-latest diff --git a/app/Actions/CoolifyTask/RunRemoteProcess.php b/app/Actions/CoolifyTask/RunRemoteProcess.php index c75a30ae8..51c5a1f9e 100644 --- a/app/Actions/CoolifyTask/RunRemoteProcess.php +++ b/app/Actions/CoolifyTask/RunRemoteProcess.php @@ -39,7 +39,6 @@ class RunRemoteProcess */ public function __construct(Activity $activity, bool $hide_from_output = false, bool $ignore_errors = false, $call_event_on_finish = null, $call_event_data = null) { - if ($activity->getExtraProperty('type') !== ActivityTypes::INLINE->value && $activity->getExtraProperty('type') !== ActivityTypes::COMMAND->value) { throw new \RuntimeException('Incompatible Activity to run a remote command.'); } diff --git a/app/Actions/Docker/GetContainersStatus.php b/app/Actions/Docker/GetContainersStatus.php index 1cabc6418..6c1a53f3a 100644 --- a/app/Actions/Docker/GetContainersStatus.php +++ b/app/Actions/Docker/GetContainersStatus.php @@ -8,7 +8,6 @@ use App\Models\ApplicationPreview; use App\Models\Server; use App\Models\ServiceDatabase; use App\Notifications\Container\ContainerRestarted; -use App\Notifications\Container\ContainerStopped; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Lorisleiva\Actions\Concerns\AsAction; diff --git a/app/Actions/Proxy/StartProxy.php b/app/Actions/Proxy/StartProxy.php index 2a6ec7d03..7c93720cb 100644 --- a/app/Actions/Proxy/StartProxy.php +++ b/app/Actions/Proxy/StartProxy.php @@ -58,9 +58,7 @@ class StartProxy } if ($async) { - $activity = remote_process($commands, $server, callEventOnFinish: 'ProxyStarted', callEventData: $server); - - return $activity; + return remote_process($commands, $server, callEventOnFinish: 'ProxyStarted', callEventData: $server); } else { instant_remote_process($commands, $server); $server->proxy->set('status', 'running'); @@ -70,6 +68,5 @@ class StartProxy return 'OK'; } - } } diff --git a/app/Actions/Server/ConfigureCloudflared.php b/app/Actions/Server/ConfigureCloudflared.php index 0819da07a..fc04e67a4 100644 --- a/app/Actions/Server/ConfigureCloudflared.php +++ b/app/Actions/Server/ConfigureCloudflared.php @@ -50,7 +50,6 @@ class ConfigureCloudflared 'rm -fr /tmp/cloudflared', ]); instant_remote_process($commands, $server); - } } } diff --git a/app/Actions/Server/RunCommand.php b/app/Actions/Server/RunCommand.php index fce862eb0..254c78587 100644 --- a/app/Actions/Server/RunCommand.php +++ b/app/Actions/Server/RunCommand.php @@ -12,8 +12,6 @@ class RunCommand public function handle(Server $server, $command) { - $activity = remote_process(command: [$command], server: $server, ignore_errors: true, type: ActivityTypes::COMMAND->value); - - return $activity; + return remote_process(command: [$command], server: $server, ignore_errors: true, type: ActivityTypes::COMMAND->value); } } diff --git a/app/Actions/Server/InstallLogDrain.php b/app/Actions/Server/StartLogDrain.php similarity index 96% rename from app/Actions/Server/InstallLogDrain.php rename to app/Actions/Server/StartLogDrain.php index 43376efe5..0e8036cd9 100644 --- a/app/Actions/Server/InstallLogDrain.php +++ b/app/Actions/Server/StartLogDrain.php @@ -5,7 +5,7 @@ namespace App\Actions\Server; use App\Models\Server; use Lorisleiva\Actions\Concerns\AsAction; -class InstallLogDrain +class StartLogDrain { use AsAction; @@ -13,12 +13,16 @@ class InstallLogDrain { if ($server->settings->is_logdrain_newrelic_enabled) { $type = 'newrelic'; + StopLogDrain::run($server); } elseif ($server->settings->is_logdrain_highlight_enabled) { $type = 'highlight'; + StopLogDrain::run($server); } elseif ($server->settings->is_logdrain_axiom_enabled) { $type = 'axiom'; + StopLogDrain::run($server); } elseif ($server->settings->is_logdrain_custom_enabled) { $type = 'custom'; + StopLogDrain::run($server); } else { $type = 'none'; } @@ -151,6 +155,8 @@ services: - ./parsers.conf:/parsers.conf ports: - 127.0.0.1:24224:24224 + labels: + - coolify.managed=true restart: unless-stopped '); $readme = base64_encode('# New Relic Log Drain @@ -202,15 +208,11 @@ Files: throw new \Exception('Unknown log drain type.'); } $restart_command = [ - "echo 'Stopping old Fluent Bit'", - "cd $config_path && docker compose down --remove-orphans || true", "echo 'Starting Fluent Bit'", - "cd $config_path && docker compose up -d --remove-orphans", + "cd $config_path && docker compose up -d", ]; $command = array_merge($command, $add_envs_command, $restart_command); - StopLogDrain::run($server); - return instant_remote_process($command, $server); } catch (\Throwable $e) { return handleError($e); diff --git a/app/Actions/Server/StopLogDrain.php b/app/Actions/Server/StopLogDrain.php index a5bce94a5..96c2466de 100644 --- a/app/Actions/Server/StopLogDrain.php +++ b/app/Actions/Server/StopLogDrain.php @@ -12,7 +12,7 @@ class StopLogDrain public function handle(Server $server) { try { - return instant_remote_process(['docker rm -f coolify-log-drain || true'], $server); + return instant_remote_process(['docker rm -f coolify-log-drain'], $server, false); } catch (\Throwable $e) { return handleError($e); } diff --git a/app/Actions/Service/StartService.php b/app/Actions/Service/StartService.php index 5b8279221..82de066d7 100644 --- a/app/Actions/Service/StartService.php +++ b/app/Actions/Service/StartService.php @@ -33,8 +33,7 @@ class StartService $commands[] = "docker network connect --alias {$serviceName}-{$service->uuid} $network {$serviceName}-{$service->uuid} >/dev/null 2>&1 || true"; } } - $activity = remote_process($commands, $service->server, type_uuid: $service->uuid, callEventOnFinish: 'ServiceStatusChanged'); - return $activity; + return remote_process($commands, $service->server, type_uuid: $service->uuid, callEventOnFinish: 'ServiceStatusChanged'); } } diff --git a/app/Console/Commands/CleanupDatabase.php b/app/Console/Commands/CleanupDatabase.php index 6f130626b..0b2b766f4 100644 --- a/app/Console/Commands/CleanupDatabase.php +++ b/app/Console/Commands/CleanupDatabase.php @@ -64,6 +64,5 @@ class CleanupDatabase extends Command if ($this->option('yes')) { $webhooks->delete(); } - } } diff --git a/app/Console/Commands/CleanupRedis.php b/app/Console/Commands/CleanupRedis.php index ed0740d34..5fc2b4e61 100644 --- a/app/Console/Commands/CleanupRedis.php +++ b/app/Console/Commands/CleanupRedis.php @@ -26,6 +26,5 @@ class CleanupRedis extends Command collect($queueOverlaps)->each(function ($key) { Redis::connection()->del($key); }); - } } diff --git a/app/Console/Commands/CleanupStuckedResources.php b/app/Console/Commands/CleanupStuckedResources.php index da757c99f..9d36ce9b8 100644 --- a/app/Console/Commands/CleanupStuckedResources.php +++ b/app/Console/Commands/CleanupStuckedResources.php @@ -36,7 +36,6 @@ class CleanupStuckedResources extends Command private function cleanup_stucked_resources() { - try { $servers = Server::all()->filter(function ($server) { return $server->isFunctional(); diff --git a/app/Console/Commands/CloudCleanupSubscriptions.php b/app/Console/Commands/CloudCleanupSubscriptions.php index 5054d125c..8bb420ab8 100644 --- a/app/Console/Commands/CloudCleanupSubscriptions.php +++ b/app/Console/Commands/CloudCleanupSubscriptions.php @@ -73,7 +73,6 @@ class CloudCleanupSubscriptions extends Command } } } - } catch (\Exception $e) { $this->error($e->getMessage()); @@ -95,6 +94,5 @@ class CloudCleanupSubscriptions extends Command ]); } } - } } diff --git a/app/Console/Commands/Dev.php b/app/Console/Commands/Dev.php index 20a2667c3..f5f1233fe 100644 --- a/app/Console/Commands/Dev.php +++ b/app/Console/Commands/Dev.php @@ -25,7 +25,6 @@ class Dev extends Command return; } - } public function generateOpenApi() diff --git a/app/Console/Commands/Init.php b/app/Console/Commands/Init.php index 8f68966a5..ccb864e1f 100644 --- a/app/Console/Commands/Init.php +++ b/app/Console/Commands/Init.php @@ -32,7 +32,6 @@ class Init extends Command $this->servers = Server::all(); if (isCloud()) { - } else { $this->send_alive_signal(); get_public_ips(); @@ -120,7 +119,6 @@ class Init extends Command } catch (\Throwable $e) { echo "Error in cleaning up unnecessary dynamic proxy configuration: {$e->getMessage()}\n"; } - } } diff --git a/app/Console/Commands/OpenApi.php b/app/Console/Commands/OpenApi.php index e8d73ef47..e248aa2c0 100644 --- a/app/Console/Commands/OpenApi.php +++ b/app/Console/Commands/OpenApi.php @@ -21,6 +21,5 @@ class OpenApi extends Command $error = preg_replace('/^\h*\v+/m', '', $error); echo $error; echo $process->output(); - } } diff --git a/app/Console/Commands/ServicesGenerate.php b/app/Console/Commands/ServicesGenerate.php index 9720e81ac..1559e5f6d 100644 --- a/app/Console/Commands/ServicesGenerate.php +++ b/app/Console/Commands/ServicesGenerate.php @@ -3,128 +3,82 @@ namespace App\Console\Commands; use Illuminate\Console\Command; +use Illuminate\Support\Arr; use Symfony\Component\Yaml\Yaml; class ServicesGenerate extends Command { /** - * The name and signature of the console command. - * - * @var string + * {@inheritdoc} */ protected $signature = 'services:generate'; /** - * The console command description. - * - * @var string + * {@inheritdoc} */ protected $description = 'Generate service-templates.yaml based on /templates/compose directory'; - /** - * Execute the console command. - */ - public function handle() + public function handle(): int { - $files = array_diff(scandir(base_path('templates/compose')), ['.', '..']); - $files = array_filter($files, function ($file) { - return strpos($file, '.yaml') !== false; - }); - $serviceTemplatesJson = []; - foreach ($files as $file) { - $parsed = $this->process_file($file); - if ($parsed) { - $name = data_get($parsed, 'name'); - $parsed = data_forget($parsed, 'name'); - $serviceTemplatesJson[$name] = $parsed; - } - } - $serviceTemplatesJson = json_encode($serviceTemplatesJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + $serviceTemplatesJson = collect(glob(base_path('templates/compose/*.yaml'))) + ->mapWithKeys(function ($file): array { + $file = basename($file); + $parsed = $this->processFile($file); + + return $parsed === false ? [] : [ + Arr::pull($parsed, 'name') => $parsed, + ]; + })->toJson(JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + file_put_contents(base_path('templates/service-templates.json'), $serviceTemplatesJson.PHP_EOL); + + return self::SUCCESS; } - private function process_file($file) + private function processFile(string $file): false|array { - $serviceName = str($file)->before('.yaml')->value(); $content = file_get_contents(base_path("templates/compose/$file")); - // $this->info($content); - $ignore = collect(preg_grep('/^# ignore:/', explode("\n", $content)))->values(); - if ($ignore->count() > 0) { - $ignore = (bool) str($ignore[0])->after('# ignore:')->trim()->value(); - } else { - $ignore = false; - } - if ($ignore) { + + $data = collect(explode(PHP_EOL, $content))->mapWithKeys(function ($line): array { + preg_match('/^#(?.*):(?.*)$/U', $line, $m); + + return $m ? [trim($m['key']) => trim($m['value'])] : []; + }); + + if (str($data->get('ignore'))->toBoolean()) { $this->info("Ignoring $file"); - return; + return false; } + $this->info("Processing $file"); - $documentation = collect(preg_grep('/^# documentation:/', explode("\n", $content)))->values(); - if ($documentation->count() > 0) { - $documentation = str($documentation[0])->after('# documentation:')->trim()->value(); - $documentation = str($documentation)->append('?utm_source=coolify.io'); - } else { - $documentation = 'https://coolify.io/docs'; - } - $slogan = collect(preg_grep('/^# slogan:/', explode("\n", $content)))->values(); - if ($slogan->count() > 0) { - $slogan = str($slogan[0])->after('# slogan:')->trim()->value(); - } else { - $slogan = str($file)->headline()->value(); - } - $logo = collect(preg_grep('/^# logo:/', explode("\n", $content)))->values(); - if ($logo->count() > 0) { - $logo = str($logo[0])->after('# logo:')->trim()->value(); - } else { - $logo = 'svgs/coolify.png'; - } - $minversion = collect(preg_grep('/^# minversion:/', explode("\n", $content)))->values(); - if ($minversion->count() > 0) { - $minversion = str($minversion[0])->after('# minversion:')->trim()->value(); - } else { - $minversion = '0.0.0'; - } - $env_file = collect(preg_grep('/^# env_file:/', explode("\n", $content)))->values(); - if ($env_file->count() > 0) { - $env_file = str($env_file[0])->after('# env_file:')->trim()->value(); - } else { - $env_file = null; - } + $documentation = $data->get('documentation'); + $documentation = $documentation ? $documentation.'?utm_source=coolify.io' : 'https://coolify.io/docs'; - $tags = collect(preg_grep('/^# tags:/', explode("\n", $content)))->values(); - if ($tags->count() > 0) { - $tags = str($tags[0])->after('# tags:')->trim()->explode(',')->map(function ($tag) { - return str($tag)->trim()->lower()->value(); - })->values(); - } else { - $tags = null; - } - $port = collect(preg_grep('/^# port:/', explode("\n", $content)))->values(); - if ($port->count() > 0) { - $port = str($port[0])->after('# port:')->trim()->value(); - } else { - $port = null; - } $json = Yaml::parse($content); - $yaml = base64_encode(Yaml::dump($json, 10, 2)); + $compose = base64_encode(Yaml::dump($json, 10, 2)); + + $tags = str($data->get('tags'))->lower()->explode(',')->map(fn ($tag) => trim($tag))->filter(); + $tags = $tags->isEmpty() ? null : $tags->all(); + $payload = [ - 'name' => $serviceName, + 'name' => pathinfo($file, PATHINFO_FILENAME), 'documentation' => $documentation, - 'slogan' => $slogan, - 'compose' => $yaml, + 'slogan' => $data->get('slogan', str($file)->headline()), + 'compose' => $compose, 'tags' => $tags, - 'logo' => $logo, - 'minversion' => $minversion, + 'logo' => $data->get('logo', 'svgs/coolify.png'), + 'minversion' => $data->get('minversion', '0.0.0'), ]; - if ($port) { + + if ($port = $data->get('port')) { $payload['port'] = $port; } - if ($env_file) { - $env_file_content = file_get_contents(base_path("templates/compose/$env_file")); - $env_file_base64 = base64_encode($env_file_content); - $payload['envs'] = $env_file_base64; + + if ($envFile = $data->get('env_file')) { + $envFileContent = file_get_contents(base_path("templates/compose/$envFile")); + $payload['envs'] = base64_encode($envFileContent); } return $payload; diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 67ff819ed..cd560eee3 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -12,6 +12,7 @@ use App\Jobs\DockerCleanupJob; use App\Jobs\PullTemplatesFromCDN; use App\Jobs\ScheduledTaskJob; use App\Jobs\ServerCheckJob; +use App\Jobs\ServerCleanupMux; use App\Jobs\UpdateCoolifyJob; use App\Models\ScheduledDatabaseBackup; use App\Models\ScheduledTask; @@ -120,6 +121,8 @@ class Kernel extends ConsoleKernel } else { $schedule->job(new DockerCleanupJob($server))->everyTenMinutes()->timezone($serverTimezone)->onOneServer(); } + // Cleanup multiplexed connections every hour + $schedule->job(new ServerCleanupMux($server))->hourly()->onOneServer(); // Temporary solution until we have better memory management for Sentinel if ($server->isSentinelEnabled()) { diff --git a/app/Http/Controllers/Api/ApplicationsController.php b/app/Http/Controllers/Api/ApplicationsController.php index 0a088d1c3..6402ec651 100644 --- a/app/Http/Controllers/Api/ApplicationsController.php +++ b/app/Http/Controllers/Api/ApplicationsController.php @@ -1213,7 +1213,6 @@ class ApplicationsController extends Controller } return response()->json(['message' => 'Invalid type.'], 400); - } #[OA\Get( @@ -1692,9 +1691,8 @@ class ApplicationsController extends Controller 'standalone_postgresql_id', 'standalone_redis_id', ]); - $env = $this->removeSensitiveData($env); - return $env; + return $this->removeSensitiveData($env); }); return response()->json($envs); @@ -1869,18 +1867,15 @@ class ApplicationsController extends Controller return response()->json($this->removeSensitiveData($env))->setStatusCode(201); } else { - return response()->json([ 'message' => 'Environment variable not found.', ], 404); - } } return response()->json([ 'message' => 'Something is not okay. Are you okay?', ], 500); - } #[OA\Patch( @@ -2225,14 +2220,12 @@ class ApplicationsController extends Controller return response()->json([ 'uuid' => $env->uuid, ])->setStatusCode(201); - } } return response()->json([ 'message' => 'Something went wrong.', ], 500); - } #[OA\Delete( @@ -2580,7 +2573,6 @@ class ApplicationsController extends Controller 'deployment_uuid' => $deployment_uuid->toString(), ], ); - } #[OA\Post( @@ -2746,7 +2738,6 @@ class ApplicationsController extends Controller 'custom_labels' => 'The custom_labels should be base64 encoded.', ], ], 422); - } } if ($request->has('domains') && $server->isProxyShouldRun()) { diff --git a/app/Http/Controllers/Api/DatabasesController.php b/app/Http/Controllers/Api/DatabasesController.php index e30388ec8..821a40b79 100644 --- a/app/Http/Controllers/Api/DatabasesController.php +++ b/app/Http/Controllers/Api/DatabasesController.php @@ -471,7 +471,6 @@ class DatabasesController extends Controller $request->offsetSet('mysql_conf', $mysqlConf); } break; - } $extraFields = array_diff(array_keys($request->all()), $allowedFields); if ($validator->fails() || ! empty($extraFields)) { @@ -506,7 +505,6 @@ class DatabasesController extends Controller return response()->json([ 'message' => 'Database updated.', ]); - } #[OA\Post( @@ -1165,7 +1163,6 @@ class DatabasesController extends Controller } return response()->json(serializeApiResponse($payload))->setStatusCode(201); - } elseif ($type === NewDatabaseTypes::MARIADB) { $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'mariadb_conf', 'mariadb_root_password', 'mariadb_user', 'mariadb_password', 'mariadb_database']; $validator = customApiValidator($request->all(), [ @@ -1826,6 +1823,5 @@ class DatabasesController extends Controller ], 200 ); - } } diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php index f1958de2c..491179d5d 100644 --- a/app/Http/Controllers/Api/ProjectController.php +++ b/app/Http/Controllers/Api/ProjectController.php @@ -356,7 +356,6 @@ class ProjectController extends Controller 'name' => $project->name, 'description' => $project->description, ])->setStatusCode(201); - } #[OA\Delete( diff --git a/app/Http/Controllers/Api/ServicesController.php b/app/Http/Controllers/Api/ServicesController.php index 8ba2a938c..9127fa498 100644 --- a/app/Http/Controllers/Api/ServicesController.php +++ b/app/Http/Controllers/Api/ServicesController.php @@ -566,9 +566,8 @@ class ServicesController extends Controller 'standalone_postgresql_id', 'standalone_redis_id', ]); - $env = $this->removeSensitiveData($env); - return $env; + return $this->removeSensitiveData($env); }); return response()->json($envs); @@ -1238,6 +1237,5 @@ class ServicesController extends Controller ], 200 ); - } } diff --git a/app/Http/Controllers/UploadController.php b/app/Http/Controllers/UploadController.php index 21fdd2ef8..4d34a1000 100644 --- a/app/Http/Controllers/UploadController.php +++ b/app/Http/Controllers/UploadController.php @@ -5,7 +5,6 @@ namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Http\UploadedFile; use Illuminate\Routing\Controller as BaseController; -use Illuminate\Support\Facades\Storage; use Pion\Laravel\ChunkUpload\Exceptions\UploadMissingFileException; use Pion\Laravel\ChunkUpload\Handler\HandlerFactory; use Pion\Laravel\ChunkUpload\Receiver\FileReceiver; diff --git a/app/Http/Controllers/Webhook/Gitea.php b/app/Http/Controllers/Webhook/Gitea.php index 3689ca7b3..cc53f2034 100644 --- a/app/Http/Controllers/Webhook/Gitea.php +++ b/app/Http/Controllers/Webhook/Gitea.php @@ -174,7 +174,6 @@ class Gitea extends Controller 'pull_request_html_url' => $pull_request_html_url, ]); } - } queue_application_deployment( application: $application, diff --git a/app/Http/Controllers/Webhook/Stripe.php b/app/Http/Controllers/Webhook/Stripe.php index 55c94a618..5d297b242 100644 --- a/app/Http/Controllers/Webhook/Stripe.php +++ b/app/Http/Controllers/Webhook/Stripe.php @@ -13,7 +13,6 @@ use App\Models\Webhook; use Exception; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; -use Illuminate\Support\Sleep; use Illuminate\Support\Str; class Stripe extends Controller @@ -64,22 +63,18 @@ class Stripe extends Controller $piData = $stripe->paymentIntents->retrieve($pi, []); $customerId = data_get($piData, 'customer'); $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if (! $subscription) { - Sleep::for(5)->seconds(); - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - } - if (! $subscription) { - Sleep::for(5)->seconds(); - $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}"); + + return response("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}", 400); } - send_internal_notification("Early fraud warning created Refunded, subscription canceled. Charge: {$charge}, id: {$id}, pi: {$pi}"); break; case 'checkout.session.completed': $clientReferenceId = data_get($data, 'client_reference_id'); @@ -95,7 +90,8 @@ class Stripe extends Controller $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}."); + + 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) { @@ -123,13 +119,13 @@ class Stripe extends Controller break; } $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if (! $subscription) { - Sleep::for(5)->seconds(); - $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); + if ($subscription) { + $subscription->update([ + 'stripe_invoice_paid' => true, + ]); + } else { + return response("No subscription found for customer: {$customerId}", 400); } - $subscription->update([ - 'stripe_invoice_paid' => true, - ]); break; case 'invoice.payment_failed': $customerId = data_get($data, 'customer'); @@ -167,7 +163,42 @@ class Stripe extends Controller } 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'); @@ -177,32 +208,27 @@ class Stripe extends Controller break; } $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if (! $subscription) { - Sleep::for(5)->seconds(); - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - } if (! $subscription) { if ($status === 'incomplete_expired') { - // send_internal_notification('Subscription incomplete expired for customer: '.$customerId); - return response('Subscription incomplete expired', 200); } - // send_internal_notification('No subscription found for: '.$customerId); - - return response('No subscription found', 400); + 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); + } } - $trialEndedAlready = data_get($subscription, 'stripe_trial_already_ended'); $cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end'); - $alreadyCancelAtPeriodEnd = data_get($subscription, 'stripe_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('ultimate') || str($lookup_key)->contains('dynamic')) { - if (str($lookup_key)->contains('dynamic')) { - $quantity = data_get($data, 'items.data.0.quantity', 2); - } else { - $quantity = data_get($data, 'items.data.0.quantity', 10); - } + if (str($lookup_key)->contains('dynamic')) { + $quantity = data_get($data, 'items.data.0.quantity', 2); $team = data_get($subscription, 'team'); if ($team) { $team->update([ @@ -221,28 +247,12 @@ class Stripe extends Controller $subscription->update([ 'stripe_invoice_paid' => false, ]); - // send_internal_notification('Subscription paused or incomplete for customer: '.$customerId); } - - // Trial ended but subscribed, reactive servers - if ($trialEndedAlready && $status === 'active') { - $team = data_get($subscription, 'team'); - $team->trialEndedButSubscribed(); - } - if ($feedback) { $reason = "Cancellation feedback for {$customerId}: '".$feedback."'"; if ($comment) { $reason .= ' with comment: \''.$comment."'"; } - // send_internal_notification($reason); - } - if ($alreadyCancelAtPeriodEnd !== $cancelAtPeriodEnd) { - if ($cancelAtPeriodEnd) { - // send_internal_notification('Subscription cancelled at period end for team: ' . $subscription->team->id); - } else { - // send_internal_notification('customer.subscription.updated for customer: '.$customerId); - } } break; case 'customer.subscription.deleted': @@ -268,7 +278,7 @@ class Stripe extends Controller $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); $team = data_get($subscription, 'team'); if (! $team) { - throw new Exception('No team found for subscription: '.$subscription->id); + return response('No team found for subscription: '.$subscription->id, 400); } SubscriptionTrialEndsSoonJob::dispatch($team); break; @@ -277,7 +287,7 @@ class Stripe extends Controller $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); $team = data_get($subscription, 'team'); if (! $team) { - throw new Exception('No team found for subscription: '.$subscription->id); + return response('No team found for subscription: '.$subscription->id, 400); } $team->trialEnded(); $subscription->update([ diff --git a/app/Jobs/CheckHelperImageJob.php b/app/Jobs/CheckHelperImageJob.php index d62ad601f..6abb8a150 100644 --- a/app/Jobs/CheckHelperImageJob.php +++ b/app/Jobs/CheckHelperImageJob.php @@ -31,7 +31,6 @@ class CheckHelperImageJob implements ShouldBeEncrypted, ShouldQueue $settings->update(['helper_version' => $latest_version]); } } - } catch (\Throwable $e) { send_internal_notification('CheckHelperImageJob failed with: '.$e->getMessage()); throw $e; diff --git a/app/Jobs/DatabaseBackupJob.php b/app/Jobs/DatabaseBackupJob.php index 196af2a83..fcfe2fe3d 100644 --- a/app/Jobs/DatabaseBackupJob.php +++ b/app/Jobs/DatabaseBackupJob.php @@ -129,7 +129,6 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue if ($this->postgres_password) { $this->postgres_password = str($this->postgres_password)->after('POSTGRES_PASSWORD=')->value(); } - } elseif (str($databaseType)->contains('mysql')) { $this->container_name = "{$this->database->name}-$serviceUuid"; $this->directory_name = $serviceName.'-'.$this->container_name; diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index c1db7001d..24f8d1e6b 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -6,7 +6,7 @@ use App\Actions\Database\StartDatabaseProxy; use App\Actions\Database\StopDatabaseProxy; use App\Actions\Proxy\CheckProxy; use App\Actions\Proxy\StartProxy; -use App\Actions\Server\InstallLogDrain; +use App\Actions\Server\StartLogDrain; use App\Actions\Shared\ComplexStatusCheck; use App\Models\Application; use App\Models\ApplicationPreview; @@ -167,7 +167,6 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue $this->foundServiceDatabaseIds->push($subId); $this->updateServiceSubStatus($serviceId, $subType, $subId, $containerStatus); } - } else { $uuid = $labels->get('com.docker.compose.service'); $type = $labels->get('coolify.type'); @@ -265,7 +264,6 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue instant_remote_process($connectProxyToDockerNetworks, $this->server, false); } } - } private function updateDatabaseStatus(string $databaseUuid, string $containerStatus, bool $tcpProxy = false) @@ -362,7 +360,7 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue private function checkLogDrainContainer() { if ($this->server->isLogDrainEnabled() && $this->foundLogDrainContainer === false) { - InstallLogDrain::dispatch($this->server); + StartLogDrain::dispatch($this->server); } } } diff --git a/app/Jobs/ScheduledTaskJob.php b/app/Jobs/ScheduledTaskJob.php index 6850ae98a..827641e8c 100644 --- a/app/Jobs/ScheduledTaskJob.php +++ b/app/Jobs/ScheduledTaskJob.php @@ -54,13 +54,9 @@ class ScheduledTaskJob implements ShouldQueue private function getServerTimezone(): string { if ($this->resource instanceof Application) { - $timezone = $this->resource->destination->server->settings->server_timezone; - - return $timezone; + return $this->resource->destination->server->settings->server_timezone; } elseif ($this->resource instanceof Service) { - $timezone = $this->resource->server->settings->server_timezone; - - return $timezone; + return $this->resource->server->settings->server_timezone; } return 'UTC'; @@ -68,7 +64,6 @@ class ScheduledTaskJob implements ShouldQueue public function handle(): void { - try { $this->task_log = ScheduledTaskExecution::create([ 'scheduled_task_id' => $this->task->id, @@ -76,14 +71,14 @@ class ScheduledTaskJob implements ShouldQueue $this->server = $this->resource->destination->server; - if ($this->resource->type() == 'application') { + if ($this->resource->type() === 'application') { $containers = getCurrentApplicationContainerStatus($this->server, $this->resource->id, 0); if ($containers->count() > 0) { $containers->each(function ($container) { $this->containers[] = str_replace('/', '', $container['Names']); }); } - } elseif ($this->resource->type() == 'service') { + } elseif ($this->resource->type() === 'service') { $this->resource->applications()->get()->each(function ($application) { if (str(data_get($application, 'status'))->contains('running')) { $this->containers[] = data_get($application, 'name').'-'.data_get($this->resource, 'uuid'); diff --git a/app/Jobs/ServerCheckJob.php b/app/Jobs/ServerCheckJob.php index 727149181..26cb3c4f5 100644 --- a/app/Jobs/ServerCheckJob.php +++ b/app/Jobs/ServerCheckJob.php @@ -5,7 +5,7 @@ namespace App\Jobs; use App\Actions\Docker\GetContainersStatus; use App\Actions\Proxy\CheckProxy; use App\Actions\Proxy\StartProxy; -use App\Actions\Server\InstallLogDrain; +use App\Actions\Server\StartLogDrain; use App\Models\Server; use App\Notifications\Container\ContainerRestarted; use Illuminate\Bus\Queueable; @@ -94,11 +94,9 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue } } } - } catch (\Throwable $e) { return handleError($e); } - } private function checkLogDrainContainer() @@ -109,10 +107,10 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue if ($foundLogDrainContainer) { $status = data_get($foundLogDrainContainer, 'State.Status'); if ($status !== 'running') { - InstallLogDrain::dispatch($this->server); + StartLogDrain::dispatch($this->server); } } else { - InstallLogDrain::dispatch($this->server); + StartLogDrain::dispatch($this->server); } } } diff --git a/app/Jobs/ServerCleanupMux.php b/app/Jobs/ServerCleanupMux.php new file mode 100644 index 000000000..b793c3eca --- /dev/null +++ b/app/Jobs/ServerCleanupMux.php @@ -0,0 +1,40 @@ +server->serverStatus() === false) { + return 'Server is not reachable or not ready.'; + } + SshMultiplexingHelper::removeMuxFile($this->server); + } catch (\Throwable $e) { + return handleError($e); + } + } +} diff --git a/app/Jobs/ServerStorageCheckJob.php b/app/Jobs/ServerStorageCheckJob.php index c646f77eb..cc838c77f 100644 --- a/app/Jobs/ServerStorageCheckJob.php +++ b/app/Jobs/ServerStorageCheckJob.php @@ -38,7 +38,6 @@ class ServerStorageCheckJob implements ShouldBeEncrypted, ShouldQueue if (is_null($this->percentage)) { $this->percentage = $this->server->storageCheck(); - loggy('Server storage check percentage: '.$this->percentage); } if (! $this->percentage) { return 'No percentage could be retrieved.'; @@ -59,10 +58,8 @@ class ServerStorageCheckJob implements ShouldBeEncrypted, ShouldQueue } else { RateLimiter::hit('high-disk-usage:'.$this->server->id, 600); } - } catch (\Throwable $e) { return handleError($e); } - } } diff --git a/app/Jobs/UpdateCoolifyJob.php b/app/Jobs/UpdateCoolifyJob.php index 2cc705e4a..1e5197b6f 100644 --- a/app/Jobs/UpdateCoolifyJob.php +++ b/app/Jobs/UpdateCoolifyJob.php @@ -41,7 +41,6 @@ class UpdateCoolifyJob implements ShouldBeEncrypted, ShouldQueue $settings->update(['new_version_available' => false]); Log::info('Coolify update completed successfully.'); - } catch (\Throwable $e) { Log::error('UpdateCoolifyJob failed: '.$e->getMessage()); // Consider implementing a notification to administrators diff --git a/app/Livewire/ActivityMonitor.php b/app/Livewire/ActivityMonitor.php index bd1e30088..2e36f34ee 100644 --- a/app/Livewire/ActivityMonitor.php +++ b/app/Livewire/ActivityMonitor.php @@ -2,7 +2,6 @@ namespace App\Livewire; -use App\Enums\ProcessStatus; use App\Models\User; use Livewire\Component; use Spatie\Activitylog\Models\Activity; diff --git a/app/Livewire/Notifications/Discord.php b/app/Livewire/Notifications/Discord.php index 01ba8ffe1..db8594558 100644 --- a/app/Livewire/Notifications/Discord.php +++ b/app/Livewire/Notifications/Discord.php @@ -34,7 +34,7 @@ class Discord extends Component { try { $this->submit(); - } catch (\Throwable $e) { + } catch (\Throwable) { $this->team->discord_enabled = false; $this->validate(); } diff --git a/app/Livewire/Notifications/Telegram.php b/app/Livewire/Notifications/Telegram.php index 09a0f1c3c..862b9b3ea 100644 --- a/app/Livewire/Notifications/Telegram.php +++ b/app/Livewire/Notifications/Telegram.php @@ -41,7 +41,7 @@ class Telegram extends Component { try { $this->submit(); - } catch (\Throwable $e) { + } catch (\Throwable) { $this->team->telegram_enabled = false; $this->validate(); } diff --git a/app/Livewire/Project/Application/Deployment/Show.php b/app/Livewire/Project/Application/Deployment/Show.php index 3de895f8c..04170fa28 100644 --- a/app/Livewire/Project/Application/Deployment/Show.php +++ b/app/Livewire/Project/Application/Deployment/Show.php @@ -64,7 +64,7 @@ class Show extends Component { $this->dispatch('deploymentFinished'); $this->application_deployment_queue->refresh(); - if (data_get($this->application_deployment_queue, 'status') == 'finished' || data_get($this->application_deployment_queue, 'status') == 'failed') { + if (data_get($this->application_deployment_queue, 'status') === 'finished' || data_get($this->application_deployment_queue, 'status') === 'failed') { $this->isKeepAliveOn = false; } } diff --git a/app/Livewire/Project/Application/Preview/Form.php b/app/Livewire/Project/Application/Preview/Form.php index 9a0b9b851..73b423f90 100644 --- a/app/Livewire/Project/Application/Preview/Form.php +++ b/app/Livewire/Project/Application/Preview/Form.php @@ -36,7 +36,7 @@ class Form extends Component $url = Url::fromString($firstFqdn); $host = $url->getHost(); $this->preview_url_template = str($this->application->preview_url_template)->replace('{{domain}}', $host); - } catch (\Exception $e) { + } catch (\Exception) { $this->dispatch('error', 'Invalid FQDN.'); } } diff --git a/app/Livewire/Project/Application/Previews.php b/app/Livewire/Project/Application/Previews.php index b1ba035dc..d42bf03d7 100644 --- a/app/Livewire/Project/Application/Previews.php +++ b/app/Livewire/Project/Application/Previews.php @@ -5,6 +5,7 @@ namespace App\Livewire\Project\Application; use App\Actions\Docker\GetContainersStatus; use App\Models\Application; use App\Models\ApplicationPreview; +use Carbon\Carbon; use Illuminate\Process\InvokedProcess; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Process; @@ -239,7 +240,7 @@ class Previews extends Component $processes[$containerName] = $this->stopContainer($containerName, $timeout); } - $startTime = time(); + $startTime = Carbon::now()->getTimestamp(); while (count($processes) > 0) { $finishedProcesses = array_filter($processes, function ($process) { return ! $process->running(); @@ -249,7 +250,7 @@ class Previews extends Component $this->removeContainer($containerName, $server); } - if (time() - $startTime >= $timeout) { + if (Carbon::now()->getTimestamp() - $startTime >= $timeout) { $this->forceStopRemainingContainers(array_keys($processes), $server); break; } diff --git a/app/Livewire/Project/Database/BackupEdit.php b/app/Livewire/Project/Database/BackupEdit.php index 8d838ed3b..9b82c4b11 100644 --- a/app/Livewire/Project/Database/BackupEdit.php +++ b/app/Livewire/Project/Database/BackupEdit.php @@ -121,7 +121,7 @@ class BackupEdit extends Component { try { $this->custom_validate(); - if ($this->backup->databases_to_backup == '' || $this->backup->databases_to_backup === null) { + if ($this->backup->databases_to_backup === '' || $this->backup->databases_to_backup === null) { $this->backup->databases_to_backup = null; } $this->backup->save(); diff --git a/app/Livewire/Project/Database/BackupExecutions.php b/app/Livewire/Project/Database/BackupExecutions.php index 45c7c30e2..f91b8bfaf 100644 --- a/app/Livewire/Project/Database/BackupExecutions.php +++ b/app/Livewire/Project/Database/BackupExecutions.php @@ -119,9 +119,8 @@ class BackupExecutions extends Component if (! $server) { return 'UTC'; } - $serverTimezone = $server->settings->server_timezone; - return $serverTimezone; + return $server->settings->server_timezone; } public function formatDateInServerTimezone($date) @@ -130,7 +129,7 @@ class BackupExecutions extends Component $dateObj = new \DateTime($date); try { $dateObj->setTimezone(new \DateTimeZone($serverTimezone)); - } catch (\Exception $e) { + } catch (\Exception) { $dateObj->setTimezone(new \DateTimeZone('UTC')); } diff --git a/app/Livewire/Project/Database/Import.php b/app/Livewire/Project/Database/Import.php index cd9818b41..663e7a6d7 100644 --- a/app/Livewire/Project/Database/Import.php +++ b/app/Livewire/Project/Database/Import.php @@ -77,10 +77,10 @@ class Import extends Component } if ( - $this->resource->getMorphClass() == \App\Models\StandaloneRedis::class || - $this->resource->getMorphClass() == \App\Models\StandaloneKeydb::class || - $this->resource->getMorphClass() == \App\Models\StandaloneDragonfly::class || - $this->resource->getMorphClass() == \App\Models\StandaloneClickhouse::class + $this->resource->getMorphClass() === \App\Models\StandaloneRedis::class || + $this->resource->getMorphClass() === \App\Models\StandaloneKeydb::class || + $this->resource->getMorphClass() === \App\Models\StandaloneDragonfly::class || + $this->resource->getMorphClass() === \App\Models\StandaloneClickhouse::class ) { $this->unsupported = true; } @@ -88,8 +88,7 @@ class Import extends Component public function runImport() { - - if ($this->filename == '') { + if ($this->filename === '') { $this->dispatch('error', 'Please select a file to import.'); return; diff --git a/app/Livewire/Project/Database/Keydb/General.php b/app/Livewire/Project/Database/Keydb/General.php index f976e1edd..df04f70d7 100644 --- a/app/Livewire/Project/Database/Keydb/General.php +++ b/app/Livewire/Project/Database/Keydb/General.php @@ -51,7 +51,6 @@ class General extends Component $this->db_url = $this->database->internal_db_url; $this->db_url_public = $this->database->external_db_url; $this->server = data_get($this->database, 'destination.server'); - } public function instantSaveAdvanced() diff --git a/app/Livewire/Project/Database/Mariadb/General.php b/app/Livewire/Project/Database/Mariadb/General.php index 12d4882f3..c9d473223 100644 --- a/app/Livewire/Project/Database/Mariadb/General.php +++ b/app/Livewire/Project/Database/Mariadb/General.php @@ -57,7 +57,6 @@ class General extends Component $this->db_url = $this->database->internal_db_url; $this->db_url_public = $this->database->external_db_url; $this->server = data_get($this->database, 'destination.server'); - } public function instantSaveAdvanced() diff --git a/app/Livewire/Project/Database/Mongodb/General.php b/app/Livewire/Project/Database/Mongodb/General.php index ac40e7dfa..e19895dae 100644 --- a/app/Livewire/Project/Database/Mongodb/General.php +++ b/app/Livewire/Project/Database/Mongodb/General.php @@ -55,7 +55,6 @@ class General extends Component $this->db_url = $this->database->internal_db_url; $this->db_url_public = $this->database->external_db_url; $this->server = data_get($this->database, 'destination.server'); - } public function instantSaveAdvanced() diff --git a/app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php b/app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php index 0edafd040..b46c4a794 100644 --- a/app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php +++ b/app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php @@ -198,7 +198,7 @@ class GithubPrivateRepositoryDeployKey extends Component $this->git_host = $this->repository_url_parsed->getHost(); $this->git_repository = $this->repository_url_parsed->getSegment(1).'/'.$this->repository_url_parsed->getSegment(2); - if ($this->git_host == 'github.com') { + if ($this->git_host === 'github.com') { $this->git_source = GithubApp::where('name', 'Public GitHub')->first(); return; diff --git a/app/Livewire/Project/New/PublicGitRepository.php b/app/Livewire/Project/New/PublicGitRepository.php index 55eb5c77d..bd35dccef 100644 --- a/app/Livewire/Project/New/PublicGitRepository.php +++ b/app/Livewire/Project/New/PublicGitRepository.php @@ -99,7 +99,6 @@ class PublicGitRepository extends Component $this->base_directory = '/'.$this->base_directory; } } - } public function updatedDockerComposeLocation() @@ -174,7 +173,7 @@ class PublicGitRepository extends Component return; } - if (! $this->branchFound && $this->git_branch == 'main') { + if (! $this->branchFound && $this->git_branch === 'main') { try { $this->git_branch = 'master'; $this->getBranch(); @@ -197,7 +196,7 @@ class PublicGitRepository extends Component } else { $this->git_branch = 'main'; } - if ($this->git_host == 'github.com') { + if ($this->git_host === 'github.com') { $this->git_source = GithubApp::where('name', 'Public GitHub')->first(); return; diff --git a/app/Livewire/Project/Resource/Create.php b/app/Livewire/Project/Resource/Create.php index 5c6a37d6d..9266a57fc 100644 --- a/app/Livewire/Project/Resource/Create.php +++ b/app/Livewire/Project/Resource/Create.php @@ -100,7 +100,6 @@ class Create extends Component 'is_preview' => false, ]); } - }); } $service->parse(isNew: true); diff --git a/app/Livewire/Project/Service/Database.php b/app/Livewire/Project/Service/Database.php index f95075de6..9f02db05c 100644 --- a/app/Livewire/Project/Service/Database.php +++ b/app/Livewire/Project/Service/Database.php @@ -95,7 +95,7 @@ class Database extends Component $this->database->save(); updateCompose($this->database); $this->dispatch('success', 'Database saved.'); - } catch (\Throwable $e) { + } catch (\Throwable) { } finally { $this->dispatch('generateDockerCompose'); } diff --git a/app/Livewire/Project/Service/Index.php b/app/Livewire/Project/Service/Index.php index 0a7b6ec90..ba4ebe2fc 100644 --- a/app/Livewire/Project/Service/Index.php +++ b/app/Livewire/Project/Service/Index.php @@ -48,7 +48,6 @@ class Index extends Component } catch (\Throwable $e) { return handleError($e, $this); } - } public function generateDockerCompose() diff --git a/app/Livewire/Project/Service/Navbar.php b/app/Livewire/Project/Service/Navbar.php index 2c5198387..67b575599 100644 --- a/app/Livewire/Project/Service/Navbar.php +++ b/app/Livewire/Project/Service/Navbar.php @@ -76,7 +76,7 @@ class Navbar extends Component } else { $this->isDeploymentProgress = false; } - } catch (\Throwable $e) { + } catch (\Throwable) { $this->isDeploymentProgress = false; } } diff --git a/app/Livewire/Project/Shared/Danger.php b/app/Livewire/Project/Shared/Danger.php index 2a21532ce..a0b4ac2c4 100644 --- a/app/Livewire/Project/Shared/Danger.php +++ b/app/Livewire/Project/Shared/Danger.php @@ -62,32 +62,21 @@ class Danger extends Component return; } - switch ($this->resource->type()) { - case 'application': - $this->resourceName = $this->resource->name ?? 'Application'; - break; - case 'standalone-postgresql': - case 'standalone-redis': - case 'standalone-mongodb': - case 'standalone-mysql': - case 'standalone-mariadb': - case 'standalone-keydb': - case 'standalone-dragonfly': - case 'standalone-clickhouse': - $this->resourceName = $this->resource->name ?? 'Database'; - break; - case 'service': - $this->resourceName = $this->resource->name ?? 'Service'; - break; - case 'service-application': - $this->resourceName = $this->resource->name ?? 'Service Application'; - break; - case 'service-database': - $this->resourceName = $this->resource->name ?? 'Service Database'; - break; - default: - $this->resourceName = 'Unknown Resource'; - } + $this->resourceName = match ($this->resource->type()) { + 'application' => $this->resource->name ?? 'Application', + 'standalone-postgresql', + 'standalone-redis', + 'standalone-mongodb', + 'standalone-mysql', + 'standalone-mariadb', + 'standalone-keydb', + 'standalone-dragonfly', + 'standalone-clickhouse' => $this->resource->name ?? 'Database', + 'service' => $this->resource->name ?? 'Service', + 'service-application' => $this->resource->name ?? 'Service Application', + 'service-database' => $this->resource->name ?? 'Service Database', + default => 'Unknown Resource', + }; } public function delete($password) diff --git a/app/Livewire/Project/Shared/ExecuteContainerCommand.php b/app/Livewire/Project/Shared/ExecuteContainerCommand.php index 574dfa969..621ab1bac 100644 --- a/app/Livewire/Project/Shared/ExecuteContainerCommand.php +++ b/app/Livewire/Project/Shared/ExecuteContainerCommand.php @@ -132,7 +132,6 @@ class ExecuteContainerCommand extends Component } }); } - } if ($this->containers->count() > 0) { $this->container = $this->containers->first(); @@ -155,7 +154,6 @@ class ExecuteContainerCommand extends Component data_get($this->server, 'name'), data_get($this->server, 'uuid') ); - } catch (\Throwable $e) { return handleError($e, $this); } @@ -185,7 +183,6 @@ class ExecuteContainerCommand extends Component data_get($container, 'container.Names'), data_get($container, 'server.uuid') ); - } catch (\Throwable $e) { return handleError($e, $this); } diff --git a/app/Livewire/Project/Shared/Logs.php b/app/Livewire/Project/Shared/Logs.php index e2b57aab3..12022b1ee 100644 --- a/app/Livewire/Project/Shared/Logs.php +++ b/app/Livewire/Project/Shared/Logs.php @@ -109,9 +109,7 @@ class Logs extends Component $this->containers = $this->containers->filter(function ($container) { return str_contains($container, $this->query['pull_request_id']); }); - } - } catch (\Exception $e) { return handleError($e, $this); } diff --git a/app/Livewire/Project/Shared/ResourceOperations.php b/app/Livewire/Project/Shared/ResourceOperations.php index 414ebba03..e67df6aa9 100644 --- a/app/Livewire/Project/Shared/ResourceOperations.php +++ b/app/Livewire/Project/Shared/ResourceOperations.php @@ -147,7 +147,6 @@ class ResourceOperations extends Component return redirect()->to($route); } - } public function moveTo($environment_id) diff --git a/app/Livewire/Project/Shared/ScheduledTask/Add.php b/app/Livewire/Project/Shared/ScheduledTask/Add.php index f36b7b141..adfd59217 100644 --- a/app/Livewire/Project/Shared/ScheduledTask/Add.php +++ b/app/Livewire/Project/Shared/ScheduledTask/Add.php @@ -55,8 +55,8 @@ class Add extends Component return; } - if (empty($this->container) || $this->container == 'null') { - if ($this->type == 'service') { + if (empty($this->container) || $this->container === 'null') { + if ($this->type === 'service') { $this->container = $this->subServiceName; } } diff --git a/app/Livewire/Project/Shared/ScheduledTask/All.php b/app/Livewire/Project/Shared/ScheduledTask/All.php index b383e294a..6ab8426f3 100644 --- a/app/Livewire/Project/Shared/ScheduledTask/All.php +++ b/app/Livewire/Project/Shared/ScheduledTask/All.php @@ -21,10 +21,10 @@ class All extends Component public function mount() { $this->parameters = get_route_parameters(); - if ($this->resource->type() == 'service') { + if ($this->resource->type() === 'service') { $this->containerNames = $this->resource->applications()->pluck('name'); $this->containerNames = $this->containerNames->merge($this->resource->databases()->pluck('name')); - } elseif ($this->resource->type() == 'application') { + } elseif ($this->resource->type() === 'application') { if ($this->resource->build_pack === 'dockercompose') { $parsed = $this->resource->parse(); $containers = collect(data_get($parsed, 'services'))->keys(); diff --git a/app/Livewire/Project/Shared/ScheduledTask/Executions.php b/app/Livewire/Project/Shared/ScheduledTask/Executions.php index 017cc9fd7..05d9a7a13 100644 --- a/app/Livewire/Project/Shared/ScheduledTask/Executions.php +++ b/app/Livewire/Project/Shared/ScheduledTask/Executions.php @@ -54,9 +54,8 @@ class Executions extends Component if (! $server) { return 'UTC'; } - $serverTimezone = $server->settings->server_timezone; - return $serverTimezone; + return $server->settings->server_timezone; } public function formatDateInServerTimezone($date) @@ -65,7 +64,7 @@ class Executions extends Component $dateObj = new \DateTime($date); try { $dateObj->setTimezone(new \DateTimeZone($serverTimezone)); - } catch (\Exception $e) { + } catch (\Exception) { $dateObj->setTimezone(new \DateTimeZone('UTC')); } diff --git a/app/Livewire/Project/Shared/ScheduledTask/Show.php b/app/Livewire/Project/Shared/ScheduledTask/Show.php index 37f50dd32..36194edb7 100644 --- a/app/Livewire/Project/Shared/ScheduledTask/Show.php +++ b/app/Livewire/Project/Shared/ScheduledTask/Show.php @@ -77,7 +77,7 @@ class Show extends Component try { $this->task->delete(); - if ($this->type == 'application') { + if ($this->type === 'application') { return redirect()->route('project.application.configuration', $this->parameters, $this->scheduledTaskName); } else { return redirect()->route('project.service.configuration', $this->parameters, $this->scheduledTaskName); diff --git a/app/Livewire/Project/Shared/Storages/Add.php b/app/Livewire/Project/Shared/Storages/Add.php index afa27a6bd..6e250bd90 100644 --- a/app/Livewire/Project/Shared/Storages/Add.php +++ b/app/Livewire/Project/Shared/Storages/Add.php @@ -100,7 +100,6 @@ class Add extends Component } catch (\Throwable $e) { return handleError($e, $this); } - } public function submitFileStorageDirectory() @@ -127,7 +126,6 @@ class Add extends Component } catch (\Throwable $e) { return handleError($e, $this); } - } public function submitPersistentVolume() @@ -144,7 +142,6 @@ class Add extends Component 'mount_path' => $this->mount_path, 'host_path' => $this->host_path, ]); - } catch (\Throwable $e) { return handleError($e, $this); } diff --git a/app/Livewire/Project/Shared/Terminal.php b/app/Livewire/Project/Shared/Terminal.php index 916db650f..5af8f057e 100644 --- a/app/Livewire/Project/Shared/Terminal.php +++ b/app/Livewire/Project/Shared/Terminal.php @@ -26,7 +26,6 @@ class Terminal extends Component #[On('send-terminal-command')] public function sendTerminalCommand($isContainer, $identifier, $serverUuid) { - $server = Server::ownedByCurrentTeam()->whereUuid($serverUuid)->firstOrFail(); if ($isContainer) { diff --git a/app/Livewire/Project/Shared/UploadConfig.php b/app/Livewire/Project/Shared/UploadConfig.php index 3859b387a..1b10f588b 100644 --- a/app/Livewire/Project/Shared/UploadConfig.php +++ b/app/Livewire/Project/Shared/UploadConfig.php @@ -37,7 +37,6 @@ class UploadConfig extends Component return; } - } public function render() diff --git a/app/Livewire/Security/PrivateKey/Show.php b/app/Livewire/Security/PrivateKey/Show.php index 249c84f14..b9195b543 100644 --- a/app/Livewire/Security/PrivateKey/Show.php +++ b/app/Livewire/Security/PrivateKey/Show.php @@ -28,7 +28,7 @@ class Show extends Component { try { $this->private_key = PrivateKey::ownedByCurrentTeam(['name', 'description', 'private_key', 'is_git_related'])->whereUuid(request()->private_key_uuid)->firstOrFail(); - } catch (\Throwable $e) { + } catch (\Throwable) { abort(404); } } diff --git a/app/Livewire/Server/Advanced.php b/app/Livewire/Server/Advanced.php index 4d2d777d4..becae9f04 100644 --- a/app/Livewire/Server/Advanced.php +++ b/app/Livewire/Server/Advanced.php @@ -4,45 +4,82 @@ namespace App\Livewire\Server; use App\Jobs\DockerCleanupJob; use App\Models\Server; +use Livewire\Attributes\Rule; use Livewire\Component; class Advanced extends Component { public Server $server; - protected $rules = [ - 'server.settings.concurrent_builds' => 'required|integer|min:1', - 'server.settings.dynamic_timeout' => 'required|integer|min:1', - 'server.settings.force_docker_cleanup' => 'required|boolean', - 'server.settings.docker_cleanup_frequency' => 'required_if:server.settings.force_docker_cleanup,true|string', - 'server.settings.docker_cleanup_threshold' => 'required_if:server.settings.force_docker_cleanup,false|integer|min:1|max:100', - 'server.settings.server_disk_usage_notification_threshold' => 'required|integer|min:50|max:100', - 'server.settings.delete_unused_volumes' => 'boolean', - 'server.settings.delete_unused_networks' => 'boolean', - ]; + public array $parameters = []; - protected $validationAttributes = [ + #[Rule(['integer', 'min:1'])] + public int $concurrentBuilds = 1; - 'server.settings.concurrent_builds' => 'Concurrent Builds', - 'server.settings.dynamic_timeout' => 'Dynamic Timeout', - 'server.settings.force_docker_cleanup' => 'Force Docker Cleanup', - 'server.settings.docker_cleanup_frequency' => 'Docker Cleanup Frequency', - 'server.settings.docker_cleanup_threshold' => 'Docker Cleanup Threshold', - 'server.settings.server_disk_usage_notification_threshold' => 'Server Disk Usage Notification Threshold', - 'server.settings.delete_unused_volumes' => 'Delete Unused Volumes', - 'server.settings.delete_unused_networks' => 'Delete Unused Networks', - ]; + #[Rule(['integer', 'min:1'])] + public int $dynamicTimeout = 1; + + #[Rule('boolean')] + public bool $forceDockerCleanup = false; + + #[Rule('string')] + public string $dockerCleanupFrequency = '*/10 * * * *'; + + #[Rule(['integer', 'min:1', 'max:99'])] + public int $dockerCleanupThreshold = 10; + + #[Rule(['integer', 'min:1', 'max:99'])] + public int $serverDiskUsageNotificationThreshold = 50; + + #[Rule('boolean')] + public bool $deleteUnusedVolumes = false; + + #[Rule('boolean')] + public bool $deleteUnusedNetworks = false; + + public function mount(string $server_uuid) + { + try { + $this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail(); + $this->parameters = get_route_parameters(); + $this->syncData(); + } catch (\Throwable) { + return redirect()->route('server.show'); + } + } + + public function syncData(bool $toModel = false) + { + if ($toModel) { + $this->validate(); + $this->server->settings->concurrent_builds = $this->concurrentBuilds; + $this->server->settings->dynamic_timeout = $this->dynamicTimeout; + $this->server->settings->force_docker_cleanup = $this->forceDockerCleanup; + $this->server->settings->docker_cleanup_frequency = $this->dockerCleanupFrequency; + $this->server->settings->docker_cleanup_threshold = $this->dockerCleanupThreshold; + $this->server->settings->server_disk_usage_notification_threshold = $this->serverDiskUsageNotificationThreshold; + $this->server->settings->delete_unused_volumes = $this->deleteUnusedVolumes; + $this->server->settings->delete_unused_networks = $this->deleteUnusedNetworks; + $this->server->settings->save(); + } else { + $this->concurrentBuilds = $this->server->settings->concurrent_builds; + $this->dynamicTimeout = $this->server->settings->dynamic_timeout; + $this->forceDockerCleanup = $this->server->settings->force_docker_cleanup; + $this->dockerCleanupFrequency = $this->server->settings->docker_cleanup_frequency; + $this->dockerCleanupThreshold = $this->server->settings->docker_cleanup_threshold; + $this->serverDiskUsageNotificationThreshold = $this->server->settings->server_disk_usage_notification_threshold; + $this->deleteUnusedVolumes = $this->server->settings->delete_unused_volumes; + $this->deleteUnusedNetworks = $this->server->settings->delete_unused_networks; + } + } public function instantSave() { try { - $this->validate(); - $this->server->settings->save(); + $this->syncData(true); $this->dispatch('success', 'Server updated.'); - $this->dispatch('refreshServerShow'); + // $this->dispatch('refreshServerShow'); } catch (\Throwable $e) { - $this->server->settings->refresh(); - return handleError($e, $this); } } @@ -60,12 +97,11 @@ class Advanced extends Component public function submit() { try { - $frequency = $this->server->settings->docker_cleanup_frequency; - if (empty($frequency) || ! validate_cron_expression($frequency)) { - $this->server->settings->docker_cleanup_frequency = '*/10 * * * *'; - throw new \Exception('Invalid Cron / Human expression for Docker Cleanup Frequency. Resetting to default 10 minutes.'); + if (! validate_cron_expression($this->dockerCleanupFrequency)) { + $this->dockerCleanupFrequency = $this->server->settings->getOriginal('docker_cleanup_frequency'); + throw new \Exception('Invalid Cron / Human expression for Docker Cleanup Frequency.'); } - $this->server->settings->save(); + $this->syncData(true); $this->dispatch('success', 'Server updated.'); } catch (\Throwable $e) { return handleError($e, $this); diff --git a/app/Livewire/Server/Charts.php b/app/Livewire/Server/Charts.php index 20f8dd9ed..d0db87f57 100644 --- a/app/Livewire/Server/Charts.php +++ b/app/Livewire/Server/Charts.php @@ -19,6 +19,15 @@ class Charts extends Component public bool $poll = true; + public function mount(string $server_uuid) + { + try { + $this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail(); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + public function pollData() { if ($this->poll || $this->interval <= 10) { @@ -40,7 +49,6 @@ class Charts extends Component $this->dispatch("refreshChartData-{$this->chartId}-memory", [ 'seriesData' => $memoryMetrics, ]); - } catch (\Throwable $e) { return handleError($e, $this); } diff --git a/app/Livewire/Server/CloudflareTunnels.php b/app/Livewire/Server/CloudflareTunnels.php index 82bc789db..f16962bca 100644 --- a/app/Livewire/Server/CloudflareTunnels.php +++ b/app/Livewire/Server/CloudflareTunnels.php @@ -3,27 +3,33 @@ namespace App\Livewire\Server; use App\Models\Server; +use Livewire\Attributes\Rule; use Livewire\Component; class CloudflareTunnels extends Component { public Server $server; - protected $rules = [ - 'server.settings.is_cloudflare_tunnel' => 'required|boolean', - ]; + #[Rule(['required', 'boolean'])] + public bool $isCloudflareTunnelsEnabled; - protected $validationAttributes = [ - 'server.settings.is_cloudflare_tunnel' => 'Cloudflare Tunnel', - ]; + public function mount(string $server_uuid) + { + try { + $this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail(); + $this->isCloudflareTunnelsEnabled = $this->server->settings->is_cloudflare_tunnel; + } catch (\Throwable $e) { + return handleError($e, $this); + } + } public function instantSave() { try { $this->validate(); + $this->server->settings->is_cloudflare_tunnel = $this->isCloudflareTunnelsEnabled; $this->server->settings->save(); $this->dispatch('success', 'Server updated.'); - $this->dispatch('refreshServerShow'); } catch (\Throwable $e) { return handleError($e, $this); } @@ -31,6 +37,7 @@ class CloudflareTunnels extends Component public function manualCloudflareConfig() { + $this->isCloudflareTunnelsEnabled = true; $this->server->settings->is_cloudflare_tunnel = true; $this->server->settings->save(); $this->server->refresh(); diff --git a/app/Livewire/Server/Delete.php b/app/Livewire/Server/Delete.php index cc2b335e1..b9e3944b5 100644 --- a/app/Livewire/Server/Delete.php +++ b/app/Livewire/Server/Delete.php @@ -4,6 +4,7 @@ namespace App\Livewire\Server; use App\Actions\Server\DeleteServer; use App\Models\InstanceSettings; +use App\Models\Server; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; @@ -13,7 +14,16 @@ class Delete extends Component { use AuthorizesRequests; - public $server; + public Server $server; + + public function mount(string $server_uuid) + { + try { + $this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail(); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } public function delete($password) { diff --git a/app/Livewire/Server/Destination/Show.php b/app/Livewire/Server/Destination/Show.php index 986e16cbf..71c051a74 100644 --- a/app/Livewire/Server/Destination/Show.php +++ b/app/Livewire/Server/Destination/Show.php @@ -3,27 +3,87 @@ namespace App\Livewire\Server\Destination; use App\Models\Server; +use App\Models\StandaloneDocker; +use App\Models\SwarmDocker; +use Illuminate\Support\Collection; use Livewire\Component; class Show extends Component { - public ?Server $server = null; + public Server $server; - public $parameters = []; + public Collection $networks; - public function mount() + public function mount(string $server_uuid) { - $this->parameters = get_route_parameters(); try { - $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first(); - if (is_null($this->server)) { - return redirect()->route('server.index'); - } + $this->networks = collect(); + $this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail(); + loggy($this->server); } catch (\Throwable $e) { return handleError($e, $this); } } + private function createNetworkAndAttachToProxy() + { + $connectProxyToDockerNetworks = connectProxyToNetworks($this->server); + instant_remote_process($connectProxyToDockerNetworks, $this->server, false); + } + + public function add($name) + { + if ($this->server->isSwarm()) { + $found = $this->server->swarmDockers()->where('network', $name)->first(); + if ($found) { + $this->dispatch('error', 'Network already added to this server.'); + + return; + } else { + SwarmDocker::create([ + 'name' => $this->server->name.'-'.$name, + 'network' => $this->name, + 'server_id' => $this->server->id, + ]); + } + } else { + $found = $this->server->standaloneDockers()->where('network', $name)->first(); + if ($found) { + $this->dispatch('error', 'Network already added to this server.'); + + return; + } else { + StandaloneDocker::create([ + 'name' => $this->server->name.'-'.$name, + 'network' => $name, + 'server_id' => $this->server->id, + ]); + } + $this->createNetworkAndAttachToProxy(); + } + } + + public function scan() + { + if ($this->server->isSwarm()) { + $alreadyAddedNetworks = $this->server->swarmDockers; + } else { + $alreadyAddedNetworks = $this->server->standaloneDockers; + } + $networks = instant_remote_process(['docker network ls --format "{{json .}}"'], $this->server, false); + $this->networks = format_docker_command_output_to_json($networks)->filter(function ($network) { + return $network['Name'] !== 'bridge' && $network['Name'] !== 'host' && $network['Name'] !== 'none'; + })->filter(function ($network) use ($alreadyAddedNetworks) { + return ! $alreadyAddedNetworks->contains('network', $network['Name']); + }); + if ($this->networks->count() === 0) { + $this->dispatch('success', 'No new destinations found on this server.'); + + return; + } + $this->dispatch('success', 'Scan done.'); + } + public function render() { return view('livewire.server.destination.show'); diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index bfe2853c0..740421373 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -86,7 +86,6 @@ class Form extends Component $this->server = $server; $this->timezones = collect(timezone_identifiers_list())->sort()->values()->toArray(); $this->wildcard_domain = $this->server->settings->wildcard_domain; - } public function checkSyncStatus() @@ -111,7 +110,7 @@ class Form extends Component { if ($field === 'server.settings.docker_cleanup_frequency') { $frequency = $this->server->settings->docker_cleanup_frequency; - if (empty($frequency) || ! validate_cron_expression($frequency)) { + if (! validate_cron_expression($frequency)) { $this->dispatch('error', 'Invalid Cron / Human expression for Docker Cleanup Frequency. Resetting to default 10 minutes.'); $this->server->settings->docker_cleanup_frequency = '*/10 * * * *'; } @@ -169,7 +168,6 @@ class Form extends Component public function instantSave() { try { - $this->validate(); refresh_server_connection($this->server->privateKey); $this->validateServer(false); diff --git a/app/Livewire/Server/LogDrains.php b/app/Livewire/Server/LogDrains.php index 6e09eecdd..fb8ef329f 100644 --- a/app/Livewire/Server/LogDrains.php +++ b/app/Livewire/Server/LogDrains.php @@ -2,84 +2,94 @@ namespace App\Livewire\Server; -use App\Actions\Server\InstallLogDrain; +use App\Actions\Server\StartLogDrain; use App\Actions\Server\StopLogDrain; use App\Models\Server; +use Livewire\Attributes\Rule; use Livewire\Component; class LogDrains extends Component { public Server $server; - public $parameters = []; + #[Rule(['boolean'])] + public bool $isLogDrainNewRelicEnabled = false; - protected $rules = [ - 'server.settings.is_logdrain_newrelic_enabled' => 'required|boolean', - 'server.settings.logdrain_newrelic_license_key' => 'required|string', - 'server.settings.logdrain_newrelic_base_uri' => 'required|string', - 'server.settings.is_logdrain_highlight_enabled' => 'required|boolean', - 'server.settings.logdrain_highlight_project_id' => 'required|string', - 'server.settings.is_logdrain_axiom_enabled' => 'required|boolean', - 'server.settings.logdrain_axiom_dataset_name' => 'required|string', - 'server.settings.logdrain_axiom_api_key' => 'required|string', - 'server.settings.is_logdrain_custom_enabled' => 'required|boolean', - 'server.settings.logdrain_custom_config' => 'required|string', - 'server.settings.logdrain_custom_config_parser' => 'nullable', - ]; + #[Rule(['boolean'])] + public bool $isLogDrainCustomEnabled = false; - protected $validationAttributes = [ - 'server.settings.is_logdrain_newrelic_enabled' => 'New Relic log drain', - 'server.settings.logdrain_newrelic_license_key' => 'New Relic license key', - 'server.settings.logdrain_newrelic_base_uri' => 'New Relic base URI', - 'server.settings.is_logdrain_highlight_enabled' => 'Highlight log drain', - 'server.settings.logdrain_highlight_project_id' => 'Highlight project ID', - 'server.settings.is_logdrain_axiom_enabled' => 'Axiom log drain', - 'server.settings.logdrain_axiom_dataset_name' => 'Axiom dataset name', - 'server.settings.logdrain_axiom_api_key' => 'Axiom API key', - 'server.settings.is_logdrain_custom_enabled' => 'Custom log drain', - 'server.settings.logdrain_custom_config' => 'Custom log drain configuration', - 'server.settings.logdrain_custom_config_parser' => 'Custom log drain configuration parser', - ]; + #[Rule(['boolean'])] + public bool $isLogDrainAxiomEnabled = false; - public function mount() + #[Rule(['string', 'nullable'])] + public ?string $logDrainNewRelicLicenseKey = null; + + #[Rule(['url', 'nullable'])] + public ?string $logDrainNewRelicBaseUri = null; + + #[Rule(['string', 'nullable'])] + public ?string $logDrainAxiomDatasetName = null; + + #[Rule(['string', 'nullable'])] + public ?string $logDrainAxiomApiKey = null; + + #[Rule(['string', 'nullable'])] + public ?string $logDrainCustomConfig = null; + + #[Rule(['string', 'nullable'])] + public ?string $logDrainCustomConfigParser = null; + + public function mount(string $server_uuid) { - $this->parameters = get_route_parameters(); try { - $server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first(); - if (is_null($server)) { - return redirect()->route('server.index'); - } - $this->server = $server; + $this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail(); + $this->syncData(); } catch (\Throwable $e) { return handleError($e, $this); } } - public function configureLogDrain() + public function syncData(bool $toModel = false) + { + if ($toModel) { + $this->validate(); + $this->server->settings->is_logdrain_newrelic_enabled = $this->isLogDrainNewRelicEnabled; + $this->server->settings->is_logdrain_axiom_enabled = $this->isLogDrainAxiomEnabled; + $this->server->settings->is_logdrain_custom_enabled = $this->isLogDrainCustomEnabled; + + $this->server->settings->logdrain_newrelic_license_key = $this->logDrainNewRelicLicenseKey; + $this->server->settings->logdrain_newrelic_base_uri = $this->logDrainNewRelicBaseUri; + $this->server->settings->logdrain_axiom_dataset_name = $this->logDrainAxiomDatasetName; + $this->server->settings->logdrain_axiom_api_key = $this->logDrainAxiomApiKey; + $this->server->settings->logdrain_custom_config = $this->logDrainCustomConfig; + $this->server->settings->logdrain_custom_config_parser = $this->logDrainCustomConfigParser; + + $this->server->settings->save(); + } else { + $this->isLogDrainNewRelicEnabled = $this->server->settings->is_logdrain_newrelic_enabled; + $this->isLogDrainAxiomEnabled = $this->server->settings->is_logdrain_axiom_enabled; + $this->isLogDrainCustomEnabled = $this->server->settings->is_logdrain_custom_enabled; + + $this->logDrainNewRelicLicenseKey = $this->server->settings->logdrain_newrelic_license_key; + $this->logDrainNewRelicBaseUri = $this->server->settings->logdrain_newrelic_base_uri; + $this->logDrainAxiomDatasetName = $this->server->settings->logdrain_axiom_dataset_name; + $this->logDrainAxiomApiKey = $this->server->settings->logdrain_axiom_api_key; + $this->logDrainCustomConfig = $this->server->settings->logdrain_custom_config; + $this->logDrainCustomConfigParser = $this->server->settings->logdrain_custom_config_parser; + } + } + + public function instantSave() { try { - InstallLogDrain::run($this->server); - if (! $this->server->isLogDrainEnabled()) { - $this->dispatch('serverRefresh'); + $this->syncData(true); + if ($this->server->isLogDrainEnabled()) { + StartLogDrain::run($this->server); + $this->dispatch('success', 'Log drain service started.'); + } else { + StopLogDrain::run($this->server); $this->dispatch('success', 'Log drain service stopped.'); - - return; } - $this->dispatch('serverRefresh'); - $this->dispatch('success', 'Log drain service started.'); - } catch (\Throwable $e) { - return handleError($e, $this); - } - } - - public function instantSave(string $type) - { - try { - $ok = $this->submit($type); - if (! $ok) { - return; - } - $this->configureLogDrain(); } catch (\Throwable $e) { return handleError($e, $this); } @@ -88,79 +98,10 @@ class LogDrains extends Component public function submit(string $type) { try { - $this->resetErrorBag(); - if ($type === 'newrelic') { - $this->validate([ - 'server.settings.is_logdrain_newrelic_enabled' => 'required|boolean', - 'server.settings.logdrain_newrelic_license_key' => 'required|string', - 'server.settings.logdrain_newrelic_base_uri' => 'required|string', - ]); - $this->server->settings->update([ - 'is_logdrain_highlight_enabled' => false, - 'is_logdrain_axiom_enabled' => false, - 'is_logdrain_custom_enabled' => false, - ]); - } elseif ($type === 'highlight') { - $this->validate([ - 'server.settings.is_logdrain_highlight_enabled' => 'required|boolean', - 'server.settings.logdrain_highlight_project_id' => 'required|string', - ]); - $this->server->settings->update([ - 'is_logdrain_newrelic_enabled' => false, - 'is_logdrain_axiom_enabled' => false, - 'is_logdrain_custom_enabled' => false, - ]); - } elseif ($type === 'axiom') { - $this->validate([ - 'server.settings.is_logdrain_axiom_enabled' => 'required|boolean', - 'server.settings.logdrain_axiom_dataset_name' => 'required|string', - 'server.settings.logdrain_axiom_api_key' => 'required|string', - ]); - $this->server->settings->update([ - 'is_logdrain_newrelic_enabled' => false, - 'is_logdrain_highlight_enabled' => false, - 'is_logdrain_custom_enabled' => false, - ]); - } elseif ($type === 'custom') { - $this->validate([ - 'server.settings.is_logdrain_custom_enabled' => 'required|boolean', - 'server.settings.logdrain_custom_config' => 'required|string', - 'server.settings.logdrain_custom_config_parser' => 'nullable', - ]); - $this->server->settings->update([ - 'is_logdrain_newrelic_enabled' => false, - 'is_logdrain_highlight_enabled' => false, - 'is_logdrain_axiom_enabled' => false, - ]); - } - if (! $this->server->isLogDrainEnabled()) { - StopLogDrain::dispatch($this->server); - } - $this->server->settings->save(); + $this->syncData(true); $this->dispatch('success', 'Settings saved.'); - - return true; } catch (\Throwable $e) { - if ($type === 'newrelic') { - $this->server->settings->update([ - 'is_logdrain_newrelic_enabled' => false, - ]); - } elseif ($type === 'highlight') { - $this->server->settings->update([ - 'is_logdrain_highlight_enabled' => false, - ]); - } elseif ($type === 'axiom') { - $this->server->settings->update([ - 'is_logdrain_axiom_enabled' => false, - ]); - } elseif ($type === 'custom') { - $this->server->settings->update([ - 'is_logdrain_custom_enabled' => false, - ]); - } - handleError($e, $this); - - return false; + return handleError($e, $this); } } diff --git a/app/Livewire/Server/PrivateKey/Show.php b/app/Livewire/Server/PrivateKey/Show.php index 0ad820428..64aa1884b 100644 --- a/app/Livewire/Server/PrivateKey/Show.php +++ b/app/Livewire/Server/PrivateKey/Show.php @@ -8,26 +8,63 @@ use Livewire\Component; class Show extends Component { - public ?Server $server = null; + public Server $server; public $privateKeys = []; public $parameters = []; - public function mount() + public function mount(string $server_uuid) { - $this->parameters = get_route_parameters(); try { - $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first(); - if (is_null($this->server)) { - return redirect()->route('server.index'); - } + $this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail(); $this->privateKeys = PrivateKey::ownedByCurrentTeam()->get()->where('is_git_related', false); } catch (\Throwable $e) { return handleError($e, $this); } } + public function setPrivateKey($privateKeyId) + { + $ownedPrivateKey = PrivateKey::ownedByCurrentTeam()->find($privateKeyId); + if (is_null($ownedPrivateKey)) { + $this->dispatch('error', 'You are not allowed to use this private key.'); + + return; + } + + $originalPrivateKeyId = $this->server->getOriginal('private_key_id'); + try { + $this->server->update(['private_key_id' => $privateKeyId]); + ['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection(justCheckingNewKey: true); + if ($uptime) { + $this->dispatch('success', 'Private key updated successfully.'); + } else { + throw new \Exception($error); + } + } catch (\Exception $e) { + $this->server->update(['private_key_id' => $originalPrivateKeyId]); + $this->server->validateConnection(); + $this->dispatch('error', $e->getMessage()); + } + } + + public function checkConnection() + { + try { + ['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection(); + if ($uptime) { + $this->dispatch('success', 'Server is reachable.'); + } else { + $this->dispatch('error', 'Server is not reachable.

Check this documentation for further help.

Error: '.$error); + + return; + } + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + public function render() { return view('livewire.server.private-key.show'); diff --git a/app/Livewire/Server/Proxy.php b/app/Livewire/Server/Proxy.php index 55d0c4966..94ea3509a 100644 --- a/app/Livewire/Server/Proxy.php +++ b/app/Livewire/Server/Proxy.php @@ -99,7 +99,6 @@ class Proxy extends Component } else { $this->dispatch('traefikDashboardAvailable', false); } - } catch (\Throwable $e) { return handleError($e, $this); } diff --git a/app/Livewire/Server/Proxy/Deploy.php b/app/Livewire/Server/Proxy/Deploy.php index eaa312663..8fcff85d6 100644 --- a/app/Livewire/Server/Proxy/Deploy.php +++ b/app/Livewire/Server/Proxy/Deploy.php @@ -6,6 +6,7 @@ use App\Actions\Proxy\CheckProxy; use App\Actions\Proxy\StartProxy; use App\Events\ProxyStatusChanged; use App\Models\Server; +use Carbon\Carbon; use Illuminate\Process\InvokedProcess; use Illuminate\Support\Facades\Process; use Livewire\Component; @@ -102,9 +103,9 @@ class Deploy extends Component $process = $this->stopContainer($containerName, $timeout); - $startTime = time(); + $startTime = Carbon::now()->getTimestamp(); while ($process->running()) { - if (time() - $startTime >= $timeout) { + if (Carbon::now()->getTimestamp() - $startTime >= $timeout) { $this->forceStopContainer($containerName); break; } diff --git a/app/Livewire/Server/Show.php b/app/Livewire/Server/Show.php index 85c5f95f8..afc7682a4 100644 --- a/app/Livewire/Server/Show.php +++ b/app/Livewire/Server/Show.php @@ -3,38 +3,203 @@ namespace App\Livewire\Server; use App\Models\Server; -use Illuminate\Foundation\Auth\Access\AuthorizesRequests; +use Livewire\Attributes\Rule; use Livewire\Component; class Show extends Component { - use AuthorizesRequests; - public Server $server; - public array $parameters; + #[Rule(['required'])] + public string $name; - protected $listeners = ['refreshServerShow']; + #[Rule(['nullable'])] + public ?string $description; - public function mount() + #[Rule(['required'])] + public string $ip; + + #[Rule(['required'])] + public string $user; + + #[Rule(['required'])] + public string $port; + + #[Rule(['nullable'])] + public ?string $validationLogs = null; + + #[Rule(['nullable', 'url'])] + public ?string $wildcardDomain; + + #[Rule(['required'])] + public bool $isReachable; + + #[Rule(['required'])] + public bool $isUsable; + + #[Rule(['required'])] + public bool $isSwarmManager; + + #[Rule(['required'])] + public bool $isSwarmWorker; + + #[Rule(['required'])] + public bool $isBuildServer; + + #[Rule(['required'])] + public bool $isMetricsEnabled; + + #[Rule(['required'])] + public string $sentinelToken; + + #[Rule(['nullable'])] + public ?string $sentinelUpdatedAt; + + #[Rule(['required', 'integer', 'min:1'])] + public int $sentinelMetricsRefreshRateSeconds; + + #[Rule(['required', 'integer', 'min:1'])] + public int $sentinelMetricsHistoryDays; + + #[Rule(['required', 'integer', 'min:10'])] + public int $sentinelPushIntervalSeconds; + + #[Rule(['nullable', 'url'])] + public ?string $sentinelCustomUrl; + + #[Rule(['required'])] + public bool $isSentinelEnabled; + + #[Rule(['required'])] + public bool $isSentinelDebugEnabled; + + #[Rule(['required'])] + public string $serverTimezone; + + public array $timezones; + + public function getListeners() + { + $teamId = auth()->user()->currentTeam()->id; + + return [ + "echo-private:team.{$teamId},CloudflareTunnelConfigured" => '$refresh', + 'refreshServerShow' => '$refresh', + ]; + } + + public function mount(string $server_uuid) { try { - $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->firstOrFail(); - $this->parameters = get_route_parameters(); + $this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail(); + $this->timezones = collect(timezone_identifiers_list())->sort()->values()->toArray(); + $this->syncData(); } catch (\Throwable $e) { return handleError($e, $this); } } - public function refreshServerShow() + public function syncData(bool $toModel = false) { - $this->server->refresh(); - $this->dispatch('$refresh'); + if ($toModel) { + $this->validate(); + $this->server->name = $this->name; + $this->server->description = $this->description; + $this->server->ip = $this->ip; + $this->server->user = $this->user; + $this->server->port = $this->port; + $this->server->validation_logs = $this->validationLogs; + $this->server->save(); + + $this->server->settings->is_swarm_manager = $this->isSwarmManager; + $this->server->settings->is_swarm_worker = $this->isSwarmWorker; + $this->server->settings->is_build_server = $this->isBuildServer; + $this->server->settings->is_metrics_enabled = $this->isMetricsEnabled; + $this->server->settings->sentinel_token = $this->sentinelToken; + $this->server->settings->sentinel_metrics_refresh_rate_seconds = $this->sentinelMetricsRefreshRateSeconds; + $this->server->settings->sentinel_metrics_history_days = $this->sentinelMetricsHistoryDays; + $this->server->settings->sentinel_push_interval_seconds = $this->sentinelPushIntervalSeconds; + $this->server->settings->sentinel_custom_url = $this->sentinelCustomUrl; + $this->server->settings->is_sentinel_enabled = $this->isSentinelEnabled; + $this->server->settings->is_sentinel_debug_enabled = $this->isSentinelDebugEnabled; + $this->server->settings->server_timezone = $this->serverTimezone; + $this->server->settings->save(); + } else { + $this->name = $this->server->name; + $this->description = $this->server->description; + $this->ip = $this->server->ip; + $this->user = $this->server->user; + $this->port = $this->server->port; + $this->wildcardDomain = $this->server->settings->wildcard_domain; + $this->isReachable = $this->server->settings->is_reachable; + $this->isUsable = $this->server->settings->is_usable; + $this->isSwarmManager = $this->server->settings->is_swarm_manager; + $this->isSwarmWorker = $this->server->settings->is_swarm_worker; + $this->isBuildServer = $this->server->settings->is_build_server; + $this->isMetricsEnabled = $this->server->settings->is_metrics_enabled; + $this->sentinelToken = $this->server->settings->sentinel_token; + $this->sentinelMetricsRefreshRateSeconds = $this->server->settings->sentinel_metrics_refresh_rate_seconds; + $this->sentinelMetricsHistoryDays = $this->server->settings->sentinel_metrics_history_days; + $this->sentinelPushIntervalSeconds = $this->server->settings->sentinel_push_interval_seconds; + $this->sentinelCustomUrl = $this->server->settings->sentinel_custom_url; + $this->isSentinelEnabled = $this->server->settings->is_sentinel_enabled; + $this->isSentinelDebugEnabled = $this->server->settings->is_sentinel_debug_enabled; + $this->sentinelUpdatedAt = $this->server->settings->updated_at; + $this->serverTimezone = $this->server->settings->server_timezone; + } + } + + public function validateServer($install = true) + { + try { + $this->validationLogs = $this->server->validation_logs = null; + $this->server->save(); + $this->dispatch('init', $install); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + + public function checkLocalhostConnection() + { + $this->syncData(true); + ['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection(); + if ($uptime) { + $this->dispatch('success', 'Server is reachable.'); + $this->server->settings->is_reachable = $this->isReachable = true; + $this->server->settings->is_usable = $this->isUsable = true; + $this->server->settings->save(); + $this->dispatch('proxyStatusUpdated'); + } else { + $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.

Check this documentation for further help.

Error: '.$error); + + return; + } + } + + public function regenerateSentinelToken() + { + try { + $this->server->settings->generateSentinelToken(); + $this->dispatch('success', 'Token regenerated & Sentinel restarted.'); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + + public function instantSave() + { + $this->submit(); } public function submit() { - $this->dispatch('serverRefresh', false); + try { + $this->syncData(true); + $this->dispatch('success', 'Server updated'); + } catch (\Throwable $e) { + return handleError($e, $this); + } } public function render() diff --git a/app/Livewire/Server/ShowPrivateKey.php b/app/Livewire/Server/ShowPrivateKey.php deleted file mode 100644 index cc77fd611..000000000 --- a/app/Livewire/Server/ShowPrivateKey.php +++ /dev/null @@ -1,68 +0,0 @@ -parameters = get_route_parameters(); - } - - public function setPrivateKey($privateKeyId) - { - $ownedPrivateKey = PrivateKey::ownedByCurrentTeam()->find($privateKeyId); - if (is_null($ownedPrivateKey)) { - $this->dispatch('error', 'You are not allowed to use this private key.'); - - return; - } - - $originalPrivateKeyId = $this->server->getOriginal('private_key_id'); - try { - $this->server->update(['private_key_id' => $privateKeyId]); - ['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection(); - if ($uptime) { - $this->dispatch('success', 'Private key updated successfully.'); - } else { - throw new \Exception('Server is not reachable.

Check this documentation for further help.

Error: '.$error); - } - } catch (\Exception $e) { - $this->server->update(['private_key_id' => $originalPrivateKeyId]); - $this->server->validateConnection(); - $this->dispatch('error', 'Failed to update private key: '.$e->getMessage()); - } finally { - $this->dispatch('refreshServerShow'); - $this->server->refresh(); - } - } - - public function checkConnection() - { - try { - ['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection(); - if ($uptime) { - $this->dispatch('success', 'Server is reachable.'); - } else { - $this->dispatch('error', 'Server is not reachable.

Check this documentation for further help.

Error: '.$error); - - return; - } - } catch (\Throwable $e) { - return handleError($e, $this); - } finally { - $this->dispatch('refreshServerShow'); - $this->server->refresh(); - } - } -} diff --git a/app/Livewire/SettingsEmail.php b/app/Livewire/SettingsEmail.php index 2b515bf68..fe329f270 100644 --- a/app/Livewire/SettingsEmail.php +++ b/app/Livewire/SettingsEmail.php @@ -47,7 +47,6 @@ class SettingsEmail extends Component } else { return redirect()->route('dashboard'); } - } public function submitFromFields() diff --git a/app/Livewire/Source/Github/Change.php b/app/Livewire/Source/Github/Change.php index 7df6f968f..07cef54f9 100644 --- a/app/Livewire/Source/Github/Change.php +++ b/app/Livewire/Source/Github/Change.php @@ -4,7 +4,6 @@ namespace App\Livewire\Source\Github; use App\Jobs\GithubAppPermissionJob; use App\Models\GithubApp; -use Illuminate\Support\Facades\Http; use Livewire\Component; class Change extends Component @@ -141,7 +140,6 @@ class Change extends Component } catch (\Throwable $e) { return handleError($e, $this); } - } public function submit() diff --git a/app/Livewire/Subscription/PricingPlans.php b/app/Livewire/Subscription/PricingPlans.php index 9bc11d862..9186cc978 100644 --- a/app/Livewire/Subscription/PricingPlans.php +++ b/app/Livewire/Subscription/PricingPlans.php @@ -8,49 +8,16 @@ use Stripe\Stripe; class PricingPlans extends Component { - public bool $isTrial = false; - - public function mount() - { - $this->isTrial = ! data_get(currentTeam(), 'subscription.stripe_trial_already_ended'); - if (config('constants.limits.trial_period') == 0) { - $this->isTrial = false; - } - } - public function subscribeStripe($type) { - $team = currentTeam(); Stripe::setApiKey(config('subscription.stripe_api_key')); - switch ($type) { - case 'basic-monthly': - $priceId = config('subscription.stripe_price_id_basic_monthly'); - break; - case 'basic-yearly': - $priceId = config('subscription.stripe_price_id_basic_yearly'); - break; - case 'pro-monthly': - $priceId = config('subscription.stripe_price_id_pro_monthly'); - break; - case 'pro-yearly': - $priceId = config('subscription.stripe_price_id_pro_yearly'); - break; - case 'ultimate-monthly': - $priceId = config('subscription.stripe_price_id_ultimate_monthly'); - break; - case 'ultimate-yearly': - $priceId = config('subscription.stripe_price_id_ultimate_yearly'); - break; - case 'dynamic-monthly': - $priceId = config('subscription.stripe_price_id_dynamic_monthly'); - break; - case 'dynamic-yearly': - $priceId = config('subscription.stripe_price_id_dynamic_yearly'); - break; - default: - $priceId = config('subscription.stripe_price_id_basic_monthly'); - break; - } + + $priceId = match ($type) { + 'dynamic-monthly' => config('subscription.stripe_price_id_dynamic_monthly'), + 'dynamic-yearly' => config('subscription.stripe_price_id_dynamic_yearly'), + default => config('subscription.stripe_price_id_dynamic_monthly'), + }; + if (! $priceId) { $this->dispatch('error', 'Price ID not found! Please contact the administrator.'); @@ -62,7 +29,11 @@ class PricingPlans extends Component 'client_reference_id' => auth()->user()->id.':'.currentTeam()->id, 'line_items' => [[ 'price' => $priceId, - 'quantity' => 1, + 'adjustable_quantity' => [ + 'enabled' => true, + 'minimum' => 2, + ], + 'quantity' => 2, ]], 'tax_id_collection' => [ 'enabled' => true, @@ -70,39 +41,18 @@ class PricingPlans extends Component 'automatic_tax' => [ 'enabled' => true, ], - + 'subscription_data' => [ + 'metadata' => [ + 'user_id' => auth()->user()->id, + 'team_id' => currentTeam()->id, + ], + ], + 'payment_method_collection' => 'if_required', 'mode' => 'subscription', 'success_url' => route('dashboard', ['success' => true]), 'cancel_url' => route('subscription.index', ['cancelled' => true]), ]; - if (str($type)->contains('ultimate')) { - $payload['line_items'][0]['adjustable_quantity'] = [ - 'enabled' => true, - 'minimum' => 10, - ]; - $payload['line_items'][0]['quantity'] = 10; - } - if (str($type)->contains('dynamic')) { - $payload['line_items'][0]['adjustable_quantity'] = [ - 'enabled' => true, - 'minimum' => 2, - ]; - $payload['line_items'][0]['quantity'] = 2; - } - if (! data_get($team, 'subscription.stripe_trial_already_ended')) { - if (config('constants.limits.trial_period') > 0) { - $payload['subscription_data'] = [ - 'trial_period_days' => config('constants.limits.trial_period'), - 'trial_settings' => [ - 'end_behavior' => [ - 'missing_payment_method' => 'cancel', - ], - ], - ]; - } - $payload['payment_method_collection'] = 'if_required'; - } $customer = currentTeam()->subscription?->stripe_customer_id ?? null; if ($customer) { $payload['customer'] = $customer; diff --git a/app/Livewire/Tags/Index.php b/app/Livewire/Tags/Index.php index 642b2bded..116f19e4e 100644 --- a/app/Livewire/Tags/Index.php +++ b/app/Livewire/Tags/Index.php @@ -47,7 +47,7 @@ class Index extends Component public function tagUpdated() { - if ($this->tag == '') { + if ($this->tag === '') { return; } $sanitizedTag = htmlspecialchars($this->tag, ENT_QUOTES, 'UTF-8'); diff --git a/app/Livewire/Team/Invitations.php b/app/Livewire/Team/Invitations.php index 043c4e2e8..93432efc8 100644 --- a/app/Livewire/Team/Invitations.php +++ b/app/Livewire/Team/Invitations.php @@ -18,7 +18,7 @@ class Invitations extends Component $initiation_found->delete(); $this->refreshInvitations(); $this->dispatch('success', 'Invitation revoked.'); - } catch (\Exception $e) { + } catch (\Exception) { return $this->dispatch('error', 'Invitation not found.'); } } diff --git a/app/Livewire/Upgrade.php b/app/Livewire/Upgrade.php index dfbd945f5..88ed88cb7 100644 --- a/app/Livewire/Upgrade.php +++ b/app/Livewire/Upgrade.php @@ -23,11 +23,9 @@ class Upgrade extends Component try { $this->latestVersion = get_latest_version_of_coolify(); $this->isUpgradeAvailable = data_get(InstanceSettings::get(), 'new_version_available', false); - } catch (\Throwable $e) { return handleError($e, $this); } - } public function upgrade() diff --git a/app/Livewire/VerifyEmail.php b/app/Livewire/VerifyEmail.php index 9d1fdab98..fab3265b6 100644 --- a/app/Livewire/VerifyEmail.php +++ b/app/Livewire/VerifyEmail.php @@ -15,7 +15,6 @@ class VerifyEmail extends Component $this->rateLimit(1, 300); auth()->user()->sendVerificationEmail(); $this->dispatch('success', 'Email verification link sent!'); - } catch (\Exception $e) { return handleError($e, $this); } diff --git a/app/Models/Application.php b/app/Models/Application.php index c747c75c5..cd7bb533e 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -114,7 +114,7 @@ class Application extends BaseModel protected static function booted() { static::saving(function ($application) { - if ($application->fqdn == '') { + if ($application->fqdn === '') { $application->fqdn = null; } $application->forceFill([ @@ -936,7 +936,7 @@ class Application extends BaseModel $source_html_url_host = $url['host']; $source_html_url_scheme = $url['scheme']; - if ($this->source->getMorphClass() == \App\Models\GithubApp::class) { + if ($this->source->getMorphClass() === \App\Models\GithubApp::class) { if ($this->source->is_public) { $fullRepoUrl = "{$this->source->html_url}/{$customRepository}"; $git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$customRepository} {$baseDir}"; @@ -1407,7 +1407,7 @@ class Application extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); @@ -1431,7 +1431,7 @@ class Application extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); diff --git a/app/Models/Environment.php b/app/Models/Environment.php index d0bb5d2a6..71e8bbd21 100644 --- a/app/Models/Environment.php +++ b/app/Models/Environment.php @@ -29,7 +29,6 @@ class Environment extends Model foreach ($shared_variables as $shared_variable) { $shared_variable->delete(); } - }); } diff --git a/app/Models/EnvironmentVariable.php b/app/Models/EnvironmentVariable.php index f77d73db8..08f23d7ab 100644 --- a/app/Models/EnvironmentVariable.php +++ b/app/Models/EnvironmentVariable.php @@ -156,13 +156,12 @@ class EnvironmentVariable extends Model private function get_real_environment_variables(?string $environment_variable = null, $resource = null) { - if ((is_null($environment_variable) && $environment_variable == '') || is_null($resource)) { + if ((is_null($environment_variable) && $environment_variable === '') || is_null($resource)) { return null; } $environment_variable = trim($environment_variable); $sharedEnvsFound = str($environment_variable)->matchAll('/{{(.*?)}}/'); if ($sharedEnvsFound->isEmpty()) { - return $environment_variable; } @@ -202,7 +201,7 @@ class EnvironmentVariable extends Model private function set_environment_variables(?string $environment_variable = null): ?string { - if (is_null($environment_variable) && $environment_variable == '') { + if (is_null($environment_variable) && $environment_variable === '') { return null; } $environment_variable = trim($environment_variable); diff --git a/app/Models/InstanceSettings.php b/app/Models/InstanceSettings.php index 339daed2a..eeb803925 100644 --- a/app/Models/InstanceSettings.php +++ b/app/Models/InstanceSettings.php @@ -36,7 +36,6 @@ class InstanceSettings extends Model implements SendsEmail }); } }); - } public function fqdn(): Attribute diff --git a/app/Models/LocalFileVolume.php b/app/Models/LocalFileVolume.php index d528099ff..2c223be77 100644 --- a/app/Models/LocalFileVolume.php +++ b/app/Models/LocalFileVolume.php @@ -72,7 +72,6 @@ class LocalFileVolume extends BaseModel if ($path && $path != '/' && $path != '.' && $path != '..') { if ($isFile === 'OK') { $commands->push("rm -rf $path > /dev/null 2>&1 || true"); - } elseif ($isDir === 'OK') { $commands->push("rm -rf $path > /dev/null 2>&1 || true"); $commands->push("rmdir $path > /dev/null 2>&1 || true"); @@ -113,15 +112,15 @@ class LocalFileVolume extends BaseModel } $isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server); $isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server); - if ($isFile == 'OK' && $this->is_directory) { + if ($isFile === 'OK' && $this->is_directory) { $content = instant_remote_process(["cat $path"], $server, false); $this->is_directory = false; $this->content = $content; $this->save(); FileStorageChanged::dispatch(data_get($server, 'team_id')); throw new \Exception('The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.'); - } elseif ($isDir == 'OK' && ! $this->is_directory) { - if ($path == '/' || $path == '.' || $path == '..' || $path == '' || str($path)->isEmpty() || is_null($path)) { + } elseif ($isDir === 'OK' && ! $this->is_directory) { + if ($path === '/' || $path === '.' || $path === '..' || $path === '' || str($path)->isEmpty() || is_null($path)) { $this->is_directory = true; $this->save(); throw new \Exception('The following file is a directory on the server, but you are trying to mark it as a file.

Please delete the directory on the server or mark it as directory.'); @@ -132,7 +131,7 @@ class LocalFileVolume extends BaseModel ], $server, false); FileStorageChanged::dispatch(data_get($server, 'team_id')); } - if ($isDir == 'NOK' && ! $this->is_directory) { + if ($isDir === 'NOK' && ! $this->is_directory) { $chmod = data_get($this, 'chmod'); $chown = data_get($this, 'chown'); if ($content) { @@ -148,7 +147,7 @@ class LocalFileVolume extends BaseModel if ($chmod) { $commands->push("chmod $chmod $path"); } - } elseif ($isDir == 'NOK' && $this->is_directory) { + } elseif ($isDir === 'NOK' && $this->is_directory) { $commands->push("mkdir -p $path > /dev/null 2>&1 || true"); } diff --git a/app/Models/ScheduledTask.php b/app/Models/ScheduledTask.php index 3cee5a875..264a04d1f 100644 --- a/app/Models/ScheduledTask.php +++ b/app/Models/ScheduledTask.php @@ -34,21 +34,15 @@ class ScheduledTask extends BaseModel { if ($this->application) { if ($this->application->destination && $this->application->destination->server) { - $server = $this->application->destination->server; - - return $server; + return $this->application->destination->server; } } elseif ($this->service) { if ($this->service->destination && $this->service->destination->server) { - $server = $this->service->destination->server; - - return $server; + return $this->service->destination->server; } } elseif ($this->database) { if ($this->database->destination && $this->database->destination->server) { - $server = $this->database->destination->server; - - return $server; + return $this->database->destination->server; } } diff --git a/app/Models/Server.php b/app/Models/Server.php index c9915e3fb..d43ae54d3 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -5,6 +5,7 @@ namespace App\Models; use App\Actions\Server\InstallDocker; use App\Actions\Server\StartSentinel; use App\Enums\ProxyTypes; +use App\Helpers\SshMultiplexingHelper; use App\Jobs\CheckAndStartSentinelJob; use App\Notifications\Server\Reachable; use App\Notifications\Server\Unreachable; @@ -14,7 +15,6 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; -use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Stringable; use OpenApi\Attributes as OA; @@ -63,7 +63,11 @@ class Server extends BaseModel $payload['ip'] = str($server->ip)->trim(); } $server->forceFill($payload); - + }); + static::saved(function ($server) { + if ($server->privateKey->isDirty()) { + refresh_server_connection($server->privateKey); + } }); static::created(function ($server) { ServerSetting::create([ @@ -416,7 +420,7 @@ respond 404 "echo '$base64' | base64 -d | tee $file > /dev/null", ], $this); - if (config('app.env') == 'local') { + if (config('app.env') === 'local') { // ray($yaml); } } @@ -592,17 +596,16 @@ $schema://$host { if (str($cpu)->contains('error')) { $error = json_decode($cpu, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); } $cpu = json_decode($cpu, true); - $parsedCollection = collect($cpu)->map(function ($metric) { + + return collect($cpu)->map(function ($metric) { return [(int) $metric['time'], (float) $metric['percent']]; }); - - return $parsedCollection; } } @@ -614,7 +617,7 @@ $schema://$host { if (str($memory)->contains('error')) { $error = json_decode($memory, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); @@ -833,9 +836,7 @@ $schema://$host { { return Attribute::make( get: function ($value) { - $sanitizedValue = preg_replace('/[^A-Za-z0-9\-_]/', '', $value); - - return $sanitizedValue; + return preg_replace('/[^A-Za-z0-9\-_]/', '', $value); } ); } @@ -1027,7 +1028,6 @@ $schema://$host { $this->refresh(); $unreachableNotificationSent = (bool) $this->unreachable_notification_sent; $isReachable = (bool) $this->settings->is_reachable; - loggy('Server setting is_reachable changed to '.$isReachable.' for server '.$this->id.'. Unreachable notification sent: '.$unreachableNotificationSent); // If the server is reachable, send the reachable notification if it was sent before if ($isReachable === true) { if ($unreachableNotificationSent === true) { @@ -1057,10 +1057,12 @@ $schema://$host { $this->team->notify(new Unreachable($this)); } - public function validateConnection($isManualCheck = true) + public function validateConnection(bool $isManualCheck = true, bool $justCheckingNewKey = false) { config()->set('constants.ssh.mux_enabled', ! $isManualCheck); + SshMultiplexingHelper::removeMuxFile($this); + if ($this->skipServer()) { return ['uptime' => false, 'error' => 'Server skipped.']; } @@ -1077,6 +1079,9 @@ $schema://$host { return ['uptime' => true, 'error' => null]; } catch (\Throwable $e) { + if ($justCheckingNewKey) { + return ['uptime' => false, 'error' => 'This key is not valid for this server.']; + } if ($this->settings->is_reachable === true) { $this->settings->is_reachable = false; $this->settings->save(); @@ -1088,9 +1093,7 @@ $schema://$host { public function installDocker() { - $activity = InstallDocker::run($this); - - return $activity; + return InstallDocker::run($this); } public function validateDockerEngine($throwError = false) diff --git a/app/Models/ServerSetting.php b/app/Models/ServerSetting.php index 7a8e7b8ed..bca16536e 100644 --- a/app/Models/ServerSetting.php +++ b/app/Models/ServerSetting.php @@ -117,7 +117,6 @@ class ServerSetting extends Model $domain = 'http://'.$settings->public_ipv6.':8000'; } $this->sentinel_custom_url = $domain; - loggy('Sentinel URL: '.$domain); if ($save) { $this->save(); } diff --git a/app/Models/Service.php b/app/Models/Service.php index c4f4c2d3c..f88a23641 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -1095,7 +1095,6 @@ class Service extends BaseModel } $fields->put('MariaDB', $data->toArray()); break; - } } @@ -1304,14 +1303,11 @@ class Service extends BaseModel } else { return collect([]); } - } public function networks() { - $networks = getTopLevelNetworks($this); - - return $networks; + return getTopLevelNetworks($this); } protected function isDeployable(): Attribute diff --git a/app/Models/StandaloneClickhouse.php b/app/Models/StandaloneClickhouse.php index c9d3ea031..fa27d50d8 100644 --- a/app/Models/StandaloneClickhouse.php +++ b/app/Models/StandaloneClickhouse.php @@ -275,7 +275,7 @@ class StandaloneClickhouse extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); @@ -297,7 +297,7 @@ class StandaloneClickhouse extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); diff --git a/app/Models/StandaloneDragonfly.php b/app/Models/StandaloneDragonfly.php index 2bde51080..fa0bd4b44 100644 --- a/app/Models/StandaloneDragonfly.php +++ b/app/Models/StandaloneDragonfly.php @@ -275,7 +275,7 @@ class StandaloneDragonfly extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); @@ -297,7 +297,7 @@ class StandaloneDragonfly extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); diff --git a/app/Models/StandaloneKeydb.php b/app/Models/StandaloneKeydb.php index fbee9789a..56ee4d4a2 100644 --- a/app/Models/StandaloneKeydb.php +++ b/app/Models/StandaloneKeydb.php @@ -275,7 +275,7 @@ class StandaloneKeydb extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); @@ -297,7 +297,7 @@ class StandaloneKeydb extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); diff --git a/app/Models/StandaloneMariadb.php b/app/Models/StandaloneMariadb.php index 00f635faf..c55a76af7 100644 --- a/app/Models/StandaloneMariadb.php +++ b/app/Models/StandaloneMariadb.php @@ -275,7 +275,7 @@ class StandaloneMariadb extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); @@ -297,7 +297,7 @@ class StandaloneMariadb extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); diff --git a/app/Models/StandaloneMongodb.php b/app/Models/StandaloneMongodb.php index c225011c5..3f12a8557 100644 --- a/app/Models/StandaloneMongodb.php +++ b/app/Models/StandaloneMongodb.php @@ -295,7 +295,7 @@ class StandaloneMongodb extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); @@ -317,7 +317,7 @@ class StandaloneMongodb extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); diff --git a/app/Models/StandaloneMysql.php b/app/Models/StandaloneMysql.php index 52725ffc7..0d8359f88 100644 --- a/app/Models/StandaloneMysql.php +++ b/app/Models/StandaloneMysql.php @@ -276,7 +276,7 @@ class StandaloneMysql extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); @@ -298,7 +298,7 @@ class StandaloneMysql extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); diff --git a/app/Models/StandalonePostgresql.php b/app/Models/StandalonePostgresql.php index 3dd13b633..f31582c35 100644 --- a/app/Models/StandalonePostgresql.php +++ b/app/Models/StandalonePostgresql.php @@ -281,7 +281,7 @@ class StandalonePostgresql extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); @@ -303,7 +303,7 @@ class StandalonePostgresql extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); diff --git a/app/Models/StandaloneRedis.php b/app/Models/StandaloneRedis.php index 5b6993b9a..119978530 100644 --- a/app/Models/StandaloneRedis.php +++ b/app/Models/StandaloneRedis.php @@ -286,7 +286,7 @@ class StandaloneRedis extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); @@ -308,7 +308,7 @@ class StandaloneRedis extends BaseModel if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { + if ($error === 'Unauthorized') { $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } throw new \Exception($error); diff --git a/app/Models/Team.php b/app/Models/Team.php index 49b019725..5b4a80cb1 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -131,9 +131,7 @@ class Team extends Model implements SendsDiscord, SendsEmail { $recipients = data_get($notification, 'emails', null); if (is_null($recipients)) { - $recipients = $this->members()->pluck('email')->toArray(); - - return $recipients; + return $this->members()->pluck('email')->toArray(); } return explode(',', $recipients); @@ -251,9 +249,8 @@ class Team extends Model implements SendsDiscord, SendsEmail $sources = collect([]); $github_apps = $this->hasMany(GithubApp::class)->whereisPublic(false)->get(); $gitlab_apps = $this->hasMany(GitlabApp::class)->whereisPublic(false)->get(); - $sources = $sources->merge($github_apps)->merge($gitlab_apps); - return $sources; + return $sources->merge($github_apps)->merge($gitlab_apps); } public function s3s() diff --git a/app/Notifications/Application/StatusChanged.php b/app/Notifications/Application/StatusChanged.php index a080fcabe..852c6b526 100644 --- a/app/Notifications/Application/StatusChanged.php +++ b/app/Notifications/Application/StatusChanged.php @@ -58,14 +58,12 @@ class StatusChanged extends Notification implements ShouldQueue public function toDiscord(): DiscordMessage { - $message = new DiscordMessage( + return new DiscordMessage( title: ':cross_mark: Application stopped', description: '[Open Application in Coolify]('.$this->resource_url.')', color: DiscordMessage::errorColor(), isCritical: true, ); - - return $message; } public function toTelegram(): array diff --git a/app/Notifications/ScheduledTask/TaskFailed.php b/app/Notifications/ScheduledTask/TaskFailed.php index 2cc33f2ba..c3501a8eb 100644 --- a/app/Notifications/ScheduledTask/TaskFailed.php +++ b/app/Notifications/ScheduledTask/TaskFailed.php @@ -30,7 +30,6 @@ class TaskFailed extends Notification implements ShouldQueue public function via(object $notifiable): array { - return setNotificationChannels($notifiable, 'scheduled_tasks'); } diff --git a/app/View/Components/Server/Sidebar.php b/app/View/Components/Server/Sidebar.php deleted file mode 100644 index f968b6d0c..000000000 --- a/app/View/Components/Server/Sidebar.php +++ /dev/null @@ -1,27 +0,0 @@ -map(function ($d) { + return $data->map(function ($d) { $d = collect($d)->sortKeys(); $created_at = data_get($d, 'created_at'); $updated_at = data_get($d, 'updated_at'); if ($created_at) { unset($d['created_at']); $d['created_at'] = $created_at; - } if ($updated_at) { unset($d['updated_at']); @@ -50,8 +49,6 @@ function serializeApiResponse($data) return $d; }); - - return $data; } else { $d = collect($data)->sortKeys(); $created_at = data_get($d, 'created_at'); @@ -59,7 +56,6 @@ function serializeApiResponse($data) if ($created_at) { unset($d['created_at']); $d['created_at'] = $created_at; - } if ($updated_at) { unset($d['updated_at']); diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php index 2795ae295..52435703c 100644 --- a/bootstrap/helpers/docker.php +++ b/bootstrap/helpers/docker.php @@ -32,9 +32,8 @@ function getCurrentApplicationContainerStatus(Server $server, int $id, ?int $pul return null; }); - $containers = $containers->filter(); - return $containers; + return $containers->filter(); } return $containers; @@ -46,9 +45,8 @@ function getCurrentServiceContainerStatus(Server $server, int $id): Collection if (! $server->isSwarm()) { $containers = instant_remote_process(["docker ps -a --filter='label=coolify.serviceId={$id}' --format '{{json .}}' "], $server); $containers = format_docker_command_output_to_json($containers); - $containers = $containers->filter(); - return $containers; + return $containers->filter(); } return $containers; @@ -67,7 +65,7 @@ function format_docker_command_output_to_json($rawOutput): Collection return $outputLines ->reject(fn ($line) => empty($line)) ->map(fn ($outputLine) => json_decode($outputLine, true, flags: JSON_THROW_ON_ERROR)); - } catch (\Throwable $e) { + } catch (\Throwable) { return collect([]); } } @@ -104,7 +102,7 @@ function format_docker_envs_to_json($rawOutput) return [$env[0] => $env[1]]; }); - } catch (\Throwable $e) { + } catch (\Throwable) { return collect([]); } } @@ -510,7 +508,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_ } } } - } catch (\Throwable $e) { + } catch (\Throwable) { continue; } } @@ -581,7 +579,6 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview redirect_direction: $application->redirect )); } - } } else { if (data_get($preview, 'fqdn')) { @@ -633,7 +630,6 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview is_stripprefix_enabled: $application->isStripprefixEnabled() )); } - } return $labels->all(); diff --git a/bootstrap/helpers/github.php b/bootstrap/helpers/github.php index 0b5f7034b..529ac82b1 100644 --- a/bootstrap/helpers/github.php +++ b/bootstrap/helpers/github.php @@ -3,6 +3,7 @@ use App\Models\GithubApp; use App\Models\GitlabApp; use Carbon\Carbon; +use Carbon\CarbonImmutable; use Illuminate\Support\Facades\Http; use Illuminate\Support\Str; use Lcobucci\JWT\Encoding\ChainedFormatter; @@ -16,7 +17,7 @@ function generate_github_installation_token(GithubApp $source) $signingKey = InMemory::plainText($source->privateKey->private_key); $algorithm = new Sha256; $tokenBuilder = (new Builder(new JoseEncoder, ChainedFormatter::default())); - $now = new DateTimeImmutable; + $now = CarbonImmutable::now(); $now = $now->setTime($now->format('H'), $now->format('i')); $issuedToken = $tokenBuilder ->issuedBy($source->app_id) @@ -40,16 +41,15 @@ function generate_github_jwt_token(GithubApp $source) $signingKey = InMemory::plainText($source->privateKey->private_key); $algorithm = new Sha256; $tokenBuilder = (new Builder(new JoseEncoder, ChainedFormatter::default())); - $now = new DateTimeImmutable; + $now = CarbonImmutable::now(); $now = $now->setTime($now->format('H'), $now->format('i')); - $issuedToken = $tokenBuilder + + return $tokenBuilder ->issuedBy($source->app_id) ->issuedAt($now->modify('-1 minute')) ->expiresAt($now->modify('+10 minutes')) ->getToken($algorithm, $signingKey) ->toString(); - - return $issuedToken; } function githubApi(GithubApp|GitlabApp|null $source, string $endpoint, string $method = 'get', ?array $data = null, bool $throwError = true) @@ -57,7 +57,7 @@ function githubApi(GithubApp|GitlabApp|null $source, string $endpoint, string $m if (is_null($source)) { throw new \Exception('Not implemented yet.'); } - if ($source->getMorphClass() == \App\Models\GithubApp::class) { + if ($source->getMorphClass() === \App\Models\GithubApp::class) { if ($source->is_public) { $response = Http::github($source->api_url)->$method($endpoint); } else { diff --git a/bootstrap/helpers/proxy.php b/bootstrap/helpers/proxy.php index 496017217..a8ef0fe5a 100644 --- a/bootstrap/helpers/proxy.php +++ b/bootstrap/helpers/proxy.php @@ -16,12 +16,10 @@ function collectProxyDockerNetworksByServer(Server $server) return collect(); } $networks = instant_remote_process(['docker inspect --format="{{json .NetworkSettings.Networks }}" coolify-proxy'], $server, false); - $networks = collect($networks)->map(function ($network) { + + return collect($networks)->map(function ($network) { return collect(json_decode($network))->keys(); })->flatten()->unique(); - - return $networks; - } function collectDockerNetworksByServer(Server $server) { diff --git a/bootstrap/helpers/remoteProcess.php b/bootstrap/helpers/remoteProcess.php index 67b60d6b7..c7dd2cb83 100644 --- a/bootstrap/helpers/remoteProcess.php +++ b/bootstrap/helpers/remoteProcess.php @@ -124,7 +124,7 @@ function decode_remote_command_output(?ApplicationDeploymentQueue $application_d associative: true, flags: JSON_THROW_ON_ERROR ); - } catch (\JsonException $exception) { + } catch (\JsonException) { return collect([]); } $seenCommands = collect(); @@ -204,7 +204,7 @@ function checkRequiredCommands(Server $server) } try { instant_remote_process(["docker run --rm --privileged --net=host --pid=host --ipc=host --volume /:/host busybox chroot /host bash -c 'apt update && apt install -y {$command}'"], $server); - } catch (\Throwable $e) { + } catch (\Throwable) { break; } $commandFound = instant_remote_process(["docker run --rm --privileged --net=host --pid=host --ipc=host --volume /:/host busybox chroot /host bash -c 'command -v {$command}'"], $server, false); diff --git a/bootstrap/helpers/services.php b/bootstrap/helpers/services.php index 94c3c5f45..fd2e1231f 100644 --- a/bootstrap/helpers/services.php +++ b/bootstrap/helpers/services.php @@ -51,7 +51,7 @@ function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase|Appli // Exists and is a directory $isDir = instant_remote_process(["test -d $fileLocation && echo OK || echo NOK"], $server); - if ($isFile == 'OK') { + if ($isFile === 'OK') { // If its a file & exists $filesystemContent = instant_remote_process(["cat $fileLocation"], $server); if ($fileVolume->is_based_on_git) { @@ -59,12 +59,12 @@ function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase|Appli } $fileVolume->is_directory = false; $fileVolume->save(); - } elseif ($isDir == 'OK') { + } elseif ($isDir === 'OK') { // If its a directory & exists $fileVolume->content = null; $fileVolume->is_directory = true; $fileVolume->save(); - } elseif ($isFile == 'NOK' && $isDir == 'NOK' && ! $fileVolume->is_directory && $isInit && $content) { + } elseif ($isFile === 'NOK' && $isDir === 'NOK' && ! $fileVolume->is_directory && $isInit && $content) { // Does not exists (no dir or file), not flagged as directory, is init, has content $fileVolume->content = $content; $fileVolume->is_directory = false; @@ -75,13 +75,13 @@ function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase|Appli "mkdir -p $dir", "echo '$content' | base64 -d | tee $fileLocation", ], $server); - } elseif ($isFile == 'NOK' && $isDir == 'NOK' && $fileVolume->is_directory && $isInit) { + } elseif ($isFile === 'NOK' && $isDir === 'NOK' && $fileVolume->is_directory && $isInit) { // Does not exists (no dir or file), flagged as directory, is init $fileVolume->content = null; $fileVolume->is_directory = true; $fileVolume->save(); instant_remote_process(["mkdir -p $fileLocation"], $server); - } elseif ($isFile == 'NOK' && $isDir == 'NOK' && ! $fileVolume->is_directory && $isInit && is_null($content)) { + } elseif ($isFile === 'NOK' && $isDir === 'NOK' && ! $fileVolume->is_directory && $isInit && is_null($content)) { // Does not exists (no dir or file), not flagged as directory, is init, has no content => create directory $fileVolume->content = null; $fileVolume->is_directory = true; @@ -245,8 +245,5 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource) } function serviceKeys() { - $services = get_service_templates(); - $serviceKeys = $services->keys(); - - return $serviceKeys; + return get_service_templates()->keys(); } diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index f92cd5a73..fb4ae3699 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -28,6 +28,7 @@ use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\EmailChannel; use App\Notifications\Channels\TelegramChannel; use App\Notifications\Internal\GeneralNotification; +use Carbon\CarbonImmutable; use DanHarrin\LivewireRateLimiting\Exceptions\TooManyRequestsException; use Illuminate\Database\UniqueConstraintViolationException; use Illuminate\Mail\Message; @@ -127,7 +128,6 @@ function refreshSession(?Team $team = null): void } function handleError(?Throwable $error = null, ?Livewire\Component $livewire = null, ?string $customErrorMessage = null) { - loggy($error); if ($error instanceof TooManyRequestsException) { if (isset($livewire)) { return $livewire->dispatch('error', "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds."); @@ -173,7 +173,7 @@ function get_latest_sentinel_version(): string $versions = $response->json(); return data_get($versions, 'coolify.sentinel.version'); - } catch (\Throwable $e) { + } catch (\Throwable) { return '0.0.0'; } } @@ -302,7 +302,7 @@ function getFqdnWithoutPort(string $fqdn) $path = $url->getPath(); return "$scheme://$host$path"; - } catch (\Throwable $e) { + } catch (\Throwable) { return $fqdn; } } @@ -370,6 +370,9 @@ function translate_cron_expression($expression_to_validate): string } function validate_cron_expression($expression_to_validate): bool { + if (empty($expression_to_validate)) { + return false; + } $isValid = false; $expression = new CronExpression($expression_to_validate); $isValid = $expression->isValid(); @@ -498,9 +501,8 @@ function generateFqdn(Server $server, string $random, bool $forceHttps = false): if ($forceHttps) { $scheme = 'https'; } - $finalFqdn = "$scheme://{$random}.$host$path"; - return $finalFqdn; + return "$scheme://{$random}.$host$path"; } function sslip(Server $server) { @@ -538,7 +540,7 @@ function get_service_templates(bool $force = false): Collection $services = $response->json(); return collect($services); - } catch (\Throwable $e) { + } catch (\Throwable) { $services = File::get(base_path('templates/service-templates.json')); return collect(json_decode($services))->sortKeys(); @@ -650,9 +652,8 @@ function generateTagDeployWebhook($tag_name) $baseUrl = base_url(); $api = Url::fromString($baseUrl).'/api/v1'; $endpoint = "/deploy?tag=$tag_name"; - $url = $api.$endpoint; - return $url; + return $api.$endpoint; } function generateDeployWebhook($resource) { @@ -660,9 +661,8 @@ function generateDeployWebhook($resource) $api = Url::fromString($baseUrl).'/api/v1'; $endpoint = '/deploy'; $uuid = data_get($resource, 'uuid'); - $url = $api.$endpoint."?uuid=$uuid&force=false"; - return $url; + return $api.$endpoint."?uuid=$uuid&force=false"; } function generateGitManualWebhook($resource, $type) { @@ -671,9 +671,8 @@ function generateGitManualWebhook($resource, $type) } if ($resource->getMorphClass() === \App\Models\Application::class) { $baseUrl = base_url(); - $api = Url::fromString($baseUrl)."/webhooks/source/$type/events/manual"; - return $api; + return Url::fromString($baseUrl)."/webhooks/source/$type/events/manual"; } return null; @@ -947,7 +946,7 @@ function generateEnvValue(string $command, Service|Application|null $service = n $key = InMemory::plainText($signingKey); $algorithm = new Sha256; $tokenBuilder = (new Builder(new JoseEncoder, ChainedFormatter::default())); - $now = new DateTimeImmutable; + $now = CarbonImmutable::now(); $now = $now->setTime($now->format('H'), $now->format('i')); $token = $tokenBuilder ->issuedBy('supabase') @@ -967,7 +966,7 @@ function generateEnvValue(string $command, Service|Application|null $service = n $key = InMemory::plainText($signingKey); $algorithm = new Sha256; $tokenBuilder = (new Builder(new JoseEncoder, ChainedFormatter::default())); - $now = new DateTimeImmutable; + $now = CarbonImmutable::now(); $now = $now->setTime($now->format('H'), $now->format('i')); $token = $tokenBuilder ->issuedBy('supabase') @@ -1050,7 +1049,7 @@ function validate_dns_entry(string $fqdn, Server $server) } } } - } catch (\Exception $e) { + } catch (\Exception) { } } ray("Found match: $found_matching_ip"); @@ -2211,7 +2210,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal } elseif ($resource->getMorphClass() === \App\Models\Application::class) { try { $yaml = Yaml::parse($resource->docker_compose_raw); - } catch (\Exception $e) { + } catch (\Exception) { return; } $server = $resource->destination->server; @@ -2957,7 +2956,7 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int try { $yaml = Yaml::parse($compose); - } catch (\Exception $e) { + } catch (\Exception) { return collect([]); } @@ -3185,7 +3184,6 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int 'is_build_time' => false, 'is_preview' => false, ]); - } else { $value = generateEnvValue($command, $resource); $resource->environment_variables()->where('key', $key->value())->where($nameOfId, $resource->id)->firstOrCreate([ @@ -3613,7 +3611,6 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int 'is_required' => $isRequired, ]); } - } } if ($isApplication) { @@ -3977,7 +3974,6 @@ function convertComposeEnvironmentToArray($environment) } return $convertedServiceVariables; - } function instanceSettings() { @@ -3986,7 +3982,6 @@ function instanceSettings() function loadConfigFromGit(string $repository, string $branch, string $base_directory, int $server_id, int $team_id) { - $server = Server::find($server_id)->where('team_id', $team_id)->first(); if (! $server) { return; @@ -4008,7 +4003,7 @@ function loadConfigFromGit(string $repository, string $branch, string $base_dire ]); try { return instant_remote_process($commands, $server); - } catch (\Exception $e) { + } catch (\Exception) { // continue } } diff --git a/bootstrap/helpers/socialite.php b/bootstrap/helpers/socialite.php index a23dc24d3..cad9de7fa 100644 --- a/bootstrap/helpers/socialite.php +++ b/bootstrap/helpers/socialite.php @@ -7,7 +7,7 @@ function get_socialite_provider(string $provider) { $oauth_setting = OauthSetting::firstWhere('provider', $provider); - if ($provider == 'azure') { + if ($provider === 'azure') { $azure_config = new \SocialiteProviders\Manager\Config( $oauth_setting->client_id, $oauth_setting->client_secret, diff --git a/bootstrap/helpers/subscriptions.php b/bootstrap/helpers/subscriptions.php index aadd2dd34..8ddb1331c 100644 --- a/bootstrap/helpers/subscriptions.php +++ b/bootstrap/helpers/subscriptions.php @@ -55,12 +55,11 @@ function getStripeCustomerPortalSession(Team $team) if (! $stripe_customer_id) { return null; } - $session = \Stripe\BillingPortal\Session::create([ + + return \Stripe\BillingPortal\Session::create([ 'customer' => $stripe_customer_id, 'return_url' => $return_url, ]); - - return $session; } function allowedPathsForUnsubscribedAccounts() { diff --git a/composer.json b/composer.json index b17c3bf4e..40eec4882 100644 --- a/composer.json +++ b/composer.json @@ -1,26 +1,29 @@ { - "name": "laravel/laravel", + "name": "coollabsio/coolify", + "description": "The Coolify project.", + "license": "Apache-2.0", "type": "project", - "description": "The Laravel Framework.", "keywords": [ - "framework", - "laravel" + "coolify", + "deployment", + "docker", + "self-hosted", + "server" ], - "license": "MIT", "require": { "php": "^8.2", "danharrin/livewire-rate-limiting": "^1.1", "doctrine/dbal": "^3.6", "guzzlehttp/guzzle": "^7.5.0", - "laravel/fortify": "^v1.16.0", - "laravel/framework": "^v11", + "laravel/fortify": "^1.16.0", + "laravel/framework": "^11", "laravel/horizon": "^5.29.1", "laravel/pail": "^1.1", "laravel/prompts": "^0.1.6", - "laravel/sanctum": "^v4.0", - "laravel/socialite": "^v5.14.0", + "laravel/sanctum": "^4.0", + "laravel/socialite": "^5.14.0", "laravel/telescope": "^5.2", - "laravel/tinker": "^v2.8.1", + "laravel/tinker": "^2.8.1", "laravel/ui": "^4.2", "lcobucci/jwt": "^5.0.0", "league/flysystem-aws-s3-v3": "^3.0", @@ -29,7 +32,7 @@ "log1x/laravel-webfonts": "^1.0", "lorisleiva/laravel-actions": "^2.7", "nubs/random-name-generator": "^2.2", - "phpseclib/phpseclib": "~3.0", + "phpseclib/phpseclib": "^3.0", "pion/laravel-chunk-upload": "^1.5", "poliander/cron": "^3.0", "purplepixie/phpdns": "^2.1", @@ -50,53 +53,43 @@ }, "require-dev": { "barryvdh/laravel-debugbar": "^3.13", - "fakerphp/faker": "^v1.21.0", - "laravel/dusk": "^v8.0", + "fakerphp/faker": "^1.21.0", + "laravel/dusk": "^8.0", "laravel/pint": "^1.16", "mockery/mockery": "^1.5.1", - "nunomaduro/collision": "^v8.1", + "nunomaduro/collision": "^8.1", "pestphp/pest": "^2.16", "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^10.0.19", - "serversideup/spin": "^v1.1.0", + "serversideup/spin": "^1.1.0", "spatie/laravel-ignition": "^2.1.0", "symfony/http-client": "^6.2" }, + "minimum-stability": "stable", + "prefer-stable": true, "autoload": { - "files": [ - "bootstrap/includeHelpers.php" - ], "psr-4": { "App\\": "app/", "Database\\Factories\\": "database/factories/", "Database\\Seeders\\": "database/seeders/" - } + }, + "files": [ + "bootstrap/includeHelpers.php" + ] }, "autoload-dev": { "psr-4": { "Tests\\": "tests/" } }, - "scripts": { - "post-autoload-dump": [ - "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", - "@php artisan package:discover --ansi" - ], - "post-update-cmd": [ - "@php artisan vendor:publish --tag=laravel-assets --ansi --force", - "Illuminate\\Foundation\\ComposerScripts::postUpdate" - ], - "post-install-cmd": [ - "cp -r 'hooks/' '.git/hooks/'", - "php -r \"copy('hooks/pre-commit', '.git/hooks/pre-commit');\"", - "php -r \"chmod('.git/hooks/pre-commit', 0777);\"" - ], - "post-root-package-install": [ - "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" - ], - "post-create-project-cmd": [ - "@php artisan key:generate --ansi" - ] + "config": { + "allow-plugins": { + "pestphp/pest-plugin": true, + "php-http/discovery": true + }, + "optimize-autoloader": true, + "preferred-install": "dist", + "sort-packages": true }, "extra": { "laravel": { @@ -105,15 +98,25 @@ ] } }, - "config": { - "optimize-autoloader": true, - "preferred-install": "dist", - "sort-packages": true, - "allow-plugins": { - "pestphp/pest-plugin": true, - "php-http/discovery": true - } - }, - "minimum-stability": "stable", - "prefer-stable": true + "scripts": { + "post-install-cmd": [ + "cp -r 'hooks/' '.git/hooks/'", + "php -r \"copy('hooks/pre-commit', '.git/hooks/pre-commit');\"", + "php -r \"chmod('.git/hooks/pre-commit', 0777);\"" + ], + "post-update-cmd": [ + "@php artisan vendor:publish --tag=laravel-assets --ansi --force", + "Illuminate\\Foundation\\ComposerScripts::postUpdate" + ], + "post-autoload-dump": [ + "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", + "@php artisan package:discover --ansi" + ], + "post-root-package-install": [ + "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" + ], + "post-create-project-cmd": [ + "@php artisan key:generate --ansi" + ] + } } diff --git a/composer.lock b/composer.lock index 981e723d4..4b33d41cd 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": "943975ec232403b96a40d215253492d8", + "content-hash": "74c6029744c5c1101c704098a280bba1", "packages": [ { "name": "amphp/amp", diff --git a/database/migrations/2023_08_22_071051_add_stripe_plan_to_subscriptions.php b/database/migrations/2023_08_22_071051_add_stripe_plan_to_subscriptions.php index 3da187320..a04eaf983 100644 --- a/database/migrations/2023_08_22_071051_add_stripe_plan_to_subscriptions.php +++ b/database/migrations/2023_08_22_071051_add_stripe_plan_to_subscriptions.php @@ -13,7 +13,6 @@ return new class extends Migration { Schema::table('subscriptions', function (Blueprint $table) { $table->string('stripe_plan_id')->nullable()->after('stripe_cancel_at_period_end'); - }); } diff --git a/database/migrations/2023_08_22_071054_add_stripe_reasons.php b/database/migrations/2023_08_22_071054_add_stripe_reasons.php index efd611aac..6ffe37e98 100644 --- a/database/migrations/2023_08_22_071054_add_stripe_reasons.php +++ b/database/migrations/2023_08_22_071054_add_stripe_reasons.php @@ -14,7 +14,6 @@ return new class extends Migration Schema::table('subscriptions', function (Blueprint $table) { $table->string('stripe_feedback')->nullable()->after('stripe_cancel_at_period_end'); $table->string('stripe_comment')->nullable()->after('stripe_feedback'); - }); } diff --git a/database/migrations/2023_08_22_071059_add_stripe_trial_ended.php b/database/migrations/2023_08_22_071059_add_stripe_trial_ended.php index c22317e6b..61fcbda6b 100644 --- a/database/migrations/2023_08_22_071059_add_stripe_trial_ended.php +++ b/database/migrations/2023_08_22_071059_add_stripe_trial_ended.php @@ -13,7 +13,6 @@ return new class extends Migration { Schema::table('subscriptions', function (Blueprint $table) { $table->boolean('stripe_trial_already_ended')->default(false)->after('stripe_cancel_at_period_end'); - }); } diff --git a/database/migrations/2023_08_22_071060_change_invitation_link_length.php b/database/migrations/2023_08_22_071060_change_invitation_link_length.php index 4efb03351..9d14c3f26 100644 --- a/database/migrations/2023_08_22_071060_change_invitation_link_length.php +++ b/database/migrations/2023_08_22_071060_change_invitation_link_length.php @@ -13,7 +13,6 @@ return new class extends Migration { Schema::table('team_invitations', function (Blueprint $table) { $table->text('link')->change(); - }); } diff --git a/database/migrations/2023_09_20_082541_update_services_table.php b/database/migrations/2023_09_20_082541_update_services_table.php index 8c6b350f7..c70cd28f7 100644 --- a/database/migrations/2023_09_20_082541_update_services_table.php +++ b/database/migrations/2023_09_20_082541_update_services_table.php @@ -16,7 +16,6 @@ return new class extends Migration $table->longText('description')->nullable(); $table->longText('docker_compose_raw'); $table->longText('docker_compose')->nullable(); - }); } diff --git a/database/migrations/2023_09_20_083549_update_environment_variables_table.php b/database/migrations/2023_09_20_083549_update_environment_variables_table.php index 40eb6aa44..a96d096bb 100644 --- a/database/migrations/2023_09_20_083549_update_environment_variables_table.php +++ b/database/migrations/2023_09_20_083549_update_environment_variables_table.php @@ -13,7 +13,6 @@ return new class extends Migration { Schema::table('environment_variables', function (Blueprint $table) { $table->foreignId('service_id')->nullable(); - }); } diff --git a/database/migrations/2023_09_23_111809_remove_destination_from_services_table.php b/database/migrations/2023_09_23_111809_remove_destination_from_services_table.php index 920f44a72..729146a4a 100644 --- a/database/migrations/2023_09_23_111809_remove_destination_from_services_table.php +++ b/database/migrations/2023_09_23_111809_remove_destination_from_services_table.php @@ -14,7 +14,6 @@ return new class extends Migration Schema::table('services', function (Blueprint $table) { $table->dropColumn('destination_type'); $table->dropColumn('destination_id'); - }); } diff --git a/database/migrations/2023_09_23_111819_add_server_emails.php b/database/migrations/2023_09_23_111819_add_server_emails.php index 03c1e6bd2..775e82010 100644 --- a/database/migrations/2023_09_23_111819_add_server_emails.php +++ b/database/migrations/2023_09_23_111819_add_server_emails.php @@ -26,6 +26,5 @@ return new class extends Migration $table->dropColumn('unreachable_email_sent'); $table->integer('unreachable_count')->default(0); }); - } }; diff --git a/database/migrations/2023_11_16_220647_add_log_drains.php b/database/migrations/2023_11_16_220647_add_log_drains.php index 05b1ed054..f5161b3d7 100644 --- a/database/migrations/2023_11_16_220647_add_log_drains.php +++ b/database/migrations/2023_11_16_220647_add_log_drains.php @@ -22,7 +22,6 @@ return new class extends Migration $table->boolean('is_logdrain_axiom_enabled')->default(false); $table->string('logdrain_axiom_dataset_name')->nullable(); $table->string('logdrain_axiom_api_key')->nullable(); - }); } diff --git a/database/migrations/2023_12_13_110214_add_soft_deletes.php b/database/migrations/2023_12_13_110214_add_soft_deletes.php index ab7b562b4..72350b77f 100644 --- a/database/migrations/2023_12_13_110214_add_soft_deletes.php +++ b/database/migrations/2023_12_13_110214_add_soft_deletes.php @@ -66,6 +66,5 @@ return new class extends Migration Schema::table('service_databases', function (Blueprint $table) { $table->dropSoftDeletes(); }); - } }; diff --git a/database/migrations/2023_12_17_155616_add_custom_docker_compose_start_command.php b/database/migrations/2023_12_17_155616_add_custom_docker_compose_start_command.php index eeb2769fe..f28b2670e 100644 --- a/database/migrations/2023_12_17_155616_add_custom_docker_compose_start_command.php +++ b/database/migrations/2023_12_17_155616_add_custom_docker_compose_start_command.php @@ -14,7 +14,6 @@ return new class extends Migration Schema::table('applications', function (Blueprint $table) { $table->string('docker_compose_custom_start_command')->nullable(); $table->string('docker_compose_custom_build_command')->nullable(); - }); } diff --git a/database/migrations/2024_04_09_095517_make_custom_docker_commands_longer.php b/database/migrations/2024_04_09_095517_make_custom_docker_commands_longer.php index 7df53ec06..b3f2c1920 100644 --- a/database/migrations/2024_04_09_095517_make_custom_docker_commands_longer.php +++ b/database/migrations/2024_04_09_095517_make_custom_docker_commands_longer.php @@ -13,7 +13,6 @@ return new class extends Migration { Schema::table('applications', function (Blueprint $table) { $table->text('custom_docker_run_options')->nullable()->change(); - }); } diff --git a/database/migrations/2024_04_25_073615_add_docker_network_to_application_settings.php b/database/migrations/2024_04_25_073615_add_docker_network_to_application_settings.php index aeae6f77d..bea410eab 100644 --- a/database/migrations/2024_04_25_073615_add_docker_network_to_application_settings.php +++ b/database/migrations/2024_04_25_073615_add_docker_network_to_application_settings.php @@ -13,7 +13,6 @@ return new class extends Migration { Schema::table('application_settings', function (Blueprint $table) { $table->boolean('connect_to_docker_network')->default(false); - }); } diff --git a/database/migrations/2024_05_23_091713_add_gitea_webhook_to_applications.php b/database/migrations/2024_05_23_091713_add_gitea_webhook_to_applications.php index 716f1f44c..b46a07203 100644 --- a/database/migrations/2024_05_23_091713_add_gitea_webhook_to_applications.php +++ b/database/migrations/2024_05_23_091713_add_gitea_webhook_to_applications.php @@ -13,7 +13,6 @@ return new class extends Migration { Schema::table('applications', function (Blueprint $table) { $table->string('manual_webhook_secret_gitea')->nullable(); - }); } diff --git a/database/migrations/2024_08_09_215659_add_server_cleanup_fields_to_server_settings_table.php b/database/migrations/2024_08_09_215659_add_server_cleanup_fields_to_server_settings_table.php index b5300c905..e3bdc68c6 100644 --- a/database/migrations/2024_08_09_215659_add_server_cleanup_fields_to_server_settings_table.php +++ b/database/migrations/2024_08_09_215659_add_server_cleanup_fields_to_server_settings_table.php @@ -30,7 +30,6 @@ class AddServerCleanupFieldsToServerSettingsTable extends Migration $serverSetting->docker_cleanup_threshold = $serverSetting->cleanup_after_percentage; $serverSetting->save(); } - } /** diff --git a/database/migrations/2024_09_16_111428_encrypt_existing_private_keys.php b/database/migrations/2024_09_16_111428_encrypt_existing_private_keys.php index 19274ad9b..e16181ac7 100644 --- a/database/migrations/2024_09_16_111428_encrypt_existing_private_keys.php +++ b/database/migrations/2024_09_16_111428_encrypt_existing_private_keys.php @@ -20,6 +20,5 @@ class EncryptExistingPrivateKeys extends Migration echo 'Encrypting private keys failed.'; echo $e->getMessage(); } - } } diff --git a/database/seeders/ProductionSeeder.php b/database/seeders/ProductionSeeder.php index 90b9d46ff..3e820a162 100644 --- a/database/seeders/ProductionSeeder.php +++ b/database/seeders/ProductionSeeder.php @@ -126,7 +126,6 @@ class ProductionSeeder extends Seeder echo "Your localhost connection won't work until then."; } } - } if (config('coolify.is_windows_docker_desktop')) { PrivateKey::updateOrCreate( @@ -187,6 +186,5 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== $this->call(OauthSettingSeeder::class); $this->call(PopulateSshKeysDirectorySeeder::class); $this->call(SentinelSeeder::class); - } } diff --git a/resources/css/app.css b/resources/css/app.css index 00a62a131..73f19de96 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -69,7 +69,7 @@ button[isHighlighted]:not(:disabled) { } h1 { - @apply text-2xl font-bold dark:text-white; + @apply text-3xl font-bold dark:text-white; } h2 { @@ -124,6 +124,10 @@ tr td:first-child { @apply pl-4 pr-3 font-bold sm:pl-6; } +section { + @apply mb-12; +} + .alert-success { @apply flex items-center gap-2 text-success; } @@ -217,7 +221,7 @@ tr td:first-child { } .box { - @apply relative flex lg:flex-row flex-col p-2 transition-colors cursor-pointer min-h-[4rem] dark:bg-coolgray-100 bg-white border text-black dark:text-white hover:text-black border-neutral-200 dark:border-black hover:bg-neutral-100 dark:hover:bg-coollabs-100 dark:hover:text-white hover:no-underline; + @apply relative flex lg:flex-row flex-col p-2 transition-colors cursor-pointer min-h-[4rem] dark:bg-coolgray-100 shadow bg-white border text-black dark:text-white hover:text-black border-neutral-200 dark:border-black hover:bg-neutral-100 dark:hover:bg-coollabs-100 dark:hover:text-white hover:no-underline; } .box-boarding { diff --git a/resources/views/components/forms/checkbox.blade.php b/resources/views/components/forms/checkbox.blade.php index 3f01a70c5..316e73949 100644 --- a/resources/views/components/forms/checkbox.blade.php +++ b/resources/views/components/forms/checkbox.blade.php @@ -15,10 +15,7 @@ 'w-full' => $fullWidth, ])> @if (!$hideLabel) -