Internal: Fix CSV export formatting and score calculation issues - refs BT#22096

pull/5853/head
Christian Beeznest 9 months ago
parent e260348234
commit 9b1f1e6b69
  1. 45
      public/main/inc/lib/export.lib.inc.php
  2. 280
      public/main/inc/lib/sessionmanager.lib.php
  3. 19
      public/main/inc/lib/tracking.lib.php
  4. 2
      public/main/my_space/myStudents.php

@ -26,14 +26,9 @@ class Export
/** /**
* Export tabular data to CSV-file. * Export tabular data to CSV-file.
* *
* @param array $data
* @param string $filename
* @param bool $writeOnly Whether to only write on disk or also send for download
* @param string $enclosure
*
* @return mixed csv raw data | false if no data to export | string file path if success in $writeOnly mode * @return mixed csv raw data | false if no data to export | string file path if success in $writeOnly mode
*/ */
public static function arrayToCsv($data, $filename = 'export', $writeOnly = false, $enclosure = '"') public static function arrayToCsv(array $data, string $filename = 'export', bool $writeOnly = false, string $enclosure = '"')
{ {
if (empty($data)) { if (empty($data)) {
return false; return false;
@ -55,6 +50,44 @@ class Export
return $filePath; return $filePath;
} }
/**
* Converts an array of data into a CSV file and optionally sends it for download.
*
* @return string|void Returns the file path if $writeOnly is true, otherwise sends the file for download and exits.
*/
public static function arrayToCsvSimple(array $data, string $filename = 'export', bool $writeOnly = false)
{
$file = api_get_path(SYS_ARCHIVE_PATH) . uniqid('') . '.csv';
$handle = fopen($file, 'w');
if ($handle === false) {
throw new \RuntimeException("Unable to create or open the file: $file");
}
if (is_array($data)) {
foreach ($data as $row) {
$line = '';
if (is_array($row)) {
foreach ($row as $value) {
$line .= '"' . str_replace('"', '""', (string)$value) . '";';
}
}
fwrite($handle, rtrim($line, ';') . "\n");
}
}
fclose($handle);
if (!$writeOnly) {
DocumentManager::file_send_for_download($file, true, $filename . '.csv');
unlink($file);
exit;
}
return $file;
}
/** /**
* Export tabular data to XLS-file. * Export tabular data to XLS-file.
*/ */

@ -10232,38 +10232,9 @@ class SessionManager
*/ */
public static function exportSessionsAsCSV(array $selectedSessions): void public static function exportSessionsAsCSV(array $selectedSessions): void
{ {
$csvHeaders = [];
$csvHeaders[] = get_lang('Session name');
$csvHeaders[] = get_lang('Session start date');
$csvHeaders[] = get_lang('Session end date');
$csvHeaders[] = get_lang('Course name');
$csvHeaders[] = get_lang('Official code');
if (api_sort_by_first_name()) {
$csvHeaders[] = get_lang('First name');
$csvHeaders[] = get_lang('Last name');
} else {
$csvHeaders[] = get_lang('Last name');
$csvHeaders[] = get_lang('First name');
}
$csvHeaders[] = get_lang('Login');
$csvHeaders[] = get_lang('Training time');
$csvHeaders[] = get_lang('Course progress');
$csvHeaders[] = get_lang('Exercise progress');
$csvHeaders[] = get_lang('Exercise average');
$csvHeaders[] = get_lang('Score');
$csvHeaders[] = get_lang('Score').' - '.get_lang('Best attempt');
$csvHeaders[] = get_lang('Student_publication');
$csvHeaders[] = get_lang('Messages');
$csvHeaders[] = get_lang('Classes');
$csvHeaders[] = get_lang('Registration date');
$csvHeaders[] = get_lang('FirstLogin in course');
$csvHeaders[] = get_lang('Latest login in course');
$csvHeaders[] = get_lang('Lp finalization date');
$csvHeaders[] = get_lang('Quiz finalization date');
$csvData = []; $csvData = [];
$headersGenerated = false;
$csvHeaders = [];
foreach ($selectedSessions as $sessionId) { foreach ($selectedSessions as $sessionId) {
$courses = SessionManager::get_course_list_by_session_id($sessionId); $courses = SessionManager::get_course_list_by_session_id($sessionId);
@ -10271,30 +10242,24 @@ class SessionManager
if (!empty($courses)) { if (!empty($courses)) {
foreach ($courses as $course) { foreach ($courses as $course) {
$courseCode = $course['course_code']; $courseCode = $course['course_code'];
$courseId = $course['id'];
$studentList = CourseManager::get_student_list_from_course_code( $studentList = CourseManager::get_student_list_from_course_code(
$courseCode, $courseCode,
true, true,
$sessionId $sessionId
); );
$nbStudents = count($studentList);
$userIds = array_keys($studentList); $userIds = array_keys($studentList);
$csvContentInSession = TrackingCourseLog::getUserData(
null,
$nbStudents,
null,
null,
[],
false,
true,
$courseCode,
$sessionId,
true,
$userIds
);
if (!empty($csvContentInSession)) { [$generatedHeaders, $csvContent] = self::generateSessionCourseReportData($sessionId, $courseId, $userIds);
$csvData = array_merge($csvData, $csvContentInSession);
if (!$headersGenerated) {
$csvHeaders = $generatedHeaders;
$headersGenerated = true;
}
foreach ($csvContent as $row) {
$csvData[] = $row;
} }
} }
} }
@ -10302,8 +10267,8 @@ class SessionManager
if (!empty($csvData)) { if (!empty($csvData)) {
array_unshift($csvData, $csvHeaders); array_unshift($csvData, $csvHeaders);
$filename = 'export_session_courses_reports_complete_' . api_get_local_time(); $filename = 'export_session_courses_reports_complete_' . date('Y-m-d_H-i-s') . '.csv';
Export::arrayToCsv($csvData, $filename); Export::arrayToCsvSimple($csvData, $filename);
exit; exit;
} }
} }
@ -10313,161 +10278,140 @@ class SessionManager
*/ */
public static function exportSessionsAsZip(array $sessionList): void public static function exportSessionsAsZip(array $sessionList): void
{ {
// Create a temporary ZIP file
$tempZipFile = api_get_path(SYS_ARCHIVE_PATH) . api_get_unique_id() . '.zip'; $tempZipFile = api_get_path(SYS_ARCHIVE_PATH) . api_get_unique_id() . '.zip';
$tempDir = dirname($tempZipFile); $tempDir = dirname($tempZipFile);
// Check if the directory exists and has write permissions
if (!is_dir($tempDir) || !is_writable($tempDir)) { if (!is_dir($tempDir) || !is_writable($tempDir)) {
exit("The directory for creating the ZIP file does not exist or lacks write permissions: $tempDir"); exit("The directory for creating the ZIP file does not exist or lacks write permissions: $tempDir");
} }
// Create a new ZIP archive
$zip = new \ZipArchive(); $zip = new \ZipArchive();
// Try to open the ZIP file for writing
if ($zip->open($tempZipFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== true) { if ($zip->open($tempZipFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== true) {
exit("Unable to open the ZIP file for writing: $tempZipFile"); exit("Unable to open the ZIP file for writing: $tempZipFile");
} }
$csvList = [];
// Process each session in the list
foreach ($sessionList as $sessionItemId) { foreach ($sessionList as $sessionItemId) {
$em = Database::getManager(); $courses = SessionManager::get_course_list_by_session_id($sessionItemId);
$sessionRepository = $em->getRepository(Session::class);
$session = $sessionRepository->find($sessionItemId);
if ($session->getNbrCourses() > 0) { if (!empty($courses)) {
$courses = $session->getCourses(); foreach ($courses as $course) {
$courseList = []; $courseCode = $course['course_code'];
$courseId = $course['id'];
$studentList = CourseManager::get_student_list_from_course_code($courseCode, true, $sessionItemId);
$userIds = array_keys($studentList);
// Collect courses for the session [$csvHeaders, $csvContent] = self::generateSessionCourseReportData($sessionItemId, $courseId, $userIds);
foreach ($courses as $sessionRelCourse) { array_unshift($csvContent, $csvHeaders);
$courseList[] = $sessionRelCourse->getCourse();
}
foreach ($courseList as $course) { $sessionInfo = api_get_session_info($sessionItemId);
$courseId = $course->getId();
$courseInfo = api_get_course_info_by_id($courseId); $courseInfo = api_get_course_info_by_id($courseId);
$addExerciseOption = api_get_configuration_value('add_exercise_best_attempt_in_report'); $csvFileName = $sessionInfo['name'] . '_' . $courseInfo['name'] . '.csv';
$sortByFirstName = api_sort_by_first_name();
$bestScoreLabel = get_lang('Score') . ' - ' . get_lang('Best attempt');
$courseCode = $courseInfo['code'];
// Prepare CSV headers $csvFilePath = Export::arrayToCsvSimple($csvContent, $csvFileName, true);
$csvHeaders = [];
$csvHeaders[] = get_lang('Official code'); if ($csvFilePath && file_exists($csvFilePath)) {
$zip->addFile($csvFilePath, $csvFileName);
}
}
}
}
if ($sortByFirstName) { if (!$zip->close()) {
$csvHeaders[] = get_lang('First name'); exit("Could not close the ZIP file correctly.");
$csvHeaders[] = get_lang('Last name'); }
if (file_exists($tempZipFile)) {
DocumentManager::file_send_for_download($tempZipFile, true);
unlink($tempZipFile);
} else { } else {
$csvHeaders[] = get_lang('Last name'); exit("The ZIP file was not created correctly.");
$csvHeaders[] = get_lang('First name'); }
} }
$csvHeaders[] = get_lang('Login');
$csvHeaders[] = get_lang('Training time');
$csvHeaders[] = get_lang('Course progress');
$csvHeaders[] = get_lang('Exercise progress');
$csvHeaders[] = get_lang('Exercise average');
$csvHeaders[] = get_lang('Score');
$csvHeaders[] = $bestScoreLabel;
// Include exercise results if available
$exerciseResultHeaders = [];
if (!empty($addExerciseOption) && isset($addExerciseOption['courses']) &&
isset($addExerciseOption['courses'][$courseCode])) {
foreach ($addExerciseOption['courses'][$courseCode] as $exerciseId) {
$exercise = new Exercise();
$exercise->read($exerciseId);
if ($exercise->iid) {
$title = get_lang('Exercise') . ': ' . $exercise->get_formated_title();
$csvHeaders[] = $title;
$exerciseResultHeaders[] = $title;
}
}
}
// Add more fields to the CSV headers
$csvHeaders[] = get_lang('Student_publication');
$csvHeaders[] = get_lang('Messages');
$csvHeaders[] = get_lang('Classes');
$csvHeaders[] = get_lang('Registration date');
$csvHeaders[] = get_lang('First login in course');
$csvHeaders[] = get_lang('Latest login in course');
// Get the list of students for the course
$studentList = CourseManager::get_student_list_from_course_code($courseCode, true, $sessionItemId);
$nbStudents = count($studentList);
// Pass the necessary data as parameters instead of using globals private static function generateSessionCourseReportData($sessionId, $courseId, $userIds): array
$userIds = array_keys($studentList); {
$em = Database::getManager();
$sessionRepository = $em->getRepository(Session::class);
$session = $sessionRepository->find($sessionId);
if (!$session instanceof Session) {
throw new \InvalidArgumentException("Invalid session object for session ID $sessionId");
}
$courseInfo = api_get_course_info_by_id($courseId);
$courseCode = $courseInfo['code'];
// Get the user data for CSV content $csvHeaders = [
$csvContentInSession = TrackingCourseLog::getUserData( get_lang('Session name'),
get_lang('Session access dates'),
get_lang('Session display dates'),
get_lang('Course name'),
get_lang('Official code'),
get_lang('First name'),
get_lang('Last name'),
get_lang('Login'),
get_lang('Training time'),
get_lang('Course progress'),
get_lang('Exercise progress'),
get_lang('Exercise average'),
get_lang('Score'),
get_lang('Score') . ' - ' . get_lang('Best attempt'),
get_lang('Student_publication'),
get_lang('Messages'),
get_lang('Classes'),
get_lang('Registration date'),
get_lang('First login in course'),
get_lang('Latest login in course'),
];
$csvData = TrackingCourseLog::getUserData(
null, null,
$nbStudents, count($userIds),
null, null,
null, null,
[], [],
true, true,
true, true,
$courseCode, $courseCode,
$sessionItemId, $sessionId,
true, true,
$userIds $userIds
); );
array_unshift($csvContentInSession, $csvHeaders);
// Get session info and dates $rawCsvContent = ChamiloSession::read('csv_content');
$sessionInfo = api_get_session_info($sessionItemId);
$sessionDates = SessionManager::parseSessionDates($session); if (empty($rawCsvContent)) {
throw new \RuntimeException("No CSV content found in session for course $courseCode and session $sessionId.");
// Add session name and dates to the CSV content }
array_unshift($csvContentInSession, [get_lang('Date'), $sessionDates['access']]);
array_unshift($csvContentInSession, [get_lang('SessionName'), Security::remove_XSS($sessionInfo['name'])]); $csvContent = [];
foreach ($rawCsvContent as $row) {
// Prepare CSV file information $alignedRow = [
$csvList[] = [ $row['session_name'] ?? '',
'session_id' => $sessionItemId, $row['session_startdate'] ?? '',
'session_name' => $session->getTitle(), $row['session_enddate'] ?? '',
'course_id' => $courseId, $row['course_name'] ?? '',
'course_name' => $courseInfo['name'], $row['official_code'] ?? '',
'path' => Export::arrayToCsv($csvContentInSession, '', true), // Generate the CSV $row['firstname'] ?? '',
$row['lastname'] ?? '',
$row['username'] ?? '',
$row['time'] ?? '',
$row['average_progress'] ?? '',
$row['exercise_progress'] ?? '',
$row['exercise_average'] ?? '',
$row['student_score'] ?? '',
$row['student_score_best'] ?? '',
$row['count_assignments'] ?? '',
$row['count_messages'] ?? '',
$row['classes'] ?? '',
$row['registered_at'] ?? '',
$row['first_connection'] ?? '',
$row['last_connection'] ?? '',
]; ];
} $csvContent[] = $alignedRow;
}
}
// Add the generated CSV files to the ZIP archive
foreach ($csvList as $csv) {
$newFileName = $csv['session_id'] . '_' . $csv['session_name'] . '-' . $csv['course_id'] . '_' . $csv['course_name'] . '.csv';
if (file_exists($csv['path'])) {
$zip->addFile($csv['path'], $newFileName);
}
} }
// Close the ZIP file return [$csvHeaders, $csvContent];
if ($zip->close() === false) {
exit("Could not close the ZIP file correctly.");
} }
// Clean up the CSV files after adding them to the ZIP
foreach ($csvList as $csv) {
if (file_exists($csv['path'])) {
unlink($csv['path']);
}
}
// Send the ZIP file for download
if (file_exists($tempZipFile)) {
DocumentManager::file_send_for_download($tempZipFile, true);
unlink($tempZipFile); // Delete the temporary ZIP file after download
} else {
exit("The ZIP file was not created correctly.");
}
}
} }

@ -2899,25 +2899,6 @@ class Tracking
} }
$sessionCondition = api_get_session_condition($sessionId); $sessionCondition = api_get_session_condition($sessionId);
//$sessionId = (int) $sessionId;
/*if (count($lp_ids) > 0) {
$condition_session = " AND session_id = $sessionId ";
} else {
$condition_session = " WHERE session_id = $sessionId ";
}
// Check the real number of LPs corresponding to the filter in the
// database (and if no list was given, get them all)
if (empty($sessionId)) {
$sql = "SELECT DISTINCT(iid), use_max_score
FROM $lp_table
WHERE
c_id = $courseId AND
(session_id = 0 OR session_id IS NULL) $condition_lp ";
} else {
}*/
$lp_list = $use_max_score = []; $lp_list = $use_max_score = [];
if (empty($condition_lp)) { if (empty($condition_lp)) {
$repo = Container::getLpRepository(); $repo = Container::getLpRepository();

@ -350,7 +350,7 @@ switch ($action) {
$studentId, $studentId,
$course, $course,
[], [],
$sId, api_get_session_entity($sId),
false, false,
false, false,
true true

Loading…
Cancel
Save