homeos/app/Services/NotificationService.php

81 lines
2.7 KiB
PHP

<?php
namespace App\Services;
use App\Models\Addon;
use Illuminate\Support\Facades\Mail;
/**
* Sends e-mail notifications via the user's SMTP add-on. The SMTP settings live (encrypted) on the
* addon row; we configure a runtime mailer from them so no .env editing is needed. Each event type
* is individually toggleable, so the user controls exactly what they get mailed about.
*/
class NotificationService
{
/** @return array<string,mixed>|null */
public function config(): ?array
{
return Addon::where('key', 'smtp')->where('installed', true)->first()?->config;
}
public function eventEnabled(string $event): bool
{
return (bool) data_get($this->config(), "events.{$event}", false);
}
/** Send only if the SMTP add-on is set up AND this event type is enabled. */
public function notify(string $event, string $subject, string $body): bool
{
if (! $this->eventEnabled($event)) {
return false;
}
return $this->send($subject, $body);
}
/** Send unconditionally (used by the "send test" button). Returns success, never throws. */
public function send(string $subject, string $body): bool
{
$cfg = $this->config();
if ($cfg === null || blank($cfg['to_email'] ?? null) || blank($cfg['host'] ?? null)) {
return false;
}
$this->configureMailer($cfg);
try {
Mail::mailer('homeos_smtp')->raw($body, function ($message) use ($cfg) {
$message->to($cfg['to_email'])
->subject('[HomeOS] '.$subject)
->from($cfg['from_email'] ?: 'homeos@localhost', $cfg['from_name'] ?: 'HomeOS');
});
} catch (\Throwable $e) {
// A transient SMTP failure must not abort the caller (a sweep over many devices, an
// automation run). Log and report failure so the loop keeps going.
report($e);
return false;
}
return true;
}
/** @param array<string,mixed> $cfg */
private function configureMailer(array $cfg): void
{
config(['mail.mailers.homeos_smtp' => [
'transport' => 'smtp',
'host' => $cfg['host'],
'port' => (int) ($cfg['port'] ?? 587),
'encryption' => ($cfg['encryption'] ?? '') ?: null,
'username' => ($cfg['username'] ?? '') ?: null,
'password' => ($cfg['password'] ?? '') ?: null,
'timeout' => 10,
]]);
// MailManager caches the resolved mailer by name; purge it so a long-running worker
// (Horizon) picks up config changes instead of reusing the first mailer it built.
Mail::purge('homeos_smtp');
}
}