]> BookStack Code Mirror - bookstack/blobdiff - app/Entities/Managers/TrashCan.php
LDAP: Added TLS support
[bookstack] / app / Entities / Managers / TrashCan.php
index 9a21f5e2c13d9abd15ab8b2d9fbc1c410010d1c1..48768ab9375ee81acb1a99e6ce19a60e3de112d2 100644 (file)
@@ -3,8 +3,9 @@
 use BookStack\Entities\Book;
 use BookStack\Entities\Bookshelf;
 use BookStack\Entities\Chapter;
-use BookStack\Entities\DeleteRecord;
+use BookStack\Entities\Deletion;
 use BookStack\Entities\Entity;
+use BookStack\Entities\EntityProvider;
 use BookStack\Entities\HasCoverImage;
 use BookStack\Entities\Page;
 use BookStack\Exceptions\NotifyException;
@@ -12,6 +13,7 @@ use BookStack\Facades\Activity;
 use BookStack\Uploads\AttachmentService;
 use BookStack\Uploads\ImageService;
 use Exception;
+use Illuminate\Support\Carbon;
 
 class TrashCan
 {
@@ -21,7 +23,7 @@ class TrashCan
      */
     public function softDestroyShelf(Bookshelf $shelf)
     {
-        DeleteRecord::createForEntity($shelf);
+        Deletion::createForEntity($shelf);
         $shelf->delete();
     }
 
@@ -31,7 +33,7 @@ class TrashCan
      */
     public function softDestroyBook(Book $book)
     {
-        DeleteRecord::createForEntity($book);
+        Deletion::createForEntity($book);
 
         foreach ($book->pages as $page) {
             $this->softDestroyPage($page, false);
@@ -51,7 +53,7 @@ class TrashCan
     public function softDestroyChapter(Chapter $chapter, bool $recordDelete = true)
     {
         if ($recordDelete) {
-            DeleteRecord::createForEntity($chapter);
+            Deletion::createForEntity($chapter);
         }
 
         if (count($chapter->pages) > 0) {
@@ -70,7 +72,7 @@ class TrashCan
     public function softDestroyPage(Page $page, bool $recordDelete = true)
     {
         if ($recordDelete) {
-            DeleteRecord::createForEntity($page);
+            Deletion::createForEntity($page);
         }
 
         // Check if set as custom homepage & remove setting if not used or throw error if active
@@ -89,10 +91,11 @@ class TrashCan
      * Remove a bookshelf from the system.
      * @throws Exception
      */
-    public function destroyShelf(Bookshelf $shelf)
+    protected function destroyShelf(Bookshelf $shelf): int
     {
         $this->destroyCommonRelations($shelf);
         $shelf->forceDelete();
+        return 1;
     }
 
     /**
@@ -100,20 +103,24 @@ class TrashCan
      * Destroys any child chapters and pages.
      * @throws Exception
      */
-    public function destroyBook(Book $book)
+    protected function destroyBook(Book $book): int
     {
+        $count = 0;
         $pages = $book->pages()->withTrashed()->get();
         foreach ($pages as $page) {
             $this->destroyPage($page);
+            $count++;
         }
 
         $chapters = $book->chapters()->withTrashed()->get();
         foreach ($chapters as $chapter) {
             $this->destroyChapter($chapter);
+            $count++;
         }
 
         $this->destroyCommonRelations($book);
         $book->forceDelete();
+        return $count + 1;
     }
 
     /**
@@ -121,24 +128,27 @@ class TrashCan
      * Destroys all pages within.
      * @throws Exception
      */
-    public function destroyChapter(Chapter $chapter)
+    protected function destroyChapter(Chapter $chapter): int
     {
+        $count = 0;
         $pages = $chapter->pages()->withTrashed()->get();
         if (count($pages)) {
             foreach ($pages as $page) {
                 $this->destroyPage($page);
+                $count++;
             }
         }
 
         $this->destroyCommonRelations($chapter);
         $chapter->forceDelete();
+        return $count + 1;
     }
 
     /**
      * Remove a page from the system.
      * @throws Exception
      */
-    public function destroyPage(Page $page)
+    protected function destroyPage(Page $page): int
     {
         $this->destroyCommonRelations($page);
 
@@ -149,6 +159,149 @@ class TrashCan
         }
 
         $page->forceDelete();
+        return 1;
+    }
+
+    /**
+     * Get the total counts of those that have been trashed
+     * but not yet fully deleted (In recycle bin).
+     */
+    public function getTrashedCounts(): array
+    {
+        $provider = app(EntityProvider::class);
+        $counts = [];
+
+        /** @var Entity $instance */
+        foreach ($provider->all() as $key => $instance) {
+            $counts[$key] = $instance->newQuery()->onlyTrashed()->count();
+        }
+
+        return $counts;
+    }
+
+    /**
+     * Destroy all items that have pending deletions.
+     * @throws Exception
+     */
+    public function empty(): int
+    {
+        $deletions = Deletion::all();
+        $deleteCount = 0;
+        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
+    {
+        // 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.
+     */
+    protected function destroyEntity(Entity $entity): int
+    {
+        if ($entity->isA('page')) {
+            return $this->destroyPage($entity);
+        }
+        if ($entity->isA('chapter')) {
+            return $this->destroyChapter($entity);
+        }
+        if ($entity->isA('book')) {
+            return $this->destroyBook($entity);
+        }
+        if ($entity->isA('shelf')) {
+            return $this->destroyShelf($entity);
+        }
     }
 
     /**
@@ -163,7 +316,7 @@ class TrashCan
         $entity->comments()->delete();
         $entity->jointPermissions()->delete();
         $entity->searchTerms()->delete();
-        $entity->deleteRecords()->delete();
+        $entity->deletions()->delete();
 
         if ($entity instanceof HasCoverImage && $entity->cover) {
             $imageService = app()->make(ImageService::class);