]> BookStack Code Mirror - bookstack/blob - tests/RecycleBinTest.php
LDAP: Added TLS support
[bookstack] / tests / RecycleBinTest.php
1 <?php namespace Tests;
2
3 use BookStack\Entities\Book;
4 use BookStack\Entities\Deletion;
5 use BookStack\Entities\Page;
6 use DB;
7 use Illuminate\Support\Carbon;
8
9 class RecycleBinTest extends TestCase
10 {
11     public function test_recycle_bin_routes_permissions()
12     {
13         $page = Page::query()->first();
14         $editor = $this->getEditor();
15         $this->actingAs($editor)->delete($page->getUrl());
16         $deletion = Deletion::query()->firstOrFail();
17
18         $routes = [
19             'GET:/settings/recycle-bin',
20             'POST:/settings/recycle-bin/empty',
21             "GET:/settings/recycle-bin/{$deletion->id}/destroy",
22             "GET:/settings/recycle-bin/{$deletion->id}/restore",
23             "POST:/settings/recycle-bin/{$deletion->id}/restore",
24             "DELETE:/settings/recycle-bin/{$deletion->id}",
25         ];
26
27         foreach($routes as $route) {
28             [$method, $url] = explode(':', $route);
29             $resp = $this->call($method, $url);
30             $this->assertPermissionError($resp);
31         }
32
33         $this->giveUserPermissions($editor, ['restrictions-manage-all']);
34
35         foreach($routes as $route) {
36             [$method, $url] = explode(':', $route);
37             $resp = $this->call($method, $url);
38             $this->assertPermissionError($resp);
39         }
40
41         $this->giveUserPermissions($editor, ['settings-manage']);
42
43         foreach($routes as $route) {
44             DB::beginTransaction();
45             [$method, $url] = explode(':', $route);
46             $resp = $this->call($method, $url);
47             $this->assertNotPermissionError($resp);
48             DB::rollBack();
49         }
50
51     }
52
53     public function test_recycle_bin_view()
54     {
55         $page = Page::query()->first();
56         $book = Book::query()->whereHas('pages')->whereHas('chapters')->withCount(['pages', 'chapters'])->first();
57         $editor = $this->getEditor();
58         $this->actingAs($editor)->delete($page->getUrl());
59         $this->actingAs($editor)->delete($book->getUrl());
60
61         $viewReq = $this->asAdmin()->get('/settings/recycle-bin');
62         $viewReq->assertElementContains('table.table', $page->name);
63         $viewReq->assertElementContains('table.table', $editor->name);
64         $viewReq->assertElementContains('table.table', $book->name);
65         $viewReq->assertElementContains('table.table', $book->pages_count . ' Pages');
66         $viewReq->assertElementContains('table.table', $book->chapters_count . ' Chapters');
67     }
68
69     public function test_recycle_bin_empty()
70     {
71         $page = Page::query()->first();
72         $book = Book::query()->where('id' , '!=', $page->book_id)->whereHas('pages')->whereHas('chapters')->with(['pages', 'chapters'])->firstOrFail();
73         $editor = $this->getEditor();
74         $this->actingAs($editor)->delete($page->getUrl());
75         $this->actingAs($editor)->delete($book->getUrl());
76
77         $this->assertTrue(Deletion::query()->count() === 2);
78         $emptyReq = $this->asAdmin()->post('/settings/recycle-bin/empty');
79         $emptyReq->assertRedirect('/settings/recycle-bin');
80
81         $this->assertTrue(Deletion::query()->count() === 0);
82         $this->assertDatabaseMissing('books', ['id' => $book->id]);
83         $this->assertDatabaseMissing('pages', ['id' => $page->id]);
84         $this->assertDatabaseMissing('pages', ['id' => $book->pages->first()->id]);
85         $this->assertDatabaseMissing('chapters', ['id' => $book->chapters->first()->id]);
86
87         $itemCount = 2 + $book->pages->count() + $book->chapters->count();
88         $redirectReq = $this->get('/settings/recycle-bin');
89         $redirectReq->assertNotificationContains('Deleted '.$itemCount.' total items from the recycle bin');
90     }
91
92     public function test_entity_restore()
93     {
94         $book = Book::query()->whereHas('pages')->whereHas('chapters')->with(['pages', 'chapters'])->firstOrFail();
95         $this->asEditor()->delete($book->getUrl());
96         $deletion = Deletion::query()->firstOrFail();
97
98         $this->assertEquals($book->pages->count(), DB::table('pages')->where('book_id', '=', $book->id)->whereNotNull('deleted_at')->count());
99         $this->assertEquals($book->chapters->count(), DB::table('chapters')->where('book_id', '=', $book->id)->whereNotNull('deleted_at')->count());
100
101         $restoreReq = $this->asAdmin()->post("/settings/recycle-bin/{$deletion->id}/restore");
102         $restoreReq->assertRedirect('/settings/recycle-bin');
103         $this->assertTrue(Deletion::query()->count() === 0);
104
105         $this->assertEquals($book->pages->count(), DB::table('pages')->where('book_id', '=', $book->id)->whereNull('deleted_at')->count());
106         $this->assertEquals($book->chapters->count(), DB::table('chapters')->where('book_id', '=', $book->id)->whereNull('deleted_at')->count());
107
108         $itemCount = 1 + $book->pages->count() + $book->chapters->count();
109         $redirectReq = $this->get('/settings/recycle-bin');
110         $redirectReq->assertNotificationContains('Restored '.$itemCount.' total items from the recycle bin');
111     }
112
113     public function test_permanent_delete()
114     {
115         $book = Book::query()->whereHas('pages')->whereHas('chapters')->with(['pages', 'chapters'])->firstOrFail();
116         $this->asEditor()->delete($book->getUrl());
117         $deletion = Deletion::query()->firstOrFail();
118
119         $deleteReq = $this->asAdmin()->delete("/settings/recycle-bin/{$deletion->id}");
120         $deleteReq->assertRedirect('/settings/recycle-bin');
121         $this->assertTrue(Deletion::query()->count() === 0);
122
123         $this->assertDatabaseMissing('books', ['id' => $book->id]);
124         $this->assertDatabaseMissing('pages', ['id' => $book->pages->first()->id]);
125         $this->assertDatabaseMissing('chapters', ['id' => $book->chapters->first()->id]);
126
127         $itemCount = 1 + $book->pages->count() + $book->chapters->count();
128         $redirectReq = $this->get('/settings/recycle-bin');
129         $redirectReq->assertNotificationContains('Deleted '.$itemCount.' total items from the recycle bin');
130     }
131
132     public function test_permanent_entity_delete_updates_existing_activity_with_entity_name()
133     {
134         $page = Page::query()->firstOrFail();
135         $this->asEditor()->delete($page->getUrl());
136         $deletion = $page->deletions()->firstOrFail();
137
138         $this->assertDatabaseHas('activities', [
139             'key' => 'page_delete',
140             'entity_id' => $page->id,
141             'entity_type' => $page->getMorphClass(),
142         ]);
143
144         $this->asAdmin()->delete("/settings/recycle-bin/{$deletion->id}");
145
146         $this->assertDatabaseMissing('activities', [
147             'key' => 'page_delete',
148             'entity_id' => $page->id,
149             'entity_type' => $page->getMorphClass(),
150         ]);
151
152         $this->assertDatabaseHas('activities', [
153             'key' => 'page_delete',
154             'entity_id' => 0,
155             'entity_type' => '',
156             'extra' => $page->name,
157         ]);
158     }
159
160     public function test_auto_clear_functionality_works()
161     {
162         config()->set('app.recycle_bin_lifetime', 5);
163         $page = Page::query()->firstOrFail();
164         $otherPage = Page::query()->where('id', '!=', $page->id)->firstOrFail();
165
166         $this->asEditor()->delete($page->getUrl());
167         $this->assertDatabaseHas('pages', ['id' => $page->id]);
168         $this->assertEquals(1, Deletion::query()->count());
169
170         Carbon::setTestNow(Carbon::now()->addDays(6));
171         $this->asEditor()->delete($otherPage->getUrl());
172         $this->assertEquals(1, Deletion::query()->count());
173
174         $this->assertDatabaseMissing('pages', ['id' => $page->id]);
175     }
176
177     public function test_auto_clear_functionality_with_negative_time_keeps_forever()
178     {
179         config()->set('app.recycle_bin_lifetime', -1);
180         $page = Page::query()->firstOrFail();
181         $otherPage = Page::query()->where('id', '!=', $page->id)->firstOrFail();
182
183         $this->asEditor()->delete($page->getUrl());
184         $this->assertEquals(1, Deletion::query()->count());
185
186         Carbon::setTestNow(Carbon::now()->addDays(6000));
187         $this->asEditor()->delete($otherPage->getUrl());
188         $this->assertEquals(2, Deletion::query()->count());
189
190         $this->assertDatabaseHas('pages', ['id' => $page->id]);
191     }
192
193     public function test_auto_clear_functionality_with_zero_time_deletes_instantly()
194     {
195         config()->set('app.recycle_bin_lifetime', 0);
196         $page = Page::query()->firstOrFail();
197
198         $this->asEditor()->delete($page->getUrl());
199         $this->assertDatabaseMissing('pages', ['id' => $page->id]);
200         $this->assertEquals(0, Deletion::query()->count());
201     }
202
203     public function test_restore_flow_when_restoring_nested_delete_first()
204     {
205         $book = Book::query()->whereHas('pages')->whereHas('chapters')->with(['pages', 'chapters'])->firstOrFail();
206         $chapter = $book->chapters->first();
207         $this->asEditor()->delete($chapter->getUrl());
208         $this->asEditor()->delete($book->getUrl());
209
210         $bookDeletion = $book->deletions()->first();
211         $chapterDeletion = $chapter->deletions()->first();
212
213         $chapterRestoreView = $this->asAdmin()->get("/settings/recycle-bin/{$chapterDeletion->id}/restore");
214         $chapterRestoreView->assertStatus(200);
215         $chapterRestoreView->assertSeeText($chapter->name);
216
217         $chapterRestore = $this->post("/settings/recycle-bin/{$chapterDeletion->id}/restore");
218         $chapterRestore->assertRedirect("/settings/recycle-bin");
219         $this->assertDatabaseMissing("deletions", ["id" => $chapterDeletion->id]);
220
221         $chapter->refresh();
222         $this->assertNotNull($chapter->deleted_at);
223
224         $bookRestoreView = $this->asAdmin()->get("/settings/recycle-bin/{$bookDeletion->id}/restore");
225         $bookRestoreView->assertStatus(200);
226         $bookRestoreView->assertSeeText($chapter->name);
227
228         $this->post("/settings/recycle-bin/{$bookDeletion->id}/restore");
229         $chapter->refresh();
230         $this->assertNull($chapter->deleted_at);
231     }
232 }
Morty Proxy This is a proxified and sanitized view of the page, visit original site.