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' )
160 if ( $params[
'tag'] !==
null ) {
163 [
'change_tag' => [
'JOIN', [
'rev_id=ct_rev_id' ] ] ]
166 $this->
addWhereFld(
'ct_tag_id', $this->changeTagDefStore->getId( $params[
'tag'] ) );
173 if ( $resultPageSet ===
null && $this->fetchContent ) {
175 $status = Status::newGood();
178 foreach ( $pageSet->getGoodPages() as $pageIdentity ) {
179 if ( !$this->
getAuthority()->authorizeRead(
'read', $pageIdentity ) ) {
182 'apierror-cannotviewtitle',
183 wfEscapeWikiText( $this->titleFormatter->getPrefixedText( $pageIdentity ) ),
189 if ( !$status->isGood() ) {
194 if ( $enumRevMode ) {
206 if ( $params[
'continue'] !==
null ) {
208 $op = ( $params[
'dir'] ===
'newer' ?
'>=' :
'<=' );
209 $continueTimestamp = $db->timestamp( $cont[0] );
210 $continueId = (int)$cont[1];
211 $this->
addWhere( $db->buildComparison( $op, [
212 $tsField => $continueTimestamp,
213 $idField => $continueId,
219 if ( $params[
'startid'] !==
null ) {
220 $revids[] = (int)$params[
'startid'];
222 if ( $params[
'endid'] !==
null ) {
223 $revids[] = (int)$params[
'endid'];
226 $db = $this->
getDB();
227 $uqb = $db->newUnionQueryBuilder();
229 $db->newSelectQueryBuilder()
230 ->select( [
'id' =>
'rev_id',
'ts' =>
'rev_timestamp' ] )
232 ->where( [
'rev_id' => $revids ] )
235 $db->newSelectQueryBuilder()
236 ->select( [
'id' =>
'ar_rev_id',
'ts' =>
'ar_timestamp' ] )
238 ->where( [
'ar_rev_id' => $revids ] )
240 $res = $uqb->caller( __METHOD__ )->fetchResultSet();
241 foreach ( $res as $row ) {
242 if ( (
int)$row->id === (
int)$params[
'startid'] ) {
243 $params[
'start'] = $row->ts;
245 if ( (
int)$row->id === (
int)$params[
'endid'] ) {
246 $params[
'end'] = $row->ts;
249 if ( $params[
'startid'] !==
null && $params[
'start'] ===
null ) {
251 $this->
dieWithError( [
'apierror-revisions-badid', $p ],
"badid_$p" );
253 if ( $params[
'endid'] !==
null && $params[
'end'] ===
null ) {
255 $this->
dieWithError( [
'apierror-revisions-badid', $p ],
"badid_$p" );
258 if ( $params[
'start'] !==
null ) {
259 $op = ( $params[
'dir'] ===
'newer' ?
'>=' :
'<=' );
260 $ts = $db->timestampOrNull( $params[
'start'] );
261 if ( $params[
'startid'] !==
null ) {
262 $this->
addWhere( $db->buildComparison( $op, [
264 $idField => (
int)$params[
'startid'],
267 $this->
addWhere( $db->buildComparison( $op, [ $tsField => $ts ] ) );
270 if ( $params[
'end'] !==
null ) {
271 $op = ( $params[
'dir'] ===
'newer' ?
'<=' :
'>=' );
272 $ts = $db->timestampOrNull( $params[
'end'] );
273 if ( $params[
'endid'] !==
null ) {
274 $this->
addWhere( $db->buildComparison( $op, [
276 $idField => (
int)$params[
'endid'],
279 $this->
addWhere( $db->buildComparison( $op, [ $tsField => $ts ] ) );
284 $params[
'start'], $params[
'end'] );
287 $sort = ( $params[
'dir'] ===
'newer' ?
'' :
'DESC' );
288 $this->
addOption(
'ORDER BY', [
"rev_timestamp $sort",
"rev_id $sort" ] );
291 $ids = array_keys( $pageSet->getGoodPages() );
294 if ( $params[
'user'] !==
null ) {
295 $actorQuery = $this->actorMigration->getWhere( $db,
'rev_user', $params[
'user'] );
296 $this->
addTables( $actorQuery[
'tables'] );
298 $this->
addWhere( $actorQuery[
'conds'] );
299 } elseif ( $params[
'excludeuser'] !==
null ) {
300 $actorQuery = $this->actorMigration->getWhere( $db,
'rev_user', $params[
'excludeuser'] );
301 $this->
addTables( $actorQuery[
'tables'] );
303 $this->
addWhere(
'NOT(' . $actorQuery[
'conds'] .
')' );
309 $useIndex[
'revision'] =
'rev_page_timestamp';
312 if ( $params[
'user'] !==
null || $params[
'excludeuser'] !==
null ) {
314 if ( !$this->
getAuthority()->isAllowed(
'deletedhistory' ) ) {
315 $bitmask = RevisionRecord::DELETED_USER;
316 } elseif ( !$this->
getAuthority()->isAllowedAny(
'suppressrevision',
'viewsuppressed' ) ) {
317 $bitmask = RevisionRecord::DELETED_USER | RevisionRecord::DELETED_RESTRICTED;
322 $this->
addWhere( $db->bitAnd(
'rev_deleted', $bitmask ) .
" != $bitmask" );
325 } elseif ( $revCount > 0 ) {
328 $revs = $pageSet->getLiveRevisionIDs();
331 $this->
addWhereFld(
'rev_id', array_keys( $revs ) );
333 if ( $params[
'continue'] !==
null ) {
334 $this->
addWhere( $db->buildComparison(
'>=', [
335 'rev_id' => (
int)$params[
'continue']
338 $this->
addOption(
'ORDER BY',
'rev_id' );
339 } elseif ( $pageCount > 0 ) {
342 $pageids = array_keys( $pageSet->getGoodPages() );
346 $this->
addWhere(
'page_latest=rev_id' );
353 if ( $params[
'continue'] !==
null ) {
355 $this->
addWhere( $db->buildComparison(
'>=', [
356 'rev_page' => $cont[0],
357 'rev_id' => $cont[1],
368 $this->
addOption(
'LIMIT', $this->limit + 1 );
370 $this->
addOption(
'IGNORE INDEX', $ignoreIndex );
373 $this->
addOption(
'USE INDEX', $useIndex );
379 $res = $this->
select( __METHOD__, [], $hookData );
381 foreach ( $res as $row ) {
382 if ( ++$count > $this->limit ) {
385 if ( $enumRevMode ) {
387 $row->rev_timestamp .
'|' . (
int)$row->rev_id );
388 } elseif ( $revCount > 0 ) {
392 '|' . (
int)$row->rev_id );
397 if ( $resultPageSet !==
null ) {
398 $generated[] = $row->rev_id;
400 $revision = $this->revisionStore->newRevisionFromRow( $row, 0, Title::newFromRow( $row ) );
402 $fit = $this->
processRow( $row, $rev, $hookData ) &&
405 if ( $enumRevMode ) {
407 $row->rev_timestamp .
'|' . (
int)$row->rev_id );
408 } elseif ( $revCount > 0 ) {
412 '|' . (
int)$row->rev_id );
419 if ( $resultPageSet !==
null ) {
420 $resultPageSet->populateFromRevisionIDs( $generated );
426 $ret = parent::getAllowedParams() + [
428 ParamValidator::PARAM_TYPE =>
'integer',
432 ParamValidator::PARAM_TYPE =>
'integer',
436 ParamValidator::PARAM_TYPE =>
'timestamp',
440 ParamValidator::PARAM_TYPE =>
'timestamp',
444 ParamValidator::PARAM_DEFAULT =>
'older',
445 ParamValidator::PARAM_TYPE => [
451 'newer' =>
'api-help-paramvalue-direction-newer',
452 'older' =>
'api-help-paramvalue-direction-older',
457 ParamValidator::PARAM_TYPE =>
'user',
458 UserDef::PARAM_ALLOWED_USER_TYPES => [
'name',
'ip',
'temp',
'id',
'interwiki' ],
459 UserDef::PARAM_RETURN_OBJECT =>
true,
463 ParamValidator::PARAM_TYPE =>
'user',
464 UserDef::PARAM_ALLOWED_USER_TYPES => [
'name',
'ip',
'temp',
'id',
'interwiki' ],
465 UserDef::PARAM_RETURN_OBJECT =>
true,
481 $title = Title::newMainPage()->getPrefixedText();
482 $mp = rawurlencode( $title );
485 "action=query&prop=revisions&titles=API|{$mp}&" .
486 'rvslots=*&rvprop=timestamp|user|comment|content'
487 =>
'apihelp-query+revisions-example-content',
488 "action=query&prop=revisions&titles={$mp}&rvlimit=5&" .
489 'rvprop=timestamp|user|comment'
490 =>
'apihelp-query+revisions-example-last5',
491 "action=query&prop=revisions&titles={$mp}&rvlimit=5&" .
492 'rvprop=timestamp|user|comment&rvdir=newer'
493 =>
'apihelp-query+revisions-example-first5',
494 "action=query&prop=revisions&titles={$mp}&rvlimit=5&" .
495 'rvprop=timestamp|user|comment&rvdir=newer&rvstart=2006-05-01T00:00:00Z'
496 =>
'apihelp-query+revisions-example-first5-after',
497 "action=query&prop=revisions&titles={$mp}&rvlimit=5&" .
498 'rvprop=timestamp|user|comment&rvexcludeuser=127.0.0.1'
499 =>
'apihelp-query+revisions-example-first5-not-localhost',
500 "action=query&prop=revisions&titles={$mp}&rvlimit=5&" .
501 'rvprop=timestamp|user|comment&rvuser=MediaWiki%20default'
502 =>
'apihelp-query+revisions-example-first5-user',
508 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Revisions';
513class_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.