<?php
-
/**
- * Created on Oct 16, 2006
*
- * API for MediaWiki 1.8+
+ *
+ * Created on Oct 16, 2006
*
* Copyright © 2006 Yuri Astrakhan <Firstname><Lastname>@gmail.com
*
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
*/
-if ( !defined( 'MEDIAWIKI' ) ) {
- // Eclipse helper - will be ignored in production
- require_once( 'ApiQueryBase.php' );
-}
-
/**
* This query action adds a list of a specified user's contributions to the output.
*
parent::__construct( $query, $moduleName, 'uc' );
}
- private $params, $username;
+ private $params, $prefixMode, $userprefix, $multiUserMode, $usernames, $parentLens;
private $fld_ids = false, $fld_title = false, $fld_timestamp = false,
$fld_comment = false, $fld_parsedcomment = false, $fld_flags = false,
- $fld_patrolled = false, $fld_tags = false;
+ $fld_patrolled = false, $fld_tags = false, $fld_size = false, $fld_sizediff = false;
public function execute() {
// Parse some parameters
$this->fld_comment = isset( $prop['comment'] );
$this->fld_parsedcomment = isset ( $prop['parsedcomment'] );
$this->fld_size = isset( $prop['size'] );
+ $this->fld_sizediff = isset( $prop['sizediff'] );
$this->fld_flags = isset( $prop['flags'] );
$this->fld_timestamp = isset( $prop['timestamp'] );
$this->fld_patrolled = isset( $prop['patrolled'] );
// TODO: if the query is going only against the revision table, should this be done?
$this->selectNamedDB( 'contributions', DB_SLAVE, 'contributions' );
- $db = $this->getDB();
if ( isset( $this->params['userprefix'] ) ) {
$this->prefixMode = true;
$this->prefixMode = false;
$this->multiUserMode = ( count( $this->params['user'] ) > 1 );
}
+
$this->prepareQuery();
// Do the actual query.
$res = $this->select( __METHOD__ );
+ if( $this->fld_sizediff ) {
+ $revIds = array();
+ foreach ( $res as $row ) {
+ if( $row->rev_parent_id ) {
+ $revIds[] = $row->rev_parent_id;
+ }
+ }
+ $this->parentLens = Revision::getParentLengths( $this->getDB(), $revIds );
+ $res->rewind(); // reset
+ }
+
// Initialise some variables
$count = 0;
$limit = $this->params['limit'];
/**
* Validate the 'user' parameter and set the value to compare
* against `revision`.`rev_user_text`
+ *
+ * @param $user string
*/
private function prepareUsername( $user ) {
if ( !is_null( $user ) && $user !== '' ) {
// We're after the revision table, and the corresponding page
// row for anything we retrieve. We may also need the
// recentchanges row and/or tag summary row.
- global $wgUser;
+ $user = $this->getUser();
$tables = array( 'page', 'revision' ); // Order may change
$this->addWhere( 'page_id=rev_page' );
$this->dieUsage( 'Invalid continue param. You should pass the original ' .
'value returned by the previous query', '_badcontinue' );
}
- $encUser = $this->getDB()->strencode( $continue[0] );
- $encTS = wfTimestamp( TS_MW, $continue[1] );
+ $db = $this->getDB();
+ $encUser = $db->addQuotes( $continue[0] );
+ $encTS = $db->addQuotes( $db->timestamp( $continue[1] ) );
$op = ( $this->params['dir'] == 'older' ? '<' : '>' );
$this->addWhere(
- "rev_user_text $op '$encUser' OR " .
- "(rev_user_text = '$encUser' AND " .
- "rev_timestamp $op= '$encTS')"
+ "rev_user_text $op $encUser OR " .
+ "(rev_user_text = $encUser AND " .
+ "rev_timestamp $op= $encTS)"
);
}
- if ( !$wgUser->isAllowed( 'hideuser' ) ) {
+ if ( !$user->isAllowed( 'hideuser' ) ) {
$this->addWhere( $this->getDB()->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0' );
}
// We only want pages by the specified users.
if ( $this->multiUserMode ) {
$this->addWhereRange( 'rev_user_text', $this->params['dir'], null, null );
}
- $this->addWhereRange( 'rev_timestamp',
+ $this->addTimestampWhereRange( 'rev_timestamp',
$this->params['dir'], $this->params['start'], $this->params['end'] );
$this->addWhereFld( 'page_namespace', $this->params['namespace'] );
if ( !is_null( $show ) ) {
$show = array_flip( $show );
if ( ( isset( $show['minor'] ) && isset( $show['!minor'] ) )
- || ( isset( $show['patrolled'] ) && isset( $show['!patrolled'] ) ) )
- {
- $this->dieUsageMsg( array( 'show' ) );
+ || ( isset( $show['patrolled'] ) && isset( $show['!patrolled'] ) ) ) {
+ $this->dieUsageMsg( 'show' );
}
$this->addWhereIf( 'rev_minor_edit = 0', isset( $show['!minor'] ) );
'rev_timestamp',
'page_namespace',
'page_title',
+ 'rev_user',
'rev_user_text',
'rev_deleted'
) );
if ( isset( $show['patrolled'] ) || isset( $show['!patrolled'] ) ||
- $this->fld_patrolled )
- {
- global $wgUser;
- if ( !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol() ) {
+ $this->fld_patrolled ) {
+ if ( !$user->useRCPatrol() && !$user->useNPPatrol() ) {
$this->dieUsage( 'You need the patrol right to request the patrolled flag', 'permissiondenied' );
}
+
// Use a redundant join condition on both
// timestamp and ID so we can use the timestamp
// index
$this->addFieldsIf( 'page_latest', $this->fld_flags );
// $this->addFieldsIf( 'rev_text_id', $this->fld_ids ); // Should this field be exposed?
$this->addFieldsIf( 'rev_comment', $this->fld_comment || $this->fld_parsedcomment );
- $this->addFieldsIf( 'rev_len', $this->fld_size );
+ $this->addFieldsIf( 'rev_len', $this->fld_size || $this->fld_sizediff );
$this->addFieldsIf( 'rev_minor_edit', $this->fld_flags );
- $this->addFieldsIf( 'rev_parent_id', $this->fld_flags );
+ $this->addFieldsIf( 'rev_parent_id', $this->fld_flags || $this->fld_sizediff );
$this->addFieldsIf( 'rc_patrolled', $this->fld_patrolled );
if ( $this->fld_tags ) {
$index['change_tag'] = $wgOldChangeTagsIndex ? 'ct_tag' : 'change_tag_tag_id';
}
+ if ( $this->params['toponly'] ) {
+ $this->addWhere( 'rev_id = page_latest' );
+ }
+
$this->addOption( 'USE INDEX', $index );
}
/**
* Extract fields from the database row and append them to a result array
+ *
+ * @param $row
+ * @return array
*/
private function extractRowInfo( $row ) {
$vals = array();
+ $vals['userid'] = $row->rev_user;
$vals['user'] = $row->rev_user_text;
if ( $row->rev_deleted & Revision::DELETED_USER ) {
$vals['userhidden'] = '';
}
if ( $this->fld_parsedcomment ) {
- global $wgUser;
- $vals['parsedcomment'] = $wgUser->getSkin()->formatComment( $row->rev_comment, $title );
+ $vals['parsedcomment'] = Linker::formatComment( $row->rev_comment, $title );
}
}
}
$vals['size'] = intval( $row->rev_len );
}
+ if ( $this->fld_sizediff && !is_null( $row->rev_len ) && !is_null( $row->rev_parent_id ) ) {
+ $parentLen = isset( $this->parentLens[$row->rev_parent_id] ) ? $this->parentLens[$row->rev_parent_id] : 0;
+ $vals['sizediff'] = intval( $row->rev_len - $parentLen );
+ }
+
if ( $this->fld_tags ) {
if ( $row->ts_tags ) {
$tags = explode( ',', $row->ts_tags );
wfTimestamp( TS_ISO_8601, $row->rev_timestamp );
}
+ public function getCacheMode( $params ) {
+ // This module provides access to deleted revisions and patrol flags if
+ // the requester is logged in
+ return 'anon-public-user-private';
+ }
+
public function getAllowedParams() {
return array(
'limit' => array(
'comment',
'parsedcomment',
'size',
+ 'sizediff',
'flags',
'patrolled',
'tags'
)
),
'tag' => null,
+ 'toponly' => false,
);
}
'continue' => 'When more results are available, use this to continue',
'user' => 'The users to retrieve contributions for',
'userprefix' => "Retrieve contibutions for all users whose names begin with this value. Overrides {$p}user",
- 'dir' => 'The direction to search (older or newer)',
+ 'dir' => $this->getDirectionDescription( $p ),
'namespace' => 'Only list contributions in these namespaces',
'prop' => array(
'Include additional pieces of information',
- ' ids - Adds the page id and revision id',
- ' title - Adds the title and namespace id of the page',
+ ' ids - Adds the page ID and revision ID',
+ ' title - Adds the title and namespace ID of the page',
' timestamp - Adds the timestamp of the edit',
' comment - Adds the comment of the edit',
' parsedcomment - Adds the parsed comment of the edit',
- ' size - Adds the size of the page',
+ ' size - Adds the new size of the edit',
+ ' sizediff - Adds the size delta of the edit against its parent',
' flags - Adds flags of the edit',
' patrolled - Tags patrolled edits',
' tags - Lists tags for the edit',
),
'show' => array( "Show only items that meet this criteria, e.g. non minor edits only: {$p}show=!minor",
- "NOTE: if {$p}show=patrolled or {$p}show=!patrolled is set, revisions older than $wgRCMaxAge won\'t be shown", ),
+ "NOTE: if {$p}show=patrolled or {$p}show=!patrolled is set, revisions older than \$wgRCMaxAge ($wgRCMaxAge) won't be shown", ),
'tag' => 'Only list revisions tagged with this tag',
+ 'toponly' => 'Only list changes which are the latest revision',
+ );
+ }
+
+ public function getResultProperties() {
+ return array(
+ '' => array(
+ 'userid' => 'integer',
+ 'user' => 'string',
+ 'userhidden' => 'boolean'
+ ),
+ 'ids' => array(
+ 'pageid' => 'integer',
+ 'revid' => 'integer'
+ ),
+ 'title' => array(
+ 'ns' => 'namespace',
+ 'title' => 'string'
+ ),
+ 'timestamp' => array(
+ 'timestamp' => 'timestamp'
+ ),
+ 'flags' => array(
+ 'new' => 'boolean',
+ 'minor' => 'boolean',
+ 'top' => 'boolean'
+ ),
+ 'comment' => array(
+ 'commenthidden' => 'boolean',
+ 'comment' => array(
+ ApiBase::PROP_TYPE => 'string',
+ ApiBase::PROP_NULLABLE => true
+ )
+ ),
+ 'parsedcomment' => array(
+ 'commenthidden' => 'boolean',
+ 'parsedcomment' => array(
+ ApiBase::PROP_TYPE => 'string',
+ ApiBase::PROP_NULLABLE => true
+ )
+ ),
+ 'patrolled' => array(
+ 'patrolled' => 'boolean'
+ ),
+ 'size' => array(
+ 'size' => array(
+ ApiBase::PROP_TYPE => 'integer',
+ ApiBase::PROP_NULLABLE => true
+ )
+ )
);
}
) );
}
- protected function getExamples() {
+ public function getExamples() {
return array(
'api.php?action=query&list=usercontribs&ucuser=YurikBot',
'api.php?action=query&list=usercontribs&ucuserprefix=217.121.114.',
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Usercontribs';
+ }
+
public function getVersion() {
return __CLASS__ . ': $Id$';
}