MediaWiki master
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 ( $user->isTemp() ) {
153 $vals['temp'] = true;
154 }
155
156 if ( isset( $this->prop['blockinfo'] ) ) {
157 $block = $user->getBlock();
158 if ( $block ) {
159 $vals = array_merge( $vals, $this->getBlockDetails( $block ) );
160 }
161 }
162
163 if ( isset( $this->prop['hasmsg'] ) ) {
164 $vals['messages'] = $this->talkPageNotificationManager->userHasNewMessages( $user );
165 }
166
167 if ( isset( $this->prop['groups'] ) ) {
168 $vals['groups'] = $this->userGroupManager->getUserEffectiveGroups( $user );
169 ApiResult::setArrayType( $vals['groups'], 'array' ); // even if empty
170 ApiResult::setIndexedTagName( $vals['groups'], 'g' ); // even if empty
171 }
172
173 if ( isset( $this->prop['groupmemberships'] ) ) {
174 $ugms = $this->userGroupManager->getUserGroupMemberships( $user );
175 $vals['groupmemberships'] = [];
176 foreach ( $ugms as $group => $ugm ) {
177 $vals['groupmemberships'][] = [
178 'group' => $group,
179 'expiry' => ApiResult::formatExpiry( $ugm->getExpiry() ),
180 ];
181 }
182 ApiResult::setArrayType( $vals['groupmemberships'], 'array' ); // even if empty
183 ApiResult::setIndexedTagName( $vals['groupmemberships'], 'groupmembership' ); // even if empty
184 }
185
186 if ( isset( $this->prop['implicitgroups'] ) ) {
187 $vals['implicitgroups'] = $this->userGroupManager->getUserImplicitGroups( $user );
188 ApiResult::setArrayType( $vals['implicitgroups'], 'array' ); // even if empty
189 ApiResult::setIndexedTagName( $vals['implicitgroups'], 'g' ); // even if empty
190 }
191
192 if ( isset( $this->prop['rights'] ) ) {
193 $vals['rights'] = $this->getPermissionManager()->getUserPermissions( $user );
194 ApiResult::setArrayType( $vals['rights'], 'array' ); // even if empty
195 ApiResult::setIndexedTagName( $vals['rights'], 'r' ); // even if empty
196 }
197
198 if ( isset( $this->prop['changeablegroups'] ) ) {
199 $vals['changeablegroups'] = $this->userGroupManager->getGroupsChangeableBy( $this->getAuthority() );
200 ApiResult::setIndexedTagName( $vals['changeablegroups']['add'], 'g' );
201 ApiResult::setIndexedTagName( $vals['changeablegroups']['remove'], 'g' );
202 ApiResult::setIndexedTagName( $vals['changeablegroups']['add-self'], 'g' );
203 ApiResult::setIndexedTagName( $vals['changeablegroups']['remove-self'], 'g' );
204 }
205
206 if ( isset( $this->prop['options'] ) ) {
207 $vals['options'] = $this->userOptionsLookup->getOptions( $user );
208 $vals['options'][ApiResult::META_BC_BOOLS] = array_keys( $vals['options'] );
209 }
210
211 if ( isset( $this->prop['editcount'] ) ) {
212 // use intval to prevent null if a non-logged-in user calls
213 // api.php?format=jsonfm&action=query&meta=userinfo&uiprop=editcount
214 $vals['editcount'] = (int)$user->getEditCount();
215 }
216
217 if ( isset( $this->prop['ratelimits'] ) ) {
218 // true = real rate limits, taking User::isPingLimitable into account
219 $vals['ratelimits'] = $this->getRateLimits( true );
220 }
221 if ( isset( $this->prop['theoreticalratelimits'] ) ) {
222 // false = ignore User::isPingLimitable
223 $vals['theoreticalratelimits'] = $this->getRateLimits( false );
224 }
225
226 if ( isset( $this->prop['realname'] ) &&
227 !in_array( 'realname', $this->getConfig()->get( MainConfigNames::HiddenPrefs ) )
228 ) {
229 $vals['realname'] = $user->getRealName();
230 }
231
232 if ( $this->getAuthority()->isAllowed( 'viewmyprivateinfo' ) && isset( $this->prop['email'] ) ) {
233 $vals['email'] = $user->getEmail();
234 $auth = $user->getEmailAuthenticationTimestamp();
235 if ( $auth !== null ) {
236 $vals['emailauthenticated'] = wfTimestamp( TS_ISO_8601, $auth );
237 }
238 }
239
240 if ( isset( $this->prop['registrationdate'] ) ) {
241 $regDate = $user->getRegistration();
242 if ( $regDate !== false ) {
243 $vals['registrationdate'] = wfTimestamp( TS_ISO_8601, $regDate );
244 }
245 }
246
247 if ( isset( $this->prop['acceptlang'] ) ) {
248 $langs = $this->getRequest()->getAcceptLang();
249 $acceptLang = [];
250 foreach ( $langs as $lang => $val ) {
251 $r = [ 'q' => $val ];
252 ApiResult::setContentValue( $r, 'code', $lang );
253 $acceptLang[] = $r;
254 }
255 ApiResult::setIndexedTagName( $acceptLang, 'lang' );
256 $vals['acceptlang'] = $acceptLang;
257 }
258
259 if ( isset( $this->prop['unreadcount'] ) ) {
260 $unreadNotifications = $this->watchedItemStore->countUnreadNotifications(
261 $user,
262 self::WL_UNREAD_LIMIT
263 );
264
265 if ( $unreadNotifications === true ) {
266 $vals['unreadcount'] = self::WL_UNREAD_LIMIT . '+';
267 } else {
268 $vals['unreadcount'] = $unreadNotifications;
269 }
270 }
271
272 if ( isset( $this->prop['centralids'] ) ) {
274 $this->getConfig(), $this->getUser(), $this->params['attachedwiki']
275 );
276 }
277
278 if ( isset( $this->prop['latestcontrib'] ) ) {
279 $ts = $this->getLatestContributionTime();
280 if ( $ts !== null ) {
281 $vals['latestcontrib'] = $ts;
282 }
283 }
284
285 if ( isset( $this->prop['cancreateaccount'] ) ) {
286 $status = PermissionStatus::newEmpty();
287 $vals['cancreateaccount'] = $user->definitelyCan( 'createaccount',
288 SpecialPage::getTitleFor( 'CreateAccount' ), $status );
289 if ( !$status->isGood() ) {
290 $vals['cancreateaccounterror'] = $this->getErrorFormatter()->arrayFromStatus( $status );
291 }
292 }
293
294 return $vals;
295 }
296
304 protected function getRateLimits( bool $applyNoRateLimit ) {
305 $retval = [
306 ApiResult::META_TYPE => 'assoc',
307 ];
308
309 $user = $this->getUser();
310 if ( $applyNoRateLimit && !$user->isPingLimitable() ) {
311 return $retval; // No limits
312 }
313
314 // Find out which categories we belong to
315 $categories = [];
316 if ( !$user->isRegistered() ) {
317 $categories[] = 'anon';
318 } else {
319 $categories[] = 'user';
320 }
321 if ( $user->isNewbie() ) {
322 $categories[] = 'ip';
323 $categories[] = 'subnet';
324 if ( $user->isRegistered() ) {
325 $categories[] = 'newbie';
326 }
327 }
328 $categories = array_merge( $categories, $this->userGroupManager->getUserGroups( $user ) );
329
330 // Now get the actual limits
331 foreach ( $this->getConfig()->get( MainConfigNames::RateLimits ) as $action => $limits ) {
332 foreach ( $categories as $cat ) {
333 if ( isset( $limits[$cat] ) ) {
334 $retval[$action][$cat]['hits'] = (int)$limits[$cat][0];
335 $retval[$action][$cat]['seconds'] = (int)$limits[$cat][1];
336 }
337 }
338 }
339
340 return $retval;
341 }
342
346 protected function getLatestContributionTime() {
347 $timestamp = $this->userEditTracker->getLatestEditTimestamp( $this->getUser() );
348 if ( $timestamp === false ) {
349 return null;
350 }
351 return MWTimestamp::convert( TS_ISO_8601, $timestamp );
352 }
353
354 public function getAllowedParams() {
355 return [
356 'prop' => [
357 ParamValidator::PARAM_ISMULTI => true,
358 ParamValidator::PARAM_ALL => true,
359 ParamValidator::PARAM_TYPE => [
360 'blockinfo',
361 'hasmsg',
362 'groups',
363 'groupmemberships',
364 'implicitgroups',
365 'rights',
366 'changeablegroups',
367 'options',
368 'editcount',
369 'ratelimits',
370 'theoreticalratelimits',
371 'email',
372 'realname',
373 'acceptlang',
374 'registrationdate',
375 'unreadcount',
376 'centralids',
377 'latestcontrib',
378 'cancreateaccount',
379 ],
381 'unreadcount' => [
382 'apihelp-query+userinfo-paramvalue-prop-unreadcount',
383 self::WL_UNREAD_LIMIT - 1,
384 self::WL_UNREAD_LIMIT . '+',
385 ],
386 ],
387 ],
388 'attachedwiki' => null,
389 ];
390 }
391
392 protected function getExamplesMessages() {
393 return [
394 'action=query&meta=userinfo'
395 => 'apihelp-query+userinfo-example-simple',
396 'action=query&meta=userinfo&uiprop=blockinfo|groups|rights|hasmsg'
397 => 'apihelp-query+userinfo-example-data',
398 ];
399 }
400
401 public function getHelpUrls() {
402 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Userinfo';
403 }
404}
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
getErrorFormatter()
Definition ApiBase.php:682
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks.
Definition ApiBase.php:731
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:671
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:811
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:532
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.