3 namespace BookStack\Http\Controllers;
5 use BookStack\Actions\ActivityType;
6 use BookStack\Entities\Repos\PageRepo;
7 use BookStack\Entities\Tools\PageContent;
8 use BookStack\Exceptions\NotFoundException;
9 use BookStack\Facades\Activity;
10 use Ssddanbrown\HtmlDiff\Diff;
12 class PageRevisionController extends Controller
17 * PageRevisionController constructor.
19 public function __construct(PageRepo $pageRepo)
21 $this->pageRepo = $pageRepo;
25 * Shows the last revisions for this page.
27 * @throws NotFoundException
29 public function index(string $bookSlug, string $pageSlug)
31 $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
32 $this->setPageTitle(trans('entities.pages_revisions_named', ['pageName'=>$page->getShortName()]));
34 return view('pages.revisions', [
41 * Shows a preview of a single revision.
43 * @throws NotFoundException
45 public function show(string $bookSlug, string $pageSlug, int $revisionId)
47 $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
48 $revision = $page->revisions()->where('id', '=', $revisionId)->first();
49 if ($revision === null) {
50 throw new NotFoundException();
53 $page->fill($revision->toArray());
54 // TODO - Refactor PageContent so we don't need to juggle this
55 $page->html = $revision->html;
56 $page->html = (new PageContent($page))->render();
58 $this->setPageTitle(trans('entities.pages_revision_named', ['pageName' => $page->getShortName()]));
60 return view('pages.revision', [
62 'book' => $page->book,
64 'revision' => $revision,
69 * Shows the changes of a single revision.
71 * @throws NotFoundException
73 public function changes(string $bookSlug, string $pageSlug, int $revisionId)
75 $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
76 $revision = $page->revisions()->where('id', '=', $revisionId)->first();
77 if ($revision === null) {
78 throw new NotFoundException();
81 $prev = $revision->getPrevious();
82 $prevContent = $prev->html ?? '';
83 $diff = Diff::excecute($prevContent, $revision->html);
85 $page->fill($revision->toArray());
86 // TODO - Refactor PageContent so we don't need to juggle this
87 $page->html = $revision->html;
88 $page->html = (new PageContent($page))->render();
89 $this->setPageTitle(trans('entities.pages_revision_named', ['pageName'=>$page->getShortName()]));
91 return view('pages.revision', [
93 'book' => $page->book,
95 'revision' => $revision,
100 * Restores a page using the content of the specified revision.
102 * @throws NotFoundException
104 public function restore(string $bookSlug, string $pageSlug, int $revisionId)
106 $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
107 $this->checkOwnablePermission('page-update', $page);
109 $page = $this->pageRepo->restoreRevision($page, $revisionId);
111 return redirect($page->getUrl());
115 * Deletes a revision using the id of the specified revision.
117 * @throws NotFoundException
119 public function destroy(string $bookSlug, string $pageSlug, int $revId)
121 $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
122 $this->checkOwnablePermission('page-delete', $page);
124 $revision = $page->revisions()->where('id', '=', $revId)->first();
125 if ($revision === null) {
126 throw new NotFoundException("Revision #{$revId} not found");
129 // Check if it's the latest revision, cannot delete the latest revision.
130 if (intval($page->currentRevision->id ?? null) === intval($revId)) {
131 $this->showErrorNotification(trans('entities.revision_cannot_delete_latest'));
133 return redirect($page->getUrl('/revisions'));
137 Activity::add(ActivityType::REVISION_DELETE, $revision);
138 $this->showSuccessNotification(trans('entities.revision_delete_success'));
140 return redirect($page->getUrl('/revisions'));