--- /dev/null
+<?php namespace BookStack\Exceptions;
+
+class BadRequestException extends PrettyException
+{
+
+ /**
+ * BadRequestException constructor.
+ * @param string $message
+ */
+ public function __construct($message = 'Bad request')
+ {
+ parent::__construct($message, 400);
+ }
+}
use Activity;
use BookStack\Exceptions\NotFoundException;
+use BookStack\Exceptions\BadRequestException;
use BookStack\Repos\EntityRepo;
use BookStack\Repos\UserRepo;
use BookStack\Services\ExportService;
return redirect($page->getUrl());
}
+
+ /**
+ * Deletes a revision using the id of the specified revision.
+ * @param string $bookSlug
+ * @param string $pageSlug
+ * @param int $revisionId
+ * @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-update', $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
+ $current = $revision->getCurrent();
+
+ // Check if its the latest revision, cannot delete latest revision.
+ if (intval($current->id) === intval($revId)) {
+ throw new BadRequestException("Cannot delete the current revision #{$revId}");
+ }
+
+ $revision->delete();
+ return view('pages/revisions', ['page' => $page, 'book' => $page->book, 'current' => $page]);
+ }
+
/**
* Exports a page to a PDF.
* https://github.com/barryvdh/laravel-dompdf
return null;
}
+ /**
+ * Get the current revision for the same page if existing
+ * @return \BookStack\PageRevision|null
+ */
+ public function getCurrent()
+ {
+ if ($id = static::where('page_id', '=', $this->page_id)->max('id')) {
+ return static::find($id);
+ }
+ return null;
+ }
+
/**
* Allows checking of the exact class, Used to check entity type.
* Included here to align with entities in similar use cases.
&.neg {
color: $negative;
}
+ &.link {
+ &:hover {
+ text-decoration: underline;
+ }
+ }
}
.button-group {
padding: $-xs $-m;
line-height: 1.2;
}
- a {
+ a, button {
display: block;
padding: $-xs $-m;
color: #555;
width: 16px;
}
}
+ button {
+ width: 100%;
+ text-align: left;
+ }
li.border-bottom {
border-bottom: 1px solid #DDD;
}
.text-center {
text-align: center;
}
+ td.actions {
+ overflow: visible;
+ }
}
table.no-style {
<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">
+ <button type="button" dropdown-toggle class="text-button link">{{ trans('common.delete') }}</button>
+ <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>
color: {{ setting('app-color') }};
fill: {{ setting('app-color') }};
}
-</style>
\ No newline at end of file
+</style>
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');
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