ILIAS  release_8 Revision v8.24
class.ilExAssignmentReminder.php
Go to the documentation of this file.
1<?php
2
30{
31 public const SUBMIT_REMINDER = "submit";
32 public const GRADE_REMINDER = "grade";
33 public const FEEDBACK_REMINDER = "peer";
34
35 protected ilDBInterface $db;
36 protected ilTree $tree;
37
38 protected ?bool $rmd_status = null;
39 protected int $rmd_start = 0;
40 protected int $rmd_end = 0;
41 protected int $rmd_frequency = 0;
42 protected int $rmd_last_send = 0;
43 protected int $rmd_tpl_id = 0;
44
45 protected int $ass_id = 0;
46 protected int $exc_id = 0;
47 protected string $rmd_type = "";
48
49 protected ilLogger $log;
51
52 //todo remove the params as soon as possible.
53 public function __construct(
54 int $a_exc_id = 0,
55 int $a_ass_id = 0,
56 string $a_type = ""
57 ) {
58 global $DIC;
59 $this->db = $DIC->database();
60 $this->tree = $DIC->repositoryTree();
61 $this->access = $DIC->access();
62 $this->log = ilLoggerFactory::getLogger("exc");
63
64 if ($a_ass_id) {
65 $this->ass_id = $a_ass_id;
66 }
67 if ($a_exc_id) {
68 $this->exc_id = $a_exc_id;
69 }
70 if ($a_type) {
71 $this->rmd_type = $a_type;
72 }
73 if ($a_exc_id and $a_ass_id and $a_type) {
74 $this->read();
75 }
76 }
77
78 public function getReminderType(): string
79 {
80 return $this->rmd_type;
81 }
82
87 public function setReminderStatus(?bool $a_status): void
88 {
89 $this->rmd_status = $a_status;
90 }
91
92 public function getReminderStatus(): ?bool
93 {
94 return $this->rmd_status;
95 }
96
97 // Set num days before the deadline to start sending notifications.
98 public function setReminderStart(int $a_num_days): void
99 {
100 $this->rmd_start = $a_num_days;
101 }
102
103 public function getReminderStart(): int
104 {
105 return $this->rmd_start;
106 }
107
108 public function setReminderEnd(int $a_date): void
109 {
110 $this->rmd_end = $a_date;
111 }
112
113 public function getReminderEnd(): int
114 {
115 return $this->rmd_end;
116 }
117
118 // Set frequency in days
119 public function setReminderFrequency(int $a_num_days): void
120 {
121 $this->rmd_frequency = $a_num_days;
122 }
123
124 public function getReminderFrequency(): int
125 {
127 }
128
129 public function setReminderLastSend(int $a_timestamp): void
130 {
131 $this->rmd_last_send = $a_timestamp;
132 }
133
134 public function getReminderLastSend(): int
135 {
137 }
138
139 public function setReminderMailTemplate(int $a_tpl_id): void
140 {
141 $this->rmd_tpl_id = $a_tpl_id;
142 }
143
144 public function getReminderMailTemplate(): int
145 {
146 return $this->rmd_tpl_id;
147 }
148
149 public function save(): void
150 {
151 $this->db->insert("exc_ass_reminders", array(
152 "type" => array("text", $this->rmd_type),
153 "ass_id" => array("integer", $this->ass_id),
154 "exc_id" => array("integer", $this->exc_id),
155 "status" => array("integer", $this->getReminderStatus()),
156 "start" => array("integer", $this->getReminderStart()),
157 "end" => array("integer", $this->getReminderEnd()),
158 "freq" => array("integer", $this->getReminderFrequency()),
159 "last_send" => array("integer", $this->getReminderLastSend()),
160 "template_id" => array("integer", $this->getReminderMailTemplate())
161 ));
162 }
163
164 public function update(): void
165 {
166 $this->db->update(
167 "exc_ass_reminders",
168 array(
169 "status" => array("integer", $this->getReminderStatus()),
170 "start" => array("integer", $this->getReminderStart()),
171 "end" => array("integer", $this->getReminderEnd()),
172 "freq" => array("integer", $this->getReminderFrequency()),
173 "last_send" => array("integer", $this->getReminderLastSend()),
174 "template_id" => array("integer", $this->getReminderMailTemplate())
175 ),
176 array(
177 "type" => array("text", $this->rmd_type),
178 "exc_id" => array("integer", $this->exc_id),
179 "ass_id" => array("integer", $this->ass_id)
180 )
181 );
182 }
183
184
185 public function read(): void
186 {
187 $set = $this->db->queryF(
188 "SELECT status, start, freq, end, last_send, template_id" .
189 " FROM exc_ass_reminders" .
190 " WHERE type = %s AND ass_id = %s AND exc_id = %s",
191 ["text", "integer", "integer"],
192 [$this->rmd_type, $this->ass_id, $this->exc_id]
193 );
194
195 $rec = $this->db->fetchAssoc($set);
196 if (is_array($rec)) {
197 $this->initFromDB($rec);
198 }
199 }
200
201 protected function initFromDB(array $a_set): void
202 {
203 $this->setReminderStatus((bool) $a_set["status"]);
204 $this->setReminderStart((int) $a_set["start"]);
205 $this->setReminderEnd((int) $a_set["end"]);
206 $this->setReminderFrequency((int) $a_set["freq"]);
207 $this->setReminderLastSend((int) $a_set["last_send"]);
208 $this->setReminderMailTemplate((int) $a_set["template_id"]);
209 }
210
211
212 // Specific Methods to be used via Cron Job.
213
218 public function getReminders(string $a_type = ""): array
219 {
220 $now = time();
221 $today = date("Y-m-d");
222
223 $this->log->debug("Get reminders $a_type.");
224
225 //remove time from the timestamp (86400 = 24h)
226 //$now = floor($now/86400)*86400;
227 $and_type = "";
228 if ($a_type == self::SUBMIT_REMINDER || $a_type == self::GRADE_REMINDER || $a_type == self::FEEDBACK_REMINDER) {
229 $and_type = " AND type = '" . $a_type . "'";
230 }
231
232 $query = "SELECT last_send_day, ass_id, exc_id, status, start, freq, end, type, last_send, template_id" .
233 " FROM exc_ass_reminders" .
234 " WHERE status = 1" .
235 " AND start <= " . $now .
236 " AND end > " . ($now - 86400) .
237 $and_type;
238
239
240 $result = $this->db->query($query);
241
242 $array_data = array();
243 while ($rec = $this->db->fetchAssoc($result)) {
244 $rem = array(
245 "ass_id" => $rec["ass_id"],
246 "exc_id" => $rec["exc_id"],
247 "start" => $rec["start"],
248 "end" => $rec["end"],
249 "freq" => $rec["freq"],
250 "type" => $rec["type"],
251 "last_send" => $rec["last_send"],
252 "last_send_day" => $rec["last_send_day"],
253 "template_id" => $rec["template_id"]
254 );
255
256 $end_day = date("Y-m-d", $rec["end"]);
257
258 //frequency
259 $next_send = "";
260 if ($rec["last_send_day"] != "") {
261 $date = new DateTime($rec["last_send_day"]);
262 $date->add(new DateInterval('P' . $rec["freq"] . 'D'));
263 $next_send = $date->format('Y-m-d');
264 }
265 $this->log->debug("ass: " . $rec["ass_id"] . ", last send: " . $rec["last_send_day"] .
266 ", freq: " . $rec["freq"] . ", end_day: $end_day, today: " . $today . ", next send: $next_send");
267 if ($rec["last_send_day"] == "" || $next_send <= $today) {
268 if ($end_day >= $today) {
269 $this->log->debug("included");
270 $array_data[] = $rem;
271 }
272 }
273 }
274
275 return $array_data;
276 }
277
283 public function parseSubmissionReminders(array $a_reminders): array
284 {
285 $reminders = $a_reminders;
286 $users_to_remind = array();
287
288 foreach ($reminders as $rem) {
289 $ass_id = $rem["ass_id"];
290 $ass_obj = new ilExAssignment($ass_id);
291
292 $exc_id = $rem["exc_id"];
293
295 foreach ($exc_refs as $exc_ref) {
296
297 // check if we have an upper course
298 if ($course_ref_id = $this->tree->checkForParentType($exc_ref, 'crs')) {
299 $obj = new ilObjCourse($course_ref_id);
300 $participants_class = ilCourseParticipants::class;
301 $parent_ref_id = $course_ref_id;
302 $parent_obj_type = 'crs';
303
304 // check if we have an upper group
305 } elseif ($group_ref_id = $this->tree->checkForParentType($exc_ref, 'grp')) {
306 $obj = new ilObjGroup($group_ref_id);
307 $participants_class = ilGroupParticipants::class;
308 $parent_ref_id = $group_ref_id;
309 $parent_obj_type = 'grp';
310 } else {
311 continue;
312 }
313
314 // get participants
315 $parent_obj_id = $obj->getId();
317 $participants_ids = $participants_class::getInstance($parent_ref_id)->getMembers();
318
319 foreach ($participants_ids as $member_id) {
320 $this->log->debug("submission reminder: ass: $ass_id, member: $member_id.");
321
322 // check read permission
323 if ($this->access->checkAccessOfUser($member_id, "read", "", $exc_ref)) {
325
326 $deadline_day = date("Y-m-d", $state->getOfficialDeadline());
327 $today = date("Y-m-d");
328 $date = new DateTime($deadline_day);
329 $date->sub(new DateInterval('P' . $rem["start"] . 'D'));
330 $send_from = $date->format('Y-m-d');
331 $this->log->debug("today: $today, send from: $send_from, start: " . $rem["start"] . ", submission allowed: " . $state->isSubmissionAllowed());
332
333 // check if user can submit and difference in days is smaller than reminder start
334 if ($state->isSubmissionAllowed() && $send_from <= $today) {
335 $submission = new ilExSubmission($ass_obj, $member_id);
336
337 // check if user has submitted anything
338 if (!$submission->getLastSubmission()) {
339 $member_data = array(
340 "parent_type" => $parent_obj_type,
341 "parent_id" => $parent_obj_id,
342 "exc_id" => $exc_id,
343 "exc_ref" => $exc_ref,
344 "ass_id" => $ass_id,
345 "member_id" => $member_id,
346 "reminder_type" => $rem["type"],
347 "template_id" => $rem["template_id"]
348 );
349 $users_to_remind[] = $member_data;
350 }
351 }
352 }
353 }
354 }
355 }
356 return $users_to_remind;
357 }
358
362 public function parseGradeReminders(array $a_reminders): array
363 {
364 $reminders = $a_reminders;
365 $users_to_remind = array();
366
367 $has_pending_to_grade = false;
368
369 foreach ($reminders as $rem) {
370 //$this->log->debug("---- parse grade reminder with values -> ",$rem);
371 $ass_obj = new ilExAssignment($rem["ass_id"]);
372 $members_data = $ass_obj->getMemberListData();
373
374 //$this->log->debug("--- get members list data => ",$members_data);
375 foreach ($members_data as $assignment_data) {
376 if ($assignment_data["status"] == ilExerciseManagementGUI::GRADE_NOT_GRADED) {
377 //at least there is one submission pending to grade.
378 $has_pending_to_grade = true;
379 }
380 }
381
382 if ($has_pending_to_grade) {
383 //get tutor of this exercise.
385
386 foreach ($users as $user_id) {
387 $exc_refs = ilObject::_getAllReferences($rem["exc_id"]);
388 $unike_usr_id = array();
389 foreach ($exc_refs as $exc_ref) {
390 if ($this->access->checkAccessOfUser($user_id, "write", "", $exc_ref)) {
391 if (!in_array($user_id, $unike_usr_id)) {
392 $member_data = array(
393 "exc_id" => $rem["exc_id"],
394 "exc_ref" => $exc_ref,
395 "ass_id" => $rem["ass_id"],
396 "member_id" => $user_id,
397 "reminder_type" => $rem["type"],
398 "template_id" => $rem["template_id"]
399 );
400 $users_to_remind[] = $member_data;
401 $unike_usr_id[] = $user_id;
402 }
403 }
404 }
405 }
406 }
407 }
408
409 return $users_to_remind;
410 }
411
415 public function parsePeerReminders(array $a_reminders): array
416 {
417 $reminders = $a_reminders;
418 $users_to_remind = array();
419
420 $this->log->debug("Peer Reminders: " . count($a_reminders));
421
422 foreach ($reminders as $reminder) {
423 $this->log->debug("Init peer review: " . $reminder["ass_id"]);
424 $pr = new ilExPeerReview(new ilExAssignment($reminder["ass_id"]));
425 $pr->initPeerReviews();
426 $giver_ids = array_unique(ilExPeerReview::lookupGiversWithPendingFeedback($reminder["ass_id"]));
427 foreach ($giver_ids as $giver_id) {
428 $state = ilExcAssMemberState::getInstanceByIds($reminder["ass_id"], $giver_id);
429 $days_diff = (($state->getPeerReviewDeadline() - time()) / (60 * 60 * 24));
430
431 if ($state->isPeerReviewAllowed() && $days_diff < $reminder["start"]) {
432 $exc_refs = ilObject::_getAllReferences($reminder["exc_id"]);
433 foreach ($exc_refs as $exc_ref) {
434 if ($this->access->checkAccessOfUser($giver_id, "read", "", $exc_ref)) {
435 $member_data = array(
436 "exc_id" => $reminder["exc_id"],
437 "exc_ref" => $exc_ref,
438 "ass_id" => $reminder["ass_id"],
439 "member_id" => $giver_id,
440 "reminder_type" => $reminder["type"],
441 "template_id" => $reminder["template_id"]
442 );
443 $users_to_remind[] = $member_data;
444 }
445 }
446 }
447 }
448 }
449
450 return $users_to_remind;
451 }
452
458 public function checkReminders(): int
459 {
460 $submit_reminders = $this->getReminders(self::SUBMIT_REMINDER);
461 $parsed_submit_reminders = $this->parseSubmissionReminders($submit_reminders);
462
463 $grade_reminders = $this->getReminders(self::GRADE_REMINDER);
464 $parsed_grade_reminders = $this->parseGradeReminders($grade_reminders);
465
466 $peer_reminders = $this->getReminders(self::FEEDBACK_REMINDER);
467 $parsed_peer_reminders = $this->parsePeerReminders($peer_reminders);
468
469 /* //DEBUG
470 $this->log->debug("ALL SUBMIT REMINDERS");
471 $this->log->dump($submit_reminders);
472 $this->log->debug("PARSED SUBMIT REMINDERS");
473 $this->log->dump($parsed_submit_reminders);
474 $this->log->debug("GRADE REMINDERS ARRAY");
475 $this->log->dump($grade_reminders);
476 $this->log->debug("PARSED GRADE REMINDERS");
477 $this->log->dump($parsed_grade_reminders);
478 $this->log->debug("PEER REMINDERS ARRAY");
479 $this->log->dump($peer_reminders);
480 $this->log->debug("PARSED PEER REMINDERS");
481 $this->log->dump($parsed_peer_reminders);
482 */
483
484 $reminders = array_merge($parsed_submit_reminders, $parsed_grade_reminders, $parsed_peer_reminders);
485
486 return $this->sendReminders($reminders);
487 }
488
489 protected function sendReminders(array $reminders): int
490 {
491 global $DIC;
492
493 $tpl = null;
494
495 foreach ($reminders as $reminder) {
496 $template_id = $reminder['template_id'];
497
498 $rmd_type = $reminder["reminder_type"];
499 $this->log->debug("Sending reminder type = " . $rmd_type);
500
501 //if the template exists (can be deleted via Administration/Mail)
502 if ($template_id) {
504 $templateService = $DIC['mail.texttemplates.service'];
505 $tpl = $templateService->loadTemplateForId((int) $template_id);
506 }
507 $subject = "";
508 if ($tpl) {
509 $this->log->debug("** send reminder WITH template.");
510 $subject = $tpl->getSubject();
511
512 $placeholder_params = array(
513 "exc_id" => $reminder["exc_id"],
514 "exc_ref" => $reminder["exc_ref"],
515 "ass_id" => $reminder["ass_id"],
516 "member_id" => $reminder["member_id"]
517 );
518 $message = $this->sentReminderPlaceholders($tpl->getMessage(), $placeholder_params, $rmd_type);
519 } else {
520 $this->log->debug("** send reminder WITHOUT template.");
521
522 $ass_title = ilExAssignment::lookupTitle($reminder["ass_id"]);
523 $exc_title = ilObjExercise::_lookupTitle($reminder["exc_id"]);
524
525 // use language of recipient to compose message
526 $ulng = ilLanguageFactory::_getLanguageOfUser($reminder["member_id"]);
527 $ulng->loadLanguageModule('exc');
528
529 $link = ilLink::_getLink($reminder["exc_ref"], "exc", array(), "_" . $reminder["ass_id"]);
530
531 $message = sprintf($ulng->txt('exc_reminder_salutation'), ilObjUser::_lookupFullname($reminder["member_id"])) . "\n\n";
532
533 $this->log->debug("send: MAIL TYPE = " . $rmd_type . ", user: " . $reminder["member_id"] . ", ass: " . $reminder["ass_id"]);
534
535 switch ($rmd_type) {
536 case "submit":
537 $subject = sprintf($ulng->txt('exc_reminder_submit_subject'), $ass_title);
538 $message .= $ulng->txt('exc_reminder_submit_body') . ":\n\n";
539 break;
540
541 case "grade":
542 $subject = sprintf($ulng->txt('exc_reminder_grade_subject'), $ass_title);
543 $message .= $ulng->txt('exc_reminder_grade_body') . ":\n\n";
544 break;
545
546 case "peer":
547 $subject = sprintf($ulng->txt('exc_reminder_peer_subject'), $ass_title);
548 $message .= $ulng->txt('exc_reminder_peer_body') . ":\n\n";
549 break;
550 }
551
552 $message .= $ulng->txt('obj_exc') . ": " . $exc_title . "\n";
553 $message .= $ulng->txt('obj_ass') . ": " . $ass_title . "\n";
554 $message .= "\n" . $ulng->txt('exc_reminder_link') . ": " . $link;
555 }
556 $mail_obj = new ilMail(ANONYMOUS_USER_ID);
557 $mail_obj->appendInstallationSignature(true);
558 $mail_obj->enqueue(
559 ilObjUser::_lookupLogin($reminder["member_id"]),
560 "",
561 "",
562 $subject,
563 $message,
564 array()
565 );
566 }
567
568 $this->updateRemindersLastDate($reminders);
569 return count($reminders);
570 }
571
572 //see ilObjSurvey.
573 protected function sentReminderPlaceholders(
574 string $a_message,
575 array $a_reminder_data,
576 string $a_reminder_type
577 ): string {
578 // see ilMail::replacePlaceholders()
579 try {
580 switch ($a_reminder_type) {
583 break;
586 break;
589 break;
590 default:
591 exit();
592 }
593
594 $user = new ilObjUser($a_reminder_data["member_id"]);
595
596 $processor = new ilMailTemplatePlaceholderResolver($context, $a_message);
597 $a_message = $processor->resolve($user, $a_reminder_data);
598 } catch (Exception $e) {
599 ilLoggerFactory::getLogger('mail')->error(__METHOD__ . ' has been called with invalid context.');
600 }
601
602 return $a_message;
603 }
604
605 // Update reminders last_send value with the current timestamp.
606 protected function updateRemindersLastDate(array $a_reminders): void
607 {
608 $today = date("Y-m-d");
609 foreach ($a_reminders as $reminder) {
610 $sql = "UPDATE exc_ass_reminders" .
611 " SET last_send = " . $this->db->quote(time(), 'integer') .
612 " , last_send_day = " . $this->db->quote($today, 'date') .
613 " WHERE type = " . $this->db->quote($reminder["reminder_type"], 'text') .
614 " AND ass_id = " . $this->db->quote($reminder["ass_id"], 'integer') .
615 " AND exc_id = " . $this->db->quote($reminder["exc_id"], 'integer');
616
617 $this->db->manipulate($sql);
618 }
619 }
620
621 // remove reminders from DB when the parent assignment is deleted.
622 public function deleteReminders(int $a_ass_id): void
623 {
624 $sql = "DELETE FROM exc_ass_reminders" .
625 " WHERE ass_id = " . $a_ass_id;
626
627 $this->db->manipulate($sql);
628 }
629}
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
sentReminderPlaceholders(string $a_message, array $a_reminder_data, string $a_reminder_type)
updateRemindersLastDate(array $a_reminders)
getReminders(string $a_type="")
Get reminders available by date/frequence.
__construct(int $a_exc_id=0, int $a_ass_id=0, string $a_type="")
setReminderStatus(?bool $a_status)
Set reminder for users without submission.
Exercise assignment.
static lookupTitle(int $a_id)
Exercise peer review.
static lookupGiversWithPendingFeedback(int $a_ass_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getInstanceByIds(int $a_ass_id, int $a_user_id=0)
static _getLanguageOfUser(int $a_usr_id)
Get language object of user.
static getLogger(string $a_component_id)
Get component logger.
Component logger with individual log levels by component id.
static getNotificationsForObject(int $type, int $id, ?int $page_id=null, bool $ignore_threshold=false)
Get all users/recipients for given object.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Class ilObjGroup.
User class.
static _lookupFullname(int $a_user_id)
static _lookupLogin(int $a_user_id)
static _getAllReferences(int $id)
get all reference ids for object ID
static _lookupTitle(int $obj_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
const ANONYMOUS_USER_ID
Definition: constants.php:27
try
Definition: cron.php:23
global $DIC
Definition: feed.php:28
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Interface ilDBInterface.
if($DIC->http() ->request() ->getMethod()=="GET" &&isset($DIC->http() ->request() ->getQueryParams()['tex'])) $tpl
Definition: latex.php:41
exit
Definition: login.php:28
$query
$context
Definition: webdav.php:29
$message
Definition: xapiexit.php:32