From 85f330c79a14d0393af46d5ccb1105b822950d91 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 13 Oct 2018 11:27:55 +0100 Subject: [PATCH] Extracted many page-specific repo methods into page-specific repo --- app/Auth/UserRepo.php | 2 +- app/Entities/ExportService.php | 1 + app/Entities/{ => Repos}/EntityRepo.php | 499 +---------------- app/Entities/Repos/PageRepo.php | 508 ++++++++++++++++++ app/Http/Controllers/AttachmentController.php | 2 +- app/Http/Controllers/BookController.php | 2 +- app/Http/Controllers/BookshelfController.php | 4 +- app/Http/Controllers/ChapterController.php | 2 +- app/Http/Controllers/CommentController.php | 4 +- app/Http/Controllers/HomeController.php | 2 +- app/Http/Controllers/ImageController.php | 4 +- app/Http/Controllers/PageController.php | 136 ++--- app/Http/Controllers/SearchController.php | 4 +- tests/CommandsTest.php | 9 +- tests/Entity/EntityTest.php | 7 +- tests/Entity/PageContentTest.php | 13 +- tests/Entity/PageDraftTest.php | 14 +- tests/Entity/SortTest.php | 7 +- tests/ImageTest.php | 9 +- tests/Permissions/RestrictionsTest.php | 2 +- tests/SharedTestHelpers.php | 17 +- 21 files changed, 642 insertions(+), 606 deletions(-) rename app/Entities/{ => Repos}/EntityRepo.php (60%) create mode 100644 app/Entities/Repos/PageRepo.php diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index c1fd9df2c..7c88badb8 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -1,7 +1,7 @@ entityProvider->pageRevision->where('slug', '=', $pageSlug) - ->whereHas('page', function ($query) { - $this->permissionService->enforceEntityRestrictions('page', $query); - }) - ->where('type', '=', 'version') - ->where('book_slug', '=', $bookSlug) - ->orderBy('created_at', 'desc') - ->with('page')->first(); - return $revision !== null ? $revision->page : null; - } - /** * Get all entities of a type with the given permission, limited by count unless count is false. * @param string $type @@ -613,191 +598,6 @@ class EntityRepo return $slug; } - /** - * Get a new draft page instance. - * @param Book $book - * @param Chapter|bool $chapter - * @return \BookStack\Entities\Page - */ - public function getDraftPage(Book $book, $chapter = false) - { - $page = $this->entityProvider->page->newInstance(); - $page->name = trans('entities.pages_initial_name'); - $page->created_by = user()->id; - $page->updated_by = user()->id; - $page->draft = true; - - if ($chapter) { - $page->chapter_id = $chapter->id; - } - - $book->pages()->save($page); - $page = $this->entityProvider->page->find($page->id); - $this->permissionService->buildJointPermissionsForEntity($page); - return $page; - } - - /** - * Publish a draft page to make it a normal page. - * Sets the slug and updates the content. - * @param Page $draftPage - * @param array $input - * @return Page - */ - public function publishPageDraft(Page $draftPage, array $input) - { - $draftPage->fill($input); - - // Save page tags if present - if (isset($input['tags'])) { - $this->tagRepo->saveTagsToEntity($draftPage, $input['tags']); - } - - $draftPage->slug = $this->findSuitableSlug('page', $draftPage->name, false, $draftPage->book->id); - $draftPage->html = $this->formatHtml($input['html']); - $draftPage->text = $this->pageToPlainText($draftPage); - $draftPage->draft = false; - $draftPage->revision_count = 1; - - $draftPage->save(); - $this->savePageRevision($draftPage, trans('entities.pages_initial_revision')); - $this->searchService->indexEntity($draftPage); - return $draftPage; - } - - /** - * Create a copy of a page in a new location with a new name. - * @param \BookStack\Entities\Page $page - * @param \BookStack\Entities\Entity $newParent - * @param string $newName - * @return \BookStack\Entities\Page - */ - public function copyPage(Page $page, Entity $newParent, $newName = '') - { - $newBook = $newParent->isA('book') ? $newParent : $newParent->book; - $newChapter = $newParent->isA('chapter') ? $newParent : null; - $copyPage = $this->getDraftPage($newBook, $newChapter); - $pageData = $page->getAttributes(); - - // Update name - if (!empty($newName)) { - $pageData['name'] = $newName; - } - - // Copy tags from previous page if set - if ($page->tags) { - $pageData['tags'] = []; - foreach ($page->tags as $tag) { - $pageData['tags'][] = ['name' => $tag->name, 'value' => $tag->value]; - } - } - - // Set priority - if ($newParent->isA('chapter')) { - $pageData['priority'] = $this->getNewChapterPriority($newParent); - } else { - $pageData['priority'] = $this->getNewBookPriority($newParent); - } - - return $this->publishPageDraft($copyPage, $pageData); - } - - /** - * Saves a page revision into the system. - * @param Page $page - * @param null|string $summary - * @return \BookStack\Entities\PageRevision - */ - public function savePageRevision(Page $page, $summary = null) - { - $revision = $this->entityProvider->pageRevision->newInstance($page->toArray()); - if (setting('app-editor') !== 'markdown') { - $revision->markdown = ''; - } - $revision->page_id = $page->id; - $revision->slug = $page->slug; - $revision->book_slug = $page->book->slug; - $revision->created_by = user()->id; - $revision->created_at = $page->updated_at; - $revision->type = 'version'; - $revision->summary = $summary; - $revision->revision_number = $page->revision_count; - $revision->save(); - - $revisionLimit = config('app.revision_limit'); - if ($revisionLimit !== false) { - $revisionsToDelete = $this->entityProvider->pageRevision->where('page_id', '=', $page->id) - ->orderBy('created_at', 'desc')->skip(intval($revisionLimit))->take(10)->get(['id']); - if ($revisionsToDelete->count() > 0) { - $this->entityProvider->pageRevision->whereIn('id', $revisionsToDelete->pluck('id'))->delete(); - } - } - - return $revision; - } - - /** - * Formats a page's html to be tagged correctly - * within the system. - * @param string $htmlText - * @return string - */ - protected function formatHtml($htmlText) - { - if ($htmlText == '') { - return $htmlText; - } - libxml_use_internal_errors(true); - $doc = new DOMDocument(); - $doc->loadHTML(mb_convert_encoding($htmlText, 'HTML-ENTITIES', 'UTF-8')); - - $container = $doc->documentElement; - $body = $container->childNodes->item(0); - $childNodes = $body->childNodes; - - // Ensure no duplicate ids are used - $idArray = []; - - foreach ($childNodes as $index => $childNode) { - /** @var \DOMElement $childNode */ - if (get_class($childNode) !== 'DOMElement') { - continue; - } - - // Overwrite id if not a BookStack custom id - if ($childNode->hasAttribute('id')) { - $id = $childNode->getAttribute('id'); - if (strpos($id, 'bkmrk') === 0 && array_search($id, $idArray) === false) { - $idArray[] = $id; - continue; - }; - } - - // Create an unique id for the element - // Uses the content as a basis to ensure output is the same every time - // the same content is passed through. - $contentId = 'bkmrk-' . substr(strtolower(preg_replace('/\s+/', '-', trim($childNode->nodeValue))), 0, 20); - $newId = urlencode($contentId); - $loopIndex = 0; - while (in_array($newId, $idArray)) { - $newId = urlencode($contentId . '-' . $loopIndex); - $loopIndex++; - } - - $childNode->setAttribute('id', $newId); - $idArray[] = $newId; - } - - // Generate inner html as a string - $html = ''; - foreach ($childNodes as $childNode) { - $html .= $doc->saveHTML($childNode); - } - - return $html; - } - - /** * Render the page for viewing, Parsing and performing features such as page transclusion. * @param Page $page @@ -878,17 +678,6 @@ class EntityRepo return $html; } - /** - * Get the plain text version of a page's content. - * @param \BookStack\Entities\Page $page - * @return string - */ - public function pageToPlainText(Page $page) - { - $html = $this->renderPage($page); - return strip_tags($html); - } - /** * Search for image usage within page content. * @param $imageString @@ -905,278 +694,6 @@ class EntityRepo return count($pages) > 0 ? $pages : false; } - /** - * Parse the headers on the page to get a navigation menu - * @param String $pageContent - * @return array - */ - public function getPageNav($pageContent) - { - if ($pageContent == '') { - return []; - } - libxml_use_internal_errors(true); - $doc = new DOMDocument(); - $doc->loadHTML(mb_convert_encoding($pageContent, 'HTML-ENTITIES', 'UTF-8')); - $xPath = new DOMXPath($doc); - $headers = $xPath->query("//h1|//h2|//h3|//h4|//h5|//h6"); - - if (is_null($headers)) { - return []; - } - - $tree = collect([]); - foreach ($headers as $header) { - $text = $header->nodeValue; - $tree->push([ - 'nodeName' => strtolower($header->nodeName), - 'level' => intval(str_replace('h', '', $header->nodeName)), - 'link' => '#' . $header->getAttribute('id'), - 'text' => strlen($text) > 30 ? substr($text, 0, 27) . '...' : $text - ]); - } - - // Normalise headers if only smaller headers have been used - if (count($tree) > 0) { - $minLevel = $tree->pluck('level')->min(); - $tree = $tree->map(function ($header) use ($minLevel) { - $header['level'] -= ($minLevel - 2); - return $header; - }); - } - return $tree->toArray(); - } - - /** - * Updates a page with any fillable data and saves it into the database. - * @param \BookStack\Entities\Page $page - * @param int $book_id - * @param array $input - * @return \BookStack\Entities\Page - */ - public function updatePage(Page $page, $book_id, $input) - { - // Hold the old details to compare later - $oldHtml = $page->html; - $oldName = $page->name; - - // Prevent slug being updated if no name change - if ($page->name !== $input['name']) { - $page->slug = $this->findSuitableSlug('page', $input['name'], $page->id, $book_id); - } - - // Save page tags if present - if (isset($input['tags'])) { - $this->tagRepo->saveTagsToEntity($page, $input['tags']); - } - - // Update with new details - $userId = user()->id; - $page->fill($input); - $page->html = $this->formatHtml($input['html']); - $page->text = $this->pageToPlainText($page); - if (setting('app-editor') !== 'markdown') { - $page->markdown = ''; - } - $page->updated_by = $userId; - $page->revision_count++; - $page->save(); - - // Remove all update drafts for this user & page. - $this->userUpdatePageDraftsQuery($page, $userId)->delete(); - - // Save a revision after updating - if ($oldHtml !== $input['html'] || $oldName !== $input['name'] || $input['summary'] !== null) { - $this->savePageRevision($page, $input['summary']); - } - - $this->searchService->indexEntity($page); - - return $page; - } - - /** - * The base query for getting user update drafts. - * @param \BookStack\Entities\Page $page - * @param $userId - * @return mixed - */ - protected function userUpdatePageDraftsQuery(Page $page, $userId) - { - return $this->entityProvider->pageRevision->where('created_by', '=', $userId) - ->where('type', 'update_draft') - ->where('page_id', '=', $page->id) - ->orderBy('created_at', 'desc'); - } - - /** - * Checks whether a user has a draft version of a particular page or not. - * @param \BookStack\Entities\Page $page - * @param $userId - * @return bool - */ - public function hasUserGotPageDraft(Page $page, $userId) - { - return $this->userUpdatePageDraftsQuery($page, $userId)->count() > 0; - } - - /** - * Get the latest updated draft revision for a particular page and user. - * @param Page $page - * @param $userId - * @return mixed - */ - public function getUserPageDraft(Page $page, $userId) - { - return $this->userUpdatePageDraftsQuery($page, $userId)->first(); - } - - /** - * Get the notification message that informs the user that they are editing a draft page. - * @param PageRevision $draft - * @return string - */ - public function getUserPageDraftMessage(PageRevision $draft) - { - $message = trans('entities.pages_editing_draft_notification', ['timeDiff' => $draft->updated_at->diffForHumans()]); - if ($draft->page->updated_at->timestamp <= $draft->updated_at->timestamp) { - return $message; - } - return $message . "\n" . trans('entities.pages_draft_edited_notification'); - } - - /** - * Check if a page is being actively editing. - * Checks for edits since last page updated. - * Passing in a minuted range will check for edits - * within the last x minutes. - * @param \BookStack\Entities\Page $page - * @param null $minRange - * @return bool - */ - public function isPageEditingActive(Page $page, $minRange = null) - { - $draftSearch = $this->activePageEditingQuery($page, $minRange); - return $draftSearch->count() > 0; - } - - /** - * A query to check for active update drafts on a particular page. - * @param Page $page - * @param null $minRange - * @return mixed - */ - protected function activePageEditingQuery(Page $page, $minRange = null) - { - $query = $this->entityProvider->pageRevision->where('type', '=', 'update_draft') - ->where('page_id', '=', $page->id) - ->where('updated_at', '>', $page->updated_at) - ->where('created_by', '!=', user()->id) - ->with('createdBy'); - - if ($minRange !== null) { - $query = $query->where('updated_at', '>=', Carbon::now()->subMinutes($minRange)); - } - - return $query; - } - - /** - * Restores a revision's content back into a page. - * @param Page $page - * @param Book $book - * @param int $revisionId - * @return \BookStack\Entities\Page - */ - public function restorePageRevision(Page $page, Book $book, $revisionId) - { - $page->revision_count++; - $this->savePageRevision($page); - $revision = $page->revisions()->where('id', '=', $revisionId)->first(); - $page->fill($revision->toArray()); - $page->slug = $this->findSuitableSlug('page', $page->name, $page->id, $book->id); - $page->text = $this->pageToPlainText($page); - $page->updated_by = user()->id; - $page->save(); - $this->searchService->indexEntity($page); - return $page; - } - - - /** - * Save a page update draft. - * @param Page $page - * @param array $data - * @return PageRevision|Page - */ - public function updatePageDraft(Page $page, $data = []) - { - // If the page itself is a draft simply update that - if ($page->draft) { - $page->fill($data); - if (isset($data['html'])) { - $page->text = $this->pageToPlainText($page); - } - $page->save(); - return $page; - } - - // Otherwise save the data to a revision - $userId = user()->id; - $drafts = $this->userUpdatePageDraftsQuery($page, $userId)->get(); - - if ($drafts->count() > 0) { - $draft = $drafts->first(); - } else { - $draft = $this->entityProvider->pageRevision->newInstance(); - $draft->page_id = $page->id; - $draft->slug = $page->slug; - $draft->book_slug = $page->book->slug; - $draft->created_by = $userId; - $draft->type = 'update_draft'; - } - - $draft->fill($data); - if (setting('app-editor') !== 'markdown') { - $draft->markdown = ''; - } - - $draft->save(); - return $draft; - } - - /** - * Get a notification message concerning the editing activity on a particular page. - * @param Page $page - * @param null $minRange - * @return string - */ - public function getPageEditingActiveMessage(Page $page, $minRange = null) - { - $pageDraftEdits = $this->activePageEditingQuery($page, $minRange)->get(); - - $userMessage = $pageDraftEdits->count() > 1 ? trans('entities.pages_draft_edit_active.start_a', ['count' => $pageDraftEdits->count()]): trans('entities.pages_draft_edit_active.start_b', ['userName' => $pageDraftEdits->first()->createdBy->name]); - $timeMessage = $minRange === null ? trans('entities.pages_draft_edit_active.time_a') : trans('entities.pages_draft_edit_active.time_b', ['minCount'=>$minRange]); - return trans('entities.pages_draft_edit_active.message', ['start' => $userMessage, 'time' => $timeMessage]); - } - - /** - * Change the page's parent to the given entity. - * @param \BookStack\Entities\Page $page - * @param \BookStack\Entities\Entity $parent - */ - public function changePageParent(Page $page, Entity $parent) - { - $book = $parent->isA('book') ? $parent : $parent->book; - $page->chapter_id = $parent->isA('chapter') ? $parent->id : 0; - $page->save(); - if ($page->book->id !== $book->id) { - $page = $this->changeBook('page', $book->id, $page); - } - $page->load('book'); - $this->permissionService->buildJointPermissionsForEntity($book); - } - /** * Destroy a bookshelf instance * @param \BookStack\Entities\Bookshelf $shelf diff --git a/app/Entities/Repos/PageRepo.php b/app/Entities/Repos/PageRepo.php new file mode 100644 index 000000000..d9f9c2720 --- /dev/null +++ b/app/Entities/Repos/PageRepo.php @@ -0,0 +1,508 @@ +getBySlug('page', $pageSlug, $bookSlug); + } + + /** + * Search through page revisions and retrieve the last page in the + * current book that has a slug equal to the one given. + * @param string $pageSlug + * @param string $bookSlug + * @return null|Page + */ + public function getPageByOldSlug(string $pageSlug, string $bookSlug) + { + $revision = $this->entityProvider->pageRevision->where('slug', '=', $pageSlug) + ->whereHas('page', function ($query) { + $this->permissionService->enforceEntityRestrictions('page', $query); + }) + ->where('type', '=', 'version') + ->where('book_slug', '=', $bookSlug) + ->orderBy('created_at', 'desc') + ->with('page')->first(); + return $revision !== null ? $revision->page : null; + } + + /** + * Updates a page with any fillable data and saves it into the database. + * @param Page $page + * @param int $book_id + * @param array $input + * @return Page + * @throws \Exception + */ + public function updatePage(Page $page, int $book_id, array $input) + { + // Hold the old details to compare later + $oldHtml = $page->html; + $oldName = $page->name; + + // Prevent slug being updated if no name change + if ($page->name !== $input['name']) { + $page->slug = $this->findSuitableSlug('page', $input['name'], $page->id, $book_id); + } + + // Save page tags if present + if (isset($input['tags'])) { + $this->tagRepo->saveTagsToEntity($page, $input['tags']); + } + + // Update with new details + $userId = user()->id; + $page->fill($input); + $page->html = $this->formatHtml($input['html']); + $page->text = $this->pageToPlainText($page); + if (setting('app-editor') !== 'markdown') { + $page->markdown = ''; + } + $page->updated_by = $userId; + $page->revision_count++; + $page->save(); + + // Remove all update drafts for this user & page. + $this->userUpdatePageDraftsQuery($page, $userId)->delete(); + + // Save a revision after updating + if ($oldHtml !== $input['html'] || $oldName !== $input['name'] || $input['summary'] !== null) { + $this->savePageRevision($page, $input['summary']); + } + + $this->searchService->indexEntity($page); + + return $page; + } + + /** + * Saves a page revision into the system. + * @param Page $page + * @param null|string $summary + * @return PageRevision + * @throws \Exception + */ + public function savePageRevision(Page $page, string $summary = null) + { + $revision = $this->entityProvider->pageRevision->newInstance($page->toArray()); + if (setting('app-editor') !== 'markdown') { + $revision->markdown = ''; + } + $revision->page_id = $page->id; + $revision->slug = $page->slug; + $revision->book_slug = $page->book->slug; + $revision->created_by = user()->id; + $revision->created_at = $page->updated_at; + $revision->type = 'version'; + $revision->summary = $summary; + $revision->revision_number = $page->revision_count; + $revision->save(); + + $revisionLimit = config('app.revision_limit'); + if ($revisionLimit !== false) { + $revisionsToDelete = $this->entityProvider->pageRevision->where('page_id', '=', $page->id) + ->orderBy('created_at', 'desc')->skip(intval($revisionLimit))->take(10)->get(['id']); + if ($revisionsToDelete->count() > 0) { + $this->entityProvider->pageRevision->whereIn('id', $revisionsToDelete->pluck('id'))->delete(); + } + } + + return $revision; + } + + /** + * Formats a page's html to be tagged correctly + * within the system. + * @param string $htmlText + * @return string + */ + protected function formatHtml(string $htmlText) + { + if ($htmlText == '') { + return $htmlText; + } + libxml_use_internal_errors(true); + $doc = new DOMDocument(); + $doc->loadHTML(mb_convert_encoding($htmlText, 'HTML-ENTITIES', 'UTF-8')); + + $container = $doc->documentElement; + $body = $container->childNodes->item(0); + $childNodes = $body->childNodes; + + // Ensure no duplicate ids are used + $idArray = []; + + foreach ($childNodes as $index => $childNode) { + /** @var \DOMElement $childNode */ + if (get_class($childNode) !== 'DOMElement') { + continue; + } + + // Overwrite id if not a BookStack custom id + if ($childNode->hasAttribute('id')) { + $id = $childNode->getAttribute('id'); + if (strpos($id, 'bkmrk') === 0 && array_search($id, $idArray) === false) { + $idArray[] = $id; + continue; + }; + } + + // Create an unique id for the element + // Uses the content as a basis to ensure output is the same every time + // the same content is passed through. + $contentId = 'bkmrk-' . substr(strtolower(preg_replace('/\s+/', '-', trim($childNode->nodeValue))), 0, 20); + $newId = urlencode($contentId); + $loopIndex = 0; + while (in_array($newId, $idArray)) { + $newId = urlencode($contentId . '-' . $loopIndex); + $loopIndex++; + } + + $childNode->setAttribute('id', $newId); + $idArray[] = $newId; + } + + // Generate inner html as a string + $html = ''; + foreach ($childNodes as $childNode) { + $html .= $doc->saveHTML($childNode); + } + + return $html; + } + + /** + * Get the plain text version of a page's content. + * @param \BookStack\Entities\Page $page + * @return string + */ + public function pageToPlainText(Page $page) + { + $html = $this->renderPage($page); + return strip_tags($html); + } + + /** + * Get a new draft page instance. + * @param Book $book + * @param Chapter|null $chapter + * @return \BookStack\Entities\Page + * @throws \Throwable + */ + public function getDraftPage(Book $book, Chapter $chapter = null) + { + $page = $this->entityProvider->page->newInstance(); + $page->name = trans('entities.pages_initial_name'); + $page->created_by = user()->id; + $page->updated_by = user()->id; + $page->draft = true; + + if ($chapter) { + $page->chapter_id = $chapter->id; + } + + $book->pages()->save($page); + $page = $this->entityProvider->page->find($page->id); + $this->permissionService->buildJointPermissionsForEntity($page); + return $page; + } + + /** + * Save a page update draft. + * @param Page $page + * @param array $data + * @return PageRevision|Page + */ + public function updatePageDraft(Page $page, array $data = []) + { + // If the page itself is a draft simply update that + if ($page->draft) { + $page->fill($data); + if (isset($data['html'])) { + $page->text = $this->pageToPlainText($page); + } + $page->save(); + return $page; + } + + // Otherwise save the data to a revision + $userId = user()->id; + $drafts = $this->userUpdatePageDraftsQuery($page, $userId)->get(); + + if ($drafts->count() > 0) { + $draft = $drafts->first(); + } else { + $draft = $this->entityProvider->pageRevision->newInstance(); + $draft->page_id = $page->id; + $draft->slug = $page->slug; + $draft->book_slug = $page->book->slug; + $draft->created_by = $userId; + $draft->type = 'update_draft'; + } + + $draft->fill($data); + if (setting('app-editor') !== 'markdown') { + $draft->markdown = ''; + } + + $draft->save(); + return $draft; + } + + /** + * Publish a draft page to make it a normal page. + * Sets the slug and updates the content. + * @param Page $draftPage + * @param array $input + * @return Page + * @throws \Exception + */ + public function publishPageDraft(Page $draftPage, array $input) + { + $draftPage->fill($input); + + // Save page tags if present + if (isset($input['tags'])) { + $this->tagRepo->saveTagsToEntity($draftPage, $input['tags']); + } + + $draftPage->slug = $this->findSuitableSlug('page', $draftPage->name, false, $draftPage->book->id); + $draftPage->html = $this->formatHtml($input['html']); + $draftPage->text = $this->pageToPlainText($draftPage); + $draftPage->draft = false; + $draftPage->revision_count = 1; + + $draftPage->save(); + $this->savePageRevision($draftPage, trans('entities.pages_initial_revision')); + $this->searchService->indexEntity($draftPage); + return $draftPage; + } + + /** + * The base query for getting user update drafts. + * @param Page $page + * @param $userId + * @return mixed + */ + protected function userUpdatePageDraftsQuery(Page $page, int $userId) + { + return $this->entityProvider->pageRevision->where('created_by', '=', $userId) + ->where('type', 'update_draft') + ->where('page_id', '=', $page->id) + ->orderBy('created_at', 'desc'); + } + + /** + * Get the latest updated draft revision for a particular page and user. + * @param Page $page + * @param $userId + * @return PageRevision|null + */ + public function getUserPageDraft(Page $page, int $userId) + { + return $this->userUpdatePageDraftsQuery($page, $userId)->first(); + } + + /** + * Get the notification message that informs the user that they are editing a draft page. + * @param PageRevision $draft + * @return string + */ + public function getUserPageDraftMessage(PageRevision $draft) + { + $message = trans('entities.pages_editing_draft_notification', ['timeDiff' => $draft->updated_at->diffForHumans()]); + if ($draft->page->updated_at->timestamp <= $draft->updated_at->timestamp) { + return $message; + } + return $message . "\n" . trans('entities.pages_draft_edited_notification'); + } + + /** + * A query to check for active update drafts on a particular page. + * @param Page $page + * @param int $minRange + * @return mixed + */ + protected function activePageEditingQuery(Page $page, int $minRange = null) + { + $query = $this->entityProvider->pageRevision->where('type', '=', 'update_draft') + ->where('page_id', '=', $page->id) + ->where('updated_at', '>', $page->updated_at) + ->where('created_by', '!=', user()->id) + ->with('createdBy'); + + if ($minRange !== null) { + $query = $query->where('updated_at', '>=', Carbon::now()->subMinutes($minRange)); + } + + return $query; + } + + /** + * Check if a page is being actively editing. + * Checks for edits since last page updated. + * Passing in a minuted range will check for edits + * within the last x minutes. + * @param Page $page + * @param int $minRange + * @return bool + */ + public function isPageEditingActive(Page $page, int $minRange = null) + { + $draftSearch = $this->activePageEditingQuery($page, $minRange); + return $draftSearch->count() > 0; + } + + /** + * Get a notification message concerning the editing activity on a particular page. + * @param Page $page + * @param int $minRange + * @return string + */ + public function getPageEditingActiveMessage(Page $page, int $minRange = null) + { + $pageDraftEdits = $this->activePageEditingQuery($page, $minRange)->get(); + + $userMessage = $pageDraftEdits->count() > 1 ? trans('entities.pages_draft_edit_active.start_a', ['count' => $pageDraftEdits->count()]): trans('entities.pages_draft_edit_active.start_b', ['userName' => $pageDraftEdits->first()->createdBy->name]); + $timeMessage = $minRange === null ? trans('entities.pages_draft_edit_active.time_a') : trans('entities.pages_draft_edit_active.time_b', ['minCount'=>$minRange]); + return trans('entities.pages_draft_edit_active.message', ['start' => $userMessage, 'time' => $timeMessage]); + } + + /** + * Parse the headers on the page to get a navigation menu + * @param string $pageContent + * @return array + */ + public function getPageNav(string $pageContent) + { + if ($pageContent == '') { + return []; + } + libxml_use_internal_errors(true); + $doc = new DOMDocument(); + $doc->loadHTML(mb_convert_encoding($pageContent, 'HTML-ENTITIES', 'UTF-8')); + $xPath = new DOMXPath($doc); + $headers = $xPath->query("//h1|//h2|//h3|//h4|//h5|//h6"); + + if (is_null($headers)) { + return []; + } + + $tree = collect([]); + foreach ($headers as $header) { + $text = $header->nodeValue; + $tree->push([ + 'nodeName' => strtolower($header->nodeName), + 'level' => intval(str_replace('h', '', $header->nodeName)), + 'link' => '#' . $header->getAttribute('id'), + 'text' => strlen($text) > 30 ? substr($text, 0, 27) . '...' : $text + ]); + } + + // Normalise headers if only smaller headers have been used + if (count($tree) > 0) { + $minLevel = $tree->pluck('level')->min(); + $tree = $tree->map(function ($header) use ($minLevel) { + $header['level'] -= ($minLevel - 2); + return $header; + }); + } + return $tree->toArray(); + } + + /** + * Restores a revision's content back into a page. + * @param Page $page + * @param Book $book + * @param int $revisionId + * @return Page + * @throws \Exception + */ + public function restorePageRevision(Page $page, Book $book, int $revisionId) + { + $page->revision_count++; + $this->savePageRevision($page); + $revision = $page->revisions()->where('id', '=', $revisionId)->first(); + $page->fill($revision->toArray()); + $page->slug = $this->findSuitableSlug('page', $page->name, $page->id, $book->id); + $page->text = $this->pageToPlainText($page); + $page->updated_by = user()->id; + $page->save(); + $this->searchService->indexEntity($page); + return $page; + } + + /** + * Change the page's parent to the given entity. + * @param Page $page + * @param Entity $parent + * @throws \Throwable + */ + public function changePageParent(Page $page, Entity $parent) + { + $book = $parent->isA('book') ? $parent : $parent->book; + $page->chapter_id = $parent->isA('chapter') ? $parent->id : 0; + $page->save(); + if ($page->book->id !== $book->id) { + $page = $this->changeBook('page', $book->id, $page); + } + $page->load('book'); + $this->permissionService->buildJointPermissionsForEntity($book); + } + + /** + * Create a copy of a page in a new location with a new name. + * @param \BookStack\Entities\Page $page + * @param \BookStack\Entities\Entity $newParent + * @param string $newName + * @return \BookStack\Entities\Page + * @throws \Throwable + */ + public function copyPage(Page $page, Entity $newParent, string $newName = '') + { + $newBook = $newParent->isA('book') ? $newParent : $newParent->book; + $newChapter = $newParent->isA('chapter') ? $newParent : null; + $copyPage = $this->getDraftPage($newBook, $newChapter); + $pageData = $page->getAttributes(); + + // Update name + if (!empty($newName)) { + $pageData['name'] = $newName; + } + + // Copy tags from previous page if set + if ($page->tags) { + $pageData['tags'] = []; + foreach ($page->tags as $tag) { + $pageData['tags'][] = ['name' => $tag->name, 'value' => $tag->value]; + } + } + + // Set priority + if ($newParent->isA('chapter')) { + $pageData['priority'] = $this->getNewChapterPriority($newParent); + } else { + $pageData['priority'] = $this->getNewBookPriority($newParent); + } + + return $this->publishPageDraft($copyPage, $pageData); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/AttachmentController.php b/app/Http/Controllers/AttachmentController.php index 14a1b9f3a..0289f8e1d 100644 --- a/app/Http/Controllers/AttachmentController.php +++ b/app/Http/Controllers/AttachmentController.php @@ -1,6 +1,6 @@ entityRepo = $entityRepo; + $this->pageRepo = $pageRepo; $this->exportService = $exportService; $this->userRepo = $userRepo; parent::__construct(); @@ -42,11 +43,11 @@ class PageController extends Controller public function create($bookSlug, $chapterSlug = null) { if ($chapterSlug !== null) { - $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); + $chapter = $this->pageRepo->getBySlug('chapter', $chapterSlug, $bookSlug); $book = $chapter->book; } else { $chapter = null; - $book = $this->entityRepo->getBySlug('book', $bookSlug); + $book = $this->pageRepo->getBySlug('book', $bookSlug); } $parent = $chapter ? $chapter : $book; @@ -54,7 +55,7 @@ class PageController extends Controller // Redirect to draft edit screen if signed in if ($this->signedIn) { - $draft = $this->entityRepo->getDraftPage($book, $chapter); + $draft = $this->pageRepo->getDraftPage($book, $chapter); return redirect($draft->getUrl()); } @@ -78,18 +79,18 @@ class PageController extends Controller ]); if ($chapterSlug !== null) { - $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); + $chapter = $this->pageRepo->getBySlug('chapter', $chapterSlug, $bookSlug); $book = $chapter->book; } else { $chapter = null; - $book = $this->entityRepo->getBySlug('book', $bookSlug); + $book = $this->pageRepo->getBySlug('book', $bookSlug); } $parent = $chapter ? $chapter : $book; $this->checkOwnablePermission('page-create', $parent); - $page = $this->entityRepo->getDraftPage($book, $chapter); - $this->entityRepo->publishPageDraft($page, [ + $page = $this->pageRepo->getDraftPage($book, $chapter); + $this->pageRepo->publishPageDraft($page, [ 'name' => $request->get('name'), 'html' => '' ]); @@ -104,7 +105,7 @@ class PageController extends Controller */ public function editDraft($bookSlug, $pageId) { - $draft = $this->entityRepo->getById('page', $pageId, true); + $draft = $this->pageRepo->getById('page', $pageId, true); $this->checkOwnablePermission('page-create', $draft->parent); $this->setPageTitle(trans('entities.pages_edit_draft')); @@ -131,19 +132,19 @@ class PageController extends Controller ]); $input = $request->all(); - $draftPage = $this->entityRepo->getById('page', $pageId, true); + $draftPage = $this->pageRepo->getById('page', $pageId, true); $book = $draftPage->book; $parent = $draftPage->parent; $this->checkOwnablePermission('page-create', $parent); if ($parent->isA('chapter')) { - $input['priority'] = $this->entityRepo->getNewChapterPriority($parent); + $input['priority'] = $this->pageRepo->getNewChapterPriority($parent); } else { - $input['priority'] = $this->entityRepo->getNewBookPriority($parent); + $input['priority'] = $this->pageRepo->getNewBookPriority($parent); } - $page = $this->entityRepo->publishPageDraft($draftPage, $input); + $page = $this->pageRepo->publishPageDraft($draftPage, $input); Activity::add($page, 'page_create', $book->id); return redirect($page->getUrl()); @@ -160,9 +161,9 @@ class PageController extends Controller public function show($bookSlug, $pageSlug) { try { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); } catch (NotFoundException $e) { - $page = $this->entityRepo->getPageByOldSlug($pageSlug, $bookSlug); + $page = $this->pageRepo->getPageByOldSlug($pageSlug, $bookSlug); if ($page === null) { throw $e; } @@ -171,9 +172,9 @@ class PageController extends Controller $this->checkOwnablePermission('page-view', $page); - $page->html = $this->entityRepo->renderPage($page); - $sidebarTree = $this->entityRepo->getBookChildren($page->book); - $pageNav = $this->entityRepo->getPageNav($page->html); + $page->html = $this->pageRepo->renderPage($page); + $sidebarTree = $this->pageRepo->getBookChildren($page->book); + $pageNav = $this->pageRepo->getPageNav($page->html); // check if the comment's are enabled $commentsEnabled = !setting('app-disable-comments'); @@ -199,7 +200,7 @@ class PageController extends Controller */ public function getPageAjax($pageId) { - $page = $this->entityRepo->getById('page', $pageId); + $page = $this->pageRepo->getById('page', $pageId); return response()->json($page); } @@ -208,28 +209,29 @@ class PageController extends Controller * @param string $bookSlug * @param string $pageSlug * @return Response + * @throws NotFoundException */ public function edit($bookSlug, $pageSlug) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $this->checkOwnablePermission('page-update', $page); $this->setPageTitle(trans('entities.pages_editing_named', ['pageName'=>$page->getShortName()])); $page->isDraft = false; // Check for active editing $warnings = []; - if ($this->entityRepo->isPageEditingActive($page, 60)) { - $warnings[] = $this->entityRepo->getPageEditingActiveMessage($page, 60); + if ($this->pageRepo->isPageEditingActive($page, 60)) { + $warnings[] = $this->pageRepo->getPageEditingActiveMessage($page, 60); } // Check for a current draft version for this user - if ($this->entityRepo->hasUserGotPageDraft($page, $this->currentUser->id)) { - $draft = $this->entityRepo->getUserPageDraft($page, $this->currentUser->id); - $page->name = $draft->name; - $page->html = $draft->html; - $page->markdown = $draft->markdown; + $userPageDraft = $this->pageRepo->getUserPageDraft($page, $this->currentUser->id); + if ($userPageDraft !== null) { + $page->name = $userPageDraft->name; + $page->html = $userPageDraft->html; + $page->markdown = $userPageDraft->markdown; $page->isDraft = true; - $warnings [] = $this->entityRepo->getUserPageDraftMessage($draft); + $warnings [] = $this->pageRepo->getUserPageDraftMessage($userPageDraft); } if (count($warnings) > 0) { @@ -257,9 +259,9 @@ class PageController extends Controller $this->validate($request, [ 'name' => 'required|string|max:255' ]); - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $this->checkOwnablePermission('page-update', $page); - $this->entityRepo->updatePage($page, $page->book->id, $request->all()); + $this->pageRepo->updatePage($page, $page->book->id, $request->all()); Activity::add($page, 'page_update', $page->book->id); return redirect($page->getUrl()); } @@ -272,7 +274,7 @@ class PageController extends Controller */ public function saveDraft(Request $request, $pageId) { - $page = $this->entityRepo->getById('page', $pageId, true); + $page = $this->pageRepo->getById('page', $pageId, true); $this->checkOwnablePermission('page-update', $page); if (!$this->signedIn) { @@ -282,7 +284,7 @@ class PageController extends Controller ], 500); } - $draft = $this->entityRepo->updatePageDraft($page, $request->only(['name', 'html', 'markdown'])); + $draft = $this->pageRepo->updatePageDraft($page, $request->only(['name', 'html', 'markdown'])); $updateTime = $draft->updated_at->timestamp; return response()->json([ @@ -300,7 +302,7 @@ class PageController extends Controller */ public function redirectFromLink($pageId) { - $page = $this->entityRepo->getById('page', $pageId); + $page = $this->pageRepo->getById('page', $pageId); return redirect($page->getUrl()); } @@ -312,7 +314,7 @@ class PageController extends Controller */ public function showDelete($bookSlug, $pageSlug) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $this->checkOwnablePermission('page-delete', $page); $this->setPageTitle(trans('entities.pages_delete_named', ['pageName'=>$page->getShortName()])); return view('pages/delete', ['book' => $page->book, 'page' => $page, 'current' => $page]); @@ -328,7 +330,7 @@ class PageController extends Controller */ public function showDeleteDraft($bookSlug, $pageId) { - $page = $this->entityRepo->getById('page', $pageId, true); + $page = $this->pageRepo->getById('page', $pageId, true); $this->checkOwnablePermission('page-update', $page); $this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName'=>$page->getShortName()])); return view('pages/delete', ['book' => $page->book, 'page' => $page, 'current' => $page]); @@ -343,10 +345,10 @@ class PageController extends Controller */ public function destroy($bookSlug, $pageSlug) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $book = $page->book; $this->checkOwnablePermission('page-delete', $page); - $this->entityRepo->destroyPage($page); + $this->pageRepo->destroyPage($page); Activity::addMessage('page_delete', $book->id, $page->name); session()->flash('success', trans('entities.pages_delete_success')); @@ -362,11 +364,11 @@ class PageController extends Controller */ public function destroyDraft($bookSlug, $pageId) { - $page = $this->entityRepo->getById('page', $pageId, true); + $page = $this->pageRepo->getById('page', $pageId, true); $book = $page->book; $this->checkOwnablePermission('page-update', $page); session()->flash('success', trans('entities.pages_delete_draft_success')); - $this->entityRepo->destroyPage($page); + $this->pageRepo->destroyPage($page); return redirect($book->getUrl()); } @@ -378,7 +380,7 @@ class PageController extends Controller */ public function showRevisions($bookSlug, $pageSlug) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $this->setPageTitle(trans('entities.pages_revisions_named', ['pageName'=>$page->getShortName()])); return view('pages/revisions', ['page' => $page, 'book' => $page->book, 'current' => $page]); } @@ -392,7 +394,7 @@ class PageController extends Controller */ public function showRevision($bookSlug, $pageSlug, $revisionId) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $revision = $page->revisions()->where('id', '=', $revisionId)->first(); if ($revision === null) { abort(404); @@ -417,7 +419,7 @@ class PageController extends Controller */ public function showRevisionChanges($bookSlug, $pageSlug, $revisionId) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $revision = $page->revisions()->where('id', '=', $revisionId)->first(); if ($revision === null) { abort(404); @@ -447,9 +449,9 @@ class PageController extends Controller */ public function restoreRevision($bookSlug, $pageSlug, $revisionId) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $this->checkOwnablePermission('page-update', $page); - $page = $this->entityRepo->restorePageRevision($page, $page->book, $revisionId); + $page = $this->pageRepo->restorePageRevision($page, $page->book, $revisionId); Activity::add($page, 'page_restore', $page->book->id); return redirect($page->getUrl()); } @@ -466,7 +468,7 @@ class PageController extends Controller */ public function destroyRevision($bookSlug, $pageSlug, $revId) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $this->checkOwnablePermission('page-delete', $page); $revision = $page->revisions()->where('id', '=', $revId)->first(); @@ -497,8 +499,8 @@ class PageController extends Controller */ public function exportPdf($bookSlug, $pageSlug) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); - $page->html = $this->entityRepo->renderPage($page); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); + $page->html = $this->pageRepo->renderPage($page); $pdfContent = $this->exportService->pageToPdf($page); return $this->downloadResponse($pdfContent, $pageSlug . '.pdf'); } @@ -511,8 +513,8 @@ class PageController extends Controller */ public function exportHtml($bookSlug, $pageSlug) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); - $page->html = $this->entityRepo->renderPage($page); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); + $page->html = $this->pageRepo->renderPage($page); $containedHtml = $this->exportService->pageToContainedHtml($page); return $this->downloadResponse($containedHtml, $pageSlug . '.html'); } @@ -525,7 +527,7 @@ class PageController extends Controller */ public function exportPlainText($bookSlug, $pageSlug) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $pageText = $this->exportService->pageToPlainText($page); return $this->downloadResponse($pageText, $pageSlug . '.txt'); } @@ -536,7 +538,7 @@ class PageController extends Controller */ public function showRecentlyCreated() { - $pages = $this->entityRepo->getRecentlyCreatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-created')); + $pages = $this->pageRepo->getRecentlyCreatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-created')); return view('pages/detailed-listing', [ 'title' => trans('entities.recently_created_pages'), 'pages' => $pages @@ -549,7 +551,7 @@ class PageController extends Controller */ public function showRecentlyUpdated() { - $pages = $this->entityRepo->getRecentlyUpdatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-updated')); + $pages = $this->pageRepo->getRecentlyUpdatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-updated')); return view('pages/detailed-listing', [ 'title' => trans('entities.recently_updated_pages'), 'pages' => $pages @@ -564,7 +566,7 @@ class PageController extends Controller */ public function showRestrict($bookSlug, $pageSlug) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $this->checkOwnablePermission('restrictions-manage', $page); $roles = $this->userRepo->getRestrictableRoles(); return view('pages/restrictions', [ @@ -582,7 +584,7 @@ class PageController extends Controller */ public function showMove($bookSlug, $pageSlug) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $this->checkOwnablePermission('page-update', $page); return view('pages/move', [ 'book' => $page->book, @@ -600,7 +602,7 @@ class PageController extends Controller */ public function move($bookSlug, $pageSlug, Request $request) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $this->checkOwnablePermission('page-update', $page); $entitySelection = $request->get('entity_selection', null); @@ -614,7 +616,7 @@ class PageController extends Controller try { - $parent = $this->entityRepo->getById($entityType, $entityId); + $parent = $this->pageRepo->getById($entityType, $entityId); } catch (\Exception $e) { session()->flash(trans('entities.selected_book_chapter_not_found')); return redirect()->back(); @@ -622,7 +624,7 @@ class PageController extends Controller $this->checkOwnablePermission('page-create', $parent); - $this->entityRepo->changePageParent($page, $parent); + $this->pageRepo->changePageParent($page, $parent); Activity::add($page, 'page_move', $page->book->id); session()->flash('success', trans('entities.pages_move_success', ['parentName' => $parent->name])); @@ -638,7 +640,7 @@ class PageController extends Controller */ public function showCopy($bookSlug, $pageSlug) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $this->checkOwnablePermission('page-update', $page); session()->flashInput(['name' => $page->name]); return view('pages/copy', [ @@ -657,7 +659,7 @@ class PageController extends Controller */ public function copy($bookSlug, $pageSlug, Request $request) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $this->checkOwnablePermission('page-update', $page); $entitySelection = $request->get('entity_selection', null); @@ -669,7 +671,7 @@ class PageController extends Controller $entityId = intval($stringExploded[1]); try { - $parent = $this->entityRepo->getById($entityType, $entityId); + $parent = $this->pageRepo->getById($entityType, $entityId); } catch (\Exception $e) { session()->flash(trans('entities.selected_book_chapter_not_found')); return redirect()->back(); @@ -678,7 +680,7 @@ class PageController extends Controller $this->checkOwnablePermission('page-create', $parent); - $pageCopy = $this->entityRepo->copyPage($page, $parent, $request->get('name', '')); + $pageCopy = $this->pageRepo->copyPage($page, $parent, $request->get('name', '')); Activity::add($pageCopy, 'page_create', $pageCopy->book->id); session()->flash('success', trans('entities.pages_copy_success')); @@ -696,9 +698,9 @@ class PageController extends Controller */ public function restrict($bookSlug, $pageSlug, Request $request) { - $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); + $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); $this->checkOwnablePermission('restrictions-manage', $page); - $this->entityRepo->updateEntityPermissionsFromRequest($request, $page); + $this->pageRepo->updateEntityPermissionsFromRequest($request, $page); session()->flash('success', trans('entities.pages_permissions_success')); return redirect($page->getUrl()); } diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php index 4402b7caf..d8f2dc4d7 100644 --- a/app/Http/Controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -1,7 +1,7 @@ asEditor(); - $entityRepo = $this->app[EntityRepo::class]; + $pageRepo = app(PageRepo::class); $page = Page::first(); - $entityRepo->updatePage($page, $page->book_id, ['name' => 'updated page', 'html' => '

new content

', 'summary' => 'page revision testing']); - $entityRepo->updatePageDraft($page, ['name' => 'updated page', 'html' => '

new content in draft

', 'summary' => 'page revision testing']); + $pageRepo->updatePage($page, $page->book_id, ['name' => 'updated page', 'html' => '

new content

', 'summary' => 'page revision testing']); + $pageRepo->updatePageDraft($page, ['name' => 'updated page', 'html' => '

new content in draft

', 'summary' => 'page revision testing']); $this->assertDatabaseHas('page_revisions', [ 'page_id' => $page->id, diff --git a/tests/Entity/EntityTest.php b/tests/Entity/EntityTest.php index 90082deaf..ef9597d32 100644 --- a/tests/Entity/EntityTest.php +++ b/tests/Entity/EntityTest.php @@ -3,8 +3,9 @@ use BookStack\Entities\Book; use BookStack\Entities\Chapter; use BookStack\Entities\Page; -use BookStack\Entities\EntityRepo; +use BookStack\Entities\Repos\EntityRepo; use BookStack\Auth\UserRepo; +use BookStack\Entities\Repos\PageRepo; use Carbon\Carbon; class EntityTest extends BrowserKitTest @@ -193,7 +194,7 @@ class EntityTest extends BrowserKitTest $entities = $this->createEntityChainBelongingToUser($creator, $updater); $this->actingAs($creator); app(UserRepo::class)->destroy($creator); - app(EntityRepo::class)->savePageRevision($entities['page']); + app(PageRepo::class)->savePageRevision($entities['page']); $this->checkEntitiesViewable($entities); } @@ -206,7 +207,7 @@ class EntityTest extends BrowserKitTest $entities = $this->createEntityChainBelongingToUser($creator, $updater); $this->actingAs($updater); app(UserRepo::class)->destroy($updater); - app(EntityRepo::class)->savePageRevision($entities['page']); + app(PageRepo::class)->savePageRevision($entities['page']); $this->checkEntitiesViewable($entities); } diff --git a/tests/Entity/PageContentTest.php b/tests/Entity/PageContentTest.php index 4c0d1c47a..6a7112bcb 100644 --- a/tests/Entity/PageContentTest.php +++ b/tests/Entity/PageContentTest.php @@ -1,7 +1,8 @@ asEditor(); - $entityRepo = $this->app[EntityRepo::class]; + $pageRepo = app(PageRepo::class); $page = Page::first(); - $entityRepo->updatePage($page, $page->book_id, ['name' => 'updated page', 'html' => '

new content

', 'summary' => 'page revision testing']); + $pageRepo->updatePage($page, $page->book_id, ['name' => 'updated page', 'html' => '

new content

', 'summary' => 'page revision testing']); $pageRevision = $page->revisions->last(); $revisionView = $this->get($page->getUrl() . '/revisions/' . $pageRevision->id); @@ -89,10 +90,10 @@ class PageContentTest extends TestCase { $this->asEditor(); - $entityRepo = $this->app[EntityRepo::class]; + $pageRepo = app(PageRepo::class); $page = Page::first(); - $entityRepo->updatePage($page, $page->book_id, ['name' => 'updated page abc123', 'html' => '

new contente def456

', 'summary' => 'initial page revision testing']); - $entityRepo->updatePage($page, $page->book_id, ['name' => 'updated page again', 'html' => '

new content

', 'summary' => 'page revision testing']); + $pageRepo->updatePage($page, $page->book_id, ['name' => 'updated page abc123', 'html' => '

new contente def456

', 'summary' => 'initial page revision testing']); + $pageRepo->updatePage($page, $page->book_id, ['name' => 'updated page again', 'html' => '

new content

', 'summary' => 'page revision testing']); $page = Page::find($page->id); diff --git a/tests/Entity/PageDraftTest.php b/tests/Entity/PageDraftTest.php index baae9bded..1ebd5860b 100644 --- a/tests/Entity/PageDraftTest.php +++ b/tests/Entity/PageDraftTest.php @@ -1,16 +1,18 @@ page = \BookStack\Entities\Page::first(); - $this->entityRepo = app('\BookStack\Entities\EntityRepo'); + $this->pageRepo = app(PageRepo::class); } public function test_draft_content_shows_if_available() @@ -20,7 +22,7 @@ class PageDraftTest extends BrowserKitTest ->dontSeeInField('html', $addedContent); $newContent = $this->page->html . $addedContent; - $this->entityRepo->updatePageDraft($this->page, ['html' => $newContent]); + $this->pageRepo->updatePageDraft($this->page, ['html' => $newContent]); $this->asAdmin()->visit($this->page->getUrl() . '/edit') ->seeInField('html', $newContent); } @@ -33,7 +35,7 @@ class PageDraftTest extends BrowserKitTest $newContent = $this->page->html . $addedContent; $newUser = $this->getEditor(); - $this->entityRepo->updatePageDraft($this->page, ['html' => $newContent]); + $this->pageRepo->updatePageDraft($this->page, ['html' => $newContent]); $this->actingAs($newUser)->visit($this->page->getUrl() . '/edit') ->dontSeeInField('html', $newContent); } @@ -41,7 +43,7 @@ class PageDraftTest extends BrowserKitTest public function test_alert_message_shows_if_editing_draft() { $this->asAdmin(); - $this->entityRepo->updatePageDraft($this->page, ['html' => 'test content']); + $this->pageRepo->updatePageDraft($this->page, ['html' => 'test content']); $this->asAdmin()->visit($this->page->getUrl() . '/edit') ->see('You are currently editing a draft'); } @@ -55,7 +57,7 @@ class PageDraftTest extends BrowserKitTest $newContent = $this->page->html . $addedContent; $newUser = $this->getEditor(); - $this->entityRepo->updatePageDraft($this->page, ['html' => $newContent]); + $this->pageRepo->updatePageDraft($this->page, ['html' => $newContent]); $this->actingAs($newUser) ->visit($this->page->getUrl() . '/edit') diff --git a/tests/Entity/SortTest.php b/tests/Entity/SortTest.php index 689ca690f..5b23acfd5 100644 --- a/tests/Entity/SortTest.php +++ b/tests/Entity/SortTest.php @@ -3,7 +3,8 @@ use BookStack\Entities\Book; use BookStack\Entities\Chapter; use BookStack\Entities\Page; -use BookStack\Entities\EntityRepo; +use BookStack\Entities\Repos\EntityRepo; +use BookStack\Entities\Repos\PageRepo; class SortTest extends TestCase { @@ -18,8 +19,8 @@ class SortTest extends TestCase public function test_drafts_do_not_show_up() { $this->asAdmin(); - $entityRepo = app(EntityRepo::class); - $draft = $entityRepo->getDraftPage($this->book); + $pageRepo = app(PageRepo::class); + $draft = $pageRepo->getDraftPage($this->book); $resp = $this->get($this->book->getUrl()); $resp->assertSee($draft->name); diff --git a/tests/ImageTest.php b/tests/ImageTest.php index d5c13cd95..38bac2cca 100644 --- a/tests/ImageTest.php +++ b/tests/ImageTest.php @@ -1,8 +1,9 @@ assertStatus(200); $image = Image::where('type', '=', 'gallery')->first(); - $entityRepo = app(EntityRepo::class); - $entityRepo->updatePage($page, $page->book_id, [ + $pageRepo = app(PageRepo::class); + $pageRepo->updatePage($page, $page->book_id, [ 'name' => $page->name, 'html' => $page->html . "url}\">", 'summary' => '' @@ -263,7 +264,7 @@ class ImageTest extends TestCase $this->assertCount(0, $toDelete); // Save a revision of our page without the image; - $entityRepo->updatePage($page, $page->book_id, [ + $pageRepo->updatePage($page, $page->book_id, [ 'name' => $page->name, 'html' => "

Hello

", 'summary' => '' diff --git a/tests/Permissions/RestrictionsTest.php b/tests/Permissions/RestrictionsTest.php index cc4211843..351132ffe 100644 --- a/tests/Permissions/RestrictionsTest.php +++ b/tests/Permissions/RestrictionsTest.php @@ -5,7 +5,7 @@ use BookStack\Entities\Bookshelf; use BookStack\Entities\Chapter; use BookStack\Entities\Entity; use BookStack\Auth\User; -use BookStack\Entities\EntityRepo; +use BookStack\Entities\Repos\EntityRepo; use BookStack\Entities\Page; class RestrictionsTest extends BrowserKitTest diff --git a/tests/SharedTestHelpers.php b/tests/SharedTestHelpers.php index 80fab874c..8e903be11 100644 --- a/tests/SharedTestHelpers.php +++ b/tests/SharedTestHelpers.php @@ -5,10 +5,11 @@ use BookStack\Entities\Bookshelf; use BookStack\Entities\Chapter; use BookStack\Entities\Entity; use BookStack\Entities\Page; -use BookStack\Entities\EntityRepo; +use BookStack\Entities\Repos\EntityRepo; use BookStack\Auth\Permissions\PermissionsRepo; use BookStack\Auth\Role; use BookStack\Auth\Permissions\PermissionService; +use BookStack\Entities\Repos\PageRepo; use BookStack\Settings\SettingService; trait SharedTestHelpers @@ -78,7 +79,7 @@ trait SharedTestHelpers */ protected function regenEntityPermissions(Entity $entity) { - $this->app[PermissionService::class]->buildJointPermissionsForEntity($entity); + app(PermissionService::class)->buildJointPermissionsForEntity($entity); $entity->load('jointPermissions'); } @@ -88,7 +89,7 @@ trait SharedTestHelpers * @return \BookStack\Entities\Bookshelf */ public function newShelf($input = ['name' => 'test shelf', 'description' => 'My new test shelf']) { - return $this->app[EntityRepo::class]->createFromInput('bookshelf', $input, false); + return app(EntityRepo::class)->createFromInput('bookshelf', $input, false); } /** @@ -97,7 +98,7 @@ trait SharedTestHelpers * @return Book */ public function newBook($input = ['name' => 'test book', 'description' => 'My new test book']) { - return $this->app[EntityRepo::class]->createFromInput('book', $input, false); + return app(EntityRepo::class)->createFromInput('book', $input, false); } /** @@ -107,7 +108,7 @@ trait SharedTestHelpers * @return \BookStack\Entities\Chapter */ public function newChapter($input = ['name' => 'test chapter', 'description' => 'My new test chapter'], Book $book) { - return $this->app[EntityRepo::class]->createFromInput('chapter', $input, $book); + return app(EntityRepo::class)->createFromInput('chapter', $input, $book); } /** @@ -117,9 +118,9 @@ trait SharedTestHelpers */ public function newPage($input = ['name' => 'test page', 'html' => 'My new test page']) { $book = Book::first(); - $entityRepo = $this->app[EntityRepo::class]; - $draftPage = $entityRepo->getDraftPage($book); - return $entityRepo->publishPageDraft($draftPage, $input); + $pageRepo = app(PageRepo::class); + $draftPage = $pageRepo->getDraftPage($book); + return $pageRepo->publishPageDraft($draftPage, $input); } /**