MediaWiki  master
ApiQueryUserInfo.php
Go to the documentation of this file.
1 <?php
30 
37 
39 
40  private const WL_UNREAD_LIMIT = 1000;
41 
43  private $params = [];
44 
46  private $prop = [];
47 
52 
57 
62 
67 
70 
80  public function __construct(
81  ApiQuery $query,
82  $moduleName,
88  ) {
89  parent::__construct( $query, $moduleName, 'ui' );
90  $this->talkPageNotificationManager = $talkPageNotificationManager;
91  $this->watchedItemStore = $watchedItemStore;
92  $this->userEditTracker = $userEditTracker;
93  $this->userOptionsLookup = $userOptionsLookup;
94  $this->userGroupManager = $userGroupManager;
95  }
96 
97  public function execute() {
98  $this->params = $this->extractRequestParams();
99  $result = $this->getResult();
100 
101  if ( $this->params['prop'] !== null ) {
102  $this->prop = array_fill_keys( $this->params['prop'], true );
103  }
104 
105  $r = $this->getCurrentUserInfo();
106  $result->addValue( 'query', $this->getModuleName(), $r );
107  }
108 
121  public static function getCentralUserInfo(
122  Config $config,
123  UserIdentity $user,
124  $attachedWiki = UserIdentity::LOCAL
125  ) {
126  $providerIds = array_keys( $config->get( MainConfigNames::CentralIdLookupProviders ) );
127 
128  $ret = [
129  'centralids' => [],
130  'attachedlocal' => [],
131  ];
132  ApiResult::setArrayType( $ret['centralids'], 'assoc' );
133  ApiResult::setArrayType( $ret['attachedlocal'], 'assoc' );
134  if ( $attachedWiki ) {
135  $ret['attachedwiki'] = [];
136  ApiResult::setArrayType( $ret['attachedwiki'], 'assoc' );
137  }
138 
139  $name = $user->getName();
140  $centralIdLookupFactory = MediaWikiServices::getInstance()
141  ->getCentralIdLookupFactory();
142  foreach ( $providerIds as $providerId ) {
143  $provider = $centralIdLookupFactory->getLookup( $providerId );
144  $ret['centralids'][$providerId] = $provider->centralIdFromName( $name );
145  $ret['attachedlocal'][$providerId] = $provider->isAttached( $user );
146  if ( $attachedWiki ) {
147  $ret['attachedwiki'][$providerId] = $provider->isAttached( $user, $attachedWiki );
148  }
149  }
150 
151  return $ret;
152  }
153 
154  protected function getCurrentUserInfo() {
155  $user = $this->getUser();
156  $vals = [];
157  $vals['id'] = $user->getId();
158  $vals['name'] = $user->getName();
159 
160  if ( !$user->isRegistered() ) {
161  $vals['anon'] = true;
162  }
163 
164  if ( isset( $this->prop['blockinfo'] ) ) {
165  $block = $user->getBlock();
166  if ( $block ) {
167  $vals = array_merge( $vals, $this->getBlockDetails( $block ) );
168  }
169  }
170 
171  if ( isset( $this->prop['hasmsg'] ) ) {
172  $vals['messages'] = $this->talkPageNotificationManager->userHasNewMessages( $user );
173  }
174 
175  if ( isset( $this->prop['groups'] ) ) {
176  $vals['groups'] = $this->userGroupManager->getUserEffectiveGroups( $user );
177  ApiResult::setArrayType( $vals['groups'], 'array' ); // even if empty
178  ApiResult::setIndexedTagName( $vals['groups'], 'g' ); // even if empty
179  }
180 
181  if ( isset( $this->prop['groupmemberships'] ) ) {
182  $ugms = $this->userGroupManager->getUserGroupMemberships( $user );
183  $vals['groupmemberships'] = [];
184  foreach ( $ugms as $group => $ugm ) {
185  $vals['groupmemberships'][] = [
186  'group' => $group,
187  'expiry' => ApiResult::formatExpiry( $ugm->getExpiry() ),
188  ];
189  }
190  ApiResult::setArrayType( $vals['groupmemberships'], 'array' ); // even if empty
191  ApiResult::setIndexedTagName( $vals['groupmemberships'], 'groupmembership' ); // even if empty
192  }
193 
194  if ( isset( $this->prop['implicitgroups'] ) ) {
195  $vals['implicitgroups'] = $this->userGroupManager->getUserImplicitGroups( $user );
196  ApiResult::setArrayType( $vals['implicitgroups'], 'array' ); // even if empty
197  ApiResult::setIndexedTagName( $vals['implicitgroups'], 'g' ); // even if empty
198  }
199 
200  if ( isset( $this->prop['rights'] ) ) {
201  $vals['rights'] = $this->getPermissionManager()->getUserPermissions( $user );
202  ApiResult::setArrayType( $vals['rights'], 'array' ); // even if empty
203  ApiResult::setIndexedTagName( $vals['rights'], 'r' ); // even if empty
204  }
205 
206  if ( isset( $this->prop['changeablegroups'] ) ) {
207  $vals['changeablegroups'] = $this->userGroupManager->getGroupsChangeableBy( $this->getAuthority() );
208  ApiResult::setIndexedTagName( $vals['changeablegroups']['add'], 'g' );
209  ApiResult::setIndexedTagName( $vals['changeablegroups']['remove'], 'g' );
210  ApiResult::setIndexedTagName( $vals['changeablegroups']['add-self'], 'g' );
211  ApiResult::setIndexedTagName( $vals['changeablegroups']['remove-self'], 'g' );
212  }
213 
214  if ( isset( $this->prop['options'] ) ) {
215  $vals['options'] = $this->userOptionsLookup->getOptions( $user );
216  $vals['options'][ApiResult::META_BC_BOOLS] = array_keys( $vals['options'] );
217  }
218 
219  if ( isset( $this->prop['editcount'] ) ) {
220  // use intval to prevent null if a non-logged-in user calls
221  // api.php?format=jsonfm&action=query&meta=userinfo&uiprop=editcount
222  $vals['editcount'] = (int)$user->getEditCount();
223  }
224 
225  if ( isset( $this->prop['ratelimits'] ) ) {
226  // true = real rate limits, taking User::isPingLimitable into account
227  $vals['ratelimits'] = $this->getRateLimits( true );
228  }
229  if ( isset( $this->prop['theoreticalratelimits'] ) ) {
230  // false = ignore User::isPingLimitable
231  $vals['theoreticalratelimits'] = $this->getRateLimits( false );
232  }
233 
234  if ( isset( $this->prop['realname'] ) &&
235  !in_array( 'realname', $this->getConfig()->get( MainConfigNames::HiddenPrefs ) )
236  ) {
237  $vals['realname'] = $user->getRealName();
238  }
239 
240  if ( $this->getAuthority()->isAllowed( 'viewmyprivateinfo' ) && isset( $this->prop['email'] ) ) {
241  $vals['email'] = $user->getEmail();
242  $auth = $user->getEmailAuthenticationTimestamp();
243  if ( $auth !== null ) {
244  $vals['emailauthenticated'] = wfTimestamp( TS_ISO_8601, $auth );
245  }
246  }
247 
248  if ( isset( $this->prop['registrationdate'] ) ) {
249  $regDate = $user->getRegistration();
250  if ( $regDate !== false ) {
251  $vals['registrationdate'] = wfTimestamp( TS_ISO_8601, $regDate );
252  }
253  }
254 
255  if ( isset( $this->prop['acceptlang'] ) ) {
256  $langs = $this->getRequest()->getAcceptLang();
257  $acceptLang = [];
258  foreach ( $langs as $lang => $val ) {
259  $r = [ 'q' => $val ];
260  ApiResult::setContentValue( $r, 'code', $lang );
261  $acceptLang[] = $r;
262  }
263  ApiResult::setIndexedTagName( $acceptLang, 'lang' );
264  $vals['acceptlang'] = $acceptLang;
265  }
266 
267  if ( isset( $this->prop['unreadcount'] ) ) {
268  $unreadNotifications = $this->watchedItemStore->countUnreadNotifications(
269  $user,
270  self::WL_UNREAD_LIMIT
271  );
272 
273  if ( $unreadNotifications === true ) {
274  $vals['unreadcount'] = self::WL_UNREAD_LIMIT . '+';
275  } else {
276  $vals['unreadcount'] = $unreadNotifications;
277  }
278  }
279 
280  if ( isset( $this->prop['centralids'] ) ) {
281  $vals += self::getCentralUserInfo(
282  $this->getConfig(), $this->getUser(), $this->params['attachedwiki']
283  );
284  }
285 
286  if ( isset( $this->prop['latestcontrib'] ) ) {
287  $ts = $this->getLatestContributionTime();
288  if ( $ts !== null ) {
289  $vals['latestcontrib'] = $ts;
290  }
291  }
292 
293  return $vals;
294  }
295 
303  protected function getRateLimits( bool $applyNoRateLimit ) {
304  $retval = [
305  ApiResult::META_TYPE => 'assoc',
306  ];
307 
308  $user = $this->getUser();
309  if ( $applyNoRateLimit && !$user->isPingLimitable() ) {
310  return $retval; // No limits
311  }
312 
313  // Find out which categories we belong to
314  $categories = [];
315  if ( !$user->isRegistered() ) {
316  $categories[] = 'anon';
317  } else {
318  $categories[] = 'user';
319  }
320  if ( $user->isNewbie() ) {
321  $categories[] = 'ip';
322  $categories[] = 'subnet';
323  if ( $user->isRegistered() ) {
324  $categories[] = 'newbie';
325  }
326  }
327  $categories = array_merge( $categories, $this->userGroupManager->getUserGroups( $user ) );
328 
329  // Now get the actual limits
330  foreach ( $this->getConfig()->get( MainConfigNames::RateLimits ) as $action => $limits ) {
331  foreach ( $categories as $cat ) {
332  if ( isset( $limits[$cat] ) ) {
333  $retval[$action][$cat]['hits'] = (int)$limits[$cat][0];
334  $retval[$action][$cat]['seconds'] = (int)$limits[$cat][1];
335  }
336  }
337  }
338 
339  return $retval;
340  }
341 
345  protected function getLatestContributionTime() {
346  $timestamp = $this->userEditTracker->getLatestEditTimestamp( $this->getUser() );
347  if ( $timestamp === false ) {
348  return null;
349  }
350  return MWTimestamp::convert( TS_ISO_8601, $timestamp );
351  }
352 
353  public function getAllowedParams() {
354  return [
355  'prop' => [
356  ApiBase::PARAM_ISMULTI => true,
357  ApiBase::PARAM_ALL => true,
359  'blockinfo',
360  'hasmsg',
361  'groups',
362  'groupmemberships',
363  'implicitgroups',
364  'rights',
365  'changeablegroups',
366  'options',
367  'editcount',
368  'ratelimits',
369  'theoreticalratelimits',
370  'email',
371  'realname',
372  'acceptlang',
373  'registrationdate',
374  'unreadcount',
375  'centralids',
376  'latestcontrib',
377  ],
379  'unreadcount' => [
380  'apihelp-query+userinfo-paramvalue-prop-unreadcount',
381  self::WL_UNREAD_LIMIT - 1,
382  self::WL_UNREAD_LIMIT . '+',
383  ],
384  ],
385  ],
386  'attachedwiki' => null,
387  ];
388  }
389 
390  protected function getExamplesMessages() {
391  return [
392  'action=query&meta=userinfo'
393  => 'apihelp-query+userinfo-example-simple',
394  'action=query&meta=userinfo&uiprop=blockinfo|groups|rights|hasmsg'
395  => 'apihelp-query+userinfo-example-data',
396  ];
397  }
398 
399  public function getHelpUrls() {
400  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Userinfo';
401  }
402 }
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
const PARAM_TYPE
Definition: ApiBase.php:82
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks.
Definition: ApiBase.php:686
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:196
getResult()
Get the result object.
Definition: ApiBase.php:629
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:765
const PARAM_ALL
Definition: ApiBase.php:118
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:498
const PARAM_ISMULTI
Definition: ApiBase.php:78
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.
UserGroupManager $userGroupManager
static getCentralUserInfo(Config $config, UserIdentity $user, $attachedWiki=UserIdentity::LOCAL)
Get central user info.
getHelpUrls()
Return links to more detailed help pages about the module.
UserOptionsLookup $userOptionsLookup
UserEditTracker $userEditTracker
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.
TalkPageNotificationManager $talkPageNotificationManager
__construct(ApiQuery $query, $moduleName, TalkPageNotificationManager $talkPageNotificationManager, WatchedItemStore $watchedItemStore, UserEditTracker $userEditTracker, UserOptionsLookup $userOptionsLookup, UserGroupManager $userGroupManager)
WatchedItemStore $watchedItemStore
This is the main query class.
Definition: ApiQuery.php:40
const META_TYPE
Key for the 'type' metadata item.
Definition: ApiResult.php:110
static setArrayType(array &$arr, $type, $kvpKeyName=null)
Set the array data type.
Definition: ApiResult.php:716
const META_BC_BOOLS
Key for the 'BC bools' metadata item.
Definition: ApiResult.php:136
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Definition: ApiResult.php:604
static setContentValue(array &$arr, $name, $value, $flags=0)
Add an output value to the array by name and mark as META_CONTENT.
Definition: ApiResult.php:467
static formatExpiry( $expiry, $infinity='infinity')
Format an expiry timestamp for API output.
Definition: ApiResult.php:1199
A class containing constants representing the names of configuration variables.
MediaWikiServices is the service locator for the application scope of MediaWiki.
Track info about user edit counts and timings.
Provides access to user options.
Storage layer class for WatchedItems.
trait ApiBlockInfoTrait
Interface for configuration instances.
Definition: Config.php:30
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
Interface for objects representing user identity.
if(!isset( $args[0])) $lang