X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/a6633642232efd164d4708967ab59e498fbff896..refs/pull/3391/head:/app/Entities/Tools/TrashCan.php diff --git a/app/Entities/Tools/TrashCan.php b/app/Entities/Tools/TrashCan.php index d2447ec68..1e130c9e1 100644 --- a/app/Entities/Tools/TrashCan.php +++ b/app/Entities/Tools/TrashCan.php @@ -1,11 +1,13 @@ -ensureDeletable($shelf); Deletion::createForEntity($shelf); $shelf->delete(); } /** * Send a book to the recycle bin. + * * @throws Exception */ public function softDestroyBook(Book $book) { + $this->ensureDeletable($book); Deletion::createForEntity($book); foreach ($book->pages as $page) { @@ -48,11 +55,13 @@ class TrashCan /** * Send a chapter to the recycle bin. + * * @throws Exception */ public function softDestroyChapter(Chapter $chapter, bool $recordDelete = true) { if ($recordDelete) { + $this->ensureDeletable($chapter); Deletion::createForEntity($chapter); } @@ -67,40 +76,72 @@ class TrashCan /** * Send a page to the recycle bin. + * * @throws Exception */ public function softDestroyPage(Page $page, bool $recordDelete = true) { if ($recordDelete) { + $this->ensureDeletable($page); Deletion::createForEntity($page); } - // Check if set as custom homepage & remove setting if not used or throw error if active - $customHome = setting('app-homepage', '0:'); - if (intval($page->id) === intval(explode(':', $customHome)[0])) { - if (setting('app-homepage-type') === 'page') { - throw new NotifyException(trans('errors.page_custom_home_deletion'), $page->getUrl()); + $page->delete(); + } + + /** + * Ensure the given entity is deletable. + * Is not for permissions, but logical conditions within the application. + * Will throw if not deletable. + * + * @throws NotifyException + */ + protected function ensureDeletable(Entity $entity): void + { + $customHomeId = intval(explode(':', setting('app-homepage', '0:'))[0]); + $customHomeActive = setting('app-homepage-type') === 'page'; + $removeCustomHome = false; + + // Check custom homepage usage for pages + if ($entity instanceof Page && $entity->id === $customHomeId) { + if ($customHomeActive) { + throw new NotifyException(trans('errors.page_custom_home_deletion'), $entity->getUrl()); + } + $removeCustomHome = true; + } + + // Check custom homepage usage within chapters or books + if ($entity instanceof Chapter || $entity instanceof Book) { + if ($entity->pages()->where('id', '=', $customHomeId)->exists()) { + if ($customHomeActive) { + throw new NotifyException(trans('errors.page_custom_home_deletion'), $entity->getUrl()); + } + $removeCustomHome = true; } - setting()->remove('app-homepage'); } - $page->delete(); + if ($removeCustomHome) { + setting()->remove('app-homepage'); + } } /** * Remove a bookshelf from the system. + * * @throws Exception */ protected function destroyShelf(Bookshelf $shelf): int { $this->destroyCommonRelations($shelf); $shelf->forceDelete(); + return 1; } /** * Remove a book from the system. * Destroys any child chapters and pages. + * * @throws Exception */ protected function destroyBook(Book $book): int @@ -120,37 +161,40 @@ class TrashCan $this->destroyCommonRelations($book); $book->forceDelete(); + return $count + 1; } /** * Remove a chapter from the system. * Destroys all pages within. + * * @throws Exception */ protected function destroyChapter(Chapter $chapter): int { $count = 0; $pages = $chapter->pages()->withTrashed()->get(); - if (count($pages)) { - foreach ($pages as $page) { - $this->destroyPage($page); - $count++; - } + foreach ($pages as $page) { + $this->destroyPage($page); + $count++; } $this->destroyCommonRelations($chapter); $chapter->forceDelete(); + return $count + 1; } /** * Remove a page from the system. + * * @throws Exception */ protected function destroyPage(Page $page): int { $this->destroyCommonRelations($page); + $page->allRevisions()->delete(); // Delete Attached Files $attachmentService = app(AttachmentService::class); @@ -159,6 +203,7 @@ class TrashCan } $page->forceDelete(); + return 1; } @@ -170,9 +215,10 @@ class TrashCan { $counts = []; - /** @var Entity $instance */ - foreach ((new EntityProvider)->all() as $key => $instance) { - $counts[$key] = $instance->newQuery()->onlyTrashed()->count(); + foreach ((new EntityProvider())->all() as $key => $instance) { + /** @var Builder $query */ + $query = $instance->newQuery(); + $counts[$key] = $query->onlyTrashed()->count(); } return $counts; @@ -180,6 +226,7 @@ class TrashCan /** * Destroy all items that have pending deletions. + * * @throws Exception */ public function empty(): int @@ -189,11 +236,13 @@ class TrashCan foreach ($deletions as $deletion) { $deleteCount += $this->destroyFromDeletion($deletion); } + return $deleteCount; } /** * Destroy an element from the given deletion model. + * * @throws Exception */ public function destroyFromDeletion(Deletion $deletion): int @@ -206,28 +255,33 @@ class TrashCan $count = $this->destroyEntity($deletion->deletable); } $deletion->delete(); + return $count; } /** * Restore the content within the given deletion. + * * @throws Exception */ public function restoreFromDeletion(Deletion $deletion): int { $shouldRestore = true; $restoreCount = 0; - $parent = $deletion->deletable->getParent(); - if ($parent && $parent->trashed()) { - $shouldRestore = false; + if ($deletion->deletable instanceof Entity) { + $parent = $deletion->deletable->getParent(); + if ($parent && $parent->trashed()) { + $shouldRestore = false; + } } - if ($shouldRestore) { + if ($deletion->deletable instanceof Entity && $shouldRestore) { $restoreCount = $this->restoreEntity($deletion->deletable); } $deletion->delete(); + return $restoreCount; } @@ -235,6 +289,7 @@ class TrashCan * Automatically clear old content from the recycle bin * depending on the configured lifetime. * Returns the total number of deleted elements. + * * @throws Exception */ public function autoClearOld(): int @@ -273,11 +328,11 @@ class TrashCan $count++; }; - if ($entity->isA('chapter') || $entity->isA('book')) { + if ($entity instanceof Chapter || $entity instanceof Book) { $entity->pages()->withTrashed()->withCount('deletions')->get()->each($restoreAction); } - if ($entity->isA('book')) { + if ($entity instanceof Book) { $entity->chapters()->withTrashed()->withCount('deletions')->get()->each($restoreAction); } @@ -286,21 +341,25 @@ class TrashCan /** * Destroy the given entity. + * + * @throws Exception */ protected function destroyEntity(Entity $entity): int { - if ($entity->isA('page')) { + if ($entity instanceof Page) { return $this->destroyPage($entity); } - if ($entity->isA('chapter')) { + if ($entity instanceof Chapter) { return $this->destroyChapter($entity); } - if ($entity->isA('book')) { + if ($entity instanceof Book) { return $this->destroyBook($entity); } - if ($entity->isA('shelf')) { + if ($entity instanceof Bookshelf) { return $this->destroyShelf($entity); } + + return 0; } /** @@ -316,10 +375,11 @@ class TrashCan $entity->jointPermissions()->delete(); $entity->searchTerms()->delete(); $entity->deletions()->delete(); + $entity->favourites()->delete(); - if ($entity instanceof HasCoverImage && $entity->cover) { + if ($entity instanceof HasCoverImage && $entity->cover()->exists()) { $imageService = app()->make(ImageService::class); - $imageService->destroy($entity->cover); + $imageService->destroy($entity->cover()->first()); } } }