tosfos has submitted this change and it was merged.

Change subject: Initial code - whitespace fix and URL to documentation
......................................................................


Initial code - whitespace fix and URL to documentation

Change-Id: Ic3c0892cd0952551ae5cc3e9bfcfc26f631ade54
---
A QuizTabulate.class.php
A QuizTabulate.hooks.php
A QuizTabulate.i18n.php
A QuizTabulate.php
A QuizTabulate.sql
5 files changed, 394 insertions(+), 0 deletions(-)

Approvals:
  tosfos: Verified; Looks good to me, approved



diff --git a/QuizTabulate.class.php b/QuizTabulate.class.php
new file mode 100644
index 0000000..77aad39
--- /dev/null
+++ b/QuizTabulate.class.php
@@ -0,0 +1,155 @@
+<?php
+class QuestionTabulate extends Question {
+       /**
+        * Constructor
+        *
+        * @param $beingCorrected Boolean.
+        * @param $caseSensitive Boolean.
+        * @param $questionId Integer: the Identifier of the question used to 
generate input names.
+        * @param $parser Parser the wikitext parser.
+        */
+       public function __construct( $beingCorrected, $caseSensitive, 
$questionId, &$parser ) {
+               global $wgQuizPageLatestRevID;
+
+               parent::__construct( $beingCorrected, $caseSensitive, 
$questionId, $parser );
+
+               #if $wgQuizPageLatestRevID is not set, this quiz page doesn't 
use the #quiztabulate: parser function, so it must have the
+               #actual quiz stored on this page.
+               if ( !$wgQuizPageLatestRevID ) {
+                       $wgQuizPageLatestRevID = $parser->getRevisionId();
+               }
+       }
+
+       /**
+        * Convert a basic type object from quiz syntax to HTML.
+        * Save answers to the database
+        *
+        * @param $input string A question object in quiz syntax
+        * @param $inputType string
+        *
+        * @return string A question object in HTML.
+        */
+       function basicTypeParseObject( $input, $inputType ) {
+               global $wgQuizPageLatestRevID;
+
+               $output = parent::basicTypeParseObject( $input, $inputType );
+               $output .= "<input type=\"hidden\" name=\"quiz_page_id\" 
value=\"$wgQuizPageLatestRevID\" />";
+
+               if ( !$this->mBeingCorrected ) {
+                       return $output;
+               }
+
+               #These lines were borrowed from Question::basicTypeParseObject()
+               $raws = preg_split( '`\n`s', $input, -1, PREG_SPLIT_NO_EMPTY );
+
+               $allAnswers = array();
+               $rightAnswer = false;
+               $answerChosen = '';
+               foreach( $raws as $proposalId => $raw ) {
+                       if( preg_match( $this->mProposalPattern, $raw, $matches 
) ) {
+                               array_shift( $matches );
+
+                               $sign = $matches[0];
+                               $answerText = $matches[1];
+                               #If the quiz was constructed having the same 
answer twice with two different signs, that's a user error anyway.
+                               #@todo use array syntax
+                               $allAnswers[$proposalId]['sign'] = $sign;
+                               $allAnswers[$proposalId]['answerText'] = 
$answerText;
+                               array_pop( $matches );
+                               # Determine a type ID, according to the 
questionType and the number of signes.
+                               $typeId  = substr( $this->mType, 0, 1 );
+                               $typeId .= array_key_exists( 1, $matches ) ? 
'c' : 'n';
+
+                               switch( $typeId ) {
+                                       #@todo extension only set up to track a 
linear right/wrong answer, which likely limits it to this type.
+                                       case 'sn':
+                                               $name = "q$this->mQuestionId";
+                                               $value = "p$proposalId";
+                                               break;
+                               }
+                               # Determine if the input had to be checked.
+                               $checked = ( $this->mRequest->getVal( $name ) 
== $value ) ? 'checked="checked"' : null;
+                               if ( $checked ) {
+                                       $allAnswers[$proposalId]['checked'] = 
true;
+                               } else {
+                                       $allAnswers[$proposalId]['checked'] = 
false;
+                               }
+                       }
+               }
+               $this->tabulate( $allAnswers );
+
+       return $output;
+       }
+
+       function tabulate( $allAnswers ){
+               global $wgQuizPageLatestRevID;
+               $fullTableName = QUIZ_TABULATE_TABLE;
+
+               foreach ( $allAnswers as $answerId => $proposal ) {
+                       #@todo extension does not enter answer into db until it 
is checked. so not all answers may be shown when viewing quiz tabulation.
+                       if ( $proposal['checked'] == true ) {
+                               $dbr = wfGetDB( DB_SLAVE );
+                               if ( !$dbr->tableExists( $fullTableName ) ) {
+                                       #@todo error message
+                                       echo "$fullTableName table not found. 
Please run update.php!";
+                                       return;
+                               }
+                               $existingProposalObject = $dbr->select(
+                                       $fullTableName,
+                                       array( 'count_attempt' ),
+                                       "quiz_rev_id=$wgQuizPageLatestRevID AND 
question_id=$this->mQuestionId AND answer_id=$answerId",
+                                       __METHOD__
+                               );
+                               $dbw = wfGetDB( DB_MASTER );
+                               if ( $existingProposalObject->numRows() !== 0 ) 
{
+                                       $dbw->update(
+                                               $fullTableName,
+                                               array( 'count_attempt = 
count_attempt + 1' ),
+                                               array( 'quiz_rev_id' => 
$wgQuizPageLatestRevID, 'question_id' => $this->mQuestionId, 'answer_id' => 
$answerId ),
+                                                __METHOD__
+                                       );
+                               } else {
+                                       $dbw->insert(
+                                               $fullTableName,
+                                                array( 'quiz_rev_id' => 
$wgQuizPageLatestRevID, 'question_id' => $this->mQuestionId, 'answer_id' => 
$answerId, 'answer_text' => $proposal['answerText'], 'count_attempt' => 1 ),
+                                                __METHOD__
+                                       );
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Convert the question's header into HTML.
+        * Store question in db
+        *
+        * @param $input String: the quiz header in quiz syntax.
+        * @return string
+        */
+       function parseHeader( $input ) {
+               global $wgQuizPageLatestRevID;
+
+               $output = parent::parseHeader( $input );
+               if ( $this->mBeingCorrected ) {
+                       $fullTableName = QUIZ_TABULATE_QUESTIONS_TABLE;
+                       $dbr = wfGetDB( DB_SLAVE );
+                       #check if question already exists
+                       $existingQuestion = $dbr->select(
+                               $fullTableName,
+                               array( 'question_id' ),
+                               "quiz_rev_id=$wgQuizPageLatestRevID AND 
question_id = $this->mQuestionId",
+                               __METHOD__
+                       );
+                       if ( $existingQuestion->numRows() == 0 ) {
+                               $dbw = wfGetDB( DB_MASTER );
+                               $dbw->insert(
+                                       $fullTableName,
+                                       array( 'quiz_rev_id' => 
$wgQuizPageLatestRevID, 'question_id' => $this->mQuestionId, 'question_text' => 
$output ),
+                                        __METHOD__
+                               );
+                       }
+               }
+
+               return $output;
+       }
+}
diff --git a/QuizTabulate.hooks.php b/QuizTabulate.hooks.php
new file mode 100644
index 0000000..51f97e3
--- /dev/null
+++ b/QuizTabulate.hooks.php
@@ -0,0 +1,146 @@
+<?php
+
+final class QuizTabulateHooks {
+
+       /**
+        * Schema update to set up the needed database tables.
+        */
+       public static function quizTabulateSchemaUpdate( DatabaseUpdater 
$updater = null ) {
+               global $wgDBtype;
+
+               // Set up the current schema.
+               $updater->addExtensionTable(
+                       QUIZ_TABULATE_TABLE,
+                       __DIR__ . '/QuizTabulate.sql',
+                       true
+               );
+               $updater->addExtensionTable(
+                       QUIZ_TABULATE_QUESTIONS_TABLE,
+                       __DIR__ . '/QuizTabulate.sql',
+                       true
+               );
+
+               return true;
+       }
+
+       public static function outputQuizTabulate( OutputPage $outputpage, 
&$text ) {
+               global $wgQuizNamespace;
+
+               if ( !$outputpage->getUser()->isAllowed( 'viewquiztabulate' ) ) 
{
+                       return true;
+               }
+
+               $title = $outputpage->getTitle();
+               $currentAction = Action::getActionName( $outputpage );
+               if ( !$title->getNamespace() == $wgQuizNamespace || 
$currentAction != 'view' ) {
+                       return true;
+               }
+
+               $revisionId = $outputpage->getRevisionId();
+               # if latest revision, getRevisionId is 0 so find latest 
revision id. is there a better way?
+               if ( !$revisionId ) {
+                       $revisionId = $title->getLatestRevID();
+               }
+
+               #get this revision's data from db
+               $dbr = wfGetDB( DB_SLAVE );
+               $fullTableName = QUIZ_TABULATE_TABLE;
+               $proposals = $dbr->select(
+                       $fullTableName,
+                       array( 'question_id', 'answer_id', 'count_attempt', 
'answer_text' ),
+                       "quiz_rev_id=$revisionId",
+                       __METHOD__
+               );
+               if ( $proposals->numRows() == 0 ) {
+                       return true; #no quizzes submitted
+               }
+
+               #first put all data for this revision into an array
+               $allResults = array();
+               while ( $row = $proposals->fetchObject() ) {
+                       $allResults[$row->question_id][$row->answer_id] = array(
+                               'countAttempt' => $row->count_attempt,
+                               'answerText' => $row->answer_text
+                       );
+               }
+
+               #then spit it out nice-like
+               $text .= XML::openElement( 'div', array( 'id' => 
'quiz_tabulate', 'style' => 'clear:both;' ) );
+               $text .= Xml::element( 'h2', array( 'id' => 
'quiz_tabulate_title' ), wfMessage( 'quiz-tabulate-results' )->text() );
+
+               $fullTableName = QUIZ_TABULATE_QUESTIONS_TABLE;
+               foreach ( $allResults as $question_id => $results ) {
+                       $totalAnswers = 0;
+                       foreach( $results as $answer ) {
+                               $totalAnswers += $answer['countAttempt'];
+                       }
+
+                       $questionTextObject = $dbr->select(
+                               $fullTableName,
+                               array( 'question_text' ),
+                               "quiz_rev_id=$revisionId AND question_id = 
$question_id",
+                               __METHOD__
+                       );
+
+                       $headingText = 'Question #' . ( $question_id + 1 ). ': 
' . $questionTextObject->fetchObject()->question_text;
+                       $text .= Xml::element( 'h3', array( 'class' => 
'quiz_tabulate_question' ), $headingText );
+                       $text .= Xml::element( 'p', array( 'class' => 
'quiz_tabulate_total' ), "Answers: $totalAnswers" );
+                       $tableRows = array();
+                       foreach( $results as $answer ) {
+                               $tableRows[] =  array( $answer['answerText'], 
$answer['countAttempt'], number_format( $answer['countAttempt'] / $totalAnswers 
* 100, 0 ) . '%' );
+                       }
+                       $text .= Xml::buildTable( $tableRows, array( 'class' => 
'wikitable quiz_tabulate_answers' ), array( 'Answer', 'Count', 'Percentage' ) );
+               }
+               $text .= XML::closeElement( 'div' );
+               return true;
+       }
+
+       public static function quizTabulateSetupParserFunction( &$parser ) {
+               $parser->setFunctionHook( 'quiztabulate', 
'QuizTabulateHooks::quizTabulateRenderParserFunction' );
+
+               return true;
+       }
+
+       public static function quizTabulateRenderParserFunction( $parser, 
$quizName = '', $includeQuizTags = false ) {
+               global $wgQuizPageLatestRevID, $wgQuizNamespace;
+
+               if ( $quizName == '' ) {
+                       return '';
+               }
+               $quizPage = Title::newFromText( $quizName, $wgQuizNamespace );
+               if ( !$quizPage->isKnown() ) {
+                       return '';
+               }
+
+               $wgQuizPageLatestRevID = $quizPage->getLatestRevID();
+
+               #@todo Perhaps return page contents instead of transclude.
+               #@todo Only works for one quiz per page, which is not so bad 
since Quiz is buggy when including more than once anyway.
+               if ( $includeQuizTags ) {
+                       $output = "{{#tag:quiz|\n{{" . $quizPage->getFullText() 
. '}}}}';
+               } else {
+                       $output = "{{" . $quizPage->getFullText() . '}}';
+               }
+
+               return array( $output, 'noparse' => false );
+       }
+
+       #override Question object with our own Question child
+       public static function quizTabulateSetupTabulator ( $quiz, &$question ) 
{
+               global $wgQuizPageLatestRevID, $wgQuizNamespace;
+
+               #if this isn't in the Quiz namespace and wgQuizPageLatestRevID 
wasn't set (in other words, the #quiztabulate: function wasn't called)
+               if ( $quiz->mParser->getTitle()->getNamespace() != 
$wgQuizNamespace
+                       && !$wgQuizPageLatestRevID ) {
+                       return true;
+               }
+               $question = new QuestionTabulate(
+                       $quiz->mBeingCorrected,
+                       $quiz->mCaseSensitive,
+                       $quiz->mQuestionId,
+                       $quiz->mParser
+               );
+
+               return true;
+       }
+}
diff --git a/QuizTabulate.i18n.php b/QuizTabulate.i18n.php
new file mode 100644
index 0000000..2028ee8
--- /dev/null
+++ b/QuizTabulate.i18n.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Internationalization file.
+ */
+
+$messages['en'] = array(
+       'quiz-tabulate-description' => 'Tabulates results of the quiz 
extension',
+       'editnotice-' . $GLOBALS['wgQuizNamespace'] => "'''Warning:''' Editing 
this page will reset this quiz's tabulation statistics. The previous statistics 
will still be available in the page history.",
+       'quiz-tabulate-results' => 'Quiz results'
+);
+
+$magicWords = array();
+
+$magicWords['en'] = array(
+   'quiztabulate' => array( 0, 'quiztabulate' ),
+);
diff --git a/QuizTabulate.php b/QuizTabulate.php
new file mode 100644
index 0000000..b43ee9d
--- /dev/null
+++ b/QuizTabulate.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * QuizTabulate is a quiz tabulation tool for MediaWiki. It requires the Quiz 
extension.
+ *
+ * To activate this extension, add the following to your LocalSettings.php :
+ * require_once( "$IP/extensions/QuizTabulate/QuizTabulate.php" );
+ *
+ * @file
+ * @ingroup Extensions
+ * @version 1.1.0
+ * @author Ike Hecht for [http://www.wikiworks.com/ WikiWorks]
+ * @link http://www.mediawiki.org/wiki/Extension:QuizTabulate Documentation
+ */
+
+if ( !defined( 'MEDIAWIKI' ) ) {
+       die( 'This is not a valid entry point to MediaWiki.' );
+}
+
+/**
+ * Extension credits that will show up on Special:Version
+ */
+$wgExtensionCredits['parserhook'][] = array(
+       'path' => __FILE__,
+       'name' => 'QuizTabulate',
+       'descriptionmsg' => 'quiz-tabulate-description',
+       'version' => '1.1.0', #corresponds to Quiz version it was based on and 
tested with
+       'author' => 'Ike Hecht for [http://www.wikiworks.com/ WikiWorks]',
+       'url' => 'http://www.mediawiki.org/wiki/Extension:QuizTabulate',
+);
+
+$wgAutoloadClasses['QuizTabulate'] = __DIR__ . '/QuizTabulate.class.php';
+$wgAutoloadClasses['QuestionTabulate'] = __DIR__ . '/QuizTabulate.class.php';
+$wgAutoloadClasses['QuizTabulateHooks'] = __DIR__ . '/QuizTabulate.hooks.php';
+$wgExtensionMessagesFiles['QuizTabulate'] = __DIR__ . '/QuizTabulate.i18n.php';
+
+$wgHooks['LoadExtensionSchemaUpdates'][] = 
'QuizTabulateHooks::quizTabulateSchemaUpdate';
+$wgHooks['ParserFirstCallInit'][] = 
'QuizTabulateHooks::quizTabulateSetupParserFunction';
+$wgHooks['QuizTabulate'][] = 'QuizTabulateHooks::quizTabulateSetupTabulator';
+$wgHooks['OutputPageBeforeHTML'][] = 'QuizTabulateHooks::outputQuizTabulate';
+
+#Which users can see quiz tabulations?
+$wgGroupPermissions['*'            ]['viewquiztabulate'] = false;
+$wgGroupPermissions['user'         ]['viewquiztabulate'] = false;
+$wgGroupPermissions['autoconfirmed']['viewquiztabulate'] = false;
+$wgGroupPermissions['bot'          ]['viewquiztabulate'] = true; // registered 
bots
+$wgGroupPermissions['sysop'        ]['viewquiztabulate'] = true;
+$wgAvailableRights[] = 'viewquiztabulate';
+
+define( 'QUIZ_TABULATE_TABLE' , 'quiz_tabulate' );
+define( 'QUIZ_TABULATE_QUESTIONS_TABLE' , 'quiz_tabulate_questions' );
+
+#set custom namespaces
+#@todo Perhaps this should only be done if $wgQuizNamespace was not set.
+define( 'QuizTabulate_NS_QUIZ' , 430 );
+define( 'QuizTabulate_NS_QUIZ_TALK' , 431 );
+$wgExtraNamespaces[QuizTabulate_NS_QUIZ] = "Quiz";
+$wgExtraNamespaces[QuizTabulate_NS_QUIZ_TALK] = "Quiz_talk";
+$wgQuizNamespace = QuizTabulate_NS_QUIZ;
+
+#Global used to store which quiz page is being displayed. Is there a better 
way?
+$wgQuizPageID = '';
+$wgQuizPageLatestRevID = '';
diff --git a/QuizTabulate.sql b/QuizTabulate.sql
new file mode 100644
index 0000000..3b40c08
--- /dev/null
+++ b/QuizTabulate.sql
@@ -0,0 +1,15 @@
+-- SQL for database schema for the QuizTabulate extension.
+CREATE TABLE IF NOT EXISTS /*_*/quiz_tabulate (
+  quiz_tabulate_id INT unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
+  quiz_rev_id INT(10) unsigned NOT NULL,
+  question_id INT(10) unsigned NOT NULL,
+  answer_id INT(10) unsigned NOT NULL,
+  answer_text BLOB NOT NULL,
+  count_attempt INT(10) unsigned NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE TABLE IF NOT EXISTS /*_*/quiz_tabulate_questions (
+  quiz_tabulate_questions_id INT unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
+  quiz_rev_id INT(10) unsigned NOT NULL,
+  question_id INT(10) unsigned NOT NULL,
+  question_text BLOB NOT NULL
+) /*$wgDBTableOptions*/;

-- 
To view, visit https://gerrit.wikimedia.org/r/77993
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ic3c0892cd0952551ae5cc3e9bfcfc26f631ade54
Gerrit-PatchSet: 2
Gerrit-Project: mediawiki/extensions/QuizTabulate
Gerrit-Branch: master
Gerrit-Owner: tosfos <[email protected]>
Gerrit-Reviewer: tosfos <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to