refactor server limit check job + email notifications view

This commit is contained in:
Andras Bacsai
2024-11-05 11:22:23 +01:00
parent bfad7c7d7f
commit 5ce6c3ded1
4 changed files with 211 additions and 204 deletions

View File

@@ -30,8 +30,7 @@ class ServerLimitCheckJob implements ShouldBeEncrypted, ShouldQueue
try { try {
$servers = $this->team->servers; $servers = $this->team->servers;
$servers_count = $servers->count(); $servers_count = $servers->count();
$limit = data_get($this->team->limits, 'serverLimit', 2); $number_of_servers_to_disable = $servers_count - $this->team->limits;
$number_of_servers_to_disable = $servers_count - $limit;
if ($number_of_servers_to_disable > 0) { if ($number_of_servers_to_disable > 0) {
$servers = $servers->sortbyDesc('created_at'); $servers = $servers->sortbyDesc('created_at');
$servers_to_disable = $servers->take($number_of_servers_to_disable); $servers_to_disable = $servers->take($number_of_servers_to_disable);

View File

@@ -5,6 +5,7 @@ namespace App\Livewire\Notifications;
use App\Models\Team; use App\Models\Team;
use App\Notifications\Test; use App\Notifications\Test;
use Illuminate\Support\Facades\RateLimiter; use Illuminate\Support\Facades\RateLimiter;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Validate; use Livewire\Attributes\Validate;
use Livewire\Component; use Livewire\Component;
@@ -12,72 +13,124 @@ class Email extends Component
{ {
public Team $team; public Team $team;
#[Locked]
public string $emails; public string $emails;
public bool $sharedEmailEnabled = false;
#[Validate(['boolean'])] #[Validate(['boolean'])]
public bool $smtpEnabled = false; public bool $smtpEnabled = false;
protected $rules = [ #[Validate(['boolean'])]
'team.smtp_enabled' => 'nullable|boolean', public bool $useInstanceEmailSettings = false;
'team.smtp_from_address' => 'required|email',
'team.smtp_from_name' => 'required',
'team.smtp_recipients' => 'nullable',
'team.smtp_host' => 'required',
'team.smtp_port' => 'required',
'team.smtp_encryption' => 'nullable',
'team.smtp_username' => 'nullable',
'team.smtp_password' => 'nullable',
'team.smtp_timeout' => 'nullable',
'team.smtp_notifications_test' => 'nullable|boolean',
'team.smtp_notifications_deployments' => 'nullable|boolean',
'team.smtp_notifications_status_changes' => 'nullable|boolean',
'team.smtp_notifications_database_backups' => 'nullable|boolean',
'team.smtp_notifications_scheduled_tasks' => 'nullable|boolean',
'team.smtp_notifications_server_disk_usage' => 'nullable|boolean',
'team.use_instance_email_settings' => 'boolean',
'team.resend_enabled' => 'nullable|boolean',
'team.resend_api_key' => 'nullable',
];
protected $validationAttributes = [ #[Validate(['nullable', 'email'])]
'team.smtp_from_address' => 'From Address', public ?string $smtpFromAddress = null;
'team.smtp_from_name' => 'From Name',
'team.smtp_recipients' => 'Recipients', #[Validate(['nullable', 'string'])]
'team.smtp_host' => 'Host', public ?string $smtpFromName = null;
'team.smtp_port' => 'Port',
'team.smtp_encryption' => 'Encryption', #[Validate(['nullable', 'string'])]
'team.smtp_username' => 'Username', public ?string $smtpRecipients = null;
'team.smtp_password' => 'Password',
'team.smtp_timeout' => 'Timeout', #[Validate(['nullable', 'string'])]
'team.resend_enabled' => 'Resend Enabled', public ?string $smtpHost = null;
'team.resend_api_key' => 'Resend API Key',
]; #[Validate(['nullable', 'numeric'])]
public ?int $smtpPort = null;
#[Validate(['nullable', 'string'])]
public ?string $smtpEncryption = null;
#[Validate(['nullable', 'string'])]
public ?string $smtpUsername = null;
#[Validate(['nullable', 'string'])]
public ?string $smtpPassword = null;
#[Validate(['nullable', 'numeric'])]
public ?int $smtpTimeout = null;
#[Validate(['boolean'])]
public bool $smtpNotificationsTest;
#[Validate(['boolean'])]
public bool $smtpNotificationsDeployments;
#[Validate(['boolean'])]
public bool $smtpNotificationsStatusChanges;
#[Validate(['boolean'])]
public bool $smtpNotificationsDatabaseBackups;
#[Validate(['boolean'])]
public bool $smtpNotificationsScheduledTasks;
#[Validate(['boolean'])]
public bool $smtpNotificationsServerDiskUsage;
#[Validate(['boolean'])]
public bool $resendEnabled;
#[Validate(['nullable', 'string'])]
public ?string $resendApiKey = null;
public function mount() public function mount()
{
$this->team = auth()->user()->currentTeam();
['sharedEmailEnabled' => $this->sharedEmailEnabled] = $this->team->limits;
$this->emails = auth()->user()->email;
}
public function submitFromFields()
{ {
try { try {
$this->resetErrorBag(); $this->team = auth()->user()->currentTeam();
$this->validate([ $this->emails = auth()->user()->email;
'team.smtp_from_address' => 'required|email', $this->syncData();
'team.smtp_from_name' => 'required',
]);
$this->team->save();
refreshSession();
$this->dispatch('success', 'Settings saved.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return handleError($e, $this); return handleError($e, $this);
} }
} }
public function syncData(bool $toModel = false)
{
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();
} 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;
}
}
public function sendTestNotification() public function sendTestNotification()
{ {
try { try {
@@ -102,38 +155,45 @@ class Email extends Component
public function instantSaveInstance() public function instantSaveInstance()
{ {
try { try {
if (! $this->sharedEmailEnabled) { $this->smtpEnabled = false;
throw new \Exception('Not allowed to change settings. Please upgrade your subscription.'); $this->resendEnabled = false;
} $this->saveModel();
$this->team->smtp_enabled = false;
$this->team->resend_enabled = false;
$this->team->save();
refreshSession();
$this->dispatch('success', 'Settings saved.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return handleError($e, $this); 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() public function instantSaveResend()
{ {
try { try {
$this->team->smtp_enabled = false; $this->validate([
$this->submitResend(); 'resendApiKey' => 'required',
], [
'resendApiKey.required' => 'Resend API Key is required',
]);
$this->smtpEnabled = false;
$this->saveModel();
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->team->smtp_enabled = false; $this->resendEnabled = false;
return handleError($e, $this);
}
}
public function instantSave()
{
try {
$this->team->resend_enabled = false;
$this->submit();
} catch (\Throwable $e) {
$this->team->smtp_enabled = false;
return handleError($e, $this); return handleError($e, $this);
} }
@@ -141,7 +201,7 @@ class Email extends Component
public function saveModel() public function saveModel()
{ {
$this->team->save(); $this->syncData(true);
refreshSession(); refreshSession();
$this->dispatch('success', 'Settings saved.'); $this->dispatch('success', 'Settings saved.');
} }
@@ -150,43 +210,8 @@ class Email extends Component
{ {
try { try {
$this->resetErrorBag(); $this->resetErrorBag();
if (! $this->team->use_instance_email_settings) { $this->saveModel();
$this->validate([
'team.smtp_from_address' => 'required|email',
'team.smtp_from_name' => 'required',
'team.smtp_host' => 'required',
'team.smtp_port' => 'required|numeric',
'team.smtp_encryption' => 'nullable',
'team.smtp_username' => 'nullable',
'team.smtp_password' => 'nullable',
'team.smtp_timeout' => 'nullable',
]);
}
$this->team->save();
refreshSession();
$this->dispatch('success', 'Settings saved.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->team->smtp_enabled = false;
return handleError($e, $this);
}
}
public function submitResend()
{
try {
$this->resetErrorBag();
$this->validate([
'team.smtp_from_address' => 'required|email',
'team.smtp_from_name' => 'required',
'team.resend_api_key' => 'required',
]);
$this->team->save();
refreshSession();
$this->dispatch('success', 'Settings saved.');
} catch (\Throwable $e) {
$this->team->resend_enabled = false;
return handleError($e, $this); return handleError($e, $this);
} }
} }
@@ -194,35 +219,28 @@ class Email extends Component
public function copyFromInstanceSettings() public function copyFromInstanceSettings()
{ {
$settings = instanceSettings(); $settings = instanceSettings();
if ($settings->smtp_enabled) { if ($settings->smtp_enabled) {
$team = currentTeam(); $this->smtpEnabled = true;
$team->update([ $this->smtpFromAddress = $settings->smtp_from_address;
'smtp_enabled' => $settings->smtp_enabled, $this->smtpFromName = $settings->smtp_from_name;
'smtp_from_address' => $settings->smtp_from_address, $this->smtpRecipients = $settings->smtp_recipients;
'smtp_from_name' => $settings->smtp_from_name, $this->smtpHost = $settings->smtp_host;
'smtp_recipients' => $settings->smtp_recipients, $this->smtpPort = $settings->smtp_port;
'smtp_host' => $settings->smtp_host, $this->smtpEncryption = $settings->smtp_encryption;
'smtp_port' => $settings->smtp_port, $this->smtpUsername = $settings->smtp_username;
'smtp_encryption' => $settings->smtp_encryption, $this->smtpPassword = $settings->smtp_password;
'smtp_username' => $settings->smtp_username, $this->smtpTimeout = $settings->smtp_timeout;
'smtp_password' => $settings->smtp_password, $this->resendEnabled = false;
'smtp_timeout' => $settings->smtp_timeout, $this->saveModel();
]);
refreshSession();
$this->team = $team;
$this->dispatch('success', 'Settings saved.');
return; return;
} }
if ($settings->resend_enabled) { if ($settings->resend_enabled) {
$team = currentTeam(); $this->resendEnabled = true;
$team->update([ $this->resendApiKey = $settings->resend_api_key;
'resend_enabled' => $settings->resend_enabled, $this->smtpEnabled = false;
'resend_api_key' => $settings->resend_api_key, $this->saveModel();
]);
refreshSession();
$this->team = $team;
$this->dispatch('success', 'Settings saved.');
return; return;
} }

View File

@@ -187,9 +187,8 @@ class Team extends Model implements SendsDiscord, SendsEmail
} else { } else {
$serverLimit = config('constants.limits.server')[strtolower($subscription)]; $serverLimit = config('constants.limits.server')[strtolower($subscription)];
} }
$sharedEmailEnabled = config('constants.limits.email')[strtolower($subscription)];
return ['serverLimit' => $serverLimit, 'sharedEmailEnabled' => $sharedEmailEnabled]; return $serverLimit ?? 2;
} }
); );

View File

@@ -9,7 +9,7 @@
<x-forms.button type="submit"> <x-forms.button type="submit">
Save Save
</x-forms.button> </x-forms.button>
@if (isInstanceAdmin() && !$team->use_instance_email_settings) @if (isInstanceAdmin() && !$useInstanceEmailSettings)
<x-forms.button wire:click='copyFromInstanceSettings'> <x-forms.button wire:click='copyFromInstanceSettings'>
Copy from Instance Settings Copy from Instance Settings
</x-forms.button> </x-forms.button>
@@ -25,99 +25,90 @@
</x-modal-input> </x-modal-input>
@endif @endif
</div> </div>
</form> @if (!isCloud())
@if (isCloud()) <div class="w-96">
@if ($this->sharedEmailEnabled) <x-forms.checkbox instantSave="instantSaveInstance" id="useInstanceEmailSettings"
<div class="w-64 py-4"> label="Use system wide (transactional) email settings" />
<x-forms.checkbox instantSave="instantSaveInstance" id="team.use_instance_email_settings"
label="Use Hosted Email Service" />
</div>
@else
<div class="w-96 pb-4">
<x-forms.checkbox disabled id="team.use_instance_email_settings"
label="Use Hosted Email Service (Pro+ subscription required)" />
</div> </div>
@endif @endif
@else @if (!$useInstanceEmailSettings)
<div class="w-96"> <div class="flex gap-4">
<x-forms.checkbox instantSave="instantSaveInstance" id="team.use_instance_email_settings" <x-forms.input required id="smtpFromName" helper="Name used in emails." label="From Name" />
label="Use system wide (transactional) email settings" /> <x-forms.input required id="smtpFromAddress" helper="Email address used in emails."
label="From Address" />
</div>
@endif
</form>
@if (isCloud())
<div class="w-64 py-4">
<x-forms.checkbox instantSave="instantSaveInstance" id="useInstanceEmailSettings"
label="Use Hosted Email Service" />
</div> </div>
@endif @endif
@if (!$team->use_instance_email_settings) @if (!$useInstanceEmailSettings)
<form class="flex flex-col items-end gap-2 pt-4 pb-4 xl:flex-row" wire:submit='submitFromFields'>
<x-forms.input required id="team.smtp_from_name" helper="Name used in emails." label="From Name" />
<x-forms.input required id="team.smtp_from_address" helper="Email address used in emails."
label="From Address" />
<x-forms.button type="submit">
Save
</x-forms.button>
</form>
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<div class="p-4 border dark:border-coolgray-300"> <form wire:submit='submit' class="p-4 border dark:border-coolgray-300 flex flex-col gap-2">
<h3>SMTP Server</h3> <div class="flex items-center gap-2">
<div class="w-32"> <h3>SMTP Server</h3>
<x-forms.checkbox instantSave id="team.smtp_enabled" label="Enabled" /> <x-forms.button type="submit">
Save
</x-forms.button>
</div> </div>
<form wire:submit='submit' class="flex flex-col"> <div class="w-32">
<x-forms.checkbox instantSave="instantSaveSmtpEnabled" id="smtpEnabled" label="Enabled" />
</div>
<div class="flex flex-col">
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<div class="flex flex-col w-full gap-2 xl:flex-row"> <div class="flex flex-col w-full gap-2 xl:flex-row">
<x-forms.input required id="team.smtp_host" placeholder="smtp.mailgun.org" label="Host" /> <x-forms.input required id="smtpHost" placeholder="smtp.mailgun.org" label="Host" />
<x-forms.input required id="team.smtp_port" placeholder="587" label="Port" /> <x-forms.input required id="smtpPort" placeholder="587" label="Port" />
<x-forms.input id="team.smtp_encryption" helper="If SMTP uses SSL, set it to 'tls'." <x-forms.input id="smtpEncryption" helper="If SMTP uses SSL, set it to 'tls'."
placeholder="tls" label="Encryption" /> placeholder="tls" label="Encryption" />
</div> </div>
<div class="flex flex-col w-full gap-2 xl:flex-row"> <div class="flex flex-col w-full gap-2 xl:flex-row">
<x-forms.input id="team.smtp_username" label="SMTP Username" /> <x-forms.input id="smtpUsername" label="SMTP Username" />
<x-forms.input id="team.smtp_password" type="password" label="SMTP Password" /> <x-forms.input id="smtpPassword" type="password" label="SMTP Password" />
<x-forms.input id="team.smtp_timeout" helper="Timeout value for sending emails." <x-forms.input id="smtpTimeout" helper="Timeout value for sending emails."
label="Timeout" /> label="Timeout" />
</div> </div>
</div> </div>
<div class="flex justify-end gap-4 pt-6">
<x-forms.button type="submit">
Save
</x-forms.button>
</div>
</form>
</div>
<div class="p-4 border dark:border-coolgray-300">
<h3>Resend</h3>
<div class="w-32">
<x-forms.checkbox instantSave='instantSaveResend' id="team.resend_enabled" label="Enabled" />
</div> </div>
<form wire:submit='submitResend' class="flex flex-col"> </form>
<form wire:submit='submit' class="p-4 border dark:border-coolgray-300 flex flex-col gap-2">
<div class="flex items-center gap-2">
<h3>Resend</h3>
<x-forms.button type="submit">
Save
</x-forms.button>
</div>
<div class="w-32">
<x-forms.checkbox instantSave='instantSaveResend' id="resendEnabled" label="Enabled" />
</div>
<div class="flex flex-col">
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<div class="flex flex-col w-full gap-2 xl:flex-row"> <div class="flex flex-col w-full gap-2 xl:flex-row">
<x-forms.input required type="password" id="team.resend_api_key" placeholder="API key" <x-forms.input required type="password" id="resendApiKey" placeholder="API key"
label="API Key" /> label="API Key" />
</div> </div>
</div> </div>
<div class="flex justify-end gap-4 pt-6"> </div>
<x-forms.button type="submit"> </form>
Save
</x-forms.button>
</div>
</form>
</div>
</div> </div>
@endif @endif
@if (isEmailEnabled($team) || data_get($team, 'use_instance_email_settings')) @if (isEmailEnabled($team) || $useInstanceEmailSettings)
<h2 class="mt-4">Subscribe to events</h2> <h2 class="mt-4">Subscribe to events</h2>
<div class="w-64"> <div class="w-64">
@if (isDev()) @if (isDev())
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_test" label="Test" /> <x-forms.checkbox instantSave="saveModel" id="smtpNotificationsTest" label="Test" />
@endif @endif
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_status_changes" <x-forms.checkbox instantSave="saveModel" id="smtpNotificationsStatusChanges"
label="Container Status Changes" /> label="Container Status Changes" />
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_deployments" <x-forms.checkbox instantSave="saveModel" id="smtpNotificationsDeployments"
label="Application Deployments" /> label="Application Deployments" />
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_database_backups" <x-forms.checkbox instantSave="saveModel" id="smtpNotificationsDatabaseBackups" label="Backup Status" />
label="Backup Status" /> <x-forms.checkbox instantSave="saveModel" id="smtpNotificationsScheduledTasks"
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_scheduled_tasks"
label="Scheduled Tasks Status" /> label="Scheduled Tasks Status" />
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_server_disk_usage" <x-forms.checkbox instantSave="saveModel" id="smtpNotificationsServerDiskUsage" label="Server Disk Usage" />
label="Server Disk Usage" />
</div> </div>
@endif @endif
</div> </div>