private $fld_comment = false, $fld_user = false, $fld_flags = false,
$fld_timestamp = false, $fld_title = false, $fld_ids = false,
$fld_sizes = false;
-
+ /**
+ * Get an array mapping token names to their handler functions.
+ * The prototype for a token function is func($pageid, $title, $rc)
+ * it should return a token or false (permission denied)
+ * @return array(tokenname => function)
+ */
protected function getTokenFunctions() {
- // tokenname => function
- // function prototype is func($pageid, $title, $rev)
- // should return token or false
-
// Don't call the hooks twice
if(isset($this->tokenFunctions))
return $this->tokenFunctions;
public static function getPatrolToken($pageid, $title, $rc)
{
global $wgUser;
- if(!$wgUser->useRCPatrol() && !$wgUser->useNPPatrol())
+ if(!$wgUser->useRCPatrol() && (!$wgUser->useNPPatrol() ||
+ $rc->getAttribute('rc_type') != RC_NEW))
return false;
// The patrol token is always the same, let's exploit that
return $cachedPatrolToken;
}
+ /**
+ * Sets internal state to include the desired properties in the output.
+ * @param $prop associative array of properties, only keys are used here
+ */
+ public function initProperties( $prop ) {
+ $this->fld_comment = isset ($prop['comment']);
+ $this->fld_user = isset ($prop['user']);
+ $this->fld_flags = isset ($prop['flags']);
+ $this->fld_timestamp = isset ($prop['timestamp']);
+ $this->fld_title = isset ($prop['title']);
+ $this->fld_ids = isset ($prop['ids']);
+ $this->fld_sizes = isset ($prop['sizes']);
+ $this->fld_redirect = isset($prop['redirect']);
+ $this->fld_patrolled = isset($prop['patrolled']);
+ $this->fld_loginfo = isset($prop['loginfo']);
+ }
+
/**
* Generates and outputs the result of this query based upon the provided parameters.
*/
public function execute() {
- /* Initialize vars */
- $limit = $prop = $namespace = $titles = $user = $excludeuser = $show = $type = $dir = $start = $end = $token = null;
-
/* Get the parameters of the request. */
- extract($this->extractRequestParams());
+ $params = $this->extractRequestParams();
/* Build our basic query. Namely, something along the lines of:
* SELECT * FROM recentchanges WHERE rc_timestamp > $start
*/
$db = $this->getDB();
$this->addTables('recentchanges');
- $this->addOption('USE INDEX', array('recentchanges' => 'rc_timestamp'));
- $this->addWhereRange('rc_timestamp', $dir, $start, $end);
- $this->addWhereFld('rc_namespace', $namespace);
+ $index = 'rc_timestamp'; // May change
+ $this->addWhereRange('rc_timestamp', $params['dir'], $params['start'], $params['end']);
+ $this->addWhereFld('rc_namespace', $params['namespace']);
$this->addWhereFld('rc_deleted', 0);
- if($titles)
- {
- $lb = new LinkBatch;
- foreach($titles as $t)
- {
- $obj = Title::newFromText($t);
- $lb->addObj($obj);
- if($obj->getNamespace() < 0)
- {
- // LinkBatch refuses these, but we need them anyway
- if(!array_key_exists($obj->getNamespace(), $lb->data))
- $lb->data[$obj->getNamespace()] = array();
- $lb->data[$obj->getNamespace()][$obj->getDBKey()] = 1;
- }
- }
- $where = $lb->constructSet('rc', $this->getDB());
- if($where != '')
- $this->addWhere($where);
- }
- if(!is_null($type))
- $this->addWhereFld('rc_type', $this->parseRCType($type));
+ if(!is_null($params['type']))
+ $this->addWhereFld('rc_type', $this->parseRCType($params['type']));
- if (!is_null($show)) {
- $show = array_flip($show);
+ if (!is_null($params['show'])) {
+ $show = array_flip($params['show']);
/* Check for conflicting parameters. */
if ((isset ($show['minor']) && isset ($show['!minor']))
$this->addWhereIf('page_is_redirect = 0 OR page_is_redirect IS NULL', isset ($show['!redirect']));
}
- if(!is_null($user) && !is_null($excludeuser))
- $this->dieUsage('user and excludeuser cannot be used together', 'badparams');
- if(!is_null($user))
- $this->addWhereFld('rc_user_text', $user);
- if(!is_null($excludeuser))
- $this->addWhere('rc_user_text != ' . $this->getDB()->addQuotes($excludeuser));
+ if(!is_null($params['user']) && !is_null($param['excludeuser']))
+ $this->dieUsage('user and excludeuser cannot be used together', 'user-excludeuser');
+ if(!is_null($params['user']))
+ {
+ $this->addWhereFld('rc_user_text', $params['user']);
+ $index = 'rc_user_text';
+ }
+ if(!is_null($params['excludeuser']))
+ // We don't use the rc_user_text index here because
+ // * it would require us to sort by rc_user_text before rc_timestamp
+ // * the != condition doesn't throw out too many rows anyway
+ $this->addWhere('rc_user_text != ' . $this->getDB()->addQuotes($params['excludeuser']));
/* Add the fields we're concerned with to our query. */
$this->addFields(array (
));
/* Determine what properties we need to display. */
- if (!is_null($prop)) {
- $prop = array_flip($prop);
+ if (!is_null($params['prop'])) {
+ $prop = array_flip($params['prop']);
/* Set up internal members based upon params. */
- $this->fld_comment = isset ($prop['comment']);
- $this->fld_user = isset ($prop['user']);
- $this->fld_flags = isset ($prop['flags']);
- $this->fld_timestamp = isset ($prop['timestamp']);
- $this->fld_title = isset ($prop['title']);
- $this->fld_ids = isset ($prop['ids']);
- $this->fld_sizes = isset ($prop['sizes']);
- $this->fld_redirect = isset($prop['redirect']);
- $this->fld_patrolled = isset($prop['patrolled']);
- $this->fld_loginfo = isset($prop['loginfo']);
+ $this->initProperties( $prop );
global $wgUser;
if($this->fld_patrolled && !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol())
$this->addFields('page_is_redirect');
}
}
- $this->token = $token;
- /* Specify the limit for our query. It's $limit+1 because we (possibly) need to
- * generate a "continue" parameter, to allow paging. */
- $this->addOption('LIMIT', $limit +1);
+ $this->token = $params['token'];
+ $this->addOption('LIMIT', $params['limit'] +1);
+ $this->addOption('USE INDEX', array('recentchanges' => $index));
- $data = array ();
$count = 0;
-
/* Perform the actual query. */
$db = $this->getDB();
$res = $this->select(__METHOD__);
/* Iterate through the rows, adding data extracted from them to our query result. */
while ($row = $db->fetchObject($res)) {
- if (++ $count > $limit) {
+ if (++ $count > $params['limit']) {
// We've reached the one extra which shows that there are additional pages to be had. Stop here...
$this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->rc_timestamp));
break;
$vals = $this->extractRowInfo($row);
/* Add that row's data to our final output. */
- if($vals)
- $data[] = $vals;
+ if(!$vals)
+ continue;
+ $fit = $this->getResult()->addValue(array('query', $this->getModuleName()), null, $vals);
+ if(!$fit)
+ {
+ $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->rc_timestamp));
+ break;
+ }
}
$db->freeResult($res);
/* Format the result */
- $result = $this->getResult();
- $result->setIndexedTagName($data, 'rc');
- $result->addValue('query', $this->getModuleName(), $data);
+ $this->getResult()->setIndexedTagName_internal(array('query', $this->getModuleName()), 'rc');
}
/**
*
* @param $row The row from which to extract the data.
* @return An array mapping strings (descriptors) to their respective string values.
- * @access private
+ * @access public
*/
- private function extractRowInfo($row) {
+ public function extractRowInfo($row) {
/* If page was moved somewhere, get the title of the move target. */
$movedToTitle = false;
if (isset($row->rc_moved_to_title) && $row->rc_moved_to_title !== '')
$vals['patrolled'] = '';
if ($this->fld_loginfo && $row->rc_type == RC_LOG) {
- $vals['logid'] = $row->rc_logid;
+ $vals['logid'] = intval($row->rc_logid);
$vals['logtype'] = $row->rc_log_type;
$vals['logaction'] = $row->rc_log_action;
ApiQueryLogEvents::addLogParams($this->getResult(),
ApiBase :: PARAM_ISMULTI => true,
ApiBase :: PARAM_TYPE => 'namespace'
),
- 'titles' => array(
- ApiBase :: PARAM_ISMULTI => true
- ),
'user' => array(
ApiBase :: PARAM_TYPE => 'user'
),
'end' => 'The timestamp to end enumerating.',
'dir' => 'In which direction to enumerate.',
'namespace' => 'Filter log entries to only this namespace(s)',
- 'titles' => 'Filter log entries to only these page titles',
'user' => 'Only list changes by this user',
'excludeuser' => 'Don\'t list changes by this user',
'prop' => 'Include additional pieces of information',