Add tests
Fix all issues so tests pass. Change-Id: I8a059c26d16944d4ddfb56959617fb73887e7b6a
This commit is contained in:
parent
8f657f7205
commit
e4cb919476
10 changed files with 146 additions and 95 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,5 +1,7 @@
|
||||||
.svn
|
|
||||||
*~
|
*~
|
||||||
*.kate-swp
|
*.kate-swp
|
||||||
.*.swp
|
.*.swp
|
||||||
.idea
|
.idea
|
||||||
|
node_modules/
|
||||||
|
/composer.lock
|
||||||
|
/vendor/
|
||||||
|
|
1
.jshintignore
Normal file
1
.jshintignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
node_modules
|
|
@ -1,35 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* This is a backwards-compatibility shim, generated by:
|
|
||||||
* https://git.wikimedia.org/blob/mediawiki%2Fcore.git/HEAD/maintenance%2FgenerateJsonI18n.php
|
|
||||||
*
|
|
||||||
* Beginning with MediaWiki 1.23, translation strings are stored in json files,
|
|
||||||
* and the EXTENSION.i18n.php file only exists to provide compatibility with
|
|
||||||
* older releases of MediaWiki. For more information about this migration, see:
|
|
||||||
* https://www.mediawiki.org/wiki/Requests_for_comment/Localisation_format
|
|
||||||
*
|
|
||||||
* This shim maintains compatibility back to MediaWiki 1.17.
|
|
||||||
*/
|
|
||||||
$messages = array();
|
|
||||||
if ( !function_exists( 'wfJsonI18nShim9e08550f702d6269' ) ) {
|
|
||||||
function wfJsonI18nShim9e08550f702d6269( $cache, $code, &$cachedData ) {
|
|
||||||
$codeSequence = array_merge( array( $code ), $cachedData['fallbackSequence'] );
|
|
||||||
foreach ( $codeSequence as $csCode ) {
|
|
||||||
$fileName = dirname( __FILE__ ) . "/i18n/$csCode.json";
|
|
||||||
if ( is_readable( $fileName ) ) {
|
|
||||||
$data = FormatJson::decode( file_get_contents( $fileName ), true );
|
|
||||||
foreach ( array_keys( $data ) as $key ) {
|
|
||||||
if ( $key === '' || $key[0] === '@' ) {
|
|
||||||
unset( $data[$key] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$cachedData['messages'] = array_merge( $data, $cachedData['messages'] );
|
|
||||||
}
|
|
||||||
|
|
||||||
$cachedData['deps'][] = new FileDependency( $fileName );
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$GLOBALS['wgHooks']['LocalisationCacheRecache'][] = 'wfJsonI18nShim9e08550f702d6269';
|
|
||||||
}
|
|
|
@ -1,11 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
/** \file
|
/** \file
|
||||||
* \brief Contains setup code for the Contribution Scores Extension.
|
* \brief Contains setup code for the Contribution Scores Extension.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
# Not a valid entry point, skip unless MEDIAWIKI is defined
|
# Not a valid entry point, skip unless MEDIAWIKI is defined
|
||||||
if ( !defined( 'MEDIAWIKI' ) ) {
|
if ( !defined( 'MEDIAWIKI' ) ) {
|
||||||
echo "Contribution Scores extension";
|
echo 'Contribution Scores extension';
|
||||||
exit( 1 );
|
exit( 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,32 +15,39 @@ $wgExtensionCredits['specialpage'][] = array(
|
||||||
'url' => 'https://www.mediawiki.org/wiki/Extension:Contribution_Scores',
|
'url' => 'https://www.mediawiki.org/wiki/Extension:Contribution_Scores',
|
||||||
'author' => 'Tim Laqua',
|
'author' => 'Tim Laqua',
|
||||||
'descriptionmsg' => 'contributionscores-desc',
|
'descriptionmsg' => 'contributionscores-desc',
|
||||||
'version' => '1.17.0'
|
'version' => '1.23.0'
|
||||||
);
|
);
|
||||||
|
|
||||||
$dir = dirname( __FILE__ ) . '/';
|
|
||||||
|
|
||||||
define( 'CONTRIBUTIONSCORES_MAXINCLUDELIMIT', 50 );
|
define( 'CONTRIBUTIONSCORES_MAXINCLUDELIMIT', 50 );
|
||||||
$wgContribScoreReports = null;
|
$wgContribScoreReports = null;
|
||||||
|
|
||||||
// These settings can be overridden in LocalSettings.php.
|
// These settings can be overridden in LocalSettings.php.
|
||||||
$wgContribScoreIgnoreBlockedUsers = false; // Set to true to exclude bots from the reporting.
|
|
||||||
$wgContribScoreIgnoreBots = false; // Set to true to exclude blocked users from the reporting.
|
|
||||||
$wgContribScoresUseRealName = false; // Set to true to use real user names when available. Only for MediaWiki 1.19 and later.
|
|
||||||
$wgContribScoreDisableCache = false; // Set to true to disable cache for parser function and inclusion of table.
|
|
||||||
|
|
||||||
$wgAutoloadClasses['ContributionScores'] = $dir . 'ContributionScores_body.php';
|
// Set to true to exclude bots from the reporting.
|
||||||
|
$wgContribScoreIgnoreBlockedUsers = false;
|
||||||
|
|
||||||
|
// Set to true to exclude blocked users from the reporting.
|
||||||
|
$wgContribScoreIgnoreBots = false;
|
||||||
|
|
||||||
|
// Set to true to use real user names when available. Only for MediaWiki 1.19 and later.
|
||||||
|
$wgContribScoresUseRealName = false;
|
||||||
|
|
||||||
|
// Set to true to disable cache for parser function and inclusion of table.
|
||||||
|
$wgContribScoreDisableCache = false;
|
||||||
|
|
||||||
|
$wgAutoloadClasses['ContributionScores'] = __DIR__ . '/ContributionScores_body.php';
|
||||||
$wgSpecialPages['ContributionScores'] = 'ContributionScores';
|
$wgSpecialPages['ContributionScores'] = 'ContributionScores';
|
||||||
|
|
||||||
$wgMessagesDirs['ContributionScores'] = __DIR__ . '/i18n';
|
$wgMessagesDirs['ContributionScores'] = __DIR__ . '/i18n';
|
||||||
$wgExtensionMessagesFiles['ContributionScores'] = $dir . 'ContributionScores.i18n.php';
|
$wgExtensionMessagesFiles['ContributionScoresAlias'] = __DIR__ . '/ContributionScores.alias.php';
|
||||||
$wgExtensionMessagesFiles['ContributionScoresAlias'] = $dir . 'ContributionScores.alias.php';
|
$wgExtensionMessagesFiles['ContributionScoresMagic'] =
|
||||||
$wgExtensionMessagesFiles['ContributionScoresMagic'] = $dir . 'ContributionScores.i18n.magic.php';
|
__DIR__ . '/ContributionScores.i18n.magic.php';
|
||||||
|
|
||||||
$wgHooks['ParserFirstCallInit'][] = 'efContributionScores_Setup';
|
$wgHooks['ParserFirstCallInit'][] = 'efContributionScores_Setup';
|
||||||
|
|
||||||
function efContributionScores_Setup( &$parser ) {
|
function efContributionScores_Setup( &$parser ) {
|
||||||
$parser->setFunctionHook( 'cscore', 'efContributionScores_Render' );
|
$parser->setFunctionHook( 'cscore', 'efContributionScores_Render' );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,21 +66,20 @@ function efContributionScores_Render( &$parser, $usertext, $metric = 'score' ) {
|
||||||
|
|
||||||
if ( $metric == 'score' ) {
|
if ( $metric == 'score' ) {
|
||||||
$res = $dbr->select( 'revision',
|
$res = $dbr->select( 'revision',
|
||||||
'COUNT(DISTINCT rev_page)+SQRT(COUNT(rev_id)-COUNT(DISTINCT rev_page))*2 AS wiki_rank',
|
'COUNT(DISTINCT rev_page)+SQRT(COUNT(rev_id)-COUNT(DISTINCT rev_page))*2 AS wiki_rank',
|
||||||
array( 'rev_user' => $user->getID() ) );
|
array( 'rev_user' => $user->getID() ) );
|
||||||
$row = $dbr->fetchObject( $res );
|
$row = $dbr->fetchObject( $res );
|
||||||
$output = $wgLang->formatNum( round( $row->wiki_rank, 0 ) );
|
$output = $wgLang->formatNum( round( $row->wiki_rank, 0 ) );
|
||||||
} elseif ( $metric == 'changes' ) {
|
} elseif ( $metric == 'changes' ) {
|
||||||
$res = $dbr->select( 'revision',
|
$res = $dbr->select( 'revision',
|
||||||
'COUNT(rev_id) AS rev_count',
|
'COUNT(rev_id) AS rev_count',
|
||||||
array( 'rev_user' => $user->getID() ) );
|
array( 'rev_user' => $user->getID() ) );
|
||||||
$row = $dbr->fetchObject( $res );
|
$row = $dbr->fetchObject( $res );
|
||||||
$output = $wgLang->formatNum( $row->rev_count );
|
$output = $wgLang->formatNum( $row->rev_count );
|
||||||
|
|
||||||
} elseif ( $metric == 'pages' ) {
|
} elseif ( $metric == 'pages' ) {
|
||||||
$res = $dbr->select( 'revision',
|
$res = $dbr->select( 'revision',
|
||||||
'COUNT(DISTINCT rev_page) AS page_count',
|
'COUNT(DISTINCT rev_page) AS page_count',
|
||||||
array( 'rev_user' => $user->getID() ) );
|
array( 'rev_user' => $user->getID() ) );
|
||||||
$row = $dbr->fetchObject( $res );
|
$row = $dbr->fetchObject( $res );
|
||||||
$output = $wgLang->formatNum( $row->page_count );
|
$output = $wgLang->formatNum( $row->page_count );
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
/** \file
|
/** \file
|
||||||
* \brief Contains code for the ContributionScores Class (extends SpecialPage).
|
* \brief Contains code for the ContributionScores Class (extends SpecialPage).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// Special page class for the Contribution Scores extension
|
/// Special page class for the Contribution Scores extension
|
||||||
/**
|
/**
|
||||||
|
@ -50,12 +50,14 @@ class ContributionScores extends IncludableSpecialPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $wgContribScoreIgnoreBlockedUsers ) {
|
if ( $wgContribScoreIgnoreBlockedUsers ) {
|
||||||
$sqlWhere .= " {$nextPrefix} rev_user NOT IN (SELECT ipb_user FROM {$ipBlocksTable} WHERE ipb_user <> 0)";
|
$sqlWhere .= " {$nextPrefix} rev_user NOT IN " .
|
||||||
|
"(SELECT ipb_user FROM {$ipBlocksTable} WHERE ipb_user <> 0)";
|
||||||
$nextPrefix = "AND";
|
$nextPrefix = "AND";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $wgContribScoreIgnoreBots ) {
|
if ( $wgContribScoreIgnoreBots ) {
|
||||||
$sqlWhere .= " {$nextPrefix} rev_user NOT IN (SELECT ug_user FROM {$userGroupTable} WHERE ug_group='bot')";
|
$sqlWhere .= " {$nextPrefix} rev_user NOT IN " .
|
||||||
|
"(SELECT ug_user FROM {$userGroupTable} WHERE ug_group='bot')";
|
||||||
}
|
}
|
||||||
|
|
||||||
$sqlMostPages = "SELECT rev_user,
|
$sqlMostPages = "SELECT rev_user,
|
||||||
|
@ -67,7 +69,7 @@ class ContributionScores extends IncludableSpecialPage {
|
||||||
ORDER BY page_count DESC
|
ORDER BY page_count DESC
|
||||||
LIMIT {$limit}";
|
LIMIT {$limit}";
|
||||||
|
|
||||||
$sqlMostRevs = "SELECT rev_user,
|
$sqlMostRevs = "SELECT rev_user,
|
||||||
COUNT(DISTINCT rev_page) AS page_count,
|
COUNT(DISTINCT rev_page) AS page_count,
|
||||||
COUNT(rev_id) AS rev_count
|
COUNT(rev_id) AS rev_count
|
||||||
FROM {$revTable}
|
FROM {$revTable}
|
||||||
|
@ -118,11 +120,16 @@ class ContributionScores extends IncludableSpecialPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
$output .= Html::closeElement( 'tr' );
|
$output .= Html::closeElement( 'tr' );
|
||||||
$output .= "<tr class='{$altrow}'>\n<td class='content' style='padding-right:10px;text-align:right;'>" .
|
$output .= "<tr class='{$altrow}'>\n" .
|
||||||
$lang->formatNum( round( $user_rank, 0 ) ) . "\n</td><td class='content' style='padding-right:10px;text-align:right;'>" .
|
"<td class='content' style='padding-right:10px;text-align:right;'>" .
|
||||||
$lang->formatNum( round( $row->wiki_rank, 0 ) ) . "\n</td><td class='content' style='padding-right:10px;text-align:right;'>" .
|
$lang->formatNum( round( $user_rank, 0 ) ) .
|
||||||
$lang->formatNum( $row->page_count ) . "\n</td><td class='content' style='padding-right:10px;text-align:right;'>" .
|
"\n</td><td class='content' style='padding-right:10px;text-align:right;'>" .
|
||||||
$lang->formatNum( $row->rev_count ) . "\n</td><td class='content'>" .
|
$lang->formatNum( round( $row->wiki_rank, 0 ) ) .
|
||||||
|
"\n</td><td class='content' style='padding-right:10px;text-align:right;'>" .
|
||||||
|
$lang->formatNum( $row->page_count ) .
|
||||||
|
"\n</td><td class='content' style='padding-right:10px;text-align:right;'>" .
|
||||||
|
$lang->formatNum( $row->rev_count ) .
|
||||||
|
"\n</td><td class='content'>" .
|
||||||
$userLink;
|
$userLink;
|
||||||
|
|
||||||
# Option to not display user tools
|
# Option to not display user tools
|
||||||
|
@ -150,16 +157,16 @@ class ContributionScores extends IncludableSpecialPage {
|
||||||
array(
|
array(
|
||||||
'style' => 'border-spacing: 0; padding: 0',
|
'style' => 'border-spacing: 0; padding: 0',
|
||||||
'class' => 'contributionscores-wrapper',
|
'class' => 'contributionscores-wrapper',
|
||||||
'lang' => htmlspecialchars( $lang->getCode()),
|
'lang' => htmlspecialchars( $lang->getCode() ),
|
||||||
'dir' => $lang->getDir()
|
'dir' => $lang->getDir()
|
||||||
),
|
),
|
||||||
"\n" .
|
"\n" .
|
||||||
"<tr>\n" .
|
"<tr>\n" .
|
||||||
"<td style='padding: 0px;'>{$title}</td>\n" .
|
"<td style='padding: 0px;'>{$title}</td>\n" .
|
||||||
"</tr>\n" .
|
"</tr>\n" .
|
||||||
"<tr>\n" .
|
"<tr>\n" .
|
||||||
"<td style='padding: 0px;'>{$output}</td>\n" .
|
"<td style='padding: 0px;'>{$output}</td>\n" .
|
||||||
"</tr>\n"
|
"</tr>\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
|
@ -213,9 +220,17 @@ class ContributionScores extends IncludableSpecialPage {
|
||||||
} else {
|
} else {
|
||||||
$reportTitle = $this->msg( 'contributionscores-allrevisions' )->text();
|
$reportTitle = $this->msg( 'contributionscores-allrevisions' )->text();
|
||||||
}
|
}
|
||||||
$reportTitle .= " " . $this->msg( 'contributionscores-top' )->numParams( $limit )->text();
|
$reportTitle .= ' ' . $this->msg( 'contributionscores-top' )->numParams( $limit )->text();
|
||||||
$title = Xml::element( 'h4', array( 'class' => 'contributionscores-title' ), $reportTitle ) . "\n";
|
$title = Xml::element( 'h4',
|
||||||
$this->getOutput()->addHTML( $this->genContributionScoreTable( $days, $limit, $title, $options ) );
|
array( 'class' => 'contributionscores-title' ),
|
||||||
|
$reportTitle
|
||||||
|
) . "\n";
|
||||||
|
$this->getOutput()->addHTML( $this->genContributionScoreTable(
|
||||||
|
$days,
|
||||||
|
$limit,
|
||||||
|
$title,
|
||||||
|
$options
|
||||||
|
) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -242,8 +257,11 @@ class ContributionScores extends IncludableSpecialPage {
|
||||||
} else {
|
} else {
|
||||||
$reportTitle = $this->msg( 'contributionscores-allrevisions' )->text();
|
$reportTitle = $this->msg( 'contributionscores-allrevisions' )->text();
|
||||||
}
|
}
|
||||||
$reportTitle .= " " . $this->msg( 'contributionscores-top' )->numParams( $revs )->text();
|
$reportTitle .= ' ' . $this->msg( 'contributionscores-top' )->numParams( $revs )->text();
|
||||||
$title = Xml::element( 'h2', array( 'class' => 'contributionscores-title' ), $reportTitle ) . "\n";
|
$title = Xml::element( 'h2',
|
||||||
|
array( 'class' => 'contributionscores-title' ),
|
||||||
|
$reportTitle
|
||||||
|
) . "\n";
|
||||||
$out->addHTML( $title );
|
$out->addHTML( $title );
|
||||||
$out->addHTML( $this->genContributionScoreTable( $days, $revs ) );
|
$out->addHTML( $this->genContributionScoreTable( $days, $revs ) );
|
||||||
}
|
}
|
||||||
|
|
26
Gruntfile.js
Normal file
26
Gruntfile.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*jshint node:true */
|
||||||
|
module.exports = function ( grunt ) {
|
||||||
|
grunt.loadNpmTasks( 'grunt-contrib-jshint' );
|
||||||
|
grunt.loadNpmTasks( 'grunt-banana-checker' );
|
||||||
|
grunt.loadNpmTasks( 'grunt-jsonlint' );
|
||||||
|
|
||||||
|
grunt.initConfig( {
|
||||||
|
jshint: {
|
||||||
|
all: [
|
||||||
|
'*.js'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
banana: {
|
||||||
|
all: 'i18n/'
|
||||||
|
},
|
||||||
|
jsonlint: {
|
||||||
|
all: [
|
||||||
|
'**/*.json',
|
||||||
|
'!node_modules/**'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
grunt.registerTask( 'test', [ 'jshint', 'jsonlint', 'banana' ] );
|
||||||
|
grunt.registerTask( 'default', 'test' );
|
||||||
|
};
|
12
composer.json
Normal file
12
composer.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"require-dev": {
|
||||||
|
"jakub-onderka/php-parallel-lint": "0.9",
|
||||||
|
"mediawiki/mediawiki-codesniffer": "0.4.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": [
|
||||||
|
"parallel-lint . --exclude vendor",
|
||||||
|
"phpcs -p -s"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
32
i18n/en.json
32
i18n/en.json
|
@ -1,18 +1,18 @@
|
||||||
{
|
{
|
||||||
"@metadata": {
|
"@metadata": {
|
||||||
"authors": []
|
"authors": []
|
||||||
},
|
},
|
||||||
"contributionscores": "Contribution scores",
|
"contributionscores": "Contribution scores",
|
||||||
"contributionscores-desc": "Polls the wiki database for highest [[Special:ContributionScores|user contribution volume]]",
|
"contributionscores-desc": "Polls the wiki database for highest [[Special:ContributionScores|user contribution volume]]",
|
||||||
"contributionscores-info": "The score primarily measures unique pages edited, with consideration for high edit volume.",
|
"contributionscores-info": "The score primarily measures unique pages edited, with consideration for high edit volume.",
|
||||||
"contributionscores-top": "(Top $1)",
|
"contributionscores-top": "(Top $1)",
|
||||||
"contributionscores-days": "Last {{PLURAL:$1|day|$1 days}}",
|
"contributionscores-days": "Last {{PLURAL:$1|day|$1 days}}",
|
||||||
"contributionscores-allrevisions": "All time",
|
"contributionscores-allrevisions": "All time",
|
||||||
"contributionscores-score": "Score",
|
"contributionscores-score": "Score",
|
||||||
"contributionscores-rank": "Rank",
|
"contributionscores-rank": "Rank",
|
||||||
"contributionscores-pages": "Pages",
|
"contributionscores-pages": "Pages",
|
||||||
"contributionscores-changes": "Changes",
|
"contributionscores-changes": "Changes",
|
||||||
"contributionscores-username": "Username",
|
"contributionscores-username": "Username",
|
||||||
"contributionscores-invalidusername": "Invalid username",
|
"contributionscores-invalidusername": "Invalid username",
|
||||||
"contributionscores-invalidmetric": "Invalid metric"
|
"contributionscores-invalidmetric": "Invalid metric"
|
||||||
}
|
}
|
13
package.json
Normal file
13
package.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"test": "grunt test"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"grunt": "0.4.5",
|
||||||
|
"grunt-cli": "0.1.13",
|
||||||
|
"grunt-contrib-jshint": "0.11.3",
|
||||||
|
"grunt-banana-checker": "0.2.2",
|
||||||
|
"grunt-jsonlint": "1.0.4"
|
||||||
|
}
|
||||||
|
}
|
8
phpcs.xml
Normal file
8
phpcs.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<ruleset>
|
||||||
|
<rule ref="vendor/mediawiki/mediawiki-codesniffer/MediaWiki"/>
|
||||||
|
<file>.</file>
|
||||||
|
<arg name="extensions" value="php,php5,inc"/>
|
||||||
|
<arg name="encoding" value="utf8"/>
|
||||||
|
<exclude-pattern>vendor</exclude-pattern>
|
||||||
|
</ruleset>
|
Loading…
Add table
Reference in a new issue