37 parent::__construct( $query, $moduleName,
'dr' );
44 $this->
addDeprecation(
'apiwarn-deprecation-deletedrevs',
'action=query&list=deletedrevs' );
48 $commentStore = CommentStore::getStore();
50 $prop = array_flip( $params[
'prop'] );
51 $fld_parentid = isset( $prop[
'parentid'] );
52 $fld_revid = isset( $prop[
'revid'] );
53 $fld_user = isset( $prop[
'user'] );
54 $fld_userid = isset( $prop[
'userid'] );
55 $fld_comment = isset( $prop[
'comment'] );
56 $fld_parsedcomment = isset( $prop[
'parsedcomment'] );
57 $fld_minor = isset( $prop[
'minor'] );
58 $fld_len = isset( $prop[
'len'] );
59 $fld_sha1 = isset( $prop[
'sha1'] );
60 $fld_content = isset( $prop[
'content'] );
61 $fld_token = isset( $prop[
'token'] );
62 $fld_tags = isset( $prop[
'tags'] );
77 $titles = $pageSet->getTitles();
84 if ( count( $titles ) > 0 ) {
86 } elseif ( !is_null( $params[
'user'] ) ) {
90 if ( $mode ==
'revs' || $mode ==
'user' ) {
92 foreach ( [
'from',
'to',
'prefix', ] as $p ) {
93 if ( !is_null( $params[$p] ) ) {
94 $this->
dieWithError( [
'apierror-deletedrevs-param-not-1-2', $p ],
'badparams' );
98 foreach ( [
'start',
'end' ] as $p ) {
99 if ( !is_null( $params[$p] ) ) {
100 $this->
dieWithError( [
'apierror-deletedrevs-param-not-3', $p ],
'badparams' );
105 if ( !is_null( $params[
'user'] ) && !is_null( $params[
'excludeuser'] ) ) {
106 $this->
dieWithError(
'user and excludeuser cannot be used together',
'badparams' );
109 $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
110 $arQuery = $revisionStore->getArchiveQueryInfo();
114 $this->
addFields( [
'ar_title',
'ar_namespace' ] );
120 if ( !is_null( $params[
'tag'] ) ) {
123 [
'change_tag' => [
'JOIN', [
'ar_rev_id=ct_rev_id' ] ] ]
125 $changeTagDefStore = MediaWikiServices::getInstance()->getChangeTagDefStore();
127 $this->
addWhereFld(
'ct_tag_id', $changeTagDefStore->getId( $params[
'tag'] ) );
135 if ( $fld_content ) {
142 $limit = $params[
'limit'];
144 if ( $limit ==
'max' ) {
145 $limit = $this->
getMain()->canApiHighLimits() ? $botMax : $userMax;
149 $this->
validateLimit(
'limit', $limit, 1, $userMax, $botMax );
156 $dir = $params[
'dir'];
159 if ( $mode ==
'revs' ) {
161 $where = $lb->constructSet(
'ar', $db );
163 } elseif ( $mode ==
'all' ) {
164 $this->
addWhereFld(
'ar_namespace', $params[
'namespace'] );
166 $from = $params[
'from'] ===
null
169 $to = $params[
'to'] ===
null
174 if ( isset( $params[
'prefix'] ) ) {
175 $this->
addWhere(
'ar_title' . $db->buildLike(
176 $this->titlePartToKey( $params[
'prefix'], $params[
'namespace'] ),
177 $db->anyString() ) );
181 if ( !is_null( $params[
'user'] ) ) {
183 $actorQuery = ActorMigration::newMigration()
184 ->getWhere( $db,
'ar_user', User::newFromName( $params[
'user'],
false ),
false );
185 $this->
addTables( $actorQuery[
'tables'] );
187 $this->
addWhere( $actorQuery[
'conds'] );
188 } elseif ( !is_null( $params[
'excludeuser'] ) ) {
190 $actorQuery = ActorMigration::newMigration()
191 ->getWhere( $db,
'ar_user', User::newFromName( $params[
'excludeuser'],
false ) );
192 $this->
addTables( $actorQuery[
'tables'] );
194 $this->
addWhere(
'NOT(' . $actorQuery[
'conds'] .
')' );
197 if ( !is_null( $params[
'user'] ) || !is_null( $params[
'excludeuser'] ) ) {
202 $bitmask = RevisionRecord::DELETED_USER;
204 ->userHasAnyRight( $user,
'suppressrevision',
'viewsuppressed' )
206 $bitmask = RevisionRecord::DELETED_USER | RevisionRecord::DELETED_RESTRICTED;
211 $this->
addWhere( $db->bitAnd(
'ar_deleted', $bitmask ) .
" != $bitmask" );
215 if ( !is_null( $params[
'continue'] ) ) {
216 $cont = explode(
'|', $params[
'continue'] );
217 $op = ( $dir ==
'newer' ?
'>' :
'<' );
218 if ( $mode ==
'all' || $mode ==
'revs' ) {
222 $title = $db->addQuotes( $cont[1] );
223 $ts = $db->addQuotes( $db->timestamp( $cont[2] ) );
224 $ar_id = (int)$cont[3];
226 $this->
addWhere(
"ar_namespace $op $ns OR " .
227 "(ar_namespace = $ns AND " .
228 "(ar_title $op $title OR " .
229 "(ar_title = $title AND " .
230 "(ar_timestamp $op $ts OR " .
231 "(ar_timestamp = $ts AND " .
232 "ar_id $op= $ar_id)))))" );
235 $ts = $db->addQuotes( $db->timestamp( $cont[0] ) );
236 $ar_id = (int)$cont[1];
238 $this->
addWhere(
"ar_timestamp $op $ts OR " .
239 "(ar_timestamp = $ts AND " .
240 "ar_id $op= $ar_id)" );
245 if ( $mode ==
'all' ) {
246 if ( $params[
'unique'] ) {
248 $this->
addOption(
'GROUP BY',
'ar_title' );
250 $sort = ( $dir ==
'newer' ?
'' :
' DESC' );
253 'ar_timestamp' .
$sort,
258 if ( $mode ==
'revs' ) {
271 foreach (
$res as $row ) {
272 if ( ++$count > $limit ) {
274 if ( $mode ==
'all' || $mode ==
'revs' ) {
276 "$row->ar_namespace|$row->ar_title|$row->ar_timestamp|$row->ar_id"
287 $rev[
'timestamp'] =
wfTimestamp( TS_ISO_8601, $row->ar_timestamp );
289 $rev[
'revid'] = (int)$row->ar_rev_id;
291 if ( $fld_parentid && !is_null( $row->ar_parent_id ) ) {
292 $rev[
'parentid'] = (int)$row->ar_parent_id;
294 if ( $fld_user || $fld_userid ) {
295 if ( $row->ar_deleted & RevisionRecord::DELETED_USER ) {
296 $rev[
'userhidden'] =
true;
299 if ( Revision::userCanBitfield( $row->ar_deleted, RevisionRecord::DELETED_USER, $user ) ) {
301 $rev[
'user'] = $row->ar_user_text;
304 $rev[
'userid'] = (int)$row->ar_user;
309 if ( $fld_comment || $fld_parsedcomment ) {
310 if ( $row->ar_deleted & RevisionRecord::DELETED_COMMENT ) {
311 $rev[
'commenthidden'] =
true;
314 if ( Revision::userCanBitfield( $row->ar_deleted, RevisionRecord::DELETED_COMMENT, $user ) ) {
315 $comment = $commentStore->getComment(
'ar_comment', $row )->text;
316 if ( $fld_comment ) {
317 $rev[
'comment'] = $comment;
319 if ( $fld_parsedcomment ) {
320 $title = Title::makeTitle( $row->ar_namespace, $row->ar_title );
327 $rev[
'minor'] = $row->ar_minor_edit == 1;
330 $rev[
'len'] = $row->ar_len;
333 if ( $row->ar_deleted & RevisionRecord::DELETED_TEXT ) {
334 $rev[
'sha1hidden'] =
true;
337 if ( Revision::userCanBitfield( $row->ar_deleted, RevisionRecord::DELETED_TEXT, $user ) ) {
338 if ( $row->ar_sha1 !=
'' ) {
339 $rev[
'sha1'] = Wikimedia\base_convert( $row->ar_sha1, 36, 16, 40 );
345 if ( $fld_content ) {
346 if ( $row->ar_deleted & RevisionRecord::DELETED_TEXT ) {
347 $rev[
'texthidden'] =
true;
350 if ( Revision::userCanBitfield( $row->ar_deleted, RevisionRecord::DELETED_TEXT, $user ) ) {
351 ApiResult::setContentValue( $rev,
'text',
352 $revisionStore->newRevisionFromArchiveRow( $row )
353 ->getContent( SlotRecord::MAIN )->serialize() );
358 if ( $row->ts_tags ) {
359 $tags = explode(
',', $row->ts_tags );
360 ApiResult::setIndexedTagName( $tags,
'tag' );
361 $rev[
'tags'] = $tags;
367 if ( $anyHidden && ( $row->ar_deleted & RevisionRecord::DELETED_RESTRICTED ) ) {
368 $rev[
'suppressed'] =
true;
371 if ( !isset( $pageMap[$row->ar_namespace][$row->ar_title] ) ) {
372 $pageID = $newPageID++;
373 $pageMap[$row->ar_namespace][$row->ar_title] = $pageID;
374 $a = [
'revisions' => [ $rev ] ];
375 ApiResult::setIndexedTagName( $a[
'revisions'],
'rev' );
376 $title = Title::makeTitle( $row->ar_namespace, $row->ar_title );
379 $a[
'token'] = $token;
381 $fit = $result->addValue( [
'query', $this->
getModuleName() ], $pageID, $a );
383 $pageID = $pageMap[$row->ar_namespace][$row->ar_title];
384 $fit = $result->addValue(
389 if ( $mode ==
'all' || $mode ==
'revs' ) {
391 "$row->ar_namespace|$row->ar_title|$row->ar_timestamp|$row->ar_id"
399 $result->addIndexedTagName( [
'query', $this->
getModuleName() ],
'page' );
483 'action=query&list=deletedrevs&titles=Main%20Page|Talk:Main%20Page&' .
484 'drprop=user|comment|content'
485 =>
'apihelp-query+deletedrevs-example-mode1',
486 'action=query&list=deletedrevs&druser=Bob&drlimit=50'
487 =>
'apihelp-query+deletedrevs-example-mode2',
488 'action=query&list=deletedrevs&drdir=newer&drlimit=50'
489 =>
'apihelp-query+deletedrevs-example-mode3-main',
490 'action=query&list=deletedrevs&drdir=newer&drlimit=50&drnamespace=1&drunique='
491 =>
'apihelp-query+deletedrevs-example-mode3-talk',
496 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Deletedrevs';
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
const PARAM_MAX2
(integer) Max value allowed for the parameter for users with the apihighlimits right,...
checkUserRightsAny( $rights, $user=null)
Helper function for permission-denied errors.
const PARAM_MAX
(integer) Max value allowed for the parameter, for PARAM_TYPE 'integer' and 'limit'.
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
getMain()
Get the main module.
const PARAM_TYPE
(string|string[]) Either an array of allowed value strings, or a string type as described below.
const PARAM_HELP_MSG_INFO
(array) Specify additional information tags for the parameter.
const PARAM_DFLT
(null|boolean|integer|string) Default value of the parameter.
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks.
addDeprecation( $msg, $feature, $data=[])
Add a deprecation warning for this module.
const PARAM_MIN
(integer) Lowest value allowed for the parameter, for PARAM_TYPE 'integer' and 'limit'.
const LIMIT_BIG1
Fast query, standard limit.
const LIMIT_SML2
Slow query, apihighlimits limit.
validateLimit( $paramName, &$value, $min, $max, $botMax=null, $enforceLimits=false)
Validate the value against the minimum and user/bot maximum limits.
getResult()
Get the result object.
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
const LIMIT_SML1
Slow query, standard limit.
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
const LIMIT_BIG2
Fast query, apihighlimits limit.
getModuleName()
Get the name of the module being executed by this instance.
const PARAM_ISMULTI
(boolean) Accept multiple pipe-separated values for this parameter (e.g.
lacksSameOriginSecurity()
Returns true if the current request breaks the same-origin policy.
This is a base class for all Query modules.
static addTitleInfo(&$arr, $title, $prefix='')
Add information (title and namespace) about a Title object to a result array.
setContinueEnumParameter( $paramName, $paramValue)
Set a query-continue value.
addWhereRange( $field, $dir, $start, $end, $sort=true)
Add a WHERE clause corresponding to a range, and an ORDER BY clause to sort in the right direction.
addFields( $value)
Add a set of fields to select to the internal array.
addOption( $name, $value=null)
Add an option such as LIMIT or USE INDEX.
addTables( $tables, $alias=null)
Add a set of tables to the internal array.
addTimestampWhereRange( $field, $dir, $start, $end, $sort=true)
Add a WHERE clause corresponding to a range, similar to addWhereRange, but converts $start and $end t...
getDB()
Get the Query database connection (read-only)
select( $method, $extraQuery=[], array &$hookData=null)
Execute a SELECT query based on the values in the internal arrays.
addJoinConds( $join_conds)
Add a set of JOIN conditions to the internal array.
addWhereFld( $field, $value)
Equivalent to addWhere( [ $field => $value ] )
getPageSet()
Get the PageSet object to work on.
titlePartToKey( $titlePart, $namespace=NS_MAIN)
Convert an input title or title prefix into a dbkey.
addWhere( $value)
Add a set of WHERE clauses to the internal array.
Query module to enumerate all deleted revisions.
getExamplesMessages()
Returns usage examples for this module.
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
getHelpUrls()
Return links to more detailed help pages about the module.
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
isDeprecated()
Indicates whether this module is deprecated.
__construct(ApiQuery $query, $moduleName)
This is the main query class.
Class representing a list of titles The execute() method checks them all for existence and adds them ...
static formatComment( $comment, $title=null, $local=false, $wikiId=null)
This function is called by all recent changes variants, by the page history, and by the user contribu...