]> BookStack Code Mirror - bookstack/blobdiff - tests/Activity/WatchTest.php
Fixed OIDC Logout
[bookstack] / tests / Activity / WatchTest.php
index 919e526081979c81de34c0075223b0bd4b40177a..fd86029d32c740f07d1ffac5298f681c3bba7e92 100644 (file)
@@ -2,9 +2,14 @@
 
 namespace Tests\Activity;
 
+use BookStack\Activity\Notifications\Messages\CommentCreationNotification;
+use BookStack\Activity\Notifications\Messages\PageCreationNotification;
+use BookStack\Activity\Notifications\Messages\PageUpdateNotification;
 use BookStack\Activity\Tools\UserEntityWatchOptions;
 use BookStack\Activity\WatchLevels;
 use BookStack\Entities\Models\Entity;
+use BookStack\Settings\UserNotificationPreferences;
+use Illuminate\Support\Facades\Notification;
 use Tests\TestCase;
 
 class WatchTest extends TestCase
@@ -21,7 +26,7 @@ class WatchTest extends TestCase
             $this->withHtml($resp)->assertElementContains('form[action$="/watching/update"] button.icon-list-item', 'Watch');
 
             $watchOptions = new UserEntityWatchOptions($editor, $entity);
-            $watchOptions->updateWatchLevel('comments');
+            $watchOptions->updateLevelByValue(WatchLevels::COMMENTS);
 
             $resp = $this->get($entity->getUrl());
             $this->withHtml($resp)->assertElementNotExists('form[action$="/watching/update"] button.icon-list-item');
@@ -83,6 +88,23 @@ class WatchTest extends TestCase
         ]);
     }
 
+    public function test_watch_update_fails_for_guest()
+    {
+        $this->setSettings(['app-public' => 'true']);
+        $guest = $this->users->guest();
+        $this->permissions->grantUserRolePermissions($guest, ['receive-notifications']);
+        $book = $this->entities->book();
+
+        $resp = $this->put('/watching/update', [
+            'type' => get_class($book),
+            'id' => $book->id,
+            'level' => 'comments'
+        ]);
+
+        $this->assertPermissionError($resp);
+        $guest->unsetRelations();
+    }
+
     public function test_watch_detail_display_reflects_state()
     {
         $editor = $this->users->editor();
@@ -90,17 +112,17 @@ class WatchTest extends TestCase
         $chapter = $book->chapters()->first();
         $page = $chapter->pages()->first();
 
-        (new UserEntityWatchOptions($editor, $book))->updateWatchLevel('updates');
+        (new UserEntityWatchOptions($editor, $book))->updateLevelByValue(WatchLevels::UPDATES);
 
         $this->actingAs($editor)->get($book->getUrl())->assertSee('Watching new pages and updates');
         $this->get($chapter->getUrl())->assertSee('Watching via parent book');
         $this->get($page->getUrl())->assertSee('Watching via parent book');
 
-        (new UserEntityWatchOptions($editor, $chapter))->updateWatchLevel('comments');
+        (new UserEntityWatchOptions($editor, $chapter))->updateLevelByValue(WatchLevels::COMMENTS);
         $this->get($chapter->getUrl())->assertSee('Watching new pages, updates & comments');
         $this->get($page->getUrl())->assertSee('Watching via parent chapter');
 
-        (new UserEntityWatchOptions($editor, $page))->updateWatchLevel('updates');
+        (new UserEntityWatchOptions($editor, $page))->updateLevelByValue(WatchLevels::UPDATES);
         $this->get($page->getUrl())->assertSee('Watching new pages and updates');
     }
 
@@ -108,7 +130,7 @@ class WatchTest extends TestCase
     {
         $editor = $this->users->editor();
         $book = $this->entities->bookHasChaptersAndPages();
-        (new UserEntityWatchOptions($editor, $book))->updateWatchLevel('ignore');
+        (new UserEntityWatchOptions($editor, $book))->updateLevelByValue(WatchLevels::IGNORE);
 
         $this->actingAs($editor)->get($book->getUrl())->assertSee('Ignoring notifications');
         $this->get($book->chapters()->first()->getUrl())->assertSee('Ignoring via parent book');
@@ -124,11 +146,11 @@ class WatchTest extends TestCase
         $respHtml = $this->withHtml($this->actingAs($editor)->get($book->getUrl()));
         $respHtml->assertElementNotExists('form[action$="/watching/update"] svg[data-icon="check-circle"]');
 
-        $options->updateWatchLevel('comments');
+        $options->updateLevelByValue(WatchLevels::COMMENTS);
         $respHtml = $this->withHtml($this->actingAs($editor)->get($book->getUrl()));
         $respHtml->assertElementExists('form[action$="/watching/update"] button[value="comments"] svg[data-icon="check-circle"]');
 
-        $options->updateWatchLevel('ignore');
+        $options->updateLevelByValue(WatchLevels::IGNORE);
         $respHtml = $this->withHtml($this->actingAs($editor)->get($book->getUrl()));
         $respHtml->assertElementExists('form[action$="/watching/update"] button[value="ignore"] svg[data-icon="check-circle"]');
     }
@@ -137,7 +159,7 @@ class WatchTest extends TestCase
     {
         $editor = $this->users->editor();
         $book = $this->entities->bookHasChaptersAndPages();
-        (new UserEntityWatchOptions($editor, $book))->updateWatchLevel('ignore');
+        (new UserEntityWatchOptions($editor, $book))->updateLevelByValue(WatchLevels::IGNORE);
 
         $respHtml = $this->withHtml($this->actingAs($editor)->get($book->getUrl()));
         $respHtml->assertElementExists('form[action$="/watching/update"] button[name="level"][value="new"]');
@@ -147,6 +169,164 @@ class WatchTest extends TestCase
         $respHtml->assertElementNotExists('form[action$="/watching/update"] button[name="level"][value="new"]');
     }
 
-    // TODO - Guest user cannot see/set notifications
-    // TODO - Actual notification testing
+    public function test_notify_own_page_changes()
+    {
+        $editor = $this->users->editor();
+        $entities = $this->entities->createChainBelongingToUser($editor);
+        $prefs = new UserNotificationPreferences($editor);
+        $prefs->updateFromSettingsArray(['own-page-changes' => 'true']);
+
+        $notifications = Notification::fake();
+
+        $this->asAdmin();
+        $this->entities->updatePage($entities['page'], ['name' => 'My updated page', 'html' => 'Hello']);
+        $notifications->assertSentTo($editor, PageUpdateNotification::class);
+    }
+
+    public function test_notify_own_page_comments()
+    {
+        $editor = $this->users->editor();
+        $entities = $this->entities->createChainBelongingToUser($editor);
+        $prefs = new UserNotificationPreferences($editor);
+        $prefs->updateFromSettingsArray(['own-page-comments' => 'true']);
+
+        $notifications = Notification::fake();
+
+        $this->asAdmin()->post("/comment/{$entities['page']->id}", [
+            'text' => 'My new comment'
+        ]);
+        $notifications->assertSentTo($editor, CommentCreationNotification::class);
+    }
+
+    public function test_notify_comment_replies()
+    {
+        $editor = $this->users->editor();
+        $entities = $this->entities->createChainBelongingToUser($editor);
+        $prefs = new UserNotificationPreferences($editor);
+        $prefs->updateFromSettingsArray(['comment-replies' => 'true']);
+
+        $notifications = Notification::fake();
+
+        $this->actingAs($editor)->post("/comment/{$entities['page']->id}", [
+            'text' => 'My new comment'
+        ]);
+        $comment = $entities['page']->comments()->first();
+
+        $this->asAdmin()->post("/comment/{$entities['page']->id}", [
+            'text' => 'My new comment response',
+            'parent_id' => $comment->id,
+        ]);
+        $notifications->assertSentTo($editor, CommentCreationNotification::class);
+    }
+
+    public function test_notify_watch_parent_book_ignore()
+    {
+        $editor = $this->users->editor();
+        $entities = $this->entities->createChainBelongingToUser($editor);
+        $watches = new UserEntityWatchOptions($editor, $entities['book']);
+        $prefs = new UserNotificationPreferences($editor);
+        $watches->updateLevelByValue(WatchLevels::IGNORE);
+        $prefs->updateFromSettingsArray(['own-page-changes' => 'true', 'own-page-comments' => true]);
+
+        $notifications = Notification::fake();
+
+        $this->asAdmin()->post("/comment/{$entities['page']->id}", [
+            'text' => 'My new comment response',
+        ]);
+        $this->entities->updatePage($entities['page'], ['name' => 'My updated page', 'html' => 'Hello']);
+        $notifications->assertNothingSent();
+    }
+
+    public function test_notify_watch_parent_book_comments()
+    {
+        $notifications = Notification::fake();
+        $editor = $this->users->editor();
+        $admin = $this->users->admin();
+        $entities = $this->entities->createChainBelongingToUser($editor);
+        $watches = new UserEntityWatchOptions($editor, $entities['book']);
+        $watches->updateLevelByValue(WatchLevels::COMMENTS);
+
+        // Comment post
+        $this->actingAs($admin)->post("/comment/{$entities['page']->id}", [
+            'text' => 'My new comment response',
+        ]);
+
+        $notifications->assertSentTo($editor, function (CommentCreationNotification $notification) use ($editor, $admin, $entities) {
+            $mail = $notification->toMail($editor);
+            $mailContent = html_entity_decode(strip_tags($mail->render()));
+            return $mail->subject === 'New comment on page: ' . $entities['page']->getShortName()
+                && str_contains($mailContent, 'View Comment')
+                && str_contains($mailContent, 'Page Name: ' . $entities['page']->name)
+                && str_contains($mailContent, 'Commenter: ' . $admin->name)
+                && str_contains($mailContent, 'Comment: My new comment response');
+        });
+    }
+
+    public function test_notify_watch_parent_book_updates()
+    {
+        $notifications = Notification::fake();
+        $editor = $this->users->editor();
+        $admin = $this->users->admin();
+        $entities = $this->entities->createChainBelongingToUser($editor);
+        $watches = new UserEntityWatchOptions($editor, $entities['book']);
+        $watches->updateLevelByValue(WatchLevels::UPDATES);
+
+        $this->actingAs($admin);
+        $this->entities->updatePage($entities['page'], ['name' => 'Updated page', 'html' => 'new page content']);
+
+        $notifications->assertSentTo($editor, function (PageUpdateNotification $notification) use ($editor, $admin) {
+            $mail = $notification->toMail($editor);
+            $mailContent = html_entity_decode(strip_tags($mail->render()));
+            return $mail->subject === 'Updated page: Updated page'
+                && str_contains($mailContent, 'View Page')
+                && str_contains($mailContent, 'Page Name: Updated page')
+                && str_contains($mailContent, 'Updated By: ' . $admin->name)
+                && str_contains($mailContent, 'you won\'t be sent notifications for further edits to this page by the same editor');
+        });
+
+        // Test debounce
+        $notifications = Notification::fake();
+        $this->entities->updatePage($entities['page'], ['name' => 'Updated page', 'html' => 'new page content']);
+        $notifications->assertNothingSentTo($editor);
+    }
+
+    public function test_notify_watch_parent_book_new()
+    {
+        $notifications = Notification::fake();
+        $editor = $this->users->editor();
+        $admin = $this->users->admin();
+        $entities = $this->entities->createChainBelongingToUser($editor);
+        $watches = new UserEntityWatchOptions($editor, $entities['book']);
+        $watches->updateLevelByValue(WatchLevels::NEW);
+
+        $this->actingAs($admin)->get($entities['chapter']->getUrl('/create-page'));
+        $page = $entities['chapter']->pages()->where('draft', '=', true)->first();
+        $this->post($page->getUrl(), ['name' => 'My new page', 'html' => 'My new page content']);
+
+        $notifications->assertSentTo($editor, function (PageCreationNotification $notification) use ($editor, $admin) {
+            $mail = $notification->toMail($editor);
+            $mailContent = html_entity_decode(strip_tags($mail->render()));
+            return $mail->subject === 'New page: My new page'
+                && str_contains($mailContent, 'View Page')
+                && str_contains($mailContent, 'Page Name: My new page')
+                && str_contains($mailContent, 'Created By: ' . $admin->name);
+        });
+    }
+
+    public function test_notifications_not_sent_if_lacking_view_permission_for_related_item()
+    {
+        $notifications = Notification::fake();
+        $editor = $this->users->editor();
+        $page = $this->entities->page();
+
+        $watches = new UserEntityWatchOptions($editor, $page);
+        $watches->updateLevelByValue(WatchLevels::COMMENTS);
+        $this->permissions->disableEntityInheritedPermissions($page);
+
+        $this->asAdmin()->post("/comment/{$page->id}", [
+            'text' => 'My new comment response',
+        ])->assertOk();
+
+        $notifications->assertNothingSentTo($editor);
+    }
 }