Merge branch 'master' of github.com:chamilo/chamilo-lms

pull/6027/head
Angel Fernando Quiroz Campos 8 months ago
commit aac741b6e4
No known key found for this signature in database
GPG Key ID: B284841AE3E562CD
  1. 4
      public/main/exercise/exercise.class.php
  2. 28
      public/main/exercise/exercise_report.php
  3. 40
      public/main/exercise/exercise_show.php
  4. 126
      public/main/inc/lib/exercise.lib.php
  5. 8
      public/main/inc/lib/pdf.lib.php

@ -8072,7 +8072,7 @@ class Exercise
INNER JOIN c_quiz cq
ON cq.id = te.exe_exo_id AND te.c_id = cq.c_id
WHERE
te.id = %s AND
te.c_id = %d AND
te.session_id = %s AND
cq.id IN (%s)
ORDER BY cq.id";
@ -8082,7 +8082,7 @@ class Exercise
$sql = "SELECT * FROM $track_exercises te
INNER JOIN c_quiz cq ON cq.id = te.exe_exo_id AND te.c_id = cq.c_id
WHERE
te.id = %s AND
te.c_id = %d AND
cq.id IN (%s)
ORDER BY cq.id";
$sql = sprintf($sql, $courseId, $ids);

@ -62,6 +62,7 @@ $course_id = api_get_course_int_id();
$exercise_id = isset($_REQUEST['exerciseId']) ? (int) $_REQUEST['exerciseId'] : (isset($_GET['id']) ? (int) $_GET['id'] : 0);
$locked = api_resource_is_locked_by_gradebook($exercise_id, LINK_EXERCISE);
$sessionId = api_get_session_id();
$action = $_REQUEST['action'] ?? null;
if (empty($exercise_id)) {
api_not_allowed(true);
@ -94,6 +95,27 @@ if (!empty($_GET['path'])) {
$parameters['path'] = Security::remove_XSS($_GET['path']);
}
switch ($action) {
case 'export_all_results':
$sessionId = api_get_session_id();
$courseId = api_get_course_int_id();
ExerciseLib::exportExerciseAllResultsZip($sessionId, $courseId, $exercise_id);
break;
case 'export_pdf':
$exerciseId = (int) $_GET['exerciseId'];
$attemptId = (int) $_GET['attemptId'];
$userId = (int) $_GET['userId'];
$urlExportPdf = api_get_path(WEB_PATH).'main/exercise/exercise_show.php?'.api_get_cidreq().'&id='.$attemptId.'&action=export&export_type=result_pdf';
if (!$exerciseId || !$attemptId) {
api_not_allowed(true);
}
header('Location: '.$urlExportPdf);
exit;
}
if (!empty($_REQUEST['export_report']) && '1' == $_REQUEST['export_report']) {
if (api_is_platform_admin() || api_is_course_admin() ||
api_is_course_tutor() || api_is_session_general_coach()
@ -431,9 +453,13 @@ if ($is_allowedToEdit && 'learnpath' != $origin) {
$actions .= '<a id="export_opener" href="'.api_get_self().'?export_report=1&exerciseId='.$exercise_id.'" >'.
Display::getMdiIcon('content-save', 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Export')).'</a>';
$actions .= Display::url(
Display::getMdiIcon(ActionIcon::REFRESH, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('RecalculateResults')),
Display::getMdiIcon(ActionIcon::REFRESH, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Recalculate Results')),
api_get_path(WEB_CODE_PATH).'exercise/recalculate_all.php?'.api_get_cidreq()."&exercise=$exercise_id"
);
$actions .= Display::url(
Display::getMdiIcon(ActionIcon::EXPORT_PDF, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Export all attempts')),
api_get_self().'?'.api_get_cidreq().'&action=export_all_results&exerciseId='.$exercise_id
);
// clean result before a selected date icon
if ($allowClean) {

@ -21,6 +21,7 @@ $origin = api_get_origin();
$currentUserId = api_get_user_id();
$printHeaders = 'learnpath' === $origin;
$id = isset($_REQUEST['id']) ? (int) $_REQUEST['id'] : 0; //exe id
$exportTypeAllResults = ('export' === $_GET['action'] && (in_array($_GET['export_type'], ['all_results', 'result_pdf'])));
if (empty($id)) {
api_not_allowed(true);
@ -39,15 +40,17 @@ $learnpath_id = $track_exercise_info['orig_lp_id'];
$learnpath_item_id = $track_exercise_info['orig_lp_item_id'];
$lp_item_view_id = $track_exercise_info['orig_lp_item_view_id'];
$isBossOfStudent = false;
if (api_is_student_boss()) {
// Check if boss has access to user info.
if (UserManager::userIsBossOfStudent($currentUserId, $student_id)) {
$isBossOfStudent = true;
if (!$exportTypeAllResults) {
if (api_is_student_boss()) {
// Check if boss has access to user info.
if (UserManager::userIsBossOfStudent($currentUserId, $student_id)) {
$isBossOfStudent = true;
} else {
api_not_allowed($printHeaders);
}
} else {
api_not_allowed($printHeaders);
api_protect_course_script($printHeaders, false, true);
}
} else {
api_protect_course_script($printHeaders, false, true);
}
// Database table definitions
@ -80,6 +83,7 @@ if (empty($nbrQuestions)) {
if (empty($questionList)) {
$questionList = Session::read('questionList');
}
/* @var Exercise $objExercise */
if (empty($objExercise)) {
$objExercise = Session::read('objExercise');
}
@ -93,7 +97,8 @@ $is_allowedToEdit =
api_is_course_tutor() ||
api_is_session_admin() ||
api_is_drh() ||
api_is_student_boss();
api_is_student_boss() ||
$exportTypeAllResults;
if (!empty($sessionId) && !$is_allowedToEdit) {
if (api_is_course_session_coach(
@ -973,7 +978,24 @@ if ('export' === $action) {
'orientation' => 'P',
];
$pdf = new PDF('A4', $params['orientation'], $params);
$pdf->html_to_pdf_with_template($content, false, false, true);
if ('all_results' === $_GET['export_type']) {
$sessionId = api_get_session_id();
$courseId = api_get_course_int_id();
$exportName = 'S'.$sessionId.'-C'.$courseId.'-T'.$exercise_id;
$baseDir = api_get_path(SYS_ARCHIVE_PATH);
$folderName = 'pdfexport-'.$exportName;
$exportFolderPath = $baseDir.$folderName;
if (!is_dir($exportFolderPath)) {
@mkdir($exportFolderPath);
}
$pdfFileName = $user_info['firstname'].' '.$user_info['lastname'].'-attemptId'.$id.'.pdf';
$pdfFileName = api_replace_dangerous_char($pdfFileName);
$fileNameToSave = $exportFolderPath.'/'.$pdfFileName;
$pdf->html_to_pdf_with_template($content, true, false, true, [], 'F', $fileNameToSave);
} else {
$pdf->html_to_pdf_with_template($content, false, false, true);
}
exit;
}

@ -2351,6 +2351,13 @@ HOTSPOT;
]
);
$exportPdfUrl = api_get_path(WEB_CODE_PATH).'exercise/exercise_report.php?'.
api_get_cidreq().'&exerciseId='.$exercise_id.'&action=export_pdf&attemptId='.$id.'&userId='.(int) $results[$i]['exe_user_id'];
$actions .= '<a href="'.$exportPdfUrl.'" target="_blank">'
.Display::getMdiIcon(ActionIcon::EXPORT_PDF, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Export to PDF'))
.'</a>';
$filterByUser = isset($_GET['filter_by_user']) ? (int) $_GET['filter_by_user'] : 0;
$delete_link = '<a
href="exercise_report.php?'.api_get_cidreq().'&filter_by_user='.$filterByUser.'&filter='.$filter.'&exerciseId='.$exercise_id.'&delete=delete&did='.$id.'"
@ -6024,4 +6031,123 @@ EOT;
return $scorePassed;
}
/**
* Export all results of *one* exercise to a ZIP file containing individual PDFs.
*
* @return false|void
* @throws Exception
*/
public static function exportExerciseAllResultsZip(
int $sessionId,
int $courseId,
int $exerciseId,
array $filterDates = [],
string $mainPath = ''
) {
$objExerciseTmp = new Exercise($courseId);
$exeResults = $objExerciseTmp->getExerciseAndResult(
$courseId,
$sessionId,
$exerciseId
);
$exportOk = false;
if (!empty($exeResults)) {
$exportName = 'S'.$sessionId.'-C'.$courseId.'-T'.$exerciseId;
$baseDir = api_get_path(SYS_ARCHIVE_PATH);
$folderName = 'pdfexport-'.$exportName;
$exportFolderPath = $baseDir.$folderName;
// 1. Cleans the export folder if it exists.
if (is_dir($exportFolderPath)) {
rmdirr($exportFolderPath);
}
// 2. Create the pdfs inside a new export folder path.
foreach ($exeResults as $exeResult) {
$exeId = (int) $exeResult['exe_id'];
self::saveFileExerciseResultPdf($exeId, $courseId, $sessionId);
}
// 3. If export folder is not empty will be zipped.
$isFolderPathEmpty = (file_exists($exportFolderPath) && 2 == count(scandir($exportFolderPath)));
if (is_dir($exportFolderPath) && !$isFolderPathEmpty) {
$exportOk = true;
$exportFilePath = $baseDir.$exportName.'.zip';
$zip = new \ZipArchive();
if ($zip->open($exportFilePath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) === true) {
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($exportFolderPath),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file) {
if (!$file->isDir()) {
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($exportFolderPath) + 1);
$zip->addFile($filePath, $relativePath);
}
}
$zip->close();
} else {
throw new Exception('Failed to create ZIP file');
}
rmdirr($exportFolderPath);
if (!empty($mainPath) && file_exists($exportFilePath)) {
@rename($exportFilePath, $mainPath.'/'.$exportName.'.zip');
} else {
DocumentManager::file_send_for_download($exportFilePath, true, $exportName.'.zip');
exit;
}
}
}
if (empty($mainPath) && !$exportOk) {
Display::addFlash(
Display::return_message(
get_lang('ExportExerciseNoResult'),
'warning',
false
)
);
}
return false;
}
/**
* Generates and saves a PDF file for a specific exercise attempt result.
*/
public static function saveFileExerciseResultPdf(
int $exeId,
int $courseId,
int $sessionId
): void
{
$cidReq = 'cid='.$courseId.'&sid='.$sessionId.'&gid=0&gradebook=0';
$url = api_get_path(WEB_PATH).'main/exercise/exercise_show.php?'.$cidReq.'&id='.$exeId.'&action=export&export_type=all_results';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_COOKIE, session_id());
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
curl_setopt($ch, CURLOPT_COOKIESESSION, true);
curl_setopt($ch, CURLOPT_FAILONERROR, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
if (false === $result) {
error_log('saveFileExerciseResultPdf error: '.curl_error($ch));
}
curl_close($ch);
}
}

@ -102,7 +102,9 @@ class PDF
$saveToFile = false,
$returnHtml = false,
$addDefaultCss = false,
$extraRows = []
$extraRows = [],
$outputMode = 'D',
$fileToSave = null
) {
if (empty($this->template)) {
$tpl = new Template('', false, false, false, false, true, false);
@ -170,9 +172,9 @@ class PDF
$css,
$this->params['filename'],
$this->params['course_code'],
'D',
$outputMode,
$saveToFile,
null,
$fileToSave,
$returnHtml,
$addDefaultCss
);

Loading…
Cancel
Save