Index: trunk/extensions/SecurePoll/includes/Tallier.php |
— | — | @@ -259,14 +259,14 @@ |
260 | 260 | |
261 | 261 | # Header row |
262 | 262 | foreach ( $rankedIds as $oid ) { |
263 | | - $s .= Xml::element( 'th', array(), $abbrevs[$oid] ) . "\n"; |
| 263 | + $s .= Xml::tags( 'th', array(), $abbrevs[$oid] ) . "\n"; |
264 | 264 | } |
265 | 265 | $s .= "</tr>\n"; |
266 | 266 | |
267 | 267 | foreach ( $rankedIds as $oid1 ) { |
268 | 268 | # Header column |
269 | 269 | $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' ), |
271 | 271 | $rowLabels[$oid1] ); |
272 | 272 | # Rest of the matrix |
273 | 273 | foreach ( $rankedIds as $oid2 ) { |
— | — | @@ -283,6 +283,7 @@ |
284 | 284 | $s .= "</tr>\n"; |
285 | 285 | } |
286 | 286 | $s .= "</table>"; |
| 287 | + return $s; |
287 | 288 | } |
288 | 289 | |
289 | 290 | function convertMatrixToText( $matrix, $rankedIds ) { |
— | — | @@ -567,7 +568,7 @@ |
568 | 569 | $s = $wgOut->parse( '<h2>' . wfMsgNoTrans( 'securepoll-ranks' ) . "</h2>\n" ); |
569 | 570 | $s .= $this->convertRanksToHtml( $this->ranks ); |
570 | 571 | |
571 | | - $s = $wgOut->parse( '<h2>' . wfMsgNoTrans( 'securepoll-pairwise-victories' ) . "</h2>\n" ); |
| 572 | + $s .= $wgOut->parse( '<h2>' . wfMsgNoTrans( 'securepoll-pairwise-victories' ) . "</h2>\n" ); |
572 | 573 | $rankedIds = array_keys( $this->ranks ); |
573 | 574 | $s .= $this->convertMatrixToHtml( $this->victories, $rankedIds ); |
574 | 575 | |
Index: trunk/extensions/SecurePoll/includes/Store.php |
— | — | @@ -323,7 +323,7 @@ |
324 | 324 | */ |
325 | 325 | class SecurePoll_XMLStore extends SecurePoll_MemoryStore { |
326 | 326 | var $xmlReader, $fileName; |
327 | | - var $voteCallback, $voteElectionId; |
| 327 | + var $voteCallback, $voteElectionId, $voteCallbackStatus; |
328 | 328 | |
329 | 329 | /** Valid entity info keys by entity type. */ |
330 | 330 | static $entityInfoKeys = array( |
— | — | @@ -440,7 +440,11 @@ |
441 | 441 | && $electionInfo['id'] == $this->voteElectionId ) |
442 | 442 | { |
443 | 443 | $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 | + } |
445 | 449 | } else { |
446 | 450 | $xr->next(); |
447 | 451 | } |
— | — | @@ -579,9 +583,12 @@ |
580 | 584 | function callbackValidVotes( $electionId, $callback ) { |
581 | 585 | $this->voteCallback = $callback; |
582 | 586 | $this->voteElectionId = $electionId; |
| 587 | + $this->voteCallbackStatus = Status::newGood(); |
583 | 588 | $success = $this->readFile(); |
584 | 589 | $this->voteCallback = $this->voteElectionId = null; |
585 | | - if ( $success ) { |
| 590 | + if ( !$this->voteCallbackStatus->isOK() ) { |
| 591 | + return $this->voteCallbackStatus; |
| 592 | + } elseif ( $success ) { |
586 | 593 | return Status::newGood(); |
587 | 594 | } else { |
588 | 595 | return Status::newFatal( 'securepoll-dump-file-corrupt' ); |
Index: trunk/extensions/SecurePoll/includes/Ballot.php |
— | — | @@ -34,6 +34,19 @@ |
35 | 35 | abstract function unpackRecord( $record ); |
36 | 36 | |
37 | 37 | /** |
| 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 | + /** |
38 | 51 | * Create a ballot of the given type |
39 | 52 | * @param $context SecurePoll_Context |
40 | 53 | * @param $type string |
— | — | @@ -166,6 +179,23 @@ |
167 | 180 | } |
168 | 181 | return $result; |
169 | 182 | } |
| 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 | + } |
170 | 200 | } |
171 | 201 | |
172 | 202 | /** |
— | — | @@ -264,5 +294,33 @@ |
265 | 295 | } |
266 | 296 | return $ranks; |
267 | 297 | } |
| 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 | + } |
268 | 326 | } |
269 | 327 | |
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 |
1 | 118 | + native |
Index: trunk/extensions/SecurePoll/cli/tally.php |
— | — | @@ -10,6 +10,8 @@ |
11 | 11 | $optionsWithArgs = array( 'name' ); |
12 | 12 | require( dirname(__FILE__).'/cli.inc' ); |
13 | 13 | |
| 14 | +$wgTitle = Title::newFromText( 'Special:SecurePoll' ); |
| 15 | + |
14 | 16 | $usage = <<<EOT |
15 | 17 | Usage: |
16 | 18 | php tally.php [--html] --name <election name> |