mirror of
https://github.com/coollabsio/coolify.git
synced 2026-03-11 08:55:47 +00:00
Merge branch 'next' into fix-amd-on-arm-and-dep
This commit is contained in:
commit
25f5989933
159 changed files with 4741 additions and 2872 deletions
|
|
@ -3,7 +3,6 @@
|
|||
/public/build
|
||||
/public/hot
|
||||
/public/storage
|
||||
/storage/*.key
|
||||
/vendor
|
||||
.env
|
||||
.env.backup
|
||||
|
|
@ -25,3 +24,15 @@ yarn-error.log
|
|||
.ignition.json
|
||||
.env.dusk.local
|
||||
docker/coolify-realtime/node_modules
|
||||
|
||||
/storage/*.key
|
||||
/storage/app/backups
|
||||
/storage/app/ssh/keys
|
||||
/storage/app/ssh/mux
|
||||
/storage/app/tmp
|
||||
/storage/app/debugbar
|
||||
/storage/logs
|
||||
/storage/pail
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ jobs:
|
|||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/prod/Dockerfile
|
||||
file: docker/production/Dockerfile
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: |
|
||||
|
|
@ -82,7 +82,7 @@ jobs:
|
|||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/prod/Dockerfile
|
||||
file: docker/production/Dockerfile
|
||||
platforms: linux/aarch64
|
||||
push: true
|
||||
tags: |
|
||||
|
|
|
|||
4
.github/workflows/coolify-staging-build.yml
vendored
4
.github/workflows/coolify-staging-build.yml
vendored
|
|
@ -42,7 +42,7 @@ jobs:
|
|||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/prod/Dockerfile
|
||||
file: docker/production/Dockerfile
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: |
|
||||
|
|
@ -75,7 +75,7 @@ jobs:
|
|||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/prod/Dockerfile
|
||||
file: docker/production/Dockerfile
|
||||
platforms: linux/aarch64
|
||||
push: true
|
||||
tags: |
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ class CleanupUnreachableServers extends Command
|
|||
if ($servers->count() > 0) {
|
||||
foreach ($servers as $server) {
|
||||
echo "Cleanup unreachable server ($server->id) with name $server->name";
|
||||
// send_internal_notification("Server $server->name is unreachable for 7 days. Cleaning up...");
|
||||
$server->update([
|
||||
'ip' => '1.2.3.4',
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,5 @@ class Dev extends Command
|
|||
} else {
|
||||
echo "Instance already initialized.\n";
|
||||
}
|
||||
// Set permissions
|
||||
Process::run(['chmod', '-R', 'o+rwx', '.']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,12 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Jobs\SendConfirmationForWaitlistJob;
|
||||
use App\Models\Application;
|
||||
use App\Models\ApplicationPreview;
|
||||
use App\Models\ScheduledDatabaseBackup;
|
||||
use App\Models\Server;
|
||||
use App\Models\StandalonePostgresql;
|
||||
use App\Models\Team;
|
||||
use App\Models\Waitlist;
|
||||
use App\Notifications\Application\DeploymentFailed;
|
||||
use App\Notifications\Application\DeploymentSuccess;
|
||||
use App\Notifications\Application\StatusChanged;
|
||||
|
|
@ -64,8 +62,6 @@ class Emails extends Command
|
|||
'backup-success' => 'Database - Backup Success',
|
||||
'backup-failed' => 'Database - Backup Failed',
|
||||
// 'invitation-link' => 'Invitation Link',
|
||||
'waitlist-invitation-link' => 'Waitlist Invitation Link',
|
||||
'waitlist-confirmation' => 'Waitlist Confirmation',
|
||||
'realusers-before-trial' => 'REAL - Registered Users Before Trial without Subscription',
|
||||
'realusers-server-lost-connection' => 'REAL - Server Lost Connection',
|
||||
],
|
||||
|
|
@ -187,7 +183,7 @@ class Emails extends Command
|
|||
'team_id' => 0,
|
||||
]);
|
||||
}
|
||||
// $this->mail = (new BackupSuccess($backup->frequency, $db->name))->toMail();
|
||||
//$this->mail = (new BackupSuccess($backup->frequency, $db->name))->toMail();
|
||||
$this->sendEmail();
|
||||
break;
|
||||
// case 'invitation-link':
|
||||
|
|
@ -204,23 +200,6 @@ class Emails extends Command
|
|||
// $this->mail = (new InvitationLink($user))->toMail();
|
||||
// $this->sendEmail();
|
||||
// break;
|
||||
case 'waitlist-invitation-link':
|
||||
$this->mail = new MailMessage;
|
||||
$this->mail->view('emails.waitlist-invitation', [
|
||||
'loginLink' => 'https://coolify.io',
|
||||
]);
|
||||
$this->mail->subject('Congratulations! You are invited to join Coolify Cloud.');
|
||||
$this->sendEmail();
|
||||
break;
|
||||
case 'waitlist-confirmation':
|
||||
$found = Waitlist::where('email', $this->email)->first();
|
||||
if ($found) {
|
||||
SendConfirmationForWaitlistJob::dispatch($this->email, $found->uuid);
|
||||
} else {
|
||||
throw new Exception('Waitlist not found');
|
||||
}
|
||||
|
||||
break;
|
||||
case 'realusers-before-trial':
|
||||
$this->mail = new MailMessage;
|
||||
$this->mail->view('emails.before-trial-conversion');
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class Horizon extends Command
|
|||
public function handle()
|
||||
{
|
||||
if (config('constants.horizon.is_horizon_enabled')) {
|
||||
$this->info('[x]: Horizon is enabled. Starting.');
|
||||
$this->info('Horizon is enabled on this server.');
|
||||
$this->call('horizon');
|
||||
exit(0);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -55,10 +55,8 @@ class Init extends Command
|
|||
} else {
|
||||
$this->cleanup_in_progress_application_deployments();
|
||||
}
|
||||
echo "[3]: Cleanup Redis keys.\n";
|
||||
$this->call('cleanup:redis');
|
||||
|
||||
echo "[4]: Cleanup stucked resources.\n";
|
||||
$this->call('cleanup:stucked-resources');
|
||||
|
||||
try {
|
||||
|
|
@ -114,7 +112,6 @@ class Init extends Command
|
|||
|
||||
private function optimize()
|
||||
{
|
||||
echo "[1]: Optimizing Laravel (caching config, routes, views).\n";
|
||||
Artisan::call('optimize:clear');
|
||||
Artisan::call('optimize');
|
||||
}
|
||||
|
|
@ -189,7 +186,6 @@ class Init extends Command
|
|||
}
|
||||
}
|
||||
if ($commands->isNotEmpty()) {
|
||||
echo "Cleaning up unused networks from coolify proxy\n";
|
||||
remote_process(command: $commands, type: ActivityTypes::INLINE->value, server: $server, ignore_errors: false);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
|
|
@ -232,15 +228,14 @@ class Init extends Command
|
|||
$settings = instanceSettings();
|
||||
$do_not_track = data_get($settings, 'do_not_track');
|
||||
if ($do_not_track == true) {
|
||||
echo "[2]: Skipping sending live signal as do_not_track is enabled\n";
|
||||
echo "Do_not_track is enabled\n";
|
||||
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Http::get("https://undead.coolify.io/v4/alive?appId=$id&version=$version");
|
||||
echo "[2]: Sending live signal!\n";
|
||||
} catch (\Throwable $e) {
|
||||
echo "[2]: Error in sending live signal: {$e->getMessage()}\n";
|
||||
echo "Error in sending live signal: {$e->getMessage()}\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -253,7 +248,6 @@ class Init extends Command
|
|||
}
|
||||
$queued_inprogress_deployments = ApplicationDeploymentQueue::whereIn('status', [ApplicationDeploymentStatus::IN_PROGRESS->value, ApplicationDeploymentStatus::QUEUED->value])->get();
|
||||
foreach ($queued_inprogress_deployments as $deployment) {
|
||||
echo "Cleaning up deployment: {$deployment->id}\n";
|
||||
$deployment->status = ApplicationDeploymentStatus::FAILED->value;
|
||||
$deployment->save();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class Scheduler extends Command
|
|||
public function handle()
|
||||
{
|
||||
if (config('constants.horizon.is_scheduler_enabled')) {
|
||||
$this->info('[x]: Scheduler is enabled. Starting.');
|
||||
$this->info('Scheduler is enabled on this server.');
|
||||
$this->call('schedule:work');
|
||||
exit(0);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,114 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Waitlist;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class WaitlistInvite extends Command
|
||||
{
|
||||
public Waitlist|User|null $next_patient = null;
|
||||
|
||||
public ?string $password = null;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'waitlist:invite {--people=1} {--only-email} {email?}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Send invitation to the next user (or by email) in the waitlist';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$people = $this->option('people');
|
||||
for ($i = 0; $i < $people; $i++) {
|
||||
$this->main();
|
||||
}
|
||||
}
|
||||
|
||||
private function main()
|
||||
{
|
||||
if ($this->argument('email')) {
|
||||
if ($this->option('only-email')) {
|
||||
$this->next_patient = User::whereEmail($this->argument('email'))->first();
|
||||
$this->password = Str::password();
|
||||
$this->next_patient->update([
|
||||
'password' => Hash::make($this->password),
|
||||
'force_password_reset' => true,
|
||||
]);
|
||||
} else {
|
||||
$this->next_patient = Waitlist::where('email', $this->argument('email'))->first();
|
||||
}
|
||||
if (! $this->next_patient) {
|
||||
$this->error("{$this->argument('email')} not found in the waitlist.");
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$this->next_patient = Waitlist::orderBy('created_at', 'asc')->where('verified', true)->first();
|
||||
}
|
||||
if ($this->next_patient) {
|
||||
if ($this->option('only-email')) {
|
||||
$this->send_email();
|
||||
|
||||
return;
|
||||
}
|
||||
$this->register_user();
|
||||
$this->remove_from_waitlist();
|
||||
$this->send_email();
|
||||
} else {
|
||||
$this->info('No verified user found in the waitlist. 👀');
|
||||
}
|
||||
}
|
||||
|
||||
private function register_user()
|
||||
{
|
||||
$already_registered = User::whereEmail($this->next_patient->email)->first();
|
||||
if (! $already_registered) {
|
||||
$this->password = Str::password();
|
||||
User::create([
|
||||
'name' => str($this->next_patient->email)->before('@'),
|
||||
'email' => $this->next_patient->email,
|
||||
'password' => Hash::make($this->password),
|
||||
'force_password_reset' => true,
|
||||
]);
|
||||
$this->info("User registered ({$this->next_patient->email}) successfully. 🎉");
|
||||
} else {
|
||||
throw new \Exception('User already registered');
|
||||
}
|
||||
}
|
||||
|
||||
private function remove_from_waitlist()
|
||||
{
|
||||
$this->next_patient->delete();
|
||||
$this->info('User removed from waitlist successfully.');
|
||||
}
|
||||
|
||||
private function send_email()
|
||||
{
|
||||
$token = Crypt::encryptString("{$this->next_patient->email}@@@$this->password");
|
||||
$loginLink = route('auth.link', ['token' => $token]);
|
||||
$mail = new MailMessage;
|
||||
$mail->view('emails.waitlist-invitation', [
|
||||
'loginLink' => $loginLink,
|
||||
]);
|
||||
$mail->subject('Congratulations! You are invited to join Coolify Cloud.');
|
||||
send_user_an_email($mail, $this->next_patient->email);
|
||||
$this->info('Email sent successfully. 📧');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Actions\Server\ServerCheck;
|
||||
use App\Enums\ProxyStatus;
|
||||
use App\Enums\ProxyTypes;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Console\Command;
|
||||
use Str;
|
||||
|
||||
class Weird extends Command
|
||||
{
|
||||
protected $signature = 'weird {--number=1} {--run}';
|
||||
|
||||
protected $description = 'Weird stuff';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
try {
|
||||
if (! isDev()) {
|
||||
$this->error('This command can only be run in development mode');
|
||||
|
||||
return;
|
||||
}
|
||||
$run = $this->option('run');
|
||||
if ($run) {
|
||||
$servers = Server::all();
|
||||
foreach ($servers as $server) {
|
||||
ServerCheck::dispatch($server);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
$number = $this->option('number');
|
||||
for ($i = 0; $i < $number; $i++) {
|
||||
$uuid = Str::uuid();
|
||||
$server = Server::create([
|
||||
'name' => 'localhost-'.$uuid,
|
||||
'description' => 'This is a test docker container in development mode',
|
||||
'ip' => 'coolify-testing-host',
|
||||
'team_id' => 0,
|
||||
'private_key_id' => 1,
|
||||
'proxy' => [
|
||||
'type' => ProxyTypes::NONE->value,
|
||||
'status' => ProxyStatus::EXITED->value,
|
||||
],
|
||||
]);
|
||||
$server->settings->update([
|
||||
'is_usable' => true,
|
||||
'is_reachable' => true,
|
||||
]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -42,15 +42,13 @@ class Controller extends BaseController
|
|||
public function email_verify(EmailVerificationRequest $request)
|
||||
{
|
||||
$request->fulfill();
|
||||
$name = request()->user()?->name;
|
||||
|
||||
// send_internal_notification("User {$name} verified their email address.");
|
||||
return redirect(RouteServiceProvider::HOME);
|
||||
}
|
||||
|
||||
public function forgot_password(Request $request)
|
||||
{
|
||||
if (is_transactional_emails_active()) {
|
||||
if (is_transactional_emails_enabled()) {
|
||||
$arrayOfRequest = $request->only(Fortify::email());
|
||||
$request->merge([
|
||||
'email' => Str::lower($arrayOfRequest['email']),
|
||||
|
|
|
|||
|
|
@ -1,63 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Webhook;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Waitlist as ModelsWaitlist;
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class Waitlist extends Controller
|
||||
{
|
||||
public function confirm(Request $request)
|
||||
{
|
||||
$email = request()->get('email');
|
||||
$confirmation_code = request()->get('confirmation_code');
|
||||
try {
|
||||
$found = ModelsWaitlist::where('uuid', $confirmation_code)->where('email', $email)->first();
|
||||
if ($found) {
|
||||
if (! $found->verified) {
|
||||
if ($found->created_at > now()->subMinutes(config('constants.waitlist.expiration'))) {
|
||||
$found->verified = true;
|
||||
$found->save();
|
||||
send_internal_notification('Waitlist confirmed: '.$email);
|
||||
|
||||
return 'Thank you for confirming your email address. We will notify you when you are next in line.';
|
||||
} else {
|
||||
$found->delete();
|
||||
send_internal_notification('Waitlist expired: '.$email);
|
||||
|
||||
return 'Your confirmation code has expired. Please sign up again.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('dashboard');
|
||||
} catch (Exception $e) {
|
||||
send_internal_notification('Waitlist confirmation failed: '.$e->getMessage());
|
||||
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
}
|
||||
|
||||
public function cancel(Request $request)
|
||||
{
|
||||
$email = request()->get('email');
|
||||
$confirmation_code = request()->get('confirmation_code');
|
||||
try {
|
||||
$found = ModelsWaitlist::where('uuid', $confirmation_code)->where('email', $email)->first();
|
||||
if ($found && ! $found->verified) {
|
||||
$found->delete();
|
||||
send_internal_notification('Waitlist cancelled: '.$email);
|
||||
|
||||
return 'Your email address has been removed from the waitlist.';
|
||||
}
|
||||
|
||||
return redirect()->route('dashboard');
|
||||
} catch (Exception $e) {
|
||||
send_internal_notification('Waitlist cancellation failed: '.$e->getMessage());
|
||||
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2409,7 +2409,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||
if (! $this->only_this_server) {
|
||||
$this->deploy_to_additional_destinations();
|
||||
}
|
||||
//$this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview));
|
||||
$this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Actions\License\CheckResaleLicense;
|
||||
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;
|
||||
|
||||
class CheckResaleLicenseJob implements ShouldBeEncrypted, ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public function __construct() {}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
CheckResaleLicense::run();
|
||||
} catch (\Throwable $e) {
|
||||
send_internal_notification('CheckResaleLicenseJob failed with: '.$e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -306,7 +306,9 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
|||
if ($this->backup->save_s3) {
|
||||
$this->upload_to_s3();
|
||||
}
|
||||
//$this->team?->notify(new BackupSuccess($this->backup, $this->database, $database));
|
||||
|
||||
$this->team->notify(new BackupSuccess($this->backup, $this->database, $database));
|
||||
|
||||
$this->backup_log->update([
|
||||
'status' => 'success',
|
||||
'message' => $this->backup_output,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ namespace App\Jobs;
|
|||
|
||||
use App\Actions\Server\CleanupDocker;
|
||||
use App\Models\Server;
|
||||
use App\Notifications\Server\DockerCleanup;
|
||||
use App\Notifications\Server\DockerCleanupFailed;
|
||||
use App\Notifications\Server\DockerCleanupSuccess;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
|
@ -12,7 +13,6 @@ use Illuminate\Foundation\Bus\Dispatchable;
|
|||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue
|
||||
{
|
||||
|
|
@ -38,35 +38,36 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue
|
|||
return;
|
||||
}
|
||||
|
||||
if ($this->manualCleanup || $this->server->settings->force_docker_cleanup) {
|
||||
Log::info('DockerCleanupJob '.($this->manualCleanup ? 'manual' : 'force').' cleanup on '.$this->server->name);
|
||||
CleanupDocker::run(server: $this->server);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->usageBefore = $this->server->getDiskUsage();
|
||||
if (str($this->usageBefore)->isEmpty() || $this->usageBefore === null || $this->usageBefore === 0) {
|
||||
Log::info('DockerCleanupJob force cleanup on '.$this->server->name);
|
||||
|
||||
if ($this->manualCleanup || $this->server->settings->force_docker_cleanup) {
|
||||
CleanupDocker::run(server: $this->server);
|
||||
$usageAfter = $this->server->getDiskUsage();
|
||||
$this->server->team?->notify(new DockerCleanupSuccess($this->server, ($this->manualCleanup ? 'Manual' : 'Forced').' Docker cleanup job executed successfully. Disk usage before: '.$this->usageBefore.'%, Disk usage after: '.$usageAfter.'%.'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (str($this->usageBefore)->isEmpty() || $this->usageBefore === null || $this->usageBefore === 0) {
|
||||
CleanupDocker::run(server: $this->server);
|
||||
$this->server->team?->notify(new DockerCleanupSuccess($this->server, 'Docker cleanup job executed successfully, but no disk usage could be determined.'));
|
||||
}
|
||||
|
||||
if ($this->usageBefore >= $this->server->settings->docker_cleanup_threshold) {
|
||||
CleanupDocker::run(server: $this->server);
|
||||
$usageAfter = $this->server->getDiskUsage();
|
||||
if ($usageAfter < $this->usageBefore) {
|
||||
$this->server->team?->notify(new DockerCleanup($this->server, 'Saved '.($this->usageBefore - $usageAfter).'% disk space.'));
|
||||
Log::info('DockerCleanupJob done: Saved '.($this->usageBefore - $usageAfter).'% disk space on '.$this->server->name);
|
||||
$diskSaved = $this->usageBefore - $usageAfter;
|
||||
|
||||
if ($diskSaved > 0) {
|
||||
$this->server->team?->notify(new DockerCleanupSuccess($this->server, 'Saved '.$diskSaved.'% disk space. Disk usage before: '.$this->usageBefore.'%, Disk usage after: '.$usageAfter.'%.'));
|
||||
} else {
|
||||
Log::info('DockerCleanupJob failed to save disk space on '.$this->server->name);
|
||||
$this->server->team?->notify(new DockerCleanupSuccess($this->server, 'Docker cleanup job executed successfully, but no disk space was saved. Disk usage before: '.$this->usageBefore.'%, Disk usage after: '.$usageAfter.'%.'));
|
||||
}
|
||||
} else {
|
||||
Log::info('No need to clean up '.$this->server->name);
|
||||
$this->server->team?->notify(new DockerCleanupSuccess($this->server, 'No cleanup needed for '.$this->server->name));
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
CleanupDocker::run(server: $this->server);
|
||||
Log::error('DockerCleanupJob failed: '.$e->getMessage());
|
||||
$this->server->team?->notify(new DockerCleanupFailed($this->server, 'Docker cleanup job failed with the following error: '.$e->getMessage()));
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use App\Models\Server;
|
|||
use App\Models\Service;
|
||||
use App\Models\Team;
|
||||
use App\Notifications\ScheduledTask\TaskFailed;
|
||||
use App\Notifications\ScheduledTask\TaskSuccess;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
|
|
@ -111,6 +112,8 @@ class ScheduledTaskJob implements ShouldQueue
|
|||
'message' => $this->task_output,
|
||||
]);
|
||||
|
||||
$this->team?->notify(new TaskSuccess($this->task, $this->task_output));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -125,7 +128,6 @@ class ScheduledTaskJob implements ShouldQueue
|
|||
]);
|
||||
}
|
||||
$this->team?->notify(new TaskFailed($this->task, $e->getMessage()));
|
||||
// send_internal_notification('ScheduledTaskJob failed with: ' . $e->getMessage());
|
||||
throw $e;
|
||||
} finally {
|
||||
ScheduledTaskDone::dispatch($this->team->id);
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class SendConfirmationForWaitlistJob implements ShouldBeEncrypted, ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public function __construct(public string $email, public string $uuid) {}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
try {
|
||||
$mail = new MailMessage;
|
||||
$confirmation_url = base_url().'/webhooks/waitlist/confirm?email='.$this->email.'&confirmation_code='.$this->uuid;
|
||||
$cancel_url = base_url().'/webhooks/waitlist/cancel?email='.$this->email.'&confirmation_code='.$this->uuid;
|
||||
$mail->view('emails.waitlist-confirmation',
|
||||
[
|
||||
'confirmation_url' => $confirmation_url,
|
||||
'cancel_url' => $cancel_url,
|
||||
]);
|
||||
$mail->subject('You are on the waitlist!');
|
||||
send_user_an_email($mail, $this->email);
|
||||
} catch (\Throwable $e) {
|
||||
send_internal_notification("SendConfirmationForWaitlistJob failed for {$this->email} with error: ".$e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Livewire\Notifications;
|
||||
|
||||
use App\Models\DiscordNotificationSettings;
|
||||
use App\Models\Team;
|
||||
use App\Notifications\Test;
|
||||
use Livewire\Attributes\Validate;
|
||||
|
|
@ -11,6 +12,8 @@ class Discord extends Component
|
|||
{
|
||||
public Team $team;
|
||||
|
||||
public DiscordNotificationSettings $settings;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $discordEnabled = false;
|
||||
|
||||
|
|
@ -18,27 +21,46 @@ class Discord extends Component
|
|||
public ?string $discordWebhookUrl = null;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $discordNotificationsTest = false;
|
||||
public bool $deploymentSuccessDiscordNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $discordNotificationsDeployments = false;
|
||||
public bool $deploymentFailureDiscordNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $discordNotificationsStatusChanges = false;
|
||||
public bool $statusChangeDiscordNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $discordNotificationsDatabaseBackups = false;
|
||||
public bool $backupSuccessDiscordNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $discordNotificationsScheduledTasks = false;
|
||||
public bool $backupFailureDiscordNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $discordNotificationsServerDiskUsage = false;
|
||||
public bool $scheduledTaskSuccessDiscordNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $scheduledTaskFailureDiscordNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $dockerCleanupSuccessDiscordNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $dockerCleanupFailureDiscordNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $serverDiskUsageDiscordNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $serverReachableDiscordNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $serverUnreachableDiscordNotifications = true;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
try {
|
||||
$this->team = auth()->user()->currentTeam();
|
||||
$this->settings = $this->team->discordNotificationSettings;
|
||||
$this->syncData();
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
|
@ -49,25 +71,40 @@ class Discord extends Component
|
|||
{
|
||||
if ($toModel) {
|
||||
$this->validate();
|
||||
$this->team->discord_enabled = $this->discordEnabled;
|
||||
$this->team->discord_webhook_url = $this->discordWebhookUrl;
|
||||
$this->team->discord_notifications_test = $this->discordNotificationsTest;
|
||||
$this->team->discord_notifications_deployments = $this->discordNotificationsDeployments;
|
||||
$this->team->discord_notifications_status_changes = $this->discordNotificationsStatusChanges;
|
||||
$this->team->discord_notifications_database_backups = $this->discordNotificationsDatabaseBackups;
|
||||
$this->team->discord_notifications_scheduled_tasks = $this->discordNotificationsScheduledTasks;
|
||||
$this->team->discord_notifications_server_disk_usage = $this->discordNotificationsServerDiskUsage;
|
||||
$this->team->save();
|
||||
$this->settings->discord_enabled = $this->discordEnabled;
|
||||
$this->settings->discord_webhook_url = $this->discordWebhookUrl;
|
||||
|
||||
$this->settings->deployment_success_discord_notifications = $this->deploymentSuccessDiscordNotifications;
|
||||
$this->settings->deployment_failure_discord_notifications = $this->deploymentFailureDiscordNotifications;
|
||||
$this->settings->status_change_discord_notifications = $this->statusChangeDiscordNotifications;
|
||||
$this->settings->backup_success_discord_notifications = $this->backupSuccessDiscordNotifications;
|
||||
$this->settings->backup_failure_discord_notifications = $this->backupFailureDiscordNotifications;
|
||||
$this->settings->scheduled_task_success_discord_notifications = $this->scheduledTaskSuccessDiscordNotifications;
|
||||
$this->settings->scheduled_task_failure_discord_notifications = $this->scheduledTaskFailureDiscordNotifications;
|
||||
$this->settings->docker_cleanup_success_discord_notifications = $this->dockerCleanupSuccessDiscordNotifications;
|
||||
$this->settings->docker_cleanup_failure_discord_notifications = $this->dockerCleanupFailureDiscordNotifications;
|
||||
$this->settings->server_disk_usage_discord_notifications = $this->serverDiskUsageDiscordNotifications;
|
||||
$this->settings->server_reachable_discord_notifications = $this->serverReachableDiscordNotifications;
|
||||
$this->settings->server_unreachable_discord_notifications = $this->serverUnreachableDiscordNotifications;
|
||||
|
||||
$this->settings->save();
|
||||
refreshSession();
|
||||
} else {
|
||||
$this->discordEnabled = $this->team->discord_enabled;
|
||||
$this->discordWebhookUrl = $this->team->discord_webhook_url;
|
||||
$this->discordNotificationsTest = $this->team->discord_notifications_test;
|
||||
$this->discordNotificationsDeployments = $this->team->discord_notifications_deployments;
|
||||
$this->discordNotificationsStatusChanges = $this->team->discord_notifications_status_changes;
|
||||
$this->discordNotificationsDatabaseBackups = $this->team->discord_notifications_database_backups;
|
||||
$this->discordNotificationsScheduledTasks = $this->team->discord_notifications_scheduled_tasks;
|
||||
$this->discordNotificationsServerDiskUsage = $this->team->discord_notifications_server_disk_usage;
|
||||
$this->discordEnabled = $this->settings->discord_enabled;
|
||||
$this->discordWebhookUrl = $this->settings->discord_webhook_url;
|
||||
|
||||
$this->deploymentSuccessDiscordNotifications = $this->settings->deployment_success_discord_notifications;
|
||||
$this->deploymentFailureDiscordNotifications = $this->settings->deployment_failure_discord_notifications;
|
||||
$this->statusChangeDiscordNotifications = $this->settings->status_change_discord_notifications;
|
||||
$this->backupSuccessDiscordNotifications = $this->settings->backup_success_discord_notifications;
|
||||
$this->backupFailureDiscordNotifications = $this->settings->backup_failure_discord_notifications;
|
||||
$this->scheduledTaskSuccessDiscordNotifications = $this->settings->scheduled_task_success_discord_notifications;
|
||||
$this->scheduledTaskFailureDiscordNotifications = $this->settings->scheduled_task_failure_discord_notifications;
|
||||
$this->dockerCleanupSuccessDiscordNotifications = $this->settings->docker_cleanup_success_discord_notifications;
|
||||
$this->dockerCleanupFailureDiscordNotifications = $this->settings->docker_cleanup_failure_discord_notifications;
|
||||
$this->serverDiskUsageDiscordNotifications = $this->settings->server_disk_usage_discord_notifications;
|
||||
$this->serverReachableDiscordNotifications = $this->settings->server_reachable_discord_notifications;
|
||||
$this->serverUnreachableDiscordNotifications = $this->settings->server_unreachable_discord_notifications;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +154,7 @@ class Discord extends Component
|
|||
public function sendTestNotification()
|
||||
{
|
||||
try {
|
||||
$this->team->notify(new Test);
|
||||
$this->team->notify(new Test(channel: 'discord'));
|
||||
$this->dispatch('success', 'Test notification sent.');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Livewire\Notifications;
|
||||
|
||||
use App\Models\EmailNotificationSettings;
|
||||
use App\Models\Team;
|
||||
use App\Notifications\Test;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
|
|
@ -11,17 +12,18 @@ use Livewire\Component;
|
|||
|
||||
class Email extends Component
|
||||
{
|
||||
protected $listeners = ['refresh' => '$refresh'];
|
||||
|
||||
public Team $team;
|
||||
|
||||
public EmailNotificationSettings $settings;
|
||||
|
||||
#[Locked]
|
||||
public string $emails;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $smtpEnabled = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $useInstanceEmailSettings = false;
|
||||
|
||||
#[Validate(['nullable', 'email'])]
|
||||
public ?string $smtpFromAddress = null;
|
||||
|
||||
|
|
@ -34,11 +36,11 @@ class Email extends Component
|
|||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $smtpHost = null;
|
||||
|
||||
#[Validate(['nullable', 'numeric'])]
|
||||
#[Validate(['nullable', 'numeric', 'min:1', 'max:65535'])]
|
||||
public ?int $smtpPort = null;
|
||||
|
||||
#[Validate(['nullable', 'string', 'in:tls,ssl,none'])]
|
||||
public ?string $smtpEncryption = null;
|
||||
public ?string $smtpEncryption = 'tls';
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $smtpUsername = null;
|
||||
|
|
@ -50,29 +52,50 @@ class Email extends Component
|
|||
public ?int $smtpTimeout = null;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $smtpNotificationsTest = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $smtpNotificationsDeployments = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $smtpNotificationsStatusChanges = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $smtpNotificationsDatabaseBackups = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $smtpNotificationsScheduledTasks = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $smtpNotificationsServerDiskUsage = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $resendEnabled;
|
||||
public bool $resendEnabled = false;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $resendApiKey = null;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $useInstanceEmailSettings = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $deploymentSuccessEmailNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $deploymentFailureEmailNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $statusChangeEmailNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $backupSuccessEmailNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $backupFailureEmailNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $scheduledTaskSuccessEmailNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $scheduledTaskFailureEmailNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $dockerCleanupSuccessEmailNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $dockerCleanupFailureEmailNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $serverDiskUsageEmailNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $serverReachableEmailNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $serverUnreachableEmailNotifications = true;
|
||||
|
||||
#[Validate(['nullable', 'email'])]
|
||||
public ?string $testEmailAddress = null;
|
||||
|
||||
|
|
@ -81,7 +104,9 @@ class Email extends Component
|
|||
try {
|
||||
$this->team = auth()->user()->currentTeam();
|
||||
$this->emails = auth()->user()->email;
|
||||
$this->settings = $this->team->emailNotificationSettings;
|
||||
$this->syncData();
|
||||
$this->testEmailAddress = auth()->user()->email;
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
|
|
@ -91,47 +116,191 @@ class Email extends Component
|
|||
{
|
||||
if ($toModel) {
|
||||
$this->validate();
|
||||
$this->team->smtp_enabled = $this->smtpEnabled;
|
||||
$this->team->smtp_from_address = $this->smtpFromAddress;
|
||||
$this->team->smtp_from_name = $this->smtpFromName;
|
||||
$this->team->smtp_host = $this->smtpHost;
|
||||
$this->team->smtp_port = $this->smtpPort;
|
||||
$this->team->smtp_encryption = $this->smtpEncryption;
|
||||
$this->team->smtp_username = $this->smtpUsername;
|
||||
$this->team->smtp_password = $this->smtpPassword;
|
||||
$this->team->smtp_timeout = $this->smtpTimeout;
|
||||
$this->team->smtp_recipients = $this->smtpRecipients;
|
||||
$this->team->smtp_notifications_test = $this->smtpNotificationsTest;
|
||||
$this->team->smtp_notifications_deployments = $this->smtpNotificationsDeployments;
|
||||
$this->team->smtp_notifications_status_changes = $this->smtpNotificationsStatusChanges;
|
||||
$this->team->smtp_notifications_database_backups = $this->smtpNotificationsDatabaseBackups;
|
||||
$this->team->smtp_notifications_scheduled_tasks = $this->smtpNotificationsScheduledTasks;
|
||||
$this->team->smtp_notifications_server_disk_usage = $this->smtpNotificationsServerDiskUsage;
|
||||
$this->team->use_instance_email_settings = $this->useInstanceEmailSettings;
|
||||
$this->team->resend_enabled = $this->resendEnabled;
|
||||
$this->team->resend_api_key = $this->resendApiKey;
|
||||
$this->team->save();
|
||||
refreshSession();
|
||||
$this->settings->smtp_enabled = $this->smtpEnabled;
|
||||
$this->settings->smtp_from_address = $this->smtpFromAddress;
|
||||
$this->settings->smtp_from_name = $this->smtpFromName;
|
||||
$this->settings->smtp_recipients = $this->smtpRecipients;
|
||||
$this->settings->smtp_host = $this->smtpHost;
|
||||
$this->settings->smtp_port = $this->smtpPort;
|
||||
$this->settings->smtp_encryption = $this->smtpEncryption;
|
||||
$this->settings->smtp_username = $this->smtpUsername;
|
||||
$this->settings->smtp_password = $this->smtpPassword;
|
||||
$this->settings->smtp_timeout = $this->smtpTimeout;
|
||||
|
||||
$this->settings->resend_enabled = $this->resendEnabled;
|
||||
$this->settings->resend_api_key = $this->resendApiKey;
|
||||
|
||||
$this->settings->use_instance_email_settings = $this->useInstanceEmailSettings;
|
||||
|
||||
$this->settings->deployment_success_email_notifications = $this->deploymentSuccessEmailNotifications;
|
||||
$this->settings->deployment_failure_email_notifications = $this->deploymentFailureEmailNotifications;
|
||||
$this->settings->status_change_email_notifications = $this->statusChangeEmailNotifications;
|
||||
$this->settings->backup_success_email_notifications = $this->backupSuccessEmailNotifications;
|
||||
$this->settings->backup_failure_email_notifications = $this->backupFailureEmailNotifications;
|
||||
$this->settings->scheduled_task_success_email_notifications = $this->scheduledTaskSuccessEmailNotifications;
|
||||
$this->settings->scheduled_task_failure_email_notifications = $this->scheduledTaskFailureEmailNotifications;
|
||||
$this->settings->docker_cleanup_success_email_notifications = $this->dockerCleanupSuccessEmailNotifications;
|
||||
$this->settings->docker_cleanup_failure_email_notifications = $this->dockerCleanupFailureEmailNotifications;
|
||||
$this->settings->server_disk_usage_email_notifications = $this->serverDiskUsageEmailNotifications;
|
||||
$this->settings->server_reachable_email_notifications = $this->serverReachableEmailNotifications;
|
||||
$this->settings->server_unreachable_email_notifications = $this->serverUnreachableEmailNotifications;
|
||||
$this->settings->save();
|
||||
|
||||
} else {
|
||||
$this->smtpEnabled = $this->team->smtp_enabled;
|
||||
$this->smtpFromAddress = $this->team->smtp_from_address;
|
||||
$this->smtpFromName = $this->team->smtp_from_name;
|
||||
$this->smtpHost = $this->team->smtp_host;
|
||||
$this->smtpPort = $this->team->smtp_port;
|
||||
$this->smtpEncryption = $this->team->smtp_encryption;
|
||||
$this->smtpUsername = $this->team->smtp_username;
|
||||
$this->smtpPassword = $this->team->smtp_password;
|
||||
$this->smtpTimeout = $this->team->smtp_timeout;
|
||||
$this->smtpRecipients = $this->team->smtp_recipients;
|
||||
$this->smtpNotificationsTest = $this->team->smtp_notifications_test;
|
||||
$this->smtpNotificationsDeployments = $this->team->smtp_notifications_deployments;
|
||||
$this->smtpNotificationsStatusChanges = $this->team->smtp_notifications_status_changes;
|
||||
$this->smtpNotificationsDatabaseBackups = $this->team->smtp_notifications_database_backups;
|
||||
$this->smtpNotificationsScheduledTasks = $this->team->smtp_notifications_scheduled_tasks;
|
||||
$this->smtpNotificationsServerDiskUsage = $this->team->smtp_notifications_server_disk_usage;
|
||||
$this->useInstanceEmailSettings = $this->team->use_instance_email_settings;
|
||||
$this->resendEnabled = $this->team->resend_enabled;
|
||||
$this->resendApiKey = $this->team->resend_api_key;
|
||||
$this->smtpEnabled = $this->settings->smtp_enabled;
|
||||
$this->smtpFromAddress = $this->settings->smtp_from_address;
|
||||
$this->smtpFromName = $this->settings->smtp_from_name;
|
||||
$this->smtpRecipients = $this->settings->smtp_recipients;
|
||||
$this->smtpHost = $this->settings->smtp_host;
|
||||
$this->smtpPort = $this->settings->smtp_port;
|
||||
$this->smtpEncryption = $this->settings->smtp_encryption;
|
||||
$this->smtpUsername = $this->settings->smtp_username;
|
||||
$this->smtpPassword = $this->settings->smtp_password;
|
||||
$this->smtpTimeout = $this->settings->smtp_timeout;
|
||||
|
||||
$this->resendEnabled = $this->settings->resend_enabled;
|
||||
$this->resendApiKey = $this->settings->resend_api_key;
|
||||
|
||||
$this->useInstanceEmailSettings = $this->settings->use_instance_email_settings;
|
||||
|
||||
$this->deploymentSuccessEmailNotifications = $this->settings->deployment_success_email_notifications;
|
||||
$this->deploymentFailureEmailNotifications = $this->settings->deployment_failure_email_notifications;
|
||||
$this->statusChangeEmailNotifications = $this->settings->status_change_email_notifications;
|
||||
$this->backupSuccessEmailNotifications = $this->settings->backup_success_email_notifications;
|
||||
$this->backupFailureEmailNotifications = $this->settings->backup_failure_email_notifications;
|
||||
$this->scheduledTaskSuccessEmailNotifications = $this->settings->scheduled_task_success_email_notifications;
|
||||
$this->scheduledTaskFailureEmailNotifications = $this->settings->scheduled_task_failure_email_notifications;
|
||||
$this->dockerCleanupSuccessEmailNotifications = $this->settings->docker_cleanup_success_email_notifications;
|
||||
$this->dockerCleanupFailureEmailNotifications = $this->settings->docker_cleanup_failure_email_notifications;
|
||||
$this->serverDiskUsageEmailNotifications = $this->settings->server_disk_usage_email_notifications;
|
||||
$this->serverReachableEmailNotifications = $this->settings->server_reachable_email_notifications;
|
||||
$this->serverUnreachableEmailNotifications = $this->settings->server_unreachable_email_notifications;
|
||||
}
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
$this->resetErrorBag();
|
||||
$this->saveModel();
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function saveModel()
|
||||
{
|
||||
$this->syncData(true);
|
||||
$this->dispatch('success', 'Email notifications settings updated.');
|
||||
}
|
||||
|
||||
public function instantSave(?string $type = null)
|
||||
{
|
||||
try {
|
||||
$this->resetErrorBag();
|
||||
|
||||
if ($type === 'SMTP') {
|
||||
$this->submitSmtp();
|
||||
} elseif ($type === 'Resend') {
|
||||
$this->submitResend();
|
||||
} else {
|
||||
$this->smtpEnabled = false;
|
||||
$this->resendEnabled = false;
|
||||
$this->saveModel();
|
||||
|
||||
return;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
if ($type === 'SMTP') {
|
||||
$this->smtpEnabled = false;
|
||||
} elseif ($type === 'Resend') {
|
||||
$this->resendEnabled = false;
|
||||
}
|
||||
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
$this->dispatch('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
public function submitSmtp()
|
||||
{
|
||||
try {
|
||||
$this->resetErrorBag();
|
||||
$this->validate([
|
||||
'smtpEnabled' => 'boolean',
|
||||
'smtpFromAddress' => 'required|email',
|
||||
'smtpFromName' => 'required|string',
|
||||
'smtpHost' => 'required|string',
|
||||
'smtpPort' => 'required|numeric',
|
||||
'smtpEncryption' => 'required|string|in:tls,ssl,none',
|
||||
'smtpUsername' => 'nullable|string',
|
||||
'smtpPassword' => 'nullable|string',
|
||||
'smtpTimeout' => 'nullable|numeric',
|
||||
], [
|
||||
'smtpFromAddress.required' => 'From Address is required.',
|
||||
'smtpFromAddress.email' => 'Please enter a valid email address.',
|
||||
'smtpFromName.required' => 'From Name is required.',
|
||||
'smtpHost.required' => 'SMTP Host is required.',
|
||||
'smtpPort.required' => 'SMTP Port is required.',
|
||||
'smtpPort.numeric' => 'SMTP Port must be a number.',
|
||||
'smtpEncryption.required' => 'Encryption type is required.',
|
||||
]);
|
||||
|
||||
$this->settings->resend_enabled = false;
|
||||
$this->settings->use_instance_email_settings = false;
|
||||
$this->resendEnabled = false;
|
||||
$this->useInstanceEmailSettings = false;
|
||||
|
||||
$this->settings->smtp_enabled = $this->smtpEnabled;
|
||||
$this->settings->smtp_from_address = $this->smtpFromAddress;
|
||||
$this->settings->smtp_from_name = $this->smtpFromName;
|
||||
$this->settings->smtp_host = $this->smtpHost;
|
||||
$this->settings->smtp_port = $this->smtpPort;
|
||||
$this->settings->smtp_encryption = $this->smtpEncryption;
|
||||
$this->settings->smtp_username = $this->smtpUsername;
|
||||
$this->settings->smtp_password = $this->smtpPassword;
|
||||
$this->settings->smtp_timeout = $this->smtpTimeout;
|
||||
|
||||
$this->settings->save();
|
||||
$this->dispatch('success', 'SMTP settings updated.');
|
||||
} catch (\Throwable $e) {
|
||||
$this->smtpEnabled = false;
|
||||
|
||||
return handleError($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function submitResend()
|
||||
{
|
||||
try {
|
||||
$this->resetErrorBag();
|
||||
$this->validate([
|
||||
'resendEnabled' => 'boolean',
|
||||
'resendApiKey' => 'required|string',
|
||||
'smtpFromAddress' => 'required|email',
|
||||
'smtpFromName' => 'required|string',
|
||||
], [
|
||||
'resendApiKey.required' => 'Resend API Key is required.',
|
||||
'smtpFromAddress.required' => 'From Address is required.',
|
||||
'smtpFromAddress.email' => 'Please enter a valid email address.',
|
||||
'smtpFromName.required' => 'From Name is required.',
|
||||
]);
|
||||
|
||||
$this->settings->smtp_enabled = false;
|
||||
$this->settings->use_instance_email_settings = false;
|
||||
$this->smtpEnabled = false;
|
||||
$this->useInstanceEmailSettings = false;
|
||||
|
||||
$this->settings->resend_enabled = $this->resendEnabled;
|
||||
$this->settings->resend_api_key = $this->resendApiKey;
|
||||
$this->settings->smtp_from_address = $this->smtpFromAddress;
|
||||
$this->settings->smtp_from_name = $this->smtpFromName;
|
||||
|
||||
$this->settings->save();
|
||||
$this->dispatch('success', 'Resend settings updated.');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -149,7 +318,7 @@ class Email extends Component
|
|||
'test-email:'.$this->team->id,
|
||||
$perMinute = 0,
|
||||
function () {
|
||||
$this->team?->notify(new Test($this->testEmailAddress));
|
||||
$this->team?->notify(new Test($this->testEmailAddress, 'email'));
|
||||
$this->dispatch('success', 'Test Email sent.');
|
||||
},
|
||||
$decaySeconds = 10,
|
||||
|
|
@ -163,70 +332,6 @@ class Email extends Component
|
|||
}
|
||||
}
|
||||
|
||||
public function instantSaveInstance()
|
||||
{
|
||||
try {
|
||||
$this->smtpEnabled = false;
|
||||
$this->resendEnabled = false;
|
||||
$this->saveModel();
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSaveSmtpEnabled()
|
||||
{
|
||||
try {
|
||||
$this->validate([
|
||||
'smtpHost' => 'required',
|
||||
'smtpPort' => 'required|numeric',
|
||||
], [
|
||||
'smtpHost.required' => 'SMTP Host is required.',
|
||||
'smtpPort.required' => 'SMTP Port is required.',
|
||||
]);
|
||||
$this->resendEnabled = false;
|
||||
$this->saveModel();
|
||||
} catch (\Throwable $e) {
|
||||
$this->smtpEnabled = false;
|
||||
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSaveResend()
|
||||
{
|
||||
try {
|
||||
$this->validate([
|
||||
'resendApiKey' => 'required',
|
||||
], [
|
||||
'resendApiKey.required' => 'Resend API Key is required.',
|
||||
]);
|
||||
$this->smtpEnabled = false;
|
||||
$this->saveModel();
|
||||
} catch (\Throwable $e) {
|
||||
$this->resendEnabled = false;
|
||||
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function saveModel()
|
||||
{
|
||||
$this->syncData(true);
|
||||
refreshSession();
|
||||
$this->dispatch('success', 'Settings saved.');
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
$this->resetErrorBag();
|
||||
$this->saveModel();
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function copyFromInstanceSettings()
|
||||
{
|
||||
$settings = instanceSettings();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Livewire\Notifications;
|
||||
|
||||
use App\Models\SlackNotificationSettings;
|
||||
use App\Models\Team;
|
||||
use App\Notifications\Test;
|
||||
use Livewire\Attributes\Validate;
|
||||
|
|
@ -11,6 +12,8 @@ class Slack extends Component
|
|||
{
|
||||
public Team $team;
|
||||
|
||||
public SlackNotificationSettings $settings;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $slackEnabled = false;
|
||||
|
||||
|
|
@ -18,27 +21,46 @@ class Slack extends Component
|
|||
public ?string $slackWebhookUrl = null;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $slackNotificationsTest = false;
|
||||
public bool $deploymentSuccessSlackNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $slackNotificationsDeployments = false;
|
||||
public bool $deploymentFailureSlackNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $slackNotificationsStatusChanges = false;
|
||||
public bool $statusChangeSlackNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $slackNotificationsDatabaseBackups = false;
|
||||
public bool $backupSuccessSlackNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $slackNotificationsScheduledTasks = false;
|
||||
public bool $backupFailureSlackNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $slackNotificationsServerDiskUsage = false;
|
||||
public bool $scheduledTaskSuccessSlackNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $scheduledTaskFailureSlackNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $dockerCleanupSuccessSlackNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $dockerCleanupFailureSlackNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $serverDiskUsageSlackNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $serverReachableSlackNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $serverUnreachableSlackNotifications = true;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
try {
|
||||
$this->team = auth()->user()->currentTeam();
|
||||
$this->settings = $this->team->slackNotificationSettings;
|
||||
$this->syncData();
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
|
@ -49,25 +71,40 @@ class Slack extends Component
|
|||
{
|
||||
if ($toModel) {
|
||||
$this->validate();
|
||||
$this->team->slack_enabled = $this->slackEnabled;
|
||||
$this->team->slack_webhook_url = $this->slackWebhookUrl;
|
||||
$this->team->slack_notifications_test = $this->slackNotificationsTest;
|
||||
$this->team->slack_notifications_deployments = $this->slackNotificationsDeployments;
|
||||
$this->team->slack_notifications_status_changes = $this->slackNotificationsStatusChanges;
|
||||
$this->team->slack_notifications_database_backups = $this->slackNotificationsDatabaseBackups;
|
||||
$this->team->slack_notifications_scheduled_tasks = $this->slackNotificationsScheduledTasks;
|
||||
$this->team->slack_notifications_server_disk_usage = $this->slackNotificationsServerDiskUsage;
|
||||
$this->team->save();
|
||||
$this->settings->slack_enabled = $this->slackEnabled;
|
||||
$this->settings->slack_webhook_url = $this->slackWebhookUrl;
|
||||
|
||||
$this->settings->deployment_success_slack_notifications = $this->deploymentSuccessSlackNotifications;
|
||||
$this->settings->deployment_failure_slack_notifications = $this->deploymentFailureSlackNotifications;
|
||||
$this->settings->status_change_slack_notifications = $this->statusChangeSlackNotifications;
|
||||
$this->settings->backup_success_slack_notifications = $this->backupSuccessSlackNotifications;
|
||||
$this->settings->backup_failure_slack_notifications = $this->backupFailureSlackNotifications;
|
||||
$this->settings->scheduled_task_success_slack_notifications = $this->scheduledTaskSuccessSlackNotifications;
|
||||
$this->settings->scheduled_task_failure_slack_notifications = $this->scheduledTaskFailureSlackNotifications;
|
||||
$this->settings->docker_cleanup_success_slack_notifications = $this->dockerCleanupSuccessSlackNotifications;
|
||||
$this->settings->docker_cleanup_failure_slack_notifications = $this->dockerCleanupFailureSlackNotifications;
|
||||
$this->settings->server_disk_usage_slack_notifications = $this->serverDiskUsageSlackNotifications;
|
||||
$this->settings->server_reachable_slack_notifications = $this->serverReachableSlackNotifications;
|
||||
$this->settings->server_unreachable_slack_notifications = $this->serverUnreachableSlackNotifications;
|
||||
|
||||
$this->settings->save();
|
||||
refreshSession();
|
||||
} else {
|
||||
$this->slackEnabled = $this->team->slack_enabled;
|
||||
$this->slackWebhookUrl = $this->team->slack_webhook_url;
|
||||
$this->slackNotificationsTest = $this->team->slack_notifications_test;
|
||||
$this->slackNotificationsDeployments = $this->team->slack_notifications_deployments;
|
||||
$this->slackNotificationsStatusChanges = $this->team->slack_notifications_status_changes;
|
||||
$this->slackNotificationsDatabaseBackups = $this->team->slack_notifications_database_backups;
|
||||
$this->slackNotificationsScheduledTasks = $this->team->slack_notifications_scheduled_tasks;
|
||||
$this->slackNotificationsServerDiskUsage = $this->team->slack_notifications_server_disk_usage;
|
||||
$this->slackEnabled = $this->settings->slack_enabled;
|
||||
$this->slackWebhookUrl = $this->settings->slack_webhook_url;
|
||||
|
||||
$this->deploymentSuccessSlackNotifications = $this->settings->deployment_success_slack_notifications;
|
||||
$this->deploymentFailureSlackNotifications = $this->settings->deployment_failure_slack_notifications;
|
||||
$this->statusChangeSlackNotifications = $this->settings->status_change_slack_notifications;
|
||||
$this->backupSuccessSlackNotifications = $this->settings->backup_success_slack_notifications;
|
||||
$this->backupFailureSlackNotifications = $this->settings->backup_failure_slack_notifications;
|
||||
$this->scheduledTaskSuccessSlackNotifications = $this->settings->scheduled_task_success_slack_notifications;
|
||||
$this->scheduledTaskFailureSlackNotifications = $this->settings->scheduled_task_failure_slack_notifications;
|
||||
$this->dockerCleanupSuccessSlackNotifications = $this->settings->docker_cleanup_success_slack_notifications;
|
||||
$this->dockerCleanupFailureSlackNotifications = $this->settings->docker_cleanup_failure_slack_notifications;
|
||||
$this->serverDiskUsageSlackNotifications = $this->settings->server_disk_usage_slack_notifications;
|
||||
$this->serverReachableSlackNotifications = $this->settings->server_reachable_slack_notifications;
|
||||
$this->serverUnreachableSlackNotifications = $this->settings->server_unreachable_slack_notifications;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +154,7 @@ class Slack extends Component
|
|||
public function sendTestNotification()
|
||||
{
|
||||
try {
|
||||
$this->team->notify(new Test);
|
||||
$this->team->notify(new Test(channel: 'slack'));
|
||||
$this->dispatch('success', 'Test notification sent.');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Livewire\Notifications;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\TelegramNotificationSettings;
|
||||
use App\Notifications\Test;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
|
|
@ -11,6 +12,8 @@ class Telegram extends Component
|
|||
{
|
||||
public Team $team;
|
||||
|
||||
public TelegramNotificationSettings $settings;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $telegramEnabled = false;
|
||||
|
||||
|
|
@ -21,42 +24,82 @@ class Telegram extends Component
|
|||
public ?string $telegramChatId = null;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $telegramNotificationsTest = false;
|
||||
public bool $deploymentSuccessTelegramNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $telegramNotificationsDeployments = false;
|
||||
public bool $deploymentFailureTelegramNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $telegramNotificationsStatusChanges = false;
|
||||
public bool $statusChangeTelegramNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $telegramNotificationsDatabaseBackups = false;
|
||||
public bool $backupSuccessTelegramNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $telegramNotificationsScheduledTasks = false;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsTestMessageThreadId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsDeploymentsMessageThreadId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsStatusChangesMessageThreadId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsDatabaseBackupsMessageThreadId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsScheduledTasksThreadId = null;
|
||||
public bool $backupFailureTelegramNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $telegramNotificationsServerDiskUsage = false;
|
||||
public bool $scheduledTaskSuccessTelegramNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $scheduledTaskFailureTelegramNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $dockerCleanupSuccessTelegramNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $dockerCleanupFailureTelegramNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $serverDiskUsageTelegramNotifications = true;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $serverReachableTelegramNotifications = false;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $serverUnreachableTelegramNotifications = true;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsDeploymentSuccessTopicId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsDeploymentFailureTopicId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsStatusChangeTopicId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsBackupSuccessTopicId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsBackupFailureTopicId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsScheduledTaskSuccessTopicId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsScheduledTaskFailureTopicId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsDockerCleanupSuccessTopicId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsDockerCleanupFailureTopicId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsServerDiskUsageTopicId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsServerReachableTopicId = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $telegramNotificationsServerUnreachableTopicId = null;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
try {
|
||||
$this->team = auth()->user()->currentTeam();
|
||||
$this->settings = $this->team->telegramNotificationSettings;
|
||||
$this->syncData();
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
|
@ -67,39 +110,69 @@ class Telegram extends Component
|
|||
{
|
||||
if ($toModel) {
|
||||
$this->validate();
|
||||
$this->team->telegram_enabled = $this->telegramEnabled;
|
||||
$this->team->telegram_token = $this->telegramToken;
|
||||
$this->team->telegram_chat_id = $this->telegramChatId;
|
||||
$this->team->telegram_notifications_test = $this->telegramNotificationsTest;
|
||||
$this->team->telegram_notifications_deployments = $this->telegramNotificationsDeployments;
|
||||
$this->team->telegram_notifications_status_changes = $this->telegramNotificationsStatusChanges;
|
||||
$this->team->telegram_notifications_database_backups = $this->telegramNotificationsDatabaseBackups;
|
||||
$this->team->telegram_notifications_scheduled_tasks = $this->telegramNotificationsScheduledTasks;
|
||||
$this->team->telegram_notifications_test_message_thread_id = $this->telegramNotificationsTestMessageThreadId;
|
||||
$this->team->telegram_notifications_deployments_message_thread_id = $this->telegramNotificationsDeploymentsMessageThreadId;
|
||||
$this->team->telegram_notifications_status_changes_message_thread_id = $this->telegramNotificationsStatusChangesMessageThreadId;
|
||||
$this->team->telegram_notifications_database_backups_message_thread_id = $this->telegramNotificationsDatabaseBackupsMessageThreadId;
|
||||
$this->team->telegram_notifications_scheduled_tasks_thread_id = $this->telegramNotificationsScheduledTasksThreadId;
|
||||
$this->team->telegram_notifications_server_disk_usage = $this->telegramNotificationsServerDiskUsage;
|
||||
$this->team->save();
|
||||
$this->settings->telegram_enabled = $this->telegramEnabled;
|
||||
$this->settings->telegram_token = $this->telegramToken;
|
||||
$this->settings->telegram_chat_id = $this->telegramChatId;
|
||||
|
||||
$this->settings->deployment_success_telegram_notifications = $this->deploymentSuccessTelegramNotifications;
|
||||
$this->settings->deployment_failure_telegram_notifications = $this->deploymentFailureTelegramNotifications;
|
||||
$this->settings->status_change_telegram_notifications = $this->statusChangeTelegramNotifications;
|
||||
$this->settings->backup_success_telegram_notifications = $this->backupSuccessTelegramNotifications;
|
||||
$this->settings->backup_failure_telegram_notifications = $this->backupFailureTelegramNotifications;
|
||||
$this->settings->scheduled_task_success_telegram_notifications = $this->scheduledTaskSuccessTelegramNotifications;
|
||||
$this->settings->scheduled_task_failure_telegram_notifications = $this->scheduledTaskFailureTelegramNotifications;
|
||||
$this->settings->docker_cleanup_success_telegram_notifications = $this->dockerCleanupSuccessTelegramNotifications;
|
||||
$this->settings->docker_cleanup_failure_telegram_notifications = $this->dockerCleanupFailureTelegramNotifications;
|
||||
$this->settings->server_disk_usage_telegram_notifications = $this->serverDiskUsageTelegramNotifications;
|
||||
$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->save();
|
||||
refreshSession();
|
||||
} else {
|
||||
$this->telegramEnabled = $this->team->telegram_enabled;
|
||||
$this->telegramToken = $this->team->telegram_token;
|
||||
$this->telegramChatId = $this->team->telegram_chat_id;
|
||||
$this->telegramNotificationsTest = $this->team->telegram_notifications_test;
|
||||
$this->telegramNotificationsDeployments = $this->team->telegram_notifications_deployments;
|
||||
$this->telegramNotificationsStatusChanges = $this->team->telegram_notifications_status_changes;
|
||||
$this->telegramNotificationsDatabaseBackups = $this->team->telegram_notifications_database_backups;
|
||||
$this->telegramNotificationsScheduledTasks = $this->team->telegram_notifications_scheduled_tasks;
|
||||
$this->telegramNotificationsTestMessageThreadId = $this->team->telegram_notifications_test_message_thread_id;
|
||||
$this->telegramNotificationsDeploymentsMessageThreadId = $this->team->telegram_notifications_deployments_message_thread_id;
|
||||
$this->telegramNotificationsStatusChangesMessageThreadId = $this->team->telegram_notifications_status_changes_message_thread_id;
|
||||
$this->telegramNotificationsDatabaseBackupsMessageThreadId = $this->team->telegram_notifications_database_backups_message_thread_id;
|
||||
$this->telegramNotificationsScheduledTasksThreadId = $this->team->telegram_notifications_scheduled_tasks_thread_id;
|
||||
$this->telegramNotificationsServerDiskUsage = $this->team->telegram_notifications_server_disk_usage;
|
||||
}
|
||||
$this->telegramEnabled = $this->settings->telegram_enabled;
|
||||
$this->telegramToken = $this->settings->telegram_token;
|
||||
$this->telegramChatId = $this->settings->telegram_chat_id;
|
||||
|
||||
$this->deploymentSuccessTelegramNotifications = $this->settings->deployment_success_telegram_notifications;
|
||||
$this->deploymentFailureTelegramNotifications = $this->settings->deployment_failure_telegram_notifications;
|
||||
$this->statusChangeTelegramNotifications = $this->settings->status_change_telegram_notifications;
|
||||
$this->backupSuccessTelegramNotifications = $this->settings->backup_success_telegram_notifications;
|
||||
$this->backupFailureTelegramNotifications = $this->settings->backup_failure_telegram_notifications;
|
||||
$this->scheduledTaskSuccessTelegramNotifications = $this->settings->scheduled_task_success_telegram_notifications;
|
||||
$this->scheduledTaskFailureTelegramNotifications = $this->settings->scheduled_task_failure_telegram_notifications;
|
||||
$this->dockerCleanupSuccessTelegramNotifications = $this->settings->docker_cleanup_success_telegram_notifications;
|
||||
$this->dockerCleanupFailureTelegramNotifications = $this->settings->docker_cleanup_failure_telegram_notifications;
|
||||
$this->serverDiskUsageTelegramNotifications = $this->settings->server_disk_usage_telegram_notifications;
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
|
|
@ -150,7 +223,7 @@ class Telegram extends Component
|
|||
public function sendTestNotification()
|
||||
{
|
||||
try {
|
||||
$this->team->notify(new Test);
|
||||
$this->team->notify(new Test(channel: 'telegram'));
|
||||
$this->dispatch('success', 'Test notification sent.');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
|
|
|||
|
|
@ -23,9 +23,6 @@ class Index extends Component
|
|||
#[Validate('nullable|string|max:255')]
|
||||
public ?string $fqdn = null;
|
||||
|
||||
#[Validate('nullable|string|max:255')]
|
||||
public ?string $resale_license = null;
|
||||
|
||||
#[Validate('required|integer|min:1025|max:65535')]
|
||||
public int $public_port_min;
|
||||
|
||||
|
|
@ -83,7 +80,6 @@ class Index extends Component
|
|||
} else {
|
||||
$this->settings = instanceSettings();
|
||||
$this->fqdn = $this->settings->fqdn;
|
||||
$this->resale_license = $this->settings->resale_license;
|
||||
$this->public_port_min = $this->settings->public_port_min;
|
||||
$this->public_port_max = $this->settings->public_port_max;
|
||||
$this->custom_dns_servers = $this->settings->custom_dns_servers;
|
||||
|
|
@ -122,7 +118,6 @@ class Index extends Component
|
|||
}
|
||||
|
||||
$this->settings->fqdn = $this->fqdn;
|
||||
$this->settings->resale_license = $this->resale_license;
|
||||
$this->settings->public_port_min = $this->public_port_min;
|
||||
$this->settings->public_port_max = $this->public_port_max;
|
||||
$this->settings->custom_dns_servers = $this->custom_dns_servers;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
namespace App\Livewire;
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\Team;
|
||||
use App\Notifications\Test;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Livewire\Attributes\Locked;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
|
||||
|
|
@ -10,9 +14,21 @@ class SettingsEmail extends Component
|
|||
{
|
||||
public InstanceSettings $settings;
|
||||
|
||||
#[Locked]
|
||||
public Team $team;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $smtpEnabled = false;
|
||||
|
||||
#[Validate(['nullable', 'email'])]
|
||||
public ?string $smtpFromAddress = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $smtpFromName = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $smtpRecipients = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $smtpHost = null;
|
||||
|
||||
|
|
@ -20,29 +36,26 @@ class SettingsEmail extends Component
|
|||
public ?int $smtpPort = null;
|
||||
|
||||
#[Validate(['nullable', 'string', 'in:tls,ssl,none'])]
|
||||
public ?string $smtpEncryption = null;
|
||||
public ?string $smtpEncryption = 'tls';
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $smtpUsername = null;
|
||||
|
||||
#[Validate(['nullable'])]
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $smtpPassword = null;
|
||||
|
||||
#[Validate(['nullable', 'numeric'])]
|
||||
public ?int $smtpTimeout = null;
|
||||
|
||||
#[Validate(['nullable', 'email'])]
|
||||
public ?string $smtpFromAddress = null;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $smtpFromName = null;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $resendEnabled = false;
|
||||
|
||||
#[Validate(['nullable', 'string'])]
|
||||
public ?string $resendApiKey = null;
|
||||
|
||||
#[Validate(['nullable', 'email'])]
|
||||
public ?string $testEmailAddress = null;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
if (isInstanceAdmin() === false) {
|
||||
|
|
@ -50,6 +63,8 @@ class SettingsEmail extends Component
|
|||
}
|
||||
$this->settings = instanceSettings();
|
||||
$this->syncData();
|
||||
$this->team = auth()->user()->currentTeam();
|
||||
$this->testEmailAddress = auth()->user()->email;
|
||||
}
|
||||
|
||||
public function syncData(bool $toModel = false)
|
||||
|
|
@ -90,7 +105,7 @@ class SettingsEmail extends Component
|
|||
try {
|
||||
$this->resetErrorBag();
|
||||
$this->syncData(true);
|
||||
$this->dispatch('success', 'Settings saved.');
|
||||
$this->dispatch('success', 'Transactional email settings updated.');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
|
|
@ -99,19 +114,129 @@ class SettingsEmail extends Component
|
|||
public function instantSave(string $type)
|
||||
{
|
||||
try {
|
||||
$this->resetErrorBag();
|
||||
|
||||
if ($type === 'SMTP') {
|
||||
$this->resendEnabled = false;
|
||||
} else {
|
||||
$this->smtpEnabled = false;
|
||||
}
|
||||
$this->syncData(true);
|
||||
if ($this->smtpEnabled || $this->resendEnabled) {
|
||||
$this->dispatch('success', "{$type} enabled.");
|
||||
} else {
|
||||
$this->dispatch('success', "{$type} disabled.");
|
||||
$this->submitSmtp();
|
||||
} elseif ($type === 'Resend') {
|
||||
$this->submitResend();
|
||||
}
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
if ($type === 'SMTP') {
|
||||
$this->smtpEnabled = false;
|
||||
} elseif ($type === 'Resend') {
|
||||
$this->resendEnabled = false;
|
||||
}
|
||||
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function submitSmtp()
|
||||
{
|
||||
try {
|
||||
$this->validate([
|
||||
'smtpEnabled' => 'boolean',
|
||||
'smtpFromAddress' => 'required|email',
|
||||
'smtpFromName' => 'required|string',
|
||||
'smtpHost' => 'required|string',
|
||||
'smtpPort' => 'required|numeric',
|
||||
'smtpEncryption' => 'required|string|in:tls,ssl,none',
|
||||
'smtpUsername' => 'nullable|string',
|
||||
'smtpPassword' => 'nullable|string',
|
||||
'smtpTimeout' => 'nullable|numeric',
|
||||
], [
|
||||
'smtpFromAddress.required' => 'From Address is required.',
|
||||
'smtpFromAddress.email' => 'Please enter a valid email address.',
|
||||
'smtpFromName.required' => 'From Name is required.',
|
||||
'smtpHost.required' => 'SMTP Host is required.',
|
||||
'smtpPort.required' => 'SMTP Port is required.',
|
||||
'smtpPort.numeric' => 'SMTP Port must be a number.',
|
||||
'smtpEncryption.required' => 'Encryption type is required.',
|
||||
]);
|
||||
|
||||
$this->resendEnabled = false;
|
||||
$this->settings->resend_enabled = false;
|
||||
|
||||
$this->settings->smtp_enabled = $this->smtpEnabled;
|
||||
$this->settings->smtp_host = $this->smtpHost;
|
||||
$this->settings->smtp_port = $this->smtpPort;
|
||||
$this->settings->smtp_encryption = $this->smtpEncryption;
|
||||
$this->settings->smtp_username = $this->smtpUsername;
|
||||
$this->settings->smtp_password = $this->smtpPassword;
|
||||
$this->settings->smtp_timeout = $this->smtpTimeout;
|
||||
$this->settings->smtp_from_address = $this->smtpFromAddress;
|
||||
$this->settings->smtp_from_name = $this->smtpFromName;
|
||||
|
||||
$this->settings->save();
|
||||
|
||||
$this->dispatch('success', 'SMTP settings updated.');
|
||||
} catch (\Throwable $e) {
|
||||
$this->smtpEnabled = false;
|
||||
|
||||
return handleError($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function submitResend()
|
||||
{
|
||||
try {
|
||||
$this->validate([
|
||||
'resendEnabled' => 'boolean',
|
||||
'resendApiKey' => 'required|string',
|
||||
'smtpFromAddress' => 'required|email',
|
||||
'smtpFromName' => 'required|string',
|
||||
], [
|
||||
'resendApiKey.required' => 'Resend API Key is required.',
|
||||
'smtpFromAddress.required' => 'From Address is required.',
|
||||
'smtpFromAddress.email' => 'Please enter a valid email address.',
|
||||
'smtpFromName.required' => 'From Name is required.',
|
||||
]);
|
||||
|
||||
$this->smtpEnabled = false;
|
||||
$this->settings->smtp_enabled = false;
|
||||
|
||||
$this->settings->resend_enabled = $this->resendEnabled;
|
||||
$this->settings->resend_api_key = $this->resendApiKey;
|
||||
$this->settings->smtp_from_address = $this->smtpFromAddress;
|
||||
$this->settings->smtp_from_name = $this->smtpFromName;
|
||||
|
||||
$this->settings->save();
|
||||
|
||||
$this->dispatch('success', 'Resend settings updated.');
|
||||
} catch (\Throwable $e) {
|
||||
$this->resendEnabled = false;
|
||||
|
||||
return handleError($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function sendTestEmail()
|
||||
{
|
||||
try {
|
||||
$this->validate([
|
||||
'testEmailAddress' => 'required|email',
|
||||
], [
|
||||
'testEmailAddress.required' => 'Test email address is required.',
|
||||
'testEmailAddress.email' => 'Please enter a valid email address.',
|
||||
]);
|
||||
|
||||
$executed = RateLimiter::attempt(
|
||||
'test-email:'.$this->team->id,
|
||||
$perMinute = 0,
|
||||
function () {
|
||||
$this->team?->notify(new Test($this->testEmailAddress, 'email'));
|
||||
$this->dispatch('success', 'Test Email sent.');
|
||||
},
|
||||
$decaySeconds = 10,
|
||||
);
|
||||
|
||||
if (! $executed) {
|
||||
throw new \Exception('Too many messages sent!');
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Livewire\Waitlist;
|
||||
|
||||
use App\Jobs\SendConfirmationForWaitlistJob;
|
||||
use App\Models\User;
|
||||
use App\Models\Waitlist;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
|
||||
class Index extends Component
|
||||
{
|
||||
public string $email;
|
||||
|
||||
public int $users = 0;
|
||||
|
||||
public int $waitingInLine = 0;
|
||||
|
||||
protected $rules = [
|
||||
'email' => 'required|email',
|
||||
];
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.waitlist.index')->layout('layouts.simple');
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
if (config('constants.waitlist.enabled') == false) {
|
||||
return redirect()->route('register');
|
||||
}
|
||||
$this->waitingInLine = Waitlist::whereVerified(true)->count();
|
||||
$this->users = User::count();
|
||||
if (isDev()) {
|
||||
$this->email = 'waitlist@example.com';
|
||||
}
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->validate();
|
||||
try {
|
||||
$already_registered = User::whereEmail($this->email)->first();
|
||||
if ($already_registered) {
|
||||
throw new \Exception('You are already on the waitlist or registered. <br>Please check your email to verify your email address or contact support.');
|
||||
}
|
||||
$found = Waitlist::where('email', $this->email)->first();
|
||||
if ($found) {
|
||||
if (! $found->verified) {
|
||||
$this->dispatch('error', 'You are already on the waitlist. <br>Please check your email to verify your email address.');
|
||||
|
||||
return;
|
||||
}
|
||||
$this->dispatch('error', 'You are already on the waitlist. <br>You will be notified when your turn comes. <br>Thank you.');
|
||||
|
||||
return;
|
||||
}
|
||||
$waitlist = Waitlist::create([
|
||||
'email' => Str::lower($this->email),
|
||||
'type' => 'registration',
|
||||
]);
|
||||
|
||||
$this->dispatch('success', 'Check your email to verify your email address.');
|
||||
dispatch(new SendConfirmationForWaitlistJob($this->email, $waitlist->uuid));
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -327,7 +327,7 @@ class Application extends BaseModel
|
|||
return null;
|
||||
}
|
||||
|
||||
public function failedTaskLink($task_uuid)
|
||||
public function taskLink($task_uuid)
|
||||
{
|
||||
if (data_get($this, 'environment.project.uuid')) {
|
||||
$route = route('project.application.scheduled-tasks', [
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ abstract class BaseModel extends Model
|
|||
});
|
||||
}
|
||||
|
||||
public function name(): Attribute
|
||||
public function sanitizedName(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: fn () => sanitize_string($this->getRawOriginal('name')),
|
||||
|
|
|
|||
59
app/Models/DiscordNotificationSettings.php
Normal file
59
app/Models/DiscordNotificationSettings.php
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class DiscordNotificationSettings extends Model
|
||||
{
|
||||
use Notifiable;
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = [
|
||||
'team_id',
|
||||
|
||||
'discord_enabled',
|
||||
'discord_webhook_url',
|
||||
|
||||
'deployment_success_discord_notifications',
|
||||
'deployment_failure_discord_notifications',
|
||||
'status_change_discord_notifications',
|
||||
'backup_success_discord_notifications',
|
||||
'backup_failure_discord_notifications',
|
||||
'scheduled_task_success_discord_notifications',
|
||||
'scheduled_task_failure_discord_notifications',
|
||||
'docker_cleanup_discord_notifications',
|
||||
'server_disk_usage_discord_notifications',
|
||||
'server_reachable_discord_notifications',
|
||||
'server_unreachable_discord_notifications',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'discord_enabled' => 'boolean',
|
||||
'discord_webhook_url' => 'encrypted',
|
||||
|
||||
'deployment_success_discord_notifications' => 'boolean',
|
||||
'deployment_failure_discord_notifications' => 'boolean',
|
||||
'status_change_discord_notifications' => 'boolean',
|
||||
'backup_success_discord_notifications' => 'boolean',
|
||||
'backup_failure_discord_notifications' => 'boolean',
|
||||
'scheduled_task_success_discord_notifications' => 'boolean',
|
||||
'scheduled_task_failure_discord_notifications' => 'boolean',
|
||||
'docker_cleanup_discord_notifications' => 'boolean',
|
||||
'server_disk_usage_discord_notifications' => 'boolean',
|
||||
'server_reachable_discord_notifications' => 'boolean',
|
||||
'server_unreachable_discord_notifications' => 'boolean',
|
||||
];
|
||||
|
||||
public function team()
|
||||
{
|
||||
return $this->belongsTo(Team::class);
|
||||
}
|
||||
|
||||
public function isEnabled()
|
||||
{
|
||||
return $this->discord_enabled;
|
||||
}
|
||||
}
|
||||
79
app/Models/EmailNotificationSettings.php
Normal file
79
app/Models/EmailNotificationSettings.php
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class EmailNotificationSettings extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = [
|
||||
'team_id',
|
||||
|
||||
'smtp_enabled',
|
||||
'smtp_from_address',
|
||||
'smtp_from_name',
|
||||
'smtp_recipients',
|
||||
'smtp_host',
|
||||
'smtp_port',
|
||||
'smtp_encryption',
|
||||
'smtp_username',
|
||||
'smtp_password',
|
||||
'smtp_timeout',
|
||||
|
||||
'resend_enabled',
|
||||
'resend_api_key',
|
||||
|
||||
'use_instance_email_settings',
|
||||
|
||||
'deployment_success_email_notifications',
|
||||
'deployment_failure_email_notifications',
|
||||
'status_change_email_notifications',
|
||||
'backup_success_email_notifications',
|
||||
'backup_failure_email_notifications',
|
||||
'scheduled_task_success_email_notifications',
|
||||
'scheduled_task_failure_email_notifications',
|
||||
'server_disk_usage_email_notifications',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'smtp_enabled' => 'boolean',
|
||||
'smtp_from_address' => 'encrypted',
|
||||
'smtp_from_name' => 'encrypted',
|
||||
'smtp_recipients' => 'encrypted',
|
||||
'smtp_host' => 'encrypted',
|
||||
'smtp_port' => 'integer',
|
||||
'smtp_username' => 'encrypted',
|
||||
'smtp_password' => 'encrypted',
|
||||
'smtp_timeout' => 'integer',
|
||||
|
||||
'resend_enabled' => 'boolean',
|
||||
'resend_api_key' => 'encrypted',
|
||||
|
||||
'use_instance_email_settings' => 'boolean',
|
||||
|
||||
'deployment_success_email_notifications' => 'boolean',
|
||||
'deployment_failure_email_notifications' => 'boolean',
|
||||
'status_change_email_notifications' => 'boolean',
|
||||
'backup_success_email_notifications' => 'boolean',
|
||||
'backup_failure_email_notifications' => 'boolean',
|
||||
'scheduled_task_success_email_notifications' => 'boolean',
|
||||
'scheduled_task_failure_email_notifications' => 'boolean',
|
||||
'server_disk_usage_email_notifications' => 'boolean',
|
||||
];
|
||||
|
||||
public function team()
|
||||
{
|
||||
return $this->belongsTo(Team::class);
|
||||
}
|
||||
|
||||
public function isEnabled()
|
||||
{
|
||||
if (isCloud()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->smtp_enabled || $this->resend_enabled || $this->use_instance_email_settings;
|
||||
}
|
||||
}
|
||||
|
|
@ -16,8 +16,19 @@ class InstanceSettings extends Model implements SendsEmail
|
|||
protected $guarded = [];
|
||||
|
||||
protected $casts = [
|
||||
'resale_license' => 'encrypted',
|
||||
'smtp_enabled' => 'boolean',
|
||||
'smtp_from_address' => 'encrypted',
|
||||
'smtp_from_name' => 'encrypted',
|
||||
'smtp_recipients' => 'encrypted',
|
||||
'smtp_host' => 'encrypted',
|
||||
'smtp_port' => 'integer',
|
||||
'smtp_username' => 'encrypted',
|
||||
'smtp_password' => 'encrypted',
|
||||
'smtp_timeout' => 'integer',
|
||||
|
||||
'resend_enabled' => 'boolean',
|
||||
'resend_api_key' => 'encrypted',
|
||||
|
||||
'allowed_ip_ranges' => 'array',
|
||||
'is_auto_update_enabled' => 'boolean',
|
||||
'auto_update_frequency' => 'string',
|
||||
|
|
@ -81,7 +92,7 @@ class InstanceSettings extends Model implements SendsEmail
|
|||
return InstanceSettings::findOrFail(0);
|
||||
}
|
||||
|
||||
public function getRecepients($notification)
|
||||
public function getRecipients($notification)
|
||||
{
|
||||
$recipients = data_get($notification, 'emails', null);
|
||||
if (is_null($recipients) || $recipients === '') {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ class S3Storage extends BaseModel
|
|||
$this->is_usable = true;
|
||||
} catch (\Throwable $e) {
|
||||
$this->is_usable = false;
|
||||
if ($this->unusable_email_sent === false && is_transactional_emails_active()) {
|
||||
if ($this->unusable_email_sent === false && is_transactional_emails_enabled()) {
|
||||
$mail = new MailMessage;
|
||||
$mail->subject('Coolify: S3 Storage Connection Error');
|
||||
$mail->view('emails.s3-connection-error', ['name' => $this->name, 'reason' => $e->getMessage(), 'url' => route('storage.show', ['storage_uuid' => $this->uuid])]);
|
||||
|
|
|
|||
|
|
@ -1042,7 +1042,7 @@ $schema://$host {
|
|||
$this->unreachable_notification_sent = false;
|
||||
$this->save();
|
||||
$this->refresh();
|
||||
// $this->team->notify(new Reachable($this));
|
||||
$this->team->notify(new Reachable($this));
|
||||
}
|
||||
|
||||
public function sendUnreachableNotification()
|
||||
|
|
@ -1050,7 +1050,7 @@ $schema://$host {
|
|||
$this->unreachable_notification_sent = true;
|
||||
$this->save();
|
||||
$this->refresh();
|
||||
// $this->team->notify(new Unreachable($this));
|
||||
$this->team->notify(new Unreachable($this));
|
||||
}
|
||||
|
||||
public function validateConnection(bool $justCheckingNewKey = false)
|
||||
|
|
|
|||
|
|
@ -1140,7 +1140,7 @@ class Service extends BaseModel
|
|||
return null;
|
||||
}
|
||||
|
||||
public function failedTaskLink($task_uuid)
|
||||
public function taskLink($task_uuid)
|
||||
{
|
||||
if (data_get($this, 'environment.project.uuid')) {
|
||||
$route = route('project.service.scheduled-tasks', [
|
||||
|
|
|
|||
59
app/Models/SlackNotificationSettings.php
Normal file
59
app/Models/SlackNotificationSettings.php
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class SlackNotificationSettings extends Model
|
||||
{
|
||||
use Notifiable;
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = [
|
||||
'team_id',
|
||||
|
||||
'slack_enabled',
|
||||
'slack_webhook_url',
|
||||
|
||||
'deployment_success_slack_notifications',
|
||||
'deployment_failure_slack_notifications',
|
||||
'status_change_slack_notifications',
|
||||
'backup_success_slack_notifications',
|
||||
'backup_failure_slack_notifications',
|
||||
'scheduled_task_success_slack_notifications',
|
||||
'scheduled_task_failure_slack_notifications',
|
||||
'docker_cleanup_slack_notifications',
|
||||
'server_disk_usage_slack_notifications',
|
||||
'server_reachable_slack_notifications',
|
||||
'server_unreachable_slack_notifications',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'slack_enabled' => 'boolean',
|
||||
'slack_webhook_url' => 'encrypted',
|
||||
|
||||
'deployment_success_slack_notifications' => 'boolean',
|
||||
'deployment_failure_slack_notifications' => 'boolean',
|
||||
'status_change_slack_notifications' => 'boolean',
|
||||
'backup_success_slack_notifications' => 'boolean',
|
||||
'backup_failure_slack_notifications' => 'boolean',
|
||||
'scheduled_task_success_slack_notifications' => 'boolean',
|
||||
'scheduled_task_failure_slack_notifications' => 'boolean',
|
||||
'docker_cleanup_slack_notifications' => 'boolean',
|
||||
'server_disk_usage_slack_notifications' => 'boolean',
|
||||
'server_reachable_slack_notifications' => 'boolean',
|
||||
'server_unreachable_slack_notifications' => 'boolean',
|
||||
];
|
||||
|
||||
public function team()
|
||||
{
|
||||
return $this->belongsTo(Team::class);
|
||||
}
|
||||
|
||||
public function isEnabled()
|
||||
{
|
||||
return $this->slack_enabled;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ namespace App\Models;
|
|||
use App\Notifications\Channels\SendsDiscord;
|
||||
use App\Notifications\Channels\SendsEmail;
|
||||
use App\Notifications\Channels\SendsSlack;
|
||||
use App\Traits\HasNotificationSettings;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
|
@ -20,49 +21,8 @@ use OpenApi\Attributes as OA;
|
|||
'personal_team' => ['type' => 'boolean', 'description' => 'Whether the team is personal or not.'],
|
||||
'created_at' => ['type' => 'string', 'description' => 'The date and time the team was created.'],
|
||||
'updated_at' => ['type' => 'string', 'description' => 'The date and time the team was last updated.'],
|
||||
'smtp_enabled' => ['type' => 'boolean', 'description' => 'Whether SMTP is enabled or not.'],
|
||||
'smtp_from_address' => ['type' => 'string', 'description' => 'The email address to send emails from.'],
|
||||
'smtp_from_name' => ['type' => 'string', 'description' => 'The name to send emails from.'],
|
||||
'smtp_recipients' => ['type' => 'string', 'description' => 'The email addresses to send emails to.'],
|
||||
'smtp_host' => ['type' => 'string', 'description' => 'The SMTP host.'],
|
||||
'smtp_port' => ['type' => 'string', 'description' => 'The SMTP port.'],
|
||||
'smtp_encryption' => ['type' => 'string', 'description' => 'The SMTP encryption.'],
|
||||
'smtp_username' => ['type' => 'string', 'description' => 'The SMTP username.'],
|
||||
'smtp_password' => ['type' => 'string', 'description' => 'The SMTP password.'],
|
||||
'smtp_timeout' => ['type' => 'string', 'description' => 'The SMTP timeout.'],
|
||||
'smtp_notifications_test' => ['type' => 'boolean', 'description' => 'Whether to send test notifications via SMTP.'],
|
||||
'smtp_notifications_deployments' => ['type' => 'boolean', 'description' => 'Whether to send deployment notifications via SMTP.'],
|
||||
'smtp_notifications_status_changes' => ['type' => 'boolean', 'description' => 'Whether to send status change notifications via SMTP.'],
|
||||
'smtp_notifications_scheduled_tasks' => ['type' => 'boolean', 'description' => 'Whether to send scheduled task notifications via SMTP.'],
|
||||
'smtp_notifications_database_backups' => ['type' => 'boolean', 'description' => 'Whether to send database backup notifications via SMTP.'],
|
||||
'smtp_notifications_server_disk_usage' => ['type' => 'boolean', 'description' => 'Whether to send server disk usage notifications via SMTP.'],
|
||||
'discord_enabled' => ['type' => 'boolean', 'description' => 'Whether Discord is enabled or not.'],
|
||||
'discord_webhook_url' => ['type' => 'string', 'description' => 'The Discord webhook URL.'],
|
||||
'discord_notifications_test' => ['type' => 'boolean', 'description' => 'Whether to send test notifications via Discord.'],
|
||||
'discord_notifications_deployments' => ['type' => 'boolean', 'description' => 'Whether to send deployment notifications via Discord.'],
|
||||
'discord_notifications_status_changes' => ['type' => 'boolean', 'description' => 'Whether to send status change notifications via Discord.'],
|
||||
'discord_notifications_database_backups' => ['type' => 'boolean', 'description' => 'Whether to send database backup notifications via Discord.'],
|
||||
'discord_notifications_scheduled_tasks' => ['type' => 'boolean', 'description' => 'Whether to send scheduled task notifications via Discord.'],
|
||||
'discord_notifications_server_disk_usage' => ['type' => 'boolean', 'description' => 'Whether to send server disk usage notifications via Discord.'],
|
||||
'show_boarding' => ['type' => 'boolean', 'description' => 'Whether to show the boarding screen or not.'],
|
||||
'resend_enabled' => ['type' => 'boolean', 'description' => 'Whether to enable resending or not.'],
|
||||
'resend_api_key' => ['type' => 'string', 'description' => 'The resending API key.'],
|
||||
'use_instance_email_settings' => ['type' => 'boolean', 'description' => 'Whether to use instance email settings or not.'],
|
||||
'telegram_enabled' => ['type' => 'boolean', 'description' => 'Whether Telegram is enabled or not.'],
|
||||
'telegram_token' => ['type' => 'string', 'description' => 'The Telegram token.'],
|
||||
'telegram_chat_id' => ['type' => 'string', 'description' => 'The Telegram chat ID.'],
|
||||
'telegram_notifications_test' => ['type' => 'boolean', 'description' => 'Whether to send test notifications via Telegram.'],
|
||||
'telegram_notifications_deployments' => ['type' => 'boolean', 'description' => 'Whether to send deployment notifications via Telegram.'],
|
||||
'telegram_notifications_status_changes' => ['type' => 'boolean', 'description' => 'Whether to send status change notifications via Telegram.'],
|
||||
'telegram_notifications_database_backups' => ['type' => 'boolean', 'description' => 'Whether to send database backup notifications via Telegram.'],
|
||||
'telegram_notifications_test_message_thread_id' => ['type' => 'string', 'description' => 'The Telegram test message thread ID.'],
|
||||
'telegram_notifications_deployments_message_thread_id' => ['type' => 'string', 'description' => 'The Telegram deployment message thread ID.'],
|
||||
'telegram_notifications_status_changes_message_thread_id' => ['type' => 'string', 'description' => 'The Telegram status change message thread ID.'],
|
||||
'telegram_notifications_database_backups_message_thread_id' => ['type' => 'string', 'description' => 'The Telegram database backup message thread ID.'],
|
||||
|
||||
'custom_server_limit' => ['type' => 'string', 'description' => 'The custom server limit.'],
|
||||
'telegram_notifications_scheduled_tasks' => ['type' => 'boolean', 'description' => 'Whether to send scheduled task notifications via Telegram.'],
|
||||
'telegram_notifications_scheduled_tasks_thread_id' => ['type' => 'string', 'description' => 'The Telegram scheduled task message thread ID.'],
|
||||
'members' => new OA\Property(
|
||||
property: 'members',
|
||||
type: 'array',
|
||||
|
|
@ -71,20 +31,26 @@ use OpenApi\Attributes as OA;
|
|||
),
|
||||
]
|
||||
)]
|
||||
|
||||
class Team extends Model implements SendsDiscord, SendsEmail, SendsSlack
|
||||
{
|
||||
use Notifiable;
|
||||
use HasNotificationSettings, Notifiable;
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
protected $casts = [
|
||||
'personal_team' => 'boolean',
|
||||
'smtp_password' => 'encrypted',
|
||||
'resend_api_key' => 'encrypted',
|
||||
];
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
static::created(function ($team) {
|
||||
$team->emailNotificationSettings()->create();
|
||||
$team->discordNotificationSettings()->create();
|
||||
$team->slackNotificationSettings()->create();
|
||||
$team->telegramNotificationSettings()->create();
|
||||
});
|
||||
|
||||
static::saving(function ($team) {
|
||||
if (auth()->user()?->isMember()) {
|
||||
throw new \Exception('You are not allowed to update this team.');
|
||||
|
|
@ -115,34 +81,6 @@ class Team extends Model implements SendsDiscord, SendsEmail, SendsSlack
|
|||
});
|
||||
}
|
||||
|
||||
public function routeNotificationForDiscord()
|
||||
{
|
||||
return data_get($this, 'discord_webhook_url', null);
|
||||
}
|
||||
|
||||
public function routeNotificationForTelegram()
|
||||
{
|
||||
return [
|
||||
'token' => data_get($this, 'telegram_token', null),
|
||||
'chat_id' => data_get($this, 'telegram_chat_id', null),
|
||||
];
|
||||
}
|
||||
|
||||
public function routeNotificationForSlack()
|
||||
{
|
||||
return data_get($this, 'slack_webhook_url', null);
|
||||
}
|
||||
|
||||
public function getRecepients($notification)
|
||||
{
|
||||
$recipients = data_get($notification, 'emails', null);
|
||||
if (is_null($recipients)) {
|
||||
return $this->members()->pluck('email')->toArray();
|
||||
}
|
||||
|
||||
return explode(',', $recipients);
|
||||
}
|
||||
|
||||
public static function serverLimitReached()
|
||||
{
|
||||
$serverLimit = Team::serverLimit();
|
||||
|
|
@ -196,10 +134,66 @@ class Team extends Model implements SendsDiscord, SendsEmail, SendsSlack
|
|||
|
||||
return $serverLimit ?? 2;
|
||||
}
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
public function routeNotificationForDiscord()
|
||||
{
|
||||
return data_get($this, 'discord_webhook_url', null);
|
||||
}
|
||||
|
||||
public function routeNotificationForTelegram()
|
||||
{
|
||||
return [
|
||||
'token' => data_get($this, 'telegram_token', null),
|
||||
'chat_id' => data_get($this, 'telegram_chat_id', null),
|
||||
];
|
||||
}
|
||||
|
||||
public function routeNotificationForSlack()
|
||||
{
|
||||
return data_get($this, 'slack_webhook_url', null);
|
||||
}
|
||||
|
||||
public function getRecipients($notification)
|
||||
{
|
||||
$recipients = data_get($notification, 'emails', null);
|
||||
if (is_null($recipients)) {
|
||||
return $this->members()->pluck('email')->toArray();
|
||||
}
|
||||
|
||||
return explode(',', $recipients);
|
||||
}
|
||||
|
||||
public function isAnyNotificationEnabled()
|
||||
{
|
||||
if (isCloud()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->getNotificationSettings('email')?->isEnabled() ||
|
||||
$this->getNotificationSettings('discord')?->isEnabled() ||
|
||||
$this->getNotificationSettings('slack')?->isEnabled() ||
|
||||
$this->getNotificationSettings('telegram')?->isEnabled();
|
||||
}
|
||||
|
||||
public function subscriptionEnded()
|
||||
{
|
||||
$this->subscription->update([
|
||||
'stripe_subscription_id' => null,
|
||||
'stripe_plan_id' => null,
|
||||
'stripe_cancel_at_period_end' => false,
|
||||
'stripe_invoice_paid' => false,
|
||||
'stripe_trial_already_ended' => false,
|
||||
]);
|
||||
foreach ($this->servers as $server) {
|
||||
$server->settings()->update([
|
||||
'is_usable' => false,
|
||||
'is_reachable' => false,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function environment_variables()
|
||||
{
|
||||
return $this->hasMany(SharedEnvironmentVariable::class)->whereNull('project_id')->whereNull('environment_id');
|
||||
|
|
@ -263,32 +257,23 @@ class Team extends Model implements SendsDiscord, SendsEmail, SendsSlack
|
|||
return $this->hasMany(S3Storage::class)->where('is_usable', true);
|
||||
}
|
||||
|
||||
public function subscriptionEnded()
|
||||
public function emailNotificationSettings()
|
||||
{
|
||||
$this->subscription->update([
|
||||
'stripe_subscription_id' => null,
|
||||
'stripe_plan_id' => null,
|
||||
'stripe_cancel_at_period_end' => false,
|
||||
'stripe_invoice_paid' => false,
|
||||
'stripe_trial_already_ended' => false,
|
||||
]);
|
||||
foreach ($this->servers as $server) {
|
||||
$server->settings()->update([
|
||||
'is_usable' => false,
|
||||
'is_reachable' => false,
|
||||
]);
|
||||
}
|
||||
return $this->hasOne(EmailNotificationSettings::class);
|
||||
}
|
||||
|
||||
public function isAnyNotificationEnabled()
|
||||
public function discordNotificationSettings()
|
||||
{
|
||||
if (isCloud()) {
|
||||
return true;
|
||||
}
|
||||
if ($this->smtp_enabled || $this->resend_enabled || $this->discord_enabled || $this->telegram_enabled || $this->use_instance_email_settings) {
|
||||
return true;
|
||||
}
|
||||
return $this->hasOne(DiscordNotificationSettings::class);
|
||||
}
|
||||
|
||||
return false;
|
||||
public function telegramNotificationSettings()
|
||||
{
|
||||
return $this->hasOne(TelegramNotificationSettings::class);
|
||||
}
|
||||
|
||||
public function slackNotificationSettings()
|
||||
{
|
||||
return $this->hasOne(SlackNotificationSettings::class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
85
app/Models/TelegramNotificationSettings.php
Normal file
85
app/Models/TelegramNotificationSettings.php
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class TelegramNotificationSettings extends Model
|
||||
{
|
||||
use Notifiable;
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = [
|
||||
'team_id',
|
||||
|
||||
'telegram_enabled',
|
||||
'telegram_token',
|
||||
'telegram_chat_id',
|
||||
|
||||
'deployment_success_telegram_notifications',
|
||||
'deployment_failure_telegram_notifications',
|
||||
'status_change_telegram_notifications',
|
||||
'backup_success_telegram_notifications',
|
||||
'backup_failure_telegram_notifications',
|
||||
'scheduled_task_success_telegram_notifications',
|
||||
'scheduled_task_failure_telegram_notifications',
|
||||
'docker_cleanup_telegram_notifications',
|
||||
'server_disk_usage_telegram_notifications',
|
||||
'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',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'telegram_enabled' => 'boolean',
|
||||
'telegram_token' => 'encrypted',
|
||||
'telegram_chat_id' => 'encrypted',
|
||||
|
||||
'deployment_success_telegram_notifications' => 'boolean',
|
||||
'deployment_failure_telegram_notifications' => 'boolean',
|
||||
'status_change_telegram_notifications' => 'boolean',
|
||||
'backup_success_telegram_notifications' => 'boolean',
|
||||
'backup_failure_telegram_notifications' => 'boolean',
|
||||
'scheduled_task_success_telegram_notifications' => 'boolean',
|
||||
'scheduled_task_failure_telegram_notifications' => 'boolean',
|
||||
'docker_cleanup_telegram_notifications' => 'boolean',
|
||||
'server_disk_usage_telegram_notifications' => 'boolean',
|
||||
'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',
|
||||
];
|
||||
|
||||
public function team()
|
||||
{
|
||||
return $this->belongsTo(Team::class);
|
||||
}
|
||||
|
||||
public function isEnabled()
|
||||
{
|
||||
return $this->telegram_enabled;
|
||||
}
|
||||
}
|
||||
|
|
@ -114,7 +114,7 @@ class User extends Authenticatable implements SendsEmail
|
|||
return $this->belongsToMany(Team::class)->withPivot('role');
|
||||
}
|
||||
|
||||
public function getRecepients($notification)
|
||||
public function getRecipients($notification)
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
class Waitlist extends BaseModel
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = [];
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ class DeploymentFailed extends CustomEmailNotification
|
|||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return setNotificationChannels($notifiable, 'deployments');
|
||||
return $notifiable->getEnabledChannels('deployment_failure');
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
|
|
|
|||
|
|
@ -45,13 +45,7 @@ class DeploymentSuccess extends CustomEmailNotification
|
|||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
$channels = setNotificationChannels($notifiable, 'deployments');
|
||||
if (isCloud()) {
|
||||
// TODO: Make batch notifications work with email
|
||||
$channels = array_diff($channels, [\App\Notifications\Channels\EmailChannel::class]);
|
||||
}
|
||||
|
||||
return $channels;
|
||||
return $notifiable->getEnabledChannels('deployment_success');
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class StatusChanged extends CustomEmailNotification
|
|||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return setNotificationChannels($notifiable, 'status_changes');
|
||||
return $notifiable->getEnabledChannels('status_change');
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
|
|
|
|||
|
|
@ -13,10 +13,13 @@ class DiscordChannel
|
|||
public function send(SendsDiscord $notifiable, Notification $notification): void
|
||||
{
|
||||
$message = $notification->toDiscord();
|
||||
$webhookUrl = $notifiable->routeNotificationForDiscord();
|
||||
if (! $webhookUrl) {
|
||||
|
||||
$discordSettings = $notifiable->discordNotificationSettings;
|
||||
|
||||
if (! $discordSettings || ! $discordSettings->isEnabled() || ! $discordSettings->discord_webhook_url) {
|
||||
return;
|
||||
}
|
||||
SendMessageToDiscordJob::dispatch($message, $webhookUrl);
|
||||
|
||||
SendMessageToDiscordJob::dispatch($message, $discordSettings->discord_webhook_url);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class EmailChannel
|
|||
{
|
||||
try {
|
||||
$this->bootConfigs($notifiable);
|
||||
$recipients = $notifiable->getRecepients($notification);
|
||||
$recipients = $notifiable->getRecipients($notification);
|
||||
if (count($recipients) === 0) {
|
||||
throw new Exception('No email recipients found');
|
||||
}
|
||||
|
|
@ -46,7 +46,9 @@ class EmailChannel
|
|||
|
||||
private function bootConfigs($notifiable): void
|
||||
{
|
||||
if (data_get($notifiable, 'use_instance_email_settings')) {
|
||||
$emailSettings = $notifiable->emailNotificationSettings;
|
||||
|
||||
if ($emailSettings->use_instance_email_settings) {
|
||||
$type = set_transanctional_email_settings();
|
||||
if (! $type) {
|
||||
throw new Exception('No email settings found.');
|
||||
|
|
@ -54,24 +56,27 @@ class EmailChannel
|
|||
|
||||
return;
|
||||
}
|
||||
config()->set('mail.from.address', data_get($notifiable, 'smtp_from_address', 'test@example.com'));
|
||||
config()->set('mail.from.name', data_get($notifiable, 'smtp_from_name', 'Test'));
|
||||
if (data_get($notifiable, 'resend_enabled')) {
|
||||
|
||||
config()->set('mail.from.address', $emailSettings->smtp_from_address ?? 'test@example.com');
|
||||
config()->set('mail.from.name', $emailSettings->smtp_from_name ?? 'Test');
|
||||
|
||||
if ($emailSettings->resend_enabled) {
|
||||
config()->set('mail.default', 'resend');
|
||||
config()->set('resend.api_key', data_get($notifiable, 'resend_api_key'));
|
||||
config()->set('resend.api_key', $emailSettings->resend_api_key);
|
||||
}
|
||||
if (data_get($notifiable, 'smtp_enabled')) {
|
||||
|
||||
if ($emailSettings->smtp_enabled) {
|
||||
config()->set('mail.default', 'smtp');
|
||||
config()->set('mail.mailers.smtp', [
|
||||
'transport' => 'smtp',
|
||||
'host' => data_get($notifiable, 'smtp_host'),
|
||||
'port' => data_get($notifiable, 'smtp_port'),
|
||||
'encryption' => data_get($notifiable, 'smtp_encryption') === 'none' ? null : data_get($notifiable, 'smtp_encryption'),
|
||||
'username' => data_get($notifiable, 'smtp_username'),
|
||||
'password' => data_get($notifiable, 'smtp_password'),
|
||||
'timeout' => data_get($notifiable, 'smtp_timeout'),
|
||||
'host' => $emailSettings->smtp_host,
|
||||
'port' => $emailSettings->smtp_port,
|
||||
'encryption' => $emailSettings->smtp_encryption === 'none' ? null : $emailSettings->smtp_encryption,
|
||||
'username' => $emailSettings->smtp_username,
|
||||
'password' => $emailSettings->smtp_password,
|
||||
'timeout' => $emailSettings->smtp_timeout,
|
||||
'local_domain' => null,
|
||||
'auto_tls' => data_get($notifiable, 'smtp_encryption') === 'none' ? '0' : '',
|
||||
'auto_tls' => $emailSettings->smtp_encryption === 'none' ? '0' : '',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ namespace App\Notifications\Channels;
|
|||
|
||||
interface SendsEmail
|
||||
{
|
||||
public function getRecepients($notification);
|
||||
public function getRecipients($notification);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,12 @@ class SlackChannel
|
|||
public function send(SendsSlack $notifiable, Notification $notification): void
|
||||
{
|
||||
$message = $notification->toSlack();
|
||||
$webhookUrl = $notifiable->routeNotificationForSlack();
|
||||
if (! $webhookUrl) {
|
||||
$slackSettings = $notifiable->slackNotificationSettings;
|
||||
|
||||
if (! $slackSettings || ! $slackSettings->isEnabled() || ! $slackSettings->slack_webhook_url) {
|
||||
return;
|
||||
}
|
||||
SendMessageToSlackJob::dispatch($message, $webhookUrl);
|
||||
|
||||
SendMessageToSlackJob::dispatch($message, $slackSettings->slack_webhook_url);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,38 +9,32 @@ class TelegramChannel
|
|||
public function send($notifiable, $notification): void
|
||||
{
|
||||
$data = $notification->toTelegram($notifiable);
|
||||
$telegramData = $notifiable->routeNotificationForTelegram();
|
||||
$settings = $notifiable->telegramNotificationSettings;
|
||||
|
||||
$message = data_get($data, 'message');
|
||||
$buttons = data_get($data, 'buttons', []);
|
||||
$telegramToken = data_get($telegramData, 'token');
|
||||
$chatId = data_get($telegramData, 'chat_id');
|
||||
$topicId = null;
|
||||
$topicsInstance = get_class($notification);
|
||||
$telegramToken = $settings->telegram_token;
|
||||
$chatId = $settings->telegram_chat_id;
|
||||
|
||||
$topicId = match (get_class($notification)) {
|
||||
\App\Notifications\Test::class => $settings->telegram_notifications_test_topic_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,
|
||||
default => null,
|
||||
};
|
||||
|
||||
switch ($topicsInstance) {
|
||||
case \App\Notifications\Test::class:
|
||||
$topicId = data_get($notifiable, 'telegram_notifications_test_message_thread_id');
|
||||
break;
|
||||
case \App\Notifications\Application\StatusChanged::class:
|
||||
case \App\Notifications\Container\ContainerRestarted::class:
|
||||
case \App\Notifications\Container\ContainerStopped::class:
|
||||
$topicId = data_get($notifiable, 'telegram_notifications_status_changes_message_thread_id');
|
||||
break;
|
||||
case \App\Notifications\Application\DeploymentSuccess::class:
|
||||
case \App\Notifications\Application\DeploymentFailed::class:
|
||||
$topicId = data_get($notifiable, 'telegram_notifications_deployments_message_thread_id');
|
||||
break;
|
||||
case \App\Notifications\Database\BackupSuccess::class:
|
||||
case \App\Notifications\Database\BackupFailed::class:
|
||||
$topicId = data_get($notifiable, 'telegram_notifications_database_backups_message_thread_id');
|
||||
break;
|
||||
case \App\Notifications\ScheduledTask\TaskFailed::class:
|
||||
$topicId = data_get($notifiable, 'telegram_notifications_scheduled_tasks_thread_id');
|
||||
break;
|
||||
}
|
||||
if (! $telegramToken || ! $chatId || ! $message) {
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessageToTelegramJob::dispatch($message, $buttons, $telegramToken, $chatId, $topicId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ use Exception;
|
|||
use Illuminate\Mail\Message;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Log;
|
||||
|
||||
class TransactionalEmailChannel
|
||||
{
|
||||
|
|
@ -15,8 +14,6 @@ class TransactionalEmailChannel
|
|||
{
|
||||
$settings = instanceSettings();
|
||||
if (! data_get($settings, 'smtp_enabled') && ! data_get($settings, 'resend_enabled')) {
|
||||
Log::info('SMTP/Resend not enabled');
|
||||
|
||||
return;
|
||||
}
|
||||
$email = $notifiable->email;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class ContainerRestarted extends CustomEmailNotification
|
|||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return setNotificationChannels($notifiable, 'status_changes');
|
||||
return $notifiable->getEnabledChannels('status_change');
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class ContainerStopped extends CustomEmailNotification
|
|||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return setNotificationChannels($notifiable, 'status_changes');
|
||||
return $notifiable->getEnabledChannels('status_change');
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
|
|
|
|||
|
|
@ -23,13 +23,13 @@ class BackupFailed extends CustomEmailNotification
|
|||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return setNotificationChannels($notifiable, 'database_backups');
|
||||
return $notifiable->getEnabledChannels('backup_failure');
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mail = new MailMessage;
|
||||
$mail->subject("Coolify: [ACTION REQUIRED] Backup FAILED for {$this->database->name}");
|
||||
$mail->subject("Coolify: [ACTION REQUIRED] Database Backup FAILED for {$this->database->name}");
|
||||
$mail->view('emails.backup-failed', [
|
||||
'name' => $this->name,
|
||||
'database_name' => $this->database_name,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class BackupSuccess extends CustomEmailNotification
|
|||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return setNotificationChannels($notifiable, 'database_backups');
|
||||
return $notifiable->getEnabledChannels('backup_success');
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
namespace App\Notifications\Internal;
|
||||
|
||||
use App\Notifications\Channels\DiscordChannel;
|
||||
use App\Notifications\Channels\SlackChannel;
|
||||
use App\Notifications\Channels\TelegramChannel;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Bus\Queueable;
|
||||
|
|
@ -24,22 +21,7 @@ class GeneralNotification extends Notification implements ShouldQueue
|
|||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
$channels = [];
|
||||
$isDiscordEnabled = data_get($notifiable, 'discord_enabled');
|
||||
$isTelegramEnabled = data_get($notifiable, 'telegram_enabled');
|
||||
$isSlackEnabled = data_get($notifiable, 'slack_enabled');
|
||||
|
||||
if ($isDiscordEnabled) {
|
||||
$channels[] = DiscordChannel::class;
|
||||
}
|
||||
if ($isTelegramEnabled) {
|
||||
$channels[] = TelegramChannel::class;
|
||||
}
|
||||
if ($isSlackEnabled) {
|
||||
$channels[] = SlackChannel::class;
|
||||
}
|
||||
|
||||
return $channels;
|
||||
return $notifiable->getEnabledChannels('general');
|
||||
}
|
||||
|
||||
public function toDiscord(): DiscordMessage
|
||||
|
|
|
|||
|
|
@ -16,15 +16,15 @@ class TaskFailed extends CustomEmailNotification
|
|||
{
|
||||
$this->onQueue('high');
|
||||
if ($task->application) {
|
||||
$this->url = $task->application->failedTaskLink($task->uuid);
|
||||
$this->url = $task->application->taskLink($task->uuid);
|
||||
} elseif ($task->service) {
|
||||
$this->url = $task->service->failedTaskLink($task->uuid);
|
||||
$this->url = $task->service->taskLink($task->uuid);
|
||||
}
|
||||
}
|
||||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return setNotificationChannels($notifiable, 'scheduled_tasks');
|
||||
return $notifiable->getEnabledChannels('scheduled_task_failure');
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
|
|
|
|||
88
app/Notifications/ScheduledTask/TaskSuccess.php
Normal file
88
app/Notifications/ScheduledTask/TaskSuccess.php
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications\ScheduledTask;
|
||||
|
||||
use App\Models\ScheduledTask;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class TaskSuccess extends CustomEmailNotification
|
||||
{
|
||||
public ?string $url = null;
|
||||
|
||||
public function __construct(public ScheduledTask $task, public string $output)
|
||||
{
|
||||
$this->onQueue('high');
|
||||
if ($task->application) {
|
||||
$this->url = $task->application->taskLink($task->uuid);
|
||||
} elseif ($task->service) {
|
||||
$this->url = $task->service->taskLink($task->uuid);
|
||||
}
|
||||
}
|
||||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return $notifiable->getEnabledChannels('scheduled_task_success');
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mail = new MailMessage;
|
||||
$mail->subject("Coolify: Scheduled task ({$this->task->name}) succeeded.");
|
||||
$mail->view('emails.scheduled-task-success', [
|
||||
'task' => $this->task,
|
||||
'url' => $this->url,
|
||||
'output' => $this->output,
|
||||
]);
|
||||
|
||||
return $mail;
|
||||
}
|
||||
|
||||
public function toDiscord(): DiscordMessage
|
||||
{
|
||||
$message = new DiscordMessage(
|
||||
title: ':white_check_mark: Scheduled task succeeded',
|
||||
description: "Scheduled task ({$this->task->name}) succeeded.",
|
||||
color: DiscordMessage::successColor(),
|
||||
);
|
||||
|
||||
if ($this->url) {
|
||||
$message->addField('Scheduled task', '[Link]('.$this->url.')');
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
public function toTelegram(): array
|
||||
{
|
||||
$message = "Coolify: Scheduled task ({$this->task->name}) succeeded.";
|
||||
if ($this->url) {
|
||||
$buttons[] = [
|
||||
'text' => 'Open task in Coolify',
|
||||
'url' => (string) $this->url,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'message' => $message,
|
||||
];
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
$title = 'Scheduled task succeeded';
|
||||
$description = "Scheduled task ({$this->task->name}) succeeded.";
|
||||
|
||||
if ($this->url) {
|
||||
$description .= "\n\n**Task URL:** {$this->url}";
|
||||
}
|
||||
|
||||
return new SlackMessage(
|
||||
title: $title,
|
||||
description: $description,
|
||||
color: SlackMessage::successColor()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Notifications\Channels\DiscordChannel;
|
||||
use App\Notifications\Channels\TelegramChannel;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
|
||||
class DockerCleanup extends CustomEmailNotification
|
||||
{
|
||||
public function __construct(public Server $server, public string $message)
|
||||
{
|
||||
$this->onQueue('high');
|
||||
}
|
||||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
$channels = [];
|
||||
// $isEmailEnabled = isEmailEnabled($notifiable);
|
||||
$isDiscordEnabled = data_get($notifiable, 'discord_enabled');
|
||||
$isTelegramEnabled = data_get($notifiable, 'telegram_enabled');
|
||||
$isSlackEnabled = data_get($notifiable, 'slack_enabled');
|
||||
if ($isDiscordEnabled) {
|
||||
$channels[] = DiscordChannel::class;
|
||||
}
|
||||
// if ($isEmailEnabled) {
|
||||
// $channels[] = EmailChannel::class;
|
||||
// }
|
||||
if ($isTelegramEnabled) {
|
||||
$channels[] = TelegramChannel::class;
|
||||
}
|
||||
if ($isSlackEnabled) {
|
||||
$channels[] = SlackChannel::class;
|
||||
}
|
||||
|
||||
return $channels;
|
||||
}
|
||||
|
||||
// public function toMail(): MailMessage
|
||||
// {
|
||||
// $mail = new MailMessage();
|
||||
// $mail->subject("Coolify: Server ({$this->server->name}) high disk usage detected!");
|
||||
// $mail->view('emails.high-disk-usage', [
|
||||
// 'name' => $this->server->name,
|
||||
// 'disk_usage' => $this->disk_usage,
|
||||
// 'threshold' => $this->docker_cleanup_threshold,
|
||||
// ]);
|
||||
// return $mail;
|
||||
// }
|
||||
|
||||
public function toDiscord(): DiscordMessage
|
||||
{
|
||||
return new DiscordMessage(
|
||||
title: ':white_check_mark: Server cleanup job done',
|
||||
description: $this->message,
|
||||
color: DiscordMessage::successColor(),
|
||||
);
|
||||
}
|
||||
|
||||
public function toTelegram(): array
|
||||
{
|
||||
return [
|
||||
'message' => "Coolify: Server '{$this->server->name}' cleanup job done!\n\n{$this->message}",
|
||||
];
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
return new SlackMessage(
|
||||
title: 'Server cleanup job done',
|
||||
description: "Server '{$this->server->name}' cleanup job done!\n\n{$this->message}",
|
||||
color: SlackMessage::successColor()
|
||||
);
|
||||
}
|
||||
}
|
||||
59
app/Notifications/Server/DockerCleanupFailed.php
Normal file
59
app/Notifications/Server/DockerCleanupFailed.php
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class DockerCleanupFailed extends CustomEmailNotification
|
||||
{
|
||||
public function __construct(public Server $server, public string $message)
|
||||
{
|
||||
$this->onQueue('high');
|
||||
}
|
||||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return $notifiable->getEnabledChannels('docker_cleanup_failure');
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mail = new MailMessage;
|
||||
$mail->subject("Coolify: [ACTION REQUIRED] Docker cleanup job failed on {$this->server->name}");
|
||||
$mail->view('emails.docker-cleanup-failed', [
|
||||
'name' => $this->server->name,
|
||||
'text' => $this->message,
|
||||
]);
|
||||
|
||||
return $mail;
|
||||
}
|
||||
|
||||
public function toDiscord(): DiscordMessage
|
||||
{
|
||||
return new DiscordMessage(
|
||||
title: ':cross_mark: Coolify: [ACTION REQUIRED] Docker cleanup job failed on '.$this->server->name,
|
||||
description: $this->message,
|
||||
color: DiscordMessage::errorColor(),
|
||||
);
|
||||
}
|
||||
|
||||
public function toTelegram(): array
|
||||
{
|
||||
return [
|
||||
'message' => "Coolify: [ACTION REQUIRED] Docker cleanup job failed on {$this->server->name}!\n\n{$this->message}",
|
||||
];
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
return new SlackMessage(
|
||||
title: 'Coolify: [ACTION REQUIRED] Docker cleanup job failed',
|
||||
description: "Docker cleanup job failed on '{$this->server->name}'!\n\n{$this->message}",
|
||||
color: SlackMessage::errorColor()
|
||||
);
|
||||
}
|
||||
}
|
||||
59
app/Notifications/Server/DockerCleanupSuccess.php
Normal file
59
app/Notifications/Server/DockerCleanupSuccess.php
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class DockerCleanupSuccess extends CustomEmailNotification
|
||||
{
|
||||
public function __construct(public Server $server, public string $message)
|
||||
{
|
||||
$this->onQueue('high');
|
||||
}
|
||||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return $notifiable->getEnabledChannels('docker_cleanup_success');
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mail = new MailMessage;
|
||||
$mail->subject("Coolify: Docker cleanup job succeeded on {$this->server->name}");
|
||||
$mail->view('emails.docker-cleanup-success', [
|
||||
'name' => $this->server->name,
|
||||
'text' => $this->message,
|
||||
]);
|
||||
|
||||
return $mail;
|
||||
}
|
||||
|
||||
public function toDiscord(): DiscordMessage
|
||||
{
|
||||
return new DiscordMessage(
|
||||
title: ':white_check_mark: Coolify: Docker cleanup job succeeded on '.$this->server->name,
|
||||
description: $this->message,
|
||||
color: DiscordMessage::successColor(),
|
||||
);
|
||||
}
|
||||
|
||||
public function toTelegram(): array
|
||||
{
|
||||
return [
|
||||
'message' => "Coolify: Docker cleanup job succeeded on {$this->server->name}!\n\n{$this->message}",
|
||||
];
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
return new SlackMessage(
|
||||
title: 'Coolify: Docker cleanup job succeeded',
|
||||
description: "Docker cleanup job succeeded on '{$this->server->name}'!\n\n{$this->message}",
|
||||
color: SlackMessage::successColor()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,10 +3,6 @@
|
|||
namespace App\Notifications\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Notifications\Channels\DiscordChannel;
|
||||
use App\Notifications\Channels\EmailChannel;
|
||||
use App\Notifications\Channels\SlackChannel;
|
||||
use App\Notifications\Channels\TelegramChannel;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
|
|
@ -21,25 +17,7 @@ class ForceDisabled extends CustomEmailNotification
|
|||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
$channels = [];
|
||||
$isEmailEnabled = isEmailEnabled($notifiable);
|
||||
$isDiscordEnabled = data_get($notifiable, 'discord_enabled');
|
||||
$isTelegramEnabled = data_get($notifiable, 'telegram_enabled');
|
||||
$isSlackEnabled = data_get($notifiable, 'slack_enabled');
|
||||
if ($isDiscordEnabled) {
|
||||
$channels[] = DiscordChannel::class;
|
||||
}
|
||||
if ($isEmailEnabled) {
|
||||
$channels[] = EmailChannel::class;
|
||||
}
|
||||
if ($isTelegramEnabled) {
|
||||
$channels[] = TelegramChannel::class;
|
||||
}
|
||||
if ($isSlackEnabled) {
|
||||
$channels[] = SlackChannel::class;
|
||||
}
|
||||
|
||||
return $channels;
|
||||
return $notifiable->getEnabledChannels('server_force_disabled');
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
|
|
|
|||
|
|
@ -3,10 +3,6 @@
|
|||
namespace App\Notifications\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Notifications\Channels\DiscordChannel;
|
||||
use App\Notifications\Channels\EmailChannel;
|
||||
use App\Notifications\Channels\SlackChannel;
|
||||
use App\Notifications\Channels\TelegramChannel;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
|
|
@ -21,25 +17,7 @@ class ForceEnabled extends CustomEmailNotification
|
|||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
$channels = [];
|
||||
$isEmailEnabled = isEmailEnabled($notifiable);
|
||||
$isDiscordEnabled = data_get($notifiable, 'discord_enabled');
|
||||
$isTelegramEnabled = data_get($notifiable, 'telegram_enabled');
|
||||
$isSlackEnabled = data_get($notifiable, 'slack_enabled');
|
||||
if ($isDiscordEnabled) {
|
||||
$channels[] = DiscordChannel::class;
|
||||
}
|
||||
if ($isEmailEnabled) {
|
||||
$channels[] = EmailChannel::class;
|
||||
}
|
||||
if ($isTelegramEnabled) {
|
||||
$channels[] = TelegramChannel::class;
|
||||
}
|
||||
if ($isSlackEnabled) {
|
||||
$channels[] = SlackChannel::class;
|
||||
}
|
||||
|
||||
return $channels;
|
||||
return $notifiable->getEnabledChannels('server_force_enabled');
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class HighDiskUsage extends CustomEmailNotification
|
|||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return setNotificationChannels($notifiable, 'server_disk_usage');
|
||||
return $notifiable->getEnabledChannels('server_disk_usage');
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
|
|
|
|||
|
|
@ -3,10 +3,6 @@
|
|||
namespace App\Notifications\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Notifications\Channels\DiscordChannel;
|
||||
use App\Notifications\Channels\EmailChannel;
|
||||
use App\Notifications\Channels\SlackChannel;
|
||||
use App\Notifications\Channels\TelegramChannel;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
|
|
@ -30,25 +26,7 @@ class Reachable extends CustomEmailNotification
|
|||
return [];
|
||||
}
|
||||
|
||||
$channels = [];
|
||||
$isEmailEnabled = isEmailEnabled($notifiable);
|
||||
$isDiscordEnabled = data_get($notifiable, 'discord_enabled');
|
||||
$isTelegramEnabled = data_get($notifiable, 'telegram_enabled');
|
||||
$isSlackEnabled = data_get($notifiable, 'slack_enabled');
|
||||
if ($isDiscordEnabled) {
|
||||
$channels[] = DiscordChannel::class;
|
||||
}
|
||||
if ($isEmailEnabled) {
|
||||
$channels[] = EmailChannel::class;
|
||||
}
|
||||
if ($isTelegramEnabled) {
|
||||
$channels[] = TelegramChannel::class;
|
||||
}
|
||||
if ($isSlackEnabled) {
|
||||
$channels[] = SlackChannel::class;
|
||||
}
|
||||
|
||||
return $channels;
|
||||
return $notifiable->getEnabledChannels('server_reachable');
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
|
|
|
|||
|
|
@ -3,10 +3,6 @@
|
|||
namespace App\Notifications\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Notifications\Channels\DiscordChannel;
|
||||
use App\Notifications\Channels\EmailChannel;
|
||||
use App\Notifications\Channels\SlackChannel;
|
||||
use App\Notifications\Channels\TelegramChannel;
|
||||
use App\Notifications\CustomEmailNotification;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
|
|
@ -30,26 +26,7 @@ class Unreachable extends CustomEmailNotification
|
|||
return [];
|
||||
}
|
||||
|
||||
$channels = [];
|
||||
$isEmailEnabled = isEmailEnabled($notifiable);
|
||||
$isDiscordEnabled = data_get($notifiable, 'discord_enabled');
|
||||
$isTelegramEnabled = data_get($notifiable, 'telegram_enabled');
|
||||
$isSlackEnabled = data_get($notifiable, 'slack_enabled');
|
||||
|
||||
if ($isDiscordEnabled) {
|
||||
$channels[] = DiscordChannel::class;
|
||||
}
|
||||
if ($isEmailEnabled) {
|
||||
$channels[] = EmailChannel::class;
|
||||
}
|
||||
if ($isTelegramEnabled) {
|
||||
$channels[] = TelegramChannel::class;
|
||||
}
|
||||
if ($isSlackEnabled) {
|
||||
$channels[] = SlackChannel::class;
|
||||
}
|
||||
|
||||
return $channels;
|
||||
return $notifiable->getEnabledChannels('server_unreachable');
|
||||
}
|
||||
|
||||
public function toMail(): ?MailMessage
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Notifications\Channels\DiscordChannel;
|
||||
use App\Notifications\Channels\EmailChannel;
|
||||
use App\Notifications\Channels\SlackChannel;
|
||||
use App\Notifications\Channels\TelegramChannel;
|
||||
use App\Notifications\Dto\DiscordMessage;
|
||||
use App\Notifications\Dto\SlackMessage;
|
||||
use Illuminate\Bus\Queueable;
|
||||
|
|
@ -16,20 +20,32 @@ class Test extends Notification implements ShouldQueue
|
|||
|
||||
public $tries = 5;
|
||||
|
||||
public function __construct(public ?string $emails = null)
|
||||
public function __construct(public ?string $emails = null, public ?string $channel = null)
|
||||
{
|
||||
$this->onQueue('high');
|
||||
}
|
||||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return setNotificationChannels($notifiable, 'test');
|
||||
if ($this->channel) {
|
||||
$channels = match ($this->channel) {
|
||||
'email' => [EmailChannel::class],
|
||||
'discord' => [DiscordChannel::class],
|
||||
'telegram' => [TelegramChannel::class],
|
||||
'slack' => [SlackChannel::class],
|
||||
default => [],
|
||||
};
|
||||
} else {
|
||||
$channels = $notifiable->getEnabledChannels('test');
|
||||
}
|
||||
|
||||
return $channels;
|
||||
}
|
||||
|
||||
public function middleware(object $notifiable, string $channel)
|
||||
{
|
||||
return match ($channel) {
|
||||
\App\Notifications\Channels\EmailChannel::class => [new RateLimited('email')],
|
||||
EmailChannel::class => [new RateLimited('email')],
|
||||
default => [],
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,13 +50,10 @@ class FortifyServiceProvider extends ServiceProvider
|
|||
if (! $settings->is_registration_enabled) {
|
||||
return redirect()->route('login');
|
||||
}
|
||||
if (config('constants.waitlist.enabled')) {
|
||||
return redirect()->route('waitlist.index');
|
||||
} else {
|
||||
return view('auth.register', [
|
||||
'isFirstUser' => $isFirstUser,
|
||||
]);
|
||||
}
|
||||
|
||||
return view('auth.register', [
|
||||
'isFirstUser' => $isFirstUser,
|
||||
]);
|
||||
});
|
||||
|
||||
Fortify::loginView(function () {
|
||||
|
|
|
|||
90
app/Traits/HasNotificationSettings.php
Normal file
90
app/Traits/HasNotificationSettings.php
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace App\Traits;
|
||||
|
||||
use App\Notifications\Channels\DiscordChannel;
|
||||
use App\Notifications\Channels\EmailChannel;
|
||||
use App\Notifications\Channels\SlackChannel;
|
||||
use App\Notifications\Channels\TelegramChannel;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
trait HasNotificationSettings
|
||||
{
|
||||
protected $alwaysSendEvents = [
|
||||
'server_force_enabled',
|
||||
'server_force_disabled',
|
||||
'general',
|
||||
'test',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get settings model for specific channel
|
||||
*/
|
||||
public function getNotificationSettings(string $channel): ?Model
|
||||
{
|
||||
return match ($channel) {
|
||||
'email' => $this->emailNotificationSettings,
|
||||
'discord' => $this->discordNotificationSettings,
|
||||
'telegram' => $this->telegramNotificationSettings,
|
||||
'slack' => $this->slackNotificationSettings,
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a notification channel is enabled
|
||||
*/
|
||||
public function isNotificationEnabled(string $channel): bool
|
||||
{
|
||||
$settings = $this->getNotificationSettings($channel);
|
||||
|
||||
return $settings?->isEnabled() ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a specific notification type is enabled for a channel
|
||||
*/
|
||||
public function isNotificationTypeEnabled(string $channel, string $event): bool
|
||||
{
|
||||
$settings = $this->getNotificationSettings($channel);
|
||||
|
||||
if (! $settings || ! $this->isNotificationEnabled($channel)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (in_array($event, $this->alwaysSendEvents)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$settingKey = "{$event}_{$channel}_notifications";
|
||||
|
||||
return (bool) $settings->$settingKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all enabled notification channels for an event
|
||||
*/
|
||||
public function getEnabledChannels(string $event): array
|
||||
{
|
||||
$channels = [];
|
||||
|
||||
$channelMap = [
|
||||
'email' => EmailChannel::class,
|
||||
'discord' => DiscordChannel::class,
|
||||
'telegram' => TelegramChannel::class,
|
||||
'slack' => SlackChannel::class,
|
||||
];
|
||||
|
||||
if ($event === 'general') {
|
||||
unset($channelMap['email']);
|
||||
}
|
||||
|
||||
foreach ($channelMap as $channel => $channelClass) {
|
||||
if ($this->isNotificationEnabled($channel) && $this->isNotificationTypeEnabled($channel, $event)) {
|
||||
$channels[] = $channelClass;
|
||||
}
|
||||
}
|
||||
|
||||
return $channels;
|
||||
}
|
||||
}
|
||||
87
bootstrap/helpers/notifications.php
Normal file
87
bootstrap/helpers/notifications.php
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\Team;
|
||||
use App\Notifications\Internal\GeneralNotification;
|
||||
use Illuminate\Mail\Message;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
function is_transactional_emails_enabled(): bool
|
||||
{
|
||||
$settings = instanceSettings();
|
||||
|
||||
return $settings->smtp_enabled || $settings->resend_enabled;
|
||||
}
|
||||
|
||||
function send_internal_notification(string $message): void
|
||||
{
|
||||
try {
|
||||
$team = Team::find(0);
|
||||
$team?->notify(new GeneralNotification($message));
|
||||
} catch (\Throwable $e) {
|
||||
ray($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
function send_user_an_email(MailMessage $mail, string $email, ?string $cc = null): void
|
||||
{
|
||||
$settings = instanceSettings();
|
||||
$type = set_transanctional_email_settings($settings);
|
||||
if (! $type) {
|
||||
throw new Exception('No email settings found.');
|
||||
}
|
||||
if ($cc) {
|
||||
Mail::send(
|
||||
[],
|
||||
[],
|
||||
fn (Message $message) => $message
|
||||
->to($email)
|
||||
->replyTo($email)
|
||||
->cc($cc)
|
||||
->subject($mail->subject)
|
||||
->html((string) $mail->render())
|
||||
);
|
||||
} else {
|
||||
Mail::send(
|
||||
[],
|
||||
[],
|
||||
fn (Message $message) => $message
|
||||
->to($email)
|
||||
->subject($mail->subject)
|
||||
->html((string) $mail->render())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function set_transanctional_email_settings(?InstanceSettings $settings = null): ?string //
|
||||
{
|
||||
if (! $settings) {
|
||||
$settings = instanceSettings();
|
||||
}
|
||||
config()->set('mail.from.address', data_get($settings, 'smtp_from_address'));
|
||||
config()->set('mail.from.name', data_get($settings, 'smtp_from_name'));
|
||||
if (data_get($settings, 'resend_enabled')) {
|
||||
config()->set('mail.default', 'resend');
|
||||
config()->set('resend.api_key', data_get($settings, 'resend_api_key'));
|
||||
|
||||
return 'resend';
|
||||
}
|
||||
if (data_get($settings, 'smtp_enabled')) {
|
||||
config()->set('mail.default', 'smtp');
|
||||
config()->set('mail.mailers.smtp', [
|
||||
'transport' => 'smtp',
|
||||
'host' => data_get($settings, 'smtp_host'),
|
||||
'port' => data_get($settings, 'smtp_port'),
|
||||
'encryption' => data_get($settings, 'smtp_encryption'),
|
||||
'username' => data_get($settings, 'smtp_username'),
|
||||
'password' => data_get($settings, 'smtp_password'),
|
||||
'timeout' => data_get($settings, 'smtp_timeout'),
|
||||
'local_domain' => null,
|
||||
]);
|
||||
|
||||
return 'smtp';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
@ -25,23 +25,15 @@ use App\Models\StandalonePostgresql;
|
|||
use App\Models\StandaloneRedis;
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use App\Notifications\Channels\DiscordChannel;
|
||||
use App\Notifications\Channels\EmailChannel;
|
||||
use App\Notifications\Channels\SlackChannel;
|
||||
use App\Notifications\Channels\TelegramChannel;
|
||||
use App\Notifications\Internal\GeneralNotification;
|
||||
use Carbon\CarbonImmutable;
|
||||
use DanHarrin\LivewireRateLimiting\Exceptions\TooManyRequestsException;
|
||||
use Illuminate\Database\UniqueConstraintViolationException;
|
||||
use Illuminate\Mail\Message;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Process\Pool;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Illuminate\Support\Facades\Request;
|
||||
|
|
@ -267,43 +259,6 @@ function generate_application_name(string $git_repository, string $git_branch, ?
|
|||
return Str::kebab("$git_repository:$git_branch-$cuid");
|
||||
}
|
||||
|
||||
function is_transactional_emails_active(): bool
|
||||
{
|
||||
return isEmailEnabled(\App\Models\InstanceSettings::get());
|
||||
}
|
||||
|
||||
function set_transanctional_email_settings(?InstanceSettings $settings = null): ?string
|
||||
{
|
||||
if (! $settings) {
|
||||
$settings = instanceSettings();
|
||||
}
|
||||
config()->set('mail.from.address', data_get($settings, 'smtp_from_address'));
|
||||
config()->set('mail.from.name', data_get($settings, 'smtp_from_name'));
|
||||
if (data_get($settings, 'resend_enabled')) {
|
||||
config()->set('mail.default', 'resend');
|
||||
config()->set('resend.api_key', data_get($settings, 'resend_api_key'));
|
||||
|
||||
return 'resend';
|
||||
}
|
||||
if (data_get($settings, 'smtp_enabled')) {
|
||||
config()->set('mail.default', 'smtp');
|
||||
config()->set('mail.mailers.smtp', [
|
||||
'transport' => 'smtp',
|
||||
'host' => data_get($settings, 'smtp_host'),
|
||||
'port' => data_get($settings, 'smtp_port'),
|
||||
'encryption' => data_get($settings, 'smtp_encryption'),
|
||||
'username' => data_get($settings, 'smtp_username'),
|
||||
'password' => data_get($settings, 'smtp_password'),
|
||||
'timeout' => data_get($settings, 'smtp_timeout'),
|
||||
'local_domain' => null,
|
||||
]);
|
||||
|
||||
return 'smtp';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function base_ip(): string
|
||||
{
|
||||
if (isDev()) {
|
||||
|
|
@ -414,85 +369,7 @@ function validate_timezone(string $timezone): bool
|
|||
{
|
||||
return in_array($timezone, timezone_identifiers_list());
|
||||
}
|
||||
function send_internal_notification(string $message): void
|
||||
{
|
||||
try {
|
||||
$team = Team::find(0);
|
||||
$team?->notify(new GeneralNotification($message));
|
||||
} catch (\Throwable $e) {
|
||||
ray($e->getMessage());
|
||||
}
|
||||
}
|
||||
function send_user_an_email(MailMessage $mail, string $email, ?string $cc = null): void
|
||||
{
|
||||
$settings = instanceSettings();
|
||||
$type = set_transanctional_email_settings($settings);
|
||||
if (! $type) {
|
||||
throw new Exception('No email settings found.');
|
||||
}
|
||||
if ($cc) {
|
||||
Mail::send(
|
||||
[],
|
||||
[],
|
||||
fn (Message $message) => $message
|
||||
->to($email)
|
||||
->replyTo($email)
|
||||
->cc($cc)
|
||||
->subject($mail->subject)
|
||||
->html((string) $mail->render())
|
||||
);
|
||||
} else {
|
||||
Mail::send(
|
||||
[],
|
||||
[],
|
||||
fn (Message $message) => $message
|
||||
->to($email)
|
||||
->subject($mail->subject)
|
||||
->html((string) $mail->render())
|
||||
);
|
||||
}
|
||||
}
|
||||
function isTestEmailEnabled($notifiable)
|
||||
{
|
||||
if (data_get($notifiable, 'use_instance_email_settings') && isInstanceAdmin()) {
|
||||
return true;
|
||||
} elseif (data_get($notifiable, 'smtp_enabled') || data_get($notifiable, 'resend_enabled') && auth()->user()->isAdminFromSession()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
function isEmailEnabled($notifiable)
|
||||
{
|
||||
return data_get($notifiable, 'smtp_enabled') || data_get($notifiable, 'resend_enabled') || data_get($notifiable, 'use_instance_email_settings');
|
||||
}
|
||||
function setNotificationChannels($notifiable, $event)
|
||||
{
|
||||
$channels = [];
|
||||
$isEmailEnabled = isEmailEnabled($notifiable);
|
||||
$isSlackEnabled = data_get($notifiable, 'slack_enabled');
|
||||
$isDiscordEnabled = data_get($notifiable, 'discord_enabled');
|
||||
$isTelegramEnabled = data_get($notifiable, 'telegram_enabled');
|
||||
$isSubscribedToEmailEvent = data_get($notifiable, "smtp_notifications_$event");
|
||||
$isSubscribedToDiscordEvent = data_get($notifiable, "discord_notifications_$event");
|
||||
$isSubscribedToTelegramEvent = data_get($notifiable, "telegram_notifications_$event");
|
||||
$isSubscribedToSlackEvent = data_get($notifiable, "slack_notifications_$event");
|
||||
|
||||
if ($isDiscordEnabled && $isSubscribedToDiscordEvent) {
|
||||
$channels[] = DiscordChannel::class;
|
||||
}
|
||||
if ($isEmailEnabled && $isSubscribedToEmailEvent) {
|
||||
$channels[] = EmailChannel::class;
|
||||
}
|
||||
if ($isTelegramEnabled && $isSubscribedToTelegramEvent) {
|
||||
$channels[] = TelegramChannel::class;
|
||||
}
|
||||
if ($isSlackEnabled && $isSubscribedToSlackEvent) {
|
||||
$channels[] = SlackChannel::class;
|
||||
}
|
||||
|
||||
return $channels;
|
||||
}
|
||||
function parseEnvFormatToArray($env_file_contents)
|
||||
{
|
||||
$env_array = [];
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ function allowedPathsForUnsubscribedAccounts()
|
|||
'subscription/new',
|
||||
'login',
|
||||
'logout',
|
||||
'waitlist',
|
||||
'force-password-reset',
|
||||
'livewire/update',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"require": {
|
||||
"php": "^8.2",
|
||||
"3sidedcube/laravel-redoc": "^1.0",
|
||||
"danharrin/livewire-rate-limiting": "^1.1",
|
||||
"danharrin/livewire-rate-limiting": "2.0.0",
|
||||
"doctrine/dbal": "^4.2",
|
||||
"guzzlehttp/guzzle": "^7.5.0",
|
||||
"laravel/fortify": "^1.16.0",
|
||||
|
|
|
|||
1488
composer.lock
generated
1488
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -78,11 +78,6 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'waitlist' => [
|
||||
'enabled' => env('WAITLIST', false),
|
||||
'expiration' => 10,
|
||||
],
|
||||
|
||||
'sentry' => [
|
||||
'sentry_dsn' => env('SENTRY_DSN'),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ return new class extends Migration
|
|||
public function up(): void
|
||||
{
|
||||
Schema::table('applications', function (Blueprint $table) {
|
||||
$table->string('redirect')->enum('www', 'non-www', 'both')->default('both')->after('domain');
|
||||
$table->enum('redirect', ['www', 'non-www', 'both'])->default('both')->after('domain');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('teams', function (Blueprint $table) {
|
||||
$table->boolean('slack_enabled')->default(false);
|
||||
$table->string('slack_webhook_url')->nullable();
|
||||
$table->boolean('slack_notifications_test')->default(true);
|
||||
$table->boolean('slack_notifications_deployments')->default(true);
|
||||
$table->boolean('slack_notifications_status_changes')->default(true);
|
||||
$table->boolean('slack_notifications_database_backups')->default(true);
|
||||
$table->boolean('slack_notifications_scheduled_tasks')->default(true);
|
||||
$table->boolean('slack_notifications_server_disk_usage')->default(true);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('teams', function (Blueprint $table) {
|
||||
$table->dropColumn([
|
||||
'slack_enabled',
|
||||
'slack_webhook_url',
|
||||
'slack_notifications_test',
|
||||
'slack_notifications_deployments',
|
||||
'slack_notifications_status_changes',
|
||||
'slack_notifications_database_backups',
|
||||
'slack_notifications_scheduled_tasks',
|
||||
'slack_notifications_server_disk_usage',
|
||||
]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<?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::create('email_notification_settings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('team_id')->constrained()->cascadeOnDelete();
|
||||
|
||||
$table->boolean('smtp_enabled')->default(false);
|
||||
$table->text('smtp_from_address')->nullable();
|
||||
$table->text('smtp_from_name')->nullable();
|
||||
$table->text('smtp_recipients')->nullable();
|
||||
$table->text('smtp_host')->nullable();
|
||||
$table->integer('smtp_port')->nullable();
|
||||
$table->string('smtp_encryption')->nullable();
|
||||
$table->text('smtp_username')->nullable();
|
||||
$table->text('smtp_password')->nullable();
|
||||
$table->integer('smtp_timeout')->nullable();
|
||||
|
||||
$table->boolean('resend_enabled')->default(false);
|
||||
$table->text('resend_api_key')->nullable();
|
||||
|
||||
$table->boolean('use_instance_email_settings')->default(false);
|
||||
|
||||
$table->boolean('deployment_success_email_notifications')->default(false);
|
||||
$table->boolean('deployment_failure_email_notifications')->default(true);
|
||||
$table->boolean('status_change_email_notifications')->default(false);
|
||||
$table->boolean('backup_success_email_notifications')->default(false);
|
||||
$table->boolean('backup_failure_email_notifications')->default(true);
|
||||
$table->boolean('scheduled_task_success_email_notifications')->default(false);
|
||||
$table->boolean('scheduled_task_failure_email_notifications')->default(true);
|
||||
$table->boolean('docker_cleanup_success_email_notifications')->default(false);
|
||||
$table->boolean('docker_cleanup_failure_email_notifications')->default(true);
|
||||
$table->boolean('server_disk_usage_email_notifications')->default(true);
|
||||
$table->boolean('server_reachable_email_notifications')->default(false);
|
||||
$table->boolean('server_unreachable_email_notifications')->default(true);
|
||||
|
||||
$table->unique(['team_id']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('email_notification_settings');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?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::create('discord_notification_settings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('team_id')->constrained()->cascadeOnDelete();
|
||||
|
||||
$table->boolean('discord_enabled')->default(false);
|
||||
$table->text('discord_webhook_url')->nullable();
|
||||
|
||||
$table->boolean('deployment_success_discord_notifications')->default(false);
|
||||
$table->boolean('deployment_failure_discord_notifications')->default(true);
|
||||
$table->boolean('status_change_discord_notifications')->default(false);
|
||||
$table->boolean('backup_success_discord_notifications')->default(false);
|
||||
$table->boolean('backup_failure_discord_notifications')->default(true);
|
||||
$table->boolean('scheduled_task_success_discord_notifications')->default(false);
|
||||
$table->boolean('scheduled_task_failure_discord_notifications')->default(true);
|
||||
$table->boolean('docker_cleanup_success_discord_notifications')->default(false);
|
||||
$table->boolean('docker_cleanup_failure_discord_notifications')->default(true);
|
||||
$table->boolean('server_disk_usage_discord_notifications')->default(true);
|
||||
$table->boolean('server_reachable_discord_notifications')->default(false);
|
||||
$table->boolean('server_unreachable_discord_notifications')->default(true);
|
||||
|
||||
$table->unique(['team_id']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('discord_notification_settings');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?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::create('telegram_notification_settings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('team_id')->constrained()->cascadeOnDelete();
|
||||
|
||||
$table->boolean('telegram_enabled')->default(false);
|
||||
$table->text('telegram_token')->nullable();
|
||||
$table->text('telegram_chat_id')->nullable();
|
||||
|
||||
$table->boolean('deployment_success_telegram_notifications')->default(false);
|
||||
$table->boolean('deployment_failure_telegram_notifications')->default(true);
|
||||
$table->boolean('status_change_telegram_notifications')->default(false);
|
||||
$table->boolean('backup_success_telegram_notifications')->default(false);
|
||||
$table->boolean('backup_failure_telegram_notifications')->default(true);
|
||||
$table->boolean('scheduled_task_success_telegram_notifications')->default(false);
|
||||
$table->boolean('scheduled_task_failure_telegram_notifications')->default(true);
|
||||
$table->boolean('docker_cleanup_success_telegram_notifications')->default(false);
|
||||
$table->boolean('docker_cleanup_failure_telegram_notifications')->default(true);
|
||||
$table->boolean('server_disk_usage_telegram_notifications')->default(true);
|
||||
$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->unique(['team_id']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('telegram_notification_settings');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$teams = DB::table('teams')->get();
|
||||
|
||||
foreach ($teams as $team) {
|
||||
try {
|
||||
DB::table('email_notification_settings')->updateOrInsert(
|
||||
['team_id' => $team->id],
|
||||
[
|
||||
'smtp_enabled' => $team->smtp_enabled ?? false,
|
||||
'smtp_from_address' => $team->smtp_from_address ? Crypt::encryptString($team->smtp_from_address) : null,
|
||||
'smtp_from_name' => $team->smtp_from_name ? Crypt::encryptString($team->smtp_from_name) : null,
|
||||
'smtp_recipients' => $team->smtp_recipients ? Crypt::encryptString($team->smtp_recipients) : null,
|
||||
'smtp_host' => $team->smtp_host ? Crypt::encryptString($team->smtp_host) : null,
|
||||
'smtp_port' => $team->smtp_port,
|
||||
'smtp_encryption' => $team->smtp_encryption,
|
||||
'smtp_username' => $team->smtp_username ? Crypt::encryptString($team->smtp_username) : null,
|
||||
'smtp_password' => $team->smtp_password,
|
||||
'smtp_timeout' => $team->smtp_timeout,
|
||||
|
||||
'use_instance_email_settings' => $team->use_instance_email_settings ?? false,
|
||||
|
||||
'resend_enabled' => $team->resend_enabled ?? false,
|
||||
'resend_api_key' => $team->resend_api_key,
|
||||
|
||||
'deployment_success_email_notifications' => $team->smtp_notifications_deployments ?? false,
|
||||
'deployment_failure_email_notifications' => $team->smtp_notifications_deployments ?? true,
|
||||
'backup_success_email_notifications' => $team->smtp_notifications_database_backups ?? false,
|
||||
'backup_failure_email_notifications' => $team->smtp_notifications_database_backups ?? true,
|
||||
'scheduled_task_success_email_notifications' => $team->smtp_notifications_scheduled_tasks ?? false,
|
||||
'scheduled_task_failure_email_notifications' => $team->smtp_notifications_scheduled_tasks ?? true,
|
||||
'status_change_email_notifications' => $team->smtp_notifications_status_changes ?? false,
|
||||
'server_disk_usage_email_notifications' => $team->smtp_notifications_server_disk_usage ?? true,
|
||||
]
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
\Log::error('Error migrating email notification settings from teams table: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
Schema::table('teams', function (Blueprint $table) {
|
||||
$table->dropColumn([
|
||||
'smtp_enabled',
|
||||
'smtp_from_address',
|
||||
'smtp_from_name',
|
||||
'smtp_recipients',
|
||||
'smtp_host',
|
||||
'smtp_port',
|
||||
'smtp_encryption',
|
||||
'smtp_username',
|
||||
'smtp_password',
|
||||
'smtp_timeout',
|
||||
'use_instance_email_settings',
|
||||
'resend_enabled',
|
||||
'resend_api_key',
|
||||
'smtp_notifications_test',
|
||||
'smtp_notifications_deployments',
|
||||
'smtp_notifications_database_backups',
|
||||
'smtp_notifications_scheduled_tasks',
|
||||
'smtp_notifications_status_changes',
|
||||
'smtp_notifications_server_disk_usage',
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('teams', function (Blueprint $table) {
|
||||
$table->boolean('smtp_enabled')->default(false);
|
||||
$table->string('smtp_from_address')->nullable();
|
||||
$table->string('smtp_from_name')->nullable();
|
||||
$table->string('smtp_recipients')->nullable();
|
||||
$table->string('smtp_host')->nullable();
|
||||
$table->integer('smtp_port')->nullable();
|
||||
$table->string('smtp_encryption')->nullable();
|
||||
$table->text('smtp_username')->nullable();
|
||||
$table->text('smtp_password')->nullable();
|
||||
$table->integer('smtp_timeout')->nullable();
|
||||
|
||||
$table->boolean('use_instance_email_settings')->default(false);
|
||||
$table->boolean('resend_enabled')->default(false);
|
||||
|
||||
$table->text('resend_api_key')->nullable();
|
||||
|
||||
$table->boolean('smtp_notifications_test')->default(false);
|
||||
$table->boolean('smtp_notifications_deployments')->default(false);
|
||||
$table->boolean('smtp_notifications_database_backups')->default(true);
|
||||
$table->boolean('smtp_notifications_scheduled_tasks')->default(false);
|
||||
$table->boolean('smtp_notifications_status_changes')->default(false);
|
||||
$table->boolean('smtp_notifications_server_disk_usage')->default(true);
|
||||
});
|
||||
|
||||
$settings = DB::table('email_notification_settings')->get();
|
||||
foreach ($settings as $setting) {
|
||||
try {
|
||||
DB::table('teams')
|
||||
->where('id', $setting->team_id)
|
||||
->update([
|
||||
'smtp_enabled' => $setting->smtp_enabled,
|
||||
'smtp_from_address' => $setting->smtp_from_address ? Crypt::decryptString($setting->smtp_from_address) : null,
|
||||
'smtp_from_name' => $setting->smtp_from_name ? Crypt::decryptString($setting->smtp_from_name) : null,
|
||||
'smtp_recipients' => $setting->smtp_recipients ? Crypt::decryptString($setting->smtp_recipients) : null,
|
||||
'smtp_host' => $setting->smtp_host ? Crypt::decryptString($setting->smtp_host) : null,
|
||||
'smtp_port' => $setting->smtp_port,
|
||||
'smtp_encryption' => $setting->smtp_encryption,
|
||||
'smtp_username' => $setting->smtp_username ? Crypt::decryptString($setting->smtp_username) : null,
|
||||
'smtp_password' => $setting->smtp_password,
|
||||
'smtp_timeout' => $setting->smtp_timeout,
|
||||
|
||||
'use_instance_email_settings' => $setting->use_instance_email_settings,
|
||||
|
||||
'resend_enabled' => $setting->resend_enabled,
|
||||
'resend_api_key' => $setting->resend_api_key,
|
||||
|
||||
'smtp_notifications_deployments' => $setting->deployment_success_email_notifications || $setting->deployment_failure_email_notifications,
|
||||
'smtp_notifications_database_backups' => $setting->backup_success_email_notifications || $setting->backup_failure_email_notifications,
|
||||
'smtp_notifications_scheduled_tasks' => $setting->scheduled_task_success_email_notifications || $setting->scheduled_task_failure_email_notifications,
|
||||
'smtp_notifications_status_changes' => $setting->status_change_email_notifications,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
\Log::error('Error migrating email notification settings from teams table: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$teams = DB::table('teams')->get();
|
||||
|
||||
foreach ($teams as $team) {
|
||||
try {
|
||||
DB::table('discord_notification_settings')->updateOrInsert(
|
||||
['team_id' => $team->id],
|
||||
[
|
||||
'discord_enabled' => $team->discord_enabled ?? false,
|
||||
'discord_webhook_url' => $team->discord_webhook_url ? Crypt::encryptString($team->discord_webhook_url) : null,
|
||||
|
||||
'deployment_success_discord_notifications' => $team->discord_notifications_deployments ?? false,
|
||||
'deployment_failure_discord_notifications' => $team->discord_notifications_deployments ?? true,
|
||||
'backup_success_discord_notifications' => $team->discord_notifications_database_backups ?? false,
|
||||
'backup_failure_discord_notifications' => $team->discord_notifications_database_backups ?? true,
|
||||
'scheduled_task_success_discord_notifications' => $team->discord_notifications_scheduled_tasks ?? false,
|
||||
'scheduled_task_failure_discord_notifications' => $team->discord_notifications_scheduled_tasks ?? true,
|
||||
'status_change_discord_notifications' => $team->discord_notifications_status_changes ?? false,
|
||||
'server_disk_usage_discord_notifications' => $team->discord_notifications_server_disk_usage ?? true,
|
||||
]
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
\Log::error('Error migrating discord notification settings from teams table: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
Schema::table('teams', function (Blueprint $table) {
|
||||
$table->dropColumn([
|
||||
'discord_enabled',
|
||||
'discord_webhook_url',
|
||||
'discord_notifications_test',
|
||||
'discord_notifications_deployments',
|
||||
'discord_notifications_status_changes',
|
||||
'discord_notifications_database_backups',
|
||||
'discord_notifications_scheduled_tasks',
|
||||
'discord_notifications_server_disk_usage',
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('teams', function (Blueprint $table) {
|
||||
$table->boolean('discord_enabled')->default(false);
|
||||
$table->string('discord_webhook_url')->nullable();
|
||||
|
||||
$table->boolean('discord_notifications_test')->default(true);
|
||||
$table->boolean('discord_notifications_deployments')->default(true);
|
||||
$table->boolean('discord_notifications_status_changes')->default(true);
|
||||
$table->boolean('discord_notifications_database_backups')->default(true);
|
||||
$table->boolean('discord_notifications_scheduled_tasks')->default(true);
|
||||
$table->boolean('discord_notifications_server_disk_usage')->default(true);
|
||||
});
|
||||
|
||||
$settings = DB::table('discord_notification_settings')->get();
|
||||
foreach ($settings as $setting) {
|
||||
try {
|
||||
DB::table('teams')
|
||||
->where('id', $setting->team_id)
|
||||
->update([
|
||||
'discord_enabled' => $setting->discord_enabled,
|
||||
'discord_webhook_url' => Crypt::decryptString($setting->discord_webhook_url),
|
||||
|
||||
'discord_notifications_deployments' => $setting->deployment_success_discord_notifications || $setting->deployment_failure_discord_notifications,
|
||||
'discord_notifications_status_changes' => $setting->status_change_discord_notifications,
|
||||
'discord_notifications_database_backups' => $setting->backup_success_discord_notifications || $setting->backup_failure_discord_notifications,
|
||||
'discord_notifications_scheduled_tasks' => $setting->scheduled_task_success_discord_notifications || $setting->scheduled_task_failure_discord_notifications,
|
||||
'discord_notifications_server_disk_usage' => $setting->server_disk_usage_discord_notifications,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
\Log::error('Error migrating discord notification settings from teams table: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$teams = DB::table('teams')->get();
|
||||
|
||||
foreach ($teams as $team) {
|
||||
try {
|
||||
DB::table('telegram_notification_settings')->updateOrInsert(
|
||||
['team_id' => $team->id],
|
||||
[
|
||||
'telegram_enabled' => $team->telegram_enabled ?? false,
|
||||
'telegram_token' => $team->telegram_token ? Crypt::encryptString($team->telegram_token) : null,
|
||||
'telegram_chat_id' => $team->telegram_chat_id ? Crypt::encryptString($team->telegram_chat_id) : null,
|
||||
|
||||
'deployment_success_telegram_notifications' => $team->telegram_notifications_deployments ?? false,
|
||||
'deployment_failure_telegram_notifications' => $team->telegram_notifications_deployments ?? true,
|
||||
'backup_success_telegram_notifications' => $team->telegram_notifications_database_backups ?? false,
|
||||
'backup_failure_telegram_notifications' => $team->telegram_notifications_database_backups ?? true,
|
||||
'scheduled_task_success_telegram_notifications' => $team->telegram_notifications_scheduled_tasks ?? false,
|
||||
'scheduled_task_failure_telegram_notifications' => $team->telegram_notifications_scheduled_tasks ?? true,
|
||||
'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,
|
||||
]
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
\Log::error('Error migrating telegram notification settings from teams table: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
Schema::table('teams', function (Blueprint $table) {
|
||||
$table->dropColumn([
|
||||
'telegram_enabled',
|
||||
'telegram_token',
|
||||
'telegram_chat_id',
|
||||
'telegram_notifications_test',
|
||||
'telegram_notifications_deployments',
|
||||
'telegram_notifications_status_changes',
|
||||
'telegram_notifications_database_backups',
|
||||
'telegram_notifications_scheduled_tasks',
|
||||
'telegram_notifications_server_disk_usage',
|
||||
'telegram_notifications_test_message_thread_id',
|
||||
'telegram_notifications_deployments_message_thread_id',
|
||||
'telegram_notifications_status_changes_message_thread_id',
|
||||
'telegram_notifications_database_backups_message_thread_id',
|
||||
'telegram_notifications_scheduled_tasks_thread_id',
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('teams', function (Blueprint $table) {
|
||||
$table->boolean('telegram_enabled')->default(false);
|
||||
$table->text('telegram_token')->nullable();
|
||||
$table->text('telegram_chat_id')->nullable();
|
||||
|
||||
$table->boolean('telegram_notifications_test')->default(true);
|
||||
$table->boolean('telegram_notifications_deployments')->default(true);
|
||||
$table->boolean('telegram_notifications_status_changes')->default(true);
|
||||
$table->boolean('telegram_notifications_database_backups')->default(true);
|
||||
$table->boolean('telegram_notifications_scheduled_tasks')->default(true);
|
||||
$table->boolean('telegram_notifications_server_disk_usage')->default(true);
|
||||
|
||||
$table->text('telegram_notifications_test_message_thread_id')->nullable();
|
||||
$table->text('telegram_notifications_deployments_message_thread_id')->nullable();
|
||||
$table->text('telegram_notifications_status_changes_message_thread_id')->nullable();
|
||||
$table->text('telegram_notifications_database_backups_message_thread_id')->nullable();
|
||||
$table->text('telegram_notifications_scheduled_tasks_thread_id')->nullable();
|
||||
});
|
||||
|
||||
$settings = DB::table('telegram_notification_settings')->get();
|
||||
foreach ($settings as $setting) {
|
||||
try {
|
||||
DB::table('teams')
|
||||
->where('id', $setting->team_id)
|
||||
->update([
|
||||
'telegram_enabled' => $setting->telegram_enabled,
|
||||
'telegram_token' => $setting->telegram_token ? Crypt::decryptString($setting->telegram_token) : null,
|
||||
'telegram_chat_id' => $setting->telegram_chat_id ? Crypt::decryptString($setting->telegram_chat_id) : null,
|
||||
|
||||
'telegram_notifications_deployments' => $setting->deployment_success_telegram_notifications || $setting->deployment_failure_telegram_notifications,
|
||||
'telegram_notifications_status_changes' => $setting->status_change_telegram_notifications,
|
||||
'telegram_notifications_database_backups' => $setting->backup_success_telegram_notifications || $setting->backup_failure_telegram_notifications,
|
||||
'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,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
\Log::error('Error migrating telegram notification settings from teams table: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('slack_notification_settings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('team_id')->constrained()->cascadeOnDelete();
|
||||
|
||||
$table->boolean('slack_enabled')->default(false);
|
||||
$table->text('slack_webhook_url')->nullable();
|
||||
|
||||
$table->boolean('deployment_success_slack_notifications')->default(false);
|
||||
$table->boolean('deployment_failure_slack_notifications')->default(true);
|
||||
$table->boolean('status_change_slack_notifications')->default(false);
|
||||
$table->boolean('backup_success_slack_notifications')->default(false);
|
||||
$table->boolean('backup_failure_slack_notifications')->default(true);
|
||||
$table->boolean('scheduled_task_success_slack_notifications')->default(false);
|
||||
$table->boolean('scheduled_task_failure_slack_notifications')->default(true);
|
||||
$table->boolean('docker_cleanup_success_slack_notifications')->default(false);
|
||||
$table->boolean('docker_cleanup_failure_slack_notifications')->default(true);
|
||||
$table->boolean('server_disk_usage_slack_notifications')->default(true);
|
||||
$table->boolean('server_reachable_slack_notifications')->default(false);
|
||||
$table->boolean('server_unreachable_slack_notifications')->default(true);
|
||||
|
||||
$table->unique(['team_id']);
|
||||
});
|
||||
$teams = DB::table('teams')->get();
|
||||
|
||||
foreach ($teams as $team) {
|
||||
try {
|
||||
DB::table('slack_notification_settings')->insert([
|
||||
'team_id' => $team->id,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
\Log::error('Error migrating slack notification settings from teams table: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('slack_notification_settings');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<?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::dropIfExists('waitlists');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::create('waitlists', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('uuid');
|
||||
$table->string('type');
|
||||
$table->string('email')->unique();
|
||||
$table->boolean('verified')->default(false);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if (DB::table('instance_settings')->exists()) {
|
||||
Schema::table('instance_settings', function (Blueprint $table) {
|
||||
$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();
|
||||
});
|
||||
|
||||
$settings = DB::table('instance_settings')->get();
|
||||
foreach ($settings as $setting) {
|
||||
try {
|
||||
DB::table('instance_settings')->where('id', $setting->id)->update([
|
||||
'smtp_from_address' => $setting->smtp_from_address ? Crypt::encryptString($setting->smtp_from_address) : null,
|
||||
'smtp_from_name' => $setting->smtp_from_name ? Crypt::encryptString($setting->smtp_from_name) : null,
|
||||
'smtp_recipients' => $setting->smtp_recipients ? Crypt::encryptString($setting->smtp_recipients) : null,
|
||||
'smtp_host' => $setting->smtp_host ? Crypt::encryptString($setting->smtp_host) : null,
|
||||
'smtp_username' => $setting->smtp_username ? Crypt::encryptString($setting->smtp_username) : null,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
\Log::error('Error encrypting instance settings email columns: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
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();
|
||||
});
|
||||
|
||||
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([
|
||||
'smtp_from_address' => $setting->smtp_from_address ? Crypt::decryptString($setting->smtp_from_address) : null,
|
||||
'smtp_from_name' => $setting->smtp_from_name ? Crypt::decryptString($setting->smtp_from_name) : null,
|
||||
'smtp_recipients' => $setting->smtp_recipients ? Crypt::decryptString($setting->smtp_recipients) : null,
|
||||
'smtp_host' => $setting->smtp_host ? Crypt::decryptString($setting->smtp_host) : null,
|
||||
'smtp_username' => $setting->smtp_username ? Crypt::decryptString($setting->smtp_username) : null,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
\Log::error('Error decrypting instance settings email columns: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?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('instance_settings', function (Blueprint $table) {
|
||||
$table->dropColumn('is_resale_license_active');
|
||||
$table->dropColumn('resale_license');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('instance_settings', function (Blueprint $table) {
|
||||
$table->boolean('is_resale_license_active')->default(false);
|
||||
$table->longText('resale_license')->nullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -16,7 +16,6 @@ class InstanceSettingsSeeder extends Seeder
|
|||
InstanceSettings::create([
|
||||
'id' => 0,
|
||||
'is_registration_enabled' => true,
|
||||
'is_resale_license_active' => true,
|
||||
'smtp_enabled' => true,
|
||||
'smtp_host' => 'coolify-mail',
|
||||
'smtp_port' => 1025,
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@ class ProductionSeeder extends Seeder
|
|||
public function run(): void
|
||||
{
|
||||
if (isCloud()) {
|
||||
echo "[x]: Running in cloud mode.\n";
|
||||
echo " Running in cloud mode.\n";
|
||||
} else {
|
||||
echo "[x]: Running in self-hosted mode.\n";
|
||||
echo " Running in self-hosted mode.\n";
|
||||
}
|
||||
|
||||
// Fix for 4.0.0-beta.37
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class TestTeamSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
// User has 2 teams, 1 personal, 1 other where it is the owner and no other members are in the team
|
||||
$user = User::factory()->create([
|
||||
'name' => '1 personal, 1 other team, owner, no other members',
|
||||
'email' => '1@example.com',
|
||||
]);
|
||||
$team = Team::create([
|
||||
'name' => '1@example.com',
|
||||
'personal_team' => false,
|
||||
'show_boarding' => true,
|
||||
]);
|
||||
$user->teams()->attach($team, ['role' => 'owner']);
|
||||
|
||||
// User has 2 teams, 1 personal, 1 other where it is the owner and 1 other member is in the team
|
||||
$user = User::factory()->create([
|
||||
'name' => 'owner: 1 personal, 1 other team, owner, 1 other member',
|
||||
'email' => '2@example.com',
|
||||
]);
|
||||
$team = Team::create([
|
||||
'name' => '2@example.com',
|
||||
'personal_team' => false,
|
||||
'show_boarding' => true,
|
||||
]);
|
||||
$user->teams()->attach($team, ['role' => 'owner']);
|
||||
$user = User::factory()->create([
|
||||
'name' => 'member: 1 personal, 1 other team, owner, 1 other member',
|
||||
'email' => '3@example.com',
|
||||
]);
|
||||
$team->members()->attach($user, ['role' => 'member']);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,15 +2,14 @@ services:
|
|||
coolify:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./docker/dev/Dockerfile
|
||||
dockerfile: ./docker/development/Dockerfile
|
||||
args:
|
||||
- USER_ID=${USERID:-1000}
|
||||
- GROUP_ID=${GROUPID:-1000}
|
||||
ports:
|
||||
- "${APP_PORT:-8000}:80"
|
||||
environment:
|
||||
PUID: "${USERID:-1000}"
|
||||
PGID: "${GROUPID:-1000}"
|
||||
SSL_MODE: "off"
|
||||
AUTORUN_LARAVEL_STORAGE_LINK: "false"
|
||||
AUTORUN_LARAVEL_MIGRATION: "false"
|
||||
AUTORUN_ENABLED: false
|
||||
PUSHER_HOST: "${PUSHER_HOST}"
|
||||
PUSHER_PORT: "${PUSHER_PORT}"
|
||||
PUSHER_SCHEME: "${PUSHER_SCHEME:-http}"
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
# Versions
|
||||
# https://hub.docker.com/r/serversideup/php/tags?name=8.3-fpm-nginx-alpine
|
||||
ARG SERVERSIDEUP_PHP_VERSION=8.2-fpm-nginx-v2.2.1
|
||||
# https://github.com/minio/mc/releases
|
||||
ARG MINIO_VERSION=RELEASE.2024-11-05T11-29-45Z
|
||||
# https://github.com/cloudflare/cloudflared/releases
|
||||
ARG CLOUDFLARED_VERSION=2024.11.0
|
||||
# https://www.postgresql.org/support/versioning/ - Can not updated automatically so keep it at 15
|
||||
ARG POSTGRES_VERSION=15
|
||||
|
||||
FROM minio/mc:${MINIO_VERSION} AS minio-client
|
||||
|
||||
FROM serversideup/php:${SERVERSIDEUP_PHP_VERSION}
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
ARG CLOUDFLARED_VERSION
|
||||
ARG MINIO_VERSION
|
||||
ARG POSTGRES_VERSION
|
||||
|
||||
# Use build arguments for caching
|
||||
ARG BUILDTIME_DEPS="dirmngr ca-certificates software-properties-common gnupg gnupg2 apt-transport-https curl"
|
||||
ARG RUNTIME_DEPS="postgresql-client-$POSTGRES_VERSION php8.2-pgsql openssh-client git git-lfs jq lsof"
|
||||
|
||||
# Install dependencies
|
||||
RUN --mount=type=cache,target=/var/cache/apt \
|
||||
apt-get update && \
|
||||
apt-get install -y $BUILDTIME_DEPS && \
|
||||
curl -fSsL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/postgresql.gpg > /dev/null && \
|
||||
echo deb [arch=amd64,arm64,ppc64el signed-by=/usr/share/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt/ jammy-pgdg main | tee -a /etc/apt/sources.list.d/postgresql.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y $RUNTIME_DEPS && \
|
||||
apt-get -y autoremove && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
|
||||
|
||||
COPY --chmod=755 docker/dev/etc/s6-overlay/ /etc/s6-overlay/
|
||||
|
||||
COPY docker/dev/nginx.conf /etc/nginx/conf.d/custom.conf
|
||||
|
||||
RUN echo "alias ll='ls -al'" >>/etc/bash.bashrc && \
|
||||
echo "alias a='php artisan'" >>/etc/bash.bashrc
|
||||
|
||||
RUN mkdir -p /usr/local/bin
|
||||
|
||||
RUN --mount=type=cache,target=/root/.cache \
|
||||
/bin/bash -c "if [[ ${TARGETPLATFORM} == 'linux/amd64' ]]; then \
|
||||
echo 'amd64' && \
|
||||
curl -sSL https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-amd64 -o /usr/local/bin/cloudflared && chmod +x /usr/local/bin/cloudflared \
|
||||
;fi"
|
||||
|
||||
RUN --mount=type=cache,target=/root/.cache \
|
||||
/bin/bash -c "if [[ ${TARGETPLATFORM} == 'linux/arm64' ]]; then \
|
||||
echo 'arm64' && \
|
||||
curl -L https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-arm64 -o /usr/local/bin/cloudflared && chmod +x /usr/local/bin/cloudflared \
|
||||
;fi"
|
||||
|
||||
COPY --from=minio-client /usr/bin/mc /usr/bin/mc
|
||||
RUN chmod +x /usr/bin/mc
|
||||
|
||||
RUN { \
|
||||
echo 'upload_max_filesize=256M'; \
|
||||
echo 'post_max_size=256M'; \
|
||||
} > /etc/php/current_version/cli/conf.d/upload-limits.ini
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#!/command/execlineb -P
|
||||
foreground {
|
||||
s6-sleep 5
|
||||
su - webuser -c "php /var/www/html/artisan start:horizon"
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#!/command/execlineb -P
|
||||
foreground { composer -d /var/www/html/ install }
|
||||
foreground { php /var/www/html/artisan migrate --step }
|
||||
foreground { php /var/www/html/artisan dev --init }
|
||||
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#!/command/execlineb -P
|
||||
foreground {
|
||||
s6-sleep 5
|
||||
su - webuser -c "php /var/www/html/artisan start:scheduler"
|
||||
}
|
||||
81
docker/development/Dockerfile
Normal file
81
docker/development/Dockerfile
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# Versions
|
||||
# https://hub.docker.com/r/serversideup/php/tags?name=8.4-fpm-nginx-alpine
|
||||
ARG SERVERSIDEUP_PHP_VERSION=8.4-fpm-nginx-alpine
|
||||
# https://github.com/minio/mc/releases
|
||||
ARG MINIO_VERSION=RELEASE.2024-11-17T19-35-25Z
|
||||
# https://github.com/cloudflare/cloudflared/releases
|
||||
ARG CLOUDFLARED_VERSION=2024.11.1
|
||||
# https://www.postgresql.org/support/versioning/
|
||||
ARG POSTGRES_VERSION=15
|
||||
|
||||
# =================================================================
|
||||
# Get MinIO client
|
||||
# =================================================================
|
||||
FROM minio/mc:${MINIO_VERSION} AS minio-client
|
||||
|
||||
# =================================================================
|
||||
# Final Stage: Production image
|
||||
# =================================================================
|
||||
FROM serversideup/php:${SERVERSIDEUP_PHP_VERSION}
|
||||
|
||||
ARG USER_ID
|
||||
ARG GROUP_ID
|
||||
ARG TARGETPLATFORM
|
||||
ARG POSTGRES_VERSION
|
||||
ARG CLOUDFLARED_VERSION
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
USER root
|
||||
|
||||
RUN docker-php-serversideup-set-id www-data $USER_ID:$GROUP_ID && \
|
||||
docker-php-serversideup-set-file-permissions --owner $USER_ID:$GROUP_ID --service nginx
|
||||
|
||||
# Install PostgreSQL repository and keys
|
||||
RUN apk add --no-cache gnupg && \
|
||||
mkdir -p /usr/share/keyrings && \
|
||||
curl -fSsL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor > /usr/share/keyrings/postgresql.gpg
|
||||
|
||||
# Install system dependencies
|
||||
RUN apk add --no-cache \
|
||||
postgresql${POSTGRES_VERSION}-client \
|
||||
openssh-client \
|
||||
git \
|
||||
git-lfs \
|
||||
jq \
|
||||
lsof \
|
||||
vim
|
||||
|
||||
# Configure shell aliases
|
||||
RUN echo "alias ll='ls -al'" >> /etc/profile && \
|
||||
echo "alias a='php artisan'" >> /etc/profile && \
|
||||
echo "alias logs='tail -f storage/logs/laravel.log'" >> /etc/profile
|
||||
|
||||
# Install Cloudflared based on architecture
|
||||
RUN mkdir -p /usr/local/bin && \
|
||||
if [ "${TARGETPLATFORM}" = "linux/amd64" ]; then \
|
||||
curl -sSL "https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-amd64" -o /usr/local/bin/cloudflared; \
|
||||
elif [ "${TARGETPLATFORM}" = "linux/arm64" ]; then \
|
||||
curl -sSL "https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-arm64" -o /usr/local/bin/cloudflared; \
|
||||
fi && \
|
||||
chmod +x /usr/local/bin/cloudflared
|
||||
|
||||
# Configure PHP
|
||||
COPY docker/development/etc/php/conf.d/zzz-custom-php.ini /usr/local/etc/php/conf.d/zzz-custom-php.ini
|
||||
ENV PHP_OPCACHE_ENABLE=0
|
||||
|
||||
# Configure Nginx and S6 overlay
|
||||
COPY docker/development/etc/nginx/conf.d/custom.conf /etc/nginx/conf.d/custom.conf
|
||||
COPY docker/development/etc/nginx/site-opts.d/http.conf /etc/nginx/site-opts.d/http.conf
|
||||
COPY --chmod=755 docker/development/etc/s6-overlay/ /etc/s6-overlay/
|
||||
|
||||
RUN mkdir -p /etc/nginx/conf.d && \
|
||||
chown -R www-data:www-data /etc/nginx && \
|
||||
chmod -R 755 /etc/nginx
|
||||
|
||||
# Install MinIO client
|
||||
COPY --from=minio-client /usr/bin/mc /usr/bin/mc
|
||||
RUN chmod +x /usr/bin/mc
|
||||
|
||||
# Switch to non-root user
|
||||
USER www-data
|
||||
45
docker/development/etc/nginx/site-opts.d/http.conf
Normal file
45
docker/development/etc/nginx/site-opts.d/http.conf
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
listen 8080 default_server;
|
||||
listen [::]:8080 default_server;
|
||||
|
||||
root /var/www/html/public;
|
||||
|
||||
# Set allowed "index" files
|
||||
index index.html index.htm index.php;
|
||||
|
||||
server_name _;
|
||||
|
||||
charset utf-8;
|
||||
|
||||
# Set max upload to 2048M
|
||||
client_max_body_size 2048M;
|
||||
|
||||
# Healthchecks: Set /healthcheck to be the healthcheck URL
|
||||
location /healthcheck {
|
||||
access_log off;
|
||||
|
||||
# set max 5 seconds for healthcheck
|
||||
fastcgi_read_timeout 5s;
|
||||
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_NAME /healthcheck;
|
||||
fastcgi_param SCRIPT_FILENAME /healthcheck;
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
}
|
||||
|
||||
# Have NGINX try searching for PHP files as well
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
# Pass "*.php" files to PHP-FPM
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
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_read_timeout 99;
|
||||
}
|
||||
9
docker/development/etc/php/conf.d/zzz-custom-php.ini
Normal file
9
docker/development/etc/php/conf.d/zzz-custom-php.ini
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
error_reporting = E_ERROR
|
||||
error_log = /dev/stderr
|
||||
log_errors = On
|
||||
log_errors_max_len = 8192
|
||||
ignore_repeated_errors = On
|
||||
ignore_repeated_source = On
|
||||
|
||||
upload_max_filesize = 256M
|
||||
post_max_size = 256M
|
||||
12
docker/development/etc/s6-overlay/s6-rc.d/horizon/run
Normal file
12
docker/development/etc/s6-overlay/s6-rc.d/horizon/run
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#!/command/execlineb -P
|
||||
|
||||
# Use with-contenv to ensure environment variables are available
|
||||
with-contenv
|
||||
cd /var/www/html
|
||||
|
||||
foreground {
|
||||
php
|
||||
artisan
|
||||
start:horizon
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue