r92857 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r92856‎ | r92857 | r92858 >
Date:10:53, 22 July 2011
Author:questpc
Status:deferred
Tags:
Comment:
Additional question randomizer fixes
Modified paths:
  • /trunk/extensions/QPoll/ctrl/qp_abstractpoll.php (modified) (history)
  • /trunk/extensions/QPoll/ctrl/qp_poll.php (modified) (history)
  • /trunk/extensions/QPoll/ctrl/qp_question.php (modified) (history)
  • /trunk/extensions/QPoll/qp_eval.php (modified) (history)
  • /trunk/extensions/QPoll/qp_interpret.php (modified) (history)
  • /trunk/extensions/QPoll/qp_pollstore.php (modified) (history)
  • /trunk/extensions/QPoll/qp_results.php (modified) (history)
  • /trunk/extensions/QPoll/qp_user.php (modified) (history)
  • /trunk/extensions/QPoll/view/qp_pollview.php (modified) (history)

Diff [purge]

Index: trunk/extensions/QPoll/qp_results.php
@@ -321,13 +321,13 @@
322322 /*
323323 # currently, error is not stored in DB, only the vote and long / short interpretations
324324 # todo: is it worth to store it?
325 - if ( $pollStore->interpAnswer->error != '' ) {
326 - return '<strong class="error">' . qp_Setup::specialchars( $pollStore->interpAnswer->error ) . '</strong>';
 325+ if ( $pollStore->interpResult->error != '' ) {
 326+ return '<strong class="error">' . qp_Setup::specialchars( $pollStore->interpResult->error ) . '</strong>';
327327 }
328328 */
329329 $out .= '<div class="interp_answer">' . wfMsg( 'qp_results_interpretation_header' ) .
330 - '<div class="interp_answer_body">' . nl2br( wfMsg( 'qp_results_short_interpretation', qp_Setup::specialChars( $pollStore->interpAnswer->short ) ) ) . '</div>' .
331 - '<div class="interp_answer_body">' . nl2br( wfMsg( 'qp_results_long_interpretation', qp_Setup::specialChars( $pollStore->interpAnswer->long ) ) ) . '</div>' .
 330+ '<div class="interp_answer_body">' . nl2br( wfMsg( 'qp_results_short_interpretation', qp_Setup::specialChars( $pollStore->interpResult->short ) ) ) . '</div>' .
 331+ '<div class="interp_answer_body">' . nl2br( wfMsg( 'qp_results_long_interpretation', qp_Setup::specialChars( $pollStore->interpResult->long ) ) ) . '</div>' .
332332 '</div>';
333333 return $out;
334334 }
Index: trunk/extensions/QPoll/qp_interpret.php
@@ -43,16 +43,20 @@
4444 * Glues the content of <qpinterpret> tags together, checks "lang" attribute
4545 * and calls appropriate interpretator to evaluate the user answer
4646 *
47 - * @param $interpArticle _existing_ article with interpretation script enclosed in <qpinterp> tags
48 - * @param $answers array of user selected categories for every proposal & question of the poll
49 - * @return instance of qp_InterpAnswer class
 47+ * @param $interpArticle _existing_ Article with interpretation script enclosed in <qpinterp> tags
 48+ * @param $injectVars array with the following possible keys:
 49+ * key 'answer' array of user selected categories for
 50+ * every proposal & question of the poll;
 51+ * key 'usedQuestions' array of used questions for randomized polls
 52+ * or false, when the poll questions were not randomized
 53+ * @return instance of qp_InterpResult class (interpretation result)
5054 */
51 - static function getAnswer( $interpArticle, $answers ) {
 55+ static function getResult( $interpArticle, $injectVars ) {
5256 global $wgParser;
5357 $matches = array();
5458 # extract <qpinterpret> tags from the article content
5559 $wgParser->extractTagsAndParams( array( qp_Setup::$interpTag ), $interpArticle->getRawText(), $matches );
56 - $interpAnswer = new qp_InterpAnswer();
 60+ $interpResult = new qp_InterpResult();
5761 # glue content of all <qpinterpret> tags at the page together
5862 $interpretScript = '';
5963 $lang = '';
@@ -62,12 +66,12 @@
6367 # however we do not want to limit interpretation language,
6468 # so the attribute is enforced to use
6569 if ( !isset( $attrs['lang'] ) ) {
66 - return $interpAnswer->setError( wfMsg( 'qp_error_eval_missed_lang_attr' ) );
 70+ return $interpResult->setError( wfMsg( 'qp_error_eval_missed_lang_attr' ) );
6771 }
6872 if ( $lang == '' ) {
6973 $lang = $attrs['lang'];
7074 } elseif ( $attrs['lang'] != $lang ) {
71 - return $interpAnswer->setError( wfMsg( 'qp_error_eval_mix_languages', $lang, $attrs['lang'] ) );
 75+ return $interpResult->setError( wfMsg( 'qp_error_eval_mix_languages', $lang, $attrs['lang'] ) );
7276 }
7377 if ( $tagName == qp_Setup::$interpTag ) {
7478 $interpretScript .= $content;
@@ -75,43 +79,43 @@
7680 }
7781 switch ( $lang ) {
7882 case 'php' :
79 - $result = qp_Eval::interpretAnswer( $interpretScript, $answers, $interpAnswer );
80 - if ( $result instanceof qp_InterpAnswer ) {
 83+ $result = qp_Eval::interpretAnswer( $interpretScript, $injectVars, $interpResult );
 84+ if ( $result instanceof qp_InterpResult ) {
8185 # evaluation error (environment error) , return it;
82 - return $interpAnswer;
 86+ return $interpResult;
8387 }
8488 break;
8589 default :
86 - return $interpAnswer->setError( wfMsg( 'qp_error_eval_unsupported_language', $lang ) );
 90+ return $interpResult->setError( wfMsg( 'qp_error_eval_unsupported_language', $lang ) );
8791 }
8892 /*** process the result ***/
8993 if ( !is_array( $result ) ) {
90 - return $interpAnswer->setError( wfMsg( 'qp_error_interpretation_no_return' ) );
 94+ return $interpResult->setError( wfMsg( 'qp_error_interpretation_no_return' ) );
9195 }
92 - # initialize $interpAnswer->qpError[] member array
 96+ # initialize $interpResult->qpError[] member array
9397 foreach ( $result as $qidx => $question ) {
9498 if ( is_int( $qidx ) && is_array( $question ) ) {
9599 foreach ( $question as $pidx => $error ) {
96100 if ( is_int( $pidx ) ) {
97 - $interpAnswer->setQPerror( $qidx, $pidx, $error );
 101+ $interpResult->setQPerror( $qidx, $pidx, $error );
98102 }
99103 }
100104 }
101105 }
102106 if ( isset( $result['error'] ) && trim( $result['error'] ) != '' ) {
103107 # script-generated error for the whole answer
104 - return $interpAnswer->setError( (string) $result['error'] );
 108+ return $interpResult->setError( (string) $result['error'] );
105109 }
106110 # if there were question/proposal errors, return them;
107 - if ( $interpAnswer->isError() ) {
108 - return $interpAnswer->setDefaultErrorMessage();
 111+ if ( $interpResult->isError() ) {
 112+ return $interpResult->setDefaultErrorMessage();
109113 }
110114 if ( !isset( $result['short'] ) || !isset( $result['long'] ) ) {
111 - return $interpAnswer->setError( wfMsg( 'qp_error_interpretation_no_return' ) );
 115+ return $interpResult->setError( wfMsg( 'qp_error_interpretation_no_return' ) );
112116 }
113 - $interpAnswer->short = (string) $result['short'];
114 - $interpAnswer->long = (string) $result['long'];
115 - return $interpAnswer;
 117+ $interpResult->short = (string) $result['short'];
 118+ $interpResult->long = (string) $result['long'];
 119+ return $interpResult;
116120 }
117121
118122 } /* end of qp_Interpret class */
Index: trunk/extensions/QPoll/ctrl/qp_abstractpoll.php
@@ -86,8 +86,9 @@
8787 qp_Setup::onLoadAllMessages();
8888 # *** get visual style poll attributes ***
8989 $perRow = intval( array_key_exists( 'perrow', $argv ) ? $argv['perrow'] : 1 );
90 - if ( $perRow < 1 )
 90+ if ( $perRow < 1 ) {
9191 $perRow = 1;
 92+ }
9293 $view->setController( $this, $perRow );
9394 $this->view = $view;
9495 # reset the unique index number of the question in the current poll (used to instantiate the questions)
@@ -101,12 +102,6 @@
102103 }
103104 $this->view->showResults = self::parseShowResults( $argv['showresults'] );
104105 }
105 - # check whether current user has rights for showresults
106 - $user = User::newFromName( $this->username );
107 - if ( !$user->isAllowed( 'showresults' ) ) {
108 - $this->view->showResults = false;
109 - }
110 - unset( $user );
111106
112107 # every poll on the page should have unique poll id, to minimize the risk of collisions
113108 # it is required to be set manually via id="value" parameter
Index: trunk/extensions/QPoll/ctrl/qp_poll.php
@@ -228,7 +228,7 @@
229229 $this->pollStore->setLastUser( $this->username );
230230 $this->pollStore->setUserVote();
231231 }
232 - if ( $this->pollStore->interpAnswer->isError() ) {
 232+ if ( $this->pollStore->interpResult->isError() ) {
233233 # no redirect when there are script-generated proposal errors (quiz mode)
234234 return false;
235235 }
Index: trunk/extensions/QPoll/ctrl/qp_question.php
@@ -623,12 +623,12 @@
624624 * false, when there are no script-generated error messages
625625 */
626626 function getProposalsErrors() {
627 - $interpAnswer = &$this->poll->pollStore->interpAnswer;
628 - if ( !is_array( $interpAnswer->qpErrors ) ||
629 - !isset( $interpAnswer->qpErrors[$this->mQuestionId] ) ) {
 627+ $interpResult = &$this->poll->pollStore->interpResult;
 628+ if ( !is_array( $interpResult->qpErrors ) ||
 629+ !isset( $interpResult->qpErrors[$this->mQuestionId] ) ) {
630630 return false;
631631 }
632 - return $interpAnswer->qpErrors[$this->mQuestionId];
 632+ return $interpResult->qpErrors[$this->mQuestionId];
633633 }
634634
635635 } /* end of qp_Question class */
Index: trunk/extensions/QPoll/qp_user.php
@@ -98,8 +98,8 @@
9999 static $messagesLoaded = false; // check whether the extension's localized messages are loaded
100100 static $article; // Article instance we got from hook parameter
101101 static $user; // User instance we got from hook parameter
102 - # extension's namespaces with their canonical names
103 - static $namespaces = array(
 102+ # interpretation script namespaces with their canonical names
 103+ static $interpNamespaces = array(
104104 NS_QP_INTERPRETATION => 'Interpretation',
105105 NS_QP_INTERPRETATION_TALK => 'Interpretation_talk'
106106 );
@@ -225,7 +225,7 @@
226226 'view/qp_pollstatsview.php' => 'qp_PollStatsView',
227227
228228 # storage
229 - 'qp_pollstore.php' => array( 'qp_QuestionData', 'qp_InterpAnswer', 'qp_PollStore' ),
 229+ 'qp_pollstore.php' => array( 'qp_QuestionData', 'qp_InterpResult', 'qp_PollStore' ),
230230
231231 # results page
232232 'qp_results.php' => array( 'qp_SpecialPage', 'qp_QueryPage', 'PollResults' ),
@@ -247,21 +247,26 @@
248248 $wgHooks['CanonicalNamespaces'][] =
249249 new qp_Setup;
250250
251 - # define namespaces for the interpretation scripts and their talk pages
252 - foreach ( self::$namespaces as $ns_idx => $canonical_name ) {
253 - if ( isset( $wgExtraNamespaces[$ns_idx] ) ) {
254 - die( "QPoll requires namespace index {$ns_idx} which is already used by another extension. Either disable another extension or change the namespace index." );
 251+ if ( self::mediaWikiVersionCompare( '1.17' ) ) {
 252+ # define namespaces for the interpretation scripts and their talk pages
 253+ # used only for non-localized namespace names in MW < 1.17
 254+ if ( !is_array( $wgExtraNamespaces ) ) {
 255+ $wgExtraNamespaces = array();
255256 }
256 - $wgNamespaceProtection[$ns_idx] = array( 'editinterpretation' );
257 - }
258 - if ( self::mediaWikiVersionCompare( '1.17' ) ) {
259 - foreach ( self::$namespaces as $ns_idx => $canonical_name ) {
 257+ foreach ( self::$interpNamespaces as $ns_idx => $canonical_name ) {
 258+ if ( isset( $wgExtraNamespaces[$ns_idx] ) ) {
 259+ die( "QPoll requires namespace index {$ns_idx} which is already used by another extension. Either disable another extension or change the namespace index." );
 260+ }
 261+ }
 262+ foreach ( self::$interpNamespaces as $ns_idx => $canonical_name ) {
260263 $wgExtraNamespaces[$ns_idx] = $canonical_name;
261264 }
262265 }
263 -
 266+
 267+ foreach ( self::$interpNamespaces as $ns_idx => $canonical_name ) {
 268+ $wgNamespaceProtection[$ns_idx] = array( 'editinterpretation' );
 269+ }
264270 # groups which has permission to access poll results by default
265 - $wgGroupPermissions['user']['showresults'] = true;
266271 $wgGroupPermissions['sysop']['pollresults'] = true;
267272 $wgGroupPermissions['bureaucrat']['pollresults'] = true;
268273 $wgGroupPermissions['polladmin']['pollresults'] = true;
@@ -510,7 +515,7 @@
511516 public static function onCanonicalNamespaces( &$list ) {
512517 # do not use array_merge() as it will destroy negative indexes in $list
513518 # thus completely ruining the namespaces list
514 - foreach ( self::$namespaces as $ns_idx => $canonical_name ) {
 519+ foreach ( self::$interpNamespaces as $ns_idx => $canonical_name ) {
515520 $list[$ns_idx] = $canonical_name;
516521 }
517522 return true;
Index: trunk/extensions/QPoll/qp_pollstore.php
@@ -108,7 +108,10 @@
109109
110110 } /* end of qp_QuestionData class */
111111
112 -class qp_InterpAnswer {
 112+/**
 113+ * An interpretation result of user answer to the quiz
 114+ */
 115+class qp_InterpResult {
113116 # short answer. it is supposed to be sortable and accountable in statistics
114117 # blank value means short answer is unavailable
115118 var $short = '';
@@ -172,7 +175,7 @@
173176 return $this->error != '' || is_array( $this->qpErrors );
174177 }
175178
176 -} /* end of qp_InterpAnswer class */
 179+} /* end of qp_InterpResult class */
177180
178181 /**
179182 * poll storage and retrieval using DB
@@ -205,7 +208,7 @@
206209 var $interpNS = 0;
207210 var $interpDBkey = null;
208211 # interpretation of user answer
209 - var $interpAnswer;
 212+ var $interpResult;
210213
211214 # array of QuestionData instances (data from/to DB)
212215 var $Questions = null;
@@ -238,7 +241,7 @@
239242 if ( self::$db == null ) {
240243 self::$db = & wfGetDB( DB_MASTER );
241244 }
242 - $this->interpAnswer = new qp_InterpAnswer();
 245+ $this->interpResult = new qp_InterpResult();
243246 if ( is_array($argv) && array_key_exists( "from", $argv ) ) {
244247 $this->Questions = Array();
245248 $this->mCompletedPostData = 'NA';
@@ -770,9 +773,9 @@
771774 if ( self::$db->numRows( $res ) != 0 ) {
772775 $row = self::$db->fetchObject( $res );
773776 $this->attempts = $row->attempts;
774 - $this->interpAnswer = new qp_InterpAnswer();
775 - $this->interpAnswer->short = $row->short_interpretation;
776 - $this->interpAnswer->long = $row->long_interpretation;
 777+ $this->interpResult = new qp_InterpResult();
 778+ $this->interpResult->short = $row->short_interpretation;
 779+ $this->interpResult->long = $row->long_interpretation;
777780 }
778781 // todo: change to "insert ... on duplicate key update ..." when last_insert_id() bugs will be fixed
779782 }
@@ -891,10 +894,10 @@
892895
893896 /**
894897 * Prepares an array of user answer to the current poll and interprets these
895 - * Stores the result in $this->interpAnswer
 898+ * Stores the result in $this->interpResult
896899 */
897900 private function interpretVote() {
898 - $this->interpAnswer = new qp_InterpAnswer();
 901+ $this->interpResult = new qp_InterpResult();
899902 $interpTitle = $this->getInterpTitle();
900903 if ( $interpTitle === null ) {
901904 return;
@@ -903,8 +906,9 @@
904907 if ( !$interpArticle->exists() ) {
905908 return;
906909 }
 910+
907911 # prepare array of user answers that will be passed to the interpreter
908 - $poll_answer = array( false );
 912+ $poll_answer = array();
909913 foreach ( $this->Questions as $qkey => &$qdata ) {
910914 $questions = array();
911915 foreach( $qdata->ProposalText as $propkey => &$proposal_text ) {
@@ -916,14 +920,13 @@
917921 $proposals[$catkey] = $qdata->ProposalCategoryText[ $propkey ][ $id_key ];
918922 }
919923 }
920 - $questions[] = $proposals;
 924+ $questions[$propkey] = $proposals;
921925 }
922 - $poll_answer[] = $questions;
 926+ $poll_answer[$qkey] = $questions;
923927 }
924 - # only the questions are numbered from 1;
925 - unset( $poll_answer[0] );
 928+
926929 # interpret the poll answer to get interpretation answer
927 - $this->interpAnswer = qp_Interpret::getAnswer( $interpArticle, $poll_answer );
 930+ $this->interpResult = qp_Interpret::getResult( $interpArticle, array( 'answer' => $poll_answer ) );
928931 }
929932
930933 // warning: requires qp_PollStorage::last_uid to be set
@@ -951,8 +954,8 @@
952955 $this->interpretVote();
953956 # update interpretation result and number of syntax-valid resubmit attempts
954957 $qp_users_polls = self::$db->tableName( 'qp_users_polls' );
955 - $short = self::$db->addQuotes( $this->interpAnswer->short );
956 - $long = self::$db->addQuotes( $this->interpAnswer->long );
 958+ $short = self::$db->addQuotes( $this->interpResult->short );
 959+ $long = self::$db->addQuotes( $this->interpResult->long );
957960 $this->attempts++;
958961 $stmt = "INSERT INTO {$qp_users_polls} (uid,pid,short_interpretation,long_interpretation)\n VALUES ( " . intval( $this->last_uid ) . ", " . intval( $this->pid ) . ", {$short}, {$long} )\n ON DUPLICATE KEY UPDATE attempts = " . intval( $this->attempts ) . ", short_interpretation = {$short} , long_interpretation = {$long}";
959962 self::$db->query( $stmt, __METHOD__ );
Index: trunk/extensions/QPoll/view/qp_pollview.php
@@ -104,11 +104,11 @@
105105 $qpoll_div = array( '__tag'=>'div', 'class'=>'qpoll' );
106106 $qpoll_div[] = array( '__tag'=>'a', 'name'=>$this->ctrl->getPollTitleFragment( null, '' ), 0=>'' );
107107 # output script-generated error, when available
108 - if ( ( $scriptError = $this->ctrl->pollStore->interpAnswer->error ) != '' ) {
 108+ if ( ( $scriptError = $this->ctrl->pollStore->interpResult->error ) != '' ) {
109109 $qpoll_div[] = array( '__tag'=>'div', 'class'=>'interp_error', qp_Setup::specialchars( $scriptError ) );
110110 }
111111 # output long result, when available
112 - if ( ( $longAnswer = $this->ctrl->pollStore->interpAnswer->long ) != '' ) {
 112+ if ( ( $longAnswer = $this->ctrl->pollStore->interpResult->long ) != '' ) {
113113 $qpoll_div[] = array( '__tag'=>'div', 'class'=>'interp_answer', qp_Setup::specialchars( $longAnswer ) );
114114 }
115115 # create voting form and fill it with messages and inputs
Index: trunk/extensions/QPoll/qp_eval.php
@@ -328,25 +328,33 @@
329329 /**
330330 * Interpretates the answer with selected script
331331 * @param $interpretScript string source code of interpretation script
332 - * @param $answers array of user selected categories for every proposal & question of the poll
333 - * @param $interpAnswer instance of qp_InterpAnswer class
334 - * @modifies $interpAnswer
 332+ * @param $injectVars array of PHP data to inject into interpretation script;
 333+ * key of element will become variable name
 334+ * in the interpretation script;
 335+ * value of element will become variable value
 336+ * in the interpretation script;
 337+ * @param $interpResult instance of qp_InterpResult class
 338+ * @modifies $interpResult
335339 * @return array script result to check, or
336 - * qpInterpAnswer $interpAnswer (in case of error)
 340+ * qp_InterpResult $interpResult (in case of error)
337341 */
338 - function interpretAnswer( $interpretScript, $answers, qp_InterpAnswer $interpAnswer ) {
 342+ function interpretAnswer( $interpretScript, $injectVars, qp_InterpResult $interpResult ) {
339343 # template page evaluation
340344 if ( ( $check = self::selfCheck() ) !== true ) {
341345 # self-check error
342 - return $interpAnswer->setError( wfMsg( 'qp_error_eval_self_check', $check ) );
 346+ return $interpResult->setError( wfMsg( 'qp_error_eval_self_check', $check ) );
343347 }
344348 $evalScript = '';
345349 if ( ( $check = self::checkAndTransformCode( $interpretScript, $evalScript ) ) !== true ) {
346350 # possible malicious code
347 - return $interpAnswer->setError( $check );
 351+ return $interpResult->setError( $check );
348352 }
349353 # inject poll answer into the interpretation script
350 - $evalScript = "\$" . self::$pseudoNamespace . "a = unserialize( base64_decode( '" . base64_encode( serialize( $answers ) ) . "' ) ); /* */ " . $evalScript;
 354+ $evalInject = '';
 355+ foreach ( $injectVars as $varname => $var ) {
 356+ $evalInject .= "\$" . self::$pseudoNamespace . "{$varname} = unserialize( base64_decode( '" . base64_encode( serialize( $var ) ) . "' ) ); ";
 357+ }
 358+ $evalScript = "{$evalInject}/* */ {$evalScript}";
351359 $result = eval( $evalScript );
352360 return $result;
353361 }

Status & tagging log