fix: Instance email settins
- fix: resend, smtp save button should only save respective settings - feat: ability to send test email
This commit is contained in:
		@@ -3,6 +3,8 @@
 | 
			
		||||
namespace App\Livewire;
 | 
			
		||||
 | 
			
		||||
use App\Models\InstanceSettings;
 | 
			
		||||
use App\Notifications\Test;
 | 
			
		||||
use Illuminate\Support\Facades\RateLimiter;
 | 
			
		||||
use Livewire\Attributes\Validate;
 | 
			
		||||
use Livewire\Component;
 | 
			
		||||
 | 
			
		||||
@@ -13,6 +15,15 @@ class SettingsEmail extends Component
 | 
			
		||||
    #[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 +31,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) {
 | 
			
		||||
@@ -90,7 +98,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 +107,120 @@ class SettingsEmail extends Component
 | 
			
		||||
    public function instantSave(string $type)
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $this->resetErrorBag();
 | 
			
		||||
 | 
			
		||||
            if ($type === 'SMTP') {
 | 
			
		||||
                $this->resendEnabled = false;
 | 
			
		||||
            } else {
 | 
			
		||||
                $this->smtpEnabled = false;
 | 
			
		||||
                $this->submitSmtp();
 | 
			
		||||
            } elseif ($type === 'Resend') {
 | 
			
		||||
                $this->submitResend();
 | 
			
		||||
            }
 | 
			
		||||
            $this->syncData(true);
 | 
			
		||||
            if ($this->smtpEnabled || $this->resendEnabled) {
 | 
			
		||||
                $this->dispatch('success', "{$type} enabled.");
 | 
			
		||||
            } else {
 | 
			
		||||
                $this->dispatch('success', "{$type} disabled.");
 | 
			
		||||
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            if ($type === 'SMTP') {
 | 
			
		||||
                $this->smtpEnabled = false;
 | 
			
		||||
            } elseif ($type === 'Resend') {
 | 
			
		||||
                $this->resendEnabled = false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return handleError($e, $this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function submitSmtp(): void
 | 
			
		||||
    {
 | 
			
		||||
        $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->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->resend_enabled = false;
 | 
			
		||||
        $this->settings->save();
 | 
			
		||||
 | 
			
		||||
        $this->dispatch('success', 'SMTP settings updated.');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function submitResend(): void
 | 
			
		||||
    {
 | 
			
		||||
        $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->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->smtp_enabled = false;
 | 
			
		||||
        $this->settings->save();
 | 
			
		||||
 | 
			
		||||
        $this->dispatch('success', 'Resend settings updated.');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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));
 | 
			
		||||
                    $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 isEmailEnabled(): bool
 | 
			
		||||
    {
 | 
			
		||||
        return $this->settings->smtp_enabled || $this->settings->resend_enabled;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,17 +9,26 @@
 | 
			
		||||
                <x-forms.button type="submit">
 | 
			
		||||
                    Save
 | 
			
		||||
                </x-forms.button>
 | 
			
		||||
                @if ($this->isEmailEnabled() && auth()->user()->isAdminFromSession())
 | 
			
		||||
                <x-modal-input buttonTitle="Send Test Email" title="Send Test Email">
 | 
			
		||||
                    <form wire:submit.prevent="sendTestEmail" class="flex flex-col w-full gap-2">
 | 
			
		||||
                        <x-forms.input wire:model="testEmailAddress" placeholder="test@example.com" id="testEmailAddress" label="Recipients" required />
 | 
			
		||||
                        <x-forms.button type="submit" @click="modalOpen=false">
 | 
			
		||||
                            Send Email
 | 
			
		||||
                        </x-forms.button>
 | 
			
		||||
                    </form>
 | 
			
		||||
                </x-modal-input>
 | 
			
		||||
                @endif
 | 
			
		||||
            </div>
 | 
			
		||||
        <div class="pb-4 ">Email settings for password resets, invitations, etc.</div>
 | 
			
		||||
            <div class="pb-4">Instance wide email settings for password resets, invitations, etc.</div>
 | 
			
		||||
            <div class="flex gap-4">
 | 
			
		||||
                <x-forms.input required id="smtpFromName" helper="Name used in emails." label="From Name" />
 | 
			
		||||
                <x-forms.input required id="smtpFromAddress" helper="Email address used in emails." label="From Address" />
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
        </form>
 | 
			
		||||
        <div class="flex flex-col gap-4">
 | 
			
		||||
            <div class="p-4 border dark:border-coolgray-300">
 | 
			
		||||
            <form wire:submit='submit' class="flex flex-col">
 | 
			
		||||
                <form wire:submit.prevent="submitSmtp" class="flex flex-col">
 | 
			
		||||
                    <div class="flex gap-2">
 | 
			
		||||
                        <h3>SMTP Server</h3>
 | 
			
		||||
                        <x-forms.button type="submit">
 | 
			
		||||
@@ -41,15 +50,14 @@
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="flex flex-col w-full gap-2 xl:flex-row">
 | 
			
		||||
                            <x-forms.input id="smtpUsername" label="SMTP Username" />
 | 
			
		||||
                        <x-forms.input id="smtpPassword" type="password" label="SMTP Password"
 | 
			
		||||
                            autocomplete="new-password" />
 | 
			
		||||
                            <x-forms.input id="smtpPassword" type="password" label="SMTP Password" autocomplete="new-password" />
 | 
			
		||||
                            <x-forms.input id="smtpTimeout" helper="Timeout value for sending emails." label="Timeout" />
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </form>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="p-4 border dark:border-coolgray-300">
 | 
			
		||||
            <form wire:submit='submit' class="flex flex-col">
 | 
			
		||||
                <form wire:submit.prevent="submitResend" class="flex flex-col">
 | 
			
		||||
                    <div class="flex gap-2">
 | 
			
		||||
                        <h3>Resend</h3>
 | 
			
		||||
                        <x-forms.button type="submit">
 | 
			
		||||
@@ -61,8 +69,7 @@
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="flex flex-col gap-4">
 | 
			
		||||
                        <div class="flex flex-col w-full gap-2 xl:flex-row">
 | 
			
		||||
                        <x-forms.input type="password" id="resendApiKey" placeholder="API key" required label="API Key"
 | 
			
		||||
                            autocomplete="new-password" />
 | 
			
		||||
                            <x-forms.input type="password" id="resendApiKey" placeholder="API key" required label="API Key" autocomplete="new-password" />
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </form>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user