MediaWiki  master
ApiQueryUsers.php
Go to the documentation of this file.
1 <?php
29 
35 class ApiQueryUsers extends ApiQueryBase {
37 
38  private $prop;
39 
41  private $userNameUtils;
42 
44  private $userFactory;
45 
48 
51 
53  private $authManager;
54 
60  protected static $publicProps = [
61  // everything except 'blockinfo' which might show hidden records if the user
62  // making the request has the appropriate permissions
63  'groups',
64  'groupmemberships',
65  'implicitgroups',
66  'rights',
67  'editcount',
68  'registration',
69  'emailable',
70  'gender',
71  'centralids',
72  'cancreate',
73  ];
74 
84  public function __construct(
85  ApiQuery $query,
86  $moduleName,
92  ) {
93  parent::__construct( $query, $moduleName, 'us' );
94  $this->userNameUtils = $userNameUtils;
95  $this->userFactory = $userFactory;
96  $this->userGroupManager = $userGroupManager;
97  $this->userOptionsLookup = $userOptionsLookup;
98  $this->authManager = $authManager;
99  }
100 
101  public function execute() {
102  $db = $this->getDB();
103  $params = $this->extractRequestParams();
104  $this->requireMaxOneParameter( $params, 'userids', 'users' );
105 
106  if ( $params['prop'] !== null ) {
107  $this->prop = array_fill_keys( $params['prop'], true );
108  } else {
109  $this->prop = [];
110  }
111  $useNames = $params['users'] !== null;
112 
113  $users = (array)$params['users'];
114  $userids = (array)$params['userids'];
115 
116  $goodNames = $done = [];
117  $result = $this->getResult();
118  // Canonicalize user names
119  foreach ( $users as $u ) {
120  $n = $this->userNameUtils->getCanonical( $u );
121  if ( $n === false || $n === '' ) {
122  $vals = [ 'name' => $u, 'invalid' => true ];
123  $fit = $result->addValue( [ 'query', $this->getModuleName() ],
124  null, $vals );
125  if ( !$fit ) {
126  $this->setContinueEnumParameter( 'users',
127  implode( '|', array_diff( $users, $done ) ) );
128  $goodNames = [];
129  break;
130  }
131  $done[] = $u;
132  } else {
133  $goodNames[] = $n;
134  }
135  }
136 
137  if ( $useNames ) {
138  $parameters = &$goodNames;
139  } else {
140  $parameters = &$userids;
141  }
142 
143  $result = $this->getResult();
144 
145  if ( count( $parameters ) ) {
146  $userQuery = User::getQueryInfo();
147  $this->addTables( $userQuery['tables'] );
148  $this->addFields( $userQuery['fields'] );
149  $this->addJoinConds( $userQuery['joins'] );
150  if ( $useNames ) {
151  $this->addWhereFld( 'user_name', $goodNames );
152  } else {
153  $this->addWhereFld( 'user_id', $userids );
154  }
155 
156  $this->addBlockInfoToQuery( isset( $this->prop['blockinfo'] ) );
157 
158  $data = [];
159  $res = $this->select( __METHOD__ );
160  $this->resetQueryParams();
161 
162  // get user groups if needed
163  if ( isset( $this->prop['groups'] ) || isset( $this->prop['rights'] ) ) {
164  $userGroups = [];
165 
166  $this->addTables( 'user' );
167  if ( $useNames ) {
168  $this->addWhereFld( 'user_name', $goodNames );
169  } else {
170  $this->addWhereFld( 'user_id', $userids );
171  }
172 
173  $this->addTables( 'user_groups' );
174  $this->addJoinConds( [ 'user_groups' => [ 'JOIN', 'ug_user=user_id' ] ] );
175  $this->addFields( [ 'user_name' ] );
176  $this->addFields( $this->userGroupManager->getQueryInfo()['fields'] );
177  $this->addWhere( 'ug_expiry IS NULL OR ug_expiry >= ' .
178  $db->addQuotes( $db->timestamp() ) );
179  $userGroupsRes = $this->select( __METHOD__ );
180 
181  foreach ( $userGroupsRes as $row ) {
182  $userGroups[$row->user_name][] = $row;
183  }
184  }
185 
186  foreach ( $res as $row ) {
187  // create user object and pass along $userGroups if set
188  // that reduces the number of database queries needed in User dramatically
189  if ( !isset( $userGroups ) ) {
190  $user = $this->userFactory->newFromRow( $row );
191  } else {
192  if ( !isset( $userGroups[$row->user_name] ) || !is_array( $userGroups[$row->user_name] ) ) {
193  $userGroups[$row->user_name] = [];
194  }
195  $user = $this->userFactory->newFromRow( $row, [ 'user_groups' => $userGroups[$row->user_name] ] );
196  }
197  if ( $useNames ) {
198  $key = $user->getName();
199  } else {
200  $key = $user->getId();
201  }
202  $data[$key]['userid'] = $user->getId();
203  $data[$key]['name'] = $user->getName();
204 
205  if ( isset( $this->prop['editcount'] ) ) {
206  $data[$key]['editcount'] = $user->getEditCount();
207  }
208 
209  if ( isset( $this->prop['registration'] ) ) {
210  $data[$key]['registration'] = wfTimestampOrNull( TS_ISO_8601, $user->getRegistration() );
211  }
212 
213  if ( isset( $this->prop['groups'] ) ) {
214  $data[$key]['groups'] = $this->userGroupManager->getUserEffectiveGroups( $user );
215  }
216 
217  if ( isset( $this->prop['groupmemberships'] ) ) {
218  $data[$key]['groupmemberships'] = array_map( static function ( $ugm ) {
219  return [
220  'group' => $ugm->getGroup(),
221  'expiry' => ApiResult::formatExpiry( $ugm->getExpiry() ),
222  ];
223  }, $this->userGroupManager->getUserGroupMemberships( $user ) );
224  }
225 
226  if ( isset( $this->prop['implicitgroups'] ) ) {
227  $data[$key]['implicitgroups'] = $this->userGroupManager->getUserImplicitGroups( $user );
228  }
229 
230  if ( isset( $this->prop['rights'] ) ) {
231  $data[$key]['rights'] = $this->getPermissionManager()
232  ->getUserPermissions( $user );
233  }
234  if ( $row->ipb_deleted ) {
235  $data[$key]['hidden'] = true;
236  }
237  if ( isset( $this->prop['blockinfo'] ) && $row->ipb_by_text !== null ) {
238  $data[$key] += $this->getBlockDetails( DatabaseBlock::newFromRow( $row ) );
239  }
240 
241  if ( isset( $this->prop['emailable'] ) ) {
242  $data[$key]['emailable'] = $user->canReceiveEmail();
243  }
244 
245  if ( isset( $this->prop['gender'] ) ) {
246  $gender = $this->userOptionsLookup->getOption( $user, 'gender' );
247  if ( strval( $gender ) === '' ) {
248  $gender = 'unknown';
249  }
250  $data[$key]['gender'] = $gender;
251  }
252 
253  if ( isset( $this->prop['centralids'] ) ) {
255  $this->getConfig(), $user, $params['attachedwiki']
256  );
257  }
258  }
259  }
260 
261  $context = $this->getContext();
262  // Second pass: add result data to $retval
263  foreach ( $parameters as $u ) {
264  if ( !isset( $data[$u] ) ) {
265  if ( $useNames ) {
266  $data[$u] = [ 'name' => $u ];
267  $urPage = new UserrightsPage;
268  $urPage->setContext( $context );
269 
270  $iwUser = $urPage->fetchUser( $u );
271 
272  if ( $iwUser instanceof UserRightsProxy ) {
273  $data[$u]['interwiki'] = true;
274  } else {
275  $data[$u]['missing'] = true;
276  if ( isset( $this->prop['cancreate'] ) ) {
277  $status = $this->authManager->canCreateAccount( $u );
278  $data[$u]['cancreate'] = $status->isGood();
279  if ( !$status->isGood() ) {
280  $data[$u]['cancreateerror'] = $this->getErrorFormatter()->arrayFromStatus( $status );
281  }
282  }
283  }
284  } else {
285  $data[$u] = [ 'userid' => $u, 'missing' => true ];
286  }
287 
288  } else {
289  if ( isset( $this->prop['groups'] ) && isset( $data[$u]['groups'] ) ) {
290  ApiResult::setArrayType( $data[$u]['groups'], 'array' );
291  ApiResult::setIndexedTagName( $data[$u]['groups'], 'g' );
292  }
293  if ( isset( $this->prop['groupmemberships'] ) && isset( $data[$u]['groupmemberships'] ) ) {
294  ApiResult::setArrayType( $data[$u]['groupmemberships'], 'array' );
295  ApiResult::setIndexedTagName( $data[$u]['groupmemberships'], 'groupmembership' );
296  }
297  if ( isset( $this->prop['implicitgroups'] ) && isset( $data[$u]['implicitgroups'] ) ) {
298  ApiResult::setArrayType( $data[$u]['implicitgroups'], 'array' );
299  ApiResult::setIndexedTagName( $data[$u]['implicitgroups'], 'g' );
300  }
301  if ( isset( $this->prop['rights'] ) && isset( $data[$u]['rights'] ) ) {
302  ApiResult::setArrayType( $data[$u]['rights'], 'array' );
303  ApiResult::setIndexedTagName( $data[$u]['rights'], 'r' );
304  }
305  }
306 
307  $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $data[$u] );
308  if ( !$fit ) {
309  if ( $useNames ) {
310  $this->setContinueEnumParameter( 'users',
311  implode( '|', array_diff( $users, $done ) ) );
312  } else {
313  $this->setContinueEnumParameter( 'userids',
314  implode( '|', array_diff( $userids, $done ) ) );
315  }
316  break;
317  }
318  $done[] = $u;
319  }
320  $result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'user' );
321  }
322 
323  public function getCacheMode( $params ) {
324  if ( array_diff( (array)$params['prop'], static::$publicProps ) ) {
325  return 'anon-public-user-private';
326  } else {
327  return 'public';
328  }
329  }
330 
331  public function getAllowedParams() {
332  return [
333  'prop' => [
334  ApiBase::PARAM_ISMULTI => true,
336  'blockinfo',
337  'groups',
338  'groupmemberships',
339  'implicitgroups',
340  'rights',
341  'editcount',
342  'registration',
343  'emailable',
344  'gender',
345  'centralids',
346  'cancreate',
347  // When adding a prop, consider whether it should be added
348  // to self::$publicProps
349  ],
351  ],
352  'attachedwiki' => null,
353  'users' => [
355  ],
356  'userids' => [
357  ApiBase::PARAM_ISMULTI => true,
358  ApiBase::PARAM_TYPE => 'integer'
359  ],
360  ];
361  }
362 
363  protected function getExamplesMessages() {
364  return [
365  'action=query&list=users&ususers=Example&usprop=groups|editcount|gender'
366  => 'apihelp-query+users-example-simple',
367  ];
368  }
369 
370  public function getHelpUrls() {
371  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Users';
372  }
373 }
ContextSource\$context
IContextSource $context
Definition: ContextSource.php:39
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:72
ApiQueryBase\addFields
addFields( $value)
Add a set of fields to select to the internal array.
Definition: ApiQueryBase.php:212
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:47
ApiQueryUsers\$userNameUtils
UserNameUtils $userNameUtils
Definition: ApiQueryUsers.php:41
ApiQuery
This is the main query class.
Definition: ApiQuery.php:37
ApiQueryUsers
Query module to get information about a list of users.
Definition: ApiQueryUsers.php:35
ApiQueryUsers\__construct
__construct(ApiQuery $query, $moduleName, UserNameUtils $userNameUtils, UserFactory $userFactory, UserGroupManager $userGroupManager, UserOptionsLookup $userOptionsLookup, AuthManager $authManager)
Definition: ApiQueryUsers.php:84
ApiQueryBase\resetQueryParams
resetQueryParams()
Blank the internal arrays with query parameters.
Definition: ApiQueryBase.php:156
true
return true
Definition: router.php:90
ApiBase\PARAM_TYPE
const PARAM_TYPE
Definition: ApiBase.php:72
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:571
UserRightsProxy
Cut-down copy of User interface for local-interwiki-database user rights manipulation.
Definition: UserRightsProxy.php:33
$res
$res
Definition: testCompression.php:57
MediaWiki\Block\DatabaseBlock
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
Definition: DatabaseBlock.php:52
MediaWiki\User\UserGroupManager
Managers user groups.
Definition: UserGroupManager.php:52
ApiQueryBlockInfoTrait
trait ApiQueryBlockInfoTrait
Definition: ApiQueryBlockInfoTrait.php:28
UserrightsPage
Special page to allow managing user group membership.
Definition: SpecialUserrights.php:36
ApiResult\setArrayType
static setArrayType(array &$arr, $type, $kvpKeyName=null)
Set the array data type.
Definition: ApiResult.php:715
ApiQueryBase
This is a base class for all Query modules.
Definition: ApiQueryBase.php:37
wfTimestampOrNull
wfTimestampOrNull( $outputtype=TS_UNIX, $ts=null)
Return a formatted timestamp, or null if input is null.
Definition: GlobalFunctions.php:1684
ApiQueryBase\getDB
getDB()
Get the Query database connection (read-only)
Definition: ApiQueryBase.php:117
ApiQueryUsers\$authManager
AuthManager $authManager
Definition: ApiQueryUsers.php:53
ApiQueryUsers\$userFactory
UserFactory $userFactory
Definition: ApiQueryUsers.php:44
ApiQueryBase\addTables
addTables( $tables, $alias=null)
Add a set of tables to the internal array.
Definition: ApiQueryBase.php:182
ApiQueryBase\select
select( $method, $extraQuery=[], array &$hookData=null)
Execute a SELECT query based on the values in the internal arrays.
Definition: ApiQueryBase.php:399
ApiBase\extractRequestParams
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:707
ApiQueryUsers\$userGroupManager
UserGroupManager $userGroupManager
Definition: ApiQueryUsers.php:47
ApiQueryUserInfo\getCentralUserInfo
static getCentralUserInfo(Config $config, UserIdentity $user, $attachedWiki=UserIdentity::LOCAL)
Get central user info.
Definition: ApiQueryUserInfo.php:120
ApiQueryUsers\getHelpUrls
getHelpUrls()
Return links to more detailed help pages about the module.
Definition: ApiQueryUsers.php:370
ApiResult\setIndexedTagName
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Definition: ApiResult.php:603
ApiBase\requireMaxOneParameter
requireMaxOneParameter( $params,... $required)
Die if more than one of a certain set of parameters is set and not false.
Definition: ApiBase.php:879
ApiBase\getPermissionManager
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks.
Definition: ApiBase.php:628
ApiQueryUsers\execute
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
Definition: ApiQueryUsers.php:101
ApiQueryBase\addJoinConds
addJoinConds( $join_conds)
Add a set of JOIN conditions to the internal array.
Definition: ApiQueryBase.php:201
ApiQueryBase\addWhereFld
addWhereFld( $field, $value)
Equivalent to addWhere( [ $field => $value ] )
Definition: ApiQueryBase.php:282
ApiQueryUsers\$userOptionsLookup
UserOptionsLookup $userOptionsLookup
Definition: ApiQueryUsers.php:50
User\getQueryInfo
static getQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new user object.
Definition: User.php:4181
MediaWiki\User\UserOptionsLookup
Provides access to user options.
Definition: UserOptionsLookup.php:29
MediaWiki\Auth\AuthManager
This serves as the entry point to the authentication system.
Definition: AuthManager.php:102
ApiQueryUsers\getCacheMode
getCacheMode( $params)
Get the cache mode for the data generated by this module.
Definition: ApiQueryUsers.php:323
ApiQueryUsers\getExamplesMessages
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiQueryUsers.php:363
MediaWiki\User\UserNameUtils
UserNameUtils service.
Definition: UserNameUtils.php:42
SpecialPage\setContext
setContext( $context)
Sets the context this SpecialPage is executed in.
Definition: SpecialPage.php:754
ApiBase\getModuleName
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:440
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
Definition: ApiBase.php:71
ApiQueryUsers\getAllowedParams
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiQueryUsers.php:331
ApiResult\formatExpiry
static formatExpiry( $expiry, $infinity='infinity')
Format an expiry timestamp for API output.
Definition: ApiResult.php:1194
ApiQueryUsers\$publicProps
static array $publicProps
Properties whose contents does not depend on who is looking at them.
Definition: ApiQueryUsers.php:60
ApiQueryBase\addWhere
addWhere( $value)
Add a set of WHERE clauses to the internal array.
Definition: ApiQueryBase.php:245
ApiQueryBase\setContinueEnumParameter
setContinueEnumParameter( $paramName, $paramValue)
Set a query-continue value.
Definition: ApiQueryBase.php:515
ApiBase\PARAM_HELP_MSG_PER_VALUE
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, this is an array mapping those values to $msg...
Definition: ApiBase.php:138
ApiQueryUsers\$prop
$prop
Definition: ApiQueryUsers.php:38
MediaWiki\User\UserFactory
Creates User objects.
Definition: UserFactory.php:41
ApiBase\getErrorFormatter
getErrorFormatter()
Definition: ApiBase.php:582
addBlockInfoToQuery
addBlockInfoToQuery( $showBlockInfo)
Filters hidden users (where the user doesn't have the right to view them) Also adds relevant block in...
Definition: ApiQueryBlockInfoTrait.php:38