81 $activeUserDays = $this->
getConfig()->get( MainConfigNames::ActiveUserDays );
86 if ( $prop !==
null ) {
87 $prop = array_fill_keys( $prop,
true );
88 $fld_blockinfo = isset( $prop[
'blockinfo'] );
89 $fld_editcount = isset( $prop[
'editcount'] );
90 $fld_groups = isset( $prop[
'groups'] );
91 $fld_rights = isset( $prop[
'rights'] );
92 $fld_registration = isset( $prop[
'registration'] );
93 $fld_implicitgroups = isset( $prop[
'implicitgroups'] );
94 $fld_centralids = isset( $prop[
'centralids'] );
96 $fld_blockinfo = $fld_editcount = $fld_groups = $fld_registration =
97 $fld_rights = $fld_implicitgroups = $fld_centralids =
false;
104 $dir = (
$params[
'dir'] ==
'descending' ?
'older' :
'newer' );
105 $from =
$params[
'from'] ===
null ? null : $this->getCanonicalUserName(
$params[
'from'] );
106 $to =
$params[
'to'] ===
null ? null : $this->getCanonicalUserName(
$params[
'to'] );
108 # MySQL can't figure out that 'user_name' and 'qcc_title' are the same
109 # despite the JOIN condition, so manually sort on the correct one.
110 $userFieldToSort =
$params[
'activeusers'] ?
'qcc_title' :
'user_name';
112 # Some of these subtable joins are going to give us duplicate rows, so
113 # calculate the maximum number of duplicates we might see.
114 $maxDuplicateRows = 1;
118 if (
$params[
'prefix'] !==
null ) {
123 new LikeValue( $this->getCanonicalUserName(
$params[
'prefix'] ), $db->anyString() )
131 foreach (
$params[
'rights'] as $r ) {
135 $groups = array_merge(
137 $this->groupPermissionsLookup->getGroupsWithPermission( $r )
142 if ( $groups === [] ) {
149 $groups = array_unique( $groups );
150 if ( in_array(
'*', $groups,
true ) || in_array(
'user', $groups,
true ) ) {
155 if (
$params[
'group'] ===
null ) {
158 $params[
'group'] = array_unique( array_merge(
$params[
'group'], $groups ) );
167 $this->
addTables(
'user_groups',
'ug1' );
172 'ug1.ug_user=user_id',
173 'ug1.ug_group' =>
$params[
'group'],
174 $db->expr(
'ug1.ug_expiry',
'=',
null )->or(
'ug1.ug_expiry',
'>=', $db->timestamp() ),
178 $maxDuplicateRows *= count(
$params[
'group'] );
181 if (
$params[
'excludegroup'] !==
null && count(
$params[
'excludegroup'] ) ) {
184 $this->
addTables(
'user_groups',
'ug1' );
188 'ug1.ug_user=user_id',
189 $db->expr(
'ug1.ug_expiry',
'=',
null )->or(
'ug1.ug_expiry',
'>=', $db->timestamp() ),
190 'ug1.ug_group' =>
$params[
'excludegroup'],
193 $this->
addWhere( [
'ug1.ug_user' =>
null ] );
196 if (
$params[
'witheditsonly'] ) {
197 $this->
addWhere( $db->expr(
'user_editcount',
'>', 0 ) );
200 $this->addDeletedUserFilter();
202 if ( $fld_groups || $fld_rights ) {
204 $db->newSelectQueryBuilder()
205 ->table(
'user_groups' )
206 ->field(
'ug_group' )
209 $db->expr(
'ug_expiry',
'=',
null )->or(
'ug_expiry',
'>=', $db->timestamp() )
211 ->buildGroupConcatField(
'|' )
215 if (
$params[
'activeusers'] ) {
216 $activeUserSeconds = $activeUserDays * 86400;
223 'qcc_type' =>
'activeusers',
225 'qcc_title=user_name',
230 $timestamp = $db->timestamp( (
int)
wfTimestamp( TS_UNIX ) - $activeUserSeconds );
231 $subqueryBuilder = $db->newSelectQueryBuilder()
232 ->select(
'COUNT(*)' )
233 ->from(
'recentchanges' )
234 ->join(
'actor',
null,
'rc_actor = actor_id' )
236 'actor_user = user_id',
238 $db->expr(
'rc_log_type',
'=',
null )
239 ->or(
'rc_log_type',
'!=',
'newusers' ),
240 $db->expr(
'rc_timestamp',
'>=', $timestamp ),
243 'recentactions' =>
'(' . $subqueryBuilder->caller( __METHOD__ )->getSQL() .
')'
247 $sqlLimit = $limit + $maxDuplicateRows;
254 $this->
addFieldsIf(
'user_editcount', $fld_editcount );
255 $this->
addFieldsIf(
'user_registration', $fld_registration );
257 $res = $this->
select( __METHOD__ );
259 $countDuplicates = 0;
262 $blockInfos = $fld_blockinfo ? $this->getBlockDetailsForRows( $res ) :
null;
263 foreach ( $res as $row ) {
266 if ( $lastUser === $row->user_name ) {
271 if ( $countDuplicates == $maxDuplicateRows ) {
277 $countDuplicates = 0;
278 $lastUser = $row->user_name;
280 if ( $count > $limit ) {
287 if ( $count == $sqlLimit ) {
294 if (
$params[
'activeusers'] && (
int)$row->recentactions === 0 ) {
300 'userid' => (int)$row->user_id,
301 'name' => $row->user_name,
304 if ( $fld_centralids ) {
306 $this->
getConfig(), $this->userFactory->newFromId( (
int)$row->user_id ),
$params[
'attachedwiki']
310 if ( $fld_blockinfo && isset( $blockInfos[$row->user_id] ) ) {
311 $data += $blockInfos[$row->user_id];
313 if ( $row->hu_deleted ) {
314 $data[
'hidden'] =
true;
316 if ( $fld_editcount ) {
317 $data[
'editcount'] = (int)$row->user_editcount;
319 if (
$params[
'activeusers'] ) {
320 $data[
'recentactions'] = (int)$row->recentactions;
322 if ( $fld_registration ) {
323 $data[
'registration'] = $row->user_registration ?
324 wfTimestamp( TS_ISO_8601, $row->user_registration ) :
'';
327 if ( $fld_implicitgroups || $fld_groups || $fld_rights ) {
328 $implicitGroups = $this->userGroupManager
329 ->getUserImplicitGroups( $this->userFactory->newFromId( (
int)$row->user_id ) );
330 if ( isset( $row->groups ) && $row->groups !==
'' ) {
331 $groups = array_merge( $implicitGroups, explode(
'|', $row->groups ) );
333 $groups = $implicitGroups;
337 $data[
'groups'] = $groups;
338 ApiResult::setIndexedTagName( $data[
'groups'],
'g' );
339 ApiResult::setArrayType( $data[
'groups'],
'array' );
342 if ( $fld_implicitgroups ) {
343 $data[
'implicitgroups'] = $implicitGroups;
344 ApiResult::setIndexedTagName( $data[
'implicitgroups'],
'g' );
345 ApiResult::setArrayType( $data[
'implicitgroups'],
'array' );
349 $user = $this->userFactory->newFromId( (
int)$row->user_id );
351 ApiResult::setIndexedTagName( $data[
'rights'],
'r' );
352 ApiResult::setArrayType( $data[
'rights'],
'array' );
356 $fit = $result->addValue( [
'query', $this->
getModuleName() ],
null, $data );
363 $result->addIndexedTagName( [
'query', $this->
getModuleName() ],
'u' );
371 $userGroups = $this->userGroupManager->listAllGroups();
382 ParamValidator::PARAM_DEFAULT =>
'ascending',
383 ParamValidator::PARAM_TYPE => [
389 ParamValidator::PARAM_TYPE => $userGroups,
390 ParamValidator::PARAM_ISMULTI =>
true,
393 ParamValidator::PARAM_TYPE => $userGroups,
394 ParamValidator::PARAM_ISMULTI =>
true,
397 ParamValidator::PARAM_TYPE => array_unique( array_merge(
401 ParamValidator::PARAM_ISMULTI =>
true,
404 ParamValidator::PARAM_ISMULTI =>
true,
405 ParamValidator::PARAM_TYPE => [
417 ParamValidator::PARAM_DEFAULT => 10,
418 ParamValidator::PARAM_TYPE =>
'limit',
419 IntegerDef::PARAM_MIN => 1,
423 'witheditsonly' =>
false,
425 ParamValidator::PARAM_DEFAULT =>
false,
427 'apihelp-query+allusers-param-activeusers',
428 $this->
getConfig()->get( MainConfigNames::ActiveUserDays )
431 'attachedwiki' =>
null,