70 $contentHandlerFactory,
79 $this->revisionStore = $revisionStore;
80 $this->changeTagDefStore = $changeTagDefStore;
81 $this->changeTagsStore = $changeTagsStore;
82 $this->actorMigration = $actorMigration;
83 $this->titleFormatter = $titleFormatter;
93 $enumRevMode = ( $params[
'user'] !==
null || $params[
'excludeuser'] !==
null ||
94 $params[
'limit'] !==
null || $params[
'startid'] !==
null ||
95 $params[
'endid'] !==
null || $params[
'dir'] ===
'newer' ||
96 $params[
'start'] !==
null || $params[
'end'] !== null );
99 $pageCount = $pageSet->getGoodTitleCount();
100 $revCount = $pageSet->getRevisionCount();
103 if ( $revCount === 0 && $pageCount === 0 ) {
107 if ( $revCount > 0 && count( $pageSet->getLiveRevisionIDs() ) === 0 ) {
112 if ( $revCount > 0 && $enumRevMode ) {
114 [
'apierror-revisions-norevids', $this->
getModulePrefix() ],
'invalidparammix'
118 if ( $pageCount > 1 && $enumRevMode ) {
120 [
'apierror-revisions-singlepage', $this->
getModulePrefix() ],
'invalidparammix'
126 if ( !$enumRevMode ) {
127 $this->setParsedLimit =
false;
128 $params[
'limit'] =
'max';
131 $db = $this->
getDB();
134 $tsField =
'rev_timestamp';
135 $pageField =
'rev_page';
141 'revision' =>
'rev_timestamp',
144 if ( $resultPageSet ===
null ) {
146 $queryBuilder = $this->revisionStore->newSelectQueryBuilder( $db )
149 if ( $this->fld_user ) {
150 $queryBuilder->joinUser();
156 $this->
addTables( [
'revision',
'page' ] );
158 [
'page' => [
'JOIN', [
'page_id = rev_page' ] ] ]
161 'rev_id' => $idField,
'rev_timestamp' => $tsField,
'rev_page' => $pageField
165 if ( $this->fld_tags ) {
167 'ts_tags' => $this->changeTagsStore->makeTagSummarySubquery(
'revision' )
171 if ( $params[
'tag'] !==
null ) {
174 [
'change_tag' => [
'JOIN', [
'rev_id=ct_rev_id' ] ] ]
177 $this->
addWhereFld(
'ct_tag_id', $this->changeTagDefStore->getId( $params[
'tag'] ) );
184 if ( $resultPageSet ===
null && $this->fetchContent ) {
186 $status = Status::newGood();
189 foreach ( $pageSet->getGoodPages() as $pageIdentity ) {
190 if ( !$this->
getAuthority()->authorizeRead(
'read', $pageIdentity ) ) {
193 'apierror-cannotviewtitle',
194 wfEscapeWikiText( $this->titleFormatter->getPrefixedText( $pageIdentity ) ),
200 if ( !$status->isGood() ) {
205 if ( $enumRevMode ) {
217 if ( $params[
'continue'] !==
null ) {
219 $op = ( $params[
'dir'] ===
'newer' ?
'>=' :
'<=' );
220 $continueTimestamp = $db->timestamp( $cont[0] );
221 $continueId = (int)$cont[1];
222 $this->
addWhere( $db->buildComparison( $op, [
223 $tsField => $continueTimestamp,
224 $idField => $continueId,
230 if ( $params[
'startid'] !==
null ) {
231 $revids[] = (int)$params[
'startid'];
233 if ( $params[
'endid'] !==
null ) {
234 $revids[] = (int)$params[
'endid'];
237 $db = $this->
getDB();
238 $uqb = $db->newUnionQueryBuilder();
240 $db->newSelectQueryBuilder()
241 ->select( [
'id' =>
'rev_id',
'ts' =>
'rev_timestamp' ] )
243 ->where( [
'rev_id' => $revids ] )
246 $db->newSelectQueryBuilder()
247 ->select( [
'id' =>
'ar_rev_id',
'ts' =>
'ar_timestamp' ] )
249 ->where( [
'ar_rev_id' => $revids ] )
251 $res = $uqb->caller( __METHOD__ )->fetchResultSet();
252 foreach ( $res as $row ) {
253 if ( (
int)$row->id === (
int)$params[
'startid'] ) {
254 $params[
'start'] = $row->ts;
256 if ( (
int)$row->id === (
int)$params[
'endid'] ) {
257 $params[
'end'] = $row->ts;
261 if ( $params[
'startid'] !==
null && $params[
'start'] ===
null ) {
263 $this->
dieWithError( [
'apierror-revisions-badid', $p ],
"badid_$p" );
266 if ( $params[
'endid'] !==
null && $params[
'end'] ===
null ) {
268 $this->
dieWithError( [
'apierror-revisions-badid', $p ],
"badid_$p" );
272 if ( $params[
'start'] !==
null ) {
273 $op = ( $params[
'dir'] ===
'newer' ?
'>=' :
'<=' );
275 $ts = $db->timestampOrNull( $params[
'start'] );
276 if ( $params[
'startid'] !==
null ) {
277 $this->
addWhere( $db->buildComparison( $op, [
279 $idField => (
int)$params[
'startid'],
282 $this->
addWhere( $db->buildComparison( $op, [ $tsField => $ts ] ) );
286 if ( $params[
'end'] !==
null ) {
287 $op = ( $params[
'dir'] ===
'newer' ?
'<=' :
'>=' );
289 $ts = $db->timestampOrNull( $params[
'end'] );
290 if ( $params[
'endid'] !==
null ) {
291 $this->
addWhere( $db->buildComparison( $op, [
293 $idField => (
int)$params[
'endid'],
296 $this->
addWhere( $db->buildComparison( $op, [ $tsField => $ts ] ) );
301 $params[
'start'], $params[
'end'] );
304 $sort = ( $params[
'dir'] ===
'newer' ?
'' :
'DESC' );
305 $this->
addOption(
'ORDER BY', [
"rev_timestamp $sort",
"rev_id $sort" ] );
308 $ids = array_keys( $pageSet->getGoodPages() );
311 if ( $params[
'user'] !==
null ) {
312 $actorQuery = $this->actorMigration->getWhere( $db,
'rev_user', $params[
'user'] );
313 $this->
addTables( $actorQuery[
'tables'] );
315 $this->
addWhere( $actorQuery[
'conds'] );
316 } elseif ( $params[
'excludeuser'] !==
null ) {
317 $actorQuery = $this->actorMigration->getWhere( $db,
'rev_user', $params[
'excludeuser'] );
318 $this->
addTables( $actorQuery[
'tables'] );
320 $this->
addWhere(
'NOT(' . $actorQuery[
'conds'] .
')' );
326 $useIndex[
'revision'] =
'rev_page_timestamp';
329 if ( $params[
'user'] !==
null || $params[
'excludeuser'] !==
null ) {
331 if ( !$this->
getAuthority()->isAllowed(
'deletedhistory' ) ) {
332 $bitmask = RevisionRecord::DELETED_USER;
333 } elseif ( !$this->
getAuthority()->isAllowedAny(
'suppressrevision',
'viewsuppressed' ) ) {
334 $bitmask = RevisionRecord::DELETED_USER | RevisionRecord::DELETED_RESTRICTED;
339 $this->
addWhere( $db->bitAnd(
'rev_deleted', $bitmask ) .
" != $bitmask" );
342 } elseif ( $revCount > 0 ) {
345 $revs = $pageSet->getLiveRevisionIDs();
348 $this->
addWhereFld(
'rev_id', array_keys( $revs ) );
350 if ( $params[
'continue'] !==
null ) {
351 $this->
addWhere( $db->buildComparison(
'>=', [
352 'rev_id' => (
int)$params[
'continue']
355 $this->
addOption(
'ORDER BY',
'rev_id' );
356 } elseif ( $pageCount > 0 ) {
359 $pageids = array_keys( $pageSet->getGoodPages() );
363 $this->
addWhere(
'page_latest=rev_id' );
370 if ( $params[
'continue'] !==
null ) {
372 $this->
addWhere( $db->buildComparison(
'>=', [
373 'rev_page' => $cont[0],
374 'rev_id' => $cont[1],
385 $this->
addOption(
'LIMIT', $this->limit + 1 );
387 $this->
addOption(
'IGNORE INDEX', $ignoreIndex );
390 $this->
addOption(
'USE INDEX', $useIndex );
396 $res = $this->
select( __METHOD__, [], $hookData );
398 foreach ( $res as $row ) {
399 if ( ++$count > $this->limit ) {
402 if ( $enumRevMode ) {
404 $row->rev_timestamp .
'|' . (
int)$row->rev_id );
405 } elseif ( $revCount > 0 ) {
409 '|' . (
int)$row->rev_id );
414 if ( $resultPageSet !==
null ) {
415 $generated[] = $row->rev_id;
417 $revision = $this->revisionStore->newRevisionFromRow( $row, 0, Title::newFromRow( $row ) );
419 $fit = $this->
processRow( $row, $rev, $hookData ) &&
422 if ( $enumRevMode ) {
424 $row->rev_timestamp .
'|' . (
int)$row->rev_id );
425 } elseif ( $revCount > 0 ) {
429 '|' . (
int)$row->rev_id );
436 if ( $resultPageSet !==
null ) {
437 $resultPageSet->populateFromRevisionIDs( $generated );
443 $ret = parent::getAllowedParams() + [
445 ParamValidator::PARAM_TYPE =>
'integer',
449 ParamValidator::PARAM_TYPE =>
'integer',
453 ParamValidator::PARAM_TYPE =>
'timestamp',
457 ParamValidator::PARAM_TYPE =>
'timestamp',
461 ParamValidator::PARAM_DEFAULT =>
'older',
462 ParamValidator::PARAM_TYPE => [
468 'newer' =>
'api-help-paramvalue-direction-newer',
469 'older' =>
'api-help-paramvalue-direction-older',
474 ParamValidator::PARAM_TYPE =>
'user',
475 UserDef::PARAM_ALLOWED_USER_TYPES => [
'name',
'ip',
'temp',
'id',
'interwiki' ],
476 UserDef::PARAM_RETURN_OBJECT =>
true,
480 ParamValidator::PARAM_TYPE =>
'user',
481 UserDef::PARAM_ALLOWED_USER_TYPES => [
'name',
'ip',
'temp',
'id',
'interwiki' ],
482 UserDef::PARAM_RETURN_OBJECT =>
true,
498 $title = Title::newMainPage()->getPrefixedText();
499 $mp = rawurlencode( $title );
502 "action=query&prop=revisions&titles=API|{$mp}&" .
503 'rvslots=*&rvprop=timestamp|user|comment|content'
504 =>
'apihelp-query+revisions-example-content',
505 "action=query&prop=revisions&titles={$mp}&rvlimit=5&" .
506 'rvprop=timestamp|user|comment'
507 =>
'apihelp-query+revisions-example-last5',
508 "action=query&prop=revisions&titles={$mp}&rvlimit=5&" .
509 'rvprop=timestamp|user|comment&rvdir=newer'
510 =>
'apihelp-query+revisions-example-first5',
511 "action=query&prop=revisions&titles={$mp}&rvlimit=5&" .
512 'rvprop=timestamp|user|comment&rvdir=newer&rvstart=2006-05-01T00:00:00Z'
513 =>
'apihelp-query+revisions-example-first5-after',
514 "action=query&prop=revisions&titles={$mp}&rvlimit=5&" .
515 'rvprop=timestamp|user|comment&rvexcludeuser=127.0.0.1'
516 =>
'apihelp-query+revisions-example-first5-not-localhost',
517 "action=query&prop=revisions&titles={$mp}&rvlimit=5&" .
518 'rvprop=timestamp|user|comment&rvuser=MediaWiki%20default'
519 =>
'apihelp-query+revisions-example-first5-user',
525 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Revisions';
530class_alias( ApiQueryRevisions::class,
'ApiQueryRevisions' );
wfEscapeWikiText( $input)
Escapes the given text so that it may be output using addWikiText() without any linking,...
This class contains a list of pages that the client has requested.
A service to render content.
A service to transform content.
Interface for objects (potentially) representing an editable wiki page.