Files
coolify/app/Livewire/Notifications/Email.php
Andras Bacsai 5f3108b68d feat(ui): unify resource headings with responsive action menus
Add responsive overflow handling and dedicated action menus for application,
service, database, and server headings, while improving upgrade and email
settings flows and returning 404s for missing deployment environments.
2026-08-13 12:17:16 +02:00

393 lines
15 KiB
PHP

<?php
namespace App\Livewire\Notifications;
use App\Livewire\Notifications\Concerns\TogglesNotificationEvents;
use App\Models\EmailNotificationSettings;
use App\Models\Team;
use App\Notifications\Test;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\RateLimiter;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Validate;
use Livewire\Component;
class Email extends Component
{
use AuthorizesRequests, TogglesNotificationEvents;
protected $listeners = ['refresh' => '$refresh'];
#[Locked]
public Team $team;
#[Locked]
public EmailNotificationSettings $settings;
#[Locked]
public string $emails;
#[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;
#[Validate(['nullable', 'numeric', 'min:1', 'max:65535'])]
public ?string $smtpPort = null;
#[Validate(['nullable', 'string', 'in:starttls,tls,none'])]
public ?string $smtpEncryption = 'starttls';
#[Validate(['nullable', 'string'])]
public ?string $smtpUsername = null;
#[Validate(['nullable', 'string'])]
public ?string $smtpPassword = null;
#[Validate(['nullable', 'numeric'])]
public ?string $smtpTimeout = null;
#[Validate(['boolean'])]
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(['boolean'])]
public bool $serverPatchEmailNotifications = false;
#[Validate(['boolean'])]
public bool $traefikOutdatedEmailNotifications = true;
#[Validate(['nullable', 'email'])]
public ?string $testEmailAddress = null;
public function mount()
{
try {
$this->team = auth()->user()->currentTeam();
$this->emails = auth()->user()->email;
$this->settings = $this->team->emailNotificationSettings;
$this->authorize('view', $this->settings);
$this->syncData();
$this->testEmailAddress = auth()->user()->email;
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function syncData(bool $toModel = false)
{
if ($toModel) {
$this->validate();
$this->authorize('update', $this->settings);
$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->server_patch_email_notifications = $this->serverPatchEmailNotifications;
$this->settings->traefik_outdated_email_notifications = $this->traefikOutdatedEmailNotifications;
$this->settings->save();
} else {
$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 = auth()->user()->can('update', $this->settings)
? $this->settings->smtp_password
: null;
$this->smtpTimeout = $this->settings->smtp_timeout;
$this->resendEnabled = $this->settings->resend_enabled;
$this->resendApiKey = auth()->user()->can('update', $this->settings)
? $this->settings->resend_api_key
: null;
$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;
$this->serverPatchEmailNotifications = $this->settings->server_patch_email_notifications;
$this->traefikOutdatedEmailNotifications = $this->settings->traefik_outdated_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()
{
$this->authorize('update', $this->settings);
try {
$this->resetErrorBag();
$this->validate([
'smtpEnabled' => 'boolean',
'smtpFromAddress' => 'required|email',
'smtpFromName' => 'required|string',
'smtpHost' => 'required|string',
'smtpPort' => 'required|numeric',
'smtpEncryption' => 'required|string|in:starttls,tls,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.',
]);
if ($this->smtpEnabled) {
$this->settings->resend_enabled = $this->resendEnabled = 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, $this);
}
}
public function submitResend()
{
$this->authorize('update', $this->settings);
try {
$this->resetErrorBag();
$this->validate([
'resendEnabled' => 'boolean',
'resendApiKey' => $this->resendEnabled ? 'required|string' : 'nullable|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.',
]);
if ($this->resendEnabled) {
$this->settings->smtp_enabled = $this->smtpEnabled = 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);
}
}
public function sendTestEmail()
{
try {
$this->authorize('sendTest', $this->settings);
$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?->notifyNow(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, $this);
}
}
public function copyFromInstanceSettings()
{
$this->authorize('update', $this->settings);
$settings = instanceSettings();
$this->smtpFromAddress = $settings->smtp_from_address;
$this->smtpFromName = $settings->smtp_from_name;
if ($settings->smtp_enabled) {
$this->smtpEnabled = true;
$this->resendEnabled = false;
}
$this->smtpRecipients = $settings->smtp_recipients;
$this->smtpHost = $settings->smtp_host;
$this->smtpPort = $settings->smtp_port;
$this->smtpEncryption = $settings->smtp_encryption;
$this->smtpUsername = $settings->smtp_username;
$this->smtpPassword = $settings->smtp_password;
$this->smtpTimeout = $settings->smtp_timeout;
if ($settings->resend_enabled) {
$this->resendEnabled = true;
$this->smtpEnabled = false;
}
$this->resendApiKey = $settings->resend_api_key;
$this->saveModel();
}
public function render()
{
return view('livewire.notifications.email');
}
}