Эх сурвалжийг харах

Allow different "save_correct_answers" options see BT#15844

In order to get all answers (correct and incorrect) from previous attempt

Requires a DB change.

$_configuration['allow_quiz_save_correct_options'] = false;
Julio Montoya 5 жил өмнө
parent
commit
dbbb577a48

+ 84 - 44
main/exercise/exercise.class.php

@@ -1,10 +1,12 @@
 <?php
 /* For licensing terms, see /license.txt */
 
+use Chamilo\CoreBundle\Entity\GradebookLink;
 use Chamilo\CoreBundle\Entity\TrackEHotspot;
 use ChamiloSession as Session;
 use Doctrine\DBAL\Types\Type;
 
+
 /**
  * Class Exercise.
  *
@@ -125,6 +127,8 @@ class Exercise
         $this->globalCategoryId = null;
         $this->notifications = [];
         $this->exerciseCategoryId = 0;
+        $this->pageResultConfiguration = [];
+
 
         if (!empty($courseId)) {
             $courseInfo = api_get_course_info_by_id($courseId);
@@ -422,7 +426,7 @@ class Exercise
      *
      * @return string html text : the text to display ay the end of the test
      */
-    public function selectTextWhenFinished()
+    public function getTextWhenFinished()
     {
         return $this->text_when_finished;
     }
@@ -1094,7 +1098,7 @@ class Exercise
     /**
      * @return int
      */
-    public function selectSaveCorrectAnswers()
+    public function getSaveCorrectAnswers()
     {
         return $this->saveCorrectAnswers;
     }
@@ -1263,7 +1267,7 @@ class Exercise
      */
     public function updateSaveCorrectAnswers($value)
     {
-        $this->saveCorrectAnswers = $value;
+        $this->saveCorrectAnswers = (int) $value;
     }
 
     /**
@@ -1520,7 +1524,7 @@ class Exercise
         $random_answers = $this->random_answers;
         $active = $this->active;
         $propagate_neg = (int) $this->propagate_neg;
-        $saveCorrectAnswers = isset($this->saveCorrectAnswers) && $this->saveCorrectAnswers ? 1 : 0;
+        $saveCorrectAnswers = isset($this->saveCorrectAnswers) ? (int) $this->saveCorrectAnswers : 0;
         $review_answers = isset($this->review_answers) && $this->review_answers ? 1 : 0;
         $randomByCat = (int) $this->randomByCat;
         $text_when_finished = $this->text_when_finished;
@@ -1659,7 +1663,7 @@ class Exercise
                 'text_when_finished' => $text_when_finished,
                 'display_category_name' => $display_category_name,
                 'pass_percentage' => $pass_percentage,
-                'save_correct_answers' => (int) $saveCorrectAnswers,
+                'save_correct_answers' => $saveCorrectAnswers,
                 'propagate_neg' => $propagate_neg,
                 'hide_question_title' => $this->getHideQuestionTitle(),
             ];
@@ -2270,11 +2274,26 @@ class Exercise
                 null,
                 get_lang('PropagateNegativeResults')
             );
-            $form->addCheckBox(
-                'save_correct_answers',
-                null,
-                get_lang('SaveTheCorrectAnswersForTheNextAttempt')
-            );
+
+            if (api_get_configuration_value('allow_quiz_save_correct_options')) {
+                $options = [
+                    '' => get_lang('SelectAnOption'),
+                    1 => get_lang('SaveTheCorrectAnswersForTheNextAttempt'),
+                    2 => get_lang('SaveAllAnswers'),
+                ];
+                $form->addSelect(
+                    'save_correct_answers',
+                    get_lang('SaveAnswers'),
+                    $options
+                );
+            } else {
+                $form->addCheckBox(
+                    'save_correct_answers',
+                    null,
+                    get_lang('SaveTheCorrectAnswersForTheNextAttempt')
+                );
+            }
+
             $form->addElement('html', '<div class="clear">&nbsp;</div>');
             $form->addElement('checkbox', 'review_answers', null, get_lang('ReviewAnswers'));
             $form->addElement('html', '<div id="divtimecontrol"  style="display:'.$display.';">');
@@ -2420,10 +2439,10 @@ class Exercise
                 $defaults['exerciseFeedbackType'] = $this->getFeedbackType();
                 $defaults['results_disabled'] = $this->selectResultsDisabled();
                 $defaults['propagate_neg'] = $this->selectPropagateNeg();
-                $defaults['save_correct_answers'] = $this->selectSaveCorrectAnswers();
+                $defaults['save_correct_answers'] = $this->getSaveCorrectAnswers();
                 $defaults['review_answers'] = $this->review_answers;
                 $defaults['randomByCat'] = $this->getRandomByCategory();
-                $defaults['text_when_finished'] = $this->selectTextWhenFinished();
+                $defaults['text_when_finished'] = $this->getTextWhenFinished();
                 $defaults['display_category_name'] = $this->selectDisplayCategoryName();
                 $defaults['pass_percentage'] = $this->selectPassPercentage();
                 $defaults['question_selection_type'] = $this->getQuestionSelectionType();
@@ -7854,12 +7873,13 @@ class Exercise
     /**
      * Get the correct answers in all attempts.
      *
-     * @param int $learnPathId
-     * @param int $learnPathItemId
+     * @param int  $learnPathId
+     * @param int  $learnPathItemId
+     * @param bool $onlyCorrect
      *
      * @return array
      */
-    public function getCorrectAnswersInAllAttempts($learnPathId = 0, $learnPathItemId = 0)
+    public function getAnswersInAllAttempts($learnPathId = 0, $learnPathItemId = 0, $onlyCorrect = true)
     {
         $attempts = Event::getExerciseResultsByUser(
             api_get_user_id(),
@@ -7868,43 +7888,63 @@ class Exercise
             api_get_session_id(),
             $learnPathId,
             $learnPathItemId,
-            'asc'
+            'DESC'
         );
 
-        $corrects = [];
+        $list = [];
         foreach ($attempts as $attempt) {
             foreach ($attempt['question_list'] as $answers) {
                 foreach ($answers as $answer) {
                     $objAnswer = new Answer($answer['question_id']);
-
-                    switch ($objAnswer->getQuestionType()) {
-                        case FILL_IN_BLANKS:
-                            $isCorrect = FillBlanks::isCorrect($answer['answer']);
-                            break;
-                        case MATCHING:
-                        case DRAGGABLE:
-                        case MATCHING_DRAGGABLE:
-                            $isCorrect = Matching::isCorrect(
-                                $answer['position'],
-                                $answer['answer'],
-                                $answer['question_id']
-                            );
-                            break;
-                        case ORAL_EXPRESSION:
-                            $isCorrect = false;
-                            break;
-                        default:
-                            $isCorrect = $objAnswer->isCorrectByAutoId($answer['answer']);
-                    }
-
-                    if ($isCorrect) {
-                        $corrects[$answer['question_id']][] = $answer;
+                    if ($onlyCorrect) {
+                        switch ($objAnswer->getQuestionType()) {
+                            case FILL_IN_BLANKS:
+                                $isCorrect = FillBlanks::isCorrect($answer['answer']);
+                                break;
+                            case MATCHING:
+                            case DRAGGABLE:
+                            case MATCHING_DRAGGABLE:
+                                $isCorrect = Matching::isCorrect(
+                                    $answer['position'],
+                                    $answer['answer'],
+                                    $answer['question_id']
+                                );
+                                break;
+                            case ORAL_EXPRESSION:
+                                $isCorrect = false;
+                                break;
+                            default:
+                                $isCorrect = $objAnswer->isCorrectByAutoId($answer['answer']);
+                        }
+                        if ($isCorrect) {
+                            $list[$answer['question_id']][] = $answer;
+                        }
+                    } else {
+                        $list[$answer['question_id']][] = $answer;
                     }
                 }
             }
+
+            if ($onlyCorrect === false) {
+                // Only take latest attempt
+                break;
+            }
         }
 
-        return $corrects;
+        return $list;
+    }
+
+    /**
+     * Get the correct answers in all attempts.
+     *
+     * @param int $learnPathId
+     * @param int $learnPathItemId
+     *
+     * @return array
+     */
+    public function getCorrectAnswersInAllAttempts($learnPathId = 0, $learnPathItemId = 0)
+    {
+        return $this->getAnswersInAllAttempts($learnPathId , $learnPathItemId);
     }
 
     /**
@@ -7979,14 +8019,14 @@ class Exercise
                 'hide_question_score' => isset($values['hide_question_score']) ? $values['hide_question_score'] : '',
                 'hide_total_score' => isset($values['hide_total_score']) ? $values['hide_total_score'] : ''
             ];*/
-            $type = \Doctrine\DBAL\Types\Type::getType('array');
+            $type = Type::getType('array');
             $platform = Database::getManager()->getConnection()->getDatabasePlatform();
             $result = $type->convertToPHPValue($this->pageResultConfiguration, $platform);
 
             return $result;
         }
 
-        return $this->pageResultConfiguration;
+        return [];
     }
 
     /**
@@ -8336,7 +8376,7 @@ class Exercise
 
             foreach ($links as $link) {
                 $linkId = $link['id'];
-                /** @var \Chamilo\CoreBundle\Entity\GradebookLink $exerciseLink */
+                /** @var GradebookLink $exerciseLink */
                 $exerciseLink = $repo->find($linkId);
                 if ($exerciseLink) {
                     $exerciseLink

+ 1 - 1
main/exercise/exercise_show.php

@@ -358,7 +358,7 @@ if (!empty($track_exercise_info['data_tracking'])) {
 }
 
 // Display the text when finished message if we are on a LP #4227
-$end_of_message = $objExercise->selectTextWhenFinished();
+$end_of_message = $objExercise->getTextWhenFinished();
 if (!empty($end_of_message) && ($origin === 'learnpath')) {
     echo Display::return_message($end_of_message, 'normal', false);
     echo "<div class='clear'>&nbsp;</div>";

+ 18 - 8
main/exercise/exercise_submit.php

@@ -109,7 +109,6 @@ $logInfo = [
 ];
 Event::registerLog($logInfo);
 
-// Error message
 $error = '';
 $exercise_attempt_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
 
@@ -1414,11 +1413,23 @@ if (!empty($error)) {
         $user_choice = null;
         if (isset($attempt_list[$questionId])) {
             $user_choice = $attempt_list[$questionId];
-        } elseif ($objExercise->saveCorrectAnswers) {
-            $correctAnswers = $objExercise->getCorrectAnswersInAllAttempts(
-                $learnpath_id,
-                $learnpath_item_id
-            );
+        } elseif ($objExercise->getSaveCorrectAnswers()) {
+            $correctAnswers = [];
+            switch ($objExercise->getSaveCorrectAnswers()) {
+                case 1:
+                    $correctAnswers = $objExercise->getCorrectAnswersInAllAttempts(
+                        $learnpath_id,
+                        $learnpath_item_id
+                    );
+                    break;
+                case 2:
+                    $correctAnswers = $objExercise->getAnswersInAllAttempts(
+                        $learnpath_id,
+                        $learnpath_item_id,
+                        false
+                    );
+                    break;
+            }
 
             if (isset($correctAnswers[$questionId])) {
                 $user_choice = $correctAnswers[$questionId];
@@ -1426,8 +1437,7 @@ if (!empty($error)) {
         }
 
         $remind_highlight = '';
-
-        //Hides questions when reviewing a ALL_ON_ONE_PAGE exercise see #4542 no_remind_highlight class hide with jquery
+        // Hides questions when reviewing a ALL_ON_ONE_PAGE exercise see #4542 no_remind_highlight class hide with jquery
         if ($objExercise->type == ALL_ON_ONE_PAGE &&
             isset($_GET['reminder']) && $_GET['reminder'] == 2
         ) {

+ 149 - 165
main/inc/lib/exercise.lib.php

@@ -118,111 +118,119 @@ class ExerciseLib
             // suggestions here, for the sake of comprehensions, while the ones
             // on the right side are called answers
             $num_suggestions = 0;
-            if (in_array($answerType, [MATCHING, DRAGGABLE, MATCHING_DRAGGABLE])) {
-                if ($answerType == DRAGGABLE) {
-                    $isVertical = $objQuestionTmp->extra == 'v';
-                    $s .= '
-                        <div class="col-md-12 ui-widget ui-helper-clearfix">
-                            <div class="clearfix">
-                            <ul class="exercise-draggable-answer '.($isVertical ? '' : 'list-inline').'"
-                                id="question-'.$questionId.'" data-question="'.$questionId.'">
-                    ';
-                } else {
-                    $s .= '<div id="drag'.$questionId.'_question" class="drag_question">
-                           <table class="data_table">';
-                }
 
-                // Iterate through answers
-                $x = 1;
-                //mark letters for each answer
-                $letter = 'A';
-                $answer_matching = [];
-                $cpt1 = [];
-                for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) {
-                    $answerCorrect = $objAnswerTmp->isCorrect($answerId);
-                    $numAnswer = $objAnswerTmp->selectAutoId($answerId);
-                    if ($answerCorrect == 0) {
-                        // options (A, B, C, ...) that will be put into the list-box
-                        // have the "correct" field set to 0 because they are answer
-                        $cpt1[$x] = $letter;
-                        $answer_matching[$x] = $objAnswerTmp->selectAnswerByAutoId(
-                            $numAnswer
-                        );
-                        $x++;
-                        $letter++;
+            switch ($answerType) {
+                case MATCHING:
+                case DRAGGABLE:
+                case MATCHING_DRAGGABLE:
+                    if ($answerType == DRAGGABLE) {
+                        $isVertical = $objQuestionTmp->extra == 'v';
+                        $s .= '
+                            <div class="col-md-12 ui-widget ui-helper-clearfix">
+                                <div class="clearfix">
+                                <ul class="exercise-draggable-answer '.($isVertical ? '' : 'list-inline').'"
+                                    id="question-'.$questionId.'" data-question="'.$questionId.'">
+                        ';
+                    } else {
+                        $s .= '<div id="drag'.$questionId.'_question" class="drag_question">
+                               <table class="data_table">';
                     }
-                }
 
-                $i = 1;
-                $select_items[0]['id'] = 0;
-                $select_items[0]['letter'] = '--';
-                $select_items[0]['answer'] = '';
-                foreach ($answer_matching as $id => $value) {
-                    $select_items[$i]['id'] = $value['id_auto'];
-                    $select_items[$i]['letter'] = $cpt1[$id];
-                    $select_items[$i]['answer'] = $value['answer'];
-                    $i++;
-                }
+                    // Iterate through answers
+                    $x = 1;
+                    //mark letters for each answer
+                    $letter = 'A';
+                    $answer_matching = [];
+                    $cpt1 = [];
+                    for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) {
+                        $answerCorrect = $objAnswerTmp->isCorrect($answerId);
+                        $numAnswer = $objAnswerTmp->selectAutoId($answerId);
+                        if ($answerCorrect == 0) {
+                            // options (A, B, C, ...) that will be put into the list-box
+                            // have the "correct" field set to 0 because they are answer
+                            $cpt1[$x] = $letter;
+                            $answer_matching[$x] = $objAnswerTmp->selectAnswerByAutoId(
+                                $numAnswer
+                            );
+                            $x++;
+                            $letter++;
+                        }
+                    }
 
-                $user_choice_array_position = [];
-                if (!empty($user_choice)) {
-                    foreach ($user_choice as $item) {
-                        $user_choice_array_position[$item['position']] = $item['answer'];
+                    $i = 1;
+                    $select_items[0]['id'] = 0;
+                    $select_items[0]['letter'] = '--';
+                    $select_items[0]['answer'] = '';
+                    foreach ($answer_matching as $id => $value) {
+                        $select_items[$i]['id'] = $value['id_auto'];
+                        $select_items[$i]['letter'] = $cpt1[$id];
+                        $select_items[$i]['answer'] = $value['answer'];
+                        $i++;
                     }
-                }
-                $num_suggestions = ($nbrAnswers - $x) + 1;
-            } elseif ($answerType == FREE_ANSWER) {
-                $fck_content = isset($user_choice[0]) && !empty($user_choice[0]['answer']) ? $user_choice[0]['answer'] : null;
-                $form = new FormValidator('free_choice_'.$questionId);
-                $config = [
-                    'ToolbarSet' => 'TestFreeAnswer',
-                ];
-                $form->addHtmlEditor(
-                    "choice[".$questionId."]",
-                    null,
-                    false,
-                    false,
-                    $config
-                );
-                $form->setDefaults(["choice[".$questionId."]" => $fck_content]);
-                $s .= $form->returnForm();
-            } elseif ($answerType == ORAL_EXPRESSION) {
-                // Add nanog
-                if (api_get_setting('enable_record_audio') === 'true') {
-                    //@todo pass this as a parameter
-                    global $exercise_stat_info, $exerciseId;
-                    if (!empty($exercise_stat_info)) {
-                        $objQuestionTmp->initFile(
-                            api_get_session_id(),
-                            api_get_user_id(),
-                            $exercise_stat_info['exe_exo_id'],
-                            $exercise_stat_info['exe_id']
-                        );
-                    } else {
-                        $objQuestionTmp->initFile(
-                            api_get_session_id(),
-                            api_get_user_id(),
-                            $exerciseId,
-                            'temp_exe'
-                        );
+
+                    $user_choice_array_position = [];
+                    if (!empty($user_choice)) {
+                        foreach ($user_choice as $item) {
+                            $user_choice_array_position[$item['position']] = $item['answer'];
+                        }
                     }
 
-                    echo $objQuestionTmp->returnRecorder();
-                }
+                    $num_suggestions = ($nbrAnswers - $x) + 1;
+                    break;
+                case FREE_ANSWER:
+                    $fck_content = isset($user_choice[0]) && !empty($user_choice[0]['answer']) ? $user_choice[0]['answer'] : null;
+                    $form = new FormValidator('free_choice_'.$questionId);
+                    $config = [
+                        'ToolbarSet' => 'TestFreeAnswer',
+                    ];
+                    $form->addHtmlEditor(
+                        "choice[".$questionId."]",
+                        null,
+                        false,
+                        false,
+                        $config
+                    );
+                    $form->setDefaults(["choice[".$questionId."]" => $fck_content]);
+                    $s .= $form->returnForm();
+                    break;
+                case ORAL_EXPRESSION:
+                    // Add nanog
+                    if (api_get_setting('enable_record_audio') === 'true') {
+                        //@todo pass this as a parameter
+                        global $exercise_stat_info, $exerciseId;
+                        if (!empty($exercise_stat_info)) {
+                            $objQuestionTmp->initFile(
+                                api_get_session_id(),
+                                api_get_user_id(),
+                                $exercise_stat_info['exe_exo_id'],
+                                $exercise_stat_info['exe_id']
+                            );
+                        } else {
+                            $objQuestionTmp->initFile(
+                                api_get_session_id(),
+                                api_get_user_id(),
+                                $exerciseId,
+                                'temp_exe'
+                            );
+                        }
 
-                $form = new FormValidator('free_choice_'.$questionId);
-                $config = ['ToolbarSet' => 'TestFreeAnswer'];
+                        echo $objQuestionTmp->returnRecorder();
+                    }
 
-                $form->addHtml('<div id="'.'hide_description_'.$questionId.'_options" style="display: none;">');
-                $form->addHtmlEditor(
-                    "choice[$questionId]",
-                    null,
-                    false,
-                    false,
-                    $config
-                );
-                $form->addHtml('</div>');
-                $s .= $form->returnForm();
+                    $form = new FormValidator('free_choice_'.$questionId);
+                    $config = ['ToolbarSet' => 'TestFreeAnswer'];
+
+                    $form->addHtml('<div id="'.'hide_description_'.$questionId.'_options" style="display: none;">');
+                    $form->addHtmlEditor(
+                        "choice[$questionId]",
+                        null,
+                        false,
+                        false,
+                        $config
+                    );
+                    $form->addHtml('</div>');
+                    $s .= $form->returnForm();
+                    break;
             }
 
             // Now navigate through the possible answers, using the max number of
@@ -911,9 +919,10 @@ class ExerciseLib
                          */
                         if ($origin !== null) {
                             global $exe_id;
+                            $exe_id = (int) $exe_id;
                             $trackAttempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
-                            $sql = 'SELECT answer FROM '.$trackAttempts.'
-                                    WHERE exe_id='.$exe_id.' AND question_id='.$questionId;
+                            $sql = "SELECT answer FROM $trackAttempts
+                                    WHERE exe_id = $exe_id AND question_id= $questionId";
                             $rsLastAttempt = Database::query($sql);
                             $rowLastAttempt = Database::fetch_array($rsLastAttempt);
                             $answer = $rowLastAttempt['answer'];
@@ -998,7 +1007,7 @@ class ExerciseLib
                             $answer = '';
                             $i = 0;
                             foreach ($studentAnswerList as $studentItem) {
-                                // remove surronding brackets
+                                // Remove surronding brackets
                                 $studentResponse = api_substr(
                                     $studentItem,
                                     1,
@@ -1081,7 +1090,7 @@ class ExerciseLib
                                     $selected = 'selected="selected"';
                                 }
                                 $s .= '<option value="'.$val['id'].'" '.$selected.'>'.$val['letter'].'</option>';
-                            }  // end foreach()
+                            }
 
                             $s .= '</select></div></td><td width="5%" class="separate">&nbsp;</td>';
                             $s .= '<td width="40%" valign="top" >';
@@ -1098,7 +1107,7 @@ class ExerciseLib
                             $s .= '</td>';
                             $s .= '</tr>';
                             $lines_count++;
-                            //if the left side of the "matching" has been completely
+                            // If the left side of the "matching" has been completely
                             // shown but the right side still has values to show...
                             if (($lines_count - 1) == $num_suggestions) {
                                 // if it remains answers to shown at the right side
@@ -1111,8 +1120,8 @@ class ExerciseLib
                                     $s .= "</td>
                                 </tr>";
                                     $lines_count++;
-                                }    // end while()
-                            }  // end if()
+                                }
+                            }
                             $matching_correct_answer++;
                         }
                         break;
@@ -1314,7 +1323,7 @@ HTML;
                         }
                         break;
                 }
-            } // end for()
+            }
 
             if ($show_comment) {
                 $s .= '</table>';
@@ -1334,9 +1343,8 @@ HTML;
 
             if ($answerType == DRAGGABLE) {
                 $isVertical = $objQuestionTmp->extra == 'v';
-
                 $s .= "</ul>";
-                $s .= "</div>"; //clearfix
+                $s .= "</div>";
                 $counterAnswer = 1;
                 $s .= $isVertical ? '' : '<div class="row">';
                 for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) {
@@ -1378,7 +1386,7 @@ HTML;
         } elseif ($answerType == HOT_SPOT || $answerType == HOT_SPOT_DELINEATION) {
             global $exerciseId, $exe_id;
             // Question is a HOT_SPOT
-            //checking document/images visibility
+            // Checking document/images visibility
             if (api_is_platform_admin() || api_is_course_admin()) {
                 $doc_id = $objQuestionTmp->getPictureId();
                 if (is_numeric($doc_id)) {
@@ -1672,12 +1680,12 @@ HOTSPOT;
                 }
 
                 return true;
-            } else {
-                return false;
             }
-        } else {
-            return true;
+
+            return false;
         }
+
+        return true;
     }
 
     /**
@@ -1782,18 +1790,18 @@ HOTSPOT;
     }
 
     /**
-     * @param string $in_hotpot_path
+     * @param string $path
      *
      * @return int
      */
-    public static function get_count_exam_hotpotatoes_results($in_hotpot_path)
+    public static function get_count_exam_hotpotatoes_results($path)
     {
         return self::get_exam_results_hotpotatoes_data(
             0,
             0,
             '',
             '',
-            $in_hotpot_path,
+            $path,
             true,
             ''
         );
@@ -1828,16 +1836,20 @@ HOTSPOT;
         $in_direction = Database::escape_string($in_direction);
         $in_column = Database::escape_string($in_column);
         $in_number_of_items = intval($in_number_of_items);
-        $in_from = intval($in_from);
+        $in_from = (int) $in_from;
 
         $TBL_TRACK_HOTPOTATOES = Database::get_main_table(
             TABLE_STATISTIC_TRACK_E_HOTPOTATOES
         );
         $TBL_USER = Database::get_main_table(TABLE_MAIN_USER);
 
-        $sql = "SELECT *, thp.id AS thp_id FROM $TBL_TRACK_HOTPOTATOES thp
-            JOIN $TBL_USER u ON thp.exe_user_id = u.user_id
-            WHERE thp.c_id = $courseId AND exe_name LIKE '$in_hotpot_path%'";
+        $sql = "SELECT *, thp.id AS thp_id 
+                FROM $TBL_TRACK_HOTPOTATOES thp
+                JOIN $TBL_USER u 
+                ON thp.exe_user_id = u.user_id
+                WHERE 
+                    thp.c_id = $courseId AND 
+                    exe_name LIKE '$in_hotpot_path%'";
 
         // just count how many answers
         if ($in_get_count) {
@@ -1872,7 +1884,7 @@ HOTSPOT;
                 'lastname' => $data['lastname'],
                 'username' => $data['username'],
                 'group_name' => implode(
-                    "<br/>",
+                    '<br/>',
                     GroupManager::get_user_group_name($data['user_id'])
                 ),
                 'exe_date' => $data['exe_date'],
@@ -1898,11 +1910,10 @@ HOTSPOT;
         $courseId,
         $sessionId
     ) {
-        $table = Database::get_main_table(
-            TABLE_STATISTIC_TRACK_E_HOTPOTATOES
-        );
+        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES);
         $exercisePath = Database::escape_string($exercisePath);
         $userId = (int) $userId;
+        $courseId = (int) $courseId;
 
         $sql = "SELECT * FROM $table
                 WHERE
@@ -1967,6 +1978,9 @@ HOTSPOT;
         }
 
         $course_id = $courseInfo['real_id'];
+        $sessionId = api_get_session_id();
+        $exercise_id = (int) $exercise_id;
+
         $is_allowedToEdit =
             api_is_allowed_to_edit(null, true) ||
             api_is_allowed_to_edit(true) ||
@@ -1980,14 +1994,14 @@ HOTSPOT;
         $TBL_TRACK_EXERCICES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $TBL_TRACK_HOTPOTATOES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES);
         $TBL_TRACK_ATTEMPT_RECORDING = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
-        $sessionId = api_get_session_id();
+
         $session_id_and = '';
         $sessionCondition = '';
         if (!$showSessionField) {
             $session_id_and = " AND te.session_id = $sessionId ";
             $sessionCondition = " AND ttte.session_id = $sessionId";
         }
-        $exercise_id = (int) $exercise_id;
+
         $exercise_where = '';
         if (!empty($exercise_id)) {
             $exercise_where .= ' AND te.exe_exo_id = '.$exercise_id.'  ';
@@ -2160,9 +2174,9 @@ HOTSPOT;
 
             // sql for hotpotatoes tests for teacher / tutor view
             if ($get_count) {
-                $hpsql_select = "SELECT count(username)";
+                $hpsql_select = ' SELECT count(username) ';
             } else {
-                $hpsql_select = "SELECT
+                $hpsql_select = " SELECT
                     $first_and_last_name ,
                     username,
                     official_code,
@@ -2761,8 +2775,6 @@ HOTSPOT;
      */
     public static function convertScoreToPlatformSetting($score, $weight)
     {
-        $result = ['score' => $score, 'weight' => $weight];
-
         $maxNote = api_get_setting('exercise_max_score');
         $minNote = api_get_setting('exercise_min_score');
 
@@ -2981,7 +2993,7 @@ HOTSPOT;
      * @return bool
      */
     public static function addScoreModelInput(
-        FormValidator &$form,
+        FormValidator $form,
         $name,
         $weight,
         $selected
@@ -3134,35 +3146,6 @@ EOT;
         return $return;
     }
 
-    /**
-     * Converts a score/weight values to the platform scale.
-     *
-     * @param float $score
-     * @param float $weight
-     *
-     * @deprecated seem not to be used
-     *
-     * @return float the score rounded converted to the new range
-     */
-    public static function convert_score($score, $weight)
-    {
-        $maxNote = api_get_setting('exercise_max_score');
-        $minNote = api_get_setting('exercise_min_score');
-
-        if ($score != '' && $weight != '') {
-            if ($maxNote != '' && $minNote != '') {
-                if (!empty($weight)) {
-                    $score = $minNote + ($maxNote - $minNote) * $score / $weight;
-                } else {
-                    $score = $minNote;
-                }
-            }
-        }
-        $score_rounded = float_format($score, 1);
-
-        return $score_rounded;
-    }
-
     /**
      * Getting all active exercises from a course from a session
      * (if a session_id is provided we will show all the exercises in the course +
@@ -3693,9 +3676,10 @@ EOT;
     /**
      * Get average score by score (NO Exercises in LPs ).
      *
-     * @param    int        exercise id
+     * @param int $exercise_id
      * @param int $courseId
-     * @param    int        session id
+     * @param int $session_id
+     * @param int $user_count
      *
      * @return float Best average score
      */
@@ -3718,7 +3702,7 @@ EOT;
                     $avg_score += $score;
                 }
             }
-            //We asumme that all exe_weighting
+            // We asumme that all exe_weighting
             if (!empty($user_count)) {
                 $avg_score = float_format($avg_score / $user_count, 1) * 100;
             } else {
@@ -3732,9 +3716,9 @@ EOT;
     /**
      * Get average score by score (NO Exercises in LPs ).
      *
-     * @param    int        exercise id
+     * @param int $exercise_id
      * @param int $courseId
-     * @param    int        session id
+     * @param int $session_id
      *
      * @return float Best average score
      */
@@ -4084,7 +4068,7 @@ EOT;
         switch ($question_type) {
             case FILL_IN_BLANKS:
                 $answer_condition = '';
-                $select_condition = " e.exe_id, answer ";
+                $select_condition = ' e.exe_id, answer ';
                 break;
             case MATCHING:
             case MATCHING_DRAGGABLE:
@@ -4538,7 +4522,7 @@ EOT;
         }
 
         // Display text when test is finished #4074 and for LP #4227
-        $endOfMessage = $objExercise->selectTextWhenFinished();
+        $endOfMessage = $objExercise->getTextWhenFinished();
         if (!empty($endOfMessage)) {
             echo Display::return_message($endOfMessage, 'normal', false);
             echo "<div class='clear'>&nbsp;</div>";

+ 3 - 0
main/install/configuration.dist.php

@@ -1231,6 +1231,9 @@ $_configuration['required_extra_fields_in_profile'] = [
 // ALTER TABLE c_quiz ADD page_result_configuration LONGTEXT DEFAULT NULL COMMENT '(DC2Type:array)';
 //$_configuration['allow_quiz_results_page_config'] = false;
 
+// ALTER TABLE c_quiz MODIFY COLUMN save_correct_answers INT NULL DEFAULT NULL;
+//$_configuration['allow_quiz_save_correct_options'] = false;
+
 // KEEP THIS AT THE END
 // -------- Custom DB changes
 // Add user activation by confirmation email