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
00037 class ApiQueryRecentChanges extends ApiQueryBase {
00038
00039 public function __construct($query, $moduleName) {
00040 parent :: __construct($query, $moduleName, 'rc');
00041 }
00042
00043 private $fld_comment = false, $fld_user = false, $fld_flags = false,
00044 $fld_timestamp = false, $fld_title = false, $fld_ids = false,
00045 $fld_sizes = false;
00046
00047 protected function getTokenFunctions() {
00048
00049
00050
00051
00052
00053 if(isset($this->tokenFunctions))
00054 return $this->tokenFunctions;
00055
00056
00057 if(!is_null($this->getMain()->getRequest()->getVal('callback')))
00058 return array();
00059
00060 $this->tokenFunctions = array(
00061 'patrol' => array( 'ApiQueryRecentChanges', 'getPatrolToken' )
00062 );
00063 wfRunHooks('APIQueryRecentChangesTokens', array(&$this->tokenFunctions));
00064 return $this->tokenFunctions;
00065 }
00066
00067 public static function getPatrolToken($pageid, $title, $rc)
00068 {
00069 global $wgUser;
00070 if(!$wgUser->useRCPatrol() && !$wgUser->useNPPatrol())
00071 return false;
00072
00073
00074 static $cachedPatrolToken = null;
00075 if(!is_null($cachedPatrolToken))
00076 return $cachedPatrolToken;
00077
00078 $cachedPatrolToken = $wgUser->editToken();
00079 return $cachedPatrolToken;
00080 }
00081
00085 public function execute() {
00086
00087 $params = $this->extractRequestParams();
00088
00089
00090
00091
00092
00093
00094 $db = $this->getDB();
00095 $this->addTables('recentchanges');
00096 $this->addOption('USE INDEX', array('recentchanges' => 'rc_timestamp'));
00097 $this->addWhereRange('rc_timestamp', $params['dir'], $params['start'], $params['end']);
00098 $this->addWhereFld('rc_namespace', $params['namespace']);
00099 $this->addWhereFld('rc_deleted', 0);
00100
00101 if(!is_null($params['type']))
00102 $this->addWhereFld('rc_type', $this->parseRCType($params['type']));
00103
00104 if (!is_null($params['show'])) {
00105 $show = array_flip($params['show']);
00106
00107
00108 if ((isset ($show['minor']) && isset ($show['!minor']))
00109 || (isset ($show['bot']) && isset ($show['!bot']))
00110 || (isset ($show['anon']) && isset ($show['!anon']))
00111 || (isset ($show['redirect']) && isset ($show['!redirect']))
00112 || (isset ($show['patrolled']) && isset ($show['!patrolled']))) {
00113
00114 $this->dieUsage("Incorrect parameter - mutually exclusive values may not be supplied", 'show');
00115 }
00116
00117
00118 global $wgUser;
00119 if((isset($show['patrolled']) || isset($show['!patrolled'])) && !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol())
00120 $this->dieUsage("You need the patrol right to request the patrolled flag", 'permissiondenied');
00121
00122
00123 $this->addWhereIf('rc_minor = 0', isset ($show['!minor']));
00124 $this->addWhereIf('rc_minor != 0', isset ($show['minor']));
00125 $this->addWhereIf('rc_bot = 0', isset ($show['!bot']));
00126 $this->addWhereIf('rc_bot != 0', isset ($show['bot']));
00127 $this->addWhereIf('rc_user = 0', isset ($show['anon']));
00128 $this->addWhereIf('rc_user != 0', isset ($show['!anon']));
00129 $this->addWhereIf('rc_patrolled = 0', isset($show['!patrolled']));
00130 $this->addWhereIf('rc_patrolled != 0', isset($show['patrolled']));
00131 $this->addWhereIf('page_is_redirect = 1', isset ($show['redirect']));
00132
00133 $this->addWhereIf('page_is_redirect = 0 OR page_is_redirect IS NULL', isset ($show['!redirect']));
00134 }
00135
00136
00137 $this->addFields(array (
00138 'rc_timestamp',
00139 'rc_namespace',
00140 'rc_title',
00141 'rc_cur_id',
00142 'rc_type',
00143 'rc_moved_to_ns',
00144 'rc_moved_to_title'
00145 ));
00146
00147
00148 if (!is_null($params['prop'])) {
00149 $prop = array_flip($params['prop']);
00150
00151
00152 $this->fld_comment = isset ($prop['comment']);
00153 $this->fld_user = isset ($prop['user']);
00154 $this->fld_flags = isset ($prop['flags']);
00155 $this->fld_timestamp = isset ($prop['timestamp']);
00156 $this->fld_title = isset ($prop['title']);
00157 $this->fld_ids = isset ($prop['ids']);
00158 $this->fld_sizes = isset ($prop['sizes']);
00159 $this->fld_redirect = isset($prop['redirect']);
00160 $this->fld_patrolled = isset($prop['patrolled']);
00161 $this->fld_loginfo = isset($prop['loginfo']);
00162
00163 global $wgUser;
00164 if($this->fld_patrolled && !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol())
00165 $this->dieUsage("You need the patrol right to request the patrolled flag", 'permissiondenied');
00166
00167
00168 $this->addFieldsIf('rc_id', $this->fld_ids);
00169 $this->addFieldsIf('rc_this_oldid', $this->fld_ids);
00170 $this->addFieldsIf('rc_last_oldid', $this->fld_ids);
00171 $this->addFieldsIf('rc_comment', $this->fld_comment);
00172 $this->addFieldsIf('rc_user', $this->fld_user);
00173 $this->addFieldsIf('rc_user_text', $this->fld_user);
00174 $this->addFieldsIf('rc_minor', $this->fld_flags);
00175 $this->addFieldsIf('rc_bot', $this->fld_flags);
00176 $this->addFieldsIf('rc_new', $this->fld_flags);
00177 $this->addFieldsIf('rc_old_len', $this->fld_sizes);
00178 $this->addFieldsIf('rc_new_len', $this->fld_sizes);
00179 $this->addFieldsIf('rc_patrolled', $this->fld_patrolled);
00180 $this->addFieldsIf('rc_logid', $this->fld_loginfo);
00181 $this->addFieldsIf('rc_log_type', $this->fld_loginfo);
00182 $this->addFieldsIf('rc_log_action', $this->fld_loginfo);
00183 $this->addFieldsIf('rc_params', $this->fld_loginfo);
00184 if($this->fld_redirect || isset($show['redirect']) || isset($show['!redirect']))
00185 {
00186 $this->addTables('page');
00187 $this->addJoinConds(array('page' => array('LEFT JOIN', array('rc_namespace=page_namespace', 'rc_title=page_title'))));
00188 $this->addFields('page_is_redirect');
00189 }
00190 }
00191 $this->token = $params['token'];
00192 $this->addOption('LIMIT', $params['limit'] +1);
00193
00194 $count = 0;
00195
00196 $db = $this->getDB();
00197 $res = $this->select(__METHOD__);
00198
00199
00200 while ($row = $db->fetchObject($res)) {
00201 if (++ $count > $params['limit']) {
00202
00203 $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->rc_timestamp));
00204 break;
00205 }
00206
00207
00208 $vals = $this->extractRowInfo($row);
00209
00210
00211 if(!$vals)
00212 continue;
00213 $fit = $this->getResult()->addValue(array('query', $this->getModuleName()), null, $vals);
00214 if(!$fit)
00215 {
00216 $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->rc_timestamp));
00217 break;
00218 }
00219 }
00220
00221 $db->freeResult($res);
00222
00223
00224 $this->getResult()->setIndexedTagName_internal(array('query', $this->getModuleName()), 'rc');
00225 }
00226
00234 private function extractRowInfo($row) {
00235
00236 $movedToTitle = false;
00237 if (isset($row->rc_moved_to_title) && $row->rc_moved_to_title !== '')
00238 $movedToTitle = Title :: makeTitle($row->rc_moved_to_ns, $row->rc_moved_to_title);
00239
00240
00241 $title = Title :: makeTitle($row->rc_namespace, $row->rc_title);
00242
00243
00244 $vals = array ();
00245
00246 $type = intval ( $row->rc_type );
00247
00248
00249 switch ( $type ) {
00250 case RC_EDIT: $vals['type'] = 'edit'; break;
00251 case RC_NEW: $vals['type'] = 'new'; break;
00252 case RC_MOVE: $vals['type'] = 'move'; break;
00253 case RC_LOG: $vals['type'] = 'log'; break;
00254 case RC_MOVE_OVER_REDIRECT: $vals['type'] = 'move over redirect'; break;
00255 default: $vals['type'] = $type;
00256 }
00257
00258
00259 if ($this->fld_title) {
00260 ApiQueryBase :: addTitleInfo($vals, $title);
00261 if ($movedToTitle)
00262 ApiQueryBase :: addTitleInfo($vals, $movedToTitle, "new_");
00263 }
00264
00265
00266 if ($this->fld_ids) {
00267 $vals['rcid'] = intval($row->rc_id);
00268 $vals['pageid'] = intval($row->rc_cur_id);
00269 $vals['revid'] = intval($row->rc_this_oldid);
00270 $vals['old_revid'] = intval( $row->rc_last_oldid );
00271 }
00272
00273
00274 if ($this->fld_user) {
00275 $vals['user'] = $row->rc_user_text;
00276 if(!$row->rc_user)
00277 $vals['anon'] = '';
00278 }
00279
00280
00281 if ($this->fld_flags) {
00282 if ($row->rc_bot)
00283 $vals['bot'] = '';
00284 if ($row->rc_new)
00285 $vals['new'] = '';
00286 if ($row->rc_minor)
00287 $vals['minor'] = '';
00288 }
00289
00290
00291 if ($this->fld_sizes) {
00292 $vals['oldlen'] = intval($row->rc_old_len);
00293 $vals['newlen'] = intval($row->rc_new_len);
00294 }
00295
00296
00297 if ($this->fld_timestamp)
00298 $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rc_timestamp);
00299
00300
00301 if ($this->fld_comment && isset($row->rc_comment)) {
00302 $vals['comment'] = $row->rc_comment;
00303 }
00304
00305 if ($this->fld_redirect)
00306 if($row->page_is_redirect)
00307 $vals['redirect'] = '';
00308
00309
00310 if ($this->fld_patrolled && $row->rc_patrolled == 1)
00311 $vals['patrolled'] = '';
00312
00313 if ($this->fld_loginfo && $row->rc_type == RC_LOG) {
00314 $vals['logid'] = intval($row->rc_logid);
00315 $vals['logtype'] = $row->rc_log_type;
00316 $vals['logaction'] = $row->rc_log_action;
00317 ApiQueryLogEvents::addLogParams($this->getResult(),
00318 $vals, $row->rc_params,
00319 $row->rc_log_type, $row->rc_timestamp);
00320 }
00321
00322 if(!is_null($this->token))
00323 {
00324 $tokenFunctions = $this->getTokenFunctions();
00325 foreach($this->token as $t)
00326 {
00327 $val = call_user_func($tokenFunctions[$t], $row->rc_cur_id,
00328 $title, RecentChange::newFromRow($row));
00329 if($val === false)
00330 $this->setWarning("Action '$t' is not allowed for the current user");
00331 else
00332 $vals[$t . 'token'] = $val;
00333 }
00334 }
00335
00336 return $vals;
00337 }
00338
00339 private function parseRCType($type)
00340 {
00341 if(is_array($type))
00342 {
00343 $retval = array();
00344 foreach($type as $t)
00345 $retval[] = $this->parseRCType($t);
00346 return $retval;
00347 }
00348 switch($type)
00349 {
00350 case 'edit': return RC_EDIT;
00351 case 'new': return RC_NEW;
00352 case 'log': return RC_LOG;
00353 }
00354 }
00355
00356 public function getAllowedParams() {
00357 return array (
00358 'start' => array (
00359 ApiBase :: PARAM_TYPE => 'timestamp'
00360 ),
00361 'end' => array (
00362 ApiBase :: PARAM_TYPE => 'timestamp'
00363 ),
00364 'dir' => array (
00365 ApiBase :: PARAM_DFLT => 'older',
00366 ApiBase :: PARAM_TYPE => array (
00367 'newer',
00368 'older'
00369 )
00370 ),
00371 'namespace' => array (
00372 ApiBase :: PARAM_ISMULTI => true,
00373 ApiBase :: PARAM_TYPE => 'namespace'
00374 ),
00375 'prop' => array (
00376 ApiBase :: PARAM_ISMULTI => true,
00377 ApiBase :: PARAM_DFLT => 'title|timestamp|ids',
00378 ApiBase :: PARAM_TYPE => array (
00379 'user',
00380 'comment',
00381 'flags',
00382 'timestamp',
00383 'title',
00384 'ids',
00385 'sizes',
00386 'redirect',
00387 'patrolled',
00388 'loginfo',
00389 )
00390 ),
00391 'token' => array(
00392 ApiBase :: PARAM_TYPE => array_keys($this->getTokenFunctions()),
00393 ApiBase :: PARAM_ISMULTI => true
00394 ),
00395 'show' => array (
00396 ApiBase :: PARAM_ISMULTI => true,
00397 ApiBase :: PARAM_TYPE => array (
00398 'minor',
00399 '!minor',
00400 'bot',
00401 '!bot',
00402 'anon',
00403 '!anon',
00404 'redirect',
00405 '!redirect',
00406 'patrolled',
00407 '!patrolled'
00408 )
00409 ),
00410 'limit' => array (
00411 ApiBase :: PARAM_DFLT => 10,
00412 ApiBase :: PARAM_TYPE => 'limit',
00413 ApiBase :: PARAM_MIN => 1,
00414 ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
00415 ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
00416 ),
00417 'type' => array (
00418 ApiBase :: PARAM_ISMULTI => true,
00419 ApiBase :: PARAM_TYPE => array (
00420 'edit',
00421 'new',
00422 'log'
00423 )
00424 )
00425 );
00426 }
00427
00428 public function getParamDescription() {
00429 return array (
00430 'start' => 'The timestamp to start enumerating from.',
00431 'end' => 'The timestamp to end enumerating.',
00432 'dir' => 'In which direction to enumerate.',
00433 'namespace' => 'Filter log entries to only this namespace(s)',
00434 'prop' => 'Include additional pieces of information',
00435 'token' => 'Which tokens to obtain for each change',
00436 'show' => array (
00437 'Show only items that meet this criteria.',
00438 'For example, to see only minor edits done by logged-in users, set show=minor|!anon'
00439 ),
00440 'type' => 'Which types of changes to show.',
00441 'limit' => 'How many total changes to return.'
00442 );
00443 }
00444
00445 public function getDescription() {
00446 return 'Enumerate recent changes';
00447 }
00448
00449 protected function getExamples() {
00450 return array (
00451 'api.php?action=query&list=recentchanges'
00452 );
00453 }
00454
00455 public function getVersion() {
00456 return __CLASS__ . ': $Id: ApiQueryRecentChanges.php 50094 2009-05-01 06:24:09Z tstarling $';
00457 }
00458 }