26use Wikimedia\Timestamp\ConvertibleTimestamp;
27use Wikimedia\Timestamp\TimestampFormat as TS;
51 private $blockStatusByUid;
57 private $excludegroups;
85 $this->requestedUser =
'';
89 $username = Title::makeTitleSafe(
NS_USER, $un );
90 if ( $username !==
null ) {
91 $this->requestedUser = $username->getText();
99 $this->excludegroups[] =
'bot';
102 $this->excludegroups[] =
'sysop';
116 $timestamp = $dbr->timestamp( (
int)ConvertibleTimestamp::now( TS::UNIX ) - $activeUserSeconds );
120 $subquery = $dbr->newSelectQueryBuilder()
121 ->select( [
'qcc_title',
'user_id',
'actor_id' ] )
122 ->from(
'querycachetwo' )
123 ->join(
'user',
null,
'user_name = qcc_title' )
124 ->join(
'actor',
null,
'actor_user = user_id' )
126 'qcc_type' =>
'activeusers',
130 if ( $data !==
null ) {
132 ->orderBy(
'qcc_title', $data[
'order'] )
133 ->limit( $data[
'limit'] )
134 ->andWhere( $data[
'conds'] );
136 if ( $this->requestedUser !=
'' ) {
137 $subquery->andWhere( $dbr->expr(
'qcc_title',
'>=', $this->requestedUser ) );
139 if ( $this->groups !== [] ) {
141 ->join(
'user_groups',
'ug1',
'ug1.ug_user = user_id' )
143 'ug1.ug_group' => $this->groups,
144 $dbr->expr(
'ug1.ug_expiry',
'=',
null )->or(
'ug1.ug_expiry',
'>=', $dbr->timestamp() ),
147 if ( $this->excludegroups !== [] ) {
149 ->leftJoin(
'user_groups',
'ug2', [
150 'ug2.ug_user = user_id',
151 'ug2.ug_group' => $this->excludegroups,
152 $dbr->expr(
'ug2.ug_expiry',
'=',
null )->or(
'ug2.ug_expiry',
'>=', $dbr->timestamp() ),
154 ->andWhere( [
'ug2.ug_user' =>
null ] );
157 $subquery->andWhere( $this->hideUserUtils->getExpression( $dbr ) );
162 'tables' => [
'qcc_users' =>
new Subquery( $subquery->getSQL() ),
'recentchanges' ],
165 'user_name' =>
'qcc_title',
166 'user_id' =>
'user_id',
167 'recentedits' =>
'COUNT(DISTINCT rc_id)'
169 'options' => [
'GROUP BY' => [
'qcc_title',
'user_id' ] ],
171 'join_conds' => [
'recentchanges' => [
'LEFT JOIN', [
172 'rc_actor = actor_id',
173 $dbr->expr(
'rc_source',
'=', $this->recentChangeLookup->getPrimarySources() ),
174 $dbr->expr(
'rc_log_type',
'=',
null )->or(
'rc_log_type',
'!=',
'newusers' ),
175 $dbr->expr(
'rc_timestamp',
'>=', $timestamp ),
185 if ( $order === self::QUERY_ASCENDING ) {
187 $orderBy = $sortColumns;
188 $operator = $this->mIncludeOffset ?
'>=' :
'>';
192 foreach ( $sortColumns as $col ) {
193 $orderBy[] = $col .
' DESC';
195 $operator = $this->mIncludeOffset ?
'<=' :
'<';
198 'limit' => intval( $limit ),
201 $offset !=
'' ? [ $this->
getDatabase()->expr( $this->mIndexField, $operator, $offset ) ] : [],
204 $tables = $info[
'tables'];
205 $fields = $info[
'fields'];
206 $conds = $info[
'conds'];
207 $options = $info[
'options'];
208 $join_conds = $info[
'join_conds'];
209 $options[
'ORDER BY'] = $orderBy;
210 return [ $tables, $fields, $conds, $fname, $options, $join_conds ];
214 parent::doBatchLookups();
217 foreach ( $this->mResult as $row ) {
218 $uids[] = (int)$row->user_id;
225 $blockedUsers = $dbr->newSelectQueryBuilder()
228 'sitewide' =>
'MAX(bl_sitewide)'
230 ->from(
'block_target' )
231 ->join(
'block',
null,
'bl_target=bt_id' )
234 $dbr->expr(
'bl_expiry',
'>=', $dbr->timestamp() ),
236 ->groupBy( [
'bt_user' ] )
237 ->caller( __METHOD__ )
240 $hiddenUsers = $dbr->newSelectQueryBuilder()
241 ->select(
'bt_user' )
242 ->from(
'block_target' )
243 ->join(
'block',
null,
'bl_target=bt_id' )
247 $dbr->expr(
'bl_expiry',
'>=', $dbr->timestamp() ),
249 ->groupBy(
'bt_user' )
250 ->caller( __METHOD__ )
251 ->fetchFieldValues();
253 $this->blockStatusByUid = [];
254 foreach ( $blockedUsers as $row ) {
255 $this->blockStatusByUid[$row->bt_user] = [
256 'deleted' => in_array( $row->bt_user, $hiddenUsers,
true ),
257 'sitewide' => $row->sitewide,
260 $this->mResult->seek( 0 );
265 $userName = $row->user_name;
267 $ulinks = Linker::userLink( $row->user_id, $userName );
268 $ulinks .= Linker::userToolLinks(
287 foreach ( $ugms as $ugm ) {
291 $groups = $lang->commaList( $list );
293 $item = $lang->specialList( $ulinks,
$groups );
298 $isBlocked = isset( $this->blockStatusByUid[$row->user_id] );
300 if ( $this->blockStatusByUid[$row->user_id][
'deleted'] == 1 ) {
301 $item =
"<span class=\"deleted\">$item</span>";
303 if ( $this->blockStatusByUid[$row->user_id][
'sitewide'] == 1 ) {
304 $blocked =
' ' . $this->
msg(
'listusers-blocked', $userName )->escaped();
307 $count = $this->
msg(
'activeusers-count' )->numParams( $row->recentedits )
308 ->params( $userName )->numParams( $this->RCMaxAge )->escaped();
310 return Html::rawElement(
'li', [],
"{$item} [{$count}]{$blocked}" );
319class_alias( ActiveUsersPager::class,
'ActiveUsersPager' );
322class_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.