|
@@ -7853,7 +7853,6 @@ class Exercise
|
|
|
|
|
|
/**
|
|
|
* @param int $value
|
|
|
- *
|
|
|
*/
|
|
|
public function setExerciseCategoryId($value)
|
|
|
{
|
|
@@ -8170,1519 +8169,1520 @@ class Exercise
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Gets the question list ordered by the question_order setting (drag and drop).
|
|
|
+ * @param int $categoryId
|
|
|
+ * @param int $page
|
|
|
+ * @param int $from
|
|
|
+ * @param int $limit
|
|
|
*
|
|
|
- * @return array
|
|
|
+ * @throws \Doctrine\ORM\Query\QueryException
|
|
|
+ *
|
|
|
+ * @return string
|
|
|
*/
|
|
|
- private function getQuestionOrderedList()
|
|
|
+ public static function exerciseGrid($categoryId, $page, $from, $limit)
|
|
|
{
|
|
|
- $TBL_EXERCICE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
|
|
|
- $TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION);
|
|
|
+ $TBL_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
|
|
|
+ $TBL_ITEM_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
|
|
|
+ $TBL_EXERCISE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
|
|
|
+ $TBL_EXERCISES = Database::get_course_table(TABLE_QUIZ_TEST);
|
|
|
+ $TBL_TRACK_EXERCISES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
|
|
|
|
|
|
- // Getting question_order to verify that the question
|
|
|
- // list is correct and all question_order's were set
|
|
|
- $sql = "SELECT DISTINCT count(e.question_order) as count
|
|
|
- FROM $TBL_EXERCICE_QUESTION e
|
|
|
- INNER JOIN $TBL_QUESTIONS q
|
|
|
- ON (e.question_id = q.id AND e.c_id = q.c_id)
|
|
|
- WHERE
|
|
|
- e.c_id = {$this->course_id} AND
|
|
|
- e.exercice_id = ".$this->id;
|
|
|
+ $categoryId = (int) $categoryId;
|
|
|
+ $page = (int) $page;
|
|
|
+ $from = (int) $from;
|
|
|
+ $limit = (int) $limit;
|
|
|
|
|
|
- $result = Database::query($sql);
|
|
|
- $row = Database::fetch_array($result);
|
|
|
- $count_question_orders = $row['count'];
|
|
|
+ $autoLaunchAvailable = false;
|
|
|
+ if (api_get_course_setting('enable_exercise_auto_launch') == 1 &&
|
|
|
+ api_get_configuration_value('allow_exercise_auto_launch')
|
|
|
+ ) {
|
|
|
+ $autoLaunchAvailable = true;
|
|
|
+ }
|
|
|
|
|
|
- // Getting question list from the order (question list drag n drop interface).
|
|
|
- $sql = "SELECT DISTINCT e.question_id, e.question_order
|
|
|
- FROM $TBL_EXERCICE_QUESTION e
|
|
|
- INNER JOIN $TBL_QUESTIONS q
|
|
|
- ON (e.question_id = q.id AND e.c_id = q.c_id)
|
|
|
- WHERE
|
|
|
- e.c_id = {$this->course_id} AND
|
|
|
- e.exercice_id = '".$this->id."'
|
|
|
- ORDER BY question_order";
|
|
|
- $result = Database::query($sql);
|
|
|
+ $is_allowedToEdit = api_is_allowed_to_edit(null, true);
|
|
|
+ $courseInfo = api_get_course_info();
|
|
|
+ $sessionId = api_get_session_id();
|
|
|
+ $courseId = $courseInfo['real_id'];
|
|
|
+ $tableRows = [];
|
|
|
+ $uploadPath = DIR_HOTPOTATOES; //defined in main_api
|
|
|
+ $exercisePath = api_get_self();
|
|
|
+ $origin = api_get_origin();
|
|
|
+ $userInfo = api_get_user_info();
|
|
|
+ $charset = 'utf-8';
|
|
|
+ $token = Security::get_token();
|
|
|
+ $userId = api_get_user_id();
|
|
|
+ $isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh(
|
|
|
+ $userId,
|
|
|
+ $courseInfo
|
|
|
+ );
|
|
|
+ $documentPath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
|
|
|
|
|
|
- // Fills the array with the question ID for this exercise
|
|
|
- // the key of the array is the question position
|
|
|
- $temp_question_list = [];
|
|
|
- $counter = 1;
|
|
|
- $questionList = [];
|
|
|
- while ($new_object = Database::fetch_object($result)) {
|
|
|
- // Correct order.
|
|
|
- $questionList[$new_object->question_order] = $new_object->question_id;
|
|
|
- // Just in case we save the order in other array
|
|
|
- $temp_question_list[$counter] = $new_object->question_id;
|
|
|
- $counter++;
|
|
|
- }
|
|
|
+ $limitTeacherAccess = api_get_configuration_value('limit_exercise_teacher_access');
|
|
|
|
|
|
- if (!empty($temp_question_list)) {
|
|
|
- /* If both array don't match it means that question_order was not correctly set
|
|
|
- for all questions using the default mysql order */
|
|
|
- if (count($temp_question_list) != $count_question_orders) {
|
|
|
- $questionList = $temp_question_list;
|
|
|
- }
|
|
|
- }
|
|
|
+ $learnpath_id = isset($_REQUEST['learnpath_id']) ? (int) $_REQUEST['learnpath_id'] : null;
|
|
|
+ $learnpath_item_id = isset($_REQUEST['learnpath_item_id']) ? (int) $_REQUEST['learnpath_item_id'] : null;
|
|
|
|
|
|
- return $questionList;
|
|
|
- }
|
|
|
+ // Condition for the session
|
|
|
+ $condition_session = api_get_session_condition($sessionId, true, true);
|
|
|
+ $content = '';
|
|
|
|
|
|
- /**
|
|
|
- * Select N values from the questions per category array.
|
|
|
- *
|
|
|
- * @param array $categoriesAddedInExercise
|
|
|
- * @param array $question_list
|
|
|
- * @param array $questions_by_category per category
|
|
|
- * @param bool $flatResult
|
|
|
- * @param bool $randomizeQuestions
|
|
|
- *
|
|
|
- * @return array
|
|
|
- */
|
|
|
- private function pickQuestionsPerCategory(
|
|
|
- $categoriesAddedInExercise,
|
|
|
- $question_list,
|
|
|
- &$questions_by_category,
|
|
|
- $flatResult = true,
|
|
|
- $randomizeQuestions = false
|
|
|
- ) {
|
|
|
- $addAll = true;
|
|
|
- $categoryCountArray = [];
|
|
|
+ $categoryCondition = '';
|
|
|
+ if (!empty($categoryId)) {
|
|
|
+ $categoryCondition = " AND exercise_category_id = $categoryId ";
|
|
|
+ }
|
|
|
|
|
|
- // Getting how many questions will be selected per category.
|
|
|
- if (!empty($categoriesAddedInExercise)) {
|
|
|
- $addAll = false;
|
|
|
- // Parsing question according the category rel exercise settings
|
|
|
- foreach ($categoriesAddedInExercise as $category_info) {
|
|
|
- $category_id = $category_info['category_id'];
|
|
|
- if (isset($questions_by_category[$category_id])) {
|
|
|
- // How many question will be picked from this category.
|
|
|
- $count = $category_info['count_questions'];
|
|
|
- // -1 means all questions
|
|
|
- $categoryCountArray[$category_id] = $count;
|
|
|
- if ($count == -1) {
|
|
|
- $categoryCountArray[$category_id] = 999;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ // Only for administrators
|
|
|
+ if ($is_allowedToEdit) {
|
|
|
+ $total_sql = "SELECT count(iid) as count
|
|
|
+ FROM $TBL_EXERCISES
|
|
|
+ WHERE
|
|
|
+ c_id = $courseId AND
|
|
|
+ active<>'-1'
|
|
|
+ $condition_session
|
|
|
+ $categoryCondition
|
|
|
+ ";
|
|
|
+ $sql = "SELECT * FROM $TBL_EXERCISES
|
|
|
+ WHERE c_id = $courseId AND active<>'-1' $condition_session $categoryCondition
|
|
|
+ ORDER BY title
|
|
|
+ LIMIT ".$from.",".$limit;
|
|
|
+ } else {
|
|
|
+ // Only for students
|
|
|
+ $total_sql = "SELECT count(iid) as count
|
|
|
+ FROM $TBL_EXERCISES
|
|
|
+ WHERE c_id = $courseId AND active = '1' $condition_session $categoryCondition";
|
|
|
+ $sql = "SELECT * FROM $TBL_EXERCISES
|
|
|
+ WHERE c_id = $courseId AND
|
|
|
+ active='1' $condition_session
|
|
|
+ $categoryCondition
|
|
|
+ ORDER BY title LIMIT ".$from.",".$limit;
|
|
|
}
|
|
|
+ $result = Database::query($sql);
|
|
|
+ $result_total = Database::query($total_sql);
|
|
|
|
|
|
- if (!empty($questions_by_category)) {
|
|
|
- $temp_question_list = [];
|
|
|
- foreach ($questions_by_category as $category_id => &$categoryQuestionList) {
|
|
|
- if (isset($categoryCountArray) && !empty($categoryCountArray)) {
|
|
|
- $numberOfQuestions = 0;
|
|
|
- if (isset($categoryCountArray[$category_id])) {
|
|
|
- $numberOfQuestions = $categoryCountArray[$category_id];
|
|
|
- }
|
|
|
- }
|
|
|
+ $total_exercises = 0;
|
|
|
+ if (Database :: num_rows($result_total)) {
|
|
|
+ $result_total = Database::fetch_array($result_total);
|
|
|
+ $total_exercises = $result_total['count'];
|
|
|
+ }
|
|
|
|
|
|
- if ($addAll) {
|
|
|
- $numberOfQuestions = 999;
|
|
|
- }
|
|
|
+ //get HotPotatoes files (active and inactive)
|
|
|
+ if ($is_allowedToEdit) {
|
|
|
+ $sql = "SELECT * FROM $TBL_DOCUMENT
|
|
|
+ WHERE
|
|
|
+ c_id = $courseId AND
|
|
|
+ path LIKE '".Database::escape_string($uploadPath.'/%/%')."'";
|
|
|
+ $res = Database::query($sql);
|
|
|
+ $hp_count = Database :: num_rows($res);
|
|
|
+ } else {
|
|
|
+ $sql = "SELECT * FROM $TBL_DOCUMENT d
|
|
|
+ INNER JOIN $TBL_ITEM_PROPERTY ip
|
|
|
+ ON (d.id = ip.ref AND d.c_id = ip.c_id)
|
|
|
+ WHERE
|
|
|
+ ip.tool = '".TOOL_DOCUMENT."' AND
|
|
|
+ d.path LIKE '".Database::escape_string($uploadPath.'/%/%')."' AND
|
|
|
+ ip.visibility ='1' AND
|
|
|
+ d.c_id = $courseId AND
|
|
|
+ ip.c_id = $courseId";
|
|
|
+ $res = Database::query($sql);
|
|
|
+ $hp_count = Database::num_rows($res);
|
|
|
+ }
|
|
|
|
|
|
- if (!empty($numberOfQuestions)) {
|
|
|
- $elements = TestCategory::getNElementsFromArray(
|
|
|
- $categoryQuestionList,
|
|
|
- $numberOfQuestions,
|
|
|
- $randomizeQuestions
|
|
|
- );
|
|
|
+ $total = $total_exercises + $hp_count;
|
|
|
|
|
|
- if (!empty($elements)) {
|
|
|
- $temp_question_list[$category_id] = $elements;
|
|
|
- $categoryQuestionList = $elements;
|
|
|
- }
|
|
|
- }
|
|
|
+ if ($total > $limit) {
|
|
|
+ $content .= '<div style="float:right;height:20px;">';
|
|
|
+ // Show pages navigation link for previous page
|
|
|
+ if ($page) {
|
|
|
+ $content .= "<a href=\"".api_get_self()."?".api_get_cidreq()."&page=".($page - 1)."\">".
|
|
|
+ Display::return_icon('action_prev.png', get_lang('PreviousPage')).'</a>';
|
|
|
+ } elseif ($total_exercises + $hp_count > $limit) {
|
|
|
+ $content .= Display::return_icon('action_prev_na.png', get_lang('PreviousPage'));
|
|
|
}
|
|
|
|
|
|
- if (!empty($temp_question_list)) {
|
|
|
- if ($flatResult) {
|
|
|
- $temp_question_list = array_flatten($temp_question_list);
|
|
|
- }
|
|
|
- $question_list = $temp_question_list;
|
|
|
+ // Show pages navigation link for previous page
|
|
|
+ if ($total_exercises > $from + $limit || $hp_count > $from + $limit) {
|
|
|
+ $content .= ' '."<a href=\"".api_get_self()."?".api_get_cidreq()."&page=".($page + 1)."\">".
|
|
|
+ Display::return_icon('action_next.png', get_lang('NextPage')).'</a>';
|
|
|
+ } elseif ($page) {
|
|
|
+ $content .= ' '.Display::return_icon('action_next_na.png', get_lang('NextPage'));
|
|
|
}
|
|
|
+ $content .= '</div>';
|
|
|
}
|
|
|
|
|
|
- return $question_list;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Changes the exercise id.
|
|
|
- *
|
|
|
- * @param int $id - exercise id
|
|
|
- */
|
|
|
- private function updateId($id)
|
|
|
- {
|
|
|
- $this->id = $id;
|
|
|
- }
|
|
|
+ $exerciseList = [];
|
|
|
+ $list_ordered = null;
|
|
|
+ while ($row = Database::fetch_array($result, 'ASSOC')) {
|
|
|
+ $exerciseList[$row['iid']] = $row;
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * Sends a notification when a user ends an examn.
|
|
|
- *
|
|
|
- * @param array $question_list_answers
|
|
|
- * @param string $origin
|
|
|
- * @param array $user_info
|
|
|
- * @param string $url_email
|
|
|
- * @param array $teachers
|
|
|
- */
|
|
|
- private function sendNotificationForOpenQuestions(
|
|
|
- $question_list_answers,
|
|
|
- $origin,
|
|
|
- $user_info,
|
|
|
- $url_email,
|
|
|
- $teachers
|
|
|
- ) {
|
|
|
- // Email configuration settings
|
|
|
- $courseCode = api_get_course_id();
|
|
|
- $courseInfo = api_get_course_info($courseCode);
|
|
|
- $sessionId = api_get_session_id();
|
|
|
- $sessionData = '';
|
|
|
- if (!empty($sessionId)) {
|
|
|
- $sessionInfo = api_get_session_info($sessionId);
|
|
|
- if (!empty($sessionInfo)) {
|
|
|
- $sessionData = '<tr>'
|
|
|
- .'<td><em>'.get_lang('SessionName').'</em></td>'
|
|
|
- .'<td> <b>'.$sessionInfo['name'].'</b></td>'
|
|
|
- .'</tr>';
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- $msg = get_lang('OpenQuestionsAttempted').'<br /><br />'
|
|
|
- .get_lang('AttemptDetails').' : <br /><br />'
|
|
|
- .'<table>'
|
|
|
- .'<tr>'
|
|
|
- .'<td><em>'.get_lang('CourseName').'</em></td>'
|
|
|
- .'<td> <b>#course#</b></td>'
|
|
|
- .'</tr>'
|
|
|
- .$sessionData
|
|
|
- .'<tr>'
|
|
|
- .'<td>'.get_lang('TestAttempted').'</td>'
|
|
|
- .'<td> #exercise#</td>'
|
|
|
- .'</tr>'
|
|
|
- .'<tr>'
|
|
|
- .'<td>'.get_lang('StudentName').'</td>'
|
|
|
- .'<td> #firstName# #lastName#</td>'
|
|
|
- .'</tr>'
|
|
|
- .'<tr>'
|
|
|
- .'<td>'.get_lang('StudentEmail').'</td>'
|
|
|
- .'<td> #mail#</td>'
|
|
|
- .'</tr>'
|
|
|
- .'</table>';
|
|
|
-
|
|
|
- $open_question_list = null;
|
|
|
- foreach ($question_list_answers as $item) {
|
|
|
- $question = $item['question'];
|
|
|
- $answer = $item['answer'];
|
|
|
- $answer_type = $item['answer_type'];
|
|
|
-
|
|
|
- if (!empty($question) && !empty($answer) && $answer_type == FREE_ANSWER) {
|
|
|
- $open_question_list .=
|
|
|
- '<tr>'
|
|
|
- .'<td width="220" valign="top" bgcolor="#E5EDF8"> '.get_lang('Question').'</td>'
|
|
|
- .'<td width="473" valign="top" bgcolor="#F3F3F3">'.$question.'</td>'
|
|
|
- .'</tr>'
|
|
|
- .'<tr>'
|
|
|
- .'<td width="220" valign="top" bgcolor="#E5EDF8"> '.get_lang('Answer').'</td>'
|
|
|
- .'<td valign="top" bgcolor="#F3F3F3">'.$answer.'</td>'
|
|
|
- .'</tr>';
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!empty($open_question_list)) {
|
|
|
- $msg .= '<p><br />'.get_lang('OpenQuestionsAttemptedAre').' :</p>'.
|
|
|
- '<table width="730" height="136" border="0" cellpadding="3" cellspacing="3">';
|
|
|
- $msg .= $open_question_list;
|
|
|
- $msg .= '</table><br />';
|
|
|
-
|
|
|
- $msg = str_replace('#exercise#', $this->exercise, $msg);
|
|
|
- $msg = str_replace('#firstName#', $user_info['firstname'], $msg);
|
|
|
- $msg = str_replace('#lastName#', $user_info['lastname'], $msg);
|
|
|
- $msg = str_replace('#mail#', $user_info['email'], $msg);
|
|
|
- $msg = str_replace(
|
|
|
- '#course#',
|
|
|
- Display::url($courseInfo['title'], $courseInfo['course_public_url'].'?id_session='.$sessionId),
|
|
|
- $msg
|
|
|
- );
|
|
|
-
|
|
|
- if ($origin != 'learnpath') {
|
|
|
- $msg .= '<br /><a href="#url#">'.get_lang('ClickToCommentAndGiveFeedback').'</a>';
|
|
|
- }
|
|
|
- $msg = str_replace('#url#', $url_email, $msg);
|
|
|
- $subject = get_lang('OpenQuestionsAttempted');
|
|
|
-
|
|
|
- if (!empty($teachers)) {
|
|
|
- foreach ($teachers as $user_id => $teacher_data) {
|
|
|
- MessageManager::send_message_simple(
|
|
|
- $user_id,
|
|
|
- $subject,
|
|
|
- $msg
|
|
|
- );
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Send notification for oral questions.
|
|
|
- *
|
|
|
- * @param array $question_list_answers
|
|
|
- * @param string $origin
|
|
|
- * @param int $exe_id
|
|
|
- * @param array $user_info
|
|
|
- * @param string $url_email
|
|
|
- * @param array $teachers
|
|
|
- */
|
|
|
- private function sendNotificationForOralQuestions(
|
|
|
- $question_list_answers,
|
|
|
- $origin,
|
|
|
- $exe_id,
|
|
|
- $user_info,
|
|
|
- $url_email,
|
|
|
- $teachers
|
|
|
- ) {
|
|
|
- // Email configuration settings
|
|
|
- $courseCode = api_get_course_id();
|
|
|
- $courseInfo = api_get_course_info($courseCode);
|
|
|
- $oral_question_list = null;
|
|
|
- foreach ($question_list_answers as $item) {
|
|
|
- $question = $item['question'];
|
|
|
- $file = $item['generated_oral_file'];
|
|
|
- $answer = $item['answer'];
|
|
|
- if ($answer == 0) {
|
|
|
- $answer = '';
|
|
|
- }
|
|
|
- $answer_type = $item['answer_type'];
|
|
|
- if (!empty($question) && (!empty($answer) || !empty($file)) && $answer_type == ORAL_EXPRESSION) {
|
|
|
- if (!empty($file)) {
|
|
|
- $file = Display::url($file, $file);
|
|
|
+ if (!empty($exerciseList) &&
|
|
|
+ api_get_setting('exercise_invisible_in_session') === 'true'
|
|
|
+ ) {
|
|
|
+ if (!empty($sessionId)) {
|
|
|
+ $changeDefaultVisibility = true;
|
|
|
+ if (api_get_setting('configure_exercise_visibility_in_course') === 'true') {
|
|
|
+ $changeDefaultVisibility = false;
|
|
|
+ if (api_get_course_setting('exercise_invisible_in_session') == 1) {
|
|
|
+ $changeDefaultVisibility = true;
|
|
|
+ }
|
|
|
}
|
|
|
- $oral_question_list .= '<br />
|
|
|
- <table width="730" height="136" border="0" cellpadding="3" cellspacing="3">
|
|
|
- <tr>
|
|
|
- <td width="220" valign="top" bgcolor="#E5EDF8"> '.get_lang('Question').'</td>
|
|
|
- <td width="473" valign="top" bgcolor="#F3F3F3">'.$question.'</td>
|
|
|
- </tr>
|
|
|
- <tr>
|
|
|
- <td width="220" valign="top" bgcolor="#E5EDF8"> '.get_lang('Answer').'</td>
|
|
|
- <td valign="top" bgcolor="#F3F3F3">'.$answer.$file.'</td>
|
|
|
- </tr></table>';
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!empty($oral_question_list)) {
|
|
|
- $msg = get_lang('OralQuestionsAttempted').'<br /><br />
|
|
|
- '.get_lang('AttemptDetails').' : <br /><br />
|
|
|
- <table>
|
|
|
- <tr>
|
|
|
- <td><em>'.get_lang('CourseName').'</em></td>
|
|
|
- <td> <b>#course#</b></td>
|
|
|
- </tr>
|
|
|
- <tr>
|
|
|
- <td>'.get_lang('TestAttempted').'</td>
|
|
|
- <td> #exercise#</td>
|
|
|
- </tr>
|
|
|
- <tr>
|
|
|
- <td>'.get_lang('StudentName').'</td>
|
|
|
- <td> #firstName# #lastName#</td>
|
|
|
- </tr>
|
|
|
- <tr>
|
|
|
- <td>'.get_lang('StudentEmail').'</td>
|
|
|
- <td> #mail#</td>
|
|
|
- </tr>
|
|
|
- </table>';
|
|
|
- $msg .= '<br />'.sprintf(get_lang('OralQuestionsAttemptedAreX'), $oral_question_list).'<br />';
|
|
|
- $msg1 = str_replace("#exercise#", $this->exercise, $msg);
|
|
|
- $msg = str_replace("#firstName#", $user_info['firstname'], $msg1);
|
|
|
- $msg1 = str_replace("#lastName#", $user_info['lastname'], $msg);
|
|
|
- $msg = str_replace("#mail#", $user_info['email'], $msg1);
|
|
|
- $msg = str_replace("#course#", $courseInfo['name'], $msg1);
|
|
|
|
|
|
- if (!in_array($origin, ['learnpath', 'embeddable'])) {
|
|
|
- $msg .= '<br /><a href="#url#">'.get_lang('ClickToCommentAndGiveFeedback').'</a>';
|
|
|
- }
|
|
|
- $msg1 = str_replace("#url#", $url_email, $msg);
|
|
|
- $mail_content = $msg1;
|
|
|
- $subject = get_lang('OralQuestionsAttempted');
|
|
|
+ if ($changeDefaultVisibility) {
|
|
|
+ // Check exercise
|
|
|
+ foreach ($exerciseList as $exercise) {
|
|
|
+ if ($exercise['session_id'] == 0) {
|
|
|
+ $visibilityInfo = api_get_item_property_info(
|
|
|
+ $courseId,
|
|
|
+ TOOL_QUIZ,
|
|
|
+ $exercise['iid'],
|
|
|
+ $sessionId
|
|
|
+ );
|
|
|
|
|
|
- if (!empty($teachers)) {
|
|
|
- foreach ($teachers as $user_id => $teacher_data) {
|
|
|
- MessageManager::send_message_simple(
|
|
|
- $user_id,
|
|
|
- $subject,
|
|
|
- $mail_content
|
|
|
- );
|
|
|
+ if (empty($visibilityInfo)) {
|
|
|
+ // Create a record for this
|
|
|
+ api_item_property_update(
|
|
|
+ $courseInfo,
|
|
|
+ TOOL_QUIZ,
|
|
|
+ $exercise['iid'],
|
|
|
+ 'invisible',
|
|
|
+ api_get_user_id(),
|
|
|
+ 0,
|
|
|
+ null,
|
|
|
+ '',
|
|
|
+ '',
|
|
|
+ $sessionId
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- /**
|
|
|
- * Returns an array with the media list.
|
|
|
- *
|
|
|
- * @param array question list
|
|
|
- *
|
|
|
- * @example there's 1 question with iid 5 that belongs to the media question with iid = 100
|
|
|
- * <code>
|
|
|
- * array (size=2)
|
|
|
- * 999 =>
|
|
|
- * array (size=3)
|
|
|
- * 0 => int 7
|
|
|
- * 1 => int 6
|
|
|
- * 2 => int 3254
|
|
|
- * 100 =>
|
|
|
- * array (size=1)
|
|
|
- * 0 => int 5
|
|
|
- * </code>
|
|
|
- */
|
|
|
- private function setMediaList($questionList)
|
|
|
- {
|
|
|
- $mediaList = [];
|
|
|
- /*
|
|
|
- * Media feature is not activated in 1.11.x
|
|
|
- if (!empty($questionList)) {
|
|
|
- foreach ($questionList as $questionId) {
|
|
|
- $objQuestionTmp = Question::read($questionId, $this->course_id);
|
|
|
- // If a media question exists
|
|
|
- if (isset($objQuestionTmp->parent_id) && $objQuestionTmp->parent_id != 0) {
|
|
|
- $mediaList[$objQuestionTmp->parent_id][] = $objQuestionTmp->id;
|
|
|
- } else {
|
|
|
- // Always the last item
|
|
|
- $mediaList[999][] = $objQuestionTmp->id;
|
|
|
+ if (isset($list_ordered) && !empty($list_ordered)) {
|
|
|
+ $new_question_list = [];
|
|
|
+ foreach ($list_ordered as $exercise_id) {
|
|
|
+ if (isset($exerciseList[$exercise_id])) {
|
|
|
+ $new_question_list[] = $exerciseList[$exercise_id];
|
|
|
}
|
|
|
}
|
|
|
- }*/
|
|
|
-
|
|
|
- $this->mediaList = $mediaList;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @param FormValidator $form
|
|
|
- *
|
|
|
- * @return HTML_QuickForm_group
|
|
|
- */
|
|
|
- private function setResultDisabledGroup(FormValidator $form)
|
|
|
- {
|
|
|
- $resultDisabledGroup = [];
|
|
|
-
|
|
|
- $resultDisabledGroup[] = $form->createElement(
|
|
|
- 'radio',
|
|
|
- 'results_disabled',
|
|
|
- null,
|
|
|
- get_lang('ShowScoreAndRightAnswer'),
|
|
|
- '0',
|
|
|
- ['id' => 'result_disabled_0']
|
|
|
- );
|
|
|
-
|
|
|
- $resultDisabledGroup[] = $form->createElement(
|
|
|
- 'radio',
|
|
|
- 'results_disabled',
|
|
|
- null,
|
|
|
- get_lang('DoNotShowScoreNorRightAnswer'),
|
|
|
- '1',
|
|
|
- ['id' => 'result_disabled_1', 'onclick' => 'check_results_disabled()']
|
|
|
- );
|
|
|
-
|
|
|
- $resultDisabledGroup[] = $form->createElement(
|
|
|
- 'radio',
|
|
|
- 'results_disabled',
|
|
|
- null,
|
|
|
- get_lang('OnlyShowScore'),
|
|
|
- '2',
|
|
|
- ['id' => 'result_disabled_2', 'onclick' => 'check_results_disabled()']
|
|
|
- );
|
|
|
+ $exerciseList = $new_question_list;
|
|
|
+ }
|
|
|
|
|
|
- if ($this->selectFeedbackType() == EXERCISE_FEEDBACK_TYPE_DIRECT) {
|
|
|
- $group = $form->addGroup(
|
|
|
- $resultDisabledGroup,
|
|
|
- null,
|
|
|
- get_lang('ShowResultsToStudents')
|
|
|
- );
|
|
|
+ if (!empty($exerciseList)) {
|
|
|
+ if ($origin !== 'learnpath') {
|
|
|
+ //avoid sending empty parameters
|
|
|
+ $mylpid = empty($learnpath_id) ? '' : '&learnpath_id='.$learnpath_id;
|
|
|
+ $mylpitemid = empty($learnpath_item_id) ? '' : '&learnpath_item_id='.$learnpath_item_id;
|
|
|
+ foreach ($exerciseList as $row) {
|
|
|
+ $my_exercise_id = $row['id'];
|
|
|
+ $exercise = new Exercise();
|
|
|
+ $exercise->read($my_exercise_id, false);
|
|
|
|
|
|
- return $group;
|
|
|
- }
|
|
|
+ if (empty($exercise->id)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- $resultDisabledGroup[] = $form->createElement(
|
|
|
- 'radio',
|
|
|
- 'results_disabled',
|
|
|
- null,
|
|
|
- get_lang('ShowScoreEveryAttemptShowAnswersLastAttempt'),
|
|
|
- '4',
|
|
|
- ['id' => 'result_disabled_4']
|
|
|
- );
|
|
|
+ $locked = $exercise->is_gradebook_locked;
|
|
|
+ // Validation when belongs to a session
|
|
|
+ $session_img = api_get_session_image($row['session_id'], $userInfo['status']);
|
|
|
|
|
|
- $resultDisabledGroup[] = $form->createElement(
|
|
|
- 'radio',
|
|
|
- 'results_disabled',
|
|
|
- null,
|
|
|
- get_lang('DontShowScoreOnlyWhenUserFinishesAllAttemptsButShowFeedbackEachAttempt'),
|
|
|
- '5',
|
|
|
- ['id' => 'result_disabled_5', 'onclick' => 'check_results_disabled()']
|
|
|
- );
|
|
|
+ $time_limits = false;
|
|
|
+ if (!empty($row['start_time']) || !empty($row['end_time'])) {
|
|
|
+ $time_limits = true;
|
|
|
+ }
|
|
|
|
|
|
- $resultDisabledGroup[] = $form->createElement(
|
|
|
- 'radio',
|
|
|
- 'results_disabled',
|
|
|
- null,
|
|
|
- get_lang('ExerciseRankingMode'),
|
|
|
- RESULT_DISABLE_RANKING,
|
|
|
- ['id' => 'result_disabled_6']
|
|
|
- );
|
|
|
+ $is_actived_time = false;
|
|
|
+ if ($time_limits) {
|
|
|
+ // check if start time
|
|
|
+ $start_time = false;
|
|
|
+ if (!empty($row['start_time'])) {
|
|
|
+ $start_time = api_strtotime($row['start_time'], 'UTC');
|
|
|
+ }
|
|
|
+ $end_time = false;
|
|
|
+ if (!empty($row['end_time'])) {
|
|
|
+ $end_time = api_strtotime($row['end_time'], 'UTC');
|
|
|
+ }
|
|
|
+ $now = time();
|
|
|
|
|
|
- $resultDisabledGroup[] = $form->createElement(
|
|
|
- 'radio',
|
|
|
- 'results_disabled',
|
|
|
- null,
|
|
|
- get_lang('ExerciseShowOnlyGlobalScoreAndCorrectAnswers'),
|
|
|
- RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER,
|
|
|
- ['id' => 'result_disabled_7']
|
|
|
- );
|
|
|
+ //If both "clocks" are enable
|
|
|
+ if ($start_time && $end_time) {
|
|
|
+ if ($now > $start_time && $end_time > $now) {
|
|
|
+ $is_actived_time = true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //we check the start and end
|
|
|
+ if ($start_time) {
|
|
|
+ if ($now > $start_time) {
|
|
|
+ $is_actived_time = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($end_time) {
|
|
|
+ if ($end_time > $now) {
|
|
|
+ $is_actived_time = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- $resultDisabledGroup[] = $form->createElement(
|
|
|
- 'radio',
|
|
|
- 'results_disabled',
|
|
|
- null,
|
|
|
- get_lang('ExerciseAutoEvaluationAndRankingMode'),
|
|
|
- RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING,
|
|
|
- ['id' => 'result_disabled_8']
|
|
|
- );
|
|
|
+ // Blocking empty start times see BT#2800
|
|
|
+ global $_custom;
|
|
|
+ if (isset($_custom['exercises_hidden_when_no_start_date']) &&
|
|
|
+ $_custom['exercises_hidden_when_no_start_date']
|
|
|
+ ) {
|
|
|
+ if (empty($row['start_time'])) {
|
|
|
+ $time_limits = true;
|
|
|
+ $is_actived_time = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- $group = $form->addGroup(
|
|
|
- $resultDisabledGroup,
|
|
|
- null,
|
|
|
- get_lang('ShowResultsToStudents')
|
|
|
- );
|
|
|
+ $cut_title = $exercise->getCutTitle();
|
|
|
+ $alt_title = '';
|
|
|
+ if ($cut_title != $row['title']) {
|
|
|
+ $alt_title = ' title = "'.$exercise->getUnformattedTitle().'" ';
|
|
|
+ }
|
|
|
|
|
|
- return $group;
|
|
|
- }
|
|
|
+ // Teacher only
|
|
|
+ if ($is_allowedToEdit) {
|
|
|
+ $lp_blocked = null;
|
|
|
+ if ($exercise->exercise_was_added_in_lp == true) {
|
|
|
+ $lp_blocked = Display::div(
|
|
|
+ get_lang('AddedToLPCannotBeAccessed'),
|
|
|
+ ['class' => 'lp_content_type_label']
|
|
|
+ );
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * @param int $categoryId
|
|
|
- * @param int $page
|
|
|
- * @param int $from
|
|
|
- * @param int $limit
|
|
|
- *
|
|
|
- * @return string
|
|
|
- * @throws \Doctrine\ORM\Query\QueryException
|
|
|
- */
|
|
|
- public static function exerciseGrid($categoryId, $page, $from, $limit)
|
|
|
- {
|
|
|
- $TBL_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
|
|
|
- $TBL_ITEM_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
|
|
|
- $TBL_EXERCISE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
|
|
|
- $TBL_EXERCISES = Database::get_course_table(TABLE_QUIZ_TEST);
|
|
|
- $TBL_TRACK_EXERCISES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
|
|
|
+ $visibility = api_get_item_visibility(
|
|
|
+ $courseInfo,
|
|
|
+ TOOL_QUIZ,
|
|
|
+ $my_exercise_id,
|
|
|
+ 0
|
|
|
+ );
|
|
|
|
|
|
- $categoryId = (int) $categoryId;
|
|
|
- $page = (int) $page;
|
|
|
- $from = (int) $from;
|
|
|
- $limit = (int) $limit;
|
|
|
+ if (!empty($sessionId)) {
|
|
|
+ $setting = api_get_configuration_value('show_hidden_exercise_added_to_lp');
|
|
|
+ if ($setting) {
|
|
|
+ if ($exercise->exercise_was_added_in_lp == false) {
|
|
|
+ if ($visibility == 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if ($visibility == 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- $autoLaunchAvailable = false;
|
|
|
- if (api_get_course_setting('enable_exercise_auto_launch') == 1 &&
|
|
|
- api_get_configuration_value('allow_exercise_auto_launch')
|
|
|
- ) {
|
|
|
- $autoLaunchAvailable = true;
|
|
|
- }
|
|
|
+ $visibility = api_get_item_visibility(
|
|
|
+ $courseInfo,
|
|
|
+ TOOL_QUIZ,
|
|
|
+ $my_exercise_id,
|
|
|
+ $sessionId
|
|
|
+ );
|
|
|
+ }
|
|
|
|
|
|
- $is_allowedToEdit = api_is_allowed_to_edit(null, true);
|
|
|
- $courseInfo = api_get_course_info();
|
|
|
- $sessionId = api_get_session_id();
|
|
|
- $courseId = $courseInfo['real_id'];
|
|
|
- $tableRows = [];
|
|
|
- $uploadPath = DIR_HOTPOTATOES; //defined in main_api
|
|
|
- $exercisePath = api_get_self();
|
|
|
- $origin = api_get_origin();
|
|
|
- $userInfo = api_get_user_info();
|
|
|
- $charset = 'utf-8';
|
|
|
- $token = Security::get_token();
|
|
|
- $userId = api_get_user_id();
|
|
|
- $isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh(
|
|
|
- $userId,
|
|
|
- $courseInfo
|
|
|
- );
|
|
|
- $documentPath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
|
|
|
+ if ($row['active'] == 0 || $visibility == 0) {
|
|
|
+ $title = Display::tag('font', $cut_title, ['style' => 'color:grey']);
|
|
|
+ } else {
|
|
|
+ $title = $cut_title;
|
|
|
+ }
|
|
|
|
|
|
- $limitTeacherAccess = api_get_configuration_value('limit_exercise_teacher_access');
|
|
|
+ $count_exercise_not_validated = (int) Event::count_exercise_result_not_validated(
|
|
|
+ $my_exercise_id,
|
|
|
+ $courseId,
|
|
|
+ $sessionId
|
|
|
+ );
|
|
|
|
|
|
- $learnpath_id = isset($_REQUEST['learnpath_id']) ? (int) $_REQUEST['learnpath_id'] : null;
|
|
|
- $learnpath_item_id = isset($_REQUEST['learnpath_item_id']) ? (int) $_REQUEST['learnpath_item_id'] : null;
|
|
|
+ $move = Display::return_icon(
|
|
|
+ 'all_directions.png',
|
|
|
+ get_lang('Move'),
|
|
|
+ ['class' => 'moved', 'style' => 'margin-bottom:-0.5em;']
|
|
|
+ );
|
|
|
+ $move = null;
|
|
|
+ $class_tip = '';
|
|
|
|
|
|
- // Condition for the session
|
|
|
- $condition_session = api_get_session_condition($sessionId, true, true);
|
|
|
- $content = '';
|
|
|
+ if (!empty($count_exercise_not_validated)) {
|
|
|
+ $results_text = $count_exercise_not_validated == 1 ? get_lang('ResultNotRevised') : get_lang('ResultsNotRevised');
|
|
|
+ $title .= '<span class="exercise_tooltip" style="display: none;">'.$count_exercise_not_validated.' '.$results_text.' </span>';
|
|
|
+ $class_tip = 'link_tooltip';
|
|
|
+ }
|
|
|
|
|
|
- $categoryCondition = '';
|
|
|
- if (!empty($categoryId)) {
|
|
|
- $categoryCondition = " AND exercise_category_id = $categoryId ";
|
|
|
- }
|
|
|
+ $url = $move.'<a '.$alt_title.' class="'.$class_tip.'" id="tooltip_'.$row['id'].'" href="overview.php?'.api_get_cidreq().$mylpid.$mylpitemid.'&exerciseId='.$row['id'].'">
|
|
|
+ '.Display::return_icon('quiz.png', $row['title']).'
|
|
|
+ '.$title.' </a>'.PHP_EOL;
|
|
|
|
|
|
- // Only for administrators
|
|
|
- if ($is_allowedToEdit) {
|
|
|
- $total_sql = "SELECT count(iid) as count
|
|
|
- FROM $TBL_EXERCISES
|
|
|
- WHERE
|
|
|
- c_id = $courseId AND
|
|
|
- active<>'-1'
|
|
|
- $condition_session
|
|
|
- $categoryCondition
|
|
|
- ";
|
|
|
- $sql = "SELECT * FROM $TBL_EXERCISES
|
|
|
- WHERE c_id = $courseId AND active<>'-1' $condition_session $categoryCondition
|
|
|
- ORDER BY title
|
|
|
- LIMIT ".$from.",".$limit;
|
|
|
- } else {
|
|
|
- // Only for students
|
|
|
- $total_sql = "SELECT count(iid) as count
|
|
|
- FROM $TBL_EXERCISES
|
|
|
- WHERE c_id = $courseId AND active = '1' $condition_session $categoryCondition";
|
|
|
- $sql = "SELECT * FROM $TBL_EXERCISES
|
|
|
- WHERE c_id = $courseId AND
|
|
|
- active='1' $condition_session
|
|
|
- $categoryCondition
|
|
|
- ORDER BY title LIMIT ".$from.",".$limit;
|
|
|
- }
|
|
|
- $result = Database::query($sql);
|
|
|
- $result_total = Database::query($total_sql);
|
|
|
+ if (ExerciseLib::isQuizEmbeddable($row)) {
|
|
|
+ $embeddableIcon = Display::return_icon('om_integration.png', get_lang('ThisQuizCanBeEmbeddable'));
|
|
|
+ $url .= Display::div($embeddableIcon, ['class' => 'pull-right']);
|
|
|
+ }
|
|
|
|
|
|
- $total_exercises = 0;
|
|
|
- if (Database :: num_rows($result_total)) {
|
|
|
- $result_total = Database::fetch_array($result_total);
|
|
|
- $total_exercises = $result_total['count'];
|
|
|
- }
|
|
|
+ $item = Display::tag('td', $url.' '.$session_img.$lp_blocked);
|
|
|
|
|
|
- //get HotPotatoes files (active and inactive)
|
|
|
- if ($is_allowedToEdit) {
|
|
|
- $sql = "SELECT * FROM $TBL_DOCUMENT
|
|
|
- WHERE
|
|
|
- c_id = $courseId AND
|
|
|
- path LIKE '".Database::escape_string($uploadPath.'/%/%')."'";
|
|
|
- $res = Database::query($sql);
|
|
|
- $hp_count = Database :: num_rows($res);
|
|
|
- } else {
|
|
|
- $sql = "SELECT * FROM $TBL_DOCUMENT d
|
|
|
- INNER JOIN $TBL_ITEM_PROPERTY ip
|
|
|
- ON (d.id = ip.ref AND d.c_id = ip.c_id)
|
|
|
- WHERE
|
|
|
- ip.tool = '".TOOL_DOCUMENT."' AND
|
|
|
- d.path LIKE '".Database::escape_string($uploadPath.'/%/%')."' AND
|
|
|
- ip.visibility ='1' AND
|
|
|
- d.c_id = $courseId AND
|
|
|
- ip.c_id = $courseId";
|
|
|
- $res = Database::query($sql);
|
|
|
- $hp_count = Database::num_rows($res);
|
|
|
- }
|
|
|
+ // Count number exercise - teacher
|
|
|
+ $sql = "SELECT count(*) count FROM $TBL_EXERCISE_QUESTION
|
|
|
+ WHERE c_id = $courseId AND exercice_id = $my_exercise_id";
|
|
|
+ $sqlresult = Database::query($sql);
|
|
|
+ $rowi = (int) Database::result($sqlresult, 0, 0);
|
|
|
|
|
|
- $total = $total_exercises + $hp_count;
|
|
|
+ if ($sessionId == $row['session_id']) {
|
|
|
+ // Questions list
|
|
|
+ $actions = Display::url(
|
|
|
+ Display::return_icon('edit.png', get_lang('Edit'), '', ICON_SIZE_SMALL),
|
|
|
+ 'admin.php?'.api_get_cidreq().'&exerciseId='.$row['id']
|
|
|
+ );
|
|
|
|
|
|
- if ($total > $limit) {
|
|
|
- $content .= '<div style="float:right;height:20px;">';
|
|
|
- // Show pages navigation link for previous page
|
|
|
- if ($page) {
|
|
|
- $content .= "<a href=\"".api_get_self()."?".api_get_cidreq()."&page=".($page - 1)."\">".
|
|
|
- Display::return_icon('action_prev.png', get_lang('PreviousPage')).'</a>';
|
|
|
- } elseif ($total_exercises + $hp_count > $limit) {
|
|
|
- $content .= Display::return_icon('action_prev_na.png', get_lang('PreviousPage'));
|
|
|
- }
|
|
|
+ // Test settings
|
|
|
+ $settings = Display::url(
|
|
|
+ Display::return_icon('settings.png', get_lang('Configure'), '', ICON_SIZE_SMALL),
|
|
|
+ 'exercise_admin.php?'.api_get_cidreq().'&exerciseId='.$row['id']
|
|
|
+ );
|
|
|
|
|
|
- // Show pages navigation link for previous page
|
|
|
- if ($total_exercises > $from + $limit || $hp_count > $from + $limit) {
|
|
|
- $content .= ' '."<a href=\"".api_get_self()."?".api_get_cidreq()."&page=".($page + 1)."\">".
|
|
|
- Display::return_icon('action_next.png', get_lang('NextPage')).'</a>';
|
|
|
- } elseif ($page) {
|
|
|
- $content .= ' '.Display::return_icon('action_next_na.png', get_lang('NextPage'));
|
|
|
- }
|
|
|
- $content .= '</div>';
|
|
|
- }
|
|
|
+ if ($limitTeacherAccess && !api_is_platform_admin()) {
|
|
|
+ $settings = '';
|
|
|
+ }
|
|
|
+ $actions .= $settings;
|
|
|
|
|
|
- $exerciseList = [];
|
|
|
- $list_ordered = null;
|
|
|
- while ($row = Database::fetch_array($result, 'ASSOC')) {
|
|
|
- $exerciseList[$row['iid']] = $row;
|
|
|
- }
|
|
|
+ // Exercise results
|
|
|
+ $resultsLink = '<a href="exercise_report.php?'.api_get_cidreq().'&exerciseId='.$row['id'].'">'.
|
|
|
+ Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
+
|
|
|
+ if ($limitTeacherAccess) {
|
|
|
+ if (api_is_platform_admin()) {
|
|
|
+ $actions .= $resultsLink;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // Exercise results
|
|
|
+ $actions .= $resultsLink;
|
|
|
+ }
|
|
|
|
|
|
- if (!empty($exerciseList) &&
|
|
|
- api_get_setting('exercise_invisible_in_session') === 'true'
|
|
|
- ) {
|
|
|
- if (!empty($sessionId)) {
|
|
|
- $changeDefaultVisibility = true;
|
|
|
- if (api_get_setting('configure_exercise_visibility_in_course') === 'true') {
|
|
|
- $changeDefaultVisibility = false;
|
|
|
- if (api_get_course_setting('exercise_invisible_in_session') == 1) {
|
|
|
- $changeDefaultVisibility = true;
|
|
|
- }
|
|
|
- }
|
|
|
+ // Auto launch
|
|
|
+ if ($autoLaunchAvailable) {
|
|
|
+ $autoLaunch = $exercise->getAutoLaunch();
|
|
|
+ if (empty($autoLaunch)) {
|
|
|
+ $actions .= Display::url(
|
|
|
+ Display::return_icon(
|
|
|
+ 'launch_na.png',
|
|
|
+ get_lang('Enable'),
|
|
|
+ '',
|
|
|
+ ICON_SIZE_SMALL
|
|
|
+ ),
|
|
|
+ 'exercise.php?'.api_get_cidreq().'&choice=enable_launch&sec_token='.$token.'&page='.$page.'&exerciseId='.$row['id']
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ $actions .= Display::url(
|
|
|
+ Display::return_icon(
|
|
|
+ 'launch.png',
|
|
|
+ get_lang('Disable'),
|
|
|
+ '',
|
|
|
+ ICON_SIZE_SMALL
|
|
|
+ ),
|
|
|
+ 'exercise.php?'.api_get_cidreq().'&choice=disable_launch&sec_token='.$token.'&page='.$page.'&exerciseId='.$row['id']
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if ($changeDefaultVisibility) {
|
|
|
- // Check exercise
|
|
|
- foreach ($exerciseList as $exercise) {
|
|
|
- if ($exercise['session_id'] == 0) {
|
|
|
- $visibilityInfo = api_get_item_property_info(
|
|
|
- $courseId,
|
|
|
- TOOL_QUIZ,
|
|
|
- $exercise['iid'],
|
|
|
- $sessionId
|
|
|
+ // Export
|
|
|
+ $actions .= Display::url(
|
|
|
+ Display::return_icon('cd.png', get_lang('CopyExercise')),
|
|
|
+ '',
|
|
|
+ [
|
|
|
+ 'onclick' => "javascript:if(!confirm('".addslashes(api_htmlentities(get_lang('AreYouSureToCopy'), ENT_QUOTES, $charset))." ".addslashes($row['title'])."?"."')) return false;",
|
|
|
+ 'href' => 'exercise.php?'.api_get_cidreq().'&choice=copy_exercise&sec_token='.$token.'&exerciseId='.$row['id'],
|
|
|
+ ]
|
|
|
);
|
|
|
|
|
|
- if (empty($visibilityInfo)) {
|
|
|
- // Create a record for this
|
|
|
- api_item_property_update(
|
|
|
- $courseInfo,
|
|
|
- TOOL_QUIZ,
|
|
|
- $exercise['iid'],
|
|
|
- 'invisible',
|
|
|
- api_get_user_id(),
|
|
|
- 0,
|
|
|
- null,
|
|
|
+ // Clean exercise
|
|
|
+ if ($locked == false) {
|
|
|
+ $clean = Display::url(
|
|
|
+ Display::return_icon(
|
|
|
+ 'clean.png',
|
|
|
+ get_lang('CleanStudentResults'),
|
|
|
+ '',
|
|
|
+ ICON_SIZE_SMALL
|
|
|
+ ),
|
|
|
'',
|
|
|
+ [
|
|
|
+ 'onclick' => "javascript:if(!confirm('".addslashes(api_htmlentities(get_lang('AreYouSureToDeleteResults'), ENT_QUOTES, $charset))." ".addslashes($row['title'])."?"."')) return false;",
|
|
|
+ 'href' => 'exercise.php?'.api_get_cidreq().'&choice=clean_results&sec_token='.$token.'&exerciseId='.$row['id'],
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ $clean = Display::return_icon(
|
|
|
+ 'clean_na.png',
|
|
|
+ get_lang('ResourceLockedByGradebook'),
|
|
|
'',
|
|
|
- $sessionId
|
|
|
+ ICON_SIZE_SMALL
|
|
|
);
|
|
|
}
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (isset($list_ordered) && !empty($list_ordered)) {
|
|
|
- $new_question_list = [];
|
|
|
- foreach ($list_ordered as $exercise_id) {
|
|
|
- if (isset($exerciseList[$exercise_id])) {
|
|
|
- $new_question_list[] = $exerciseList[$exercise_id];
|
|
|
- }
|
|
|
- }
|
|
|
- $exerciseList = $new_question_list;
|
|
|
- }
|
|
|
-
|
|
|
- if (!empty($exerciseList)) {
|
|
|
- if ($origin !== 'learnpath') {
|
|
|
- //avoid sending empty parameters
|
|
|
- $mylpid = empty($learnpath_id) ? '' : '&learnpath_id='.$learnpath_id;
|
|
|
- $mylpitemid = empty($learnpath_item_id) ? '' : '&learnpath_item_id='.$learnpath_item_id;
|
|
|
- foreach ($exerciseList as $row) {
|
|
|
- $my_exercise_id = $row['id'];
|
|
|
- $exercise = new Exercise();
|
|
|
- $exercise->read($my_exercise_id, false);
|
|
|
|
|
|
- if (empty($exercise->id)) {
|
|
|
- continue;
|
|
|
- }
|
|
|
+ if ($limitTeacherAccess && !api_is_platform_admin()) {
|
|
|
+ $clean = '';
|
|
|
+ }
|
|
|
+ $actions .= $clean;
|
|
|
+ // Visible / invisible
|
|
|
+ // Check if this exercise was added in a LP
|
|
|
+ if ($exercise->exercise_was_added_in_lp == true) {
|
|
|
+ $visibility = Display::return_icon(
|
|
|
+ 'invisible.png',
|
|
|
+ get_lang('AddedToLPCannotBeAccessed'),
|
|
|
+ '',
|
|
|
+ ICON_SIZE_SMALL
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ if ($row['active'] == 0 || $visibility == 0) {
|
|
|
+ $visibility = Display::url(
|
|
|
+ Display::return_icon(
|
|
|
+ 'invisible.png',
|
|
|
+ get_lang('Activate'),
|
|
|
+ '',
|
|
|
+ ICON_SIZE_SMALL
|
|
|
+ ),
|
|
|
+ 'exercise.php?'.api_get_cidreq().'&choice=enable&sec_token='.$token.'&page='.$page.'&exerciseId='.$row['id']
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // else if not active
|
|
|
+ $visibility = Display::url(
|
|
|
+ Display::return_icon(
|
|
|
+ 'visible.png',
|
|
|
+ get_lang('Deactivate'),
|
|
|
+ '',
|
|
|
+ ICON_SIZE_SMALL
|
|
|
+ ),
|
|
|
+ 'exercise.php?'.api_get_cidreq().'&choice=disable&sec_token='.$token.'&page='.$page.'&exerciseId='.$row['id']
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- $locked = $exercise->is_gradebook_locked;
|
|
|
- // Validation when belongs to a session
|
|
|
- $session_img = api_get_session_image($row['session_id'], $userInfo['status']);
|
|
|
+ if ($limitTeacherAccess && !api_is_platform_admin()) {
|
|
|
+ $visibility = '';
|
|
|
+ }
|
|
|
|
|
|
- $time_limits = false;
|
|
|
- if (!empty($row['start_time']) || !empty($row['end_time'])) {
|
|
|
- $time_limits = true;
|
|
|
- }
|
|
|
+ $actions .= $visibility;
|
|
|
|
|
|
- $is_actived_time = false;
|
|
|
- if ($time_limits) {
|
|
|
- // check if start time
|
|
|
- $start_time = false;
|
|
|
- if (!empty($row['start_time'])) {
|
|
|
- $start_time = api_strtotime($row['start_time'], 'UTC');
|
|
|
- }
|
|
|
- $end_time = false;
|
|
|
- if (!empty($row['end_time'])) {
|
|
|
- $end_time = api_strtotime($row['end_time'], 'UTC');
|
|
|
- }
|
|
|
- $now = time();
|
|
|
+ // Export qti ...
|
|
|
+ $export = Display::url(
|
|
|
+ Display::return_icon(
|
|
|
+ 'export_qti2.png',
|
|
|
+ 'IMS/QTI',
|
|
|
+ '',
|
|
|
+ ICON_SIZE_SMALL
|
|
|
+ ),
|
|
|
+ 'exercise.php?choice=exportqti2&exerciseId='.$row['id'].'&'.api_get_cidreq()
|
|
|
+ );
|
|
|
|
|
|
- //If both "clocks" are enable
|
|
|
- if ($start_time && $end_time) {
|
|
|
- if ($now > $start_time && $end_time > $now) {
|
|
|
- $is_actived_time = true;
|
|
|
+ if ($limitTeacherAccess && !api_is_platform_admin()) {
|
|
|
+ $export = '';
|
|
|
}
|
|
|
+
|
|
|
+ $actions .= $export;
|
|
|
} else {
|
|
|
- //we check the start and end
|
|
|
- if ($start_time) {
|
|
|
- if ($now > $start_time) {
|
|
|
- $is_actived_time = true;
|
|
|
+ // not session
|
|
|
+ $actions = Display::return_icon(
|
|
|
+ 'edit_na.png',
|
|
|
+ get_lang('ExerciseEditionNotAvailableInSession')
|
|
|
+ );
|
|
|
+
|
|
|
+ // Check if this exercise was added in a LP
|
|
|
+ if ($exercise->exercise_was_added_in_lp == true) {
|
|
|
+ $visibility = Display::return_icon(
|
|
|
+ 'invisible.png',
|
|
|
+ get_lang('AddedToLPCannotBeAccessed'),
|
|
|
+ '',
|
|
|
+ ICON_SIZE_SMALL
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ if ($row['active'] == 0 || $visibility == 0) {
|
|
|
+ $visibility = Display::url(
|
|
|
+ Display::return_icon(
|
|
|
+ 'invisible.png',
|
|
|
+ get_lang('Activate'),
|
|
|
+ '',
|
|
|
+ ICON_SIZE_SMALL
|
|
|
+ ),
|
|
|
+ 'exercise.php?'.api_get_cidreq().'&choice=enable&sec_token='.$token.'&page='.$page.'&exerciseId='.$row['id']
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // else if not active
|
|
|
+ $visibility = Display::url(
|
|
|
+ Display::return_icon(
|
|
|
+ 'visible.png',
|
|
|
+ get_lang('Deactivate'),
|
|
|
+ '',
|
|
|
+ ICON_SIZE_SMALL
|
|
|
+ ),
|
|
|
+ 'exercise.php?'.api_get_cidreq().'&choice=disable&sec_token='.$token.'&page='.$page.'&exerciseId='.$row['id']
|
|
|
+ );
|
|
|
}
|
|
|
}
|
|
|
- if ($end_time) {
|
|
|
- if ($end_time > $now) {
|
|
|
- $is_actived_time = true;
|
|
|
- }
|
|
|
+
|
|
|
+ if ($limitTeacherAccess && !api_is_platform_admin()) {
|
|
|
+ $visibility = '';
|
|
|
+ }
|
|
|
+
|
|
|
+ $actions .= $visibility;
|
|
|
+
|
|
|
+ $actions .= '<a href="exercise_report.php?'.api_get_cidreq().'&exerciseId='.$row['id'].'">'.
|
|
|
+ Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
+ $actions .= Display::url(
|
|
|
+ Display::return_icon('cd.gif', get_lang('CopyExercise')),
|
|
|
+ '',
|
|
|
+ [
|
|
|
+ 'onclick' => "javascript:if(!confirm('".addslashes(api_htmlentities(get_lang('AreYouSureToCopy'), ENT_QUOTES, $charset))." ".addslashes($row['title'])."?"."')) return false;",
|
|
|
+ 'href' => 'exercise.php?'.api_get_cidreq().'&choice=copy_exercise&sec_token='.$token.'&exerciseId='.$row['id'],
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // Delete
|
|
|
+ $delete = '';
|
|
|
+ if ($sessionId == $row['session_id']) {
|
|
|
+ if ($locked == false) {
|
|
|
+ $delete = Display::url(
|
|
|
+ Display::return_icon(
|
|
|
+ 'delete.png',
|
|
|
+ get_lang('Delete'),
|
|
|
+ '',
|
|
|
+ ICON_SIZE_SMALL
|
|
|
+ ),
|
|
|
+ '',
|
|
|
+ [
|
|
|
+ 'onclick' => "javascript:if(!confirm('".addslashes(api_htmlentities(get_lang('AreYouSureToDeleteJS'), ENT_QUOTES, $charset))." ".addslashes($exercise->getUnformattedTitle())."?"."')) return false;",
|
|
|
+ 'href' => 'exercise.php?'.api_get_cidreq().'&choice=delete&sec_token='.$token.'&exerciseId='.$row['id'],
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ $delete = Display::return_icon(
|
|
|
+ 'delete_na.png',
|
|
|
+ get_lang('ResourceLockedByGradebook'),
|
|
|
+ '',
|
|
|
+ ICON_SIZE_SMALL
|
|
|
+ );
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- // Blocking empty start times see BT#2800
|
|
|
- global $_custom;
|
|
|
- if (isset($_custom['exercises_hidden_when_no_start_date']) &&
|
|
|
- $_custom['exercises_hidden_when_no_start_date']
|
|
|
- ) {
|
|
|
- if (empty($row['start_time'])) {
|
|
|
- $time_limits = true;
|
|
|
- $is_actived_time = false;
|
|
|
+ if ($limitTeacherAccess && !api_is_platform_admin()) {
|
|
|
+ $delete = '';
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- $cut_title = $exercise->getCutTitle();
|
|
|
- $alt_title = '';
|
|
|
- if ($cut_title != $row['title']) {
|
|
|
- $alt_title = ' title = "'.$exercise->getUnformattedTitle().'" ';
|
|
|
- }
|
|
|
+ $actions .= $delete;
|
|
|
|
|
|
- // Teacher only
|
|
|
- if ($is_allowedToEdit) {
|
|
|
- $lp_blocked = null;
|
|
|
- if ($exercise->exercise_was_added_in_lp == true) {
|
|
|
- $lp_blocked = Display::div(
|
|
|
- get_lang('AddedToLPCannotBeAccessed'),
|
|
|
- ['class' => 'lp_content_type_label']
|
|
|
- );
|
|
|
+ // Number of questions
|
|
|
+ $random_label = null;
|
|
|
+ if ($row['random'] > 0 || $row['random'] == -1) {
|
|
|
+ // if random == -1 means use random questions with all questions
|
|
|
+ $random_number_of_question = $row['random'];
|
|
|
+ if ($random_number_of_question == -1) {
|
|
|
+ $random_number_of_question = $rowi;
|
|
|
+ }
|
|
|
+ if ($row['random_by_category'] > 0) {
|
|
|
+ $nbQuestionsTotal = TestCategory::getNumberOfQuestionRandomByCategory(
|
|
|
+ $my_exercise_id,
|
|
|
+ $random_number_of_question
|
|
|
+ );
|
|
|
+ $number_of_questions = $nbQuestionsTotal.' ';
|
|
|
+ $number_of_questions .= ($nbQuestionsTotal > 1) ? get_lang('QuestionsLowerCase') : get_lang('QuestionLowerCase');
|
|
|
+ $number_of_questions .= ' - ';
|
|
|
+ $number_of_questions .= min(
|
|
|
+ TestCategory::getNumberMaxQuestionByCat($my_exercise_id), $random_number_of_question
|
|
|
+ ).' '.get_lang('QuestionByCategory');
|
|
|
+ } else {
|
|
|
+ $random_label = ' ('.get_lang('Random').') ';
|
|
|
+ $number_of_questions = $random_number_of_question.' '.$random_label.' / '.$rowi;
|
|
|
+ // Bug if we set a random value bigger than the real number of questions
|
|
|
+ if ($random_number_of_question > $rowi) {
|
|
|
+ $number_of_questions = $rowi.' '.$random_label;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $number_of_questions = $rowi;
|
|
|
}
|
|
|
-
|
|
|
+ $item .= Display::tag('td', $number_of_questions);
|
|
|
+ } else {
|
|
|
+ // Student only.
|
|
|
$visibility = api_get_item_visibility(
|
|
|
$courseInfo,
|
|
|
TOOL_QUIZ,
|
|
|
$my_exercise_id,
|
|
|
- 0
|
|
|
+ $sessionId
|
|
|
);
|
|
|
|
|
|
- if (!empty($sessionId)) {
|
|
|
- $setting = api_get_configuration_value('show_hidden_exercise_added_to_lp');
|
|
|
- if ($setting) {
|
|
|
- if ($exercise->exercise_was_added_in_lp == false) {
|
|
|
- if ($visibility == 0) {
|
|
|
- continue;
|
|
|
+ if ($visibility == 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ $url = '<a '.$alt_title.' href="overview.php?'.api_get_cidreq().$mylpid.$mylpitemid.'&exerciseId='.$row['id'].'">'.
|
|
|
+ $cut_title.'</a>';
|
|
|
+
|
|
|
+ // Link of the exercise.
|
|
|
+ $item = Display::tag('td', $url.' '.$session_img);
|
|
|
+
|
|
|
+ // This query might be improved later on by ordering by the new "tms" field rather than by exe_id
|
|
|
+ // Don't remove this marker: note-query-exe-results
|
|
|
+ $sql = "SELECT * FROM $TBL_TRACK_EXERCISES
|
|
|
+ WHERE
|
|
|
+ exe_exo_id = ".$row['id']." AND
|
|
|
+ exe_user_id = $userId AND
|
|
|
+ c_id = ".api_get_course_int_id()." AND
|
|
|
+ status <> 'incomplete' AND
|
|
|
+ orig_lp_id = 0 AND
|
|
|
+ orig_lp_item_id = 0 AND
|
|
|
+ session_id = '".api_get_session_id()."'
|
|
|
+ ORDER BY exe_id DESC";
|
|
|
+
|
|
|
+ $qryres = Database::query($sql);
|
|
|
+ $num = Database :: num_rows($qryres);
|
|
|
+
|
|
|
+ // Hide the results.
|
|
|
+ $my_result_disabled = $row['results_disabled'];
|
|
|
+
|
|
|
+ // Time limits are on
|
|
|
+ if ($time_limits) {
|
|
|
+ // Exam is ready to be taken
|
|
|
+ if ($is_actived_time) {
|
|
|
+ // Show results
|
|
|
+ if (
|
|
|
+ in_array(
|
|
|
+ $my_result_disabled,
|
|
|
+ [
|
|
|
+ RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS,
|
|
|
+ RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING,
|
|
|
+ RESULT_DISABLE_SHOW_SCORE_ONLY,
|
|
|
+ RESULT_DISABLE_RANKING,
|
|
|
+ ]
|
|
|
+ )
|
|
|
+ ) {
|
|
|
+ // More than one attempt
|
|
|
+ if ($num > 0) {
|
|
|
+ $row_track = Database :: fetch_array($qryres);
|
|
|
+ $attempt_text = get_lang('LatestAttempt').' : ';
|
|
|
+ $attempt_text .= ExerciseLib::show_score(
|
|
|
+ $row_track['exe_result'],
|
|
|
+ $row_track['exe_weighting']
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ //No attempts
|
|
|
+ $attempt_text = get_lang('NotAttempted');
|
|
|
}
|
|
|
+ } else {
|
|
|
+ $attempt_text = '-';
|
|
|
}
|
|
|
} else {
|
|
|
- if ($visibility == 0) {
|
|
|
- continue;
|
|
|
+ // Quiz not ready due to time limits
|
|
|
+ //@todo use the is_visible function
|
|
|
+ if (!empty($row['start_time']) && !empty($row['end_time'])) {
|
|
|
+ $today = time();
|
|
|
+ $start_time = api_strtotime($row['start_time'], 'UTC');
|
|
|
+ $end_time = api_strtotime($row['end_time'], 'UTC');
|
|
|
+ if ($today < $start_time) {
|
|
|
+ $attempt_text = sprintf(
|
|
|
+ get_lang('ExerciseWillBeActivatedFromXToY'),
|
|
|
+ api_convert_and_format_date($row['start_time']),
|
|
|
+ api_convert_and_format_date($row['end_time'])
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ if ($today > $end_time) {
|
|
|
+ $attempt_text = sprintf(
|
|
|
+ get_lang('ExerciseWasActivatedFromXToY'),
|
|
|
+ api_convert_and_format_date($row['start_time']),
|
|
|
+ api_convert_and_format_date($row['end_time'])
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //$attempt_text = get_lang('ExamNotAvailableAtThisTime');
|
|
|
+ if (!empty($row['start_time'])) {
|
|
|
+ $attempt_text = sprintf(
|
|
|
+ get_lang('ExerciseAvailableFromX'),
|
|
|
+ api_convert_and_format_date($row['start_time'])
|
|
|
+ );
|
|
|
+ }
|
|
|
+ if (!empty($row['end_time'])) {
|
|
|
+ $attempt_text = sprintf(
|
|
|
+ get_lang('ExerciseAvailableUntilX'),
|
|
|
+ api_convert_and_format_date($row['end_time'])
|
|
|
+ );
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- $visibility = api_get_item_visibility(
|
|
|
- $courseInfo,
|
|
|
- TOOL_QUIZ,
|
|
|
- $my_exercise_id,
|
|
|
- $sessionId
|
|
|
- );
|
|
|
+ } else {
|
|
|
+ // Normal behaviour.
|
|
|
+ // Show results.
|
|
|
+ if (
|
|
|
+ in_array(
|
|
|
+ $my_result_disabled,
|
|
|
+ [
|
|
|
+ RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS,
|
|
|
+ RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING,
|
|
|
+ RESULT_DISABLE_SHOW_SCORE_ONLY,
|
|
|
+ RESULT_DISABLE_RANKING,
|
|
|
+ ]
|
|
|
+ )
|
|
|
+ ) {
|
|
|
+ if ($num > 0) {
|
|
|
+ $row_track = Database :: fetch_array($qryres);
|
|
|
+ $attempt_text = get_lang('LatestAttempt').' : ';
|
|
|
+ $attempt_text .= ExerciseLib::show_score(
|
|
|
+ $row_track['exe_result'],
|
|
|
+ $row_track['exe_weighting']
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ $attempt_text = get_lang('NotAttempted');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $attempt_text = '-';
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- if ($row['active'] == 0 || $visibility == 0) {
|
|
|
- $title = Display::tag('font', $cut_title, ['style' => 'color:grey']);
|
|
|
+ $class_tip = '';
|
|
|
+ if (empty($num)) {
|
|
|
+ $num = '';
|
|
|
} else {
|
|
|
- $title = $cut_title;
|
|
|
+ $class_tip = 'link_tooltip';
|
|
|
+ //@todo use sprintf and show the results validated by the teacher
|
|
|
+ if ($num == 1) {
|
|
|
+ $num = $num.' '.get_lang('Result');
|
|
|
+ } else {
|
|
|
+ $num = $num.' '.get_lang('Results');
|
|
|
+ }
|
|
|
+ $num = '<span class="tooltip" style="display: none;">'.$num.'</span>';
|
|
|
}
|
|
|
|
|
|
- $count_exercise_not_validated = (int) Event::count_exercise_result_not_validated(
|
|
|
- $my_exercise_id,
|
|
|
- $courseId,
|
|
|
- $sessionId
|
|
|
- );
|
|
|
+ $item .= Display::tag('td', $attempt_text);
|
|
|
+ }
|
|
|
|
|
|
- $move = Display::return_icon(
|
|
|
- 'all_directions.png',
|
|
|
- get_lang('Move'),
|
|
|
- ['class' => 'moved', 'style' => 'margin-bottom:-0.5em;']
|
|
|
- );
|
|
|
- $move = null;
|
|
|
- $class_tip = '';
|
|
|
+ if ($is_allowedToEdit) {
|
|
|
+ $additionalActions = ExerciseLib::getAdditionalTeacherActions($row['id']);
|
|
|
|
|
|
- if (!empty($count_exercise_not_validated)) {
|
|
|
- $results_text = $count_exercise_not_validated == 1 ? get_lang('ResultNotRevised') : get_lang('ResultsNotRevised');
|
|
|
- $title .= '<span class="exercise_tooltip" style="display: none;">'.$count_exercise_not_validated.' '.$results_text.' </span>';
|
|
|
- $class_tip = 'link_tooltip';
|
|
|
+ if (!empty($additionalActions)) {
|
|
|
+ $actions .= $additionalActions.PHP_EOL;
|
|
|
}
|
|
|
|
|
|
- $url = $move.'<a '.$alt_title.' class="'.$class_tip.'" id="tooltip_'.$row['id'].'" href="overview.php?'.api_get_cidreq().$mylpid.$mylpitemid.'&exerciseId='.$row['id'].'">
|
|
|
- '.Display::return_icon('quiz.png', $row['title']).'
|
|
|
- '.$title.' </a>'.PHP_EOL;
|
|
|
-
|
|
|
- if (ExerciseLib::isQuizEmbeddable($row)) {
|
|
|
- $embeddableIcon = Display::return_icon('om_integration.png', get_lang('ThisQuizCanBeEmbeddable'));
|
|
|
- $url .= Display::div($embeddableIcon, ['class' => 'pull-right']);
|
|
|
+ $item .= Display::tag('td', $actions, ['class' => 'td_actions']);
|
|
|
+ } else {
|
|
|
+ if ($isDrhOfCourse) {
|
|
|
+ $actions = '<a href="exercise_report.php?'.api_get_cidreq().'&exerciseId='.$row['id'].'">'.
|
|
|
+ Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
+ $item .= Display::tag('td', $actions, ['class' => 'td_actions']);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- $item = Display::tag('td', $url.' '.$session_img.$lp_blocked);
|
|
|
+ $tableRows[] = Display::tag(
|
|
|
+ 'tr',
|
|
|
+ $item,
|
|
|
+ [
|
|
|
+ 'id' => 'exercise_list_'.$my_exercise_id,
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // Count number exercise - teacher
|
|
|
- $sql = "SELECT count(*) count FROM $TBL_EXERCISE_QUESTION
|
|
|
- WHERE c_id = $courseId AND exercice_id = $my_exercise_id";
|
|
|
- $sqlresult = Database::query($sql);
|
|
|
- $rowi = (int) Database::result($sqlresult, 0, 0);
|
|
|
+ // end exercise list
|
|
|
+ // Hotpotatoes results
|
|
|
+ $hotpotatoes_exist = false;
|
|
|
|
|
|
- if ($sessionId == $row['session_id']) {
|
|
|
- // Questions list
|
|
|
- $actions = Display::url(
|
|
|
- Display::return_icon('edit.png', get_lang('Edit'), '', ICON_SIZE_SMALL),
|
|
|
- 'admin.php?'.api_get_cidreq().'&exerciseId='.$row['id']
|
|
|
- );
|
|
|
+ if ($is_allowedToEdit) {
|
|
|
+ $sql = "SELECT d.iid, d.path as path, d.comment as comment
|
|
|
+ FROM $TBL_DOCUMENT d
|
|
|
+ WHERE
|
|
|
+ d.c_id = $courseId AND
|
|
|
+ (d.path LIKE '%htm%') AND
|
|
|
+ d.path LIKE '".Database :: escape_string($uploadPath.'/%/%')."'
|
|
|
+ LIMIT ".$from.",".$limit; // only .htm or .html files listed
|
|
|
+ } else {
|
|
|
+ $sql = "SELECT d.iid, d.path as path, d.comment as comment
|
|
|
+ FROM $TBL_DOCUMENT d
|
|
|
+ WHERE
|
|
|
+ d.c_id = $courseId AND
|
|
|
+ (d.path LIKE '%htm%') AND
|
|
|
+ d.path LIKE '".Database :: escape_string($uploadPath.'/%/%')."'
|
|
|
+ LIMIT ".$from.",".$limit;
|
|
|
+ }
|
|
|
|
|
|
- // Test settings
|
|
|
- $settings = Display::url(
|
|
|
- Display::return_icon('settings.png', get_lang('Configure'), '', ICON_SIZE_SMALL),
|
|
|
- 'exercise_admin.php?'.api_get_cidreq().'&exerciseId='.$row['id']
|
|
|
- );
|
|
|
+ $result = Database::query($sql);
|
|
|
+ $attribute = [];
|
|
|
+ while ($row = Database :: fetch_array($result, 'ASSOC')) {
|
|
|
+ $attribute['id'][] = $row['iid'];
|
|
|
+ $attribute['path'][] = $row['path'];
|
|
|
+ $attribute['comment'][] = $row['comment'];
|
|
|
+ }
|
|
|
|
|
|
- if ($limitTeacherAccess && !api_is_platform_admin()) {
|
|
|
- $settings = '';
|
|
|
- }
|
|
|
- $actions .= $settings;
|
|
|
+ $nbrActiveTests = 0;
|
|
|
+ if (isset($attribute['path']) && is_array($attribute['path'])) {
|
|
|
+ $hotpotatoes_exist = true;
|
|
|
+ foreach ($attribute['path'] as $key => $path) {
|
|
|
+ $item = '';
|
|
|
+ $title = GetQuizName($path, $documentPath);
|
|
|
+ if ($title == '') {
|
|
|
+ $title = basename($path);
|
|
|
+ }
|
|
|
|
|
|
- // Exercise results
|
|
|
- $resultsLink = '<a href="exercise_report.php?'.api_get_cidreq().'&exerciseId='.$row['id'].'">'.
|
|
|
- Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
+ // prof only
|
|
|
+ if ($is_allowedToEdit) {
|
|
|
+ $visibility = api_get_item_visibility(
|
|
|
+ ['real_id' => $courseId],
|
|
|
+ TOOL_DOCUMENT,
|
|
|
+ $attribute['id'][$key],
|
|
|
+ 0
|
|
|
+ );
|
|
|
|
|
|
- if ($limitTeacherAccess) {
|
|
|
- if (api_is_platform_admin()) {
|
|
|
- $actions .= $resultsLink;
|
|
|
- }
|
|
|
- } else {
|
|
|
- // Exercise results
|
|
|
- $actions .= $resultsLink;
|
|
|
- }
|
|
|
+ if (!empty($sessionId)) {
|
|
|
+ if (0 == $visibility) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- // Auto launch
|
|
|
- if ($autoLaunchAvailable) {
|
|
|
- $autoLaunch = $exercise->getAutoLaunch();
|
|
|
- if (empty($autoLaunch)) {
|
|
|
- $actions .= Display::url(
|
|
|
- Display::return_icon(
|
|
|
- 'launch_na.png',
|
|
|
- get_lang('Enable'),
|
|
|
- '',
|
|
|
- ICON_SIZE_SMALL
|
|
|
- ),
|
|
|
- 'exercise.php?'.api_get_cidreq().'&choice=enable_launch&sec_token='.$token.'&page='.$page.'&exerciseId='.$row['id']
|
|
|
- );
|
|
|
- } else {
|
|
|
- $actions .= Display::url(
|
|
|
- Display::return_icon(
|
|
|
- 'launch.png',
|
|
|
- get_lang('Disable'),
|
|
|
- '',
|
|
|
- ICON_SIZE_SMALL
|
|
|
- ),
|
|
|
- 'exercise.php?'.api_get_cidreq().'&choice=disable_launch&sec_token='.$token.'&page='.$page.'&exerciseId='.$row['id']
|
|
|
- );
|
|
|
- }
|
|
|
- }
|
|
|
+ $visibility = api_get_item_visibility(
|
|
|
+ ['real_id' => $courseId],
|
|
|
+ TOOL_DOCUMENT,
|
|
|
+ $attribute['id'][$key],
|
|
|
+ $sessionId
|
|
|
+ );
|
|
|
+ }
|
|
|
|
|
|
- // Export
|
|
|
- $actions .= Display::url(
|
|
|
- Display::return_icon('cd.png', get_lang('CopyExercise')),
|
|
|
- '',
|
|
|
- [
|
|
|
- 'onclick' => "javascript:if(!confirm('".addslashes(api_htmlentities(get_lang('AreYouSureToCopy'), ENT_QUOTES, $charset))." ".addslashes($row['title'])."?"."')) return false;",
|
|
|
- 'href' => 'exercise.php?'.api_get_cidreq().'&choice=copy_exercise&sec_token='.$token.'&exerciseId='.$row['id'],
|
|
|
- ]
|
|
|
- );
|
|
|
+ $item = Display::tag(
|
|
|
+ 'td',
|
|
|
+ implode(PHP_EOL, [
|
|
|
+ Display::return_icon('hotpotatoes_s.png', "HotPotatoes"),
|
|
|
+ Display::url(
|
|
|
+ $title,
|
|
|
+ 'showinframes.php?'.api_get_cidreq().'&'.http_build_query([
|
|
|
+ 'file' => $path,
|
|
|
+ 'uid' => $userId,
|
|
|
+ ]),
|
|
|
+ ['class' => $visibility == 0 ? 'text-muted' : null]
|
|
|
+ ),
|
|
|
+ ])
|
|
|
+ );
|
|
|
|
|
|
- // Clean exercise
|
|
|
- if ($locked == false) {
|
|
|
- $clean = Display::url(
|
|
|
- Display::return_icon(
|
|
|
- 'clean.png',
|
|
|
- get_lang('CleanStudentResults'),
|
|
|
- '',
|
|
|
- ICON_SIZE_SMALL
|
|
|
- ),
|
|
|
- '',
|
|
|
- [
|
|
|
- 'onclick' => "javascript:if(!confirm('".addslashes(api_htmlentities(get_lang('AreYouSureToDeleteResults'), ENT_QUOTES, $charset))." ".addslashes($row['title'])."?"."')) return false;",
|
|
|
- 'href' => 'exercise.php?'.api_get_cidreq().'&choice=clean_results&sec_token='.$token.'&exerciseId='.$row['id'],
|
|
|
- ]
|
|
|
- );
|
|
|
- } else {
|
|
|
- $clean = Display::return_icon(
|
|
|
- 'clean_na.png',
|
|
|
- get_lang('ResourceLockedByGradebook'),
|
|
|
- '',
|
|
|
- ICON_SIZE_SMALL
|
|
|
- );
|
|
|
- }
|
|
|
+ $item .= Display::tag('td', '-');
|
|
|
|
|
|
- if ($limitTeacherAccess && !api_is_platform_admin()) {
|
|
|
- $clean = '';
|
|
|
- }
|
|
|
- $actions .= $clean;
|
|
|
- // Visible / invisible
|
|
|
- // Check if this exercise was added in a LP
|
|
|
- if ($exercise->exercise_was_added_in_lp == true) {
|
|
|
- $visibility = Display::return_icon(
|
|
|
- 'invisible.png',
|
|
|
- get_lang('AddedToLPCannotBeAccessed'),
|
|
|
- '',
|
|
|
- ICON_SIZE_SMALL
|
|
|
- );
|
|
|
- } else {
|
|
|
- if ($row['active'] == 0 || $visibility == 0) {
|
|
|
- $visibility = Display::url(
|
|
|
- Display::return_icon(
|
|
|
- 'invisible.png',
|
|
|
- get_lang('Activate'),
|
|
|
- '',
|
|
|
- ICON_SIZE_SMALL
|
|
|
- ),
|
|
|
- 'exercise.php?'.api_get_cidreq().'&choice=enable&sec_token='.$token.'&page='.$page.'&exerciseId='.$row['id']
|
|
|
- );
|
|
|
- } else {
|
|
|
- // else if not active
|
|
|
- $visibility = Display::url(
|
|
|
- Display::return_icon(
|
|
|
- 'visible.png',
|
|
|
- get_lang('Deactivate'),
|
|
|
- '',
|
|
|
- ICON_SIZE_SMALL
|
|
|
- ),
|
|
|
- 'exercise.php?'.api_get_cidreq().'&choice=disable&sec_token='.$token.'&page='.$page.'&exerciseId='.$row['id']
|
|
|
- );
|
|
|
- }
|
|
|
- }
|
|
|
+ $actions = Display::url(
|
|
|
+ Display::return_icon(
|
|
|
+ 'edit.png',
|
|
|
+ get_lang('Edit'),
|
|
|
+ '',
|
|
|
+ ICON_SIZE_SMALL
|
|
|
+ ),
|
|
|
+ 'adminhp.php?'.api_get_cidreq().'&hotpotatoesName='.$path
|
|
|
+ );
|
|
|
+
|
|
|
+ $actions .= '<a href="hotpotatoes_exercise_report.php?'.api_get_cidreq().'&path='.$path.'">'.
|
|
|
+ Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
+
|
|
|
+ // if active
|
|
|
+ if ($visibility != 0) {
|
|
|
+ $nbrActiveTests = $nbrActiveTests + 1;
|
|
|
+ $actions .= ' <a href="'.$exercisePath.'?'.api_get_cidreq().'&hpchoice=disable&page='.$page.'&file='.$path.'">'.
|
|
|
+ Display::return_icon('visible.png', get_lang('Deactivate'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
+ } else { // else if not active
|
|
|
+ $actions .= ' <a href="'.$exercisePath.'?'.api_get_cidreq().'&hpchoice=enable&page='.$page.'&file='.$path.'">'.
|
|
|
+ Display::return_icon('invisible.png', get_lang('Activate'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
+ }
|
|
|
+ $actions .= '<a href="'.$exercisePath.'?'.api_get_cidreq().'&hpchoice=delete&file='.$path.'" onclick="javascript:if(!confirm(\''.addslashes(api_htmlentities(get_lang('AreYouSureToDeleteJS'), ENT_QUOTES, $charset).' '.$title."?").'\')) return false;">'.
|
|
|
+ Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
+ $item .= Display::tag('td', $actions);
|
|
|
+ $tableRows[] = Display::tag('tr', $item);
|
|
|
+ } else {
|
|
|
+ $visibility = api_get_item_visibility(
|
|
|
+ ['real_id' => $courseId],
|
|
|
+ TOOL_DOCUMENT,
|
|
|
+ $attribute['id'][$key],
|
|
|
+ $sessionId
|
|
|
+ );
|
|
|
+
|
|
|
+ if (0 == $visibility) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- if ($limitTeacherAccess && !api_is_platform_admin()) {
|
|
|
- $visibility = '';
|
|
|
- }
|
|
|
+ // Student only
|
|
|
+ $attempt = ExerciseLib::getLatestHotPotatoResult(
|
|
|
+ $path,
|
|
|
+ $userId,
|
|
|
+ api_get_course_int_id(),
|
|
|
+ api_get_session_id()
|
|
|
+ );
|
|
|
|
|
|
- $actions .= $visibility;
|
|
|
+ $nbrActiveTests = $nbrActiveTests + 1;
|
|
|
+ $item .= Display::tag(
|
|
|
+ 'td',
|
|
|
+ Display::url(
|
|
|
+ $title,
|
|
|
+ 'showinframes.php?'.api_get_cidreq().'&'.http_build_query([
|
|
|
+ 'file' => $path,
|
|
|
+ 'cid' => api_get_course_id(),
|
|
|
+ 'uid' => $userId,
|
|
|
+ ])
|
|
|
+ )
|
|
|
+ );
|
|
|
|
|
|
- // Export qti ...
|
|
|
- $export = Display::url(
|
|
|
- Display::return_icon(
|
|
|
- 'export_qti2.png',
|
|
|
- 'IMS/QTI',
|
|
|
- '',
|
|
|
- ICON_SIZE_SMALL
|
|
|
- ),
|
|
|
- 'exercise.php?choice=exportqti2&exerciseId='.$row['id'].'&'.api_get_cidreq()
|
|
|
- );
|
|
|
+ if (!empty($attempt)) {
|
|
|
+ $actions = '<a href="hotpotatoes_exercise_report.php?'.api_get_cidreq().'&path='.$path.'&filter_by_user='.$userId.'">'.Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
+ $attemptText = get_lang('LatestAttempt').' : ';
|
|
|
+ $attemptText .= ExerciseLib::show_score(
|
|
|
+ $attempt['exe_result'],
|
|
|
+ $attempt['exe_weighting']
|
|
|
+ ).' ';
|
|
|
+ $attemptText .= $actions;
|
|
|
+ } else {
|
|
|
+ // No attempts.
|
|
|
+ $attemptText = get_lang('NotAttempted').' ';
|
|
|
+ }
|
|
|
|
|
|
- if ($limitTeacherAccess && !api_is_platform_admin()) {
|
|
|
- $export = '';
|
|
|
- }
|
|
|
+ $item .= Display::tag('td', $attemptText);
|
|
|
|
|
|
- $actions .= $export;
|
|
|
- } else {
|
|
|
- // not session
|
|
|
- $actions = Display::return_icon(
|
|
|
- 'edit_na.png',
|
|
|
- get_lang('ExerciseEditionNotAvailableInSession')
|
|
|
- );
|
|
|
+ if ($isDrhOfCourse) {
|
|
|
+ $actions = '<a href="hotpotatoes_exercise_report.php?'.api_get_cidreq().'&path='.$path.'">'.
|
|
|
+ Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
|
|
|
- // Check if this exercise was added in a LP
|
|
|
- if ($exercise->exercise_was_added_in_lp == true) {
|
|
|
- $visibility = Display::return_icon(
|
|
|
- 'invisible.png',
|
|
|
- get_lang('AddedToLPCannotBeAccessed'),
|
|
|
- '',
|
|
|
- ICON_SIZE_SMALL
|
|
|
- );
|
|
|
- } else {
|
|
|
- if ($row['active'] == 0 || $visibility == 0) {
|
|
|
- $visibility = Display::url(
|
|
|
- Display::return_icon(
|
|
|
- 'invisible.png',
|
|
|
- get_lang('Activate'),
|
|
|
- '',
|
|
|
- ICON_SIZE_SMALL
|
|
|
- ),
|
|
|
- 'exercise.php?'.api_get_cidreq().'&choice=enable&sec_token='.$token.'&page='.$page.'&exerciseId='.$row['id']
|
|
|
- );
|
|
|
- } else {
|
|
|
- // else if not active
|
|
|
- $visibility = Display::url(
|
|
|
- Display::return_icon(
|
|
|
- 'visible.png',
|
|
|
- get_lang('Deactivate'),
|
|
|
- '',
|
|
|
- ICON_SIZE_SMALL
|
|
|
- ),
|
|
|
- 'exercise.php?'.api_get_cidreq().'&choice=disable&sec_token='.$token.'&page='.$page.'&exerciseId='.$row['id']
|
|
|
- );
|
|
|
- }
|
|
|
- }
|
|
|
+ $item .= Display::tag(
|
|
|
+ 'td',
|
|
|
+ $actions,
|
|
|
+ ['class' => 'td_actions']
|
|
|
+ );
|
|
|
+ }
|
|
|
+ $tableRows[] = Display::tag('tr', $item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if ($limitTeacherAccess && !api_is_platform_admin()) {
|
|
|
- $visibility = '';
|
|
|
- }
|
|
|
+ if (empty($tableRows)) {
|
|
|
+ if ($is_allowedToEdit && $origin != 'learnpath') {
|
|
|
+ $content .= '<div id="no-data-view">';
|
|
|
+ $content .= '<h3>'.get_lang('Quiz').'</h3>';
|
|
|
+ $content .= Display::return_icon('quiz.png', '', [], 64);
|
|
|
+ $content .= '<div class="controls">';
|
|
|
+ $content .= Display::url(
|
|
|
+ '<em class="fa fa-plus"></em> '.get_lang('NewEx'),
|
|
|
+ 'exercise_admin.php?'.api_get_cidreq(),
|
|
|
+ ['class' => 'btn btn-primary']
|
|
|
+ );
|
|
|
+ $content .= '</div>';
|
|
|
+ $content .= '</div>';
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if ($is_allowedToEdit) {
|
|
|
+ $headers = [
|
|
|
+ get_lang('ExerciseName'),
|
|
|
+ get_lang('QuantityQuestions'),
|
|
|
+ get_lang('Actions'),
|
|
|
+ ];
|
|
|
+ } else {
|
|
|
+ $headers = [
|
|
|
+ get_lang('ExerciseName'),
|
|
|
+ get_lang('Status'),
|
|
|
+ ];
|
|
|
|
|
|
- $actions .= $visibility;
|
|
|
+ if ($isDrhOfCourse) {
|
|
|
+ $headers[] = get_lang('Actions');
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- $actions .= '<a href="exercise_report.php?'.api_get_cidreq().'&exerciseId='.$row['id'].'">'.
|
|
|
- Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
- $actions .= Display::url(
|
|
|
- Display::return_icon('cd.gif', get_lang('CopyExercise')),
|
|
|
- '',
|
|
|
- [
|
|
|
- 'onclick' => "javascript:if(!confirm('".addslashes(api_htmlentities(get_lang('AreYouSureToCopy'), ENT_QUOTES, $charset))." ".addslashes($row['title'])."?"."')) return false;",
|
|
|
- 'href' => 'exercise.php?'.api_get_cidreq().'&choice=copy_exercise&sec_token='.$token.'&exerciseId='.$row['id'],
|
|
|
- ]
|
|
|
- );
|
|
|
- }
|
|
|
+ foreach ($tableRows as $roz) {
|
|
|
+ echo $roz;
|
|
|
+ }
|
|
|
|
|
|
- // Delete
|
|
|
- $delete = '';
|
|
|
- if ($sessionId == $row['session_id']) {
|
|
|
- if ($locked == false) {
|
|
|
- $delete = Display::url(
|
|
|
- Display::return_icon(
|
|
|
- 'delete.png',
|
|
|
- get_lang('Delete'),
|
|
|
- '',
|
|
|
- ICON_SIZE_SMALL
|
|
|
- ),
|
|
|
- '',
|
|
|
- [
|
|
|
- 'onclick' => "javascript:if(!confirm('".addslashes(api_htmlentities(get_lang('AreYouSureToDeleteJS'), ENT_QUOTES, $charset))." ".addslashes($exercise->getUnformattedTitle())."?"."')) return false;",
|
|
|
- 'href' => 'exercise.php?'.api_get_cidreq().'&choice=delete&sec_token='.$token.'&exerciseId='.$row['id'],
|
|
|
- ]
|
|
|
- );
|
|
|
- } else {
|
|
|
- $delete = Display::return_icon(
|
|
|
- 'delete_na.png',
|
|
|
- get_lang('ResourceLockedByGradebook'),
|
|
|
- '',
|
|
|
- ICON_SIZE_SMALL
|
|
|
- );
|
|
|
- }
|
|
|
- }
|
|
|
+ $content .= '<div class="table-responsive">';
|
|
|
+ $table = new SortableTableFromArrayConfig(
|
|
|
+ $tableRows,
|
|
|
+ 1,
|
|
|
+ 20,
|
|
|
+ 'exercises'
|
|
|
+ );
|
|
|
+ $i = 0;
|
|
|
+ foreach ($headers as $header) {
|
|
|
+ $table->set_header($i++, $header);
|
|
|
+ }
|
|
|
+ $table->set_header($i++, 'aa');
|
|
|
|
|
|
- if ($limitTeacherAccess && !api_is_platform_admin()) {
|
|
|
- $delete = '';
|
|
|
- }
|
|
|
+ $content .= $table->return_table();
|
|
|
+ $content .= '</div>';
|
|
|
+ }
|
|
|
|
|
|
- $actions .= $delete;
|
|
|
+ return $content;
|
|
|
+ }
|
|
|
|
|
|
- // Number of questions
|
|
|
- $random_label = null;
|
|
|
- if ($row['random'] > 0 || $row['random'] == -1) {
|
|
|
- // if random == -1 means use random questions with all questions
|
|
|
- $random_number_of_question = $row['random'];
|
|
|
- if ($random_number_of_question == -1) {
|
|
|
- $random_number_of_question = $rowi;
|
|
|
- }
|
|
|
- if ($row['random_by_category'] > 0) {
|
|
|
- $nbQuestionsTotal = TestCategory::getNumberOfQuestionRandomByCategory(
|
|
|
- $my_exercise_id,
|
|
|
- $random_number_of_question
|
|
|
- );
|
|
|
- $number_of_questions = $nbQuestionsTotal.' ';
|
|
|
- $number_of_questions .= ($nbQuestionsTotal > 1) ? get_lang('QuestionsLowerCase') : get_lang('QuestionLowerCase');
|
|
|
- $number_of_questions .= ' - ';
|
|
|
- $number_of_questions .= min(
|
|
|
- TestCategory::getNumberMaxQuestionByCat($my_exercise_id), $random_number_of_question
|
|
|
- ).' '.get_lang('QuestionByCategory');
|
|
|
- } else {
|
|
|
- $random_label = ' ('.get_lang('Random').') ';
|
|
|
- $number_of_questions = $random_number_of_question.' '.$random_label.' / '.$rowi;
|
|
|
- // Bug if we set a random value bigger than the real number of questions
|
|
|
- if ($random_number_of_question > $rowi) {
|
|
|
- $number_of_questions = $rowi.' '.$random_label;
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- $number_of_questions = $rowi;
|
|
|
- }
|
|
|
- $item .= Display::tag('td', $number_of_questions);
|
|
|
- } else {
|
|
|
- // Student only.
|
|
|
- $visibility = api_get_item_visibility(
|
|
|
- $courseInfo,
|
|
|
- TOOL_QUIZ,
|
|
|
- $my_exercise_id,
|
|
|
- $sessionId
|
|
|
- );
|
|
|
+ /**
|
|
|
+ * Gets the question list ordered by the question_order setting (drag and drop).
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ private function getQuestionOrderedList()
|
|
|
+ {
|
|
|
+ $TBL_EXERCICE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
|
|
|
+ $TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION);
|
|
|
|
|
|
- if ($visibility == 0) {
|
|
|
- continue;
|
|
|
- }
|
|
|
+ // Getting question_order to verify that the question
|
|
|
+ // list is correct and all question_order's were set
|
|
|
+ $sql = "SELECT DISTINCT count(e.question_order) as count
|
|
|
+ FROM $TBL_EXERCICE_QUESTION e
|
|
|
+ INNER JOIN $TBL_QUESTIONS q
|
|
|
+ ON (e.question_id = q.id AND e.c_id = q.c_id)
|
|
|
+ WHERE
|
|
|
+ e.c_id = {$this->course_id} AND
|
|
|
+ e.exercice_id = ".$this->id;
|
|
|
|
|
|
- $url = '<a '.$alt_title.' href="overview.php?'.api_get_cidreq().$mylpid.$mylpitemid.'&exerciseId='.$row['id'].'">'.
|
|
|
- $cut_title.'</a>';
|
|
|
+ $result = Database::query($sql);
|
|
|
+ $row = Database::fetch_array($result);
|
|
|
+ $count_question_orders = $row['count'];
|
|
|
|
|
|
- // Link of the exercise.
|
|
|
- $item = Display::tag('td', $url.' '.$session_img);
|
|
|
+ // Getting question list from the order (question list drag n drop interface).
|
|
|
+ $sql = "SELECT DISTINCT e.question_id, e.question_order
|
|
|
+ FROM $TBL_EXERCICE_QUESTION e
|
|
|
+ INNER JOIN $TBL_QUESTIONS q
|
|
|
+ ON (e.question_id = q.id AND e.c_id = q.c_id)
|
|
|
+ WHERE
|
|
|
+ e.c_id = {$this->course_id} AND
|
|
|
+ e.exercice_id = '".$this->id."'
|
|
|
+ ORDER BY question_order";
|
|
|
+ $result = Database::query($sql);
|
|
|
|
|
|
- // This query might be improved later on by ordering by the new "tms" field rather than by exe_id
|
|
|
- // Don't remove this marker: note-query-exe-results
|
|
|
- $sql = "SELECT * FROM $TBL_TRACK_EXERCISES
|
|
|
- WHERE
|
|
|
- exe_exo_id = ".$row['id']." AND
|
|
|
- exe_user_id = $userId AND
|
|
|
- c_id = ".api_get_course_int_id()." AND
|
|
|
- status <> 'incomplete' AND
|
|
|
- orig_lp_id = 0 AND
|
|
|
- orig_lp_item_id = 0 AND
|
|
|
- session_id = '".api_get_session_id()."'
|
|
|
- ORDER BY exe_id DESC";
|
|
|
+ // Fills the array with the question ID for this exercise
|
|
|
+ // the key of the array is the question position
|
|
|
+ $temp_question_list = [];
|
|
|
+ $counter = 1;
|
|
|
+ $questionList = [];
|
|
|
+ while ($new_object = Database::fetch_object($result)) {
|
|
|
+ // Correct order.
|
|
|
+ $questionList[$new_object->question_order] = $new_object->question_id;
|
|
|
+ // Just in case we save the order in other array
|
|
|
+ $temp_question_list[$counter] = $new_object->question_id;
|
|
|
+ $counter++;
|
|
|
+ }
|
|
|
|
|
|
- $qryres = Database::query($sql);
|
|
|
- $num = Database :: num_rows($qryres);
|
|
|
+ if (!empty($temp_question_list)) {
|
|
|
+ /* If both array don't match it means that question_order was not correctly set
|
|
|
+ for all questions using the default mysql order */
|
|
|
+ if (count($temp_question_list) != $count_question_orders) {
|
|
|
+ $questionList = $temp_question_list;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // Hide the results.
|
|
|
- $my_result_disabled = $row['results_disabled'];
|
|
|
+ return $questionList;
|
|
|
+ }
|
|
|
|
|
|
- // Time limits are on
|
|
|
- if ($time_limits) {
|
|
|
- // Exam is ready to be taken
|
|
|
- if ($is_actived_time) {
|
|
|
- // Show results
|
|
|
- if (
|
|
|
- in_array(
|
|
|
- $my_result_disabled,
|
|
|
- [
|
|
|
- RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS,
|
|
|
- RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING,
|
|
|
- RESULT_DISABLE_SHOW_SCORE_ONLY,
|
|
|
- RESULT_DISABLE_RANKING,
|
|
|
- ]
|
|
|
- )
|
|
|
- ) {
|
|
|
- // More than one attempt
|
|
|
- if ($num > 0) {
|
|
|
- $row_track = Database :: fetch_array($qryres);
|
|
|
- $attempt_text = get_lang('LatestAttempt').' : ';
|
|
|
- $attempt_text .= ExerciseLib::show_score(
|
|
|
- $row_track['exe_result'],
|
|
|
- $row_track['exe_weighting']
|
|
|
- );
|
|
|
- } else {
|
|
|
- //No attempts
|
|
|
- $attempt_text = get_lang('NotAttempted');
|
|
|
- }
|
|
|
- } else {
|
|
|
- $attempt_text = '-';
|
|
|
- }
|
|
|
- } else {
|
|
|
- // Quiz not ready due to time limits
|
|
|
- //@todo use the is_visible function
|
|
|
- if (!empty($row['start_time']) && !empty($row['end_time'])) {
|
|
|
- $today = time();
|
|
|
- $start_time = api_strtotime($row['start_time'], 'UTC');
|
|
|
- $end_time = api_strtotime($row['end_time'], 'UTC');
|
|
|
- if ($today < $start_time) {
|
|
|
- $attempt_text = sprintf(
|
|
|
- get_lang('ExerciseWillBeActivatedFromXToY'),
|
|
|
- api_convert_and_format_date($row['start_time']),
|
|
|
- api_convert_and_format_date($row['end_time'])
|
|
|
- );
|
|
|
- } else {
|
|
|
- if ($today > $end_time) {
|
|
|
- $attempt_text = sprintf(
|
|
|
- get_lang('ExerciseWasActivatedFromXToY'),
|
|
|
- api_convert_and_format_date($row['start_time']),
|
|
|
- api_convert_and_format_date($row['end_time'])
|
|
|
- );
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- //$attempt_text = get_lang('ExamNotAvailableAtThisTime');
|
|
|
- if (!empty($row['start_time'])) {
|
|
|
- $attempt_text = sprintf(
|
|
|
- get_lang('ExerciseAvailableFromX'),
|
|
|
- api_convert_and_format_date($row['start_time'])
|
|
|
- );
|
|
|
- }
|
|
|
- if (!empty($row['end_time'])) {
|
|
|
- $attempt_text = sprintf(
|
|
|
- get_lang('ExerciseAvailableUntilX'),
|
|
|
- api_convert_and_format_date($row['end_time'])
|
|
|
- );
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- // Normal behaviour.
|
|
|
- // Show results.
|
|
|
- if (
|
|
|
- in_array(
|
|
|
- $my_result_disabled,
|
|
|
- [
|
|
|
- RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS,
|
|
|
- RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING,
|
|
|
- RESULT_DISABLE_SHOW_SCORE_ONLY,
|
|
|
- RESULT_DISABLE_RANKING,
|
|
|
- ]
|
|
|
- )
|
|
|
- ) {
|
|
|
- if ($num > 0) {
|
|
|
- $row_track = Database :: fetch_array($qryres);
|
|
|
- $attempt_text = get_lang('LatestAttempt').' : ';
|
|
|
- $attempt_text .= ExerciseLib::show_score(
|
|
|
- $row_track['exe_result'],
|
|
|
- $row_track['exe_weighting']
|
|
|
- );
|
|
|
- } else {
|
|
|
- $attempt_text = get_lang('NotAttempted');
|
|
|
- }
|
|
|
- } else {
|
|
|
- $attempt_text = '-';
|
|
|
- }
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * Select N values from the questions per category array.
|
|
|
+ *
|
|
|
+ * @param array $categoriesAddedInExercise
|
|
|
+ * @param array $question_list
|
|
|
+ * @param array $questions_by_category per category
|
|
|
+ * @param bool $flatResult
|
|
|
+ * @param bool $randomizeQuestions
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ private function pickQuestionsPerCategory(
|
|
|
+ $categoriesAddedInExercise,
|
|
|
+ $question_list,
|
|
|
+ &$questions_by_category,
|
|
|
+ $flatResult = true,
|
|
|
+ $randomizeQuestions = false
|
|
|
+ ) {
|
|
|
+ $addAll = true;
|
|
|
+ $categoryCountArray = [];
|
|
|
|
|
|
- $class_tip = '';
|
|
|
- if (empty($num)) {
|
|
|
- $num = '';
|
|
|
- } else {
|
|
|
- $class_tip = 'link_tooltip';
|
|
|
- //@todo use sprintf and show the results validated by the teacher
|
|
|
- if ($num == 1) {
|
|
|
- $num = $num.' '.get_lang('Result');
|
|
|
- } else {
|
|
|
- $num = $num.' '.get_lang('Results');
|
|
|
- }
|
|
|
- $num = '<span class="tooltip" style="display: none;">'.$num.'</span>';
|
|
|
- }
|
|
|
+ // Getting how many questions will be selected per category.
|
|
|
+ if (!empty($categoriesAddedInExercise)) {
|
|
|
+ $addAll = false;
|
|
|
+ // Parsing question according the category rel exercise settings
|
|
|
+ foreach ($categoriesAddedInExercise as $category_info) {
|
|
|
+ $category_id = $category_info['category_id'];
|
|
|
+ if (isset($questions_by_category[$category_id])) {
|
|
|
+ // How many question will be picked from this category.
|
|
|
+ $count = $category_info['count_questions'];
|
|
|
+ // -1 means all questions
|
|
|
+ $categoryCountArray[$category_id] = $count;
|
|
|
+ if ($count == -1) {
|
|
|
+ $categoryCountArray[$category_id] = 999;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- $item .= Display::tag('td', $attempt_text);
|
|
|
+ if (!empty($questions_by_category)) {
|
|
|
+ $temp_question_list = [];
|
|
|
+ foreach ($questions_by_category as $category_id => &$categoryQuestionList) {
|
|
|
+ if (isset($categoryCountArray) && !empty($categoryCountArray)) {
|
|
|
+ $numberOfQuestions = 0;
|
|
|
+ if (isset($categoryCountArray[$category_id])) {
|
|
|
+ $numberOfQuestions = $categoryCountArray[$category_id];
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- if ($is_allowedToEdit) {
|
|
|
- $additionalActions = ExerciseLib::getAdditionalTeacherActions($row['id']);
|
|
|
+ if ($addAll) {
|
|
|
+ $numberOfQuestions = 999;
|
|
|
+ }
|
|
|
|
|
|
- if (!empty($additionalActions)) {
|
|
|
- $actions .= $additionalActions.PHP_EOL;
|
|
|
- }
|
|
|
+ if (!empty($numberOfQuestions)) {
|
|
|
+ $elements = TestCategory::getNElementsFromArray(
|
|
|
+ $categoryQuestionList,
|
|
|
+ $numberOfQuestions,
|
|
|
+ $randomizeQuestions
|
|
|
+ );
|
|
|
|
|
|
- $item .= Display::tag('td', $actions, ['class' => 'td_actions']);
|
|
|
- } else {
|
|
|
- if ($isDrhOfCourse) {
|
|
|
- $actions = '<a href="exercise_report.php?'.api_get_cidreq().'&exerciseId='.$row['id'].'">'.
|
|
|
- Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
- $item .= Display::tag('td', $actions, ['class' => 'td_actions']);
|
|
|
- }
|
|
|
+ if (!empty($elements)) {
|
|
|
+ $temp_question_list[$category_id] = $elements;
|
|
|
+ $categoryQuestionList = $elements;
|
|
|
}
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($temp_question_list)) {
|
|
|
+ if ($flatResult) {
|
|
|
+ $temp_question_list = array_flatten($temp_question_list);
|
|
|
+ }
|
|
|
+ $question_list = $temp_question_list;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return $question_list;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Changes the exercise id.
|
|
|
+ *
|
|
|
+ * @param int $id - exercise id
|
|
|
+ */
|
|
|
+ private function updateId($id)
|
|
|
+ {
|
|
|
+ $this->id = $id;
|
|
|
+ }
|
|
|
|
|
|
- $tableRows[] = Display::tag(
|
|
|
- 'tr',
|
|
|
- $item,
|
|
|
- [
|
|
|
- 'id' => 'exercise_list_'.$my_exercise_id,
|
|
|
- ]
|
|
|
- );
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * Sends a notification when a user ends an examn.
|
|
|
+ *
|
|
|
+ * @param array $question_list_answers
|
|
|
+ * @param string $origin
|
|
|
+ * @param array $user_info
|
|
|
+ * @param string $url_email
|
|
|
+ * @param array $teachers
|
|
|
+ */
|
|
|
+ private function sendNotificationForOpenQuestions(
|
|
|
+ $question_list_answers,
|
|
|
+ $origin,
|
|
|
+ $user_info,
|
|
|
+ $url_email,
|
|
|
+ $teachers
|
|
|
+ ) {
|
|
|
+ // Email configuration settings
|
|
|
+ $courseCode = api_get_course_id();
|
|
|
+ $courseInfo = api_get_course_info($courseCode);
|
|
|
+ $sessionId = api_get_session_id();
|
|
|
+ $sessionData = '';
|
|
|
+ if (!empty($sessionId)) {
|
|
|
+ $sessionInfo = api_get_session_info($sessionId);
|
|
|
+ if (!empty($sessionInfo)) {
|
|
|
+ $sessionData = '<tr>'
|
|
|
+ .'<td><em>'.get_lang('SessionName').'</em></td>'
|
|
|
+ .'<td> <b>'.$sessionInfo['name'].'</b></td>'
|
|
|
+ .'</tr>';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // end exercise list
|
|
|
- // Hotpotatoes results
|
|
|
- $hotpotatoes_exist = false;
|
|
|
+ $msg = get_lang('OpenQuestionsAttempted').'<br /><br />'
|
|
|
+ .get_lang('AttemptDetails').' : <br /><br />'
|
|
|
+ .'<table>'
|
|
|
+ .'<tr>'
|
|
|
+ .'<td><em>'.get_lang('CourseName').'</em></td>'
|
|
|
+ .'<td> <b>#course#</b></td>'
|
|
|
+ .'</tr>'
|
|
|
+ .$sessionData
|
|
|
+ .'<tr>'
|
|
|
+ .'<td>'.get_lang('TestAttempted').'</td>'
|
|
|
+ .'<td> #exercise#</td>'
|
|
|
+ .'</tr>'
|
|
|
+ .'<tr>'
|
|
|
+ .'<td>'.get_lang('StudentName').'</td>'
|
|
|
+ .'<td> #firstName# #lastName#</td>'
|
|
|
+ .'</tr>'
|
|
|
+ .'<tr>'
|
|
|
+ .'<td>'.get_lang('StudentEmail').'</td>'
|
|
|
+ .'<td> #mail#</td>'
|
|
|
+ .'</tr>'
|
|
|
+ .'</table>';
|
|
|
|
|
|
- if ($is_allowedToEdit) {
|
|
|
- $sql = "SELECT d.iid, d.path as path, d.comment as comment
|
|
|
- FROM $TBL_DOCUMENT d
|
|
|
- WHERE
|
|
|
- d.c_id = $courseId AND
|
|
|
- (d.path LIKE '%htm%') AND
|
|
|
- d.path LIKE '".Database :: escape_string($uploadPath.'/%/%')."'
|
|
|
- LIMIT ".$from.",".$limit; // only .htm or .html files listed
|
|
|
- } else {
|
|
|
- $sql = "SELECT d.iid, d.path as path, d.comment as comment
|
|
|
- FROM $TBL_DOCUMENT d
|
|
|
- WHERE
|
|
|
- d.c_id = $courseId AND
|
|
|
- (d.path LIKE '%htm%') AND
|
|
|
- d.path LIKE '".Database :: escape_string($uploadPath.'/%/%')."'
|
|
|
- LIMIT ".$from.",".$limit;
|
|
|
- }
|
|
|
+ $open_question_list = null;
|
|
|
+ foreach ($question_list_answers as $item) {
|
|
|
+ $question = $item['question'];
|
|
|
+ $answer = $item['answer'];
|
|
|
+ $answer_type = $item['answer_type'];
|
|
|
|
|
|
- $result = Database::query($sql);
|
|
|
- $attribute = [];
|
|
|
- while ($row = Database :: fetch_array($result, 'ASSOC')) {
|
|
|
- $attribute['id'][] = $row['iid'];
|
|
|
- $attribute['path'][] = $row['path'];
|
|
|
- $attribute['comment'][] = $row['comment'];
|
|
|
+ if (!empty($question) && !empty($answer) && $answer_type == FREE_ANSWER) {
|
|
|
+ $open_question_list .=
|
|
|
+ '<tr>'
|
|
|
+ .'<td width="220" valign="top" bgcolor="#E5EDF8"> '.get_lang('Question').'</td>'
|
|
|
+ .'<td width="473" valign="top" bgcolor="#F3F3F3">'.$question.'</td>'
|
|
|
+ .'</tr>'
|
|
|
+ .'<tr>'
|
|
|
+ .'<td width="220" valign="top" bgcolor="#E5EDF8"> '.get_lang('Answer').'</td>'
|
|
|
+ .'<td valign="top" bgcolor="#F3F3F3">'.$answer.'</td>'
|
|
|
+ .'</tr>';
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- $nbrActiveTests = 0;
|
|
|
- if (isset($attribute['path']) && is_array($attribute['path'])) {
|
|
|
- $hotpotatoes_exist = true;
|
|
|
- foreach ($attribute['path'] as $key => $path) {
|
|
|
- $item = '';
|
|
|
- $title = GetQuizName($path, $documentPath);
|
|
|
- if ($title == '') {
|
|
|
- $title = basename($path);
|
|
|
- }
|
|
|
-
|
|
|
- // prof only
|
|
|
- if ($is_allowedToEdit) {
|
|
|
- $visibility = api_get_item_visibility(
|
|
|
- ['real_id' => $courseId],
|
|
|
- TOOL_DOCUMENT,
|
|
|
- $attribute['id'][$key],
|
|
|
- 0
|
|
|
- );
|
|
|
+ if (!empty($open_question_list)) {
|
|
|
+ $msg .= '<p><br />'.get_lang('OpenQuestionsAttemptedAre').' :</p>'.
|
|
|
+ '<table width="730" height="136" border="0" cellpadding="3" cellspacing="3">';
|
|
|
+ $msg .= $open_question_list;
|
|
|
+ $msg .= '</table><br />';
|
|
|
|
|
|
- if (!empty($sessionId)) {
|
|
|
- if (0 == $visibility) {
|
|
|
- continue;
|
|
|
- }
|
|
|
+ $msg = str_replace('#exercise#', $this->exercise, $msg);
|
|
|
+ $msg = str_replace('#firstName#', $user_info['firstname'], $msg);
|
|
|
+ $msg = str_replace('#lastName#', $user_info['lastname'], $msg);
|
|
|
+ $msg = str_replace('#mail#', $user_info['email'], $msg);
|
|
|
+ $msg = str_replace(
|
|
|
+ '#course#',
|
|
|
+ Display::url($courseInfo['title'], $courseInfo['course_public_url'].'?id_session='.$sessionId),
|
|
|
+ $msg
|
|
|
+ );
|
|
|
|
|
|
- $visibility = api_get_item_visibility(
|
|
|
- ['real_id' => $courseId],
|
|
|
- TOOL_DOCUMENT,
|
|
|
- $attribute['id'][$key],
|
|
|
- $sessionId
|
|
|
- );
|
|
|
- }
|
|
|
+ if ($origin != 'learnpath') {
|
|
|
+ $msg .= '<br /><a href="#url#">'.get_lang('ClickToCommentAndGiveFeedback').'</a>';
|
|
|
+ }
|
|
|
+ $msg = str_replace('#url#', $url_email, $msg);
|
|
|
+ $subject = get_lang('OpenQuestionsAttempted');
|
|
|
|
|
|
- $item = Display::tag(
|
|
|
- 'td',
|
|
|
- implode(PHP_EOL, [
|
|
|
- Display::return_icon('hotpotatoes_s.png', "HotPotatoes"),
|
|
|
- Display::url(
|
|
|
- $title,
|
|
|
- 'showinframes.php?'.api_get_cidreq().'&'.http_build_query([
|
|
|
- 'file' => $path,
|
|
|
- 'uid' => $userId,
|
|
|
- ]),
|
|
|
- ['class' => $visibility == 0 ? 'text-muted' : null]
|
|
|
- ),
|
|
|
- ])
|
|
|
+ if (!empty($teachers)) {
|
|
|
+ foreach ($teachers as $user_id => $teacher_data) {
|
|
|
+ MessageManager::send_message_simple(
|
|
|
+ $user_id,
|
|
|
+ $subject,
|
|
|
+ $msg
|
|
|
);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- $item .= Display::tag('td', '-');
|
|
|
+ /**
|
|
|
+ * Send notification for oral questions.
|
|
|
+ *
|
|
|
+ * @param array $question_list_answers
|
|
|
+ * @param string $origin
|
|
|
+ * @param int $exe_id
|
|
|
+ * @param array $user_info
|
|
|
+ * @param string $url_email
|
|
|
+ * @param array $teachers
|
|
|
+ */
|
|
|
+ private function sendNotificationForOralQuestions(
|
|
|
+ $question_list_answers,
|
|
|
+ $origin,
|
|
|
+ $exe_id,
|
|
|
+ $user_info,
|
|
|
+ $url_email,
|
|
|
+ $teachers
|
|
|
+ ) {
|
|
|
+ // Email configuration settings
|
|
|
+ $courseCode = api_get_course_id();
|
|
|
+ $courseInfo = api_get_course_info($courseCode);
|
|
|
+ $oral_question_list = null;
|
|
|
+ foreach ($question_list_answers as $item) {
|
|
|
+ $question = $item['question'];
|
|
|
+ $file = $item['generated_oral_file'];
|
|
|
+ $answer = $item['answer'];
|
|
|
+ if ($answer == 0) {
|
|
|
+ $answer = '';
|
|
|
+ }
|
|
|
+ $answer_type = $item['answer_type'];
|
|
|
+ if (!empty($question) && (!empty($answer) || !empty($file)) && $answer_type == ORAL_EXPRESSION) {
|
|
|
+ if (!empty($file)) {
|
|
|
+ $file = Display::url($file, $file);
|
|
|
+ }
|
|
|
+ $oral_question_list .= '<br />
|
|
|
+ <table width="730" height="136" border="0" cellpadding="3" cellspacing="3">
|
|
|
+ <tr>
|
|
|
+ <td width="220" valign="top" bgcolor="#E5EDF8"> '.get_lang('Question').'</td>
|
|
|
+ <td width="473" valign="top" bgcolor="#F3F3F3">'.$question.'</td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td width="220" valign="top" bgcolor="#E5EDF8"> '.get_lang('Answer').'</td>
|
|
|
+ <td valign="top" bgcolor="#F3F3F3">'.$answer.$file.'</td>
|
|
|
+ </tr></table>';
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- $actions = Display::url(
|
|
|
- Display::return_icon(
|
|
|
- 'edit.png',
|
|
|
- get_lang('Edit'),
|
|
|
- '',
|
|
|
- ICON_SIZE_SMALL
|
|
|
- ),
|
|
|
- 'adminhp.php?'.api_get_cidreq().'&hotpotatoesName='.$path
|
|
|
- );
|
|
|
+ if (!empty($oral_question_list)) {
|
|
|
+ $msg = get_lang('OralQuestionsAttempted').'<br /><br />
|
|
|
+ '.get_lang('AttemptDetails').' : <br /><br />
|
|
|
+ <table>
|
|
|
+ <tr>
|
|
|
+ <td><em>'.get_lang('CourseName').'</em></td>
|
|
|
+ <td> <b>#course#</b></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>'.get_lang('TestAttempted').'</td>
|
|
|
+ <td> #exercise#</td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>'.get_lang('StudentName').'</td>
|
|
|
+ <td> #firstName# #lastName#</td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>'.get_lang('StudentEmail').'</td>
|
|
|
+ <td> #mail#</td>
|
|
|
+ </tr>
|
|
|
+ </table>';
|
|
|
+ $msg .= '<br />'.sprintf(get_lang('OralQuestionsAttemptedAreX'), $oral_question_list).'<br />';
|
|
|
+ $msg1 = str_replace("#exercise#", $this->exercise, $msg);
|
|
|
+ $msg = str_replace("#firstName#", $user_info['firstname'], $msg1);
|
|
|
+ $msg1 = str_replace("#lastName#", $user_info['lastname'], $msg);
|
|
|
+ $msg = str_replace("#mail#", $user_info['email'], $msg1);
|
|
|
+ $msg = str_replace("#course#", $courseInfo['name'], $msg1);
|
|
|
+
|
|
|
+ if (!in_array($origin, ['learnpath', 'embeddable'])) {
|
|
|
+ $msg .= '<br /><a href="#url#">'.get_lang('ClickToCommentAndGiveFeedback').'</a>';
|
|
|
+ }
|
|
|
+ $msg1 = str_replace("#url#", $url_email, $msg);
|
|
|
+ $mail_content = $msg1;
|
|
|
+ $subject = get_lang('OralQuestionsAttempted');
|
|
|
|
|
|
- $actions .= '<a href="hotpotatoes_exercise_report.php?'.api_get_cidreq().'&path='.$path.'">'.
|
|
|
- Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
+ if (!empty($teachers)) {
|
|
|
+ foreach ($teachers as $user_id => $teacher_data) {
|
|
|
+ MessageManager::send_message_simple(
|
|
|
+ $user_id,
|
|
|
+ $subject,
|
|
|
+ $mail_content
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // if active
|
|
|
- if ($visibility != 0) {
|
|
|
- $nbrActiveTests = $nbrActiveTests + 1;
|
|
|
- $actions .= ' <a href="'.$exercisePath.'?'.api_get_cidreq().'&hpchoice=disable&page='.$page.'&file='.$path.'">'.
|
|
|
- Display::return_icon('visible.png', get_lang('Deactivate'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
- } else { // else if not active
|
|
|
- $actions .= ' <a href="'.$exercisePath.'?'.api_get_cidreq().'&hpchoice=enable&page='.$page.'&file='.$path.'">'.
|
|
|
- Display::return_icon('invisible.png', get_lang('Activate'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
- }
|
|
|
- $actions .= '<a href="'.$exercisePath.'?'.api_get_cidreq().'&hpchoice=delete&file='.$path.'" onclick="javascript:if(!confirm(\''.addslashes(api_htmlentities(get_lang('AreYouSureToDeleteJS'), ENT_QUOTES, $charset).' '.$title."?").'\')) return false;">'.
|
|
|
- Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
- $item .= Display::tag('td', $actions);
|
|
|
- $tableRows[] = Display::tag('tr', $item);
|
|
|
+ /**
|
|
|
+ * Returns an array with the media list.
|
|
|
+ *
|
|
|
+ * @param array question list
|
|
|
+ *
|
|
|
+ * @example there's 1 question with iid 5 that belongs to the media question with iid = 100
|
|
|
+ * <code>
|
|
|
+ * array (size=2)
|
|
|
+ * 999 =>
|
|
|
+ * array (size=3)
|
|
|
+ * 0 => int 7
|
|
|
+ * 1 => int 6
|
|
|
+ * 2 => int 3254
|
|
|
+ * 100 =>
|
|
|
+ * array (size=1)
|
|
|
+ * 0 => int 5
|
|
|
+ * </code>
|
|
|
+ */
|
|
|
+ private function setMediaList($questionList)
|
|
|
+ {
|
|
|
+ $mediaList = [];
|
|
|
+ /*
|
|
|
+ * Media feature is not activated in 1.11.x
|
|
|
+ if (!empty($questionList)) {
|
|
|
+ foreach ($questionList as $questionId) {
|
|
|
+ $objQuestionTmp = Question::read($questionId, $this->course_id);
|
|
|
+ // If a media question exists
|
|
|
+ if (isset($objQuestionTmp->parent_id) && $objQuestionTmp->parent_id != 0) {
|
|
|
+ $mediaList[$objQuestionTmp->parent_id][] = $objQuestionTmp->id;
|
|
|
} else {
|
|
|
- $visibility = api_get_item_visibility(
|
|
|
- ['real_id' => $courseId],
|
|
|
- TOOL_DOCUMENT,
|
|
|
- $attribute['id'][$key],
|
|
|
- $sessionId
|
|
|
- );
|
|
|
+ // Always the last item
|
|
|
+ $mediaList[999][] = $objQuestionTmp->id;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }*/
|
|
|
|
|
|
- if (0 == $visibility) {
|
|
|
- continue;
|
|
|
- }
|
|
|
+ $this->mediaList = $mediaList;
|
|
|
+ }
|
|
|
|
|
|
- // Student only
|
|
|
- $attempt = ExerciseLib::getLatestHotPotatoResult(
|
|
|
- $path,
|
|
|
- $userId,
|
|
|
- api_get_course_int_id(),
|
|
|
- api_get_session_id()
|
|
|
- );
|
|
|
+ /**
|
|
|
+ * @param FormValidator $form
|
|
|
+ *
|
|
|
+ * @return HTML_QuickForm_group
|
|
|
+ */
|
|
|
+ private function setResultDisabledGroup(FormValidator $form)
|
|
|
+ {
|
|
|
+ $resultDisabledGroup = [];
|
|
|
|
|
|
- $nbrActiveTests = $nbrActiveTests + 1;
|
|
|
- $item .= Display::tag(
|
|
|
- 'td',
|
|
|
- Display::url(
|
|
|
- $title,
|
|
|
- 'showinframes.php?'.api_get_cidreq().'&'.http_build_query([
|
|
|
- 'file' => $path,
|
|
|
- 'cid' => api_get_course_id(),
|
|
|
- 'uid' => $userId,
|
|
|
- ])
|
|
|
- )
|
|
|
- );
|
|
|
+ $resultDisabledGroup[] = $form->createElement(
|
|
|
+ 'radio',
|
|
|
+ 'results_disabled',
|
|
|
+ null,
|
|
|
+ get_lang('ShowScoreAndRightAnswer'),
|
|
|
+ '0',
|
|
|
+ ['id' => 'result_disabled_0']
|
|
|
+ );
|
|
|
|
|
|
- if (!empty($attempt)) {
|
|
|
- $actions = '<a href="hotpotatoes_exercise_report.php?'.api_get_cidreq().'&path='.$path.'&filter_by_user='.$userId.'">'.Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
- $attemptText = get_lang('LatestAttempt').' : ';
|
|
|
- $attemptText .= ExerciseLib::show_score(
|
|
|
- $attempt['exe_result'],
|
|
|
- $attempt['exe_weighting']
|
|
|
- ).' ';
|
|
|
- $attemptText .= $actions;
|
|
|
- } else {
|
|
|
- // No attempts.
|
|
|
- $attemptText = get_lang('NotAttempted').' ';
|
|
|
- }
|
|
|
+ $resultDisabledGroup[] = $form->createElement(
|
|
|
+ 'radio',
|
|
|
+ 'results_disabled',
|
|
|
+ null,
|
|
|
+ get_lang('DoNotShowScoreNorRightAnswer'),
|
|
|
+ '1',
|
|
|
+ ['id' => 'result_disabled_1', 'onclick' => 'check_results_disabled()']
|
|
|
+ );
|
|
|
|
|
|
- $item .= Display::tag('td', $attemptText);
|
|
|
+ $resultDisabledGroup[] = $form->createElement(
|
|
|
+ 'radio',
|
|
|
+ 'results_disabled',
|
|
|
+ null,
|
|
|
+ get_lang('OnlyShowScore'),
|
|
|
+ '2',
|
|
|
+ ['id' => 'result_disabled_2', 'onclick' => 'check_results_disabled()']
|
|
|
+ );
|
|
|
|
|
|
- if ($isDrhOfCourse) {
|
|
|
- $actions = '<a href="hotpotatoes_exercise_report.php?'.api_get_cidreq().'&path='.$path.'">'.
|
|
|
- Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
|
|
|
+ if ($this->selectFeedbackType() == EXERCISE_FEEDBACK_TYPE_DIRECT) {
|
|
|
+ $group = $form->addGroup(
|
|
|
+ $resultDisabledGroup,
|
|
|
+ null,
|
|
|
+ get_lang('ShowResultsToStudents')
|
|
|
+ );
|
|
|
|
|
|
- $item .= Display::tag(
|
|
|
- 'td',
|
|
|
- $actions,
|
|
|
- ['class' => 'td_actions']
|
|
|
- );
|
|
|
- }
|
|
|
- $tableRows[] = Display::tag('tr', $item);
|
|
|
- }
|
|
|
- }
|
|
|
+ return $group;
|
|
|
}
|
|
|
|
|
|
- if (empty($tableRows)) {
|
|
|
- if ($is_allowedToEdit && $origin != 'learnpath') {
|
|
|
- $content .= '<div id="no-data-view">';
|
|
|
- $content .= '<h3>'.get_lang('Quiz').'</h3>';
|
|
|
- $content .= Display::return_icon('quiz.png', '', [], 64);
|
|
|
- $content .= '<div class="controls">';
|
|
|
- $content .= Display::url(
|
|
|
- '<em class="fa fa-plus"></em> '.get_lang('NewEx'),
|
|
|
- 'exercise_admin.php?'.api_get_cidreq(),
|
|
|
- ['class' => 'btn btn-primary']
|
|
|
- );
|
|
|
- $content .= '</div>';
|
|
|
- $content .= '</div>';
|
|
|
- }
|
|
|
- } else {
|
|
|
- if ($is_allowedToEdit) {
|
|
|
- $headers = [
|
|
|
- get_lang('ExerciseName'),
|
|
|
- get_lang('QuantityQuestions'),
|
|
|
- get_lang('Actions'),
|
|
|
- ];
|
|
|
- } else {
|
|
|
- $headers = [
|
|
|
- get_lang('ExerciseName'),
|
|
|
- get_lang('Status'),
|
|
|
- ];
|
|
|
+ $resultDisabledGroup[] = $form->createElement(
|
|
|
+ 'radio',
|
|
|
+ 'results_disabled',
|
|
|
+ null,
|
|
|
+ get_lang('ShowScoreEveryAttemptShowAnswersLastAttempt'),
|
|
|
+ '4',
|
|
|
+ ['id' => 'result_disabled_4']
|
|
|
+ );
|
|
|
|
|
|
- if ($isDrhOfCourse) {
|
|
|
- $headers[] = get_lang('Actions');
|
|
|
- }
|
|
|
- }
|
|
|
+ $resultDisabledGroup[] = $form->createElement(
|
|
|
+ 'radio',
|
|
|
+ 'results_disabled',
|
|
|
+ null,
|
|
|
+ get_lang('DontShowScoreOnlyWhenUserFinishesAllAttemptsButShowFeedbackEachAttempt'),
|
|
|
+ '5',
|
|
|
+ ['id' => 'result_disabled_5', 'onclick' => 'check_results_disabled()']
|
|
|
+ );
|
|
|
|
|
|
- foreach ($tableRows as $roz) {
|
|
|
- echo $roz;
|
|
|
- }
|
|
|
-var_dump($tableRows);
|
|
|
- $content .= '<div class="table-responsive">';
|
|
|
- $table = new SortableTableFromArrayConfig(
|
|
|
- $tableRows,
|
|
|
- 1,
|
|
|
- 20,
|
|
|
- 'exercises'
|
|
|
- );
|
|
|
- $i = 0;
|
|
|
- foreach ($headers as $header) {
|
|
|
- $table->set_header($i++, $header);
|
|
|
- }
|
|
|
- $table->set_header($i++, 'aa');
|
|
|
+ $resultDisabledGroup[] = $form->createElement(
|
|
|
+ 'radio',
|
|
|
+ 'results_disabled',
|
|
|
+ null,
|
|
|
+ get_lang('ExerciseRankingMode'),
|
|
|
+ RESULT_DISABLE_RANKING,
|
|
|
+ ['id' => 'result_disabled_6']
|
|
|
+ );
|
|
|
|
|
|
- $content .= $table->return_table();
|
|
|
- $content .= '</div>';
|
|
|
- }
|
|
|
+ $resultDisabledGroup[] = $form->createElement(
|
|
|
+ 'radio',
|
|
|
+ 'results_disabled',
|
|
|
+ null,
|
|
|
+ get_lang('ExerciseShowOnlyGlobalScoreAndCorrectAnswers'),
|
|
|
+ RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER,
|
|
|
+ ['id' => 'result_disabled_7']
|
|
|
+ );
|
|
|
|
|
|
- return $content;
|
|
|
+ $resultDisabledGroup[] = $form->createElement(
|
|
|
+ 'radio',
|
|
|
+ 'results_disabled',
|
|
|
+ null,
|
|
|
+ get_lang('ExerciseAutoEvaluationAndRankingMode'),
|
|
|
+ RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING,
|
|
|
+ ['id' => 'result_disabled_8']
|
|
|
+ );
|
|
|
+
|
|
|
+ $group = $form->addGroup(
|
|
|
+ $resultDisabledGroup,
|
|
|
+ null,
|
|
|
+ get_lang('ShowResultsToStudents')
|
|
|
+ );
|
|
|
+
|
|
|
+ return $group;
|
|
|
}
|
|
|
}
|