20 private $revisionLookup;
26 private $revisions = [];
29 private $textCache = [];
35 $this->revisionLookup = $revisionLookup;
36 $this->parser = $parser;
40 $fromRev = $this->getRevisionOrThrow(
'from' );
41 $toRev = $this->getRevisionOrThrow(
'to' );
43 if ( $fromRev->getPageId() !== $toRev->getPageId() ) {
48 if ( !$this->
getAuthority()->authorizeRead(
'read', $toRev->getPage() ) ) {
50 new MessageValue(
'rest-compare-permission-denied' ), 403 );
55 'id' => $fromRev->getId(),
56 'slot_role' => $this->getRole(),
57 'sections' => $this->getSectionInfo(
'from' )
60 'id' => $toRev->getId(),
61 'slot_role' => $this->getRole(),
62 'sections' => $this->getSectionInfo(
'to' )
64 'diff' => [
'PLACEHOLDER' => null ]
67 $wrapperJson = $rf->encodeJson( $data );
68 $diff = $this->getJsonDiff();
69 $response = $rf->create();
70 $response->setHeader(
'Content-Type',
'application/json' );
72 $innerDiff = substr( $diff, 1, -1 );
74 str_replace(
'"diff":{"PLACEHOLDER":null}', $innerDiff, $wrapperJson ) ) );
82 private function getRevision( $paramName ) {
83 if ( !isset( $this->revisions[$paramName] ) ) {
84 $this->revisions[$paramName] =
87 return $this->revisions[$paramName];
95 private function getRevisionOrThrow( $paramName ) {
96 $rev = $this->getRevision( $paramName );
98 throw new LocalizedHttpException(
99 new MessageValue(
'rest-compare-nonexistent', [ $paramName ] ), 404 );
102 if ( !$this->isAccessible( $rev ) ) {
103 throw new LocalizedHttpException(
104 new MessageValue(
'rest-compare-inaccessible', [ $paramName ] ), 403 );
113 private function isAccessible( $rev ) {
114 return $rev->userCan( RevisionRecord::DELETED_TEXT, $this->
getAuthority() );
117 private function getRole() {
118 return SlotRecord::MAIN;
121 private function getRevisionText( $paramName ) {
122 if ( !isset( $this->textCache[$paramName] ) ) {
123 $revision = $this->getRevision( $paramName );
126 ->getSlot( $this->getRole(), RevisionRecord::FOR_THIS_USER, $this->
getAuthority() )
130 $this->textCache[$paramName] =
$content->getText();
132 throw new LocalizedHttpException(
134 'rest-compare-wrong-content',
135 [ $this->getRole(), $paramName ]
139 }
catch ( SuppressedDataException $e ) {
140 throw new LocalizedHttpException(
141 new MessageValue(
'rest-compare-inaccessible', [ $paramName ] ), 403 );
142 }
catch ( RevisionAccessException $e ) {
143 throw new LocalizedHttpException(
144 new MessageValue(
'rest-compare-nonexistent', [ $paramName ] ), 404 );
147 return $this->textCache[$paramName];
153 private function getJsonDiff() {
156 $fromText = $this->getRevisionText(
'from' );
157 $toText = $this->getRevisionText(
'to' );
158 if ( !function_exists(
'wikidiff2_inline_json_diff' ) ) {
159 throw new LocalizedHttpException(
160 new MessageValue(
'rest-compare-wikidiff2' ), 500 );
162 return wikidiff2_inline_json_diff( $fromText, $toText, 2 );
169 private function getSectionInfo( $paramName ) {
170 $text = $this->getRevisionText( $paramName );
171 $parserSections = $this->parser->getFlatSectionInfo( $text );
173 foreach ( $parserSections as $i => $parserSection ) {
178 'level' => $parserSection[
'level'],
179 'heading' => $parserSection[
'heading'],
180 'offset' => $parserSection[
'offset'],
190 ParamValidator::PARAM_TYPE =>
'integer',
191 ParamValidator::PARAM_REQUIRED =>
true,
195 ParamValidator::PARAM_TYPE =>
'integer',
196 ParamValidator::PARAM_REQUIRED =>
true,
Content object implementation for representing flat text.