Skip to content

Commit

Permalink
Exercise: Improve PDF export of exercise results. Export all exercise…
Browse files Browse the repository at this point in the history
…s in a course + allow for dates range - refs BT#20691
  • Loading branch information
ywarnier committed May 26, 2023
1 parent 796008a commit 3ae1780
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 16 deletions.
18 changes: 17 additions & 1 deletion main/admin/export_exercise_results.php
Expand Up @@ -144,6 +144,18 @@ function confirm_your_choice() {
)
->setSelected($exerciseId);

$form->addDateTimePicker('start_date', get_lang('StartDate'));
$form->addDateTimePicker('end_date', get_lang('EndDate'));
$form->addRule('start_date', get_lang('InvalidDate'), 'datetime');
$form->addRule('end_date', get_lang('InvalidDate'), 'datetime');

$form->addRule(
['start_date', 'end_date'],
get_lang('StartDateShouldBeBeforeEndDate'),
'date_compare',
'lte'
);

$form->addHidden('course_id_changed', '0');
$form->addHidden('exercise_id_changed', '0');
$form->addButtonExport(get_lang('Export'), 'name');
Expand All @@ -155,7 +167,11 @@ function confirm_your_choice() {
$sessionId = (int) $values['session_id'];
$courseId = (int) $values['selected_course'];
$exerciseId = (int) $values['exerciseId'];
ExerciseLib::exportExerciseAllResultsZip($sessionId, $courseId, $exerciseId);
$filterDates = [
'start_date' => (!empty($values['start_date']) ? $values['start_date'] : ''),
'end_date' => (!empty($values['end_date']) ? $values['end_date'] : ''),
];
ExerciseLib::exportExerciseAllResultsZip($sessionId, $courseId, $exerciseId, $filterDates);
}
}

Expand Down
34 changes: 26 additions & 8 deletions main/exercise/exercise.class.php
Expand Up @@ -8420,13 +8420,16 @@ public function getExercisesByCourseSession($courseId, $sessionId)
}

/**
* Get array of exercise details and user results
* @param int $courseId
* @param int $sessionId
* @param array $quizId
* @param bool $checkOnlyActiveUsers
* @param array $filterDates Limit the results exported to those within this range ('start_date' to 'end_date')
*
* @return array exercises
*/
public function getExerciseAndResult($courseId, $sessionId, $quizId = [], $status = null)
public function getExerciseAndResult($courseId, $sessionId, $quizId = [], $checkOnlyActiveUsers = false, $filterDates = [])
{
if (empty($quizId)) {
return [];
Expand All @@ -8438,16 +8441,30 @@ public function getExerciseAndResult($courseId, $sessionId, $quizId = [], $statu
$ids = is_array($quizId) ? $quizId : [$quizId];
$ids = array_map('intval', $ids);
$ids = implode(',', $ids);
$track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
$trackExcercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
$tblQuiz = Database::get_course_table(TABLE_QUIZ_TEST);
$tblUser = Database::get_main_table(TABLE_MAIN_USER);

$condition = '';
if (isset($status)) {
$condition .= " AND te.status = '$status' ";
$innerJoinUser = '';
if ($checkOnlyActiveUsers) {
$condition .= " AND te.status = '' ";
$innerJoinUser .= " INNER JOIN $tblUser u ON u.user_id = te. exe_user_id";
}

if (!empty($filterDates)) {
if (!empty($filterDates['start_date'])) {
$condition .= " AND te.exe_date >= '".Database::escape_string($filterDates['start_date'])."' ";
}
if (!empty($filterDates['end_date'])) {
$condition .= " AND te.exe_date <= '".Database::escape_string($filterDates['end_date'])."' ";
}
}

if (0 != $sessionId) {
$sql = "SELECT * FROM $track_exercises te
INNER JOIN c_quiz cq ON cq.iid = te.exe_exo_id
$sql = "SELECT * FROM $trackExcercises te
INNER JOIN $tblQuiz cq ON cq.iid = te.exe_exo_id
$innerJoinUser
WHERE
te.c_id = %s AND
te.session_id = %s AND
Expand All @@ -8457,8 +8474,9 @@ public function getExerciseAndResult($courseId, $sessionId, $quizId = [], $statu

$sql = sprintf($sql, $courseId, $sessionId, $ids);
} else {
$sql = "SELECT * FROM $track_exercises te
INNER JOIN c_quiz cq ON cq.iid = te.exe_exo_id
$sql = "SELECT * FROM $trackExcercises te
INNER JOIN $tblQuiz cq ON cq.iid = te.exe_exo_id
$innerJoinUser
WHERE
te.c_id = %s AND
cq.iid IN (%s)
Expand Down
5 changes: 5 additions & 0 deletions main/exercise/exercise.php
Expand Up @@ -660,6 +660,11 @@ function showUserToSendNotificacion(element) {
);
}

$actionsLeft .= Display::url(
Display::return_icon('export_pdf.png', get_lang('ExportAllExercisesAllResults'), [], ICON_SIZE_MEDIUM),
api_get_path(WEB_CODE_PATH).'exercise/exercise_report.php?'.api_get_cidreq().'&action=export_all_exercises_results'
);

if ($limitTeacherAccess) {
if (api_is_platform_admin()) {
$actionsLeft .= $cleanAll;
Expand Down
14 changes: 11 additions & 3 deletions main/exercise/exercise_report.php
Expand Up @@ -58,9 +58,12 @@
$exercise_id = isset($_REQUEST['exerciseId']) ? (int) $_REQUEST['exerciseId'] : 0;
$locked = api_resource_is_locked_by_gradebook($exercise_id, LINK_EXERCISE);
$sessionId = api_get_session_id();
$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : null;

if (empty($exercise_id)) {
api_not_allowed(true);
if ('export_all_exercises_results' !== $action) {
if (empty($exercise_id)) {
api_not_allowed(true);
}
}

$blockPage = true;
Expand Down Expand Up @@ -149,8 +152,13 @@
$objExerciseTmp = new Exercise();
$exerciseExists = $objExerciseTmp->read($exercise_id);

$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : null;
switch ($action) {
case 'export_all_exercises_results':
$sessionId = api_get_session_id();
$courseId = api_get_course_int_id();
ExerciseLib::exportAllExercisesResultsZip($sessionId, $courseId);

break;
case 'export_all_results':
$sessionId = api_get_session_id();
$courseId = api_get_course_int_id();
Expand Down
70 changes: 66 additions & 4 deletions main/inc/lib/exercise.lib.php
Expand Up @@ -7190,17 +7190,75 @@ public static function saveFileExerciseResultPdf(
curl_close($ch);
}

public static function exportAllExercisesResultsZip(
int $sessionId,
int $courseId,
$filterDates = []
) {
$exercises = self::get_all_exercises_for_course_id(
null,
$sessionId,
$courseId,
true
);

$exportOk = false;
if (!empty($exercises)) {
$exportName = 'S'.$sessionId.'-C'.$courseId.'-ALL';
$baseDir = api_get_path(SYS_ARCHIVE_PATH);
$folderName = 'pdfexport-'.$exportName;
$exportFolderPath = $baseDir.$folderName;

if (!is_dir($exportFolderPath)) {
@mkdir($exportFolderPath);
}

foreach ($exercises as $exercise) {
$exerciseId = $exercise['iid'];
self::exportExerciseAllResultsZip($sessionId, $courseId, $exerciseId, [], $exportFolderPath);
}

// 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 \PclZip($exportFilePath);
$zip->create($exportFolderPath, PCLZIP_OPT_REMOVE_PATH, $exportFolderPath);
rmdirr($exportFolderPath);

DocumentManager::file_send_for_download($exportFilePath, true, $exportName.'.zip');
exit;
}
}

if (!$exportOk) {
Display::addFlash(
Display::return_message(
get_lang('ExportExerciseNoResult'),
'warning',
false
)
);
}

return false;
}

public static function exportExerciseAllResultsZip(
int $sessionId,
int $courseId,
int $exerciseId
int $exerciseId,
$filterDates = [],
string $mainPath = ''
) {
$objExerciseTmp = new Exercise($courseId);
$exeResults = $objExerciseTmp->getExerciseAndResult(
$courseId,
$sessionId,
$exerciseId,
''
true,
$filterDates
);

$exportOk = false;
Expand Down Expand Up @@ -7232,8 +7290,12 @@ public static function exportExerciseAllResultsZip(
$zip->create($exportFolderPath, PCLZIP_OPT_REMOVE_PATH, $exportFolderPath);
rmdirr($exportFolderPath);

DocumentManager::file_send_for_download($exportFilePath, true, $exportName.'.zip');
exit;
if (!empty($mainPath) && file_exists($exportFilePath)) {
@rename($exportFilePath, $mainPath.'/'.$exportName.'.zip');
} else {
DocumentManager::file_send_for_download($exportFilePath, true, $exportName.'.zip');
exit;
}
}
}

Expand Down
1 change: 1 addition & 0 deletions main/lang/english/trad4all.inc.php
Expand Up @@ -9024,4 +9024,5 @@
$AddEmailPictureComment = "This picture will be used in the course header and in the e-mails sent and PDFs generated from this course. The picture will have a ratio of 25:7. You can crop the picture you upload.";
$DeleteEmailPicture = "Delete picture for headers";
$AddPictureComment = "The final picture must be in a 16:9 ratio, but you can crop the picture you upload.";
$ExportAllExercisesAllResults = "Export all results of all tests";
?>
1 change: 1 addition & 0 deletions main/lang/french/trad4all.inc.php
Expand Up @@ -8958,4 +8958,5 @@
$AddEmailPictureComment = "L'image sera utilisée dans les en-têtes de ce cours mais également des e-mails envoyés et des PDFs générés depuis ce cours. L'image doit avoir un ratio de 25:7. Vous pouvez recouper l'image au moment de l'envoi.";
$DeleteEmailPicture = "Supprimer l'image d'en-tête";
$AddPictureComment = "L'image finale doit avoir un format 16:9, mais vous pouvez la recouper lors de l'envoi.";
$ExportAllExercisesAllResults = "Exporter tous les résultats de tous les exercices";
?>
1 change: 1 addition & 0 deletions main/lang/spanish/trad4all.inc.php
Expand Up @@ -9049,4 +9049,5 @@
$AddEmailPictureComment = "Esta imagen será usada en la cabecera de este curso y la de los e-mails enviados desde este curso, pero también en los PDFs generados desde este curso. La imagen final tiene que tener una proporción de 25:7, pero la puede recortar al momento de subirla.";
$DeleteEmailPicture = "Eliminar la imagen de cabecera";
$AddPictureComment = "La imagen final tiene que tener una proporción de 16:9, pero la puede recortar durante la subida.";
$ExportAllExercisesAllResults = "Exportar todos los resultados de todos los ejercicios";
?>

0 comments on commit 3ae1780

Please sign in to comment.