]> BookStack Code Mirror - bookstack/blob - tests/Entity/SortTest.php
Skip intermediate login page with single provider
[bookstack] / tests / Entity / SortTest.php
1 <?php
2
3 namespace Tests\Entity;
4
5 use BookStack\Entities\Models\Book;
6 use BookStack\Entities\Models\Chapter;
7 use BookStack\Entities\Models\Page;
8 use BookStack\Entities\Repos\PageRepo;
9 use Tests\TestCase;
10
11 class SortTest extends TestCase
12 {
13     protected $book;
14
15     protected function setUp(): void
16     {
17         parent::setUp();
18         $this->book = Book::first();
19     }
20
21     public function test_drafts_do_not_show_up()
22     {
23         $this->asAdmin();
24         $pageRepo = app(PageRepo::class);
25         $draft = $pageRepo->getNewDraftPage($this->book);
26
27         $resp = $this->get($this->book->getUrl());
28         $resp->assertSee($draft->name);
29
30         $resp = $this->get($this->book->getUrl() . '/sort');
31         $resp->assertDontSee($draft->name);
32     }
33
34     public function test_page_move_into_book()
35     {
36         $page = Page::query()->first();
37         $currentBook = $page->book;
38         $newBook = Book::query()->where('id', '!=', $currentBook->id)->first();
39
40         $resp = $this->asEditor()->get($page->getUrl('/move'));
41         $resp->assertSee('Move Page');
42
43         $movePageResp = $this->put($page->getUrl('/move'), [
44             'entity_selection' => 'book:' . $newBook->id,
45         ]);
46         $page = Page::query()->find($page->id);
47
48         $movePageResp->assertRedirect($page->getUrl());
49         $this->assertTrue($page->book->id == $newBook->id, 'Page book is now the new book');
50
51         $newBookResp = $this->get($newBook->getUrl());
52         $newBookResp->assertSee('moved page');
53         $newBookResp->assertSee($page->name);
54     }
55
56     public function test_page_move_into_chapter()
57     {
58         $page = Page::query()->first();
59         $currentBook = $page->book;
60         $newBook = Book::query()->where('id', '!=', $currentBook->id)->first();
61         $newChapter = $newBook->chapters()->first();
62
63         $movePageResp = $this->actingAs($this->getEditor())->put($page->getUrl('/move'), [
64             'entity_selection' => 'chapter:' . $newChapter->id,
65         ]);
66         $page = Page::query()->find($page->id);
67
68         $movePageResp->assertRedirect($page->getUrl());
69         $this->assertTrue($page->book->id == $newBook->id, 'Page parent is now the new chapter');
70
71         $newChapterResp = $this->get($newChapter->getUrl());
72         $newChapterResp->assertSee($page->name);
73     }
74
75     public function test_page_move_from_chapter_to_book()
76     {
77         $oldChapter = Chapter::query()->first();
78         $page = $oldChapter->pages()->first();
79         $newBook = Book::query()->where('id', '!=', $oldChapter->book_id)->first();
80
81         $movePageResp = $this->actingAs($this->getEditor())->put($page->getUrl('/move'), [
82             'entity_selection' => 'book:' . $newBook->id,
83         ]);
84         $page->refresh();
85
86         $movePageResp->assertRedirect($page->getUrl());
87         $this->assertTrue($page->book->id == $newBook->id, 'Page parent is now the new book');
88         $this->assertTrue($page->chapter === null, 'Page has no parent chapter');
89
90         $newBookResp = $this->get($newBook->getUrl());
91         $newBookResp->assertSee($page->name);
92     }
93
94     public function test_page_move_requires_create_permissions_on_parent()
95     {
96         $page = Page::query()->first();
97         $currentBook = $page->book;
98         $newBook = Book::query()->where('id', '!=', $currentBook->id)->first();
99         $editor = $this->getEditor();
100
101         $this->setEntityRestrictions($newBook, ['view', 'update', 'delete'], $editor->roles->all());
102
103         $movePageResp = $this->actingAs($editor)->put($page->getUrl('/move'), [
104             'entity_selection' => 'book:' . $newBook->id,
105         ]);
106         $this->assertPermissionError($movePageResp);
107
108         $this->setEntityRestrictions($newBook, ['view', 'update', 'delete', 'create'], $editor->roles->all());
109         $movePageResp = $this->put($page->getUrl('/move'), [
110             'entity_selection' => 'book:' . $newBook->id,
111         ]);
112
113         $page = Page::query()->find($page->id);
114         $movePageResp->assertRedirect($page->getUrl());
115
116         $this->assertTrue($page->book->id == $newBook->id, 'Page book is now the new book');
117     }
118
119     public function test_page_move_requires_delete_permissions()
120     {
121         $page = Page::query()->first();
122         $currentBook = $page->book;
123         $newBook = Book::query()->where('id', '!=', $currentBook->id)->first();
124         $editor = $this->getEditor();
125
126         $this->setEntityRestrictions($newBook, ['view', 'update', 'create', 'delete'], $editor->roles->all());
127         $this->setEntityRestrictions($page, ['view', 'update', 'create'], $editor->roles->all());
128
129         $movePageResp = $this->actingAs($editor)->put($page->getUrl('/move'), [
130             'entity_selection' => 'book:' . $newBook->id,
131         ]);
132         $this->assertPermissionError($movePageResp);
133         $pageView = $this->get($page->getUrl());
134         $pageView->assertDontSee($page->getUrl('/move'));
135
136         $this->setEntityRestrictions($page, ['view', 'update', 'create', 'delete'], $editor->roles->all());
137         $movePageResp = $this->put($page->getUrl('/move'), [
138             'entity_selection' => 'book:' . $newBook->id,
139         ]);
140
141         $page = Page::query()->find($page->id);
142         $movePageResp->assertRedirect($page->getUrl());
143         $this->assertTrue($page->book->id == $newBook->id, 'Page book is now the new book');
144     }
145
146     public function test_chapter_move()
147     {
148         $chapter = Chapter::query()->first();
149         $currentBook = $chapter->book;
150         $pageToCheck = $chapter->pages->first();
151         $newBook = Book::query()->where('id', '!=', $currentBook->id)->first();
152
153         $chapterMoveResp = $this->asEditor()->get($chapter->getUrl('/move'));
154         $chapterMoveResp->assertSee('Move Chapter');
155
156         $moveChapterResp = $this->put($chapter->getUrl('/move'), [
157             'entity_selection' => 'book:' . $newBook->id,
158         ]);
159
160         $chapter = Chapter::query()->find($chapter->id);
161         $moveChapterResp->assertRedirect($chapter->getUrl());
162         $this->assertTrue($chapter->book->id === $newBook->id, 'Chapter Book is now the new book');
163
164         $newBookResp = $this->get($newBook->getUrl());
165         $newBookResp->assertSee('moved chapter');
166         $newBookResp->assertSee($chapter->name);
167
168         $pageToCheck = Page::query()->find($pageToCheck->id);
169         $this->assertTrue($pageToCheck->book_id === $newBook->id, 'Chapter child page\'s book id has changed to the new book');
170         $pageCheckResp = $this->get($pageToCheck->getUrl());
171         $pageCheckResp->assertSee($newBook->name);
172     }
173
174     public function test_chapter_move_requires_delete_permissions()
175     {
176         $chapter = Chapter::query()->first();
177         $currentBook = $chapter->book;
178         $newBook = Book::query()->where('id', '!=', $currentBook->id)->first();
179         $editor = $this->getEditor();
180
181         $this->setEntityRestrictions($newBook, ['view', 'update', 'create', 'delete'], $editor->roles->all());
182         $this->setEntityRestrictions($chapter, ['view', 'update', 'create'], $editor->roles->all());
183
184         $moveChapterResp = $this->actingAs($editor)->put($chapter->getUrl('/move'), [
185             'entity_selection' => 'book:' . $newBook->id,
186         ]);
187         $this->assertPermissionError($moveChapterResp);
188         $pageView = $this->get($chapter->getUrl());
189         $pageView->assertDontSee($chapter->getUrl('/move'));
190
191         $this->setEntityRestrictions($chapter, ['view', 'update', 'create', 'delete'], $editor->roles->all());
192         $moveChapterResp = $this->put($chapter->getUrl('/move'), [
193             'entity_selection' => 'book:' . $newBook->id,
194         ]);
195
196         $chapter = Chapter::query()->find($chapter->id);
197         $moveChapterResp->assertRedirect($chapter->getUrl());
198         $this->assertTrue($chapter->book->id == $newBook->id, 'Page book is now the new book');
199     }
200
201     public function test_chapter_move_requires_create_permissions_in_new_book()
202     {
203         $chapter = Chapter::query()->first();
204         $currentBook = $chapter->book;
205         $newBook = Book::query()->where('id', '!=', $currentBook->id)->first();
206         $editor = $this->getEditor();
207
208         $this->setEntityRestrictions($newBook, ['view', 'update', 'delete'], [$editor->roles->first()]);
209         $this->setEntityRestrictions($chapter, ['view', 'update', 'create', 'delete'], [$editor->roles->first()]);
210
211         $moveChapterResp = $this->actingAs($editor)->put($chapter->getUrl('/move'), [
212             'entity_selection' => 'book:' . $newBook->id,
213         ]);
214         $this->assertPermissionError($moveChapterResp);
215
216         $this->setEntityRestrictions($newBook, ['view', 'update', 'create', 'delete'], [$editor->roles->first()]);
217         $moveChapterResp = $this->put($chapter->getUrl('/move'), [
218             'entity_selection' => 'book:' . $newBook->id,
219         ]);
220
221         $chapter = Chapter::query()->find($chapter->id);
222         $moveChapterResp->assertRedirect($chapter->getUrl());
223         $this->assertTrue($chapter->book->id == $newBook->id, 'Page book is now the new book');
224     }
225
226     public function test_chapter_move_changes_book_for_deleted_pages_within()
227     {
228         /** @var Chapter $chapter */
229         $chapter = Chapter::query()->whereHas('pages')->first();
230         $currentBook = $chapter->book;
231         $pageToCheck = $chapter->pages->first();
232         $newBook = Book::query()->where('id', '!=', $currentBook->id)->first();
233
234         $pageToCheck->delete();
235
236         $this->asEditor()->put($chapter->getUrl('/move'), [
237             'entity_selection' => 'book:' . $newBook->id,
238         ]);
239
240         $pageToCheck->refresh();
241         $this->assertEquals($newBook->id, $pageToCheck->book_id);
242     }
243
244     public function test_book_sort_page_shows()
245     {
246         /** @var Book $bookToSort */
247         $bookToSort = Book::query()->first();
248
249         $resp = $this->asAdmin()->get($bookToSort->getUrl());
250         $resp->assertElementExists('a[href="' . $bookToSort->getUrl('/sort') . '"]');
251
252         $resp = $this->get($bookToSort->getUrl('/sort'));
253         $resp->assertStatus(200);
254         $resp->assertSee($bookToSort->name);
255     }
256
257     public function test_book_sort()
258     {
259         $oldBook = Book::query()->first();
260         $chapterToMove = $this->newChapter(['name' => 'chapter to move'], $oldBook);
261         $newBook = $this->newBook(['name' => 'New sort book']);
262         $pagesToMove = Page::query()->take(5)->get();
263
264         // Create request data
265         $reqData = [
266             [
267                 'id'            => $chapterToMove->id,
268                 'sort'          => 0,
269                 'parentChapter' => false,
270                 'type'          => 'chapter',
271                 'book'          => $newBook->id,
272             ],
273         ];
274         foreach ($pagesToMove as $index => $page) {
275             $reqData[] = [
276                 'id'            => $page->id,
277                 'sort'          => $index,
278                 'parentChapter' => $index === count($pagesToMove) - 1 ? $chapterToMove->id : false,
279                 'type'          => 'page',
280                 'book'          => $newBook->id,
281             ];
282         }
283
284         $sortResp = $this->asEditor()->put($newBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)]);
285         $sortResp->assertRedirect($newBook->getUrl());
286         $sortResp->assertStatus(302);
287         $this->assertDatabaseHas('chapters', [
288             'id'       => $chapterToMove->id,
289             'book_id'  => $newBook->id,
290             'priority' => 0,
291         ]);
292         $this->assertTrue($newBook->chapters()->count() === 1);
293         $this->assertTrue($newBook->chapters()->first()->pages()->count() === 1);
294
295         $checkPage = $pagesToMove[1];
296         $checkResp = $this->get($checkPage->refresh()->getUrl());
297         $checkResp->assertSee($newBook->name);
298     }
299
300     public function test_book_sort_makes_no_changes_if_new_chapter_does_not_align_with_new_book()
301     {
302         /** @var Page $page */
303         $page = Page::query()->where('chapter_id', '!=', 0)->first();
304         $otherChapter = Chapter::query()->where('book_id', '!=', $page->book_id)->first();
305
306         $sortData = [
307             'id'            => $page->id,
308             'sort'          => 0,
309             'parentChapter' => $otherChapter->id,
310             'type'          => 'page',
311             'book'          => $page->book_id,
312         ];
313         $this->asEditor()->put($page->book->getUrl('/sort'), ['sort-tree' => json_encode([$sortData])])->assertRedirect();
314
315         $this->assertDatabaseHas('pages', [
316             'id' => $page->id, 'chapter_id' => $page->chapter_id, 'book_id' => $page->book_id,
317         ]);
318     }
319
320     public function test_book_sort_makes_no_changes_if_no_view_permissions_on_new_chapter()
321     {
322         /** @var Page $page */
323         $page = Page::query()->where('chapter_id', '!=', 0)->first();
324         /** @var Chapter $otherChapter */
325         $otherChapter = Chapter::query()->where('book_id', '!=', $page->book_id)->first();
326         $this->setEntityRestrictions($otherChapter);
327
328         $sortData = [
329             'id'            => $page->id,
330             'sort'          => 0,
331             'parentChapter' => $otherChapter->id,
332             'type'          => 'page',
333             'book'          => $otherChapter->book_id,
334         ];
335         $this->asEditor()->put($page->book->getUrl('/sort'), ['sort-tree' => json_encode([$sortData])])->assertRedirect();
336
337         $this->assertDatabaseHas('pages', [
338             'id' => $page->id, 'chapter_id' => $page->chapter_id, 'book_id' => $page->book_id,
339         ]);
340     }
341
342     public function test_book_sort_makes_no_changes_if_no_view_permissions_on_new_book()
343     {
344         /** @var Page $page */
345         $page = Page::query()->where('chapter_id', '!=', 0)->first();
346         /** @var Chapter $otherChapter */
347         $otherChapter = Chapter::query()->where('book_id', '!=', $page->book_id)->first();
348         $editor = $this->getEditor();
349         $this->setEntityRestrictions($otherChapter->book, ['update', 'delete'], [$editor->roles()->first()]);
350
351         $sortData = [
352             'id'            => $page->id,
353             'sort'          => 0,
354             'parentChapter' => $otherChapter->id,
355             'type'          => 'page',
356             'book'          => $otherChapter->book_id,
357         ];
358         $this->actingAs($editor)->put($page->book->getUrl('/sort'), ['sort-tree' => json_encode([$sortData])])->assertRedirect();
359
360         $this->assertDatabaseHas('pages', [
361             'id' => $page->id, 'chapter_id' => $page->chapter_id, 'book_id' => $page->book_id,
362         ]);
363     }
364
365     public function test_book_sort_makes_no_changes_if_no_update_or_create_permissions_on_new_chapter()
366     {
367         /** @var Page $page */
368         $page = Page::query()->where('chapter_id', '!=', 0)->first();
369         /** @var Chapter $otherChapter */
370         $otherChapter = Chapter::query()->where('book_id', '!=', $page->book_id)->first();
371         $editor = $this->getEditor();
372         $this->setEntityRestrictions($otherChapter, ['view', 'delete'], [$editor->roles()->first()]);
373
374         $sortData = [
375             'id'            => $page->id,
376             'sort'          => 0,
377             'parentChapter' => $otherChapter->id,
378             'type'          => 'page',
379             'book'          => $otherChapter->book_id,
380         ];
381         $this->actingAs($editor)->put($page->book->getUrl('/sort'), ['sort-tree' => json_encode([$sortData])])->assertRedirect();
382
383         $this->assertDatabaseHas('pages', [
384             'id' => $page->id, 'chapter_id' => $page->chapter_id, 'book_id' => $page->book_id,
385         ]);
386     }
387
388     public function test_book_sort_makes_no_changes_if_no_update_permissions_on_moved_item()
389     {
390         /** @var Page $page */
391         $page = Page::query()->where('chapter_id', '!=', 0)->first();
392         /** @var Chapter $otherChapter */
393         $otherChapter = Chapter::query()->where('book_id', '!=', $page->book_id)->first();
394         $editor = $this->getEditor();
395         $this->setEntityRestrictions($page, ['view', 'delete'], [$editor->roles()->first()]);
396
397         $sortData = [
398             'id'            => $page->id,
399             'sort'          => 0,
400             'parentChapter' => $otherChapter->id,
401             'type'          => 'page',
402             'book'          => $otherChapter->book_id,
403         ];
404         $this->actingAs($editor)->put($page->book->getUrl('/sort'), ['sort-tree' => json_encode([$sortData])])->assertRedirect();
405
406         $this->assertDatabaseHas('pages', [
407             'id' => $page->id, 'chapter_id' => $page->chapter_id, 'book_id' => $page->book_id,
408         ]);
409     }
410
411     public function test_book_sort_makes_no_changes_if_no_delete_permissions_on_moved_item()
412     {
413         /** @var Page $page */
414         $page = Page::query()->where('chapter_id', '!=', 0)->first();
415         /** @var Chapter $otherChapter */
416         $otherChapter = Chapter::query()->where('book_id', '!=', $page->book_id)->first();
417         $editor = $this->getEditor();
418         $this->setEntityRestrictions($page, ['view', 'update'], [$editor->roles()->first()]);
419
420         $sortData = [
421             'id'            => $page->id,
422             'sort'          => 0,
423             'parentChapter' => $otherChapter->id,
424             'type'          => 'page',
425             'book'          => $otherChapter->book_id,
426         ];
427         $this->actingAs($editor)->put($page->book->getUrl('/sort'), ['sort-tree' => json_encode([$sortData])])->assertRedirect();
428
429         $this->assertDatabaseHas('pages', [
430             'id' => $page->id, 'chapter_id' => $page->chapter_id, 'book_id' => $page->book_id,
431         ]);
432     }
433
434     public function test_book_sort_item_returns_book_content()
435     {
436         $books = Book::all();
437         $bookToSort = $books[0];
438         $firstPage = $bookToSort->pages[0];
439         $firstChapter = $bookToSort->chapters[0];
440
441         $resp = $this->asAdmin()->get($bookToSort->getUrl() . '/sort-item');
442
443         // Ensure book details are returned
444         $resp->assertSee($bookToSort->name);
445         $resp->assertSee($firstPage->name);
446         $resp->assertSee($firstChapter->name);
447     }
448
449     public function test_pages_in_book_show_sorted_by_priority()
450     {
451         /** @var Book $book */
452         $book = Book::query()->whereHas('pages')->first();
453         $book->chapters()->forceDelete();
454         /** @var Page[] $pages */
455         $pages = $book->pages()->where('chapter_id', '=', 0)->take(2)->get();
456         $book->pages()->whereNotIn('id', $pages->pluck('id'))->delete();
457
458         $resp = $this->asEditor()->get($book->getUrl());
459         $resp->assertElementContains('.content-wrap a.page:nth-child(1)', $pages[0]->name);
460         $resp->assertElementContains('.content-wrap a.page:nth-child(2)', $pages[1]->name);
461
462         $pages[0]->forceFill(['priority' => 10])->save();
463         $pages[1]->forceFill(['priority' => 5])->save();
464
465         $resp = $this->asEditor()->get($book->getUrl());
466         $resp->assertElementContains('.content-wrap a.page:nth-child(1)', $pages[1]->name);
467         $resp->assertElementContains('.content-wrap a.page:nth-child(2)', $pages[0]->name);
468     }
469 }
Morty Proxy This is a proxified and sanitized view of the page, visit original site.