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

View File

@ -210,7 +210,7 @@ class PagesApiTest extends TestCase
$this->actingAsApiEditor(); $this->actingAsApiEditor();
$page = Page::visible()->first(); $page = Page::visible()->first();
$chapter = Chapter::visible()->where('book_id', '!=', $page->book_id)->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 = [ $details = [
'name' => 'My updated API page', 'name' => 'My updated API page',
'chapter_id' => $chapter->id, 'chapter_id' => $chapter->id,

View File

@ -239,7 +239,7 @@ class UsersApiTest extends TestCase
$user = User::query()->where('id', '!=', $this->getAdmin()->id) $user = User::query()->where('id', '!=', $this->getAdmin()->id)
->whereNull('system_name') ->whereNull('system_name')
->first(); ->first();
$entityChain = $this->createEntityChainBelongingToUser($user); $entityChain = $this->entities->createChainBelongingToUser($user);
/** @var User $newOwner */ /** @var User $newOwner */
$newOwner = User::query()->where('id', '!=', $user->id)->first(); $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->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->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', [ $this->artisan('bookstack:copy-shelf-permissions', [
'--slug' => $shelf->slug, '--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->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->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') $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'); ->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(); $child = $shelf->books()->first();

View File

@ -45,7 +45,7 @@ class BookShelfTest extends TestCase
$resp = $this->actingAs($user)->get('/'); $resp = $this->actingAs($user)->get('/');
$this->withHtml($resp)->assertElementNotContains('header', 'Shelves'); $this->withHtml($resp)->assertElementNotContains('header', 'Shelves');
$this->setEntityRestrictions($shelf, ['view'], [$userRole]); $this->entities->setPermissions($shelf, ['view'], [$userRole]);
$resp = $this->get('/'); $resp = $this->get('/');
$this->withHtml($resp)->assertElementContains('header', 'Shelves'); $this->withHtml($resp)->assertElementContains('header', 'Shelves');
@ -69,7 +69,7 @@ class BookShelfTest extends TestCase
$resp->assertSee($book->name); $resp->assertSee($book->name);
$resp->assertSee($book->getUrl()); $resp->assertSee($book->getUrl());
$this->setEntityRestrictions($book, []); $this->entities->setPermissions($book, []);
$resp = $this->asEditor()->get('/shelves'); $resp = $this->asEditor()->get('/shelves');
$resp->assertDontSee($book->name); $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->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->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')); $resp = $this->post($shelf->getUrl('/copy-permissions'));
$child = $shelf->books()->first(); $child = $shelf->books()->first();

View File

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

View File

@ -14,7 +14,7 @@ class EntityAccessTest extends TestCase
// Create required assets and revisions // Create required assets and revisions
$creator = $this->getEditor(); $creator = $this->getEditor();
$updater = $this->getViewer(); $updater = $this->getViewer();
$entities = $this->createEntityChainBelongingToUser($creator, $updater); $entities = $this->entities->createChainBelongingToUser($creator, $updater);
app()->make(UserRepo::class)->destroy($creator); app()->make(UserRepo::class)->destroy($creator);
app()->make(PageRepo::class)->update($entities['page'], ['html' => '<p>hello!</p>>']); app()->make(PageRepo::class)->update($entities['page'], ['html' => '<p>hello!</p>>']);
@ -26,7 +26,7 @@ class EntityAccessTest extends TestCase
// Create required assets and revisions // Create required assets and revisions
$creator = $this->getViewer(); $creator = $this->getViewer();
$updater = $this->getEditor(); $updater = $this->getEditor();
$entities = $this->createEntityChainBelongingToUser($creator, $updater); $entities = $this->entities->createChainBelongingToUser($creator, $updater);
app()->make(UserRepo::class)->destroy($updater); app()->make(UserRepo::class)->destroy($updater);
app()->make(PageRepo::class)->update($entities['page'], ['html' => '<p>Hello there!</p>']); 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() 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(); $this->asEditor();
$accentSearch = $this->get('/search?term=' . urlencode('áéíí')); $accentSearch = $this->get('/search?term=' . urlencode('áéíí'));
@ -111,7 +111,7 @@ class EntitySearchTest extends TestCase
public function test_exact_searches() 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 = $this->asEditor()->get('/search?term=' . urlencode('"story about an orange"'));
$exactSearchA->assertStatus(200)->assertSee($page->name); $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() public function test_search_terms_with_delimiters_are_converted_to_exact_matches()
{ {
$this->asEditor(); $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`'); $terms = explode(' ', '1.1 2,2 3?3 4:4 5;5 (8) <9> "10" \'11\' `12`');
foreach ($terms as $term) { foreach ($terms as $term) {
@ -134,7 +134,7 @@ class EntitySearchTest extends TestCase
public function test_search_filters() 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(); $this->asEditor();
$editorId = $this->getEditor()->id; $editorId = $this->getEditor()->id;
$editorSlug = $this->getEditor()->slug; $editorSlug = $this->getEditor()->slug;
@ -197,7 +197,7 @@ class EntitySearchTest extends TestCase
public function test_ajax_entity_search() 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(); $notVisitedPage = Page::first();
// Visit the page to make popular // Visit the page to make popular
@ -334,15 +334,15 @@ class EntitySearchTest extends TestCase
public function test_search_ranks_common_words_lower() public function test_search_ranks_common_words_lower()
{ {
$this->newPage(['name' => 'Test page A', 'html' => '<p>dog biscuit dog dog</p>']); $this->entities->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 B', 'html' => '<p>cat biscuit</p>']);
$search = $this->asEditor()->get('/search?term=cat+dog+biscuit'); $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(1)', 'Test page A');
$this->withHtml($search)->assertElementContains('.entity-list > .page:nth-child(2)', 'Test page B'); $this->withHtml($search)->assertElementContains('.entity-list > .page:nth-child(2)', 'Test page B');
for ($i = 0; $i < 2; $i++) { 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'); $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() 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> <p>TermA</p>
<h1>TermB <strong>TermNested</strong></h1> <h1>TermB <strong>TermNested</strong></h1>
<h2>TermC</h2> <h2>TermC</h2>
@ -377,7 +377,7 @@ class EntitySearchTest extends TestCase
public function test_name_and_content_terms_are_merged_to_single_score() 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> <p>TermA</p>
']); ']);
@ -389,7 +389,7 @@ class EntitySearchTest extends TestCase
public function test_tag_names_and_values_are_indexed_for_search() 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' => 'Animal', 'value' => 'MeowieCat'],
['name' => 'SuperImportant'], ['name' => 'SuperImportant'],
]]); ]]);
@ -402,7 +402,7 @@ class EntitySearchTest extends TestCase
public function test_matching_terms_in_search_results_are_highlighted() 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' => 'Animal', 'value' => 'MeowieCat'],
['name' => 'SuperImportant'], ['name' => 'SuperImportant'],
]]); ]]);
@ -420,7 +420,7 @@ class EntitySearchTest extends TestCase
public function test_match_highlighting_works_with_multibyte_content() public function test_match_highlighting_works_with_multibyte_content()
{ {
$this->newPage([ $this->entities->newPage([
'name' => 'Test Page', 'name' => 'Test Page',
'html' => '<p>На мен ми трябва нещо добро test</p>', '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() 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 = $this->asEditor()->get('/search?term=TestPageContent');
$search->assertSee('My &lt;cool&gt; <strong>TestPageContent</strong>', false); $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() 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> <p>TermA<br>TermB<br>TermC</p>
']); ']);

View File

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

View File

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

View File

@ -188,7 +188,7 @@ class TagTest extends TestCase
$resp->assertSee('GreatTestContent'); $resp->assertSee('GreatTestContent');
$page->restricted = true; $page->restricted = true;
$this->regenEntityPermissions($page); $this->entities->regenPermissions($page);
$resp = $this->asEditor()->get('/tags'); $resp = $this->asEditor()->get('/tags');
$resp->assertDontSee('SuperCategory'); $resp->assertDontSee('SuperCategory');
@ -207,7 +207,7 @@ class TagTest extends TestCase
{ {
$this->asEditor(); $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']); $entity->tags()->create(['name' => 'My Super Tag Name', 'value' => 'An-awesome-value']);
$html = $this->withHtml($this->get($entity->getUrl())); $html = $this->withHtml($this->get($entity->getUrl()));
$html->assertElementExists('body.tag-name-mysupertagname.tag-value-anawesomevalue.tag-pair-mysupertagname-anawesomevalue'); $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(); $this->asEditor();
$name = 'My custom homepage'; $name = 'My custom homepage';
$content = str_repeat('This is the body content of my custom homepage.', 20); $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' => $customPage->id]);
$this->setSettings(['app-homepage-type' => 'page']); $this->setSettings(['app-homepage-type' => 'page']);
@ -41,7 +41,7 @@ class HomepageTest extends TestCase
$this->asEditor(); $this->asEditor();
$name = 'My custom homepage'; $name = 'My custom homepage';
$content = str_repeat('This is the body content of my custom homepage.', 20); $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([ $this->setSettings([
'app-homepage' => $customPage->id, 'app-homepage' => $customPage->id,
'app-homepage-type' => 'page', 'app-homepage-type' => 'page',
@ -67,7 +67,7 @@ class HomepageTest extends TestCase
$this->asEditor(); $this->asEditor();
$name = 'My custom homepage'; $name = 'My custom homepage';
$content = str_repeat('This is the body content of my custom homepage.', 20); $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([ $this->setSettings([
'app-homepage' => $customPage->id, 'app-homepage' => $customPage->id,
'app-homepage-type' => 'default', 'app-homepage-type' => 'default',
@ -107,7 +107,7 @@ class HomepageTest extends TestCase
$included->save(); $included->save();
$name = 'My custom homepage'; $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' => $customPage->id]);
$this->setSettings(['app-homepage-type' => 'page']); $this->setSettings(['app-homepage-type' => 'page']);
@ -177,7 +177,7 @@ class HomepageTest extends TestCase
$this->withHtml($homeVisit)->assertElementNotContains('.content-wrap', $book->name); $this->withHtml($homeVisit)->assertElementNotContains('.content-wrap', $book->name);
// Ensure is visible again with entity-level view permission // 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('/'); $homeVisit = $this->get('/');
$this->withHtml($homeVisit)->assertElementContains('.content-wrap', $shelf->name); $this->withHtml($homeVisit)->assertElementContains('.content-wrap', $shelf->name);
$this->withHtml($homeVisit)->assertElementContains('.content-wrap', $book->name); $this->withHtml($homeVisit)->assertElementContains('.content-wrap', $book->name);

View File

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

View File

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

View File

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

View File

@ -177,7 +177,7 @@ class PublicActionTest extends TestCase
$this->setSettings(['app-public' => 'true']); $this->setSettings(['app-public' => 'true']);
/** @var Book $book */ /** @var Book $book */
$book = Book::query()->first(); $book = Book::query()->first();
$this->setEntityRestrictions($book); $this->entities->setPermissions($book);
$resp = $this->get($book->getUrl()); $resp = $this->get($book->getUrl());
$resp->assertSee('Book not found'); $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() 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(); $otherPage = Page::query()->where('id', '!=', $entities['page']->id)->first();
$html = ' $html = '

View File

@ -57,7 +57,7 @@ class ReferencesTest extends TestCase
public function test_references_to_count_visible_on_entity_show_view() public function test_references_to_count_visible_on_entity_show_view()
{ {
$entities = $this->getEachEntityType(); $entities = $this->entities->all();
/** @var Page $otherPage */ /** @var Page $otherPage */
$otherPage = Page::query()->where('id', '!=', $entities['page']->id)->first(); $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() public function test_references_to_visible_on_references_page()
{ {
$entities = $this->getEachEntityType(); $entities = $this->entities->all();
$this->asEditor(); $this->asEditor();
foreach ($entities as $entity) { foreach ($entities as $entity) {
$this->createReference($entities['page'], $entity); $this->createReference($entities['page'], $entity);
@ -101,7 +101,7 @@ class ReferencesTest extends TestCase
$pageB = Page::query()->where('id', '!=', $page->id)->first(); $pageB = Page::query()->where('id', '!=', $page->id)->first();
$this->createReference($pageB, $page); $this->createReference($pageB, $page);
$this->setEntityRestrictions($pageB); $this->entities->setPermissions($pageB);
$this->asEditor()->get($page->getUrl('/references'))->assertDontSee($pageB->name); $this->asEditor()->get($page->getUrl('/references'))->assertDontSee($pageB->name);
$this->asAdmin()->get($page->getUrl('/references'))->assertSee($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\Permissions\RolePermission;
use BookStack\Auth\Role; use BookStack\Auth\Role;
use BookStack\Auth\User; 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\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\Settings\SettingService;
use BookStack\Uploads\HttpFetcher; use BookStack\Uploads\HttpFetcher;
use GuzzleHttp\Client; use GuzzleHttp\Client;
@ -34,6 +26,7 @@ use Monolog\Handler\TestHandler;
use Monolog\Logger; use Monolog\Logger;
use Psr\Http\Client\ClientInterface; use Psr\Http\Client\ClientInterface;
use Ssddanbrown\AssertHtml\TestsHtml; use Ssddanbrown\AssertHtml\TestsHtml;
use Tests\Helpers\EntityProvider;
abstract class TestCase extends BaseTestCase abstract class TestCase extends BaseTestCase
{ {
@ -43,6 +36,13 @@ abstract class TestCase extends BaseTestCase
protected ?User $admin = null; protected ?User $admin = null;
protected ?User $editor = 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. * 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(); 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. * 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. * Give the given user some permissions.
*/ */
@ -262,27 +192,6 @@ abstract class TestCase extends BaseTestCase
return $permissionRepo->saveNewRole($roleData); 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. * Mock the HttpFetcher service and return the given data on fetch.
*/ */
@ -460,17 +369,4 @@ abstract class TestCase extends BaseTestCase
$this->assertDatabaseHas('activities', $detailsToCheck); $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->get($expectedUrl)->assertOk();
$this->setEntityRestrictions($page, [], []); $this->entities->setPermissions($page, [], []);
$resp = $this->get($expectedUrl); $resp = $this->get($expectedUrl);
$resp->assertNotFound(); $resp->assertNotFound();
@ -367,7 +367,7 @@ class ImageTest extends TestCase
$this->get($expectedUrl)->assertOk(); $this->get($expectedUrl)->assertOk();
$this->setEntityRestrictions($page, [], []); $this->entities->setPermissions($page, [], []);
$resp = $this->get($expectedUrl); $resp = $this->get($expectedUrl);
$resp->assertNotFound(); $resp->assertNotFound();
@ -400,7 +400,7 @@ class ImageTest extends TestCase
$export = $this->get($pageB->getUrl('/export/html')); $export = $this->get($pageB->getUrl('/export/html'));
$this->assertStringContainsString($encodedImageContent, $export->getContent()); $this->assertStringContainsString($encodedImageContent, $export->getContent());
$this->setEntityRestrictions($pageA, [], []); $this->entities->setPermissions($pageA, [], []);
$export = $this->get($pageB->getUrl('/export/html')); $export = $this->get($pageB->getUrl('/export/html'));
$this->assertStringNotContainsString($encodedImageContent, $export->getContent()); $this->assertStringNotContainsString($encodedImageContent, $export->getContent());

View File

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