82 $parms = explode(
'/', $par );
83 $symsForAll = [
'*',
'user' ];
85 if ( $parms[0] !=
'' &&
86 ( in_array( $par, $userGroupManager->listAllGroups() ) || in_array( $par, $symsForAll ) )
88 $this->requestedGroup = $par;
89 $un =
$request->getText(
'username' );
90 } elseif ( count( $parms ) == 2 ) {
91 $this->requestedGroup = $parms[0];
94 $this->requestedGroup =
$request->getVal(
'group' );
95 $un = ( $par !=
'' ) ? $par :
$request->getText(
'username' );
98 if ( in_array( $this->requestedGroup, $symsForAll ) ) {
99 $this->requestedGroup =
'';
101 $this->editsOnly =
$request->getBool(
'editsOnly' );
102 $this->temporaryGroupsOnly =
$request->getBool(
'temporaryGroupsOnly' );
103 $this->temporaryAccountsOnly =
$request->getBool(
'temporaryAccountsOnly' );
104 $this->creationSort =
$request->getBool(
'creationSort' );
106 $this->mDefaultDirection =
$request->getBool(
'desc' )
107 ? IndexPager::DIR_DESCENDING
108 : IndexPager::DIR_ASCENDING;
110 $this->requestedUser =
'';
113 $username = Title::makeTitleSafe(
NS_USER, $un );
115 if ( $username !==
null ) {
116 $this->requestedUser = $username->getText();
122 parent::__construct();
123 $this->hookRunner =
new HookRunner( $hookContainer );
142 $conds[] = $this->hideUserUtils->getExpression( $dbr );
156 $deleted =
'MAX(' . $dbr->buildIntegerCast(
157 $this->hideUserUtils->getExpression( $dbr,
'user_id', HideUserUtils::HIDDEN_USERS )
161 if ( $this->requestedGroup !=
'' || $this->temporaryGroupsOnly ) {
162 $cond = $dbr->expr(
'ug_expiry',
'>=', $dbr->timestamp() );
163 if ( !$this->temporaryGroupsOnly ) {
164 $cond = $cond->or(
'ug_expiry',
'=',
null );
169 if ( $this->temporaryAccountsOnly && $this->tempUserConfig->isKnown() ) {
170 $conds[] = $this->tempUserConfig->getMatchCondition(
171 $dbr,
'user_name', IExpression::LIKE
175 if ( $this->requestedGroup !=
'' ) {
179 if ( $this->requestedUser !=
'' ) {
180 # Sorted either by account creation or name
181 if ( $this->creationSort ) {
182 $userIdentity = $this->userIdentityLookup->getUserIdentityByName( $this->requestedUser );
183 if ( $userIdentity && $userIdentity->isRegistered() ) {
184 $conds[] = $dbr->expr(
'user_id',
'>=', $userIdentity->getId() );
187 $conds[] = $dbr->expr(
'user_name',
'>=', $this->requestedUser );
191 if ( $this->editsOnly ) {
192 $conds[] = $dbr->expr(
'user_editcount',
'>', 0 );
199 'block_with_target' => [
205 'user_name' => $this->creationSort ?
'MAX(user_name)' :
'user_name',
206 'user_id' => $this->creationSort ?
'user_id' :
'MAX(user_id)',
207 'edits' =>
'MAX(user_editcount)',
208 'creation' =>
'MIN(user_registration)',
209 'deleted' => $deleted,
210 'sitewide' =>
'MAX(bl_sitewide)'
213 'GROUP BY' => $this->creationSort ?
'user_id' :
'user_name',
216 'user_groups' => [
'LEFT JOIN',
'user_id=ug_user' ],
217 'block_with_target' => [
221 $dbr->expr(
'bl_expiry',
'>=', $dbr->timestamp() ),
224 'block' => [
'JOIN',
'bl_target=bt_id' ]
229 $this->hookRunner->onSpecialListusersQueryInfo( $this, $query );
239 if ( $row->user_id == 0 ) { # T18487
243 $userName = $row->user_name;
245 $ulinks = Linker::userLink( $row->user_id, $userName );
246 $ulinks .= Linker::userToolLinksRedContribs(
260 if ( !$this->including && count( $ugms ) > 0 ) {
262 foreach ( $ugms as $ugm ) {
265 $groups = $lang->commaList( $list );
268 $item = $lang->specialList( $ulinks, $groups );
270 if ( $row->deleted ) {
271 $item =
"<span class=\"deleted\">$item</span>";
276 $count = $this->
msg(
'usereditcount' )->numParams( $row->edits )->escaped();
277 $edits = $this->
msg(
'word-separator' )->escaped() . $this->
msg(
'brackets', $count )->escaped();
281 # Some rows may be null
282 if ( !$this->including && $row->creation ) {
284 $d = $lang->userDate( $row->creation, $user );
285 $t = $lang->userTime( $row->creation, $user );
286 $created = $this->
msg(
'usercreated', $d, $t, $row->user_name )->escaped();
287 $created =
' ' . $this->
msg(
'parentheses' )->rawParams( $created )->escaped();
290 $blocked = $row->deleted !==
null && $row->sitewide ===
'1' ?
291 ' ' . $this->
msg(
'listusers-blocked', $userName )->escaped() :
294 $this->hookRunner->onSpecialListusersFormatRow( $item, $row );
296 return Html::rawElement(
'li', [],
"{$item}{$edits}{$created}{$blocked}" );
301 $batch = $this->linkBatchFactory->newLinkBatch()->setCaller( __METHOD__ );
303 # Give some pointers to make user links
304 foreach ( $this->mResult as $row ) {
306 $batch->addUser( $user );
307 $userIds[] = $user->getId();
311 $queryBuilder = $this->userGroupManager->newQueryBuilder( $this->
getDatabase() );
312 $groupRes = $queryBuilder->where( [
'ug_user' => $userIds ] )
313 ->caller( __METHOD__ )
317 foreach ( $groupRes as $row ) {
318 $ugm = $this->userGroupManager->newGroupMembershipFromRow( $row );
319 if ( !$ugm->isExpired() ) {
320 $cache[$row->ug_user][$row->ug_group] = $ugm;
321 $groups[$row->ug_group] =
true;
327 $this->hookRunner->onUsersPagerDoBatchLookups( $this->
getDatabase(), $userIds, $cache, $groups );
329 $this->userGroupCache = $cache;
332 foreach ( $groups as $group => $unused ) {
333 $groupPage = UserGroupMembership::getGroupPage( $group );
335 $batch->addObj( $groupPage );
340 $this->mResult->rewind();
347 $self = explode(
'/', $this->
getTitle()->getPrefixedDBkey(), 2 )[0];
349 $groupOptions = [ $this->
msg(
'group-all' )->text() =>
'' ];
350 foreach ( $this->getAllGroups() as $group => $groupText ) {
351 if ( array_key_exists( $groupText, $groupOptions ) ) {
352 LoggerFactory::getInstance(
'translation-problem' )->error(
353 'The group {group_one} has the same translation as {group_two} for {lang}. ' .
354 '{group_one} will not be displayed in group dropdown of the UsersPager.',
356 'group_one' => $group,
357 'group_two' => $groupOptions[$groupText],
363 $groupOptions[ $groupText ] = $group;
368 'class' => HTMLUserTextField::class,
369 'label' => $this->
msg(
'listusersfrom' )->text(),
370 'name' =>
'username',
374 'label' => $this->
msg(
'group' )->text(),
377 'class' => HTMLSelectField::class,
378 'options' => $groupOptions,
382 'label' => $this->
msg(
'listusers-editsonly' )->text(),
383 'name' =>
'editsOnly',
387 'temporaryGroupsOnly' => [
389 'label' => $this->
msg(
'listusers-temporarygroupsonly' )->text(),
390 'name' =>
'temporaryGroupsOnly',
391 'id' =>
'temporaryGroupsOnly',
397 if ( $this->tempUserConfig->isKnown() ) {
398 $formDescriptor = array_merge( $formDescriptor, [
399 'temporaryAccountsOnly' => [
401 'label' => $this->
msg(
'listusers-temporaryaccountsonly' )->text(),
402 'name' =>
'temporaryAccountsOnly',
403 'id' =>
'temporaryAccountsOnly',
404 'default' => $this->temporaryAccountsOnly
410 $formDescriptor = array_merge( $formDescriptor, [
413 'label' => $this->
msg(
'listusers-creationsort' )->text(),
414 'name' =>
'creationSort',
415 'id' =>
'creationSort',
416 'default' => $this->creationSort
420 'label' => $this->
msg(
'listusers-desc' )->text(),
423 'default' => $this->mDefaultDirection
425 'limithiddenfield' => [
426 'class' => HTMLHiddenField::class,
428 'default' => $this->mLimit
432 $beforeSubmitButtonHookOut =
'';
433 $this->hookRunner->onSpecialListusersHeaderForm( $this, $beforeSubmitButtonHookOut );
435 if ( $beforeSubmitButtonHookOut !==
'' ) {
436 $formDescriptor[
'beforeSubmitButtonHookOut' ] = [
437 'class' => HTMLInfoField::class,
439 'default' => $beforeSubmitButtonHookOut
443 $formDescriptor[
'submit' ] = [
444 'class' => HTMLSubmitField::class,
445 'buttonlabel-message' =>
'listusers-submit',
448 $beforeClosingFieldsetHookOut =
'';
449 $this->hookRunner->onSpecialListusersHeader( $this, $beforeClosingFieldsetHookOut );
451 if ( $beforeClosingFieldsetHookOut !==
'' ) {
452 $formDescriptor[
'beforeClosingFieldsetHookOut' ] = [
453 'class' => HTMLInfoField::class,
455 'default' => $beforeClosingFieldsetHookOut
459 $htmlForm = HTMLForm::factory(
'ooui', $formDescriptor, $this->
getContext() );
462 ->setTitle( Title::newFromText(
$self ) )
463 ->setId(
'mw-listusers-form' )
464 ->setFormIdentifier(
'mw-listusers-form' )
465 ->suppressDefaultSubmit()
466 ->setWrapperLegendMsg(
'listusers' );
467 return $htmlForm->prepareForm()->getHTML(
true );