Merge branch '3.0'
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / page / EditHistoryPage.class.php
CommitLineData
c1c06a6a
TD
1<?php
2namespace wcf\page;
3use wcf\data\edit\history\entry\EditHistoryEntry;
5e40b0b2 4use wcf\data\edit\history\entry\EditHistoryEntryList;
849204bd 5use wcf\data\object\type\ObjectType;
c1c06a6a 6use wcf\data\object\type\ObjectTypeCache;
2c04b6a9 7use wcf\data\DatabaseObjectList;
849204bd 8use wcf\system\edit\IHistorySavingObject;
e4499881 9use wcf\system\edit\IHistorySavingObjectTypeProvider;
c1c06a6a 10use wcf\system\exception\IllegalLinkException;
4b3690e1 11use wcf\system\request\LinkHandler;
c1c06a6a
TD
12use wcf\system\WCF;
13use wcf\util\Diff;
4b3690e1 14use wcf\util\HeaderUtil;
c1c06a6a
TD
15use wcf\util\StringUtil;
16
17/**
18 * Compares two templates.
19 *
20 * @author Tim Duesterhus
c839bd49 21 * @copyright 2001-2018 WoltLab GmbH
c1c06a6a 22 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
e71525e4 23 * @package WoltLabSuite\Core\Page
c1c06a6a
TD
24 */
25class EditHistoryPage extends AbstractPage {
77838209 26 /**
849204bd 27 * @inheritDoc
77838209 28 */
849204bd 29 public $neededModules = ['MODULE_EDIT_HISTORY'];
77838209 30
5e40b0b2
TD
31 /**
32 * DatabaseObjectList object
849204bd 33 * @var DatabaseObjectList
5e40b0b2 34 */
849204bd 35 public $objectList;
1a6e8c52 36
c1c06a6a
TD
37 /**
38 * left / old version id
39 * @var integer
40 */
41 public $oldID = 0;
42
43 /**
44 * left / old version
849204bd 45 * @var EditHistoryEntry
c1c06a6a 46 */
849204bd 47 public $old;
c1c06a6a
TD
48
49 /**
50 * right / new version id
51 * @var integer
52 */
53 public $newID = 0;
54
55 /**
56 * right / new version
849204bd 57 * @var EditHistoryEntry
c1c06a6a 58 */
849204bd 59 public $new;
c1c06a6a
TD
60
61 /**
62 * differences between both versions
849204bd 63 * @var Diff
c1c06a6a 64 */
849204bd 65 public $diff;
c1c06a6a 66
c1c06a6a
TD
67 /**
68 * object type of the requested object
849204bd 69 * @var ObjectType
c1c06a6a 70 */
849204bd 71 public $objectType;
c1c06a6a
TD
72
73 /**
74 * id of the requested object
75 * @var integer
76 */
77 public $objectID = 0;
78
79 /**
80 * requested object
849204bd 81 * @var IHistorySavingObject
c1c06a6a 82 */
849204bd 83 public $object;
c1c06a6a
TD
84
85 /**
849204bd 86 * @inheritDoc
5e40b0b2 87 */
c1c06a6a
TD
88 public function readParameters() {
89 parent::readParameters();
90
ca1f89cf 91 if (isset($_REQUEST['oldID'])) {
c1c06a6a
TD
92 $this->oldID = intval($_REQUEST['oldID']);
93 $this->old = new EditHistoryEntry($this->oldID);
94 if (!$this->old->entryID) throw new IllegalLinkException();
95
ca1f89cf 96 if (isset($_REQUEST['newID']) && $_REQUEST['newID'] !== 'current') {
c1c06a6a
TD
97 $this->newID = intval($_REQUEST['newID']);
98 $this->new = new EditHistoryEntry($this->newID);
99 if (!$this->new->entryID) throw new IllegalLinkException();
100 }
101
102 // if new version isn't 'current' check whether they are comparable
103 if ($this->new) {
104 // different objectTypes cannot be compared
105 if ($this->old->objectTypeID != $this->new->objectTypeID) throw new IllegalLinkException();
106 // different items cannot be compared
107 if ($this->old->objectID != $this->new->objectID) throw new IllegalLinkException();
108 }
109
110 $this->objectID = $this->old->objectID;
812915cc 111 $this->objectType = ObjectTypeCache::getInstance()->getObjectType($this->old->objectTypeID);
c1c06a6a 112 }
812915cc 113 else if (isset($_REQUEST['objectID']) && isset($_REQUEST['objectType'])) {
c1c06a6a 114 $this->objectID = intval($_REQUEST['objectID']);
812915cc 115 $this->objectType = ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.edit.historySavingObject', $_REQUEST['objectType']);
c1c06a6a
TD
116 }
117 else {
118 throw new IllegalLinkException();
119 }
120
c4a4a442 121 if (!$this->objectType) throw new IllegalLinkException();
e4499881
MS
122
123 /** @var IHistorySavingObjectTypeProvider $processor */
c1c06a6a 124 $processor = $this->objectType->getProcessor();
e4499881
MS
125
126 /** @var IHistorySavingObject object */
c1c06a6a 127 $this->object = $processor->getObjectByID($this->objectID);
f9c4a0ba 128 if (!$this->object->getObjectID()) throw new IllegalLinkException();
c1c06a6a 129 $processor->checkPermissions($this->object);
849204bd 130 $this->object->setLocation();
c1c06a6a 131
c4a4a442 132 if (isset($_REQUEST['newID']) && !$this->new) {
c1c06a6a 133 $this->new = $this->object;
519200eb 134 $this->newID = 'current';
c1c06a6a 135 }
4b3690e1
MW
136
137 if (!empty($_POST)) {
849204bd 138 HeaderUtil::redirect(LinkHandler::getInstance()->getLink('EditHistory', [
4b3690e1
MW
139 'objectID' => $this->objectID,
140 'objectType' => $this->objectType->objectType,
141 'newID' => $this->newID,
142 'oldID' => $this->oldID
849204bd 143 ]));
4b3690e1
MW
144 exit;
145 }
c1c06a6a
TD
146 }
147
148 /**
849204bd 149 * @inheritDoc
996db334 150 */
c1c06a6a
TD
151 public function readData() {
152 parent::readData();
153
5e40b0b2 154 $this->objectList = new EditHistoryEntryList();
fd1a6431 155 $this->objectList->sqlOrderBy = "time DESC, entryID DESC";
849204bd
AE
156 $this->objectList->getConditionBuilder()->add('objectTypeID = ?', [$this->objectType->objectTypeID]);
157 $this->objectList->getConditionBuilder()->add('objectID = ?', [$this->objectID]);
5e40b0b2
TD
158 $this->objectList->readObjects();
159
c1c06a6a 160 // valid IDs were given, calculate diff
ca1f89cf 161 if ($this->old && $this->new) {
b32308d4
TD
162 $a = explode("\n", StringUtil::unifyNewlines(StringUtil::trim($this->old->getMessage())));
163 $b = explode("\n", StringUtil::unifyNewlines(StringUtil::trim($this->new->getMessage())));
948b2593
TD
164 $diff = new Diff($a, $b);
165 $this->diff = $diff->getRawDiff();
166
167 // create word diff for small changes (only one consecutive paragraph modified)
168 for ($i = 0, $max = count($this->diff); $i < $max;) {
169 $previousIsNotRemoved = !isset($this->diff[$i - 1][0]) || $this->diff[$i - 1][0] !== Diff::REMOVED;
170 $currentIsRemoved = $this->diff[$i][0] === Diff::REMOVED;
171 $nextIsAdded = isset($this->diff[$i + 1][0]) && $this->diff[$i + 1][0] === Diff::ADDED;
172 $afterNextIsNotAdded = !isset($this->diff[$i + 2][0]) || $this->diff[$i + 2][0] !== Diff::ADDED;
173
174 if ($previousIsNotRemoved && $currentIsRemoved && $nextIsAdded && $afterNextIsNotAdded) {
175 $a = preg_split('/(\\W)/u', $this->diff[$i][1], -1, PREG_SPLIT_DELIM_CAPTURE);
176 $b = preg_split('/(\\W)/u', $this->diff[$i + 1][1], -1, PREG_SPLIT_DELIM_CAPTURE);
177
178 $diff = new Diff($a, $b);
179 $this->diff[$i][1] = '';
180 $this->diff[$i + 1][1] = '';
181 foreach ($diff->getRawDiff() as $entry) {
182 $entry[1] = StringUtil::encodeHTML($entry[1]);
183
184 if ($entry[0] === Diff::SAME) {
185 $this->diff[$i][1] .= $entry[1];
186 $this->diff[$i + 1][1] .= $entry[1];
187 }
188 else if ($entry[0] === Diff::REMOVED) {
189 $this->diff[$i][1] .= '<strong>'.$entry[1].'</strong>';
190 }
191 else if ($entry[0] === Diff::ADDED) {
192 $this->diff[$i + 1][1] .= '<strong>'.$entry[1].'</strong>';
193 }
194 }
195 $i += 2;
196 }
197 else {
198 $this->diff[$i][1] = StringUtil::encodeHTML($this->diff[$i][1]);
199 $i++;
200 }
201 }
c1c06a6a 202 }
4a89a7d1
MW
203
204 // set default values
205 if (!isset($_REQUEST['oldID']) && !isset($_REQUEST['newID'])) {
206 foreach ($this->objectList as $object) {
207 $this->oldID = $object->entryID;
208 break;
209 }
210 $this->newID = 'current';
211 }
c1c06a6a
TD
212 }
213
214 /**
849204bd 215 * @inheritDoc
996db334 216 */
c1c06a6a
TD
217 public function assignVariables() {
218 parent::assignVariables();
219
849204bd 220 WCF::getTPL()->assign([
c1c06a6a
TD
221 'oldID' => $this->oldID,
222 'old' => $this->old,
223 'newID' => $this->newID,
224 'new' => $this->new,
225 'object' => $this->object,
5e40b0b2 226 'diff' => $this->diff,
812915cc
TD
227 'objects' => $this->objectList,
228 'objectID' => $this->objectID,
229 'objectType' => $this->objectType
849204bd 230 ]);
c1c06a6a
TD
231 }
232}