diff --git a/public/main/course_progress/index.php b/public/main/course_progress/index.php index 1a2b8da02a..3bac2cf259 100644 --- a/public/main/course_progress/index.php +++ b/public/main/course_progress/index.php @@ -486,7 +486,7 @@ switch ($action) { Display::return_icon('export_to_documents.png', get_lang('Export latest version of this page to Documents'), [], ICON_SIZE_MEDIUM), api_get_self().'?'.api_get_cidreq().'&'.http_build_query(['action' => 'export_documents']).$url_token );*/ - + $total_average_of_advances = null; $tpl->assign('token', $url_token); $tpl->assign('is_allowed_to_edit', $isTeacher); $toolbar = null; @@ -508,8 +508,8 @@ switch ($action) { if (!empty($message) && !empty($total_average_of_advances)) { $tpl->assign('message', $message); - $tpl->assign('score_progress', $total_average_of_advances); } + $tpl->assign('score_progress', $total_average_of_advances); if (isset($last_id) && $last_id) { $link_to_thematic_plan = 'get_item_id_from_field_variable_and_field_value( + 'group_id', + $groupId, + false, + false, + true + ); + + if (!empty($surveyList)) { + $exportList = []; + foreach ($surveyList as $data) { + $surveyId = $data['item_id']; + $surveyData = SurveyManager::get_survey($surveyId, 0, api_get_course_id()); + if (!empty($surveyData)) { + $filename = $surveyData['code'].'.xlsx'; + $exportList[] = @SurveyUtil::export_complete_report_xls($surveyData, $filename, 0, true); + } + } + + if (!empty($exportList)) { + $tempZipFile = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().'.zip'; + $zip = new PclZip($tempZipFile); + foreach ($exportList as $file) { + $zip->add($file, PCLZIP_OPT_REMOVE_ALL_PATH); + } + + DocumentManager::file_send_for_download( + $tempZipFile, + true, + get_lang('Surveys').'-'.api_get_course_id().'-'.api_get_local_time().'.zip' + ); + unlink($tempZipFile); + exit; + } + } + + Display::addFlash(Display::return_message(get_lang('NoSurveyAvailable'))); + + header('Location: '.api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq()); + exit; + + break; case 'export_all': $data = GroupManager::exportCategoriesAndGroupsToArray(null, true); Export::arrayToCsv($data); diff --git a/public/main/inc/lib/api.lib.php b/public/main/inc/lib/api.lib.php index c27bc1d358..9b1bcf5214 100644 --- a/public/main/inc/lib/api.lib.php +++ b/public/main/inc/lib/api.lib.php @@ -1654,6 +1654,7 @@ function api_get_user_info_from_entity( } $result['username'] = $user->getUsername(); + $result['status'] = $user->getStatus(); $result['firstname'] = $user->getFirstname(); $result['lastname'] = $user->getLastname(); $result['email'] = $result['mail'] = $user->getEmail(); diff --git a/public/main/mySpace/access_details.php b/public/main/mySpace/access_details.php index 93f935cda1..d88b53205e 100644 --- a/public/main/mySpace/access_details.php +++ b/public/main/mySpace/access_details.php @@ -1,4 +1,5 @@ '). + attr(\"href\", url+'&export=excel') + .attr('class', 'btn btn-default') + .attr('target', '_blank') + .html('".addslashes(get_lang('ExportAsXLS'))."'); + + $('#messages').append(exportLink); + $('#cev_cont_stats').html(db.stats); $('#graph' ).html(db.graph_result); } else { @@ -114,24 +125,16 @@ $(function() { changeMonth: true, changeYear: true }); + + $(\"#cev_button\").hide(); }); "; -$htmlHeadXtra[] = ''; - $interbreadcrumb[] = ['url' => '#', 'name' => get_lang('Access details')]; Display::display_header(''); $userInfo = api_get_user_info($user_id); -$result_to_print = ''; -$sql_result = MySpace::get_connections_to_course($user_id, $courseInfo); -$result_to_print = convert_to_string($sql_result); echo Display::page_header(get_lang('Learner details in course')); echo Display::page_subheader( @@ -153,14 +156,14 @@ $form->display();
'.get_lang('Total').': '.$rst['total'].'
'; - $foo_stats .= ''.get_lang('Average').': '.$rst['avg'].'
'; - $foo_stats .= ''.get_lang('Quantity').' : '.$rst['times'].'
'; - echo $foo_stats; + $data = MySpace::getStats($user_id, $courseInfo, $session_id); + if (!empty($data)) { + $stats = ''.get_lang('Total').': '.$data['total'].'
'; + $stats .= ''.get_lang('Average').': '.$data['avg'].'
'; + $stats .= ''.get_lang('Quantity').' : '.$data['times'].'
'; + echo $stats; } else { - echo Display::return_message(get_lang('No data available'), 'warning'); + echo Display::return_message(get_lang('NoDataAvailable'), 'warning'); } ?>
diff --git a/public/main/mySpace/access_details_session.php b/public/main/mySpace/access_details_session.php index 80d9ccc08b..76dc756aed 100644 --- a/public/main/mySpace/access_details_session.php +++ b/public/main/mySpace/access_details_session.php @@ -49,7 +49,8 @@ function customDate($dateTime, $showTime = false) return $dateTime; } -$sessions = SessionManager::getSessionsFollowedByUser($userId, +$sessions = SessionManager::getSessionsFollowedByUser( + $userId, null, null, null, @@ -131,7 +132,10 @@ if ($form->validate()) { $to ); + $partialMinLogin = 0; + $partialMaxLogin = 0; $partialDuration = 0; + foreach ($result as $item) { $record = [ customDate($item['login'], true), @@ -153,14 +157,24 @@ if ($form->validate()) { // Partials $partialDuration += $item['duration']; + if (empty($partialMinLogin)) { + $partialMinLogin = api_strtotime($item['login'], 'UTC'); + } + if ($partialMinLogin > api_strtotime($item['login'], 'UTC')) { + $partialMinLogin = api_strtotime($item['login'], 'UTC'); + } + if (api_strtotime($item['logout'], 'UTC') > $partialMaxLogin) { + $partialMaxLogin = api_strtotime($item['logout'], 'UTC'); + } + $report[$sessionId]['courses'][$course['real_id']][] = $record; $report[$sessionId]['name'][$course['real_id']] = $courseInfo['title'].'  ('.$session['session_name'].')'; } if (!empty($result)) { $record = [ - '', - '', + customDate($partialMinLogin, true), + customDate($partialMaxLogin, true), api_format_time($partialDuration, 'js'), ]; $report[$sessionId]['courses'][$course['real_id']][] = $record; @@ -173,6 +187,14 @@ if ($form->validate()) { $courses = CourseManager::returnCourses($userId); $courses = array_merge($courses['in_category'], $courses['not_category']); + if ($addTime) { + $fromFirst = api_get_local_time($from.' 00:00:00'); + $toEnd = api_get_local_time($from.' 23:59:59'); + + $from = api_get_utc_datetime($fromFirst); + $to = api_get_utc_datetime($toEnd); + } + foreach ($courses as $course) { $result = MySpace::get_connections_to_course_by_date( $userId, @@ -181,7 +203,8 @@ if ($form->validate()) { $from, $to ); - + $partialMinLogin = 0; + $partialMaxLogin = 0; $partialDuration = 0; foreach ($result as $item) { @@ -207,12 +230,21 @@ if ($form->validate()) { // Partials $partialDuration += $item['duration']; + if (empty($partialMinLogin)) { + $partialMinLogin = api_strtotime($item['login'], 'UTC'); + } + if ($partialMinLogin > api_strtotime($item['login'], 'UTC')) { + $partialMinLogin = api_strtotime($item['login'], 'UTC'); + } + if (api_strtotime($item['logout'], 'UTC') > $partialMaxLogin) { + $partialMaxLogin = api_strtotime($item['logout'], 'UTC'); + } } if (!empty($result)) { $record = [ - '', - '', + customDate($partialMinLogin, true), + customDate($partialMaxLogin, true), api_format_time($partialDuration, 'js'), ]; @@ -238,16 +270,21 @@ if ($form->validate()) { $table->setCellContents($row, $column++, customDate($minLogin)); $table->setCellContents($row, $column++, customDate($maxLogin)); $table->setRowAttributes($row, ['style' => 'font-weight:bold']); - $table->setCellContents($row, $column++, api_format_time($totalDuration, 'js')); - $totalTable = Display::page_subheader3(sprintf(get_lang('Extraction from %s'), api_get_local_time())); - $totalTable .= $table->toHtml(); + + $first = $table->toHtml(); $courseSessionTable = ''; $courseSessionTableData = []; + $iconCourse = Display::return_icon('course.png', null, [], ICON_SIZE_SMALL); foreach ($report as $sessionId => $data) { foreach ($data['courses'] as $courseId => $courseData) { - $courseSessionTable .= Display::page_subheader3($data['name'][$courseId]); + if (empty($courseData)) { + continue; + } + $courseSessionTable .= '
'.Display::page_subheader3( + $iconCourse.$data['name'][$courseId] + ).'
'; $table = new HTML_Table(['class' => 'data_table']); $headers = [ get_lang('Start Date'), @@ -276,11 +313,12 @@ if ($form->validate()) { $courseSessionTable .= $table->toHtml(); } } - + $totalCourseSessionTable = ''; + if ($courseSessionTableData) { $table = new HTML_Table(['class' => 'data_table']); $headers = [ get_lang('Course'), - get_lang('Total time spent'), + get_lang('TotalDuration'), ]; $row = 0; $column = 0; @@ -296,6 +334,33 @@ if ($form->validate()) { $row++; } $totalCourseSessionTable = $table->toHtml(); + } + + $result = []; + $result['first'] = $first; + $result['second'] = $courseSessionTable; + $result['third'] = $totalCourseSessionTable; + $result['total'] = $totalDuration; + + return $result; +} + +if ($form->validate()) { + $values = $form->getSubmitValues(); + $from = $values['from']; + $to = $values['to']; + + $from = DateTime::createFromFormat('d/m/Y', $from); + $to = DateTime::createFromFormat('d/m/Y', $to); + + $from = api_get_utc_datetime($from->format('Y-m-d')); + $to = api_get_utc_datetime($to->format('Y-m-d')); + $title = Display::page_subheader3(sprintf(get_lang('ExtractionFromX'), api_get_local_time())); + $result = getReport($userId, $from, $to); + + $first = $result['first']; + $courseSessionTable = $result['second']; + $totalCourseSessionTable = $result['third']; $tpl = new Template('', false, false, false, true, false, false); $tpl->assign('title', get_lang('Certificate of achievement')); @@ -303,9 +368,9 @@ if ($form->validate()) { $tpl->assign('table_progress', $totalTable.$totalCourseSessionTable.''.$courseSessionTable); $content = $tpl->fetch($tpl->get_template('my_space/pdf_export_student.tpl')); + $params = [ 'pdf_title' => get_lang('Resume'), - //'session_info' => $sessionInfo, 'course_info' => '', 'pdf_date' => '', 'student_info' => $userInfo, @@ -315,13 +380,13 @@ if ($form->validate()) { 'orientation' => 'P', ]; + $pdfName = api_strtoupper($userInfo['lastname'].'_'.$userInfo['firstname']).'_'.api_get_local_time(); @$pdf = new PDF('A4', $params['orientation'], $params); - - $pdf->setBackground($tpl->theme); + @$pdf->setBackground($tpl->theme); @$pdf->content_to_pdf( $content, '', - '', + $pdfName, null, 'D', false, @@ -334,6 +399,202 @@ if ($form->validate()) { } $interbreadcrumb[] = ['url' => '#', 'name' => get_lang('Access details')]; +$userInfo = api_get_user_info($userId); + +$form->setDefaults(['from' => $startDate, 'to' => $endDate]); + +$formByDay = new FormValidator( + 'by_day', + 'get', + api_get_self().'?user_id='.$userId, + null, + ['id' => 'by_day'] +); +$formByDay->addElement('text', 'from', get_lang('From')); +$formByDay->addElement('text', 'to', get_lang('Until')); +$formByDay->addCheckBox('reduced', null, get_lang('ReducedReport')); +$formByDay->addHidden('user_id', $userId); +$formByDay->addRule('from', get_lang('ThisFieldIsRequired'), 'required'); +$formByDay->addRule('from', get_lang('ThisFieldIsRequired').' dd/mm/yyyy', 'callback', 'validateDate'); +$formByDay->addRule('to', get_lang('ThisFieldIsRequired'), 'required'); +$formByDay->addRule('to', get_lang('ThisFieldIsRequired').' dd/mm/yyyy', 'callback', 'validateDate'); +$formByDay->addButtonSearch(get_lang('GenerateReport')); + +if ($formByDay->validate()) { + $from = $formByDay->getSubmitValue('from'); + $to = $formByDay->getSubmitValue('to'); + $reduced = !empty($formByDay->getSubmitValue('reduced')); + + $fromObject = DateTime::createFromFormat('d/m/Y', $from); + $toObject = DateTime::createFromFormat('d/m/Y', $to); + + $from = api_get_utc_datetime($fromObject->format('Y-m-d').' 00:00:00'); + $to = api_get_utc_datetime($toObject->format('Y-m-d').' 23:59:59'); + + $list = Tracking::get_time_spent_on_the_platform($userId, 'wide', $from, $to, true); + $newList = []; + foreach ($list as $item) { + $key = substr($item['login_date'], 0, 10); + + $dateLogout = substr($item['logout_date'], 0, 10); + if ($dateLogout > $key) { + $itemLogoutOriginal = $item['logout_date']; + $fromItemObject = DateTime::createFromFormat('Y-m-d H:i:s', $item['login_date'], new DateTimeZone('UTC')); + $toItemObject = DateTime::createFromFormat('Y-m-d H:i:s', $item['logout_date'], new DateTimeZone('UTC')); + $item['logout_date'] = api_get_utc_datetime($key.' 23:59:59'); + + $period = new DatePeriod( + $fromItemObject, + new DateInterval('P1D'), + $toItemObject + ); + + $counter = 1; + $itemKey = null; + foreach ($period as $value) { + $dateToCheck = api_get_utc_datetime($value->format('Y-m-d').' 00:00:01'); + $end = api_get_utc_datetime($value->format('Y-m-d').' 23:59:59'); + if ($counter === 1) { + $dateToCheck = $item['login_date']; + } + $itemKey = substr($value->format('Y-m-d'), 0, 10); + + if (isset($newList[$itemKey])) { + if ($newList[$itemKey]['login_date']) { + $dateToCheck = $newList[$itemKey]['login_date']; + } + } + + $newList[$itemKey] = [ + 'login_date' => $dateToCheck, + 'logout_date' => $end, + 'diff' => 0, + ]; + + $counter++; + } + + if (!empty($itemKey) && isset($newList[$itemKey])) { + if ( + substr(api_get_local_time($newList[$itemKey]['login_date']), 0, 10) === + substr(api_get_local_time($itemLogoutOriginal), 0, 10) + ) { + $newList[$itemKey]['logout_date'] = $itemLogoutOriginal; + } + } + } + + if (!isset($newList[$key])) { + $newList[$key] = [ + 'login_date' => $item['login_date'], + 'logout_date' => $item['logout_date'], + 'diff' => 0, + ]; + } else { + $newList[$key] = [ + 'login_date' => $newList[$key]['login_date'], + 'logout_date' => $item['logout_date'], + 'diff' => 0, + ]; + } + } + + if (!empty($newList)) { + foreach ($newList as &$item) { + $item['diff'] = api_strtotime($item['logout_date']) - api_strtotime($item['login_date']); + } + } + + $period = new DatePeriod( + $fromObject, + new DateInterval('P1D'), + $toObject + ); + + $tableList = ''; + foreach ($period as $value) { + $dateToCheck = $value->format('Y-m-d'); + $data = isset($newList[$dateToCheck]) ? $newList[$dateToCheck] : []; + + if (empty($data)) { + continue; + } + + $table = new HTML_Table(['class' => ' table_print']); + $headers = [ + get_lang('FirstLogin'), + get_lang('LastConnection'), + get_lang('Total'), + ]; + + $row = 0; + $column = 0; + foreach ($headers as $header) { + $table->setHeaderContents($row, $column, $header); + $column++; + } + + $row = 1; + $column = 0; + $table->setCellContents($row, $column++, customDate($data['login_date'], true)); + $table->setCellContents($row, $column++, customDate($data['logout_date'], true)); + $table->setCellContents($row, $column, api_format_time($data['diff'], 'js')); + + $result = getReport($userId, $dateToCheck, $dateToCheck, true); + $first = $result['first']; + $courseSessionTable = $result['second']; + $totalCourseSessionTable = $result['third']; + $total = $result['total']; + $iconCalendar = Display::return_icon('calendar.png', null, [], ICON_SIZE_SMALL); + $tableList .= '
'.Display::page_subheader2( + $iconCalendar.get_lang('Date').': '.$dateToCheck + ).'
'; + $tableList .= $table->toHtml(); + if (!$reduced && !empty($total)) { + $diff = get_lang('NotInCourse').' '.api_format_time($data['diff'] - $total, 'js'); + $tableList .= $courseSessionTable; + $tableList .= $totalCourseSessionTable; + $tableList .= '
'.Display::page_subheader3($diff).'
'; + } + } + + $tpl = new Template('', false, false, false, true, false, false); + $tpl->assign('title', get_lang('RealisationCertificate')); + $tpl->assign('student', $userInfo['complete_name']); + $totalTable = Display::page_subheader3(sprintf(get_lang('ExtractionFromX'), api_get_local_time())); + $tpl->assign('table_progress', $totalTable.$tableList); + + $content = $tpl->fetch($tpl->get_template('my_space/pdf_export_student.tpl')); + + $params = [ + 'pdf_title' => get_lang('Resume'), + 'course_info' => '', + 'pdf_date' => '', + 'student_info' => $userInfo, + 'show_grade_generated_date' => true, + 'show_real_course_teachers' => false, + 'show_teacher_as_myself' => false, + 'orientation' => 'P', + ]; + $pdfName = api_strtoupper($userInfo['lastname'].'_'.$userInfo['firstname']).'_'.api_get_local_time(); + @$pdf = new PDF('A4', $params['orientation'], $params); + @$pdf->setBackground($tpl->theme, true); + @$pdf->content_to_pdf( + $content, + '', + $pdfName, + null, + 'D', + false, + null, + false, + true, + false + ); + exit; +} + +$formByDay->setDefaults(['from' => $startDate, 'to' => $endDate]); Display::display_header(''); $userInfo = api_get_user_info($userId); diff --git a/public/main/mySpace/admin_view.php b/public/main/mySpace/admin_view.php index 3ba4e560f1..a254a8f1c7 100644 --- a/public/main/mySpace/admin_view.php +++ b/public/main/mySpace/admin_view.php @@ -1,4 +1,5 @@ api_get_path(WEB_COURSE_PATH).$courseInfo['directory'], 'name' => $courseInfo['title'], ]; } $interbreadcrumb[] = [ - 'url' => '../user/user.php?cidReq='.$course_code, + 'url' => '../user/user.php?cidReq='.$courseCode, 'name' => get_lang('Users'), ]; } else { @@ -674,7 +675,7 @@ if (!empty($user_info['email'])) { $send_mail = Display::return_icon('mail_send_na.png', get_lang('Send message mail'), '', ICON_SIZE_MEDIUM); } echo $send_mail; -if (!empty($student_id) && !empty($course_code)) { +if (!empty($student_id) && !empty($courseCode)) { // Only show link to connection details if course and student were defined in the URL echo '' @@ -685,7 +686,7 @@ if (!empty($student_id) && !empty($course_code)) { $notebookTeacherEnable = 'true' === api_get_plugin_setting('notebookteacher', 'enable_plugin_notebookteacher'); if ($notebookTeacherEnable && !empty($student_id) && !empty($course_code)) { // link notebookteacher - $optionsLink = 'student_id='.$student_id.'&origin='.$origin.'&cidReq='.$course_code.'&id_session='.$sessionId; + $optionsLink = 'student_id='.$student_id.'&origin='.$origin.'&cidReq='.$courseCode.'&id_session='.$sessionId; echo '' .Display::return_icon('notebookteacher.png', get_lang('Notebook'), '', ICON_SIZE_MEDIUM) .''; @@ -738,11 +739,11 @@ if (user_is_online($student_id)) { $avg_student_progress = $avg_student_score = 0; if (empty($sessionId)) { - $isSubscribedToCourse = CourseManager::is_user_subscribed_in_course($user_info['user_id'], $course_code); + $isSubscribedToCourse = CourseManager::is_user_subscribed_in_course($user_info['user_id'], $courseCode); } else { $isSubscribedToCourse = CourseManager::is_user_subscribed_in_course( $user_info['user_id'], - $course_code, + $courseCode, true, $sessionId ); @@ -751,7 +752,7 @@ if (empty($sessionId)) { if ($isSubscribedToCourse) { $avg_student_progress = Tracking::get_avg_student_progress( $user_info['user_id'], - $course_code, + $courseCode, [], $sessionId ); @@ -759,7 +760,7 @@ if ($isSubscribedToCourse) { // the score inside the Reporting table $avg_student_score = Tracking::get_avg_student_score( $user_info['user_id'], - $course_code, + $courseCode, [], $sessionId ); @@ -855,16 +856,16 @@ $userInfo = [ 'online' => $online, ]; -if (!empty($course_code)) { +if (!empty($courseCode)) { $userInfo['url_access'] = Display::url( get_lang('See accesses'), 'access_details.php?' .http_build_query( [ 'student' => $student_id, - 'course' => $course_code, + 'course' => $courseCode, 'origin' => $origin, - 'cidReq' => $course_code, + 'cidReq' => $courseCode, 'id_session' => $sessionId, ] ), @@ -952,12 +953,12 @@ $tpl = new Template( ); if (!empty($courseInfo)) { - $nb_assignments = Tracking::count_student_assignments($student_id, $course_code, $sessionId); - $messages = Tracking::count_student_messages($student_id, $course_code, $sessionId); + $nb_assignments = Tracking::count_student_assignments($student_id, $courseCode, $sessionId); + $messages = Tracking::count_student_messages($student_id, $courseCode, $sessionId); $links = Tracking::count_student_visited_links($student_id, $courseInfo['real_id'], $sessionId); $chat_last_connection = Tracking::chat_last_connection($student_id, $courseInfo['real_id'], $sessionId); $documents = Tracking::count_student_downloaded_documents($student_id, $courseInfo['real_id'], $sessionId); - $uploaded_documents = Tracking::count_student_uploaded_documents($student_id, $course_code, $sessionId); + $uploaded_documents = Tracking::count_student_uploaded_documents($student_id, $courseCode, $sessionId); $tpl->assign('title', $courseInfo['title']); $userInfo['tools'] = [ @@ -967,6 +968,9 @@ if (!empty($courseInfo)) { 'chat_connection' => $chat_last_connection, 'documents' => $documents, 'upload_documents' => $uploaded_documents, + 'course_first_access' => Tracking::get_first_connection_date_on_the_course($student_id, $courseInfo['real_id'], $sessionId), + 'course_last_access' => Tracking::get_last_connection_date_on_the_course($student_id, $courseInfo, $sessionId), + 'count_access_dates' => Tracking::getNumberOfCourseAccessDates($student_id, $courseInfo['real_id'], $sessionId), ]; } else { $details = false; @@ -1379,7 +1383,6 @@ if (empty($details)) { } $userEntity = api_get_user_entity(api_get_user_id()); - $codePath = api_get_path(WEB_CODE_PATH); /** @var CLpCategory $item */ foreach ($categories as $item) { @@ -1441,7 +1444,7 @@ if (empty($details)) { } else { $total_time = Tracking::get_time_spent_in_lp( $student_id, - $course_code, + $courseCode, [$lp_id], $sessionId ); @@ -1454,7 +1457,7 @@ if (empty($details)) { // Get last connection time in lp $start_time = Tracking::get_last_connection_time_in_lp( $student_id, - $course_code, + $courseCode, $lp_id, $sessionId ); @@ -1472,7 +1475,7 @@ if (empty($details)) { // Quiz in lp $score = Tracking::get_avg_student_score( $student_id, - $course_code, + $courseCode, [$lp_id], $sessionId ); @@ -1480,7 +1483,7 @@ if (empty($details)) { // Latest exercise results in a LP $score_latest = Tracking::get_avg_student_score( $student_id, - $course_code, + $courseCode, [$lp_id], $sessionId, false, @@ -1489,7 +1492,7 @@ if (empty($details)) { $bestScore = Tracking::get_avg_student_score( $student_id, - $course_code, + $courseCode, [$lp_id], $sessionId, false, @@ -1658,7 +1661,7 @@ if (empty($details)) { ); $score_percentage = Tracking::get_avg_student_exercise_score( $student_id, - $course_code, + $courseCode, $exercise_id, $sessionId, 1, @@ -1669,7 +1672,7 @@ if (empty($details)) { if (!isset($score_percentage) && $count_attempts > 0) { $scores_lp = Tracking::get_avg_student_exercise_score( $student_id, - $course_code, + $courseCode, $exercise_id, $sessionId, 2, @@ -1725,7 +1728,7 @@ if (empty($details)) { if ($allowToQualify) { $qualifyLink = '&action=qualify'; } - $attemptLink = '../exercise/exercise_show.php?id='.$id_last_attempt.'&cidReq='.$course_code + $attemptLink = '../exercise/exercise_show.php?id='.$id_last_attempt.'&cidReq='.$courseCode .'&id_session='.$sessionId.'&session_id='.$sessionId.'&student='.$student_id.'&origin=' .(empty($origin) ? 'tracking' : $origin).$qualifyLink; echo Display::url( @@ -1739,7 +1742,7 @@ if (empty($details)) { echo ''; if ($count_attempts > 0) { $all_attempt_url = "../exercise/exercise_report.php?id=$exercise_id&" - ."cidReq=$course_code&filter_by_user=$student_id&id_session=$sessionId"; + ."cidReq=$courseCode&filter_by_user=$student_id&id_session=$sessionId"; echo Display::url( Display::return_icon( 'test_results.png', @@ -1773,7 +1776,7 @@ if (empty($details)) { // @when using sessions we do not show the survey list if (empty($sessionId)) { - $survey_list = SurveyManager::get_surveys($course_code, $sessionId); + $survey_list = SurveyManager::get_surveys($courseCode, $sessionId); if (!empty($survey_list)) { $survey_data = []; foreach ($survey_list as $survey) { @@ -1850,7 +1853,7 @@ if (empty($details)) { echo ''; echo ''.$work->title.''; $documentNumber = $key + 1; - $url = api_get_path(WEB_CODE_PATH).'work/view.php?cidReq='.$course_code.'&id_session='.$sessionId.'&id=' + $url = api_get_path(WEB_CODE_PATH).'work/view.php?cidReq='.$courseCode.'&id_session='.$sessionId.'&id=' .$results['id']; echo '('.$documentNumber.')'; $qualification = !empty($results['qualification']) ? $results['qualification'] : '-'; diff --git a/public/main/mySpace/session.php b/public/main/mySpace/session.php index f389101244..bd4482fc57 100644 --- a/public/main/mySpace/session.php +++ b/public/main/mySpace/session.php @@ -1,9 +1,7 @@ validate()) { $extraFields = $extraField->get_all(null, 'option_order'); $extraFields = array_column($extraFields, 'variable'); $filter = new stdClass(); - $filter->groupOp = 'AND'; foreach ($columnModel as $col) { if (isset($values[$col['index']]) && !empty($values[$col['index']]) && in_array(str_replace('extra_', '', $col['index']), $extraFields) ) { $rule = new stdClass(); - $rule->field = $col['index']; + $index = $col['index']; + $rule->field = $index; $rule->op = 'in'; - $rule->data = Security::remove_XSS($values[$col['index']]); + $data = $values[$index]; + if (is_array($data) && array_key_exists($index, $data)) { + $data = $data[$index]; + } + $rule->data = Security::remove_XSS($data); $filter->rules[] = $rule; $filter->groupOp = 'AND'; } diff --git a/public/main/notification_event/edit.php b/public/main/notification_event/edit.php index 5b807d3f29..4945992dea 100644 --- a/public/main/notification_event/edit.php +++ b/public/main/notification_event/edit.php @@ -16,6 +16,11 @@ if (empty($id)) { $manager = new NotificationEvent(); $notification = $manager->get($id); + +if (empty($notification)) { + api_not_allowed(true); +} + $tpl = new Template($tool); $fields = []; diff --git a/public/main/palettes/pchart/default.color b/public/main/palettes/pchart/default.color index 08466973ce..8243bdd919 100644 --- a/public/main/palettes/pchart/default.color +++ b/public/main/palettes/pchart/default.color @@ -1,10 +1,15 @@ -171,70,67,100 -221,133,61,100 -255,235,141,100 +186,206,151,100 210,148,147,100 -114,88,144,100 148,170,208,100 -186,206,151,100 +221,133,61,100 65,153,176,100 +114,88,144,100 138,166,78,100 +171,70,67,100 69,115,168,100 +239,210,121,100 +149,203,233,100 +2,71,105,100 +175,215,117,100 +44,87,0,100 +222,157,127,100 diff --git a/public/main/survey/ch_dropdown.php b/public/main/survey/ch_dropdown.php index 49f1023d51..53b33ebed2 100644 --- a/public/main/survey/ch_dropdown.php +++ b/public/main/survey/ch_dropdown.php @@ -20,6 +20,12 @@ class ch_dropdown extends survey_question } } + if (isset($formData['answersid']) && !empty($formData['answersid'])) { + foreach ($formData['answersid'] as $value) { + $this->getForm()->addHidden('answersid[]', $value); + } + } + parent::addRemoveButtons($formData); } diff --git a/public/main/survey/ch_multiplechoice.php b/public/main/survey/ch_multiplechoice.php index 9b7bcf5e34..4a3749815f 100644 --- a/public/main/survey/ch_multiplechoice.php +++ b/public/main/survey/ch_multiplechoice.php @@ -20,13 +20,14 @@ class ch_multiplechoice extends survey_question 'horizontal' => get_lang('Horizontal'), 'vertical' => get_lang('Vertical'), ]; - $this->getForm()->addRadio('horizontalvertical', get_lang('Display'), $options); + $this->getForm()->addRadio('horizontalvertical', get_lang('DisplayAnswersHorVert'), $options); $formData['horizontalvertical'] = isset($formData['horizontalvertical']) ? $formData['horizontalvertical'] : 'horizontal'; $this->getForm()->setDefaults($formData); $config = ['ToolbarSet' => 'Survey', 'Width' => '100%', 'Height' => '120']; $total = count($formData['answers']); + if (is_array($formData['answers'])) { foreach ($formData['answers'] as $key => $value) { $this->getForm()->addHtmlEditor('answers['.$key.']', null, false, false, $config); @@ -36,6 +37,12 @@ class ch_multiplechoice extends survey_question } } + if (isset($formData['answersid']) && !empty($formData['answersid'])) { + foreach ($formData['answersid'] as $value) { + $this->getForm()->addHidden('answersid[]', $value); + } + } + parent::addRemoveButtons($formData); } diff --git a/public/main/survey/ch_multiplechoiceother.php b/public/main/survey/ch_multiplechoiceother.php new file mode 100644 index 0000000000..c8083b0672 --- /dev/null +++ b/public/main/survey/ch_multiplechoiceother.php @@ -0,0 +1,120 @@ + get_lang('Horizontal'), + 'vertical' => get_lang('Vertical'), + ]; + $this->getForm()->addRadio('horizontalvertical', get_lang('DisplayAnswersHorVert'), $options); + + $formData['horizontalvertical'] = isset($formData['horizontalvertical']) ? $formData['horizontalvertical'] : 'horizontal'; + $this->getForm()->setDefaults($formData); + + $config = ['ToolbarSet' => 'Survey', 'Width' => '100%', 'Height' => '120']; + $total = count($formData['answers']); + + if (is_array($formData['answers'])) { + foreach ($formData['answers'] as $key => $value) { + if ($value === 'other') { + continue; + } + $this->getForm()->addHtmlEditor('answers['.$key.']', null, false, false, $config); + if ($total > 2) { + $this->getForm()->addButton("delete_answer[$key]", get_lang('Delete'), 'trash', 'danger'); + } + } + } + + if (isset($formData['answersid']) && !empty($formData['answersid'])) { + $counter = 1; + $total = count($formData['answersid']); + foreach ($formData['answersid'] as $value) { + if ($counter === $total) { + break; + } + $this->getForm()->addHidden('answersid[]', $value); + $counter++; + } + } + + parent::addRemoveButtons($formData); + } + + /** + * @param array $questionData + * @param array $answers + */ + public function render(FormValidator $form, $questionData = [], $answers = []) + { + $question = new ch_yesno(); + $otherId = 0; + foreach ($questionData['options'] as $key => $option) { + if ('other' === $option) { + $otherId = $key; + } + } + + foreach ($questionData['options'] as &$option) { + if ($option === 'other') { + $option = '

'.get_lang('SurveyOtherAnswerSpecify').'

'; + } + } + $questionId = $questionData['question_id']; + $question->render($form, $questionData, $answers); + $form->addHtml( + '' + ); + + $display = 'display:none'; + $defaultOtherData = ''; + if (!empty($answers)) { + $answers = self::decodeOptionValue($answers); + if (isset($answers[1])) { + $display = ''; + $defaultOtherData = $answers[1]; + } + } + $form->addHtml('
'); + $element = $form->addText( + 'other_question'.$questionId, + get_lang('SurveyOtherAnswer'), + false, + ['id' => 'other_question'.$questionId] + ); + $form->addHtml('
'); + + if (!empty($answers) && !empty($defaultOtherData)) { + $element->setValue($defaultOtherData); + $element->freeze(); + } + } + + public static function decodeOptionValue($value) + { + return explode('@:@', $value); + } +} diff --git a/public/main/survey/ch_multipleresponse.php b/public/main/survey/ch_multipleresponse.php index e7d382fead..aad1da5560 100644 --- a/public/main/survey/ch_multipleresponse.php +++ b/public/main/survey/ch_multipleresponse.php @@ -17,7 +17,7 @@ class ch_multipleresponse extends survey_question 'horizontal' => get_lang('Horizontal'), 'vertical' => get_lang('Vertical'), ]; - $this->getForm()->addRadio('horizontalvertical', get_lang('Display'), $options); + $this->getForm()->addRadio('horizontalvertical', get_lang('DisplayAnswersHorVert'), $options); $formData['horizontalvertical'] = isset($formData['horizontalvertical']) ? $formData['horizontalvertical'] : 'horizontal'; $this->getForm()->setDefaults($formData); @@ -35,6 +35,12 @@ class ch_multipleresponse extends survey_question } } + if (isset($formData['answersid']) && !empty($formData['answersid'])) { + foreach ($formData['answersid'] as $value) { + $this->getForm()->addHidden('answersid[]', $value); + } + } + parent::addRemoveButtons($formData); } @@ -54,7 +60,6 @@ class ch_multipleresponse extends survey_question } $name = 'question'.$questionData['question_id']; - $form->addCheckBoxGroup( $name, null, @@ -63,7 +68,6 @@ class ch_multipleresponse extends survey_question ); $defaults = []; - if (!empty($answers)) { foreach ($answers as $answer) { $defaults[$name.'['.$answer.']'] = true; diff --git a/public/main/survey/ch_percentage.php b/public/main/survey/ch_percentage.php index 2536965aaa..b724059aca 100644 --- a/public/main/survey/ch_percentage.php +++ b/public/main/survey/ch_percentage.php @@ -21,7 +21,6 @@ class ch_percentage extends survey_question } $name = 'question'.$questionData['question_id']; - $form->addSelect( $name, null, diff --git a/public/main/survey/ch_score.php b/public/main/survey/ch_score.php index d6df065302..5d3880fb03 100644 --- a/public/main/survey/ch_score.php +++ b/public/main/survey/ch_score.php @@ -13,9 +13,7 @@ class ch_score extends survey_question public function createForm($survey_data, $formData) { parent::createForm($survey_data, $formData); - $this->getForm()->addText('maximum_score', get_lang('Score')); - $config = ['ToolbarSet' => 'Survey', 'Width' => '100%', 'Height' => '120']; if (is_array($formData['answers'])) { foreach ($formData['answers'] as $key => $value) { @@ -29,6 +27,12 @@ class ch_score extends survey_question } } + if (isset($formData['answersid']) && !empty($formData['answersid'])) { + foreach ($formData['answersid'] as $value) { + $this->getForm()->addHidden('answersid[]', $value); + } + } + parent::addRemoveButtons($formData); } @@ -49,6 +53,7 @@ class ch_score extends survey_question $name = 'question'.$questionData['question_id'].'['.$key.']'; + $form->addHidden('question_id', $questionData['question_id']); $form->addSelect( $name, $value, diff --git a/public/main/survey/ch_selectivedisplay.php b/public/main/survey/ch_selectivedisplay.php new file mode 100644 index 0000000000..52cb5616b5 --- /dev/null +++ b/public/main/survey/ch_selectivedisplay.php @@ -0,0 +1,85 @@ + $class, + 'label-class' => $labelClass, + 'class' => 'survey_selective_input', + ]; + + if (!empty($questionData['is_required'])) { + $radioAttributes['required'] = 'required'; + } + + $form->addRadio( + $name, + null, + $questionData['options'], + $radioAttributes + ); + + if (!empty($answers)) { + $form->setDefaults([$name => is_array($answers) ? current($answers) : $answers]); + } + } + } + + public static function getJs() + { + return ''; + } +} diff --git a/public/main/survey/ch_yesno.php b/public/main/survey/ch_yesno.php index 587611136f..080d3892df 100644 --- a/public/main/survey/ch_yesno.php +++ b/public/main/survey/ch_yesno.php @@ -1,4 +1,5 @@ '100%', 'Height' => '120', ]; + $this->getForm()->addHtmlEditor( 'answers[0]', get_lang('Answer options'), @@ -36,6 +38,7 @@ class ch_yesno extends survey_question false, $config ); + $this->getForm()->addHtmlEditor( 'answers[1]', null, @@ -43,6 +46,12 @@ class ch_yesno extends survey_question false, $config ); + + if (isset($formData['answersid']) && !empty($formData['answersid'])) { + foreach ($formData['answersid'] as $value) { + $this->getForm()->addHidden('answersid[]', $value); + } + } } /** @@ -64,6 +73,7 @@ class ch_yesno extends survey_question if (!empty($questionData['is_required'])) { $radioAttributes['required'] = 'required'; } + $form->addRadio( $name, null, diff --git a/public/main/survey/copy_survey.php b/public/main/survey/copy_survey.php index f52107afec..fcc6ade18e 100644 --- a/public/main/survey/copy_survey.php +++ b/public/main/survey/copy_survey.php @@ -1,4 +1,5 @@ , Ghent University: cleanup, * refactoring and rewriting large parts (if not all) of the code * @author Julio Montoya Armas , Chamilo: Personality * Test modification and rewriting large parts of the code * - * @version $Id: create_new_survey.php 22297 2009-07-22 22:08:30Z cfasanando $ - * * @todo only the available platform languages should be used => need an * api get_languages and and api_get_available_languages (or a parameter) */ require_once __DIR__.'/../inc/global.inc.php'; $_course = api_get_course_info(); - $this_section = SECTION_COURSES; $allowSurveyAvailabilityDatetime = api_get_configuration_value('allow_survey_availability_datetime'); @@ -82,9 +80,9 @@ if ('edit' == $action && isset($survey_id) && is_numeric($survey_id)) { $survey_id, $session_id ); - $gradebook_link_id = $link_info['id']; if ($link_info) { + $gradebook_link_id = $link_info['id']; $defaults['category_id'] = $link_info['category_id']; $gradebook_link_id = (int) $gradebook_link_id; $sql = "SELECT weight FROM $table_gradebook_link WHERE id = $gradebook_link_id"; @@ -204,7 +202,26 @@ $form->addElement( ); $extraField = new ExtraField('survey'); -$extraField->addElements($form, $survey_id); +$extraField->addElements($form, $survey_id, ['group_id']); + +if ($extraField->get_handler_field_info_by_field_variable('group_id')) { + $extraFieldValue = new ExtraFieldValue('survey'); + $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($survey_id, 'group_id'); + $groupValue = []; + if ($groupData && !empty($groupData['value'])) { + $groupInfo = GroupManager::get_group_properties($groupData['value']); + $groupValue = [$groupInfo['iid'] => $groupInfo['name']]; + } + + $form->addSelectAjax( + 'extra_group_id', + get_lang('Group'), + $groupValue, + [ + 'url' => api_get_path(WEB_AJAX_PATH).'group.ajax.php?a=search&'.api_get_cidreq(), + ] + ); +} // Additional Parameters $form->addButtonAdvancedSettings('advanced_params'); diff --git a/public/main/survey/fillsurvey.php b/public/main/survey/fillsurvey.php index 2e132985f4..4440568128 100644 --- a/public/main/survey/fillsurvey.php +++ b/public/main/survey/fillsurvey.php @@ -1,4 +1,5 @@ TOOL_SURVEY, 'tool_id' => $survey_invitation['survey_invitation_id'], - 'tool_id_detail' => 0, 'action' => 'invitationcode', 'action_details' => $invitationcode, ]; @@ -258,7 +258,9 @@ if (count($_POST) > 0) { // Looping through all the post values foreach ($_POST as $key => &$value) { // If the post value key contains the string 'question' then it is an answer on a question - if (false !== strpos($key, 'question') && ('_qf__question' != $key)) { + if (strpos($key, 'other_question') === false && + strpos($key, 'question') !== false && $key !== '_qf__question' + ) { // Finding the question id by removing 'question' $survey_question_id = str_replace('question', '', $key); // If not question ID was defined, we're on the start @@ -267,6 +269,9 @@ if (count($_POST) > 0) { if (empty($survey_question_id)) { continue; } + + $other = isset($_POST['other_question'.$survey_question_id]) ? $_POST['other_question'.$survey_question_id] : ''; + /* If the post value is an array then we have a multiple response question or a scoring question type remark: when it is a multiple response then the value of the array is the option_id when it is a scoring question then the key of the array is the option_id and the value is the value @@ -318,7 +323,6 @@ if (count($_POST) > 0) { } $survey_question_answer = $value; - SurveyUtil::remove_answer( $survey_invitation['user'], $survey_invitation['survey_id'], @@ -332,7 +336,8 @@ if (count($_POST) > 0) { $survey_question_id, $value, $option_value, - $survey_data + $survey_data, + $other ); } } @@ -546,6 +551,8 @@ if ('' != $survey_data['form_fields'] && } $htmlHeadXtra[] = ''; +$htmlHeadXtra[] = ch_selectivedisplay::getJs(); +$htmlHeadXtra[] = survey_question::getJs(); Display::display_header(get_lang('Surveys')); @@ -675,10 +682,15 @@ if ((isset($_GET['show']) && '' != $_GET['show']) || // As long as there is no pagebreak fount we keep adding questions to the page $questions_displayed = []; $counter = 0; - //$paged_questions = Session::read('paged_questions'); $paged_questions = []; // If non-conditional survey - if ('0' == $survey_data['survey_type']) { + $select = ''; + if (true === api_get_configuration_value('survey_question_dependency')) { + $select = ' survey_question.parent_id, survey_question.parent_option_id, '; + } + + // If non-conditional survey + if ($survey_data['survey_type'] == '0') { if (empty($paged_questions)) { $sql = "SELECT * FROM $table_survey_question WHERE @@ -729,6 +741,7 @@ if ((isset($_GET['show']) && '' != $_GET['show']) || survey_question.max_value, survey_question_option.question_option_id, survey_question_option.option_text, + $select survey_question_option.sort as option_sort FROM $table_survey_question survey_question LEFT JOIN $table_survey_question_option survey_question_option @@ -757,6 +770,7 @@ if ((isset($_GET['show']) && '' != $_GET['show']) || survey_question.max_value, survey_question_option.question_option_id, survey_question_option.option_text, + $select survey_question_option.sort as option_sort ".($allowRequiredSurveyQuestions ? ', survey_question.is_required' : '')." FROM $table_survey_question survey_question @@ -778,16 +792,19 @@ if ((isset($_GET['show']) && '' != $_GET['show']) || $questions = []; while ($row = Database :: fetch_array($result, 'ASSOC')) { // If the type is not a pagebreak we store it in the $questions array - if ('pagebreak' != $row['type']) { - $questions[$row['sort']]['question_id'] = $row['question_id']; - $questions[$row['sort']]['survey_id'] = $row['survey_id']; - $questions[$row['sort']]['survey_question'] = $row['survey_question']; - $questions[$row['sort']]['display'] = $row['display']; - $questions[$row['sort']]['type'] = $row['type']; - $questions[$row['sort']]['options'][$row['question_option_id']] = $row['option_text']; - $questions[$row['sort']]['maximum_score'] = $row['max_value']; - $questions[$row['sort']]['sort'] = $row['sort']; - $questions[$row['sort']]['is_required'] = $allowRequiredSurveyQuestions && $row['is_required']; + if ($row['type'] !== 'pagebreak') { + $sort = $row['sort']; + $questions[$sort]['question_id'] = $row['question_id']; + $questions[$sort]['survey_id'] = $row['survey_id']; + $questions[$sort]['survey_question'] = $row['survey_question']; + $questions[$sort]['display'] = $row['display']; + $questions[$sort]['type'] = $row['type']; + $questions[$sort]['options'][$row['question_option_id']] = $row['option_text']; + $questions[$sort]['maximum_score'] = $row['max_value']; + $questions[$sort]['sort'] = $sort; + $questions[$sort]['is_required'] = $allowRequiredSurveyQuestions && $row['is_required']; + $questions[$sort]['parent_id'] = isset($row['parent_id']) ? $row['parent_id'] : 0; + $questions[$sort]['parent_option_id'] = isset($row['parent_option_id']) ? $row['parent_option_id'] : 0; } $counter++; } @@ -1206,6 +1223,10 @@ $url = api_get_self().'?cid='.$courseInfo['real_id'].'&sid='.$sessionId.$add_par '&course='.$g_c. '&invitationcode='.$g_ic. '&show='.$show; +if (!empty($_GET['language'])) { + $lang = Security::remove_XSS($_GET['language']); + $url .= '&language='.$lang; +} $form = new FormValidator( 'question', 'post', @@ -1229,12 +1250,29 @@ if (isset($questions) && is_array($questions)) { $questionCounter = $before + 1; } + $form->addHtml('
'); + $js = ''; foreach ($questions as $key => &$question) { $ch_type = 'ch_'.$question['type']; $questionNumber = $questionCounter; - $display = survey_question::createQuestion($question['type']); + $display = new $ch_type(); + $parent = $question['parent_id']; + $parentClass = ''; // @todo move this in a function. - $form->addHtml('
'); + if (!empty($parent)) { + $parentClass = ' with_parent with_parent_'.$question['question_id']; + $parents = survey_question::getParents($question['question_id']); + if (!empty($parents)) { + foreach ($parents as $parentId) { + $parentClass .= ' with_parent_only_hide_'.$parentId; + } + } + } + + $js .= survey_question::getQuestionJs($question); + + // @todo move this in a function. + $form->addHtml('
'); $form->addHtml('
'.$questionNumber.'.
'); $form->addHtml('
'.Security::remove_XSS($question['survey_question']).'
'); @@ -1264,6 +1302,8 @@ if (isset($questions) && is_array($questions)) { $form->addHtml('
'); $questionCounter++; } + + $form->addHtml($js); } $form->addHtml('
'); diff --git a/public/main/survey/preview.php b/public/main/survey/preview.php index 8fb4875467..091e0cfc81 100644 --- a/public/main/survey/preview.php +++ b/public/main/survey/preview.php @@ -1,4 +1,5 @@ '.api_get_language_translate_html().''; - +$htmlHeadXtra[] = ch_selectivedisplay::getJs(); +$htmlHeadXtra[] = survey_question::getJs(); $show = 0; Display::display_header(get_lang('Survey preview')); @@ -85,7 +86,7 @@ if (isset($_GET['show'])) { WHERE survey_question NOT LIKE '%{{%' AND c_id = $course_id AND - survey_id = '".$surveyId."' + survey_id = $surveyId ORDER BY sort ASC"; $result = Database::query($sql); $questions_exists = true; @@ -110,6 +111,10 @@ if (isset($_GET['show'])) { } if (array_key_exists($_GET['show'], $paged_questions)) { + $select = ''; + if (true === api_get_configuration_value('survey_question_dependency')) { + $select = ' survey_question.parent_id, survey_question.parent_option_id, '; + } $sql = "SELECT survey_question.question_id, survey_question.survey_id, @@ -120,6 +125,7 @@ if (isset($_GET['show'])) { survey_question.max_value, survey_question_option.question_option_id, survey_question_option.option_text, + $select survey_question_option.sort as option_sort ".($allowRequiredSurveyQuestions ? ', survey_question.is_required' : '')." FROM $table_survey_question survey_question @@ -146,6 +152,8 @@ if (isset($_GET['show'])) { $questions[$sort]['type'] = $row['type']; $questions[$sort]['options'][$row['question_option_id']] = $row['option_text']; $questions[$sort]['maximum_score'] = $row['max_value']; + $questions[$sort]['parent_id'] = isset($row['parent_id']) ? $row['parent_id'] : 0; + $questions[$sort]['parent_option_id'] = isset($row['parent_option_id']) ? $row['parent_option_id'] : 0; $questions[$row['sort']]['is_required'] = $allowRequiredSurveyQuestions && $row['is_required']; } } @@ -161,6 +169,7 @@ if (isset($_GET['show'])) { $originalShow = isset($_GET['show']) ? (int) $_GET['show'] : 0; $url = api_get_self().'?survey_id='.$surveyId.'&show='.$show.'&'.api_get_cidreq(); + $form = new FormValidator( 'question-survey', 'post', @@ -181,16 +190,34 @@ if (is_array($questions) && count($questions) > 0) { } $counter = $before + 1; } + + $js = ''; foreach ($questions as $key => &$question) { $ch_type = 'ch_'.$question['type']; $display = survey_question::createQuestion($question['type']); - $form->addHtml('
'); + $parent = $question['parent_id']; + $parentClass = ''; + + if (!empty($parent)) { + $parentClass = ' with_parent with_parent_'.$question['question_id']; + $parents = survey_question::getParents($question['question_id']); + if (!empty($parents)) { + foreach ($parents as $parentId) { + $parentClass .= ' with_parent_only_hide_'.$parentId; + } + } + } + + $js .= survey_question::getQuestionJs($question); + + $form->addHtml('
'); $form->addHtml('
'.$counter.'.
'); $form->addHtml('
'.Security::remove_XSS($question['survey_question']).'
'); $display->render($form, $question); $form->addHtml('
'); $counter++; } + $form->addHtml($js); } $form->addHtml('
'); diff --git a/public/main/survey/question.php b/public/main/survey/question.php index 2c90149b40..02852bb7d8 100644 --- a/public/main/survey/question.php +++ b/public/main/survey/question.php @@ -1,4 +1,5 @@ '; +}); +'; $htmlHeadXtra[] = ''; @@ -22,8 +24,9 @@ if (!api_is_allowed_to_edit(false, true)) { api_not_allowed(true); } +$surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0; // Getting the survey information -$surveyData = SurveyManager::get_survey($_GET['survey_id']); +$surveyData = SurveyManager::get_survey($surveyId); if (empty($surveyData)) { api_not_allowed(true); } @@ -38,13 +41,13 @@ if (1 == $surveyData['survey_type']) { $sql = 'SELECT id FROM '.Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP).' WHERE c_id = '.$course_id.' AND - survey_id = '.(int) $_GET['survey_id'].' LIMIT 1'; + survey_id = '.$surveyId.' LIMIT 1'; $rs = Database::query($sql); if (0 === Database::num_rows($rs)) { Display::addFlash( Display::return_message(get_lang('You need to create groups')) ); - header('Location: '.api_get_path(WEB_CODE_PATH).'survey/survey.php?survey_id='.(int) $_GET['survey_id']); + header('Location: '.api_get_path(WEB_CODE_PATH).'survey/survey.php?survey_id='.$surveyId); exit; } } @@ -55,7 +58,7 @@ $interbreadcrumb[] = [ 'name' => get_lang('Survey list'), ]; $interbreadcrumb[] = [ - 'url' => api_get_path(WEB_CODE_PATH).'survey/survey.php?survey_id='.intval($_GET['survey_id']), + 'url' => api_get_path(WEB_CODE_PATH).'survey/survey.php?survey_id='.$surveyId, 'name' => strip_tags($urlname), ]; @@ -79,6 +82,8 @@ $possible_types = [ 'pagebreak', 'percentage', 'score', + 'selectivedisplay', + 'multiplechoiceother', ]; // Actions @@ -88,10 +93,7 @@ $actions .= ' 1) { // Checks length of the question $empty_answer = false; - - if (1 == $survey_data['survey_type']) { + if ($survey_data['survey_type'] == 1) { if (empty($form_content['choose'])) { - $return_message = 'PleaseChooseACondition'; - - return $return_message; + return 'PleaseChooseACondition'; } - if ((2 == $form_content['choose']) && + if (($form_content['choose'] == 2) && ($form_content['assigned1'] == $form_content['assigned2']) ) { - $return_message = 'ChooseDifferentCategories'; - - return $return_message; + return 'ChooseDifferentCategories'; } } - if ('percentage' != $form_content['type']) { + if ($form_content['type'] !== 'percentage') { if (isset($form_content['answers'])) { for ($i = 0; $i < count($form_content['answers']); $i++) { if (strlen($form_content['answers'][$i]) < 1) { @@ -1154,16 +1159,19 @@ class SurveyManager $empty_answer = true; } } + $course_id = api_get_course_int_id(); + if (!$empty_answer) { // Table definitions $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION); + $surveyId = (int) $form_content['survey_id']; // Getting all the information of the survey - $survey_data = self::get_survey($form_content['survey_id']); + $survey_data = self::get_survey($surveyId); // Storing the question in the shared database - if (is_numeric($survey_data['survey_share']) && 0 != $survey_data['survey_share']) { + if (is_numeric($survey_data['survey_share']) && $survey_data['survey_share'] != 0) { $shared_question_id = self::save_shared_question($form_content, $survey_data); $form_content['shared_question_id'] = $shared_question_id; } @@ -1173,7 +1181,7 @@ class SurveyManager // Finding the max sort order of the questions in the given survey $sql = "SELECT max(sort) AS max_sort FROM $tbl_survey_question - WHERE c_id = $course_id AND survey_id='".intval($form_content['survey_id'])."'"; + WHERE c_id = $course_id AND survey_id = $surveyId "; $result = Database::query($sql); $row = Database::fetch_array($result, 'ASSOC'); $max_sort = $row['max_sort']; @@ -1207,6 +1215,19 @@ class SurveyManager $question->setIsMandatory(isset($form_content['is_required'])); } + if (api_get_configuration_value('survey_question_dependency')) { + $params['parent_id'] = 0; + $params['parent_option_id'] = 0; + if (isset($form_content['parent_id']) && + isset($form_content['parent_option_id']) && + !empty($form_content['parent_id']) && + !empty($form_content['parent_option_id']) + ) { + $params['parent_id'] = $form_content['parent_id']; + $params['parent_option_id'] = $form_content['parent_option_id']; + } + } + $em = Database::getManager(); $em->persist($question); $em->flush(); @@ -1251,6 +1272,19 @@ class SurveyManager $params['is_required'] = isset($form_content['is_required']); } + if (api_get_configuration_value('survey_question_dependency')) { + $params['parent_id'] = 0; + $params['parent_option_id'] = 0; + if (isset($form_content['parent_id']) && + isset($form_content['parent_option_id']) && + !empty($form_content['parent_id']) && + !empty($form_content['parent_option_id']) + ) { + $params['parent_id'] = $form_content['parent_id']; + $params['parent_option_id'] = $form_content['parent_option_id']; + } + } + $params = array_merge($params, $extraParams); Database::update( $tbl_survey_question, @@ -1277,7 +1311,7 @@ class SurveyManager } // Storing the options of the question - self::save_question_options($form_content, $survey_data); + self::save_question_options($form_content, $survey_data, $dataFromDatabase); } else { $return_message = 'PleasFillAllAnswer'; } @@ -1285,8 +1319,10 @@ class SurveyManager $return_message = 'PleaseEnterAQuestion'; } - if (!empty($return_message)) { - Display::addFlash(Display::return_message(get_lang($return_message))); + if ($showMessage) { + if (!empty($return_message)) { + Display::addFlash(Display::return_message(get_lang($return_message))); + } } return $return_message; @@ -1531,9 +1567,10 @@ class SurveyManager * * @todo writing the update statement when editing a question */ - public static function save_question_options($form_content, $survey_data) + public static function save_question_options($form_content, $survey_data, $dataFromDatabase = []) { $course_id = api_get_course_int_id(); + $type = $form_content['type']; // A percentage question type has options 1 -> 100 if ('percentage' === $form_content['type']) { for ($i = 1; $i < 101; $i++) { @@ -1546,42 +1583,108 @@ class SurveyManager } // Table definition - $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION); + $table = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION); // We are editing a question so we first have to remove all the existing options from the database - if (is_numeric($form_content['question_id'])) { - $sql = "DELETE FROM $table_survey_question_option - WHERE c_id = $course_id AND question_id = '".intval($form_content['question_id'])."'"; + $optionsToDelete = []; + if (isset($dataFromDatabase['answer_data'])) { + foreach ($dataFromDatabase['answer_data'] as $data) { + if ('other' === $data['data'] && 'multiplechoiceother' === $type) { + continue; + } + + if (!in_array($data['iid'], $form_content['answersid'])) { + $optionsToDelete[] = $data['iid']; + } + } + } + + if (!empty($optionsToDelete)) { + foreach ($optionsToDelete as $iid) { + $iid = (int) $iid; + $sql = "DELETE FROM $table + WHERE + iid = $iid AND + c_id = $course_id AND + question_id = '".intval($form_content['question_id'])."' + "; Database::query($sql); + } } $counter = 1; - $em = Database::getManager(); if (isset($form_content['answers']) && is_array($form_content['answers'])) { for ($i = 0; $i < count($form_content['answers']); $i++) { - $values = isset($form_content['values']) ? $form_content['values'][$i] : 0; - $option = new CSurveyQuestionOption(); - $option - ->setCId($course_id) - ->setQuestionId($form_content['question_id']) - ->setSurveyId($form_content['survey_id']) - ->setOptionText($form_content['answers'][$i]) - ->setValue($values) - ->setSort($counter) - ; + $values = isset($form_content['values']) ? $form_content['values'][$i] : ''; + $answerId = 0; + if (isset($form_content['answersid']) && isset($form_content['answersid'][$i])) { + $answerId = $form_content['answersid'][$i]; + } + if (empty($answerId)) { + $params = [ + 'c_id' => $course_id, + 'question_id' => $form_content['question_id'], + 'survey_id' => $form_content['survey_id'], + 'option_text' => $form_content['answers'][$i], + 'value' => $values, + 'sort' => $counter, + ]; + $insertId = Database::insert($table, $params); + if ($insertId) { + $sql = "UPDATE $table + SET question_option_id = $insertId + WHERE iid = $insertId"; + Database::query($sql); + $counter++; + } + } else { + $params = [ + 'option_text' => $form_content['answers'][$i], + 'value' => $values, + 'sort' => $counter, + ]; + Database::update($table, $params, ['iid = ?' => [$answerId]]); + $counter++; + } + } + } - $em->persist($option); - $em->flush(); + if ('multiplechoiceother' === $type) { - $insertId = $option->getIid(); + if (empty($dataFromDatabase['answer_data'])) { + $params = [ + 'c_id' => $course_id, + 'question_id' => $form_content['question_id'], + 'survey_id' => $form_content['survey_id'], + 'option_text' => 'other', + 'value' => 0, + 'sort' => $counter, + ]; + $insertId = Database::insert($table, $params); if ($insertId) { - $sql = "UPDATE $table_survey_question_option + $sql = "UPDATE $table SET question_option_id = $insertId WHERE iid = $insertId"; Database::query($sql); - - $counter++; } + } else { + $params = [ + 'option_text' => 'other', + 'value' => 0, + 'sort' => $counter, + ]; + Database::update( + $table, + $params, + [ + 'c_id = ? AND question_id = ? AND survey_id = ? AND option_text = ?' => [ + $course_id, + $form_content['question_id'], + $form_content['survey_id'], + 'other', + ], + ] + ); } } } @@ -1851,9 +1954,7 @@ class SurveyManager */ public static function generate_survey_hash($survey_id, $course_id, $session_id, $group_id) { - $hash = hash('sha512', api_get_security_key().'_'.$course_id.'_'.$session_id.'_'.$group_id.'_'.$survey_id); - - return $hash; + return hash('sha512', api_get_security_key().'_'.$course_id.'_'.$session_id.'_'.$group_id.'_'.$survey_id); } /** @@ -2184,22 +2285,72 @@ class SurveyManager $questions = self::get_questions($surveyId); - $obj = new UserGroup(); + if (empty($questions)) { + return false; + } + $obj = new UserGroup(); $options['where'] = [' usergroup.course_id = ? ' => $courseId]; $classList = $obj->getUserGroupInCourse($options); - $classTag = '{{class_name}}'; - $studentTag = '{{student_full_name}}'; - $classCounter = 0; + $classToParse = []; foreach ($classList as $class) { - $className = $class['name']; - foreach ($questions as $question) { $users = $obj->get_users_by_usergroup($class['id']); if (empty($users)) { continue; + } + $classToParse[] = [ + 'name' => $class['name'], + 'users' => $users, + ]; } + self::parseMultiplicateUserList($classToParse, $questions, $courseId, $surveyData); + + $extraFieldValue = new ExtraFieldValue('survey'); + $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($surveyId, 'group_id'); + if ($groupData && !empty($groupData['value'])) { + $groupInfo = GroupManager::get_group_properties($groupData['value']); + if (!empty($groupInfo)) { + $users = GroupManager::getStudents($groupInfo['iid'], true); + if (!empty($users)) { + $users = array_column($users, 'id'); + $classToParse = [ + [ + 'name' => $groupInfo['name'], + 'users' => $users, + ], + ]; + self::parseMultiplicateUserList($classToParse, $questions, $courseId, $surveyData); + } + } + } + + return true; + } + + public static function parseMultiplicateUserList($itemList, $questions, $courseId, $surveyData) + { + if (empty($itemList) || empty($questions)) { + return false; + } + + $surveyId = $surveyData['survey_id']; + $classTag = '{{class_name}}'; + $studentTag = '{{student_full_name}}'; + $classCounter = 0; + + $newQuestionList = []; + foreach ($questions as $question) { + $newQuestionList[$question['sort']] = $question; + } + ksort($newQuestionList); + + foreach ($itemList as $class) { + $className = $class['name']; + $users = $class['users']; + + foreach ($newQuestionList as $question) { $text = $question['question']; if (false !== strpos($text, $classTag)) { $replacedText = str_replace($classTag, $className, $text); @@ -2208,12 +2359,14 @@ class SurveyManager 'question_comment' => 'generated', 'type' => $question['type'], 'display' => $question['horizontalvertical'], + 'horizontalvertical' => $question['horizontalvertical'], 'question' => $replacedText, 'survey_id' => $surveyId, 'question_id' => 0, 'shared_question_id' => 0, + 'answers' => $question['answers'], ]; - self::save_question($surveyData, $values); + self::save_question($surveyData, $values, false); $classCounter++; continue; } @@ -2243,11 +2396,11 @@ class SurveyManager } } $values['answers'] = $answers; - self::save_question($surveyData, $values); + self::save_question($surveyData, $values, false); } } - if ($classCounter < count($classList)) { + if ($classCounter < count($itemList)) { // Add end page $values = [ 'c_id' => $courseId, @@ -2259,10 +2412,12 @@ class SurveyManager 'question_id' => 0, 'shared_question_id' => 0, ]; - self::save_question($surveyData, $values); + self::save_question($surveyData, $values, false); } } } + + return true; } /** @@ -2513,4 +2668,54 @@ class SurveyManager return $content; } + + public static function sendToTutors($surveyId) + { + $survey = Database::getManager()->getRepository('ChamiloCourseBundle:CSurvey')->find($surveyId); + if (null === $survey) { + return false; + } + + $extraFieldValue = new ExtraFieldValue('survey'); + $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($surveyId, 'group_id'); + if ($groupData && !empty($groupData['value'])) { + $groupInfo = GroupManager::get_group_properties($groupData['value']); + if ($groupInfo) { + $tutors = GroupManager::getTutors($groupInfo); + if (!empty($tutors)) { + SurveyUtil::saveInviteMail( + $survey, + ' ', + ' ', + false + ); + + foreach ($tutors as $tutor) { + $subject = sprintf(get_lang('GroupSurveyX'), $groupInfo['name']); + $content = sprintf( + get_lang('HelloXGroupX'), + $tutor['complete_name'], + $groupInfo['name'] + ); + + SurveyUtil::saveInvitations( + ['users' => $tutor['user_id']], + $subject, + $content, + false, + true, + false, + true + ); + } + Display::addFlash(Display::return_message(get_lang('Updated'), 'confirmation', false)); + } + SurveyUtil::update_count_invited($survey->getCode()); + + return true; + } + } + + return false; + } } diff --git a/public/main/survey/survey.php b/public/main/survey/survey.php index b0439de161..86a6641d9e 100644 --- a/public/main/survey/survey.php +++ b/public/main/survey/survey.php @@ -1,4 +1,5 @@ get_lang('Survey list'), ]; +Session::erase('answer_count'); +Session::erase('answer_list'); + // Getting the survey information if (!empty($_GET['survey_id'])) { $course_code = api_get_course_id(); @@ -194,10 +195,17 @@ if (0 == $survey_data['survey_type']) { Display::return_icon('commentquestion.png', get_lang('Comment'), null, ICON_SIZE_BIG), $urlQuestion.'&type=comment&survey_id='.$survey_id ); - - if (0 == $survey_data['one_question_per_page']) { echo Display::url( - Display::return_icon('page_end.png', get_lang('Page end (distinct questions)'), null, ICON_SIZE_BIG), + Display::return_icon('mcua.png', get_lang('SurveyMultipleAnswerWithOther'), null, ICON_SIZE_BIG), + $urlQuestion.'&type=multiplechoiceother&survey_id='.$survey_id + ); + if ($survey_data['one_question_per_page'] == 0) { + echo Display::url( + Display::return_icon('yesno.png', get_lang('SurveyQuestionSelectiveDisplay'), null, ICON_SIZE_BIG), + $urlQuestion.'&type=selectivedisplay&survey_id='.$survey_id + ); + echo Display::url( + Display::return_icon('page_end.png', get_lang('Pagebreak'), null, ICON_SIZE_BIG), $urlQuestion.'&type=pagebreak&survey_id='.$survey_id ); } @@ -269,10 +277,14 @@ while ($row = Database::fetch_array($result, 'ASSOC')) { echo api_get_local_time($parts[0]).' - '.api_get_local_time($parts[1]); } - if ('yesno' == $row['type']) { - $tool_name = get_lang('Yes / No'); - } elseif ('multiplechoice' == $row['type']) { - $tool_name = get_lang('Multiple choice'); + if ($row['type'] === 'yesno') { + $tool_name = get_lang('YesNo'); + } elseif ($row['type'] === 'multiplechoice') { + $tool_name = get_lang('UniqueSelect'); + } elseif ($row['type'] === 'multipleresponse') { + $tool_name = get_lang('MultipleChoiceMultipleAnswers'); + } elseif ($row['type'] === 'selectivedisplay') { + $tool_name = get_lang('SurveyQuestionSelectiveDisplay'); } else { $tool_name = get_lang(api_ucfirst(Security::remove_XSS($row['type']))); } diff --git a/public/main/survey/surveyUtil.class.php b/public/main/survey/surveyUtil.class.php index 9db050da87..29c811f5f2 100644 --- a/public/main/survey/surveyUtil.class.php +++ b/public/main/survey/surveyUtil.class.php @@ -101,7 +101,8 @@ class SurveyUtil $question_id, $option_id, $option_value, - $survey_data + $survey_data, + $otherOption = '' ) { // If the question_id is empty, don't store an answer if (empty($question_id)) { @@ -122,6 +123,11 @@ class SurveyUtil } } + if (!empty($otherOption)) { + $option_id = $option_id.'@:@'.$otherOption; + } + + $answer = new CSurveyAnswer(); $answer ->setCId($survey_data['c_id']) @@ -141,9 +147,11 @@ class SurveyUtil $sql = "UPDATE $table_survey_answer SET answer_id = $insertId WHERE iid = $insertId"; Database::query($sql); - } - return true; + return true; + } + + return false; } /** @@ -234,20 +242,16 @@ class SurveyUtil $action = isset($_GET['action']) ? $_GET['action'] : ''; // Getting the number of question - $temp_questions_data = SurveyManager::get_questions($_GET['survey_id']); - - // Sorting like they should be displayed and removing the non-answer question types (comment and pagebreak) - $my_temp_questions_data = null == $temp_questions_data ? [] : $temp_questions_data; - $questions_data = []; + $questions = SurveyManager::get_questions($survey_data['survey_id']); - foreach ($my_temp_questions_data as $key => &$value) { - if ('pagebreak' != $value['type']) { - $questions_data[$value['sort']] = $value; + $counter = 0; + foreach ($questions as $key => $value) { + if ($value['type'] !== 'pagebreak') { + $counter++; } } - // Counting the number of questions that are relevant for the reporting - $survey_data['number_of_questions'] = count($questions_data); + $survey_data['number_of_questions'] = $counter; switch ($action) { case 'questionreport': @@ -573,7 +577,7 @@ class SurveyUtil // Determining the offset of the sql statement (the n-th question of the survey) $offset = !isset($_GET['question']) ? 0 : (int) $_GET['question']; $currentQuestion = isset($_GET['question']) ? (int) $_GET['question'] : 0; - $surveyId = (int) $_GET['survey_id']; + $surveyId = (int) $survey_data['survey_id']; $action = Security::remove_XSS($_GET['action']); $course_id = api_get_course_int_id(); @@ -651,8 +655,8 @@ class SurveyUtil $sql = "SELECT * FROM $table_survey_answer WHERE c_id = $course_id AND - survey_id='".$surveyId."' AND - question_id = '".$questionId."'"; + survey_id= $surveyId AND + question_id = $questionId "; $result = Database::query($sql); while ($row = Database::fetch_array($result, 'ASSOC')) { echo $row['option_id'].'
'; @@ -662,19 +666,20 @@ class SurveyUtil $sql = "SELECT * FROM $table_survey_question_option WHERE c_id = $course_id AND - survey_id='".$surveyId."' - AND question_id = '".$questionId."' + survey_id = $surveyId AND + question_id = $questionId ORDER BY sort ASC"; $result = Database::query($sql); while ($row = Database::fetch_array($result, 'ASSOC')) { $options[$row['question_option_id']] = $row; } // Getting the answers - $sql = "SELECT *, count(answer_id) as total FROM $table_survey_answer + $sql = "SELECT *, count(answer_id) as total + FROM $table_survey_answer WHERE c_id = $course_id AND - survey_id='".$surveyId."' - AND question_id = '".$questionId."' + survey_id = $surveyId AND + question_id = $questionId GROUP BY option_id, value"; $result = Database::query($sql); $number_of_answers = []; @@ -684,18 +689,27 @@ class SurveyUtil $number_of_answers[$row['question_id']] = 0; } $number_of_answers[$row['question_id']] += $row['total']; + + if ('multiplechoiceother' === $question['type']) { + $parts = ch_multiplechoiceother::decodeOptionValue($row['option_id']); + $row['option_id'] = $parts[0]; + } + $data[$row['option_id']] = $row; } foreach ($options as $option) { $optionText = strip_tags($option['option_text']); $optionText = html_entity_decode($optionText); - $votes = isset($data[$option['question_option_id']]['total']) ? - $data[$option['question_option_id']]['total'] : '0'; + $votes = 0; + if (isset($data[$option['question_option_id']]['total'])) { + $votes = $data[$option['question_option_id']]['total']; + } array_push($chartData, ['option' => $optionText, 'votes' => $votes]); } $chartContainerId = 'chartContainer'.$question['question_id']; echo '
'; + echo self::drawChart($chartData, false, $chartContainerId); // displaying the table: headers @@ -710,6 +724,10 @@ class SurveyUtil // Displaying the table: the content if (is_array($options)) { foreach ($options as $key => &$value) { + if ('multiplechoiceother' === $question['type'] && 'other' === $value['option_text']) { + $value['option_text'] = get_lang('SurveyOtherAnswer'); + } + $absolute_number = null; if (isset($data[$value['question_option_id']])) { $absolute_number = $data[$value['question_option_id']]['total']; @@ -813,12 +831,13 @@ class SurveyUtil $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION); $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER); $course_id = api_get_course_int_id(); + $surveyId = $survey_data['survey_id']; // Getting the options $sql = "SELECT * FROM $table_survey_question_option WHERE c_id = $course_id AND - survey_id='".intval($_GET['survey_id'])."' AND + survey_id= $surveyId AND question_id = '".intval($question['question_id'])."' ORDER BY sort ASC"; $result = Database::query($sql); @@ -831,7 +850,7 @@ class SurveyUtil FROM $table_survey_answer WHERE c_id = $course_id AND - survey_id='".intval($_GET['survey_id'])."' AND + survey_id= $surveyId AND question_id = '".Database::escape_string($question['question_id'])."' GROUP BY option_id, value"; $result = Database::query($sql); @@ -846,7 +865,11 @@ class SurveyUtil $optionText = strip_tags($option['option_text']); $optionText = html_entity_decode($optionText); for ($i = 1; $i <= $question['max_value']; $i++) { - $votes = $data[$option['question_option_id']][$i]['total']; + $votes = null; + if (isset($data[$option['question_option_id']][$i])) { + $votes = $data[$option['question_option_id']][$i]['total']; + } + if (empty($votes)) { $votes = '0'; } @@ -865,7 +888,7 @@ class SurveyUtil echo '
'; // Displaying the table: headers - echo ''; + echo '
'; echo ' '; echo ' '; echo ' '; @@ -876,12 +899,16 @@ class SurveyUtil // Displaying the table: the content foreach ($options as $key => &$value) { for ($i = 1; $i <= $question['max_value']; $i++) { - $absolute_number = $data[$value['question_option_id']][$i]['total']; + $absolute_number = null; + if (isset($data[$value['question_option_id']][$i])) { + $absolute_number = $data[$value['question_option_id']][$i]['total']; + } + echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; - echo '
 '.get_lang('Score').'
'.$value['option_text'].''.$i.''.$absolute_number.''.round($absolute_number / $number_of_answers * 100, 2).' %'; @@ -901,7 +928,6 @@ class SurveyUtil echo '   
'; } @@ -952,6 +978,8 @@ class SurveyUtil .Display::return_icon('export_csv.png', get_lang('CSV export'), '', ICON_SIZE_MEDIUM).'
'; $content .= '' .Display::return_icon('export_excel.png', get_lang('Excel export'), '', ICON_SIZE_MEDIUM).''; + $content .= '' + .Display::return_icon('export_compact_csv.png', get_lang('ExportAsCompactCSV'), '', ICON_SIZE_MEDIUM).''; $content .= '
'; // The form @@ -967,6 +995,12 @@ class SurveyUtil $content .= ''; $content .= ''; $content .= ''; + $content .= '
'; + $content .= ''; + $content .= ''; + $content .= '
'; } $content .= '
"; $content .= $answers_of_user[$question_id][$option_id]['value']; @@ -1317,7 +1362,7 @@ class SurveyUtil * * @version February 2007 */ - public static function export_complete_report($survey_data, $user_id = 0) + public static function export_complete_report($survey_data, $user_id = 0, $compact = false) { $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0; @@ -1325,12 +1370,18 @@ class SurveyUtil return false; } - $course_id = api_get_course_int_id(); + $course = api_get_course_info(); + $course_id = $course['real_id']; $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION); $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION); $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER); + $translate = false; + if (api_get_configuration_value('translate_html') == true) { + $translate = true; + } + // The first column $return = ';'; @@ -1367,6 +1418,9 @@ class SurveyUtil $result = Database::query($sql); while ($row = Database::fetch_array($result)) { + if ($translate) { + $row['survey_question'] = api_get_filtered_multilingual_HTML_string($row['survey_question'], $course['language']); + } // We show the questions if // 1. there is no question filter and the export button has not been clicked // 2. there is a quesiton filter but the question is selected for display @@ -1375,7 +1429,7 @@ class SurveyUtil is_array($_POST['questions_filter']) && in_array($row['question_id'], $_POST['questions_filter'])) ) { - if (0 == $row['number_of_options']) { + if ($row['number_of_options'] == 0 or $compact) { $return .= str_replace( "\r\n", ' ', @@ -1401,6 +1455,9 @@ class SurveyUtil // Show the fields names for user fields if (!empty($extra_user_fields)) { foreach ($extra_user_fields as &$field) { + if ($translate) { + $field[3] = api_get_filtered_multilingual_HTML_string($field[3], $course['language']); + } $return .= '"' .str_replace( "\r\n", @@ -1439,14 +1496,21 @@ class SurveyUtil // We show the options if // 1. there is no question filter and the export button has not been clicked // 2. there is a question filter but the question is selected for display + if ($translate) { + $row['option_text'] = api_get_filtered_multilingual_HTML_string($row['option_text'], $course['language']); + } if (!(isset($_POST['submit_question_filter'])) || ( is_array($_POST['questions_filter']) && in_array($row['question_id'], $_POST['questions_filter']) ) ) { $row['option_text'] = str_replace(["\r", "\n"], ['', ''], $row['option_text']); - $return .= api_html_entity_decode(strip_tags($row['option_text']), ENT_QUOTES).';'; - $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id']; + if (!$compact) { + $return .= api_html_entity_decode(strip_tags($row['option_text']), ENT_QUOTES).';'; + $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id']; + } else { + $possible_answers[$row['question_id']][$row['question_option_id']] = $row['option_text']; + } $possible_answers_type[$row['question_id']] = $row['type']; } } @@ -1459,10 +1523,11 @@ class SurveyUtil $sql = "SELECT * FROM $table_survey_answer WHERE c_id = $course_id AND - survey_id='".$surveyId."' + survey_id = $surveyId "; - if (0 != $user_id) { - $sql .= "AND user='".Database::escape_string($user_id)."' "; + if ($user_id != 0) { + $user_id = intval($user_id); + $sql .= " AND user = $user_id "; } $sql .= ' ORDER BY user ASC '; @@ -1479,7 +1544,8 @@ class SurveyUtil $possible_answers, $answers_of_user, $old_user, - true + true, + $compact ); $answers_of_user = []; } @@ -1502,7 +1568,8 @@ class SurveyUtil $possible_answers, $answers_of_user, $old_user, - true + true, + $compact ); return $return; @@ -1527,7 +1594,8 @@ class SurveyUtil $possible_options, $answers_of_user, $user, - $display_extra_user_fields = false + $display_extra_user_fields = false, + $compact = false ) { $return = ''; if (0 == $survey_data['anonymous']) { @@ -1560,13 +1628,16 @@ class SurveyUtil } } + if (is_array($possible_options)) { foreach ($possible_options as $question_id => $possible_option) { if (is_array($possible_option) && count($possible_option) > 0) { foreach ($possible_option as $option_id => &$value) { - $my_answer_of_user = !isset($answers_of_user[$question_id]) || isset($answers_of_user[$question_id]) && null == $answers_of_user[$question_id] ? [] : $answers_of_user[$question_id]; + // For each option of this question, look if it matches the user's answer + $my_answer_of_user = !isset($answers_of_user[$question_id]) || isset($answers_of_user[$question_id]) && $answers_of_user[$question_id] == null ? [] : $answers_of_user[$question_id]; $key = array_keys($my_answer_of_user); - if (isset($key[0]) && 'open' == substr($key[0], 0, 4)) { + if (isset($key[0]) && substr($key[0], 0, 4) == 'open') { + // If this is an open type question (type starts by 'open'), take whatever answer is given $return .= '"'. str_replace( '"', @@ -1578,16 +1649,42 @@ class SurveyUtil ENT_QUOTES ) ). - '"'; + '";'; } elseif (!empty($answers_of_user[$question_id][$option_id])) { //$return .= 'v'; - if (0 != $answers_of_user[$question_id][$option_id]['value']) { - $return .= $answers_of_user[$question_id][$option_id]['value']; + if ($compact) { + // If we asked for a compact view, show only one column for the question + // and fill it with the text of the selected option (i.e. "Yes") instead of an ID + if ($answers_of_user[$question_id][$option_id]['value'] != 0) { + $return .= $answers_of_user[$question_id][$option_id]['value'].";"; } else { - $return .= 'v'; + $return .= '"'. + str_replace( + '"', + '""', + api_html_entity_decode( + strip_tags( + $possible_option[$option_id] + ), + ENT_QUOTES + ) + ). + '";'; } + } else { + // If we don't want a compact view, show one column per possible option and mark a 'v' + // or the defined value in the corresponding column if the user selected it + if ($answers_of_user[$question_id][$option_id]['value'] != 0) { + $return .= $answers_of_user[$question_id][$option_id]['value'].";"; + } else { + $return .= 'v;'; } + } + } else { + if (!$compact) { $return .= ';'; + } + } } } } @@ -1609,11 +1706,11 @@ class SurveyUtil * * @version February 2007 */ - public static function export_complete_report_xls($survey_data, $filename, $user_id = 0) + public static function export_complete_report_xls($survey_data, $filename, $user_id = 0, $returnFile = false) { $course_id = api_get_course_int_id(); $user_id = (int) $user_id; - $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0; + $surveyId = $survey_data['survey_id']; if (empty($course_id) || empty($surveyId)) { return false; @@ -2233,34 +2330,19 @@ class SurveyUtil return $counter; } - /** - * Save the invitation mail. - * - * @param string Text of the e-mail - * @param int Whether the mail contents are for invite mail (0, default) or reminder mail (1) - * - * @author Patrick Cool , Ghent University - * - * @version January 2007 - */ - public static function save_invite_mail($mailtext, $mail_subject, $reminder = 0) + public static function saveInviteMail(CSurvey $survey, $content, $subject, $remind) { - $course_id = api_get_course_int_id(); // Database table definition - $table_survey = Database::get_course_table(TABLE_SURVEY); - - // Reminder or not - if (0 == $reminder) { - $mail_field = 'invite_mail'; + if ($remind) { + $survey->setReminderMail($content); } else { - $mail_field = 'reminder_mail'; + $survey->setInviteMail($content); } - $sql = "UPDATE $table_survey SET - mail_subject='".Database::escape_string($mail_subject)."', - $mail_field = '".Database::escape_string($mailtext)."' - WHERE c_id = $course_id AND survey_id = '".intval($_GET['survey_id'])."'"; - Database::query($sql); + $survey->setMailSubject($subject); + $em = Database::getManager(); + $em->persist($survey); + $em->flush(); } /** @@ -2294,8 +2376,6 @@ class SurveyUtil $hideLink = false ) { if (!is_array($users_array)) { - // Should not happen - return 0; } @@ -3023,6 +3103,15 @@ class SurveyUtil $codePath.'survey/survey_invite.php?'.http_build_query($params + ['survey_id' => $survey_id]) ); + $extraFieldValue = new ExtraFieldValue('survey'); + $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($survey_id, 'group_id'); + if ($groupData && !empty($groupData['value'])) { + $actions[] = Display::url( + Display::return_icon('teacher.png', get_lang('SendToGroupTutors')), + $codePath.'survey/survey_list.php?action=send_to_tutors&'.http_build_query($params + ['survey_id' => $survey_id]) + ); + } + if (3 != $type) { $actions[] = $hideReportingButton ? null : $reportingLink; } @@ -3961,6 +4050,9 @@ class SurveyUtil if (!empty($surveyCode)) { $params['scode'] = Security::remove_XSS($surveyCode); } + if (!empty($courseInfo['language'])) { + $params['language'] = $courseInfo['language']; + } return api_get_path(WEB_CODE_PATH).'survey/fillsurvey.php?'.http_build_query($params); } diff --git a/public/main/survey/survey_invite.php b/public/main/survey/survey_invite.php index 88d86cd6c7..92d3eddb0e 100644 --- a/public/main/survey/survey_invite.php +++ b/public/main/survey/survey_invite.php @@ -1,4 +1,5 @@ , Ghent University: cleanup, refactoring and rewriting large parts of the code * @author Julio Montoya Chamilo: cleanup, refactoring, security improvements * - * @version $Id: survey_invite.php 10680 2007-01-11 21:26:23Z pcool $ - * * @todo checking if the additional emails are valid (or add a rule for this) * @todo check if the mailtext contains the **link** part, if not, add the link to the end * @todo add rules: title and text cannot be empty diff --git a/public/main/survey/survey_list.php b/public/main/survey/survey_list.php index 63db00a554..ed92c7ba10 100644 --- a/public/main/survey/survey_list.php +++ b/public/main/survey/survey_list.php @@ -6,8 +6,6 @@ * @author Patrick Cool , Ghent University: cleanup, refactoring and rewriting large parts of the code * @author Julio Montoya Armas , Chamilo: Personality Test modification and rewriting large parts of the code * - * @version $Id: survey_list.php 21933 2009-07-09 06:08:22Z ivantcholakov $ - * * @todo use quickforms for the forms */ if (!isset($_GET['cidReq'])) { @@ -28,8 +26,6 @@ Event::event_access_tool(TOOL_SURVEY); $logInfo = [ 'tool' => TOOL_SURVEY, - 'tool_id' => 0, - 'tool_id_detail' => 0, ]; Event::registerLog($logInfo); @@ -48,7 +44,6 @@ $htmlHeadXtra[] = ''; if ($isDrhOfCourse) { Display::display_header(get_lang('Survey list')); - // Tool introduction Display::display_introduction_section('survey', 'left'); SurveyUtil::displaySurveyListForDrh(); Display::display_footer(); @@ -58,7 +53,6 @@ if ($isDrhOfCourse) { if (!api_is_allowed_to_edit(false, true)) { // Coach can see this Display::display_header(get_lang('Survey list')); - // Tool introduction Display::display_introduction_section('survey', 'left'); SurveyUtil::getSurveyList($currentUserId); Display::display_footer(); @@ -67,6 +61,9 @@ if (!api_is_allowed_to_edit(false, true)) { $extend_rights_for_coachs = api_get_setting('extend_rights_for_coach_on_survey'); +Session::erase('answer_count'); +Session::erase('answer_list'); +$tool_name = get_lang('SurveyList'); // Database table definitions if (isset($_GET['search']) && 'advanced' == $_GET['search']) { $interbreadcrumb[] = [ @@ -81,22 +78,134 @@ if (isset($_GET['search']) && 'advanced' == $_GET['search']) { $listUrl = api_get_path(WEB_CODE_PATH).'survey/survey_list.php?'.api_get_cidreq(); $surveyId = isset($_GET['survey_id']) ? $_GET['survey_id'] : 0; +// Action handling: performing the same action on multiple surveys +if (isset($_POST['action']) && $_POST['action'] && isset($_POST['id']) && is_array($_POST['id'])) { + if (!api_is_allowed_to_edit()) { + api_not_allowed(true); + } + + $exportList = []; + foreach ($_POST['id'] as $value) { + $surveyData = SurveyManager::get_survey($value); + if (empty($surveyData)) { + continue; + } + $surveyData['title'] = trim(strip_tags($surveyData['title'])); + switch ($action) { - case 'remove_multiplicate': - $surveyData = SurveyManager::get_survey($surveyId); - if (!empty($surveyData)) { - SurveyManager::removeMultiplicateQuestions($surveyData); - Display::addFlash(Display::return_message(get_lang('Update successful'), 'confirmation', false)); + case 'export_all': + $filename = $surveyData['code'].'.xlsx'; + $exportList[] = @SurveyUtil::export_complete_report_xls($surveyData, $filename, 0, true); + break; + case 'send_to_tutors': + $result = SurveyManager::sendToTutors($value); + if ($result) { + Display::addFlash( + Display::return_message( + get_lang('InvitationHasBeenSent').': '.$surveyData['title'], + 'confirmation', + false + ) + ); + } else { + Display::addFlash( + Display::return_message( + get_lang('InvitationHasBeenNotSent').': '.$surveyData['title'], + 'warning', + false + ) + ); + } + break; + case 'multiplicate': + $result = SurveyManager::multiplicateQuestions($surveyData); + $title = $surveyData['title']; + if ($result) { + Display::addFlash( + Display::return_message( + sprintf(get_lang('SurveyXMultiplicated'), $title), + 'confirmation', + false + ) + ); + } else { + Display::addFlash( + Display::return_message( + sprintf(get_lang('SurveyXNotMultiplicated'), $title), + 'warning', + false + ) + ); + } + break; + case 'delete': + // if the survey is shared => also delete the shared content + if (is_numeric($surveyData['survey_share'])) { + SurveyManager::delete_survey($surveyData['survey_share'], true); + } + + // delete the actual survey + SurveyManager::delete_survey($value); + Display::addFlash( + Display::return_message(get_lang('SurveysDeleted').': '.$surveyData['title'], 'confirmation', false) + ); + break; + } + } + + if ($action === 'export_all') { + $tempZipFile = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().'.zip'; + $zip = new PclZip($tempZipFile); + foreach ($exportList as $file) { + $zip->add($file, PCLZIP_OPT_REMOVE_ALL_PATH); + } + + DocumentManager::file_send_for_download( + $tempZipFile, + true, + get_lang('Surveys').'-'.api_get_course_id().'-'.api_get_local_time().'.zip' + ); + unlink($tempZipFile); + } + + header('Location: '.$listUrl); + exit; +} + +switch ($action) { + case 'send_to_tutors': + if (!api_is_allowed_to_edit()) { + api_not_allowed(true); + } + $result = SurveyManager::sendToTutors($surveyId); + if ($result) { + Display::addFlash(Display::return_message(get_lang('Updated'), 'confirmation', false)); } + header('Location: '.$listUrl); exit; break; case 'multiplicate': + if (!api_is_allowed_to_edit()) { + api_not_allowed(true); + } $surveyData = SurveyManager::get_survey($surveyId); if (!empty($surveyData)) { SurveyManager::multiplicateQuestions($surveyData); Display::cleanFlashMessages(); - Display::addFlash(Display::return_message(get_lang('Update successful'), 'confirmation', false)); + Display::addFlash(Display::return_message(get_lang('Updated'), 'confirmation', false)); + } + header('Location: '.$listUrl); + exit; + break; + case 'remove_multiplicate': + if (!api_is_allowed_to_edit()) { + api_not_allowed(true); + } + $surveyData = SurveyManager::get_survey($surveyId); + if (!empty($surveyData)) { + SurveyManager::removeMultiplicateQuestions($surveyData); + Display::addFlash(Display::return_message(get_lang('Updated'), 'confirmation', false)); } header('Location: '.$listUrl); exit; @@ -104,7 +213,7 @@ switch ($action) { case 'copy_survey': if (!empty($surveyId) && api_is_allowed_to_edit()) { SurveyManager::copy_survey($surveyId); - Display::addFlash(Display::return_message(get_lang('Survey copied'), 'confirmation', false)); + Display::addFlash(Display::return_message(get_lang('SurveyCopied'), 'confirmation', false)); header('Location: '.$listUrl); exit; } @@ -160,7 +269,6 @@ switch ($action) { } Display::display_header($tool_name, 'Survey'); -// Tool introduction Display::display_introduction_section('survey', 'left'); // Action handling: searching @@ -168,25 +276,6 @@ if (isset($_GET['search']) && 'advanced' == $_GET['search']) { SurveyUtil::display_survey_search_form(); } -// Action handling: performing the same action on multiple surveys -if (isset($_POST['action']) && $_POST['action']) { - if (is_array($_POST['id'])) { - foreach ($_POST['id'] as $key => &$value) { - // getting the information of the survey (used for when the survey is shared) - $survey_data = SurveyManager::get_survey($value); - // if the survey is shared => also delete the shared content - if (is_numeric($survey_data['survey_share'])) { - SurveyManager::delete_survey($survey_data['survey_share'], true); - } - // delete the actual survey - SurveyManager::delete_survey($value); - } - echo Display::return_message(get_lang('Surveys deleted'), 'confirmation', false); - } else { - echo Display::return_message(get_lang('No surveys have been selected.'), 'error', false); - } -} - echo '
'; if (!api_is_session_general_coach() || 'true' == $extend_rights_for_coachs) { // Action links @@ -209,7 +298,6 @@ if (api_is_session_general_coach() && 'false' == $extend_rights_for_coachs) { Display::display_footer(); /* Bypass functions to make direct use from SortableTable possible */ - function get_number_of_surveys() { return SurveyUtil::get_number_of_surveys(); @@ -222,7 +310,7 @@ function get_survey_data($from, $number_of_items, $column, $direction) function modify_filter($survey_id) { - return SurveyUtil::modify_filter($survey_id); + return SurveyUtil::modify_filter($survey_id, false); } function modify_filter_drh($survey_id) @@ -234,6 +322,7 @@ function get_number_of_surveys_for_coach() { return SurveyUtil::get_number_of_surveys_for_coach(); } + function get_survey_data_for_coach($from, $number_of_items, $column, $direction) { return SurveyUtil::get_survey_data_for_coach($from, $number_of_items, $column, $direction); diff --git a/public/main/survey/survey_question.php b/public/main/survey/survey_question.php index 05e0b8e8b6..3e6caabfd7 100644 --- a/public/main/survey/survey_question.php +++ b/public/main/survey/survey_question.php @@ -1,4 +1,5 @@ addSelect( 'parent_id', get_lang('Parent'), $options, - ['id' => 'parent_id', 'placeholder' => get_lang('Please select an option')] + ['id' => 'parent_id', 'placeholder' => get_lang('SelectAnOption')] ); - $url = api_get_path(WEB_AJAX_PATH).'survey.ajax.php?'.api_get_cidreq(); + $url = api_get_path(WEB_AJAX_PATH). + 'survey.ajax.php?'.api_get_cidreq().'&a=load_question_options&survey_id='.$surveyId; $form->addHtml(' '); - $form->addHtml('
'); - $form->addHidden('option_id', 0); + + $style = 'display:none'; + $options = []; + if (!empty($optionId) && !empty($parentId)) { + $parentData = SurveyManager::get_question($parentId); + $style = ''; + foreach ($parentData['answer_data'] as $answer) { + $options[$answer['iid']] = strip_tags($answer['data']); + } + } + + $form->addHtml('
'); + $form->addSelect( + 'parent_option_id', + get_lang('Option'), + $options, + ['id' => 'parent_option_id', 'disable_js' => true] + ); + $form->addHtml('
'); } /** @@ -88,6 +124,10 @@ class survey_question return new ch_score(); case 'yesno': return new ch_yesno(); + case 'selectivedisplay': + return new ch_selectivedisplay(); + case 'multiplechoiceother': + return new ch_multiplechoiceother(); default: api_not_allowed(true); break; @@ -109,37 +149,69 @@ class survey_question $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : null; $type = isset($_GET['type']) ? Security::remove_XSS($_GET['type']) : null; - $toolName = Display::return_icon( - SurveyManager::icon_question($type), - get_lang(ucfirst($type)), - ['align' => 'middle', 'height' => '22px'] - ).' '; - - if ('add' == $action) { - $toolName .= get_lang('Add a question').': '; - } elseif ('edit' == $action) { - $toolName .= get_lang('Edit question').': '; + $actionHeader = get_lang('EditQuestion').': '; + if ($action === 'add') { + $actionHeader = get_lang('AddQuestion').': '; } - switch ($_GET['type']) { + $questionComment = ''; + $allowParent = false; + switch ($type) { + case 'open': + $toolName = get_lang('Open'); + $questionComment = get_lang('QuestionTags'); + $allowParent = true; + break; case 'yesno': - $toolName .= get_lang('Yes / No'); + $toolName = get_lang('YesNo'); + $allowParent = true; break; case 'multiplechoice': - $toolName .= get_lang('Multiple choice'); + $toolName = get_lang('UniqueSelect'); + $allowParent = true; break; case 'multipleresponse': - $toolName .= get_lang('Multiple answers'); + $toolName = get_lang('MultipleResponse'); + $allowParent = true; + break; + case 'selectivedisplay': + $toolName = get_lang('SurveyQuestionSelectiveDisplay'); + $questionComment = get_lang('SurveyQuestionSelectiveDisplayComment'); + $allowParent = true; + break; + case 'multiplechoiceother': + $toolName = get_lang('SurveyMultipleAnswerWithOther'); + $allowParent = true; + break; + case 'pagebreak': + $toolName = get_lang(api_ucfirst($type)); + $allowParent = false; break; default: - $toolName .= get_lang(api_ucfirst($type)); + $toolName = get_lang(api_ucfirst($type)); + $allowParent = true; + break; } + if (false === api_get_configuration_value('survey_question_dependency')) { + $allowParent = false; + } + + $icon = Display::return_icon( + SurveyManager::icon_question($type), + $toolName, + ['align' => 'middle', 'height' => '22px'] + ).' '; + + $toolName = $icon.$actionHeader.$toolName; $sharedQuestionId = isset($formData['shared_question_id']) ? $formData['shared_question_id'] : null; $url = api_get_self().'?action='.$action.'&type='.$type.'&survey_id='.$surveyId.'&question_id='.$questionId.'&'.api_get_cidreq(); $form = new FormValidator('question_form', 'post', $url); $form->addHeader($toolName); + if (!empty($questionComment)) { + $form->addHtml(Display::return_message($questionComment, 'info', false)); + } $form->addHidden('survey_id', $surveyId); $form->addHidden('question_id', $questionId); $form->addHidden('shared_question_id', Security::remove_XSS($sharedQuestionId)); @@ -163,11 +235,14 @@ class survey_question $form->addCheckBox('is_required', get_lang('Mandatory?'), get_lang('Yes')); } + if ($allowParent) { + $this->addParentMenu($formData, $form, $surveyData); + } // When survey type = 1?? if (1 == $surveyData['survey_type']) { $table_survey_question_group = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP); $sql = 'SELECT id,name FROM '.$table_survey_question_group.' - WHERE survey_id = '.(int) $_GET['survey_id'].' + WHERE survey_id = '.$surveyId.' ORDER BY name'; $rs = Database::query($sql); $glist = null; @@ -317,7 +392,9 @@ class survey_question } /** - * This solution is a little bit strange but I could not find a different solution. + * Deleting a specific answer is only saved in the session until the + * "Save question" button is pressed. This means all options are kept + * in the survey_question_option table until the question is saved. */ if (isset($_POST['delete_answer'])) { $deleted = false; @@ -327,16 +404,36 @@ class survey_question Session::write('answer_count', $counter); } + $newAnswers = []; + $newAnswersId = []; foreach ($formData['answers'] as $key => &$value) { if ($key > $deleted) { - $formData['answers'][$key - 1] = $formData['answers'][$key]; + // swap with previous (deleted) option slot + $newAnswers[$key - 1] = $formData['answers'][$key]; + $newAnswersId[$key - 1] = $formData['answersid'][$key]; unset($formData['answers'][$key]); + unset($formData['answersid'][$key]); + } elseif ($key === $deleted) { + // delete option + unset($formData['answers'][$deleted]); + unset($formData['answersid'][$deleted]); + } else { + // keep as is + $newAnswers[$key] = $value; + $newAnswersId[$key] = $formData['answersid'][$key]; } } + unset($formData['answers']); + unset($formData['answersid']); + $formData['answers'] = $newAnswers; + $formData['answersid'] = $newAnswersId; } // Adding an answer if (isset($_POST['buttons']) && isset($_POST['buttons']['add_answer'])) { + if (isset($_REQUEST['type']) && 'multiplechoiceother' === $_REQUEST['type']) { + $counter--; + } $counter++; Session::write('answer_count', $counter); } @@ -348,12 +445,18 @@ class survey_question foreach ($formData['answers'] as $index => &$data) { if ($index > $counter) { unset($formData['answers'][$index]); + unset($formData['answersid'][$index]); } } } if (!isset($_POST['delete_answer'])) { - if (isset($formData['answers'])) { + // Make sure we have an array of answers + if (!isset($formData['answers'])) { + $formData['answers'] = []; + } + // Check if no deleted answer remains at the end of the answers + // array and add empty answers if the array is too short foreach ($formData['answers'] as $index => $data) { if ($index > $counter) { unset($formData['answers'][$index]); @@ -363,7 +466,6 @@ class survey_question for ($i = 0; $i <= $counter; $i++) { if (!isset($formData['answers'][$i])) { $formData['answers'][$i] = ''; - } } } } @@ -390,13 +492,11 @@ class survey_question if (isset($_POST['buttons']) && isset($_POST['buttons']['save'])) { Session::erase('answer_count'); Session::erase('answer_list'); - $message = SurveyManager::save_question( - $surveyData, - $formData - ); + $message = SurveyManager::save_question($surveyData, $formData, true, $dataFromDatabase); - if ('QuestionAdded' == $message || 'QuestionUpdated' == $message) { - header('Location: '.api_get_path(WEB_CODE_PATH).'survey/survey.php?survey_id='.intval($_GET['survey_id']).'&message='.$message.'&'.api_get_cidreq()); + if ($message === 'QuestionAdded' || $message === 'QuestionUpdated') { + $url = api_get_path(WEB_CODE_PATH).'survey/survey.php?survey_id='.intval($_GET['survey_id']).'&message='.$message.'&'.api_get_cidreq(); + header('Location: '.$url); exit; } } @@ -435,6 +535,131 @@ class survey_question } /** + * Get the JS for questions that can depend on a previous question + * (and that hides those questions until something changes in the previous + * question). + * + * @return string HTML code + */ + public static function getJs() + { + return ' + + '; + } + + /** + * Get the question parents recursively, if any. This function depends on + * the existence of a parent_id field, which depends on the + * 'survey_question_dependency' setting and its corresponding SQL + * requirements. + * + * @param int $questionId The c_survey_question.question.id + * @param array $list An array of parents to be extended by this method + * + * @return array The completed array of parents + */ + public static function getParents($questionId, $list = []) + { + if (true !== api_get_configuration_value('survey_question_dependency')) { + return $list; + } + $courseId = api_get_course_int_id(); + $questionId = (int) $questionId; + + $table = Database::get_course_table(TABLE_SURVEY_QUESTION); + $sql = "SELECT parent_id FROM $table + WHERE c_id = $courseId AND question_id = $questionId "; + $result = Database::query($sql); + $row = Database::fetch_array($result, 'ASSOC'); + if ($row && !empty($row['parent_id'])) { + $list[] = $row['parent_id']; + $list = self::getParents($row['parent_id'], $list); + } + + return $list; + } + + /** + * Creates the JS code for the given parent question so that it shows + * the children questions when a specific answer of the parent is selected. + * + * @param array $question An array with the question details + * + * @return string JS code to add to the HTML survey question page + */ + public static function getQuestionJs($question) + { + $list = self::getDependency($question); + if (empty($list)) { + return ''; + } + + $js = ''; + $questionId = $question['question_id']; + $newList = []; + foreach ($list as $child) { + $childQuestionId = $child['question_id']; + $optionId = $child['parent_option_id']; + $newList[$optionId] = $childQuestionId; + } + + $js .= ' + '; + + return $js; + } + + /** + * Returns the (children) questions that have the given question as parent. + * + * @param array $question An array describing the parent question + * + * @return array The questions that have the given question as parent + */ + public static function getDependency($question) + { + if (true !== api_get_configuration_value('survey_question_dependency')) { + return []; + } + $table = Database::get_course_table(TABLE_SURVEY_QUESTION); + $questionId = $question['question_id']; + $courseId = api_get_course_int_id(); + + // Getting the information of the question + $sql = "SELECT * FROM $table + WHERE c_id = $courseId AND parent_id = $questionId "; + $result = Database::query($sql); + $row = Database::store_result($result, 'ASSOC'); + + return $row; + } + + /** + * This method is not implemented at this level (returns null). + * * @param array $questionData * @param array $answers */ diff --git a/public/main/tracking/courseLog.php b/public/main/tracking/courseLog.php index da0158f981..b5b45f2665 100644 --- a/public/main/tracking/courseLog.php +++ b/public/main/tracking/courseLog.php @@ -8,11 +8,22 @@ use ChamiloSession as Session; require_once __DIR__.'/../inc/global.inc.php'; $current_course_tool = TOOL_TRACKING; -$courseId = api_get_course_id(); -$courseInfo = api_get_course_info($courseId); //keep course_code form as it is loaded (global) by the table's get_user_data -$course_code = $courseCode = $courseInfo['code']; +$courseInfo = api_get_course_info(); +if (empty($courseInfo)) { + api_not_allowed(true); +} $sessionId = api_get_session_id(); +$is_allowedToTrack = Tracking::isAllowToTrack($sessionId); + +if (!$is_allowedToTrack) { + api_not_allowed(true); +} + +//keep course_code form as it is loaded (global) by the table's get_user_data +$courseCode = $courseInfo['code']; +$courseId = $courseInfo['real_id']; + // PERSON_NAME_DATA_EXPORT is buggy $sortByFirstName = api_sort_by_first_name(); $from_myspace = false; @@ -31,12 +42,6 @@ if ('myspace' === $from) { $this_section = 'session_my_space'; } -$is_allowedToTrack = Tracking::isAllowToTrack($sessionId); - -if (!$is_allowedToTrack) { - api_not_allowed(true); -} - // If the user is a HR director (drh) if (api_is_drh()) { // Blocking course for drh @@ -180,7 +185,6 @@ if (isset($_GET['additional_profile_field'])) { $fieldId, $user_array ); - $extra_info[$fieldId] = UserManager::get_extra_field_information($fieldId); } } @@ -320,15 +324,81 @@ if ($showReporting) { $trackingColumn = isset($_GET['users_tracking_column']) ? $_GET['users_tracking_column'] : null; $trackingDirection = isset($_GET['users_tracking_direction']) ? $_GET['users_tracking_direction'] : null; +$hideReports = api_get_configuration_value('hide_course_report_graph'); +$conditions = []; + +$groupList = GroupManager::get_group_list(null, $courseInfo, 1, $sessionId); + +$class = new UserGroup(); +//$options['where'] = [' usergroup.course_id = ? ' => $courseId]; +//$classes = $class->getUserGroupInCourse($options); +$classes = $class->get_all(); // Show the charts part only if there are students subscribed to this course/session if ($nbStudents > 0) { - $usersTracking = TrackingCourseLog::get_user_data(null, $nbStudents, $trackingColumn, $trackingDirection, false); + // Classes + $formClass = new FormValidator( + 'classes', + 'get', + api_get_self().'?'.api_get_cidreq().'&'.$additionalParams + ); + $formClass->addHidden('cidReq', $courseCode); + $formClass->addHidden('id_session', $sessionId); + $groupIdList = ['--']; + $select = $formClass->addSelect('class_id', get_lang('Class').'/'.get_lang('Group'), $groupIdList); + $groupIdList = []; + foreach ($classes as $class) { + //$groupIdList['class_'.$class['id']] = $class['name']; + $groupIdList[] = ['text' => $class['name'], 'value' => 'class_'.$class['id']]; + } + $select->addOptGroup($groupIdList, get_lang('Class')); + $groupIdList = []; + foreach ($groupList as $group) { + $groupIdList[] = ['text' => $group['name'], 'value' => 'group_'.$group['id']]; + //$groupIdList['group_'.$group['id']] = $group['name']; + } + $select->addOptGroup($groupIdList, get_lang('Group')); + $formClass->addButtonSearch(get_lang('Search')); + + // Groups + /*$formGroup = new FormValidator( + 'groups', + 'get', + api_get_self().'?'.api_get_cidreq().'&'.$additionalParams + ); + $formGroup->addHidden('cidReq', $courseCode); + $formGroup->addHidden('id_session', $sessionId); + $groupIdList = ['--']; + foreach ($groupList as $group) { + $groupIdList[$group['id']] = $group['name']; + } + $formGroup->addSelect('group_id', get_lang('Group'), $groupIdList); + $formGroup->addButtonSearch(get_lang('Search'));*/ + + // Extra fields + $formExtraField = new FormValidator( + 'extra_fields', + 'get', + api_get_self().'?'.api_get_cidreq().'&'.$additionalParams + ); + $formExtraField->addHidden('cidReq', $courseCode); + $formExtraField->addHidden('id_session', $sessionId); + if (isset($_GET['additional_profile_field'])) { + foreach ($_GET['additional_profile_field'] as $fieldId) { + $fieldId = Security::remove_XSS($fieldId); + $formExtraField->addHidden('additional_profile_field[]', $fieldId); + //$formGroup->addHidden('additional_profile_field[]', $fieldId); + $formClass->addHidden('additional_profile_field[]', $fieldId); + } + } + + $extraField = new ExtraField('user'); + $extraField->addElements($formExtraField, 0, [], true); + $formExtraField->addButtonSearch(get_lang('Search')); $numberStudentsCompletedLP = 0; $averageStudentsTestScore = 0; $scoresDistribution = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - $userScoreList = []; $listStudentIds = []; $timeStudent = []; @@ -336,15 +406,71 @@ if ($nbStudents > 0) { $category = Category::load( null, null, - $course_code, + $courseCode, null, null, $sessionId ); - $hideReports = api_get_configuration_value('hide_course_report_graph'); + $conditions = []; + $fields = []; + + if ($formClass->validate()) { + $classId = null; + $groupId = null; + + $part = $formClass->getSubmitValue('class_id'); + $item = explode('_', $part); + if (isset($item[0]) && isset($item[1])) { + if ('class' === $item[0]) { + $classId = (int) $item[1]; + } else { + $groupId = (int) $item[1]; + } + } + + if (!empty($classId)) { + $whereCondition = " AND gu.usergroup_id = $classId "; + $tableGroup = Database::get_main_table(TABLE_USERGROUP_REL_USER); + $joins = " INNER JOIN $tableGroup gu ON (user.id = gu.user_id) "; + $conditions = ['where' => $whereCondition, 'inject_joins' => $joins]; + } + + if (!empty($groupId)) { + $whereCondition = " AND gu.group_id = $groupId "; + $tableGroup = Database::get_course_table(TABLE_GROUP_USER); + $joins = " INNER JOIN $tableGroup gu ON (user.id = gu.user_id) "; + $conditions = ['where' => $whereCondition, 'inject_joins' => $joins]; + } + } - if (false === $hideReports) { + /*if ($formGroup->validate()) { + $groupId = (int) $formGroup->getSubmitValue('group_id'); + if (!empty($groupId)) { + $whereCondition = " AND gu.group_id = $groupId "; + $tableGroup = Database::get_course_table(TABLE_GROUP_USER); + $joins = " INNER JOIN $tableGroup gu ON (user.id = gu.user_id) "; + $conditions = ['where' => $whereCondition, 'inject_joins' => $joins]; + } + }*/ + + if ($formExtraField->validate()) { + $extraResult = $extraField->processExtraFieldSearch($_REQUEST, $formExtraField, 'user'); + if (!empty($extraResult)) { + $conditions = $extraResult['condition']; + $fields = $extraResult['fields']; + } + } + + if ($hideReports === false) { + $conditions['include_invited_users'] = false; + $usersTracking = TrackingCourseLog::get_user_data( + null, + $nbStudents, + $trackingColumn, + $trackingDirection, + $conditions + ); foreach ($usersTracking as $userTracking) { $userInfo = api_get_user_info_from_username($userTracking[3]); if (empty($userInfo)) { @@ -391,7 +517,6 @@ if ($nbStudents > 0) { $averageStudentsTestScore = round($averageStudentsTestScore / $nbStudents); $colors = ChamiloApi::getColorPalette(true, true, 10); - $tpl->assign('chart_colors', json_encode($colors)); $tpl->assign('certificate_count', $certificateCount); $tpl->assign('score_distribution', json_encode($scoresDistribution)); @@ -411,7 +536,25 @@ if ($nbStudents > 0) { $html .= Display::page_subheader2(get_lang('Learners list')); if ($nbStudents > 0) { - $getLangXDays = get_lang('%s days'); + $mainForm = new FormValidator( + 'filter', + 'get', + api_get_self().'?'.api_get_cidreq().'&'.$additionalParams + ); + $mainForm->addButtonAdvancedSettings( + 'advanced_search', + [get_lang('AdvancedSearch')] + ); + $mainForm->addHtml(''); + + //$html .= $formClass->returnForm(); + //$html .= $formExtraField->returnForm(); + $html .= $mainForm->returnForm(); + + $getLangXDays = get_lang('XDays'); $form = new FormValidator( 'reminder_form', 'get', @@ -435,20 +578,18 @@ if ($nbStudents > 0) { 'since', Display::returnFontAwesomeIcon('warning').get_lang('Remind learners inactive since'), $options, - ['disable_js' => true] + ['disable_js' => true, 'class' => 'col-sm-3'] ); $el->setSelected(7); - $form->addElement('hidden', 'action', 'add'); $form->addElement('hidden', 'remindallinactives', 'true'); $form->addElement('hidden', 'cidReq', $courseInfo['code']); $form->addElement('hidden', 'id_session', api_get_session_id()); $form->addButtonSend(get_lang('Notify')); - $extra_field_select = TrackingCourseLog::display_additional_profile_fields(); - - if (!empty($extra_field_select)) { - $html .= $extra_field_select; + $extraFieldSelect = TrackingCourseLog::display_additional_profile_fields(); + if (!empty($extraFieldSelect)) { + $html .= $extraFieldSelect; } $html .= $form->returnForm(); @@ -459,6 +600,7 @@ if ($nbStudents > 0) { $_GET['users_tracking_per_page'] = 1000000; } + if ($hideReports === false) { $table = new SortableTableFromArray( $usersTracking, 1, @@ -466,13 +608,22 @@ if ($nbStudents > 0) { 'users_tracking' ); $table->total_number_of_items = $nbStudents; + } else { + $conditions['include_invited_users'] = true; + $table = new SortableTable( + 'users_tracking', + ['TrackingCourseLog', 'get_number_of_users'], + ['TrackingCourseLog', 'get_user_data'], + 1, + 20 + ); + $table->setDataFunctionParams($conditions); + } $parameters['cidReq'] = isset($_GET['cidReq']) ? Security::remove_XSS($_GET['cidReq']) : ''; $parameters['id_session'] = $sessionId; $parameters['from'] = isset($_GET['myspace']) ? Security::remove_XSS($_GET['myspace']) : null; - $table->set_additional_parameters($parameters); - $headers = []; // tab of header texts $table->set_header(0, get_lang('Code'), true); @@ -546,42 +697,39 @@ if ($nbStudents > 0) { if (empty($sessionId)) { $table->set_header(12, get_lang('Survey'), false); $headers['survey'] = get_lang('Survey'); - $table->set_header(13, get_lang('First access to course'), false); - $headers['first_login'] = get_lang('First access to course'); - $table->set_header(14, get_lang('Latest access in course'), false); - $headers['latest_login'] = get_lang('Latest access in course'); + } else { + $table->set_header(12, get_lang('RegisteredDate'), false); + $headers['registered_at'] = get_lang('RegisteredDate'); + } + $table->set_header(13, get_lang('FirstLoginInCourse'), false); + $headers['first_login'] = get_lang('FirstLoginInCourse'); + $table->set_header(14, get_lang('LatestLoginInCourse'), false); + $headers['latest_login'] = get_lang('LatestLoginInCourse'); if (isset($_GET['additional_profile_field'])) { $counter = 15; foreach ($_GET['additional_profile_field'] as $fieldId) { $table->set_header($counter, $extra_info[$fieldId]['display_text'], false); $headers[$extra_info[$fieldId]['variable']] = $extra_info[$fieldId]['display_text']; $counter++; + $parameters['additional_profile_field'] = $fieldId; } - $table->set_header($counter, get_lang('Details'), false); $headers['details'] = get_lang('Details'); } else { $table->set_header(15, get_lang('Details'), false); $headers['details'] = get_lang('Details'); } - } else { - $table->set_header(12, get_lang('First access to course'), false); - $headers['first_login'] = get_lang('First access to course'); - $table->set_header(13, get_lang('Latest access in course'), false); - $headers['latest_login'] = get_lang('Latest access in course'); - if (isset($_GET['additional_profile_field'])) { - $counter = 15; - foreach ($_GET['additional_profile_field'] as $fieldId) { - $table->set_header($counter, $extra_info[$fieldId]['display_text'], false); - $headers[$extra_info[$fieldId]['variable']] = $extra_info[$fieldId]['display_text']; - $counter++; + if (!empty($fields)) { + foreach ($fields as $key => $value) { + $key = Security::remove_XSS($key); + $value = Security::remove_XSS($value); + $parameters[$key] = $value; } - } else { - $table->set_header(14, get_lang('Details'), false); - $headers['Details'] = get_lang('Details'); } - } + $parameters['cidReq'] = $courseCode; + $parameters['id_session'] = $sessionId; + $table->set_additional_parameters($parameters); // display buttons to un hide hidden columns $html .= '
'; $index = 0; @@ -609,8 +757,210 @@ if ($nbStudents > 0) { $html .= Display::return_message(get_lang('No users in course'), 'warning', true); } +$groupContent = ''; echo Display::panel($html, $titleSession); +$groupTable = new HTML_Table(['class' => 'table table-bordered data_table']); +$column = 0; +$groupTable->setHeaderContents(0, $column++, get_lang('Name')); +$groupTable->setHeaderContents(0, $column++, get_lang('TrainingTime')); +$groupTable->setHeaderContents(0, $column++, get_lang('AverageTrainingTime')); +$groupTable->setHeaderContents(0, $column++, get_lang('CourseProgress')); +$groupTable->setHeaderContents(0, $column++, get_lang('ExerciseAverage')); + +$exerciseList = ExerciseLib::get_all_exercises( + $courseInfo, + $sessionId, + false, + null, + false, + 3 +); +//$groupList = null; +if (!empty($groupList)) { + $totalTime = null; + $totalLpProgress = null; + $totalScore = null; + $totalAverageTime = null; + $totalBestScoreAverageNotInLP = 0; + $row = 1; + foreach ($groupList as $groupInfo) { + $column = 0; + $groupTable->setCellContents($row, $column++, $groupInfo['name']); + $usersInGroup = GroupManager::getStudents($groupInfo['iid']); + + $time = null; + $lpProgress = null; + $score = null; + $averageTime = null; + $bestScoreAverageNotInLP = null; + if (!empty($usersInGroup)) { + $usersInGroup = array_column($usersInGroup, 'user_id'); + $userInGroupCount = count($usersInGroup); + $timeInSeconds = Tracking::get_time_spent_on_the_course( + $usersInGroup, + $courseId, + $sessionId + ); + $totalTime += $timeInSeconds; + if (!empty($timeInSeconds)) { + $time = api_time_to_hms($timeInSeconds); + $averageTime = $timeInSeconds / $userInGroupCount; + $totalAverageTime += $averageTime; + $averageTime = api_time_to_hms($averageTime); + } + + $totalGroupLpProgress = 0; + foreach ($usersInGroup as $studentId) { + $lpProgress = Tracking::get_avg_student_progress( + $usersInGroup, + $courseCode, + [], + $sessionId + ); + $totalGroupLpProgress += $lpProgress; + } + + if (empty($totalGroupLpProgress)) { + $totalGroupLpProgress = ''; + } else { + $lpProgress = $totalGroupLpProgress / $userInGroupCount; + $totalLpProgress += $totalGroupLpProgress; + } + + if (!empty($exerciseList)) { + foreach ($exerciseList as $exerciseData) { + foreach ($usersInGroup as $userId) { + $results = Event::get_best_exercise_results_by_user( + $exerciseData['id'], + $courseInfo['real_id'], + 0, + $userId + ); + $best = 0; + if (!empty($results)) { + foreach ($results as $result) { + if (!empty($result['exe_weighting'])) { + $score = $result['exe_result'] / $result['exe_weighting']; + if ($score > $best) { + $best = $score; + } + } + } + } + $bestScoreAverageNotInLP += $best; + } + } + $bestScoreAverageNotInLP = round( + $bestScoreAverageNotInLP / count($exerciseList) * 100 / $userInGroupCount, + 2 + ); + + $totalBestScoreAverageNotInLP += $bestScoreAverageNotInLP; + } + + if (empty($score)) { + $score = ''; + } + if (empty($lpProgress)) { + $lpProgress = ''; + } + if (empty($bestScoreAverageNotInLP)) { + $bestScoreAverageNotInLP = ''; + } + } + + $groupTable->setCellContents($row, $column++, $time); + $groupTable->setCellContents($row, $column++, $averageTime); + $groupTable->setCellContents($row, $column++, $lpProgress); + $groupTable->setCellContents($row, $column++, $bestScoreAverageNotInLP); + $row++; + } + + $column = 0; + $totalTime = api_time_to_hms($totalTime); + $totalAverageTime = api_time_to_hms($totalAverageTime); + $groupTable->setCellContents($row, $column++, get_lang('Total')); + $groupTable->setCellContents($row, $column++, $totalTime); + $groupTable->setCellContents($row, $column++, $totalAverageTime); + $groupTable->setCellContents($row, $column++, round($totalLpProgress / count($groupList), 2).'% '); + $groupTable->setCellContents($row, $column++, round($totalBestScoreAverageNotInLP / count($groupList), 2).'% '); +} else { + $userIdList = Session::read('user_id_list'); + + if (!empty($userIdList)) { + $studentIdList = $userIdList; + } else { + $studentIdList = array_column($studentList, 'user_id'); + } + $nbStudents = count($studentIdList); + + $timeInSeconds = Tracking::get_time_spent_on_the_course( + $studentIdList, + $courseId, + $sessionId + ); + $averageTime = null; + if (!empty($timeInSeconds)) { + $time = api_time_to_hms($timeInSeconds); + $averageTime = $timeInSeconds / $nbStudents; + $averageTime = api_time_to_hms($averageTime); + } + $totalLpProgress = 0; + foreach ($studentIdList as $studentId) { + $lpProgress = Tracking::get_avg_student_progress( + $studentId, + $courseCode, + [], + $sessionId + ); + $totalLpProgress += $lpProgress; + } + + $lpProgress = round($totalLpProgress / $nbStudents, 2).' %'; + $totalBestScoreAverageNotInLP = 0; + $bestScoreAverageNotInLP = 0; + if (!empty($exerciseList)) { + foreach ($exerciseList as $exerciseData) { + foreach ($studentIdList as $userId) { + $results = Event::get_best_exercise_results_by_user( + $exerciseData['id'], + $courseInfo['real_id'], + $sessionId, + $userId + ); + $best = 0; + if (!empty($results)) { + foreach ($results as $result) { + if (!empty($result['exe_weighting'])) { + $score = $result['exe_result'] / $result['exe_weighting']; + if ($score > $best) { + $best = $score; + } + } + } + } + + $bestScoreAverageNotInLP += $best; + } + } + $bestScoreAverageNotInLP = round( + $bestScoreAverageNotInLP / count($exerciseList) * 100 / $nbStudents, + 2 + ).' %'; + } + + $row = 1; + $column = 0; + $groupTable->setCellContents($row, $column++, get_lang('Total')); + $groupTable->setCellContents($row, $column++, $time); + $groupTable->setCellContents($row, $column++, $averageTime); + $groupTable->setCellContents($row, $column++, $lpProgress); + $groupTable->setCellContents($row, $column++, $bestScoreAverageNotInLP); +} + +echo Display::panel($groupTable->toHtml(), ''); + // Send the csv file if asked. if ($export_csv) { $csv_headers = []; @@ -633,6 +983,8 @@ if ($export_csv) { if (empty($sessionId)) { $csv_headers[] = get_lang('Survey'); + } else { + $csv_headers[] = get_lang('RegistrationDate'); } $csv_headers[] = get_lang('First access to course'); diff --git a/public/main/work/edit.php b/public/main/work/edit.php index 074d78d7f6..3b82d118ce 100644 --- a/public/main/work/edit.php +++ b/public/main/work/edit.php @@ -87,7 +87,9 @@ if (!empty($my_folder_data)) { if (!empty($homework['expires_on']) || !empty($homework['ends_on'])) { $time_now = time(); - if (!empty($homework['expires_on'])) { + if (!empty($homework['expires_on']) && + !empty($homework['expires_on']) + ) { $time_expires = api_strtotime($homework['expires_on'], 'UTC'); $difference = $time_expires - $time_now; if ($difference < 0) { @@ -238,6 +240,7 @@ if ($form->validate()) { /*$add_to_update = ', qualificator_id ='."'".api_get_user_id()."', "; $add_to_update .= ' qualification = '."'".api_float_val($_POST['qualification'])."',"; $add_to_update .= ' date_of_qualification = '."'".api_get_utc_datetime()."'";*/ + if (isset($_POST['send_email'])) { $url = api_get_path(WEB_CODE_PATH).'work/view.php?'.api_get_cidreq().'&id='.$item_to_edit_id; $subject = sprintf(get_lang('There\'s a new feedback in work: %s'), $studentPublication->getTitle()); diff --git a/public/main/work/edit_work.php b/public/main/work/edit_work.php index b84510a69e..277194b5a5 100644 --- a/public/main/work/edit_work.php +++ b/public/main/work/edit_work.php @@ -116,8 +116,14 @@ if ($form->validate()) { } $workId = $params['work_id']; + $editCheck = false; $workData = get_work_data_by_id($workId); - $editCheck = true; + + if (!empty($workData)) { + $editCheck = true; + } else { + $editCheck = true; + } if ($editCheck) { updateWork($workData['iid'], $params, $courseInfo, $sessionId); diff --git a/public/main/work/view.php b/public/main/work/view.php index ac53096b84..d520608ae9 100644 --- a/public/main/work/view.php +++ b/public/main/work/view.php @@ -10,13 +10,15 @@ require_once 'work.lib.php'; $id = isset($_GET['id']) ? (int) $_GET['id'] : null; $work = get_work_data_by_id($id); -if (empty($id) || empty($work)) { +if (empty($work)) { api_not_allowed(true); } -if (1 != $work['active']) { - api_not_allowed(true); -} +protectWork(api_get_course_info(), $work['parent_id']); + +$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : null; +$page = isset($_REQUEST['page']) ? $_REQUEST['page'] : null; + $work['title'] = isset($work['title']) ? Security::remove_XSS($work['title']) : ''; $work['description'] = isset($work['description']) ? Security::remove_XSS($work['description']) : ''; @@ -26,23 +28,29 @@ $interbreadcrumb[] = [ 'name' => get_lang('Assignments'), ]; -$my_folder_data = get_work_data_by_id($work['parent_id']); +$folderData = get_work_data_by_id($work['parent_id']); $courseInfo = api_get_course_info(); -$blockScoreEdition = api_get_configuration_value('block_student_publication_score_edition'); +$isCourseManager = api_is_platform_admin() || api_is_coach() || api_is_allowed_to_edit(false, false, true); -if ($blockScoreEdition && !empty($work['qualification']) && !api_is_platform_admin()) { - api_not_allowed(true); +$allowEdition = false; +if ($isCourseManager) { + $allowEdition = true; + if (!empty($work['qualification']) && api_get_configuration_value('block_student_publication_score_edition')) { + $allowEdition = false; + } } -protectWork(api_get_course_info(), $work['parent_id']); +if (api_is_platform_admin()) { + $allowEdition = true; +} $isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh( api_get_user_id(), $courseInfo ); -if ((user_is_author($id) || $isDrhOfCourse || (api_is_allowed_to_edit() || api_is_coach())) || +if ((user_is_author($id) || $isDrhOfCourse || $allowEdition) || ( 0 == $courseInfo['show_score'] && 1 == $work['active'] && @@ -50,13 +58,13 @@ if ((user_is_author($id) || $isDrhOfCourse || (api_is_allowed_to_edit() || api_i ) ) { if ((api_is_allowed_to_edit() || api_is_coach()) || api_is_drh()) { - $url_dir = api_get_path(WEB_CODE_PATH).'work/work_list_all.php?id='.$my_folder_data['id'].'&'.api_get_cidreq(); + $url_dir = api_get_path(WEB_CODE_PATH).'work/work_list_all.php?id='.$folderData['id'].'&'.api_get_cidreq(); } else { - $url_dir = api_get_path(WEB_CODE_PATH).'work/work_list.php?id='.$my_folder_data['id'].'&'.api_get_cidreq(); + $url_dir = api_get_path(WEB_CODE_PATH).'work/work_list.php?id='.$folderData['id'].'&'.api_get_cidreq(); } $userInfo = api_get_user_info($work['user_id']); - $interbreadcrumb[] = ['url' => $url_dir, 'name' => $my_folder_data['title']]; + $interbreadcrumb[] = ['url' => $url_dir, 'name' => $folderData['title']]; $interbreadcrumb[] = ['url' => '#', 'name' => $userInfo['complete_name']]; $interbreadcrumb[] = ['url' => '#', 'name' => $work['title']]; @@ -65,13 +73,10 @@ if ((user_is_author($id) || $isDrhOfCourse || (api_is_allowed_to_edit() || api_i 1 == $work['active'] && 1 == $work['accepted'] ) || - (api_is_allowed_to_edit() || api_is_coach()) || user_is_author($id) || $isDrhOfCourse + $isCourseManager || user_is_author($id) || $isDrhOfCourse ) { - $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : null; - $page = isset($_REQUEST['page']) ? $_REQUEST['page'] : null; - - if ('edit' === $page) { - $url = api_get_path(WEB_CODE_PATH).'work/edit.php?id='.$my_folder_data['id'].'&item_id='.$work['id'].'&'.api_get_cidreq(); + if ($page === 'edit') { + $url = api_get_path(WEB_CODE_PATH).'work/edit.php?id='.$folderData['id'].'&item_id='.$work['id'].'&'.api_get_cidreq(); } else { $url = api_get_path(WEB_CODE_PATH).'work/view.php?id='.$work['id'].'&'.api_get_cidreq(); @@ -91,14 +96,12 @@ if ((user_is_author($id) || $isDrhOfCourse || (api_is_allowed_to_edit() || api_i addWorkComment( api_get_course_info(), api_get_user_id(), - $my_folder_data, + $folderData, $work, $_POST ); - if (api_is_allowed_to_edit()) { - $qualification = isset($_POST['qualification']) ? api_float_val($_POST['qualification']) : null; - if (null !== $qualification) { + if ($allowEdition) { $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION); $sql = "UPDATE $work_table SET @@ -107,21 +110,16 @@ if ((user_is_author($id) || $isDrhOfCourse || (api_is_allowed_to_edit() || api_i date_of_qualification = '".api_get_utc_datetime()."' WHERE c_id = ".$courseInfo['real_id']." AND id = $id"; Database::query($sql); - } - - Display::addFlash(Display::return_message(get_lang('Update successful'))); + Display::addFlash(Display::return_message(get_lang('Updated'))); $resultUpload = uploadWork( - $my_folder_data, + $folderData, $courseInfo, true, $work ); if ($resultUpload) { - $work_table = Database::get_course_table( - TABLE_STUDENT_PUBLICATION - ); - + $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION); if (isset($resultUpload['url']) && !empty($resultUpload['url'])) { $title = isset($resultUpload['filename']) && !empty($resultUpload['filename']) ? $resultUpload['filename'] : get_lang('Untitled'); $urlToSave = Database::escape_string($resultUpload['url']); @@ -138,11 +136,6 @@ if ((user_is_author($id) || $isDrhOfCourse || (api_is_allowed_to_edit() || api_i } } - $blockScoreEdition = api_get_configuration_value('block_student_publication_score_edition'); - - if ($blockScoreEdition && !api_is_platform_admin()) { - $url = api_get_path(WEB_CODE_PATH).'work/work_list_all.php?'.api_get_cidreq().'&id='.$my_folder_data['id']; - } header('Location: '.$url); exit; @@ -159,29 +152,24 @@ if ((user_is_author($id) || $isDrhOfCourse || (api_is_allowed_to_edit() || api_i break; case 'delete_correction': - if (isset($work['url_correction']) && !empty($work['url_correction'])) { - if (api_is_allowed_to_edit()) { + if ($allowEdition && isset($work['url_correction']) && !empty($work['url_correction'])) { deleteCorrection($courseInfo, $work); - Display::addFlash( - Display::return_message(get_lang('Deleted')) - ); - } + Display::addFlash(Display::return_message(get_lang('Deleted'))); } header('Location: '.$url); exit; - break; } $comments = getWorkComments($work); - $commentForm = getWorkCommentForm($work, $my_folder_data); + $commentForm = getWorkCommentForm($work, $folderData); $tpl = new Template(); $tpl->assign('work', $work); $tpl->assign('comments', $comments); - $actions = ''; + if (isset($work['contains_file']) && !empty($work['contains_file'])) { if (isset($work['download_url']) && !empty($work['download_url'])) { $actions = Display::url( @@ -220,7 +208,8 @@ if ((user_is_author($id) || $isDrhOfCourse || (api_is_allowed_to_edit() || api_i ), $work['download_url'].'&correction=1' ); - if (api_is_allowed_to_edit()) { + + if ($allowEdition) { $actions .= Display::url( Display::return_icon( 'delete.png', diff --git a/public/main/work/work.lib.php b/public/main/work/work.lib.php index a01241f00a..30a3e3c9ac 100644 --- a/public/main/work/work.lib.php +++ b/public/main/work/work.lib.php @@ -407,11 +407,14 @@ function getUniqueStudentAttemptsTotal($workId, $groupId, $course_id, $sessionId } /** + * @param mixed $workId * @param int $groupId * @param int $course_id * @param int $sessionId * @param int $userId user id to filter * @param array $onlyUserList only parse this user list + * + * @return mixed */ function getUniqueStudentAttempts( $workId, @@ -1854,6 +1857,8 @@ function get_work_user_list( $course_info ); + $isDrhOfSession = !empty(SessionManager::getSessionFollowedByDrh(api_get_user_id(), $session_id)); + $groupIid = 0; if ($group_id) { $groupInfo = GroupManager::get_group_properties($group_id); @@ -1870,7 +1875,7 @@ function get_work_user_list( $extra_conditions = " (work.post_group_id = '0' OR work.post_group_id is NULL) "; } - if ($is_allowed_to_edit || $isDrhOfCourse) { + if ($is_allowed_to_edit || $isDrhOfCourse || $isDrhOfSession) { $extra_conditions .= ' AND work.active IN (0, 1) '; } else { if (isset($course_info['show_score']) && @@ -2114,6 +2119,7 @@ function get_work_user_list( $work_date = api_get_local_time($work['sent_date']); $date = date_to_str_ago($work['sent_date']).' '.$work_date; $work['formatted_date'] = $work_date.' '.$add_string; + $work['expiry_note'] = $add_string; $work['sent_date_from_db'] = $work['sent_date']; $work['sent_date'] = '
'. $add_string.' '.Display::dateToStringAgoAndLongDate($work['sent_date']).'
'; @@ -2165,6 +2171,12 @@ function get_work_user_list( dropZone: $(this) }); }); + + $('.getSingleCompilatio').on('click', function () { + var parts = $(this).parent().attr('id').split('id_avancement'); + getSingleCompilatio(parts[1]); + }); + $('#file_upload_".$item_id."').fileupload({ add: function (e, data) { $('#progress_$item_id').html(); @@ -2317,7 +2329,7 @@ function get_work_user_list( /** * Send reminder to users who have not given the task. * - * @param int $task_data + * @param int * * @return array * @@ -2537,8 +2549,8 @@ function user_is_author($itemId, $userId = null, $courseId = 0, $sessionId = 0) /** * Get list of users who have not given the task. * - * @param int $task_id - * @param int $studentId + * @param int + * @param int * * @return array * @@ -2644,7 +2656,7 @@ function get_list_users_without_publication($task_id, $studentId = 0) /** * Display list of users who have not given the task. * - * @param int $task_id task id + * @param int task id * @param int $studentId * * @author cvargas carlos.vargas@beeznest.com cfasanando, christian.fasanado@beeznest.com @@ -3583,8 +3595,21 @@ function getWorkCommentForm($work, $workParent) $qualification = $workParent['qualification']; - if (api_is_allowed_to_edit()) { - if (!empty($qualification) && (int) $qualification > 0) { + $isCourseManager = api_is_platform_admin() || api_is_coach() || api_is_allowed_to_edit(false, false, true); + $allowEdition = false; + if ($isCourseManager) { + $allowEdition = true; + if (!empty($work['qualification']) && api_get_configuration_value('block_student_publication_score_edition')) { + $allowEdition = false; + } + } + + if (api_is_platform_admin()) { + $allowEdition = true; + } + + if ($allowEdition) { + if (!empty($qualification) && intval($qualification) > 0) { $model = ExerciseLib::getCourseScoreModel(); if (empty($model)) { $form->addFloat( @@ -3768,10 +3793,10 @@ function uploadWork($my_folder_data, $_course, $isCorrection = false, $workInfo $filename = add_ext_on_mime(stripslashes($file['name']), $file['type']); // Replace dangerous characters + $filename = api_replace_dangerous_char($filename); //$filename = api_replace_dangerous_char($filename); - // Transform any .php file in .phps fo security - //$filename = php2phps($filename); + $filename = php2phps($filename); $filesize = filesize($file['tmp_name']); if (empty($filesize)) {