mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-01-31 12:11:37 +01:00
Review of #2682, Also added parent deletion link on restore
On restore, added a link to the parent deletion restore if any exists on a cascading parent. Added a test to cover this case to ensure its shown. Also tweaked default empty state message on recycle bin item list to align with new column count. Also done a little existing code cleanup including a getUrl helper on the deletion items. Related to #2682 & #2594
This commit is contained in:
parent
8a9505bf8c
commit
3a402f6adc
@ -7,6 +7,9 @@ use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
|
||||
/**
|
||||
* @property Model deletable
|
||||
*/
|
||||
class Deletion extends Model implements Loggable
|
||||
{
|
||||
|
||||
@ -45,4 +48,12 @@ class Deletion extends Model implements Loggable
|
||||
$deletable = $this->deletable()->first();
|
||||
return "Deletion ({$this->id}) for {$deletable->getType()} ({$deletable->id}) {$deletable->name}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a URL for this specific deletion.
|
||||
*/
|
||||
public function getUrl($path): string
|
||||
{
|
||||
return url("/settings/recycle-bin/{$this->id}/" . ltrim($path, '/'));
|
||||
}
|
||||
}
|
||||
|
@ -266,10 +266,10 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
|
||||
*/
|
||||
public function getParent(): ?Entity
|
||||
{
|
||||
if ($this->isA('page')) {
|
||||
if ($this instanceof Page) {
|
||||
return $this->chapter_id ? $this->chapter()->withTrashed()->first() : $this->book()->withTrashed()->first();
|
||||
}
|
||||
if ($this->isA('chapter')) {
|
||||
if ($this instanceof Chapter) {
|
||||
return $this->book()->withTrashed()->first();
|
||||
}
|
||||
return null;
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
use BookStack\Actions\ActivityType;
|
||||
use BookStack\Entities\Models\Deletion;
|
||||
use BookStack\Entities\Models\Entity;
|
||||
use BookStack\Entities\Tools\TrashCan;
|
||||
|
||||
class RecycleBinController extends Controller
|
||||
@ -44,8 +45,23 @@ class RecycleBinController extends Controller
|
||||
/** @var Deletion $deletion */
|
||||
$deletion = Deletion::query()->findOrFail($id);
|
||||
|
||||
// Walk the parent chain to find any cascading parent deletions
|
||||
$currentDeletable = $deletion->deletable;
|
||||
$searching = true;
|
||||
while ($searching && $currentDeletable instanceof Entity) {
|
||||
$parent = $currentDeletable->getParent();
|
||||
if ($parent && $parent->trashed()) {
|
||||
$currentDeletable = $parent;
|
||||
} else {
|
||||
$searching = false;
|
||||
}
|
||||
}
|
||||
/** @var ?Deletion $parentDeletion */
|
||||
$parentDeletion = ($currentDeletable === $deletion->deletable) ? null : $currentDeletable->deletions()->first();
|
||||
|
||||
return view('settings.recycle-bin.restore', [
|
||||
'deletion' => $deletion,
|
||||
'parentDeletion' => $parentDeletion,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -105,6 +105,7 @@ return [
|
||||
'recycle_bin_restore_list' => 'Items to be Restored',
|
||||
'recycle_bin_restore_confirm' => 'This action will restore the deleted item, including any child elements, to their original location. If the original location has since been deleted, and is now in the recycle bin, the parent item will also need to be restored.',
|
||||
'recycle_bin_restore_deleted_parent' => 'The parent of this item has also been deleted. These will remain deleted until that parent is also restored.',
|
||||
'recycle_bin_restore_parent' => 'Restore Parent',
|
||||
'recycle_bin_destroy_notification' => 'Deleted :count total items from the recycle bin.',
|
||||
'recycle_bin_restore_notification' => 'Restored :count total items from the recycle bin.',
|
||||
|
||||
|
@ -47,7 +47,7 @@
|
||||
</tr>
|
||||
@if(count($deletions) === 0)
|
||||
<tr>
|
||||
<td colspan="4">
|
||||
<td colspan="5">
|
||||
<p class="text-muted"><em>{{ trans('settings.recycle_bin_contents_empty') }}</em></p>
|
||||
</td>
|
||||
</tr>
|
||||
@ -95,8 +95,8 @@
|
||||
<div component="dropdown" class="dropdown-container">
|
||||
<button type="button" refs="dropdown@toggle" class="button outline">{{ trans('common.actions') }}</button>
|
||||
<ul refs="dropdown@menu" class="dropdown-menu">
|
||||
<li><a class="block" href="{{ url('/settings/recycle-bin/'.$deletion->id.'/restore') }}">{{ trans('settings.recycle_bin_restore') }}</a></li>
|
||||
<li><a class="block" href="{{ url('/settings/recycle-bin/'.$deletion->id.'/destroy') }}">{{ trans('settings.recycle_bin_permanently_delete') }}</a></li>
|
||||
<li><a class="block" href="{{ $deletion->getUrl('/restore') }}">{{ trans('settings.recycle_bin_restore') }}</a></li>
|
||||
<li><a class="block" href="{{ $deletion->getUrl('/destroy') }}">{{ trans('settings.recycle_bin_permanently_delete') }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
|
@ -10,7 +10,7 @@
|
||||
<div class="card content-wrap auto-height">
|
||||
<h2 class="list-heading">{{ trans('settings.recycle_bin_restore') }}</h2>
|
||||
<p class="text-muted">{{ trans('settings.recycle_bin_restore_confirm') }}</p>
|
||||
<form action="{{ url('/settings/recycle-bin/' . $deletion->id . '/restore') }}" method="post">
|
||||
<form action="{{ $deletion->getUrl('/restore') }}" method="post">
|
||||
{!! csrf_field() !!}
|
||||
<a href="{{ url('/settings/recycle-bin') }}" class="button outline">{{ trans('common.cancel') }}</a>
|
||||
<button type="submit" class="button">{{ trans('settings.recycle_bin_restore') }}</button>
|
||||
@ -19,9 +19,17 @@
|
||||
@if($deletion->deletable instanceof \BookStack\Entities\Models\Entity)
|
||||
<hr class="mt-m">
|
||||
<h5>{{ trans('settings.recycle_bin_restore_list') }}</h5>
|
||||
@if($deletion->deletable->getParent() && $deletion->deletable->getParent()->trashed())
|
||||
<p class="text-neg">{{ trans('settings.recycle_bin_restore_deleted_parent') }}</p>
|
||||
@endif
|
||||
<div class="flex-container-row mb-s items-center">
|
||||
@if($deletion->deletable->getParent() && $deletion->deletable->getParent()->trashed())
|
||||
<div class="text-neg flex">{{ trans('settings.recycle_bin_restore_deleted_parent') }}</div>
|
||||
@endif
|
||||
@if($parentDeletion)
|
||||
<div class="flex fit-content ml-m">
|
||||
<a class="button outline" href="{{ $parentDeletion->getUrl('/restore') }}">{{ trans('settings.recycle_bin_restore_parent') }}</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@include('settings.recycle-bin.deletable-entity-list', ['entity' => $deletion->deletable])
|
||||
@endif
|
||||
|
||||
|
@ -247,4 +247,22 @@ class RecycleBinTest extends TestCase
|
||||
$chapter->refresh();
|
||||
$this->assertNull($chapter->deleted_at);
|
||||
}
|
||||
|
||||
public function test_restore_page_shows_link_to_parent_restore_if_parent_also_deleted()
|
||||
{
|
||||
/** @var Book $book */
|
||||
$book = Book::query()->whereHas('pages')->whereHas('chapters')->with(['pages', 'chapters'])->firstOrFail();
|
||||
$chapter = $book->chapters->first();
|
||||
/** @var Page $page */
|
||||
$page = $chapter->pages->first();
|
||||
$this->asEditor()->delete($page->getUrl());
|
||||
$this->asEditor()->delete($book->getUrl());
|
||||
|
||||
$bookDeletion = $book->deletions()->first();
|
||||
$pageDeletion = $page->deletions()->first();
|
||||
|
||||
$pageRestoreView = $this->asAdmin()->get("/settings/recycle-bin/{$pageDeletion->id}/restore");
|
||||
$pageRestoreView->assertSee('The parent of this item has also been deleted.');
|
||||
$pageRestoreView->assertElementContains('a[href$="/settings/recycle-bin/' . $bookDeletion->id. '/restore"]', 'Restore Parent');
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user