libra/app/Services/AdminNotificationService.php

82 lines
2.3 KiB
PHP

<?php
namespace App\Services;
use App\Contracts\ShouldNotifyAdmin;
use App\Notifications\SystemErrorNotification;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Notification;
use Throwable;
class AdminNotificationService
{
public function notifyError(Throwable $exception): void
{
if (! config('libra.notifications.system_notifications_enabled')) {
return;
}
$adminEmail = config('libra.notifications.admin_email');
if (empty($adminEmail)) {
return;
}
$errorKey = $this->getErrorKey($exception);
$throttleMinutes = config('libra.notifications.throttle_minutes', 15);
if (Cache::has($errorKey)) {
return;
}
Cache::put($errorKey, true, now()->addMinutes($throttleMinutes));
Notification::route('mail', $adminEmail)
->notifyNow(new SystemErrorNotification($exception));
}
protected function getErrorKey(Throwable $exception): string
{
return 'admin_notified:'.md5(get_class($exception).$exception->getMessage());
}
public function shouldNotifyAdmin(Throwable $exception): bool
{
if ($exception instanceof ShouldNotifyAdmin) {
return true;
}
$excludedTypes = [
\Illuminate\Validation\ValidationException::class,
\Illuminate\Auth\AuthenticationException::class,
\Illuminate\Auth\Access\AuthorizationException::class,
\Illuminate\Database\Eloquent\ModelNotFoundException::class,
\Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class,
\Illuminate\Session\TokenMismatchException::class,
];
foreach ($excludedTypes as $type) {
if ($exception instanceof $type) {
return false;
}
}
if ($exception instanceof \Illuminate\Database\QueryException) {
return $this->isCriticalDatabaseError($exception);
}
if ($exception instanceof \Symfony\Component\Mailer\Exception\TransportExceptionInterface) {
return true;
}
return false;
}
protected function isCriticalDatabaseError(\Illuminate\Database\QueryException $e): bool
{
$criticalCodes = ['2002', '1045', '1049'];
return in_array($e->getCode(), $criticalCodes);
}
}