Merge branch 'next' into feat-db-ssl
This commit is contained in:
		@@ -91,8 +91,6 @@ function next_queuable(string $server_id, string $application_id): bool
 | 
			
		||||
    $server = Server::find($server_id);
 | 
			
		||||
    $concurrent_builds = $server->settings->concurrent_builds;
 | 
			
		||||
 | 
			
		||||
    // ray("serverId:{$server->id}", "concurrentBuilds:{$concurrent_builds}", "deployments:{$deployments->count()}", "sameApplicationDeployments:{$same_application_deployments->count()}")->green();
 | 
			
		||||
 | 
			
		||||
    if ($deployments->count() > $concurrent_builds) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -236,15 +236,29 @@ function deleteEmptyBackupFolder($folderPath, Server $server): void
 | 
			
		||||
function removeOldBackups($backup): void
 | 
			
		||||
{
 | 
			
		||||
    try {
 | 
			
		||||
        $processedBackups = deleteOldBackupsLocally($backup);
 | 
			
		||||
 | 
			
		||||
        if ($backup->save_s3) {
 | 
			
		||||
            $processedBackups = $processedBackups->merge(deleteOldBackupsFromS3($backup));
 | 
			
		||||
        if ($backup->executions) {
 | 
			
		||||
            $localBackupsToDelete = deleteOldBackupsLocally($backup);
 | 
			
		||||
            if ($localBackupsToDelete->isNotEmpty()) {
 | 
			
		||||
                $backup->executions()
 | 
			
		||||
                    ->whereIn('id', $localBackupsToDelete->pluck('id'))
 | 
			
		||||
                    ->update(['local_storage_deleted' => true]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($processedBackups->isNotEmpty()) {
 | 
			
		||||
            $backup->executions()->whereIn('id', $processedBackups->pluck('id'))->delete();
 | 
			
		||||
        if ($backup->save_s3 && $backup->executions) {
 | 
			
		||||
            $s3BackupsToDelete = deleteOldBackupsFromS3($backup);
 | 
			
		||||
            if ($s3BackupsToDelete->isNotEmpty()) {
 | 
			
		||||
                $backup->executions()
 | 
			
		||||
                    ->whereIn('id', $s3BackupsToDelete->pluck('id'))
 | 
			
		||||
                    ->update(['s3_storage_deleted' => true]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $backup->executions()
 | 
			
		||||
            ->where('local_storage_deleted', true)
 | 
			
		||||
            ->where('s3_storage_deleted', true)
 | 
			
		||||
            ->delete();
 | 
			
		||||
 | 
			
		||||
    } catch (\Exception $e) {
 | 
			
		||||
        throw $e;
 | 
			
		||||
    }
 | 
			
		||||
@@ -258,6 +272,7 @@ function deleteOldBackupsLocally($backup): Collection
 | 
			
		||||
 | 
			
		||||
    $successfulBackups = $backup->executions()
 | 
			
		||||
        ->where('status', 'success')
 | 
			
		||||
        ->where('local_storage_deleted', false)
 | 
			
		||||
        ->orderBy('created_at', 'desc')
 | 
			
		||||
        ->get();
 | 
			
		||||
 | 
			
		||||
@@ -341,6 +356,7 @@ function deleteOldBackupsFromS3($backup): Collection
 | 
			
		||||
 | 
			
		||||
    $successfulBackups = $backup->executions()
 | 
			
		||||
        ->where('status', 'success')
 | 
			
		||||
        ->where('s3_storage_deleted', false)
 | 
			
		||||
        ->orderBy('created_at', 'desc')
 | 
			
		||||
        ->get();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -778,7 +778,6 @@ function convertDockerRunToCompose(?string $custom_docker_run_options = null)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            ray($payload);
 | 
			
		||||
            $compose_options->put('deploy', [
 | 
			
		||||
                'resources' => [
 | 
			
		||||
                    'reservations' => [
 | 
			
		||||
@@ -829,26 +828,29 @@ function generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker
 | 
			
		||||
 | 
			
		||||
function validateComposeFile(string $compose, int $server_id): string|Throwable
 | 
			
		||||
{
 | 
			
		||||
    return 'OK';
 | 
			
		||||
    $uuid = Str::random(18);
 | 
			
		||||
    $server = Server::ownedByCurrentTeam()->find($server_id);
 | 
			
		||||
    try {
 | 
			
		||||
        $uuid = Str::random(10);
 | 
			
		||||
        $server = Server::findOrFail($server_id);
 | 
			
		||||
        if (! $server) {
 | 
			
		||||
            throw new \Exception('Server not found');
 | 
			
		||||
        }
 | 
			
		||||
        $base64_compose = base64_encode($compose);
 | 
			
		||||
        $output = instant_remote_process([
 | 
			
		||||
        instant_remote_process([
 | 
			
		||||
            "echo {$base64_compose} | base64 -d | tee /tmp/{$uuid}.yml > /dev/null",
 | 
			
		||||
            "docker compose -f /tmp/{$uuid}.yml config",
 | 
			
		||||
            "chmod 600 /tmp/{$uuid}.yml",
 | 
			
		||||
            "docker compose -f /tmp/{$uuid}.yml config --no-interpolate --no-path-resolution -q",
 | 
			
		||||
            "rm /tmp/{$uuid}.yml",
 | 
			
		||||
        ], $server);
 | 
			
		||||
        ray($output);
 | 
			
		||||
 | 
			
		||||
        return 'OK';
 | 
			
		||||
    } catch (\Throwable $e) {
 | 
			
		||||
        ray($e);
 | 
			
		||||
 | 
			
		||||
        return $e->getMessage();
 | 
			
		||||
    } finally {
 | 
			
		||||
        instant_remote_process([
 | 
			
		||||
            "rm /tmp/{$uuid}.yml",
 | 
			
		||||
        ], $server);
 | 
			
		||||
        if (filled($server)) {
 | 
			
		||||
            instant_remote_process([
 | 
			
		||||
                "rm /tmp/{$uuid}.yml",
 | 
			
		||||
            ], $server, throwError: false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ function send_user_an_email(MailMessage $mail, string $email, ?string $cc = null
 | 
			
		||||
{
 | 
			
		||||
    $settings = instanceSettings();
 | 
			
		||||
    $type = set_transanctional_email_settings($settings);
 | 
			
		||||
    if (! $type) {
 | 
			
		||||
    if (blank($type)) {
 | 
			
		||||
        throw new Exception('No email settings found.');
 | 
			
		||||
    }
 | 
			
		||||
    if ($cc) {
 | 
			
		||||
@@ -54,15 +54,19 @@ function send_user_an_email(MailMessage $mail, string $email, ?string $cc = null
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function set_transanctional_email_settings(?InstanceSettings $settings = null): ?string //
 | 
			
		||||
function set_transanctional_email_settings(?InstanceSettings $settings = null): ?string // returns null|resend|smtp and defaults to array based on mail.php config
 | 
			
		||||
{
 | 
			
		||||
    if (! $settings) {
 | 
			
		||||
        $settings = instanceSettings();
 | 
			
		||||
    }
 | 
			
		||||
    config()->set('mail.from.address', data_get($settings, 'smtp_from_address'));
 | 
			
		||||
    config()->set('mail.from.name', data_get($settings, 'smtp_from_name'));
 | 
			
		||||
    if (! data_get($settings, 'smtp_enabled') && ! data_get($settings, 'resend_enabled')) {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (data_get($settings, 'resend_enabled')) {
 | 
			
		||||
        config()->set('mail.default', 'resend');
 | 
			
		||||
        config()->set('mail.from.address', data_get($settings, 'smtp_from_address'));
 | 
			
		||||
        config()->set('mail.from.name', data_get($settings, 'smtp_from_name'));
 | 
			
		||||
        config()->set('resend.api_key', data_get($settings, 'resend_api_key'));
 | 
			
		||||
 | 
			
		||||
        return 'resend';
 | 
			
		||||
@@ -76,6 +80,8 @@ function set_transanctional_email_settings(?InstanceSettings $settings = null):
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (data_get($settings, 'smtp_enabled')) {
 | 
			
		||||
        config()->set('mail.from.address', data_get($settings, 'smtp_from_address'));
 | 
			
		||||
        config()->set('mail.from.name', data_get($settings, 'smtp_from_name'));
 | 
			
		||||
        config()->set('mail.default', 'smtp');
 | 
			
		||||
        config()->set('mail.mailers.smtp', [
 | 
			
		||||
            'transport' => 'smtp',
 | 
			
		||||
@@ -91,6 +97,4 @@ function set_transanctional_email_settings(?InstanceSettings $settings = null):
 | 
			
		||||
 | 
			
		||||
        return 'smtp';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return null;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -748,6 +748,7 @@ function parseCommandFromMagicEnvVariable(Str|string $key): Stringable
 | 
			
		||||
{
 | 
			
		||||
    $value = str($key);
 | 
			
		||||
    $count = substr_count($value->value(), '_');
 | 
			
		||||
    $command = null;
 | 
			
		||||
    if ($count === 2) {
 | 
			
		||||
        if ($value->startsWith('SERVICE_FQDN') || $value->startsWith('SERVICE_URL')) {
 | 
			
		||||
            // SERVICE_FQDN_UMAMI
 | 
			
		||||
@@ -800,7 +801,6 @@ function parseEnvVariable(Str|string $value)
 | 
			
		||||
            } else {
 | 
			
		||||
                // SERVICE_BASE64_64_UMAMI
 | 
			
		||||
                $command = $value->after('SERVICE_')->beforeLast('_');
 | 
			
		||||
                ray($command);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -952,7 +952,6 @@ function validate_dns_entry(string $fqdn, Server $server)
 | 
			
		||||
    $type = \PurplePixie\PhpDns\DNSTypes::NAME_A;
 | 
			
		||||
    foreach ($dns_servers as $dns_server) {
 | 
			
		||||
        try {
 | 
			
		||||
            ray("Checking $host on $dns_server");
 | 
			
		||||
            $query = new DNSQuery($dns_server);
 | 
			
		||||
            $results = $query->query($host, $type);
 | 
			
		||||
            if ($results === false || $query->hasError()) {
 | 
			
		||||
@@ -961,13 +960,10 @@ function validate_dns_entry(string $fqdn, Server $server)
 | 
			
		||||
                foreach ($results as $result) {
 | 
			
		||||
                    if ($result->getType() == $type) {
 | 
			
		||||
                        if (ip_match($result->getData(), $cloudflare_ips->toArray(), $match)) {
 | 
			
		||||
                            ray("Found match in Cloudflare IPs: $match");
 | 
			
		||||
                            $found_matching_ip = true;
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                        if ($result->getData() === $ip) {
 | 
			
		||||
                            ray($host.' has IP address '.$result->getData());
 | 
			
		||||
                            ray($result->getString());
 | 
			
		||||
                            $found_matching_ip = true;
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
@@ -977,7 +973,6 @@ function validate_dns_entry(string $fqdn, Server $server)
 | 
			
		||||
        } catch (\Exception) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    ray("Found match: $found_matching_ip");
 | 
			
		||||
 | 
			
		||||
    return $found_matching_ip;
 | 
			
		||||
}
 | 
			
		||||
@@ -1331,7 +1326,6 @@ function parseServiceVolumes($serviceVolumes, $resource, $topLevelVolumes, $pull
 | 
			
		||||
                $isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
 | 
			
		||||
                if ((is_null($isDirectory) || ! $isDirectory) && is_null($content)) {
 | 
			
		||||
                    // if isDirectory is not set (or false) & content is also not set, we assume it is a directory
 | 
			
		||||
                    ray('setting isDirectory to true');
 | 
			
		||||
                    $isDirectory = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -1499,7 +1493,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
 | 
			
		||||
                        $serviceLabels->push("$removedLabelName=$removedLabel");
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $containerName = "$serviceName-{$resource->uuid}";
 | 
			
		||||
 | 
			
		||||
                // Decide if the service is a database
 | 
			
		||||
@@ -1662,7 +1655,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
 | 
			
		||||
                            }
 | 
			
		||||
                            if (is_null($isDirectory) && is_null($content)) {
 | 
			
		||||
                                // if isDirectory is not set & content is also not set, we assume it is a directory
 | 
			
		||||
                                ray('setting isDirectory to true');
 | 
			
		||||
                                $isDirectory = true;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
@@ -2529,9 +2521,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if ($collectedPorts->count() > 0) {
 | 
			
		||||
                ray($collectedPorts->implode(','));
 | 
			
		||||
            }
 | 
			
		||||
            $definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
 | 
			
		||||
                return $value == $definedNetwork;
 | 
			
		||||
            });
 | 
			
		||||
@@ -2956,7 +2945,6 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $parsedServices = collect([]);
 | 
			
		||||
    // ray()->clearAll();
 | 
			
		||||
 | 
			
		||||
    $allMagicEnvironments = collect([]);
 | 
			
		||||
    foreach ($services as $serviceName => $service) {
 | 
			
		||||
@@ -3016,7 +3004,7 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
 | 
			
		||||
            $environment = $environment->merge($buildArgs);
 | 
			
		||||
 | 
			
		||||
            // convert environment variables to one format
 | 
			
		||||
            $environment = convertComposeEnvironmentToArray($environment);
 | 
			
		||||
            $environment = convertToKeyValueCollection($environment);
 | 
			
		||||
 | 
			
		||||
            // Add Coolify defined environments
 | 
			
		||||
            $allEnvironments = $resource->environment_variables()->get(['key', 'value']);
 | 
			
		||||
@@ -3197,7 +3185,7 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
 | 
			
		||||
        $buildArgs = collect(data_get($service, 'build.args', []));
 | 
			
		||||
        $environment = $environment->merge($buildArgs);
 | 
			
		||||
 | 
			
		||||
        $environment = convertComposeEnvironmentToArray($environment);
 | 
			
		||||
        $environment = convertToKeyValueCollection($environment);
 | 
			
		||||
        $coolifyEnvironments = collect([]);
 | 
			
		||||
 | 
			
		||||
        $isDatabase = isDatabaseImage(data_get_str($service, 'image'));
 | 
			
		||||
@@ -3934,7 +3922,7 @@ function add_coolify_default_environment_variables(StandaloneRedis|StandalonePos
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function convertComposeEnvironmentToArray($environment)
 | 
			
		||||
function convertToKeyValueCollection($environment)
 | 
			
		||||
{
 | 
			
		||||
    $convertedServiceVariables = collect([]);
 | 
			
		||||
    if (isAssociativeArray($environment)) {
 | 
			
		||||
@@ -4066,29 +4054,24 @@ function defaultNginxConfiguration(): string
 | 
			
		||||
{
 | 
			
		||||
    return 'server {
 | 
			
		||||
    location / {
 | 
			
		||||
        root   /usr/share/nginx/html;
 | 
			
		||||
        index  index.html index.htm;
 | 
			
		||||
        try_files $uri $uri.html $uri/index.html $uri/index.htm $uri/ /index.html /index.htm =404;
 | 
			
		||||
        root /usr/share/nginx/html;
 | 
			
		||||
        index index.html index.htm;
 | 
			
		||||
        try_files $uri $uri.html $uri/index.html $uri/index.htm $uri/ =404;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # Handle 404 errors
 | 
			
		||||
    error_page 404 /404.html;
 | 
			
		||||
    location = /404.html {
 | 
			
		||||
        root /usr/share/nginx/html;
 | 
			
		||||
        internal;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # Handle server errors (50x)
 | 
			
		||||
    error_page 500 502 503 504 /50x.html;
 | 
			
		||||
    location = /50x.html {
 | 
			
		||||
        root /usr/share/nginx/html;
 | 
			
		||||
        try_files $uri @redirect_to_index;
 | 
			
		||||
        internal;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    error_page 404 = @handle_404;
 | 
			
		||||
 | 
			
		||||
    location @handle_404 {
 | 
			
		||||
        root /usr/share/nginx/html;
 | 
			
		||||
        try_files /404.html @redirect_to_index;
 | 
			
		||||
        internal;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    location @redirect_to_index {
 | 
			
		||||
        return 302 /;
 | 
			
		||||
    }
 | 
			
		||||
}';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,18 @@ function get_socialite_provider(string $provider)
 | 
			
		||||
        return Socialite::driver('authentik')->setConfig($authentik_config);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($provider == 'google') {
 | 
			
		||||
        $google_config = new \SocialiteProviders\Manager\Config(
 | 
			
		||||
            $oauth_setting->client_id,
 | 
			
		||||
            $oauth_setting->client_secret,
 | 
			
		||||
            $oauth_setting->redirect_uri
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return Socialite::driver('google')
 | 
			
		||||
            ->setConfig($google_config)
 | 
			
		||||
            ->with(['hd' => $oauth_setting->tenant]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $config = [
 | 
			
		||||
        'client_id' => $oauth_setting->client_id,
 | 
			
		||||
        'client_secret' => $oauth_setting->client_secret,
 | 
			
		||||
@@ -39,7 +51,6 @@ function get_socialite_provider(string $provider)
 | 
			
		||||
        'bitbucket' => \Laravel\Socialite\Two\BitbucketProvider::class,
 | 
			
		||||
        'github' => \Laravel\Socialite\Two\GithubProvider::class,
 | 
			
		||||
        'gitlab' => \Laravel\Socialite\Two\GitlabProvider::class,
 | 
			
		||||
        'google' => \Laravel\Socialite\Two\GoogleProvider::class,
 | 
			
		||||
        'infomaniak' => \SocialiteProviders\Infomaniak\Provider::class,
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user