73 $parms = explode(
'/', $par );
74 $symsForAll = [
'*',
'user' ];
76 if ( $parms[0] !=
'' &&
79 $this->requestedGroup = $par;
80 $un = $request->getText(
'username' );
81 } elseif ( count( $parms ) == 2 ) {
82 $this->requestedGroup = $parms[0];
85 $this->requestedGroup = $request->getVal(
'group' );
86 $un = ( $par !=
'' ) ? $par : $request->getText(
'username' );
89 if ( in_array( $this->requestedGroup, $symsForAll ) ) {
90 $this->requestedGroup =
'';
92 $this->editsOnly = $request->getBool(
'editsOnly' );
93 $this->temporaryGroupsOnly = $request->getBool(
'temporaryGroupsOnly' );
94 $this->creationSort = $request->getBool(
'creationSort' );
96 $this->mDefaultDirection = $request->getBool(
'desc' )
100 $this->requestedUser =
'';
103 $username = Title::makeTitleSafe(
NS_USER, $un );
105 if ( $username !==
null ) {
106 $this->requestedUser = $username->getText();
110 parent::__construct();
128 if ( !MediaWikiServices::getInstance()
130 ->userHasRight( $this->
getUser(),
'hideuser' )
132 $conds[] =
'ipb_deleted IS NULL OR ipb_deleted = 0';
137 if ( $this->requestedGroup !=
'' || $this->temporaryGroupsOnly ) {
138 $conds[] =
'ug_expiry >= ' .
$dbr->addQuotes(
$dbr->timestamp() ) .
139 ( !$this->temporaryGroupsOnly ?
' OR ug_expiry IS NULL' :
'' );
142 if ( $this->requestedGroup !=
'' ) {
143 $conds[
'ug_group'] = $this->requestedGroup;
146 if ( $this->requestedUser !=
'' ) {
147 # Sorted either by account creation or name
148 if ( $this->creationSort ) {
149 $conds[] =
'user_id >= ' . intval(
User::idFromName( $this->requestedUser ) );
151 $conds[] =
'user_name >= ' .
$dbr->addQuotes( $this->requestedUser );
155 if ( $this->editsOnly ) {
156 $conds[] =
'user_editcount > 0';
159 $options[
'GROUP BY'] = $this->creationSort ?
'user_id' :
'user_name';
162 'tables' => [
'user',
'user_groups',
'ipblocks' ],
164 'user_name' => $this->creationSort ?
'MAX(user_name)' :
'user_name',
165 'user_id' => $this->creationSort ?
'user_id' :
'MAX(user_id)',
166 'edits' =>
'MAX(user_editcount)',
167 'creation' =>
'MIN(user_registration)',
168 'ipb_deleted' =>
'MAX(ipb_deleted)',
169 'ipb_sitewide' =>
'MAX(ipb_sitewide)'
171 'options' => $options,
173 'user_groups' => [
'LEFT JOIN',
'user_id=ug_user' ],
184 $this->getHookRunner()->onSpecialListusersQueryInfo( $this, $query );
194 if ( $row->user_id == 0 ) { # T18487
198 $userName = $row->user_name;
212 $ugms = self::getGroupMemberships( intval( $row->user_id ), $this->userGroupCache );
214 if ( !$this->including && count( $ugms ) > 0 ) {
216 foreach ( $ugms as $ugm ) {
219 $groups =
$lang->commaList( $list );
222 $item =
$lang->specialList( $ulinks, $groups );
224 if ( $row->ipb_deleted ) {
225 $item =
"<span class=\"deleted\">$item</span>";
229 if ( !$this->including && $this->
getConfig()->
get(
'Edititis' ) ) {
230 $count = $this->
msg(
'usereditcount' )->numParams( $row->edits )->escaped();
231 $edits = $this->
msg(
'word-separator' )->escaped() . $this->
msg(
'brackets', $count )->escaped();
235 # Some rows may be null
236 if ( !$this->including && $row->creation ) {
238 $d =
$lang->userDate( $row->creation, $user );
239 $t =
$lang->userTime( $row->creation, $user );
240 $created = $this->
msg(
'usercreated', $d,
$t, $row->user_name )->escaped();
241 $created =
' ' . $this->
msg(
'parentheses' )->rawParams( $created )->escaped();
244 $blocked = $row->ipb_deleted !==
null && $row->ipb_sitewide ===
'1' ?
245 ' ' . $this->
msg(
'listusers-blocked', $userName )->escaped() :
248 $this->getHookRunner()->onSpecialListusersFormatRow( $item, $row );
250 return Html::rawElement(
'li', [],
"{$item}{$edits}{$created}{$blocked}" );
256 # Give some pointers to make user links
257 foreach ( $this->mResult as $row ) {
258 $batch->add(
NS_USER, $row->user_name );
260 $userIds[] = $row->user_id;
265 $groupManager = MediaWikiServices::getInstance()->getUserGroupManager();
266 $groupsQueryInfo = $groupManager->getQueryInfo();
267 $groupRes =
$dbr->select(
268 $groupsQueryInfo[
'tables'],
269 $groupsQueryInfo[
'fields'],
270 [
'ug_user' => $userIds ],
272 $groupsQueryInfo[
'joins']
276 foreach ( $groupRes as $row ) {
277 $ugm = $groupManager->newGroupMembershipFromRow( $row );
278 if ( !$ugm->isExpired() ) {
279 $cache[$row->ug_user][$row->ug_group] = $ugm;
280 $groups[$row->ug_group] =
true;
286 $this->getHookRunner()->onUsersPagerDoBatchLookups(
$dbr, $userIds,
$cache, $groups );
288 $this->userGroupCache =
$cache;
291 foreach ( $groups as $group => $unused ) {
292 $groupPage = UserGroupMembership::getGroupPage( $group );
294 $batch->addObj( $groupPage );
299 $this->mResult->rewind();
306 $self = explode(
'/', $this->
getTitle()->getPrefixedDBkey(), 2 )[0];
308 $groupOptions = [ $this->
msg(
'group-all' )->text() =>
'' ];
309 foreach ( $this->
getAllGroups() as $group => $groupText ) {
310 $groupOptions[ $groupText ] = $group;
315 'class' => HTMLUserTextField::class,
316 'label' => $this->
msg(
'listusersfrom' )->text(),
317 'name' =>
'username',
318 'default' => $this->requestedUser,
321 'label' => $this->
msg(
'group' )->text(),
323 'default' => $this->requestedGroup,
324 'class' => HTMLSelectField::class,
325 'options' => $groupOptions,
329 'label' => $this->
msg(
'listusers-editsonly' )->text(),
330 'name' =>
'editsOnly',
332 'default' => $this->editsOnly
334 'temporaryGroupsOnly' => [
336 'label' => $this->
msg(
'listusers-temporarygroupsonly' )->text(),
337 'name' =>
'temporaryGroupsOnly',
338 'id' =>
'temporaryGroupsOnly',
339 'default' => $this->temporaryGroupsOnly
343 'label' => $this->
msg(
'listusers-creationsort' )->text(),
344 'name' =>
'creationSort',
345 'id' =>
'creationSort',
346 'default' => $this->creationSort
350 'label' => $this->
msg(
'listusers-desc' )->text(),
353 'default' => $this->mDefaultDirection
355 'limithiddenfield' => [
356 'class' => HTMLHiddenField::class,
358 'default' => $this->mLimit
362 $beforeSubmitButtonHookOut =
'';
363 $this->getHookRunner()->onSpecialListusersHeaderForm( $this, $beforeSubmitButtonHookOut );
365 if ( $beforeSubmitButtonHookOut !==
'' ) {
366 $formDescriptor[
'beforeSubmitButtonHookOut' ] = [
367 'class' => HTMLInfoField::class,
369 'default' => $beforeSubmitButtonHookOut
373 $formDescriptor[
'submit' ] = [
374 'class' => HTMLSubmitField::class,
375 'buttonlabel-message' =>
'listusers-submit',
378 $beforeClosingFieldsetHookOut =
'';
379 $this->getHookRunner()->onSpecialListusersHeader( $this, $beforeClosingFieldsetHookOut );
381 if ( $beforeClosingFieldsetHookOut !==
'' ) {
382 $formDescriptor[
'beforeClosingFieldsetHookOut' ] = [
383 'class' => HTMLInfoField::class,
385 'default' => $beforeClosingFieldsetHookOut
389 $htmlForm = HTMLForm::factory(
'ooui', $formDescriptor, $this->
getContext() );
392 ->setAction( Title::newFromText(
$self )->getLocalURL() )
393 ->setId(
'mw-listusers-form' )
394 ->setFormIdentifier(
'mw-listusers-form' )
395 ->suppressDefaultSubmit()
396 ->setWrapperLegendMsg(
'listusers' );
397 return $htmlForm->prepareForm()->getHTML(
true );
419 $query = parent::getDefaultQuery();
420 if ( $this->requestedGroup !=
'' ) {
421 $query[
'group'] = $this->requestedGroup;
423 if ( $this->requestedUser !=
'' ) {
424 $query[
'username'] = $this->requestedUser;
426 $this->getHookRunner()->onSpecialListusersDefaultQuery( $this, $query );