Upgrade 1-11.38

This commit is contained in:
xesmyd
2026-03-30 14:10:30 +02:00
parent f2a7e6d1fc
commit ac648ef29d
24665 changed files with 69682 additions and 2205004 deletions
+111 -44
View File
@@ -56,6 +56,28 @@ $sessionCategory = $session->getCategory();
$action = isset($_GET['action']) ? $_GET['action'] : null;
$url_id = api_get_current_access_url_id();
// Course DRAG & DROP via AJAX
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] == 'reorder_courses') {
api_protect_admin_script(true);
$order = $_POST['order'] ?? [];
if (!empty($order) && is_array($order)) {
foreach ($order as $position => $courseId) {
$qb = $em->createQueryBuilder();
$qb->update('ChamiloCoreBundle:SessionRelCourse', 'src')
->set('src.position', ':position')
->where('src.session = :session')
->andWhere('src.course = :course')
->setParameter('position', $position + 1)
->setParameter('session', $sessionId)
->setParameter('course', $courseId)
->getQuery()
->execute();
}
echo json_encode(['success' => true]);
exit;
}
}
switch ($action) {
case 'export_certified_course_users':
$courseCode = $_GET['course_code'] ?? null;
@@ -63,16 +85,6 @@ switch ($action) {
SessionManager::exportCourseSessionReport($sessionId, $courseCode);
}
break;
case 'move_up':
SessionManager::moveUp($sessionId, $_GET['course_id']);
header('Location: resume_session.php?id_session='.$sessionId);
exit;
break;
case 'move_down':
SessionManager::moveDown($sessionId, $_GET['course_id']);
header('Location: resume_session.php?id_session='.$sessionId);
exit;
break;
case 'add_user_to_url':
$user_id = $_REQUEST['user_id'];
$result = UrlManager::add_user_to_url($user_id, $url_id);
@@ -164,15 +176,28 @@ $url = Display::url(
Display::return_icon('edit.png', get_lang('Edit'), [], ICON_SIZE_SMALL),
"add_courses_to_session.php?page=resume_session.php&id_session=$sessionId"
);
$theoreticalTimeEnabled = api_get_configuration_value('display_theoretical_time');
$courseListToShow = Display::page_subheader(get_lang('CourseList').$url);
$courseListToShow .= '<table id="session-list-course" class="table table-hover table-striped data_table">
<tr>
<th width="35%">'.get_lang('CourseTitle').'</th>
<th width="30%">'.get_lang('CourseCoach').'</th>
<th width="10%">'.get_lang('UsersNumber').'</th>
<th width="25%">'.get_lang('Actions').'</th>
</tr>';
<thead><tr>';
if ($theoreticalTimeEnabled) {
$courseListToShow .= '<th></th>
<th width="30%">'.get_lang('CourseTitle').'</th>
<th width="20%">'.get_lang('TheoreticalTime').'</th>
<th width="15%">'.get_lang('CourseCoach').'</th>
<th width="10%">'.get_lang('UsersNumber').'</th>
<th width="25%">'.get_lang('Actions').'</th>
</tr></thead><tbody id="sortable-course-list">';
} else {
$courseListToShow .= '<th></th>
<th width="35%">'.get_lang('CourseTitle').'</th>
<th width="30%">'.get_lang('CourseCoach').'</th>
<th width="10%">'.get_lang('UsersNumber').'</th>
<th width="25%">'.get_lang('Actions').'</th>
</tr></thead><tbody id="sortable-course-list">';
}
if ($session->getNbrCourses() === 0) {
$courseListToShow .= '<tr>
@@ -213,6 +238,8 @@ if ($session->getNbrCourses() === 0) {
$courseList = $newCourseList;
}
$totalTheoreticalTime = 0;
/** @var Course $course */
foreach ($courseList as $course) {
// Select the number of users
@@ -229,41 +256,34 @@ if ($session->getNbrCourses() === 0) {
}
}
$orderButtons = '';
if (SessionManager::orderCourseIsEnabled()) {
$orderButtons = Display::url(
Display::return_icon(
!$count ? 'up_na.png' : 'up.png',
get_lang('MoveUp')
),
!$count
? '#'
: api_get_self().'?id_session='.$sessionId.'&course_id='.$course->getId().'&action=move_up'
);
$orderButtons .= Display::url(
Display::return_icon(
$count + 1 == count($courses) ? 'down_na.png' : 'down.png',
get_lang('MoveDown')
),
$count + 1 == count($courses)
? '#'
: api_get_self().'?id_session='.$sessionId.'&course_id='.$course->getId().'&action=move_down'
);
}
$courseUrl = api_get_course_url($course->getCode(), $sessionId);
$courseBaseUrl = api_get_course_url($course->getCode());
if ($theoreticalTimeEnabled) {
$theoreticalTime = CourseManager::get_course_extra_field_value('theoretical_time', $course->getCode());
if (is_numeric($theoreticalTime) && (float) $theoreticalTime != 0) {
$totalTheoreticalTime += (float) $theoreticalTime;
$hours = floor($theoreticalTime / 60);
$minutes = $theoreticalTime % 60;
$theoreticalTimeDisplay = sprintf('%02d:%02d', $hours, $minutes);
} else {
$theoreticalTimeDisplay = '00:00';
}
}
// hide_course_breadcrumb the parameter has been added to hide the name
// of the course, that appeared in the default $interbreadcrumb
$courseItem .= '<tr>
<td class="title">'
$courseItem .= '<tr data-course-id="'.$course->getId().'">';
$courseItem .= '<td class="handle" style="cursor:move;text-align:center;width:30px;"><span style="font-size:1.4em;">&#9776;</span></td>';
$courseItem .= '<td class="title">'
.Display::url(
$course->getTitle().' ('.$course->getVisualCode().')',
$courseUrl
)
.'</td>';
if ($theoreticalTimeEnabled) {
$courseItem .= '<td>'.$theoreticalTimeDisplay.'</td>';
}
$courseItem .= '<td>'.($namesOfCoaches ? implode('<br>', $namesOfCoaches) : get_lang('None')).'</td>';
$courseItem .= '<td>'.$numberOfUsers.'</td>';
$courseItem .= '<td>';
@@ -281,7 +301,6 @@ if ($session->getNbrCourses() === 0) {
$codePath.'admin/skill_rel_course.php?session_id='.$sessionId.'&course_id='.$course->getId()
);
}
$courseItem .= $orderButtons;
$courseItem .= Display::url(
Display::return_icon('new_user.png', get_lang('AddUsers')),
@@ -336,9 +355,20 @@ if ($session->getNbrCourses() === 0) {
$courseItem .= '</td></tr>';
$count++;
}
if ($theoreticalTimeEnabled) {
$totalHours = floor($totalTheoreticalTime / 60);
$totalMinutes = $totalTheoreticalTime % 60;
$totalTheoreticalTimeDisplay = sprintf('%02d:%02d', $totalHours, $totalMinutes);
$courseItem .= '<tr style="font-weight:bold"><td></td><td>Total</td>';
$courseItem .= '<td>'.$totalTheoreticalTimeDisplay.'</td>';
$courseItem .= '<td>-</td>';
$courseItem .= '<td>-</td>';
$courseItem .= '<td>-</td></tr>';
}
$courseListToShow .= $courseItem;
}
$courseListToShow .= '</table><br />';
$courseListToShow .= '</tbody></table><br />';
$url = '&nbsp;'.Display::url(
Display::return_icon('user_subscribe_session.png', get_lang('Add')),
@@ -363,6 +393,12 @@ $url .= Display::url(
]
)
);
$url .= Display::url(
Display::return_icon('excel.png', get_lang('Progress')),
$codePath.'session/session_student_progress.php?'.http_build_query([
'session_id' => $sessionId,
])
);
$userListToShow = Display::page_subheader(get_lang('UserList').$url);
$userList = SessionManager::get_users_by_session($sessionId);
@@ -436,7 +472,7 @@ if (!empty($userList)) {
$editUrl = null;
if (isset($sessionInfo['duration']) && !empty($sessionInfo['duration'])) {
$editUrl = $codePath . 'session/session_user_edit.php?session_id=' . $sessionId . '&user_id=' . $userId;
$editUrl = $codePath.'session/session_user_edit.php?session_id='.$sessionId.'&user_id='.$userId;
$editUrl = Display::url(
Display::return_icon('agenda.png', get_lang('SessionDurationEdit')),
$editUrl
@@ -495,6 +531,37 @@ $programmedAnnouncement = new ScheduledAnnouncement();
$programmedAnnouncement = $programmedAnnouncement->allowed();
$htmlHeadXtra[] = api_get_jquery_libraries_js(['jquery-ui', 'jquery-upload']);
$htmlHeadXtra[] = <<<EOD
<script>
$(function() {
$("#sortable-course-list").sortable({
handle: '.handle',
placeholder: "ui-sortable-placeholder",
update: function(event, ui) {
var order = [];
$("#sortable-course-list tr").each(function() {
order.push($(this).data('course-id'));
});
$.ajax({
url: window.location.pathname + window.location.search,
method: "POST",
data: {
action: "reorder_courses",
order: order
},
success: function(response) {
// Optionnel : affiche un message
}
});
}
}).disableSelection();
});
</script>
<style>
.ui-sortable-placeholder { background: #fffae6; height:40px; }
.handle { cursor:move; }
</style>
EOD;
$tpl = new Template($tool_name);
$tpl->assign('session_header', $sessionHeader);
+37 -33
View File
@@ -47,7 +47,7 @@ $frmSearch->addText('keyword', get_lang('Search'), false);
$frmSearch->addButtonSearch(get_lang('Search'));
if ($frmSearch->validate()) {
$keyword = $frmSearch->exportValues()['keyword'];
$keyword = Security::remove_XSS($frmSearch->exportValues()['keyword']);
}
$interbreadcrumb[] = ['url' => 'session_list.php', 'name' => get_lang('SessionList')];
@@ -138,28 +138,30 @@ if (isset($_GET['search']) && $_GET['search'] === 'advanced') {
<div>
<?php
if ($page) {
?>
<a href="<?php echo api_get_self(); ?>?page=<?php echo $page
- 1; ?>&sort=<?php echo $sort; ?>&order=<?php echo Security::remove_XSS(
$order
); ?>&keyword=<?php echo $keyword; ?><?php echo @$cond_url; ?>"><?php echo get_lang(
'Previous'
); ?></a>
<?php
echo Display::url(
get_lang('Previous'),
api_get_self().'?'.http_build_query([
'page' => $page - 1,
'sort' => $sort,
'order' => $order,
'keyword' => $keyword,
])
);
} else {
echo get_lang('Previous');
} ?>
|
<?php
if ($nbr_results > $limit) {
?>
<a href="<?php echo api_get_self(); ?>?page=<?php echo $page
+ 1; ?>&sort=<?php echo $sort; ?>&order=<?php echo Security::remove_XSS(
$order
); ?>&keyword=<?php echo $keyword; ?><?php echo @$cond_url; ?>"><?php echo get_lang(
'Next'
); ?></a>
<?php
echo Display::url(
get_lang('Next'),
api_get_self().'?'.http_build_query([
'page' => $page + 1,
'sort' => $sort,
'order' => $order,
'keyword' => $keyword,
])
);
} else {
echo get_lang('Next');
} ?>
@@ -237,28 +239,30 @@ if (isset($_GET['search']) && $_GET['search'] === 'advanced') {
<?php
if ($num > $limit) {
if ($page) {
?>
<a href="<?php echo api_get_self(); ?>?page=<?php echo $page
- 1; ?>&sort=<?php echo $sort; ?>&order=<?php echo Security::remove_XSS(
$_REQUEST['order']
); ?>&keyword=<?php echo $_REQUEST['keyword']; ?><?php echo @$cond_url; ?>">
<?php echo get_lang('Previous'); ?></a>
<?php
echo Display::url(
get_lang('Previous'),
api_get_self().'?'.http_build_query([
'page' => $page - 1,
'sort' => $sort,
'order' => $order,
'keyword' => $keyword,
]),
);
} else {
echo get_lang('Previous');
} ?>
|
<?php
if ($nbr_results > $limit) {
?>
<a href="<?php echo api_get_self(); ?>?page=<?php echo $page
+ 1; ?>&sort=<?php echo $sort; ?>&order=<?php echo Security::remove_XSS(
$_REQUEST['order']
); ?>&keyword=<?php echo $_REQUEST['keyword']; ?><?php echo @$cond_url; ?>">
<?php echo get_lang('Next'); ?></a>
<?php
echo Display::url(
get_lang('Next'),
api_get_self().'?'.http_build_query([
'page' => $page + 1,
'sort' => $sort,
'order' => $order,
'keyword' => $keyword,
])
);
} else {
echo get_lang('Next');
}
+16 -14
View File
@@ -42,6 +42,18 @@ if (!list($session_name, $course_title) = Database::fetch_row($result)) {
exit();
}
$allowedPages = [
'session_course_list.php',
'resume_session.php',
];
$page = isset($_GET['page']) ? basename($_GET['page']) : 'session_course_list.php';
if (!in_array($page,$allowedPages)) {
$page = 'session_course_list.php';
}
$interbreadcrumb[] = ['url' => "session_list.php", "name" => get_lang("SessionList")];
$interbreadcrumb[] = [
'url' => "resume_session.php?id_session=".$id_session,
@@ -49,25 +61,15 @@ $interbreadcrumb[] = [
];
$interbreadcrumb[] = [
'url' => "session_course_list.php?id_session=$id_session",
"name" => api_htmlentities($session_name, ENT_QUOTES, $charset),
"name" => api_htmlentities($session_name, ENT_QUOTES),
];
$arr_infos = [];
if (isset($_POST['formSent']) && $_POST['formSent']) {
// get all tutor by course_code in the session
$sql = "SELECT user_id
FROM $tbl_session_rel_course_rel_user
WHERE session_id = '$id_session' AND c_id = '".$courseId."' AND status = 2";
$rs_coaches = Database::query($sql);
$coaches_course_session = SessionManager::getCoachesByCourseSession($id_session, $courseId);
$coaches_course_session = [];
if (Database::num_rows($rs_coaches) > 0) {
while ($row_coaches = Database::fetch_row($rs_coaches)) {
$coaches_course_session[] = $row_coaches[0];
}
}
$id_coaches = isset($_POST['id_coach']) ? $_POST['id_coach'] : [0];
$id_coaches = $_POST['id_coach'] ?? [0];
if (is_array($id_coaches) && count($id_coaches) > 0) {
foreach ($id_coaches as $id_coach) {
$id_coach = intval($id_coach);
@@ -90,7 +92,7 @@ if (isset($_POST['formSent']) && $_POST['formSent']) {
);
}
Display::addFlash(Display::return_message(get_lang('Updated')));
header('Location: '.Security::remove_XSS($_GET['page']).'?id_session='.$id_session);
header('Location: '.$page.'?id_session='.$id_session);
exit();
}
} else {
+1 -1
View File
@@ -58,7 +58,7 @@ if (isset($_POST['formSent']) && $_POST['formSent']) {
$content = file_get_contents($_FILES['import_file']['tmp_name']);
$content = api_utf8_encode_xml($content);
$root = @simplexml_load_string($content);
$root = simplexml_load_string($content, SimpleXMLElement::class, LIBXML_NONET);
unset($content);
if (is_object($root)) {
+175
View File
@@ -0,0 +1,175 @@
<?php
/* For licensing terms, see /license.txt */
$cidReset = true;
require_once __DIR__.'/../inc/global.inc.php';
api_block_anonymous_users();
$allowToTrack = api_is_platform_admin(true, true) || api_is_teacher();
if (!$allowToTrack) {
api_not_allowed(true);
}
$sessionId = isset($_GET['session_id']) ? (int) $_GET['session_id'] : 0;
$fileType = $_GET['file_type'] ?? 'xls';
if (empty($sessionId)) {
api_not_allowed(true);
}
$sessionInfo = api_get_session_info($sessionId);
if (empty($sessionInfo)) {
api_not_allowed(true);
}
$strDate = api_get_local_time(null, null, null, false, false, true);
$courses = array_map(
function ($courseInfo) {
$courseInfo['real_id'] = $courseInfo['c_id'];
return $courseInfo;
},
Tracking::get_courses_list_from_session($sessionId)
);
$users = SessionManager::get_users_by_session($sessionId, 0);
$studentList = array_column($users, 'user_id');
$rowSession = [
$sessionInfo['name'],
];
$rowDate = [$strDate];
$rowCourses = ['', '', ''];
$rowHeaders = [
get_lang('LastName'),
get_lang('FirstName'),
get_lang('ScormAndLPProgressTotalAverage'),
];
foreach ($courses as $course) {
$courseInfo = api_get_course_info_by_id($course['c_id']);
$rowCourses[] = $courseInfo['title'];
$rowCourses[] = '';
$rowHeaders[] = get_lang('Progress');
$rowHeaders[] = get_lang('FinalScore');
}
$data = [];
$data[] = $rowSession;
$data[] = $rowDate;
$data[] = $rowCourses;
$data[] = $rowHeaders;
$totalCourses = count($courses);
foreach ($studentList as $studentId) {
$studentInfo = api_get_user_info($studentId);
if (empty($studentInfo)) {
continue;
}
$progressSum = 0;
$courseValues = [];
foreach ($courses as $course) {
if (!CourseManager::is_user_subscribed_in_course($studentId, $course['code'], true, $sessionId)) {
$courseValues[] = ['', ''];
continue;
}
$objLearnpaths = new LearnpathList(
$studentId,
$course,
$sessionId,
null,
false,
null,
true,
false,
true,
true
);
$lpList = $objLearnpaths->get_flat_list();
$lastLearnpath = end($lpList);
if (!$lastLearnpath) {
$courseValues[] = ['0 %', 0];
continue;
}
$courseProgress = Tracking::get_avg_student_progress(
$studentId,
$course['code'],
[],
$sessionId
);
$evaluationResult = '0';
$lp = new learnpath($course['code'], $lastLearnpath['iid'], $studentId);
if ($finalEvaluationItem = $lp->getFinalEvaluationItem()) {
$bestScoreData = ExerciseLib::get_best_attempt_by_user(
$studentId,
$finalEvaluationItem->path,
$course['real_id'],
$sessionId,
false
);
if ($bestScoreData) {
$evaluationResult = ExerciseLib::show_score(
$bestScoreData['exe_result'],
$bestScoreData['exe_weighting']
);
}
}
$value = is_numeric($courseProgress) ? round($courseProgress, 2) : 0;
$progressSum += $value;
$courseValues[] = [
sprintf(get_lang('XPercent'), $value),
strip_tags($evaluationResult),
];
}
$average = $totalCourses > 0 ? round($progressSum / $totalCourses, 2) : 0;
$row = [
$studentInfo['lastname'],
$studentInfo['firstname'],
sprintf(get_lang('XPercent'), $average),
];
foreach ($courseValues as $courseValue) {
$row[] = $courseValue[0];
$row[] = $courseValue[1];
}
$data[] = $row;
}
$filename = 'session_student_progress_'.$sessionInfo['name'].'_'.api_get_local_time();
switch ($fileType) {
case 'xls':
Export::arrayToXls($data, $filename);
break;
case 'csv':
default:
Export::arrayToCsv($data, $filename);
break;
}
+8 -8
View File
@@ -75,7 +75,7 @@ if (count($userAccess) == 0) {
}
}
$header = '<div class="row">';
$header = '<div class="row">';
$header .= '<div class="col-sm-5">';
$header .= '<div class="thumbnail">';
$header .= Display::img($userInfo['avatar'], $userInfo['complete_name'], null, false);
@@ -90,17 +90,17 @@ $userData = $userInfo['complete_name']
.PHP_EOL
.$user_info['official_code'];
$header .= '<h3>Usuario: ' . Display::url(
$header .= '<h3>Usuario: '.Display::url(
$userData,
api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_info['user_id']
) .'</h3>';
).'</h3>';
$header .= '<p><h3>Sesión: ' . $sessionInfo['name'] . '<h3></p>';
$header .= '<p><h3>Sesión: '.$sessionInfo['name'].'<h3></p>';
$header .= '</div>';
$header .='</div>';
$header .= '</div>';
$header .= '<div class="row">';
$header .= '<div class="row">';
$header .= '<div class="col-sm-12">';
$header .= $msg;
@@ -111,7 +111,7 @@ $header .= '</div>';
$form->addElement('html', $header);
$formData = '<div class="row">';
$formData = '<div class="row">';
$formData .= '<div class="col-sm-12">';
$form->addElement('html', $formData);
@@ -133,7 +133,7 @@ if ($form->validate()) {
$url = api_get_self().'?'.Security::remove_XSS($_SERVER['QUERY_STRING']);
$url = str_replace('&amp;', '&', $url);
header("Location: " . $url);
header("Location: ".$url);
exit();
}