]> BookStack Code Mirror - bookstack/commitdiff
Added page revisions. Fixes #2
authorDan Brown <redacted>
Sun, 9 Aug 2015 11:06:52 +0000 (12:06 +0100)
committerDan Brown <redacted>
Sun, 9 Aug 2015 11:06:52 +0000 (12:06 +0100)
app/Http/Controllers/PageController.php
app/Http/routes.php
app/Page.php
app/PageRevision.php [new file with mode: 0644]
app/Repos/PageRepo.php
database/migrations/2015_08_09_093534_create_page_revisions_table.php [new file with mode: 0644]
resources/views/pages/page-display.blade.php [new file with mode: 0644]
resources/views/pages/revision.blade.php [new file with mode: 0644]
resources/views/pages/revisions.blade.php [new file with mode: 0644]
resources/views/pages/show.blade.php

index b660819282a10eada9bc6a0198ada92dd656ff15..b64290eaa24ecd35d84fda4872ac2118d6a5e1be 100644 (file)
@@ -31,19 +31,8 @@ class PageController extends Controller
         $this->chapterRepo = $chapterRepo;
     }
 
-
     /**
-     * Display a listing of the resource.
-     *
-     * @return Response
-     */
-    public function index()
-    {
-        //
-    }
-
-    /**
-     * Show the form for creating a new resource.
+     * Show the form for creating a new page.
      *
      * @param $bookSlug
      * @param bool $chapterSlug
@@ -58,7 +47,7 @@ class PageController extends Controller
     }
 
     /**
-     * Store a newly created resource in storage.
+     * Store a newly created page in storage.
      *
      * @param  Request $request
      * @param $bookSlug
@@ -86,11 +75,12 @@ class PageController extends Controller
         $page->created_by = Auth::user()->id;
         $page->updated_by = Auth::user()->id;
         $page->save();
+        $this->pageRepo->saveRevision($page);
         return redirect($page->getUrl());
     }
 
     /**
-     * Display the specified resource.
+     * Display the specified page.
      *
      * @param $bookSlug
      * @param $pageSlug
@@ -100,12 +90,11 @@ class PageController extends Controller
     {
         $book = $this->bookRepo->getBySlug($bookSlug);
         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
-        //dd($sidebarBookTree);
         return view('pages/show', ['page' => $page, 'book' => $book]);
     }
 
     /**
-     * Show the form for editing the specified resource.
+     * Show the form for editing the specified page.
      *
      * @param $bookSlug
      * @param $pageSlug
@@ -119,7 +108,7 @@ class PageController extends Controller
     }
 
     /**
-     * Update the specified resource in storage.
+     * Update the specified page in storage.
      *
      * @param  Request $request
      * @param $bookSlug
@@ -130,11 +119,7 @@ class PageController extends Controller
     {
         $book = $this->bookRepo->getBySlug($bookSlug);
         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
-        $page->fill($request->all());
-        $page->slug = $this->pageRepo->findSuitableSlug($page->name, $book->id, $page->id);
-        $page->text = strip_tags($page->html);
-        $page->updated_by = Auth::user()->id;
-        $page->save();
+        $this->pageRepo->updatePage($page, $book->id, $request->all());
         return redirect($page->getUrl());
     }
 
@@ -205,6 +190,12 @@ class PageController extends Controller
         return redirect($book->getUrl());
     }
 
+    /**
+     * Show the deletion page for the specified page.
+     * @param $bookSlug
+     * @param $pageSlug
+     * @return \Illuminate\View\View
+     */
     public function showDelete($bookSlug, $pageSlug)
     {
         $book = $this->bookRepo->getBySlug($bookSlug);
@@ -213,7 +204,7 @@ class PageController extends Controller
     }
 
     /**
-     * Remove the specified resource from storage.
+     * Remove the specified page from storage.
      *
      * @param $bookSlug
      * @param $pageSlug
@@ -227,4 +218,42 @@ class PageController extends Controller
         $page->delete();
         return redirect($book->getUrl());
     }
+
+    /**
+     * Shows the last revisions for this page.
+     * @param $bookSlug
+     * @param $pageSlug
+     * @return \Illuminate\View\View
+     */
+    public function showRevisions($bookSlug, $pageSlug)
+    {
+        $book = $this->bookRepo->getBySlug($bookSlug);
+        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
+        return view('pages/revisions', ['page' => $page, 'book' => $book]);
+    }
+
+    /**
+     * Shows a preview of a single revision
+     * @param $bookSlug
+     * @param $pageSlug
+     * @param $revisionId
+     * @return \Illuminate\View\View
+     */
+    public function showRevision($bookSlug, $pageSlug, $revisionId)
+    {
+        $book = $this->bookRepo->getBySlug($bookSlug);
+        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
+        $revision = $this->pageRepo->getRevisionById($revisionId);
+        $page->fill($revision->toArray());
+        return view('pages/revision', ['page' => $page, 'book' => $book]);
+    }
+
+    public function restoreRevision($bookSlug, $pageSlug, $revisionId)
+    {
+        $book = $this->bookRepo->getBySlug($bookSlug);
+        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
+        $revision = $this->pageRepo->getRevisionById($revisionId);
+        $page = $this->pageRepo->updatePage($page, $book->id, $revision->toArray());
+        return redirect($page->getUrl());
+    }
 }
index d1ea3e854e79d714c40830f5d12cd8b5fe816c61..3065f7eb50b6b85b088e3e24007fc26144c5390a 100644 (file)
@@ -18,6 +18,7 @@ Route::group(['middleware' => 'auth'], function() {
 
     Route::group(['prefix' => 'books'], function() {
 
+        // Books
         Route::get('/', 'BookController@index');
         Route::get('/create', 'BookController@create');
         Route::post('/', 'BookController@store');
@@ -27,6 +28,7 @@ Route::group(['middleware' => 'auth'], function() {
         Route::get('/{slug}', 'BookController@show');
         Route::get('/{slug}/delete', 'BookController@showDelete');
 
+        // Pages
         Route::get('/{bookSlug}/page/create', 'PageController@create');
         Route::post('/{bookSlug}/page', 'PageController@store');
         Route::get('/{bookSlug}/sort', 'PageController@sortPages');
@@ -36,7 +38,12 @@ Route::group(['middleware' => 'auth'], function() {
         Route::get('/{bookSlug}/page/{pageSlug}/delete', 'PageController@showDelete');
         Route::put('/{bookSlug}/page/{pageSlug}', 'PageController@update');
         Route::delete('/{bookSlug}/page/{pageSlug}', 'PageController@destroy');
+        //Revisions
+        Route::get('/{bookSlug}/page/{pageSlug}/revisions', 'PageController@showRevisions');
+        Route::get('/{bookSlug}/page/{pageSlug}/revisions/{revId}', 'PageController@showRevision');
+        Route::get('/{bookSlug}/page/{pageSlug}/revisions/{revId}/restore', 'PageController@restoreRevision');
 
+        // Chapters
         Route::get('/{bookSlug}/chapter/{chapterSlug}/create-page', 'PageController@create');
         Route::get('/{bookSlug}/chapter/create', 'ChapterController@create');
         Route::post('/{bookSlug}/chapter/create', 'ChapterController@store');
index fd90b6d48f8131bca30b3adbf87ca7cd5c9f9b68..8ae744a8aed7af56594f021ca1a3f4ead4e3236a 100644 (file)
@@ -42,6 +42,11 @@ class Page extends Model
         return $this->belongsTo('Oxbow\User', 'updated_by');
     }
 
+    public function revisions()
+    {
+        return $this->hasMany('Oxbow\PageRevision')->orderBy('created_at', 'desc');
+    }
+
     public function getUrl()
     {
         return '/books/' . $this->book->slug . '/page/' . $this->slug;
diff --git a/app/PageRevision.php b/app/PageRevision.php
new file mode 100644 (file)
index 0000000..baabe0f
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+
+namespace Oxbow;
+
+use Illuminate\Database\Eloquent\Model;
+
+class PageRevision extends Model
+{
+    protected $fillable = ['name', 'html', 'text'];
+
+    public function createdBy()
+    {
+        return $this->belongsTo('Oxbow\User', 'created_by');
+    }
+
+    public function page()
+    {
+        return $this->belongsTo('Oxbow\Page');
+    }
+
+    public function getUrl()
+    {
+        return $this->page->getUrl() . '/revisions/' . $this->id;
+    }
+
+}
index 99be07d7ad38077b9610bcbabf87d57412519132..52620961f33c202ef1ac95c1cad3616eb8f5ee82 100644 (file)
@@ -1,20 +1,25 @@
 <?php namespace Oxbow\Repos;
 
 
+use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Str;
 use Oxbow\Page;
+use Oxbow\PageRevision;
 
 class PageRepo
 {
     protected $page;
+    protected $pageRevision;
 
     /**
      * PageRepo constructor.
-     * @param $page
+     * @param Page $page
+     * @param PageRevision $pageRevision
      */
-    public function __construct(Page $page)
+    public function __construct(Page $page, PageRevision $pageRevision)
     {
         $this->page = $page;
+        $this->pageRevision = $pageRevision;
     }
 
     public function idExists($id)
@@ -64,6 +69,68 @@ class PageRepo
         return $query->get();
     }
 
+    /**
+     * Updates a page with any fillable data and saves it into the database.
+     * @param Page $page
+     * @param $book_id
+     * @param $data
+     * @return Page
+     */
+    public function updatePage(Page $page, $book_id, $data)
+    {
+        $page->fill($data);
+        $page->slug = $this->findSuitableSlug($page->name, $book_id, $page->id);
+        $page->text = strip_tags($page->html);
+        $page->updated_by = Auth::user()->id;
+        $page->save();
+        $this->saveRevision($page);
+        return $page;
+    }
+
+    /**
+     * Saves a page revision into the system.
+     * @param Page $page
+     * @return $this
+     */
+    public function saveRevision(Page $page)
+    {
+        $lastRevision = $this->getLastRevision($page);
+        if($lastRevision && ($lastRevision->html === $page->html && $lastRevision->name === $page->name)) {
+            return $page;
+        }
+        $revision = $this->pageRevision->fill($page->toArray());
+        $revision->page_id = $page->id;
+        $revision->created_by = Auth::user()->id;
+        $revision->save();
+        // Clear old revisions
+        if($this->pageRevision->where('page_id', '=', $page->id)->count() > 50) {
+            $this->pageRevision->where('page_id', '=', $page->id)
+                ->orderBy('created_at', 'desc')->skip(50)->take(5)->delete();
+        }
+        return $revision;
+    }
+
+    /**
+     * Gets the most recent revision for a page.
+     * @param Page $page
+     * @return mixed
+     */
+    public function getLastRevision(Page $page)
+    {
+        return $this->pageRevision->where('page_id', '=', $page->id)
+            ->orderBy('created_at', 'desc')->first();
+    }
+
+    /**
+     * Gets a single revision via it's id.
+     * @param $id
+     * @return mixed
+     */
+    public function getRevisionById($id)
+    {
+        return $this->pageRevision->findOrFail($id);
+    }
+
     /**
      * Checks if a slug exists within a book already.
      * @param $slug
diff --git a/database/migrations/2015_08_09_093534_create_page_revisions_table.php b/database/migrations/2015_08_09_093534_create_page_revisions_table.php
new file mode 100644 (file)
index 0000000..b55097f
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+class CreatePageRevisionsTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('page_revisions', function (Blueprint $table) {
+            $table->increments('id');
+            $table->integer('page_id')->indexed();
+            $table->string('name');
+            $table->longText('html');
+            $table->longText('text');
+            $table->integer('created_by');
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::drop('page_revisions');
+    }
+}
diff --git a/resources/views/pages/page-display.blade.php b/resources/views/pages/page-display.blade.php
new file mode 100644 (file)
index 0000000..6eb623b
--- /dev/null
@@ -0,0 +1,10 @@
+<h1>{{$page->name}}</h1>
+@if(count($page->children) > 0)
+    <h4 class="text-muted">Sub-pages</h4>
+    <div class="page-list">
+        @foreach($page->children as $childPage)
+            <a href="{{ $childPage->getUrl() }}">{{ $childPage->name }}</a>
+        @endforeach
+    </div>
+@endif
+{!! $page->html !!}
\ No newline at end of file
diff --git a/resources/views/pages/revision.blade.php b/resources/views/pages/revision.blade.php
new file mode 100644 (file)
index 0000000..9f16789
--- /dev/null
@@ -0,0 +1,9 @@
+@extends('base')
+
+@section('content')
+
+    <div class="page-content">
+        @include('pages/page-display')
+    </div>
+
+@stop
diff --git a/resources/views/pages/revisions.blade.php b/resources/views/pages/revisions.blade.php
new file mode 100644 (file)
index 0000000..03ed0ce
--- /dev/null
@@ -0,0 +1,47 @@
+@extends('base')
+
+@section('content')
+
+    <div class="row faded-small">
+        <div class="col-md-6 faded">
+            <div class="breadcrumbs padded-horizontal">
+                <a href="{{$page->getUrl()}}" class="text-primary"><i class="zmdi zmdi-arrow-left"></i>Back to page</a>
+            </div>
+        </div>
+        <div class="col-md-6 faded">
+        </div>
+    </div>
+
+    <div class="page-content">
+        <h1>Page Revisions <span class="subheader">For "{{ $page->name }}"</span></h1>
+
+        @if(count($page->revisions) > 0)
+
+            <table class="table">
+                <tr>
+                    <th>Name</th>
+                    <th>Created By</th>
+                    <th>Revision Date</th>
+                    <th>Actions</th>
+                </tr>
+                @foreach($page->revisions as $revision)
+                    <tr>
+                        <td>{{$revision->name}}</td>
+                        <td>{{$revision->createdBy->name}}</td>
+                        <td><small>{{$revision->created_at->format('jS F, Y H:i:s')}} ({{$revision->created_at->diffForHumans()}})</small></td>
+                        <td>
+                            <a href="{{$revision->getUrl()}}" target="_blank">Preview</a>
+                            <span class="text-muted">&nbsp;|&nbsp;</span>
+                            <a href="{{$revision->getUrl()}}/restore">Restore</a>
+                        </td>
+                    </tr>
+                @endforeach
+            </table>
+
+        @else
+            <p>This page has no revisions.</p>
+        @endif
+
+    </div>
+
+@stop
index 2fae349526e6322396eb504558d329f31a39aed4..3149b6945f3619e337b57a6f3d8a94e8dbc52c03 100644 (file)
@@ -17,6 +17,7 @@
         </div>
         <div class="col-md-6 faded">
             <div class="action-buttons">
+                <a href="{{$page->getUrl() . '/revisions'}}" class="text-primary"><i class="zmdi zmdi-replay"></i>Revisions</a>
                 <a href="{{$page->getUrl() . '/edit'}}" class="text-primary" ><i class="zmdi zmdi-edit"></i>Edit</a>
                 <a href="{{$page->getUrl() . '/delete'}}" class="text-neg"><i class="zmdi zmdi-delete"></i>Delete</a>
             </div>
 
 
     <div class="page-content">
-        <h1>{{$page->name}}</h1>
-        @if(count($page->children) > 0)
-            <h4 class="text-muted">Sub-pages</h4>
-            <div class="page-list">
-                @foreach($page->children as $childPage)
-                    <a href="{{ $childPage->getUrl() }}">{{ $childPage->name }}</a>
-                @endforeach
-            </div>
-        @endif
-        {!! $page->html !!}
-
+        @include('pages/page-display')
         <hr>
         <p class="text-muted small">
             Created {{$page->created_at->diffForHumans()}} @if($page->createdBy) by {{$page->createdBy->name}} @endif