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