$opts->add( 'categories_any', false );
$opts->add( 'tagfilter', '' );
+ $opts->add( 'userExpLevel', 'all' );
+
return $opts;
}
$opts['tagfilter']
);
+ $this->filterOnUserExperienceLevel( $tables, $conds, $join_conds, $opts );
+
if ( !$this->runMainQueryHook( $tables, $fields, $conds, $query_options, $join_conds,
$opts )
) {
return 60 * 5;
}
+ function filterOnUserExperienceLevel( &$tables, &$conds, &$join_conds, $opts ) {
+ global $wgLearnerEdits,
+ $wgExperiencedUserEdits,
+ $wgLearnerMemberSince,
+ $wgExperiencedUserMemberSince;
+
+ $selectedExpLevels = explode( ',', strtolower( $opts['userExpLevel'] ) );
+ // remove values that are not recognized
+ $selectedExpLevels = array_intersect(
+ $selectedExpLevels,
+ [ 'newcomer', 'learner', 'experienced' ]
+ );
+ sort( $selectedExpLevels );
+
+ if ( $selectedExpLevels ) {
+ $tables[] = 'user';
+ $join_conds['user'] = [ 'LEFT JOIN', 'rc_user = user_id' ];
+
+ $now = time();
+ $secondsPerDay = 86400;
+ $learnerCutoff = $now - $wgLearnerMemberSince * $secondsPerDay;
+ $experiencedUserCutoff = $now - $wgExperiencedUserMemberSince * $secondsPerDay;
+
+ $aboveNewcomer = $this->getDB()->makeList(
+ [
+ 'user_editcount >= ' . intval( $wgLearnerEdits ),
+ 'user_registration <= ' . $this->getDB()->timestamp( $learnerCutoff ),
+ ],
+ IDatabase::LIST_AND
+ );
+
+ $aboveLearner = $this->getDB()->makeList(
+ [
+ 'user_editcount >= ' . intval( $wgExperiencedUserEdits ),
+ 'user_registration <= ' . $this->getDB()->timestamp( $experiencedUserCutoff ),
+ ],
+ IDatabase::LIST_AND
+ );
+
+ if ( $selectedExpLevels === [ 'newcomer' ] ) {
+ $conds[] = "NOT ( $aboveNewcomer )";
+ } elseif ( $selectedExpLevels === [ 'learner' ] ) {
+ $conds[] = $this->getDB()->makeList(
+ [ $aboveNewcomer, "NOT ( $aboveLearner )" ],
+ IDatabase::LIST_AND
+ );
+ } elseif ( $selectedExpLevels === [ 'experienced' ] ) {
+ $conds[] = $aboveLearner;
+ } elseif ( $selectedExpLevels === [ 'learner', 'newcomer' ] ) {
+ $conds[] = "NOT ( $aboveLearner )";
+ } elseif ( $selectedExpLevels === [ 'experienced', 'newcomer' ] ) {
+ $conds[] = $this->getDB()->makeList(
+ [ "NOT ( $aboveNewcomer )", $aboveLearner ],
+ IDatabase::LIST_OR
+ );
+ } elseif ( $selectedExpLevels === [ 'experienced', 'learner' ] ) {
+ $conds[] = $aboveNewcomer;
+ }
+ }
+ }
+
}
$user
);
}
+
+ public function testFilterUserExpLevel() {
+ $this->setMwGlobals( [
+ 'wgLearnerEdits' => 10,
+ 'wgLearnerMemberSince' => 4,
+ 'wgExperiencedUserEdits' => 500,
+ 'wgExperiencedUserMemberSince' => 30,
+ ] );
+
+ $this->createUsers( [
+ 'Newcomer1' => [ 'edits' => 2, 'days' => 2 ],
+ 'Newcomer2' => [ 'edits' => 12, 'days' => 3 ],
+ 'Newcomer3' => [ 'edits' => 8, 'days' => 5 ],
+ 'Learner1' => [ 'edits' => 15, 'days' => 10 ],
+ 'Learner2' => [ 'edits' => 450, 'days' => 20 ],
+ 'Learner3' => [ 'edits' => 460, 'days' => 33 ],
+ 'Learner4' => [ 'edits' => 525, 'days' => 28 ],
+ 'Experienced1' => [ 'edits' => 538, 'days' => 33 ],
+ ] );
+
+ // newcomers only
+ $this->assertArrayEquals(
+ [ 'Newcomer1', 'Newcomer2', 'Newcomer3' ],
+ $this->fetchUsers( [ 'userExpLevel' => 'newcomer' ] )
+ );
+
+ // newcomers and learner
+ $this->assertArrayEquals(
+ [
+ 'Newcomer1', 'Newcomer2', 'Newcomer3',
+ 'Learner1', 'Learner2', 'Learner3', 'Learner4',
+ ],
+ $this->fetchUsers( [ 'userExpLevel' => 'newcomer,learner' ] )
+ );
+
+ // newcomers and more learner
+ $this->assertArrayEquals(
+ [
+ 'Newcomer1', 'Newcomer2', 'Newcomer3',
+ 'Experienced1',
+ ],
+ $this->fetchUsers( [ 'userExpLevel' => 'newcomer,experienced' ] )
+ );
+
+ // learner only
+ $this->assertArrayEquals(
+ [ 'Learner1', 'Learner2', 'Learner3', 'Learner4' ],
+ $this->fetchUsers( [ 'userExpLevel' => 'learner' ] )
+ );
+
+ // more experienced only
+ $this->assertArrayEquals(
+ [ 'Experienced1' ],
+ $this->fetchUsers( [ 'userExpLevel' => 'experienced' ] )
+ );
+
+ // learner and more experienced
+ $this->assertArrayEquals(
+ [
+ 'Learner1', 'Learner2', 'Learner3', 'Learner4',
+ 'Experienced1',
+ ],
+ $this->fetchUsers( [ 'userExpLevel' => 'learner,experienced' ] )
+ );
+
+ // newcomers, learner, and more experienced
+ $this->assertArrayEquals(
+ [
+ 'Newcomer1', 'Newcomer2', 'Newcomer3',
+ 'Learner1', 'Learner2', 'Learner3', 'Learner4',
+ 'Experienced1',
+ ],
+ $this->fetchUsers( [ 'userExpLevel' => 'newcomer,learner,experienced' ] )
+ );
+
+ // 'all'
+ $this->assertArrayEquals(
+ [
+ 'Newcomer1', 'Newcomer2', 'Newcomer3',
+ 'Learner1', 'Learner2', 'Learner3', 'Learner4',
+ 'Experienced1',
+ ],
+ $this->fetchUsers( [ 'userExpLevel' => 'all' ] )
+ );
+ }
+
+ private function createUsers( $specs ) {
+ $dbw = wfGetDB( DB_MASTER );
+ foreach ( $specs as $name => $spec ) {
+ User::createNew(
+ $name,
+ [
+ 'editcount' => $spec['edits'],
+ 'registration' => $dbw->timestamp( $this->daysAgo( $spec['days'] ) ),
+ 'email' => 'ut',
+ ]
+ );
+ }
+ }
+
+ private function fetchUsers( $filters ) {
+ $specialRC = new SpecialRecentChanges();
+
+ $tables = [];
+ $conds = [];
+ $join_conds = [];
+
+ $specialRC->filterOnUserExperienceLevel(
+ $tables,
+ $conds,
+ $join_conds,
+ $filters
+ );
+
+ $result = wfGetDB( DB_MASTER )->select(
+ 'user',
+ 'user_name',
+ array_filter( $conds ) + [ 'user_email' => 'ut' ]
+ );
+
+ $usernames = [];
+ foreach ( $result as $row ) {
+ $usernames[] = $row->user_name;
+ }
+
+ return $usernames;
+ }
+
+ private function daysAgo( $days ) {
+ $secondsPerDay = 86400;
+ return time() - $days * $secondsPerDay;
+ }
}