Files
trackbugs/app/Services/NotificationDispatcher.php
T
2026-03-19 19:47:06 +02:00

98 lines
2.8 KiB
PHP

<?php
namespace App\Services;
use App\Models\AlertRule;
use App\Models\Event;
use App\Models\Issue;
use App\Models\Project;
use App\Notifications\EventSpikeNotification;
use App\Notifications\IssueRegressionNotification;
use App\Notifications\NewIssueNotification;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Notification;
class NotificationDispatcher
{
public function onNewIssue(Project $project, Issue $issue): void
{
if (! $this->ruleEnabled($project, 'new_issue')) {
return;
}
$recipients = $this->getRecipients($project);
Notification::send($recipients, new NewIssueNotification($project, $issue));
}
public function onRegression(Project $project, Issue $issue): void
{
if (! $this->ruleEnabled($project, 'regression')) {
return;
}
$recipients = $this->getRecipients($project);
Notification::send($recipients, new IssueRegressionNotification($project, $issue));
}
public function checkSpike(Project $project, Issue $issue): void
{
$rule = $project->alertRules()
->where('type', 'spike')
->where('enabled', true)
->first();
if (! $rule) {
return;
}
$threshold = $rule->getSpikeThreshold();
$windowMinutes = $rule->getSpikeWindowMinutes();
$recentCount = Event::where('issue_id', $issue->id)
->where('created_at', '>=', Carbon::now()->subMinutes($windowMinutes))
->count();
if ($recentCount < $threshold) {
return;
}
// Only send once per spike window — check if we already notified
$alreadyNotified = $project->users()
->first()
?->notifications()
->where('type', EventSpikeNotification::class)
->where('created_at', '>=', Carbon::now()->subMinutes($windowMinutes))
->whereJsonContains('data->issue_id', $issue->id)
->exists();
if ($alreadyNotified) {
return;
}
$recipients = $this->getRecipients($project);
Notification::send(
$recipients,
new EventSpikeNotification($project, $issue, $recentCount, $windowMinutes),
);
}
private function ruleEnabled(Project $project, string $type): bool
{
$rule = $project->alertRules()->where('type', $type)->first();
// Default: enabled if no rule exists (opt-out model)
return $rule === null || $rule->enabled;
}
private function getRecipients(Project $project)
{
return $project->users()
->get()
->filter(function ($user) use ($project) {
$pref = $user->notificationPreferenceFor($project);
return ! $pref->muted;
});
}
}