diff --git a/main/exercise/MultipleAnswerTrueFalseDegreeCertainty.php b/main/exercise/MultipleAnswerTrueFalseDegreeCertainty.php index 2db792414c..b1583861b4 100644 --- a/main/exercise/MultipleAnswerTrueFalseDegreeCertainty.php +++ b/main/exercise/MultipleAnswerTrueFalseDegreeCertainty.php @@ -1097,10 +1097,14 @@ class MultipleAnswerTrueFalseDegreeCertainty extends Question } // get student answer option id - $studentAnswerOptionId = $splitAnswer[1]; + $studentAnswerOptionId = isset($splitAnswer[1]) ? $splitAnswer[1] : null; // we got the correct answer option id, let's compare ti with the student answer - $percentage = self::getPercentagePosition($splitAnswer[2]); + $percentage = null; + if (isset($splitAnswer[2])) { + $percentage = self::getPercentagePosition($splitAnswer[2]); + } + if ($studentAnswerOptionId == $correctAnswerOptionId) { // yeah, student got correct answer switch ($percentage) { @@ -1199,6 +1203,7 @@ class MultipleAnswerTrueFalseDegreeCertainty extends Question $and = ''; $questionId = (int) $questionId; $position = (int) $position; + $exeId = (int) $exeId; if ($questionId >= 0) { $and .= " AND question_id = $questionId"; diff --git a/main/exercise/exercise.class.php b/main/exercise/exercise.class.php index a1ad081824..0fa3bb18ec 100755 --- a/main/exercise/exercise.class.php +++ b/main/exercise/exercise.class.php @@ -3318,6 +3318,7 @@ class Exercise * @param int $propagate_neg * @param array $hotspot_delineation_result * @param bool $showTotalScoreAndUserChoicesInLastAttempt + * @param bool $updateResults * * @todo reduce parameters of this function * @@ -3334,7 +3335,8 @@ class Exercise $show_result = true, $propagate_neg = 0, $hotspot_delineation_result = [], - $showTotalScoreAndUserChoicesInLastAttempt = true + $showTotalScoreAndUserChoicesInLastAttempt = true, + $updateResults = false ) { $debug = false; //needed in order to use in the exercise_attempt() for the time @@ -3425,8 +3427,8 @@ class Exercise if ($answerType == MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY) { $choiceTmp = $choice; - $choice = $choiceTmp["choice"]; - $choiceDegreeCertainty = $choiceTmp["choiceDegreeCertainty"]; + $choice = isset($choiceTmp['choice']) ? $choiceTmp['choice'] : ''; + $choiceDegreeCertainty = isset($choiceTmp['choiceDegreeCertainty']) ? $choiceTmp['choiceDegreeCertainty'] : ''; } if ($answerType == FREE_ANSWER || @@ -5650,11 +5652,12 @@ class Exercise Event::saveQuestionAttempt( $questionScore, $chosenAnswer.':'.$choice[$chosenAnswer].':'. - $choiceDegreeCertainty[$answerDegreeCertainty], + $choiceDegreeCertainty[$answerDegreeCertainty], $quesId, $exeId, $i, - $this->id + $this->id, + $updateResults ); } } else { @@ -5664,7 +5667,8 @@ class Exercise $quesId, $exeId, $i, - $this->id + $this->id, + $updateResults ); } if ($debug) { diff --git a/main/exercise/fill_blanks.class.php b/main/exercise/fill_blanks.class.php index 49a9a5ae1b..0a9d99e49d 100755 --- a/main/exercise/fill_blanks.class.php +++ b/main/exercise/fill_blanks.class.php @@ -991,10 +991,19 @@ class FillBlanks extends Question // lets rebuild the sentence with [correct answer][student answer][answer is correct] $result = ''; for ($i = 0; $i < count($listWithStudentAnswer['common_words']) - 1; $i++) { + $answerValue = null; + if (isset($listWithStudentAnswer['student_answer'][$i])) { + $answerValue = $listWithStudentAnswer['student_answer'][$i]; + } + $scoreValue = null; + if (isset($listWithStudentAnswer['student_score'][$i])) { + $scoreValue = $listWithStudentAnswer['student_score'][$i]; + } + $result .= $listWithStudentAnswer['common_words'][$i]; $result .= $listWithStudentAnswer['words_with_bracket'][$i]; - $result .= $separatorStart.$listWithStudentAnswer['student_answer'][$i].$separatorEnd; - $result .= $separatorStart.$listWithStudentAnswer['student_score'][$i].$separatorEnd; + $result .= $separatorStart.$answerValue.$separatorEnd; + $result .= $separatorStart.$scoreValue.$separatorEnd; } $result .= $listWithStudentAnswer['common_words'][$i]; $result .= '::'; diff --git a/main/exercise/recalculate.php b/main/exercise/recalculate.php index b40ef7a4b0..e04788b989 100644 --- a/main/exercise/recalculate.php +++ b/main/exercise/recalculate.php @@ -1,69 +1,106 @@ getRepository('ChamiloCoreBundle:TrackEExercises') - ->find(intval($_REQUEST['id'])); +/** @var TrackEExercises $trackedExercise */ +$trackedExercise = $em->getRepository('ChamiloCoreBundle:TrackEExercises')->find($_REQUEST['id']); -if ($trackedExercise->getExeUserId() != intval($_REQUEST['user']) || - $trackedExercise->getExeExoId() != intval($_REQUEST['exercise']) -) { - api_not_allowed(true); +if (empty($trackedExercise)) { exit; } -$attempts = $em->getRepository('ChamiloCoreBundle:TrackEAttempt') - ->findBy([ - 'exeId' => $trackedExercise->getExeId(), - 'userId' => $trackedExercise->getExeUserId(), - ]); +$studentId = $trackedExercise->getExeUserId(); +$exerciseId = $trackedExercise->getExeExoId(); +$exeId = $trackedExercise->getExeId(); -$newResult = 0; -/** @var \Chamilo\CoreBundle\Entity\TrackEAttempt $attempt */ -foreach ($attempts as $attempt) { - $questionId = $attempt->getQuestionId(); +if ($studentId != intval($_REQUEST['user']) || + $exerciseId != intval($_REQUEST['exercise']) +) { + exit; +} - $question = $em->find('ChamiloCourseBundle:CQuizQuestion', $questionId); +$questionList = $trackedExercise->getDataTracking(); - if (!$question) { - continue; - } +if (empty($questionList)) { + exit; +} - $answers = $em->getRepository('ChamiloCourseBundle:CQuizAnswer')->findBy([ - 'questionId' => $questionId, - 'correct' => 1, - ]); - - $newMarks = 0; - foreach ($answers as $answer) { - if ($answer->getId() != $attempt->getAnswer()) { - continue; - } - $newMarks += $answer->getPonderation(); +$questionList = explode(',', $questionList); + +$exercise = new Exercise($courseId); +$exercise->read($exerciseId); +$totalScore = 0; +$totalWeight = 0; + +foreach ($questionList as $questionId) { + $question = Question::read($questionId, $courseId); + $totalWeight += $question->selectWeighting(); + + // We're inside *one* question. Go through each possible answer for this question + if ($question->type === MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY) { + $result = $exercise->manage_answer( + $exeId, + $questionId, + [], + 'exercise_result', + [], + false, + true, + false, + $exercise->selectPropagateNeg(), + [], + [], + true + ); + } else { + $result = $exercise->manage_answer( + $exeId, + $questionId, + [], + 'exercise_result', + [], + false, + true, + false, + $exercise->selectPropagateNeg(), + [], + [], + true + ); } - $newResult += $newMarks; - $attempt->setMarks($newMarks); - $em->merge($attempt); + // Adding the new score. + $totalScore += $result['score']; } -$trackedExercise->setScore($newResult); +$remindList = $trackedExercise->getQuestionsToCheck(); +if (!empty($remindList)) { + $remindList = explode(',', $remindList); +} + +$table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); + +$sql = "UPDATE $table SET + exe_result = '$totalScore', + exe_weighting = '$totalWeight' + WHERE exe_id = $exeId"; +Database::query($sql); -$em->merge($trackedExercise); -$em->flush(); +echo $totalScore.'/'.$totalWeight; diff --git a/main/forum/forumfunction.inc.php b/main/forum/forumfunction.inc.php index f2d564faf9..2b1bd2b6e7 100755 --- a/main/forum/forumfunction.inc.php +++ b/main/forum/forumfunction.inc.php @@ -670,7 +670,7 @@ function store_forumcategory($values, $courseInfo = [], $showMessage = true) function store_forum($values, $courseInfo = [], $returnId = false) { $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo; - $course_id = $courseInfo['real_id']; + $courseId = $courseInfo['real_id']; $session_id = api_get_session_id(); $group_id = api_get_group_id(); if (isset($values['group_id']) && !empty($values['group_id'])) { @@ -690,7 +690,7 @@ function store_forum($values, $courseInfo = [], $returnId = false) $sql = "SELECT MAX(forum_order) as sort_max FROM $table_forums WHERE - c_id = $course_id AND + c_id = $courseId AND forum_category='".Database::escape_string($values['forum_category'])."'"; $result = Database::query($sql); $row = Database::fetch_array($result); @@ -770,10 +770,62 @@ function store_forum($values, $courseInfo = [], $returnId = false) delete_forum_image($values['forum_id']); } + // Move groups from one group to another + if (isset($values['group_forum'])) { + $forumData = get_forums($values['forum_id']); + $currentGroupId = $forumData['forum_of_group']; + if ($currentGroupId != $values['group_forum']) { + $threads = get_threads($values['forum_id']); + $toGroupId = 'NULL'; + if (!empty($values['group_forum'])) { + $toGroupId = $values['group_forum']; + } + $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY); + foreach ($threads as $thread) { + $sql = "UPDATE $tableItemProperty + SET to_group_id = $toGroupId + WHERE + tool = '".TOOL_FORUM_THREAD."' AND + ref = ".$thread['thread_id']." AND + c_id = ".$courseId; + Database::query($sql); + + $posts = getPosts( + $forumData, + $thread['thread_id'] + ); + + foreach ($posts as $post) { + $postId = $post['post_id']; + $attachMentList = getAllAttachment($postId); + if (!empty($attachMentList)) { + foreach ($attachMentList as $attachMent) { + $sql = "UPDATE $tableItemProperty + SET to_group_id = $toGroupId + WHERE + tool = '".TOOL_FORUM_ATTACH."' AND + ref = ".$attachMent['iid']." AND + c_id = ".$courseId; + Database::query($sql); + } + } + + $sql = "UPDATE $tableItemProperty + SET to_group_id = $toGroupId + WHERE + tool = '".TOOL_FORUM_POST."' AND + ref = $postId AND + c_id = $courseId"; + Database::query($sql); + } + } + } + } + Database::update( $table_forums, $params, - ['c_id = ? AND forum_id = ?' => [$course_id, $values['forum_id']]] + ['c_id = ? AND forum_id = ?' => [$courseId, $values['forum_id']]] ); api_item_property_update( @@ -792,7 +844,7 @@ function store_forum($values, $courseInfo = [], $returnId = false) $new_file_name = isset($new_file_name) ? $new_file_name : ''; } $params = [ - 'c_id' => $course_id, + 'c_id' => $courseId, 'forum_title' => $values['forum_title'], 'forum_image' => $new_file_name, 'forum_comment' => isset($values['forum_comment']) ? $values['forum_comment'] : null, @@ -1917,12 +1969,12 @@ function get_last_post_information($forum_id, $show_invisibles = false, $course_ function get_threads($forum_id, $courseId = null, $sessionId = null) { $groupId = api_get_group_id(); - $sessionId = $sessionId !== null ? intval($sessionId) : api_get_session_id(); + $sessionId = $sessionId !== null ? (int) $sessionId : api_get_session_id(); $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY); $table_threads = Database::get_course_table(TABLE_FORUM_THREAD); $table_users = Database::get_main_table(TABLE_MAIN_USER); - $courseId = $courseId !== null ? intval($courseId) : api_get_course_int_id(); + $courseId = $courseId !== null ? (int) $courseId : api_get_course_int_id(); $groupInfo = GroupManager::get_group_properties($groupId); $groupCondition = ''; @@ -3986,10 +4038,11 @@ function increase_thread_view($thread_id) * * @version february 2006, dokeos 1.8 * + * @param int $threadId * @param string $lastPostId * @param string $post_date */ -function updateThreadInfo($thread_id, $lastPostId, $post_date) +function updateThreadInfo($threadId, $lastPostId, $post_date) { $table_threads = Database::get_course_table(TABLE_FORUM_THREAD); $course_id = api_get_course_int_id(); @@ -3999,7 +4052,7 @@ function updateThreadInfo($thread_id, $lastPostId, $post_date) thread_date = '".Database::escape_string($post_date)."' WHERE c_id = $course_id AND - thread_id='".Database::escape_string($thread_id)."'"; // this needs to be cleaned first + thread_id='".Database::escape_string($threadId)."'"; // this needs to be cleaned first Database::query($sql); } @@ -5043,7 +5096,7 @@ function edit_forum_attachment_file($file_comment, $post_id, $id_attach) /** * Show a list with all the attachments according to the post's id. * - * @param int $post_id + * @param int $postId * * @return array with the post info * @@ -5051,15 +5104,20 @@ function edit_forum_attachment_file($file_comment, $post_id, $id_attach) * * @version avril 2008, dokeos 1.8.5 */ -function get_attachment($post_id) +function get_attachment($postId) { - $forum_table_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT); + $table = Database::get_course_table(TABLE_FORUM_ATTACHMENT); $course_id = api_get_course_int_id(); $row = []; - $post_id = intval($post_id); + $postId = (int) $postId; + + if (empty($postId)) { + return []; + } + $sql = "SELECT iid, path, filename, comment - FROM $forum_table_attachment - WHERE c_id = $course_id AND post_id = $post_id"; + FROM $table + WHERE c_id = $course_id AND post_id = $postId"; $result = Database::query($sql); if (Database::num_rows($result) != 0) { $row = Database::fetch_array($result); @@ -5077,7 +5135,12 @@ function getAllAttachment($postId) { $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT); $courseId = api_get_course_int_id(); - $postId = intval($postId); + $postId = (int) $postId; + + if (empty($postId)) { + return []; + } + $columns = ['iid', 'path', 'filename', 'comment']; $conditions = [ 'where' => [ diff --git a/main/gradebook/gradebook_display_certificate.php b/main/gradebook/gradebook_display_certificate.php index e803ba7cf1..6a16d40383 100755 --- a/main/gradebook/gradebook_display_certificate.php +++ b/main/gradebook/gradebook_display_certificate.php @@ -85,7 +85,7 @@ switch ($action) { $currentUserInfo = api_get_user_info(); $message = isset($_POST['message']) ? $_POST['message'] : ''; $subject = get_lang('NotificationCertificateSubject'); - if (!empty($originalMessage)) { + if (!empty($message)) { foreach ($certificate_list as $index => $value) { $userInfo = api_get_user_info($value['user_id']); if (empty($userInfo)) { diff --git a/main/inc/lib/agenda.lib.php b/main/inc/lib/agenda.lib.php index a78b3131c6..cf546b15b7 100644 --- a/main/inc/lib/agenda.lib.php +++ b/main/inc/lib/agenda.lib.php @@ -1319,6 +1319,8 @@ class Agenda break; } + $this->cleanEvents(); + switch ($format) { case 'json': if (empty($this->events)) { @@ -1337,6 +1339,25 @@ class Agenda } } + /** + * Clean events. + * + * @return bool + */ + public function cleanEvents() + { + if (empty($this->events)) { + return false; + } + + foreach ($this->events as &$event) { + $event['description'] = Security::remove_XSS($event['description']); + $event['title'] = Security::remove_XSS($event['title']); + } + + return true; + } + /** * @param int $id * @param int $minute_delta diff --git a/main/inc/lib/course.lib.php b/main/inc/lib/course.lib.php index a5c4df5594..b967e7c686 100755 --- a/main/inc/lib/course.lib.php +++ b/main/inc/lib/course.lib.php @@ -3401,7 +3401,7 @@ class CourseManager $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); $sessionId = (int) $sessionId; $user_id = (int) $user_id; - $select = "SELECT DISTINCT *, c.id as real_id "; + $select = "SELECT DISTINCT c.*, c.id as real_id "; if ($getCount) { $select = "SELECT COUNT(DISTINCT c.id) as count"; @@ -3440,9 +3440,7 @@ class CourseManager // Teacher of course or teacher inside session $whereConditions = " AND (cru.status = ".COURSEMANAGER." OR srcru.status = 2) "; } - $courseList = SessionManager::get_course_list_by_session_id( - $sessionId - ); + $courseList = SessionManager::get_course_list_by_session_id($sessionId); if (!empty($courseList)) { $courseListToString = implode("','", array_keys($courseList)); $whereConditions .= " AND c.id IN ('".$courseListToString."')"; @@ -6078,10 +6076,10 @@ class CourseManager switch ($type) { case 'GROUP': - $groupList[] = intval($id); + $groupList[] = (int) $id; break; case 'USER': - $userList[] = intval($id); + $userList[] = (int) $id; break; } } diff --git a/main/inc/lib/fileUpload.lib.php b/main/inc/lib/fileUpload.lib.php index 9e9478080c..d6e8ccee15 100755 --- a/main/inc/lib/fileUpload.lib.php +++ b/main/inc/lib/fileUpload.lib.php @@ -216,7 +216,7 @@ function process_uploaded_file($uploaded_file, $show_output = true) * @param bool $treat_spaces_as_hyphens * * So far only use for unzip_uploaded_document function. - * If no output wanted on success, set to false + * If no output wanted on success, set to false. * * @return string path of the saved file */ diff --git a/main/lp/learnpath.class.php b/main/lp/learnpath.class.php index 0fd6bce524..07465d770a 100755 --- a/main/lp/learnpath.class.php +++ b/main/lp/learnpath.class.php @@ -6,6 +6,7 @@ use Chamilo\CoreBundle\Entity\Repository\ItemPropertyRepository; use Chamilo\CourseBundle\Component\CourseCopy\CourseArchiver; use Chamilo\CourseBundle\Component\CourseCopy\CourseBuilder; use Chamilo\CourseBundle\Component\CourseCopy\CourseRestorer; +use Chamilo\CourseBundle\Entity\CDocument; use Chamilo\CourseBundle\Entity\CItemProperty; use Chamilo\CourseBundle\Entity\CLp; use Chamilo\CourseBundle\Entity\CLpCategory; @@ -2300,22 +2301,30 @@ class learnpath if (!empty($row['audio'])) { $list = $_SESSION['oLP']->get_toc(); - $type_quiz = false; - foreach ($list as $toc) { - if ($toc['id'] == $_SESSION['oLP']->current && $toc['type'] == 'quiz') { - $type_quiz = true; - } - } + switch ($row['item_type']) { + case 'quiz': + $type_quiz = false; - if ($type_quiz) { - if ($_SESSION['oLP']->prevent_reinit == 1) { - $autostart_audio = $row['status'] === 'completed' ? 'false' : 'true'; - } else { - $autostart_audio = $autostart; - } - } else { - $autostart_audio = 'true'; + foreach ($list as $toc) { + if ($toc['id'] == $_SESSION['oLP']->current) { + $type_quiz = true; + } + } + + if ($type_quiz) { + if ($_SESSION['oLP']->prevent_reinit == 1) { + $autostart_audio = $row['status'] === 'completed' ? 'false' : 'true'; + } else { + $autostart_audio = $autostart; + } + } + break; + case TOOL_READOUT_TEXT:; + $autostart_audio = 'false'; + break; + default: + $autostart_audio = 'true'; } $courseInfo = api_get_course_info(); @@ -6253,7 +6262,7 @@ class learnpath $title_cut = cut($arrLP[$i]['title'], self::MAX_LP_ITEM_TITLE_LENGTH); // Link for the documents - if ($arrLP[$i]['item_type'] == 'document') { + if ($arrLP[$i]['item_type'] == 'document' || $arrLP[$i]['item_type'] == TOOL_READOUT_TEXT) { $url = $mainUrl.'&action=view_item&mode=preview_document&id='.$arrLP[$i]['id'].'&lp_id='.$this->lp_id; $title_cut = Display::url( $title_cut, @@ -6466,6 +6475,7 @@ class learnpath switch ($arrLP[$i]['item_type']) { case TOOL_DOCUMENT: case TOOL_LP_FINAL_ITEM: + case TOOL_READOUT_TEXT: $urlPreviewLink = $mainUrl.'&action=view_item&mode=preview_document&id='.$arrLP[$i]['id'].'&lp_id='.$this->lp_id; $previewIcon = Display::url( $previewImage, @@ -7336,6 +7346,7 @@ class learnpath $return .= $this->getSavedFinalItem(); break; case TOOL_DOCUMENT: + case TOOL_READOUT_TEXT: $tbl_doc = Database::get_course_table(TABLE_DOCUMENT); $sql_doc = "SELECT path FROM ".$tbl_doc." WHERE c_id = ".$course_id." AND iid = ".intval($row['path']); @@ -7439,6 +7450,27 @@ class learnpath $row_step ); break; + case TOOL_READOUT_TEXT: + $tbl_doc = Database::get_course_table(TABLE_DOCUMENT); + $sql = "SELECT lp.*, doc.path as dir + FROM $tbl_lp_item as lp + LEFT JOIN $tbl_doc as doc + ON (doc.iid = lp.path AND lp.c_id = doc.c_id) + WHERE + doc.c_id = $course_id AND + lp.iid = ".$item_id; + $res_step = Database::query($sql); + $row_step = Database::fetch_array($res_step, 'ASSOC'); + $return .= $this->display_manipulate( + $item_id, + $row['item_type'] + ); + $return .= $this->displayFrmReadOutText( + 'edit', + $item_id, + $row_step + ); + break; case TOOL_LINK: $link_id = (string) $row['path']; if (ctype_digit($link_id)) { @@ -9104,6 +9136,473 @@ class learnpath return $form->returnForm(); } + /** + * Returns the form to update or create a read-out text. + * + * @param string $action "add" or "edit" + * @param int $id ID of the lp_item (if already exists) + * @param mixed $extra_info Integer if document ID, string if info ('new') + * + * @throws Exception + * @throws HTML_QuickForm_Error + * + * @return string HTML form + */ + public function displayFrmReadOutText($action = 'add', $id = 0, $extra_info = 'new') + { + $course_id = api_get_course_int_id(); + $_course = api_get_course_info(); + $tbl_lp_item = Database::get_course_table(TABLE_LP_ITEM); + $tbl_doc = Database::get_course_table(TABLE_DOCUMENT); + + $no_display_edit_textarea = false; + $item_description = ''; + //If action==edit document + //We don't display the document form if it's not an editable document (html or txt file) + if ($action == 'edit') { + if (is_array($extra_info)) { + $path_parts = pathinfo($extra_info['dir']); + if ($path_parts['extension'] != "txt" && $path_parts['extension'] != "html") { + $no_display_edit_textarea = true; + } + } + } + $no_display_add = false; + + if ($id != 0 && is_array($extra_info)) { + $item_title = stripslashes($extra_info['title']); + $item_description = stripslashes($extra_info['description']); + $item_terms = stripslashes($extra_info['terms']); + if (empty($item_title)) { + $path_parts = pathinfo($extra_info['path']); + $item_title = stripslashes($path_parts['filename']); + } + } elseif (is_numeric($extra_info)) { + $sql = "SELECT path, title FROM $tbl_doc WHERE c_id = ".$course_id." AND iid = ".intval($extra_info); + $result = Database::query($sql); + $row = Database::fetch_array($result); + $item_title = $row['title']; + $item_title = str_replace('_', ' ', $item_title); + if (empty($item_title)) { + $path_parts = pathinfo($row['path']); + $item_title = stripslashes($path_parts['filename']); + } + } else { + $item_title = ''; + $item_description = ''; + } + + if ($id != 0 && is_array($extra_info)) { + $parent = $extra_info['parent_item_id']; + } else { + $parent = 0; + } + + $sql = "SELECT * FROM $tbl_lp_item WHERE c_id = $course_id AND lp_id = ".$this->lp_id; + $result = Database::query($sql); + $arrLP = []; + + while ($row = Database::fetch_array($result)) { + $arrLP[] = [ + 'id' => $row['iid'], + 'item_type' => $row['item_type'], + 'title' => $row['title'], + 'path' => $row['path'], + 'description' => $row['description'], + 'parent_item_id' => $row['parent_item_id'], + 'previous_item_id' => $row['previous_item_id'], + 'next_item_id' => $row['next_item_id'], + 'display_order' => $row['display_order'], + 'max_score' => $row['max_score'], + 'min_score' => $row['min_score'], + 'mastery_score' => $row['mastery_score'], + 'prerequisite' => $row['prerequisite'], + ]; + } + + $this->tree_array($arrLP); + $arrLP = isset($this->arrMenu) ? $this->arrMenu : []; + unset($this->arrMenu); + + if ($action == 'add') { + $formHeader = get_lang('CreateTheDocument'); + } else { + $formHeader = get_lang('EditTheCurrentDocument'); + } + + if ('edit' === $action) { + $urlAudioIcon = Display::url( + Display::return_icon('audio.png', get_lang('CreateReadOutText'), [], ICON_SIZE_TINY), + api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?'.api_get_cidreq().'&lp_id='.$this->lp_id.'&' + .http_build_query(['view' => 'build', 'id' => $id, 'action' => 'add_audio']) + ); + } else { + $urlAudioIcon = Display::return_icon('audio.png', get_lang('CreateReadOutText'), [], ICON_SIZE_TINY); + } + + $form = new FormValidator( + 'frm_add_reading', + 'POST', + $this->getCurrentBuildingModeURL(), + '', + ['enctype' => 'multipart/form-data'] + ); + $form->addHeader($formHeader); + $form->addHtml( + Display::return_message( + sprintf(get_lang('FrmReadOutTextIntro'), $urlAudioIcon), + 'normal', + false + ) + ); + $defaults['title'] = !empty($item_title) ? Security::remove_XSS($item_title) : ''; + $defaults['description'] = $item_description; + + $data = $this->generate_lp_folder($_course); + + if ($action != 'edit') { + $folders = DocumentManager::get_all_document_folders($_course, 0, true); + DocumentManager::build_directory_selector( + $folders, + '', + [], + true, + $form, + 'directory_parent_id' + ); + } + + if (isset($data['id'])) { + $defaults['directory_parent_id'] = $data['id']; + } + + $form->addElement( + 'text', + 'title', + get_lang('Title') + ); + $form->applyFilter('title', 'trim'); + $form->applyFilter('title', 'html_filter'); + + $arrHide[0]['value'] = $this->name; + $arrHide[0]['padding'] = 20; + + for ($i = 0; $i < count($arrLP); $i++) { + if ($action != 'add') { + if ($arrLP[$i]['item_type'] == 'dir' && + !in_array($arrLP[$i]['id'], $arrHide) && + !in_array($arrLP[$i]['parent_item_id'], $arrHide) + ) { + $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title']; + $arrHide[$arrLP[$i]['id']]['padding'] = 20 + $arrLP[$i]['depth'] * 20; + } + } else { + if ($arrLP[$i]['item_type'] == 'dir') { + $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title']; + $arrHide[$arrLP[$i]['id']]['padding'] = 20 + $arrLP[$i]['depth'] * 20; + } + } + } + + $parent_select = $form->addSelect( + 'parent', + get_lang('Parent'), + [], + ['onchange' => "javascript: load_cbo(this.value, 'frm_add_reading_previous');"] + ); + + $my_count = 0; + foreach ($arrHide as $key => $value) { + if ($my_count != 0) { + // The LP name is also the first section and is not in the same charset like the other sections. + $value['value'] = Security::remove_XSS($value['value']); + $parent_select->addOption( + $value['value'], + $key, + 'style="padding-left:'.$value['padding'].'px;"' + ); + } else { + $value['value'] = Security::remove_XSS($value['value']); + $parent_select->addOption( + $value['value'], + $key, + 'style="padding-left:'.$value['padding'].'px;"' + ); + } + $my_count++; + } + + if (!empty($id)) { + $parent_select->setSelected($parent); + } else { + $parent_item_id = Session::read('parent_item_id', 0); + $parent_select->setSelected($parent_item_id); + } + + if (is_array($arrLP)) { + reset($arrLP); + } + + $arrHide = []; + $s_selected_position = null; + + // POSITION + $lastPosition = null; + + for ($i = 0; $i < count($arrLP); $i++) { + if (($arrLP[$i]['parent_item_id'] == $parent && $arrLP[$i]['id'] != $id) || + $arrLP[$i]['item_type'] == TOOL_LP_FINAL_ITEM + ) { + if ((isset($extra_info['previous_item_id']) && + $extra_info['previous_item_id'] == $arrLP[$i]['id']) || $action == 'add' + ) { + $s_selected_position = $arrLP[$i]['id']; + } + $arrHide[$arrLP[$i]['id']]['value'] = get_lang('After').' "'.$arrLP[$i]['title'].'"'; + } + $lastPosition = $arrLP[$i]['id']; + } + + if (empty($s_selected_position)) { + $s_selected_position = $lastPosition; + } + + $position = $form->addSelect( + 'previous', + get_lang('Position'), + [] + ); + $position->addOption(get_lang('FirstPosition'), 0); + + foreach ($arrHide as $key => $value) { + $padding = isset($value['padding']) ? $value['padding'] : 20; + $position->addOption( + $value['value'], + $key, + 'style="padding-left:'.$padding.'px;"' + ); + } + $position->setSelected($s_selected_position); + + if (is_array($arrLP)) { + reset($arrLP); + } + + $arrHide = []; + + for ($i = 0; $i < count($arrLP); $i++) { + if ($arrLP[$i]['id'] != $id && $arrLP[$i]['item_type'] != 'dir' && + $arrLP[$i]['item_type'] !== TOOL_LP_FINAL_ITEM + ) { + $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title']; + } + } + + if (!$no_display_add) { + $item_type = isset($extra_info['item_type']) ? $extra_info['item_type'] : null; + $edit = isset($_GET['edit']) ? $_GET['edit'] : null; + + if ($extra_info == 'new' || $item_type == TOOL_READOUT_TEXT || $edit == 'true') { + if (!$no_display_edit_textarea) { + $content = ''; + + if (isset($_POST['content'])) { + $content = stripslashes($_POST['content']); + } elseif (is_array($extra_info)) { + $content = $this->display_document($extra_info['path'], false, false); + } elseif (is_numeric($extra_info)) { + $content = $this->display_document($extra_info, false, false); + } + + // A new document, it is in the root of the repository. + if (is_array($extra_info) && $extra_info != 'new') { + } else { + $this->generate_lp_folder($_course); + } + + if ($_GET['action'] == 'add_item') { + $text = get_lang('LPCreateDocument'); + } else { + $text = get_lang('SaveDocument'); + } + + $form->addTextarea('content_lp', get_lang('Content'), ['rows' => 20]); + $form + ->defaultRenderer() + ->setElementTemplate($form->getDefaultElementTemplate(), 'content_lp'); + $form->addButtonSave($text, 'submit_button'); + $defaults['content_lp'] = $content; + } + } elseif (is_numeric($extra_info)) { + $form->addButtonSave(get_lang('SaveDocument'), 'submit_button'); + + $return = $this->display_document($extra_info, true, true, true); + $form->addElement('html', $return); + } + } + + if (is_numeric($extra_info)) { + $form->addElement('hidden', 'path', $extra_info); + } elseif (is_array($extra_info)) { + $form->addElement('hidden', 'path', $extra_info['path']); + } + + $form->addElement('hidden', 'type', TOOL_READOUT_TEXT); + $form->addElement('hidden', 'post_time', time()); + $form->setDefaults($defaults); + + return $form->returnForm(); + } + + /** + * @param array $courseInfo + * @param string $content + * @param string $title + * @param int $parentId + * + * @throws \Doctrine\ORM\ORMException + * @throws \Doctrine\ORM\OptimisticLockException + * @throws \Doctrine\ORM\TransactionRequiredException + * + * @return int + */ + public function createReadOutText($courseInfo, $content = '', $title = '', $parentId = 0) + { + $creatorId = api_get_user_id(); + $sessionId = api_get_session_id(); + + // Generates folder + $result = $this->generate_lp_folder($courseInfo); + $dir = $result['dir']; + + if (empty($parentId) || $parentId == '/') { + $postDir = isset($_POST['dir']) ? $_POST['dir'] : $dir; + $dir = isset($_GET['dir']) ? $_GET['dir'] : $postDir; // Please, do not modify this dirname formatting. + + if ($parentId === '/') { + $dir = '/'; + } + + // Please, do not modify this dirname formatting. + if (strstr($dir, '..')) { + $dir = '/'; + } + + if (!empty($dir[0]) && $dir[0] == '.') { + $dir = substr($dir, 1); + } + if (!empty($dir[0]) && $dir[0] != '/') { + $dir = '/'.$dir; + } + if (isset($dir[strlen($dir) - 1]) && $dir[strlen($dir) - 1] != '/') { + $dir .= '/'; + } + } else { + $parentInfo = DocumentManager::get_document_data_by_id( + $parentId, + $courseInfo['code'] + ); + if (!empty($parentInfo)) { + $dir = $parentInfo['path'].'/'; + } + } + + $filepath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/'.$dir; + + if (!is_dir($filepath)) { + $dir = '/'; + $filepath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/'.$dir; + } + + $originalTitle = !empty($title) ? $title : $_POST['title']; + + if (!empty($title)) { + $title = api_replace_dangerous_char(stripslashes($title)); + } else { + $title = api_replace_dangerous_char(stripslashes($_POST['title'])); + } + + $title = disable_dangerous_file($title); + $filename = $title; + $content = !empty($content) ? $content : $_POST['content_lp']; + $tmpFileName = $filename; + + $i = 0; + while (file_exists($filepath.$tmpFileName.'.html')) { + $tmpFileName = $filename.'_'.++$i; + } + + $filename = $tmpFileName.'.html'; + $content = stripslashes($content); + + if (file_exists($filepath.$filename)) { + return 0; + } + + $putContent = file_put_contents($filepath.$filename, $content); + + if ($putContent === false) { + return 0; + } + + $fileSize = filesize($filepath.$filename); + $saveFilePath = $dir.$filename; + + $documentId = add_document( + $courseInfo, + $saveFilePath, + 'file', + $fileSize, + $tmpFileName, + '', + 0, //readonly + true, + null, + $sessionId, + $creatorId + ); + + if (!$documentId) { + return 0; + } + + api_item_property_update( + $courseInfo, + TOOL_DOCUMENT, + $documentId, + 'DocumentAdded', + $creatorId, + null, + null, + null, + null, + $sessionId + ); + + $newComment = isset($_POST['comment']) ? trim($_POST['comment']) : ''; + $newTitle = $originalTitle; + + if ($newComment || $newTitle) { + $em = Database::getManager(); + + /** @var CDocument $doc */ + $doc = $em->find('ChamiloCourseBundle:CDocument', $documentId); + + if ($newComment) { + $doc->setComment($newComment); + } + + if ($newTitle) { + $doc->setTitle($newTitle); + } + + $em->persist($doc); + $em->flush(); + } + + return $documentId; + } + /** * Return HTML form to add/edit a link item. * @@ -10020,6 +10519,7 @@ class learnpath $headers = [ get_lang('Files'), get_lang('CreateTheDocument'), + get_lang('CreateReadOutText'), get_lang('Upload'), ]; @@ -10091,9 +10591,10 @@ class learnpath $url = api_get_path(WEB_AJAX_PATH).'document.ajax.php?'.api_get_cidreq().'&a=upload_file&curdirpath='; $form->addMultipleUpload($url); $new = $this->display_document_form('add', 0); + $frmReadOutText = $this->displayFrmReadOutText('add'); $tabs = Display::tabs( $headers, - [$documentTree, $new, $form->returnForm()], + [$documentTree, $new, $frmReadOutText, $form->returnForm()], 'subtab' ); @@ -12890,6 +13391,9 @@ EOD; return $main_dir_path.'forum/viewthread.php?post='.$id.'&thread='.$myrow['thread_id'].'&forum=' .$myrow['forum_id'].'&lp=true&'.$extraParams; + case TOOL_READOUT_TEXT: + return api_get_path(WEB_CODE_PATH).'lp/readout_text.php?&id='.$id.'&lp_id='.$learningPathId.'&' + .$extraParams; case TOOL_DOCUMENT: $document = $em ->getRepository('ChamiloCourseBundle:CDocument') diff --git a/main/lp/learnpathItem.class.php b/main/lp/learnpathItem.class.php index 49e0cefb51..88c41777f5 100755 --- a/main/lp/learnpathItem.class.php +++ b/main/lp/learnpathItem.class.php @@ -2451,6 +2451,7 @@ class learnpathItem ) { /** @var learnpathItem $itemToCheck */ $itemToCheck = $items[$refs_list[$prereqs_string]]; + if ($itemToCheck->type == 'quiz') { // 1. Checking the status in current items. $status = $itemToCheck->get_status(true); diff --git a/main/lp/lp_ajax_save_item.php b/main/lp/lp_ajax_save_item.php index 50de78f54e..5b519479bc 100755 --- a/main/lp/lp_ajax_save_item.php +++ b/main/lp/lp_ajax_save_item.php @@ -85,7 +85,7 @@ function save_item( if (!is_a($myLP, 'learnpath')) { if ($debug) { - error_log("mylp variable is not an learnpath object"); + error_log('mylp variable is not an learnpath object'); } return null; @@ -146,7 +146,7 @@ function save_item( } } else { if ($debug > 1) { - error_log("Score not updated"); + error_log('Score not updated'); } } @@ -164,7 +164,7 @@ function save_item( } } else { if ($debug > 1) { - error_log("Status not updated"); + error_log('Status not updated'); } } @@ -248,8 +248,14 @@ function save_item( ) { if ($score >= $masteryScore) { $myLPI->set_status('passed'); + if ($debug) { + error_log('Set status: passed'); + } } else { $myLPI->set_status('failed'); + if ($debug) { + error_log('Set status: failed'); + } } $statusIsSet = true; } @@ -261,6 +267,9 @@ function save_item( */ if (!$statusIsSet && !$masteryScore && !$statusSignalReceived) { if (!empty($status)) { + if ($debug) { + error_log("Set status: $status because: statusSignalReceived "); + } $myLPI->set_status($status); $statusIsSet = true; } @@ -276,6 +285,9 @@ function save_item( if (!$statusIsSet && $credit == 'no-credit' && !$statusSignalReceived) { $mode = $myLPI->get_lesson_mode(); if ($mode == 'browse' && $status == 'browsed') { + if ($debug) { + error_log("Set status: $status because mode browse"); + } $myLPI->set_status($status); $statusIsSet = true; } @@ -319,6 +331,9 @@ function save_item( $myStatus = 'failed'; } } + if ($debug) { + error_log("Set status: $myStatus because lmsFinish || userNavigatesAway"); + } $myLPI->set_status($myStatus); $statusIsSet = true; } @@ -410,6 +425,10 @@ function save_item( $myStatusInDB != 'failed' ) { $myStatusInMemory = $myLPI->get_status(false); + if ($debug) { + error_log("myStatusInMemory: $myStatusInMemory"); + } + if ($myStatusInMemory != $myStatusInDB) { $myStatus = $myStatusInMemory; } else { diff --git a/main/lp/lp_controller.php b/main/lp/lp_controller.php index b63e58ec6f..bf89c0eada 100755 --- a/main/lp/lp_controller.php +++ b/main/lp/lp_controller.php @@ -451,6 +451,27 @@ switch ($action) { $description, $prerequisites ); + } elseif ($_POST['type'] == TOOL_READOUT_TEXT) { + if (isset($_POST['path']) && $_GET['edit'] != 'true') { + $document_id = $_POST['path']; + } else { + $document_id = $_SESSION['oLP']->createReadOutText( + $_course, + $_POST['content_lp'], + $_POST['title'], + $directoryParentId + ); + } + + $new_item_id = $_SESSION['oLP']->add_item( + $parent, + $previous, + TOOL_READOUT_TEXT, + $document_id, + $post_title, + $description, + $prerequisites + ); } else { // For all other item types than documents, // load the item using the item type and path rather than its ID. diff --git a/main/lp/lp_nav.php b/main/lp/lp_nav.php index 706c899df0..b3301471fe 100755 --- a/main/lp/lp_nav.php +++ b/main/lp/lp_nav.php @@ -50,17 +50,14 @@ if ($myLP) { $progress_bar = $myLP->getProgressBar(); $navigation_bar = $myLP->get_navigation_bar(); $mediaplayer = $myLP->get_mediaplayer($lpItemId, $autostart); + + if ($mediaplayer) { + echo $mediaplayer; + echo ""; + } } session_write_close(); -?> - - - - diff --git a/main/lp/scorm_api.php b/main/lp/scorm_api.php index 096b1a6c58..e0c2d57f6e 100755 --- a/main/lp/scorm_api.php +++ b/main/lp/scorm_api.php @@ -303,7 +303,7 @@ function LMSInitialize() { dataType: 'script', async: false, success:function(data) { - jQuery("video:not(.skip), audio:not(.skip)").mediaelementplayer(); + $('video:not(.skip), audio:not(.skip)').mediaelementplayer(); } }); @@ -387,8 +387,7 @@ function Initialize() { function LMSGetValue(param) { olms.G_LastError = G_NoError; olms.G_LastErrorMessage = 'No error'; - var result=''; - + var result = ''; // the LMSInitialize is missing if (olms.lms_initialized == 0) { if (param == 'cmi.core.score.raw') { @@ -539,7 +538,7 @@ function LMSGetValue(param) { olms.G_LastError = G_NotImplementedError; olms.G_LastErrorString = 'Not implemented yet'; } - }else if(req_type == 'status'){ + } else if(req_type == 'status'){ result = 'not attempted'; } } else { @@ -612,7 +611,9 @@ function LMSGetValue(param) { result = ''; return result; } - logit_scorm("LMSGetValue\n\t('"+param+"') returned '"+result+"'",1); + + logit_scorm("LMSGetValue ('"+param+"') returned '"+result+"'",1); + return result; } @@ -653,7 +654,7 @@ function LMSSetValue(param, val) { } else if ( param == "cmi.core.lesson_location" ) { olms.lesson_location = val; olms.updatable_vars_list['cmi.core.lesson_location']=true; - return_value='true'; + return_value = 'true'; } else if ( param == "cmi.core.lesson_status" ) { olms.lesson_status = val; olms.updatable_vars_list['cmi.core.lesson_status'] = true; @@ -843,7 +844,7 @@ function LMSSetValue(param, val) { echo " var mycommit = LMSCommit('force');"; } ?> - return(return_value); + return return_value; } /** @@ -862,7 +863,7 @@ function savedata(item_id) { // Status is NOT modified here see the lp_ajax_save_item.php file if (olms.lesson_status != '') { - olms.updatable_vars_list['cmi.core.lesson_status'] = true; + //olms.updatable_vars_list['cmi.core.lesson_status'] = true; } old_item_id = olms.info_lms_item[0]; @@ -1434,7 +1435,18 @@ function reinit_updatable_vars_list() { * @param string This parameter can be a string specifying the next * item (like 'next', 'previous', 'first' or 'last') or the id to the next item */ -function switch_item(current_item, next_item){ +function switch_item(current_item, next_item) { + if (olms.lms_initialized == 0) { + // Fix error when flash is not loaded and SCO is not started BT#14944 + olms.G_LastError = G_NotInitialized; + olms.G_LastErrorMessage = G_NotInitializedMessage; + logit_scorm('Error '+ G_NotInitialized + G_NotInitializedMessage, 0); + window.location.reload(false); + return false; + } + + olms.switch_finished = 0; //only changed back once LMSInitialize() happens + // backup these params var orig_current_item = current_item; var orig_next_item = next_item; @@ -1519,7 +1531,9 @@ function switch_item(current_item, next_item){ 1, olms.statusSignalReceived ); + reinit_updatable_vars_list(); + xajax_switch_item_toc( olms.lms_lp_id, olms.lms_user_id, @@ -1680,7 +1694,6 @@ function switch_item(current_item, next_item){ } } }); - olms.switch_finished = 0; //only changed back once LMSInitialize() happens loadForumThread(olms.lms_lp_id, next_item); checkCurrentItemPosition(olms.lms_item_id); diff --git a/main/mySpace/myStudents.php b/main/mySpace/myStudents.php index 58024fa528..d71e0977c9 100755 --- a/main/mySpace/myStudents.php +++ b/main/mySpace/myStudents.php @@ -34,6 +34,10 @@ if (empty($student_id)) { // user info $user_info = api_get_user_info($student_id); +if (empty($user_info)) { + api_not_allowed(true); +} + $allowToQualify = api_is_allowed_to_edit(null, true) || api_is_course_tutor() || api_is_session_admin() || @@ -354,9 +358,10 @@ $sessions_coached_by_user = Tracking::get_sessions_coached_by_user(api_get_user_ // RRHH or session admin if (api_is_session_admin() || api_is_drh()) { $courses = CourseManager::get_courses_followed_by_drh(api_get_user_id()); - $session_by_session_admin = SessionManager::get_sessions_followed_by_drh( - api_get_user_id() - ); + if (!empty($courses)) { + $courses = array_column($courses, 'real_id'); + } + $session_by_session_admin = SessionManager::get_sessions_followed_by_drh(api_get_user_id()); if (!empty($session_by_session_admin)) { foreach ($session_by_session_admin as $session_coached_by_user) { diff --git a/main/social/home.php b/main/social/home.php index b4b27496bd..788480cf18 100755 --- a/main/social/home.php +++ b/main/social/home.php @@ -13,15 +13,15 @@ $cidReset = true; require_once __DIR__.'/../inc/global.inc.php'; +api_block_anonymous_users(); + $user_id = api_get_user_id(); $show_full_profile = true; // social tab -$this_section = SECTION_SOCIAL; Session::erase('this_section'); +$this_section = SECTION_SOCIAL; -api_block_anonymous_users(); - -if (api_get_setting('allow_social_tool') != 'true') { +if (api_get_setting('allow_social_tool') !== 'true') { $url = api_get_path(WEB_CODE_PATH).'auth/profile.php'; header('Location: '.$url); exit; diff --git a/main/social/myfiles.php b/main/social/myfiles.php index 82a538c8e4..252a0b5a24 100755 --- a/main/social/myfiles.php +++ b/main/social/myfiles.php @@ -17,6 +17,8 @@ if (api_get_setting('allow_my_files') === 'false') { api_not_allowed(true); } +$this_section = SECTION_SOCIAL; + $htmlHeadXtra[] = '