X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/ff7cbd14fcdad963a7f53f788dabbb43ccd73b8b..refs/pull/2376/head:/app/Entities/Managers/TrashCan.php diff --git a/app/Entities/Managers/TrashCan.php b/app/Entities/Managers/TrashCan.php index aedf4d7af..48768ab93 100644 --- a/app/Entities/Managers/TrashCan.php +++ b/app/Entities/Managers/TrashCan.php @@ -13,6 +13,7 @@ use BookStack\Facades\Activity; use BookStack\Uploads\AttachmentService; use BookStack\Uploads\ImageService; use Exception; +use Illuminate\Support\Carbon; class TrashCan { @@ -90,7 +91,7 @@ class TrashCan * Remove a bookshelf from the system. * @throws Exception */ - public function destroyShelf(Bookshelf $shelf): int + protected function destroyShelf(Bookshelf $shelf): int { $this->destroyCommonRelations($shelf); $shelf->forceDelete(); @@ -102,7 +103,7 @@ class TrashCan * Destroys any child chapters and pages. * @throws Exception */ - public function destroyBook(Book $book): int + protected function destroyBook(Book $book): int { $count = 0; $pages = $book->pages()->withTrashed()->get(); @@ -127,7 +128,7 @@ class TrashCan * Destroys all pages within. * @throws Exception */ - public function destroyChapter(Chapter $chapter): int + protected function destroyChapter(Chapter $chapter): int { $count = 0; $pages = $chapter->pages()->withTrashed()->get(); @@ -147,7 +148,7 @@ class TrashCan * Remove a page from the system. * @throws Exception */ - public function destroyPage(Page $page): int + protected function destroyPage(Page $page): int { $this->destroyCommonRelations($page); @@ -180,24 +181,110 @@ class TrashCan /** * Destroy all items that have pending deletions. + * @throws Exception */ - public function destroyFromAllDeletions(): int + public function empty(): int { $deletions = Deletion::all(); $deleteCount = 0; foreach ($deletions as $deletion) { - // For each one we load in the relation since it may have already - // been deleted as part of another deletion in this loop. - $entity = $deletion->deletable()->first(); - if ($entity) { - $count = $this->destroyEntity($deletion->deletable); - $deleteCount += $count; - } - $deletion->delete(); + $deleteCount += $this->destroyFromDeletion($deletion); } return $deleteCount; } + /** + * Destroy an element from the given deletion model. + * @throws Exception + */ + public function destroyFromDeletion(Deletion $deletion): int + { + // We directly load the deletable element here just to ensure it still + // exists in the event it has already been destroyed during this request. + $entity = $deletion->deletable()->first(); + $count = 0; + if ($entity) { + $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 ($shouldRestore) { + $restoreCount = $this->restoreEntity($deletion->deletable); + } + + $deletion->delete(); + return $restoreCount; + } + + /** + * 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 + { + $lifetime = intval(config('app.recycle_bin_lifetime')); + if ($lifetime < 0) { + return 0; + } + + $clearBeforeDate = Carbon::now()->addSeconds(10)->subDays($lifetime); + $deleteCount = 0; + + $deletionsToRemove = Deletion::query()->where('created_at', '<', $clearBeforeDate)->get(); + foreach ($deletionsToRemove as $deletion) { + $deleteCount += $this->destroyFromDeletion($deletion); + } + + return $deleteCount; + } + + /** + * Restore an entity so it is essentially un-deleted. + * Deletions on restored child elements will be removed during this restoration. + */ + protected function restoreEntity(Entity $entity): int + { + $count = 1; + $entity->restore(); + + $restoreAction = function ($entity) use (&$count) { + if ($entity->deletions_count > 0) { + $entity->deletions()->delete(); + } + + $entity->restore(); + $count++; + }; + + if ($entity->isA('chapter') || $entity->isA('book')) { + $entity->pages()->withTrashed()->withCount('deletions')->get()->each($restoreAction); + } + + if ($entity->isA('book')) { + $entity->chapters()->withTrashed()->withCount('deletions')->get()->each($restoreAction); + } + + return $count; + } + /** * Destroy the given entity. */