r105165 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r105164‎ | r105165 | r105166 >
Date:11:20, 5 December 2011
Author:catrope
Status:ok
Tags:
Comment:
Rename extensions/GPoC to extensions/SelectionSifter . Requested on IRC by yuvipanda
Modified paths:
  • /trunk/extensions/GPoC (deleted) (history)
  • /trunk/extensions/SelectionSifter (added) (history)

Diff [purge]

Index: trunk/extensions/SelectionSifter/schema/log.sql
@@ -0,0 +1,34 @@
 2+-- Replace /*_*/ with the proper prefix
 3+-- Replace /*$wgDBTableOptions*/ with the correct options
 4+
 5+CREATE TABLE IF NOT EXISTS /*_*/assessment_changelog (
 6+ l_project varchar(63) not null,
 7+ -- project name
 8+
 9+ l_namespace int unsigned not null,
 10+ -- article namespace
 11+
 12+ l_article varchar(255) not null,
 13+ -- article name
 14+
 15+ l_action varchar(20) character set ascii not null,
 16+ -- type of log entry (e.g. 'quality')
 17+
 18+ l_timestamp binary(14) not null,
 19+ -- timestamp when log entry was added
 20+
 21+ l_old varchar(63),
 22+ -- old value (e.g. B-Class)
 23+
 24+ l_new varchar(63),
 25+ -- new value (e.g. GA-Class)
 26+
 27+ l_revision_timestamp binary(20) not null,
 28+ -- timestamp when page was edited
 29+ -- a wiki-format timestamp
 30+
 31+ primary key (l_project, l_namespace, l_article, l_action, l_timestamp),
 32+ key (l_article, l_namespace)
 33+) /*$wgDBTableOptions*/;
 34+
 35+CREATE INDEX /*i*/l_project ON /*_*/assessment_changelog (l_project);
Property changes on: trunk/extensions/SelectionSifter/schema/log.sql
___________________________________________________________________
Added: svn:eol-style
136 + native
Index: trunk/extensions/SelectionSifter/schema/project_stats.sql
@@ -0,0 +1,49 @@
 2+-- Replace /*_*/ with the proper prefix
 3+-- Replace /*$wgDBTableOptions*/ with the correct options
 4+
 5+CREATE TABLE IF NOT EXISTS /*_*/project_stats (
 6+
 7+ ps_project varchar(63) not null,
 8+ -- project name
 9+
 10+ ps_timestamp binary(14) not null,
 11+ -- last time project data was updated
 12+
 13+ ps_quality varchar(63) not null,
 14+ -- quality assessment. lowercase.
 15+ -- possible values: fa, a, ga, b, b1, b2, b3, b4, b5, b6, c, start, stub, fl, l, unclassified
 16+
 17+ ps_count int unsigned default 0,
 18+ -- how many pages are assessed in project
 19+
 20+ ps_top_icount int unsigned default 0,
 21+ -- how many pages are assessed in project to be top importance
 22+
 23+ ps_high_icount int unsigned default 0,
 24+ -- how many pages are assessed in project to be high importance
 25+
 26+ ps_mid_icount int unsigned default 0,
 27+ -- how many pages are assessed in project to be mid importance
 28+
 29+ ps_low_icount int unsigned default 0,
 30+ -- how many pages are assessed in project to be low importance
 31+
 32+ ps_bottom_icount int unsigned default 0,
 33+ -- how many pages are assessed in project to be bottom importance
 34+
 35+ ps_no_icount int unsigned default 0,
 36+ -- how many pages are assessed in project to be of no importance
 37+
 38+ ps_unclassified_icount int unsigned default 0,
 39+ -- how many pages are assessed in project without a classified importance
 40+
 41+ ps_qcount int unsigned default 0,
 42+ -- how many pages have quality assessments in the project
 43+
 44+ ps_icount int unsigned default 0,
 45+ -- how many pages have importance assessments in the project
 46+
 47+ primary key (ps_project, ps_quality)
 48+) /*$wgDBTableOptions*/;
 49+
 50+CREATE INDEX /*i*/ps_project ON /*_*/project_stats (ps_project);
Property changes on: trunk/extensions/SelectionSifter/schema/project_stats.sql
___________________________________________________________________
Added: svn:eol-style
151 + native
Index: trunk/extensions/SelectionSifter/schema/ratings.sql
@@ -0,0 +1,33 @@
 2+-- Replace /*_*/ with the proper prefix
 3+-- Replace /*$wgDBTableOptions*/ with the correct options
 4+
 5+CREATE TABLE IF NOT EXISTS /*_*/ratings (
 6+ r_project varchar(63) not null,
 7+ -- project name
 8+
 9+ r_namespace int unsigned not null,
 10+ -- article namespace
 11+
 12+ r_article varchar(255) not null,
 13+ -- article title
 14+
 15+ r_quality varchar(63),
 16+ -- quality rating
 17+
 18+ r_quality_timestamp binary(20),
 19+ -- time when quality rating was assigned
 20+ -- NOTE: a revid can be obtained from timestamp via API
 21+ -- a wiki-format timestamp
 22+
 23+ r_importance varchar(63),
 24+ -- importance rating
 25+
 26+ r_importance_timestamp binary(20),
 27+ -- time when importance rating was assigned
 28+ -- a wiki-style timestamp
 29+
 30+ primary key (r_project, r_namespace, r_article)
 31+) /*$wgDBTableOptions*/;
 32+
 33+CREATE INDEX /*i*/r_article ON /*_*/ratings (r_namespace, r_article);
 34+CREATE INDEX /*i*/r_project ON /*_*/ratings (r_project);
Property changes on: trunk/extensions/SelectionSifter/schema/ratings.sql
___________________________________________________________________
Added: svn:eol-style
135 + native
Index: trunk/extensions/SelectionSifter/schema/selections.sql
@@ -0,0 +1,23 @@
 2+-- Replace /*_*/ with the proper prefix
 3+-- Replace /*$wgDBTableOptions*/ with the correct options
 4+
 5+CREATE TABLE IF NOT EXISTS /*_*/selections (
 6+ s_selection_name varchar(63) not null,
 7+ -- project name
 8+
 9+ s_namespace int unsigned not null,
 10+ -- article namespace
 11+
 12+ s_article varchar(255) not null,
 13+ -- article name
 14+
 15+ s_timestamp binary(14) not null,
 16+ -- timestamp when entry was added
 17+
 18+ s_revision int unsigned,
 19+ -- manually set revision
 20+
 21+ primary key (s_selection_name, s_namespace, s_article)
 22+) /*$wgDBTableOptions*/;
 23+
 24+CREATE INDEX /*i*/s_selection_name ON /*_*/selections (s_selection_name);
Property changes on: trunk/extensions/SelectionSifter/schema/selections.sql
___________________________________________________________________
Added: svn:eol-style
125 + native
Index: trunk/extensions/SelectionSifter/TableDisplay.php
@@ -0,0 +1,61 @@
 2+<?php
 3+if ( !defined( 'MEDIAWIKI' ) ) {
 4+ exit( 1 );
 5+}
 6+
 7+/**
 8+ * @todo Document overall purpose of this class.
 9+ */
 10+class TableDisplay {
 11+
 12+ /**
 13+ * Register our parser functions
 14+ */
 15+ public static function ParserFunctionInit( &$parser ) {
 16+ $parser->setFunctionHook( 'AssessmentStats', 'TableDisplay::AssessmentStatsRender' );
 17+ return true;
 18+ }
 19+
 20+ /**
 21+ * Register new magic words.
 22+ */
 23+ public static function LanguageGetMagic( &$magicWords, $langCode ) {
 24+ $magicWords['AssessmentStats'] = array( 0, 'AssessmentStats' );
 25+ return true;
 26+ }
 27+
 28+ /**
 29+ * @todo Document!
 30+ * @param string $projectName
 31+ * @param unknown $projectStats
 32+ * @return string A wikitable containing statistics for a project name
 33+ */
 34+ private static function formatTable( $projectName, $projectStats ) {
 35+ // Column Headers
 36+ $col_headers = array_keys($projectStats['top']);
 37+ $output = "{| class='wikitable' \n|+ $projectName article ratings\n";
 38+ $output .= "|-\n ! scope='col' | \n";
 39+ foreach( $col_headers as $col_header ) {
 40+ $output .= "! scope='col' | $col_header \n";
 41+ }
 42+ foreach( $projectStats as $importance => $qualityRatings ) {
 43+ $output .= "|- \n ! scope='row' | $importance\n";
 44+ foreach( $qualityRatings as $quality => $qualityCount ) {
 45+ $output .= "| $qualityCount \n";
 46+ }
 47+ }
 48+ $output .= "|}";
 49+ return $output;
 50+ }
 51+
 52+ /**
 53+ * Callback for AssessmentsStats parser function
 54+ * @param Parser $parser Parser object passed by MW hook system (unused)
 55+ * @param unknown A project object??
 56+ */
 57+ public static function AssessmentStatsRender( $parser, $project ) {
 58+ $projectStats = Statistics::getProjectStats( $project );
 59+ $output = TableDisplay::formatTable( $project, $projectStats );
 60+ return $output;
 61+ }
 62+}
Property changes on: trunk/extensions/SelectionSifter/TableDisplay.php
___________________________________________________________________
Added: svn:eol-style
163 + native
Index: trunk/extensions/SelectionSifter/models/Statistics.php
@@ -0,0 +1,122 @@
 2+<?php
 3+
 4+/**
 5+ * Has static methods to grab assessment statistics
 6+ **/
 7+
 8+class Statistics {
 9+ public static function getImportanceColumn( $importance ) {
 10+ $importanceColumnMapping = array(
 11+ 'top' => 'ps_top_icount',
 12+ 'high' => 'ps_high_icount',
 13+ 'mid' => 'ps_mid_icount',
 14+ 'low' => 'ps_mid_icount',
 15+ 'no' => 'ps_no_icount',
 16+ '' => 'ps_unclassified_icount'
 17+ );
 18+
 19+ return $importanceColumnMapping[ strtolower( $importance ) ];
 20+ }
 21+
 22+ public static function updateAggregateStats( $rating, $is_new_rating, $update_global = true ) {
 23+ if(! $is_new_rating && empty($rating->old_importance) && empty($rating->old_quality) ) {
 24+ return;
 25+ }
 26+ $dbw = wfGetDB( DB_MASTER );
 27+ $importance_column = Statistics::getImportanceColumn( $rating->importance );
 28+ $dbw->insert(
 29+ 'project_stats',
 30+ array(
 31+ 'ps_project' => $rating->project,
 32+ 'ps_quality' => $rating->quality,
 33+ $importance_column => '0'
 34+ ),
 35+ __METHOD__,
 36+ array( 'IGNORE' )
 37+ );
 38+ $dbw->update(
 39+ 'project_stats',
 40+ array( "$importance_column = $importance_column + 1" ),
 41+ array(
 42+ "ps_project" => $rating->project,
 43+ "ps_quality" => $rating->quality
 44+ ),
 45+ __METHOD__
 46+ );
 47+
 48+ if(! $is_new_rating ) {
 49+ // Is not a new rating, and atleast one of quality or importance has changed
 50+ if(! empty( $rating->old_quality ) ) {
 51+ $q_value = $rating->old_quality;
 52+ } else {
 53+ $q_value = $rating->quality;
 54+ }
 55+ if(! empty( $rating->old_importance) ) {
 56+ $i_column = Statistics::getImportanceColumn( $rating->old_importance );
 57+ } else {
 58+ $i_column = Statistics::getImportanceColumn( $rating->importance );
 59+ }
 60+ $dbw->update(
 61+ 'project_stats',
 62+ array( "$i_column = $i_column - 1" ),
 63+ array(
 64+ "ps_project" => $rating->project,
 65+ "ps_quality" => $q_value
 66+ ),
 67+ __METHOD__
 68+ );
 69+ }
 70+
 71+ if( $update_global ) {
 72+ $global_rating = new Rating(
 73+ "Global Project",
 74+ $rating->namespace,
 75+ $rating->title,
 76+ $rating->quality,
 77+ $rating->quality_timestamp,
 78+ $rating->importance,
 79+ $rating->importance_timestamp
 80+ );
 81+ $global_rating->old_importance = $rating->old_importance;
 82+ $global_rating->old_quality = $rating->old_quality;
 83+ Statistics::updateAggregateStats( $global_rating, $is_new_rating, false );
 84+ }
 85+ }
 86+
 87+ public static function getProjectStats( $project ) {
 88+ $dbr = wfGetDB( DB_SLAVE );
 89+ $query = $dbr->select(
 90+ "project_stats",
 91+ "*",
 92+ array(
 93+ "ps_project" => $project
 94+ ),
 95+ __METHOD__
 96+ );
 97+
 98+ $project_statistics = array(
 99+ "top" => array(),
 100+ "high" => array(),
 101+ "mid" => array(),
 102+ "low" => array(),
 103+ "no" => array(),
 104+ "" => array()
 105+ );
 106+
 107+
 108+ foreach( $query as $row_object ) {
 109+ $data_row = (array)$row_object;
 110+ $quality = $data_row['ps_quality'];
 111+ foreach( $project_statistics as $importance => &$importance_row ) {
 112+ $importance_row[$quality] = $data_row[Statistics::getImportanceColumn( $importance )];
 113+ }
 114+ }
 115+
 116+ // Make '' into 'unclassified'
 117+ $project_statistics['unclassified'] = $project_statistics[''];
 118+ unset( $project_statistics[''] );
 119+
 120+ return $project_statistics;
 121+ }
 122+
 123+}
Property changes on: trunk/extensions/SelectionSifter/models/Statistics.php
___________________________________________________________________
Added: svn:eol-style
1124 + native
Index: trunk/extensions/SelectionSifter/models/Log.php
@@ -0,0 +1,38 @@
 2+<?php
 3+
 4+/**
 5+ * Represents an convenience methods for logging
 6+ **/
 7+class AssessmentChangeLog {
 8+ public static function makeEntry( $project, $namespace, $article, $timestamp, $action, $old, $new ) {
 9+ $dbw = wfGetDB( DB_MASTER );
 10+ $dbw->insert(
 11+ 'assessment_changelog',
 12+ array(
 13+ 'l_project' => $project,
 14+ 'l_namespace' => $namespace,
 15+ 'l_article' => $article,
 16+ 'l_action' => $action,
 17+ 'l_timestamp' => $timestamp,
 18+ 'l_old' => $old,
 19+ 'l_new' => $new,
 20+ 'l_revision_timestamp' => 0
 21+ ),
 22+ __METHOD__
 23+ );
 24+ }
 25+
 26+ public static function getLogs() {
 27+ $dbr = wfGetDB( DB_SLAVE );
 28+ $logs = $dbr->select(
 29+ 'assessment_changelog',
 30+ '*'
 31+ );
 32+ $entries = array();
 33+ foreach( $logs as $entry ) {
 34+ $entry = (array)$entry;
 35+ array_push( $entries, $entry );
 36+ }
 37+ return $entries;
 38+ }
 39+}
Property changes on: trunk/extensions/SelectionSifter/models/Log.php
___________________________________________________________________
Added: svn:eol-style
140 + native
Index: trunk/extensions/SelectionSifter/models/Rating.php
@@ -0,0 +1,207 @@
 2+<?php
 3+
 4+/**
 5+ * Represents an article and associated rating
 6+ **/
 7+class Rating {
 8+ public $project;
 9+ public $namespace;
 10+ public $title;
 11+ public $quality;
 12+ public $quality_timestamp;
 13+ public $importance;
 14+ public $importance_timestamp;
 15+
 16+ public $old_importance;
 17+ public $old_quality;
 18+ private $inDB = false;
 19+
 20+ public function __construct( $project, $namespace, $title, $quality, $quality_timestamp, $importance, $importance_timestamp ) {
 21+ $this->project = $project;
 22+ $this->namespace = $namespace;
 23+ $this->title = $title;
 24+ $this->quality = $quality;
 25+ $this->quality_timestamp = $quality_timestamp;
 26+ $this->importance = $importance;
 27+ $this->importance_timestamp = $importance_timestamp;
 28+ }
 29+
 30+ public function update( $importance, $quality, $timestamp ) {
 31+ $logAction = ""; // q for quality change, i for importance change, qi for both
 32+ if( $quality != $this->quality ) {
 33+ $this->old_quality = $this->quality;
 34+ $this->quality = $quality;
 35+ $this->quality_timestamp = $timestamp;
 36+ $logAction .= "q";
 37+ }
 38+ if( $importance != $this->importance ) {
 39+ $this->old_importance = $this->importance;
 40+ $this->importance = $importance;
 41+ $this->importance_timestamp = $timestamp;
 42+ $logAction .= "i";
 43+ }
 44+ if( $logAction != "") {
 45+ $timestamp = wfTimestamp( TS_MW );
 46+ if( strpos( $logAction, 'q' ) !== false ) {
 47+ AssessmentChangeLog::makeEntry(
 48+ $this->project,
 49+ $this->namespace,
 50+ $this->title,
 51+ $timestamp,
 52+ "quality",
 53+ $this->old_quality,
 54+ $this->quality
 55+ );
 56+ }
 57+ if( strpos( $logAction, 'i' ) !== false ) {
 58+ AssessmentChangeLog::makeEntry(
 59+ $this->project,
 60+ $this->namespace,
 61+ $this->title,
 62+ $timestamp,
 63+ "importance",
 64+ $this->old_importance,
 65+ $this->importance
 66+ );
 67+ }
 68+
 69+ $this->saveAll();
 70+ }
 71+ }
 72+
 73+ public function saveAll() {
 74+ $data_array = array(
 75+ 'r_project' => $this->project,
 76+ 'r_namespace' => $this->namespace,
 77+ 'r_article' => $this->title,
 78+ 'r_quality' => $this->quality,
 79+ 'r_quality_timestamp' => $this->quality_timestamp,
 80+ 'r_importance' => $this->importance,
 81+ 'r_importance_timestamp' => $this->importance_timestamp
 82+ );
 83+ $dbw = wfGetDB( DB_MASTER );
 84+ if( $this->inDB ) {
 85+ $dbw->update(
 86+ "ratings",
 87+ $data_array,
 88+ array(
 89+ 'r_namespace' => $this->namespace,
 90+ 'r_article' => $this->title,
 91+ 'r_project' => $this->project
 92+ ),
 93+ __METHOD__
 94+ );
 95+
 96+ Statistics::updateAggregateStats( $this, false );
 97+ } else {
 98+ $dbw->insert(
 99+ "ratings",
 100+ $data_array,
 101+ __METHOD__
 102+ );
 103+
 104+ Statistics::updateAggregateStats( $this, true );
 105+ $this->inDB = true;
 106+ }
 107+ }
 108+
 109+ public static function forTitle( $title ) {
 110+ $dbr = wfGetDB( DB_SLAVE );
 111+ $query = $dbr->select(
 112+ "ratings",
 113+ array(
 114+ "r_project", "r_namespace", "r_article", "r_quality",
 115+ "r_quality_timestamp", "r_importance", "r_importance_timestamp"
 116+ ),
 117+ array(
 118+ "r_namespace" => $title->getNamespace(),
 119+ "r_article" => $title->getText(),
 120+ ),
 121+ __METHOD__
 122+ );
 123+
 124+ $ratings = array();
 125+
 126+ foreach( $query as $row ) {
 127+ $rating = new Rating(
 128+ $row->r_project, $row->r_namespace,
 129+ $row->r_article, $row->r_quality,
 130+ $row->r_quality_timestamp, $row->r_importance,
 131+ $row->r_importance_timestamp);
 132+ $rating->inDB = true;
 133+ $ratings[$rating->project] = $rating;
 134+ }
 135+ return $ratings;
 136+ }
 137+
 138+ public static function moveArticle( $oldTitle, $newTitle ) {
 139+ // Can be optimized to use two queries - so we touch DB_MASTER only if necessary
 140+ // But is that a good thing?
 141+ $dbw = wfGetDB( DB_MASTER );
 142+ $dbw->update(
 143+ 'ratings',
 144+ array(
 145+ 'r_namespace' => $newTitle->getNamespace(),
 146+ 'r_article' => $newTitle->getText()
 147+ ),
 148+ array(
 149+ 'r_namespace' => $oldTitle->getNamespace(),
 150+ 'r_article' => $oldTitle->getText()
 151+ ),
 152+ __METHOD__
 153+ );
 154+ // Article moves not logged - yet
 155+ }
 156+
 157+ private static function checkArticle( $article, $category_filters ) {
 158+ // Check category
 159+ if( count( $category_filters ) == 0 || ( count($category_filters) == 1 && empty( $category_filters[0] ) ) ) {
 160+ return true;
 161+ }
 162+
 163+ foreach( $category_filters as $category ) {
 164+ if( in_array( $category, $article['categories'] ) ) {
 165+ return true;
 166+ }
 167+ }
 168+ return false;
 169+ }
 170+
 171+ public static function filterArticles( $filters ) {
 172+ $database_filters_columns = array( 'r_project', 'r_importance', 'r_quality' );
 173+
 174+ $dbr = wfGetDB( DB_SLAVE );
 175+ $database_filters = array();
 176+
 177+ foreach($filters as $column => $value) {
 178+ if( ! ( !isset($value) or $value == null or $value == "" ) && in_array( $column, $database_filters_columns ) ) {
 179+ $database_filters[$column] = $value;
 180+ }
 181+ }
 182+ $category_filters = explode( ',', trim( $filters['categories'] ) );
 183+ $query = $dbr->select(
 184+ 'ratings',
 185+ '*',
 186+ $database_filters,
 187+ __METHOD__
 188+ );
 189+
 190+ $articles = array();
 191+ foreach( $query as $article_row ) {
 192+ $article = (array)$article_row;
 193+ $title = Title::makeTitle( $article['r_namespace'], $article['r_article'] );
 194+ $article['title'] = $title;
 195+ $categories = array_keys( $title->getParentCategories() );
 196+ $article['categories'] = array();
 197+ foreach( $categories as $category ) {
 198+ $split = explode(':', $category);
 199+ array_push( $article['categories'], trim( $split[1] ) );
 200+ }
 201+
 202+ if( Rating::checkArticle( $article, $category_filters ) ) {
 203+ array_push( $articles, $article );
 204+ }
 205+ }
 206+ return $articles;
 207+ }
 208+}
Property changes on: trunk/extensions/SelectionSifter/models/Rating.php
___________________________________________________________________
Added: svn:eol-style
1209 + native
Index: trunk/extensions/SelectionSifter/models/Selection.php
@@ -0,0 +1,74 @@
 2+<?php
 3+
 4+/**
 5+ * Represents an convenience methods for logging
 6+ **/
 7+class Selection {
 8+ public static function addEntries( $name, $articles ) {
 9+ $dbw = wfGetDB( DB_MASTER );
 10+ $timestamp = wfTimestamp( TS_MW );
 11+ foreach( $articles as $article ) {
 12+ $success = $dbw->insert(
 13+ 'selections',
 14+ array(
 15+ 's_selection_name' => $name,
 16+ 's_namespace' => $article['r_namespace'],
 17+ 's_article' => $article['r_article'],
 18+ 's_timestamp' => $timestamp
 19+ ),
 20+ __METHOD__,
 21+ array( 'IGNORE' )
 22+ );
 23+ }
 24+ }
 25+
 26+ public static function setRevision( $name, $namespace, $article, $revision ) {
 27+ $dbw = wfGetDB( DB_MASTER );
 28+ $success = $dbw->update(
 29+ 'selections',
 30+ array(
 31+ 's_revision' => $revision
 32+ ),
 33+ array(
 34+ 's_selection_name' => $name,
 35+ 's_namespace' => $namespace,
 36+ 's_article' => $article
 37+ ),
 38+ __METHOD__
 39+ );
 40+ return $success;
 41+ }
 42+
 43+ public static function deleteArticle( $name, $namespace, $article ) {
 44+ $dbw = wfGetDB( DB_MASTER );
 45+ $success = $dbw->delete(
 46+ 'selections',
 47+ array(
 48+ 's_selection_name' => $name,
 49+ 's_namespace' => $namespace,
 50+ 's_article' => $article
 51+ ),
 52+ __METHOD__
 53+ );
 54+ return $success;
 55+ }
 56+ public static function getSelection( $name ) {
 57+ $dbr = wfGetDB( DB_SLAVE );
 58+
 59+ $query = $dbr->select(
 60+ 'selections',
 61+ '*',
 62+ array('s_selection_name' => $name),
 63+ __METHOD__
 64+ );
 65+
 66+ $articles = array();
 67+ foreach( $query as $article_row ) {
 68+ $article = (array)$article_row;
 69+ $title = Title::makeTitle( $article['s_namespace'], $article['s_article'] );
 70+ $article['title'] = $title;
 71+ array_push( $articles, $article );
 72+ }
 73+ return $articles;
 74+ }
 75+}
Property changes on: trunk/extensions/SelectionSifter/models/Selection.php
___________________________________________________________________
Added: svn:eol-style
176 + native
Index: trunk/extensions/SelectionSifter/SpecialFilterRatings.php
@@ -0,0 +1,68 @@
 2+<?php
 3+/**
 4+ */
 5+
 6+if ( !defined( 'MEDIAWIKI' ) ) {
 7+ echo( "not a valid entry point.\n" );
 8+ die( 1 );
 9+}
 10+
 11+class SpecialFilterRatings extends SpecialPage {
 12+
 13+ public function __construct() {
 14+ parent::__construct( 'FilterRatings' );
 15+ }
 16+
 17+ // prototypey code
 18+ public function execute( $par ) {
 19+ global $wgOut, $wgRequest;
 20+
 21+ $project = $wgRequest->getVal('project');
 22+ $importance = $wgRequest->getVal('importance');
 23+ $quality = $wgRequest->getVal('quality');
 24+ $categories = $wgRequest->getVal('categories');
 25+
 26+ $filters = array(
 27+ 'r_project' => $project,
 28+ 'r_importance' => $importance,
 29+ 'r_quality' => $quality,
 30+ 'categories' => $categories
 31+ );
 32+
 33+ $categories = explode(',', $wgRequest->getVal('categories'));
 34+ foreach($categories as &$category) {
 35+ $category = trim($category);
 36+ }
 37+ $entries = Rating::filterArticles($filters);
 38+
 39+ if( $wgRequest->wasPosted() ) {
 40+ $wgOut->disable();
 41+
 42+ $action = $wgRequest->getVal('action');
 43+ $selection_name = $wgRequest->getVal('selection');
 44+
 45+ if( $action == 'addtoselection' ) {
 46+ $success = Selection::addEntries($selection_name, $entries);
 47+ $sel_page = new SpecialSelection();
 48+
 49+ $url = $sel_page->getTitle()->getLinkUrl( array( 'name' => $selection_name ) );
 50+ $return = array(
 51+ 'status' => $success,
 52+ 'selection_url' => $url
 53+ );
 54+ }
 55+ echo json_encode($return);
 56+ return;
 57+ }
 58+
 59+ $this->setHeaders();
 60+
 61+ $wgOut->setPageTitle("Filter Articles by Ratings");
 62+
 63+ $template = new FilterRatingsTemplate();
 64+ $template->set( 'filters', $filters );
 65+ $template->set( 'articles', $entries );
 66+
 67+ $wgOut->addTemplate( $template );
 68+ }
 69+}
Property changes on: trunk/extensions/SelectionSifter/SpecialFilterRatings.php
___________________________________________________________________
Added: svn:eol-style
170 + native
Index: trunk/extensions/SelectionSifter/SelectionSifter.php
@@ -0,0 +1,48 @@
 2+<?php
 3+/**
 4+ * Proof of Concept for Yuvi Panda's 2011 GSoC
 5+ *
 6+ * @file
 7+ * @ingroup Extensions
 8+ * @author Yuvi Panda, http://yuvi.in
 9+ * @copyright © 2011 Yuvaraj Pandian (yuvipanda@yuvi.in)
 10+ * @licence Modified BSD License
 11+ */
 12+
 13+if( !defined( 'MEDIAWIKI' ) ) {
 14+ echo( "This file is an extension to the MediaWiki software and cannot be used standalone.\n" );
 15+ die( 1 );
 16+}
 17+
 18+// Extension credits that will show up on Special:Version
 19+
 20+// Set up the new special page
 21+$dir = dirname( __FILE__ ) . '/';
 22+
 23+$wgAutoloadClasses['SelectionSifterHooks'] = $dir . 'SelectionSifter.hooks.php';
 24+$wgAutoloadClasses['Statistics'] = $dir . 'models/Statistics.php';
 25+$wgAutoloadClasses['Rating'] = $dir . 'models/Rating.php';
 26+$wgAutoloadClasses['AssessmentChangeLog'] = $dir . 'models/Log.php';
 27+$wgAutoloadClasses['Selection'] = $dir . 'models/Selection.php';
 28+$wgAutoloadClasses['TableDisplay'] = $dir . 'TableDisplay.php';
 29+$wgAutoloadClasses['AssessmentsExtractor'] = $dir . 'AssessmentsExtractor.php';
 30+$wgAutoloadClasses['SpecialAssessmentLog'] = $dir . 'SpecialAssessmentLog.php';
 31+$wgAutoloadClasses['SpecialFilterRatings'] = $dir . 'SpecialFilterRatings.php';
 32+$wgAutoloadClasses['SpecialSelection'] = $dir . 'SpecialSelection.php';
 33+
 34+$wgAutoloadClasses['FilterRatingsTemplate'] = $dir . 'templates/FilterRatingsTemplate.php';
 35+$wgAutoloadClasses['SelectionTemplate'] = $dir . 'templates/SelectionTemplate.php';
 36+
 37+$wgHooks['ArticleSaveComplete'][] = 'SelectionSifterHooks::ArticleSaveComplete';
 38+$wgHooks['LoadExtensionSchemaUpdates'][] = 'SelectionSifterHooks::SetupSchema';
 39+
 40+$wgHooks['ParserFirstCallInit'][] = 'TableDisplay::ParserFunctionInit';
 41+$wgHooks['LanguageGetMagic'][] = 'TableDisplay::LanguageGetMagic';
 42+
 43+$wgHooks['TitleMoveComplete'][] = 'SelectionSifterHooks::TitleMoveComplete';
 44+
 45+$wgSpecialPages['AssessmentLog'] = 'SpecialAssessmentLog';
 46+$wgSpecialPages['FilterRatings'] = 'SpecialFilterRatings';
 47+$wgSpecialPages['Selection'] = 'SpecialSelection';
 48+
 49+// Configuration
Property changes on: trunk/extensions/SelectionSifter/SelectionSifter.php
___________________________________________________________________
Added: svn:eol-style
150 + native
Index: trunk/extensions/SelectionSifter/AssessmentsExtractor.php
@@ -0,0 +1,40 @@
 2+<?php
 3+
 4+/**
 5+ * Helps extract assessments from a parsed $DOM file
 6+ **/
 7+class AssessmentsExtractor
 8+{
 9+ /** @todo document */
 10+ private $mText;
 11+
 12+ /**
 13+ * @todo Document
 14+ * @param string $preparedText TODO: what is it for?
 15+ */
 16+ function __construct( $preparedText ) {
 17+ $this->mText = $preparedText;
 18+ }
 19+
 20+ /**
 21+ * Once AssessmentsExtractor is build, call this method to generate
 22+ * an array of assessment.
 23+ * @todo Describe the returned array
 24+ * @todo What happens if the preparedText does not match the expected format?
 25+ * @return array Assessments
 26+ */
 27+ public function extractAssessments() {
 28+ $regex = '/<span data-project-name="(?P<project>.*)" data-importance="(?P<importance>.*)" data-quality="(?P<quality>.*)"\s*>/';
 29+ $matches = array();
 30+ preg_match_all($regex, $this->mText, $matches, PREG_SET_ORDER);
 31+
 32+ $assessments = array();
 33+ foreach($matches as $match) {
 34+ $assessments[$match['project']] = array(
 35+ 'importance' => $match['importance'],
 36+ 'quality' => $match['quality']
 37+ );
 38+ }
 39+ return $assessments;
 40+ }
 41+}
Property changes on: trunk/extensions/SelectionSifter/AssessmentsExtractor.php
___________________________________________________________________
Added: svn:eol-style
142 + native
Index: trunk/extensions/SelectionSifter/SelectionSifter.hooks.php
@@ -0,0 +1,65 @@
 2+<?php
 3+/**
 4+ *
 5+ * @file
 6+ * @ingroup Extensions
 7+ * @author Yuvi Panda, http://yuvi.in
 8+ * @copyright © 2011 Yuvaraj Pandian (yuvipanda@yuvi.in)
 9+ * @licence Modified BSD License
 10+ */
 11+
 12+if ( !defined( 'MEDIAWIKI' ) ) {
 13+ exit( 1 );
 14+}
 15+
 16+class SelectionSifterHooks {
 17+
 18+ private static function updateDatabase( $title, $assessments, $timestamp ) {
 19+ $main_title = Title::makeTitle( NS_MAIN, $title->getText() );
 20+ $ratings = Rating::forTitle( $main_title );
 21+ foreach ( $assessments as $project => $assessment ) {
 22+ $curRating = $ratings[$project];
 23+ if( $curRating ) {
 24+ $curRating->update( $assessment['importance'], $assessment['quality'], 0 );
 25+ } else {
 26+ $rating = new Rating(
 27+ $project,
 28+ $main_title->getNamespace(),
 29+ $main_title->getText(),
 30+ $assessment['quality'],
 31+ 0,
 32+ $assessment['importance'],
 33+ 0
 34+ );
 35+ $rating->saveAll();
 36+ }
 37+ }
 38+ }
 39+
 40+ public static function TitleMoveComplete( &$title, &$newtitle, &$user, $oldid, $newid ) {
 41+ Rating::moveArticle( $title, $newtitle );
 42+ return true;
 43+ }
 44+
 45+ public static function ArticleSaveComplete(&$article, &$user, $text, $summary, $minoredit, $watchthis, $sectionanchor, &$flags, $revision, &$status, $baseRevId) {
 46+ global $wgParser;
 47+ $title = $article->getTitle();
 48+ if( $title->getNamespace() == NS_TALK && $revision ) {
 49+ // All conditions to minimize the situations we've to run the job to update the data
 50+ $preparedText = $article->prepareTextForEdit( $text )->output->getText();
 51+ $extractor = new AssessmentsExtractor( $preparedText );
 52+ $assessments = $extractor->extractAssessments();
 53+ SelectionSifterHooks::updateDatabase( $title, $assessments, $revision );
 54+ }
 55+ return true;
 56+ }
 57+
 58+ public static function SetupSchema( DatabaseUpdater $du ) {
 59+ $base = dirname( __FILE__ ) . '/schema';
 60+ $du->addExtensionTable( "ratings", "$base/ratings.sql");
 61+ $du->addExtensionTable( "project_stats", "$base/project_stats.sql" );
 62+ $du->addExtensionTable( "assessment_changelog", "$base/log.sql" );
 63+ $du->addExtensionTable( "selections", "$base/selections.sql" );
 64+ return true;
 65+ }
 66+}
Property changes on: trunk/extensions/SelectionSifter/SelectionSifter.hooks.php
___________________________________________________________________
Added: svn:eol-style
167 + native
Index: trunk/extensions/SelectionSifter/SpecialSelection.php
@@ -0,0 +1,92 @@
 2+<?php
 3+/**
 4+ */
 5+
 6+if ( !defined( 'MEDIAWIKI' ) ) {
 7+ echo( "not a valid entry point.\n" );
 8+ die( 1 );
 9+}
 10+
 11+class SpecialSelection extends SpecialPage {
 12+
 13+ public function __construct() {
 14+ parent::__construct( 'Selection' );
 15+ }
 16+
 17+ private function makeCSV( $articles, $name ) {
 18+ $outstream = fopen( "php://output", "w" );
 19+ $headers = array(
 20+ 'article',
 21+ 'revision',
 22+ 'added'
 23+ );
 24+ fputcsv( $outstream, $headers );
 25+ foreach( $articles as $article ) {
 26+ $row = array(
 27+ $article['title']->getFullText(),
 28+ $article['s_revision'],
 29+ wfTimeStamp( TS_ISO_8601, $article['s_timestamp'] )
 30+ );
 31+ fputcsv( $outstream, $row );
 32+ }
 33+ fclose( $outstream );
 34+ }
 35+
 36+ public function execute( $par ) {
 37+ global $wgOut, $wgRequest;
 38+
 39+ $name = $wgRequest->getVal( 'name' );
 40+ $format = $wgRequest->getVal( 'format' );
 41+
 42+ if( $wgRequest->wasPosted() ) {
 43+ $wgOut->disable();
 44+ $namespace = $wgRequest->getVal( 'namespace' );
 45+ $article = $wgRequest->getVal( 'article' );
 46+
 47+ $action = $wgRequest->getVal( 'action' );
 48+ if( $action == 'setrevision' ) {
 49+ $revision = $wgRequest->getVal( 'revision' );
 50+ $success = Selection::setRevision( $name, $namespace, $article, $revision );
 51+ $title = Title::makeTitle( $namespace, $article );
 52+ $url = $title->getLinkUrl( array( 'oldid' => $revision ) );
 53+ $return = array(
 54+ 'status' => $success,
 55+ 'revision' => $revision,
 56+ 'revision_url' => $url
 57+ );
 58+ } elseif ( $action == 'deletearticle') {
 59+ $success = Selection::deleteArticle( $name, $namespace, $article );
 60+ $return = array(
 61+ 'status' => $success
 62+ );
 63+ }
 64+ echo json_encode($return);
 65+ return;
 66+ }
 67+ $entries = Selection::getSelection( $name );
 68+ $this->setHeaders();
 69+
 70+ $wgOut->setPageTitle("Selection");
 71+
 72+ if( $format == 'csv' ) {
 73+ $wgRequest->response()->header( 'Content-type: text/csv' );
 74+ // Is there a security issue in letting the name be arbitrary?
 75+ $wgRequest->response()->header(
 76+ "Content-Disposition: attachment; filename=$name.csv"
 77+ );
 78+ $wgOut->disable();
 79+ $this->makeCSV( $entries, $name );
 80+ }
 81+
 82+ $csv_link = $this->getFullTitle()->getFullUrl( array(
 83+ 'format' => 'csv',
 84+ 'name' => $name
 85+ ) );
 86+ $template = new SelectionTemplate();
 87+ $template->set( 'articles', $entries );
 88+ $template->set( 'name', $name );
 89+ $template->set( 'csv_link', $csv_link );
 90+
 91+ $wgOut->addTemplate( $template );
 92+ }
 93+}
Property changes on: trunk/extensions/SelectionSifter/SpecialSelection.php
___________________________________________________________________
Added: svn:eol-style
194 + native
Index: trunk/extensions/SelectionSifter/README
@@ -0,0 +1,8 @@
 2+Extension to provide Asssessment parsing and collection/filtering based on assessments for creating collections of articles. Used primarily for the Wikipedia Offline projeect.
 3+
 4+This is YuviPanda's GSoC 2011 Project. The extension works only on MySQL, with a proper engine that supports Transactions.
 5+
 6+This is intended to replace the WP1.0 bot [1] in use on the english wikipedia. The major aim is to make it easier to select and export article selections for various offline collections (Wikipedia 1.0 being such a collection).
 7+
 8+
 9+[1] http://en.wikipedia.org/wiki/User:WP_1.0_bot
Property changes on: trunk/extensions/SelectionSifter/README
___________________________________________________________________
Added: svn:eol-style
110 + native
Index: trunk/extensions/SelectionSifter/.vimrc
@@ -0,0 +1,2 @@
 2+set noexpandtab
 3+set tabstop=4
Property changes on: trunk/extensions/SelectionSifter/.vimrc
___________________________________________________________________
Added: svn:eol-style
14 + native
Index: trunk/extensions/SelectionSifter/SpecialAssessmentLog.php
@@ -0,0 +1,29 @@
 2+<?php
 3+/**
 4+ * @todo Document this file
 5+ */
 6+
 7+if ( !defined( 'MEDIAWIKI' ) ) {
 8+ echo( "not a valid entry point.\n" );
 9+ die( 1 );
 10+}
 11+
 12+/**
 13+ * A special page showing various logs related to the assessment extension
 14+ */
 15+class SpecialAssessmentLog extends SpecialPage {
 16+
 17+ public function __construct() {
 18+ parent::__construct( 'AssessmentLog' );
 19+ }
 20+
 21+ public function execute( $par ) {
 22+ global $wgOut, $wgRequest;
 23+
 24+ $entries = AssessmentChangeLog::getLogs();
 25+
 26+ $element = Html::element( 'div', array(), print_r( $entries, true) );
 27+
 28+ $wgOut->addHTML( $element );
 29+ }
 30+}
Property changes on: trunk/extensions/SelectionSifter/SpecialAssessmentLog.php
___________________________________________________________________
Added: svn:eol-style
131 + native
Index: trunk/extensions/SelectionSifter/templates/FilterRatingsTemplate.php
@@ -0,0 +1,70 @@
 2+<?php
 3+if( !defined( 'MEDIAWIKI' ) ) {
 4+ die( -1 );
 5+}
 6+
 7+class FilterRatingsTemplate extends QuickTemplate {
 8+ public function execute() {
 9+ $articles = $this->data['articles'];
 10+ $filters = $this->data['filters'];
 11+?>
 12+
 13+<form method="GET" id="filterForm">
 14+<p>
 15+Project Name: <input type="text" name="project" value="<?php echo htmlentities( $filters['r_project'] ); ?>" />
 16+Importance: <input type="text" name="importance" value="<?php echo htmlentities( $filters['r_importance'] ); ?>" />
 17+Quality: <input type="text" name="quality" value="<?php echo htmlentities( $filters['r_quality'] ); ?>" />
 18+<br />
 19+Categories (comma separated): <input type="text" name="categories" value="<?php echo htmlentities( $filters['categories'] ); ?>" />
 20+<input type="submit" id="submit-query" />
 21+</p>
 22+</form>
 23+<div>
 24+Add to Selection:
 25+<input type="text" name="selection" id="selection" />
 26+<input type="button" id="add-to-selection" value="Add" />
 27+</div>
 28+<div id="notice">
 29+</div>
 30+<div id="">
 31+<?php if( count($articles) > 0 ) { ?>
 32+<h3>Results</h3>
 33+ <table>
 34+ <tr>
 35+ <th>Project</th>
 36+ <th>Article</th>
 37+ <th>Importance</th>
 38+ <th>Quality</th>
 39+ </tr>
 40+ <?php foreach( $articles as $article ) { ?>
 41+ <tr>
 42+ <td><?php echo htmlentities( $article['r_project'] ); ?></td>
 43+ <td><a href="<?php echo htmlentities( $article['title']->getLinkURL() ); ?>"><?php echo htmlentities( $article['r_article'] ); ?></a></td>
 44+ <td><?php echo htmlentities( $article['r_importance'] ); ?></td>
 45+ <td><?php echo htmlentities( $article['r_quality'] ); ?></td>
 46+ </tr>
 47+ <?php } ?>
 48+ </table>
 49+<?php } else { ?>
 50+<p>No results found</p>
 51+<?php } ?>
 52+</div>
 53+
 54+ <script type="text/javascript">
 55+ // Should I use RL for tiny snippets like this too?
 56+ $("#add-to-selection").click(function() {
 57+ var selection = $("#selection").val();
 58+ $.post("", {
 59+ action: "addtoselection",
 60+ selection: selection
 61+ }, function(raw_data) {
 62+ var data = $.parseJSON(raw_data);
 63+ $("#notice").hide().html("Added to selection <a href='" + data.selection_url + "'>" + selection + "</a>").fadeIn();
 64+ });
 65+ return false;
 66+ });
 67+ </script>
 68+
 69+<?php
 70+ } // execute()
 71+} // class
Property changes on: trunk/extensions/SelectionSifter/templates/FilterRatingsTemplate.php
___________________________________________________________________
Added: svn:eol-style
172 + native
Index: trunk/extensions/SelectionSifter/templates/SelectionTemplate.php
@@ -0,0 +1,109 @@
 2+<?php
 3+if( !defined( 'MEDIAWIKI' ) ) {
 4+ die( -1 );
 5+}
 6+
 7+class SelectionTemplate extends QuickTemplate {
 8+ public function execute() {
 9+ $articles = $this->data['articles'];
 10+ $name = $this->data['name'];
 11+ $csv_link = $this->data['csv_link'];
 12+?>
 13+
 14+<div id="">
 15+<?php if( count($articles) > 0 ) { ?>
 16+<h3>Articles in Selection <?php echo htmlentities( $name ); ?></h3> <small><a href="<?php echo htmlentities( $csv_link ); ?>">Export CSV</a></small>
 17+ <table>
 18+ <tr>
 19+ <th style="width:150px">Article</th>
 20+ <th style="width:150px">Added on</th>
 21+ <th style="width:75px">Revision</th>
 22+ <th style="width:300px">Actions</th>
 23+ </tr>
 24+ <?php foreach( $articles as $article ) { ?>
 25+ <tr class="article-row" data-namespace="<?php echo htmlentities( $article['s_namespace'] ); ?>" data-article="<?php echo htmlentities( $article['s_article'] ); ?>">
 26+ <td><a href="<?php echo $article['title']->getLinkURL(); ?>"><?php echo htmlentities( $article['s_article'] ); ?></a></td>
 27+ <td><?php echo wfTimeStamp( TS_ISO_8601, $article['s_timestamp'] ); ?></td>
 28+ <td><?php if($article['s_revision'] != null) { ?>
 29+ <a href="<?php echo htmlentities( $article['title']->getLinkUrl( array( 'oldid' => $article['s_revision'] ) ) ); ?>" class="revision-link"><?php echo htmlentities( $article['s_revision'] ); ?></a>
 30+ <?php } ?>
 31+ </td>
 32+ <td>
 33+ <div class="item-actions">
 34+ <div class="revision-input" style="display:none">
 35+ <input type="text" class="revision-id" placeholder="Enter revision id" value="<?php echo htmlentities( $article['s_revision'] ); ?>" />
 36+ (<a href="#" class="revision-save">Save</a> | <a href="#" class="revision-cancel">Cancel</a>)
 37+ </div>
 38+ <a href="#" class="change-revision">Set Revision</a> |
 39+ <a href="#" class="delete-article">Delete</a>
 40+ </div>
 41+ </td>
 42+ </tr>
 43+ <?php } ?>
 44+ </table>
 45+<?php } else { ?>
 46+<p>No such selection found</p>
 47+<?php } ?>
 48+</div>
 49+
 50+ <script type="text/javascript">
 51+ // Should this be a RL module?
 52+ $(document).ready(function() {
 53+ $(".change-revision").click(function() {
 54+ var parent = $(this).parents(".article-row");
 55+ var input_box = $(".revision-input", parent);
 56+ input_box.fadeToggle();
 57+ return false;
 58+ });
 59+ $(".revision-save").click(function() {
 60+ var parent = $(this).parents(".article-row");
 61+ var ns = parent.attr("data-namespace"),
 62+ article = parent.attr("data-article");
 63+ var input = $("input.revision-id", parent);
 64+ var input_box = $(".revision-input", parent);
 65+ var revlink = $(".revision-link", parent);
 66+
 67+ var revid = input.val();
 68+
 69+ $.post('', {
 70+ action: 'setrevision',
 71+ namespace: ns,
 72+ article: article,
 73+ revision: revid
 74+ }, function(raw_data) {
 75+ var data = $.parseJSON(raw_data)
 76+ console.log(data);
 77+ input_box.fadeOut();
 78+ revlink.hide();
 79+ revlink.attr("href", data.revision_url).html(data.revision).fadeIn();
 80+ });
 81+
 82+ return false;
 83+ });
 84+ $(".delete-article").click(function() {
 85+ var parent = $(this).parents(".article-row");
 86+ var ns = parent.attr("data-namespace"),
 87+ article = parent.attr("data-article");
 88+
 89+ $.post('', {
 90+ action: 'deletearticle',
 91+ namespace: ns,
 92+ article: article
 93+ }, function() {
 94+ parent.fadeOut();
 95+ });
 96+
 97+ return false;
 98+ });
 99+
 100+ $(".revision-cancel").click(function() {
 101+ var parent = $(this).parents("div.item-actions");
 102+ var input_box = parent.children(".revision-input");
 103+ input_box.fadeOut();
 104+ });
 105+ });
 106+ </script>
 107+
 108+<?php
 109+ } // execute()
 110+} // class
Property changes on: trunk/extensions/SelectionSifter/templates/SelectionTemplate.php
___________________________________________________________________
Added: svn:eol-style
1111 + native

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r105128Renamed GPoC to SelectionSifteryuvipanda21:38, 4 December 2011

Status & tagging log