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