Merge branch 'next' into docker-network-aliases
This commit is contained in:
@@ -1068,7 +1068,6 @@ class Application extends BaseModel
|
||||
if ($this->deploymentType() === 'other') {
|
||||
$fullRepoUrl = $customRepository;
|
||||
$base_command = "{$base_command} {$customRepository}";
|
||||
$base_command = $this->setGitImportSettings($deployment_uuid, $base_command, public: true);
|
||||
|
||||
if ($exec_in_docker) {
|
||||
$commands->push(executeInDocker($deployment_uuid, $base_command));
|
||||
@@ -1511,6 +1510,7 @@ class Application extends BaseModel
|
||||
|
||||
public function parseHealthcheckFromDockerfile($dockerfile, bool $isInit = false)
|
||||
{
|
||||
$dockerfile = str($dockerfile)->trim()->explode("\n");
|
||||
if (str($dockerfile)->contains('HEALTHCHECK') && ($this->isHealthcheckDisabled() || $isInit)) {
|
||||
$healthcheckCommand = null;
|
||||
$lines = $dockerfile->toArray();
|
||||
@@ -1530,27 +1530,24 @@ class Application extends BaseModel
|
||||
}
|
||||
}
|
||||
if (str($healthcheckCommand)->isNotEmpty()) {
|
||||
$interval = str($healthcheckCommand)->match('/--interval=(\d+)/');
|
||||
$timeout = str($healthcheckCommand)->match('/--timeout=(\d+)/');
|
||||
$start_period = str($healthcheckCommand)->match('/--start-period=(\d+)/');
|
||||
$start_interval = str($healthcheckCommand)->match('/--start-interval=(\d+)/');
|
||||
$interval = str($healthcheckCommand)->match('/--interval=([0-9]+[a-zµ]*)/');
|
||||
$timeout = str($healthcheckCommand)->match('/--timeout=([0-9]+[a-zµ]*)/');
|
||||
$start_period = str($healthcheckCommand)->match('/--start-period=([0-9]+[a-zµ]*)/');
|
||||
$retries = str($healthcheckCommand)->match('/--retries=(\d+)/');
|
||||
|
||||
if ($interval->isNotEmpty()) {
|
||||
$this->health_check_interval = $interval->toInteger();
|
||||
$this->health_check_interval = parseDockerfileInterval($interval);
|
||||
}
|
||||
if ($timeout->isNotEmpty()) {
|
||||
$this->health_check_timeout = $timeout->toInteger();
|
||||
$this->health_check_timeout = parseDockerfileInterval($timeout);
|
||||
}
|
||||
if ($start_period->isNotEmpty()) {
|
||||
$this->health_check_start_period = $start_period->toInteger();
|
||||
$this->health_check_start_period = parseDockerfileInterval($start_period);
|
||||
}
|
||||
// if ($start_interval) {
|
||||
// $this->health_check_start_interval = $start_interval->value();
|
||||
// }
|
||||
if ($retries->isNotEmpty()) {
|
||||
$this->health_check_retries = $retries->toInteger();
|
||||
}
|
||||
if ($interval || $timeout || $start_period || $start_interval || $retries) {
|
||||
if ($interval || $timeout || $start_period || $retries) {
|
||||
$this->custom_healthcheck_found = true;
|
||||
$this->save();
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ class DiscordNotificationSettings extends Model
|
||||
'server_disk_usage_discord_notifications',
|
||||
'server_reachable_discord_notifications',
|
||||
'server_unreachable_discord_notifications',
|
||||
'discord_ping_enabled',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
@@ -45,6 +46,7 @@ class DiscordNotificationSettings extends Model
|
||||
'server_disk_usage_discord_notifications' => 'boolean',
|
||||
'server_reachable_discord_notifications' => 'boolean',
|
||||
'server_unreachable_discord_notifications' => 'boolean',
|
||||
'discord_ping_enabled' => 'boolean',
|
||||
];
|
||||
|
||||
public function team()
|
||||
@@ -56,4 +58,9 @@ class DiscordNotificationSettings extends Model
|
||||
{
|
||||
return $this->discord_enabled;
|
||||
}
|
||||
|
||||
public function isPingEnabled()
|
||||
{
|
||||
return $this->discord_ping_enabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,10 +70,6 @@ class EmailNotificationSettings extends Model
|
||||
|
||||
public function isEnabled()
|
||||
{
|
||||
if (isCloud()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->smtp_enabled || $this->resend_enabled || $this->use_instance_email_settings;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,12 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Jobs\PullHelperImageJob;
|
||||
use App\Notifications\Channels\SendsEmail;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Spatie\Url\Url;
|
||||
|
||||
class InstanceSettings extends Model implements SendsEmail
|
||||
class InstanceSettings extends Model
|
||||
{
|
||||
use Notifiable;
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
protected $casts = [
|
||||
@@ -92,15 +88,15 @@ class InstanceSettings extends Model implements SendsEmail
|
||||
return InstanceSettings::findOrFail(0);
|
||||
}
|
||||
|
||||
public function getRecipients($notification)
|
||||
{
|
||||
$recipients = data_get($notification, 'emails', null);
|
||||
if (is_null($recipients) || $recipients === '') {
|
||||
return [];
|
||||
}
|
||||
// public function getRecipients($notification)
|
||||
// {
|
||||
// $recipients = data_get($notification, 'emails', null);
|
||||
// if (is_null($recipients) || $recipients === '') {
|
||||
// return [];
|
||||
// }
|
||||
|
||||
return explode(',', $recipients);
|
||||
}
|
||||
// return explode(',', $recipients);
|
||||
// }
|
||||
|
||||
public function getTitleDisplayName(): string
|
||||
{
|
||||
|
||||
@@ -8,6 +8,13 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
class LocalFileVolume extends BaseModel
|
||||
{
|
||||
protected $casts = [
|
||||
// 'fs_path' => 'encrypted',
|
||||
// 'mount_path' => 'encrypted',
|
||||
'content' => 'encrypted',
|
||||
'is_directory' => 'boolean',
|
||||
];
|
||||
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = [];
|
||||
@@ -169,4 +176,19 @@ class LocalFileVolume extends BaseModel
|
||||
|
||||
return instant_remote_process($commands, $server);
|
||||
}
|
||||
|
||||
// Accessor for convenient access
|
||||
protected function plainMountPath(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->mount_path,
|
||||
set: fn ($value) => $this->mount_path = $value
|
||||
);
|
||||
}
|
||||
|
||||
// Scope for searching
|
||||
public function scopeWherePlainMountPath($query, $path)
|
||||
{
|
||||
return $query->get()->where('plain_mount_path', $path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,11 +24,6 @@ class LocalPersistentVolume extends Model
|
||||
return $this->morphTo('resource');
|
||||
}
|
||||
|
||||
public function standalone_postgresql()
|
||||
{
|
||||
return $this->morphTo('resource');
|
||||
}
|
||||
|
||||
protected function name(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
|
||||
@@ -7,9 +7,12 @@ use App\Actions\Server\InstallDocker;
|
||||
use App\Actions\Server\StartSentinel;
|
||||
use App\Enums\ProxyTypes;
|
||||
use App\Events\ServerReachabilityChanged;
|
||||
use App\Helpers\SslHelper;
|
||||
use App\Jobs\CheckAndStartSentinelJob;
|
||||
use App\Jobs\RegenerateSslCertJob;
|
||||
use App\Notifications\Server\Reachable;
|
||||
use App\Notifications\Server\Unreachable;
|
||||
use App\Services\ConfigurationRepository;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
@@ -484,7 +487,7 @@ $schema://$host {
|
||||
$base_path = config('constants.coolify.base_config_path');
|
||||
$proxyType = $this->proxyType();
|
||||
$proxy_path = "$base_path/proxy";
|
||||
// TODO: should use /traefik for already exisiting configurations?
|
||||
// TODO: should use /traefik for already existing configurations?
|
||||
// Should move everything except /caddy and /nginx to /traefik
|
||||
// The code needs to be modified as well, so maybe it does not worth it
|
||||
if ($proxyType === ProxyTypes::TRAEFIK->value) {
|
||||
@@ -543,7 +546,7 @@ $schema://$host {
|
||||
$this->settings->save();
|
||||
$sshKeyFileLocation = "id.root@{$this->uuid}";
|
||||
Storage::disk('ssh-keys')->delete($sshKeyFileLocation);
|
||||
Storage::disk('ssh-mux')->delete($this->muxFilename());
|
||||
$this->disableSshMux();
|
||||
}
|
||||
|
||||
public function sentinelHeartbeat(bool $isReset = false)
|
||||
@@ -922,7 +925,7 @@ $schema://$host {
|
||||
|
||||
public function isFunctional()
|
||||
{
|
||||
$isFunctional = $this->settings->is_reachable && $this->settings->is_usable && $this->settings->force_disabled === false && $this->ip !== '1.2.3.4';
|
||||
$isFunctional = data_get($this->settings, 'is_reachable') && data_get($this->settings, 'is_usable') && data_get($this->settings, 'force_disabled') === false && $this->ip !== '1.2.3.4';
|
||||
|
||||
if ($isFunctional === false) {
|
||||
Storage::disk('ssh-mux')->delete($this->muxFilename());
|
||||
@@ -1103,7 +1106,7 @@ $schema://$host {
|
||||
|
||||
public function validateConnection(bool $justCheckingNewKey = false)
|
||||
{
|
||||
config()->set('constants.ssh.mux_enabled', false);
|
||||
$this->disableSshMux();
|
||||
|
||||
if ($this->skipServer()) {
|
||||
return ['uptime' => false, 'error' => 'Server skipped.'];
|
||||
@@ -1330,4 +1333,47 @@ $schema://$host {
|
||||
$this->databases()->count() == 0 &&
|
||||
$this->services()->count() == 0;
|
||||
}
|
||||
|
||||
private function disableSshMux(): void
|
||||
{
|
||||
$configRepository = app(ConfigurationRepository::class);
|
||||
$configRepository->disableSshMux();
|
||||
}
|
||||
|
||||
public function generateCaCertificate()
|
||||
{
|
||||
try {
|
||||
ray('Generating CA certificate for server', $this->id);
|
||||
SslHelper::generateSslCertificate(
|
||||
commonName: 'Coolify CA Certificate',
|
||||
serverId: $this->id,
|
||||
isCaCertificate: true,
|
||||
validityDays: 10 * 365
|
||||
);
|
||||
$caCertificate = SslCertificate::where('server_id', $this->id)->where('is_ca_certificate', true)->first();
|
||||
ray('CA certificate generated', $caCertificate);
|
||||
if ($caCertificate) {
|
||||
$certificateContent = $caCertificate->ssl_certificate;
|
||||
$caCertPath = config('constants.coolify.base_config_path').'/ssl/';
|
||||
|
||||
$commands = collect([
|
||||
"mkdir -p $caCertPath",
|
||||
"chown -R 9999:root $caCertPath",
|
||||
"chmod -R 700 $caCertPath",
|
||||
"rm -rf $caCertPath/coolify-ca.crt",
|
||||
"echo '{$certificateContent}' > $caCertPath/coolify-ca.crt",
|
||||
"chmod 644 $caCertPath/coolify-ca.crt",
|
||||
]);
|
||||
|
||||
instant_remote_process($commands, $this, false);
|
||||
|
||||
dispatch(new RegenerateSslCertJob(
|
||||
server_id: $this->id,
|
||||
force_regeneration: true
|
||||
));
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,11 @@ class Service extends BaseModel
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function ($service) {
|
||||
if (blank($service->name)) {
|
||||
$service->name = 'service-'.(new Cuid2);
|
||||
}
|
||||
});
|
||||
static::created(function ($service) {
|
||||
$service->compose_parsing_version = self::$parserVersion;
|
||||
$service->save();
|
||||
|
||||
49
app/Models/SslCertificate.php
Normal file
49
app/Models/SslCertificate.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class SslCertificate extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'ssl_certificate',
|
||||
'ssl_private_key',
|
||||
'configuration_dir',
|
||||
'mount_path',
|
||||
'resource_type',
|
||||
'resource_id',
|
||||
'server_id',
|
||||
'common_name',
|
||||
'subject_alternative_names',
|
||||
'valid_until',
|
||||
'is_ca_certificate',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'ssl_certificate' => 'encrypted',
|
||||
'ssl_private_key' => 'encrypted',
|
||||
'subject_alternative_names' => 'array',
|
||||
'valid_until' => 'datetime',
|
||||
];
|
||||
|
||||
public function application()
|
||||
{
|
||||
return $this->morphTo('resource');
|
||||
}
|
||||
|
||||
public function service()
|
||||
{
|
||||
return $this->morphTo('resource');
|
||||
}
|
||||
|
||||
public function database()
|
||||
{
|
||||
return $this->morphTo('resource');
|
||||
}
|
||||
|
||||
public function server()
|
||||
{
|
||||
return $this->belongsTo(Server::class);
|
||||
}
|
||||
}
|
||||
@@ -163,6 +163,11 @@ class StandaloneClickhouse extends BaseModel
|
||||
return data_get($this, 'environment.project');
|
||||
}
|
||||
|
||||
public function sslCertificates()
|
||||
{
|
||||
return $this->morphMany(SslCertificate::class, 'resource');
|
||||
}
|
||||
|
||||
public function link()
|
||||
{
|
||||
if (data_get($this, 'environment.project.uuid')) {
|
||||
@@ -218,7 +223,12 @@ class StandaloneClickhouse extends BaseModel
|
||||
protected function internalDbUrl(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: fn () => "clickhouse://{$this->clickhouse_admin_user}:{$this->clickhouse_admin_password}@{$this->uuid}:9000/{$this->clickhouse_db}",
|
||||
get: function () {
|
||||
$encodedUser = rawurlencode($this->clickhouse_admin_user);
|
||||
$encodedPass = rawurlencode($this->clickhouse_admin_password);
|
||||
|
||||
return "clickhouse://{$encodedUser}:{$encodedPass}@{$this->uuid}:9000/{$this->clickhouse_db}";
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -227,7 +237,10 @@ class StandaloneClickhouse extends BaseModel
|
||||
return new Attribute(
|
||||
get: function () {
|
||||
if ($this->is_public && $this->public_port) {
|
||||
return "clickhouse://{$this->clickhouse_admin_user}:{$this->clickhouse_admin_password}@{$this->destination->server->getIp}:{$this->public_port}/{$this->clickhouse_db}";
|
||||
$encodedUser = rawurlencode($this->clickhouse_admin_user);
|
||||
$encodedPass = rawurlencode($this->clickhouse_admin_password);
|
||||
|
||||
return "clickhouse://{$encodedUser}:{$encodedPass}@{$this->destination->server->getIp}:{$this->public_port}/{$this->clickhouse_db}";
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -168,6 +168,11 @@ class StandaloneDragonfly extends BaseModel
|
||||
return data_get($this, 'environment.project.team');
|
||||
}
|
||||
|
||||
public function sslCertificates()
|
||||
{
|
||||
return $this->morphMany(SslCertificate::class, 'resource');
|
||||
}
|
||||
|
||||
public function link()
|
||||
{
|
||||
if (data_get($this, 'environment.project.uuid')) {
|
||||
@@ -218,7 +223,18 @@ class StandaloneDragonfly extends BaseModel
|
||||
protected function internalDbUrl(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: fn () => "redis://:{$this->dragonfly_password}@{$this->uuid}:6379/0",
|
||||
get: function () {
|
||||
$scheme = $this->enable_ssl ? 'rediss' : 'redis';
|
||||
$port = $this->enable_ssl ? 6380 : 6379;
|
||||
$encodedPass = rawurlencode($this->dragonfly_password);
|
||||
$url = "{$scheme}://:{$encodedPass}@{$this->uuid}:{$port}/0";
|
||||
|
||||
if ($this->enable_ssl && $this->ssl_mode === 'verify-ca') {
|
||||
$url .= '?cacert=/etc/ssl/certs/coolify-ca.crt';
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -227,7 +243,15 @@ class StandaloneDragonfly extends BaseModel
|
||||
return new Attribute(
|
||||
get: function () {
|
||||
if ($this->is_public && $this->public_port) {
|
||||
return "redis://:{$this->dragonfly_password}@{$this->destination->server->getIp}:{$this->public_port}/0";
|
||||
$scheme = $this->enable_ssl ? 'rediss' : 'redis';
|
||||
$encodedPass = rawurlencode($this->dragonfly_password);
|
||||
$url = "{$scheme}://:{$encodedPass}@{$this->destination->server->getIp}:{$this->public_port}/0";
|
||||
|
||||
if ($this->enable_ssl && $this->ssl_mode === 'verify-ca') {
|
||||
$url .= '?cacert=/etc/ssl/certs/coolify-ca.crt';
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -168,6 +168,11 @@ class StandaloneKeydb extends BaseModel
|
||||
return data_get($this, 'environment.project.team');
|
||||
}
|
||||
|
||||
public function sslCertificates()
|
||||
{
|
||||
return $this->morphMany(SslCertificate::class, 'resource');
|
||||
}
|
||||
|
||||
public function link()
|
||||
{
|
||||
if (data_get($this, 'environment.project.uuid')) {
|
||||
@@ -218,7 +223,18 @@ class StandaloneKeydb extends BaseModel
|
||||
protected function internalDbUrl(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: fn () => "redis://:{$this->keydb_password}@{$this->uuid}:6379/0",
|
||||
get: function () {
|
||||
$scheme = $this->enable_ssl ? 'rediss' : 'redis';
|
||||
$port = $this->enable_ssl ? 6380 : 6379;
|
||||
$encodedPass = rawurlencode($this->keydb_password);
|
||||
$url = "{$scheme}://:{$encodedPass}@{$this->uuid}:{$port}/0";
|
||||
|
||||
if ($this->enable_ssl && $this->ssl_mode === 'verify-ca') {
|
||||
$url .= '?cacert=/etc/ssl/certs/coolify-ca.crt';
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -227,7 +243,15 @@ class StandaloneKeydb extends BaseModel
|
||||
return new Attribute(
|
||||
get: function () {
|
||||
if ($this->is_public && $this->public_port) {
|
||||
return "redis://:{$this->keydb_password}@{$this->destination->server->getIp}:{$this->public_port}/0";
|
||||
$scheme = $this->enable_ssl ? 'rediss' : 'redis';
|
||||
$encodedPass = rawurlencode($this->keydb_password);
|
||||
$url = "{$scheme}://:{$encodedPass}@{$this->destination->server->getIp}:{$this->public_port}/0";
|
||||
|
||||
if ($this->enable_ssl && $this->ssl_mode === 'verify-ca') {
|
||||
$url .= '?cacert=/etc/ssl/certs/coolify-ca.crt';
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -218,7 +218,12 @@ class StandaloneMariadb extends BaseModel
|
||||
protected function internalDbUrl(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: fn () => "mysql://{$this->mariadb_user}:{$this->mariadb_password}@{$this->uuid}:3306/{$this->mariadb_database}",
|
||||
get: function () {
|
||||
$encodedUser = rawurlencode($this->mariadb_user);
|
||||
$encodedPass = rawurlencode($this->mariadb_password);
|
||||
|
||||
return "mysql://{$encodedUser}:{$encodedPass}@{$this->uuid}:3306/{$this->mariadb_database}";
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -227,7 +232,10 @@ class StandaloneMariadb extends BaseModel
|
||||
return new Attribute(
|
||||
get: function () {
|
||||
if ($this->is_public && $this->public_port) {
|
||||
return "mysql://{$this->mariadb_user}:{$this->mariadb_password}@{$this->destination->server->getIp}:{$this->public_port}/{$this->mariadb_database}";
|
||||
$encodedUser = rawurlencode($this->mariadb_user);
|
||||
$encodedPass = rawurlencode($this->mariadb_password);
|
||||
|
||||
return "mysql://{$encodedUser}:{$encodedPass}@{$this->destination->server->getIp}:{$this->public_port}/{$this->mariadb_database}";
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -271,6 +279,11 @@ class StandaloneMariadb extends BaseModel
|
||||
return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
|
||||
}
|
||||
|
||||
public function sslCertificates()
|
||||
{
|
||||
return $this->morphMany(SslCertificate::class, 'resource');
|
||||
}
|
||||
|
||||
public function getCpuMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
|
||||
@@ -177,6 +177,11 @@ class StandaloneMongodb extends BaseModel
|
||||
return data_get($this, 'is_log_drain_enabled', false);
|
||||
}
|
||||
|
||||
public function sslCertificates()
|
||||
{
|
||||
return $this->morphMany(SslCertificate::class, 'resource');
|
||||
}
|
||||
|
||||
public function link()
|
||||
{
|
||||
if (data_get($this, 'environment.project.uuid')) {
|
||||
@@ -238,7 +243,19 @@ class StandaloneMongodb extends BaseModel
|
||||
protected function internalDbUrl(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: fn () => "mongodb://{$this->mongo_initdb_root_username}:{$this->mongo_initdb_root_password}@{$this->uuid}:27017/?directConnection=true",
|
||||
get: function () {
|
||||
$encodedUser = rawurlencode($this->mongo_initdb_root_username);
|
||||
$encodedPass = rawurlencode($this->mongo_initdb_root_password);
|
||||
$url = "mongodb://{$encodedUser}:{$encodedPass}@{$this->uuid}:27017/?directConnection=true";
|
||||
if ($this->enable_ssl) {
|
||||
$url .= '&tls=true&tlsCAFile=/etc/mongo/certs/ca.pem';
|
||||
if (in_array($this->ssl_mode, ['verify-full'])) {
|
||||
$url .= '&tlsCertificateKeyFile=/etc/mongo/certs/server.pem';
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -247,7 +264,17 @@ class StandaloneMongodb extends BaseModel
|
||||
return new Attribute(
|
||||
get: function () {
|
||||
if ($this->is_public && $this->public_port) {
|
||||
return "mongodb://{$this->mongo_initdb_root_username}:{$this->mongo_initdb_root_password}@{$this->destination->server->getIp}:{$this->public_port}/?directConnection=true";
|
||||
$encodedUser = rawurlencode($this->mongo_initdb_root_username);
|
||||
$encodedPass = rawurlencode($this->mongo_initdb_root_password);
|
||||
$url = "mongodb://{$encodedUser}:{$encodedPass}@{$this->destination->server->getIp}:{$this->public_port}/?directConnection=true";
|
||||
if ($this->enable_ssl) {
|
||||
$url .= '&tls=true&tlsCAFile=/etc/mongo/certs/ca.pem';
|
||||
if (in_array($this->ssl_mode, ['verify-full'])) {
|
||||
$url .= '&tlsCertificateKeyFile=/etc/mongo/certs/server.pem';
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -169,6 +169,11 @@ class StandaloneMysql extends BaseModel
|
||||
return data_get($this, 'environment.project.team');
|
||||
}
|
||||
|
||||
public function sslCertificates()
|
||||
{
|
||||
return $this->morphMany(SslCertificate::class, 'resource');
|
||||
}
|
||||
|
||||
public function link()
|
||||
{
|
||||
if (data_get($this, 'environment.project.uuid')) {
|
||||
@@ -219,7 +224,19 @@ class StandaloneMysql extends BaseModel
|
||||
protected function internalDbUrl(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: fn () => "mysql://{$this->mysql_user}:{$this->mysql_password}@{$this->uuid}:3306/{$this->mysql_database}",
|
||||
get: function () {
|
||||
$encodedUser = rawurlencode($this->mysql_user);
|
||||
$encodedPass = rawurlencode($this->mysql_password);
|
||||
$url = "mysql://{$encodedUser}:{$encodedPass}@{$this->uuid}:3306/{$this->mysql_database}";
|
||||
if ($this->enable_ssl) {
|
||||
$url .= "?ssl-mode={$this->ssl_mode}";
|
||||
if (in_array($this->ssl_mode, ['VERIFY_CA', 'VERIFY_IDENTITY'])) {
|
||||
$url .= '&ssl-ca=/etc/ssl/certs/coolify-ca.crt';
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -228,7 +245,17 @@ class StandaloneMysql extends BaseModel
|
||||
return new Attribute(
|
||||
get: function () {
|
||||
if ($this->is_public && $this->public_port) {
|
||||
return "mysql://{$this->mysql_user}:{$this->mysql_password}@{$this->destination->server->getIp}:{$this->public_port}/{$this->mysql_database}";
|
||||
$encodedUser = rawurlencode($this->mysql_user);
|
||||
$encodedPass = rawurlencode($this->mysql_password);
|
||||
$url = "mysql://{$encodedUser}:{$encodedPass}@{$this->destination->server->getIp}:{$this->public_port}/{$this->mysql_database}";
|
||||
if ($this->enable_ssl) {
|
||||
$url .= "?ssl-mode={$this->ssl_mode}";
|
||||
if (in_array($this->ssl_mode, ['VERIFY_CA', 'VERIFY_IDENTITY'])) {
|
||||
$url .= '&ssl-ca=/etc/ssl/certs/coolify-ca.crt';
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -219,7 +219,19 @@ class StandalonePostgresql extends BaseModel
|
||||
protected function internalDbUrl(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: fn () => "postgres://{$this->postgres_user}:{$this->postgres_password}@{$this->uuid}:5432/{$this->postgres_db}",
|
||||
get: function () {
|
||||
$encodedUser = rawurlencode($this->postgres_user);
|
||||
$encodedPass = rawurlencode($this->postgres_password);
|
||||
$url = "postgres://{$encodedUser}:{$encodedPass}@{$this->uuid}:5432/{$this->postgres_db}";
|
||||
if ($this->enable_ssl) {
|
||||
$url .= "?sslmode={$this->ssl_mode}";
|
||||
if (in_array($this->ssl_mode, ['verify-ca', 'verify-full'])) {
|
||||
$url .= '&sslrootcert=/etc/ssl/certs/coolify-ca.crt';
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -228,7 +240,17 @@ class StandalonePostgresql extends BaseModel
|
||||
return new Attribute(
|
||||
get: function () {
|
||||
if ($this->is_public && $this->public_port) {
|
||||
return "postgres://{$this->postgres_user}:{$this->postgres_password}@{$this->destination->server->getIp}:{$this->public_port}/{$this->postgres_db}";
|
||||
$encodedUser = rawurlencode($this->postgres_user);
|
||||
$encodedPass = rawurlencode($this->postgres_password);
|
||||
$url = "postgres://{$encodedUser}:{$encodedPass}@{$this->destination->server->getIp}:{$this->public_port}/{$this->postgres_db}";
|
||||
if ($this->enable_ssl) {
|
||||
$url .= "?sslmode={$this->ssl_mode}";
|
||||
if (in_array($this->ssl_mode, ['verify-ca', 'verify-full'])) {
|
||||
$url .= '&sslrootcert=/etc/ssl/certs/coolify-ca.crt';
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -241,11 +263,21 @@ class StandalonePostgresql extends BaseModel
|
||||
return $this->belongsTo(Environment::class);
|
||||
}
|
||||
|
||||
public function persistentStorages()
|
||||
{
|
||||
return $this->morphMany(LocalPersistentVolume::class, 'resource');
|
||||
}
|
||||
|
||||
public function fileStorages()
|
||||
{
|
||||
return $this->morphMany(LocalFileVolume::class, 'resource');
|
||||
}
|
||||
|
||||
public function sslCertificates()
|
||||
{
|
||||
return $this->morphMany(SslCertificate::class, 'resource');
|
||||
}
|
||||
|
||||
public function destination()
|
||||
{
|
||||
return $this->morphTo();
|
||||
@@ -256,16 +288,17 @@ class StandalonePostgresql extends BaseModel
|
||||
return $this->morphMany(EnvironmentVariable::class, 'resourceable');
|
||||
}
|
||||
|
||||
public function persistentStorages()
|
||||
{
|
||||
return $this->morphMany(LocalPersistentVolume::class, 'resource');
|
||||
}
|
||||
|
||||
public function scheduledBackups()
|
||||
{
|
||||
return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
|
||||
}
|
||||
|
||||
public function environment_variables()
|
||||
{
|
||||
return $this->morphMany(EnvironmentVariable::class, 'resourceable')
|
||||
->orderBy('key', 'asc');
|
||||
}
|
||||
|
||||
public function isBackupSolutionAvailable()
|
||||
{
|
||||
return true;
|
||||
@@ -314,10 +347,4 @@ class StandalonePostgresql extends BaseModel
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function environment_variables()
|
||||
{
|
||||
return $this->morphMany(EnvironmentVariable::class, 'resourceable')
|
||||
->orderBy('key', 'asc');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,6 +170,11 @@ class StandaloneRedis extends BaseModel
|
||||
return data_get($this, 'environment.project.team');
|
||||
}
|
||||
|
||||
public function sslCertificates()
|
||||
{
|
||||
return $this->morphMany(SslCertificate::class, 'resource');
|
||||
}
|
||||
|
||||
public function link()
|
||||
{
|
||||
if (data_get($this, 'environment.project.uuid')) {
|
||||
@@ -222,9 +227,17 @@ class StandaloneRedis extends BaseModel
|
||||
return new Attribute(
|
||||
get: function () {
|
||||
$redis_version = $this->getRedisVersion();
|
||||
$username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : '';
|
||||
$username_part = version_compare($redis_version, '6.0', '>=') ? rawurlencode($this->redis_username).':' : '';
|
||||
$encodedPass = rawurlencode($this->redis_password);
|
||||
$scheme = $this->enable_ssl ? 'rediss' : 'redis';
|
||||
$port = $this->enable_ssl ? 6380 : 6379;
|
||||
$url = "{$scheme}://{$username_part}{$encodedPass}@{$this->uuid}:{$port}/0";
|
||||
|
||||
return "redis://{$username_part}{$this->redis_password}@{$this->uuid}:6379/0";
|
||||
if ($this->enable_ssl && $this->ssl_mode === 'verify-ca') {
|
||||
$url .= '?cacert=/etc/ssl/certs/coolify-ca.crt';
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -235,9 +248,16 @@ class StandaloneRedis extends BaseModel
|
||||
get: function () {
|
||||
if ($this->is_public && $this->public_port) {
|
||||
$redis_version = $this->getRedisVersion();
|
||||
$username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : '';
|
||||
$username_part = version_compare($redis_version, '6.0', '>=') ? rawurlencode($this->redis_username).':' : '';
|
||||
$encodedPass = rawurlencode($this->redis_password);
|
||||
$scheme = $this->enable_ssl ? 'rediss' : 'redis';
|
||||
$url = "{$scheme}://{$username_part}{$encodedPass}@{$this->destination->server->getIp}:{$this->public_port}/0";
|
||||
|
||||
return "redis://{$username_part}{$this->redis_password}@{$this->destination->server->getIp}:{$this->public_port}/0";
|
||||
if ($this->enable_ssl && $this->ssl_mode === 'verify-ca') {
|
||||
$url .= '?cacert=/etc/ssl/certs/coolify-ca.crt';
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -163,14 +163,17 @@ class Team extends Model implements SendsDiscord, SendsEmail, SendsPushover, Sen
|
||||
];
|
||||
}
|
||||
|
||||
public function getRecipients($notification)
|
||||
public function getRecipients(): array
|
||||
{
|
||||
$recipients = data_get($notification, 'emails', null);
|
||||
if (is_null($recipients)) {
|
||||
return $this->members()->pluck('email')->toArray();
|
||||
$recipients = $this->members()->pluck('email')->toArray();
|
||||
$validatedEmails = array_filter($recipients, function ($email) {
|
||||
return filter_var($email, FILTER_VALIDATE_EMAIL);
|
||||
});
|
||||
if (is_null($validatedEmails)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return explode(',', $recipients);
|
||||
return array_values($validatedEmails);
|
||||
}
|
||||
|
||||
public function isAnyNotificationEnabled()
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Models;
|
||||
|
||||
use App\Notifications\Channels\SendsEmail;
|
||||
use App\Notifications\TransactionalEmails\ResetPassword as TransactionalEmailsResetPassword;
|
||||
use App\Traits\DeletesUserSessions;
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
@@ -37,7 +38,7 @@ use OpenApi\Attributes as OA;
|
||||
)]
|
||||
class User extends Authenticatable implements SendsEmail
|
||||
{
|
||||
use HasApiTokens, HasFactory, Notifiable, TwoFactorAuthenticatable;
|
||||
use DeletesUserSessions, HasApiTokens, HasFactory, Notifiable, TwoFactorAuthenticatable;
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
@@ -57,6 +58,7 @@ class User extends Authenticatable implements SendsEmail
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::created(function (User $user) {
|
||||
$team = [
|
||||
'name' => $user->name."'s Team",
|
||||
@@ -114,9 +116,9 @@ class User extends Authenticatable implements SendsEmail
|
||||
return $this->belongsToMany(Team::class)->withPivot('role');
|
||||
}
|
||||
|
||||
public function getRecipients($notification)
|
||||
public function getRecipients(): array
|
||||
{
|
||||
return $this->email;
|
||||
return [$this->email];
|
||||
}
|
||||
|
||||
public function sendVerificationEmail()
|
||||
|
||||
Reference in New Issue
Block a user