3 namespace Tests\Entity;
5 use BookStack\Entities\Models\Book;
6 use BookStack\Entities\Models\Chapter;
7 use BookStack\Entities\Models\Page;
8 use BookStack\Entities\Repos\PageRepo;
11 class SortTest extends TestCase
15 public function setUp(): void
18 $this->book = Book::first();
21 public function test_drafts_do_not_show_up()
24 $pageRepo = app(PageRepo::class);
25 $draft = $pageRepo->getNewDraftPage($this->book);
27 $resp = $this->get($this->book->getUrl());
28 $resp->assertSee($draft->name);
30 $resp = $this->get($this->book->getUrl() . '/sort');
31 $resp->assertDontSee($draft->name);
34 public function test_page_move_into_book()
36 $page = Page::first();
37 $currentBook = $page->book;
38 $newBook = Book::where('id', '!=', $currentBook->id)->first();
40 $resp = $this->asEditor()->get($page->getUrl('/move'));
41 $resp->assertSee('Move Page');
43 $movePageResp = $this->put($page->getUrl('/move'), [
44 'entity_selection' => 'book:' . $newBook->id,
46 $page = Page::find($page->id);
48 $movePageResp->assertRedirect($page->getUrl());
49 $this->assertTrue($page->book->id == $newBook->id, 'Page book is now the new book');
51 $newBookResp = $this->get($newBook->getUrl());
52 $newBookResp->assertSee('moved page');
53 $newBookResp->assertSee($page->name);
56 public function test_page_move_into_chapter()
58 $page = Page::first();
59 $currentBook = $page->book;
60 $newBook = Book::where('id', '!=', $currentBook->id)->first();
61 $newChapter = $newBook->chapters()->first();
63 $movePageResp = $this->actingAs($this->getEditor())->put($page->getUrl('/move'), [
64 'entity_selection' => 'chapter:' . $newChapter->id,
66 $page = Page::find($page->id);
68 $movePageResp->assertRedirect($page->getUrl());
69 $this->assertTrue($page->book->id == $newBook->id, 'Page parent is now the new chapter');
71 $newChapterResp = $this->get($newChapter->getUrl());
72 $newChapterResp->assertSee($page->name);
75 public function test_page_move_from_chapter_to_book()
77 $oldChapter = Chapter::first();
78 $page = $oldChapter->pages()->first();
79 $newBook = Book::where('id', '!=', $oldChapter->book_id)->first();
81 $movePageResp = $this->actingAs($this->getEditor())->put($page->getUrl('/move'), [
82 'entity_selection' => 'book:' . $newBook->id,
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');
90 $newBookResp = $this->get($newBook->getUrl());
91 $newBookResp->assertSee($page->name);
94 public function test_page_move_requires_create_permissions_on_parent()
96 $page = Page::query()->first();
97 $currentBook = $page->book;
98 $newBook = Book::query()->where('id', '!=', $currentBook->id)->first();
99 $editor = $this->getEditor();
101 $this->setEntityRestrictions($newBook, ['view', 'update', 'delete'], $editor->roles->all());
103 $movePageResp = $this->actingAs($editor)->put($page->getUrl('/move'), [
104 'entity_selection' => 'book:' . $newBook->id,
106 $this->assertPermissionError($movePageResp);
108 $this->setEntityRestrictions($newBook, ['view', 'update', 'delete', 'create'], $editor->roles->all());
109 $movePageResp = $this->put($page->getUrl('/move'), [
110 'entity_selection' => 'book:' . $newBook->id,
113 $page = Page::find($page->id);
114 $movePageResp->assertRedirect($page->getUrl());
116 $this->assertTrue($page->book->id == $newBook->id, 'Page book is now the new book');
119 public function test_page_move_requires_delete_permissions()
121 $page = Page::first();
122 $currentBook = $page->book;
123 $newBook = Book::where('id', '!=', $currentBook->id)->first();
124 $editor = $this->getEditor();
126 $this->setEntityRestrictions($newBook, ['view', 'update', 'create', 'delete'], $editor->roles->all());
127 $this->setEntityRestrictions($page, ['view', 'update', 'create'], $editor->roles->all());
129 $movePageResp = $this->actingAs($editor)->put($page->getUrl('/move'), [
130 'entity_selection' => 'book:' . $newBook->id,
132 $this->assertPermissionError($movePageResp);
133 $pageView = $this->get($page->getUrl());
134 $pageView->assertDontSee($page->getUrl('/move'));
136 $this->setEntityRestrictions($page, ['view', 'update', 'create', 'delete'], $editor->roles->all());
137 $movePageResp = $this->put($page->getUrl('/move'), [
138 'entity_selection' => 'book:' . $newBook->id,
141 $page = Page::find($page->id);
142 $movePageResp->assertRedirect($page->getUrl());
143 $this->assertTrue($page->book->id == $newBook->id, 'Page book is now the new book');
146 public function test_chapter_move()
148 $chapter = Chapter::first();
149 $currentBook = $chapter->book;
150 $pageToCheck = $chapter->pages->first();
151 $newBook = Book::where('id', '!=', $currentBook->id)->first();
153 $chapterMoveResp = $this->asEditor()->get($chapter->getUrl('/move'));
154 $chapterMoveResp->assertSee('Move Chapter');
156 $moveChapterResp = $this->put($chapter->getUrl('/move'), [
157 'entity_selection' => 'book:' . $newBook->id,
160 $chapter = Chapter::find($chapter->id);
161 $moveChapterResp->assertRedirect($chapter->getUrl());
162 $this->assertTrue($chapter->book->id === $newBook->id, 'Chapter Book is now the new book');
164 $newBookResp = $this->get($newBook->getUrl());
165 $newBookResp->assertSee('moved chapter');
166 $newBookResp->assertSee($chapter->name);
168 $pageToCheck = Page::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);
174 public function test_chapter_move_requires_delete_permissions()
176 $chapter = Chapter::first();
177 $currentBook = $chapter->book;
178 $newBook = Book::where('id', '!=', $currentBook->id)->first();
179 $editor = $this->getEditor();
181 $this->setEntityRestrictions($newBook, ['view', 'update', 'create', 'delete'], $editor->roles->all());
182 $this->setEntityRestrictions($chapter, ['view', 'update', 'create'], $editor->roles->all());
184 $moveChapterResp = $this->actingAs($editor)->put($chapter->getUrl('/move'), [
185 'entity_selection' => 'book:' . $newBook->id,
187 $this->assertPermissionError($moveChapterResp);
188 $pageView = $this->get($chapter->getUrl());
189 $pageView->assertDontSee($chapter->getUrl('/move'));
191 $this->setEntityRestrictions($chapter, ['view', 'update', 'create', 'delete'], $editor->roles->all());
192 $moveChapterResp = $this->put($chapter->getUrl('/move'), [
193 'entity_selection' => 'book:' . $newBook->id,
196 $chapter = Chapter::find($chapter->id);
197 $moveChapterResp->assertRedirect($chapter->getUrl());
198 $this->assertTrue($chapter->book->id == $newBook->id, 'Page book is now the new book');
201 public function test_chapter_move_changes_book_for_deleted_pages_within()
203 /** @var Chapter $chapter */
204 $chapter = Chapter::query()->whereHas('pages')->first();
205 $currentBook = $chapter->book;
206 $pageToCheck = $chapter->pages->first();
207 $newBook = Book::query()->where('id', '!=', $currentBook->id)->first();
209 $pageToCheck->delete();
211 $this->asEditor()->put($chapter->getUrl('/move'), [
212 'entity_selection' => 'book:' . $newBook->id,
215 $pageToCheck->refresh();
216 $this->assertEquals($newBook->id, $pageToCheck->book_id);
219 public function test_book_sort_page_shows()
221 /** @var Book $bookToSort */
222 $bookToSort = Book::query()->first();
224 $resp = $this->asAdmin()->get($bookToSort->getUrl());
225 $resp->assertElementExists('a[href="' . $bookToSort->getUrl('/sort') . '"]');
227 $resp = $this->get($bookToSort->getUrl('/sort'));
228 $resp->assertStatus(200);
229 $resp->assertSee($bookToSort->name);
232 public function test_book_sort()
234 $oldBook = Book::query()->first();
235 $chapterToMove = $this->newChapter(['name' => 'chapter to move'], $oldBook);
236 $newBook = $this->newBook(['name' => 'New sort book']);
237 $pagesToMove = Page::query()->take(5)->get();
239 // Create request data
242 'id' => $chapterToMove->id,
244 'parentChapter' => false,
246 'book' => $newBook->id,
249 foreach ($pagesToMove as $index => $page) {
253 'parentChapter' => $index === count($pagesToMove) - 1 ? $chapterToMove->id : false,
255 'book' => $newBook->id,
259 $sortResp = $this->asEditor()->put($newBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)]);
260 $sortResp->assertRedirect($newBook->getUrl());
261 $sortResp->assertStatus(302);
262 $this->assertDatabaseHas('chapters', [
263 'id' => $chapterToMove->id,
264 'book_id' => $newBook->id,
267 $this->assertTrue($newBook->chapters()->count() === 1);
268 $this->assertTrue($newBook->chapters()->first()->pages()->count() === 1);
270 $checkPage = $pagesToMove[1];
271 $checkResp = $this->get(Page::find($checkPage->id)->getUrl());
272 $checkResp->assertSee($newBook->name);
275 public function test_book_sort_item_returns_book_content()
277 $books = Book::all();
278 $bookToSort = $books[0];
279 $firstPage = $bookToSort->pages[0];
280 $firstChapter = $bookToSort->chapters[0];
282 $resp = $this->asAdmin()->get($bookToSort->getUrl() . '/sort-item');
284 // Ensure book details are returned
285 $resp->assertSee($bookToSort->name);
286 $resp->assertSee($firstPage->name);
287 $resp->assertSee($firstChapter->name);
290 public function test_pages_in_book_show_sorted_by_priority()
292 /** @var Book $book */
293 $book = Book::query()->whereHas('pages')->first();
294 $book->chapters()->forceDelete();
295 /** @var Page[] $pages */
296 $pages = $book->pages()->where('chapter_id', '=', 0)->take(2)->get();
297 $book->pages()->whereNotIn('id', $pages->pluck('id'))->delete();
299 $resp = $this->asEditor()->get($book->getUrl());
300 $resp->assertElementContains('.content-wrap a.page:nth-child(1)', $pages[0]->name);
301 $resp->assertElementContains('.content-wrap a.page:nth-child(2)', $pages[1]->name);
303 $pages[0]->forceFill(['priority' => 10])->save();
304 $pages[1]->forceFill(['priority' => 5])->save();
306 $resp = $this->asEditor()->get($book->getUrl());
307 $resp->assertElementContains('.content-wrap a.page:nth-child(1)', $pages[1]->name);
308 $resp->assertElementContains('.content-wrap a.page:nth-child(2)', $pages[0]->name);