MediaWiki REL1_41
ApiQueryUserInfo.php
Go to the documentation of this file.
1<?php
35
42
44
45 private const WL_UNREAD_LIMIT = 1000;
46
48 private $params = [];
49
51 private $prop = [];
52
53 private TalkPageNotificationManager $talkPageNotificationManager;
54 private WatchedItemStore $watchedItemStore;
55 private UserEditTracker $userEditTracker;
56 private UserOptionsLookup $userOptionsLookup;
57 private UserGroupManager $userGroupManager;
58
68 public function __construct(
69 ApiQuery $query,
70 $moduleName,
71 TalkPageNotificationManager $talkPageNotificationManager,
72 WatchedItemStore $watchedItemStore,
73 UserEditTracker $userEditTracker,
74 UserOptionsLookup $userOptionsLookup,
75 UserGroupManager $userGroupManager
76 ) {
77 parent::__construct( $query, $moduleName, 'ui' );
78 $this->talkPageNotificationManager = $talkPageNotificationManager;
79 $this->watchedItemStore = $watchedItemStore;
80 $this->userEditTracker = $userEditTracker;
81 $this->userOptionsLookup = $userOptionsLookup;
82 $this->userGroupManager = $userGroupManager;
83 }
84
85 public function execute() {
86 $this->params = $this->extractRequestParams();
87 $result = $this->getResult();
88
89 if ( $this->params['prop'] !== null ) {
90 $this->prop = array_fill_keys( $this->params['prop'], true );
91 }
92
93 $r = $this->getCurrentUserInfo();
94 $result->addValue( 'query', $this->getModuleName(), $r );
95 }
96
109 public static function getCentralUserInfo(
110 Config $config,
111 UserIdentity $user,
112 $attachedWiki = UserIdentity::LOCAL
113 ) {
114 $providerIds = array_keys( $config->get( MainConfigNames::CentralIdLookupProviders ) );
115
116 $ret = [
117 'centralids' => [],
118 'attachedlocal' => [],
119 ];
120 ApiResult::setArrayType( $ret['centralids'], 'assoc' );
121 ApiResult::setArrayType( $ret['attachedlocal'], 'assoc' );
122 if ( $attachedWiki ) {
123 $ret['attachedwiki'] = [];
124 ApiResult::setArrayType( $ret['attachedwiki'], 'assoc' );
125 }
126
127 $name = $user->getName();
128 $centralIdLookupFactory = MediaWikiServices::getInstance()
129 ->getCentralIdLookupFactory();
130 foreach ( $providerIds as $providerId ) {
131 $provider = $centralIdLookupFactory->getLookup( $providerId );
132 $ret['centralids'][$providerId] = $provider->centralIdFromName( $name );
133 $ret['attachedlocal'][$providerId] = $provider->isAttached( $user );
134 if ( $attachedWiki ) {
135 $ret['attachedwiki'][$providerId] = $provider->isAttached( $user, $attachedWiki );
136 }
137 }
138
139 return $ret;
140 }
141
142 protected function getCurrentUserInfo() {
143 $user = $this->getUser();
144 $vals = [];
145 $vals['id'] = $user->getId();
146 $vals['name'] = $user->getName();
147
148 if ( !$user->isRegistered() ) {
149 $vals['anon'] = true;
150 }
151
152 if ( isset( $this->prop['blockinfo'] ) ) {
153 $block = $user->getBlock();
154 if ( $block ) {
155 $vals = array_merge( $vals, $this->getBlockDetails( $block ) );
156 }
157 }
158
159 if ( isset( $this->prop['hasmsg'] ) ) {
160 $vals['messages'] = $this->talkPageNotificationManager->userHasNewMessages( $user );
161 }
162
163 if ( isset( $this->prop['groups'] ) ) {
164 $vals['groups'] = $this->userGroupManager->getUserEffectiveGroups( $user );
165 ApiResult::setArrayType( $vals['groups'], 'array' ); // even if empty
166 ApiResult::setIndexedTagName( $vals['groups'], 'g' ); // even if empty
167 }
168
169 if ( isset( $this->prop['groupmemberships'] ) ) {
170 $ugms = $this->userGroupManager->getUserGroupMemberships( $user );
171 $vals['groupmemberships'] = [];
172 foreach ( $ugms as $group => $ugm ) {
173 $vals['groupmemberships'][] = [
174 'group' => $group,
175 'expiry' => ApiResult::formatExpiry( $ugm->getExpiry() ),
176 ];
177 }
178 ApiResult::setArrayType( $vals['groupmemberships'], 'array' ); // even if empty
179 ApiResult::setIndexedTagName( $vals['groupmemberships'], 'groupmembership' ); // even if empty
180 }
181
182 if ( isset( $this->prop['implicitgroups'] ) ) {
183 $vals['implicitgroups'] = $this->userGroupManager->getUserImplicitGroups( $user );
184 ApiResult::setArrayType( $vals['implicitgroups'], 'array' ); // even if empty
185 ApiResult::setIndexedTagName( $vals['implicitgroups'], 'g' ); // even if empty
186 }
187
188 if ( isset( $this->prop['rights'] ) ) {
189 $vals['rights'] = $this->getPermissionManager()->getUserPermissions( $user );
190 ApiResult::setArrayType( $vals['rights'], 'array' ); // even if empty
191 ApiResult::setIndexedTagName( $vals['rights'], 'r' ); // even if empty
192 }
193
194 if ( isset( $this->prop['changeablegroups'] ) ) {
195 $vals['changeablegroups'] = $this->userGroupManager->getGroupsChangeableBy( $this->getAuthority() );
196 ApiResult::setIndexedTagName( $vals['changeablegroups']['add'], 'g' );
197 ApiResult::setIndexedTagName( $vals['changeablegroups']['remove'], 'g' );
198 ApiResult::setIndexedTagName( $vals['changeablegroups']['add-self'], 'g' );
199 ApiResult::setIndexedTagName( $vals['changeablegroups']['remove-self'], 'g' );
200 }
201
202 if ( isset( $this->prop['options'] ) ) {
203 $vals['options'] = $this->userOptionsLookup->getOptions( $user );
204 $vals['options'][ApiResult::META_BC_BOOLS] = array_keys( $vals['options'] );
205 }
206
207 if ( isset( $this->prop['editcount'] ) ) {
208 // use intval to prevent null if a non-logged-in user calls
209 // api.php?format=jsonfm&action=query&meta=userinfo&uiprop=editcount
210 $vals['editcount'] = (int)$user->getEditCount();
211 }
212
213 if ( isset( $this->prop['ratelimits'] ) ) {
214 // true = real rate limits, taking User::isPingLimitable into account
215 $vals['ratelimits'] = $this->getRateLimits( true );
216 }
217 if ( isset( $this->prop['theoreticalratelimits'] ) ) {
218 // false = ignore User::isPingLimitable
219 $vals['theoreticalratelimits'] = $this->getRateLimits( false );
220 }
221
222 if ( isset( $this->prop['realname'] ) &&
223 !in_array( 'realname', $this->getConfig()->get( MainConfigNames::HiddenPrefs ) )
224 ) {
225 $vals['realname'] = $user->getRealName();
226 }
227
228 if ( $this->getAuthority()->isAllowed( 'viewmyprivateinfo' ) && isset( $this->prop['email'] ) ) {
229 $vals['email'] = $user->getEmail();
230 $auth = $user->getEmailAuthenticationTimestamp();
231 if ( $auth !== null ) {
232 $vals['emailauthenticated'] = wfTimestamp( TS_ISO_8601, $auth );
233 }
234 }
235
236 if ( isset( $this->prop['registrationdate'] ) ) {
237 $regDate = $user->getRegistration();
238 if ( $regDate !== false ) {
239 $vals['registrationdate'] = wfTimestamp( TS_ISO_8601, $regDate );
240 }
241 }
242
243 if ( isset( $this->prop['acceptlang'] ) ) {
244 $langs = $this->getRequest()->getAcceptLang();
245 $acceptLang = [];
246 foreach ( $langs as $lang => $val ) {
247 $r = [ 'q' => $val ];
248 ApiResult::setContentValue( $r, 'code', $lang );
249 $acceptLang[] = $r;
250 }
251 ApiResult::setIndexedTagName( $acceptLang, 'lang' );
252 $vals['acceptlang'] = $acceptLang;
253 }
254
255 if ( isset( $this->prop['unreadcount'] ) ) {
256 $unreadNotifications = $this->watchedItemStore->countUnreadNotifications(
257 $user,
258 self::WL_UNREAD_LIMIT
259 );
260
261 if ( $unreadNotifications === true ) {
262 $vals['unreadcount'] = self::WL_UNREAD_LIMIT . '+';
263 } else {
264 $vals['unreadcount'] = $unreadNotifications;
265 }
266 }
267
268 if ( isset( $this->prop['centralids'] ) ) {
270 $this->getConfig(), $this->getUser(), $this->params['attachedwiki']
271 );
272 }
273
274 if ( isset( $this->prop['latestcontrib'] ) ) {
275 $ts = $this->getLatestContributionTime();
276 if ( $ts !== null ) {
277 $vals['latestcontrib'] = $ts;
278 }
279 }
280
281 if ( isset( $this->prop['cancreateaccount'] ) ) {
282 $status = PermissionStatus::newEmpty();
283 $vals['cancreateaccount'] = $user->definitelyCan( 'createaccount',
284 SpecialPage::getTitleFor( 'CreateAccount' ), $status );
285 if ( !$status->isGood() ) {
286 $vals['cancreateaccounterror'] = $this->getErrorFormatter()->arrayFromStatus( $status );
287 }
288 }
289
290 return $vals;
291 }
292
300 protected function getRateLimits( bool $applyNoRateLimit ) {
301 $retval = [
302 ApiResult::META_TYPE => 'assoc',
303 ];
304
305 $user = $this->getUser();
306 if ( $applyNoRateLimit && !$user->isPingLimitable() ) {
307 return $retval; // No limits
308 }
309
310 // Find out which categories we belong to
311 $categories = [];
312 if ( !$user->isRegistered() ) {
313 $categories[] = 'anon';
314 } else {
315 $categories[] = 'user';
316 }
317 if ( $user->isNewbie() ) {
318 $categories[] = 'ip';
319 $categories[] = 'subnet';
320 if ( $user->isRegistered() ) {
321 $categories[] = 'newbie';
322 }
323 }
324 $categories = array_merge( $categories, $this->userGroupManager->getUserGroups( $user ) );
325
326 // Now get the actual limits
327 foreach ( $this->getConfig()->get( MainConfigNames::RateLimits ) as $action => $limits ) {
328 foreach ( $categories as $cat ) {
329 if ( isset( $limits[$cat] ) ) {
330 $retval[$action][$cat]['hits'] = (int)$limits[$cat][0];
331 $retval[$action][$cat]['seconds'] = (int)$limits[$cat][1];
332 }
333 }
334 }
335
336 return $retval;
337 }
338
342 protected function getLatestContributionTime() {
343 $timestamp = $this->userEditTracker->getLatestEditTimestamp( $this->getUser() );
344 if ( $timestamp === false ) {
345 return null;
346 }
347 return MWTimestamp::convert( TS_ISO_8601, $timestamp );
348 }
349
350 public function getAllowedParams() {
351 return [
352 'prop' => [
353 ParamValidator::PARAM_ISMULTI => true,
354 ParamValidator::PARAM_ALL => true,
355 ParamValidator::PARAM_TYPE => [
356 'blockinfo',
357 'hasmsg',
358 'groups',
359 'groupmemberships',
360 'implicitgroups',
361 'rights',
362 'changeablegroups',
363 'options',
364 'editcount',
365 'ratelimits',
366 'theoreticalratelimits',
367 'email',
368 'realname',
369 'acceptlang',
370 'registrationdate',
371 'unreadcount',
372 'centralids',
373 'latestcontrib',
374 'cancreateaccount',
375 ],
377 'unreadcount' => [
378 'apihelp-query+userinfo-paramvalue-prop-unreadcount',
379 self::WL_UNREAD_LIMIT - 1,
380 self::WL_UNREAD_LIMIT . '+',
381 ],
382 ],
383 ],
384 'attachedwiki' => null,
385 ];
386 }
387
388 protected function getExamplesMessages() {
389 return [
390 'action=query&meta=userinfo'
391 => 'apihelp-query+userinfo-example-simple',
392 'action=query&meta=userinfo&uiprop=blockinfo|groups|rights|hasmsg'
393 => 'apihelp-query+userinfo-example-data',
394 ];
395 }
396
397 public function getHelpUrls() {
398 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Userinfo';
399 }
400}
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
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
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.
Query module to get information about the currently logged-in user.
getExamplesMessages()
Returns usage examples for this module.
static getCentralUserInfo(Config $config, UserIdentity $user, $attachedWiki=UserIdentity::LOCAL)
Get central user info.
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...
getRateLimits(bool $applyNoRateLimit)
Get the rate limits that apply to the user, or the rate limits that would apply if the user didn't ha...
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
__construct(ApiQuery $query, $moduleName, TalkPageNotificationManager $talkPageNotificationManager, WatchedItemStore $watchedItemStore, UserEditTracker $userEditTracker, UserOptionsLookup $userOptionsLookup, UserGroupManager $userGroupManager)
This is the main query class.
Definition ApiQuery.php:43
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
A StatusValue for permission errors.
Parent class for all special pages.
Track info about user edit counts and timings.
Provides access to user options.
Library for creating and parsing MW-style timestamps.
Storage layer class for WatchedItems.
Service for formatting and validating API parameters.
trait ApiBlockInfoTrait
Interface for configuration instances.
Definition Config.php:32
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
Interface for objects representing user identity.