diff --git a/public/main/exercise/exercise_report.php b/public/main/exercise/exercise_report.php
index 066cf1d564c..08a4fb21a5a 100644
--- a/public/main/exercise/exercise_report.php
+++ b/public/main/exercise/exercise_report.php
@@ -123,6 +123,22 @@
header('Location: '.$urlExportPdf);
exit;
+ case 'send_email':
+ $attemptId = (int) $_GET['attemptId'];
+ ExerciseLib::sendExerciseResultByEmail($attemptId);
+ Display::addFlash(Display::return_message(get_lang('Email content logged to error_log')));
+ header('Location: '.api_get_self().'?'.api_get_cidreq().'&exerciseId='.$exercise_id);
+ exit;
+ case 'send_all_emails':
+ $sessionId = api_get_session_id();
+ $courseId = api_get_course_int_id();
+ $attempts = ExerciseLib::getReviewedAttemptsInfo($exercise_id, $sessionId);
+ foreach ($attempts as $attempt) {
+ ExerciseLib::sendExerciseResultByEmail($attempt['exe_id']);
+ }
+ Display::addFlash(Display::return_message(get_lang('All emails sent successfully')));
+ header('Location: '.api_get_self().'?'.api_get_cidreq().'&exerciseId='.$exercise_id);
+ exit;
}
if (!empty($_REQUEST['export_report']) && '1' == $_REQUEST['export_report']) {
@@ -470,6 +486,11 @@
api_get_self().'?'.api_get_cidreq().'&action=export_all_results&exerciseId='.$exercise_id
);
+ $actions .= Display::url(
+ Display::getMdiIcon(ActionIcon::SEND_ALL_EMAILS, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Send all by email')),
+ api_get_self().'?'.api_get_cidreq().'&action=send_all_emails&exerciseId='.$exercise_id
+ );
+
// clean result before a selected date icon
if ($allowClean) {
$actions .= Display::url(
@@ -731,7 +752,7 @@
//for the top bar
'editoptions' => ['value' => $group_parameters],
],
- ['name' => 'duration', 'index' => 'exe_duration', 'width' => '150', 'align' => 'left', 'search' => 'true'],
+ ['name' => 'duration', 'index' => 'exe_duration', 'width' => '80', 'align' => 'left', 'search' => 'true'],
['name' => 'start_date', 'index' => 'start_date', 'width' => '150', 'align' => 'left', 'search' => 'true'],
['name' => 'exe_date', 'index' => 'exe_date', 'width' => '150', 'align' => 'left', 'search' => 'true'],
['name' => 'score', 'index' => 'score', 'width' => '120', 'align' => 'center', 'search' => 'true'],
@@ -755,8 +776,8 @@
),
],
],
- ['name' => 'lp', 'index' => 'orig_lp_id', 'width' => '150', 'align' => 'left', 'search' => 'false'],
- ['name' => 'actions', 'index' => 'actions', 'width' => '180', 'align' => 'left', 'search' => 'false', 'sortable' => 'false'],
+ ['name' => 'lp', 'index' => 'orig_lp_id', 'width' => '130', 'align' => 'left', 'search' => 'false'],
+ ['name' => 'actions', 'index' => 'actions', 'width' => '240', 'align' => 'left', 'search' => 'false', 'sortable' => 'false'],
];
if ('true' === $officialCodeInList) {
diff --git a/public/main/inc/lib/exercise.lib.php b/public/main/inc/lib/exercise.lib.php
index 644db38d147..8b3886f3aa6 100644
--- a/public/main/inc/lib/exercise.lib.php
+++ b/public/main/inc/lib/exercise.lib.php
@@ -2357,6 +2357,10 @@ public static function get_exam_results_data(
.Display::getMdiIcon(ActionIcon::EXPORT_PDF, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Export to PDF'))
.'';
+ $sendMailUrl = api_get_path(WEB_CODE_PATH).'exercise/exercise_report.php?'.api_get_cidreq().'&action=send_email&exerciseId='.$exercise_id.'&attemptId='.$results[$i]['exe_id'];
+ $emailLink = ''
+ .Display::getMdiIcon(ActionIcon::SEND_SINGLE_EMAIL, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Send by email'))
+ .'';
$filterByUser = isset($_GET['filter_by_user']) ? (int) $_GET['filter_by_user'] : 0;
$delete_link = ' '',
+ 'subject' => 'No exercise info found',
+ 'message' => 'Attempt ID not found or invalid.',
+ ];
+ }
+
+ $studentId = $trackExerciseInfo['exe_user_id'];
+ $courseInfo = api_get_course_info();
+ $teacherId = api_get_user_id();
+
+ if (
+ empty($trackExerciseInfo['orig_lp_id']) ||
+ empty($trackExerciseInfo['orig_lp_item_id'])
+ ) {
+ $url = api_get_path(WEB_CODE_PATH).'exercise/result.php?id='.$trackExerciseInfo['exe_id'].'&'.api_get_cidreq()
+ .'&show_headers=1&id_session='.api_get_session_id();
+ } else {
+ $url = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?action=view&item_id='
+ .$trackExerciseInfo['orig_lp_item_id'].'&lp_id='.$trackExerciseInfo['orig_lp_id'].'&'.api_get_cidreq()
+ .'&id_session='.api_get_session_id();
+ }
+
+ $message = self::getEmailNotification(
+ $teacherId,
+ $courseInfo,
+ $trackExerciseInfo['title'],
+ $url
+ );
+
+ return [
+ 'to' => $studentId,
+ 'subject' => get_lang('Corrected test result'),
+ 'message' => $message,
+ ];
+ }
+
+ /**
+ * Sends the exercise result email to the student.
+ */
+ public static function sendExerciseResultByEmail(int $attemptId): void
+ {
+ $content = self::getEmailContentForAttempt($attemptId);
+
+ if (empty($content['to'])) {
+ return;
+ }
+
+ MessageManager::send_message_simple(
+ $content['to'],
+ $content['subject'],
+ $content['message'],
+ api_get_user_id()
+ );
+ }
+
+ /**
+ * Returns all reviewed attempts for a given exercise and session.
+ */
+ public static function getReviewedAttemptsInfo(int $exerciseId, int $sessionId): array
+ {
+ $courseId = api_get_course_int_id();
+ $trackTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
+ $qualifyTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_QUALIFY);
+
+ $sessionCondition = api_get_session_condition($sessionId, true, false, 't.session_id');
+
+ $sql = "
+ SELECT DISTINCT t.exe_id
+ FROM $trackTable t
+ INNER JOIN $qualifyTable q ON (t.exe_id = q.exe_id AND q.author > 0)
+ WHERE
+ t.c_id = $courseId AND
+ t.exe_exo_id = $exerciseId
+ $sessionCondition
+ ";
+
+ return Database::store_result(Database::query($sql));
+ }
+
/**
* @param $score
* @param $weight
diff --git a/src/CoreBundle/Component/Utils/ActionIcon.php b/src/CoreBundle/Component/Utils/ActionIcon.php
index 0eabb681b92..f0bb326063f 100644
--- a/src/CoreBundle/Component/Utils/ActionIcon.php
+++ b/src/CoreBundle/Component/Utils/ActionIcon.php
@@ -104,6 +104,10 @@ enum ActionIcon: string
case SAVE_FORM = 'content-save';
// Send a message
case SEND_MESSAGE = 'send';
+ // Send all examsheets by email
+ case SEND_ALL_EMAILS = 'email-multiple';
+ // Send a single examsheet by email
+ case SEND_SINGLE_EMAIL = 'email-outline';
// Add an attachment
case ADD_ATTACHMENT = 'paperclip-plus';
// ? See RESTORE_BACKUP