summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'ContributionScores/ContributionScores_body.php')
-rw-r--r--ContributionScores/ContributionScores_body.php322
1 files changed, 322 insertions, 0 deletions
diff --git a/ContributionScores/ContributionScores_body.php b/ContributionScores/ContributionScores_body.php
new file mode 100644
index 00000000..9a59c5be
--- /dev/null
+++ b/ContributionScores/ContributionScores_body.php
@@ -0,0 +1,322 @@
+<?php
+/** \file
+ * \brief Contains code for the ContributionScores Class (extends SpecialPage).
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/// Special page class for the Contribution Scores extension
+/**
+ * Special page that generates a list of wiki contributors based
+ * on edit diversity (unique pages edited) and edit volume (total
+ * number of edits.
+ *
+ * @ingroup Extensions
+ * @author Tim Laqua <t.laqua@gmail.com>
+ */
+class ContributionScores extends IncludableSpecialPage {
+ public function __construct() {
+ parent::__construct( 'ContributionScores' );
+ }
+
+ /// Generates a "Contribution Scores" table for a given LIMIT and date range
+
+ /**
+ * Function generates Contribution Scores tables in HTML format (not wikiText)
+ *
+ * @param int $days Days in the past to run report for
+ * @param int $limit Maximum number of users to return (default 50)
+ * @param string|null $title The title of the table
+ * @param array $options array of options (default none; nosort/notools)
+ * @return string Html Table representing the requested Contribution Scores.
+ */
+ function genContributionScoreTable( $days, $limit, $title = null, $options = 'none' ) {
+ global $wgContribScoreIgnoreBots, $wgContribScoreIgnoreBlockedUsers, $wgContribScoresUseRealName;
+
+ $opts = explode( ',', strtolower( $options ) );
+
+ $dbr = wfGetDB( DB_REPLICA );
+
+ $store = MediaWikiServices::getInstance()
+ ->getRevisionStoreFactory()
+ ->getRevisionStore();
+ $revQuery = $store->getQueryInfo();
+
+ $revUser = $revQuery['fields']['rev_user'];
+
+ $sqlWhere = [];
+
+ if ( $days > 0 ) {
+ $date = time() - ( 60 * 60 * 24 * $days );
+ $dateString = $dbr->timestamp( $date );
+ $sqlWhere[] = "rev_timestamp > '$dateString'";
+ }
+
+ 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' ], __METHOD__ );
+
+ }
+
+ if ( $dbr->unionSupportsOrderAndLimit() ) {
+ $order = [
+ 'GROUP BY' => $revUser,
+ 'ORDER BY' => 'page_count DESC',
+ 'LIMIT' => $limit
+ ];
+ } else {
+ $order = [ 'GROUP BY' => $revUser ];
+ }
+
+ $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 = [
+ 'GROUP BY' => 'rev_user',
+ 'ORDER BY' => 'rev_count DESC',
+ 'LIMIT' => $limit
+ ];
+ } else {
+ $order = [ 'GROUP BY' => 'rev_user' ];
+ }
+
+ $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" .
+ "<tr class='header'>\n" .
+ Html::element( 'th', [], $this->msg( 'contributionscores-rank' )->text() ) .
+ Html::element( 'th', [], $this->msg( 'contributionscores-score' )->text() ) .
+ Html::element( 'th', [], $this->msg( 'contributionscores-pages' )->text() ) .
+ Html::element( 'th', [], $this->msg( 'contributionscores-changes' )->text() ) .
+ Html::element( 'th', [], $this->msg( 'contributionscores-username' )->text() );
+
+ $altrow = '';
+ $user_rank = 1;
+
+ $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(
+ $row->user_id,
+ $row->user_name,
+ $row->user_real_name
+ );
+ } else {
+ $userLink = Linker::userLink(
+ $row->user_id,
+ $row->user_name
+ );
+ }
+
+ $output .= Html::closeElement( 'tr' );
+ $output .= "<tr class='{$altrow}'>\n" .
+ "<td class='content' style='padding-right:10px;text-align:right;'>" .
+ $lang->formatNum( round( $user_rank, 0 ) ) .
+ "\n</td><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( $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;
+
+ # Option to not display user tools
+ if ( !in_array( 'notools', $opts ) ) {
+ $output .= Linker::userToolLinks( $row->user_id, $row->user_name );
+ }
+
+ $output .= Html::closeElement( 'td' ) . "\n";
+
+ if ( $altrow == '' && empty( $sortable ) ) {
+ $altrow = 'odd ';
+ } else {
+ $altrow = '';
+ }
+
+ $user_rank++;
+ }
+ $output .= Html::closeElement( 'tr' );
+ $output .= Html::closeElement( 'table' );
+
+ $dbr->freeResult( $res );
+
+ if ( !empty( $title ) ) {
+ $output = Html::rawElement( 'table',
+ [
+ 'style' => 'border-spacing: 0; padding: 0',
+ 'class' => 'contributionscores-wrapper',
+ 'lang' => htmlspecialchars( $lang->getCode() ),
+ 'dir' => $lang->getDir()
+ ],
+ "\n" .
+ "<tr>\n" .
+ "<td style='padding: 0px;'>{$title}</td>\n" .
+ "</tr>\n" .
+ "<tr>\n" .
+ "<td style='padding: 0px;'>{$output}</td>\n" .
+ "</tr>\n"
+ );
+ }
+
+ return $output;
+ }
+
+ function execute( $par ) {
+ $this->setHeaders();
+
+ if ( $this->including() ) {
+ $this->showInclude( $par );
+ } else {
+ $this->showPage();
+ }
+
+ return true;
+ }
+
+ /**
+ * Called when being included on a normal wiki page.
+ * Cache is disabled so it can depend on the user language.
+ * @param string|null $par A subpage give to the special page
+ */
+ function showInclude( $par ) {
+ $days = null;
+ $limit = null;
+ $options = 'none';
+
+ if ( !empty( $par ) ) {
+ $params = explode( '/', $par );
+
+ $limit = intval( $params[0] );
+
+ if ( isset( $params[1] ) ) {
+ $days = intval( $params[1] );
+ }
+
+ if ( isset( $params[2] ) ) {
+ $options = $params[2];
+ }
+ }
+
+ if ( empty( $limit ) || $limit < 1 || $limit > CONTRIBUTIONSCORES_MAXINCLUDELIMIT ) {
+ $limit = 10;
+ }
+ if ( $days === null || $days < 0 ) {
+ $days = 7;
+ }
+
+ if ( $days > 0 ) {
+ $reportTitle = $this->msg( 'contributionscores-days' )->numParams( $days )->text();
+ } else {
+ $reportTitle = $this->msg( 'contributionscores-allrevisions' )->text();
+ }
+ $reportTitle .= ' ' . $this->msg( 'contributionscores-top' )->numParams( $limit )->text();
+ $title = Xml::element( 'h4',
+ [ 'class' => 'contributionscores-title' ],
+ $reportTitle
+ ) . "\n";
+ $this->getOutput()->addHTML( $this->genContributionScoreTable(
+ $days,
+ $limit,
+ $title,
+ $options
+ ) );
+ }
+
+ /**
+ * Show the special page
+ */
+ function showPage() {
+ global $wgContribScoreReports;
+
+ if ( !is_array( $wgContribScoreReports ) ) {
+ $wgContribScoreReports = [
+ [ 7, 50 ],
+ [ 30, 50 ],
+ [ 0, 50 ]
+ ];
+ }
+
+ $out = $this->getOutput();
+ $out->addWikiMsg( 'contributionscores-info' );
+
+ foreach ( $wgContribScoreReports as $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 = Xml::element( 'h2',
+ [ 'class' => 'contributionscores-title' ],
+ $reportTitle
+ ) . "\n";
+ $out->addHTML( $title );
+ $out->addHTML( $this->genContributionScoreTable( $days, $revs ) );
+ }
+ }
+
+ protected function getGroupName() {
+ return 'wiki';
+ }
+}