X-Git-Url: http://git.cyclocoop.org/?a=blobdiff_plain;f=includes%2Fapi%2FApiQueryAllUsers.php;h=336c494067868b55811a9c48e55d683897cf51a8;hb=6bc8739f6fe38a66d63073374b947091437f56c5;hp=71ea2886c54b42100806c086764f671aa78df937;hpb=b7d460aaeb8e997473a3b0ac0cd42e550104a02c;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/api/ApiQueryAllUsers.php b/includes/api/ApiQueryAllUsers.php index 71ea2886c5..336c494067 100644 --- a/includes/api/ApiQueryAllUsers.php +++ b/includes/api/ApiQueryAllUsers.php @@ -1,11 +1,10 @@ @gmail.com + * Copyright © 2007 Yuri Astrakhan @gmail.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,24 +18,25 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html + * + * @file */ -if (!defined('MEDIAWIKI')) { +if ( !defined( 'MEDIAWIKI' ) ) { // Eclipse helper - will be ignored in production - require_once ('ApiQueryBase.php'); + require_once( 'ApiQueryBase.php' ); } /** * Query module to enumerate all registered users. * - * @addtogroup API + * @ingroup API */ class ApiQueryAllUsers extends ApiQueryBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'au'); + public function __construct( $query, $moduleName ) { + parent::__construct( $query, $moduleName, 'au' ); } public function execute() { @@ -44,58 +44,127 @@ class ApiQueryAllUsers extends ApiQueryBase { $params = $this->extractRequestParams(); $prop = $params['prop']; - if (!is_null($prop)) { - $prop = array_flip($prop); - $fld_editcount = isset($prop['editcount']); - $fld_groups = isset($prop['groups']); - $fld_registration = isset($prop['registration']); + if ( !is_null( $prop ) ) { + $prop = array_flip( $prop ); + $fld_blockinfo = isset( $prop['blockinfo'] ); + $fld_editcount = isset( $prop['editcount'] ); + $fld_groups = isset( $prop['groups'] ); + $fld_rights = isset( $prop['rights'] ); + $fld_registration = isset( $prop['registration'] ); } else { - $fld_editcount = $fld_groups = $fld_registration = false; + $fld_blockinfo = $fld_editcount = $fld_groups = $fld_registration = $fld_rights = false; } $limit = $params['limit']; - if( !is_null( $params['from'] ) ) - $this->addWhere( 'user_name >= ' . $db->addQuotes( self::keyToTitle( $params['from'] ) ) ); + $this->addTables( 'user' ); + $useIndex = true; + + $dir = ( $params['dir'] == 'descending' ? 'older' : 'newer' ); + $from = is_null( $params['from'] ) ? null : $this->keyToTitle( $params['from'] ); + $to = is_null( $params['to'] ) ? null : $this->keyToTitle( $params['to'] ); + + $this->addWhereRange( 'user_name', $dir, $from, $to ); + + if ( !is_null( $params['prefix'] ) ) { + $this->addWhere( 'user_name' . $db->buildLike( $this->keyToTitle( $params['prefix'] ), $db->anyString() ) ); + } + + if ( !is_null( $params['rights'] ) ) { + $groups = array(); + foreach( $params['rights'] as $r ) { + $groups = array_merge( $groups, User::getGroupsWithPermission( $r ) ); + } + + $groups = array_diff( array_unique( $groups ), User::getImplicitGroups() ); + + if ( is_null( $params['group'] ) ) { + $params['group'] = $groups; + } else { + $params['group'] = array_unique( array_merge( $params['group'], $groups ) ); + } + } - if( isset( $params['prefix'] ) ) - $this->addWhere( 'user_name LIKE "' . $db->escapeLike( self::keyToTitle( $params['prefix'] ) ) . '%"' ); + if ( !is_null( $params['group'] ) && !is_null( $params['excludegroup'] ) ) { + $this->dieUsage( 'group and excludegroup cannot be used together', 'group-excludegroup' ); + } - if (!is_null($params['group'])) { + if ( !is_null( $params['group'] ) && count( $params['group'] ) ) { + $useIndex = false; // Filter only users that belong to a given group - $this->addTables('user_groups', 'ug1'); - $this->addWhere('ug1.ug_user=user_id'); - $this->addWhereFld('ug1.ug_group', $params['group']); + $this->addTables( 'user_groups', 'ug1' ); + $this->addJoinConds( array( 'ug1' => array( 'INNER JOIN', array( 'ug1.ug_user=user_id', + 'ug1.ug_group' => $params['group'] ) ) ) ); + } + + if ( !is_null( $params['excludegroup'] ) && count( $params['excludegroup'] ) ) { + $useIndex = false; + // Filter only users don't belong to a given group + $this->addTables( 'user_groups', 'ug1' ); + + if ( count( $params['excludegroup'] ) == 1 ) { + $exclude = array( 'ug1.ug_group' => $params['excludegroup'][0] ); + } else { + $exclude = array( $db->makeList( array( 'ug1.ug_group' => $params['excludegroup'] ), LIST_OR ) ); + } + $this->addJoinConds( array( 'ug1' => array( 'LEFT OUTER JOIN', + array_merge( array( 'ug1.ug_user=user_id' ), $exclude ) + ) + ) ); + $this->addWhere( 'ug1.ug_user IS NULL' ); + } + + if ( $params['witheditsonly'] ) { + $this->addWhere( 'user_editcount > 0' ); } - if ($fld_groups) { + + $this->showHiddenUsersAddBlockInfo( $fld_blockinfo ); + + if ( $fld_groups || $fld_rights ) { // Show the groups the given users belong to // request more than needed to avoid not getting all rows that belong to one user - $groupCount = count(User::getAllGroups()); - $sqlLimit = $limit+$groupCount+1; - $this->addJoin( - array('user', 'user_groups'), - array(ApiQueryBase::LEFT_JOIN), - array('ug2.ug_user=user_id'), - array(null, 'ug2')); - $this->addFields('ug2.ug_group ug_group2'); + $groupCount = count( User::getAllGroups() ); + $sqlLimit = $limit + $groupCount + 1; + + $this->addTables( 'user_groups', 'ug2' ); + $this->addJoinConds( array( 'ug2' => array( 'LEFT JOIN', 'ug2.ug_user=user_id' ) ) ); + $this->addFields( 'ug2.ug_group ug_group2' ); } else { - $this->addTables('user'); - $sqlLimit = $limit+1; + $sqlLimit = $limit + 1; } - if ($fld_registration) - $this->addFields('user_registration'); + if ( $params['activeusers'] ) { + global $wgActiveUserDays; + $this->addTables( 'recentchanges' ); + + $this->addJoinConds( array( 'recentchanges' => array( + 'INNER JOIN', 'rc_user_text=user_name' + ) ) ); + + $this->addFields( 'COUNT(*) AS recentedits' ); + + $this->addWhere( "rc_log_type IS NULL OR rc_log_type != 'newusers'" ); + $timestamp = $db->timestamp( wfTimestamp( TS_UNIX ) - $wgActiveUserDays*24*3600 ); + $this->addWhere( "rc_timestamp >= {$db->addQuotes( $timestamp )}" ); + + $this->addOption( 'GROUP BY', 'user_name' ); + } - $this->addOption('LIMIT', $sqlLimit); + $this->addOption( 'LIMIT', $sqlLimit ); - $this->addFields('user_name'); - $this->addFieldsIf('user_editcount', $fld_editcount); + $this->addFields( array( + 'user_name', + 'user_id' + ) ); + $this->addFieldsIf( 'user_editcount', $fld_editcount ); + $this->addFieldsIf( 'user_registration', $fld_registration ); - $this->addOption('ORDER BY', 'user_name'); + if ( $useIndex ) { + $this->addOption( 'USE INDEX', array( 'user' => 'user_name' ) ); + } - $res = $this->select(__METHOD__); + $res = $this->select( __METHOD__ ); - $data = array (); $count = 0; $lastUserData = false; $lastUser = false; @@ -107,91 +176,172 @@ class ApiQueryAllUsers extends ApiQueryBase { // Otherwise, the group of the new row is appended to the last entry. // The setContinue... is more complex because of this, and takes into account the higher sql limit // to make sure all rows that belong to the same user are received. - // - while (true) { - $row = $db->fetchObject($res); + foreach ( $res as $row ) { $count++; - if (!$row || $lastUser != $row->user_name) { + if ( $lastUser !== $row->user_name ) { // Save the last pass's user data - if (is_array($lastUserData)) - $data[] = $lastUserData; + if ( is_array( $lastUserData ) ) { + $fit = $result->addValue( array( 'query', $this->getModuleName() ), + null, $lastUserData ); - // No more rows left - if (!$row) - break; + $lastUserData = null; - if ($count > $limit) { + if ( !$fit ) { + $this->setContinueEnumParameter( 'from', + $this->keyToTitle( $lastUserData['name'] ) ); + break; + } + } + + if ( $count > $limit ) { // We've reached the one extra which shows that there are additional pages to be had. Stop here... - $this->setContinueEnumParameter('from', ApiQueryBase :: keyToTitle($row->user_name)); + $this->setContinueEnumParameter( 'from', $this->keyToTitle( $row->user_name ) ); break; } // Record new user's data $lastUser = $row->user_name; - $lastUserData = array( 'name' => $lastUser ); - if ($fld_editcount) - $lastUserData['editcount'] = intval($row->user_editcount); - if ($fld_registration) - $lastUserData['registration'] = wfTimestamp(TS_ISO_8601, $row->user_registration); - + $lastUserData = array( + 'userid' => $row->user_id, + 'name' => $lastUser, + ); + if ( $fld_blockinfo && !is_null( $row->ipb_by_text ) ) { + $lastUserData['blockedby'] = $row->ipb_by_text; + $lastUserData['blockreason'] = $row->ipb_reason; + $lastUserData['blockexpiry'] = $row->ipb_expiry; + } + if ( $row->ipb_deleted ) { + $lastUserData['hidden'] = ''; + } + if ( $fld_editcount ) { + $lastUserData['editcount'] = intval( $row->user_editcount ); + } + if ( $params['activeusers'] ) { + $lastUserData['recenteditcount'] = intval( $row->recentedits ); + } + if ( $fld_registration ) { + $lastUserData['registration'] = $row->user_registration ? + wfTimestamp( TS_ISO_8601, $row->user_registration ) : ''; + } } - if ($sqlLimit == $count) { + if ( $sqlLimit == $count ) { // BUG! database contains group name that User::getAllGroups() does not return // TODO: should handle this more gracefully - ApiBase :: dieDebug(__METHOD__, - 'MediaWiki configuration error: the database contains more user groups than known to User::getAllGroups() function'); + ApiBase::dieDebug( __METHOD__, + 'MediaWiki configuration error: the database contains more user groups than known to User::getAllGroups() function' ); } // Add user's group info - if ($fld_groups && !is_null($row->ug_group2)) { - $lastUserData['groups'][] = $row->ug_group2; - $result->setIndexedTagName($lastUserData['groups'], 'g'); + if ( $fld_groups ) { + if ( !isset( $lastUserData['groups'] ) ) { + $lastUserData['groups'] = ApiQueryUsers::getAutoGroups( User::newFromName( $lastUser ) ); + } + + if ( !is_null( $row->ug_group2 ) ) { + $lastUserData['groups'][] = $row->ug_group2; + } + $result->setIndexedTagName( $lastUserData['groups'], 'g' ); + } + + if ( $fld_rights ) { + if ( !isset( $lastUserData['rights'] ) ) { + $lastUserData['rights'] = User::getGroupPermissions( User::getImplicitGroups() ); + } + if ( !is_null( $row->ug_group2 ) ) { + $lastUserData['rights'] = array_unique( array_merge( $lastUserData['rights'], + User::getGroupPermissions( array( $row->ug_group2 ) ) ) ); + } + $result->setIndexedTagName( $lastUserData['rights'], 'r' ); + } + } + + if ( is_array( $lastUserData ) ) { + $fit = $result->addValue( array( 'query', $this->getModuleName() ), + null, $lastUserData ); + if ( !$fit ) { + $this->setContinueEnumParameter( 'from', + $this->keyToTitle( $lastUserData['name'] ) ); } } - $db->freeResult($res); + $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'u' ); + } - $result->setIndexedTagName($data, 'u'); - $result->addValue('query', $this->getModuleName(), $data); + public function getCacheMode( $params ) { + return 'anon-public-user-private'; } public function getAllowedParams() { - return array ( + $userGroups = User::getAllGroups(); + return array( 'from' => null, + 'to' => null, 'prefix' => null, + 'dir' => array( + ApiBase::PARAM_DFLT => 'ascending', + ApiBase::PARAM_TYPE => array( + 'ascending', + 'descending' + ), + ), 'group' => array( - ApiBase :: PARAM_TYPE => User::getAllGroups() + ApiBase::PARAM_TYPE => $userGroups, + ApiBase::PARAM_ISMULTI => true, ), - 'prop' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => array ( - 'editcount', + 'excludegroup' => array( + ApiBase::PARAM_TYPE => $userGroups, + ApiBase::PARAM_ISMULTI => true, + ), + 'rights' => array( + ApiBase::PARAM_TYPE => User::getAllRights(), + ApiBase::PARAM_ISMULTI => true, + ), + 'prop' => array( + ApiBase::PARAM_ISMULTI => true, + ApiBase::PARAM_TYPE => array( + 'blockinfo', 'groups', - 'registration', + 'rights', + 'editcount', + 'registration' ) ), - 'limit' => array ( - ApiBase :: PARAM_DFLT => 10, - ApiBase :: PARAM_TYPE => 'limit', - ApiBase :: PARAM_MIN => 1, - ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, - ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 - ) + 'limit' => array( + ApiBase::PARAM_DFLT => 10, + ApiBase::PARAM_TYPE => 'limit', + ApiBase::PARAM_MIN => 1, + ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1, + ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2 + ), + 'witheditsonly' => false, + 'activeusers' => false, ); } public function getParamDescription() { - return array ( - 'from' => 'The user name to start enumerating from.', - 'prefix' => 'Search for all page titles that begin with this value.', - 'group' => 'Limit users to a given group name', + global $wgActiveUserDays; + return array( + 'from' => 'The user name to start enumerating from', + 'to' => 'The user name to stop enumerating at', + 'prefix' => 'Search for all users that begin with this value', + 'dir' => 'Direction to sort in', + 'group' => 'Limit users to given group name(s)', + 'excludegroup' => 'Exclude users in given group name(s)', + 'rights' => 'Limit users to given right(s)', 'prop' => array( 'What pieces of information to include.', - '`groups` property uses more server resources and may return fewer results than the limit.'), - 'limit' => 'How many total user names to return.', + ' blockinfo - Adds the information about a current block on the user', + ' groups - Lists groups that the user is in. This uses more server resources and may return fewer results than the limit', + ' rights - Lists rights that the user has', + ' editcount - Adds the edit count of the user', + ' registration - Adds the timestamp of when the user registered if available (may be blank)', + ), + 'limit' => 'How many total user names to return', + 'witheditsonly' => 'Only list users who have made edits', + 'activeusers' => "Only list users active in the last {$wgActiveUserDays} days(s)" ); } @@ -199,8 +349,14 @@ class ApiQueryAllUsers extends ApiQueryBase { return 'Enumerate all registered users'; } + public function getPossibleErrors() { + return array_merge( parent::getPossibleErrors(), array( + array( 'code' => 'group-excludegroup', 'info' => 'group and excludegroup cannot be used together' ), + ) ); + } + protected function getExamples() { - return array ( + return array( 'api.php?action=query&list=allusers&aufrom=Y', ); }