26use Wikimedia\Timestamp\ConvertibleTimestamp;
27use Wikimedia\Timestamp\TimestampFormat as TS;
52 private $blockStatusByUid;
58 private $excludegroups;
85 $this->recentChangeLookup = $recentChangeLookup;
87 $this->requestedUser =
'';
91 $username = Title::makeTitleSafe(
NS_USER, $un );
92 if ( $username !==
null ) {
93 $this->requestedUser = $username->getText();
101 $this->excludegroups[] =
'bot';
104 $this->excludegroups[] =
'sysop';
118 $timestamp = $dbr->timestamp( (
int)ConvertibleTimestamp::now( TS::UNIX ) - $activeUserSeconds );
122 $subquery = $dbr->newSelectQueryBuilder()
123 ->select( [
'qcc_title',
'user_id',
'actor_id' ] )
124 ->from(
'querycachetwo' )
125 ->join(
'user',
null,
'user_name = qcc_title' )
126 ->join(
'actor',
null,
'actor_user = user_id' )
128 'qcc_type' =>
'activeusers',
132 if ( $data !==
null ) {
134 ->orderBy(
'qcc_title', $data[
'order'] )
135 ->limit( $data[
'limit'] )
136 ->andWhere( $data[
'conds'] );
138 if ( $this->requestedUser !=
'' ) {
139 $subquery->andWhere( $dbr->expr(
'qcc_title',
'>=', $this->requestedUser ) );
141 if ( $this->groups !== [] ) {
143 ->join(
'user_groups',
'ug1',
'ug1.ug_user = user_id' )
145 'ug1.ug_group' => $this->groups,
146 $dbr->expr(
'ug1.ug_expiry',
'=',
null )->or(
'ug1.ug_expiry',
'>=', $dbr->timestamp() ),
149 if ( $this->excludegroups !== [] ) {
151 ->leftJoin(
'user_groups',
'ug2', [
152 'ug2.ug_user = user_id',
153 'ug2.ug_group' => $this->excludegroups,
154 $dbr->expr(
'ug2.ug_expiry',
'=',
null )->or(
'ug2.ug_expiry',
'>=', $dbr->timestamp() ),
156 ->andWhere( [
'ug2.ug_user' =>
null ] );
159 $subquery->andWhere( $this->hideUserUtils->getExpression( $dbr ) );
164 'tables' => [
'qcc_users' =>
new Subquery( $subquery->getSQL() ),
'recentchanges' ],
167 'user_name' =>
'qcc_title',
168 'user_id' =>
'user_id',
169 'recentedits' =>
'COUNT(DISTINCT rc_id)'
171 'options' => [
'GROUP BY' => [
'qcc_title',
'user_id' ] ],
173 'join_conds' => [
'recentchanges' => [
'LEFT JOIN', [
174 'rc_actor = actor_id',
175 $dbr->expr(
'rc_source',
'=', $this->recentChangeLookup->getPrimarySources() ),
176 $dbr->expr(
'rc_log_type',
'=',
null )->or(
'rc_log_type',
'!=',
'newusers' ),
177 $dbr->expr(
'rc_timestamp',
'>=', $timestamp ),
187 if ( $order === self::QUERY_ASCENDING ) {
189 $orderBy = $sortColumns;
190 $operator = $this->mIncludeOffset ?
'>=' :
'>';
194 foreach ( $sortColumns as $col ) {
195 $orderBy[] = $col .
' DESC';
197 $operator = $this->mIncludeOffset ?
'<=' :
'<';
200 'limit' => intval( $limit ),
203 $offset !=
'' ? [ $this->
getDatabase()->expr( $this->mIndexField, $operator, $offset ) ] : [],
206 $tables = $info[
'tables'];
207 $fields = $info[
'fields'];
208 $conds = $info[
'conds'];
209 $options = $info[
'options'];
210 $join_conds = $info[
'join_conds'];
211 $options[
'ORDER BY'] = $orderBy;
212 return [ $tables, $fields, $conds, $fname, $options, $join_conds ];
216 parent::doBatchLookups();
219 foreach ( $this->mResult as $row ) {
220 $uids[] = (int)$row->user_id;
227 $res = $dbr->newSelectQueryBuilder()
230 'deleted' =>
'MAX(bl_deleted)',
231 'sitewide' =>
'MAX(bl_sitewide)'
233 ->from(
'block_target' )
234 ->join(
'block',
null,
'bl_target=bt_id' )
237 $dbr->expr(
'bl_expiry',
'>=', $dbr->timestamp() ),
239 ->groupBy( [
'bt_user' ] )
240 ->caller( __METHOD__ )->fetchResultSet();
241 $this->blockStatusByUid = [];
242 foreach ( $res as $row ) {
243 $this->blockStatusByUid[$row->bt_user] = [
244 'deleted' => $row->deleted,
245 'sitewide' => $row->sitewide,
248 $this->mResult->seek( 0 );
253 $userName = $row->user_name;
255 $ulinks = Linker::userLink( $row->user_id, $userName );
256 $ulinks .= Linker::userToolLinks(
275 foreach ( $ugms as $ugm ) {
279 $groups = $lang->commaList( $list );
281 $item = $lang->specialList( $ulinks,
$groups );
286 $isBlocked = isset( $this->blockStatusByUid[$row->user_id] );
288 if ( $this->blockStatusByUid[$row->user_id][
'deleted'] == 1 ) {
289 $item =
"<span class=\"deleted\">$item</span>";
291 if ( $this->blockStatusByUid[$row->user_id][
'sitewide'] == 1 ) {
292 $blocked =
' ' . $this->
msg(
'listusers-blocked', $userName )->escaped();
295 $count = $this->
msg(
'activeusers-count' )->numParams( $row->recentedits )
296 ->params( $userName )->numParams( $this->RCMaxAge )->escaped();
298 return Html::rawElement(
'li', [],
"{$item} [{$count}]{$blocked}" );
307class_alias( ActiveUsersPager::class,
'ActiveUsersPager' );
310class_alias( ActiveUsersPager::class,
'MediaWiki\\Pager\\ActiveUsersPager' );
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
A class containing constants representing the names of configuration variables.
const ActiveUserDays
Name constant for the ActiveUserDays setting, for use with Config::get()
Factory for LinkBatch objects to batch query page metadata.
Interface for objects which can provide a MediaWiki context on request.