00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 if ( !defined( 'MEDIAWIKI' ) ) {
00027
00028 require_once ( 'ApiQueryBase.php' );
00029 }
00030
00036 class ApiQueryDeletedrevs extends ApiQueryBase {
00037
00038 public function __construct( $query, $moduleName ) {
00039 parent :: __construct( $query, $moduleName, 'dr' );
00040 }
00041
00042 public function execute() {
00043
00044 global $wgUser;
00045
00046 if ( !$wgUser->isAllowed( 'deletedhistory' ) )
00047 $this->dieUsage( 'You don\'t have permission to view deleted revision information', 'permissiondenied' );
00048
00049 $db = $this->getDB();
00050 $params = $this->extractRequestParams( false );
00051 $prop = array_flip( $params['prop'] );
00052 $fld_revid = isset( $prop['revid'] );
00053 $fld_user = isset( $prop['user'] );
00054 $fld_comment = isset( $prop['comment'] );
00055 $fld_parsedcomment = isset ( $prop['parsedcomment'] );
00056 $fld_minor = isset( $prop['minor'] );
00057 $fld_len = isset( $prop['len'] );
00058 $fld_content = isset( $prop['content'] );
00059 $fld_token = isset( $prop['token'] );
00060
00061 $result = $this->getResult();
00062 $pageSet = $this->getPageSet();
00063 $titles = $pageSet->getTitles();
00064 $data = array();
00065
00066
00067
00068
00069
00070 $mode = 'all';
00071 if ( count( $titles ) > 0 )
00072 $mode = 'revs';
00073 else if ( !is_null( $params['user'] ) )
00074 $mode = 'user';
00075
00076 if ( !is_null( $params['user'] ) && !is_null( $params['excludeuser'] ) )
00077 $this->dieUsage( 'user and excludeuser cannot be used together', 'badparams' );
00078
00079 $this->addTables( 'archive' );
00080 $this->addWhere( 'ar_deleted = 0' );
00081 $this->addFields( array( 'ar_title', 'ar_namespace', 'ar_timestamp' ) );
00082 if ( $fld_revid )
00083 $this->addFields( 'ar_rev_id' );
00084 if ( $fld_user )
00085 $this->addFields( 'ar_user_text' );
00086 if ( $fld_comment || $fld_parsedcomment )
00087 $this->addFields( 'ar_comment' );
00088 if ( $fld_minor )
00089 $this->addFields( 'ar_minor_edit' );
00090 if ( $fld_len )
00091 $this->addFields( 'ar_len' );
00092 if ( $fld_content ) {
00093 $this->addTables( 'text' );
00094 $this->addFields( array( 'ar_text', 'ar_text_id', 'old_text', 'old_flags' ) );
00095 $this->addWhere( 'ar_text_id = old_id' );
00096
00097
00098 if ( !$wgUser->isAllowed( 'undelete' ) )
00099 $this->dieUsage( 'You don\'t have permission to view deleted revision content', 'permissiondenied' );
00100 }
00101
00102 $userMax = $fld_content ? ApiBase :: LIMIT_SML1 : ApiBase :: LIMIT_BIG1;
00103 $botMax = $fld_content ? ApiBase :: LIMIT_SML2 : ApiBase :: LIMIT_BIG2;
00104
00105 $limit = $params['limit'];
00106
00107 if ( $limit == 'max' ) {
00108 $limit = $this->getMain()->canApiHighLimits() ? $botMax : $userMax;
00109 $this->getResult()->addValue( 'limits', $this->getModuleName(), $limit );
00110 }
00111
00112 $this->validateLimit( 'limit', $limit, 1, $userMax, $botMax );
00113
00114 if ( $fld_token )
00115
00116 $token = $wgUser->editToken();
00117
00118
00119 if ( $mode == 'revs' ) {
00120 $lb = new LinkBatch( $titles );
00121 $where = $lb->constructSet( 'ar', $db );
00122 $this->addWhere( $where );
00123 } elseif ( $mode == 'all' ) {
00124 $this->addWhereFld( 'ar_namespace', $params['namespace'] );
00125 if ( !is_null( $params['from'] ) )
00126 {
00127 $from = $this->getDB()->strencode( $this->titleToKey( $params['from'] ) );
00128 $this->addWhere( "ar_title >= '$from'" );
00129 }
00130 }
00131
00132 if ( !is_null( $params['user'] ) ) {
00133 $this->addWhereFld( 'ar_user_text', $params['user'] );
00134 } elseif ( !is_null( $params['excludeuser'] ) ) {
00135 $this->addWhere( 'ar_user_text != ' .
00136 $this->getDB()->addQuotes( $params['excludeuser'] ) );
00137 }
00138
00139 if ( !is_null( $params['continue'] ) && ( $mode == 'all' || $mode == 'revs' ) )
00140 {
00141 $cont = explode( '|', $params['continue'] );
00142 if ( count( $cont ) != 3 )
00143 $this->dieUsage( "Invalid continue param. You should pass the original value returned by the previous query", "badcontinue" );
00144 $ns = intval( $cont[0] );
00145 $title = $this->getDB()->strencode( $this->titleToKey( $cont[1] ) );
00146 $ts = $this->getDB()->strencode( $cont[2] );
00147 $op = ( $params['dir'] == 'newer' ? '>' : '<' );
00148 $this->addWhere( "ar_namespace $op $ns OR " .
00149 "(ar_namespace = $ns AND " .
00150 "(ar_title $op '$title' OR " .
00151 "(ar_title = '$title' AND " .
00152 "ar_timestamp $op= '$ts')))" );
00153 }
00154
00155 $this->addOption( 'LIMIT', $limit + 1 );
00156 $this->addOption( 'USE INDEX', array( 'archive' => ( $mode == 'user' ? 'usertext_timestamp' : 'name_title_timestamp' ) ) );
00157 if ( $mode == 'all' ) {
00158 if ( $params['unique'] )
00159 {
00160 $this->addOption( 'GROUP BY', 'ar_title' );
00161 $this->addOption( 'ORDER BY', 'ar_title' );
00162 } else
00163 $this->addOption( 'ORDER BY', 'ar_title, ar_timestamp' );
00164 } else {
00165 if ( $mode == 'revs' )
00166 {
00167
00168 $this->addWhereRange( 'ar_namespace', $params['dir'], null, null );
00169 $this->addWhereRange( 'ar_title', $params['dir'], null, null );
00170 }
00171 $this->addWhereRange( 'ar_timestamp', $params['dir'], $params['start'], $params['end'] );
00172 }
00173 $res = $this->select( __METHOD__ );
00174 $pageMap = array();
00175 $count = 0;
00176 $newPageID = 0;
00177 while ( $row = $db->fetchObject( $res ) )
00178 {
00179 if ( ++$count > $limit ) {
00180
00181 if ( $mode == 'all' || $mode == 'revs' )
00182 $this->setContinueEnumParameter( 'continue', intval( $row->ar_namespace ) . '|' .
00183 $this->keyToTitle( $row->ar_title ) . '|' . $row->ar_timestamp );
00184 else
00185 $this->setContinueEnumParameter( 'start', wfTimestamp( TS_ISO_8601, $row->ar_timestamp ) );
00186 break;
00187 }
00188
00189 $rev = array();
00190 $rev['timestamp'] = wfTimestamp( TS_ISO_8601, $row->ar_timestamp );
00191 if ( $fld_revid )
00192 $rev['revid'] = intval( $row->ar_rev_id );
00193 if ( $fld_user )
00194 $rev['user'] = $row->ar_user_text;
00195 if ( $fld_comment )
00196 $rev['comment'] = $row->ar_comment;
00197
00198 $title = Title::makeTitle( $row->ar_namespace, $row->ar_title );
00199
00200 if ( $fld_parsedcomment ) {
00201 global $wgUser;
00202 $rev['parsedcomment'] = $wgUser->getSkin()->formatComment( $row->ar_comment, $title );
00203 }
00204 if ( $fld_minor && $row->ar_minor_edit == 1 )
00205 $rev['minor'] = '';
00206 if ( $fld_len )
00207 $rev['len'] = $row->ar_len;
00208 if ( $fld_content )
00209 ApiResult::setContent( $rev, Revision::getRevisionText( $row ) );
00210
00211 if ( !isset( $pageMap[$row->ar_namespace][$row->ar_title] ) ) {
00212 $pageID = $newPageID++;
00213 $pageMap[$row->ar_namespace][$row->ar_title] = $pageID;
00214 $a['revisions'] = array( $rev );
00215 $result->setIndexedTagName( $a['revisions'], 'rev' );
00216 ApiQueryBase::addTitleInfo( $a, $title );
00217 if ( $fld_token )
00218 $a['token'] = $token;
00219 $fit = $result->addValue( array( 'query', $this->getModuleName() ), $pageID, $a );
00220 } else {
00221 $pageID = $pageMap[$row->ar_namespace][$row->ar_title];
00222 $fit = $result->addValue(
00223 array( 'query', $this->getModuleName(), $pageID, 'revisions' ),
00224 null, $rev );
00225 }
00226 if ( !$fit ) {
00227 if ( $mode == 'all' || $mode == 'revs' )
00228 $this->setContinueEnumParameter( 'continue', intval( $row->ar_namespace ) . '|' .
00229 $this->keyToTitle( $row->ar_title ) . '|' . $row->ar_timestamp );
00230 else
00231 $this->setContinueEnumParameter( 'start', wfTimestamp( TS_ISO_8601, $row->ar_timestamp ) );
00232 break;
00233 }
00234 }
00235 $db->freeResult( $res );
00236 $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'page' );
00237 }
00238
00239 public function getAllowedParams() {
00240 return array (
00241 'start' => array(
00242 ApiBase :: PARAM_TYPE => 'timestamp'
00243 ),
00244 'end' => array(
00245 ApiBase :: PARAM_TYPE => 'timestamp',
00246 ),
00247 'dir' => array(
00248 ApiBase :: PARAM_TYPE => array(
00249 'newer',
00250 'older'
00251 ),
00252 ApiBase :: PARAM_DFLT => 'older'
00253 ),
00254 'from' => null,
00255 'continue' => null,
00256 'unique' => false,
00257 'user' => array(
00258 ApiBase :: PARAM_TYPE => 'user'
00259 ),
00260 'excludeuser' => array(
00261 ApiBase :: PARAM_TYPE => 'user'
00262 ),
00263 'namespace' => array(
00264 ApiBase :: PARAM_TYPE => 'namespace',
00265 ApiBase :: PARAM_DFLT => 0,
00266 ),
00267 'limit' => array(
00268 ApiBase :: PARAM_DFLT => 10,
00269 ApiBase :: PARAM_TYPE => 'limit',
00270 ApiBase :: PARAM_MIN => 1,
00271 ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
00272 ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
00273 ),
00274 'prop' => array(
00275 ApiBase :: PARAM_DFLT => 'user|comment',
00276 ApiBase :: PARAM_TYPE => array(
00277 'revid',
00278 'user',
00279 'comment',
00280 'parsedcomment',
00281 'minor',
00282 'len',
00283 'content',
00284 'token'
00285 ),
00286 ApiBase :: PARAM_ISMULTI => true
00287 ),
00288 );
00289 }
00290
00291 public function getParamDescription() {
00292 return array (
00293 'start' => 'The timestamp to start enumerating from. (1,2)',
00294 'end' => 'The timestamp to stop enumerating at. (1,2)',
00295 'dir' => 'The direction in which to enumerate. (1,2)',
00296 'limit' => 'The maximum amount of revisions to list',
00297 'prop' => 'Which properties to get',
00298 'namespace' => 'Only list pages in this namespace (3)',
00299 'user' => 'Only list revisions by this user',
00300 'excludeuser' => 'Don\'t list revisions by this user',
00301 'from' => 'Start listing at this title (3)',
00302 'continue' => 'When more results are available, use this to continue (3)',
00303 'unique' => 'List only one revision for each page (3)',
00304 );
00305 }
00306
00307 public function getDescription() {
00308 return array( 'List deleted revisions.',
00309 'This module operates in three modes:',
00310 '1) List deleted revisions for the given title(s), sorted by timestamp',
00311 '2) List deleted contributions for the given user, sorted by timestamp (no titles specified)',
00312 '3) List all deleted revisions in the given namespace, sorted by title and timestamp (no titles specified, druser not set)',
00313 'Certain parameters only apply to some modes and are ignored in others.',
00314 'For instance, a parameter marked (1) only applies to mode 1 and is ignored in modes 2 and 3.',
00315 );
00316 }
00317
00318 public function getPossibleErrors() {
00319 return array_merge( parent::getPossibleErrors(), array(
00320 array( 'code' => 'permissiondenied', 'info' => 'You don\'t have permission to view deleted revision information' ),
00321 array( 'code' => 'badparams', 'info' => 'user and excludeuser cannot be used together' ),
00322 array( 'code' => 'permissiondenied', 'info' => 'You don\'t have permission to view deleted revision content' ),
00323 array( 'code' => 'badcontinue', 'info' => 'Invalid continue param. You should pass the original value returned by the previous query' ),
00324 ) );
00325 }
00326
00327 protected function getExamples() {
00328 return array (
00329 'List the last deleted revisions of Main Page and Talk:Main Page, with content (mode 1):',
00330 ' api.php?action=query&list=deletedrevs&titles=Main%20Page|Talk:Main%20Page&drprop=user|comment|content',
00331 'List the last 50 deleted contributions by Bob (mode 2):',
00332 ' api.php?action=query&list=deletedrevs&druser=Bob&drlimit=50',
00333 'List the first 50 deleted revisions in the main namespace (mode 3):',
00334 ' api.php?action=query&list=deletedrevs&drdir=newer&drlimit=50',
00335 'List the first 50 deleted pages in the Talk namespace (mode 3):',
00336 ' api.php?action=query&list=deletedrevs&drdir=newer&drlimit=50&drnamespace=1&drunique',
00337 );
00338 }
00339
00340 public function getVersion() {
00341 return __CLASS__ . ': $Id: ApiQueryDeletedrevs.php 69578 2010-07-20 02:46:20Z tstarling $';
00342 }
00343 }