1<?php 2/** 3 * Implements Special:Activeusers 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 * @ingroup SpecialPage 22 */ 23 24/** 25 * Implements Special:Activeusers 26 * 27 * @ingroup SpecialPage 28 */ 29class SpecialActiveUsers extends SpecialPage { 30 31 public function __construct() { 32 parent::__construct( 'Activeusers' ); 33 } 34 35 /** 36 * @param string|null $par Parameter passed to the page or null 37 */ 38 public function execute( $par ) { 39 $out = $this->getOutput(); 40 41 $this->setHeaders(); 42 $this->outputHeader(); 43 44 $opts = new FormOptions(); 45 46 $opts->add( 'username', '' ); 47 $opts->add( 'groups', [] ); 48 $opts->add( 'excludegroups', [] ); 49 // Backwards-compatibility with old URLs 50 $opts->add( 'hidebots', false, FormOptions::BOOL ); 51 $opts->add( 'hidesysops', false, FormOptions::BOOL ); 52 53 $opts->fetchValuesFromRequest( $this->getRequest() ); 54 55 if ( $par !== null ) { 56 $opts->setValue( 'username', $par ); 57 } 58 59 $pager = new ActiveUsersPager( $this->getContext(), $opts ); 60 $usersBody = $pager->getBody(); 61 62 $this->buildForm(); 63 64 if ( $usersBody ) { 65 $out->addHTML( 66 $pager->getNavigationBar() . 67 Html::rawElement( 'ul', [], $usersBody ) . 68 $pager->getNavigationBar() 69 ); 70 $out->addModuleStyles( 'mediawiki.interface.helpers.styles' ); 71 } else { 72 $out->addWikiMsg( 'activeusers-noresult' ); 73 } 74 } 75 76 /** 77 * Generate and output the form 78 */ 79 protected function buildForm() { 80 $groups = User::getAllGroups(); 81 82 $options = []; 83 foreach ( $groups as $group ) { 84 $msg = htmlspecialchars( UserGroupMembership::getGroupName( $group ) ); 85 $options[$msg] = $group; 86 } 87 ksort( $options ); 88 89 // Backwards-compatibility with old URLs 90 $req = $this->getRequest(); 91 $excludeDefault = []; 92 if ( $req->getCheck( 'hidebots' ) ) { 93 $excludeDefault[] = 'bot'; 94 } 95 if ( $req->getCheck( 'hidesysops' ) ) { 96 $excludeDefault[] = 'sysop'; 97 } 98 99 $formDescriptor = [ 100 'username' => [ 101 'type' => 'user', 102 'name' => 'username', 103 'label-message' => 'activeusers-from', 104 ], 105 'groups' => [ 106 'type' => 'multiselect', 107 'dropdown' => true, 108 'flatlist' => true, 109 'name' => 'groups', 110 'label-message' => 'activeusers-groups', 111 'options' => $options, 112 ], 113 'excludegroups' => [ 114 'type' => 'multiselect', 115 'dropdown' => true, 116 'flatlist' => true, 117 'name' => 'excludegroups', 118 'label-message' => 'activeusers-excludegroups', 119 'options' => $options, 120 'default' => $excludeDefault, 121 ], 122 ]; 123 124 HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() ) 125 // For the 'multiselect' field values to be preserved on submit 126 ->setFormIdentifier( 'specialactiveusers' ) 127 ->setIntro( $this->getIntroText() ) 128 ->setWrapperLegendMsg( 'activeusers' ) 129 ->setSubmitTextMsg( 'activeusers-submit' ) 130 // prevent setting subpage and 'username' parameter at the same time 131 ->setAction( $this->getPageTitle()->getLocalURL() ) 132 ->setMethod( 'get' ) 133 ->prepareForm() 134 ->displayForm( false ); 135 } 136 137 /** 138 * Return introductory message. 139 * @return string 140 */ 141 protected function getIntroText() { 142 $days = $this->getConfig()->get( 'ActiveUserDays' ); 143 144 $intro = $this->msg( 'activeusers-intro' )->numParams( $days )->parse(); 145 146 // Mention the level of cache staleness... 147 $dbr = wfGetDB( DB_REPLICA, 'recentchanges' ); 148 $rcMax = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)', '', __METHOD__ ); 149 if ( $rcMax ) { 150 $cTime = $dbr->selectField( 'querycache_info', 151 'qci_timestamp', 152 [ 'qci_type' => 'activeusers' ], 153 __METHOD__ 154 ); 155 if ( $cTime ) { 156 $secondsOld = wfTimestamp( TS_UNIX, $rcMax ) - wfTimestamp( TS_UNIX, $cTime ); 157 } else { 158 $rcMin = $dbr->selectField( 'recentchanges', 'MIN(rc_timestamp)', '', __METHOD__ ); 159 $secondsOld = time() - wfTimestamp( TS_UNIX, $rcMin ); 160 } 161 if ( $secondsOld > 0 ) { 162 $intro .= $this->msg( 'cachedspecial-viewing-cached-ttl' ) 163 ->durationParams( $secondsOld )->parseAsBlock(); 164 } 165 } 166 167 return $intro; 168 } 169 170 protected function getGroupName() { 171 return 'users'; 172 } 173} 174