Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85f1c49728 | ||
|
|
eb06751a3d | ||
|
|
c68ced7f7e | ||
|
|
4906174274 |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": [
|
||||
"wikimedia/client",
|
||||
"wikimedia/client-es5",
|
||||
"wikimedia/jquery",
|
||||
"wikimedia/mediawiki"
|
||||
]
|
||||
|
||||
@@ -268,17 +268,12 @@ $specialPageAliases['uk'] = [
|
||||
'ContributionScores' => [ 'Очки_внеску', 'Очки_вклада' ],
|
||||
];
|
||||
|
||||
/** Chinese (中文) */
|
||||
$specialPageAliases['zh'] = [
|
||||
'ContributionScores' => [ 'ContributionScores' ],
|
||||
];
|
||||
|
||||
/** Simplified Chinese (中文(简体)) */
|
||||
/** Simplified Chinese (中文(简体)) */
|
||||
$specialPageAliases['zh-hans'] = [
|
||||
'ContributionScores' => [ '贡献得分' ],
|
||||
];
|
||||
|
||||
/** Traditional Chinese (中文(繁體)) */
|
||||
/** Traditional Chinese (中文(繁體)) */
|
||||
$specialPageAliases['zh-hant'] = [
|
||||
'ContributionScores' => [ '貢獻分數' ],
|
||||
];
|
||||
|
||||
16
ContributionScores.php
Normal file
16
ContributionScores.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
if ( function_exists( 'wfLoadExtension' ) ) {
|
||||
wfLoadExtension( 'ContributionScores' );
|
||||
// Keep i18n globals so mergeMessageFileList.php doesn't break
|
||||
$wgMessageDirs['ContributionScores'] = __DIR__ . '/i18n';
|
||||
$wgExtensionMessagesFiles['ContributionScoresAlias'] = __DIR__ . '/ContributionScores.alias.php';
|
||||
$wgExtensionMessagesFiles['ContributionScoresMagic'] = __DIR__ . '/ContributionScores.i18n.magic.php';
|
||||
wfWarn(
|
||||
'Deprecated PHP entry point used for ContributionScores extension. ' .
|
||||
'Please use wfLoadExtension instead, ' .
|
||||
'see https://www.mediawiki.org/wiki/Extension_registration for more details.'
|
||||
);
|
||||
} else {
|
||||
die( 'This version of the ContributionScores extension requires MediaWiki 1.29+' );
|
||||
}
|
||||
26
README
26
README
@@ -1,28 +1,2 @@
|
||||
The Contribution Scores extension polls the wiki database to locate contributors with the highest contribution volume.
|
||||
The extension is intended to add a fun metric for contributors to see how much they are helping out.
|
||||
|
||||
--- TEAR HERE ---
|
||||
|
||||
This is a modified version of Extension:Contribution Scores, the original source
|
||||
code for which can be found here: https://www.mediawiki.org/wiki/Extension:Contribution_Scores
|
||||
The rest of this document discussed changes made to this copy of the extension.
|
||||
|
||||
This fork developed by Eunakria the config option $wgContribScoreIgnoreMinorEdits,
|
||||
which is mutually exclusive with $wgContribScoreUseRoughEditCount.
|
||||
|
||||
In addition to providing the aforementioned bug fixes, this fork also fixes two
|
||||
other unwanted behaviors exhibited by the original extension:
|
||||
|
||||
1. When $wgContribScoreUseRoughEditCount was enabled, the extension would query
|
||||
the user_editcount field of the user table but not actually join on the user
|
||||
table, in the parser function {{#cscore}}. This was presumably never noticed
|
||||
since this parser function is not frequently used.
|
||||
|
||||
2. On some databases, there was a potential for integer underflow when
|
||||
subtracting unsigned values in both the parser function and contribution
|
||||
score data. This could occur if $wgContribScoreUseRoughEditCount was enabled
|
||||
and edits went uncounted in user_editcount, and was resolved by clamping the
|
||||
right-hand side preimage of subtraction.
|
||||
|
||||
There are probably more bugs I don't know about, both in the original upstream
|
||||
code *and* my code! In other words, caveat emptor.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"require-dev": {
|
||||
"mediawiki/mediawiki-codesniffer": "51.0.0",
|
||||
"mediawiki/minus-x": "2.0.1",
|
||||
"php-parallel-lint/php-console-highlighter": "1.0.0",
|
||||
"php-parallel-lint/php-parallel-lint": "1.4.0"
|
||||
"mediawiki/mediawiki-codesniffer": "37.0.0",
|
||||
"mediawiki/minus-x": "1.1.1",
|
||||
"php-parallel-lint/php-console-highlighter": "0.5.0",
|
||||
"php-parallel-lint/php-parallel-lint": "1.3.0"
|
||||
},
|
||||
"scripts": {
|
||||
"fix": [
|
||||
@@ -16,10 +16,5 @@
|
||||
"minus-x check ."
|
||||
],
|
||||
"phpcs": "phpcs -sp --cache"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "ContributionScores",
|
||||
"author": "Tim Laqua (modified by Eunakria)",
|
||||
"url": "https://git.eunakria.com/Eunakria/mediawiki-extensions-ContributionScores",
|
||||
"author": "Tim Laqua",
|
||||
"url": "https://www.mediawiki.org/wiki/Extension:Contribution_Scores",
|
||||
"descriptionmsg": "contributionscores-desc",
|
||||
"version": "1.26.1",
|
||||
"version": "1.26.0",
|
||||
"type": "specialpage",
|
||||
"requires": {
|
||||
"MediaWiki": ">= 1.40.0"
|
||||
"MediaWiki": ">= 1.34.0"
|
||||
},
|
||||
"SpecialPages": {
|
||||
"ContributionScores": "ContributionScores"
|
||||
@@ -39,10 +39,6 @@
|
||||
"value": false,
|
||||
"description": "Set to true to exclude bots users from the reporting."
|
||||
},
|
||||
"ContribScoreIgnoreUsernames": {
|
||||
"value": [],
|
||||
"description": "Array of usernames to exclude from the reporting."
|
||||
},
|
||||
"ContribScoresUseRealName": {
|
||||
"value": false,
|
||||
"description": "Set to true to use real user names when available."
|
||||
@@ -50,18 +46,6 @@
|
||||
"ContribScoreDisableCache": {
|
||||
"value": false,
|
||||
"description": "Set to true to disable cache for parser function and inclusion of table."
|
||||
},
|
||||
"ContribScoreUseRoughEditCount": {
|
||||
"value": false,
|
||||
"description": "Set to true to use the rough number of edits in user table, for performance issue. Mutually exclusive with $ContribScoreIgnoreMinorEdits; this option will be disabled if the other is enabled."
|
||||
},
|
||||
"ContribScoreIgnoreMinorEdits": {
|
||||
"value": false,
|
||||
"description": "Set to true to ignore minor edits. Mutually exclusive with $wgContribScoreUseRoughEditCount; if this is enabled, the other option will be disabled."
|
||||
},
|
||||
"ContribScoreCacheTTL": {
|
||||
"value": 30,
|
||||
"description": "Cache the contribution scores data, in minutes."
|
||||
}
|
||||
},
|
||||
"manifest_version": 2
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
]
|
||||
},
|
||||
"contributionscores-days": "Lasta {{PLURAL:$1|dio|$1 dii}}",
|
||||
"contributionscores-score": "Nombro di punti",
|
||||
"contributionscores-pages": "Pagini",
|
||||
"contributionscores-changes": "Modifikuri",
|
||||
"contributionscores-username": "Uzeronomo"
|
||||
}
|
||||
|
||||
5402
package-lock.json
generated
5402
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -5,9 +5,9 @@
|
||||
"test": "grunt test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint-config-wikimedia": "0.32.4",
|
||||
"grunt": "1.6.2",
|
||||
"grunt-banana-checker": "0.13.0",
|
||||
"grunt-eslint": "24.3.0"
|
||||
"eslint-config-wikimedia": "0.20.0",
|
||||
"grunt": "1.5.3",
|
||||
"grunt-banana-checker": "0.9.0",
|
||||
"grunt-eslint": "23.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,6 @@
|
||||
* \brief Contains code for the ContributionScores Class (extends SpecialPage).
|
||||
*/
|
||||
|
||||
use MediaWiki\Html\Html;
|
||||
use MediaWiki\Linker\Linker;
|
||||
use MediaWiki\MediaWikiServices;
|
||||
use MediaWiki\User\ActorMigration;
|
||||
|
||||
/// Special page class for the Contribution Scores extension
|
||||
/**
|
||||
* Special page that generates a list of wiki contributors based
|
||||
@@ -16,7 +11,6 @@ use MediaWiki\User\ActorMigration;
|
||||
*
|
||||
* @ingroup Extensions
|
||||
* @author Tim Laqua <t.laqua@gmail.com>
|
||||
* @author Eunakria <eunakria@gmail.com>
|
||||
*/
|
||||
class ContributionScores extends IncludableSpecialPage {
|
||||
const CONTRIBUTIONSCORES_MAXINCLUDELIMIT = 50;
|
||||
@@ -29,106 +23,52 @@ class ContributionScores extends IncludableSpecialPage {
|
||||
$parser->setFunctionHook( 'cscore', [ self::class, 'efContributionScoresRender' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* See extension.json; this function returns whether or not to use the
|
||||
* "rough edit count" (user_editcount, stored in the user table). Since
|
||||
* ignoring minor edits is mutually exclusive with this and takes priority,
|
||||
* we check here.
|
||||
*/
|
||||
private static function shouldUseRoughEditCount(): bool {
|
||||
global $wgContribScoreIgnoreMinorEdits, $wgContribScoreUseRoughEditCount;
|
||||
return $wgContribScoreUseRoughEditCount && !$wgContribScoreIgnoreMinorEdits;
|
||||
}
|
||||
|
||||
public static function efContributionScoresRender( $parser, $usertext, $metric = 'score' ) {
|
||||
global $wgContribScoreDisableCache, $wgContribScoreIgnoreMinorEdits;
|
||||
global $wgContribScoreDisableCache;
|
||||
|
||||
if ( $wgContribScoreDisableCache ) {
|
||||
$parser->getOutput()->updateCacheExpiry( 0 );
|
||||
}
|
||||
|
||||
$user = User::newFromName( $usertext );
|
||||
$loadBalancer = MediaWikiServices::getInstance()->getDBLoadBalancer();
|
||||
$dbr = $loadBalancer->getConnection( DB_REPLICA );
|
||||
$dbr = wfGetDB( DB_REPLICA );
|
||||
|
||||
if ( $user instanceof User && $user->isRegistered() ) {
|
||||
global $wgLang;
|
||||
$revVar = self::shouldUseRoughEditCount() ? 'user_editcount' : 'COUNT(rev_id)';
|
||||
|
||||
$revWhere = ActorMigration::newMigration()->getWhere( $dbr, 'rev_user', $user );
|
||||
$revConds = (array)$revWhere['conds'];
|
||||
if ( $wgContribScoreIgnoreMinorEdits ) {
|
||||
$revConds['rev_minor_edit'] = 0;
|
||||
}
|
||||
|
||||
# HACK: The original ContributionScores doesn't actually join on
|
||||
# user despite querying on user... again not our fault, but
|
||||
# definitely our problem. What a mess...
|
||||
$revTables = array_merge([ 'revision' ], $revWhere['tables']);
|
||||
$revJoins = $revWhere['joins'];
|
||||
if ( self::shouldUseRoughEditCount() && !in_array( 'user', $revTables ) ) {
|
||||
# Not familiar enough with MediaWiki to know if this is the
|
||||
# right way to do things, but it seems like it. The
|
||||
# ActorMigration class is deprecated and I think I'm supposed
|
||||
# to just join on the bare names?
|
||||
$revTables[] = 'actor';
|
||||
$revTables[] = 'user';
|
||||
$revJoins['actor'] = [ 'JOIN', 'rev_actor = actor_id' ];
|
||||
$revJoins['user'] = [ 'JOIN', 'actor_user = user_id' ];
|
||||
}
|
||||
|
||||
# HACK: This is not our fault (this bug exists in the original
|
||||
# ContributionScores as well!) but in cases where the rough edit
|
||||
# count underestimates the number of revisions, on MariaDB the
|
||||
# unsigned subtraction can underflow, which will throw an error.
|
||||
# So we have to clamp the subtraction rhs.
|
||||
#
|
||||
# Confused by buildLeast's API? Yeah, me too. It eventually
|
||||
# dispatches to buildSuperlative, which looks like this:
|
||||
# https://doc.wikimedia.org/mediawiki-core/master/php/SQLPlatform_8php_source.html#l00127
|
||||
# The way to smuggle in an existing expression is by passing it as
|
||||
# an array element with a non-integer key to the $fields argument,
|
||||
# which is what we do here.
|
||||
#
|
||||
# Of course the use of buildLeast is necessitated by the fact that
|
||||
# MariaDB and Postgres call it "LEAST", but SQLite calls it "MIN"
|
||||
# (a more intuitive name, but the same as the aggregate function).
|
||||
#
|
||||
$clampedRhsSql = $dbr->buildLeast (
|
||||
/* $fields: */ [ 'lhs' => $revVar, 'rhs' => 'COUNT(DISTINCT rev_page)' ],
|
||||
/* $values: */ []
|
||||
);
|
||||
$wikiRankSql = "COUNT(DISTINCT rev_page) + SQRT($revVar-$clampedRhsSql) * 2";
|
||||
|
||||
if ( $metric == 'score' ) {
|
||||
$row = $dbr->selectRow(
|
||||
$revTables,
|
||||
[ 'wiki_rank' => $wikiRankSql ],
|
||||
$revConds,
|
||||
$res = $dbr->select(
|
||||
[ 'revision' ] + $revWhere['tables'],
|
||||
'COUNT(DISTINCT rev_page)+SQRT(COUNT(rev_id)-COUNT(DISTINCT rev_page))*2 AS wiki_rank',
|
||||
$revWhere['conds'],
|
||||
__METHOD__,
|
||||
[],
|
||||
$revJoins
|
||||
$revWhere['joins']
|
||||
);
|
||||
$row = $dbr->fetchObject( $res );
|
||||
$output = $wgLang->formatNum( round( $row->wiki_rank, 0 ) );
|
||||
} elseif ( $metric == 'changes' ) {
|
||||
$row = $dbr->selectRow(
|
||||
$revTables,
|
||||
[ 'rev_count' => $revVar ],
|
||||
$revConds,
|
||||
$res = $dbr->select(
|
||||
[ 'revision' ] + $revWhere['tables'],
|
||||
'COUNT(rev_id) AS rev_count',
|
||||
$revWhere['conds'],
|
||||
__METHOD__,
|
||||
[],
|
||||
$revJoins
|
||||
$revWhere['joins']
|
||||
);
|
||||
$row = $dbr->fetchObject( $res );
|
||||
$output = $wgLang->formatNum( $row->rev_count );
|
||||
} elseif ( $metric == 'pages' ) {
|
||||
$row = $dbr->selectRow(
|
||||
$revTables,
|
||||
[ 'page_count' => 'COUNT(DISTINCT rev_page)' ],
|
||||
$revConds,
|
||||
$res = $dbr->select(
|
||||
[ 'revision' ] + $revWhere['tables'],
|
||||
'COUNT(DISTINCT rev_page) AS page_count',
|
||||
$revWhere['conds'],
|
||||
__METHOD__,
|
||||
[],
|
||||
$revJoins
|
||||
$revWhere['joins']
|
||||
);
|
||||
$row = $dbr->fetchObject( $res );
|
||||
$output = $wgLang->formatNum( $row->page_count );
|
||||
} else {
|
||||
$output = wfMessage( 'contributionscores-invalidmetric' )->text();
|
||||
@@ -136,153 +76,7 @@ class ContributionScores extends IncludableSpecialPage {
|
||||
} else {
|
||||
$output = wfMessage( 'contributionscores-invalidusername' )->text();
|
||||
}
|
||||
return $parser->insertStripItem( $output, $parser->getStripState() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Function fetch Contribution Scores data from database
|
||||
*
|
||||
* @param int $days Days in the past to run report for
|
||||
* @param int $limit Maximum number of users to return (default 50)
|
||||
* @return array Data including the requested Contribution Scores.
|
||||
*/
|
||||
public static function getContributionScoreData( $days, $limit ) {
|
||||
global $wgContribScoreIgnoreBots, $wgContribScoreIgnoreBlockedUsers, $wgContribScoreIgnoreUsernames,
|
||||
$wgContribScoreIgnoreMinorEdits;
|
||||
|
||||
$loadBalancer = MediaWikiServices::getInstance()->getDBLoadBalancer();
|
||||
$dbr = $loadBalancer->getConnection( DB_REPLICA );
|
||||
|
||||
$revQuery = ActorMigration::newMigration()->getJoin( 'rev_user' );
|
||||
$revQuery['tables'] = array_merge( [ 'revision' ], $revQuery['tables'] );
|
||||
|
||||
$revUser = $revQuery['fields']['rev_user'];
|
||||
$revUsername = $revQuery['fields']['rev_user_text'];
|
||||
|
||||
$sqlWhere = [];
|
||||
|
||||
if ( $wgContribScoreIgnoreMinorEdits ) {
|
||||
$sqlWhere[] = 'rev_minor_edit = 0';
|
||||
}
|
||||
|
||||
if ( $days > 0 ) {
|
||||
$date = time() - ( 60 * 60 * 24 * $days );
|
||||
$sqlWhere[] = 'rev_timestamp > ' . $dbr->addQuotes( $dbr->timestamp( $date ) );
|
||||
}
|
||||
|
||||
$sqlVars = [
|
||||
'rev_user' => $revUser,
|
||||
'page_count' => 'COUNT(DISTINCT rev_page)'
|
||||
];
|
||||
if ( self::shouldUseRoughEditCount() ) {
|
||||
$revQuery['tables'][] = 'user';
|
||||
$revQuery['joins']['user'] = [ 'LEFT JOIN', [ "$revUser != 0", "user_id = $revUser" ] ];
|
||||
$sqlVars['rev_count'] = 'user_editcount';
|
||||
} else {
|
||||
$sqlVars['rev_count'] = 'COUNT(rev_id)';
|
||||
}
|
||||
|
||||
if ( $wgContribScoreIgnoreBlockedUsers ) {
|
||||
$sqlWhere[] = "{$revUser} NOT IN " .
|
||||
$dbr->buildSelectSubquery(
|
||||
[
|
||||
'block',
|
||||
'block_target'
|
||||
],
|
||||
'bt_user',
|
||||
'bt_user <> 0',
|
||||
__METHOD__,
|
||||
[],
|
||||
[
|
||||
'block_target' => [ 'JOIN', [
|
||||
'bl_target=bt_id'
|
||||
] ]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if ( $wgContribScoreIgnoreBots ) {
|
||||
$sqlWhere[] = "{$revUser} NOT IN " .
|
||||
$dbr->buildSelectSubquery( 'user_groups', 'ug_user', [
|
||||
'ug_group' => 'bot',
|
||||
'ug_expiry IS NULL OR ug_expiry >= ' . $dbr->addQuotes( $dbr->timestamp() )
|
||||
], __METHOD__ );
|
||||
}
|
||||
|
||||
if ( count( $wgContribScoreIgnoreUsernames ) ) {
|
||||
$listIgnoredUsernames = $dbr->makeList( $wgContribScoreIgnoreUsernames );
|
||||
$sqlWhere[] = "{$revUsername} NOT IN ($listIgnoredUsernames)";
|
||||
}
|
||||
|
||||
if ( $dbr->unionSupportsOrderAndLimit() ) {
|
||||
$order = [
|
||||
'GROUP BY' => 'rev_user',
|
||||
'ORDER BY' => 'page_count DESC',
|
||||
'LIMIT' => $limit
|
||||
];
|
||||
} else {
|
||||
$order = [ 'GROUP BY' => 'rev_user' ];
|
||||
}
|
||||
|
||||
$sqlMostPages = $dbr->selectSQLText(
|
||||
$revQuery['tables'],
|
||||
$sqlVars,
|
||||
$sqlWhere,
|
||||
__METHOD__,
|
||||
$order,
|
||||
$revQuery['joins']
|
||||
);
|
||||
|
||||
if ( $dbr->unionSupportsOrderAndLimit() ) {
|
||||
$order['ORDER BY'] = 'rev_count DESC';
|
||||
}
|
||||
|
||||
$sqlMostRevs = $dbr->selectSQLText(
|
||||
$revQuery['tables'],
|
||||
$sqlVars,
|
||||
$sqlWhere,
|
||||
__METHOD__,
|
||||
$order,
|
||||
$revQuery['joins']
|
||||
);
|
||||
|
||||
# HACK: See previous comment on the use of buildLeast. Not our fault,
|
||||
# but still our problem...
|
||||
$clampedRhsSql = $dbr->buildLeast(
|
||||
/* $fields: */ [ 'rev_count', 'page_count' ],
|
||||
/* $values: */ []
|
||||
);
|
||||
$wikiRankSql = "page_count+SQRT(rev_count-$clampedRhsSql)*2";
|
||||
|
||||
$sqlMostPagesOrRevs = $dbr->unionQueries( [ $sqlMostPages, $sqlMostRevs ], false );
|
||||
$res = $dbr->select(
|
||||
[
|
||||
'u' => 'user',
|
||||
's' => new Wikimedia\Rdbms\Subquery( $sqlMostPagesOrRevs ),
|
||||
],
|
||||
[
|
||||
'user_id',
|
||||
'user_name',
|
||||
'user_real_name',
|
||||
'page_count',
|
||||
'rev_count',
|
||||
'wiki_rank' => $wikiRankSql,
|
||||
],
|
||||
[],
|
||||
__METHOD__,
|
||||
[
|
||||
'ORDER BY' => 'wiki_rank DESC',
|
||||
'LIMIT' => $limit,
|
||||
],
|
||||
[
|
||||
's' => [
|
||||
'JOIN',
|
||||
'user_id=rev_user'
|
||||
]
|
||||
]
|
||||
);
|
||||
$ret = iterator_to_array( $res );
|
||||
return $ret;
|
||||
return $parser->insertStripItem( $output, $parser->mStripState );
|
||||
}
|
||||
|
||||
/// Generates a "Contribution Scores" table for a given LIMIT and date range
|
||||
@@ -297,10 +91,106 @@ class ContributionScores extends IncludableSpecialPage {
|
||||
* @return string Html Table representing the requested Contribution Scores.
|
||||
*/
|
||||
function genContributionScoreTable( $days, $limit, $title = null, $options = 'none' ) {
|
||||
global $wgContribScoresUseRealName, $wgContribScoreCacheTTL;
|
||||
global $wgContribScoreIgnoreBots, $wgContribScoreIgnoreBlockedUsers, $wgContribScoresUseRealName;
|
||||
|
||||
$opts = explode( ',', strtolower( $options ) );
|
||||
|
||||
$dbr = wfGetDB( DB_REPLICA );
|
||||
|
||||
$revQuery = ActorMigration::newMigration()->getJoin( 'rev_user' );
|
||||
$revQuery['tables'] = array_merge( [ 'revision' ], $revQuery['tables'] );
|
||||
|
||||
$revUser = $revQuery['fields']['rev_user'];
|
||||
|
||||
$sqlWhere = [];
|
||||
|
||||
if ( $days > 0 ) {
|
||||
$date = time() - ( 60 * 60 * 24 * $days );
|
||||
$sqlWhere[] = 'rev_timestamp > ' . $dbr->addQuotes( $dbr->timestamp( $date ) );
|
||||
}
|
||||
|
||||
if ( $wgContribScoreIgnoreBlockedUsers ) {
|
||||
$sqlWhere[] = "{$revUser} NOT IN " .
|
||||
$dbr->buildSelectSubquery( 'ipblocks', 'ipb_user', 'ipb_user <> 0', __METHOD__ );
|
||||
}
|
||||
|
||||
if ( $wgContribScoreIgnoreBots ) {
|
||||
$sqlWhere[] = "{$revUser} NOT IN " .
|
||||
$dbr->buildSelectSubquery( 'user_groups', 'ug_user', [
|
||||
'ug_group' => 'bot',
|
||||
'ug_expiry IS NULL OR ug_expiry >= ' . $dbr->addQuotes( $dbr->timestamp() )
|
||||
], __METHOD__ );
|
||||
}
|
||||
|
||||
if ( $dbr->unionSupportsOrderAndLimit() ) {
|
||||
$order = [
|
||||
'GROUP BY' => 'rev_user',
|
||||
'ORDER BY' => 'page_count DESC',
|
||||
'LIMIT' => $limit
|
||||
];
|
||||
} else {
|
||||
$order = [ 'GROUP BY' => 'rev_user' ];
|
||||
}
|
||||
|
||||
$sqlMostPages = $dbr->selectSQLText(
|
||||
$revQuery['tables'],
|
||||
[
|
||||
'rev_user' => $revUser,
|
||||
'page_count' => 'COUNT(DISTINCT rev_page)',
|
||||
'rev_count' => 'COUNT(rev_id)',
|
||||
],
|
||||
$sqlWhere,
|
||||
__METHOD__,
|
||||
$order,
|
||||
$revQuery['joins']
|
||||
);
|
||||
|
||||
if ( $dbr->unionSupportsOrderAndLimit() ) {
|
||||
$order['ORDER BY'] = 'rev_count DESC';
|
||||
}
|
||||
|
||||
$sqlMostRevs = $dbr->selectSQLText(
|
||||
$revQuery['tables'],
|
||||
[
|
||||
'rev_user' => $revUser,
|
||||
'page_count' => 'COUNT(DISTINCT rev_page)',
|
||||
'rev_count' => 'COUNT(rev_id)',
|
||||
],
|
||||
$sqlWhere,
|
||||
__METHOD__,
|
||||
$order,
|
||||
$revQuery['joins']
|
||||
);
|
||||
|
||||
$sqlMostPagesOrRevs = $dbr->unionQueries( [ $sqlMostPages, $sqlMostRevs ], false );
|
||||
$res = $dbr->select(
|
||||
[
|
||||
'u' => 'user',
|
||||
's' => new Wikimedia\Rdbms\Subquery( $sqlMostPagesOrRevs ),
|
||||
],
|
||||
[
|
||||
'user_id',
|
||||
'user_name',
|
||||
'user_real_name',
|
||||
'page_count',
|
||||
'rev_count',
|
||||
'wiki_rank' => 'page_count+SQRT(rev_count-page_count)*2',
|
||||
],
|
||||
[],
|
||||
__METHOD__,
|
||||
[
|
||||
'ORDER BY' => 'wiki_rank DESC',
|
||||
'GROUP BY' => 'user_name',
|
||||
'LIMIT' => $limit,
|
||||
],
|
||||
[
|
||||
's' => [
|
||||
'JOIN',
|
||||
'user_id=rev_user'
|
||||
]
|
||||
]
|
||||
);
|
||||
|
||||
$sortable = in_array( 'nosort', $opts ) ? '' : ' sortable';
|
||||
|
||||
$output = "<table class=\"wikitable contributionscores plainlinks{$sortable}\" >\n" .
|
||||
@@ -311,26 +201,11 @@ class ContributionScores extends IncludableSpecialPage {
|
||||
Html::element( 'th', [], $this->msg( 'contributionscores-changes' )->text() ) .
|
||||
Html::element( 'th', [], $this->msg( 'contributionscores-username' )->text() );
|
||||
|
||||
$cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
|
||||
$data = $cache->getWithSetCallback(
|
||||
$cache->makeKey( 'contributionscores', 'data-' . (string)$days ),
|
||||
$wgContribScoreCacheTTL * 60,
|
||||
function () use ( $days ) {
|
||||
// Use max limit, as limit doesn't matter with performance.
|
||||
// Avoid purge multiple times since limit on transclusion can be vary.
|
||||
return self::getContributionScoreData( $days, self::CONTRIBUTIONSCORES_MAXINCLUDELIMIT );
|
||||
} );
|
||||
|
||||
$lang = $this->getLanguage();
|
||||
|
||||
$altrow = '';
|
||||
$user_rank = 1;
|
||||
|
||||
foreach ( $data as $row ) {
|
||||
if ( $user_rank > $limit ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$lang = $this->getLanguage();
|
||||
foreach ( $res as $row ) {
|
||||
// Use real name if option used and real name present.
|
||||
if ( $wgContribScoresUseRealName && $row->user_real_name !== '' ) {
|
||||
$userLink = Linker::userLink(
|
||||
@@ -376,7 +251,8 @@ class ContributionScores extends IncludableSpecialPage {
|
||||
$output .= Html::closeElement( 'tr' );
|
||||
$output .= Html::closeElement( 'table' );
|
||||
|
||||
// Transcluded on a normal wiki page.
|
||||
$dbr->freeResult( $res );
|
||||
|
||||
if ( !empty( $title ) ) {
|
||||
$output = Html::rawElement( 'table',
|
||||
[
|
||||
@@ -447,7 +323,7 @@ class ContributionScores extends IncludableSpecialPage {
|
||||
$reportTitle = $this->msg( 'contributionscores-allrevisions' )->text();
|
||||
}
|
||||
$reportTitle .= ' ' . $this->msg( 'contributionscores-top' )->numParams( $limit )->text();
|
||||
$title = Html::element( 'h4',
|
||||
$title = Xml::element( 'h4',
|
||||
[ 'class' => 'contributionscores-title' ],
|
||||
$reportTitle
|
||||
) . "\n";
|
||||
@@ -477,14 +353,14 @@ class ContributionScores extends IncludableSpecialPage {
|
||||
$out->addWikiMsg( 'contributionscores-info' );
|
||||
|
||||
foreach ( $wgContribScoreReports as $scoreReport ) {
|
||||
[ $days, $revs ] = $scoreReport;
|
||||
list( $days, $revs ) = $scoreReport;
|
||||
if ( $days > 0 ) {
|
||||
$reportTitle = $this->msg( 'contributionscores-days' )->numParams( $days )->text();
|
||||
} else {
|
||||
$reportTitle = $this->msg( 'contributionscores-allrevisions' )->text();
|
||||
}
|
||||
$reportTitle .= ' ' . $this->msg( 'contributionscores-top' )->numParams( $revs )->text();
|
||||
$title = Html::element( 'h2',
|
||||
$title = Xml::element( 'h2',
|
||||
[ 'class' => 'contributionscores-title' ],
|
||||
$reportTitle
|
||||
) . "\n";
|
||||
@@ -493,11 +369,6 @@ class ContributionScores extends IncludableSpecialPage {
|
||||
}
|
||||
}
|
||||
|
||||
public function maxIncludeCacheTime() {
|
||||
global $wgContribScoreDisableCache, $wgContribScoreCacheTTL;
|
||||
return $wgContribScoreDisableCache ? 0 : $wgContribScoreCacheTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user