MediaWiki  master
ApiQueryUserInfo.php
Go to the documentation of this file.
1 <?php
24 
31 
33 
34  const WL_UNREAD_LIMIT = 1000;
35 
37  private $params = [];
39  private $prop = [];
40 
41  public function __construct( ApiQuery $query, $moduleName ) {
42  parent::__construct( $query, $moduleName, 'ui' );
43  }
44 
45  public function execute() {
46  $this->params = $this->extractRequestParams();
47  $result = $this->getResult();
48 
49  if ( !is_null( $this->params['prop'] ) ) {
50  $this->prop = array_flip( $this->params['prop'] );
51  }
52 
53  $r = $this->getCurrentUserInfo();
54  $result->addValue( 'query', $this->getModuleName(), $r );
55  }
56 
69  public static function getCentralUserInfo( Config $config, User $user, $attachedWiki = null ) {
70  $providerIds = array_keys( $config->get( 'CentralIdLookupProviders' ) );
71 
72  $ret = [
73  'centralids' => [],
74  'attachedlocal' => [],
75  ];
76  ApiResult::setArrayType( $ret['centralids'], 'assoc' );
77  ApiResult::setArrayType( $ret['attachedlocal'], 'assoc' );
78  if ( $attachedWiki ) {
79  $ret['attachedwiki'] = [];
80  ApiResult::setArrayType( $ret['attachedwiki'], 'assoc' );
81  }
82 
83  $name = $user->getName();
84  foreach ( $providerIds as $providerId ) {
85  $provider = CentralIdLookup::factory( $providerId );
86  $ret['centralids'][$providerId] = $provider->centralIdFromName( $name );
87  $ret['attachedlocal'][$providerId] = $provider->isAttached( $user );
88  if ( $attachedWiki ) {
89  $ret['attachedwiki'][$providerId] = $provider->isAttached( $user, $attachedWiki );
90  }
91  }
92 
93  return $ret;
94  }
95 
96  protected function getCurrentUserInfo() {
97  $user = $this->getUser();
98  $vals = [];
99  $vals['id'] = (int)$user->getId();
100  $vals['name'] = $user->getName();
101 
102  if ( $user->isAnon() ) {
103  $vals['anon'] = true;
104  }
105 
106  if ( isset( $this->prop['blockinfo'] ) ) {
107  $block = $user->getBlock();
108  if ( $block ) {
109  $vals = array_merge( $vals, $this->getBlockDetails( $block ) );
110  }
111  }
112 
113  if ( isset( $this->prop['hasmsg'] ) ) {
114  $vals['messages'] = $user->getNewtalk();
115  }
116 
117  if ( isset( $this->prop['groups'] ) ) {
118  $vals['groups'] = $user->getEffectiveGroups();
119  ApiResult::setArrayType( $vals['groups'], 'array' ); // even if empty
120  ApiResult::setIndexedTagName( $vals['groups'], 'g' ); // even if empty
121  }
122 
123  if ( isset( $this->prop['groupmemberships'] ) ) {
124  $ugms = $user->getGroupMemberships();
125  $vals['groupmemberships'] = [];
126  foreach ( $ugms as $group => $ugm ) {
127  $vals['groupmemberships'][] = [
128  'group' => $group,
129  'expiry' => ApiResult::formatExpiry( $ugm->getExpiry() ),
130  ];
131  }
132  ApiResult::setArrayType( $vals['groupmemberships'], 'array' ); // even if empty
133  ApiResult::setIndexedTagName( $vals['groupmemberships'], 'groupmembership' ); // even if empty
134  }
135 
136  if ( isset( $this->prop['implicitgroups'] ) ) {
137  $vals['implicitgroups'] = $user->getAutomaticGroups();
138  ApiResult::setArrayType( $vals['implicitgroups'], 'array' ); // even if empty
139  ApiResult::setIndexedTagName( $vals['implicitgroups'], 'g' ); // even if empty
140  }
141 
142  if ( isset( $this->prop['rights'] ) ) {
143  $vals['rights'] = $this->getPermissionManager()->getUserPermissions( $user );
144  ApiResult::setArrayType( $vals['rights'], 'array' ); // even if empty
145  ApiResult::setIndexedTagName( $vals['rights'], 'r' ); // even if empty
146  }
147 
148  if ( isset( $this->prop['changeablegroups'] ) ) {
149  $vals['changeablegroups'] = $user->changeableGroups();
150  ApiResult::setIndexedTagName( $vals['changeablegroups']['add'], 'g' );
151  ApiResult::setIndexedTagName( $vals['changeablegroups']['remove'], 'g' );
152  ApiResult::setIndexedTagName( $vals['changeablegroups']['add-self'], 'g' );
153  ApiResult::setIndexedTagName( $vals['changeablegroups']['remove-self'], 'g' );
154  }
155 
156  if ( isset( $this->prop['options'] ) ) {
157  $vals['options'] = $user->getOptions();
158  $vals['options'][ApiResult::META_BC_BOOLS] = array_keys( $vals['options'] );
159  }
160 
161  if ( isset( $this->prop['preferencestoken'] ) &&
162  !$this->lacksSameOriginSecurity() &&
163  $this->getPermissionManager()->userHasRight( $user, 'editmyoptions' )
164  ) {
165  $vals['preferencestoken'] = $user->getEditToken( '', $this->getMain()->getRequest() );
166  }
167 
168  if ( isset( $this->prop['editcount'] ) ) {
169  // use intval to prevent null if a non-logged-in user calls
170  // api.php?format=jsonfm&action=query&meta=userinfo&uiprop=editcount
171  $vals['editcount'] = (int)$user->getEditCount();
172  }
173 
174  if ( isset( $this->prop['ratelimits'] ) ) {
175  $vals['ratelimits'] = $this->getRateLimits();
176  }
177 
178  if ( isset( $this->prop['realname'] ) &&
179  !in_array( 'realname', $this->getConfig()->get( 'HiddenPrefs' ) )
180  ) {
181  $vals['realname'] = $user->getRealName();
182  }
183 
184  if ( $this->getPermissionManager()->userHasRight( $user, 'viewmyprivateinfo' ) &&
185  isset( $this->prop['email'] ) ) {
186  $vals['email'] = $user->getEmail();
187  $auth = $user->getEmailAuthenticationTimestamp();
188  if ( $auth !== null ) {
189  $vals['emailauthenticated'] = wfTimestamp( TS_ISO_8601, $auth );
190  }
191  }
192 
193  if ( isset( $this->prop['registrationdate'] ) ) {
194  $regDate = $user->getRegistration();
195  if ( $regDate !== false ) {
196  $vals['registrationdate'] = wfTimestamp( TS_ISO_8601, $regDate );
197  }
198  }
199 
200  if ( isset( $this->prop['acceptlang'] ) ) {
201  $langs = $this->getRequest()->getAcceptLang();
202  $acceptLang = [];
203  foreach ( $langs as $lang => $val ) {
204  $r = [ 'q' => $val ];
205  ApiResult::setContentValue( $r, 'code', $lang );
206  $acceptLang[] = $r;
207  }
208  ApiResult::setIndexedTagName( $acceptLang, 'lang' );
209  $vals['acceptlang'] = $acceptLang;
210  }
211 
212  if ( isset( $this->prop['unreadcount'] ) ) {
213  $store = MediaWikiServices::getInstance()->getWatchedItemStore();
214  $unreadNotifications = $store->countUnreadNotifications(
215  $user,
216  self::WL_UNREAD_LIMIT
217  );
218 
219  if ( $unreadNotifications === true ) {
220  $vals['unreadcount'] = self::WL_UNREAD_LIMIT . '+';
221  } else {
222  $vals['unreadcount'] = $unreadNotifications;
223  }
224  }
225 
226  if ( isset( $this->prop['centralids'] ) ) {
227  $vals += self::getCentralUserInfo(
228  $this->getConfig(), $this->getUser(), $this->params['attachedwiki']
229  );
230  }
231 
232  if ( isset( $this->prop['latestcontrib'] ) ) {
233  $ts = $this->getLatestContributionTime();
234  if ( $ts !== null ) {
235  $vals['latestcontrib'] = $ts;
236  }
237  }
238 
239  return $vals;
240  }
241 
242  protected function getRateLimits() {
243  $retval = [
244  ApiResult::META_TYPE => 'assoc',
245  ];
246 
247  $user = $this->getUser();
248  if ( !$user->isPingLimitable() ) {
249  return $retval; // No limits
250  }
251 
252  // Find out which categories we belong to
253  $categories = [];
254  if ( $user->isAnon() ) {
255  $categories[] = 'anon';
256  } else {
257  $categories[] = 'user';
258  }
259  if ( $user->isNewbie() ) {
260  $categories[] = 'ip';
261  $categories[] = 'subnet';
262  if ( !$user->isAnon() ) {
263  $categories[] = 'newbie';
264  }
265  }
266  $categories = array_merge( $categories, $user->getGroups() );
267 
268  // Now get the actual limits
269  foreach ( $this->getConfig()->get( 'RateLimits' ) as $action => $limits ) {
270  foreach ( $categories as $cat ) {
271  if ( isset( $limits[$cat] ) && !is_null( $limits[$cat] ) ) {
272  $retval[$action][$cat]['hits'] = (int)$limits[$cat][0];
273  $retval[$action][$cat]['seconds'] = (int)$limits[$cat][1];
274  }
275  }
276  }
277 
278  return $retval;
279  }
280 
284  protected function getLatestContributionTime() {
285  $user = $this->getUser();
286  $dbr = $this->getDB();
287 
288  if ( $user->getActorId() === null ) {
289  return null;
290  }
291  $res = $dbr->selectField( 'revision_actor_temp',
292  'MAX(revactor_timestamp)',
293  [ 'revactor_actor' => $user->getActorId() ],
294  __METHOD__
295  );
296 
297  return $res ? wfTimestamp( TS_ISO_8601, $res ) : null;
298  }
299 
300  public function getAllowedParams() {
301  return [
302  'prop' => [
303  ApiBase::PARAM_ISMULTI => true,
305  'blockinfo',
306  'hasmsg',
307  'groups',
308  'groupmemberships',
309  'implicitgroups',
310  'rights',
311  'changeablegroups',
312  'options',
313  'editcount',
314  'ratelimits',
315  'email',
316  'realname',
317  'acceptlang',
318  'registrationdate',
319  'unreadcount',
320  'centralids',
321  'preferencestoken',
322  'latestcontrib',
323  ],
325  'unreadcount' => [
326  'apihelp-query+userinfo-paramvalue-prop-unreadcount',
327  self::WL_UNREAD_LIMIT - 1,
328  self::WL_UNREAD_LIMIT . '+',
329  ],
330  ],
332  'preferencestoken' => [
333  'apiwarn-deprecation-withreplacement',
334  $this->getModulePrefix() . "prop=preferencestoken",
335  'action=query&meta=tokens',
336  ]
337  ],
338  ],
339  'attachedwiki' => null,
340  ];
341  }
342 
343  protected function getExamplesMessages() {
344  return [
345  'action=query&meta=userinfo'
346  => 'apihelp-query+userinfo-example-simple',
347  'action=query&meta=userinfo&uiprop=blockinfo|groups|rights|hasmsg'
348  => 'apihelp-query+userinfo-example-data',
349  ];
350  }
351 
352  public function getHelpUrls() {
353  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Userinfo';
354  }
355 }
const PARAM_TYPE
(string|string[]) Either an array of allowed value strings, or a string type as described below...
Definition: ApiBase.php:94
getDB()
Get the Query database connection (read-only)
getResult()
Get the result object.
Definition: ApiBase.php:640
getMain()
Get the main module.
Definition: ApiBase.php:536
if(!isset( $args[0])) $lang
This is a base class for all Query modules.
lacksSameOriginSecurity()
Returns true if the current request breaks the same-origin policy.
Definition: ApiBase.php:568
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user...
Definition: ApiBase.php:761
const META_TYPE
Key for the &#39;type&#39; metadata item.
Definition: ApiResult.php:110
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:164
trait ApiBlockInfoTrait
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:478
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Definition: ApiResult.php:616
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
getName()
Get the user name, or the IP of an anonymous user.
Definition: User.php:2230
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:51
static formatExpiry( $expiry, $infinity='infinity')
Format an expiry timestamp for API output.
Definition: ApiResult.php:1205
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
__construct(ApiQuery $query, $moduleName)
Interface for configuration instances.
Definition: Config.php:28
Query module to get information about the currently logged-in user.
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:520
This is the main query class.
Definition: ApiQuery.php:37
static getCentralUserInfo(Config $config, User $user, $attachedWiki=null)
Get central user info.
static factory( $providerId=null)
Fetch a CentralIdLookup.
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition: ApiBase.php:528
const PARAM_DEPRECATED_VALUES
(array) When PARAM_TYPE is an array, this indicates which of the values are deprecated.
Definition: ApiBase.php:209
const PARAM_ISMULTI
(boolean) Accept multiple pipe-separated values for this parameter (e.g.
Definition: ApiBase.php:58
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks...
Definition: ApiBase.php:710
const META_BC_BOOLS
Key for the &#39;BC bools&#39; metadata item.
Definition: ApiResult.php:136
static setArrayType(array &$arr, $type, $kvpKeyName=null)
Set the array data type.
Definition: ApiResult.php:728