Added page & book slug history to revisions so they can be looked up if a page is not found.
use BookStack\Repos\BookRepo;
use BookStack\Repos\ChapterRepo;
use BookStack\Repos\PageRepo;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Views;
class PageController extends Controller
/**
* Display the specified page.
+ * If the page is not found via the slug the
+ * revisions are searched for a match.
*
* @param $bookSlug
* @param $pageSlug
public function show($bookSlug, $pageSlug)
{
$book = $this->bookRepo->getBySlug($bookSlug);
- $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
+
+ try {
+ $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
+ } catch (NotFoundHttpException $e) {
+ $page = $this->pageRepo->findPageUsingOldSlug($pageSlug, $bookSlug);
+ if ($page === null) abort(404);
+ return redirect($page->getUrl());
+ }
+
$sidebarTree = $this->bookRepo->getChildren($book);
Views::add($page);
$this->setPageTitle($page->getShortName());
use Illuminate\Support\Str;
use BookStack\Page;
use BookStack\PageRevision;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class PageRepo
{
public function getBySlug($slug, $bookId)
{
$page = $this->page->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
- if ($page === null) abort(404);
+ if ($page === null) throw new NotFoundHttpException('Page not found');
return $page;
}
/**
+ * Search through page revisions and retrieve
+ * the last page in the current book that
+ * has a slug equal to the one given.
+ * @param $pageSlug
+ * @param $bookSlug
+ * @return null | Page
+ */
+ public function findPageUsingOldSlug($pageSlug, $bookSlug)
+ {
+ $revision = $this->pageRevision->where('slug', '=', $pageSlug)
+ ->where('book_slug', '=', $bookSlug)->orderBy('created_at', 'desc')
+ ->with('page')->first();
+ return $revision !== null ? $revision->page : null;
+ }
+
+ /**
+ * Get a new Page instance from the given input.
* @param $input
* @return Page
*/
$this->saveRevision($page);
}
+ // Prevent slug being updated if no name change
+ if ($page->name !== $input['name']) {
+ $page->slug = $this->findSuitableSlug($input['name'], $book_id, $page->id);
+ }
+
// Update with new details
$page->fill($input);
- $page->slug = $this->findSuitableSlug($page->name, $book_id, $page->id);
$page->html = $this->formatHtml($input['html']);
$page->text = strip_tags($page->html);
$page->updated_by = auth()->user()->id;
{
$revision = $this->pageRevision->fill($page->toArray());
$revision->page_id = $page->id;
+ $revision->slug = $page->slug;
+ $revision->book_slug = $page->book->slug;
$revision->created_by = auth()->user()->id;
$revision->created_at = $page->updated_at;
$revision->save();
--- /dev/null
+<?php
+
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+class AddSlugToRevisions extends Migration
+{
+ /**
+ * Run the migrations.
+ *
+ * @return void
+ */
+ public function up()
+ {
+ Schema::table('page_revisions', function (Blueprint $table) {
+ $table->string('slug');
+ $table->index('slug');
+ $table->string('book_slug');
+ $table->index('book_slug');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('page_revisions', function (Blueprint $table) {
+ $table->dropColumn('slug');
+ $table->dropColumn('book_slug');
+ });
+ }
+}
->seeInNthElement('.entity-list .page', 0, $content['page']->name);
}
+ public function test_old_page_slugs_redirect_to_new_pages()
+ {
+ $page = \BookStack\Page::all()->first();
+ $pageUrl = $page->getUrl();
+ $newPageUrl = '/books/' . $page->book->slug . '/page/super-test-page';
+ $this->asAdmin()->visit($pageUrl)
+ ->clickInElement('#content', 'Edit')
+ ->type('super test page', '#name')
+ ->press('Save Page')
+ ->seePageIs($newPageUrl)
+ ->visit($pageUrl)
+ ->seePageIs($newPageUrl);
+ }
}