23 private $revisions = [];
26 private $textCache = [];
32 $this->revisionLookup = $revisionLookup;
33 $this->parserFactory = $parserFactory;
37 $fromRev = $this->getRevisionOrThrow(
'from' );
38 $toRev = $this->getRevisionOrThrow(
'to' );
40 if ( $fromRev->getPageId() !== $toRev->getPageId() ) {
45 if ( !$this->
getAuthority()->authorizeRead(
'read', $toRev->getPage() ) ) {
47 new MessageValue(
'rest-compare-permission-denied' ), 403 );
52 'id' => $fromRev->getId(),
53 'slot_role' => $this->getRole(),
54 'sections' => $this->getSectionInfo(
'from' )
57 'id' => $toRev->getId(),
58 'slot_role' => $this->getRole(),
59 'sections' => $this->getSectionInfo(
'to' )
61 'diff' => [
'PLACEHOLDER' => null ]
64 $wrapperJson = $rf->encodeJson( $data );
65 $diff = $this->getJsonDiff();
66 $response = $rf->create();
67 $response->setHeader(
'Content-Type',
'application/json' );
69 $innerDiff = substr( $diff, 1, -1 );
71 str_replace(
'"diff":{"PLACEHOLDER":null}', $innerDiff, $wrapperJson ) ) );
79 private function getRevision( $paramName ) {
80 if ( !isset( $this->revisions[$paramName] ) ) {
81 $this->revisions[$paramName] =
84 return $this->revisions[$paramName];
92 private function getRevisionOrThrow( $paramName ) {
93 $rev = $this->getRevision( $paramName );
95 throw new LocalizedHttpException(
96 new MessageValue(
'rest-compare-nonexistent', [ $paramName ] ), 404 );
99 if ( !$this->isAccessible( $rev ) ) {
100 throw new LocalizedHttpException(
101 new MessageValue(
'rest-compare-inaccessible', [ $paramName ] ), 403 );
110 private function isAccessible( $rev ) {
111 return $rev->userCan( RevisionRecord::DELETED_TEXT, $this->
getAuthority() );
114 private function getRole() {
115 return SlotRecord::MAIN;
118 private function getRevisionText( $paramName ) {
119 if ( !isset( $this->textCache[$paramName] ) ) {
120 $revision = $this->getRevision( $paramName );
123 ->getSlot( $this->getRole(), RevisionRecord::FOR_THIS_USER, $this->
getAuthority() )
126 if ( $content instanceof TextContent ) {
127 $this->textCache[$paramName] = $content->getText();
129 throw new LocalizedHttpException(
131 'rest-compare-wrong-content',
132 [ $this->getRole(), $paramName ]
136 }
catch ( SuppressedDataException $e ) {
137 throw new LocalizedHttpException(
138 new MessageValue(
'rest-compare-inaccessible', [ $paramName ] ), 403 );
139 }
catch ( RevisionAccessException $e ) {
140 throw new LocalizedHttpException(
141 new MessageValue(
'rest-compare-nonexistent', [ $paramName ] ), 404 );
144 return $this->textCache[$paramName];
150 private function getJsonDiff() {
153 $fromText = $this->getRevisionText(
'from' );
154 $toText = $this->getRevisionText(
'to' );
155 if ( !function_exists(
'wikidiff2_inline_json_diff' ) ) {
156 throw new LocalizedHttpException(
157 new MessageValue(
'rest-compare-wikidiff2' ), 500 );
159 return wikidiff2_inline_json_diff( $fromText, $toText, 2 );
166 private function getSectionInfo( $paramName ) {
167 $text = $this->getRevisionText( $paramName );
168 $parserSections = $this->parserFactory->getInstance()->getFlatSectionInfo( $text );
170 foreach ( $parserSections as $i => $parserSection ) {
175 'level' => $parserSection[
'level'],
176 'heading' => $parserSection[
'heading'],
177 'offset' => $parserSection[
'offset'],
194 ParamValidator::PARAM_TYPE =>
'integer',
195 ParamValidator::PARAM_REQUIRED =>
true,
200 ParamValidator::PARAM_TYPE =>
'integer',
201 ParamValidator::PARAM_REQUIRED =>
true,