mirror of
https://github.com/coollabsio/coolify.git
synced 2026-03-11 08:55:47 +00:00
Merge branch 'next' into improve-cron-validation
This commit is contained in:
commit
b3bc47bc3d
117 changed files with 2160 additions and 1097 deletions
10
README.md
10
README.md
|
|
@ -40,7 +40,8 @@ Special thanks to our biggest sponsors!
|
|||
|
||||
### Special Sponsors
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
* [CCCareers](https://cccareers.org/) - A career development platform connecting coding bootcamp graduates with job opportunities in the tech industry.
|
||||
* [Hetzner](http://htznr.li/CoolifyXHetzner) - A German web hosting company offering affordable dedicated servers, cloud services, and web hosting solutions.
|
||||
|
|
@ -52,7 +53,9 @@ Special thanks to our biggest sponsors!
|
|||
* [SupaGuide](https://supa.guide/?ref=coolify.io) - A comprehensive resource hub offering guides and tutorials for web development using Supabase.
|
||||
* [GoldenVM](https://billing.goldenvm.com/?ref=coolify.io) - A cloud hosting provider offering scalable infrastructure solutions for businesses of all sizes.
|
||||
* [Tigris](https://tigrisdata.com/?ref=coolify.io) - A fully managed serverless object storage service compatible with Amazon S3 API. Offers high performance, scalability, and built-in search capabilities for efficient data management.
|
||||
* [Advin](https://coolify.ad.vin/?ref=coolify.io) - A digital advertising agency specializing in programmatic advertising and data-driven marketing strategies.
|
||||
* [Cloudify.ro](https://cloudify.ro/?ref=coolify.io) - A cloud hosting provider offering scalable infrastructure solutions for businesses of all sizes.
|
||||
* [Syntaxfm](https://syntax.fm/?ref=coolify.io) - Podcast for web developers.
|
||||
* [PFGlabs](https://pfglabs.com/?ref=coolify.io) - Build real project with Golang.
|
||||
* [Treive](https://trieve.ai/?ref=coolify.io) - An AI-powered search and discovery platform for enhancing information retrieval in large datasets.
|
||||
* [Blacksmith](https://blacksmith.sh/?ref=coolify.io) - A cloud-native platform for automating infrastructure provisioning and management across multiple cloud providers.
|
||||
* [Brand Dev](https://brand.dev/?ref=coolify.io) - A web development agency specializing in creating custom digital experiences and brand identities.
|
||||
|
|
@ -92,6 +95,9 @@ Special thanks to our biggest sponsors!
|
|||
<a href="https://github.com/monocursive"><img src="https://github.com/monocursive.png" width="60px" alt="Michael Mazurczak" /></a>
|
||||
<a href="https://formbricks.com/?utm_source=coolify.io"><img src="https://github.com/formbricks.png" width="60px" alt="Formbricks" /></a>
|
||||
<a href="https://startupfa.me?utm_source=coolify.io"><img src="https://github.com/startupfame.png" width="60px" alt="StartupFame" /></a>
|
||||
<a href="https://bsky.app/profile/jyc.dev"><img src="https://github.com/jycouet.png" width="60px" alt="jyc.dev" /></a>
|
||||
<a href="https://bitlaunch.io/?utm_source=coolify.io"><img src="https://github.com/bitlaunchio.png" width="60px" alt="BitLaunch" /></a>
|
||||
<a href="https://internetgarden.co/?utm_source=coolify.io"><img src="./other/logos/internetgarden.ico" width="60px" alt="Internet Garden" /></a>
|
||||
<a href="https://jonasjaeger.com?utm_source=coolify.io"><img src="https://github.com/toxin20.png" width="60px" alt="Jonas Jaeger" /></a>
|
||||
<a href="https://github.com/therealjp?utm_source=coolify.io"><img src="https://github.com/therealjp.png" width="60px" alt="JP" /></a>
|
||||
<a href="https://evercam.io/?utm_source=coolify.io"><img src="https://github.com/evercam.png" width="60px" alt="Evercam" /></a>
|
||||
|
|
|
|||
24
app/Console/Commands/Migration.php
Normal file
24
app/Console/Commands/Migration.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class Migration extends Command
|
||||
{
|
||||
protected $signature = 'start:migration';
|
||||
|
||||
protected $description = 'Start Migration';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
if (config('constants.migration.is_migration_enabled')) {
|
||||
$this->info('Migration is enabled on this server.');
|
||||
$this->call('migrate', ['--force' => true, '--isolated' => true]);
|
||||
exit(0);
|
||||
} else {
|
||||
$this->info('Migration is disabled on this server.');
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -59,9 +59,10 @@ class NotifyDemo extends Command
|
|||
<div class="text-yellow-500"> Channels: </div>
|
||||
<ul class="text-coolify">
|
||||
<li>email</li>
|
||||
<li>slack</li>
|
||||
<li>discord</li>
|
||||
<li>telegram</li>
|
||||
<li>slack</li>
|
||||
<li>pushover</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -72,6 +73,6 @@ class NotifyDemo extends Command
|
|||
<div class="mr-1">
|
||||
In which manner you wish a <strong class="text-coolify">coolified</strong> notification?
|
||||
</div>
|
||||
HTML, ['email', 'slack', 'discord', 'telegram']);
|
||||
HTML, ['email', 'discord', 'telegram', 'slack', 'pushover']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
24
app/Console/Commands/Seeder.php
Normal file
24
app/Console/Commands/Seeder.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class Seeder extends Command
|
||||
{
|
||||
protected $signature = 'start:seeder';
|
||||
|
||||
protected $description = 'Start Seeder';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
if (config('constants.seeder.is_seeder_enabled')) {
|
||||
$this->info('Seeder is enabled on this server.');
|
||||
$this->call('db:seed', ['--class' => 'ProductionSeeder', '--force' => true]);
|
||||
exit(0);
|
||||
} else {
|
||||
$this->info('Seeder is disabled on this server.');
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -218,7 +218,7 @@ class Kernel extends ConsoleKernel
|
|||
}
|
||||
}
|
||||
if ($service) {
|
||||
if (str($service->status())->contains('running') === false) {
|
||||
if (str($service->status)->contains('running') === false) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,11 +53,7 @@ class ResourcesController extends Controller
|
|||
$resources = $resources->flatten();
|
||||
$resources = $resources->map(function ($resource) {
|
||||
$payload = $resource->toArray();
|
||||
if ($resource->getMorphClass() === \App\Models\Service::class) {
|
||||
$payload['status'] = $resource->status();
|
||||
} else {
|
||||
$payload['status'] = $resource->status;
|
||||
}
|
||||
$payload['status'] = $resource->status;
|
||||
$payload['type'] = $resource->type();
|
||||
|
||||
return $payload;
|
||||
|
|
|
|||
|
|
@ -154,11 +154,7 @@ class ServersController extends Controller
|
|||
'created_at' => $resource->created_at,
|
||||
'updated_at' => $resource->updated_at,
|
||||
];
|
||||
if ($resource->type() === 'service') {
|
||||
$payload['status'] = $resource->status();
|
||||
} else {
|
||||
$payload['status'] = $resource->status;
|
||||
}
|
||||
$payload['status'] = $resource->status;
|
||||
|
||||
return $payload;
|
||||
});
|
||||
|
|
@ -237,11 +233,7 @@ class ServersController extends Controller
|
|||
'created_at' => $resource->created_at,
|
||||
'updated_at' => $resource->updated_at,
|
||||
];
|
||||
if ($resource->type() === 'service') {
|
||||
$payload['status'] = $resource->status();
|
||||
} else {
|
||||
$payload['status'] = $resource->status;
|
||||
}
|
||||
$payload['status'] = $resource->status;
|
||||
|
||||
return $payload;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ class ServicesController extends Controller
|
|||
$service->makeHidden([
|
||||
'docker_compose_raw',
|
||||
'docker_compose',
|
||||
'value',
|
||||
'real_value',
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -1070,7 +1072,7 @@ class ServicesController extends Controller
|
|||
if (! $service) {
|
||||
return response()->json(['message' => 'Service not found.'], 404);
|
||||
}
|
||||
if (str($service->status())->contains('running')) {
|
||||
if (str($service->status)->contains('running')) {
|
||||
return response()->json(['message' => 'Service is already running.'], 400);
|
||||
}
|
||||
StartService::dispatch($service);
|
||||
|
|
@ -1148,7 +1150,7 @@ class ServicesController extends Controller
|
|||
if (! $service) {
|
||||
return response()->json(['message' => 'Service not found.'], 404);
|
||||
}
|
||||
if (str($service->status())->contains('stopped') || str($service->status())->contains('exited')) {
|
||||
if (str($service->status)->contains('stopped') || str($service->status)->contains('exited')) {
|
||||
return response()->json(['message' => 'Service is already stopped.'], 400);
|
||||
}
|
||||
StopService::dispatch($service);
|
||||
|
|
|
|||
|
|
@ -32,8 +32,6 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
|||
|
||||
public Server $server;
|
||||
|
||||
public ScheduledDatabaseBackup $backup;
|
||||
|
||||
public StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|ServiceDatabase $database;
|
||||
|
||||
public ?string $container_name = null;
|
||||
|
|
@ -58,10 +56,9 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
|||
|
||||
public ?S3Storage $s3 = null;
|
||||
|
||||
public function __construct($backup)
|
||||
public function __construct(public ScheduledDatabaseBackup $backup)
|
||||
{
|
||||
$this->onQueue('high');
|
||||
$this->backup = $backup;
|
||||
}
|
||||
|
||||
public function handle(): void
|
||||
|
|
|
|||
50
app/Jobs/SendMessageToPushoverJob.php
Normal file
50
app/Jobs/SendMessageToPushoverJob.php
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class SendMessageToPushoverJob implements ShouldBeEncrypted, ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
/**
|
||||
* The number of times the job may be attempted.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $tries = 5;
|
||||
|
||||
public $backoff = 10;
|
||||
|
||||
/**
|
||||
* The maximum number of unhandled exceptions to allow before failing.
|
||||
*/
|
||||
public int $maxExceptions = 5;
|
||||
|
||||
public function __construct(
|
||||
public PushoverMessage $message,
|
||||
public string $token,
|
||||
public string $user,
|
||||
) {
|
||||
$this->onQueue('high');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$response = Http::post('https://api.pushover.net/1/messages.json', $this->message->toPayload($this->token, $this->user));
|
||||
if ($response->failed()) {
|
||||
throw new \RuntimeException('Pushover notification failed with ' . $response->status() . ' status code.' . $response->body());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ class SendMessageToTelegramJob implements ShouldBeEncrypted, ShouldQueue
|
|||
public array $buttons,
|
||||
public string $token,
|
||||
public string $chatId,
|
||||
public ?string $topicId = null,
|
||||
public ?string $threadId = null,
|
||||
) {
|
||||
$this->onQueue('high');
|
||||
}
|
||||
|
|
@ -67,8 +67,8 @@ class SendMessageToTelegramJob implements ShouldBeEncrypted, ShouldQueue
|
|||
'chat_id' => $this->chatId,
|
||||
'text' => $this->text,
|
||||
];
|
||||
if ($this->topicId) {
|
||||
$payload['message_thread_id'] = $this->topicId;
|
||||
if ($this->threadId) {
|
||||
$payload['message_thread_id'] = $this->threadId;
|
||||
}
|
||||
$response = Http::post($url, $payload);
|
||||
if ($response->failed()) {
|
||||
|
|
|
|||
|
|
@ -173,8 +173,8 @@ class StripeProcessJob implements ShouldQueue
|
|||
$userId = data_get($data, 'metadata.user_id');
|
||||
$customerId = data_get($data, 'customer');
|
||||
$status = data_get($data, 'status');
|
||||
$subscriptionId = data_get($data, 'items.data.0.subscription');
|
||||
$planId = data_get($data, 'items.data.0.plan.id');
|
||||
$subscriptionId = data_get($data, 'items.data.0.subscription') ?? data_get($data, 'id');
|
||||
$planId = data_get($data, 'items.data.0.plan.id') ?? data_get($data, 'plan.id');
|
||||
if (Str::contains($excludedPlans, $planId)) {
|
||||
send_internal_notification('Subscription excluded.');
|
||||
break;
|
||||
|
|
@ -218,9 +218,18 @@ class StripeProcessJob implements ShouldQueue
|
|||
'stripe_cancel_at_period_end' => $cancelAtPeriodEnd,
|
||||
]);
|
||||
if ($status === 'paused' || $status === 'incomplete_expired') {
|
||||
$subscription->update([
|
||||
'stripe_invoice_paid' => false,
|
||||
]);
|
||||
if ($subscription->stripe_subscription_id === $subscriptionId) {
|
||||
$subscription->update([
|
||||
'stripe_invoice_paid' => false,
|
||||
]);
|
||||
}
|
||||
}
|
||||
if ($status === 'active') {
|
||||
if ($subscription->stripe_subscription_id === $subscriptionId) {
|
||||
$subscription->update([
|
||||
'stripe_invoice_paid' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
if ($feedback) {
|
||||
$reason = "Cancellation feedback for {$customerId}: '".$feedback."'";
|
||||
|
|
@ -228,13 +237,24 @@ class StripeProcessJob implements ShouldQueue
|
|||
$reason .= ' with comment: \''.$comment."'";
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 'customer.subscription.deleted':
|
||||
// End subscription
|
||||
$customerId = data_get($data, 'customer');
|
||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
||||
$team = data_get($subscription, 'team');
|
||||
$team?->subscriptionEnded();
|
||||
$subscriptionId = data_get($data, 'id');
|
||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->where('stripe_subscription_id', $subscriptionId)->first();
|
||||
if ($subscription) {
|
||||
$team = data_get($subscription, 'team');
|
||||
if ($team) {
|
||||
$team->subscriptionEnded();
|
||||
} else {
|
||||
send_internal_notification('Subscription deleted but no team found in Coolify for customer: '.$customerId);
|
||||
throw new \RuntimeException("No team found in Coolify for customer: {$customerId}");
|
||||
}
|
||||
} else {
|
||||
send_internal_notification('Subscription deleted but no subscription found in Coolify for customer: '.$customerId);
|
||||
throw new \RuntimeException("No subscription found in Coolify for customer: {$customerId}");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new \RuntimeException("Unhandled event type: {$type}");
|
||||
|
|
|
|||
|
|
@ -21,16 +21,28 @@ class Index extends Component
|
|||
|
||||
public function mount()
|
||||
{
|
||||
if (! isCloud()) {
|
||||
if (! isCloud() && ! isDev()) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
|
||||
if (Auth::id() !== 0) {
|
||||
if (Auth::id() !== 0 && ! session('impersonating')) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
$this->getSubscribers();
|
||||
}
|
||||
|
||||
public function back()
|
||||
{
|
||||
if (session('impersonating')) {
|
||||
session()->forget('impersonating');
|
||||
$user = User::find(0);
|
||||
$team_to_switch_to = $user->teams->first();
|
||||
Auth::login($user);
|
||||
refreshSession($team_to_switch_to);
|
||||
|
||||
return redirect(request()->header('Referer'));
|
||||
}
|
||||
}
|
||||
|
||||
public function submitSearch()
|
||||
{
|
||||
if ($this->search !== '') {
|
||||
|
|
@ -52,9 +64,10 @@ class Index extends Component
|
|||
if (Auth::id() !== 0) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
session(['impersonating' => true]);
|
||||
$user = User::find($user_id);
|
||||
$team_to_switch_to = $user->teams->first();
|
||||
Cache::forget("team:{$user->id}");
|
||||
// Cache::forget("team:{$user->id}");
|
||||
Auth::login($user);
|
||||
refreshSession($team_to_switch_to);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,10 @@ class Email extends Component
|
|||
{
|
||||
protected $listeners = ['refresh' => '$refresh'];
|
||||
|
||||
#[Locked]
|
||||
public Team $team;
|
||||
|
||||
#[Locked]
|
||||
public EmailNotificationSettings $settings;
|
||||
|
||||
#[Locked]
|
||||
|
|
|
|||
184
app/Livewire/Notifications/Pushover.php
Normal file
184
app/Livewire/Notifications/Pushover.php
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
|
||||
namespace App\Livewire\Notifications;
|
||||
|
||||
use App\Models\PushoverNotificationSettings;
|
||||
use App\Models\Team;
|
||||
use App\Notifications\Test;
|
||||
use Livewire\Attributes\Locked;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
|
||||
class Pushover extends Component
|
||||
{
|
||||
protected $listeners = ['refresh' => '$refresh'];
|
||||
|
||||
#[Locked]
|
||||
public Team $team;
|
||||
|
||||
#[Locked]
|
||||
public PushoverNotificationSettings $settings;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $pushoverEnabled = false;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $pushoverUserKey = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $pushoverApiToken = null;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $deploymentSuccessPushoverNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $deploymentFailurePushoverNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $statusChangePushoverNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $backupSuccessPushoverNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $backupFailurePushoverNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $scheduledTaskSuccessPushoverNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $scheduledTaskFailurePushoverNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $dockerCleanupSuccessPushoverNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $dockerCleanupFailurePushoverNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $serverDiskUsagePushoverNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $serverReachablePushoverNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $serverUnreachablePushoverNotifications = true;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
try {
|
||||
$this->team = auth()->user()->currentTeam();
|
||||
$this->settings = $this->team->pushoverNotificationSettings;
|
||||
$this->syncData();
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function syncData(bool $toModel = false)
|
||||
{
|
||||
if ($toModel) {
|
||||
$this->validate();
|
||||
$this->settings->pushover_enabled = $this->pushoverEnabled;
|
||||
$this->settings->pushover_user_key = $this->pushoverUserKey;
|
||||
$this->settings->pushover_api_token = $this->pushoverApiToken;
|
||||
|
||||
$this->settings->deployment_success_pushover_notifications = $this->deploymentSuccessPushoverNotifications;
|
||||
$this->settings->deployment_failure_pushover_notifications = $this->deploymentFailurePushoverNotifications;
|
||||
$this->settings->status_change_pushover_notifications = $this->statusChangePushoverNotifications;
|
||||
$this->settings->backup_success_pushover_notifications = $this->backupSuccessPushoverNotifications;
|
||||
$this->settings->backup_failure_pushover_notifications = $this->backupFailurePushoverNotifications;
|
||||
$this->settings->scheduled_task_success_pushover_notifications = $this->scheduledTaskSuccessPushoverNotifications;
|
||||
$this->settings->scheduled_task_failure_pushover_notifications = $this->scheduledTaskFailurePushoverNotifications;
|
||||
$this->settings->docker_cleanup_success_pushover_notifications = $this->dockerCleanupSuccessPushoverNotifications;
|
||||
$this->settings->docker_cleanup_failure_pushover_notifications = $this->dockerCleanupFailurePushoverNotifications;
|
||||
$this->settings->server_disk_usage_pushover_notifications = $this->serverDiskUsagePushoverNotifications;
|
||||
$this->settings->server_reachable_pushover_notifications = $this->serverReachablePushoverNotifications;
|
||||
$this->settings->server_unreachable_pushover_notifications = $this->serverUnreachablePushoverNotifications;
|
||||
|
||||
$this->settings->save();
|
||||
refreshSession();
|
||||
} else {
|
||||
$this->pushoverEnabled = $this->settings->pushover_enabled;
|
||||
$this->pushoverUserKey = $this->settings->pushover_user_key;
|
||||
$this->pushoverApiToken = $this->settings->pushover_api_token;
|
||||
|
||||
$this->deploymentSuccessPushoverNotifications = $this->settings->deployment_success_pushover_notifications;
|
||||
$this->deploymentFailurePushoverNotifications = $this->settings->deployment_failure_pushover_notifications;
|
||||
$this->statusChangePushoverNotifications = $this->settings->status_change_pushover_notifications;
|
||||
$this->backupSuccessPushoverNotifications = $this->settings->backup_success_pushover_notifications;
|
||||
$this->backupFailurePushoverNotifications = $this->settings->backup_failure_pushover_notifications;
|
||||
$this->scheduledTaskSuccessPushoverNotifications = $this->settings->scheduled_task_success_pushover_notifications;
|
||||
$this->scheduledTaskFailurePushoverNotifications = $this->settings->scheduled_task_failure_pushover_notifications;
|
||||
$this->dockerCleanupSuccessPushoverNotifications = $this->settings->docker_cleanup_success_pushover_notifications;
|
||||
$this->dockerCleanupFailurePushoverNotifications = $this->settings->docker_cleanup_failure_pushover_notifications;
|
||||
$this->serverDiskUsagePushoverNotifications = $this->settings->server_disk_usage_pushover_notifications;
|
||||
$this->serverReachablePushoverNotifications = $this->settings->server_reachable_pushover_notifications;
|
||||
$this->serverUnreachablePushoverNotifications = $this->settings->server_unreachable_pushover_notifications;
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSavePushoverEnabled()
|
||||
{
|
||||
try {
|
||||
$this->validate([
|
||||
'pushoverUserKey' => 'required',
|
||||
'pushoverApiToken' => 'required',
|
||||
], [
|
||||
'pushoverUserKey.required' => 'Pushover User Key is required.',
|
||||
'pushoverApiToken.required' => 'Pushover API Token is required.',
|
||||
]);
|
||||
$this->saveModel();
|
||||
} catch (\Throwable $e) {
|
||||
$this->pushoverEnabled = false;
|
||||
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
$this->dispatch('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
{
|
||||
try {
|
||||
$this->syncData(true);
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
$this->dispatch('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
$this->resetErrorBag();
|
||||
$this->syncData(true);
|
||||
$this->saveModel();
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function saveModel()
|
||||
{
|
||||
$this->syncData(true);
|
||||
refreshSession();
|
||||
$this->dispatch('success', 'Settings saved.');
|
||||
}
|
||||
|
||||
public function sendTestNotification()
|
||||
{
|
||||
try {
|
||||
$this->team->notify(new Test(channel: 'pushover'));
|
||||
$this->dispatch('success', 'Test notification sent.');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.notifications.pushover');
|
||||
}
|
||||
}
|
||||
|
|
@ -5,13 +5,18 @@ namespace App\Livewire\Notifications;
|
|||
use App\Models\SlackNotificationSettings;
|
||||
use App\Models\Team;
|
||||
use App\Notifications\Test;
|
||||
use Livewire\Attributes\Locked;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
|
||||
class Slack extends Component
|
||||
{
|
||||
protected $listeners = ['refresh' => '$refresh'];
|
||||
|
||||
#[Locked]
|
||||
public Team $team;
|
||||
|
||||
#[Locked]
|
||||
public SlackNotificationSettings $settings;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
|
|
@ -121,6 +126,8 @@ class Slack extends Component
|
|||
$this->slackEnabled = false;
|
||||
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
$this->dispatch('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -130,6 +137,8 @@ class Slack extends Component
|
|||
$this->syncData(true);
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
$this->dispatch('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,18 @@ namespace App\Livewire\Notifications;
|
|||
use App\Models\Team;
|
||||
use App\Models\TelegramNotificationSettings;
|
||||
use App\Notifications\Test;
|
||||
use Livewire\Attributes\Locked;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
|
||||
class Telegram extends Component
|
||||
{
|
||||
protected $listeners = ['refresh' => '$refresh'];
|
||||
|
||||
#[Locked]
|
||||
public Team $team;
|
||||
|
||||
#[Locked]
|
||||
public TelegramNotificationSettings $settings;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
|
|
@ -60,40 +65,40 @@ class Telegram extends Component
|
|||
public bool $serverUnreachableTelegramNotifications = true;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsDeploymentSuccessTopicId = null;
|
||||
public ?string $telegramNotificationsDeploymentSuccessThreadId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsDeploymentFailureTopicId = null;
|
||||
public ?string $telegramNotificationsDeploymentFailureThreadId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsStatusChangeTopicId = null;
|
||||
public ?string $telegramNotificationsStatusChangeThreadId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsBackupSuccessTopicId = null;
|
||||
public ?string $telegramNotificationsBackupSuccessThreadId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsBackupFailureTopicId = null;
|
||||
public ?string $telegramNotificationsBackupFailureThreadId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsScheduledTaskSuccessTopicId = null;
|
||||
public ?string $telegramNotificationsScheduledTaskSuccessThreadId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsScheduledTaskFailureTopicId = null;
|
||||
public ?string $telegramNotificationsScheduledTaskFailureThreadId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsDockerCleanupSuccessTopicId = null;
|
||||
public ?string $telegramNotificationsDockerCleanupSuccessThreadId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsDockerCleanupFailureTopicId = null;
|
||||
public ?string $telegramNotificationsDockerCleanupFailureThreadId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsServerDiskUsageTopicId = null;
|
||||
public ?string $telegramNotificationsServerDiskUsageThreadId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsServerReachableTopicId = null;
|
||||
public ?string $telegramNotificationsServerReachableThreadId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsServerUnreachableTopicId = null;
|
||||
public ?string $telegramNotificationsServerUnreachableThreadId = null;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
|
|
@ -127,21 +132,20 @@ class Telegram extends Component
|
|||
$this->settings->server_reachable_telegram_notifications = $this->serverReachableTelegramNotifications;
|
||||
$this->settings->server_unreachable_telegram_notifications = $this->serverUnreachableTelegramNotifications;
|
||||
|
||||
$this->settings->telegram_notifications_deployment_success_topic_id = $this->telegramNotificationsDeploymentSuccessTopicId;
|
||||
$this->settings->telegram_notifications_deployment_failure_topic_id = $this->telegramNotificationsDeploymentFailureTopicId;
|
||||
$this->settings->telegram_notifications_status_change_topic_id = $this->telegramNotificationsStatusChangeTopicId;
|
||||
$this->settings->telegram_notifications_backup_success_topic_id = $this->telegramNotificationsBackupSuccessTopicId;
|
||||
$this->settings->telegram_notifications_backup_failure_topic_id = $this->telegramNotificationsBackupFailureTopicId;
|
||||
$this->settings->telegram_notifications_scheduled_task_success_topic_id = $this->telegramNotificationsScheduledTaskSuccessTopicId;
|
||||
$this->settings->telegram_notifications_scheduled_task_failure_topic_id = $this->telegramNotificationsScheduledTaskFailureTopicId;
|
||||
$this->settings->telegram_notifications_docker_cleanup_success_topic_id = $this->telegramNotificationsDockerCleanupSuccessTopicId;
|
||||
$this->settings->telegram_notifications_docker_cleanup_failure_topic_id = $this->telegramNotificationsDockerCleanupFailureTopicId;
|
||||
$this->settings->telegram_notifications_server_disk_usage_topic_id = $this->telegramNotificationsServerDiskUsageTopicId;
|
||||
$this->settings->telegram_notifications_server_reachable_topic_id = $this->telegramNotificationsServerReachableTopicId;
|
||||
$this->settings->telegram_notifications_server_unreachable_topic_id = $this->telegramNotificationsServerUnreachableTopicId;
|
||||
$this->settings->telegram_notifications_deployment_success_thread_id = $this->telegramNotificationsDeploymentSuccessThreadId;
|
||||
$this->settings->telegram_notifications_deployment_failure_thread_id = $this->telegramNotificationsDeploymentFailureThreadId;
|
||||
$this->settings->telegram_notifications_status_change_thread_id = $this->telegramNotificationsStatusChangeThreadId;
|
||||
$this->settings->telegram_notifications_backup_success_thread_id = $this->telegramNotificationsBackupSuccessThreadId;
|
||||
$this->settings->telegram_notifications_backup_failure_thread_id = $this->telegramNotificationsBackupFailureThreadId;
|
||||
$this->settings->telegram_notifications_scheduled_task_success_thread_id = $this->telegramNotificationsScheduledTaskSuccessThreadId;
|
||||
$this->settings->telegram_notifications_scheduled_task_failure_thread_id = $this->telegramNotificationsScheduledTaskFailureThreadId;
|
||||
$this->settings->telegram_notifications_docker_cleanup_success_thread_id = $this->telegramNotificationsDockerCleanupSuccessThreadId;
|
||||
$this->settings->telegram_notifications_docker_cleanup_failure_thread_id = $this->telegramNotificationsDockerCleanupFailureThreadId;
|
||||
$this->settings->telegram_notifications_server_disk_usage_thread_id = $this->telegramNotificationsServerDiskUsageThreadId;
|
||||
$this->settings->telegram_notifications_server_reachable_thread_id = $this->telegramNotificationsServerReachableThreadId;
|
||||
$this->settings->telegram_notifications_server_unreachable_thread_id = $this->telegramNotificationsServerUnreachableThreadId;
|
||||
|
||||
$this->settings->save();
|
||||
refreshSession();
|
||||
} else {
|
||||
$this->telegramEnabled = $this->settings->telegram_enabled;
|
||||
$this->telegramToken = $this->settings->telegram_token;
|
||||
|
|
@ -160,18 +164,18 @@ class Telegram extends Component
|
|||
$this->serverReachableTelegramNotifications = $this->settings->server_reachable_telegram_notifications;
|
||||
$this->serverUnreachableTelegramNotifications = $this->settings->server_unreachable_telegram_notifications;
|
||||
|
||||
$this->telegramNotificationsDeploymentSuccessTopicId = $this->settings->telegram_notifications_deployment_success_topic_id;
|
||||
$this->telegramNotificationsDeploymentFailureTopicId = $this->settings->telegram_notifications_deployment_failure_topic_id;
|
||||
$this->telegramNotificationsStatusChangeTopicId = $this->settings->telegram_notifications_status_change_topic_id;
|
||||
$this->telegramNotificationsBackupSuccessTopicId = $this->settings->telegram_notifications_backup_success_topic_id;
|
||||
$this->telegramNotificationsBackupFailureTopicId = $this->settings->telegram_notifications_backup_failure_topic_id;
|
||||
$this->telegramNotificationsScheduledTaskSuccessTopicId = $this->settings->telegram_notifications_scheduled_task_success_topic_id;
|
||||
$this->telegramNotificationsScheduledTaskFailureTopicId = $this->settings->telegram_notifications_scheduled_task_failure_topic_id;
|
||||
$this->telegramNotificationsDockerCleanupSuccessTopicId = $this->settings->telegram_notifications_docker_cleanup_success_topic_id;
|
||||
$this->telegramNotificationsDockerCleanupFailureTopicId = $this->settings->telegram_notifications_docker_cleanup_failure_topic_id;
|
||||
$this->telegramNotificationsServerDiskUsageTopicId = $this->settings->telegram_notifications_server_disk_usage_topic_id;
|
||||
$this->telegramNotificationsServerReachableTopicId = $this->settings->telegram_notifications_server_reachable_topic_id;
|
||||
$this->telegramNotificationsServerUnreachableTopicId = $this->settings->telegram_notifications_server_unreachable_topic_id;
|
||||
$this->telegramNotificationsDeploymentSuccessThreadId = $this->settings->telegram_notifications_deployment_success_thread_id;
|
||||
$this->telegramNotificationsDeploymentFailureThreadId = $this->settings->telegram_notifications_deployment_failure_thread_id;
|
||||
$this->telegramNotificationsStatusChangeThreadId = $this->settings->telegram_notifications_status_change_thread_id;
|
||||
$this->telegramNotificationsBackupSuccessThreadId = $this->settings->telegram_notifications_backup_success_thread_id;
|
||||
$this->telegramNotificationsBackupFailureThreadId = $this->settings->telegram_notifications_backup_failure_thread_id;
|
||||
$this->telegramNotificationsScheduledTaskSuccessThreadId = $this->settings->telegram_notifications_scheduled_task_success_thread_id;
|
||||
$this->telegramNotificationsScheduledTaskFailureThreadId = $this->settings->telegram_notifications_scheduled_task_failure_thread_id;
|
||||
$this->telegramNotificationsDockerCleanupSuccessThreadId = $this->settings->telegram_notifications_docker_cleanup_success_thread_id;
|
||||
$this->telegramNotificationsDockerCleanupFailureThreadId = $this->settings->telegram_notifications_docker_cleanup_failure_thread_id;
|
||||
$this->telegramNotificationsServerDiskUsageThreadId = $this->settings->telegram_notifications_server_disk_usage_thread_id;
|
||||
$this->telegramNotificationsServerReachableThreadId = $this->settings->telegram_notifications_server_reachable_thread_id;
|
||||
$this->telegramNotificationsServerUnreachableThreadId = $this->settings->telegram_notifications_server_unreachable_thread_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -181,6 +185,8 @@ class Telegram extends Component
|
|||
$this->syncData(true);
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
$this->dispatch('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -210,6 +216,8 @@ class Telegram extends Component
|
|||
$this->telegramEnabled = false;
|
||||
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
$this->dispatch('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,14 +8,21 @@ use Livewire\Component;
|
|||
|
||||
class Configuration extends Component
|
||||
{
|
||||
public $currentRoute;
|
||||
|
||||
public Application $application;
|
||||
|
||||
public $project;
|
||||
|
||||
public $environment;
|
||||
|
||||
public $servers;
|
||||
|
||||
protected $listeners = ['buildPackUpdated' => '$refresh'];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->currentRoute = request()->route()->getName();
|
||||
$project = currentTeam()
|
||||
->projects()
|
||||
->select('id', 'uuid', 'team_id')
|
||||
|
|
@ -30,6 +37,8 @@ class Configuration extends Component
|
|||
->where('uuid', request()->route('application_uuid'))
|
||||
->firstOrFail();
|
||||
|
||||
$this->project = $project;
|
||||
$this->environment = $environment;
|
||||
$this->application = $application;
|
||||
if ($application->destination && $application->destination->server) {
|
||||
$mainServer = $application->destination->server;
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ class General extends Component
|
|||
}
|
||||
}
|
||||
|
||||
public function set_redirect()
|
||||
public function setRedirect()
|
||||
{
|
||||
try {
|
||||
$has_www = collect($this->application->fqdns)->filter(fn ($fqdn) => str($fqdn)->contains('www.'))->count();
|
||||
|
|
@ -360,10 +360,10 @@ class General extends Component
|
|||
if ($warning) {
|
||||
$this->dispatch('warning', __('warning.sslipdomain'));
|
||||
}
|
||||
$this->resetDefaultLabels();
|
||||
// $this->resetDefaultLabels();
|
||||
|
||||
if ($this->application->isDirty('redirect')) {
|
||||
$this->set_redirect();
|
||||
$this->setRedirect();
|
||||
}
|
||||
|
||||
$this->checkFqdns();
|
||||
|
|
|
|||
|
|
@ -9,11 +9,9 @@ class BackupNow extends Component
|
|||
{
|
||||
public $backup;
|
||||
|
||||
public function backup_now()
|
||||
public function backupNow()
|
||||
{
|
||||
dispatch(new DatabaseBackupJob(
|
||||
backup: $this->backup
|
||||
));
|
||||
DatabaseBackupJob::dispatch($this->backup);
|
||||
$this->dispatch('success', 'Backup queued. It will be available in a few minutes.');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,125 +46,84 @@ class Index extends Component
|
|||
return redirect()->route('dashboard');
|
||||
}
|
||||
$this->project = $project;
|
||||
$this->environment = $environment;
|
||||
$this->applications = $this->environment->applications->load(['tags']);
|
||||
$this->environment = $environment->loadCount([
|
||||
'applications',
|
||||
'redis',
|
||||
'postgresqls',
|
||||
'mysqls',
|
||||
'keydbs',
|
||||
'dragonflies',
|
||||
'clickhouses',
|
||||
'mariadbs',
|
||||
'mongodbs',
|
||||
'services',
|
||||
]);
|
||||
|
||||
// Eager load all relationships for applications including nested ones
|
||||
$this->applications = $this->environment->applications()->with([
|
||||
'tags',
|
||||
'additional_servers.settings',
|
||||
'additional_networks',
|
||||
'destination.server.settings',
|
||||
'settings',
|
||||
])->get()->sortBy('name');
|
||||
$this->applications = $this->applications->map(function ($application) {
|
||||
if (data_get($application, 'environment.project.uuid')) {
|
||||
$application->hrefLink = route('project.application.configuration', [
|
||||
'project_uuid' => data_get($application, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($application, 'environment.name'),
|
||||
'application_uuid' => data_get($application, 'uuid'),
|
||||
]);
|
||||
}
|
||||
$application->hrefLink = route('project.application.configuration', [
|
||||
'project_uuid' => $this->project->uuid,
|
||||
'application_uuid' => $application->uuid,
|
||||
'environment_name' => $this->environment->name,
|
||||
]);
|
||||
|
||||
return $application;
|
||||
});
|
||||
$this->postgresqls = $this->environment->postgresqls->load(['tags'])->sortBy('name');
|
||||
$this->postgresqls = $this->postgresqls->map(function ($postgresql) {
|
||||
if (data_get($postgresql, 'environment.project.uuid')) {
|
||||
$postgresql->hrefLink = route('project.database.configuration', [
|
||||
'project_uuid' => data_get($postgresql, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($postgresql, 'environment.name'),
|
||||
'database_uuid' => data_get($postgresql, 'uuid'),
|
||||
]);
|
||||
}
|
||||
|
||||
return $postgresql;
|
||||
});
|
||||
$this->redis = $this->environment->redis->load(['tags'])->sortBy('name');
|
||||
$this->redis = $this->redis->map(function ($redis) {
|
||||
if (data_get($redis, 'environment.project.uuid')) {
|
||||
$redis->hrefLink = route('project.database.configuration', [
|
||||
'project_uuid' => data_get($redis, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($redis, 'environment.name'),
|
||||
'database_uuid' => data_get($redis, 'uuid'),
|
||||
]);
|
||||
}
|
||||
// Load all database resources in a single query per type
|
||||
$databaseTypes = [
|
||||
'postgresqls' => 'postgresqls',
|
||||
'redis' => 'redis',
|
||||
'mongodbs' => 'mongodbs',
|
||||
'mysqls' => 'mysqls',
|
||||
'mariadbs' => 'mariadbs',
|
||||
'keydbs' => 'keydbs',
|
||||
'dragonflies' => 'dragonflies',
|
||||
'clickhouses' => 'clickhouses',
|
||||
];
|
||||
|
||||
return $redis;
|
||||
});
|
||||
$this->mongodbs = $this->environment->mongodbs->load(['tags'])->sortBy('name');
|
||||
$this->mongodbs = $this->mongodbs->map(function ($mongodb) {
|
||||
if (data_get($mongodb, 'environment.project.uuid')) {
|
||||
$mongodb->hrefLink = route('project.database.configuration', [
|
||||
'project_uuid' => data_get($mongodb, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($mongodb, 'environment.name'),
|
||||
'database_uuid' => data_get($mongodb, 'uuid'),
|
||||
]);
|
||||
}
|
||||
// Load all server-related data first to prevent duplicate queries
|
||||
$serverData = $this->environment->applications()
|
||||
->with(['destination.server.settings'])
|
||||
->get()
|
||||
->pluck('destination.server')
|
||||
->filter()
|
||||
->unique('id');
|
||||
|
||||
return $mongodb;
|
||||
});
|
||||
$this->mysqls = $this->environment->mysqls->load(['tags'])->sortBy('name');
|
||||
$this->mysqls = $this->mysqls->map(function ($mysql) {
|
||||
if (data_get($mysql, 'environment.project.uuid')) {
|
||||
$mysql->hrefLink = route('project.database.configuration', [
|
||||
'project_uuid' => data_get($mysql, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($mysql, 'environment.name'),
|
||||
'database_uuid' => data_get($mysql, 'uuid'),
|
||||
foreach ($databaseTypes as $property => $relation) {
|
||||
$this->{$property} = $this->environment->{$relation}()->with([
|
||||
'tags',
|
||||
'destination.server.settings',
|
||||
])->get()->sortBy('name');
|
||||
$this->{$property} = $this->{$property}->map(function ($db) {
|
||||
$db->hrefLink = route('project.database.configuration', [
|
||||
'project_uuid' => $this->project->uuid,
|
||||
'database_uuid' => $db->uuid,
|
||||
'environment_name' => $this->environment->name,
|
||||
]);
|
||||
}
|
||||
|
||||
return $mysql;
|
||||
});
|
||||
$this->mariadbs = $this->environment->mariadbs->load(['tags'])->sortBy('name');
|
||||
$this->mariadbs = $this->mariadbs->map(function ($mariadb) {
|
||||
if (data_get($mariadb, 'environment.project.uuid')) {
|
||||
$mariadb->hrefLink = route('project.database.configuration', [
|
||||
'project_uuid' => data_get($mariadb, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($mariadb, 'environment.name'),
|
||||
'database_uuid' => data_get($mariadb, 'uuid'),
|
||||
]);
|
||||
}
|
||||
return $db;
|
||||
});
|
||||
}
|
||||
|
||||
return $mariadb;
|
||||
});
|
||||
$this->keydbs = $this->environment->keydbs->load(['tags'])->sortBy('name');
|
||||
$this->keydbs = $this->keydbs->map(function ($keydb) {
|
||||
if (data_get($keydb, 'environment.project.uuid')) {
|
||||
$keydb->hrefLink = route('project.database.configuration', [
|
||||
'project_uuid' => data_get($keydb, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($keydb, 'environment.name'),
|
||||
'database_uuid' => data_get($keydb, 'uuid'),
|
||||
]);
|
||||
}
|
||||
|
||||
return $keydb;
|
||||
});
|
||||
$this->dragonflies = $this->environment->dragonflies->load(['tags'])->sortBy('name');
|
||||
$this->dragonflies = $this->dragonflies->map(function ($dragonfly) {
|
||||
if (data_get($dragonfly, 'environment.project.uuid')) {
|
||||
$dragonfly->hrefLink = route('project.database.configuration', [
|
||||
'project_uuid' => data_get($dragonfly, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($dragonfly, 'environment.name'),
|
||||
'database_uuid' => data_get($dragonfly, 'uuid'),
|
||||
]);
|
||||
}
|
||||
|
||||
return $dragonfly;
|
||||
});
|
||||
$this->clickhouses = $this->environment->clickhouses->load(['tags'])->sortBy('name');
|
||||
$this->clickhouses = $this->clickhouses->map(function ($clickhouse) {
|
||||
if (data_get($clickhouse, 'environment.project.uuid')) {
|
||||
$clickhouse->hrefLink = route('project.database.configuration', [
|
||||
'project_uuid' => data_get($clickhouse, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($clickhouse, 'environment.name'),
|
||||
'database_uuid' => data_get($clickhouse, 'uuid'),
|
||||
]);
|
||||
}
|
||||
|
||||
return $clickhouse;
|
||||
});
|
||||
$this->services = $this->environment->services->load(['tags'])->sortBy('name');
|
||||
// Load services with their tags and server
|
||||
$this->services = $this->environment->services()->with([
|
||||
'tags',
|
||||
'destination.server.settings',
|
||||
])->get()->sortBy('name');
|
||||
$this->services = $this->services->map(function ($service) {
|
||||
if (data_get($service, 'environment.project.uuid')) {
|
||||
$service->hrefLink = route('project.service.configuration', [
|
||||
'project_uuid' => data_get($service, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($service, 'environment.name'),
|
||||
'service_uuid' => data_get($service, 'uuid'),
|
||||
]);
|
||||
$service->status = $service->status();
|
||||
}
|
||||
$service->hrefLink = route('project.service.configuration', [
|
||||
'project_uuid' => $this->project->uuid,
|
||||
'service_uuid' => $service->uuid,
|
||||
'environment_name' => $this->environment->name,
|
||||
]);
|
||||
|
||||
return $service;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class Navbar extends Component
|
|||
|
||||
public function mount()
|
||||
{
|
||||
if (str($this->service->status())->contains('running') && is_null($this->service->config_hash)) {
|
||||
if (str($this->service->status)->contains('running') && is_null($this->service->config_hash)) {
|
||||
$this->service->isConfigurationChanged(true);
|
||||
$this->dispatch('configurationChanged');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ namespace App\Livewire\Project\Shared\EnvironmentVariable;
|
|||
use App\Models\EnvironmentVariable as ModelsEnvironmentVariable;
|
||||
use App\Models\SharedEnvironmentVariable;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class Show extends Component
|
||||
{
|
||||
|
|
@ -13,8 +12,6 @@ class Show extends Component
|
|||
|
||||
public ModelsEnvironmentVariable|SharedEnvironmentVariable $env;
|
||||
|
||||
public ?string $modalId = null;
|
||||
|
||||
public bool $isDisabled = false;
|
||||
|
||||
public bool $isLocked = false;
|
||||
|
|
@ -61,7 +58,6 @@ class Show extends Component
|
|||
if ($this->env->getMorphClass() === \App\Models\SharedEnvironmentVariable::class) {
|
||||
$this->isSharedVariable = true;
|
||||
}
|
||||
$this->modalId = new Cuid2;
|
||||
$this->parameters = get_route_parameters();
|
||||
$this->checkEnvs();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,9 +42,11 @@ class ResourceOperations extends Component
|
|||
$uuid = (string) new Cuid2;
|
||||
$server = $new_destination->server;
|
||||
if ($this->resource->getMorphClass() === \App\Models\Application::class) {
|
||||
$name = 'clone-of-'.str($this->resource->name)->limit(20).'-'.$uuid;
|
||||
|
||||
$new_resource = $this->resource->replicate()->fill([
|
||||
'uuid' => $uuid,
|
||||
'name' => $this->resource->name.'-clone-'.$uuid,
|
||||
'name' => $name,
|
||||
'fqdn' => generateFqdn($server, $uuid),
|
||||
'status' => 'exited',
|
||||
'destination_id' => $new_destination->id,
|
||||
|
|
@ -64,8 +66,12 @@ class ResourceOperations extends Component
|
|||
}
|
||||
$persistentVolumes = $this->resource->persistentStorages()->get();
|
||||
foreach ($persistentVolumes as $volume) {
|
||||
$volumeName = str($volume->name)->replace($this->resource->uuid, $new_resource->uuid)->value();
|
||||
if ($volumeName === $volume->name) {
|
||||
$volumeName = $new_resource->uuid.'-'.str($volume->name)->afterLast('-');
|
||||
}
|
||||
$newPersistentVolume = $volume->replicate()->fill([
|
||||
'name' => $new_resource->uuid.'-'.str($volume->name)->afterLast('-'),
|
||||
'name' => $volumeName,
|
||||
'resource_id' => $new_resource->id,
|
||||
]);
|
||||
$newPersistentVolume->save();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ class SettingsOauth extends Component
|
|||
$carry["oauth_settings_map.$setting->provider.client_secret"] = 'nullable';
|
||||
$carry["oauth_settings_map.$setting->provider.redirect_uri"] = 'nullable';
|
||||
$carry["oauth_settings_map.$setting->provider.tenant"] = 'nullable';
|
||||
$carry["oauth_settings_map.$setting->provider.base_url"] = 'nullable';
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
|
|
@ -34,16 +35,30 @@ class SettingsOauth extends Component
|
|||
}, []);
|
||||
}
|
||||
|
||||
private function updateOauthSettings()
|
||||
private function updateOauthSettings(?string $provider = null)
|
||||
{
|
||||
foreach (array_values($this->oauth_settings_map) as &$setting) {
|
||||
$setting->save();
|
||||
if ($provider) {
|
||||
$oauth = $this->oauth_settings_map[$provider];
|
||||
if (! $oauth->couldBeEnabled()) {
|
||||
$oauth->update(['enabled' => false]);
|
||||
throw new \Exception('OAuth settings are not complete for '.$oauth->provider.'.<br/>Please fill in all required fields.');
|
||||
}
|
||||
$oauth->save();
|
||||
$this->dispatch('success', 'OAuth settings for '.$oauth->provider.' updated successfully!');
|
||||
} else {
|
||||
foreach (array_values($this->oauth_settings_map) as &$setting) {
|
||||
$setting->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
public function instantSave(string $provider)
|
||||
{
|
||||
$this->updateOauthSettings();
|
||||
try {
|
||||
$this->updateOauthSettings($provider);
|
||||
} catch (\Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function submit()
|
||||
|
|
|
|||
|
|
@ -115,6 +115,12 @@ class Application extends BaseModel
|
|||
|
||||
protected static function booted()
|
||||
{
|
||||
static::addGlobalScope('withRelations', function ($builder) {
|
||||
$builder->withCount([
|
||||
'additional_servers',
|
||||
'additional_networks',
|
||||
]);
|
||||
});
|
||||
static::saving(function ($application) {
|
||||
$payload = [];
|
||||
if ($application->isDirty('fqdn')) {
|
||||
|
|
@ -551,20 +557,21 @@ class Application extends BaseModel
|
|||
{
|
||||
return Attribute::make(
|
||||
get: function () {
|
||||
if ($this->additional_servers->count() === 0) {
|
||||
return $this->destination->server->isFunctional();
|
||||
} else {
|
||||
$additional_servers_status = $this->additional_servers->pluck('pivot.status');
|
||||
$main_server_status = $this->destination->server->isFunctional();
|
||||
foreach ($additional_servers_status as $status) {
|
||||
$server_status = str($status)->before(':')->value();
|
||||
if ($server_status !== 'running') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $main_server_status;
|
||||
if (! $this->relationLoaded('additional_servers') || $this->additional_servers->count() === 0) {
|
||||
return $this->destination?->server?->isFunctional() ?? false;
|
||||
}
|
||||
|
||||
$additional_servers_status = $this->additional_servers->pluck('pivot.status');
|
||||
$main_server_status = $this->destination?->server?->isFunctional() ?? false;
|
||||
|
||||
foreach ($additional_servers_status as $status) {
|
||||
$server_status = str($status)->before(':')->value();
|
||||
if ($server_status !== 'running') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $main_server_status;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -1331,7 +1338,9 @@ class Application extends BaseModel
|
|||
$currentPath = '';
|
||||
foreach ($parts as $part) {
|
||||
$currentPath .= ($currentPath ? '/' : '').$part;
|
||||
$paths->push($currentPath);
|
||||
if (str($currentPath)->isNotEmpty()) {
|
||||
$paths->push($currentPath);
|
||||
}
|
||||
}
|
||||
|
||||
return $paths;
|
||||
|
|
@ -1341,7 +1350,7 @@ class Application extends BaseModel
|
|||
"mkdir -p /tmp/{$uuid}",
|
||||
"cd /tmp/{$uuid}",
|
||||
$cloneCommand,
|
||||
'git sparse-checkout init --cone',
|
||||
'git sparse-checkout init',
|
||||
"git sparse-checkout set {$fileList->implode(' ')}",
|
||||
'git read-tree -mu HEAD',
|
||||
"cat .$workdir$composeFile",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ class OauthSetting extends Model
|
|||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = ['provider', 'client_id', 'client_secret', 'redirect_uri', 'tenant', 'base_url', 'enabled'];
|
||||
|
||||
protected function clientSecret(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
|
|
@ -18,4 +20,16 @@ class OauthSetting extends Model
|
|||
set: fn (?string $value) => empty($value) ? null : Crypt::encryptString($value),
|
||||
);
|
||||
}
|
||||
|
||||
public function couldBeEnabled(): bool
|
||||
{
|
||||
switch ($this->provider) {
|
||||
case 'azure':
|
||||
return filled($this->client_id) && filled($this->client_secret) && filled($this->redirect_uri) && filled($this->tenant);
|
||||
case 'authentik':
|
||||
return filled($this->client_id) && filled($this->client_secret) && filled($this->redirect_uri) && filled($this->base_url);
|
||||
default:
|
||||
return filled($this->client_id) && filled($this->client_secret) && filled($this->redirect_uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
61
app/Models/PushoverNotificationSettings.php
Normal file
61
app/Models/PushoverNotificationSettings.php
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class PushoverNotificationSettings extends Model
|
||||
{
|
||||
use Notifiable;
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = [
|
||||
'team_id',
|
||||
|
||||
'pushover_enabled',
|
||||
'pushover_user_key',
|
||||
'pushover_api_token',
|
||||
|
||||
'deployment_success_pushover_notifications',
|
||||
'deployment_failure_pushover_notifications',
|
||||
'status_change_pushover_notifications',
|
||||
'backup_success_pushover_notifications',
|
||||
'backup_failure_pushover_notifications',
|
||||
'scheduled_task_success_pushover_notifications',
|
||||
'scheduled_task_failure_pushover_notifications',
|
||||
'docker_cleanup_pushover_notifications',
|
||||
'server_disk_usage_pushover_notifications',
|
||||
'server_reachable_pushover_notifications',
|
||||
'server_unreachable_pushover_notifications',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'pushover_enabled' => 'boolean',
|
||||
'pushover_user_key' => 'encrypted',
|
||||
'pushover_api_token' => 'encrypted',
|
||||
|
||||
'deployment_success_pushover_notifications' => 'boolean',
|
||||
'deployment_failure_pushover_notifications' => 'boolean',
|
||||
'status_change_pushover_notifications' => 'boolean',
|
||||
'backup_success_pushover_notifications' => 'boolean',
|
||||
'backup_failure_pushover_notifications' => 'boolean',
|
||||
'scheduled_task_success_pushover_notifications' => 'boolean',
|
||||
'scheduled_task_failure_pushover_notifications' => 'boolean',
|
||||
'docker_cleanup_pushover_notifications' => 'boolean',
|
||||
'server_disk_usage_pushover_notifications' => 'boolean',
|
||||
'server_reachable_pushover_notifications' => 'boolean',
|
||||
'server_unreachable_pushover_notifications' => 'boolean',
|
||||
];
|
||||
|
||||
public function team()
|
||||
{
|
||||
return $this->belongsTo(Team::class);
|
||||
}
|
||||
|
||||
public function isEnabled()
|
||||
{
|
||||
return $this->pushover_enabled;
|
||||
}
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ class Service extends BaseModel
|
|||
|
||||
protected $guarded = [];
|
||||
|
||||
protected $appends = ['server_status'];
|
||||
protected $appends = ['server_status', 'status'];
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
|
|
@ -105,12 +105,12 @@ class Service extends BaseModel
|
|||
|
||||
public function isRunning()
|
||||
{
|
||||
return (bool) str($this->status())->contains('running');
|
||||
return (bool) str($this->status)->contains('running');
|
||||
}
|
||||
|
||||
public function isExited()
|
||||
{
|
||||
return (bool) str($this->status())->contains('exited');
|
||||
return (bool) str($this->status)->contains('exited');
|
||||
}
|
||||
|
||||
public function type()
|
||||
|
|
@ -213,7 +213,7 @@ class Service extends BaseModel
|
|||
instant_remote_process(["docker network rm {$uuid}"], $server, false);
|
||||
}
|
||||
|
||||
public function status()
|
||||
public function getStatusAttribute()
|
||||
{
|
||||
$applications = $this->applications;
|
||||
$databases = $this->databases;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace App\Models;
|
|||
|
||||
use App\Notifications\Channels\SendsDiscord;
|
||||
use App\Notifications\Channels\SendsEmail;
|
||||
use App\Notifications\Channels\SendsPushover;
|
||||
use App\Notifications\Channels\SendsSlack;
|
||||
use App\Traits\HasNotificationSettings;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
|
@ -32,7 +33,7 @@ use OpenApi\Attributes as OA;
|
|||
]
|
||||
)]
|
||||
|
||||
class Team extends Model implements SendsDiscord, SendsEmail, SendsSlack
|
||||
class Team extends Model implements SendsDiscord, SendsEmail, SendsPushover, SendsSlack
|
||||
{
|
||||
use HasNotificationSettings, Notifiable;
|
||||
|
||||
|
|
@ -49,6 +50,7 @@ class Team extends Model implements SendsDiscord, SendsEmail, SendsSlack
|
|||
$team->discordNotificationSettings()->create();
|
||||
$team->slackNotificationSettings()->create();
|
||||
$team->telegramNotificationSettings()->create();
|
||||
$team->pushoverNotificationSettings()->create();
|
||||
});
|
||||
|
||||
static::saving(function ($team) {
|
||||
|
|
@ -155,6 +157,14 @@ class Team extends Model implements SendsDiscord, SendsEmail, SendsSlack
|
|||
return data_get($this, 'slack_webhook_url', null);
|
||||
}
|
||||
|
||||
public function routeNotificationForPushover()
|
||||
{
|
||||
return [
|
||||
'user' => data_get($this, 'pushover_user_key', null),
|
||||
'token' => data_get($this, 'pushover_api_token', null),
|
||||
];
|
||||
}
|
||||
|
||||
public function getRecipients($notification)
|
||||
{
|
||||
$recipients = data_get($notification, 'emails', null);
|
||||
|
|
@ -174,7 +184,8 @@ class Team extends Model implements SendsDiscord, SendsEmail, SendsSlack
|
|||
return $this->getNotificationSettings('email')?->isEnabled() ||
|
||||
$this->getNotificationSettings('discord')?->isEnabled() ||
|
||||
$this->getNotificationSettings('slack')?->isEnabled() ||
|
||||
$this->getNotificationSettings('telegram')?->isEnabled();
|
||||
$this->getNotificationSettings('telegram')?->isEnabled() ||
|
||||
$this->getNotificationSettings('pushover')?->isEnabled();
|
||||
}
|
||||
|
||||
public function subscriptionEnded()
|
||||
|
|
@ -276,4 +287,9 @@ class Team extends Model implements SendsDiscord, SendsEmail, SendsSlack
|
|||
{
|
||||
return $this->hasOne(SlackNotificationSettings::class);
|
||||
}
|
||||
|
||||
public function pushoverNotificationSettings()
|
||||
{
|
||||
return $this->hasOne(PushoverNotificationSettings::class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,17 +30,17 @@ class TelegramNotificationSettings extends Model
|
|||
'server_reachable_telegram_notifications',
|
||||
'server_unreachable_telegram_notifications',
|
||||
|
||||
'telegram_notifications_deployment_success_topic_id',
|
||||
'telegram_notifications_deployment_failure_topic_id',
|
||||
'telegram_notifications_status_change_topic_id',
|
||||
'telegram_notifications_backup_success_topic_id',
|
||||
'telegram_notifications_backup_failure_topic_id',
|
||||
'telegram_notifications_scheduled_task_success_topic_id',
|
||||
'telegram_notifications_scheduled_task_failure_topic_id',
|
||||
'telegram_notifications_docker_cleanup_topic_id',
|
||||
'telegram_notifications_server_disk_usage_topic_id',
|
||||
'telegram_notifications_server_reachable_topic_id',
|
||||
'telegram_notifications_server_unreachable_topic_id',
|
||||
'telegram_notifications_deployment_success_thread_id',
|
||||
'telegram_notifications_deployment_failure_thread_id',
|
||||
'telegram_notifications_status_change_thread_id',
|
||||
'telegram_notifications_backup_success_thread_id',
|
||||
'telegram_notifications_backup_failure_thread_id',
|
||||
'telegram_notifications_scheduled_task_success_thread_id',
|
||||
'telegram_notifications_scheduled_task_failure_thread_id',
|
||||
'telegram_notifications_docker_cleanup_thread_id',
|
||||
'telegram_notifications_server_disk_usage_thread_id',
|
||||
'telegram_notifications_server_reachable_thread_id',
|
||||
'telegram_notifications_server_unreachable_thread_id',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
|
|
@ -60,17 +60,17 @@ class TelegramNotificationSettings extends Model
|
|||
'server_reachable_telegram_notifications' => 'boolean',
|
||||
'server_unreachable_telegram_notifications' => 'boolean',
|
||||
|
||||
'telegram_notifications_deployment_success_topic_id' => 'encrypted',
|
||||
'telegram_notifications_deployment_failure_topic_id' => 'encrypted',
|
||||
'telegram_notifications_status_change_topic_id' => 'encrypted',
|
||||
'telegram_notifications_backup_success_topic_id' => 'encrypted',
|
||||
'telegram_notifications_backup_failure_topic_id' => 'encrypted',
|
||||
'telegram_notifications_scheduled_task_success_topic_id' => 'encrypted',
|
||||
'telegram_notifications_scheduled_task_failure_topic_id' => 'encrypted',
|
||||
'telegram_notifications_docker_cleanup_topic_id' => 'encrypted',
|
||||
'telegram_notifications_server_disk_usage_topic_id' => 'encrypted',
|
||||
'telegram_notifications_server_reachable_topic_id' => 'encrypted',
|
||||
'telegram_notifications_server_unreachable_topic_id' => 'encrypted',
|
||||
'telegram_notifications_deployment_success_thread_id' => 'encrypted',
|
||||
'telegram_notifications_deployment_failure_thread_id' => 'encrypted',
|
||||
'telegram_notifications_status_change_thread_id' => 'encrypted',
|
||||
'telegram_notifications_backup_success_thread_id' => 'encrypted',
|
||||
'telegram_notifications_backup_failure_thread_id' => 'encrypted',
|
||||
'telegram_notifications_scheduled_task_success_thread_id' => 'encrypted',
|
||||
'telegram_notifications_scheduled_task_failure_thread_id' => 'encrypted',
|
||||
'telegram_notifications_docker_cleanup_thread_id' => 'encrypted',
|
||||
'telegram_notifications_server_disk_usage_thread_id' => 'encrypted',
|
||||
'telegram_notifications_server_reachable_thread_id' => 'encrypted',
|
||||
'telegram_notifications_server_unreachable_thread_id' => 'encrypted',
|
||||
];
|
||||
|
||||
public function team()
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use App\Models\Application;
|
|||
use App\Models\ApplicationPreview;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -130,6 +131,31 @@ class DeploymentFailed extends CustomEmailNotification
|
|||
];
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
if ($this->preview) {
|
||||
$title = "Pull request #{$this->preview->pull_request_id} deployment failed";
|
||||
$message = "Pull request deployment failed for {$this->application_name}";
|
||||
} else {
|
||||
$title = 'Deployment failed';
|
||||
$message = "Deployment failed for {$this->application_name}";
|
||||
}
|
||||
|
||||
$buttons[] = [
|
||||
'text' => 'Deployment logs',
|
||||
'url' => $this->deployment_url,
|
||||
];
|
||||
|
||||
return new PushoverMessage(
|
||||
title: $title,
|
||||
level: 'error',
|
||||
message: $message,
|
||||
buttons: [
|
||||
...$buttons,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
if ($this->preview) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use App\Models\Application;
|
|||
use App\Models\ApplicationPreview;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -139,6 +140,42 @@ class DeploymentSuccess extends CustomEmailNotification
|
|||
];
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
if ($this->preview) {
|
||||
$title = "Pull request #{$this->preview->pull_request_id} successfully deployed";
|
||||
$message = 'New PR' . $this->preview->pull_request_id . ' version successfully deployed of ' . $this->application_name . '';
|
||||
if ($this->preview->fqdn) {
|
||||
$buttons[] = [
|
||||
'text' => 'Open Application',
|
||||
'url' => $this->preview->fqdn,
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$title = 'New version successfully deployed';
|
||||
$message = 'New version successfully deployed of ' . $this->application_name . '';
|
||||
if ($this->fqdn) {
|
||||
$buttons[] = [
|
||||
'text' => 'Open Application',
|
||||
'url' => $this->fqdn,
|
||||
];
|
||||
}
|
||||
}
|
||||
$buttons[] = [
|
||||
'text' => 'Deployment logs',
|
||||
'url' => $this->deployment_url,
|
||||
];
|
||||
|
||||
return new PushoverMessage(
|
||||
title: $title,
|
||||
level: 'success',
|
||||
message: $message,
|
||||
buttons: [
|
||||
...$buttons,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
if ($this->preview) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace App\Notifications\Application;
|
|||
use App\Models\Application;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -77,6 +78,23 @@ class StatusChanged extends CustomEmailNotification
|
|||
];
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
$message = $this->resource_name . ' has been stopped.';
|
||||
|
||||
return new PushoverMessage(
|
||||
title: 'Application stopped',
|
||||
level: 'error',
|
||||
message: $message,
|
||||
buttons: [
|
||||
[
|
||||
'text' => 'Open Application in Coolify',
|
||||
'url' => $this->resource_url,
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
$title = 'Application stopped';
|
||||
|
|
|
|||
21
app/Notifications/Channels/PushoverChannel.php
Normal file
21
app/Notifications/Channels/PushoverChannel.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications\Channels;
|
||||
|
||||
use App\Jobs\SendMessageToPushoverJob;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class PushoverChannel
|
||||
{
|
||||
public function send(SendsPushover $notifiable, Notification $notification): void
|
||||
{
|
||||
$message = $notification->toPushover();
|
||||
$pushoverSettings = $notifiable->pushoverNotificationSettings;
|
||||
|
||||
if (! $pushoverSettings || ! $pushoverSettings->isEnabled() || ! $pushoverSettings->pushover_user_key || ! $pushoverSettings->pushover_api_token) {
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessageToPushoverJob::dispatch($message, $pushoverSettings->pushover_api_token, $pushoverSettings->pushover_user_key);
|
||||
}
|
||||
}
|
||||
8
app/Notifications/Channels/SendsPushover.php
Normal file
8
app/Notifications/Channels/SendsPushover.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications\Channels;
|
||||
|
||||
interface SendsPushover
|
||||
{
|
||||
public function routeNotificationForPushover();
|
||||
}
|
||||
|
|
@ -16,18 +16,25 @@ class TelegramChannel
|
|||
$telegramToken = $settings->telegram_token;
|
||||
$chatId = $settings->telegram_chat_id;
|
||||
|
||||
$topicId = match (get_class($notification)) {
|
||||
\App\Notifications\Test::class => $settings->telegram_notifications_test_topic_id,
|
||||
$threadId = match (get_class($notification)) {
|
||||
\App\Notifications\Application\DeploymentSuccess::class => $settings->telegram_notifications_deployment_success_thread_id,
|
||||
\App\Notifications\Application\DeploymentFailed::class => $settings->telegram_notifications_deployment_failure_thread_id,
|
||||
\App\Notifications\Application\StatusChanged::class,
|
||||
\App\Notifications\Container\ContainerRestarted::class,
|
||||
\App\Notifications\Container\ContainerStopped::class => $settings->telegram_notifications_status_change_topic_id,
|
||||
\App\Notifications\Application\DeploymentSuccess::class => $settings->telegram_notifications_deployment_success_topic_id,
|
||||
\App\Notifications\Application\DeploymentFailed::class => $settings->telegram_notifications_deployment_failure_topic_id,
|
||||
\App\Notifications\Database\BackupSuccess::class => $settings->telegram_notifications_backup_success_topic_id,
|
||||
\App\Notifications\Database\BackupFailed::class => $settings->telegram_notifications_backup_failure_topic_id,
|
||||
\App\Notifications\ScheduledTask\TaskFailed::class => $settings->telegram_notifications_scheduled_task_failure_topic_id,
|
||||
\App\Notifications\Server\Unreachable::class => $settings->telegram_notifications_server_unreachable_topic_id,
|
||||
\App\Notifications\Server\Reachable::class => $settings->telegram_notifications_server_reachable_topic_id,
|
||||
\App\Notifications\Container\ContainerStopped::class => $settings->telegram_notifications_status_change_thread_id,
|
||||
|
||||
\App\Notifications\Database\BackupSuccess::class => $settings->telegram_notifications_backup_success_thread_id,
|
||||
\App\Notifications\Database\BackupFailed::class => $settings->telegram_notifications_backup_failure_thread_id,
|
||||
|
||||
\App\Notifications\ScheduledTask\TaskSuccess::class => $settings->telegram_notifications_scheduled_task_success_thread_id,
|
||||
\App\Notifications\ScheduledTask\TaskFailed::class => $settings->telegram_notifications_scheduled_task_failure_thread_id,
|
||||
|
||||
\App\Notifications\Server\DockerCleanupSuccess::class => $settings->telegram_notifications_docker_cleanup_success_thread_id,
|
||||
\App\Notifications\Server\DockerCleanupFailed::class => $settings->telegram_notifications_docker_cleanup_failure_thread_id,
|
||||
\App\Notifications\Server\HighDiskUsage::class => $settings->telegram_notifications_server_disk_usage_thread_id,
|
||||
\App\Notifications\Server\Unreachable::class => $settings->telegram_notifications_server_unreachable_thread_id,
|
||||
\App\Notifications\Server\Reachable::class => $settings->telegram_notifications_server_reachable_thread_id,
|
||||
|
||||
default => null,
|
||||
};
|
||||
|
||||
|
|
@ -35,6 +42,6 @@ class TelegramChannel
|
|||
return;
|
||||
}
|
||||
|
||||
SendMessageToTelegramJob::dispatch($message, $buttons, $telegramToken, $chatId, $topicId);
|
||||
SendMessageToTelegramJob::dispatch($message, $buttons, $telegramToken, $chatId, $threadId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace App\Notifications\Container;
|
|||
use App\Models\Server;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -68,6 +69,24 @@ class ContainerRestarted extends CustomEmailNotification
|
|||
return $payload;
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
$buttons = [];
|
||||
if ($this->url) {
|
||||
$buttons[] = [
|
||||
'text' => 'Check Proxy in Coolify',
|
||||
'url' => $this->url,
|
||||
];
|
||||
}
|
||||
|
||||
return new PushoverMessage(
|
||||
title: 'Resource restarted',
|
||||
level: 'warning',
|
||||
message: "A resource ({$this->name}) has been restarted automatically on {$this->server->name}",
|
||||
buttons: $buttons,
|
||||
);
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
$title = 'Resource restarted';
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace App\Notifications\Container;
|
|||
use App\Models\Server;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -68,6 +69,25 @@ class ContainerStopped extends CustomEmailNotification
|
|||
return $payload;
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
$buttons = [];
|
||||
if ($this->url) {
|
||||
$buttons[] = [
|
||||
'text' => 'Open Application in Coolify',
|
||||
'url' => $this->url,
|
||||
];
|
||||
}
|
||||
|
||||
return new PushoverMessage(
|
||||
title: 'Resource stopped',
|
||||
level: 'error',
|
||||
message: "A resource ({$this->name}) has been stopped unexpectedly on {$this->server->name}",
|
||||
buttons: $buttons,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
$title = 'Resource stopped';
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace App\Notifications\Database;
|
|||
use App\Models\ScheduledDatabaseBackup;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -64,6 +65,15 @@ class BackupFailed extends CustomEmailNotification
|
|||
];
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
return new PushoverMessage(
|
||||
title: 'Database backup failed',
|
||||
level: 'error',
|
||||
message: "Database backup for {$this->name} (db:{$this->database_name}) was FAILED<br/><br/><b>Frequency:</b> {$this->frequency} .<br/><b>Reason:</b> {$this->output}",
|
||||
);
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
$title = 'Database backup failed';
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace App\Notifications\Database;
|
|||
use App\Models\ScheduledDatabaseBackup;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -62,6 +63,17 @@ class BackupSuccess extends CustomEmailNotification
|
|||
];
|
||||
}
|
||||
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
return new PushoverMessage(
|
||||
title: 'Database backup successful',
|
||||
level: 'success',
|
||||
message: "Database backup for {$this->name} (db:{$this->database_name}) was successful.<br/><br/><b>Frequency:</b> {$this->frequency}.",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
$title = 'Database backup successful';
|
||||
|
|
|
|||
50
app/Notifications/Dto/PushoverMessage.php
Normal file
50
app/Notifications/Dto/PushoverMessage.php
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications\Dto;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class PushoverMessage
|
||||
{
|
||||
public function __construct(
|
||||
public string $title,
|
||||
public string $message,
|
||||
public array $buttons = [],
|
||||
public string $level = 'info',
|
||||
) {}
|
||||
|
||||
public function getLevelIcon(): string
|
||||
{
|
||||
return match ($this->level) {
|
||||
'info' => 'ℹ️',
|
||||
'error' => '❌',
|
||||
'success' => '✅ ',
|
||||
'warning' => '⚠️',
|
||||
};
|
||||
}
|
||||
|
||||
public function toPayload(string $token, string $user): array
|
||||
{
|
||||
$levelIcon = $this->getLevelIcon();
|
||||
$payload = [
|
||||
'token' => $token,
|
||||
'user' => $user,
|
||||
'title' => "{$levelIcon} {$this->title}",
|
||||
'message' => $this->message,
|
||||
'html' => 1,
|
||||
];
|
||||
|
||||
foreach ($this->buttons as $button) {
|
||||
$buttonUrl = data_get($button, 'url');
|
||||
$text = data_get($button, 'text', 'Click here');
|
||||
if ($buttonUrl && str_contains($buttonUrl, 'http://localhost')) {
|
||||
$buttonUrl = str_replace('http://localhost', config('app.url'), $buttonUrl);
|
||||
}
|
||||
$payload['message'] .= " <a href='" . $buttonUrl . "'>" . $text . '</a>';
|
||||
}
|
||||
|
||||
Log::info('Pushover message', $payload);
|
||||
|
||||
return $payload;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Notifications\Internal;
|
||||
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
|
@ -40,6 +41,15 @@ class GeneralNotification extends Notification implements ShouldQueue
|
|||
];
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
return new PushoverMessage(
|
||||
title: 'General Notification',
|
||||
level: 'info',
|
||||
message: $this->message,
|
||||
);
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
return new SlackMessage(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace App\Notifications\ScheduledTask;
|
|||
use App\Models\ScheduledTask;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -70,6 +71,30 @@ class TaskFailed extends CustomEmailNotification
|
|||
];
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
$message = "Scheduled task ({$this->task->name}) failed<br/>";
|
||||
|
||||
if ($this->output) {
|
||||
$message .= "<br/><b>Error Output:</b>{$this->output}";
|
||||
}
|
||||
|
||||
$buttons = [];
|
||||
if ($this->url) {
|
||||
$buttons[] = [
|
||||
'text' => 'Open task in Coolify',
|
||||
'url' => (string) $this->url,
|
||||
];
|
||||
}
|
||||
|
||||
return new PushoverMessage(
|
||||
title: 'Scheduled task failed',
|
||||
level: 'error',
|
||||
message: $message,
|
||||
buttons: $buttons,
|
||||
);
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
$title = 'Scheduled task failed';
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace App\Notifications\ScheduledTask;
|
|||
use App\Models\ScheduledTask;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -70,6 +71,25 @@ class TaskSuccess extends CustomEmailNotification
|
|||
];
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
$message = "Coolify: Scheduled task ({$this->task->name}) succeeded.";
|
||||
$buttons = [];
|
||||
if ($this->url) {
|
||||
$buttons[] = [
|
||||
'text' => 'Open task in Coolify',
|
||||
'url' => (string) $this->url,
|
||||
];
|
||||
}
|
||||
|
||||
return new PushoverMessage(
|
||||
title: 'Scheduled task succeeded',
|
||||
level: 'success',
|
||||
message: $message,
|
||||
buttons: $buttons,
|
||||
);
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
$title = 'Scheduled task succeeded';
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace App\Notifications\Server;
|
|||
use App\Models\Server;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -48,6 +49,15 @@ class DockerCleanupFailed extends CustomEmailNotification
|
|||
];
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
return new PushoverMessage(
|
||||
title: 'Docker cleanup job failed',
|
||||
level: 'error',
|
||||
message: "[ACTION REQUIRED] Docker cleanup job failed on {$this->server->name}!\n\n{$this->message}",
|
||||
);
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
return new SlackMessage(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace App\Notifications\Server;
|
|||
use App\Models\Server;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -48,6 +49,15 @@ class DockerCleanupSuccess extends CustomEmailNotification
|
|||
];
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
return new PushoverMessage(
|
||||
title: 'Docker cleanup job succeeded',
|
||||
level: 'success',
|
||||
message: "Docker cleanup job succeeded on {$this->server->name}!\n\n{$this->message}",
|
||||
);
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
return new SlackMessage(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace App\Notifications\Server;
|
|||
use App\Models\Server;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -51,6 +52,15 @@ class ForceDisabled extends CustomEmailNotification
|
|||
];
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
return new PushoverMessage(
|
||||
title: 'Server disabled',
|
||||
level: 'error',
|
||||
message: "Server ({$this->server->name}) disabled because it is not paid!\n All automations and integrations are stopped.<br/>Please update your subscription to enable the server again [here](https://app.coolify.io/subscriptions).",
|
||||
);
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
$title = 'Server disabled';
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace App\Notifications\Server;
|
|||
use App\Models\Server;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -47,6 +48,15 @@ class ForceEnabled extends CustomEmailNotification
|
|||
];
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
return new PushoverMessage(
|
||||
title: 'Server enabled',
|
||||
level: 'success',
|
||||
message: "Server ({$this->server->name}) enabled again!",
|
||||
);
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
return new SlackMessage(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace App\Notifications\Server;
|
|||
use App\Models\Server;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -57,6 +58,19 @@ class HighDiskUsage extends CustomEmailNotification
|
|||
];
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
return new PushoverMessage(
|
||||
title: 'High disk usage detected',
|
||||
level: 'warning',
|
||||
message: "Server '{$this->server->name}' high disk usage detected!<br/><br/><b>Disk usage:</b> {$this->disk_usage}%.<br/><b>Threshold:</b> {$this->server_disk_usage_notification_threshold}%.<br/>Please cleanup your disk to prevent data-loss.",
|
||||
buttons: [
|
||||
'Change settings' => base_url().'/server/'.$this->server->uuid."#advanced",
|
||||
'Tips for cleanup' => "https://coolify.io/docs/knowledge-base/server/automated-cleanup",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
$description = "Server '{$this->server->name}' high disk usage detected!\n";
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace App\Notifications\Server;
|
|||
use App\Models\Server;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -49,6 +50,15 @@ class Reachable extends CustomEmailNotification
|
|||
);
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
return new PushoverMessage(
|
||||
title: 'Server revived',
|
||||
message: "Server '{$this->server->name}' revived. All automations & integrations are turned on again!",
|
||||
level: 'success',
|
||||
);
|
||||
}
|
||||
|
||||
public function toTelegram(): array
|
||||
{
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace App\Notifications\Server;
|
|||
use App\Models\Server;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
|
|
@ -60,6 +61,15 @@ class Unreachable extends CustomEmailNotification
|
|||
];
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
return new PushoverMessage(
|
||||
title: 'Server unreachable',
|
||||
level: 'error',
|
||||
message: "Your server '{$this->server->name}' is unreachable.<br/>All automations & integrations are turned off!<br/><br/><b>IMPORTANT:</b> We automatically try to revive your server and turn on all automations & integrations.",
|
||||
);
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
$description = "Your server '{$this->server->name}' is unreachable.\n";
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ use App\Notifications\Channels\DiscordChannel;
|
|||
use App\Notifications\Channels\EmailChannel;
|
||||
use App\Notifications\Channels\SlackChannel;
|
||||
use App\Notifications\Channels\TelegramChannel;
|
||||
use App\Notifications\Channels\PushoverChannel;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\PushoverMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
|
@ -33,6 +35,7 @@ class Test extends Notification implements ShouldQueue
|
|||
'discord' => [DiscordChannel::class],
|
||||
'telegram' => [TelegramChannel::class],
|
||||
'slack' => [SlackChannel::class],
|
||||
'pushover' => [PushoverChannel::class],
|
||||
default => [],
|
||||
};
|
||||
} else {
|
||||
|
|
@ -85,6 +88,20 @@ class Test extends Notification implements ShouldQueue
|
|||
];
|
||||
}
|
||||
|
||||
public function toPushover(): PushoverMessage
|
||||
{
|
||||
return new PushoverMessage(
|
||||
title: 'Test Pushover Notification',
|
||||
message: 'This is a test Pushover notification from Coolify.',
|
||||
buttons: [
|
||||
[
|
||||
'text' => 'Go to your dashboard',
|
||||
'url' => base_url(),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
return new SlackMessage(
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Providers;
|
||||
|
||||
use App\Models\PersonalAccessToken;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Validation\Rules\Password;
|
||||
|
|
@ -19,6 +20,9 @@ class AppServiceProvider extends ServiceProvider
|
|||
|
||||
public function boot(): void
|
||||
{
|
||||
Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) {
|
||||
$event->extendSocialite('authentik', \SocialiteProviders\Authentik\Provider::class);
|
||||
});
|
||||
Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
|
||||
|
||||
Password::defaults(function () {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ use App\Listeners\ProxyStartedNotification;
|
|||
use Illuminate\Foundation\Events\MaintenanceModeDisabled;
|
||||
use Illuminate\Foundation\Events\MaintenanceModeEnabled;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
use SocialiteProviders\Authentik\AuthentikExtendSocialite;
|
||||
use SocialiteProviders\Azure\AzureExtendSocialite;
|
||||
use SocialiteProviders\Manager\SocialiteWasCalled;
|
||||
|
||||
class EventServiceProvider extends ServiceProvider
|
||||
{
|
||||
|
|
@ -19,8 +22,9 @@ class EventServiceProvider extends ServiceProvider
|
|||
MaintenanceModeDisabled::class => [
|
||||
MaintenanceModeDisabledNotification::class,
|
||||
],
|
||||
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
|
||||
\SocialiteProviders\Azure\AzureExtendSocialite::class.'@handle',
|
||||
SocialiteWasCalled::class => [
|
||||
AzureExtendSocialite::class.'@handle',
|
||||
AuthentikExtendSocialite::class.'@handle',
|
||||
],
|
||||
ProxyStarted::class => [
|
||||
ProxyStartedNotification::class,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use App\Notifications\Channels\DiscordChannel;
|
|||
use App\Notifications\Channels\EmailChannel;
|
||||
use App\Notifications\Channels\SlackChannel;
|
||||
use App\Notifications\Channels\TelegramChannel;
|
||||
use App\Notifications\Channels\PushoverChannel;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
trait HasNotificationSettings
|
||||
|
|
@ -27,6 +28,7 @@ trait HasNotificationSettings
|
|||
'discord' => $this->discordNotificationSettings,
|
||||
'telegram' => $this->telegramNotificationSettings,
|
||||
'slack' => $this->slackNotificationSettings,
|
||||
'pushover' => $this->pushoverNotificationSettings,
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
|
@ -73,6 +75,7 @@ trait HasNotificationSettings
|
|||
'discord' => DiscordChannel::class,
|
||||
'telegram' => TelegramChannel::class,
|
||||
'slack' => SlackChannel::class,
|
||||
'pushover' => PushoverChannel::class,
|
||||
];
|
||||
|
||||
if ($event === 'general') {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class Services extends Component
|
|||
public string $complexStatus = 'exited',
|
||||
public bool $showRefreshButton = true
|
||||
) {
|
||||
$this->complexStatus = $service->status();
|
||||
$this->complexStatus = $service->status;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -830,6 +830,12 @@ function generateEnvValue(string $command, Service|Application|null $service = n
|
|||
case 'PASSWORD_64':
|
||||
$generatedValue = Str::password(length: 64, symbols: false);
|
||||
break;
|
||||
case 'PASSWORDWITHSYMBOLS':
|
||||
$generatedValue = Str::password(symbols: true);
|
||||
break;
|
||||
case 'PASSWORDWITHSYMBOLS_64':
|
||||
$generatedValue = Str::password(length: 64, symbols: true);
|
||||
break;
|
||||
// This is not base64, it's just a random string
|
||||
case 'BASE64_64':
|
||||
$generatedValue = Str::random(64);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,17 @@ function get_socialite_provider(string $provider)
|
|||
return Socialite::driver('azure')->setConfig($azure_config);
|
||||
}
|
||||
|
||||
if ($provider == 'authentik') {
|
||||
$authentik_config = new \SocialiteProviders\Manager\Config(
|
||||
$oauth_setting->client_id,
|
||||
$oauth_setting->client_secret,
|
||||
$oauth_setting->redirect_uri,
|
||||
['base_url' => $oauth_setting->base_url],
|
||||
);
|
||||
|
||||
return Socialite::driver('authentik')->setConfig($authentik_config);
|
||||
}
|
||||
|
||||
$config = [
|
||||
'client_id' => $oauth_setting->client_id,
|
||||
'client_secret' => $oauth_setting->client_secret,
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ function allowedPathsForUnsubscribedAccounts()
|
|||
'logout',
|
||||
'force-password-reset',
|
||||
'livewire/update',
|
||||
'admin',
|
||||
];
|
||||
}
|
||||
function allowedPathsForBoardingAccounts()
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
"pusher/pusher-php-server": "^7.2",
|
||||
"resend/resend-laravel": "^0.15.0",
|
||||
"sentry/sentry-laravel": "^4.6",
|
||||
"socialiteproviders/authentik": "^5.2",
|
||||
"socialiteproviders/microsoft-azure": "^5.1",
|
||||
"spatie/laravel-activitylog": "^4.7.3",
|
||||
"spatie/laravel-data": "^4.11",
|
||||
|
|
|
|||
388
composer.lock
generated
388
composer.lock
generated
|
|
@ -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": "d96fe0aedd865274164c34a1b04195fe",
|
||||
"content-hash": "871067cb42e6347ca53ff36e81ac5079",
|
||||
"packages": [
|
||||
{
|
||||
"name": "3sidedcube/laravel-redoc",
|
||||
|
|
@ -979,16 +979,16 @@
|
|||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.334.2",
|
||||
"version": "3.334.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "b19afc076bb1cc2617bdef76efd41587596109e7"
|
||||
"reference": "6576a9fcfc6ae7c76aed3c6fa4c3864060f72d04"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/b19afc076bb1cc2617bdef76efd41587596109e7",
|
||||
"reference": "b19afc076bb1cc2617bdef76efd41587596109e7",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/6576a9fcfc6ae7c76aed3c6fa4c3864060f72d04",
|
||||
"reference": "6576a9fcfc6ae7c76aed3c6fa4c3864060f72d04",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -1071,9 +1071,9 @@
|
|||
"support": {
|
||||
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.334.2"
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.334.3"
|
||||
},
|
||||
"time": "2024-12-09T19:30:23+00:00"
|
||||
"time": "2024-12-10T19:41:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
|
|
@ -3313,16 +3313,16 @@
|
|||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.x-dev"
|
||||
},
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Laravel\\Socialite\\SocialiteServiceProvider"
|
||||
],
|
||||
"aliases": {
|
||||
"Socialite": "Laravel\\Socialite\\Facades\\Socialite"
|
||||
}
|
||||
},
|
||||
"providers": [
|
||||
"Laravel\\Socialite\\SocialiteServiceProvider"
|
||||
]
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "5.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
|
@ -4037,16 +4037,16 @@
|
|||
},
|
||||
{
|
||||
"name": "league/oauth1-client",
|
||||
"version": "v1.10.1",
|
||||
"version": "v1.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/oauth1-client.git",
|
||||
"reference": "d6365b901b5c287dd41f143033315e2f777e1167"
|
||||
"reference": "f9c94b088837eb1aae1ad7c4f23eb65cc6993055"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/d6365b901b5c287dd41f143033315e2f777e1167",
|
||||
"reference": "d6365b901b5c287dd41f143033315e2f777e1167",
|
||||
"url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/f9c94b088837eb1aae1ad7c4f23eb65cc6993055",
|
||||
"reference": "f9c94b088837eb1aae1ad7c4f23eb65cc6993055",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -4107,9 +4107,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/thephpleague/oauth1-client/issues",
|
||||
"source": "https://github.com/thephpleague/oauth1-client/tree/v1.10.1"
|
||||
"source": "https://github.com/thephpleague/oauth1-client/tree/v1.11.0"
|
||||
},
|
||||
"time": "2022-04-15T14:02:14+00:00"
|
||||
"time": "2024-12-10T19:59:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/uri",
|
||||
|
|
@ -5952,64 +5952,6 @@
|
|||
},
|
||||
"time": "2024-10-13T11:29:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.12.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "b5ae1b88f471d3fd4ba1aa0046234b5ca3776dd0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/b5ae1b88f471d3fd4ba1aa0046234b5ca3776dd0",
|
||||
"reference": "b5ae1b88f471d3fd4ba1aa0046234b5ca3776dd0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2|^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"phpstan/phpstan-shim": "*"
|
||||
},
|
||||
"bin": [
|
||||
"phpstan",
|
||||
"phpstan.phar"
|
||||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "PHPStan - PHP Static Analysis Tool",
|
||||
"keywords": [
|
||||
"dev",
|
||||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://phpstan.org/user-guide/getting-started",
|
||||
"forum": "https://github.com/phpstan/phpstan/discussions",
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"security": "https://github.com/phpstan/phpstan/security/policy",
|
||||
"source": "https://github.com/phpstan/phpstan-src"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/ondrejmirtes",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/phpstan",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-28T22:13:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pimple/pimple",
|
||||
"version": "v3.5.0",
|
||||
|
|
@ -7099,65 +7041,6 @@
|
|||
],
|
||||
"time": "2024-04-27T21:32:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "rector/rector",
|
||||
"version": "1.2.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/rectorphp/rector.git",
|
||||
"reference": "40f9cf38c05296bd32f444121336a521a293fa61"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/rectorphp/rector/zipball/40f9cf38c05296bd32f444121336a521a293fa61",
|
||||
"reference": "40f9cf38c05296bd32f444121336a521a293fa61",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2|^8.0",
|
||||
"phpstan/phpstan": "^1.12.5"
|
||||
},
|
||||
"conflict": {
|
||||
"rector/rector-doctrine": "*",
|
||||
"rector/rector-downgrade-php": "*",
|
||||
"rector/rector-phpunit": "*",
|
||||
"rector/rector-symfony": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "To manipulate phpunit.xml via the custom-rule command"
|
||||
},
|
||||
"bin": [
|
||||
"bin/rector"
|
||||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Instant Upgrade and Automated Refactoring of any PHP code",
|
||||
"keywords": [
|
||||
"automation",
|
||||
"dev",
|
||||
"migration",
|
||||
"refactoring"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/rectorphp/rector/issues",
|
||||
"source": "https://github.com/rectorphp/rector/tree/1.2.10"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/tomasvotruba",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-08T13:59:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "resend/resend-laravel",
|
||||
"version": "v0.15.0",
|
||||
|
|
@ -7534,6 +7417,56 @@
|
|||
],
|
||||
"time": "2024-11-24T11:02:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "socialiteproviders/authentik",
|
||||
"version": "5.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/SocialiteProviders/Authentik.git",
|
||||
"reference": "4cf129cf04728a38e0531c54454464b162f0fa66"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/SocialiteProviders/Authentik/zipball/4cf129cf04728a38e0531c54454464b162f0fa66",
|
||||
"reference": "4cf129cf04728a38e0531c54454464b162f0fa66",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"php": "^8.0",
|
||||
"socialiteproviders/manager": "^4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"SocialiteProviders\\Authentik\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "rf152",
|
||||
"email": "git@rf152.co.uk"
|
||||
}
|
||||
],
|
||||
"description": "Authentik OAuth2 Provider for Laravel Socialite",
|
||||
"keywords": [
|
||||
"authentik",
|
||||
"laravel",
|
||||
"oauth",
|
||||
"provider",
|
||||
"socialite"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://socialiteproviders.com/authentik",
|
||||
"issues": "https://github.com/socialiteproviders/providers/issues",
|
||||
"source": "https://github.com/socialiteproviders/providers"
|
||||
},
|
||||
"time": "2023-11-07T22:21:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "socialiteproviders/manager",
|
||||
"version": "v4.7.0",
|
||||
|
|
@ -7959,40 +7892,41 @@
|
|||
},
|
||||
{
|
||||
"name": "spatie/laravel-ray",
|
||||
"version": "1.37.1",
|
||||
"version": "1.39.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-ray.git",
|
||||
"reference": "c2bedfd1172648df2c80aaceb2541d70f1d9a5b9"
|
||||
"reference": "31b601f98590606d20e76b5dd68578dc1642cd2c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-ray/zipball/c2bedfd1172648df2c80aaceb2541d70f1d9a5b9",
|
||||
"reference": "c2bedfd1172648df2c80aaceb2541d70f1d9a5b9",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-ray/zipball/31b601f98590606d20e76b5dd68578dc1642cd2c",
|
||||
"reference": "31b601f98590606d20e76b5dd68578dc1642cd2c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-runtime-api": "^2.2",
|
||||
"ext-json": "*",
|
||||
"illuminate/contracts": "^7.20|^8.19|^9.0|^10.0|^11.0",
|
||||
"illuminate/database": "^7.20|^8.19|^9.0|^10.0|^11.0",
|
||||
"illuminate/queue": "^7.20|^8.19|^9.0|^10.0|^11.0",
|
||||
"illuminate/support": "^7.20|^8.19|^9.0|^10.0|^11.0",
|
||||
"php": "^7.4|^8.0",
|
||||
"rector/rector": "^0.19.2|^1.0",
|
||||
"illuminate/contracts": "^7.20 || ^8.19 || ^9.0 || ^10.0 || ^11.0",
|
||||
"illuminate/database": "^7.20 || ^8.19 || ^9.0 || ^10.0 || ^11.0",
|
||||
"illuminate/queue": "^7.20 || ^8.19 || ^9.0 || ^10.0 || ^11.0",
|
||||
"illuminate/support": "^7.20 || ^8.19 || ^9.0 || ^10.0 || ^11.0",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"spatie/backtrace": "^1.0",
|
||||
"spatie/ray": "^1.41.1",
|
||||
"symfony/stopwatch": "4.2|^5.1|^6.0|^7.0",
|
||||
"zbateson/mail-mime-parser": "^1.3.1|^2.0|^3.0"
|
||||
"spatie/ray": "^1.41.3",
|
||||
"symfony/stopwatch": "4.2 || ^5.1 || ^6.0 || ^7.0",
|
||||
"zbateson/mail-mime-parser": "^1.3.1 || ^2.0 || ^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"guzzlehttp/guzzle": "^7.3",
|
||||
"laravel/framework": "^7.20|^8.19|^9.0|^10.0|^11.0",
|
||||
"orchestra/testbench-core": "^5.0|^6.0|^7.0|^8.0|^9.0",
|
||||
"pestphp/pest": "^1.22|^2.0",
|
||||
"phpstan/phpstan": "^1.10.57",
|
||||
"phpunit/phpunit": "^9.3|^10.1",
|
||||
"spatie/pest-plugin-snapshots": "^1.1|^2.0",
|
||||
"symfony/var-dumper": "^4.2|^5.1|^6.0|^7.0.3"
|
||||
"laravel/framework": "^7.20 || ^8.19 || ^9.0 || ^10.0 || ^11.0",
|
||||
"orchestra/testbench-core": "^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0",
|
||||
"pestphp/pest": "^1.22 || ^2.0",
|
||||
"phpstan/phpstan": "^1.10.57 || ^2.0.2",
|
||||
"phpunit/phpunit": "^9.3 || ^10.1",
|
||||
"rector/rector": "dev-main",
|
||||
"spatie/pest-plugin-snapshots": "^1.1 || ^2.0",
|
||||
"symfony/var-dumper": "^4.2 || ^5.1 || ^6.0 || ^7.0.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
|
@ -8030,7 +7964,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/laravel-ray/issues",
|
||||
"source": "https://github.com/spatie/laravel-ray/tree/1.37.1"
|
||||
"source": "https://github.com/spatie/laravel-ray/tree/1.39.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -8042,7 +7976,7 @@
|
|||
"type": "other"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-12T12:35:17+00:00"
|
||||
"time": "2024-12-11T09:34:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-schemaless-attributes",
|
||||
|
|
@ -8532,16 +8466,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v7.2.0",
|
||||
"version": "v7.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "23c8aae6d764e2bae02d2a99f7532a7f6ed619cf"
|
||||
"reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/23c8aae6d764e2bae02d2a99f7532a7f6ed619cf",
|
||||
"reference": "23c8aae6d764e2bae02d2a99f7532a7f6ed619cf",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/fefcc18c0f5d0efe3ab3152f15857298868dc2c3",
|
||||
"reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -8605,7 +8539,7 @@
|
|||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v7.2.0"
|
||||
"source": "https://github.com/symfony/console/tree/v7.2.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -8621,7 +8555,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-06T14:24:19+00:00"
|
||||
"time": "2024-12-11T03:49:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/css-selector",
|
||||
|
|
@ -8757,16 +8691,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/error-handler",
|
||||
"version": "v7.2.0",
|
||||
"version": "v7.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/error-handler.git",
|
||||
"reference": "672b3dd1ef8b87119b446d67c58c106c43f965fe"
|
||||
"reference": "6150b89186573046167796fa5f3f76601d5145f8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/error-handler/zipball/672b3dd1ef8b87119b446d67c58c106c43f965fe",
|
||||
"reference": "672b3dd1ef8b87119b446d67c58c106c43f965fe",
|
||||
"url": "https://api.github.com/repos/symfony/error-handler/zipball/6150b89186573046167796fa5f3f76601d5145f8",
|
||||
"reference": "6150b89186573046167796fa5f3f76601d5145f8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -8812,7 +8746,7 @@
|
|||
"description": "Provides tools to manage errors and ease debugging PHP code",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/error-handler/tree/v7.2.0"
|
||||
"source": "https://github.com/symfony/error-handler/tree/v7.2.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -8828,7 +8762,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-05T15:35:02+00:00"
|
||||
"time": "2024-12-07T08:50:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
|
|
@ -9130,16 +9064,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/http-kernel",
|
||||
"version": "v7.2.0",
|
||||
"version": "v7.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-kernel.git",
|
||||
"reference": "6b4722a25e0aed1ccb4914b9bcbd493cc4676b4d"
|
||||
"reference": "d8ae58eecae44c8e66833e76cc50a4ad3c002d97"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/6b4722a25e0aed1ccb4914b9bcbd493cc4676b4d",
|
||||
"reference": "6b4722a25e0aed1ccb4914b9bcbd493cc4676b4d",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/d8ae58eecae44c8e66833e76cc50a4ad3c002d97",
|
||||
"reference": "d8ae58eecae44c8e66833e76cc50a4ad3c002d97",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -9224,7 +9158,7 @@
|
|||
"description": "Provides a structured process for converting a Request into a Response",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-kernel/tree/v7.2.0"
|
||||
"source": "https://github.com/symfony/http-kernel/tree/v7.2.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -9240,7 +9174,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-29T08:42:40+00:00"
|
||||
"time": "2024-12-11T12:09:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/mailer",
|
||||
|
|
@ -9324,16 +9258,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/mime",
|
||||
"version": "v7.2.0",
|
||||
"version": "v7.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/mime.git",
|
||||
"reference": "cc84a4b81f62158c3846ac7ff10f696aae2b524d"
|
||||
"reference": "7f9617fcf15cb61be30f8b252695ed5e2bfac283"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/mime/zipball/cc84a4b81f62158c3846ac7ff10f696aae2b524d",
|
||||
"reference": "cc84a4b81f62158c3846ac7ff10f696aae2b524d",
|
||||
"url": "https://api.github.com/repos/symfony/mime/zipball/7f9617fcf15cb61be30f8b252695ed5e2bfac283",
|
||||
"reference": "7f9617fcf15cb61be30f8b252695ed5e2bfac283",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -9388,7 +9322,7 @@
|
|||
"mime-type"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/mime/tree/v7.2.0"
|
||||
"source": "https://github.com/symfony/mime/tree/v7.2.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -9404,7 +9338,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-23T09:19:39+00:00"
|
||||
"time": "2024-12-07T08:50:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
|
|
@ -13222,17 +13156,75 @@
|
|||
"time": "2024-11-21T15:12:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "11.0.7",
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.12.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "f7f08030e8811582cc459871d28d6f5a1a4d35ca"
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "b5ae1b88f471d3fd4ba1aa0046234b5ca3776dd0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f7f08030e8811582cc459871d28d6f5a1a4d35ca",
|
||||
"reference": "f7f08030e8811582cc459871d28d6f5a1a4d35ca",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/b5ae1b88f471d3fd4ba1aa0046234b5ca3776dd0",
|
||||
"reference": "b5ae1b88f471d3fd4ba1aa0046234b5ca3776dd0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2|^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"phpstan/phpstan-shim": "*"
|
||||
},
|
||||
"bin": [
|
||||
"phpstan",
|
||||
"phpstan.phar"
|
||||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "PHPStan - PHP Static Analysis Tool",
|
||||
"keywords": [
|
||||
"dev",
|
||||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://phpstan.org/user-guide/getting-started",
|
||||
"forum": "https://github.com/phpstan/phpstan/discussions",
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"security": "https://github.com/phpstan/phpstan/security/policy",
|
||||
"source": "https://github.com/phpstan/phpstan-src"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/ondrejmirtes",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/phpstan",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-28T22:13:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "11.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "418c59fd080954f8c4aa5631d9502ecda2387118"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/418c59fd080954f8c4aa5631d9502ecda2387118",
|
||||
"reference": "418c59fd080954f8c4aa5631d9502ecda2387118",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -13251,7 +13243,7 @@
|
|||
"theseer/tokenizer": "^1.2.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^11.4.1"
|
||||
"phpunit/phpunit": "^11.5.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-pcov": "PHP extension that provides line coverage",
|
||||
|
|
@ -13289,7 +13281,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.7"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.8"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -13297,7 +13289,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-09T06:21:38+00:00"
|
||||
"time": "2024-12-11T12:34:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
|
|
@ -14615,16 +14607,16 @@
|
|||
},
|
||||
{
|
||||
"name": "spatie/error-solutions",
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/error-solutions.git",
|
||||
"reference": "ae7393122eda72eed7cc4f176d1e96ea444f2d67"
|
||||
"reference": "d239a65235a1eb128dfa0a4e4c4ef032ea11b541"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/error-solutions/zipball/ae7393122eda72eed7cc4f176d1e96ea444f2d67",
|
||||
"reference": "ae7393122eda72eed7cc4f176d1e96ea444f2d67",
|
||||
"url": "https://api.github.com/repos/spatie/error-solutions/zipball/d239a65235a1eb128dfa0a4e4c4ef032ea11b541",
|
||||
"reference": "d239a65235a1eb128dfa0a4e4c4ef032ea11b541",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -14677,7 +14669,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/error-solutions/issues",
|
||||
"source": "https://github.com/spatie/error-solutions/tree/1.1.1"
|
||||
"source": "https://github.com/spatie/error-solutions/tree/1.1.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -14685,7 +14677,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-25T11:06:04+00:00"
|
||||
"time": "2024-12-11T09:51:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/flare-client-php",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
return [
|
||||
'coolify' => [
|
||||
'version' => '4.0.0-beta.377',
|
||||
'version' => '4.0.0-beta.380',
|
||||
'self_hosted' => env('SELF_HOSTED', true),
|
||||
'autoupdate' => env('AUTOUPDATE'),
|
||||
'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),
|
||||
|
|
@ -33,6 +33,14 @@ return [
|
|||
'app_key' => env('PUSHER_APP_KEY'),
|
||||
],
|
||||
|
||||
'migration' => [
|
||||
'is_migration_enabled' => env('MIGRATION_ENABLED', true),
|
||||
],
|
||||
|
||||
'seeder' => [
|
||||
'is_seeder_enabled' => env('SEEDER_ENABLED', true),
|
||||
],
|
||||
|
||||
'horizon' => [
|
||||
'is_horizon_enabled' => env('HORIZON_ENABLED', true),
|
||||
'is_scheduler_enabled' => env('SCHEDULER_ENABLED', true),
|
||||
|
|
|
|||
|
|
@ -38,4 +38,11 @@ return [
|
|||
'tenant' => env('AZURE_TENANT_ID'),
|
||||
'proxy' => env('AZURE_PROXY'),
|
||||
],
|
||||
|
||||
'authentik' => [
|
||||
'base_url' => env('AUTHENTIK_BASE_URL'),
|
||||
'client_id' => env('AUTHENTIK_CLIENT_ID'),
|
||||
'client_secret' => env('AUTHENTIK_CLIENT_SECRET'),
|
||||
'redirect' => env('AUTHENTIK_REDIRECT_URI'),
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ return new class extends Migration
|
|||
$tokens = PersonalAccessToken::all();
|
||||
foreach ($tokens as $token) {
|
||||
$abilities = collect();
|
||||
if (in_array('write', $token->abilities)) {
|
||||
if (in_array('root', $token->abilities)) {
|
||||
$abilities->push('*');
|
||||
} else {
|
||||
if (in_array('read', $token->abilities)) {
|
||||
|
|
|
|||
|
|
@ -32,18 +32,18 @@ return new class extends Migration
|
|||
$table->boolean('server_reachable_telegram_notifications')->default(false);
|
||||
$table->boolean('server_unreachable_telegram_notifications')->default(true);
|
||||
|
||||
$table->text('telegram_notifications_deployment_success_topic_id')->nullable();
|
||||
$table->text('telegram_notifications_deployment_failure_topic_id')->nullable();
|
||||
$table->text('telegram_notifications_status_change_topic_id')->nullable();
|
||||
$table->text('telegram_notifications_backup_success_topic_id')->nullable();
|
||||
$table->text('telegram_notifications_backup_failure_topic_id')->nullable();
|
||||
$table->text('telegram_notifications_scheduled_task_success_topic_id')->nullable();
|
||||
$table->text('telegram_notifications_scheduled_task_failure_topic_id')->nullable();
|
||||
$table->text('telegram_notifications_docker_cleanup_success_topic_id')->nullable();
|
||||
$table->text('telegram_notifications_docker_cleanup_failure_topic_id')->nullable();
|
||||
$table->text('telegram_notifications_server_disk_usage_topic_id')->nullable();
|
||||
$table->text('telegram_notifications_server_reachable_topic_id')->nullable();
|
||||
$table->text('telegram_notifications_server_unreachable_topic_id')->nullable();
|
||||
$table->text('telegram_notifications_deployment_success_thread_id')->nullable();
|
||||
$table->text('telegram_notifications_deployment_failure_thread_id')->nullable();
|
||||
$table->text('telegram_notifications_status_change_thread_id')->nullable();
|
||||
$table->text('telegram_notifications_backup_success_thread_id')->nullable();
|
||||
$table->text('telegram_notifications_backup_failure_thread_id')->nullable();
|
||||
$table->text('telegram_notifications_scheduled_task_success_thread_id')->nullable();
|
||||
$table->text('telegram_notifications_scheduled_task_failure_thread_id')->nullable();
|
||||
$table->text('telegram_notifications_docker_cleanup_success_thread_id')->nullable();
|
||||
$table->text('telegram_notifications_docker_cleanup_failure_thread_id')->nullable();
|
||||
$table->text('telegram_notifications_server_disk_usage_thread_id')->nullable();
|
||||
$table->text('telegram_notifications_server_reachable_thread_id')->nullable();
|
||||
$table->text('telegram_notifications_server_unreachable_thread_id')->nullable();
|
||||
|
||||
$table->unique(['team_id']);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use Illuminate\Database\Migrations\Migration;
|
|||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
|
|
@ -30,17 +31,17 @@ return new class extends Migration
|
|||
'status_change_telegram_notifications' => $team->telegram_notifications_status_changes ?? false,
|
||||
'server_disk_usage_telegram_notifications' => $team->telegram_notifications_server_disk_usage ?? true,
|
||||
|
||||
'telegram_notifications_deployment_success_topic_id' => $team->telegram_notifications_deployments_message_thread_id ? Crypt::encryptString($team->telegram_notifications_deployments_message_thread_id) : null,
|
||||
'telegram_notifications_deployment_failure_topic_id' => $team->telegram_notifications_deployments_message_thread_id ? Crypt::encryptString($team->telegram_notifications_deployments_message_thread_id) : null,
|
||||
'telegram_notifications_backup_success_topic_id' => $team->telegram_notifications_database_backups_message_thread_id ? Crypt::encryptString($team->telegram_notifications_database_backups_message_thread_id) : null,
|
||||
'telegram_notifications_backup_failure_topic_id' => $team->telegram_notifications_database_backups_message_thread_id ? Crypt::encryptString($team->telegram_notifications_database_backups_message_thread_id) : null,
|
||||
'telegram_notifications_scheduled_task_success_topic_id' => $team->telegram_notifications_scheduled_tasks_thread_id ? Crypt::encryptString($team->telegram_notifications_scheduled_tasks_thread_id) : null,
|
||||
'telegram_notifications_scheduled_task_failure_topic_id' => $team->telegram_notifications_scheduled_tasks_thread_id ? Crypt::encryptString($team->telegram_notifications_scheduled_tasks_thread_id) : null,
|
||||
'telegram_notifications_status_change_topic_id' => $team->telegram_notifications_status_changes_message_thread_id ? Crypt::encryptString($team->telegram_notifications_status_changes_message_thread_id) : null,
|
||||
'telegram_notifications_deployment_success_thread_id' => $team->telegram_notifications_deployments_message_thread_id ? Crypt::encryptString($team->telegram_notifications_deployments_message_thread_id) : null,
|
||||
'telegram_notifications_deployment_failure_thread_id' => $team->telegram_notifications_deployments_message_thread_id ? Crypt::encryptString($team->telegram_notifications_deployments_message_thread_id) : null,
|
||||
'telegram_notifications_backup_success_thread_id' => $team->telegram_notifications_database_backups_message_thread_id ? Crypt::encryptString($team->telegram_notifications_database_backups_message_thread_id) : null,
|
||||
'telegram_notifications_backup_failure_thread_id' => $team->telegram_notifications_database_backups_message_thread_id ? Crypt::encryptString($team->telegram_notifications_database_backups_message_thread_id) : null,
|
||||
'telegram_notifications_scheduled_task_success_thread_id' => $team->telegram_notifications_scheduled_tasks_thread_id ? Crypt::encryptString($team->telegram_notifications_scheduled_tasks_thread_id) : null,
|
||||
'telegram_notifications_scheduled_task_failure_thread_id' => $team->telegram_notifications_scheduled_tasks_thread_id ? Crypt::encryptString($team->telegram_notifications_scheduled_tasks_thread_id) : null,
|
||||
'telegram_notifications_status_change_thread_id' => $team->telegram_notifications_status_changes_message_thread_id ? Crypt::encryptString($team->telegram_notifications_status_changes_message_thread_id) : null,
|
||||
]
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
\Log::error('Error migrating telegram notification settings from teams table: '.$e->getMessage());
|
||||
Log::error('Error migrating telegram notification settings from teams table: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -101,13 +102,13 @@ return new class extends Migration
|
|||
'telegram_notifications_scheduled_tasks' => $setting->scheduled_task_success_telegram_notifications || $setting->scheduled_task_failure_telegram_notifications,
|
||||
'telegram_notifications_server_disk_usage' => $setting->server_disk_usage_telegram_notifications,
|
||||
|
||||
'telegram_notifications_deployments_message_thread_id' => $setting->telegram_notifications_deployment_success_topic_id ? Crypt::decryptString($setting->telegram_notifications_deployment_success_topic_id) : null,
|
||||
'telegram_notifications_status_changes_message_thread_id' => $setting->telegram_notifications_status_change_topic_id ? Crypt::decryptString($setting->telegram_notifications_status_change_topic_id) : null,
|
||||
'telegram_notifications_database_backups_message_thread_id' => $setting->telegram_notifications_backup_success_topic_id ? Crypt::decryptString($setting->telegram_notifications_backup_success_topic_id) : null,
|
||||
'telegram_notifications_scheduled_tasks_thread_id' => $setting->telegram_notifications_scheduled_task_success_topic_id ? Crypt::decryptString($setting->telegram_notifications_scheduled_task_success_topic_id) : null,
|
||||
'telegram_notifications_deployments_message_thread_id' => $setting->telegram_notifications_deployment_success_thread_id ? Crypt::decryptString($setting->telegram_notifications_deployment_success_thread_id) : null,
|
||||
'telegram_notifications_status_changes_message_thread_id' => $setting->telegram_notifications_status_change_thread_id ? Crypt::decryptString($setting->telegram_notifications_status_change_thread_id) : null,
|
||||
'telegram_notifications_database_backups_message_thread_id' => $setting->telegram_notifications_backup_success_thread_id ? Crypt::decryptString($setting->telegram_notifications_backup_success_thread_id) : null,
|
||||
'telegram_notifications_scheduled_tasks_thread_id' => $setting->telegram_notifications_scheduled_task_success_thread_id ? Crypt::decryptString($setting->telegram_notifications_scheduled_task_success_thread_id) : null,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
\Log::error('Error migrating telegram notification settings from teams table: '.$e->getMessage());
|
||||
Log::error('Error migrating telegram notification settings from teams table: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
|
|
@ -42,7 +43,7 @@ return new class extends Migration
|
|||
'team_id' => $team->id,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
\Log::error('Error migrating slack notification settings from teams table: '.$e->getMessage());
|
||||
Log::error('Error creating slack notification settings for existing teams: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,11 +45,11 @@ return new class extends Migration
|
|||
public function down(): void
|
||||
{
|
||||
Schema::table('instance_settings', function (Blueprint $table) {
|
||||
$table->string('smtp_from_address')->nullable()->change();
|
||||
$table->string('smtp_from_name')->nullable()->change();
|
||||
$table->string('smtp_recipients')->nullable()->change();
|
||||
$table->string('smtp_host')->nullable()->change();
|
||||
$table->string('smtp_username')->nullable()->change();
|
||||
$table->text('smtp_from_address')->nullable()->change();
|
||||
$table->text('smtp_from_name')->nullable()->change();
|
||||
$table->text('smtp_recipients')->nullable()->change();
|
||||
$table->text('smtp_host')->nullable()->change();
|
||||
$table->text('smtp_username')->nullable()->change();
|
||||
});
|
||||
|
||||
if (DB::table('instance_settings')->exists()) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('pushover_notification_settings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('team_id')->constrained()->cascadeOnDelete();
|
||||
|
||||
$table->boolean('pushover_enabled')->default(false);
|
||||
$table->text('pushover_user_key')->nullable();
|
||||
$table->text('pushover_api_token')->nullable();
|
||||
|
||||
$table->boolean('deployment_success_pushover_notifications')->default(false);
|
||||
$table->boolean('deployment_failure_pushover_notifications')->default(true);
|
||||
$table->boolean('status_change_pushover_notifications')->default(false);
|
||||
$table->boolean('backup_success_pushover_notifications')->default(false);
|
||||
$table->boolean('backup_failure_pushover_notifications')->default(true);
|
||||
$table->boolean('scheduled_task_success_pushover_notifications')->default(false);
|
||||
$table->boolean('scheduled_task_failure_pushover_notifications')->default(true);
|
||||
$table->boolean('docker_cleanup_success_pushover_notifications')->default(false);
|
||||
$table->boolean('docker_cleanup_failure_pushover_notifications')->default(true);
|
||||
$table->boolean('server_disk_usage_pushover_notifications')->default(true);
|
||||
$table->boolean('server_reachable_pushover_notifications')->default(false);
|
||||
$table->boolean('server_unreachable_pushover_notifications')->default(true);
|
||||
|
||||
$table->unique(['team_id']);
|
||||
});
|
||||
$teams = DB::table('teams')->get();
|
||||
|
||||
foreach ($teams as $team) {
|
||||
try {
|
||||
DB::table('pushover_notification_settings')->insert([
|
||||
'team_id' => $team->id,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Error creating pushover notification settings for existing teams: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('pushover_notification_settings');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('oauth_settings', function (Blueprint $table) {
|
||||
$table->string('base_url')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('oauth_settings', function (Blueprint $table) {
|
||||
$table->dropColumn('base_url');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if (DB::table('instance_settings')->exists()) {
|
||||
$settings = DB::table('instance_settings')->get();
|
||||
foreach ($settings as $setting) {
|
||||
try {
|
||||
DB::table('instance_settings')->where('id', $setting->id)->update([
|
||||
'resend_api_key' => $setting->resend_api_key ? Crypt::encryptString($setting->resend_api_key) : null,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
\Log::error('Error encrypting resend_api_key: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
if (DB::table('instance_settings')->exists()) {
|
||||
$settings = DB::table('instance_settings')->get();
|
||||
foreach ($settings as $setting) {
|
||||
try {
|
||||
DB::table('instance_settings')->where('id', $setting->id)->update([
|
||||
'resend_api_key' => $setting->resend_api_key ? Crypt::decryptString($setting->resend_api_key) : null,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
\Log::error('Error decrypting resend_api_key: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -4,6 +4,7 @@ namespace Database\Seeders;
|
|||
|
||||
use App\Models\OauthSetting;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class OauthSettingSeeder extends Seeder
|
||||
{
|
||||
|
|
@ -12,25 +13,53 @@ class OauthSettingSeeder extends Seeder
|
|||
*/
|
||||
public function run(): void
|
||||
{
|
||||
OauthSetting::firstOrCreate([
|
||||
'id' => 0,
|
||||
'provider' => 'azure',
|
||||
]);
|
||||
OauthSetting::firstOrCreate([
|
||||
'id' => 1,
|
||||
'provider' => 'bitbucket',
|
||||
]);
|
||||
OauthSetting::firstOrCreate([
|
||||
'id' => 2,
|
||||
'provider' => 'github',
|
||||
]);
|
||||
OauthSetting::firstOrCreate([
|
||||
'id' => 3,
|
||||
'provider' => 'gitlab',
|
||||
]);
|
||||
OauthSetting::firstOrCreate([
|
||||
'id' => 4,
|
||||
'provider' => 'google',
|
||||
]);
|
||||
try {
|
||||
$providers = collect([
|
||||
'azure',
|
||||
'bitbucket',
|
||||
'github',
|
||||
'gitlab',
|
||||
'google',
|
||||
'authentik',
|
||||
]);
|
||||
|
||||
$isOauthSeeded = OauthSetting::count() > 0;
|
||||
|
||||
// We changed how providers are defined in the database, so we authentik does not exists, we need to recreate all of the auth providers
|
||||
// Before authentik was a provider, providers started with 0 id
|
||||
|
||||
$isOauthAuthentik = OauthSetting::where('provider', 'authentik')->exists();
|
||||
if (! $isOauthSeeded || $isOauthAuthentik) {
|
||||
foreach ($providers as $provider) {
|
||||
OauthSetting::updateOrCreate([
|
||||
'provider' => $provider,
|
||||
]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$allProviders = OauthSetting::all();
|
||||
$notFoundProviders = $providers->diff($allProviders->pluck('provider'));
|
||||
|
||||
$allProviders->each(function ($provider) {
|
||||
$provider->delete();
|
||||
});
|
||||
$allProviders->each(function ($provider) {
|
||||
$provider = new OauthSetting;
|
||||
$provider->provider = $provider->provider;
|
||||
unset($provider->id);
|
||||
$provider->save();
|
||||
});
|
||||
|
||||
foreach ($notFoundProviders as $provider) {
|
||||
OauthSetting::create([
|
||||
'provider' => $provider,
|
||||
]);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ location ~ \.php$ {
|
|||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
fastcgi_buffers 8 8k;
|
||||
fastcgi_buffer_size 8k;
|
||||
fastcgi_buffers 16 16k;
|
||||
fastcgi_buffer_size 32k;
|
||||
fastcgi_read_timeout 99;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,3 +7,4 @@ ignore_repeated_source = On
|
|||
|
||||
upload_max_filesize = 256M
|
||||
post_max_size = 256M
|
||||
memory_limit = ${PHP_MEMORY_LIMIT:-256M}
|
||||
|
|
|
|||
|
|
@ -99,6 +99,9 @@ RUN mkdir -p /usr/local/bin && \
|
|||
COPY docker/production/etc/php/conf.d/zzz-custom-php.ini /usr/local/etc/php/conf.d/zzz-custom-php.ini
|
||||
ENV PHP_OPCACHE_ENABLE=1
|
||||
|
||||
# Configure entrypoint
|
||||
COPY --chmod=755 docker/production/entrypoint.d/ /etc/entrypoint.d
|
||||
|
||||
# Copy application files from previous stages
|
||||
COPY --from=base --chown=www-data:www-data /var/www/html/vendor ./vendor
|
||||
COPY --from=static-assets --chown=www-data:www-data /app/public/build ./public/build
|
||||
|
|
|
|||
8
docker/production/entrypoint.d/99-debug-mode.sh
Normal file
8
docker/production/entrypoint.d/99-debug-mode.sh
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Debug mode
|
||||
if [ "$APP_DEBUG" = "true" ]; then
|
||||
echo "Debug mode is enabled"
|
||||
echo "Installing development dependencies..."
|
||||
composer install --dev --no-scripts
|
||||
echo "Clearing optimized classes..."
|
||||
php artisan optimize:clear
|
||||
fi
|
||||
|
|
@ -39,7 +39,7 @@ location ~ \.php$ {
|
|||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
fastcgi_buffers 8 8k;
|
||||
fastcgi_buffer_size 8k;
|
||||
fastcgi_buffers 16 16k;
|
||||
fastcgi_buffer_size 32k;
|
||||
fastcgi_read_timeout 99;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,3 +7,4 @@ ignore_repeated_source = On
|
|||
|
||||
upload_max_filesize = 256M
|
||||
post_max_size = 256M
|
||||
memory_limit = ${PHP_MEMORY_LIMIT:-256M}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ cd /var/www/html
|
|||
foreground {
|
||||
php
|
||||
artisan
|
||||
migrate
|
||||
--force
|
||||
--isolated
|
||||
start:migration
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,7 @@ cd /var/www/html
|
|||
foreground {
|
||||
php
|
||||
artisan
|
||||
db:seed
|
||||
--class
|
||||
ProductionSeeder
|
||||
--force
|
||||
start:seeder
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"auth.login": "Login",
|
||||
"auth.login.authentik": "Login with Authentik",
|
||||
"auth.login.azure": "Login with Microsoft",
|
||||
"auth.login.bitbucket": "Login with Bitbucket",
|
||||
"auth.login.github": "Login with GitHub",
|
||||
|
|
|
|||
BIN
other/logos/internetgarden.ico
Normal file
BIN
other/logos/internetgarden.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
|
|
@ -13,6 +13,50 @@ DOCKER_VERSION="27.0"
|
|||
# TODO: Ask for a user
|
||||
CURRENT_USER=$USER
|
||||
|
||||
if [ $EUID != 0 ]; then
|
||||
echo "Please run this script as root or with sudo"
|
||||
exit
|
||||
fi
|
||||
|
||||
echo -e "Welcome to Coolify Installer!"
|
||||
echo -e "This script will install everything for you. Sit back and relax."
|
||||
echo -e "Source code: https://github.com/coollabsio/coolify/blob/main/scripts/install.sh\n"
|
||||
|
||||
TOTAL_SPACE=$(df -BG / | awk 'NR==2 {print $2}' | sed 's/G//')
|
||||
AVAILABLE_SPACE=$(df -BG / | awk 'NR==2 {print $4}' | sed 's/G//')
|
||||
REQUIRED_TOTAL_SPACE=30
|
||||
REQUIRED_AVAILABLE_SPACE=20
|
||||
WARNING_SPACE=false
|
||||
|
||||
if [ "$TOTAL_SPACE" -lt "$REQUIRED_TOTAL_SPACE" ]; then
|
||||
WARNING_SPACE=true
|
||||
cat << EOF
|
||||
WARNING: Insufficient total disk space!
|
||||
|
||||
Total disk space: ${TOTAL_SPACE}GB
|
||||
Required disk space: ${REQUIRED_TOTAL_SPACE}GB
|
||||
|
||||
==================
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "$AVAILABLE_SPACE" -lt "$REQUIRED_AVAILABLE_SPACE" ]; then
|
||||
cat << EOF
|
||||
WARNING: Insufficient available disk space!
|
||||
|
||||
Available disk space: ${AVAILABLE_SPACE}GB
|
||||
Required available space: ${REQUIRED_AVAILABLE_SPACE}GB
|
||||
|
||||
==================
|
||||
EOF
|
||||
WARNING_SPACE=true
|
||||
fi
|
||||
|
||||
if [ "$WARNING_SPACE" = true ]; then
|
||||
echo "Sleeping for 5 seconds."
|
||||
sleep 5
|
||||
fi
|
||||
|
||||
mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy,webhooks-during-maintenance,sentinel}
|
||||
mkdir -p /data/coolify/ssh/{keys,mux}
|
||||
mkdir -p /data/coolify/proxy/dynamic
|
||||
|
|
@ -39,6 +83,11 @@ if [ "$OS_TYPE" = "manjaro" ] || [ "$OS_TYPE" = "manjaro-arm" ]; then
|
|||
OS_TYPE="arch"
|
||||
fi
|
||||
|
||||
# Check if the OS is Endeavour OS, if so, change it to arch
|
||||
if [ "$OS_TYPE" = "endeavouros" ]; then
|
||||
OS_TYPE="arch"
|
||||
fi
|
||||
|
||||
# Check if the OS is Asahi Linux, if so, change it to fedora
|
||||
if [ "$OS_TYPE" = "fedora-asahi-remix" ]; then
|
||||
OS_TYPE="fedora"
|
||||
|
|
@ -83,11 +132,6 @@ if [ -z "$LATEST_REALTIME_VERSION" ]; then
|
|||
fi
|
||||
|
||||
|
||||
if [ $EUID != 0 ]; then
|
||||
echo "Please run as root"
|
||||
exit
|
||||
fi
|
||||
|
||||
case "$OS_TYPE" in
|
||||
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn | alpine) ;;
|
||||
*)
|
||||
|
|
@ -103,21 +147,8 @@ if [ "$1" != "" ]; then
|
|||
LATEST_VERSION="${LATEST_VERSION#v}"
|
||||
fi
|
||||
|
||||
echo -e "\033[0;35m"
|
||||
cat << "EOF"
|
||||
_____ _ _ __
|
||||
/ ____| | (_)/ _|
|
||||
| | ___ ___ | |_| |_ _ _
|
||||
| | / _ \ / _ \| | | _| | | |
|
||||
| |___| (_) | (_) | | | | | |_| |
|
||||
\_____\___/ \___/|_|_|_| \__, |
|
||||
__/ |
|
||||
|___/
|
||||
EOF
|
||||
echo -e "\033[0m"
|
||||
echo -e "Welcome to Coolify Installer!"
|
||||
echo -e "This script will install everything for you. Sit back and relax."
|
||||
echo -e "Source code: https://github.com/coollabsio/coolify/blob/main/scripts/install.sh\n"
|
||||
|
||||
|
||||
echo -e "---------------------------------------------"
|
||||
echo "| Operating System | $OS_TYPE $OS_VERSION"
|
||||
echo "| Docker | $DOCKER_VERSION"
|
||||
|
|
@ -125,24 +156,24 @@ echo "| Coolify | $LATEST_VERSION"
|
|||
echo "| Helper | $LATEST_HELPER_VERSION"
|
||||
echo "| Realtime | $LATEST_REALTIME_VERSION"
|
||||
echo -e "---------------------------------------------\n"
|
||||
echo -e "1. Installing required packages (curl, wget, git, jq). "
|
||||
echo -e "1. Installing required packages (curl, wget, git, jq, openssl). "
|
||||
|
||||
case "$OS_TYPE" in
|
||||
arch)
|
||||
pacman -Sy --noconfirm --needed curl wget git jq >/dev/null || true
|
||||
pacman -Sy --noconfirm --needed curl wget git jq openssl >/dev/null || true
|
||||
;;
|
||||
alpine)
|
||||
sed -i '/^#.*\/community/s/^#//' /etc/apk/repositories
|
||||
apk update >/dev/null
|
||||
apk add curl wget git jq >/dev/null
|
||||
apk add curl wget git jq openssl >/dev/null
|
||||
;;
|
||||
ubuntu | debian | raspbian)
|
||||
apt-get update -y >/dev/null
|
||||
apt-get install -y curl wget git jq >/dev/null
|
||||
apt-get install -y curl wget git jq openssl >/dev/null
|
||||
;;
|
||||
centos | fedora | rhel | ol | rocky | almalinux | amzn)
|
||||
if [ "$OS_TYPE" = "amzn" ]; then
|
||||
dnf install -y wget git jq >/dev/null
|
||||
dnf install -y wget git jq openssl >/dev/null
|
||||
else
|
||||
if ! command -v dnf >/dev/null; then
|
||||
yum install -y dnf >/dev/null
|
||||
|
|
@ -150,12 +181,12 @@ centos | fedora | rhel | ol | rocky | almalinux | amzn)
|
|||
if ! command -v curl >/dev/null; then
|
||||
dnf install -y curl >/dev/null
|
||||
fi
|
||||
dnf install -y wget git jq >/dev/null
|
||||
dnf install -y wget git jq openssl >/dev/null
|
||||
fi
|
||||
;;
|
||||
sles | opensuse-leap | opensuse-tumbleweed)
|
||||
zypper refresh >/dev/null
|
||||
zypper install -y curl wget git jq >/dev/null
|
||||
zypper install -y curl wget git jq openssl >/dev/null
|
||||
;;
|
||||
*)
|
||||
echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now."
|
||||
|
|
@ -300,6 +331,22 @@ if ! [ -x "$(command -v docker)" ]; then
|
|||
exit 1
|
||||
fi
|
||||
;;
|
||||
"fedora")
|
||||
if [ -x "$(command -v dnf5)" ]; then
|
||||
# dnf5 is available
|
||||
dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo --overwrite >/dev/null 2>&1
|
||||
else
|
||||
# dnf5 is not available, use dnf
|
||||
dnf config-manager --add-repo=https://download.docker.com/linux/fedora/docker-ce.repo >/dev/null 2>&1
|
||||
fi
|
||||
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1
|
||||
if ! [ -x "$(command -v docker)" ]; then
|
||||
echo " - Docker could not be installed automatically. Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||
exit 1
|
||||
fi
|
||||
systemctl start docker >/dev/null 2>&1
|
||||
systemctl enable docker >/dev/null 2>&1
|
||||
;;
|
||||
*)
|
||||
if [ "$OS_TYPE" = "ubuntu" ] && [ "$OS_VERSION" = "24.10" ]; then
|
||||
echo "Docker automated installation is not supported on Ubuntu 24.10 (non-LTS release)."
|
||||
|
|
@ -490,7 +537,21 @@ echo -e "\033[0;35m
|
|||
\____\___/|_| |_|\__, |_| \__,_|\__|\__,_|_|\__,_|\__|_|\___/|_| |_|___(_)
|
||||
|___/
|
||||
\033[0m"
|
||||
echo -e "\nYour instance is ready to use."
|
||||
echo -e "Please visit http://$(curl -4s https://ifconfig.io):8000 to get started.\n"
|
||||
echo -e "WARNING: We recommend you to backup your /data/coolify/source/.env file to a safe location, outside of this server."
|
||||
echo -e "\nYour instance is ready to use!\n"
|
||||
echo -e "You can access Coolify through your Public IP: http://$(curl -4s https://ifconfig.io):8000"
|
||||
|
||||
set +e
|
||||
DEFAULT_PRIVATE_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
|
||||
PRIVATE_IPS=$(hostname -I)
|
||||
set -e
|
||||
|
||||
if [ -n "$PRIVATE_IPS" ]; then
|
||||
echo -e "\nIf your Public IP is not accessible, you can use the following Private IPs:\n"
|
||||
for IP in $PRIVATE_IPS; do
|
||||
if [ "$IP" != "$DEFAULT_PRIVATE_IP" ]; then
|
||||
echo -e "http://$IP:8000"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
echo -e "\nWARNING: It is highly recommended to backup your Environment variables file (/data/coolify/source/.env) to a safe location, outside of this server (e.g. into a Password Manager).\n"
|
||||
cp /data/coolify/source/.env /data/coolify/source/.env.backup
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
{
|
||||
"coolify": {
|
||||
"v4": {
|
||||
"version": "4.0.0-beta.367"
|
||||
"version": "4.0.0-beta.378"
|
||||
},
|
||||
"nightly": {
|
||||
"version": "4.0.0-beta.368"
|
||||
"version": "4.0.0-beta.379"
|
||||
},
|
||||
"helper": {
|
||||
"version": "1.0.3"
|
||||
"version": "1.0.4"
|
||||
},
|
||||
"realtime": {
|
||||
"version": "1.0.4"
|
||||
"version": "1.0.5"
|
||||
},
|
||||
"sentinel": {
|
||||
"version": "0.0.15"
|
||||
|
|
|
|||
BIN
public/svgs/checkmate.png
Normal file
BIN
public/svgs/checkmate.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
BIN
public/svgs/documenso.png
Normal file
BIN
public/svgs/documenso.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
public/svgs/dolibarr.png
Normal file
BIN
public/svgs/dolibarr.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 191 KiB |
BIN
public/svgs/nexus.png
Normal file
BIN
public/svgs/nexus.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
|
|
@ -12,7 +12,7 @@
|
|||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||
<div class="p-6 space-y-4 md:space-y-3 sm:p-8">
|
||||
<form action="/login" method="POST" class="flex flex-col gap-2">
|
||||
@csrf
|
||||
@env('local')
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
monacoLoader: true,
|
||||
monacoFontSize: '15px',
|
||||
monacoId: $id('monaco-editor'),
|
||||
isDarkMode() {
|
||||
return document.documentElement.classList.contains('dark') || localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
},
|
||||
monacoEditor(editor) {
|
||||
editor.onDidChangeModelContent((e) => {
|
||||
this.monacoContent = editor.getValue();
|
||||
|
|
@ -41,357 +44,9 @@
|
|||
let proxy = URL.createObjectURL(new Blob([` self.MonacoEnvironment = { baseUrl: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.39.0/min' }; importScripts('https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.39.0/min/vs/base/worker/workerMain.min.js');`], { type: 'text/javascript' }));
|
||||
window.MonacoEnvironment = { getWorkerUrl: () => proxy };
|
||||
require(['vs/editor/editor.main'], () => {
|
||||
monaco.editor.defineTheme('blackboard', {
|
||||
'base': 'vs-dark',
|
||||
'inherit': true,
|
||||
'rules': [{
|
||||
'background': editorBackground,
|
||||
'token': ''
|
||||
},
|
||||
{
|
||||
'foreground': '959da5',
|
||||
'token': 'comment'
|
||||
},
|
||||
{
|
||||
'foreground': '959da5',
|
||||
'token': 'punctuation.definition.comment'
|
||||
},
|
||||
{
|
||||
'foreground': '959da5',
|
||||
'token': 'string.comment'
|
||||
},
|
||||
{
|
||||
'foreground': 'c8e1ff',
|
||||
'token': 'constant'
|
||||
},
|
||||
{
|
||||
'foreground': 'c8e1ff',
|
||||
'token': 'entity.name.constant'
|
||||
},
|
||||
{
|
||||
'foreground': 'c8e1ff',
|
||||
'token': 'variable.other.constant'
|
||||
},
|
||||
{
|
||||
'foreground': 'c8e1ff',
|
||||
'token': 'variable.language'
|
||||
},
|
||||
{
|
||||
'foreground': 'b392f0',
|
||||
'token': 'entity'
|
||||
},
|
||||
{
|
||||
'foreground': 'b392f0',
|
||||
'token': 'entity.name'
|
||||
},
|
||||
{
|
||||
'foreground': 'f6f8fa',
|
||||
'token': 'variable.parameter.function'
|
||||
},
|
||||
{
|
||||
'foreground': '7bcc72',
|
||||
'token': 'entity.name.tag'
|
||||
},
|
||||
{
|
||||
'foreground': 'ea4a5a',
|
||||
'token': 'keyword'
|
||||
},
|
||||
{
|
||||
'foreground': 'ea4a5a',
|
||||
'token': 'storage'
|
||||
},
|
||||
{
|
||||
'foreground': 'ea4a5a',
|
||||
'token': 'storage.type'
|
||||
},
|
||||
{
|
||||
'foreground': 'f6f8fa',
|
||||
'token': 'storage.modifier.package'
|
||||
},
|
||||
{
|
||||
'foreground': 'f6f8fa',
|
||||
'token': 'storage.modifier.import'
|
||||
},
|
||||
{
|
||||
'foreground': 'f6f8fa',
|
||||
'token': 'storage.type.java'
|
||||
},
|
||||
{
|
||||
'foreground': '79b8ff',
|
||||
'token': 'string'
|
||||
},
|
||||
{
|
||||
'foreground': '79b8ff',
|
||||
'token': 'punctuation.definition.string'
|
||||
},
|
||||
{
|
||||
'foreground': '79b8ff',
|
||||
'token': 'string punctuation.section.embedded source'
|
||||
},
|
||||
{
|
||||
'foreground': 'c8e1ff',
|
||||
'token': 'support'
|
||||
},
|
||||
{
|
||||
'foreground': 'c8e1ff',
|
||||
'token': 'meta.property-name'
|
||||
},
|
||||
{
|
||||
'foreground': 'fb8532',
|
||||
'token': 'variable'
|
||||
},
|
||||
{
|
||||
'foreground': 'f6f8fa',
|
||||
'token': 'variable.other'
|
||||
},
|
||||
{
|
||||
'foreground': 'd73a49',
|
||||
'fontStyle': 'bold italic underline',
|
||||
'token': 'invalid.broken'
|
||||
},
|
||||
{
|
||||
'foreground': 'd73a49',
|
||||
'fontStyle': 'bold italic underline',
|
||||
'token': 'invalid.deprecated'
|
||||
},
|
||||
{
|
||||
'foreground': 'fafbfc',
|
||||
'background': 'd73a49',
|
||||
'fontStyle': 'italic underline',
|
||||
'token': 'invalid.illegal'
|
||||
},
|
||||
{
|
||||
'foreground': 'fafbfc',
|
||||
'background': 'd73a49',
|
||||
'fontStyle': 'italic underline',
|
||||
'token': 'carriage-return'
|
||||
},
|
||||
{
|
||||
'foreground': 'd73a49',
|
||||
'fontStyle': 'bold italic underline',
|
||||
'token': 'invalid.unimplemented'
|
||||
},
|
||||
{
|
||||
'foreground': 'd73a49',
|
||||
'token': 'message.error'
|
||||
},
|
||||
{
|
||||
'foreground': 'f6f8fa',
|
||||
'token': 'string source'
|
||||
},
|
||||
{
|
||||
'foreground': 'c8e1ff',
|
||||
'token': 'string variable'
|
||||
},
|
||||
{
|
||||
'foreground': '79b8ff',
|
||||
'token': 'source.regexp'
|
||||
},
|
||||
{
|
||||
'foreground': '79b8ff',
|
||||
'token': 'string.regexp'
|
||||
},
|
||||
{
|
||||
'foreground': '79b8ff',
|
||||
'token': 'string.regexp.character-class'
|
||||
},
|
||||
{
|
||||
'foreground': '79b8ff',
|
||||
'token': 'string.regexp constant.character.escape'
|
||||
},
|
||||
{
|
||||
'foreground': '79b8ff',
|
||||
'token': 'string.regexp source.ruby.embedded'
|
||||
},
|
||||
{
|
||||
'foreground': '79b8ff',
|
||||
'token': 'string.regexp string.regexp.arbitrary-repitition'
|
||||
},
|
||||
{
|
||||
'foreground': '7bcc72',
|
||||
'fontStyle': 'bold',
|
||||
'token': 'string.regexp constant.character.escape'
|
||||
},
|
||||
{
|
||||
'foreground': 'c8e1ff',
|
||||
'token': 'support.constant'
|
||||
},
|
||||
{
|
||||
'foreground': 'c8e1ff',
|
||||
'token': 'support.variable'
|
||||
},
|
||||
{
|
||||
'foreground': 'c8e1ff',
|
||||
'token': 'meta.module-reference'
|
||||
},
|
||||
{
|
||||
'foreground': 'fb8532',
|
||||
'token': 'markup.list'
|
||||
},
|
||||
{
|
||||
'foreground': '0366d6',
|
||||
'fontStyle': 'bold',
|
||||
'token': 'markup.heading'
|
||||
},
|
||||
{
|
||||
'foreground': '0366d6',
|
||||
'fontStyle': 'bold',
|
||||
'token': 'markup.heading entity.name'
|
||||
},
|
||||
{
|
||||
'foreground': 'c8e1ff',
|
||||
'token': 'markup.quote'
|
||||
},
|
||||
{
|
||||
'foreground': 'f6f8fa',
|
||||
'fontStyle': 'italic',
|
||||
'token': 'markup.italic'
|
||||
},
|
||||
{
|
||||
'foreground': 'f6f8fa',
|
||||
'fontStyle': 'bold',
|
||||
'token': 'markup.bold'
|
||||
},
|
||||
{
|
||||
'foreground': 'c8e1ff',
|
||||
'token': 'markup.raw'
|
||||
},
|
||||
{
|
||||
'foreground': 'b31d28',
|
||||
'background': 'ffeef0',
|
||||
'token': 'markup.deleted'
|
||||
},
|
||||
{
|
||||
'foreground': 'b31d28',
|
||||
'background': 'ffeef0',
|
||||
'token': 'meta.diff.header.from-file'
|
||||
},
|
||||
{
|
||||
'foreground': 'b31d28',
|
||||
'background': 'ffeef0',
|
||||
'token': 'punctuation.definition.deleted'
|
||||
},
|
||||
{
|
||||
'foreground': '176f2c',
|
||||
'background': 'f0fff4',
|
||||
'token': 'markup.inserted'
|
||||
},
|
||||
{
|
||||
'foreground': '176f2c',
|
||||
'background': 'f0fff4',
|
||||
'token': 'meta.diff.header.to-file'
|
||||
},
|
||||
{
|
||||
'foreground': '176f2c',
|
||||
'background': 'f0fff4',
|
||||
'token': 'punctuation.definition.inserted'
|
||||
},
|
||||
{
|
||||
'foreground': 'b08800',
|
||||
'background': 'fffdef',
|
||||
'token': 'markup.changed'
|
||||
},
|
||||
{
|
||||
'foreground': 'b08800',
|
||||
'background': 'fffdef',
|
||||
'token': 'punctuation.definition.changed'
|
||||
},
|
||||
{
|
||||
'foreground': '2f363d',
|
||||
'background': '959da5',
|
||||
'token': 'markup.ignored'
|
||||
},
|
||||
{
|
||||
'foreground': '2f363d',
|
||||
'background': '959da5',
|
||||
'token': 'markup.untracked'
|
||||
},
|
||||
{
|
||||
'foreground': 'b392f0',
|
||||
'fontStyle': 'bold',
|
||||
'token': 'meta.diff.range'
|
||||
},
|
||||
{
|
||||
'foreground': 'c8e1ff',
|
||||
'token': 'meta.diff.header'
|
||||
},
|
||||
{
|
||||
'foreground': '0366d6',
|
||||
'fontStyle': 'bold',
|
||||
'token': 'meta.separator'
|
||||
},
|
||||
{
|
||||
'foreground': '0366d6',
|
||||
'token': 'meta.output'
|
||||
},
|
||||
{
|
||||
'foreground': 'ffeef0',
|
||||
'token': 'brackethighlighter.tag'
|
||||
},
|
||||
{
|
||||
'foreground': 'ffeef0',
|
||||
'token': 'brackethighlighter.curly'
|
||||
},
|
||||
{
|
||||
'foreground': 'ffeef0',
|
||||
'token': 'brackethighlighter.round'
|
||||
},
|
||||
{
|
||||
'foreground': 'ffeef0',
|
||||
'token': 'brackethighlighter.square'
|
||||
},
|
||||
{
|
||||
'foreground': 'ffeef0',
|
||||
'token': 'brackethighlighter.angle'
|
||||
},
|
||||
{
|
||||
'foreground': 'ffeef0',
|
||||
'token': 'brackethighlighter.quote'
|
||||
},
|
||||
{
|
||||
'foreground': 'd73a49',
|
||||
'token': 'brackethighlighter.unmatched'
|
||||
},
|
||||
{
|
||||
'foreground': 'd73a49',
|
||||
'token': 'sublimelinter.mark.error'
|
||||
},
|
||||
{
|
||||
'foreground': 'fb8532',
|
||||
'token': 'sublimelinter.mark.warning'
|
||||
},
|
||||
{
|
||||
'foreground': '6a737d',
|
||||
'token': 'sublimelinter.gutter-mark'
|
||||
},
|
||||
{
|
||||
'foreground': '79b8ff',
|
||||
'fontStyle': 'underline',
|
||||
'token': 'constant.other.reference.link'
|
||||
},
|
||||
{
|
||||
'foreground': '79b8ff',
|
||||
'fontStyle': 'underline',
|
||||
'token': 'string.other.link'
|
||||
}
|
||||
],
|
||||
'colors': {
|
||||
'editor.foreground': '#f6f8fa',
|
||||
'editor.background': editorBackground,
|
||||
'editor.selectionBackground': '#4c2889',
|
||||
'editor.inactiveSelectionBackground': '#444d56',
|
||||
'editor.lineHighlightBackground': '#444d56',
|
||||
'editorCursor.foreground': '#ffffff',
|
||||
'editorWhitespace.foreground': '#6a737d',
|
||||
'editorIndentGuide.background': '#6a737d',
|
||||
'editorIndentGuide.activeBackground': '#f6f8fa',
|
||||
'editor.selectionHighlightBorder': '#444d56'
|
||||
}
|
||||
});
|
||||
|
||||
const editor = monaco.editor.create($refs.monacoEditorElement, {
|
||||
value: monacoContent,
|
||||
theme: editorTheme,
|
||||
theme: document.documentElement.classList.contains('dark') ? 'vs-dark' : 'vs',
|
||||
wordWrap: 'on',
|
||||
readOnly: '{{ $readonly ?? false }}',
|
||||
minimap: { enabled: false },
|
||||
|
|
@ -399,7 +54,20 @@
|
|||
lineNumbersMinChars: 3,
|
||||
automaticLayout: true,
|
||||
language: '{{ $language }}'
|
||||
});
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.attributeName === 'class') {
|
||||
const isDark = document.documentElement.classList.contains('dark');
|
||||
monaco.editor.setTheme(isDark ? 'vs-dark' : 'vs');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
observer.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['class']
|
||||
});
|
||||
|
||||
monacoEditor(editor);
|
||||
|
|
@ -411,7 +79,6 @@
|
|||
|
||||
updatePlaceholder(editor.getValue());
|
||||
|
||||
// Watch for changes in monacoContent from Livewire
|
||||
$watch('monacoContent', value => {
|
||||
if (editor.getValue() !== value) {
|
||||
editor.setValue(value);
|
||||
|
|
|
|||
|
|
@ -258,6 +258,7 @@
|
|||
<input type="text" x-model="confirmationText"
|
||||
class="p-2 pr-10 w-full text-black rounded cursor-text input" readonly>
|
||||
<button @click="copyConfirmationText()"
|
||||
x-show="window.isSecureContext"
|
||||
class="absolute right-2 top-1/2 text-gray-500 transform -translate-y-1/2 hover:text-gray-700"
|
||||
title="Copy confirmation text" x-ref="copyButton">
|
||||
<template x-if="!copied">
|
||||
|
|
|
|||
|
|
@ -340,17 +340,19 @@
|
|||
</li>
|
||||
@endif
|
||||
|
||||
@if (isCloud() && isInstanceAdmin())
|
||||
<li>
|
||||
<a title="Admin" class="menu-item" href="/admin">
|
||||
<svg class="text-pink-600 icon" viewBox="0 0 256 256"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor"
|
||||
d="M177.62 159.6a52 52 0 0 1-34 34a12.2 12.2 0 0 1-3.6.55a12 12 0 0 1-3.6-23.45a28 28 0 0 0 18.32-18.32a12 12 0 0 1 22.9 7.2ZM220 144a92 92 0 0 1-184 0c0-28.81 11.27-58.18 33.48-87.28a12 12 0 0 1 17.9-1.33l19.69 19.11L127 19.89a12 12 0 0 1 18.94-5.12C168.2 33.25 220 82.85 220 144m-24 0c0-41.71-30.61-78.39-52.52-99.29l-20.21 55.4a12 12 0 0 1-19.63 4.5L80.71 82.36C67 103.38 60 124.06 60 144a68 68 0 0 0 136 0" />
|
||||
</svg>
|
||||
Admin
|
||||
</a>
|
||||
</li>
|
||||
@if (isCloud() || isDev())
|
||||
@if (isInstanceAdmin() || session('impersonating'))
|
||||
<li>
|
||||
<a title="Admin" class="menu-item" href="/admin">
|
||||
<svg class="text-pink-600 icon" viewBox="0 0 256 256"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor"
|
||||
d="M177.62 159.6a52 52 0 0 1-34 34a12.2 12.2 0 0 1-3.6.55a12 12 0 0 1-3.6-23.45a28 28 0 0 0 18.32-18.32a12 12 0 0 1 22.9 7.2ZM220 144a92 92 0 0 1-184 0c0-28.81 11.27-58.18 33.48-87.28a12 12 0 0 1 17.9-1.33l19.69 19.11L127 19.89a12 12 0 0 1 18.94-5.12C168.2 33.25 220 82.85 220 144m-24 0c0-41.71-30.61-78.39-52.52-99.29l-20.21 55.4a12 12 0 0 1-19.63 4.5L80.71 82.36C67 103.38 60 124.06 60 144a68 68 0 0 0 136 0" />
|
||||
</svg>
|
||||
Admin
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
@endif
|
||||
<div class="flex-1"></div>
|
||||
@if (isInstanceAdmin() && !isCloud())
|
||||
|
|
|
|||
|
|
@ -7,18 +7,22 @@
|
|||
href="{{ route('notifications.email') }}">
|
||||
<button>Email</button>
|
||||
</a>
|
||||
<a class="{{ request()->routeIs('notifications.telegram') ? 'dark:text-white' : '' }}"
|
||||
href="{{ route('notifications.telegram') }}">
|
||||
<button>Telegram</button>
|
||||
</a>
|
||||
<a class="{{ request()->routeIs('notifications.discord') ? 'dark:text-white' : '' }}"
|
||||
href="{{ route('notifications.discord') }}">
|
||||
<button>Discord</button>
|
||||
</a>
|
||||
<a class="{{ request()->routeIs('notifications.telegram') ? 'dark:text-white' : '' }}"
|
||||
href="{{ route('notifications.telegram') }}">
|
||||
<button>Telegram</button>
|
||||
</a>
|
||||
<a class="{{ request()->routeIs('notifications.slack') ? 'dark:text-white' : '' }}"
|
||||
href="{{ route('notifications.slack') }}">
|
||||
<button>Slack</button>
|
||||
</a>
|
||||
<a class="{{ request()->routeIs('notifications.pushover') ? 'dark:text-white' : '' }}"
|
||||
href="{{ route('notifications.pushover') }}">
|
||||
<button>Pushover</button>
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
<div>
|
||||
<h1>Admin Dashboard</h1>
|
||||
<h3 class="pt-4">Who am I now?</h3>
|
||||
<div class="pb-4">{{ auth()->user()->name }}</div>
|
||||
<div class="flex gap-2 pt-4">
|
||||
<h3>Who am I now?</h3>
|
||||
@if (session('impersonating'))
|
||||
<x-forms.button wire:click="back">Go back to root</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
<div class="pb-4">{{ auth()->user()->name }} ({{ auth()->user()->email }})</div>
|
||||
<form wire:submit="submitSearch" class="flex flex-col gap-2 lg:flex-row">
|
||||
<x-forms.input wire:model="search" placeholder="Search for a user" />
|
||||
<x-forms.button type="submit">Search</x-forms.button>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
<x-forms.checkbox instantSave="instantSaveDiscordEnabled" id="discordEnabled" label="Enabled" />
|
||||
</div>
|
||||
<x-forms.input type="password"
|
||||
helper="Generate a webhook in Discord.<br>Example: https://discord.com/api/webhooks/...." required
|
||||
helper="Create a Discord Server and generate a Webhook URL. <br><a class='inline-block underline dark:text-white' href='https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks' target='_blank'>Webhook Documentation</a>" required
|
||||
id="discordWebhookUrl" label="Webhook" />
|
||||
</form>
|
||||
<h2 class="mt-4">Notification Settings</h2>
|
||||
|
|
|
|||
86
resources/views/livewire/notifications/pushover.blade.php
Normal file
86
resources/views/livewire/notifications/pushover.blade.php
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<div>
|
||||
<x-slot:title>
|
||||
Notifications | Coolify
|
||||
</x-slot>
|
||||
<x-notification.navbar />
|
||||
<form wire:submit='submit' class="flex flex-col gap-4 pb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2>Pushover</h2>
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
@if ($pushoverEnabled)
|
||||
<x-forms.button class="normal-case dark:text-white btn btn-xs no-animation btn-primary"
|
||||
wire:click="sendTestNotification">
|
||||
Send Test Notification
|
||||
</x-forms.button>
|
||||
@else
|
||||
<x-forms.button disabled class="normal-case dark:text-white btn btn-xs no-animation btn-primary">
|
||||
Send Test Notification
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
<div class="w-32">
|
||||
<x-forms.checkbox instantSave="instantSavePushoverEnabled" id="pushoverEnabled" label="Enabled" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input type="password"
|
||||
helper="Get your User Key in Pushover. You need to be logged in to Pushover to see your user key in the top right corner. <br><a class='inline-block underline dark:text-white' href='https://pushover.net/' target='_blank'>Pushover Dashboard</a>"
|
||||
required id="pushoverUserKey" label="User Key" />
|
||||
<x-forms.input type="password"
|
||||
helper="Generate an API Token/Key in Pushover by creating a new application. <br><a class='inline-block underline dark:text-white' href='https://pushover.net/apps/build' target='_blank'>Create Pushover Application</a>"
|
||||
required id="pushoverApiToken" label="API Token" />
|
||||
</div>
|
||||
</form>
|
||||
<h2 class="mt-4">Notification Settings</h2>
|
||||
<p class="mb-4">
|
||||
Select events for which you would like to receive Pushover notifications.
|
||||
</p>
|
||||
<div class="flex flex-col gap-4 max-w-2xl">
|
||||
<div class="border dark:border-coolgray-300 p-4 rounded-lg">
|
||||
<h3 class="font-medium mb-3">Deployments</h3>
|
||||
<div class="flex flex-col gap-1.5 pl-1">
|
||||
<x-forms.checkbox instantSave="saveModel" id="deploymentSuccessPushoverNotifications"
|
||||
label="Deployment Success" />
|
||||
<x-forms.checkbox instantSave="saveModel" id="deploymentFailurePushoverNotifications"
|
||||
label="Deployment Failure" />
|
||||
<x-forms.checkbox instantSave="saveModel"
|
||||
helper="Send a notification when a container status changes. It will notify for Stopped and Restarted events of a container."
|
||||
id="statusChangePushoverNotifications" label="Container Status Changes" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="border dark:border-coolgray-300 p-4 rounded-lg">
|
||||
<h3 class="font-medium mb-3">Backups</h3>
|
||||
<div class="flex flex-col gap-1.5 pl-1">
|
||||
<x-forms.checkbox instantSave="saveModel" id="backupSuccessPushoverNotifications"
|
||||
label="Backup Success" />
|
||||
<x-forms.checkbox instantSave="saveModel" id="backupFailurePushoverNotifications"
|
||||
label="Backup Failure" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="border dark:border-coolgray-300 p-4 rounded-lg">
|
||||
<h3 class="font-medium mb-3">Scheduled Tasks</h3>
|
||||
<div class="flex flex-col gap-1.5 pl-1">
|
||||
<x-forms.checkbox instantSave="saveModel" id="scheduledTaskSuccessPushoverNotifications"
|
||||
label="Scheduled Task Success" />
|
||||
<x-forms.checkbox instantSave="saveModel" id="scheduledTaskFailurePushoverNotifications"
|
||||
label="Scheduled Task Failure" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="border dark:border-coolgray-300 p-4 rounded-lg">
|
||||
<h3 class="font-medium mb-3">Server</h3>
|
||||
<div class="flex flex-col gap-1.5 pl-1">
|
||||
<x-forms.checkbox instantSave="saveModel" id="dockerCleanupSuccessPushoverNotifications"
|
||||
label="Docker Cleanup Success" />
|
||||
<x-forms.checkbox instantSave="saveModel" id="dockerCleanupFailurePushoverNotifications"
|
||||
label="Docker Cleanup Failure" />
|
||||
<x-forms.checkbox instantSave="saveModel" id="serverDiskUsagePushoverNotifications"
|
||||
label="Server Disk Usage" />
|
||||
<x-forms.checkbox instantSave="saveModel" id="serverReachablePushoverNotifications"
|
||||
label="Server Reachable" />
|
||||
<x-forms.checkbox instantSave="saveModel" id="serverUnreachablePushoverNotifications"
|
||||
label="Server Unreachable" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
<x-forms.checkbox instantSave="instantSaveSlackEnabled" id="slackEnabled" label="Enabled" />
|
||||
</div>
|
||||
<x-forms.input type="password"
|
||||
helper="Generate a webhook in Slack.<br>Example: https://hooks.slack.com/services/...." required
|
||||
helper="Create a Slack APP and generate a Incoming Webhook URL. <br><a class='inline-block underline dark:text-white' href='https://api.slack.com/apps' target='_blank'>Create Slack APP</a>" required
|
||||
id="slackWebhookUrl" label="Webhook" />
|
||||
</form>
|
||||
<h2 class="mt-4">Notification Settings</h2>
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@
|
|||
<div class="flex gap-2">
|
||||
<x-forms.input type="password" autocomplete="new-password"
|
||||
helper="Get it from the <a class='inline-block underline dark:text-white' href='https://t.me/botfather' target='_blank'>BotFather Bot</a> on Telegram."
|
||||
required id="telegramToken" label="Token" />
|
||||
<x-forms.input helper="Recommended to add your bot to a group chat and add its Chat ID here." required
|
||||
required id="telegramToken" label="Bot API Token" />
|
||||
<x-forms.input type="password" autocomplete="new-password" helper="Add your bot to a group chat and add its Chat ID here." required
|
||||
id="telegramChatId" label="Chat ID" />
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -44,16 +44,16 @@
|
|||
<x-forms.checkbox instantSave="saveModel" id="deploymentSuccessTelegramNotifications"
|
||||
label="Deployment Success" />
|
||||
</div>
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Topic ID"
|
||||
id="telegramNotificationsDeploymentSuccessTopicId" />
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Thread ID"
|
||||
id="telegramNotificationsDeploymentSuccessThreadId" />
|
||||
</div>
|
||||
<div class="pl-1 flex gap-2">
|
||||
<div class="w-96">
|
||||
<x-forms.checkbox instantSave="saveModel" id="deploymentFailureTelegramNotifications"
|
||||
label="Deployment Failure" />
|
||||
</div>
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Topic ID"
|
||||
id="telegramNotificationsDeploymentFailureTopicId" />
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Thread ID"
|
||||
id="telegramNotificationsDeploymentFailureThreadId" />
|
||||
</div>
|
||||
<div class="pl-1 flex gap-2">
|
||||
<div class="w-96">
|
||||
|
|
@ -61,8 +61,8 @@
|
|||
label="Container Status Changes"
|
||||
helper="Send a notification when a container status changes. It will send a notification for Stopped and Restarted events of a container." />
|
||||
</div>
|
||||
<x-forms.input type="password" id="telegramNotificationsStatusChangeTopicId"
|
||||
placeholder="Custom Telegram Topic ID" />
|
||||
<x-forms.input type="password" id="telegramNotificationsStatusChangeThreadId"
|
||||
placeholder="Custom Telegram Thread ID" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -74,8 +74,8 @@
|
|||
<x-forms.checkbox instantSave="saveModel" id="backupSuccessTelegramNotifications"
|
||||
label="Backup Success" />
|
||||
</div>
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Topic ID"
|
||||
id="telegramNotificationsBackupSuccessTopicId" />
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Thread ID"
|
||||
id="telegramNotificationsBackupSuccessThreadId" />
|
||||
</div>
|
||||
|
||||
<div class="pl-1 flex gap-2">
|
||||
|
|
@ -83,8 +83,8 @@
|
|||
<x-forms.checkbox instantSave="saveModel" id="backupFailureTelegramNotifications"
|
||||
label="Backup Failure" />
|
||||
</div>
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Topic ID"
|
||||
id="telegramNotificationsBackupFailureTopicId" />
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Thread ID"
|
||||
id="telegramNotificationsBackupFailureThreadId" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -97,8 +97,8 @@
|
|||
<x-forms.checkbox instantSave="saveModel" id="scheduledTaskSuccessTelegramNotifications"
|
||||
label="Scheduled Task Success" />
|
||||
</div>
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Topic ID"
|
||||
id="telegramNotificationsScheduledTaskSuccessTopicId" />
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Thread ID"
|
||||
id="telegramNotificationsScheduledTaskSuccessThreadId" />
|
||||
</div>
|
||||
|
||||
<div class="pl-1 flex gap-2">
|
||||
|
|
@ -106,8 +106,8 @@
|
|||
<x-forms.checkbox instantSave="saveModel" id="scheduledTaskFailureTelegramNotifications"
|
||||
label="Scheduled Task Failure" />
|
||||
</div>
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Topic ID"
|
||||
id="telegramNotificationsScheduledTaskFailureTopicId" />
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Thread ID"
|
||||
id="telegramNotificationsScheduledTaskFailureThreadId" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -120,8 +120,8 @@
|
|||
<x-forms.checkbox instantSave="saveModel" id="dockerCleanupSuccessTelegramNotifications"
|
||||
label="Docker Cleanup Success" />
|
||||
</div>
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Topic ID"
|
||||
id="telegramNotificationsDockerCleanupSuccessTopicId" />
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Thread ID"
|
||||
id="telegramNotificationsDockerCleanupSuccessThreadId" />
|
||||
</div>
|
||||
|
||||
<div class="pl-1 flex gap-2">
|
||||
|
|
@ -129,8 +129,8 @@
|
|||
<x-forms.checkbox instantSave="saveModel" id="dockerCleanupFailureTelegramNotifications"
|
||||
label="Docker Cleanup Failure" />
|
||||
</div>
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Topic ID"
|
||||
id="telegramNotificationsDockerCleanupFailureTopicId" />
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Thread ID"
|
||||
id="telegramNotificationsDockerCleanupFailureThreadId" />
|
||||
</div>
|
||||
|
||||
<div class="pl-1 flex gap-2">
|
||||
|
|
@ -138,8 +138,8 @@
|
|||
<x-forms.checkbox instantSave="saveModel" id="serverDiskUsageTelegramNotifications"
|
||||
label="Server Disk Usage" />
|
||||
</div>
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Topic ID"
|
||||
id="telegramNotificationsServerDiskUsageTopicId" />
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Thread ID"
|
||||
id="telegramNotificationsServerDiskUsageThreadId" />
|
||||
</div>
|
||||
|
||||
<div class="pl-1 flex gap-2">
|
||||
|
|
@ -147,8 +147,8 @@
|
|||
<x-forms.checkbox instantSave="saveModel" id="serverReachableTelegramNotifications"
|
||||
label="Server Reachable" />
|
||||
</div>
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Topic ID"
|
||||
id="telegramNotificationsServerReachableTopicId" />
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Thread ID"
|
||||
id="telegramNotificationsServerReachableThreadId" />
|
||||
</div>
|
||||
|
||||
|
||||
|
|
@ -157,8 +157,8 @@
|
|||
<x-forms.checkbox instantSave="saveModel" id="serverUnreachableTelegramNotifications"
|
||||
label="Server Unreachable" />
|
||||
</div>
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Topic ID"
|
||||
id="telegramNotificationsServerUnreachableTopicId" />
|
||||
<x-forms.input type="password" placeholder="Custom Telegram Thread ID"
|
||||
id="telegramNotificationsServerUnreachableThreadId" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
class="font-mono pr-10"
|
||||
/>
|
||||
<button
|
||||
x-show="window.isSecureContext"
|
||||
@click="navigator.clipboard.writeText(secretKey); copiedSecretKey = true; setTimeout(() => copiedSecretKey = false, 2000)"
|
||||
class="absolute right-2 bottom-1 p-1 rounded hover:bg-gray-200 dark:hover:bg-gray-700"
|
||||
>
|
||||
|
|
@ -78,6 +79,7 @@
|
|||
class="font-mono pr-10"
|
||||
/>
|
||||
<button
|
||||
x-show="window.isSecureContext"
|
||||
@click="navigator.clipboard.writeText(otpUrl); copiedOtpUrl = true; setTimeout(() => copiedOtpUrl = false, 2000)"
|
||||
class="absolute right-2 bottom-1 p-1 rounded hover:bg-gray-200 dark:hover:bg-gray-700"
|
||||
>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue