Extracted entity testcase methods to own class

Also added some new fetch helper methods for future use.
This commit is contained in:
Dan Brown 2022-09-29 16:49:25 +01:00
parent 0e94fd44a8
commit 068a8a068c
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
23 changed files with 305 additions and 208 deletions

View File

@ -53,7 +53,7 @@ class AttachmentsApiTest extends TestCase
$page->restricted = true;
$page->save();
$this->regenEntityPermissions($page);
$this->entities->regenPermissions($page);
$resp = $this->getJson($this->baseEndpoint . '?count=1&sort=+id');
$resp->assertJsonMissing(['data' => [
@ -264,7 +264,7 @@ class AttachmentsApiTest extends TestCase
$page->draft = true;
$page->owned_by = $editor->id;
$page->save();
$this->regenEntityPermissions($page);
$this->entities->regenPermissions($page);
$attachment = $this->createAttachmentForPage($page, [
'name' => 'my attachment',

View File

@ -210,7 +210,7 @@ class PagesApiTest extends TestCase
$this->actingAsApiEditor();
$page = Page::visible()->first();
$chapter = Chapter::visible()->where('book_id', '!=', $page->book_id)->first();
$this->setEntityRestrictions($chapter, ['view'], [$this->getEditor()->roles()->first()]);
$this->entities->setPermissions($chapter, ['view'], [$this->getEditor()->roles()->first()]);
$details = [
'name' => 'My updated API page',
'chapter_id' => $chapter->id,

View File

@ -239,7 +239,7 @@ class UsersApiTest extends TestCase
$user = User::query()->where('id', '!=', $this->getAdmin()->id)
->whereNull('system_name')
->first();
$entityChain = $this->createEntityChainBelongingToUser($user);
$entityChain = $this->entities->createChainBelongingToUser($user);
/** @var User $newOwner */
$newOwner = User::query()->where('id', '!=', $user->id)->first();

View File

@ -22,7 +22,7 @@ class CopyShelfPermissionsCommandTest extends TestCase
$this->assertFalse(boolval($child->restricted), 'Child book should not be restricted by default');
$this->assertTrue($child->permissions()->count() === 0, 'Child book should have no permissions by default');
$this->setEntityRestrictions($shelf, ['view', 'update'], [$editorRole]);
$this->entities->setPermissions($shelf, ['view', 'update'], [$editorRole]);
$this->artisan('bookstack:copy-shelf-permissions', [
'--slug' => $shelf->slug,
]);
@ -43,7 +43,7 @@ class CopyShelfPermissionsCommandTest extends TestCase
$this->assertFalse(boolval($child->restricted), 'Child book should not be restricted by default');
$this->assertTrue($child->permissions()->count() === 0, 'Child book should have no permissions by default');
$this->setEntityRestrictions($shelf, ['view', 'update'], [$editorRole]);
$this->entities->setPermissions($shelf, ['view', 'update'], [$editorRole]);
$this->artisan('bookstack:copy-shelf-permissions --all')
->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');
$child = $shelf->books()->first();

View File

@ -45,7 +45,7 @@ class BookShelfTest extends TestCase
$resp = $this->actingAs($user)->get('/');
$this->withHtml($resp)->assertElementNotContains('header', 'Shelves');
$this->setEntityRestrictions($shelf, ['view'], [$userRole]);
$this->entities->setPermissions($shelf, ['view'], [$userRole]);
$resp = $this->get('/');
$this->withHtml($resp)->assertElementContains('header', 'Shelves');
@ -69,7 +69,7 @@ class BookShelfTest extends TestCase
$resp->assertSee($book->name);
$resp->assertSee($book->getUrl());
$this->setEntityRestrictions($book, []);
$this->entities->setPermissions($book, []);
$resp = $this->asEditor()->get('/shelves');
$resp->assertDontSee($book->name);
@ -298,7 +298,7 @@ class BookShelfTest extends TestCase
$this->assertFalse(boolval($child->restricted), 'Child book should not be restricted by default');
$this->assertTrue($child->permissions()->count() === 0, 'Child book should have no permissions by default');
$this->setEntityRestrictions($shelf, ['view', 'update'], [$editorRole]);
$this->entities->setPermissions($shelf, ['view', 'update'], [$editorRole]);
$resp = $this->post($shelf->getUrl('/copy-permissions'));
$child = $shelf->books()->first();

View File

@ -246,13 +246,13 @@ class BookTest extends TestCase
public function test_slug_multi_byte_url_safe()
{
$book = $this->newBook([
$book = $this->entities->newBook([
'name' => 'информация',
]);
$this->assertEquals('informaciya', $book->slug);
$book = $this->newBook([
$book = $this->entities->newBook([
'name' => '¿Qué?',
]);
@ -261,7 +261,7 @@ class BookTest extends TestCase
public function test_slug_format()
{
$book = $this->newBook([
$book = $this->entities->newBook([
'name' => 'PartA / PartB / PartC',
]);
@ -311,7 +311,7 @@ class BookTest extends TestCase
foreach ($book->getDirectChildren() as $child) {
$child->restricted = true;
$child->save();
$this->regenEntityPermissions($child);
$this->entities->regenPermissions($child);
}
$this->asEditor()->post($book->getUrl('/copy'), ['name' => 'My copy book']);
@ -365,7 +365,7 @@ class BookTest extends TestCase
$viewer = $this->getViewer();
$this->giveUserPermissions($viewer, ['book-update-all', 'book-create-all', 'bookshelf-update-all']);
$this->setEntityRestrictions($shelfB);
$this->entities->setPermissions($shelfB);
$this->asEditor()->post($book->getUrl('/copy'), ['name' => 'My copy book']);

View File

@ -107,7 +107,7 @@ class ChapterTest extends TestCase
foreach ($chapter->pages as $page) {
$page->restricted = true;
$page->save();
$this->regenEntityPermissions($page);
$this->entities->regenPermissions($page);
}
$this->asEditor()->post($chapter->getUrl('/copy'), [

View File

@ -14,7 +14,7 @@ class EntityAccessTest extends TestCase
// Create required assets and revisions
$creator = $this->getEditor();
$updater = $this->getViewer();
$entities = $this->createEntityChainBelongingToUser($creator, $updater);
$entities = $this->entities->createChainBelongingToUser($creator, $updater);
app()->make(UserRepo::class)->destroy($creator);
app()->make(PageRepo::class)->update($entities['page'], ['html' => '<p>hello!</p>>']);
@ -26,7 +26,7 @@ class EntityAccessTest extends TestCase
// Create required assets and revisions
$creator = $this->getViewer();
$updater = $this->getEditor();
$entities = $this->createEntityChainBelongingToUser($creator, $updater);
$entities = $this->entities->createChainBelongingToUser($creator, $updater);
app()->make(UserRepo::class)->destroy($updater);
app()->make(PageRepo::class)->update($entities['page'], ['html' => '<p>Hello there!</p>']);

View File

@ -47,7 +47,7 @@ class EntitySearchTest extends TestCase
public function test_searching_accents_and_small_terms()
{
$page = $this->newPage(['name' => 'My new test quaffleachits', 'html' => 'some áéííúü¿¡ test content a2 orange dog']);
$page = $this->entities->newPage(['name' => 'My new test quaffleachits', 'html' => 'some áéííúü¿¡ test content a2 orange dog']);
$this->asEditor();
$accentSearch = $this->get('/search?term=' . urlencode('áéíí'));
@ -111,7 +111,7 @@ class EntitySearchTest extends TestCase
public function test_exact_searches()
{
$page = $this->newPage(['name' => 'My new test page', 'html' => 'this is a story about an orange donkey']);
$page = $this->entities->newPage(['name' => 'My new test page', 'html' => 'this is a story about an orange donkey']);
$exactSearchA = $this->asEditor()->get('/search?term=' . urlencode('"story about an orange"'));
$exactSearchA->assertStatus(200)->assertSee($page->name);
@ -123,7 +123,7 @@ class EntitySearchTest extends TestCase
public function test_search_terms_with_delimiters_are_converted_to_exact_matches()
{
$this->asEditor();
$page = $this->newPage(['name' => 'Delimiter test', 'html' => '<p>1.1 2,2 3?3 4:4 5;5 (8) &lt;9&gt; "10" \'11\' `12`</p>']);
$page = $this->entities->newPage(['name' => 'Delimiter test', 'html' => '<p>1.1 2,2 3?3 4:4 5;5 (8) &lt;9&gt; "10" \'11\' `12`</p>']);
$terms = explode(' ', '1.1 2,2 3?3 4:4 5;5 (8) <9> "10" \'11\' `12`');
foreach ($terms as $term) {
@ -134,7 +134,7 @@ class EntitySearchTest extends TestCase
public function test_search_filters()
{
$page = $this->newPage(['name' => 'My new test quaffleachits', 'html' => 'this is about an orange donkey danzorbhsing']);
$page = $this->entities->newPage(['name' => 'My new test quaffleachits', 'html' => 'this is about an orange donkey danzorbhsing']);
$this->asEditor();
$editorId = $this->getEditor()->id;
$editorSlug = $this->getEditor()->slug;
@ -197,7 +197,7 @@ class EntitySearchTest extends TestCase
public function test_ajax_entity_search()
{
$page = $this->newPage(['name' => 'my ajax search test', 'html' => 'ajax test']);
$page = $this->entities->newPage(['name' => 'my ajax search test', 'html' => 'ajax test']);
$notVisitedPage = Page::first();
// Visit the page to make popular
@ -334,15 +334,15 @@ class EntitySearchTest extends TestCase
public function test_search_ranks_common_words_lower()
{
$this->newPage(['name' => 'Test page A', 'html' => '<p>dog biscuit dog dog</p>']);
$this->newPage(['name' => 'Test page B', 'html' => '<p>cat biscuit</p>']);
$this->entities->newPage(['name' => 'Test page A', 'html' => '<p>dog biscuit dog dog</p>']);
$this->entities->newPage(['name' => 'Test page B', 'html' => '<p>cat biscuit</p>']);
$search = $this->asEditor()->get('/search?term=cat+dog+biscuit');
$this->withHtml($search)->assertElementContains('.entity-list > .page:nth-child(1)', 'Test page A');
$this->withHtml($search)->assertElementContains('.entity-list > .page:nth-child(2)', 'Test page B');
for ($i = 0; $i < 2; $i++) {
$this->newPage(['name' => 'Test page ' . $i, 'html' => '<p>dog</p>']);
$this->entities->newPage(['name' => 'Test page ' . $i, 'html' => '<p>dog</p>']);
}
$search = $this->asEditor()->get('/search?term=cat+dog+biscuit');
@ -352,7 +352,7 @@ class EntitySearchTest extends TestCase
public function test_terms_in_headers_have_an_adjusted_index_score()
{
$page = $this->newPage(['name' => 'Test page A', 'html' => '
$page = $this->entities->newPage(['name' => 'Test page A', 'html' => '
<p>TermA</p>
<h1>TermB <strong>TermNested</strong></h1>
<h2>TermC</h2>
@ -377,7 +377,7 @@ class EntitySearchTest extends TestCase
public function test_name_and_content_terms_are_merged_to_single_score()
{
$page = $this->newPage(['name' => 'TermA', 'html' => '
$page = $this->entities->newPage(['name' => 'TermA', 'html' => '
<p>TermA</p>
']);
@ -389,7 +389,7 @@ class EntitySearchTest extends TestCase
public function test_tag_names_and_values_are_indexed_for_search()
{
$page = $this->newPage(['name' => 'PageA', 'html' => '<p>content</p>', 'tags' => [
$page = $this->entities->newPage(['name' => 'PageA', 'html' => '<p>content</p>', 'tags' => [
['name' => 'Animal', 'value' => 'MeowieCat'],
['name' => 'SuperImportant'],
]]);
@ -402,7 +402,7 @@ class EntitySearchTest extends TestCase
public function test_matching_terms_in_search_results_are_highlighted()
{
$this->newPage(['name' => 'My Meowie Cat', 'html' => '<p>A superimportant page about meowieable animals</p>', 'tags' => [
$this->entities->newPage(['name' => 'My Meowie Cat', 'html' => '<p>A superimportant page about meowieable animals</p>', 'tags' => [
['name' => 'Animal', 'value' => 'MeowieCat'],
['name' => 'SuperImportant'],
]]);
@ -420,7 +420,7 @@ class EntitySearchTest extends TestCase
public function test_match_highlighting_works_with_multibyte_content()
{
$this->newPage([
$this->entities->newPage([
'name' => 'Test Page',
'html' => '<p>На мен ми трябва нещо добро test</p>',
]);
@ -431,7 +431,7 @@ class EntitySearchTest extends TestCase
public function test_html_entities_in_item_details_remains_escaped_in_search_results()
{
$this->newPage(['name' => 'My <cool> TestPageContent', 'html' => '<p>My supercool &lt;great&gt; TestPageContent page</p>']);
$this->entities->newPage(['name' => 'My <cool> TestPageContent', 'html' => '<p>My supercool &lt;great&gt; TestPageContent page</p>']);
$search = $this->asEditor()->get('/search?term=TestPageContent');
$search->assertSee('My &lt;cool&gt; <strong>TestPageContent</strong>', false);
@ -440,7 +440,7 @@ class EntitySearchTest extends TestCase
public function test_words_adjacent_to_lines_breaks_can_be_matched_with_normal_terms()
{
$page = $this->newPage(['name' => 'TermA', 'html' => '
$page = $this->entities->newPage(['name' => 'TermA', 'html' => '
<p>TermA<br>TermB<br>TermC</p>
']);

View File

@ -201,7 +201,7 @@ class PageTest extends TestCase
$newBook->owned_by = $viewer->id;
$newBook->save();
$this->giveUserPermissions($viewer, ['page-create-own']);
$this->regenEntityPermissions($newBook);
$this->entities->regenPermissions($newBook);
$resp = $this->actingAs($viewer)->get($page->getUrl());
$resp->assertSee($page->getUrl('/copy'));
@ -255,7 +255,7 @@ class PageTest extends TestCase
public function test_recently_updated_pages_view()
{
$user = $this->getEditor();
$content = $this->createEntityChainBelongingToUser($user);
$content = $this->entities->createChainBelongingToUser($user);
$resp = $this->asAdmin()->get('/pages/recently-updated');
$this->withHtml($resp)->assertElementContains('.entity-list .page:nth-child(1)', $content['page']->name);
@ -303,8 +303,8 @@ class PageTest extends TestCase
'html' => '<p>Updated content</p>',
]);
$this->setEntityRestrictions($page->book);
$this->setEntityRestrictions($page, ['view'], [$user->roles->first()]);
$this->entities->setPermissions($page->book);
$this->entities->setPermissions($page, ['view'], [$user->roles->first()]);
$resp = $this->get('/pages/recently-updated');
$resp->assertDontSee($page->book->getShortName(42));

View File

@ -98,14 +98,14 @@ class SortTest extends TestCase
$newBook = Book::query()->where('id', '!=', $currentBook->id)->first();
$editor = $this->getEditor();
$this->setEntityRestrictions($newBook, ['view', 'update', 'delete'], $editor->roles->all());
$this->entities->setPermissions($newBook, ['view', 'update', 'delete'], $editor->roles->all());
$movePageResp = $this->actingAs($editor)->put($page->getUrl('/move'), [
'entity_selection' => 'book:' . $newBook->id,
]);
$this->assertPermissionError($movePageResp);
$this->setEntityRestrictions($newBook, ['view', 'update', 'delete', 'create'], $editor->roles->all());
$this->entities->setPermissions($newBook, ['view', 'update', 'delete', 'create'], $editor->roles->all());
$movePageResp = $this->put($page->getUrl('/move'), [
'entity_selection' => 'book:' . $newBook->id,
]);
@ -123,8 +123,8 @@ class SortTest extends TestCase
$newBook = Book::query()->where('id', '!=', $currentBook->id)->first();
$editor = $this->getEditor();
$this->setEntityRestrictions($newBook, ['view', 'update', 'create', 'delete'], $editor->roles->all());
$this->setEntityRestrictions($page, ['view', 'update', 'create'], $editor->roles->all());
$this->entities->setPermissions($newBook, ['view', 'update', 'create', 'delete'], $editor->roles->all());
$this->entities->setPermissions($page, ['view', 'update', 'create'], $editor->roles->all());
$movePageResp = $this->actingAs($editor)->put($page->getUrl('/move'), [
'entity_selection' => 'book:' . $newBook->id,
@ -133,7 +133,7 @@ class SortTest extends TestCase
$pageView = $this->get($page->getUrl());
$pageView->assertDontSee($page->getUrl('/move'));
$this->setEntityRestrictions($page, ['view', 'update', 'create', 'delete'], $editor->roles->all());
$this->entities->setPermissions($page, ['view', 'update', 'create', 'delete'], $editor->roles->all());
$movePageResp = $this->put($page->getUrl('/move'), [
'entity_selection' => 'book:' . $newBook->id,
]);
@ -178,8 +178,8 @@ class SortTest extends TestCase
$newBook = Book::query()->where('id', '!=', $currentBook->id)->first();
$editor = $this->getEditor();
$this->setEntityRestrictions($newBook, ['view', 'update', 'create', 'delete'], $editor->roles->all());
$this->setEntityRestrictions($chapter, ['view', 'update', 'create'], $editor->roles->all());
$this->entities->setPermissions($newBook, ['view', 'update', 'create', 'delete'], $editor->roles->all());
$this->entities->setPermissions($chapter, ['view', 'update', 'create'], $editor->roles->all());
$moveChapterResp = $this->actingAs($editor)->put($chapter->getUrl('/move'), [
'entity_selection' => 'book:' . $newBook->id,
@ -188,7 +188,7 @@ class SortTest extends TestCase
$pageView = $this->get($chapter->getUrl());
$pageView->assertDontSee($chapter->getUrl('/move'));
$this->setEntityRestrictions($chapter, ['view', 'update', 'create', 'delete'], $editor->roles->all());
$this->entities->setPermissions($chapter, ['view', 'update', 'create', 'delete'], $editor->roles->all());
$moveChapterResp = $this->put($chapter->getUrl('/move'), [
'entity_selection' => 'book:' . $newBook->id,
]);
@ -205,15 +205,15 @@ class SortTest extends TestCase
$newBook = Book::query()->where('id', '!=', $currentBook->id)->first();
$editor = $this->getEditor();
$this->setEntityRestrictions($newBook, ['view', 'update', 'delete'], [$editor->roles->first()]);
$this->setEntityRestrictions($chapter, ['view', 'update', 'create', 'delete'], [$editor->roles->first()]);
$this->entities->setPermissions($newBook, ['view', 'update', 'delete'], [$editor->roles->first()]);
$this->entities->setPermissions($chapter, ['view', 'update', 'create', 'delete'], [$editor->roles->first()]);
$moveChapterResp = $this->actingAs($editor)->put($chapter->getUrl('/move'), [
'entity_selection' => 'book:' . $newBook->id,
]);
$this->assertPermissionError($moveChapterResp);
$this->setEntityRestrictions($newBook, ['view', 'update', 'create', 'delete'], [$editor->roles->first()]);
$this->entities->setPermissions($newBook, ['view', 'update', 'create', 'delete'], [$editor->roles->first()]);
$moveChapterResp = $this->put($chapter->getUrl('/move'), [
'entity_selection' => 'book:' . $newBook->id,
]);
@ -257,8 +257,8 @@ class SortTest extends TestCase
public function test_book_sort()
{
$oldBook = Book::query()->first();
$chapterToMove = $this->newChapter(['name' => 'chapter to move'], $oldBook);
$newBook = $this->newBook(['name' => 'New sort book']);
$chapterToMove = $this->entities->newChapter(['name' => 'chapter to move'], $oldBook);
$newBook = $this->entities->newBook(['name' => 'New sort book']);
$pagesToMove = Page::query()->take(5)->get();
// Create request data
@ -323,7 +323,7 @@ class SortTest extends TestCase
$page = Page::query()->where('chapter_id', '!=', 0)->first();
/** @var Chapter $otherChapter */
$otherChapter = Chapter::query()->where('book_id', '!=', $page->book_id)->first();
$this->setEntityRestrictions($otherChapter);
$this->entities->setPermissions($otherChapter);
$sortData = [
'id' => $page->id,
@ -346,7 +346,7 @@ class SortTest extends TestCase
/** @var Chapter $otherChapter */
$otherChapter = Chapter::query()->where('book_id', '!=', $page->book_id)->first();
$editor = $this->getEditor();
$this->setEntityRestrictions($otherChapter->book, ['update', 'delete'], [$editor->roles()->first()]);
$this->entities->setPermissions($otherChapter->book, ['update', 'delete'], [$editor->roles()->first()]);
$sortData = [
'id' => $page->id,
@ -369,7 +369,7 @@ class SortTest extends TestCase
/** @var Chapter $otherChapter */
$otherChapter = Chapter::query()->where('book_id', '!=', $page->book_id)->first();
$editor = $this->getEditor();
$this->setEntityRestrictions($otherChapter, ['view', 'delete'], [$editor->roles()->first()]);
$this->entities->setPermissions($otherChapter, ['view', 'delete'], [$editor->roles()->first()]);
$sortData = [
'id' => $page->id,
@ -392,7 +392,7 @@ class SortTest extends TestCase
/** @var Chapter $otherChapter */
$otherChapter = Chapter::query()->where('book_id', '!=', $page->book_id)->first();
$editor = $this->getEditor();
$this->setEntityRestrictions($page, ['view', 'delete'], [$editor->roles()->first()]);
$this->entities->setPermissions($page, ['view', 'delete'], [$editor->roles()->first()]);
$sortData = [
'id' => $page->id,
@ -415,7 +415,7 @@ class SortTest extends TestCase
/** @var Chapter $otherChapter */
$otherChapter = Chapter::query()->where('book_id', '!=', $page->book_id)->first();
$editor = $this->getEditor();
$this->setEntityRestrictions($page, ['view', 'update'], [$editor->roles()->first()]);
$this->entities->setPermissions($page, ['view', 'update'], [$editor->roles()->first()]);
$sortData = [
'id' => $page->id,

View File

@ -188,7 +188,7 @@ class TagTest extends TestCase
$resp->assertSee('GreatTestContent');
$page->restricted = true;
$this->regenEntityPermissions($page);
$this->entities->regenPermissions($page);
$resp = $this->asEditor()->get('/tags');
$resp->assertDontSee('SuperCategory');
@ -207,7 +207,7 @@ class TagTest extends TestCase
{
$this->asEditor();
foreach ($this->getEachEntityType() as $entity) {
foreach ($this->entities->all() as $entity) {
$entity->tags()->create(['name' => 'My Super Tag Name', 'value' => 'An-awesome-value']);
$html = $this->withHtml($this->get($entity->getUrl()));
$html->assertElementExists('body.tag-name-mysupertagname.tag-value-anawesomevalue.tag-pair-mysupertagname-anawesomevalue');

View File

@ -0,0 +1,201 @@
<?php
namespace Tests\Helpers;
use BookStack\Auth\Role;
use BookStack\Auth\User;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Entity;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Repos\BookRepo;
use BookStack\Entities\Repos\BookshelfRepo;
use BookStack\Entities\Repos\ChapterRepo;
use BookStack\Entities\Repos\PageRepo;
class EntityProvider
{
/**
* @var array<string, int[]>
*/
protected array $fetchCache = [
'book' => [],
'page' => [],
'bookshelf' => [],
'chapter' => [],
];
/**
* Get an un-fetched page from the system.
*/
public function page(): Page
{
/** @var Page $page */
$page = Page::query()->whereNotIn('id', $this->fetchCache['page'])->first();
$this->addToCache($page);
return $page;
}
/**
* Get an un-fetched chapter from the system.
*/
public function chapter(): Chapter
{
/** @var Chapter $chapter */
$chapter = Chapter::query()->whereNotIn('id', $this->fetchCache['chapter'])->first();
$this->addToCache($chapter);
return $chapter;
}
/**
* Get an un-fetched book from the system.
*/
public function book(): Book
{
/** @var Book $book */
$book = Book::query()->whereNotIn('id', $this->fetchCache['book'])->first();
$this->addToCache($book);
return $book;
}
/**
* Get an un-fetched shelf from the system.
*/
public function shelf(): Bookshelf
{
/** @var Bookshelf $shelf */
$shelf = Bookshelf::query()->whereNotIn('id', $this->fetchCache['bookshelf'])->first();
$this->addToCache($shelf);
return $shelf;
}
/**
* Get all entity types from the system.
* @return array{page: Page, chapter: Chapter, book: Book, bookshelf: Bookshelf}
*/
public function all(): array
{
return [
'page' => $this->page(),
'chapter' => $this->chapter(),
'book' => $this->book(),
'bookshelf' => $this->shelf(),
];
}
/**
* Create a book to page chain of entities that belong to a specific user.
* @return array{book: Book, chapter: Chapter, page: Page}
*/
public function createChainBelongingToUser(User $creatorUser, ?User $updaterUser = null): array
{
if (empty($updaterUser)) {
$updaterUser = $creatorUser;
}
$userAttrs = ['created_by' => $creatorUser->id, 'owned_by' => $creatorUser->id, 'updated_by' => $updaterUser->id];
/** @var Book $book */
$book = Book::factory()->create($userAttrs);
$chapter = Chapter::factory()->create(array_merge(['book_id' => $book->id], $userAttrs));
$page = Page::factory()->create(array_merge(['book_id' => $book->id, 'chapter_id' => $chapter->id], $userAttrs));
$book->rebuildPermissions();
$this->addToCache([$page, $chapter, $book]);
return compact('book', 'chapter', 'page');
}
/**
* Create and return a new bookshelf.
*/
public function newShelf(array $input = ['name' => 'test shelf', 'description' => 'My new test shelf']): Bookshelf
{
$shelf = app(BookshelfRepo::class)->create($input, []);
$this->addToCache($shelf);
return $shelf;
}
/**
* Create and return a new book.
*/
public function newBook(array $input = ['name' => 'test book', 'description' => 'My new test book']): Book
{
$book = app(BookRepo::class)->create($input);
$this->addToCache($book);
return $book;
}
/**
* Create and return a new test chapter.
*/
public function newChapter(array $input, Book $book): Chapter
{
$chapter = app(ChapterRepo::class)->create($input, $book);
$this->addToCache($chapter);
return $chapter;
}
/**
* Create and return a new test page.
*/
public function newPage(array $input = ['name' => 'test page', 'html' => 'My new test page']): Page
{
$book = Book::query()->first();
$pageRepo = app(PageRepo::class);
$draftPage = $pageRepo->getNewDraftPage($book);
$this->addToCache($draftPage);
return $pageRepo->publishDraft($draftPage, $input);
}
/**
* Regenerate the permission for an entity.
* Centralised to manage clearing of cached elements between requests.
*/
public function regenPermissions(Entity $entity): void
{
$entity->rebuildPermissions();
$entity->load('jointPermissions');
}
/**
* Set the given entity as having restricted permissions, and apply the given
* permissions for the given roles.
* @param string[] $actions
* @param Role[] $roles
*/
public function setPermissions(Entity $entity, array $actions = [], array $roles = []): void
{
$entity->restricted = true;
$entity->permissions()->delete();
$permissions = [];
foreach ($actions as $action) {
foreach ($roles as $role) {
$permissions[] = [
'role_id' => $role->id,
'action' => strtolower($action),
];
}
}
$entity->permissions()->createMany($permissions);
$entity->save();
$entity->load('permissions');
$this->regenPermissions($entity);
}
/**
* @param Entity|Entity[] $entities
*/
protected function addToCache($entities): void
{
if (!is_array($entities)) {
$entities = [$entities];
}
foreach ($entities as $entity) {
$this->fetchCache[$entity->getType()][] = $entity->id;
}
}
}

View File

@ -24,7 +24,7 @@ class HomepageTest extends TestCase
$this->asEditor();
$name = 'My custom homepage';
$content = str_repeat('This is the body content of my custom homepage.', 20);
$customPage = $this->newPage(['name' => $name, 'html' => $content]);
$customPage = $this->entities->newPage(['name' => $name, 'html' => $content]);
$this->setSettings(['app-homepage' => $customPage->id]);
$this->setSettings(['app-homepage-type' => 'page']);
@ -41,7 +41,7 @@ class HomepageTest extends TestCase
$this->asEditor();
$name = 'My custom homepage';
$content = str_repeat('This is the body content of my custom homepage.', 20);
$customPage = $this->newPage(['name' => $name, 'html' => $content]);
$customPage = $this->entities->newPage(['name' => $name, 'html' => $content]);
$this->setSettings([
'app-homepage' => $customPage->id,
'app-homepage-type' => 'page',
@ -67,7 +67,7 @@ class HomepageTest extends TestCase
$this->asEditor();
$name = 'My custom homepage';
$content = str_repeat('This is the body content of my custom homepage.', 20);
$customPage = $this->newPage(['name' => $name, 'html' => $content]);
$customPage = $this->entities->newPage(['name' => $name, 'html' => $content]);
$this->setSettings([
'app-homepage' => $customPage->id,
'app-homepage-type' => 'default',
@ -107,7 +107,7 @@ class HomepageTest extends TestCase
$included->save();
$name = 'My custom homepage';
$customPage = $this->newPage(['name' => $name, 'html' => '{{@' . $included->id . '}}']);
$customPage = $this->entities->newPage(['name' => $name, 'html' => '{{@' . $included->id . '}}']);
$this->setSettings(['app-homepage' => $customPage->id]);
$this->setSettings(['app-homepage-type' => 'page']);
@ -177,7 +177,7 @@ class HomepageTest extends TestCase
$this->withHtml($homeVisit)->assertElementNotContains('.content-wrap', $book->name);
// Ensure is visible again with entity-level view permission
$this->setEntityRestrictions($book, ['view'], [$editor->roles()->first()]);
$this->entities->setPermissions($book, ['view'], [$editor->roles()->first()]);
$homeVisit = $this->get('/');
$this->withHtml($homeVisit)->assertElementContains('.content-wrap', $shelf->name);
$this->withHtml($homeVisit)->assertElementContains('.content-wrap', $book->name);

View File

@ -36,7 +36,7 @@ class EntityPermissionsTest extends TestCase
$this->user->roles->first(),
$this->viewer->roles->first(),
];
$this->setEntityRestrictions($entity, $actions, $roles);
$this->entities->setPermissions($entity, $actions, $roles);
}
public function test_bookshelf_view_restriction()

View File

@ -27,7 +27,7 @@ class ExportPermissionsTest extends TestCase
$resp->assertSee($pageContent);
}
$this->setEntityRestrictions($page, []);
$this->entities->setPermissions($page, []);
foreach ($formats as $format) {
$resp = $this->get($chapter->getUrl("export/{$format}"));
@ -55,7 +55,7 @@ class ExportPermissionsTest extends TestCase
$resp->assertSee($pageContent);
}
$this->setEntityRestrictions($page, []);
$this->entities->setPermissions($page, []);
foreach ($formats as $format) {
$resp = $this->get($book->getUrl("export/{$format}"));

View File

@ -285,7 +285,7 @@ class RolesTest extends TestCase
{
/** @var Page $otherUsersPage */
$otherUsersPage = Page::query()->first();
$content = $this->createEntityChainBelongingToUser($this->user);
$content = $this->entities->createChainBelongingToUser($this->user);
// Set a different creator on the page we're checking to ensure
// that the owner fields are checked
@ -355,9 +355,9 @@ class RolesTest extends TestCase
{
/** @var Bookshelf $otherShelf */
$otherShelf = Bookshelf::query()->first();
$ownShelf = $this->newShelf(['name' => 'test-shelf', 'slug' => 'test-shelf']);
$ownShelf = $this->entities->newShelf(['name' => 'test-shelf', 'slug' => 'test-shelf']);
$ownShelf->forceFill(['owned_by' => $this->user->id, 'updated_by' => $this->user->id])->save();
$this->regenEntityPermissions($ownShelf);
$this->entities->regenPermissions($ownShelf);
$this->checkAccessPermission('bookshelf-update-own', [
$ownShelf->getUrl('/edit'),
@ -386,9 +386,9 @@ class RolesTest extends TestCase
$this->giveUserPermissions($this->user, ['bookshelf-update-all']);
/** @var Bookshelf $otherShelf */
$otherShelf = Bookshelf::query()->first();
$ownShelf = $this->newShelf(['name' => 'test-shelf', 'slug' => 'test-shelf']);
$ownShelf = $this->entities->newShelf(['name' => 'test-shelf', 'slug' => 'test-shelf']);
$ownShelf->forceFill(['owned_by' => $this->user->id, 'updated_by' => $this->user->id])->save();
$this->regenEntityPermissions($ownShelf);
$this->entities->regenPermissions($ownShelf);
$this->checkAccessPermission('bookshelf-delete-own', [
$ownShelf->getUrl('/delete'),
@ -438,7 +438,7 @@ class RolesTest extends TestCase
{
/** @var Book $otherBook */
$otherBook = Book::query()->take(1)->get()->first();
$ownBook = $this->createEntityChainBelongingToUser($this->user)['book'];
$ownBook = $this->entities->createChainBelongingToUser($this->user)['book'];
$this->checkAccessPermission('book-update-own', [
$ownBook->getUrl() . '/edit',
], [
@ -466,7 +466,7 @@ class RolesTest extends TestCase
$this->giveUserPermissions($this->user, ['book-update-all']);
/** @var Book $otherBook */
$otherBook = Book::query()->take(1)->get()->first();
$ownBook = $this->createEntityChainBelongingToUser($this->user)['book'];
$ownBook = $this->entities->createChainBelongingToUser($this->user)['book'];
$this->checkAccessPermission('book-delete-own', [
$ownBook->getUrl() . '/delete',
], [
@ -501,7 +501,7 @@ class RolesTest extends TestCase
{
/** @var Book $book */
$book = Book::query()->take(1)->get()->first();
$ownBook = $this->createEntityChainBelongingToUser($this->user)['book'];
$ownBook = $this->entities->createChainBelongingToUser($this->user)['book'];
$this->checkAccessPermission('chapter-create-own', [
$ownBook->getUrl('/create-chapter'),
], [
@ -538,7 +538,7 @@ class RolesTest extends TestCase
{
/** @var Chapter $otherChapter */
$otherChapter = Chapter::query()->first();
$ownChapter = $this->createEntityChainBelongingToUser($this->user)['chapter'];
$ownChapter = $this->entities->createChainBelongingToUser($this->user)['chapter'];
$this->checkAccessPermission('chapter-update-own', [
$ownChapter->getUrl() . '/edit',
], [
@ -566,7 +566,7 @@ class RolesTest extends TestCase
$this->giveUserPermissions($this->user, ['chapter-update-all']);
/** @var Chapter $otherChapter */
$otherChapter = Chapter::query()->first();
$ownChapter = $this->createEntityChainBelongingToUser($this->user)['chapter'];
$ownChapter = $this->entities->createChainBelongingToUser($this->user)['chapter'];
$this->checkAccessPermission('chapter-delete-own', [
$ownChapter->getUrl() . '/delete',
], [
@ -608,7 +608,7 @@ class RolesTest extends TestCase
/** @var Chapter $chapter */
$chapter = Chapter::query()->first();
$entities = $this->createEntityChainBelongingToUser($this->user);
$entities = $this->entities->createChainBelongingToUser($this->user);
$ownBook = $entities['book'];
$ownChapter = $entities['chapter'];
@ -699,7 +699,7 @@ class RolesTest extends TestCase
{
/** @var Page $otherPage */
$otherPage = Page::query()->first();
$ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
$ownPage = $this->entities->createChainBelongingToUser($this->user)['page'];
$this->checkAccessPermission('page-update-own', [
$ownPage->getUrl() . '/edit',
], [
@ -727,7 +727,7 @@ class RolesTest extends TestCase
$this->giveUserPermissions($this->user, ['page-update-all']);
/** @var Page $otherPage */
$otherPage = Page::query()->first();
$ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
$ownPage = $this->entities->createChainBelongingToUser($this->user)['page'];
$this->checkAccessPermission('page-delete-own', [
$ownPage->getUrl() . '/delete',
], [
@ -865,14 +865,14 @@ class RolesTest extends TestCase
$admin = $this->getAdmin();
// Book links
$book = Book::factory()->create(['created_by' => $admin->id, 'updated_by' => $admin->id]);
$this->regenEntityPermissions($book);
$this->entities->regenPermissions($book);
$this->actingAs($this->getViewer())->get($book->getUrl())
->assertDontSee('Create a new page')
->assertDontSee('Add a chapter');
// Chapter links
$chapter = Chapter::factory()->create(['created_by' => $admin->id, 'updated_by' => $admin->id, 'book_id' => $book->id]);
$this->regenEntityPermissions($chapter);
$this->entities->regenPermissions($chapter);
$this->actingAs($this->getViewer())->get($chapter->getUrl())
->assertDontSee('Create a new page')
->assertDontSee('Sort the current book');
@ -880,7 +880,7 @@ class RolesTest extends TestCase
public function test_comment_create_permission()
{
$ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
$ownPage = $this->entities->createChainBelongingToUser($this->user)['page'];
$this->actingAs($this->user)
->addComment($ownPage)
@ -895,7 +895,7 @@ class RolesTest extends TestCase
public function test_comment_update_own_permission()
{
$ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
$ownPage = $this->entities->createChainBelongingToUser($this->user)['page'];
$this->giveUserPermissions($this->user, ['comment-create-all']);
$this->actingAs($this->user)->addComment($ownPage);
/** @var Comment $comment */
@ -913,7 +913,7 @@ class RolesTest extends TestCase
public function test_comment_update_all_permission()
{
/** @var Page $ownPage */
$ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
$ownPage = $this->entities->createChainBelongingToUser($this->user)['page'];
$this->asAdmin()->addComment($ownPage);
/** @var Comment $comment */
$comment = $ownPage->comments()->latest()->first();
@ -930,7 +930,7 @@ class RolesTest extends TestCase
public function test_comment_delete_own_permission()
{
/** @var Page $ownPage */
$ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
$ownPage = $this->entities->createChainBelongingToUser($this->user)['page'];
$this->giveUserPermissions($this->user, ['comment-create-all']);
$this->actingAs($this->user)->addComment($ownPage);
@ -949,7 +949,7 @@ class RolesTest extends TestCase
public function test_comment_delete_all_permission()
{
/** @var Page $ownPage */
$ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
$ownPage = $this->entities->createChainBelongingToUser($this->user)['page'];
$this->asAdmin()->addComment($ownPage);
/** @var Comment $comment */
$comment = $ownPage->comments()->latest()->first();

View File

@ -177,7 +177,7 @@ class PublicActionTest extends TestCase
$this->setSettings(['app-public' => 'true']);
/** @var Book $book */
$book = Book::query()->first();
$this->setEntityRestrictions($book);
$this->entities->setPermissions($book);
$resp = $this->get($book->getUrl());
$resp->assertSee('Book not found');

View File

@ -10,7 +10,7 @@ class CrossLinkParserTest extends TestCase
{
public function test_instance_with_entity_resolvers_matches_entity_links()
{
$entities = $this->getEachEntityType();
$entities = $this->entities->all();
$otherPage = Page::query()->where('id', '!=', $entities['page']->id)->first();
$html = '

View File

@ -57,7 +57,7 @@ class ReferencesTest extends TestCase
public function test_references_to_count_visible_on_entity_show_view()
{
$entities = $this->getEachEntityType();
$entities = $this->entities->all();
/** @var Page $otherPage */
$otherPage = Page::query()->where('id', '!=', $entities['page']->id)->first();
@ -79,7 +79,7 @@ class ReferencesTest extends TestCase
public function test_references_to_visible_on_references_page()
{
$entities = $this->getEachEntityType();
$entities = $this->entities->all();
$this->asEditor();
foreach ($entities as $entity) {
$this->createReference($entities['page'], $entity);
@ -101,7 +101,7 @@ class ReferencesTest extends TestCase
$pageB = Page::query()->where('id', '!=', $page->id)->first();
$this->createReference($pageB, $page);
$this->setEntityRestrictions($pageB);
$this->entities->setPermissions($pageB);
$this->asEditor()->get($page->getUrl('/references'))->assertDontSee($pageB->name);
$this->asAdmin()->get($page->getUrl('/references'))->assertSee($pageB->name);

View File

@ -7,15 +7,7 @@ use BookStack\Auth\Permissions\PermissionsRepo;
use BookStack\Auth\Permissions\RolePermission;
use BookStack\Auth\Role;
use BookStack\Auth\User;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Entity;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Repos\BookRepo;
use BookStack\Entities\Repos\BookshelfRepo;
use BookStack\Entities\Repos\ChapterRepo;
use BookStack\Entities\Repos\PageRepo;
use BookStack\Settings\SettingService;
use BookStack\Uploads\HttpFetcher;
use GuzzleHttp\Client;
@ -34,6 +26,7 @@ use Monolog\Handler\TestHandler;
use Monolog\Logger;
use Psr\Http\Client\ClientInterface;
use Ssddanbrown\AssertHtml\TestsHtml;
use Tests\Helpers\EntityProvider;
abstract class TestCase extends BaseTestCase
{
@ -43,6 +36,13 @@ abstract class TestCase extends BaseTestCase
protected ?User $admin = null;
protected ?User $editor = null;
protected EntityProvider $entities;
protected function setUp(): void
{
$this->entities = new EntityProvider();
parent::setUp();
}
/**
* The base URL to use while testing the application.
@ -135,51 +135,6 @@ abstract class TestCase extends BaseTestCase
return User::query()->where('system_name', '=', null)->get()->last();
}
/**
* Regenerate the permission for an entity.
*/
protected function regenEntityPermissions(Entity $entity): void
{
$entity->rebuildPermissions();
$entity->load('jointPermissions');
}
/**
* Create and return a new bookshelf.
*/
public function newShelf(array $input = ['name' => 'test shelf', 'description' => 'My new test shelf']): Bookshelf
{
return app(BookshelfRepo::class)->create($input, []);
}
/**
* Create and return a new book.
*/
public function newBook(array $input = ['name' => 'test book', 'description' => 'My new test book']): Book
{
return app(BookRepo::class)->create($input);
}
/**
* Create and return a new test chapter.
*/
public function newChapter(array $input, Book $book): Chapter
{
return app(ChapterRepo::class)->create($input, $book);
}
/**
* Create and return a new test page.
*/
public function newPage(array $input = ['name' => 'test page', 'html' => 'My new test page']): Page
{
$book = Book::query()->first();
$pageRepo = app(PageRepo::class);
$draftPage = $pageRepo->getNewDraftPage($book);
return $pageRepo->publishDraft($draftPage, $input);
}
/**
* Quickly sets an array of settings.
*/
@ -191,31 +146,6 @@ abstract class TestCase extends BaseTestCase
}
}
/**
* Manually set some permissions on an entity.
*/
protected function setEntityRestrictions(Entity $entity, array $actions = [], array $roles = []): void
{
$entity->restricted = true;
$entity->permissions()->delete();
$permissions = [];
foreach ($actions as $action) {
foreach ($roles as $role) {
$permissions[] = [
'role_id' => $role->id,
'action' => strtolower($action),
];
}
}
$entity->permissions()->createMany($permissions);
$entity->save();
$entity->load('permissions');
$this->app->make(JointPermissionBuilder::class)->rebuildForEntity($entity);
$entity->load('jointPermissions');
}
/**
* Give the given user some permissions.
*/
@ -262,27 +192,6 @@ abstract class TestCase extends BaseTestCase
return $permissionRepo->saveNewRole($roleData);
}
/**
* Create a group of entities that belong to a specific user.
*
* @return array{book: Book, chapter: Chapter, page: Page}
*/
protected function createEntityChainBelongingToUser(User $creatorUser, ?User $updaterUser = null): array
{
if (empty($updaterUser)) {
$updaterUser = $creatorUser;
}
$userAttrs = ['created_by' => $creatorUser->id, 'owned_by' => $creatorUser->id, 'updated_by' => $updaterUser->id];
$book = Book::factory()->create($userAttrs);
$chapter = Chapter::factory()->create(array_merge(['book_id' => $book->id], $userAttrs));
$page = Page::factory()->create(array_merge(['book_id' => $book->id, 'chapter_id' => $chapter->id], $userAttrs));
$this->app->make(JointPermissionBuilder::class)->rebuildForEntity($book);
return compact('book', 'chapter', 'page');
}
/**
* Mock the HttpFetcher service and return the given data on fetch.
*/
@ -460,17 +369,4 @@ abstract class TestCase extends BaseTestCase
$this->assertDatabaseHas('activities', $detailsToCheck);
}
/**
* @return array{page: Page, chapter: Chapter, book: Book, bookshelf: Bookshelf}
*/
protected function getEachEntityType(): array
{
return [
'page' => Page::query()->first(),
'chapter' => Chapter::query()->first(),
'book' => Book::query()->first(),
'bookshelf' => Bookshelf::query()->first(),
];
}
}

View File

@ -342,7 +342,7 @@ class ImageTest extends TestCase
$this->get($expectedUrl)->assertOk();
$this->setEntityRestrictions($page, [], []);
$this->entities->setPermissions($page, [], []);
$resp = $this->get($expectedUrl);
$resp->assertNotFound();
@ -367,7 +367,7 @@ class ImageTest extends TestCase
$this->get($expectedUrl)->assertOk();
$this->setEntityRestrictions($page, [], []);
$this->entities->setPermissions($page, [], []);
$resp = $this->get($expectedUrl);
$resp->assertNotFound();
@ -400,7 +400,7 @@ class ImageTest extends TestCase
$export = $this->get($pageB->getUrl('/export/html'));
$this->assertStringContainsString($encodedImageContent, $export->getContent());
$this->setEntityRestrictions($pageA, [], []);
$this->entities->setPermissions($pageA, [], []);
$export = $this->get($pageB->getUrl('/export/html'));
$this->assertStringNotContainsString($encodedImageContent, $export->getContent());

View File

@ -29,7 +29,7 @@ class UserProfileTest extends TestCase
public function test_profile_page_shows_recent_entities()
{
$content = $this->createEntityChainBelongingToUser($this->user, $this->user);
$content = $this->entities->createChainBelongingToUser($this->user, $this->user);
$resp = $this->asAdmin()->get('/user/' . $this->user->slug);
// Check the recently created page is shown
@ -50,7 +50,7 @@ class UserProfileTest extends TestCase
->assertElementContains('#content-counts', '0 Chapters')
->assertElementContains('#content-counts', '0 Pages');
$this->createEntityChainBelongingToUser($newUser, $newUser);
$this->entities->createChainBelongingToUser($newUser, $newUser);
$resp = $this->asAdmin()->get('/user/' . $newUser->slug)
->assertSee($newUser->name);
@ -63,7 +63,7 @@ class UserProfileTest extends TestCase
{
$newUser = User::factory()->create();
$this->actingAs($newUser);
$entities = $this->createEntityChainBelongingToUser($newUser, $newUser);
$entities = $this->entities->createChainBelongingToUser($newUser, $newUser);
Activity::add(ActivityType::BOOK_UPDATE, $entities['book']);
Activity::add(ActivityType::PAGE_CREATE, $entities['page']);
@ -77,7 +77,7 @@ class UserProfileTest extends TestCase
{
$newUser = User::factory()->create();
$this->actingAs($newUser);
$entities = $this->createEntityChainBelongingToUser($newUser, $newUser);
$entities = $this->entities->createChainBelongingToUser($newUser, $newUser);
Activity::add(ActivityType::BOOK_UPDATE, $entities['book']);
Activity::add(ActivityType::PAGE_CREATE, $entities['page']);