]> BookStack Code Mirror - bookstack/commitdiff
Notifications: Logged errors and prevented them blocking user
authorDan Brown <redacted>
Thu, 12 Dec 2024 21:45:52 +0000 (21:45 +0000)
committerDan Brown <redacted>
Thu, 12 Dec 2024 21:47:39 +0000 (21:47 +0000)
Failed notification sends could block the user action, whereas it's
probably more important that the user action takes places uninteruupted
than showing an error screen for the user to debug.
Logs notification errors so issues can still be debugged by admins.

Closes #5315

app/Activity/Notifications/Handlers/BaseNotificationHandler.php
tests/Activity/WatchTest.php

index b5f339b2ce0ba3f98f680df4339fc56910476d79..3a9b0c1dc80fa2c7ef6d7716ca0838025b063018 100644 (file)
@@ -7,6 +7,7 @@ use BookStack\Activity\Notifications\Messages\BaseActivityNotification;
 use BookStack\Entities\Models\Entity;
 use BookStack\Permissions\PermissionApplicator;
 use BookStack\Users\Models\User;
+use Illuminate\Support\Facades\Log;
 
 abstract class BaseNotificationHandler implements NotificationHandler
 {
@@ -36,7 +37,11 @@ abstract class BaseNotificationHandler implements NotificationHandler
             }
 
             // Send the notification
-            $user->notify(new $notification($detail, $initiator));
+            try {
+                $user->notify(new $notification($detail, $initiator));
+            } catch (\Exception $exception) {
+                Log::error("Failed to send email notification to user [id:{$user->id}] with error: {$exception->getMessage()}");
+            }
         }
     }
 }
index 605b60fd498e26cf95d37daa06e95d1c7a6035e4..c405b07aed7011d49f8856cd53a1e7c671c268a7 100644 (file)
@@ -13,6 +13,8 @@ use BookStack\Activity\Tools\UserEntityWatchOptions;
 use BookStack\Activity\WatchLevels;
 use BookStack\Entities\Models\Entity;
 use BookStack\Settings\UserNotificationPreferences;
+use Illuminate\Contracts\Notifications\Dispatcher;
+use Illuminate\Support\Facades\Mail;
 use Illuminate\Support\Facades\Notification;
 use Tests\TestCase;
 
@@ -365,6 +367,29 @@ class WatchTest extends TestCase
         }
     }
 
+    public function test_failed_notifications_dont_block_and_log_errors()
+    {
+        $logger = $this->withTestLogger();
+        $editor = $this->users->editor();
+        $admin = $this->users->admin();
+        $page = $this->entities->page();
+        $book = $page->book;
+        $activityLogger = app()->make(ActivityLogger::class);
+
+        $watches = new UserEntityWatchOptions($editor, $book);
+        $watches->updateLevelByValue(WatchLevels::UPDATES);
+
+        $mockDispatcher = $this->mock(Dispatcher::class);
+        $mockDispatcher->shouldReceive('send')->once()
+            ->andThrow(\Exception::class, 'Failed to connect to mail server');
+
+        $this->actingAs($admin);
+
+        $activityLogger->add(ActivityType::PAGE_UPDATE, $page);
+
+        $this->assertTrue($logger->hasErrorThatContains("Failed to send email notification to user [id:{$editor->id}] with error: Failed to connect to mail server"));
+    }
+
     public function test_notifications_not_sent_if_lacking_view_permission_for_related_item()
     {
         $notifications = Notification::fake();