64 $contentHandlerFactory,
82 $enumRevMode = ( $params[
'user'] !==
null || $params[
'excludeuser'] !==
null ||
83 $params[
'limit'] !==
null || $params[
'startid'] !==
null ||
84 $params[
'endid'] !==
null || $params[
'dir'] ===
'newer' ||
85 $params[
'start'] !==
null || $params[
'end'] !== null );
88 $pageCount = $pageSet->getGoodTitleCount();
89 $revCount = $pageSet->getRevisionCount();
92 if ( $revCount === 0 && $pageCount === 0 ) {
96 if ( $revCount > 0 && count( $pageSet->getLiveRevisionIDs() ) === 0 ) {
101 if ( $revCount > 0 && $enumRevMode ) {
103 [
'apierror-revisions-norevids', $this->
getModulePrefix() ],
'invalidparammix'
107 if ( $pageCount > 1 && $enumRevMode ) {
109 [
'apierror-revisions-singlepage', $this->
getModulePrefix() ],
'invalidparammix'
115 if ( !$enumRevMode ) {
116 $this->setParsedLimit =
false;
117 $params[
'limit'] =
'max';
120 $db = $this->
getDB();
123 $tsField =
'rev_timestamp';
124 $pageField =
'rev_page';
130 'revision' =>
'rev_timestamp',
133 if ( $resultPageSet ===
null ) {
135 $queryBuilder = $this->revisionStore->newSelectQueryBuilder( $db )
138 if ( $this->fld_user ) {
139 $queryBuilder->joinUser();
145 $this->
addTables( [
'revision',
'page' ] );
147 [
'page' => [
'JOIN', [
'page_id = rev_page' ] ] ]
150 'rev_id' => $idField,
'rev_timestamp' => $tsField,
'rev_page' => $pageField
154 if ( $this->fld_tags ) {
156 'ts_tags' => $this->changeTagsStore->makeTagSummarySubquery(
'revision', $this->getAuthority() )
160 if ( $params[
'tag'] !==
null ) {
161 if ( !$this->changeTagsStore->canViewTag( $params[
'tag'], $this->getAuthority() ) ) {
167 [
'change_tag' => [
'JOIN', [
'rev_id=ct_rev_id' ] ] ]
170 $this->
addWhereFld(
'ct_tag_id', $this->changeTagDefStore->getId( $params[
'tag'] ) );
177 if ( $resultPageSet ===
null && $this->fetchContent ) {
179 $status = Status::newGood();
182 foreach ( $pageSet->getGoodPages() as $pageIdentity ) {
183 if ( !$this->
getAuthority()->authorizeRead(
'read', $pageIdentity ) ) {
186 'apierror-cannotviewtitle',
187 wfEscapeWikiText( $this->titleFormatter->getPrefixedText( $pageIdentity ) ),
193 if ( !$status->isGood() ) {
198 if ( $enumRevMode ) {
210 if ( $params[
'continue'] !==
null ) {
212 $op = ( $params[
'dir'] ===
'newer' ?
'>=' :
'<=' );
213 $continueTimestamp = $db->timestamp( $cont[0] );
214 $continueId = (int)$cont[1];
215 $this->
addWhere( $db->buildComparison( $op, [
216 $tsField => $continueTimestamp,
217 $idField => $continueId,
223 if ( $params[
'startid'] !==
null ) {
224 $revids[] = (int)$params[
'startid'];
226 if ( $params[
'endid'] !==
null ) {
227 $revids[] = (int)$params[
'endid'];
230 $db = $this->
getDB();
231 $uqb = $db->newUnionQueryBuilder();
233 $db->newSelectQueryBuilder()
234 ->select( [
'id' =>
'rev_id',
'ts' =>
'rev_timestamp' ] )
236 ->where( [
'rev_id' => $revids ] )
239 $db->newSelectQueryBuilder()
240 ->select( [
'id' =>
'ar_rev_id',
'ts' =>
'ar_timestamp' ] )
242 ->where( [
'ar_rev_id' => $revids ] )
244 $res = $uqb->caller( __METHOD__ )->fetchResultSet();
245 foreach ( $res as $row ) {
246 if ( (
int)$row->id === (
int)$params[
'startid'] ) {
247 $params[
'start'] = $row->ts;
249 if ( (
int)$row->id === (
int)$params[
'endid'] ) {
250 $params[
'end'] = $row->ts;
253 if ( $params[
'startid'] !==
null && $params[
'start'] ===
null ) {
255 $this->
dieWithError( [
'apierror-revisions-badid', $p ],
"badid_$p" );
257 if ( $params[
'endid'] !==
null && $params[
'end'] ===
null ) {
259 $this->
dieWithError( [
'apierror-revisions-badid', $p ],
"badid_$p" );
262 if ( $params[
'start'] !==
null ) {
263 $op = ( $params[
'dir'] ===
'newer' ?
'>=' :
'<=' );
264 $ts = $db->timestampOrNull( $params[
'start'] );
265 if ( $params[
'startid'] !==
null ) {
266 $this->
addWhere( $db->buildComparison( $op, [
268 $idField => (
int)$params[
'startid'],
271 $this->
addWhere( $db->buildComparison( $op, [ $tsField => $ts ] ) );
274 if ( $params[
'end'] !==
null ) {
275 $op = ( $params[
'dir'] ===
'newer' ?
'<=' :
'>=' );
276 $ts = $db->timestampOrNull( $params[
'end'] );
277 if ( $params[
'endid'] !==
null ) {
278 $this->
addWhere( $db->buildComparison( $op, [
280 $idField => (
int)$params[
'endid'],
283 $this->
addWhere( $db->buildComparison( $op, [ $tsField => $ts ] ) );
288 $params[
'start'], $params[
'end'] );
291 $sort = ( $params[
'dir'] ===
'newer' ?
'' :
'DESC' );
292 $this->
addOption(
'ORDER BY', [
"rev_timestamp $sort",
"rev_id $sort" ] );
295 $ids = array_keys( $pageSet->getGoodPages() );
298 if ( $params[
'user'] !==
null ) {
299 $actorQuery = $this->actorMigration->getWhere( $db,
'rev_user', $params[
'user'] );
300 $this->
addTables( $actorQuery[
'tables'] );
302 $this->
addWhere( $actorQuery[
'conds'] );
303 } elseif ( $params[
'excludeuser'] !==
null ) {
304 $actorQuery = $this->actorMigration->getWhere( $db,
'rev_user', $params[
'excludeuser'] );
305 $this->
addTables( $actorQuery[
'tables'] );
307 $this->
addWhere(
'NOT(' . $actorQuery[
'conds'] .
')' );
313 $useIndex[
'revision'] =
'rev_page_timestamp';
316 if ( $params[
'user'] !==
null || $params[
'excludeuser'] !==
null ) {
318 if ( !$this->
getAuthority()->isAllowed(
'deletedhistory' ) ) {
319 $bitmask = RevisionRecord::DELETED_USER;
320 } elseif ( !$this->
getAuthority()->isAllowedAny(
'suppressrevision',
'viewsuppressed' ) ) {
321 $bitmask = RevisionRecord::DELETED_USER | RevisionRecord::DELETED_RESTRICTED;
326 $this->
addWhere( $db->bitAnd(
'rev_deleted', $bitmask ) .
" != $bitmask" );
329 } elseif ( $revCount > 0 ) {
332 $revs = $pageSet->getLiveRevisionIDs();
335 $this->
addWhereFld(
'rev_id', array_keys( $revs ) );
337 if ( $params[
'continue'] !==
null ) {
338 $this->
addWhere( $db->buildComparison(
'>=', [
339 'rev_id' => (
int)$params[
'continue']
342 $this->
addOption(
'ORDER BY',
'rev_id' );
343 } elseif ( $pageCount > 0 ) {
346 $pageids = array_keys( $pageSet->getGoodPages() );
350 $this->
addWhere(
'page_latest=rev_id' );
357 if ( $params[
'continue'] !==
null ) {
359 $this->
addWhere( $db->buildComparison(
'>=', [
360 'rev_page' => $cont[0],
361 'rev_id' => $cont[1],
372 $this->
addOption(
'LIMIT', $this->limit + 1 );
374 $this->
addOption(
'IGNORE INDEX', $ignoreIndex );
377 $this->
addOption(
'USE INDEX', $useIndex );
383 $res = $this->
select( __METHOD__, [], $hookData );
385 foreach ( $res as $row ) {
386 if ( ++$count > $this->limit ) {
389 if ( $enumRevMode ) {
391 $row->rev_timestamp .
'|' . (
int)$row->rev_id );
392 } elseif ( $revCount > 0 ) {
396 '|' . (
int)$row->rev_id );
401 if ( $resultPageSet !==
null ) {
402 $generated[] = $row->rev_id;
404 $revision = $this->revisionStore->newRevisionFromRow( $row, 0, Title::newFromRow( $row ) );
406 $fit = $this->
processRow( $row, $rev, $hookData ) &&
409 if ( $enumRevMode ) {
411 $row->rev_timestamp .
'|' . (
int)$row->rev_id );
412 } elseif ( $revCount > 0 ) {
416 '|' . (
int)$row->rev_id );
423 if ( $resultPageSet !==
null ) {
424 $resultPageSet->populateFromRevisionIDs( $generated );
430 $ret = parent::getAllowedParams() + [
432 ParamValidator::PARAM_TYPE =>
'integer',
436 ParamValidator::PARAM_TYPE =>
'integer',
440 ParamValidator::PARAM_TYPE =>
'timestamp',
444 ParamValidator::PARAM_TYPE =>
'timestamp',
448 ParamValidator::PARAM_DEFAULT =>
'older',
449 ParamValidator::PARAM_TYPE => [
455 'newer' =>
'api-help-paramvalue-direction-newer',
456 'older' =>
'api-help-paramvalue-direction-older',
461 ParamValidator::PARAM_TYPE =>
'user',
462 UserDef::PARAM_ALLOWED_USER_TYPES => [
'name',
'ip',
'temp',
'id',
'interwiki' ],
463 UserDef::PARAM_RETURN_OBJECT =>
true,
467 ParamValidator::PARAM_TYPE =>
'user',
468 UserDef::PARAM_ALLOWED_USER_TYPES => [
'name',
'ip',
'temp',
'id',
'interwiki' ],
469 UserDef::PARAM_RETURN_OBJECT =>
true,
485 $title = Title::newMainPage()->getPrefixedText();
486 $mp = rawurlencode( $title );
489 "action=query&prop=revisions&titles=API|{$mp}&" .
490 'rvslots=*&rvprop=timestamp|user|comment|content'
491 =>
'apihelp-query+revisions-example-content',
492 "action=query&prop=revisions&titles={$mp}&rvlimit=5&" .
493 'rvprop=timestamp|user|comment'
494 =>
'apihelp-query+revisions-example-last5',
495 "action=query&prop=revisions&titles={$mp}&rvlimit=5&" .
496 'rvprop=timestamp|user|comment&rvdir=newer'
497 =>
'apihelp-query+revisions-example-first5',
498 "action=query&prop=revisions&titles={$mp}&rvlimit=5&" .
499 'rvprop=timestamp|user|comment&rvdir=newer&rvstart=2006-05-01T00:00:00Z'
500 =>
'apihelp-query+revisions-example-first5-after',
501 "action=query&prop=revisions&titles={$mp}&rvlimit=5&" .
502 'rvprop=timestamp|user|comment&rvexcludeuser=127.0.0.1'
503 =>
'apihelp-query+revisions-example-first5-not-localhost',
504 "action=query&prop=revisions&titles={$mp}&rvlimit=5&" .
505 'rvprop=timestamp|user|comment&rvuser=MediaWiki%20default'
506 =>
'apihelp-query+revisions-example-first5-user',
512 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Revisions';
517class_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.