]> git.mjollnir.org Git - moodle.git/commitdiff
quiz editing: Refactor the editing actions to make functions in editlib.php for most...
authortjhunt <tjhunt>
Fri, 27 Feb 2009 08:45:05 +0000 (08:45 +0000)
committertjhunt <tjhunt>
Fri, 27 Feb 2009 08:45:05 +0000 (08:45 +0000)
In the process, do MDL-17456, move/delete questions by question id rather than position, for greater robustness.

mod/quiz/edit.php
mod/quiz/editlib.php
mod/quiz/locallib.php
mod/quiz/simpletest/testeditlib.php [new file with mode: 0644]
mod/quiz/startattempt.php

index 3f177cdedc47e27c77f1fd0ad084e2ae96533cab..e8d95a709afc057c78801effbba97605d60b387d 100644 (file)
@@ -167,54 +167,43 @@ if (isset($quiz->instance) && empty($quiz->grades)) {  // Construct an array to
     $quiz->grades = quiz_get_all_question_grades($quiz);
 }
 
-// SECTION: PROCESS COMMANDS //
-// If any edit action makes a significant change to the structure of the quiz,
-// then we will need to delete all preview attempts.
-$significantchangemade = false;
-
-if (($up = optional_param('up', false, PARAM_INT)) !== false && confirm_sesskey()) {
-/// Move the given question up a slot
-    $questions = explode(',', $quiz->questions);
-    if ($up > 0 && isset($questions[$up])) {
-        //$prevkey = ($questions[$up-1] == 0) ? $up-2 : $up-1;
-        $prevkey = $up-1;
-        $swap = $questions[$prevkey];
-        $questions[$prevkey] = $questions[$up];
-        $questions[$up] = $swap;
-        $quiz->questions = implode(',', $questions);
-        $quiz->questions = quiz_clean_layout($quiz->questions);
-        if (!$DB->set_field('quiz', 'questions', $quiz->questions,
-                array('id' => $quiz->instance))) {
-            print_error('cannotsavequestion', 'quiz');
-        }
-        $significantchangemade = true;
+// Process commands ============================================================
+
+// Get the list of question ids had their check-boxes ticked.
+$selectedquestionids = array();
+$params = (array) data_submitted();
+foreach ($params as $key => $value) {
+    if (preg_match('!^s([0-9]+)$!', $key, $matches)) {
+        $selectedquestionids[] = $matches[1];
     }
 }
 
-if (($down = optional_param('down', false, PARAM_INT)) !== false && confirm_sesskey()) {
-/// Move the given question down a slot
-    $questions = explode(',', $quiz->questions);
-    if ($down < count($questions)) {
-        //$nextkey = ($questions[$down+1] == 0) ? $down+2 : $down+1;
-        $nextkey = $down+1;
-        $swap = $questions[$nextkey];
-        $questions[$nextkey] = $questions[$down];
-        $questions[$down] = $swap;
-        $quiz->questions = implode(',', $questions);
-        $quiz->questions = quiz_clean_layout($quiz->questions);
-        if (!$DB->set_field('quiz', 'questions', $quiz->questions,
-                array('id' => $quiz->instance))) {
-            print_error('cannotsavequestion', 'quiz');
-        }
-        $significantchangemade = true;
-    }
+if (($up = optional_param('up', false, PARAM_INT)) && confirm_sesskey()) {
+    $quiz->questions = quiz_move_question_up($quiz->questions, $up);
+    quiz_save_new_layout($quiz);
+    redirect($thispageurl->out());
+}
+
+if (($down = optional_param('down', false, PARAM_INT)) && confirm_sesskey()) {
+    $quiz->questions = quiz_move_question_down($quiz->questions, $down);
+    quiz_save_new_layout($quiz);
+    redirect($thispageurl->out());
+}
+
+if (optional_param('repaginate', false, PARAM_BOOL) && confirm_sesskey()) {
+    // Re-paginate the quiz
+    $questionsperpage = optional_param('questionsperpage', $quiz->questionsperpage, PARAM_INT);
+    $quiz->questions = quiz_repaginate($quiz->questions, $questionsperpage );
+    quiz_save_new_layout($quiz);
 }
 
 if (($addquestion = optional_param('addquestion', 0, PARAM_INT)) && confirm_sesskey()) {
 /// Add a single question to the current quiz
     $addonpage = optional_param('addonpage', 0, PARAM_INT);
     quiz_add_quiz_question($addquestion, $quiz, $addonpage);
-    $significantchangemade = true;
+    quiz_update_sumgrades($quiz);
+    quiz_delete_previews($quiz);
+    redirect($thispageurl->out());
 }
 
 if (optional_param('add', false, PARAM_BOOL) && confirm_sesskey()) {
@@ -226,24 +215,20 @@ if (optional_param('add', false, PARAM_BOOL) && confirm_sesskey()) {
             quiz_add_quiz_question($key, $quiz);
         }
     }
-    $significantchangemade = true;
+    quiz_update_sumgrades($quiz);
+    quiz_delete_previews($quiz);
+    redirect($thispageurl->out());
 }
 
-$qcobject = new question_category_object(
-    $pagevars['cpage'],
-    $thispageurl,
-    $contexts->having_one_edit_tab_cap('categories'),
-    $defaultcategoryid,
-    $defaultcategory,
-    null,
-    $contexts->having_cap('moodle/question:add'));
+$qcobject = new question_category_object($pagevars['cpage'], $thispageurl,
+        $contexts->having_one_edit_tab_cap('categories'), $defaultcategoryid,
+        $defaultcategory, null, $contexts->having_cap('moodle/question:add'));
 
 $newrandomcategory = false;
 $newquestioninfo = quiz_process_randomquestion_formdata($qcobject);
 if ($newquestioninfo) {
     $newrandomcategory = $newquestioninfo->newrandomcategory;
     if (!$newrandomcategory) {
-        print_r($newquestioninfo);
         print_error('cannotcreatecategory');
     } else {
         add_to_log($quiz->course, 'quiz', 'addcategory',
@@ -311,114 +296,48 @@ if ((optional_param('addrandom', false, PARAM_BOOL) || $newrandomcategory) && co
         }
     }
 
-    $significantchangemade = true;
+    quiz_update_sumgrades($quiz);
+    quiz_delete_previews($quiz);
+    redirect($thispageurl->out());
 }
 
-$addpagesafterquestions = array();
-if ($addnewpagesafterselected = optional_param('addnewpagesafterselected', null)) {
-    $rawgrades = (array) data_submitted();
-    foreach ($rawgrades as $key => $value) {
-        /// Parse input for question -> grades
-        if (preg_match('!^s([0-9]+)$!', $key, $matches)) {
-            $addpagesafterquestions[] = $matches[1];
-        }
+if (optional_param('addnewpagesafterselected', null) && !empty($selectedquestionids) && confirm_sesskey()) {
+    foreach ($selectedquestionids as $questionid) {
+        $quiz->questions = quiz_add_page_break_after($quiz->questions, $questionid);
     }
+    quiz_save_new_layout($quiz);
+    redirect($thispageurl->out());
 }
 
 $addpage = optional_param('addpage', false, PARAM_INT);
-if (($addpage || !empty($addpagesafterquestions)) && confirm_sesskey()) {
-/// Move the given question up a slot
-
-    $questions = explode(',', $quiz->questions);
-
-    $pagebreakid = '0';
-    if ($addpage > 0 && isset($questions[$addpage])) {
-        array_splice($questions, $addpage, 0, $pagebreakid);
-        $significantchangemade = true;
-    }
-    foreach ($addpagesafterquestions as $key => $questionid) {
-        $addpage = array_search($questionid, $questions)+1;
-        if ($addpage > 0 && isset($questions[$addpage])) {
-            $pagebreakid = '0';
-            array_splice($questions, $addpage, 0, $pagebreakid);
-            $significantchangemade = true;
-        }
-    }
-    $quiz->questions = implode(',', $questions);
-    $quiz->questions = quiz_clean_layout($quiz->questions);
-
-    if (!$DB->set_field('quiz', 'questions', $quiz->questions,
-            array('id' => $quiz->instance))) {
-        print_error('cannotsavequestion', 'quiz');
-    }
-}
-
-if (optional_param('repaginate', false, PARAM_BOOL) && confirm_sesskey()) {
-    // Re-paginate the quiz
-    $questionsperpage = optional_param('questionsperpage',
-            $quiz->questionsperpage, PARAM_INT);
-    $quiz->questions = quiz_repaginate($quiz->questions,
-            $questionsperpage );
-    if (!$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id))) {
-        print_error('cannotsavelayout', 'quiz');
-    }
-    $significantchangemade = true;
+if ($addpage !== false && confirm_sesskey()) {
+    $quiz->questions = quiz_add_page_break_at($quiz->questions, $addpage);
+    quiz_save_new_layout($quiz);
+    redirect($thispageurl->out());
 }
 
 $deleteemptypage = optional_param('deleteemptypage', false, PARAM_INT);
 if (($deleteemptypage !== false) && confirm_sesskey()) {
-    $questions = explode(',', $quiz->questions);
-    if ($deleteemptypage>0) {
-        //it points to a value one too big due to the display logic
-        $deleteemptypage--;
-    }
-    if (((int)$questions[$deleteemptypage]) == 0) {
-        $questions = explode(',', $quiz->questions);
-        $endpart = array_slice($questions, $deleteemptypage + 1, null, true);
-        $beginpart = array_slice($questions, 0, $deleteemptypage, true);
-        $questions = array_merge($beginpart, $endpart);
-        $quiz->questions = implode(',', $questions);
-        $quiz->questions = quiz_clean_layout($quiz->questions);
-    }
-    if (!$DB->set_field('quiz', 'questions', $quiz->questions,
-            array('id' => $quiz->instance))) {
-        print_error('cannotsavequestion', 'quiz');
-    }
+    $quiz->questions = quiz_delete_empty_page($quiz->questions, $deleteemptypage);
+    quiz_save_new_layout($quiz);
+    redirect($thispageurl->out());
 }
 
-$deletequestions = array();
-if ($quizdeleteselected = optional_param('quizdeleteselected', false)) {
-    $rawgrades = (array) data_submitted();
-    foreach ($rawgrades as $key => $value) {
-        /// Parse input for question -> grades
-        if (preg_match('!^s([0-9]+)$!', $key, $matches)) {
-            $deletequestions[] = $matches[1];
-        }
-    }
+$remove = optional_param('remove', false, PARAM_INT);
+if (($remove = optional_param('remove', false, PARAM_INT)) && confirm_sesskey()) {
+    quiz_remove_question($quiz, $remove);
+    quiz_update_sumgrades($quiz);
+    quiz_delete_previews($quiz);
+    redirect($thispageurl->out());
 }
 
-$delete = optional_param('delete', false, PARAM_INT);
-if (($delete !== false || !empty($deletequestions)) && confirm_sesskey()) {
-
-    //was:     if ($delete > 0 ) {
-    if ($delete !==false) {
-        quiz_delete_quiz_question($delete, $quiz);
-        $significantchangemade = true;
-    }
-    foreach ($deletequestions as $key => $questionid) {
-        $questions = explode(',', $quiz->questions);
-        $delete = array_search($questionid, $questions);
-        if ($delete !== false) {
-            quiz_delete_quiz_question($delete, $quiz);
-            $significantchangemade = true;
-        }
-    }
-    $quiz->questions = quiz_clean_layout($quiz->questions);
-
-    if (!$DB->set_field('quiz', 'questions', $quiz->questions,
-            array('id' => $quiz->instance))) {
-        print_error('cannotsavequestion', 'quiz');
+if (optional_param('quizdeleteselected', false, PARAM_BOOL) && !empty($selectedquestionids) && confirm_sesskey()) {
+    foreach ($selectedquestionids as $questionid) {
+        quiz_remove_question($quiz, $questionid);
     }
+    quiz_update_sumgrades($quiz);
+    quiz_delete_previews($quiz);
+    redirect($thispageurl->out());
 }
 
 if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
@@ -436,7 +355,7 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
     }
 
     foreach ($rawgrades as $key => $value) {
-        if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
+        if (preg_match('!^g([0-9]+)$!', $key, $matches)) {
             /// Parse input for question -> grades
             $key = $matches[1];
             $quiz->grades[$key] = $value;
@@ -453,28 +372,21 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
                 $value++;
             }
             $questions[$value] = $oldquestions[$key];
-
-        } else if (preg_match('!^s([0-9]+)$!', $key, $matches)) {
-            // Parse input for selected questions
-            // (add new pages after questions in quiz)
-            $key = $matches[1];
-            if ($moveselectedonpage) {
-                $moveonpagequestions[] = $key;
-            }
         }
     }
+
     // If ordering info was given, reorder the questions
     if ($questions) {
         ksort($questions);
         $quiz->questions = implode(',', $questions) . ',0';
         $quiz->questions = quiz_clean_layout($quiz->questions);
-
     }
+
     //get a list of questions to move, later to be added in the appropriate
     //place in the string
-    if ($moveonpagequestions) {
+    if ($moveselectedonpage) {
         $questions = explode(',', $quiz->questions);
-        foreach ($moveonpagequestions as $page => $question) {
+        foreach ($selectedquestionids as $page => $question) {
             //remove the questions from their original positions first
             while (($delpos = array_search($question, $questions)) !== FALSE) {
                 //in case there are multiple instances because of an error, remove all
@@ -499,14 +411,14 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
         $pagebreakpositions = array_keys($questions, 0);
         //move to the end of the selected page
         $moveselectedpos = $pagebreakpositions[$moveselectedonpage - 1];
-        foreach ($moveonpagequestions as $question) {
+        foreach ($selectedquestionids as $question) {
             array_splice($questions, $moveselectedpos, 0, $question);
             //place the next one after this one:
             $moveselectedpos++;
         }
         $quiz->questions = implode(',', $questions);
     }
-    if ($moveonpagequestions || $questions) {
+    if ($moveselectedonpage || $questions) {
         if (!$DB->set_field('quiz', 'questions', $quiz->questions,
                 array('id' => $quiz->instance))) {
             print_error('cannotsavequestion', 'quiz');
@@ -520,24 +432,14 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
         }
     }
 
-    $significantchangemade = true;
-}
-/// Delete any teacher preview attempts if the quiz has been modified
-if ($significantchangemade) {
-    $previewattempts = $DB->get_records_select('quiz_attempts',
-             'quiz = ? AND preview = 1', array($quiz->id));
-    if ($previewattempts) {
-        foreach ($previewattempts as $attempt) {
-            quiz_delete_attempt($attempt, $quiz);
-        }
-    }
     quiz_update_sumgrades($quiz);
+    quiz_delete_previews($quiz);
     redirect($thispageurl->out());
 }
 
 $questionbank->process_actions($thispageurl, $cm);
 
-/// all commands have been dealt with, now print the page
+// End of process commands =====================================================
 
 if (isset($quiz->instance) && $DB->record_exists_select('quiz_attempts',
         'quiz = ? AND preview = 0', array($quiz->instance))) {
index 513eeebae499eb6dcc5ba57119e4593bd6f32a1e..ec9c662dc623c47c4c91b3708f4fa1c51a345d01 100644 (file)
@@ -35,35 +35,45 @@ require_once("locallib.php");
 define('NUM_QS_TO_SHOW_IN_RANDOM', 3);
 
 /**
-* Delete a question from a quiz
-*
-* Deletes a question or a pagebreak from a quiz by updating $quiz
-* as well as the quiz, quiz_question_instances
-* @return boolean         false if the question was not in the quiz
-* @param int $id          The id of the question to be deleted
-* @param object $quiz  The extended quiz object as used by edit.php
-*                         This is updated by this function
-*/
-function quiz_delete_quiz_question($id, &$quiz) {
+ * Remove a question from a quiz
+ * @param object $quiz the quiz object.
+ * @param int $questionid The id of the question to be deleted.
+ */
+function quiz_remove_question($quiz, $questionid) {
     global $DB;
-    // TODO: For the sake of safety check that this question can be deleted
-    // safely, i.e., that it is not already in use.
-    $questions = explode(",", $quiz->questions);
 
-    // only do something if this question exists
-    if (!isset($questions[$id])) {
-        return false;
+    $questionids = explode(',', $quiz->questions);
+    $key = array_search($questionid, $questionids);
+    if ($key === false) {
+        return;
     }
 
-    $question = $questions[$id];
-    unset($questions[$id]);
-    $quiz->questions = implode(",", $questions);
-    // save new questionlist in database
-    if (!$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->instance))) {
-        print_error('cannotsavequestion', 'quiz');
+    unset($questionids[$key]);
+    $quiz->questions = implode(',', $questionids);
+    $DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id));
+    $DB->delete_records('quiz_question_instances', array('quiz' => $quiz->instance, 'question' => $questionid));
+}
+
+/**
+ * Remove an empty page from the quiz layout. If that is not possible, do nothing.
+ * @param string $layout the existinng layout, $quiz->questions.
+ * @param integer $index the position into $layout where the empty page should be removed.
+ * @return the updated layout
+ */
+function quiz_delete_empty_page($layout, $index) {
+    $questionids = explode(',', $layout);
+
+    if ($index < -1 || $index >= count($questionids) - 1) {
+        return $layout;
     }
-    $DB->delete_records('quiz_question_instances', array('quiz' => $quiz->instance, 'question'=> $question));
-    return true;
+
+    if (($index >= 0 && $questionids[$index] != 0) || $questionids[$index + 1] != 0) {
+        return $layout; // This was not an empty page.
+    }
+
+    unset($questionids[$index + 1]);
+
+    return implode(',', $questionids);
 }
 
 /**
@@ -141,6 +151,53 @@ function quiz_add_quiz_question($id, &$quiz, $page=0) {
     return true;
 }
 
+/**
+ * Add a page break after at particular position$.
+ * @param string $layout the existinng layout, $quiz->questions.
+ * @param integer $index the position into $layout where the empty page should be removed.
+ * @return the updated layout
+ */
+function quiz_add_page_break_at($layout, $index) {
+    $questionids = explode(',', $layout);
+    if ($index < 0 || $index >= count($questionids)) {
+        return $layout;
+    }
+
+    array_splice($questionids, $index, 0, '0');
+
+    return implode(',', $questionids);
+}
+
+/**
+ * Add a page break after a particular question.
+ * @param string $layout the existinng layout, $quiz->questions.
+ * @param integer $qustionid the question to add the page break after.
+ * @return the updated layout
+ */
+function quiz_add_page_break_after($layout, $questionid) {
+    $questionids = explode(',', $layout);
+    $key = array_search($questionid, $questionids);
+    if ($key === false || !$questionid) {
+        return $layout;
+    }
+
+    array_splice($questionids, $key + 1, 0, '0');
+
+    return implode(',', $questionids);
+}
+
+/**
+ * Update the database after $quiz->questions has been changed. For example,
+ * this deletes preview attempts and updates $quiz->sumgrades.
+ * @param $quiz the quiz object.
+ */
+function quiz_save_new_layout($quiz) {
+    global $DB;
+    $DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id));
+    quiz_update_sumgrades($quiz);
+    quiz_delete_previews($quiz);
+}
+
 /**
 * Save changes to question instance
 *
@@ -165,6 +222,52 @@ function quiz_update_question_instance($grade, $questionid, $quizid) {
     }
 }
 
+// Private function used by the following two.
+function _quiz_move_question($layout, $questionid, $shift) {
+    if (!$questionid || !($shift == 1 || $shift == -1)) {
+        return $layout;
+    }
+
+    $questionids = explode(',', $layout);
+    $key = array_search($questionid, $questionids);
+    if ($key === false) {
+        return $layout;
+    }
+
+    $otherkey = $key + $shift;
+    if ($otherkey < 0 || $otherkey >= count($questionids) - 1) {
+        return $layout;
+    }
+
+    $temp = $questionids[$otherkey];
+    $questionids[$otherkey] = $questionids[$key];
+    $questionids[$key] = $temp;
+
+    return implode(',', $questionids);
+}
+
+/**
+ * Move a particular question one space earlier in the $quiz->questions list.
+ * If that is not possible, do nothing.
+ * @param string $layout the existinng layout, $quiz->questions.
+ * @param integer $questionid the id of a question.
+ * @return the updated layout
+ */
+function quiz_move_question_up($layout, $questionid) {
+    return _quiz_move_question($layout, $questionid, -1);
+}
+
+/**
+ * Move a particular question one space later in the $quiz->questions list.
+ * If that is not possible, do nothing.
+ * @param string $layout the existinng layout, $quiz->questions.
+ * @param integer $questionid the id of a question.
+ * @return the updated layout
+ */
+function quiz_move_question_down($layout, $questionid) {
+    return _quiz_move_question($layout, $questionid, +1);
+}
+
 /**
 * Prints a list of quiz questions for the edit.php main view for edit
 * ($reordertool=false) and order and paging ($reordertool=true) tabs
@@ -319,30 +422,28 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete=true,
             $questions[$qnum]->qtype = 'missingtype';
         }
         $deletex="delete.gif";
-        if($qnum!=0 OR ($qnum==0&&!$pageopen)){
+        if ($qnum != 0 || ($qnum == 0 && !$pageopen)) {
             //this is either a question or a page break after another
             //        (no page is currently open)
-            if(!$pageopen){
+            if (!$pageopen) {
                 //if no page is open, start display of a page
                 $pagecount++;
                 echo  '<div class="quizpage"><span class="pagetitle">'.
                         get_string('page').'&nbsp;'.$pagecount.
                         '</span><div class="pagecontent">';
-                $pageopen=true;
+                $pageopen = true;
             }
-            if($qnum==0 && $i<$questiontotalcount){
-                //this is a consequent 0 (signaling empty page), tell
-                //        the user the page is empty
+            if ($qnum == 0  && $i < $questiontotalcount) {
+                // This is the second successive page break. Tell the user the page is empty.
                 echo '<div class="pagestatus">';
                 print_string("noquestionsonpage", "quiz");
                 echo '</div>';
-                if ($allowdelete && !$quiz->questionsperpage) { // remove from quiz, not question delete.
+                if ($allowdelete && !$quiz->questionsperpage) {
                     echo '<div class="quizpagedelete">';
-                    echo "<a title=\"".get_string("removeemptypage","quiz")."\" href=\"".
-                            $pageurl->out_action(array('deleteemptypage'=>$i)).
-                            "\"><img src=\"$CFG->pixpath/t/delete.gif\" ".
-                            "class=\"iconsmall\"".
-                            " alt=\"$strremove\" /></a>";
+                    echo '<a title="' . get_string('removeemptypage', 'quiz') . '" href="' .
+                            $pageurl->out_action(array('deleteemptypage' => $i - 1)) .
+                            '"><img src="' . $CFG->pixpath . '/t/delete.gif" ' .
+                            'class="iconsmall" alt="' . $strremove . '" /></a>';
                     echo '</div>';
                 }
             }
@@ -396,31 +497,31 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete=true,
             <div class="questioncontrols">
                 <?php
             if ($count != 0) {
-                if(!$hasattempts){
+                if (!$hasattempts) {
                     $upbuttonclass="";
-                    if (!($count < $lastindex-1)) {
+                    if ($count >= $lastindex - 1) {
                         $upbuttonclass="upwithoutdown";
                     }
                     echo "<a title=\"$strmoveup\" href=\"".
-                            $pageurl->out_action(array('up'=>$count))."\"><img
+                            $pageurl->out_action(array('up' => $question->id))."\"><img
                              src=\"$CFG->pixpath/t/up.gif\" class=\"iconsmall
                             $upbuttonclass\" alt=\"$strmoveup\" /></a>";
                 }
 
             }
-            if ($count < $lastindex-1) {
+            if ($count < $lastindex - 1) {
                 if(!$hasattempts){
                     echo "<a title=\"$strmovedown\" href=\"".
-                            $pageurl->out_action(array('down'=>$count))."\"><img
+                            $pageurl->out_action(array('down' => $question->id))."\"><img
                             src=\"$CFG->pixpath/t/down.gif\" class=\"iconsmall\"".
                             " alt=\"$strmovedown\" /></a>";
                 }
             }
-            if ($allowdelete && question_has_capability_on($question, 'use',
-                    $question->category)) { // remove from quiz, not question delete.
-                if(!$hasattempts){
+            if ($allowdelete && question_has_capability_on($question, 'use', $question->category)) {
+            // remove from quiz, not question delete.
+                if (!$hasattempts) {
                     echo "<a title=\"$strremove\" href=\"".
-                            $pageurl->out_action(array('delete'=>$count))."\">
+                            $pageurl->out_action(array('remove' => $question->id))."\">
                             <img src=\"$CFG->pixpath/t/delete.gif\" ".
                             "class=\"iconsmall\" alt=\"$strremove\" /></a>";
                 }
@@ -437,7 +538,7 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete=true,
     <?php echo $pageurl->hidden_params_out(); ?>
     <input type="hidden" name="savechanges" value="save" />
         <?php
-            echo '<input type="text" name="q'.$qnum.'" id="inputq'.$qnum.'" size="' . ($quiz->decimalpoints + 2) . '"
+            echo '<input type="text" name="g'.$qnum.'" id="inputq'.$qnum.'" size="' . ($quiz->decimalpoints + 2) . '"
                     value="'.(0 + $quiz->grades[$qnum]).
                     '" tabindex="'.($lastindex+$qno).'" />';
             ?>
index ea7c8d4157d13911eb00535df2d15a2a354cac6e..c618ea2b951b14239f52c1195ae569606af071cc 100644 (file)
@@ -204,6 +204,24 @@ function quiz_delete_attempt($attempt, $quiz) {
     quiz_update_grades($quiz, $userid);
 }
 
+/**
+ * Delete all the preview attempts at a quiz, or possibly all the attempts belonging
+ * to one user.
+ * @param object $quiz the quiz object.
+ * @param integer $userid (optional) if given, only delete the previews belonging to this user.
+ */
+function quiz_delete_previews($quiz, $userid = null) {
+    global $DB;
+    $conditions = array('quiz' => $quiz->id, 'preview' => 1);
+    if (!empty($userid)) {
+        $conditions['userid'] = $userid;
+    }
+    $previewattempts = $DB->get_records('quiz_attempts', $conditions);
+    foreach ($previewattempts as $attempt) {
+        quiz_delete_attempt($attempt, $quiz);
+    }
+}
+
 /// Functions to do with quiz layout and pages ////////////////////////////////
 
 /**
@@ -298,7 +316,7 @@ function quiz_first_questionnumber($quizlayout, $pagelayout) {
  * @param boolean $shuffle Should the questions be reordered randomly?
  * @return string the new layout string
  */
-function quiz_repaginate($layout, $perpage, $shuffle=false) {
+function quiz_repaginate($layout, $perpage, $shuffle = false) {
     $layout = str_replace(',0', '', $layout); // remove existing page breaks
     $questions = explode(',', $layout);
     //remove empty pages from beginning
@@ -306,7 +324,6 @@ function quiz_repaginate($layout, $perpage, $shuffle=false) {
         array_shift($questions);
     }
     if ($shuffle) {
-        srand((float)microtime() * 1000000); // for php < 4.2
         shuffle($questions);
     }
     $i = 1;
diff --git a/mod/quiz/simpletest/testeditlib.php b/mod/quiz/simpletest/testeditlib.php
new file mode 100644 (file)
index 0000000..0a931c5
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Unit tests for (some of) mod/quiz/editlib.php.
+ *
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package quiz
+ */
+
+if (!defined('MOODLE_INTERNAL')) {
+    die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page.
+}
+
+require_once($CFG->dirroot . '/mod/quiz/editlib.php');
+
+class quiz_editlib_test extends UnitTestCase {
+    function test_quiz_move_question_up() {
+        $this->assertEqual(quiz_move_question_up('0', 123), '0');
+        $this->assertEqual(quiz_move_question_up('1,2,0', 1), '1,2,0');
+        $this->assertEqual(quiz_move_question_up('1,2,0', 0), '1,2,0');
+        $this->assertEqual(quiz_move_question_up('1,2,0', 2), '2,1,0');
+        $this->assertEqual(quiz_move_question_up('1,2,0,3,4,0', 3), '1,2,3,0,4,0');
+        $this->assertEqual(quiz_move_question_up('1,2,3,0,4,0', 4), '1,2,3,4,0,0');
+    }
+
+    function test_quiz_move_question_down() {
+        $this->assertEqual(quiz_move_question_down('0', 123), '0');
+        $this->assertEqual(quiz_move_question_down('1,2,0', 2), '1,2,0');
+        $this->assertEqual(quiz_move_question_down('1,2,0', 0), '1,2,0');
+        $this->assertEqual(quiz_move_question_down('1,2,0', 1), '2,1,0');
+        $this->assertEqual(quiz_move_question_down('1,2,0,3,4,0', 2), '1,0,2,3,4,0');
+        $this->assertEqual(quiz_move_question_down('1,0,2,3,0,4,0', 1), '0,1,2,3,0,4,0');
+    }
+
+    function test_quiz_delete_empty_page() {
+        $this->assertEqual(quiz_delete_empty_page('0', 0), '0');
+        $this->assertEqual(quiz_delete_empty_page('1,2,0', 2), '1,2,0');
+        $this->assertEqual(quiz_delete_empty_page('0,1,2,0', -1), '1,2,0');
+        $this->assertEqual(quiz_delete_empty_page('0,1,2,0', 0), '0,1,2,0');
+        $this->assertEqual(quiz_delete_empty_page('1,2,0', 3), '1,2,0');
+        $this->assertEqual(quiz_delete_empty_page('1,2,0', -1), '1,2,0');
+        $this->assertEqual(quiz_delete_empty_page('1,2,0,0', 2), '1,2,0');
+        $this->assertEqual(quiz_delete_empty_page('1,2,0,0', 1), '1,2,0,0');
+        $this->assertEqual(quiz_delete_empty_page('1,2,0,0,3,4,0', 2), '1,2,0,3,4,0');
+        $this->assertEqual(quiz_delete_empty_page('0,0,1,2,0', 0), '0,1,2,0');
+    }
+
+    function test_quiz_add_page_break_after() {
+        $this->assertEqual(quiz_add_page_break_after('0', 1), '0');
+        $this->assertEqual(quiz_add_page_break_after('1,2,0', 1), '1,0,2,0');
+        $this->assertEqual(quiz_add_page_break_after('1,2,0', 2), '1,2,0,0');
+        $this->assertEqual(quiz_add_page_break_after('1,2,0', 0), '1,2,0');
+    }
+
+    function test_quiz_add_page_break_at() {
+        $this->assertEqual(quiz_add_page_break_at('0', 0), '0,0');
+        $this->assertEqual(quiz_add_page_break_at('1,2,0', 0), '0,1,2,0');
+        $this->assertEqual(quiz_add_page_break_at('1,2,0', 1), '1,0,2,0');
+        $this->assertEqual(quiz_add_page_break_at('1,2,0', 2), '1,2,0,0');
+        $this->assertEqual(quiz_add_page_break_at('1,2,0', 3), '1,2,0');
+    }
+}
+?>
\ No newline at end of file
index e68484677de11d18cd32e4cdc4c7e99f64ccc523..82d234f7b6f971c6da9c2bf2ce30e5a0142bcb32 100644 (file)
@@ -89,12 +89,7 @@ if (!$quizobj->is_preview_user() && $messages) {
 $accessmanager->do_password_check($quizobj->is_preview_user());
 
 /// Delete any previous preview attempts belonging to this user.
-if ($oldattempts = $DB->get_records_select('quiz_attempts', "quiz = ?
-        AND userid = ? AND preview = 1", array($quiz->id, $USER->id))) {
-    foreach ($oldattempts as $oldattempt) {
-        quiz_delete_attempt($oldattempt, $quiz);
-    }
-}
+quiz_delete_previews($quiz, $USER->id);
 
 /// Create the new attempt and initialize the question sessions
 $attempt = quiz_create_attempt($quiz, $attemptnumber, $lastattempt, time(), $quizobj->is_preview_user());