1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* |
4
|
|
|
* |
5
|
|
|
* Created on July 30, 2007 |
6
|
|
|
* |
7
|
|
|
* Copyright © 2007 Yuri Astrakhan "<Firstname><Lastname>@gmail.com" |
8
|
|
|
* |
9
|
|
|
* This program is free software; you can redistribute it and/or modify |
10
|
|
|
* it under the terms of the GNU General Public License as published by |
11
|
|
|
* the Free Software Foundation; either version 2 of the License, or |
12
|
|
|
* (at your option) any later version. |
13
|
|
|
* |
14
|
|
|
* This program is distributed in the hope that it will be useful, |
15
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
16
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17
|
|
|
* GNU General Public License for more details. |
18
|
|
|
* |
19
|
|
|
* You should have received a copy of the GNU General Public License along |
20
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc., |
21
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
22
|
|
|
* http://www.gnu.org/copyleft/gpl.html |
23
|
|
|
* |
24
|
|
|
* @file |
25
|
|
|
*/ |
26
|
|
|
|
27
|
|
|
use MediaWiki\MediaWikiServices; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Query module to get information about the currently logged-in user |
31
|
|
|
* |
32
|
|
|
* @ingroup API |
33
|
|
|
*/ |
34
|
|
|
class ApiQueryUserInfo extends ApiQueryBase { |
35
|
|
|
|
36
|
|
|
const WL_UNREAD_LIMIT = 1000; |
37
|
|
|
|
38
|
|
|
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
|
|
View Code Duplication |
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
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Get basic info about a given block |
59
|
|
|
* @param Block $block |
60
|
|
|
* @return array Array containing several keys: |
61
|
|
|
* - blockid - ID of the block |
62
|
|
|
* - blockedby - username of the blocker |
63
|
|
|
* - blockedbyid - user ID of the blocker |
64
|
|
|
* - blockreason - reason provided for the block |
65
|
|
|
* - blockedtimestamp - timestamp for when the block was placed/modified |
66
|
|
|
* - blockexpiry - expiry time of the block |
67
|
|
|
*/ |
68
|
|
|
public static function getBlockInfo( Block $block ) { |
69
|
|
|
global $wgContLang; |
70
|
|
|
$vals = []; |
71
|
|
|
$vals['blockid'] = $block->getId(); |
72
|
|
|
$vals['blockedby'] = $block->getByName(); |
73
|
|
|
$vals['blockedbyid'] = $block->getBy(); |
74
|
|
|
$vals['blockreason'] = $block->mReason; |
75
|
|
|
$vals['blockedtimestamp'] = wfTimestamp( TS_ISO_8601, $block->mTimestamp ); |
76
|
|
|
$vals['blockexpiry'] = $wgContLang->formatExpiry( |
77
|
|
|
$block->getExpiry(), TS_ISO_8601, 'infinite' |
78
|
|
|
); |
79
|
|
|
return $vals; |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* Get central user info |
84
|
|
|
* @param Config $config |
85
|
|
|
* @param User $user |
86
|
|
|
* @param string|null $attachedWiki |
87
|
|
|
* @return array Central user info |
88
|
|
|
* - centralids: Array mapping non-local Central ID provider names to IDs |
89
|
|
|
* - attachedlocal: Array mapping Central ID provider names to booleans |
90
|
|
|
* indicating whether the local user is attached. |
91
|
|
|
* - attachedwiki: Array mapping Central ID provider names to booleans |
92
|
|
|
* indicating whether the user is attached to $attachedWiki. |
93
|
|
|
*/ |
94
|
|
|
public static function getCentralUserInfo( Config $config, User $user, $attachedWiki = null ) { |
95
|
|
|
$providerIds = array_keys( $config->get( 'CentralIdLookupProviders' ) ); |
96
|
|
|
|
97
|
|
|
$ret = [ |
98
|
|
|
'centralids' => [], |
99
|
|
|
'attachedlocal' => [], |
100
|
|
|
]; |
101
|
|
|
ApiResult::setArrayType( $ret['centralids'], 'assoc' ); |
102
|
|
|
ApiResult::setArrayType( $ret['attachedlocal'], 'assoc' ); |
103
|
|
|
if ( $attachedWiki ) { |
|
|
|
|
104
|
|
|
$ret['attachedwiki'] = []; |
105
|
|
|
ApiResult::setArrayType( $ret['attachedwiki'], 'assoc' ); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
$name = $user->getName(); |
109
|
|
|
foreach ( $providerIds as $providerId ) { |
110
|
|
|
$provider = CentralIdLookup::factory( $providerId ); |
111
|
|
|
$ret['centralids'][$providerId] = $provider->centralIdFromName( $name ); |
112
|
|
|
$ret['attachedlocal'][$providerId] = $provider->isAttached( $user ); |
113
|
|
|
if ( $attachedWiki ) { |
|
|
|
|
114
|
|
|
$ret['attachedwiki'][$providerId] = $provider->isAttached( $user, $attachedWiki ); |
115
|
|
|
} |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
return $ret; |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
protected function getCurrentUserInfo() { |
122
|
|
|
$user = $this->getUser(); |
123
|
|
|
$vals = []; |
124
|
|
|
$vals['id'] = intval( $user->getId() ); |
125
|
|
|
$vals['name'] = $user->getName(); |
126
|
|
|
|
127
|
|
|
if ( $user->isAnon() ) { |
128
|
|
|
$vals['anon'] = true; |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
if ( isset( $this->prop['blockinfo'] ) && $user->isBlocked() ) { |
132
|
|
|
$vals = array_merge( $vals, self::getBlockInfo( $user->getBlock() ) ); |
|
|
|
|
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
if ( isset( $this->prop['hasmsg'] ) ) { |
136
|
|
|
$vals['messages'] = $user->getNewtalk(); |
137
|
|
|
} |
138
|
|
|
|
139
|
|
View Code Duplication |
if ( isset( $this->prop['groups'] ) ) { |
140
|
|
|
$vals['groups'] = $user->getEffectiveGroups(); |
141
|
|
|
ApiResult::setArrayType( $vals['groups'], 'array' ); // even if empty |
142
|
|
|
ApiResult::setIndexedTagName( $vals['groups'], 'g' ); // even if empty |
143
|
|
|
} |
144
|
|
|
|
145
|
|
View Code Duplication |
if ( isset( $this->prop['implicitgroups'] ) ) { |
146
|
|
|
$vals['implicitgroups'] = $user->getAutomaticGroups(); |
147
|
|
|
ApiResult::setArrayType( $vals['implicitgroups'], 'array' ); // even if empty |
148
|
|
|
ApiResult::setIndexedTagName( $vals['implicitgroups'], 'g' ); // even if empty |
149
|
|
|
} |
150
|
|
|
|
151
|
|
View Code Duplication |
if ( isset( $this->prop['rights'] ) ) { |
152
|
|
|
// User::getRights() may return duplicate values, strip them |
153
|
|
|
$vals['rights'] = array_values( array_unique( $user->getRights() ) ); |
154
|
|
|
ApiResult::setArrayType( $vals['rights'], 'array' ); // even if empty |
155
|
|
|
ApiResult::setIndexedTagName( $vals['rights'], 'r' ); // even if empty |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
if ( isset( $this->prop['changeablegroups'] ) ) { |
159
|
|
|
$vals['changeablegroups'] = $user->changeableGroups(); |
160
|
|
|
ApiResult::setIndexedTagName( $vals['changeablegroups']['add'], 'g' ); |
161
|
|
|
ApiResult::setIndexedTagName( $vals['changeablegroups']['remove'], 'g' ); |
162
|
|
|
ApiResult::setIndexedTagName( $vals['changeablegroups']['add-self'], 'g' ); |
163
|
|
|
ApiResult::setIndexedTagName( $vals['changeablegroups']['remove-self'], 'g' ); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
if ( isset( $this->prop['options'] ) ) { |
167
|
|
|
$vals['options'] = $user->getOptions(); |
168
|
|
|
$vals['options'][ApiResult::META_BC_BOOLS] = array_keys( $vals['options'] ); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
if ( isset( $this->prop['preferencestoken'] ) ) { |
172
|
|
|
$p = $this->getModulePrefix(); |
173
|
|
|
$this->setWarning( |
174
|
|
|
"{$p}prop=preferencestoken has been deprecated. Please use action=query&meta=tokens instead." |
175
|
|
|
); |
176
|
|
|
} |
177
|
|
|
if ( isset( $this->prop['preferencestoken'] ) && |
178
|
|
|
!$this->lacksSameOriginSecurity() && |
179
|
|
|
$user->isAllowed( 'editmyoptions' ) |
180
|
|
|
) { |
181
|
|
|
$vals['preferencestoken'] = $user->getEditToken( '', $this->getMain()->getRequest() ); |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
if ( isset( $this->prop['editcount'] ) ) { |
185
|
|
|
// use intval to prevent null if a non-logged-in user calls |
186
|
|
|
// api.php?format=jsonfm&action=query&meta=userinfo&uiprop=editcount |
187
|
|
|
$vals['editcount'] = intval( $user->getEditCount() ); |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
if ( isset( $this->prop['ratelimits'] ) ) { |
191
|
|
|
$vals['ratelimits'] = $this->getRateLimits(); |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
if ( isset( $this->prop['realname'] ) && |
195
|
|
|
!in_array( 'realname', $this->getConfig()->get( 'HiddenPrefs' ) ) |
196
|
|
|
) { |
197
|
|
|
$vals['realname'] = $user->getRealName(); |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
if ( $user->isAllowed( 'viewmyprivateinfo' ) ) { |
201
|
|
|
if ( isset( $this->prop['email'] ) ) { |
202
|
|
|
$vals['email'] = $user->getEmail(); |
203
|
|
|
$auth = $user->getEmailAuthenticationTimestamp(); |
204
|
|
|
if ( !is_null( $auth ) ) { |
205
|
|
|
$vals['emailauthenticated'] = wfTimestamp( TS_ISO_8601, $auth ); |
206
|
|
|
} |
207
|
|
|
} |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
if ( isset( $this->prop['registrationdate'] ) ) { |
211
|
|
|
$regDate = $user->getRegistration(); |
212
|
|
|
if ( $regDate !== false ) { |
213
|
|
|
$vals['registrationdate'] = wfTimestamp( TS_ISO_8601, $regDate ); |
214
|
|
|
} |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
if ( isset( $this->prop['acceptlang'] ) ) { |
218
|
|
|
$langs = $this->getRequest()->getAcceptLang(); |
219
|
|
|
$acceptLang = []; |
220
|
|
|
foreach ( $langs as $lang => $val ) { |
221
|
|
|
$r = [ 'q' => $val ]; |
222
|
|
|
ApiResult::setContentValue( $r, 'code', $lang ); |
223
|
|
|
$acceptLang[] = $r; |
224
|
|
|
} |
225
|
|
|
ApiResult::setIndexedTagName( $acceptLang, 'lang' ); |
226
|
|
|
$vals['acceptlang'] = $acceptLang; |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
if ( isset( $this->prop['unreadcount'] ) ) { |
230
|
|
|
$store = MediaWikiServices::getInstance()->getWatchedItemStore(); |
231
|
|
|
$unreadNotifications = $store->countUnreadNotifications( |
232
|
|
|
$user, |
233
|
|
|
self::WL_UNREAD_LIMIT |
234
|
|
|
); |
235
|
|
|
|
236
|
|
|
if ( $unreadNotifications === true ) { |
237
|
|
|
$vals['unreadcount'] = self::WL_UNREAD_LIMIT . '+'; |
238
|
|
|
} else { |
239
|
|
|
$vals['unreadcount'] = $unreadNotifications; |
240
|
|
|
} |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
if ( isset( $this->prop['centralids'] ) ) { |
244
|
|
|
$vals += self::getCentralUserInfo( |
245
|
|
|
$this->getConfig(), $this->getUser(), $this->params['attachedwiki'] |
246
|
|
|
); |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
return $vals; |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
protected function getRateLimits() { |
253
|
|
|
$retval = [ |
254
|
|
|
ApiResult::META_TYPE => 'assoc', |
255
|
|
|
]; |
256
|
|
|
|
257
|
|
|
$user = $this->getUser(); |
258
|
|
|
if ( !$user->isPingLimitable() ) { |
259
|
|
|
return $retval; // No limits |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
// Find out which categories we belong to |
263
|
|
|
$categories = []; |
264
|
|
|
if ( $user->isAnon() ) { |
265
|
|
|
$categories[] = 'anon'; |
266
|
|
|
} else { |
267
|
|
|
$categories[] = 'user'; |
268
|
|
|
} |
269
|
|
|
if ( $user->isNewbie() ) { |
270
|
|
|
$categories[] = 'ip'; |
271
|
|
|
$categories[] = 'subnet'; |
272
|
|
|
if ( !$user->isAnon() ) { |
273
|
|
|
$categories[] = 'newbie'; |
274
|
|
|
} |
275
|
|
|
} |
276
|
|
|
$categories = array_merge( $categories, $user->getGroups() ); |
277
|
|
|
|
278
|
|
|
// Now get the actual limits |
279
|
|
|
foreach ( $this->getConfig()->get( 'RateLimits' ) as $action => $limits ) { |
280
|
|
|
foreach ( $categories as $cat ) { |
281
|
|
|
if ( isset( $limits[$cat] ) && !is_null( $limits[$cat] ) ) { |
282
|
|
|
$retval[$action][$cat]['hits'] = intval( $limits[$cat][0] ); |
283
|
|
|
$retval[$action][$cat]['seconds'] = intval( $limits[$cat][1] ); |
284
|
|
|
} |
285
|
|
|
} |
286
|
|
|
} |
287
|
|
|
|
288
|
|
|
return $retval; |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
public function getAllowedParams() { |
292
|
|
|
return [ |
293
|
|
|
'prop' => [ |
294
|
|
|
ApiBase::PARAM_ISMULTI => true, |
295
|
|
|
ApiBase::PARAM_TYPE => [ |
296
|
|
|
'blockinfo', |
297
|
|
|
'hasmsg', |
298
|
|
|
'groups', |
299
|
|
|
'implicitgroups', |
300
|
|
|
'rights', |
301
|
|
|
'changeablegroups', |
302
|
|
|
'options', |
303
|
|
|
'preferencestoken', |
304
|
|
|
'editcount', |
305
|
|
|
'ratelimits', |
306
|
|
|
'email', |
307
|
|
|
'realname', |
308
|
|
|
'acceptlang', |
309
|
|
|
'registrationdate', |
310
|
|
|
'unreadcount', |
311
|
|
|
'centralids', |
312
|
|
|
], |
313
|
|
|
ApiBase::PARAM_HELP_MSG_PER_VALUE => [ |
314
|
|
|
'unreadcount' => [ |
315
|
|
|
'apihelp-query+userinfo-paramvalue-prop-unreadcount', |
316
|
|
|
self::WL_UNREAD_LIMIT - 1, |
317
|
|
|
self::WL_UNREAD_LIMIT . '+', |
318
|
|
|
], |
319
|
|
|
], |
320
|
|
|
], |
321
|
|
|
'attachedwiki' => null, |
322
|
|
|
]; |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
protected function getExamplesMessages() { |
326
|
|
|
return [ |
327
|
|
|
'action=query&meta=userinfo' |
328
|
|
|
=> 'apihelp-query+userinfo-example-simple', |
329
|
|
|
'action=query&meta=userinfo&uiprop=blockinfo|groups|rights|hasmsg' |
330
|
|
|
=> 'apihelp-query+userinfo-example-data', |
331
|
|
|
]; |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
public function getHelpUrls() { |
335
|
|
|
return 'https://www.mediawiki.org/wiki/API:Userinfo'; |
336
|
|
|
} |
337
|
|
|
} |
338
|
|
|
|
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
string
values, the empty string''
is a special case, in particular the following results might be unexpected: