MediaWiki  master
CompareHandler.php
Go to the documentation of this file.
1 <?php
2 
3 namespace MediaWiki\Rest\Handler;
4 
13 use Parser;
14 use TextContent;
17 
18 class CompareHandler extends Handler {
20  private $revisionLookup;
21 
23  private $parser;
24 
26  private $revisions = [];
27 
29  private $textCache = [];
30 
31  public function __construct(
34  ) {
35  $this->revisionLookup = $revisionLookup;
36  $this->parser = $parser;
37  }
38 
39  public function execute() {
40  $fromRev = $this->getRevisionOrThrow( 'from' );
41  $toRev = $this->getRevisionOrThrow( 'to' );
42 
43  if ( $fromRev->getPageId() !== $toRev->getPageId() ) {
44  throw new LocalizedHttpException(
45  new MessageValue( 'rest-compare-page-mismatch' ), 400 );
46  }
47 
48  if ( !$this->getAuthority()->authorizeRead( 'read', $toRev->getPage() ) ) {
49  throw new LocalizedHttpException(
50  new MessageValue( 'rest-compare-permission-denied' ), 403 );
51  }
52 
53  $data = [
54  'from' => [
55  'id' => $fromRev->getId(),
56  'slot_role' => $this->getRole(),
57  'sections' => $this->getSectionInfo( 'from' )
58  ],
59  'to' => [
60  'id' => $toRev->getId(),
61  'slot_role' => $this->getRole(),
62  'sections' => $this->getSectionInfo( 'to' )
63  ],
64  'diff' => [ 'PLACEHOLDER' => null ]
65  ];
66  $rf = $this->getResponseFactory();
67  $wrapperJson = $rf->encodeJson( $data );
68  $diff = $this->getJsonDiff();
69  $response = $rf->create();
70  $response->setHeader( 'Content-Type', 'application/json' );
71  // A hack until getJsonDiff() is moved to SlotDiffRenderer and only nested inner diff is returned
72  $innerDiff = substr( $diff, 1, -1 );
73  $response->setBody( new StringStream(
74  str_replace( '"diff":{"PLACEHOLDER":null}', $innerDiff, $wrapperJson ) ) );
75  return $response;
76  }
77 
82  private function getRevision( $paramName ) {
83  if ( !isset( $this->revisions[$paramName] ) ) {
84  $this->revisions[$paramName] =
85  $this->revisionLookup->getRevisionById( $this->getValidatedParams()[$paramName] );
86  }
87  return $this->revisions[$paramName];
88  }
89 
95  private function getRevisionOrThrow( $paramName ) {
96  $rev = $this->getRevision( $paramName );
97  if ( !$rev ) {
98  throw new LocalizedHttpException(
99  new MessageValue( 'rest-compare-nonexistent', [ $paramName ] ), 404 );
100  }
101 
102  if ( !$this->isAccessible( $rev ) ) {
103  throw new LocalizedHttpException(
104  new MessageValue( 'rest-compare-inaccessible', [ $paramName ] ), 403 );
105  }
106  return $rev;
107  }
108 
113  private function isAccessible( $rev ) {
114  return $rev->userCan( RevisionRecord::DELETED_TEXT, $this->getAuthority() );
115  }
116 
117  private function getRole() {
118  return SlotRecord::MAIN;
119  }
120 
121  private function getRevisionText( $paramName ) {
122  if ( !isset( $this->textCache[$paramName] ) ) {
123  $revision = $this->getRevision( $paramName );
124  try {
125  $content = $revision
126  ->getSlot( $this->getRole(), RevisionRecord::FOR_THIS_USER, $this->getAuthority() )
127  ->getContent()
128  ->convert( CONTENT_MODEL_TEXT );
129  if ( $content instanceof TextContent ) {
130  $this->textCache[$paramName] = $content->getText();
131  } else {
132  throw new LocalizedHttpException(
133  new MessageValue(
134  'rest-compare-wrong-content',
135  [ $this->getRole(), $paramName ]
136  ),
137  400 );
138  }
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 );
145  }
146  }
147  return $this->textCache[$paramName];
148  }
149 
153  private function getJsonDiff() {
154  // TODO: properly implement
155  // This is a prototype only. SlotDiffRenderer should be extended to support this use case.
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 );
161  }
162  return wikidiff2_inline_json_diff( $fromText, $toText, 2 );
163  }
164 
169  private function getSectionInfo( $paramName ) {
170  $text = $this->getRevisionText( $paramName );
171  $parserSections = $this->parser->getFlatSectionInfo( $text );
172  $sections = [];
173  foreach ( $parserSections as $i => $parserSection ) {
174  // Skip section zero, which comes before the first heading, since
175  // its offset is always zero, so the client can assume its location.
176  if ( $i !== 0 ) {
177  $sections[] = [
178  'level' => $parserSection['level'],
179  'heading' => $parserSection['heading'],
180  'offset' => $parserSection['offset'],
181  ];
182  }
183  }
184  return $sections;
185  }
186 
187  public function getParamSettings() {
188  return [
189  'from' => [
190  ParamValidator::PARAM_TYPE => 'integer',
191  ParamValidator::PARAM_REQUIRED => true,
192  Handler::PARAM_SOURCE => 'path',
193  ],
194  'to' => [
195  ParamValidator::PARAM_TYPE => 'integer',
196  ParamValidator::PARAM_REQUIRED => true,
197  Handler::PARAM_SOURCE => 'path',
198  ],
199  ];
200  }
201 }
MediaWiki\Rest\Handler\CompareHandler\$revisionLookup
RevisionLookup $revisionLookup
Definition: CompareHandler.php:20
MediaWiki\Rest\Handler
Definition: AbstractContributionHandler.php:3
MediaWiki\Revision\RevisionAccessException
Exception representing a failure to look up a revision.
Definition: RevisionAccessException.php:34
MediaWiki\Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:47
MediaWiki\Rest\Handler\getResponseFactory
getResponseFactory()
Get the ResponseFactory which can be used to generate Response objects.
Definition: Handler.php:170
MediaWiki\Rest\Handler\CompareHandler\getSectionInfo
getSectionInfo( $paramName)
Definition: CompareHandler.php:169
MediaWiki\Revision\SuppressedDataException
Exception raised in response to an audience check when attempting to access suppressed information wi...
Definition: SuppressedDataException.php:33
MediaWiki\Rest\Handler\CompareHandler\getRevisionText
getRevisionText( $paramName)
Definition: CompareHandler.php:121
MediaWiki\Rest\Handler\PARAM_SOURCE
const PARAM_SOURCE
(string) ParamValidator constant to specify the source of the parameter.
Definition: Handler.php:26
MediaWiki\Rest\StringStream
A stream class which uses a string as the underlying storage.
Definition: StringStream.php:16
MediaWiki\Rest\Handler\CompareHandler\getRevision
getRevision( $paramName)
Definition: CompareHandler.php:82
MediaWiki\Rest\Handler\CompareHandler\$revisions
RevisionRecord[] $revisions
Definition: CompareHandler.php:26
MediaWiki\Revision\RevisionLookup
Service for looking up page revisions.
Definition: RevisionLookup.php:38
Wikimedia\Message\MessageValue
Value object representing a message for i18n.
Definition: MessageValue.php:16
MediaWiki\Rest\Handler
Base class for REST route handlers.
Definition: Handler.php:17
MediaWiki\Revision\RevisionRecord\DELETED_TEXT
const DELETED_TEXT
Definition: RevisionRecord.php:53
MediaWiki\Rest\Handler\CompareHandler\getRevisionOrThrow
getRevisionOrThrow( $paramName)
Definition: CompareHandler.php:95
MediaWiki\Rest\Handler\getValidatedParams
getValidatedParams()
Fetch the validated parameters.
Definition: Handler.php:282
$content
$content
Definition: router.php:76
MediaWiki\Rest\Handler\CompareHandler\getJsonDiff
getJsonDiff()
Definition: CompareHandler.php:153
MediaWiki\Rest\Handler\CompareHandler\__construct
__construct(RevisionLookup $revisionLookup, Parser $parser)
Definition: CompareHandler.php:31
MediaWiki\Rest\Handler\CompareHandler\$parser
Parser $parser
Definition: CompareHandler.php:23
Parser
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition: Parser.php:89
TextContent
Content object implementation for representing flat text.
Definition: TextContent.php:39
CONTENT_MODEL_TEXT
const CONTENT_MODEL_TEXT
Definition: Defines.php:211
MediaWiki\Rest\Handler\CompareHandler\getParamSettings
getParamSettings()
Fetch ParamValidator settings for parameters.
Definition: CompareHandler.php:187
MediaWiki\Revision\RevisionRecord\FOR_THIS_USER
const FOR_THIS_USER
Definition: RevisionRecord.php:63
MediaWiki\Rest\Handler\CompareHandler\isAccessible
isAccessible( $rev)
Definition: CompareHandler.php:113
MediaWiki\Rest\Handler\CompareHandler\$textCache
string[] $textCache
Definition: CompareHandler.php:29
MediaWiki\Rest\Handler\CompareHandler\getRole
getRole()
Definition: CompareHandler.php:117
MediaWiki\Rest\Handler\CompareHandler
Definition: CompareHandler.php:18
MediaWiki\Rest\Handler\CompareHandler\execute
execute()
Execute the handler.
Definition: CompareHandler.php:39
MediaWiki\Rest\Handler\getAuthority
getAuthority()
Get the current acting authority.
Definition: Handler.php:148
Wikimedia\ParamValidator\ParamValidator
Service for formatting and validating API parameters.
Definition: ParamValidator.php:42
MediaWiki\Rest\LocalizedHttpException
@newable
Definition: LocalizedHttpException.php:10
MediaWiki\Revision\SlotRecord
Value object representing a content slot associated with a page revision.
Definition: SlotRecord.php:40