Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 332 |
|
0.00% |
0 / 16 |
CRAP | |
0.00% |
0 / 1 |
SpecialMultiLock | |
0.00% |
0 / 332 |
|
0.00% |
0 / 16 |
3422 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
doesWrites | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 43 |
|
0.00% |
0 / 1 |
240 | |||
getGlobalUsers | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
72 | |||
searchForUsers | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
12 | |||
showStatusForm | |
0.00% |
0 / 76 |
|
0.00% |
0 / 1 |
12 | |||
showTableHeader | |
0.00% |
0 / 44 |
|
0.00% |
0 / 1 |
2 | |||
showUserTable | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
30 | |||
getUserTableRow | |
0.00% |
0 / 32 |
|
0.00% |
0 / 1 |
6 | |||
setStatus | |
0.00% |
0 / 27 |
|
0.00% |
0 / 1 |
110 | |||
showStatusError | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
showError | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
showSuccess | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
showUsernameForm | |
0.00% |
0 / 25 |
|
0.00% |
0 / 1 |
12 | |||
showLogExtract | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
6 | |||
getGroupName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\CentralAuth\Special; |
4 | |
5 | use LogEventsList; |
6 | use MediaWiki\Extension\CentralAuth\CentralAuthDatabaseManager; |
7 | use MediaWiki\Extension\CentralAuth\CentralAuthUIService; |
8 | use MediaWiki\Extension\CentralAuth\User\CentralAuthUser; |
9 | use MediaWiki\Html\Html; |
10 | use MediaWiki\SpecialPage\SpecialPage; |
11 | use Wikimedia\Rdbms\IExpression; |
12 | use Wikimedia\Rdbms\LikeValue; |
13 | use Xml; |
14 | |
15 | /** |
16 | * Special page to allow locking and hiding multiple users |
17 | * at one time. Lots of code derived from Special:CentralAuth. |
18 | * |
19 | * @file |
20 | * @ingroup Extensions |
21 | */ |
22 | |
23 | class SpecialMultiLock extends SpecialPage { |
24 | /** @var bool */ |
25 | private $mCanSuppress; |
26 | /** @var string[] */ |
27 | private $mGlobalUsers; |
28 | /** @var string[]|string|null */ |
29 | private $mUserNames; |
30 | /** @var string */ |
31 | private $mPrefixSearch; |
32 | /** @var bool */ |
33 | private $mPosted; |
34 | /** @var string */ |
35 | private $mMethod; |
36 | /** @var string */ |
37 | private $mActionLock; |
38 | /** @var int */ |
39 | private $mActionHide; |
40 | /** @var string */ |
41 | private $mReason; |
42 | /** @var string[] */ |
43 | private $mActionUserNames; |
44 | /** @var CentralAuthDatabaseManager */ |
45 | private $databaseManager; |
46 | /** @var CentralAuthUIService */ |
47 | private $uiService; |
48 | |
49 | /** |
50 | * @param CentralAuthDatabaseManager $databaseManager |
51 | * @param CentralAuthUIService $uiService |
52 | */ |
53 | public function __construct( |
54 | CentralAuthDatabaseManager $databaseManager, |
55 | CentralAuthUIService $uiService |
56 | ) { |
57 | parent::__construct( 'MultiLock', 'centralauth-lock' ); |
58 | $this->databaseManager = $databaseManager; |
59 | $this->uiService = $uiService; |
60 | } |
61 | |
62 | public function doesWrites() { |
63 | return true; |
64 | } |
65 | |
66 | /** @inheritDoc */ |
67 | public function execute( $subpage ) { |
68 | $this->setHeaders(); |
69 | $this->checkPermissions(); |
70 | |
71 | $this->mCanSuppress = $this->getContext()->getAuthority()->isAllowed( 'centralauth-suppress' ); |
72 | $this->getOutput()->addModules( 'ext.centralauth' ); |
73 | $this->getOutput()->addModuleStyles( 'ext.centralauth.noflash' ); |
74 | $this->mMethod = $this->getRequest()->getVal( 'wpMethod', '' ); |
75 | $this->mActionLock = $this->getRequest()->getVal( 'wpActionLock', 'nochange' ); |
76 | $this->mActionHide = $this->getRequest()->getInt( 'wpActionHide', -1 ); |
77 | $this->mUserNames = $this->getRequest()->getVal( 'wpTarget', '' ); |
78 | $this->mPrefixSearch = $this->getRequest()->getVal( 'wpSearchTarget', '' ); |
79 | $this->mActionUserNames = $this->getRequest()->getArray( 'wpActionTarget' ); |
80 | $this->mPosted = $this->getRequest()->wasPosted(); |
81 | |
82 | $this->mReason = $this->getRequest()->getText( 'wpReasonList' ); |
83 | $reasonDetail = $this->getRequest()->getText( 'wpReason' ); |
84 | |
85 | if ( $this->mReason == 'other' ) { |
86 | $this->mReason = $reasonDetail; |
87 | } elseif ( $reasonDetail ) { |
88 | $this->mReason .= $this->msg( 'colon-separator' )->inContentLanguage()->text() . |
89 | $reasonDetail; |
90 | } |
91 | |
92 | if ( $this->mUserNames !== '' ) { |
93 | $this->mUserNames = explode( "\n", $this->mUserNames ); |
94 | } else { |
95 | $this->mUserNames = []; |
96 | } |
97 | |
98 | if ( $this->mPrefixSearch !== '' ) { |
99 | $this->mPrefixSearch = $this->getLanguage()->ucfirst( trim( $this->mPrefixSearch ) ); |
100 | } |
101 | |
102 | if ( $this->mMethod === '' ) { |
103 | $this->getOutput()->addWikiMsg( 'centralauth-admin-multi-intro' ); |
104 | $this->showUsernameForm(); |
105 | return; |
106 | } elseif ( $this->mPosted && $this->mMethod == 'search' && count( $this->mUserNames ) > 0 ) { |
107 | $this->showUserTable(); |
108 | } elseif ( $this->mPosted && $this->mMethod == 'search' && $this->mPrefixSearch !== '' ) { |
109 | $this->searchForUsers(); |
110 | $this->showUserTable(); |
111 | } elseif ( $this->mPosted && $this->mMethod == 'set-status' && |
112 | is_array( $this->mActionUserNames ) |
113 | ) { |
114 | $this->mGlobalUsers = array_unique( |
115 | $this->getGlobalUsers( $this->mActionUserNames, true ), SORT_REGULAR |
116 | ); |
117 | $this->setStatus(); |
118 | $this->showUserTable(); |
119 | } else { |
120 | $this->showError( 'centralauth-admin-multi-username' ); |
121 | } |
122 | |
123 | $this->showUsernameForm(); |
124 | |
125 | $this->showLogExtract(); |
126 | } |
127 | |
128 | /** |
129 | * Get the CentralAuthUsers from lines of text |
130 | * |
131 | * @param string[] $usernames |
132 | * @param bool $fromPrimaryDb |
133 | * @return (CentralAuthUser|string|false)[] User object, a HTML error string, or false. |
134 | */ |
135 | private function getGlobalUsers( $usernames, $fromPrimaryDb = false ) { |
136 | $ret = []; |
137 | foreach ( $usernames as $username ) { |
138 | // T270954 |
139 | $username = str_replace( '_', ' ', $username ); |
140 | $username = trim( $username ); |
141 | if ( $username === '' ) { |
142 | $ret[] = false; |
143 | continue; |
144 | } |
145 | $username = $this->getLanguage()->ucfirst( $username ); |
146 | |
147 | $globalUser = $fromPrimaryDb |
148 | ? CentralAuthUser::getPrimaryInstanceByName( $username ) |
149 | : CentralAuthUser::getInstanceByName( $username ); |
150 | if ( !$globalUser->exists() |
151 | || ( !$this->mCanSuppress && |
152 | ( $globalUser->isSuppressed() || $globalUser->isHidden() ) ) |
153 | ) { |
154 | $ret[] = $this->msg( 'centralauth-admin-nonexistent', $username )->parse(); |
155 | } else { |
156 | $ret[] = $globalUser; |
157 | } |
158 | } |
159 | return $ret; |
160 | } |
161 | |
162 | /** |
163 | * Search the CentralAuth db for all usernames prefixed with mPrefixSearch |
164 | */ |
165 | private function searchForUsers() { |
166 | $dbr = $this->databaseManager->getCentralReplicaDB(); |
167 | |
168 | $where = [ |
169 | $dbr->expr( 'gu_name', IExpression::LIKE, |
170 | new LikeValue( $this->mPrefixSearch, $dbr->anyString() ) ) |
171 | ]; |
172 | if ( !$this->mCanSuppress ) { |
173 | $where['gu_hidden_level'] = CentralAuthUser::HIDDEN_LEVEL_NONE; |
174 | } |
175 | |
176 | $result = $dbr->newSelectQueryBuilder() |
177 | ->select( 'gu_name' ) |
178 | ->from( 'globaluser' ) |
179 | ->where( $where ) |
180 | ->limit( 100 ) |
181 | ->caller( __METHOD__ ) |
182 | ->fetchFieldValues(); |
183 | |
184 | foreach ( $result as $name ) { |
185 | $this->mUserNames[] = $name; |
186 | } |
187 | } |
188 | |
189 | /** |
190 | * Show the Lock and/or Hide form, appropriate for this admin user's rights. |
191 | * The <form> and <fieldset> were started in showTableHeader() |
192 | */ |
193 | private function showStatusForm() { |
194 | $form = ''; |
195 | $radioLocked = |
196 | Xml::radioLabel( |
197 | $this->msg( 'centralauth-admin-action-lock-nochange' )->text(), |
198 | 'wpActionLock', |
199 | 'nochange', |
200 | 'mw-centralauth-status-locked-no', |
201 | true ) . |
202 | '<br />' . |
203 | Xml::radioLabel( |
204 | $this->msg( 'centralauth-admin-action-lock-unlock' )->text(), |
205 | 'wpActionLock', |
206 | 'unlock', |
207 | 'centralauth-admin-action-lock-unlock', |
208 | false ) . |
209 | '<br />' . |
210 | Xml::radioLabel( |
211 | $this->msg( 'centralauth-admin-action-lock-lock' )->text(), |
212 | 'wpActionLock', |
213 | 'lock', |
214 | 'centralauth-admin-action-lock-lock', |
215 | false ); |
216 | |
217 | $radioHidden = |
218 | Xml::radioLabel( |
219 | $this->msg( 'centralauth-admin-action-hide-nochange' )->text(), |
220 | 'wpActionHide', |
221 | '-1', |
222 | 'mw-centralauth-status-hidden-nochange', |
223 | true ) . |
224 | '<br />'; |
225 | if ( $this->mCanSuppress ) { |
226 | $radioHidden .= Xml::radioLabel( |
227 | $this->msg( 'centralauth-admin-action-hide-none' )->text(), |
228 | 'wpActionHide', |
229 | (string)CentralAuthUser::HIDDEN_LEVEL_NONE, |
230 | 'mw-centralauth-status-hidden-no', |
231 | false ) . |
232 | '<br />' . |
233 | Xml::radioLabel( |
234 | $this->msg( 'centralauth-admin-action-hide-lists' )->text(), |
235 | 'wpActionHide', |
236 | (string)CentralAuthUser::HIDDEN_LEVEL_LISTS, |
237 | 'mw-centralauth-status-hidden-list', |
238 | false ) . |
239 | '<br />' . |
240 | Xml::radioLabel( |
241 | $this->msg( 'centralauth-admin-action-hide-oversight' )->text(), |
242 | 'wpActionHide', |
243 | (string)CentralAuthUser::HIDDEN_LEVEL_SUPPRESSED, |
244 | 'mw-centralauth-status-hidden-oversight', |
245 | false |
246 | ); |
247 | } |
248 | |
249 | $reasonList = Xml::listDropdown( |
250 | 'wpReasonList', |
251 | $this->msg( 'centralauth-admin-status-reasons' )->inContentLanguage()->text(), |
252 | $this->msg( 'centralauth-admin-reason-other-select' )->inContentLanguage()->text() |
253 | ); |
254 | $reasonField = Xml::input( 'wpReason', 45, false ); |
255 | $botField = Xml::check( 'markasbot' ) . |
256 | $this->msg( 'centralauth-admin-multi-botcheck' )->parse(); |
257 | |
258 | $form .= Xml::buildForm( |
259 | [ |
260 | 'centralauth-admin-status-locked' => $radioLocked, |
261 | 'centralauth-admin-status-hidden' => $radioHidden, |
262 | 'centralauth-admin-reason' => $reasonList, |
263 | 'centralauth-admin-reason-other' => $reasonField, |
264 | 'centralauth-admin-multi-bot' => $botField |
265 | ], |
266 | 'centralauth-admin-status-submit' |
267 | ); |
268 | |
269 | $searchlist = $this->mUserNames; |
270 | if ( is_array( $this->mUserNames ) ) { |
271 | $searchlist = implode( "\n", $this->mUserNames ); |
272 | } |
273 | $form .= Html::hidden( 'wpTarget', $searchlist ); |
274 | |
275 | $form .= '</fieldset></form>'; |
276 | |
277 | $this->getOutput()->addHTML( $form ); |
278 | } |
279 | |
280 | /** |
281 | * Start admin <form>, and start the table listing usernames to take action on |
282 | */ |
283 | private function showTableHeader() { |
284 | $out = $this->getOutput(); |
285 | |
286 | $header = Xml::openElement( |
287 | 'form', |
288 | [ |
289 | 'method' => 'POST', |
290 | 'action' => $this->getPageTitle()->getFullUrl() |
291 | ] |
292 | ); |
293 | |
294 | $header .= Xml::fieldset( $this->msg( 'centralauth-admin-status' )->text() ); |
295 | $header .= Html::hidden( 'wpMethod', 'set-status' ); |
296 | $header .= Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() ); |
297 | $header .= $this->msg( 'centralauth-admin-status-intro' )->parseAsBlock(); |
298 | |
299 | $header .= Xml::openElement( |
300 | 'table', |
301 | [ 'class' => 'wikitable sortable mw-centralauth-wikislist' ] |
302 | ); |
303 | |
304 | $header .= '<thead><tr>' . |
305 | '<th></th>' . |
306 | '<th>' . |
307 | $out->getContext()->msg( 'centralauth-admin-username' )->escaped() . |
308 | '</th>' . |
309 | '<th>' . |
310 | $out->getContext()->msg( 'centralauth-admin-info-registered' )->escaped() . |
311 | '</th>' . |
312 | '<th>' . |
313 | $out->getContext()->msg( 'centralauth-admin-info-locked' )->escaped() . |
314 | '</th>' . |
315 | '<th>' . |
316 | $out->getContext()->msg( 'centralauth-admin-info-hidden' )->escaped() . |
317 | '</th>' . |
318 | '<th>' . |
319 | $out->getContext()->msg( 'centralauth-admin-info-editcount' )->escaped() . |
320 | '</th>' . |
321 | '<th>' . |
322 | $out->getContext()->msg( 'centralauth-admin-info-attached' )->escaped() . |
323 | '</th>' . |
324 | '<th>' . |
325 | $out->getContext()->msg( 'centralauth-multilock-homewiki' )->escaped() . |
326 | '</th>' . |
327 | '</tr></thead>' . |
328 | '<tbody>'; |
329 | |
330 | $out->addHTML( $header ); |
331 | $out->addModuleStyles( 'jquery.tablesorter.styles' ); |
332 | $out->addModules( 'jquery.tablesorter' ); |
333 | } |
334 | |
335 | /** |
336 | * Build the table of users to lock and/or hide |
337 | */ |
338 | private function showUserTable() { |
339 | $this->mGlobalUsers = array_unique( |
340 | $this->getGlobalUsers( $this->mUserNames ), SORT_REGULAR |
341 | ); |
342 | |
343 | $out = $this->getOutput(); |
344 | |
345 | if ( count( $this->mGlobalUsers ) < 1 ) { |
346 | $this->showError( 'centralauth-admin-multi-notfound' ); |
347 | return; |
348 | } |
349 | |
350 | $this->showTableHeader(); |
351 | |
352 | foreach ( $this->mGlobalUsers as $globalUser ) { |
353 | $rowtext = Xml::openElement( 'tr' ); |
354 | |
355 | if ( $globalUser === false ) { |
356 | continue; |
357 | } elseif ( $globalUser instanceof CentralAuthUser ) { |
358 | $rowtext .= $this->getUserTableRow( $globalUser ); |
359 | } else { |
360 | $rowtext .= Html::rawElement( |
361 | 'td', |
362 | [ 'colspan' => 8 ], |
363 | $globalUser |
364 | ); |
365 | } |
366 | |
367 | $rowtext .= Xml::closeElement( 'tr' ); |
368 | $out->addHTML( $rowtext ); |
369 | } |
370 | |
371 | $out->addHTML( '</tbody></table>' ); |
372 | $this->showStatusForm(); |
373 | } |
374 | |
375 | /** |
376 | * @param CentralAuthUser $globalUser |
377 | * @return string |
378 | */ |
379 | private function getUserTableRow( CentralAuthUser $globalUser ) { |
380 | $rowHtml = ''; |
381 | |
382 | $guName = $globalUser->getName(); |
383 | $guLink = $this->getLinkRenderer()->makeLink( |
384 | SpecialPage::getTitleFor( 'CentralAuth', $guName ), |
385 | // Names are known to exist, so this is not really needed |
386 | $guName |
387 | ); |
388 | // formatHiddenLevel html escapes its output |
389 | $guHidden = $this->uiService->formatHiddenLevel( $this->getContext(), $globalUser->getHiddenLevelInt() ); |
390 | $accountAge = time() - (int)wfTimestamp( TS_UNIX, $globalUser->getRegistration() ); |
391 | $guRegister = $this->uiService->prettyTimespan( $this->getContext(), $accountAge ); |
392 | $guLocked = $this->msg( 'centralauth-admin-status-locked-no' )->text(); |
393 | if ( $globalUser->isLocked() ) { |
394 | $guLocked = $this->msg( 'centralauth-admin-status-locked-yes' )->text(); |
395 | } |
396 | $guEditCount = $this->getLanguage()->formatNum( $globalUser->getGlobalEditCount() ); |
397 | $guAttachedLocalAccounts = $this->getLanguage() |
398 | ->formatNum( count( $globalUser->listAttached() ) ); |
399 | $guHomeWiki = $globalUser->getHomeWiki() ?? ''; |
400 | |
401 | $rowHtml .= Html::rawElement( 'td', [], |
402 | Html::input( |
403 | 'wpActionTarget[' . $guName . ']', |
404 | $guName, |
405 | 'checkbox', |
406 | [ 'checked' => 'checked' ] |
407 | ) |
408 | ); |
409 | $rowHtml .= Html::rawElement( 'td', [], $guLink ); |
410 | $rowHtml .= Html::element( 'td', [ 'data-sort-value' => $accountAge ], $guRegister ); |
411 | $rowHtml .= Html::element( 'td', [], $guLocked ); |
412 | $rowHtml .= Html::rawElement( 'td', [], $guHidden ); |
413 | $rowHtml .= Html::element( 'td', [], $guEditCount ); |
414 | $rowHtml .= Html::element( 'td', [], $guAttachedLocalAccounts ); |
415 | $rowHtml .= Html::element( 'td', [], $guHomeWiki ); |
416 | |
417 | return $rowHtml; |
418 | } |
419 | |
420 | /** |
421 | * Lock and/or hide global users and log the activity (if any) |
422 | */ |
423 | private function setStatus() { |
424 | if ( !$this->getUser()->matchEditToken( $this->getRequest()->getVal( 'wpEditToken' ) ) ) { |
425 | $this->showError( 'centralauth-token-mismatch' ); |
426 | return; |
427 | } |
428 | |
429 | if ( $this->mActionHide !== -1 && !$this->mCanSuppress ) { |
430 | $this->showError( 'centralauth-admin-not-authorized' ); |
431 | return; |
432 | } |
433 | |
434 | $setLocked = null; |
435 | $setHidden = null; |
436 | |
437 | if ( $this->mActionLock != 'nochange' ) { |
438 | $setLocked = ( $this->mActionLock == 'lock' ); |
439 | } |
440 | |
441 | if ( $this->mActionHide !== -1 ) { |
442 | $setHidden = $this->mActionHide; |
443 | } |
444 | |
445 | foreach ( $this->mGlobalUsers as $globalUser ) { |
446 | if ( !$globalUser instanceof CentralAuthUser ) { |
447 | // Somehow the user submitted a bad user name |
448 | $this->showStatusError( $globalUser ); |
449 | continue; |
450 | } |
451 | |
452 | $status = $globalUser->adminLockHide( |
453 | $setLocked, |
454 | $setHidden, |
455 | $this->mReason, |
456 | $this->getContext(), |
457 | $this->getRequest()->getCheck( 'markasbot' ) |
458 | ); |
459 | |
460 | if ( !$status->isGood() ) { |
461 | $this->showStatusError( $status->getWikiText() ); |
462 | } elseif ( $status->successCount > 0 ) { |
463 | $this->showSuccess( 'centralauth-admin-setstatus-success', $globalUser->getName() ); |
464 | } |
465 | } |
466 | } |
467 | |
468 | /** |
469 | * @param string $wikitext |
470 | */ |
471 | private function showStatusError( $wikitext ) { |
472 | $out = $this->getOutput(); |
473 | $out->addHTML( |
474 | Html::errorBox( |
475 | $out->parseAsInterface( $wikitext ) |
476 | ) |
477 | ); |
478 | } |
479 | |
480 | /** |
481 | * @param string $key |
482 | * @param mixed ...$params |
483 | */ |
484 | private function showError( $key, ...$params ) { |
485 | $this->getOutput()->addHTML( Html::errorBox( $this->msg( $key, ...$params )->parse() ) ); |
486 | } |
487 | |
488 | /** |
489 | * @param string $key |
490 | * @param mixed ...$params |
491 | */ |
492 | private function showSuccess( $key, ...$params ) { |
493 | $this->getOutput()->addHTML( Html::successBox( $this->msg( $key, ...$params )->parse() ) ); |
494 | } |
495 | |
496 | private function showUsernameForm() { |
497 | if ( is_array( $this->mUserNames ) ) { |
498 | $this->mUserNames = implode( "\n", $this->mUserNames ); |
499 | } |
500 | |
501 | $form = Xml::tags( 'form', |
502 | [ |
503 | 'method' => 'post', |
504 | 'action' => $this->getPageTitle()->getLocalUrl() |
505 | ], |
506 | Xml::tags( 'fieldset', [], |
507 | Xml::element( 'legend', [], $this->msg( 'centralauth-admin-manage' )->text() ) . |
508 | Html::hidden( 'wpMethod', 'search' ) . |
509 | Xml::element( 'p', [], |
510 | $this->msg( 'centralauth-admin-multi-username' )->text() |
511 | ) . |
512 | Xml::textarea( 'wpTarget', |
513 | ( $this->mPrefixSearch ? '' : $this->mUserNames ), 25, 20 ) . |
514 | Xml::element( 'p', [], |
515 | $this->msg( 'centralauth-admin-multi-searchprefix' )->text() |
516 | ) . |
517 | Html::input( 'wpSearchTarget', $this->mPrefixSearch ) . |
518 | Xml::tags( 'p', [], |
519 | Xml::submitButton( $this->msg( 'centralauth-admin-lookup-ro' )->text() ) |
520 | ) |
521 | ) |
522 | ); |
523 | $this->getOutput()->addHTML( $form ); |
524 | } |
525 | |
526 | /** |
527 | * Show the last 50 log entries |
528 | */ |
529 | private function showLogExtract() { |
530 | $text = ''; |
531 | $numRows = LogEventsList::showLogExtract( |
532 | $text, |
533 | [ 'globalauth', 'suppress' ], |
534 | '', |
535 | '', |
536 | [ |
537 | 'conds' => [ |
538 | // T59253 |
539 | 'log_action' => 'setstatus' |
540 | ], |
541 | 'showIfEmpty' => true |
542 | ] ); |
543 | if ( $numRows ) { |
544 | $this->getOutput()->addHTML( |
545 | Xml::fieldset( $this->msg( 'centralauth-admin-logsnippet' )->text(), $text ) |
546 | ); |
547 | } |
548 | } |
549 | |
550 | /** @inheritDoc */ |
551 | protected function getGroupName() { |
552 | return 'users'; |
553 | } |
554 | } |