mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Merge pull request #1008 from BookStackApp/revision-deletion
#784 - Adds ability to remove particular revision.
This commit is contained in:
commit
32e34f10ff
@ -454,6 +454,40 @@ class PageController extends Controller
|
||||
return redirect($page->getUrl());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes a revision using the id of the specified revision.
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @param int $revId
|
||||
* @throws NotFoundException
|
||||
* @throws BadRequestException
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function destroyRevision($bookSlug, $pageSlug, $revId)
|
||||
{
|
||||
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||
$this->checkOwnablePermission('page-delete', $page);
|
||||
|
||||
$revision = $page->revisions()->where('id', '=', $revId)->first();
|
||||
if ($revision === null) {
|
||||
throw new NotFoundException("Revision #{$revId} not found");
|
||||
}
|
||||
|
||||
// Get the current revision for the page
|
||||
$currentRevision = $page->getCurrentRevision();
|
||||
|
||||
// Check if its the latest revision, cannot delete latest revision.
|
||||
if (intval($currentRevision->id) === intval($revId)) {
|
||||
session()->flash('error', trans('entities.revision_cannot_delete_latest'));
|
||||
return response()->view('pages/revisions', ['page' => $page, 'book' => $page->book, 'current' => $page], 400);
|
||||
}
|
||||
|
||||
$revision->delete();
|
||||
session()->flash('success', trans('entities.revision_delete_success'));
|
||||
return view('pages/revisions', ['page' => $page, 'book' => $page->book, 'current' => $page]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports a page to a PDF.
|
||||
* https://github.com/barryvdh/laravel-dompdf
|
||||
|
@ -112,4 +112,13 @@ class Page extends Entity
|
||||
$htmlQuery = $withContent ? 'html' : "'' as html";
|
||||
return "'BookStack\\\\Page' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text, {$htmlQuery}, book_id, priority, chapter_id, draft, created_by, updated_by, updated_at, created_at";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current revision for the page if existing
|
||||
* @return \BookStack\PageRevision|null
|
||||
*/
|
||||
public function getCurrentRevision()
|
||||
{
|
||||
return $this->revisions()->first();
|
||||
}
|
||||
}
|
||||
|
@ -367,7 +367,7 @@ ul.pagination {
|
||||
padding: $-xs $-m;
|
||||
line-height: 1.2;
|
||||
}
|
||||
a {
|
||||
a, button {
|
||||
display: block;
|
||||
padding: $-xs $-m;
|
||||
color: #555;
|
||||
@ -382,6 +382,10 @@ ul.pagination {
|
||||
width: 16px;
|
||||
}
|
||||
}
|
||||
button {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
li.border-bottom {
|
||||
border-bottom: 1px solid #DDD;
|
||||
}
|
||||
|
@ -41,6 +41,9 @@ table.table {
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
td.actions {
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
|
||||
table.no-style {
|
||||
|
@ -256,4 +256,11 @@ return [
|
||||
'comment_updated_success' => 'Kommentar aktualisiert',
|
||||
'comment_delete_confirm' => 'Möchten Sie diesen Kommentar wirklich löschen?',
|
||||
'comment_in_reply_to' => 'Antwort auf :commentId',
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
'revision_delete_confirm' => 'Sind Sie sicher, dass Sie diese Revision löschen wollen?',
|
||||
'revision_delete_success' => 'Revision gelöscht',
|
||||
'revision_cannot_delete_latest' => 'Die letzte Version kann nicht gelöscht werden.'
|
||||
];
|
||||
|
@ -265,4 +265,11 @@ return [
|
||||
'comment_updated_success' => 'Comment updated',
|
||||
'comment_delete_confirm' => 'Are you sure you want to delete this comment?',
|
||||
'comment_in_reply_to' => 'In reply to :commentId',
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
'revision_delete_confirm' => 'Are you sure you want to delete this revision?',
|
||||
'revision_delete_success' => 'Revision deleted',
|
||||
'revision_cannot_delete_latest' => 'Cannot delete the latest revision.'
|
||||
];
|
@ -265,4 +265,11 @@ return [
|
||||
'comment_updated_success' => 'Comentario actualizado',
|
||||
'comment_delete_confirm' => '¿Está seguro de que quiere borrar este comentario?',
|
||||
'comment_in_reply_to' => 'En respuesta a :commentId',
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
'revision_delete_confirm' => '¿Está seguro de que desea eliminar esta revisión?',
|
||||
'revision_delete_success' => 'Revisión eliminada',
|
||||
'revision_cannot_delete_latest' => 'No se puede eliminar la última revisión.'
|
||||
];
|
||||
|
@ -265,4 +265,11 @@ return [
|
||||
'comment_updated_success' => 'Comentario actualizado',
|
||||
'comment_delete_confirm' => '¿Está seguro que quiere borrar este comentario?',
|
||||
'comment_in_reply_to' => 'En respuesta a :commentId',
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
'revision_delete_confirm' => 'Are you sure you want to delete this revision?',
|
||||
'revision_delete_success' => 'Revisión eliminada',
|
||||
'revision_cannot_delete_latest' => 'No se puede eliminar la última revisión.'
|
||||
];
|
||||
|
@ -265,4 +265,11 @@ return [
|
||||
'comment_updated_success' => 'Commentaire mis à jour',
|
||||
'comment_delete_confirm' => 'Etes-vous sûr de vouloir supprimer ce commentaire ?',
|
||||
'comment_in_reply_to' => 'En réponse à :commentId',
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
'revision_delete_confirm' => 'Êtes-vous sûr de vouloir supprimer cette révision?',
|
||||
'revision_delete_success' => 'Révision supprimée',
|
||||
'revision_cannot_delete_latest' => 'Impossible de supprimer la dernière révision.'
|
||||
];
|
@ -260,4 +260,11 @@ return [
|
||||
'comment_updated_success' => 'Commento aggiornato',
|
||||
'comment_delete_confirm' => 'Sei sicuro di voler elminare questo commento?',
|
||||
'comment_in_reply_to' => 'In risposta a :commentId',
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
'revision_delete_confirm' => 'Sei sicuro di voler eliminare questa revisione?',
|
||||
'revision_delete_success' => 'Revisione cancellata',
|
||||
'revision_cannot_delete_latest' => 'Impossibile eliminare l\'ultima revisione.'
|
||||
];
|
@ -257,4 +257,11 @@ return [
|
||||
'comment_updated_success' => 'コメントを更新しました',
|
||||
'comment_delete_confirm' => '本当にこのコメントを削除しますか?',
|
||||
'comment_in_reply_to' => ':commentIdへ返信',
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
'revision_delete_confirm' => 'このリビジョンを削除しますか?',
|
||||
'revision_delete_success' => 'リビジョンを削除しました',
|
||||
'revision_cannot_delete_latest' => '最新のリビジョンを削除できません。'
|
||||
];
|
||||
|
@ -259,4 +259,11 @@ return [
|
||||
'comment_updated_success' => 'Reactie bijgewerkt',
|
||||
'comment_delete_confirm' => 'Zeker reactie verwijderen?',
|
||||
'comment_in_reply_to' => 'Antwoord op :commentId',
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
'revision_delete_confirm' => 'Weet u zeker dat u deze revisie wilt verwijderen?',
|
||||
'revision_delete_success' => 'Revisie verwijderd',
|
||||
'revision_cannot_delete_latest' => 'Kan de laatste revisie niet verwijderen.'
|
||||
];
|
||||
|
@ -257,4 +257,11 @@ return [
|
||||
'comment_updated_success' => 'Komentarz zaktualizowany',
|
||||
'comment_delete_confirm' => 'Czy na pewno chcesz usunąc ten komentarz?',
|
||||
'comment_in_reply_to' => 'W odpowiedzi na :commentId',
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
'revision_delete_confirm' => 'Czy na pewno chcesz usunąć tę wersję?',
|
||||
'revision_delete_success' => 'Usunięto wersję',
|
||||
'revision_cannot_delete_latest' => 'Nie można usunąć najnowszej wersji.'
|
||||
];
|
@ -258,4 +258,11 @@ return [
|
||||
'comment_updated_success' => 'Comentário editado',
|
||||
'comment_delete_confirm' => 'Você tem certeza de que quer deletar este comentário?',
|
||||
'comment_in_reply_to' => 'Em resposta à :commentId',
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
'revision_delete_confirm' => 'Tem certeza de que deseja excluir esta revisão?',
|
||||
'revision_delete_success' => 'Revisão excluída',
|
||||
'revision_cannot_delete_latest' => 'Não é possível excluir a revisão mais recente.'
|
||||
];
|
@ -258,4 +258,11 @@ return [
|
||||
'comment_updated_success' => 'Комментарий обновлён',
|
||||
'comment_delete_confirm' => 'Вы уверенны, что хотите удалить этот комментарий?',
|
||||
'comment_in_reply_to' => 'В ответ на :commentId',
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
'revision_delete_confirm' => 'Вы действительно хотите удалить эту ревизию?',
|
||||
'revision_delete_success' => 'Редактирование удалено',
|
||||
'revision_cannot_delete_latest' => 'Не удается удалить последнюю версию.'
|
||||
];
|
@ -232,4 +232,11 @@ return [
|
||||
'comments' => 'Komentáre',
|
||||
'comment_placeholder' => 'Tu zadajte svoje pripomienky',
|
||||
'comment_save' => 'Uložiť komentár',
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
'revision_delete_confirm' => 'Naozaj chcete túto revíziu odstrániť?',
|
||||
'revision_delete_success' => 'Revízia bola vymazaná',
|
||||
'revision_cannot_delete_latest' => 'Nie je možné vymazať poslednú revíziu.'
|
||||
];
|
||||
|
@ -265,4 +265,11 @@ return [
|
||||
'comment_updated_success' => 'Kommentaren har uppdaterats',
|
||||
'comment_delete_confirm' => 'Är du säker på att du vill ta bort den här kommentaren?',
|
||||
'comment_in_reply_to' => 'Som svar på :commentId',
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
'revision_delete_confirm' => 'Är du säker på att du vill radera den här versionen?',
|
||||
'revision_delete_success' => 'Revisionen raderad',
|
||||
'revision_cannot_delete_latest' => 'Det går inte att ta bort den senaste versionen.'
|
||||
];
|
@ -258,4 +258,11 @@ return [
|
||||
'comment_updated_success' => '评论已更新',
|
||||
'comment_delete_confirm' => '你确定要删除这条评论?',
|
||||
'comment_in_reply_to' => '回复 :commentId',
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
'revision_delete_confirm' => '您确定要删除此修订版吗?',
|
||||
'revision_delete_success' => '修订删除',
|
||||
'revision_cannot_delete_latest' => '无法删除最新版本。'
|
||||
];
|
||||
|
@ -259,4 +259,11 @@ return [
|
||||
'comment_updated_success' => '評論已更新',
|
||||
'comment_delete_confirm' => '你確定要刪除這條評論?',
|
||||
'comment_in_reply_to' => '回覆 :commentId',
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
'revision_delete_confirm' => '您確定要刪除此修訂版嗎?',
|
||||
'revision_delete_success' => '修訂刪除',
|
||||
'revision_cannot_delete_latest' => '無法刪除最新版本。'
|
||||
];
|
||||
|
@ -36,16 +36,31 @@
|
||||
<td> @if($revision->createdBy) {{ $revision->createdBy->name }} @else {{ trans('common.deleted_user') }} @endif</td>
|
||||
<td><small>{{ $revision->created_at->format('jS F, Y H:i:s') }} <br> ({{ $revision->created_at->diffForHumans() }})</small></td>
|
||||
<td>{{ $revision->summary }}</td>
|
||||
<td>
|
||||
<td class="actions">
|
||||
<a href="{{ $revision->getUrl('changes') }}" target="_blank">{{ trans('entities.pages_revisions_changes') }}</a>
|
||||
<span class="text-muted"> | </span>
|
||||
|
||||
|
||||
@if ($index === 0)
|
||||
<a target="_blank" href="{{ $page->getUrl() }}"><i>{{ trans('entities.pages_revisions_current') }}</i></a>
|
||||
@else
|
||||
<a href="{{ $revision->getUrl() }}" target="_blank">{{ trans('entities.pages_revisions_preview') }}</a>
|
||||
<span class="text-muted"> | </span>
|
||||
<a href="{{ $revision->getUrl('restore') }}">{{ trans('entities.pages_revisions_restore') }}</a>
|
||||
<span class="text-muted"> | </span>
|
||||
<div dropdown class="dropdown-container">
|
||||
<a dropdown-toggle>{{ trans('common.delete') }}</a>
|
||||
<ul>
|
||||
<li class="padded"><small class="text-muted">{{trans('entities.revision_delete_confirm')}}</small></li>
|
||||
<li>
|
||||
<form action="{{ $revision->getUrl('/delete/') }}" method="POST">
|
||||
{!! csrf_field() !!}
|
||||
<input type="hidden" name="_method" value="DELETE">
|
||||
<button type="submit" class="text-button neg">@icon('delete'){{ trans('common.delete') }}</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -19,4 +19,4 @@
|
||||
color: {{ setting('app-color') }};
|
||||
fill: {{ setting('app-color') }};
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
@ -61,6 +61,7 @@ Route::group(['middleware' => 'auth'], function () {
|
||||
Route::get('/{bookSlug}/page/{pageSlug}/revisions/{revId}', 'PageController@showRevision');
|
||||
Route::get('/{bookSlug}/page/{pageSlug}/revisions/{revId}/changes', 'PageController@showRevisionChanges');
|
||||
Route::get('/{bookSlug}/page/{pageSlug}/revisions/{revId}/restore', 'PageController@restoreRevision');
|
||||
Route::delete('/{bookSlug}/page/{pageSlug}/revisions/{revId}/delete', 'PageController@destroyRevision');
|
||||
|
||||
// Chapters
|
||||
Route::get('/{bookSlug}/chapter/{chapterSlug}/create-page', 'PageController@create');
|
||||
@ -79,7 +80,6 @@ Route::group(['middleware' => 'auth'], function () {
|
||||
Route::put('/{bookSlug}/chapter/{chapterSlug}/permissions', 'ChapterController@restrict');
|
||||
Route::get('/{bookSlug}/chapter/{chapterSlug}/delete', 'ChapterController@showDelete');
|
||||
Route::delete('/{bookSlug}/chapter/{chapterSlug}', 'ChapterController@destroy');
|
||||
|
||||
});
|
||||
|
||||
// User Profile routes
|
||||
|
@ -11,7 +11,6 @@ class PageRevisionTest extends TestCase
|
||||
{
|
||||
$page = Page::first();
|
||||
$startCount = $page->revision_count;
|
||||
|
||||
$resp = $this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
|
||||
$resp->assertStatus(302);
|
||||
|
||||
@ -22,11 +21,43 @@ class PageRevisionTest extends TestCase
|
||||
{
|
||||
$page = Page::first();
|
||||
$this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
|
||||
$this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
|
||||
$page = Page::find($page->id);
|
||||
|
||||
$page = Page::find($page->id);
|
||||
$this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
|
||||
|
||||
$page = Page::find($page->id);
|
||||
$pageView = $this->get($page->getUrl());
|
||||
$pageView->assertSee('Revision #' . $page->revision_count);
|
||||
}
|
||||
|
||||
public function test_revision_deletion() {
|
||||
$page = Page::first();
|
||||
$this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
|
||||
|
||||
$page = Page::find($page->id);
|
||||
$this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
|
||||
|
||||
$page = Page::find($page->id);
|
||||
$beforeRevisionCount = $page->revisions->count();
|
||||
|
||||
// Delete the first revision
|
||||
$revision = $page->revisions->get(1);
|
||||
$resp = $this->asEditor()->delete($revision->getUrl('/delete/'));
|
||||
$resp->assertStatus(200);
|
||||
|
||||
$page = Page::find($page->id);
|
||||
$afterRevisionCount = $page->revisions->count();
|
||||
|
||||
$this->assertTrue($beforeRevisionCount === ($afterRevisionCount + 1));
|
||||
|
||||
// Try to delete the latest revision
|
||||
$beforeRevisionCount = $page->revisions->count();
|
||||
$currentRevision = $page->getCurrentRevision();
|
||||
$resp = $this->asEditor()->delete($currentRevision->getUrl('/delete/'));
|
||||
$resp->assertStatus(400);
|
||||
|
||||
$page = Page::find($page->id);
|
||||
$afterRevisionCount = $page->revisions->count();
|
||||
$this->assertTrue($beforeRevisionCount === $afterRevisionCount);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user