MediaWiki 1.41.2
ApiQueryUsers.php
Go to the documentation of this file.
1<?php
30
38
39 private $prop;
40
41 private UserNameUtils $userNameUtils;
42 private UserFactory $userFactory;
43 private UserGroupManager $userGroupManager;
44 private GenderCache $genderCache;
45 private AuthManager $authManager;
46
52 protected static $publicProps = [
53 // everything except 'blockinfo' which might show hidden records if the user
54 // making the request has the appropriate permissions
55 'groups',
56 'groupmemberships',
57 'implicitgroups',
58 'rights',
59 'editcount',
60 'registration',
61 'emailable',
62 'gender',
63 'centralids',
64 'cancreate',
65 ];
66
76 public function __construct(
77 ApiQuery $query,
78 $moduleName,
79 UserNameUtils $userNameUtils,
80 UserFactory $userFactory,
81 UserGroupManager $userGroupManager,
82 GenderCache $genderCache,
83 AuthManager $authManager
84 ) {
85 parent::__construct( $query, $moduleName, 'us' );
86 $this->userNameUtils = $userNameUtils;
87 $this->userFactory = $userFactory;
88 $this->userGroupManager = $userGroupManager;
89 $this->genderCache = $genderCache;
90 $this->authManager = $authManager;
91 }
92
93 public function execute() {
94 $db = $this->getDB();
95 $params = $this->extractRequestParams();
96 $this->requireMaxOneParameter( $params, 'userids', 'users' );
97
98 if ( $params['prop'] !== null ) {
99 $this->prop = array_fill_keys( $params['prop'], true );
100 } else {
101 $this->prop = [];
102 }
103 $useNames = $params['users'] !== null;
104
105 $users = (array)$params['users'];
106 $userids = (array)$params['userids'];
107
108 $goodNames = $done = [];
109 $result = $this->getResult();
110 // Canonicalize user names
111 foreach ( $users as $u ) {
112 $n = $this->userNameUtils->getCanonical( $u );
113 if ( $n === false || $n === '' ) {
114 $vals = [ 'name' => $u, 'invalid' => true ];
115 $fit = $result->addValue( [ 'query', $this->getModuleName() ],
116 null, $vals );
117 if ( !$fit ) {
118 $this->setContinueEnumParameter( 'users',
119 implode( '|', array_diff( $users, $done ) ) );
120 $goodNames = [];
121 break;
122 }
123 $done[] = $u;
124 } else {
125 $goodNames[] = $n;
126 }
127 }
128
129 if ( $useNames ) {
130 $parameters = &$goodNames;
131 } else {
132 $parameters = &$userids;
133 }
134
135 $result = $this->getResult();
136
137 if ( count( $parameters ) ) {
138 $this->getQueryBuilder()->merge( User::newQueryBuilder( $db ) );
139 if ( $useNames ) {
140 $this->addWhereFld( 'user_name', $goodNames );
141 } else {
142 $this->addWhereFld( 'user_id', $userids );
143 }
144
145 $this->addBlockInfoToQuery( isset( $this->prop['blockinfo'] ) );
146
147 $data = [];
148 $res = $this->select( __METHOD__ );
149 $this->resetQueryParams();
150
151 // get user groups if needed
152 if ( isset( $this->prop['groups'] ) || isset( $this->prop['rights'] ) ) {
153 $userGroups = [];
154
155 $this->addTables( 'user' );
156 if ( $useNames ) {
157 $this->addWhereFld( 'user_name', $goodNames );
158 } else {
159 $this->addWhereFld( 'user_id', $userids );
160 }
161
162 $this->addTables( 'user_groups' );
163 $this->addJoinConds( [ 'user_groups' => [ 'JOIN', 'ug_user=user_id' ] ] );
164 $this->addFields( [ 'user_name' ] );
165 $this->addFields( [ 'ug_user', 'ug_group', 'ug_expiry' ] );
166 $this->addWhere( 'ug_expiry IS NULL OR ug_expiry >= ' .
167 $db->addQuotes( $db->timestamp() ) );
168 $userGroupsRes = $this->select( __METHOD__ );
169
170 foreach ( $userGroupsRes as $row ) {
171 $userGroups[$row->user_name][] = $row;
172 }
173 }
174 if ( isset( $this->prop['gender'] ) ) {
175 $userNames = [];
176 foreach ( $res as $row ) {
177 $userNames[] = $row->user_name;
178 }
179 $this->genderCache->doQuery( $userNames, __METHOD__ );
180 }
181
182 foreach ( $res as $row ) {
183 // create user object and pass along $userGroups if set
184 // that reduces the number of database queries needed in User dramatically
185 if ( !isset( $userGroups ) ) {
186 $user = $this->userFactory->newFromRow( $row );
187 } else {
188 if ( !isset( $userGroups[$row->user_name] ) || !is_array( $userGroups[$row->user_name] ) ) {
189 $userGroups[$row->user_name] = [];
190 }
191 $user = $this->userFactory->newFromRow( $row, [ 'user_groups' => $userGroups[$row->user_name] ] );
192 }
193 if ( $useNames ) {
194 $key = $user->getName();
195 } else {
196 $key = $user->getId();
197 }
198 $data[$key]['userid'] = $user->getId();
199 $data[$key]['name'] = $user->getName();
200
201 if ( isset( $this->prop['editcount'] ) ) {
202 $data[$key]['editcount'] = $user->getEditCount();
203 }
204
205 if ( isset( $this->prop['registration'] ) ) {
206 $data[$key]['registration'] = wfTimestampOrNull( TS_ISO_8601, $user->getRegistration() );
207 }
208
209 if ( isset( $this->prop['groups'] ) ) {
210 $data[$key]['groups'] = $this->userGroupManager->getUserEffectiveGroups( $user );
211 }
212
213 if ( isset( $this->prop['groupmemberships'] ) ) {
214 $data[$key]['groupmemberships'] = array_map( static function ( $ugm ) {
215 return [
216 'group' => $ugm->getGroup(),
217 'expiry' => ApiResult::formatExpiry( $ugm->getExpiry() ),
218 ];
219 }, $this->userGroupManager->getUserGroupMemberships( $user ) );
220 }
221
222 if ( isset( $this->prop['implicitgroups'] ) ) {
223 $data[$key]['implicitgroups'] = $this->userGroupManager->getUserImplicitGroups( $user );
224 }
225
226 if ( isset( $this->prop['rights'] ) ) {
227 $data[$key]['rights'] = $this->getPermissionManager()
228 ->getUserPermissions( $user );
229 }
230 if ( $row->ipb_deleted ) {
231 $data[$key]['hidden'] = true;
232 }
233 if ( isset( $this->prop['blockinfo'] ) && $row->ipb_by_text !== null ) {
234 $data[$key] += $this->getBlockDetails( DatabaseBlock::newFromRow( $row ) );
235 }
236
237 if ( isset( $this->prop['emailable'] ) ) {
238 $data[$key]['emailable'] = $user->canReceiveEmail();
239 }
240
241 if ( isset( $this->prop['gender'] ) ) {
242 $data[$key]['gender'] = $this->genderCache->getGenderOf( $user, __METHOD__ );
243 }
244
245 if ( isset( $this->prop['centralids'] ) ) {
247 $this->getConfig(), $user, $params['attachedwiki']
248 );
249 }
250 }
251 }
252
253 // Second pass: add result data to $retval
254 foreach ( $parameters as $u ) {
255 if ( !isset( $data[$u] ) ) {
256 if ( $useNames ) {
257 $data[$u] = [ 'name' => $u, 'missing' => true ];
258 if ( isset( $this->prop['cancreate'] ) ) {
259 $status = $this->authManager->canCreateAccount( $u );
260 $data[$u]['cancreate'] = $status->isGood();
261 if ( !$status->isGood() ) {
262 $data[$u]['cancreateerror'] = $this->getErrorFormatter()->arrayFromStatus( $status );
263 }
264 }
265 } else {
266 $data[$u] = [ 'userid' => $u, 'missing' => true ];
267 }
268
269 } else {
270 if ( isset( $this->prop['groups'] ) && isset( $data[$u]['groups'] ) ) {
271 ApiResult::setArrayType( $data[$u]['groups'], 'array' );
272 ApiResult::setIndexedTagName( $data[$u]['groups'], 'g' );
273 }
274 if ( isset( $this->prop['groupmemberships'] ) && isset( $data[$u]['groupmemberships'] ) ) {
275 ApiResult::setArrayType( $data[$u]['groupmemberships'], 'array' );
276 ApiResult::setIndexedTagName( $data[$u]['groupmemberships'], 'groupmembership' );
277 }
278 if ( isset( $this->prop['implicitgroups'] ) && isset( $data[$u]['implicitgroups'] ) ) {
279 ApiResult::setArrayType( $data[$u]['implicitgroups'], 'array' );
280 ApiResult::setIndexedTagName( $data[$u]['implicitgroups'], 'g' );
281 }
282 if ( isset( $this->prop['rights'] ) && isset( $data[$u]['rights'] ) ) {
283 ApiResult::setArrayType( $data[$u]['rights'], 'array' );
284 ApiResult::setIndexedTagName( $data[$u]['rights'], 'r' );
285 }
286 }
287
288 $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $data[$u] );
289 if ( !$fit ) {
290 if ( $useNames ) {
291 $this->setContinueEnumParameter( 'users',
292 implode( '|', array_diff( $users, $done ) ) );
293 } else {
294 $this->setContinueEnumParameter( 'userids',
295 implode( '|', array_diff( $userids, $done ) ) );
296 }
297 break;
298 }
299 $done[] = $u;
300 }
301 $result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'user' );
302 }
303
304 public function getCacheMode( $params ) {
305 if ( array_diff( (array)$params['prop'], static::$publicProps ) ) {
306 return 'anon-public-user-private';
307 } else {
308 return 'public';
309 }
310 }
311
312 public function getAllowedParams() {
313 return [
314 'prop' => [
315 ParamValidator::PARAM_ISMULTI => true,
316 ParamValidator::PARAM_TYPE => [
317 'blockinfo',
318 'groups',
319 'groupmemberships',
320 'implicitgroups',
321 'rights',
322 'editcount',
323 'registration',
324 'emailable',
325 'gender',
326 'centralids',
327 'cancreate',
328 // When adding a prop, consider whether it should be added
329 // to self::$publicProps
330 ],
332 ],
333 'attachedwiki' => null,
334 'users' => [
335 ParamValidator::PARAM_ISMULTI => true
336 ],
337 'userids' => [
338 ParamValidator::PARAM_ISMULTI => true,
339 ParamValidator::PARAM_TYPE => 'integer'
340 ],
341 ];
342 }
343
344 protected function getExamplesMessages() {
345 return [
346 'action=query&list=users&ususers=Example&usprop=groups|editcount|gender'
347 => 'apihelp-query+users-example-simple',
348 ];
349 }
350
351 public function getHelpUrls() {
352 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Users';
353 }
354}
wfTimestampOrNull( $outputtype=TS_UNIX, $ts=null)
Return a formatted timestamp, or null if input is null.
getErrorFormatter()
Definition ApiBase.php:678
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks.
Definition ApiBase.php:727
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, or 'string' with PARAM_ISMULTI,...
Definition ApiBase.php:209
requireMaxOneParameter( $params,... $required)
Dies if more than one parameter from a certain set of parameters are set and not false.
Definition ApiBase.php:981
getResult()
Get the result object.
Definition ApiBase.php:667
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:807
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:528
This is a base class for all Query modules.
setContinueEnumParameter( $paramName, $paramValue)
Set a query-continue value.
resetQueryParams()
Blank the internal arrays with query parameters.
getQueryBuilder()
Get the SelectQueryBuilder.
addFields( $value)
Add a set of fields to select to the internal array.
addTables( $tables, $alias=null)
Add a set of tables to the internal array.
getDB()
Get the Query database connection (read-only)
select( $method, $extraQuery=[], array &$hookData=null)
Execute a SELECT query based on the values in the internal arrays.
addJoinConds( $join_conds)
Add a set of JOIN conditions to the internal array.
addWhereFld( $field, $value)
Equivalent to addWhere( [ $field => $value ] )
addWhere( $value)
Add a set of WHERE clauses to the internal array.
static getCentralUserInfo(Config $config, UserIdentity $user, $attachedWiki=UserIdentity::LOCAL)
Get central user info.
Query module to get information about a list of users.
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
static array $publicProps
Properties whose contents does not depend on who is looking at them.
getHelpUrls()
Return links to more detailed help pages about the module.
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
getExamplesMessages()
Returns usage examples for this module.
__construct(ApiQuery $query, $moduleName, UserNameUtils $userNameUtils, UserFactory $userFactory, UserGroupManager $userGroupManager, GenderCache $genderCache, AuthManager $authManager)
getCacheMode( $params)
Get the cache mode for the data generated by this module.
This is the main query class.
Definition ApiQuery.php:43
Look up "gender" user preference.
This serves as the entry point to the authentication system.
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
Creates User objects.
UserNameUtils service.
internal since 1.36
Definition User.php:98
Service for formatting and validating API parameters.
trait ApiQueryBlockInfoTrait
return true
Definition router.php:92