TenantAtlas/app/Services/Alerts/AlertSender.php
2026-02-18 15:25:14 +01:00

97 lines
3.0 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\Alerts;
use App\Models\AlertDelivery;
use App\Models\AlertDestination;
use App\Notifications\Alerts\EmailAlertNotification;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Notification;
use RuntimeException;
use Throwable;
class AlertSender
{
public function __construct(
private readonly TeamsWebhookSender $teamsWebhookSender,
) {}
public function send(AlertDelivery $delivery): void
{
$destination = $delivery->destination;
if (! $destination instanceof AlertDestination) {
throw new RuntimeException('Alert destination is missing.');
}
if (! (bool) $destination->is_enabled) {
throw new RuntimeException('Alert destination is disabled.');
}
$payload = is_array($delivery->payload) ? $delivery->payload : [];
try {
if ($destination->type === AlertDestination::TYPE_TEAMS_WEBHOOK) {
$this->deliverTeams($destination, $payload);
return;
}
if ($destination->type === AlertDestination::TYPE_EMAIL) {
$this->deliverEmail($delivery, $destination, $payload);
return;
}
} catch (Throwable $exception) {
throw new RuntimeException($this->channelFailureMessage((string) $destination->type), previous: $exception);
}
throw new RuntimeException('Alert destination type is not supported.');
}
/**
* @param array<string, mixed> $payload
*/
private function deliverTeams(AlertDestination $destination, array $payload): void
{
$config = is_array($destination->config) ? $destination->config : [];
$webhookUrl = trim((string) Arr::get($config, 'webhook_url', ''));
if ($webhookUrl === '') {
throw new RuntimeException('Teams webhook destination is not configured.');
}
$this->teamsWebhookSender->send($webhookUrl, $payload);
}
/**
* @param array<string, mixed> $payload
*/
private function deliverEmail(AlertDelivery $delivery, AlertDestination $destination, array $payload): void
{
$config = is_array($destination->config) ? $destination->config : [];
$recipients = Arr::get($config, 'recipients', []);
$recipients = is_array($recipients)
? array_values(array_unique(array_filter(array_map(static fn (mixed $value): string => trim((string) $value), $recipients))))
: [];
if ($recipients === []) {
throw new RuntimeException('Email destination has no recipients.');
}
Notification::route('mail', $recipients)
->notify(new EmailAlertNotification($delivery, $payload));
}
private function channelFailureMessage(string $type): string
{
return match ($type) {
AlertDestination::TYPE_TEAMS_WEBHOOK => 'Teams delivery failed.',
AlertDestination::TYPE_EMAIL => 'Email delivery failed.',
default => 'Alert delivery failed.',
};
}
}