MediaWiki  master
PageHistoryCountHandler.php
Go to the documentation of this file.
1 <?php
2 
3 namespace MediaWiki\Rest\Handler;
4 
6 use ChangeTags;
18 use WANObjectCache;
24 
30  private const COUNT_LIMITS = [
31  'anonymous' => 10000,
32  'bot' => 10000,
33  'editors' => 25000,
34  'edits' => 30000,
35  'minor' => 1000,
36  'reverted' => 30000
37  ];
38 
39  private const DEPRECATED_COUNT_TYPES = [
40  'anonedits' => 'anonymous',
41  'botedits' => 'bot',
42  'revertededits' => 'reverted'
43  ];
44 
45  private const MAX_AGE_200 = 60;
46 
48  private $revisionStore;
49 
52 
55 
57  private $loadBalancer;
58 
60  private $pageLookup;
61 
63  private $cache;
64 
66  private $actorMigration;
67 
69  private $revision = false;
70 
73 
75  private $page = false;
76 
86  public function __construct(
88  NameTableStoreFactory $nameTableStoreFactory,
94  ) {
95  $this->revisionStore = $revisionStore;
96  $this->changeTagDefStore = $nameTableStoreFactory->getChangeTagDef();
97  $this->groupPermissionsLookup = $groupPermissionsLookup;
98  $this->loadBalancer = $loadBalancer;
99  $this->cache = $cache;
100  $this->pageLookup = $pageLookup;
101  $this->actorMigration = $actorMigration;
102  }
103 
104  private function normalizeType( $type ) {
105  return self::DEPRECATED_COUNT_TYPES[$type] ?? $type;
106  }
107 
114  private function validateParameterCombination( $type ) {
115  $params = $this->getValidatedParams();
116  if ( !$params ) {
117  return;
118  }
119 
120  if ( $params['from'] || $params['to'] ) {
121  if ( $type === 'edits' || $type === 'editors' ) {
122  if ( !$params['from'] || !$params['to'] ) {
123  throw new LocalizedHttpException(
124  new MessageValue( 'rest-pagehistorycount-parameters-invalid' ),
125  400
126  );
127  }
128  } else {
129  throw new LocalizedHttpException(
130  new MessageValue( 'rest-pagehistorycount-parameters-invalid' ),
131  400
132  );
133  }
134  }
135  }
136 
143  public function run( $title, $type ) {
144  $normalizedType = $this->normalizeType( $type );
145  $this->validateParameterCombination( $normalizedType );
146  $page = $this->getPage();
147  if ( !$page ) {
148  throw new LocalizedHttpException(
149  new MessageValue( 'rest-nonexistent-title',
150  [ new ScalarParam( ParamType::PLAINTEXT, $title ) ]
151  ),
152  404
153  );
154  }
155 
156  if ( !$this->getAuthority()->authorizeRead( 'read', $page ) ) {
157  throw new LocalizedHttpException(
158  new MessageValue( 'rest-permission-denied-title',
159  [ new ScalarParam( ParamType::PLAINTEXT, $title ) ]
160  ),
161  403
162  );
163  }
164 
165  $count = $this->getCount( $normalizedType );
166  $countLimit = self::COUNT_LIMITS[$normalizedType];
167  $response = $this->getResponseFactory()->createJson( [
168  'count' => $count > $countLimit ? $countLimit : $count,
169  'limit' => $count > $countLimit
170  ] );
171  $response->setHeader( 'Cache-Control', 'max-age=' . self::MAX_AGE_200 );
172 
173  // Inform clients who use a deprecated "type" value, so they can adjust
174  if ( isset( self::DEPRECATED_COUNT_TYPES[$type] ) ) {
175  $docs = '<https://www.mediawiki.org/wiki/API:REST/History_API' .
176  '#Get_page_history_counts>; rel="deprecation"';
177  $response->setHeader( 'Deprecation', 'version="v1"' );
178  $response->setHeader( 'Link', $docs );
179  }
180 
181  return $response;
182  }
183 
189  private function getCount( $type ) {
190  $pageId = $this->getPage()->getId();
191  switch ( $type ) {
192  case 'anonymous':
193  return $this->getCachedCount( $type,
194  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
195  return $this->getAnonCount( $pageId, $fromRev );
196  }
197  );
198 
199  case 'bot':
200  return $this->getCachedCount( $type,
201  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
202  return $this->getBotCount( $pageId, $fromRev );
203  }
204  );
205 
206  case 'editors':
207  $from = $this->getValidatedParams()['from'] ?? null;
208  $to = $this->getValidatedParams()['to'] ?? null;
209  if ( $from || $to ) {
210  return $this->getEditorsCount(
211  $pageId,
212  $from ? $this->getRevisionOrThrow( $from ) : null,
213  $to ? $this->getRevisionOrThrow( $to ) : null
214  );
215  } else {
216  return $this->getCachedCount( $type,
217  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
218  return $this->getEditorsCount( $pageId, $fromRev );
219  } );
220  }
221 
222  case 'edits':
223  $from = $this->getValidatedParams()['from'] ?? null;
224  $to = $this->getValidatedParams()['to'] ?? null;
225  if ( $from || $to ) {
226  return $this->getEditsCount(
227  $pageId,
228  $from ? $this->getRevisionOrThrow( $from ) : null,
229  $to ? $this->getRevisionOrThrow( $to ) : null
230  );
231  } else {
232  return $this->getCachedCount( $type,
233  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
234  return $this->getEditsCount( $pageId, $fromRev );
235  }
236  );
237  }
238 
239  case 'reverted':
240  return $this->getCachedCount( $type,
241  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
242  return $this->getRevertedCount( $pageId, $fromRev );
243  }
244  );
245 
246  case 'minor':
247  // The query for minor counts is inefficient for the database for pages with many revisions.
248  // If the specified title contains more revisions than allowed, we will return an error.
249  $editsCount = $this->getCachedCount( 'edits',
250  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
251  return $this->getEditsCount( $pageId, $fromRev );
252  }
253  );
254  if ( $editsCount > self::COUNT_LIMITS[$type] * 2 ) {
255  throw new LocalizedHttpException(
256  new MessageValue( 'rest-pagehistorycount-too-many-revisions' ),
257  500
258  );
259  }
260  return $this->getCachedCount( $type,
261  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
262  return $this->getMinorCount( $pageId, $fromRev );
263  }
264  );
265 
266  // Sanity check
267  default:
268  throw new LocalizedHttpException(
269  new MessageValue( 'rest-pagehistorycount-type-unrecognized',
270  [ new ScalarParam( ParamType::PLAINTEXT, $type ) ]
271  ),
272  500
273  );
274  }
275  }
276 
280  private function getCurrentRevision(): ?RevisionRecord {
281  if ( $this->revision === false ) {
282  $page = $this->getPage();
283  if ( $page ) {
284  $this->revision = $this->revisionStore->getKnownCurrentRevision( $page ) ?: null;
285  } else {
286  $this->revision = null;
287  }
288  }
289  return $this->revision;
290  }
291 
295  private function getPage(): ?ExistingPageRecord {
296  if ( $this->page === false ) {
297  $this->page = $this->pageLookup->getExistingPageByText(
298  $this->getValidatedParams()['title']
299  );
300  }
301  return $this->page;
302  }
303 
310  protected function getLastModified() {
312  if ( $lastModifiedTimes ) {
313  return max( array_values( $lastModifiedTimes ) );
314  }
315  return null;
316  }
317 
324  protected function getLastModifiedTimes() {
325  $currentRev = $this->getCurrentRevision();
326  if ( !$currentRev ) {
327  return null;
328  }
329  if ( $this->lastModifiedTimes === null ) {
330  $currentRevTime = (int)wfTimestampOrNull( TS_UNIX, $currentRev->getTimestamp() );
331  $loggingTableTime = $this->loggingTableTime( $currentRev->getPageId() );
332  $this->lastModifiedTimes = [
333  'currentRevTS' => $currentRevTime,
334  'dependencyModTS' => $loggingTableTime
335  ];
336  }
338  }
339 
345  private function loggingTableTime( $pageId ) {
346  $res = $this->loadBalancer->getConnectionRef( DB_REPLICA )->selectField(
347  'logging',
348  'MAX(log_timestamp)',
349  [ 'log_page' => $pageId ],
350  __METHOD__
351  );
352  return $res ? (int)wfTimestamp( TS_UNIX, $res ) : null;
353  }
354 
365  protected function getEtag() {
366  return null;
367  }
368 
374  private function getCachedCount( $type,
375  callable $fetchCount
376  ) {
377  $pageId = $this->getPage()->getId();
378  return $this->cache->getWithSetCallback(
379  $this->cache->makeKey( 'rest', 'pagehistorycount', $pageId, $type ),
380  WANObjectCache::TTL_WEEK,
381  function ( $oldValue ) use ( $fetchCount ) {
382  $currentRev = $this->getCurrentRevision();
383  if ( $oldValue ) {
384  // Last modified timestamp was NOT a dependency change (e.g. revdel)
385  $doIncrementalUpdate = (
386  $this->getLastModified() != $this->getLastModifiedTimes()['dependencyModTS']
387  );
388  if ( $doIncrementalUpdate ) {
389  $rev = $this->revisionStore->getRevisionById( $oldValue['revision'] );
390  if ( $rev ) {
391  $additionalCount = $fetchCount( $rev );
392  return [
393  'revision' => $currentRev->getId(),
394  'count' => $oldValue['count'] + $additionalCount,
395  'dependencyModTS' => $this->getLastModifiedTimes()['dependencyModTS']
396  ];
397  }
398  }
399  }
400  // Nothing was previously stored, or incremental update was done for too long,
401  // recalculate from scratch.
402  return [
403  'revision' => $currentRev->getId(),
404  'count' => $fetchCount(),
405  'dependencyModTS' => $this->getLastModifiedTimes()['dependencyModTS']
406  ];
407  },
408  [
409  'touchedCallback' => function (){
410  return $this->getLastModified();
411  },
412  'version' => 2,
413  'lockTSE' => WANObjectCache::TTL_MINUTE * 5
414  ]
415  )['count'];
416  }
417 
423  protected function getAnonCount( $pageId, RevisionRecord $fromRev = null ) {
424  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
425 
426  $revQuery = $this->actorMigration->getJoin( 'rev_user' );
427 
428  $cond = [
429  'rev_page' => $pageId,
430  'actor_user IS NULL',
431  $dbr->bitAnd( 'rev_deleted',
433  ];
434 
435  if ( $fromRev ) {
436  $oldTs = $dbr->addQuotes( $dbr->timestamp( $fromRev->getTimestamp() ) );
437  $cond[] = "(rev_timestamp = {$oldTs} AND rev_id > {$fromRev->getId()}) " .
438  "OR rev_timestamp > {$oldTs}";
439  }
440 
441  // This redundant join condition tells MySQL that rev_page and revactor_page are the
442  // same, so it can propagate the condition
443  if ( isset( $revQuery['tables']['temp_rev_user'] ) /* SCHEMA_COMPAT_READ_TEMP */ ) {
444  $revQuery['joins']['temp_rev_user'][1] =
445  "temp_rev_user.revactor_rev = rev_id AND revactor_page = rev_page";
446  }
447 
448  $edits = $dbr->selectRowCount(
449  [
450  'revision',
451  ] + $revQuery['tables'],
452  '1',
453  $cond,
454  __METHOD__,
455  [ 'LIMIT' => self::COUNT_LIMITS['anonymous'] + 1 ], // extra to detect truncation
456  $revQuery['joins']
457  );
458  return $edits;
459  }
460 
466  protected function getBotCount( $pageId, RevisionRecord $fromRev = null ) {
467  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
468 
469  $revQuery = $this->actorMigration->getJoin( 'rev_user' );
470 
471  // This redundant join condition tells MySQL that rev_page and revactor_page are the
472  // same, so it can propagate the condition
473  if ( isset( $revQuery['tables']['temp_rev_user'] ) /* SCHEMA_COMPAT_READ_TEMP */ ) {
474  $revQuery['joins']['temp_rev_user'][1] =
475  "temp_rev_user.revactor_rev = rev_id AND revactor_page = rev_page";
476  }
477 
478  $cond = [
479  'rev_page=' . intval( $pageId ),
480  $dbr->bitAnd( 'rev_deleted',
482  'EXISTS(' .
483  $dbr->selectSQLText(
484  'user_groups',
485  '1',
486  [
487  $revQuery['fields']['rev_user'] . ' = ug_user',
488  'ug_group' => $this->groupPermissionsLookup->getGroupsWithPermission( 'bot' ),
489  'ug_expiry IS NULL OR ug_expiry >= ' . $dbr->addQuotes( $dbr->timestamp() )
490  ],
491  __METHOD__
492  ) .
493  ')'
494  ];
495  if ( $fromRev ) {
496  $oldTs = $dbr->addQuotes( $dbr->timestamp( $fromRev->getTimestamp() ) );
497  $cond[] = "(rev_timestamp = {$oldTs} AND rev_id > {$fromRev->getId()}) " .
498  "OR rev_timestamp > {$oldTs}";
499  }
500 
501  $edits = $dbr->selectRowCount(
502  [
503  'revision',
504  ] + $revQuery['tables'],
505  '1',
506  $cond,
507  __METHOD__,
508  [ 'LIMIT' => self::COUNT_LIMITS['bot'] + 1 ], // extra to detect truncation
509  $revQuery['joins']
510  );
511  return $edits;
512  }
513 
520  protected function getEditorsCount( $pageId,
521  RevisionRecord $fromRev = null,
522  RevisionRecord $toRev = null
523  ) {
524  list( $fromRev, $toRev ) = $this->orderRevisions( $fromRev, $toRev );
525  return $this->revisionStore->countAuthorsBetween( $pageId, $fromRev,
526  $toRev, $this->getAuthority(), self::COUNT_LIMITS['editors'] );
527  }
528 
534  protected function getRevertedCount( $pageId, RevisionRecord $fromRev = null ) {
535  $tagIds = [];
536 
537  foreach ( ChangeTags::REVERT_TAGS as $tagName ) {
538  try {
539  $tagIds[] = $this->changeTagDefStore->getId( $tagName );
540  } catch ( NameTableAccessException $e ) {
541  // If no revisions are tagged with a name, no tag id will be present
542  }
543  }
544  if ( !$tagIds ) {
545  return 0;
546  }
547 
548  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
549 
550  $cond = [
551  'rev_page' => $pageId,
552  $dbr->bitAnd( 'rev_deleted', RevisionRecord::DELETED_TEXT ) . " = 0"
553  ];
554  if ( $fromRev ) {
555  $oldTs = $dbr->addQuotes( $dbr->timestamp( $fromRev->getTimestamp() ) );
556  $cond[] = "(rev_timestamp = {$oldTs} AND rev_id > {$fromRev->getId()}) " .
557  "OR rev_timestamp > {$oldTs}";
558  }
559  $edits = $dbr->selectRowCount(
560  [
561  'revision',
562  'change_tag'
563  ],
564  '1',
565  [ 'rev_page' => $pageId ],
566  __METHOD__,
567  [
568  'LIMIT' => self::COUNT_LIMITS['reverted'] + 1, // extra to detect truncation
569  'GROUP BY' => 'rev_id'
570  ],
571  [
572  'change_tag' => [
573  'JOIN',
574  [
575  'ct_rev_id = rev_id',
576  'ct_tag_id' => $tagIds,
577  ]
578  ],
579  ]
580  );
581  return $edits;
582  }
583 
589  protected function getMinorCount( $pageId, RevisionRecord $fromRev = null ) {
590  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
591  $cond = [
592  'rev_page' => $pageId,
593  'rev_minor_edit != 0',
594  $dbr->bitAnd( 'rev_deleted', RevisionRecord::DELETED_TEXT ) . " = 0"
595  ];
596  if ( $fromRev ) {
597  $oldTs = $dbr->addQuotes( $dbr->timestamp( $fromRev->getTimestamp() ) );
598  $cond[] = "(rev_timestamp = {$oldTs} AND rev_id > {$fromRev->getId()}) " .
599  "OR rev_timestamp > {$oldTs}";
600  }
601  $edits = $dbr->selectRowCount( 'revision', '1',
602  $cond,
603  __METHOD__,
604  [ 'LIMIT' => self::COUNT_LIMITS['minor'] + 1 ] // extra to detect truncation
605  );
606 
607  return $edits;
608  }
609 
616  protected function getEditsCount(
617  $pageId,
618  RevisionRecord $fromRev = null,
619  RevisionRecord $toRev = null
620  ) {
621  list( $fromRev, $toRev ) = $this->orderRevisions( $fromRev, $toRev );
622  return $this->revisionStore->countRevisionsBetween(
623  $pageId,
624  $fromRev,
625  $toRev,
626  self::COUNT_LIMITS['edits'] // Will be increased by 1 to detect truncation
627  );
628  }
629 
635  private function getRevisionOrThrow( $revId ) {
636  $rev = $this->revisionStore->getRevisionById( $revId );
637  if ( !$rev ) {
638  throw new LocalizedHttpException(
639  new MessageValue( 'rest-nonexistent-revision', [ $revId ] ),
640  404
641  );
642  }
643  return $rev;
644  }
645 
653  private function orderRevisions(
654  RevisionRecord $fromRev = null,
655  RevisionRecord $toRev = null
656  ) {
657  if ( $fromRev && $toRev && ( $fromRev->getTimestamp() > $toRev->getTimestamp() ||
658  ( $fromRev->getTimestamp() === $toRev->getTimestamp()
659  && $fromRev->getId() > $toRev->getId() ) )
660  ) {
661  return [ $toRev, $fromRev ];
662  }
663  return [ $fromRev, $toRev ];
664  }
665 
666  public function needsWriteAccess() {
667  return false;
668  }
669 
670  public function getParamSettings() {
671  return [
672  'title' => [
673  self::PARAM_SOURCE => 'path',
674  ParamValidator::PARAM_TYPE => 'string',
675  ParamValidator::PARAM_REQUIRED => true,
676  ],
677  'type' => [
678  self::PARAM_SOURCE => 'path',
679  ParamValidator::PARAM_TYPE => array_merge(
680  array_keys( self::COUNT_LIMITS ),
681  array_keys( self::DEPRECATED_COUNT_TYPES )
682  ),
683  ParamValidator::PARAM_REQUIRED => true,
684  ],
685  'from' => [
686  self::PARAM_SOURCE => 'query',
687  ParamValidator::PARAM_TYPE => 'integer',
688  ParamValidator::PARAM_REQUIRED => false
689  ],
690  'to' => [
691  self::PARAM_SOURCE => 'query',
692  ParamValidator::PARAM_TYPE => 'integer',
693  ParamValidator::PARAM_REQUIRED => false
694  ]
695  ];
696  }
697 }
MediaWiki\Rest\Handler\PageHistoryCountHandler\$revisionStore
RevisionStore $revisionStore
Definition: PageHistoryCountHandler.php:48
ChangeTags\REVERT_TAGS
const REVERT_TAGS
List of tags which denote a revert of some sort.
Definition: ChangeTags.php:102
MediaWiki\Rest\Handler\PageHistoryCountHandler\run
run( $title, $type)
Definition: PageHistoryCountHandler.php:143
MediaWiki\Rest\Handler
Definition: AbstractContributionHandler.php:3
MediaWiki\Rest\Handler\PageHistoryCountHandler\$cache
WANObjectCache $cache
Definition: PageHistoryCountHandler.php:63
MediaWiki\Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:47
MediaWiki\Revision\RevisionRecord\DELETED_USER
const DELETED_USER
Definition: RevisionRecord.php:55
MediaWiki\Rest\Handler\PageHistoryCountHandler\getBotCount
getBotCount( $pageId, RevisionRecord $fromRev=null)
Definition: PageHistoryCountHandler.php:466
MediaWiki\Rest\Handler\getResponseFactory
getResponseFactory()
Get the ResponseFactory which can be used to generate Response objects.
Definition: Handler.php:170
MediaWiki\Permissions\GroupPermissionsLookup
Definition: GroupPermissionsLookup.php:30
MediaWiki\Revision\RevisionStore
Service for looking up page revisions.
Definition: RevisionStore.php:88
MediaWiki\Rest\Handler\PageHistoryCountHandler\getEditsCount
getEditsCount( $pageId, RevisionRecord $fromRev=null, RevisionRecord $toRev=null)
Definition: PageHistoryCountHandler.php:616
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1668
MediaWiki\Rest\Handler\PageHistoryCountHandler\getAnonCount
getAnonCount( $pageId, RevisionRecord $fromRev=null)
Definition: PageHistoryCountHandler.php:423
MediaWiki\Rest\Handler\PageHistoryCountHandler\$revision
RevisionRecord false null $revision
Definition: PageHistoryCountHandler.php:69
MediaWiki\Rest\Handler\PageHistoryCountHandler\getParamSettings
getParamSettings()
Fetch ParamValidator settings for parameters.
Definition: PageHistoryCountHandler.php:670
MediaWiki\Rest\Handler\PageHistoryCountHandler\COUNT_LIMITS
const COUNT_LIMITS
The maximum number of counts to return per type of revision.
Definition: PageHistoryCountHandler.php:30
MediaWiki\Rest\Handler\PageHistoryCountHandler\getLastModifiedTimes
getLastModifiedTimes()
Returns array with 2 timestamps:
Definition: PageHistoryCountHandler.php:324
Wikimedia\Message\ScalarParam
Value object representing a message parameter holding a single value.
Definition: ScalarParam.php:12
ActorMigration
This is not intended to be a long-term part of MediaWiki; it will be deprecated and removed once acto...
Definition: ActorMigration.php:15
$res
$res
Definition: testCompression.php:57
MediaWiki\Rest\Handler\PageHistoryCountHandler\$changeTagDefStore
NameTableStore $changeTagDefStore
Definition: PageHistoryCountHandler.php:51
MediaWiki\Rest\Handler\PageHistoryCountHandler\getEtag
getEtag()
Choosing to not implement etags in this handler.
Definition: PageHistoryCountHandler.php:365
$revQuery
$revQuery
Definition: testCompression.php:56
Wikimedia\Message\MessageValue
Value object representing a message for i18n.
Definition: MessageValue.php:16
MediaWiki\Rest\Handler\PageHistoryCountHandler\$page
ExistingPageRecord false null $page
Definition: PageHistoryCountHandler.php:75
$dbr
$dbr
Definition: testCompression.php:54
MediaWiki\Rest\Handler\PageHistoryCountHandler\getLastModified
getLastModified()
Returns latest of 2 timestamps:
Definition: PageHistoryCountHandler.php:310
MediaWiki\Revision\RevisionRecord\DELETED_TEXT
const DELETED_TEXT
Definition: RevisionRecord.php:53
MediaWiki\Rest\Handler\PageHistoryCountHandler\validateParameterCombination
validateParameterCombination( $type)
Validates that the provided parameter combination is supported.
Definition: PageHistoryCountHandler.php:114
MediaWiki\Rest\Handler\PageHistoryCountHandler\DEPRECATED_COUNT_TYPES
const DEPRECATED_COUNT_TYPES
Definition: PageHistoryCountHandler.php:39
MediaWiki\Rest\Handler\PageHistoryCountHandler\$groupPermissionsLookup
GroupPermissionsLookup $groupPermissionsLookup
Definition: PageHistoryCountHandler.php:54
MediaWiki\Rest\Handler\PageHistoryCountHandler\__construct
__construct(RevisionStore $revisionStore, NameTableStoreFactory $nameTableStoreFactory, GroupPermissionsLookup $groupPermissionsLookup, ILoadBalancer $loadBalancer, WANObjectCache $cache, PageLookup $pageLookup, ActorMigration $actorMigration)
Definition: PageHistoryCountHandler.php:86
MediaWiki\Rest\Handler\PageHistoryCountHandler\getRevisionOrThrow
getRevisionOrThrow( $revId)
Definition: PageHistoryCountHandler.php:635
MediaWiki\Rest\Handler\PageHistoryCountHandler\getRevertedCount
getRevertedCount( $pageId, RevisionRecord $fromRev=null)
Definition: PageHistoryCountHandler.php:534
ChangeTags
Definition: ChangeTags.php:32
MediaWiki\Rest\Handler\PageHistoryCountHandler
Handler class for Core REST API endpoints that perform operations on revisions.
Definition: PageHistoryCountHandler.php:28
MediaWiki\Rest\Handler\PageHistoryCountHandler\orderRevisions
orderRevisions(RevisionRecord $fromRev=null, RevisionRecord $toRev=null)
Reorders revisions if they are present.
Definition: PageHistoryCountHandler.php:653
MediaWiki\Rest\Handler\PageHistoryCountHandler\getEditorsCount
getEditorsCount( $pageId, RevisionRecord $fromRev=null, RevisionRecord $toRev=null)
Definition: PageHistoryCountHandler.php:520
MediaWiki\Rest\Handler\PageHistoryCountHandler\$pageLookup
PageLookup $pageLookup
Definition: PageHistoryCountHandler.php:60
wfTimestampOrNull
wfTimestampOrNull( $outputtype=TS_UNIX, $ts=null)
Return a formatted timestamp, or null if input is null.
Definition: GlobalFunctions.php:1684
MediaWiki\Rest\Handler\PageHistoryCountHandler\getPage
getPage()
Definition: PageHistoryCountHandler.php:295
MediaWiki\Rest\Handler\PageHistoryCountHandler\getMinorCount
getMinorCount( $pageId, RevisionRecord $fromRev=null)
Definition: PageHistoryCountHandler.php:589
MediaWiki\Rest\Response
Definition: Response.php:8
$title
$title
Definition: testCompression.php:38
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
MediaWiki\Rest\Handler\getValidatedParams
getValidatedParams()
Fetch the validated parameters.
Definition: Handler.php:282
MediaWiki\Rest\Handler\PageHistoryCountHandler\$lastModifiedTimes
array $lastModifiedTimes
Definition: PageHistoryCountHandler.php:72
Page\ExistingPageRecord
Data record representing a page that currently exists as an editable page on a wiki.
Definition: ExistingPageRecord.php:15
Page\PageLookup
Service interface for looking up infermation about wiki pages.
Definition: PageLookup.php:14
WANObjectCache
Multi-datacenter aware caching interface.
Definition: WANObjectCache.php:128
MediaWiki\Storage\NameTableStore
Definition: NameTableStore.php:36
MediaWiki\Rest\Handler\PageHistoryCountHandler\getCount
getCount( $type)
Definition: PageHistoryCountHandler.php:189
MediaWiki\Rest\Handler\PageHistoryCountHandler\$loadBalancer
ILoadBalancer $loadBalancer
Definition: PageHistoryCountHandler.php:57
MediaWiki\Storage\NameTableStoreFactory\getChangeTagDef
getChangeTagDef( $wiki=false)
Get a NameTableStore for the change_tag_def table.
Definition: NameTableStoreFactory.php:127
MediaWiki\Rest\Handler\PageHistoryCountHandler\$actorMigration
ActorMigration $actorMigration
Definition: PageHistoryCountHandler.php:66
MediaWiki\Rest\Handler\PageHistoryCountHandler\loggingTableTime
loggingTableTime( $pageId)
Return timestamp of latest entry in logging table for given page id.
Definition: PageHistoryCountHandler.php:345
MediaWiki\Storage\NameTableAccessException
Exception representing a failure to look up a row from a name table.
Definition: NameTableAccessException.php:33
MediaWiki\Storage\NameTableStoreFactory
Definition: NameTableStoreFactory.php:26
MediaWiki\Rest\Handler\PageHistoryCountHandler\needsWriteAccess
needsWriteAccess()
Indicates whether this route requires write access.
Definition: PageHistoryCountHandler.php:666
MediaWiki\Rest\Handler\PageHistoryCountHandler\getCachedCount
getCachedCount( $type, callable $fetchCount)
Definition: PageHistoryCountHandler.php:374
MediaWiki\Rest\Handler\getAuthority
getAuthority()
Get the current acting authority.
Definition: Handler.php:148
MediaWiki\Rest\Handler\PageHistoryCountHandler\normalizeType
normalizeType( $type)
Definition: PageHistoryCountHandler.php:104
Wikimedia\ParamValidator\ParamValidator
Service for formatting and validating API parameters.
Definition: ParamValidator.php:42
Wikimedia\Rdbms\ILoadBalancer
Database cluster connection, tracking, load balancing, and transaction manager interface.
Definition: ILoadBalancer.php:81
MediaWiki\Rest\LocalizedHttpException
@newable
Definition: LocalizedHttpException.php:10
Wikimedia\Message\ParamType
The constants used to specify parameter types.
Definition: ParamType.php:11
MediaWiki\Rest\Handler\PageHistoryCountHandler\getCurrentRevision
getCurrentRevision()
Definition: PageHistoryCountHandler.php:280
MediaWiki\Rest\SimpleHandler
Definition: SimpleHandler.php:15
$type
$type
Definition: testCompression.php:52
MediaWiki\Rest\Handler\PageHistoryCountHandler\MAX_AGE_200
const MAX_AGE_200
Definition: PageHistoryCountHandler.php:45