3 namespace Tests\Entity;
5 use BookStack\Activity\ActivityType;
6 use BookStack\Activity\Models\Comment;
7 use BookStack\Entities\Models\Page;
10 class CommentStoreTest extends TestCase
12 public function test_add_comment()
15 $page = $this->entities->page();
17 $comment = Comment::factory()->make(['parent_id' => 2]);
18 $resp = $this->postJson("/comment/$page->id", $comment->getAttributes());
20 $resp->assertStatus(200);
21 $resp->assertSee($comment->html, false);
23 $pageResp = $this->get($page->getUrl());
24 $pageResp->assertSee($comment->html, false);
26 $this->assertDatabaseHas('comments', [
28 'entity_id' => $page->id,
29 'entity_type' => Page::newModelInstance()->getMorphClass(),
34 $this->assertActivityExists(ActivityType::COMMENT_CREATE);
36 public function test_add_comment_stores_content_reference_only_if_format_valid()
39 'bkmrk-my-title:4589284922:4-3' => true,
40 'bkmrk-my-title:4589284922:' => true,
41 'bkmrk-my-title:4589284922:abc' => false,
42 'my-title:4589284922:' => false,
43 'bkmrk-my-title-4589284922:' => false,
46 $page = $this->entities->page();
48 foreach ($validityByRefs as $ref => $valid) {
49 $this->asAdmin()->postJson("/comment/$page->id", [
50 'html' => '<p>My comment</p>',
52 'content_ref' => $ref,
56 $this->assertDatabaseHas('comments', ['entity_id' => $page->id, 'content_ref' => $ref]);
58 $this->assertDatabaseMissing('comments', ['entity_id' => $page->id, 'content_ref' => $ref]);
63 public function test_comment_edit()
66 $page = $this->entities->page();
68 $comment = Comment::factory()->make();
69 $this->postJson("/comment/$page->id", $comment->getAttributes());
71 $comment = $page->comments()->first();
72 $newHtml = '<p>updated text content</p>';
73 $resp = $this->putJson("/comment/$comment->id", [
77 $resp->assertStatus(200);
78 $resp->assertSee($newHtml, false);
79 $resp->assertDontSee($comment->html, false);
81 $this->assertDatabaseHas('comments', [
83 'entity_id' => $page->id,
86 $this->assertActivityExists(ActivityType::COMMENT_UPDATE);
89 public function test_comment_delete()
92 $page = $this->entities->page();
94 $comment = Comment::factory()->make();
95 $this->postJson("/comment/$page->id", $comment->getAttributes());
97 $comment = $page->comments()->first();
99 $resp = $this->delete("/comment/$comment->id");
100 $resp->assertStatus(200);
102 $this->assertDatabaseMissing('comments', [
103 'id' => $comment->id,
106 $this->assertActivityExists(ActivityType::COMMENT_DELETE);
109 public function test_comment_archive_and_unarchive()
112 $page = $this->entities->page();
114 $comment = Comment::factory()->make();
115 $page->comments()->save($comment);
118 $this->put("/comment/$comment->id/archive");
120 $this->assertDatabaseHas('comments', [
121 'id' => $comment->id,
125 $this->assertActivityExists(ActivityType::COMMENT_UPDATE);
127 $this->put("/comment/$comment->id/unarchive");
129 $this->assertDatabaseHas('comments', [
130 'id' => $comment->id,
134 $this->assertActivityExists(ActivityType::COMMENT_UPDATE);
137 public function test_archive_endpoints_require_delete_or_edit_permissions()
139 $viewer = $this->users->viewer();
140 $page = $this->entities->page();
142 $comment = Comment::factory()->make();
143 $page->comments()->save($comment);
146 $endpoints = ["/comment/$comment->id/archive", "/comment/$comment->id/unarchive"];
148 foreach ($endpoints as $endpoint) {
149 $resp = $this->actingAs($viewer)->put($endpoint);
150 $this->assertPermissionError($resp);
153 $this->permissions->grantUserRolePermissions($viewer, ['comment-delete-all']);
155 foreach ($endpoints as $endpoint) {
156 $resp = $this->actingAs($viewer)->put($endpoint);
160 $this->permissions->removeUserRolePermissions($viewer, ['comment-delete-all']);
161 $this->permissions->grantUserRolePermissions($viewer, ['comment-update-all']);
163 foreach ($endpoints as $endpoint) {
164 $resp = $this->actingAs($viewer)->put($endpoint);
169 public function test_non_top_level_comments_cant_be_archived_or_unarchived()
172 $page = $this->entities->page();
174 $comment = Comment::factory()->make();
175 $page->comments()->save($comment);
176 $subComment = Comment::factory()->make(['parent_id' => $comment->id]);
177 $page->comments()->save($subComment);
178 $subComment->refresh();
180 $resp = $this->putJson("/comment/$subComment->id/archive");
181 $resp->assertStatus(400);
183 $this->assertDatabaseHas('comments', [
184 'id' => $subComment->id,
188 $resp = $this->putJson("/comment/$subComment->id/unarchive");
189 $resp->assertStatus(400);
192 public function test_scripts_cannot_be_injected_via_comment_html()
194 $page = $this->entities->page();
196 $script = '<script>const a = "script";</script><p onclick="1">My lovely comment</p>';
197 $this->asAdmin()->postJson("/comment/$page->id", [
201 $pageView = $this->get($page->getUrl());
202 $pageView->assertDontSee($script, false);
203 $pageView->assertSee('<p>My lovely comment</p>', false);
205 $comment = $page->comments()->first();
206 $this->putJson("/comment/$comment->id", [
207 'html' => $script . '<p>updated</p>',
210 $pageView = $this->get($page->getUrl());
211 $pageView->assertDontSee($script, false);
212 $pageView->assertSee('<p>My lovely comment</p><p>updated</p>');
215 public function test_scripts_are_removed_even_if_already_in_db()
217 $page = $this->entities->page();
218 Comment::factory()->create([
219 'html' => '<script>superbadscript</script><p onclick="superbadonclick">scriptincommentest</p>',
220 'entity_type' => 'page', 'entity_id' => $page
223 $resp = $this->asAdmin()->get($page->getUrl());
224 $resp->assertSee('scriptincommentest', false);
225 $resp->assertDontSee('superbadscript', false);
226 $resp->assertDontSee('superbadonclick', false);
229 public function test_comment_html_is_limited()
231 $page = $this->entities->page();
232 $input = '<h1>Test</h1><p id="abc" href="beans">Content<a href="#cat" data-a="b">a</a><section>Hello</section></p>';
233 $expected = '<p>Content<a href="#cat">a</a></p>';
235 $resp = $this->asAdmin()->post("/comment/{$page->id}", ['html' => $input]);
237 $this->assertDatabaseHas('comments', [
238 'entity_type' => 'page',
239 'entity_id' => $page->id,
243 $comment = $page->comments()->first();
244 $resp = $this->put("/comment/{$comment->id}", ['html' => $input]);
246 $this->assertDatabaseHas('comments', [
247 'id' => $comment->id,