r55610 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r55609‎ | r55610 | r55611 >
Date:18:26, 26 August 2009
Author:tstarling
Status:deferred
Tags:
Comment:
Some improvments to tallying, and a script to convert an XML vote dump file to a more compact, human-readable format.
Modified paths:
  • /trunk/extensions/SecurePoll/cli/convertVotes.php (added) (history)
  • /trunk/extensions/SecurePoll/cli/tally.php (modified) (history)
  • /trunk/extensions/SecurePoll/includes/Ballot.php (modified) (history)
  • /trunk/extensions/SecurePoll/includes/Store.php (modified) (history)
  • /trunk/extensions/SecurePoll/includes/Tallier.php (modified) (history)

Diff [purge]

Index: trunk/extensions/SecurePoll/includes/Tallier.php
@@ -259,14 +259,14 @@
260260
261261 # Header row
262262 foreach ( $rankedIds as $oid ) {
263 - $s .= Xml::element( 'th', array(), $abbrevs[$oid] ) . "\n";
 263+ $s .= Xml::tags( 'th', array(), $abbrevs[$oid] ) . "\n";
264264 }
265265 $s .= "</tr>\n";
266266
267267 foreach ( $rankedIds as $oid1 ) {
268268 # Header column
269269 $s .= "<tr>\n";
270 - $s .= Xml::element( 'td', array( 'class' => 'securepoll-results-row-heading' ),
 270+ $s .= Xml::tags( 'td', array( 'class' => 'securepoll-results-row-heading' ),
271271 $rowLabels[$oid1] );
272272 # Rest of the matrix
273273 foreach ( $rankedIds as $oid2 ) {
@@ -283,6 +283,7 @@
284284 $s .= "</tr>\n";
285285 }
286286 $s .= "</table>";
 287+ return $s;
287288 }
288289
289290 function convertMatrixToText( $matrix, $rankedIds ) {
@@ -567,7 +568,7 @@
568569 $s = $wgOut->parse( '<h2>' . wfMsgNoTrans( 'securepoll-ranks' ) . "</h2>\n" );
569570 $s .= $this->convertRanksToHtml( $this->ranks );
570571
571 - $s = $wgOut->parse( '<h2>' . wfMsgNoTrans( 'securepoll-pairwise-victories' ) . "</h2>\n" );
 572+ $s .= $wgOut->parse( '<h2>' . wfMsgNoTrans( 'securepoll-pairwise-victories' ) . "</h2>\n" );
572573 $rankedIds = array_keys( $this->ranks );
573574 $s .= $this->convertMatrixToHtml( $this->victories, $rankedIds );
574575
Index: trunk/extensions/SecurePoll/includes/Store.php
@@ -323,7 +323,7 @@
324324 */
325325 class SecurePoll_XMLStore extends SecurePoll_MemoryStore {
326326 var $xmlReader, $fileName;
327 - var $voteCallback, $voteElectionId;
 327+ var $voteCallback, $voteElectionId, $voteCallbackStatus;
328328
329329 /** Valid entity info keys by entity type. */
330330 static $entityInfoKeys = array(
@@ -440,7 +440,11 @@
441441 && $electionInfo['id'] == $this->voteElectionId )
442442 {
443443 $record = $this->readStringElement();
444 - call_user_func( $this->voteCallback, $this, $record );
 444+ $status = call_user_func( $this->voteCallback, $this, $record );
 445+ if ( !$status->isOK() ) {
 446+ $this->voteCallbackStatus = $status;
 447+ return false;
 448+ }
445449 } else {
446450 $xr->next();
447451 }
@@ -579,9 +583,12 @@
580584 function callbackValidVotes( $electionId, $callback ) {
581585 $this->voteCallback = $callback;
582586 $this->voteElectionId = $electionId;
 587+ $this->voteCallbackStatus = Status::newGood();
583588 $success = $this->readFile();
584589 $this->voteCallback = $this->voteElectionId = null;
585 - if ( $success ) {
 590+ if ( !$this->voteCallbackStatus->isOK() ) {
 591+ return $this->voteCallbackStatus;
 592+ } elseif ( $success ) {
586593 return Status::newGood();
587594 } else {
588595 return Status::newFatal( 'securepoll-dump-file-corrupt' );
Index: trunk/extensions/SecurePoll/includes/Ballot.php
@@ -34,6 +34,19 @@
3535 abstract function unpackRecord( $record );
3636
3737 /**
 38+ * Convert a record to a string of some kind
 39+ */
 40+ function convertRecord( $record, $options = array() ) {
 41+ $scores = $this->unpackRecord( $record );
 42+ return $this->convertScores( $scores );
 43+ }
 44+
 45+ /**
 46+ * Convert a score array to a string of some kind
 47+ */
 48+ abstract function convertScores( $scores, $options = array() );
 49+
 50+ /**
3851 * Create a ballot of the given type
3952 * @param $context SecurePoll_Context
4053 * @param $type string
@@ -166,6 +179,23 @@
167180 }
168181 return $result;
169182 }
 183+
 184+ function convertScores( $scores, $options = array() ) {
 185+ $s = '';
 186+ foreach ( $this->election->getQuestions() as $question ) {
 187+ $qid = $question->getId();
 188+ if ( !isset( $scores[$qid] ) ) {
 189+ return false;
 190+ }
 191+ if ( $s !== '' ) {
 192+ $s .= '; ';
 193+ }
 194+ $oid = keys( $scores );
 195+ $option = $this->election->getOption( $oid );
 196+ $s .= $option->getMessage( 'name' );
 197+ }
 198+ return $s;
 199+ }
170200 }
171201
172202 /**
@@ -264,5 +294,33 @@
265295 }
266296 return $ranks;
267297 }
 298+
 299+ function convertScores( $scores, $options = array() ) {
 300+ $result = array();
 301+ foreach ( $this->election->getQuestions() as $question ) {
 302+ $qid = $question->getId();
 303+ if ( !isset( $scores[$qid] ) ) {
 304+ return false;
 305+ }
 306+ $s = '';
 307+ $qscores = $scores[$qid];
 308+ ksort( $qscores );
 309+ $first = true;
 310+ foreach ( $qscores as $rank ) {
 311+ if ( $first ) {
 312+ $first = false;
 313+ } else {
 314+ $s .= ', ';
 315+ }
 316+ if ( $rank == 1000 ) {
 317+ $s .= '-';
 318+ } else {
 319+ $s .= $rank;
 320+ }
 321+ }
 322+ $result[$qid] = $s;
 323+ }
 324+ return $result;
 325+ }
268326 }
269327
Index: trunk/extensions/SecurePoll/cli/convertVotes.php
@@ -0,0 +1,116 @@
 2+<?php
 3+
 4+require( dirname( __FILE__ ).'/cli.inc' );
 5+
 6+$usage = <<<EOT
 7+Usage:
 8+ php convertVotes.php [options] --name <election name>
 9+ php convertVotes.php [options] <dump file>
 10+
 11+Options are:
 12+ --no-proof-protection Disable protection for proof of vote (vote buying)
 13+EOT;
 14+
 15+
 16+if ( !isset( $options['name'] ) && !isset( $args[0] ) ) {
 17+ spFatal( $usage );
 18+}
 19+
 20+if ( !class_exists( 'SecurePoll_Context' ) ) {
 21+ if ( isset( $options['name'] ) ) {
 22+ spFatal( "Cannot load from database when SecurePoll is not installed" );
 23+ }
 24+ require( dirname( __FILE__ ) . '/../SecurePoll.php' );
 25+}
 26+
 27+$conv = new SecurePoll_ConvertVotes;
 28+
 29+if ( !isset( $options['name'] ) ) {
 30+ $conv->convertFile( $args[0] );
 31+} else {
 32+ $conv->convertLocalElection( $options['name'] );
 33+}
 34+
 35+
 36+class SecurePoll_ConvertVotes {
 37+ var $context;
 38+
 39+ function convertFile( $fileName ) {
 40+ $this->context = SecurePoll_Context::newFromXmlFile( $fileName );
 41+ if ( !$this->context ) {
 42+ spFatal( "Unable to parse XML file \"$fileName\"" );
 43+ }
 44+ $electionIds = $this->context->getStore()->getAllElectionIds();
 45+ if ( !count( $electionIds ) ) {
 46+ spFatal( "No elections found in XML file \"$fileName\"" );
 47+ }
 48+ $electionId = reset( $electionIds );
 49+ $this->election = $this->context->getElection( reset( $electionIds ) );
 50+ $this->convert( $electionId );
 51+ }
 52+
 53+ function convertLocalElection( $name ) {
 54+ $this->context = new SecurePoll_Context;
 55+ $this->election = $this->context->getElectionByTitle( $name );
 56+ if ( !$this->election ) {
 57+ spFatal( "The specified election does not exist." );
 58+ }
 59+ $this->convert( $this->election->getId() );
 60+ }
 61+
 62+ function convert( $electionId ) {
 63+ $this->votes = array();
 64+ $this->crypt = $this->election->getCrypt();
 65+ $this->ballot = $this->election->getBallot();
 66+
 67+ $status = $this->context->getStore()->callbackValidVotes( $electionId, array( $this, 'convertVote' ) );
 68+ if ( !$status->isOK() ) {
 69+ spFatal( "Error: " . $status->getWikiText() );
 70+ }
 71+ $s = '';
 72+ foreach ( $this->election->getQuestions() as $question ) {
 73+ if ( $s !== '' ) {
 74+ $s .= str_repeat( '-', 80 ) . "\n\n";
 75+ }
 76+ $s .= $question->getMessage( 'text' ) . "\n";
 77+ $names = array();
 78+ foreach ( $question->getOptions() as $option ) {
 79+ $names[$option->getId()] = $option->getMessage( 'text' );
 80+ }
 81+ ksort( $names );
 82+ $names = array_values( $names );
 83+ foreach ( $names as $i => $name ) {
 84+ $s .= ( $i + 1 ) . '. ' . $name . "\n";
 85+ }
 86+ $votes = $this->votes[$question->getId()];
 87+ sort( $votes );
 88+ $s .= implode( "\n", $votes ) . "\n";
 89+ }
 90+ echo $s;
 91+ }
 92+
 93+ function convertVote( $store, $record ) {
 94+ if ( $this->crypt ) {
 95+ $status = $this->crypt->decrypt( $record );
 96+ if ( !$status->isOK() ) {
 97+ return $status;
 98+ }
 99+ $record = $status->value;
 100+ }
 101+ $record = rtrim( $record );
 102+ $record = $this->ballot->convertRecord( $record );
 103+ if ( $record === false ) {
 104+ spFatal( 'Error: missing question in vote record' );
 105+ }
 106+ foreach ( $record as $qid => $qrecord ) {
 107+ $this->votes[$qid][] = $qrecord;
 108+ }
 109+ return Status::newGood();
 110+ }
 111+}
 112+
 113+function spFatal( $message ) {
 114+ fwrite( STDERR, rtrim( $message ) . "\n" );
 115+ exit( 1 );
 116+}
 117+
Property changes on: trunk/extensions/SecurePoll/cli/convertVotes.php
___________________________________________________________________
Name: svn:eol-style
1118 + native
Index: trunk/extensions/SecurePoll/cli/tally.php
@@ -10,6 +10,8 @@
1111 $optionsWithArgs = array( 'name' );
1212 require( dirname(__FILE__).'/cli.inc' );
1313
 14+$wgTitle = Title::newFromText( 'Special:SecurePoll' );
 15+
1416 $usage = <<<EOT
1517 Usage:
1618 php tally.php [--html] --name <election name>

Status & tagging log