diff --git a/app/Http/Livewire/Notifications/TelegramSettings.php b/app/Http/Livewire/Notifications/TelegramSettings.php
index be7081012..d6c6c8395 100644
--- a/app/Http/Livewire/Notifications/TelegramSettings.php
+++ b/app/Http/Livewire/Notifications/TelegramSettings.php
@@ -17,6 +17,10 @@ class TelegramSettings extends Component
'team.telegram_notifications_deployments' => 'nullable|boolean',
'team.telegram_notifications_status_changes' => 'nullable|boolean',
'team.telegram_notifications_database_backups' => 'nullable|boolean',
+ 'team.telegram_notifications_test_message_thread_id' => 'nullable|string',
+ 'team.telegram_notifications_deployments_message_thread_id' => 'nullable|string',
+ 'team.telegram_notifications_status_changes_message_thread_id' => 'nullable|string',
+ 'team.telegram_notifications_database_backups_message_thread_id' => 'nullable|string',
];
protected $validationAttributes = [
'team.telegram_token' => 'Token',
diff --git a/app/Http/Livewire/Project/Shared/EnvironmentVariable/All.php b/app/Http/Livewire/Project/Shared/EnvironmentVariable/All.php
index 70bfd42a1..899060085 100644
--- a/app/Http/Livewire/Project/Shared/EnvironmentVariable/All.php
+++ b/app/Http/Livewire/Project/Shared/EnvironmentVariable/All.php
@@ -5,21 +5,84 @@ namespace App\Http\Livewire\Project\Shared\EnvironmentVariable;
use App\Models\EnvironmentVariable;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
+use Str;
class All extends Component
{
public $resource;
+ public bool $showPreview = false;
public string|null $modalId = null;
+ public ?string $variables = null;
+ public ?string $variablesPreview = null;
+ public string $view = 'normal';
protected $listeners = ['refreshEnvs', 'submit'];
public function mount()
{
+ $resourceClass = get_class($this->resource);
+ $resourceWithPreviews = ['App\Models\Application'];
+ $simpleDockerfile = !is_null(data_get($this->resource, 'dockerfile'));
+ if (Str::of($resourceClass)->contains($resourceWithPreviews) && !$simpleDockerfile) {
+ $this->showPreview = true;
+ }
$this->modalId = new Cuid2(7);
+ $this->getDevView();
+ }
+ public function getDevView()
+ {
+ $this->variables = $this->resource->environment_variables->map(function ($item) {
+ return "$item->key=$item->value";
+ })->sort()->join('
+');
+ if ($this->showPreview) {
+ $this->variablesPreview = $this->resource->environment_variables_preview->map(function ($item) {
+ return "$item->key=$item->value";
+ })->sort()->join('
+');
+ }
+ }
+ public function switch()
+ {
+ $this->view = $this->view === 'normal' ? 'dev' : 'normal';
+ }
+ public function saveVariables($isPreview)
+ {
+ if ($isPreview) {
+ $variables = parseEnvFormatToArray($this->variablesPreview);
+ $existingVariables = $this->resource->environment_variables_preview();
+ $this->resource->environment_variables_preview()->delete();
+ } else {
+ $variables = parseEnvFormatToArray($this->variables);
+ $existingVariables = $this->resource->environment_variables();
+ $this->resource->environment_variables()->delete();
+ }
+ foreach ($variables as $key => $variable) {
+ $found = $existingVariables->where('key', $key)->first();
+ if ($found) {
+ $found->value = $variable;
+ $found->save();
+ continue;
+ } else {
+ $environment = new EnvironmentVariable();
+ $environment->key = $key;
+ $environment->value = $variable;
+ $environment->is_build_time = false;
+ $environment->is_preview = $isPreview ? true : false;
+ if ($this->resource->type() === 'application') {
+ $environment->application_id = $this->resource->id;
+ }
+ if ($this->resource->type() === 'standalone-postgresql') {
+ $environment->standalone_postgresql_id = $this->resource->id;
+ }
+ $environment->save();
+ }
+ }
+ $this->refreshEnvs();
}
-
public function refreshEnvs()
{
$this->resource->refresh();
+ $this->getDevView();
}
public function submit($data)
@@ -43,7 +106,7 @@ class All extends Component
$environment->standalone_postgresql_id = $this->resource->id;
}
$environment->save();
- $this->resource->refresh();
+ $this->refreshEnvs();
$this->emit('success', 'Environment variable added successfully.');
} catch (\Exception $e) {
return general_error_handler(err: $e, that: $this);
diff --git a/app/Http/Middleware/IsBoardingFlow.php b/app/Http/Middleware/IsBoardingFlow.php
index e0542a57a..5858fe191 100644
--- a/app/Http/Middleware/IsBoardingFlow.php
+++ b/app/Http/Middleware/IsBoardingFlow.php
@@ -15,7 +15,7 @@ class IsBoardingFlow
*/
public function handle(Request $request, Closure $next): Response
{
- ray()->showQueries()->color('orange');
+ // ray()->showQueries()->color('orange');
if (showBoarding() && !in_array($request->path(), allowedPathsForBoardingAccounts())) {
return redirect('boarding');
}
diff --git a/app/Jobs/DatabaseBackupJob.php b/app/Jobs/DatabaseBackupJob.php
index 98972f7af..aaef43883 100644
--- a/app/Jobs/DatabaseBackupJob.php
+++ b/app/Jobs/DatabaseBackupJob.php
@@ -46,6 +46,10 @@ class DatabaseBackupJob implements ShouldQueue
$this->backup = $backup;
$this->team = Team::find($backup->team_id);
$this->database = $this->backup->database;
+ if (!$this->database) {
+ ray('Database not found');
+ return;
+ }
$this->database_type = $this->database->type();
$this->server = $this->database->destination->server;
$this->database_status = $this->database->status;
diff --git a/app/Jobs/SendMessageToTelegramJob.php b/app/Jobs/SendMessageToTelegramJob.php
index 08afbab23..1fa1347c4 100644
--- a/app/Jobs/SendMessageToTelegramJob.php
+++ b/app/Jobs/SendMessageToTelegramJob.php
@@ -31,6 +31,7 @@ class SendMessageToTelegramJob implements ShouldQueue
public array $buttons,
public string $token,
public string $chatId,
+ public ?string $topicId = null,
) {
}
@@ -63,7 +64,9 @@ class SendMessageToTelegramJob implements ShouldQueue
'chat_id' => $this->chatId,
'text' => $this->text,
];
- ray($payload);
+ if ($this->topicId) {
+ $payload['message_thread_id'] = $this->topicId;
+ }
$response = Http::post($url, $payload);
if ($response->failed()) {
throw new \Exception('Telegram notification failed with ' . $response->status() . ' status code.' . $response->body());
diff --git a/app/Models/Application.php b/app/Models/Application.php
index 6b730edee..72d2be60f 100644
--- a/app/Models/Application.php
+++ b/app/Models/Application.php
@@ -105,7 +105,7 @@ class Application extends BaseModel
public function environment_variables(): HasMany
{
- return $this->hasMany(EnvironmentVariable::class)->where('is_preview', false);
+ return $this->hasMany(EnvironmentVariable::class)->where('is_preview', false)->orderBy('key', 'asc');
}
public function runtime_environment_variables(): HasMany
@@ -127,7 +127,7 @@ class Application extends BaseModel
public function environment_variables_preview(): HasMany
{
- return $this->hasMany(EnvironmentVariable::class)->where('is_preview', true);
+ return $this->hasMany(EnvironmentVariable::class)->where('is_preview', true)->orderBy('key', 'asc');
}
public function runtime_environment_variables_preview(): HasMany
diff --git a/app/Models/EnvironmentVariable.php b/app/Models/EnvironmentVariable.php
index 62a08c87f..3f348c42e 100644
--- a/app/Models/EnvironmentVariable.php
+++ b/app/Models/EnvironmentVariable.php
@@ -20,13 +20,16 @@ class EnvironmentVariable extends Model
{
static::created(function ($environment_variable) {
if ($environment_variable->application_id && !$environment_variable->is_preview) {
- ModelsEnvironmentVariable::create([
- 'key' => $environment_variable->key,
- 'value' => $environment_variable->value,
- 'is_build_time' => $environment_variable->is_build_time,
- 'application_id' => $environment_variable->application_id,
- 'is_preview' => true,
- ]);
+ $found = ModelsEnvironmentVariable::where('key', $environment_variable->key)->where('application_id', $environment_variable->application_id)->where('is_preview',true)->first();
+ if (!$found) {
+ ModelsEnvironmentVariable::create([
+ 'key' => $environment_variable->key,
+ 'value' => $environment_variable->value,
+ 'is_build_time' => $environment_variable->is_build_time,
+ 'application_id' => $environment_variable->application_id,
+ 'is_preview' => true,
+ ]);
+ }
}
});
}
diff --git a/app/Models/StandaloneDocker.php b/app/Models/StandaloneDocker.php
index 6ecc46a97..6f2ea7673 100644
--- a/app/Models/StandaloneDocker.php
+++ b/app/Models/StandaloneDocker.php
@@ -23,6 +23,6 @@ class StandaloneDocker extends BaseModel
public function attachedTo()
{
- return $this->applications->count() > 0 || $this->databases->count() > 0;
+ return $this->applications?->count() > 0 || $this->databases?->count() > 0;
}
}
diff --git a/app/Models/Team.php b/app/Models/Team.php
index 2d7ef3c9e..485811a17 100644
--- a/app/Models/Team.php
+++ b/app/Models/Team.php
@@ -28,7 +28,7 @@ class Team extends Model implements SendsDiscord, SendsEmail
{
return [
"token" => data_get($this, 'telegram_token', null),
- "chat_id" => data_get($this, 'telegram_chat_id', null)
+ "chat_id" => data_get($this, 'telegram_chat_id', null),
];
}
diff --git a/app/Notifications/Channels/TelegramChannel.php b/app/Notifications/Channels/TelegramChannel.php
index 938ef5d25..1401bb324 100644
--- a/app/Notifications/Channels/TelegramChannel.php
+++ b/app/Notifications/Channels/TelegramChannel.php
@@ -10,16 +10,30 @@ class TelegramChannel
{
$data = $notification->toTelegram($notifiable);
$telegramData = $notifiable->routeNotificationForTelegram();
-
$message = data_get($data, 'message');
$buttons = data_get($data, 'buttons', []);
- ray($message, $buttons);
$telegramToken = data_get($telegramData, 'token');
$chatId = data_get($telegramData, 'chat_id');
+ $topicId = null;
+ $topicsInstance = get_class($notification);
- if (!$telegramToken || !$chatId || !$message) {
- throw new \Exception('Telegram token, chat id and message are required');
+ switch ($topicsInstance) {
+ case 'App\Notifications\StatusChange':
+ $topicId = data_get($notifiable, 'telegram_notifications_status_changes_message_thread_id');
+ break;
+ case 'App\Notifications\Test':
+ $topicId = data_get($notifiable, 'telegram_notifications_test_message_thread_id');
+ break;
+ case 'App\Notifications\Deployment':
+ $topicId = data_get($notifiable, 'telegram_notifications_deployments_message_thread_id');
+ break;
+ case 'App\Notifications\DatabaseBackup':
+ $topicId = data_get($notifiable, 'telegram_notifications_database_backups_message_thread_id');
+ break;
}
- dispatch(new SendMessageToTelegramJob($message, $buttons, $telegramToken, $chatId));
+ if (!$telegramToken || !$chatId || !$message) {
+ return;
+ }
+ dispatch(new SendMessageToTelegramJob($message, $buttons, $telegramToken, $chatId, $topicId));
}
}
diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php
index 15f8fc0db..161675301 100644
--- a/bootstrap/helpers/shared.php
+++ b/bootstrap/helpers/shared.php
@@ -296,3 +296,25 @@ function setNotificationChannels($notifiable, $event)
}
return $channels;
}
+function parseEnvFormatToArray($env_file_contents) {
+ $env_array = array();
+ $lines = explode("\n", $env_file_contents);
+ foreach ($lines as $line) {
+ if ($line === '' || substr($line, 0, 1) === '#') {
+ continue;
+ }
+ $equals_pos = strpos($line, '=');
+ if ($equals_pos !== false) {
+ $key = substr($line, 0, $equals_pos);
+ $value = substr($line, $equals_pos + 1);
+ if (substr($value, 0, 1) === '"' && substr($value, -1) === '"') {
+ $value = substr($value, 1, -1);
+ }
+ elseif (substr($value, 0, 1) === "'" && substr($value, -1) === "'") {
+ $value = substr($value, 1, -1);
+ }
+ $env_array[$key] = $value;
+ }
+ }
+ return $env_array;
+}
diff --git a/config/sentry.php b/config/sentry.php
index 1cf53df07..d8316f2a6 100644
--- a/config/sentry.php
+++ b/config/sentry.php
@@ -7,7 +7,7 @@ return [
// The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
- 'release' => '4.0.0-beta.27',
+ 'release' => '4.0.0-beta.28',
'server_name' => env('APP_ID', 'coolify'),
// When left empty or `null` the Laravel environment will be used
'environment' => config('app.env'),
diff --git a/config/version.php b/config/version.php
index 0f148cc4e..6ded6b968 100644
--- a/config/version.php
+++ b/config/version.php
@@ -1,3 +1,3 @@
text('telegram_notifications_test_message_thread_id')->nullable();
+ $table->text('telegram_notifications_deployments_message_thread_id')->nullable();
+ $table->text('telegram_notifications_status_changes_message_thread_id')->nullable();
+ $table->text('telegram_notifications_database_backups_message_thread_id')->nullable();
+ });
+ }
+
+ public function down(): void
+ {
+ Schema::table('teams', function (Blueprint $table) {
+ $table->dropColumn('telegram_message_thread_id');
+ $table->dropColumn('telegram_notifications_test_message_thread_id');
+ $table->dropColumn('telegram_notifications_deployments_message_thread_id');
+ $table->dropColumn('telegram_notifications_status_changes_message_thread_id');
+ $table->dropColumn('telegram_notifications_database_backups_message_thread_id');
+ });
+ }
+};
diff --git a/resources/views/livewire/notifications/telegram-settings.blade.php b/resources/views/livewire/notifications/telegram-settings.blade.php
index 654ca106d..12b62af4d 100644
--- a/resources/views/livewire/notifications/telegram-settings.blade.php
+++ b/resources/views/livewire/notifications/telegram-settings.blade.php
@@ -16,27 +16,50 @@