MediaWiki
master
ActiveUsersPager.php
Go to the documentation of this file.
1
<?php
22
namespace
MediaWiki\Pager
;
23
24
use
IContextSource
;
25
use
MediaWiki\Block\HideUserUtils
;
26
use
MediaWiki\Cache\LinkBatchFactory
;
27
use
MediaWiki\HookContainer\HookContainer
;
28
use
MediaWiki\Html\FormOptions
;
29
use
MediaWiki\Html\Html
;
30
use
MediaWiki\Linker\Linker
;
31
use
MediaWiki\MainConfigNames
;
32
use
MediaWiki\Title\Title
;
33
use
MediaWiki\User\UserGroupManager
;
34
use
MediaWiki\User\UserIdentityLookup
;
35
use
MediaWiki\User\UserIdentityValue
;
36
use
Wikimedia\Rdbms\IConnectionProvider
;
37
45
class
ActiveUsersPager
extends
UsersPager
{
47
private
$hideUserUtils;
48
52
protected
$opts
;
53
57
protected
$groups
;
58
62
private
$blockStatusByUid;
63
65
private
$RCMaxAge;
66
68
private
$excludegroups;
69
80
public
function
__construct
(
81
IContextSource
$context,
82
HookContainer
$hookContainer,
83
LinkBatchFactory
$linkBatchFactory,
84
IConnectionProvider
$dbProvider,
85
UserGroupManager
$userGroupManager,
86
UserIdentityLookup
$userIdentityLookup,
87
HideUserUtils
$hideUserUtils,
88
FormOptions
$opts
89
) {
90
parent::__construct(
91
$context,
92
$hookContainer,
93
$linkBatchFactory,
94
$dbProvider,
95
$userGroupManager,
96
$userIdentityLookup,
97
null
,
98
null
99
);
100
101
$this->hideUserUtils = $hideUserUtils;
102
$this->RCMaxAge = $this->
getConfig
()->get(
MainConfigNames::ActiveUserDays
);
103
$this->requestedUser =
''
;
104
105
$un =
$opts
->
getValue
(
'username'
);
106
if
( $un !=
''
) {
107
$username = Title::makeTitleSafe(
NS_USER
, $un );
108
if
( $username !==
null
) {
109
$this->requestedUser = $username->getText();
110
}
111
}
112
113
$this->groups =
$opts
->
getValue
(
'groups'
);
114
$this->excludegroups =
$opts
->
getValue
(
'excludegroups'
);
115
// Backwards-compatibility with old URLs
116
if
(
$opts
->
getValue
(
'hidebots'
) ) {
117
$this->excludegroups[] =
'bot'
;
118
}
119
if
(
$opts
->
getValue
(
'hidesysops'
) ) {
120
$this->excludegroups[] =
'sysop'
;
121
}
122
}
123
124
public
function
getIndexField
() {
125
return
'qcc_title'
;
126
}
127
128
public
function
getQueryInfo
( $data =
null
) {
129
$dbr = $this->
getDatabase
();
130
131
$activeUserSeconds = $this->
getConfig
()->get(
MainConfigNames::ActiveUserDays
) * 86400;
132
$timestamp = $dbr->timestamp( (
int
)
wfTimestamp
( TS_UNIX ) - $activeUserSeconds );
133
$fname = __METHOD__ .
' ('
. $this->
getSqlComment
() .
')'
;
134
135
// Inner subselect to pull the active users out of querycachetwo
136
$tables = [
'querycachetwo'
,
'user'
,
'actor'
];
137
$fields = [
'qcc_title'
,
'user_id'
,
'actor_id'
];
138
$jconds = [
139
'user'
=> [
'JOIN'
,
'user_name = qcc_title'
],
140
'actor'
=> [
'JOIN'
,
'actor_user = user_id'
],
141
];
142
$conds = [
143
'qcc_type'
=>
'activeusers'
,
144
'qcc_namespace'
=>
NS_USER
,
145
];
146
$options = [];
147
if
( $data !==
null
) {
148
$options[
'ORDER BY'
] =
'qcc_title '
. $data[
'order'
];
149
$options[
'LIMIT'
] = $data[
'limit'
];
150
$conds = array_merge( $conds, $data[
'conds'
] );
151
}
152
if
( $this->requestedUser !=
''
) {
153
$conds[] = $dbr->expr(
'qcc_title'
,
'>='
, $this->requestedUser );
154
}
155
if
( $this->groups !== [] ) {
156
$tables[
'ug1'
] =
'user_groups'
;
157
$jconds[
'ug1'
] = [
'JOIN'
,
'ug1.ug_user = user_id'
];
158
$conds[
'ug1.ug_group'
] =
$this->groups
;
159
$conds[] =
'ug1.ug_expiry IS NULL OR ug1.ug_expiry >= '
. $dbr->addQuotes( $dbr->timestamp() );
160
}
161
if
( $this->excludegroups !== [] ) {
162
$tables[
'ug2'
] =
'user_groups'
;
163
$jconds[
'ug2'
] = [
'LEFT JOIN'
, [
164
'ug2.ug_user = user_id'
,
165
'ug2.ug_group'
=> $this->excludegroups,
166
'ug2.ug_expiry IS NULL OR ug2.ug_expiry >= '
. $dbr->addQuotes( $dbr->timestamp() ),
167
] ];
168
$conds[
'ug2.ug_user'
] =
null
;
169
}
170
if
( !$this->
canSeeHideuser
() ) {
171
$conds[] = $this->hideUserUtils->getExpression( $dbr );
172
}
173
$subquery = $dbr->buildSelectSubquery( $tables, $fields, $conds, $fname, $options, $jconds );
174
175
// Outer query to select the recent edit counts for the selected active users
176
$tables = [
'qcc_users'
=> $subquery,
'recentchanges'
];
177
$jconds = [
'recentchanges'
=> [
'LEFT JOIN'
, [
178
'rc_actor = actor_id'
,
179
$dbr->expr(
'rc_type'
,
'!='
,
RC_EXTERNAL
),
// Don't count wikidata.
180
$dbr->expr(
'rc_type'
,
'!='
,
RC_CATEGORIZE
),
// Don't count categorization changes.
181
$dbr->expr(
'rc_log_type'
,
'='
,
null
)->or(
'rc_log_type'
,
'!='
,
'newusers'
),
182
$dbr->expr(
'rc_timestamp'
,
'>='
, $timestamp ),
183
] ] ];
184
$conds = [];
185
186
return
[
187
'tables'
=> $tables,
188
'fields'
=> [
189
'qcc_title'
,
190
'user_name'
=>
'qcc_title'
,
191
'user_id'
=>
'user_id'
,
192
'recentedits'
=>
'COUNT(rc_id)'
193
],
194
'options'
=> [
'GROUP BY'
=> [
'qcc_title'
,
'user_id'
] ],
195
'conds'
=> $conds,
196
'join_conds'
=> $jconds,
197
];
198
}
199
200
protected
function
buildQueryInfo
( $offset, $limit, $order ) {
201
$fname = __METHOD__ .
' ('
. $this->
getSqlComment
() .
')'
;
202
203
$sortColumns = array_merge( [ $this->mIndexField ], $this->mExtraSortFields );
204
if
( $order === self::QUERY_ASCENDING ) {
205
$dir =
'ASC'
;
206
$orderBy = $sortColumns;
207
$operator = $this->mIncludeOffset ?
'>='
:
'>'
;
208
}
else
{
209
$dir =
'DESC'
;
210
$orderBy = [];
211
foreach
( $sortColumns as $col ) {
212
$orderBy[] = $col .
' DESC'
;
213
}
214
$operator = $this->mIncludeOffset ?
'<='
:
'<'
;
215
}
216
$info = $this->
getQueryInfo
( [
217
'limit'
=> intval( $limit ),
218
'order'
=> $dir,
219
'conds'
=>
220
$offset !=
''
? [ $this->mIndexField . $operator . $this->
getDatabase
()->addQuotes( $offset ) ] : [],
221
] );
222
223
$tables = $info[
'tables'
];
224
$fields = $info[
'fields'
];
225
$conds = $info[
'conds'
];
226
$options = $info[
'options'
];
227
$join_conds = $info[
'join_conds'
];
228
$options[
'ORDER BY'
] = $orderBy;
229
return
[ $tables, $fields, $conds, $fname, $options, $join_conds ];
230
}
231
232
protected
function
doBatchLookups
() {
233
parent::doBatchLookups();
234
235
$uids = [];
236
foreach
( $this->mResult as $row ) {
237
$uids[] = (int)$row->user_id;
238
}
239
// Fetch the block status of the user for showing "(blocked)" text and for
240
// striking out names of suppressed users when privileged user views the list.
241
// Although the first query already hits the block table for un-privileged, this
242
// is done in two queries to avoid huge quicksorts and to make COUNT(*) correct.
243
$dbr = $this->
getDatabase
();
244
if
( $this->blockTargetReadStage ===
SCHEMA_COMPAT_READ_OLD
) {
245
$res = $dbr->newSelectQueryBuilder()
246
->select( [
247
'bt_user'
=>
'ipb_user'
,
248
'deleted'
=>
'MAX(ipb_deleted)'
,
249
'sitewide'
=>
'MAX(ipb_sitewide)'
250
] )
251
->from(
'ipblocks'
)
252
->where( [
'ipb_user'
=> $uids ] )
253
->groupBy( [
'ipb_user'
] )
254
->caller( __METHOD__ )->fetchResultSet();
255
}
else
{
256
$res = $dbr->newSelectQueryBuilder()
257
->select( [
258
'bt_user'
,
259
'deleted'
=>
'MAX(bl_deleted)'
,
260
'sitewide'
=>
'MAX(bl_sitewide)'
261
] )
262
->from(
'block_target'
)
263
->join(
'block'
,
null
,
'bl_target=bt_id'
)
264
->where( [
'bt_user'
=> $uids ] )
265
->groupBy( [
'bt_user'
] )
266
->caller( __METHOD__ )->fetchResultSet();
267
}
268
$this->blockStatusByUid = [];
269
foreach
( $res as $row ) {
270
$this->blockStatusByUid[$row->bt_user] = [
271
'deleted'
=> $row->deleted,
272
'sitewide'
=> $row->sitewide,
273
];
274
}
275
$this->mResult->seek( 0 );
276
}
277
278
public
function
formatRow
( $row ) {
279
$userName = $row->user_name;
280
281
$ulinks = Linker::userLink( $row->user_id, $userName );
282
$ulinks .= Linker::userToolLinks(
283
$row->user_id,
284
$userName,
285
// Should the contributions link be red if the user has no edits (using default)
286
false
,
287
// Customisation flags (using default 0)
288
0,
289
// User edit count (using default)
290
null
,
291
// do not wrap the message in parentheses (CSS will provide these)
292
false
293
);
294
295
$lang = $this->
getLanguage
();
296
297
$list = [];
298
299
$userIdentity =
new
UserIdentityValue
( intval( $row->user_id ), $userName );
300
$ugms = $this->
getGroupMemberships
( $userIdentity );
301
foreach
( $ugms as $ugm ) {
302
$list[] = $this->
buildGroupLink
( $ugm, $userName );
303
}
304
305
$groups
= $lang->commaList( $list );
306
307
$item = $lang->specialList( $ulinks,
$groups
);
308
309
// If there is a block, 'deleted' and 'sitewide' are both set on
310
// $this->blockStatusByUid[$row->user_id].
311
$blocked =
''
;
312
$isBlocked = isset( $this->blockStatusByUid[$row->user_id] );
313
if
( $isBlocked ) {
314
if
( $this->blockStatusByUid[$row->user_id][
'deleted'
] == 1 ) {
315
$item =
"<span class=\"deleted\">$item</span>"
;
316
}
317
if
( $this->blockStatusByUid[$row->user_id][
'sitewide'
] == 1 ) {
318
$blocked =
' '
. $this->
msg
(
'listusers-blocked'
, $userName )->escaped();
319
}
320
}
321
$count = $this->
msg
(
'activeusers-count'
)->numParams( $row->recentedits )
322
->params( $userName )->numParams( $this->RCMaxAge )->escaped();
323
324
return
Html::rawElement(
'li'
, [],
"{$item} [{$count}]{$blocked}"
);
325
}
326
327
}
328
333
class_alias( ActiveUsersPager::class,
'ActiveUsersPager'
);
NS_USER
const NS_USER
Definition
Defines.php:66
SCHEMA_COMPAT_READ_OLD
const SCHEMA_COMPAT_READ_OLD
Definition
Defines.php:264
RC_EXTERNAL
const RC_EXTERNAL
Definition
Defines.php:119
RC_CATEGORIZE
const RC_CATEGORIZE
Definition
Defines.php:120
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition
GlobalFunctions.php:1329
ContextSource\msg
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition
ContextSource.php:202
ContextSource\getConfig
getConfig()
Definition
ContextSource.php:77
ContextSource\getLanguage
getLanguage()
Definition
ContextSource.php:169
MediaWiki\Block\HideUserUtils
Helpers for building queries that determine whether a user is hidden.
Definition
HideUserUtils.php:12
MediaWiki\Cache\LinkBatchFactory
Definition
LinkBatchFactory.php:41
MediaWiki\HookContainer\HookContainer
HookContainer class.
Definition
HookContainer.php:58
MediaWiki\Html\FormOptions
Helper class to keep track of options when mixing links and form elements.
Definition
FormOptions.php:41
MediaWiki\Html\FormOptions\getValue
getValue( $name)
Get the value for the given option name.
Definition
FormOptions.php:190
MediaWiki\Html\Html
This class is a collection of static functions that serve two purposes:
Definition
Html.php:57
MediaWiki\Linker\Linker
Some internal bits split of from Skin.php.
Definition
Linker.php:65
MediaWiki\MainConfigNames
A class containing constants representing the names of configuration variables.
Definition
MainConfigNames.php:22
MediaWiki\MainConfigNames\ActiveUserDays
const ActiveUserDays
Name constant for the ActiveUserDays setting, for use with Config::get()
Definition
MainConfigNames.php:2499
MediaWiki\Pager\ActiveUsersPager
This class is used to get a list of active users.
Definition
ActiveUsersPager.php:45
MediaWiki\Pager\ActiveUsersPager\getQueryInfo
getQueryInfo( $data=null)
Definition
ActiveUsersPager.php:128
MediaWiki\Pager\ActiveUsersPager\formatRow
formatRow( $row)
Definition
ActiveUsersPager.php:278
MediaWiki\Pager\ActiveUsersPager\doBatchLookups
doBatchLookups()
Called from getBody(), before getStartBody() is called and after doQuery() was called.
Definition
ActiveUsersPager.php:232
MediaWiki\Pager\ActiveUsersPager\getIndexField
getIndexField()
Definition
ActiveUsersPager.php:124
MediaWiki\Pager\ActiveUsersPager\buildQueryInfo
buildQueryInfo( $offset, $limit, $order)
Build variables to use by the database wrapper.
Definition
ActiveUsersPager.php:200
MediaWiki\Pager\ActiveUsersPager\__construct
__construct(IContextSource $context, HookContainer $hookContainer, LinkBatchFactory $linkBatchFactory, IConnectionProvider $dbProvider, UserGroupManager $userGroupManager, UserIdentityLookup $userIdentityLookup, HideUserUtils $hideUserUtils, FormOptions $opts)
Definition
ActiveUsersPager.php:80
MediaWiki\Pager\ActiveUsersPager\$opts
FormOptions $opts
Definition
ActiveUsersPager.php:52
MediaWiki\Pager\ActiveUsersPager\$groups
string[] $groups
Definition
ActiveUsersPager.php:57
MediaWiki\Pager\IndexPager\getDatabase
getDatabase()
Get the Database object in use.
Definition
IndexPager.php:256
MediaWiki\Pager\IndexPager\getSqlComment
getSqlComment()
Get some text to go in brackets in the "function name" part of the SQL comment.
Definition
IndexPager.php:447
MediaWiki\Pager\UsersPager
This class is used to get a list of user.
Definition
UsersPager.php:57
MediaWiki\Pager\UsersPager\canSeeHideuser
canSeeHideuser()
Definition
UsersPager.php:488
MediaWiki\Pager\UsersPager\getQueryInfo
getQueryInfo()
Definition
UsersPager.php:173
MediaWiki\Pager\UsersPager\getGroupMemberships
getGroupMemberships( $user)
Get an associative array containing groups the specified user belongs to, and the relevant UserGroupM...
Definition
UsersPager.php:531
MediaWiki\Pager\UsersPager\buildGroupLink
buildGroupLink( $group, $username)
Format a link to a group description page.
Definition
UsersPager.php:546
MediaWiki\Title\Title
Represents a title within MediaWiki.
Definition
Title.php:79
MediaWiki\User\UserGroupManager
Manages user groups.
Definition
UserGroupManager.php:53
MediaWiki\User\UserIdentityValue
Value object representing a user's identity.
Definition
UserIdentityValue.php:35
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition
IContextSource.php:64
MediaWiki\User\UserIdentityLookup
Definition
UserIdentityLookup.php:33
Wikimedia\Rdbms\IConnectionProvider
Provide primary and replica IDatabase connections.
Definition
IConnectionProvider.php:35
MediaWiki\Pager
Definition
HistoryPager.php:24
includes
specials
pagers
ActiveUsersPager.php
Generated on Thu Dec 7 2023 03:10:16 for MediaWiki by
1.9.8