]> BookStack Code Mirror - bookstack/blob - tests/CommandsTest.php
Organised activity types and moved most to repos
[bookstack] / tests / CommandsTest.php
1 <?php namespace Tests;
2
3 use BookStack\Actions\ActivityType;
4 use BookStack\Actions\Comment;
5 use BookStack\Actions\CommentRepo;
6 use BookStack\Auth\Permissions\JointPermission;
7 use BookStack\Entities\Bookshelf;
8 use BookStack\Entities\Page;
9 use BookStack\Auth\User;
10 use BookStack\Entities\Repos\PageRepo;
11 use Symfony\Component\Console\Exception\RuntimeException;
12
13 class CommandsTest extends TestCase
14 {
15
16     public function test_clear_views_command()
17     {
18         $this->asEditor();
19         $page = Page::first();
20
21         $this->get($page->getUrl());
22
23         $this->assertDatabaseHas('views', [
24             'user_id' => $this->getEditor()->id,
25             'viewable_id' => $page->id,
26             'views' => 1
27         ]);
28
29         $exitCode = \Artisan::call('bookstack:clear-views');
30         $this->assertTrue($exitCode === 0, 'Command executed successfully');
31
32         $this->assertDatabaseMissing('views', [
33             'user_id' => $this->getEditor()->id
34         ]);
35     }
36
37     public function test_clear_activity_command()
38     {
39         $this->asEditor();
40         $page = Page::first();
41         \Activity::add($page, ActivityType::PAGE_UPDATE, $page->book->id);
42
43         $this->assertDatabaseHas('activities', [
44             'key' => 'page_update',
45             'entity_id' => $page->id,
46             'user_id' => $this->getEditor()->id
47         ]);
48
49         $exitCode = \Artisan::call('bookstack:clear-activity');
50         $this->assertTrue($exitCode === 0, 'Command executed successfully');
51
52
53         $this->assertDatabaseMissing('activities', [
54             'key' => 'page_update'
55         ]);
56     }
57
58     public function test_clear_revisions_command()
59     {
60         $this->asEditor();
61         $pageRepo = app(PageRepo::class);
62         $page = Page::first();
63         $pageRepo->update($page, ['name' => 'updated page', 'html' => '<p>new content</p>', 'summary' => 'page revision testing']);
64         $pageRepo->updatePageDraft($page, ['name' => 'updated page', 'html' => '<p>new content in draft</p>', 'summary' => 'page revision testing']);
65
66         $this->assertDatabaseHas('page_revisions', [
67             'page_id' => $page->id,
68             'type' => 'version'
69         ]);
70         $this->assertDatabaseHas('page_revisions', [
71             'page_id' => $page->id,
72             'type' => 'update_draft'
73         ]);
74
75         $exitCode = \Artisan::call('bookstack:clear-revisions');
76         $this->assertTrue($exitCode === 0, 'Command executed successfully');
77
78         $this->assertDatabaseMissing('page_revisions', [
79             'page_id' => $page->id,
80             'type' => 'version'
81         ]);
82         $this->assertDatabaseHas('page_revisions', [
83             'page_id' => $page->id,
84             'type' => 'update_draft'
85         ]);
86
87         $exitCode = \Artisan::call('bookstack:clear-revisions', ['--all' => true]);
88         $this->assertTrue($exitCode === 0, 'Command executed successfully');
89
90         $this->assertDatabaseMissing('page_revisions', [
91             'page_id' => $page->id,
92             'type' => 'update_draft'
93         ]);
94     }
95
96     public function test_regen_permissions_command()
97     {
98         JointPermission::query()->truncate();
99         $page = Page::first();
100
101         $this->assertDatabaseMissing('joint_permissions', ['entity_id' => $page->id]);
102
103         $exitCode = \Artisan::call('bookstack:regenerate-permissions');
104         $this->assertTrue($exitCode === 0, 'Command executed successfully');
105
106         $this->assertDatabaseHas('joint_permissions', ['entity_id' => $page->id]);
107     }
108
109     public function test_add_admin_command()
110     {
111         $exitCode = \Artisan::call('bookstack:create-admin', [
112             '--email' => '[email protected]',
113             '--name' => 'Admin Test',
114             '--password' => 'testing-4',
115         ]);
116         $this->assertTrue($exitCode === 0, 'Command executed successfully');
117
118         $this->assertDatabaseHas('users', [
119             'email' => '[email protected]',
120             'name' => 'Admin Test'
121         ]);
122
123         $this->assertTrue(User::where('email', '=', '[email protected]')->first()->hasSystemRole('admin'), 'User has admin role as expected');
124         $this->assertTrue(\Auth::attempt(['email' => '[email protected]', 'password' => 'testing-4']), 'Password stored as expected');
125     }
126
127     public function test_copy_shelf_permissions_command_shows_error_when_no_required_option_given()
128     {
129         $this->artisan('bookstack:copy-shelf-permissions')
130             ->expectsOutput('Either a --slug or --all option must be provided.')
131             ->assertExitCode(0);
132     }
133
134     public function test_copy_shelf_permissions_command_using_slug()
135     {
136         $shelf = Bookshelf::first();
137         $child = $shelf->books()->first();
138         $editorRole = $this->getEditor()->roles()->first();
139         $this->assertFalse(boolval($child->restricted), "Child book should not be restricted by default");
140         $this->assertTrue($child->permissions()->count() === 0, "Child book should have no permissions by default");
141
142         $this->setEntityRestrictions($shelf, ['view', 'update'], [$editorRole]);
143         $this->artisan('bookstack:copy-shelf-permissions', [
144             '--slug' => $shelf->slug,
145         ]);
146         $child = $shelf->books()->first();
147
148         $this->assertTrue(boolval($child->restricted), "Child book should now be restricted");
149         $this->assertTrue($child->permissions()->count() === 2, "Child book should have copied permissions");
150         $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'view', 'role_id' => $editorRole->id]);
151         $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'update', 'role_id' => $editorRole->id]);
152     }
153
154     public function test_copy_shelf_permissions_command_using_all()
155     {
156         $shelf = Bookshelf::query()->first();
157         Bookshelf::query()->where('id', '!=', $shelf->id)->delete();
158         $child = $shelf->books()->first();
159         $editorRole = $this->getEditor()->roles()->first();
160         $this->assertFalse(boolval($child->restricted), "Child book should not be restricted by default");
161         $this->assertTrue($child->permissions()->count() === 0, "Child book should have no permissions by default");
162
163         $this->setEntityRestrictions($shelf, ['view', 'update'], [$editorRole]);
164         $this->artisan('bookstack:copy-shelf-permissions --all')
165             ->expectsQuestion('Permission settings for all shelves will be cascaded. Books assigned to multiple shelves will receive only the permissions of it\'s last processed shelf. Are you sure you want to proceed?', 'y');
166         $child = $shelf->books()->first();
167
168         $this->assertTrue(boolval($child->restricted), "Child book should now be restricted");
169         $this->assertTrue($child->permissions()->count() === 2, "Child book should have copied permissions");
170         $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'view', 'role_id' => $editorRole->id]);
171         $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'update', 'role_id' => $editorRole->id]);
172     }
173
174     public function test_update_url_command_updates_page_content()
175     {
176         $page = Page::query()->first();
177         $page->html = '<a href="https://example.com/donkeys"></a>';
178         $page->save();
179
180         $this->artisan('bookstack:update-url https://example.com https://cats.example.com')
181             ->expectsQuestion("This will search for \"https://example.com\" in your database and replace it with  \"https://cats.example.com\".\nAre you sure you want to proceed?", 'y')
182             ->expectsQuestion("This operation could cause issues if used incorrectly. Have you made a backup of your existing database?", 'y');
183
184         $this->assertDatabaseHas('pages', [
185             'id' => $page->id,
186             'html' => '<a href="https://cats.example.com/donkeys"></a>'
187         ]);
188     }
189
190     public function test_update_url_command_requires_valid_url()
191     {
192         $badUrlMessage = "The given urls are expected to be full urls starting with http:// or https://";
193         $this->artisan('bookstack:update-url //example.com https://cats.example.com')->expectsOutput($badUrlMessage);
194         $this->artisan('bookstack:update-url https://example.com htts://cats.example.com')->expectsOutput($badUrlMessage);
195         $this->artisan('bookstack:update-url example.com https://cats.example.com')->expectsOutput($badUrlMessage);
196
197         $this->expectException(RuntimeException::class);
198         $this->artisan('bookstack:update-url https://cats.example.com');
199     }
200
201     public function test_regenerate_comment_content_command()
202     {
203         Comment::query()->forceCreate([
204             'html' => 'some_old_content',
205             'text' => 'some_fresh_content',
206         ]);
207
208         $this->assertDatabaseHas('comments', [
209             'html' => 'some_old_content',
210         ]);
211
212         $exitCode = \Artisan::call('bookstack:regenerate-comment-content');
213         $this->assertTrue($exitCode === 0, 'Command executed successfully');
214
215         $this->assertDatabaseMissing('comments', [
216             'html' => 'some_old_content',
217         ]);
218         $this->assertDatabaseHas('comments', [
219             'html' => "<p>some_fresh_content</p>\n",
220         ]);
221     }
222 }