,
+ which can easily be styled with CSS.
+
+ @url https://github.com/paulgb/simplediff/blob/master/php/simplediff.php
+
+ Sorry for this kind of magic, I have no idea how this works.. :(
+*/
+
+class Differ
+{
+ public static function diff($old, $new)
+ {
+ $matrix = [];
+ $maxlen = 0;
+ foreach ($old as $oindex => $ovalue) {
+ $nkeys = array_keys($new, $ovalue);
+ foreach ($nkeys as $nindex) {
+ $matrix[$oindex][$nindex] = isset($matrix[$oindex - 1][$nindex - 1]) ? $matrix[$oindex - 1][$nindex - 1] + 1 : 1;
+ if ($matrix[$oindex][$nindex] > $maxlen) {
+ $maxlen = $matrix[$oindex][$nindex];
+ $omax = $oindex + 1 - $maxlen;
+ $nmax = $nindex + 1 - $maxlen;
+ }
+ }
+ }
+ if ($maxlen == 0) {
+ return [['d' => $old, 'i' => $new]];
+ }
+
+ return array_merge(self::diff(array_slice($old, 0, $omax), array_slice($new, 0, $nmax)), array_slice($new, $nmax, $maxlen), self::diff(array_slice($old, $omax + $maxlen), array_slice($new, $nmax + $maxlen)));
+ }
+
+ public static function htmlDiff($old, $new)
+ {
+ $ret = '';
+ $diff = self::diff(preg_split("/[\s]+/", $old), preg_split("/[\s]+/", $new));
+ foreach ($diff as $k) {
+ if (is_array($k)) {
+ $ret .= (!empty($k['d']) ? "" . implode(' ', $k['d']) . " " : '') . (!empty($k['i']) ? "" . implode(' ', $k['i']) . " " : '');
+ } else {
+ $ret .= $k . ' ';
+ }
+ }
+
+ return $ret;
+ }
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/Admin/History.php b/app/Http/Controllers/Admin/History.php
new file mode 100644
index 00000000..f7ad6d86
--- /dev/null
+++ b/app/Http/Controllers/Admin/History.php
@@ -0,0 +1,49 @@
+history = $history;
+ }
+
+ /**
+ * @param $id
+ *
+ * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
+ */
+ public function getOverview($id)
+ {
+ // test if given content id is static page and if exists
+ $content = Content::findOrFail($id);
+
+ $history = $this->history->getStructuredHistoryOf($content);
+
+ return view('admin/history.overview', [
+ 'history' => $history,
+ 'page' => $content
+ ]);
+ }
+
+ public function getDiff($revision, $id)
+ {
+ $change = $this->history->findOrFail($id);
+ $diff = $this->history->getDiff($change);
+
+ return view('admin/history.diff', [
+ 'change' => $change,
+ 'columnName' => 'Page content',
+ 'diff' => $diff
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/app/Http/routes.php b/app/Http/routes.php
index 763d8c64..b783ff42 100644
--- a/app/Http/routes.php
+++ b/app/Http/routes.php
@@ -81,6 +81,14 @@ Route::group([
Route::get('users/overview/{state?}/{perPage?}', 'UsersOverview@getOverview')
->name('users.overview');
+ // history of changes for specified page
+ Route::get('history/{id}', 'History@getOverview')
+ ->name('content.history');
+
+ // history of changes for specified page
+ Route::get('history/{revision}/{id}', 'History@getDiff')
+ ->name('history.diff');
+
// custom fields
// ------------------------------
diff --git a/app/Models/ContentHistory.php b/app/Models/ContentHistory.php
index 9c6e7ada..b5ea444c 100644
--- a/app/Models/ContentHistory.php
+++ b/app/Models/ContentHistory.php
@@ -2,6 +2,10 @@
namespace App\Models;
+use App\Handlers\Contracts\AppHandler;
+use App\Handlers\Contracts\HistoryHandler;
+use App\Handlers\Handler;
+use App\Helpers\Differ;
use Illuminate\Database\Eloquent\Model;
/**
@@ -10,10 +14,8 @@ use Illuminate\Database\Eloquent\Model;
class ContentHistory extends Model
{
protected $table = 'content_history';
-
// this table does not have created_at and updated_at fields
public $timestamps = false;
-
protected $fillable = [
'user_id',
'content_id',
@@ -22,8 +24,81 @@ class ContentHistory extends Model
'new_value',
'old_value'
];
-
protected $guarded = [];
-
+ /**
+ * Returns history grouped by revisions (edit_batches)
+ *
+ * @param Content $content
+ *
+ * @return array
+ */
+ public function getStructuredHistoryOf(Content $content)
+ {
+ $data = $content->history()
+ ->select('content_history.*', 'contents.module_handler', 'users.email AS user_email', 'users.name AS user_name')
+ ->join('users', 'users.id', '=', 'content_history.user_id')
+ ->join('contents', 'contents.id', '=', 'content_history.content_id')
+ ->orderBy('changed_at', 'DESC')
+ ->get();
+
+ $info = [];
+ $history = [];
+ foreach ($data as $change) {
+ $info[$change->edit_batch] = [
+ 'changed_at' => $change->changed_at,
+ 'user' => [
+ 'id' => $change->user_id,
+ 'name' => $change->user_name,
+ 'email' => $change->user_email
+ ]
+ ];
+
+ $change = $this->handleChangeset($change);
+
+ $history[$change->edit_batch][] = $change;
+ }
+
+ return [
+ 'changesets' => $history,
+ 'info' => $info
+ ];
+ }
+
+ /**
+ * @param $change
+ *
+ * @return HistoryHandler
+ */
+ protected function getHistoryHandler($change)
+ {
+ /**
+ * @var $handler AppHandler
+ * @var $historyHandler HistoryHandler
+ */
+
+ // get handler of given content page
+ if ($change->column == 'module_settings') {
+ $handler = $handler = $change->module_handler;
+ } else {
+ $handler = Handler::class;
+ }
+
+ return $handler::getHistoryHandler();
+ }
+
+ public function handleChangeset($change)
+ {
+ $historyHandler = $this->getHistoryHandler($change);
+
+ $change->column_trans = $historyHandler::parseColumnName($change->column);
+ $change->diff = $historyHandler::parseChangedValue($change);
+
+ return $change;
+ }
+
+ public function getDiff($change)
+ {
+ return Differ::htmlDiff($change->old_value, $change->new_value);
+ }
}
\ No newline at end of file
diff --git a/resources/assets/css/admin.css b/resources/assets/css/admin.css
index 8583030c..483d5e27 100644
--- a/resources/assets/css/admin.css
+++ b/resources/assets/css/admin.css
@@ -1,4 +1,13 @@
+del {
+ text-decoration: line-through;
+ color: red;
+}
+ins {
+ text-decoration: none;
+ color: green;
+}
+
.columns:last-child:not(:first-child), .column:last-child:not(:first-child) {
float: left;
}
diff --git a/resources/lang/en/admin/history.php b/resources/lang/en/admin/history.php
new file mode 100644
index 00000000..892f35e7
--- /dev/null
+++ b/resources/lang/en/admin/history.php
@@ -0,0 +1,16 @@
+ 'History of :name',
+ 'columnPageContent' => 'Page content',
+ 'columnUrl' => 'URL',
+ 'columnTitle' => 'Title',
+ 'columnMetaKeywords' => 'Meta keywords',
+ 'columnMetaDescription' => 'Description',
+ 'columnStatus' => 'Page visibility',
+ 'changedFromTo' => 'Changed from :from to :to',
+ 'numOfChanges' => 'One change|:count changes',
+ 'diff' => 'Difference',
+ 'diffPageName' => 'Difference of :column',
+ 'backToOverview' => 'Back to history overview'
+
+];
\ No newline at end of file
diff --git a/resources/views/admin/history/diff.blade.php b/resources/views/admin/history/diff.blade.php
new file mode 100644
index 00000000..ebc89eb6
--- /dev/null
+++ b/resources/views/admin/history/diff.blade.php
@@ -0,0 +1,21 @@
+@extends('admin.layout')
+
+@section('pageName', @trans('admin/history.diffPageName', ['column' => $columnName]))
+
+@section('content')
+
+
+
@lang('admin/history.diffPageName', ['column' => $columnName])
+
+
+
+
+ {!! $diff !!}
+
+
+
+@stop
\ No newline at end of file
diff --git a/resources/views/admin/history/overview.blade.php b/resources/views/admin/history/overview.blade.php
new file mode 100644
index 00000000..3ca98360
--- /dev/null
+++ b/resources/views/admin/history/overview.blade.php
@@ -0,0 +1,31 @@
+@extends('admin.layout')
+
+@section('pageName', @trans('admin/history.pageName', ['name' => $page->title]))
+
+@section('content')
+
+
+
@lang('admin/history.pageName', ['name' => $page->title])
+
+
+
+
+@stop
\ No newline at end of file