ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
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;
52
53 //todo remove the params as soon as possible.
54 public function __construct(
55 int $a_exc_id = 0,
56 int $a_ass_id = 0,
57 string $a_type = ""
58 ) {
59 global $DIC;
60 $this->db = $DIC->database();
61 $this->tree = $DIC->repositoryTree();
62 $this->access = $DIC->access();
63 $this->log = ilLoggerFactory::getLogger("exc");
64 $this->placeholder_resolver = $DIC->mail()->placeholderResolver();
65
66 if ($a_ass_id) {
67 $this->ass_id = $a_ass_id;
68 }
69 if ($a_exc_id) {
70 $this->exc_id = $a_exc_id;
71 }
72 if ($a_type) {
73 $this->rmd_type = $a_type;
74 }
75 if ($a_exc_id and $a_ass_id and $a_type) {
76 $this->read();
77 }
78 }
79
80 public function getReminderType(): string
81 {
82 return $this->rmd_type;
83 }
84
89 public function setReminderStatus(?bool $a_status): void
90 {
91 $this->rmd_status = $a_status;
92 }
93
94 public function getReminderStatus(): ?bool
95 {
96 return $this->rmd_status;
97 }
98
99 // Set num days before the deadline to start sending notifications.
100 public function setReminderStart(int $a_num_days): void
101 {
102 $this->rmd_start = $a_num_days;
103 }
104
105 public function getReminderStart(): int
106 {
107 return $this->rmd_start;
108 }
109
110 public function setReminderEnd(int $a_date): void
111 {
112 $this->rmd_end = $a_date;
113 }
114
115 public function getReminderEnd(): int
116 {
117 return $this->rmd_end;
118 }
119
120 // Set frequency in days
121 public function setReminderFrequency(int $a_num_days): void
122 {
123 $this->rmd_frequency = $a_num_days;
124 }
125
126 public function getReminderFrequency(): int
127 {
129 }
130
131 public function setReminderLastSend(int $a_timestamp): void
132 {
133 $this->rmd_last_send = $a_timestamp;
134 }
135
136 public function getReminderLastSend(): int
137 {
139 }
140
141 public function setReminderMailTemplate(int $a_tpl_id): void
142 {
143 $this->rmd_tpl_id = $a_tpl_id;
144 }
145
146 public function getReminderMailTemplate(): int
147 {
148 return $this->rmd_tpl_id;
149 }
150
151 public function save(): void
152 {
153 $this->db->insert("exc_ass_reminders", array(
154 "type" => array("text", $this->rmd_type),
155 "ass_id" => array("integer", $this->ass_id),
156 "exc_id" => array("integer", $this->exc_id),
157 "status" => array("integer", $this->getReminderStatus()),
158 "start" => array("integer", $this->getReminderStart()),
159 "end" => array("integer", $this->getReminderEnd()),
160 "freq" => array("integer", $this->getReminderFrequency()),
161 "last_send" => array("integer", $this->getReminderLastSend()),
162 "template_id" => array("integer", $this->getReminderMailTemplate())
163 ));
164 }
165
166 public function update(): void
167 {
168 $this->db->update(
169 "exc_ass_reminders",
170 array(
171 "status" => array("integer", $this->getReminderStatus()),
172 "start" => array("integer", $this->getReminderStart()),
173 "end" => array("integer", $this->getReminderEnd()),
174 "freq" => array("integer", $this->getReminderFrequency()),
175 "last_send" => array("integer", $this->getReminderLastSend()),
176 "template_id" => array("integer", $this->getReminderMailTemplate())
177 ),
178 array(
179 "type" => array("text", $this->rmd_type),
180 "exc_id" => array("integer", $this->exc_id),
181 "ass_id" => array("integer", $this->ass_id)
182 )
183 );
184 }
185
186
187 public function read(): void
188 {
189 $set = $this->db->queryF(
190 "SELECT status, start, freq, end, last_send, template_id" .
191 " FROM exc_ass_reminders" .
192 " WHERE type = %s AND ass_id = %s AND exc_id = %s",
193 ["text", "integer", "integer"],
194 [$this->rmd_type, $this->ass_id, $this->exc_id]
195 );
196
197 $rec = $this->db->fetchAssoc($set);
198 if (is_array($rec)) {
199 $this->initFromDB($rec);
200 }
201 }
202
203 protected function initFromDB(array $a_set): void
204 {
205 $this->setReminderStatus((bool) $a_set["status"]);
206 $this->setReminderStart((int) $a_set["start"]);
207 $this->setReminderEnd((int) $a_set["end"]);
208 $this->setReminderFrequency((int) $a_set["freq"]);
209 $this->setReminderLastSend((int) $a_set["last_send"]);
210 $this->setReminderMailTemplate((int) $a_set["template_id"]);
211 }
212
213
214 // Specific Methods to be used via Cron Job.
215
220 public function getReminders(string $a_type = ""): array
221 {
222 $now = time();
223 $today = date("Y-m-d");
224
225 $this->log->debug("Get reminders $a_type.");
226
227 //remove time from the timestamp (86400 = 24h)
228 //$now = floor($now/86400)*86400;
229 $and_type = "";
230 if ($a_type == self::SUBMIT_REMINDER || $a_type == self::GRADE_REMINDER || $a_type == self::FEEDBACK_REMINDER) {
231 $and_type = " AND type = '" . $a_type . "'";
232 }
233
234 $query = "SELECT last_send_day, ass_id, exc_id, status, start, freq, end, type, last_send, template_id" .
235 " FROM exc_ass_reminders" .
236 " WHERE status = 1" .
237 " AND start <= " . $now .
238 " AND end > " . ($now - 86400) .
239 $and_type;
240
241
242 $result = $this->db->query($query);
243
244 $array_data = array();
245 while ($rec = $this->db->fetchAssoc($result)) {
246 $rem = array(
247 "ass_id" => $rec["ass_id"],
248 "exc_id" => $rec["exc_id"],
249 "start" => $rec["start"],
250 "end" => $rec["end"],
251 "freq" => $rec["freq"],
252 "type" => $rec["type"],
253 "last_send" => $rec["last_send"],
254 "last_send_day" => $rec["last_send_day"],
255 "template_id" => $rec["template_id"]
256 );
257
258 $end_day = date("Y-m-d", $rec["end"]);
259
260 //frequency
261 $next_send = "";
262 if ($rec["last_send_day"] != "") {
263 $date = new DateTime($rec["last_send_day"]);
264 $date->add(new DateInterval('P' . $rec["freq"] . 'D'));
265 $next_send = $date->format('Y-m-d');
266 }
267 $this->log->debug("ass: " . $rec["ass_id"] . ", last send: " . $rec["last_send_day"] .
268 ", freq: " . $rec["freq"] . ", end_day: $end_day, today: " . $today . ", next send: $next_send");
269 if ($rec["last_send_day"] == "" || $next_send <= $today) {
270 if ($end_day >= $today) {
271 $this->log->debug("included");
272 $array_data[] = $rem;
273 }
274 }
275 }
276
277 return $array_data;
278 }
279
285 public function parseSubmissionReminders(array $a_reminders): array
286 {
287 $reminders = $a_reminders;
288 $users_to_remind = array();
289
290 foreach ($reminders as $rem) {
291 $ass_id = $rem["ass_id"];
292 $ass_obj = new ilExAssignment($ass_id);
293
294 $exc_id = $rem["exc_id"];
295
297 foreach ($exc_refs as $exc_ref) {
298 // check if we have an upper course
299 if ($course_ref_id = $this->tree->checkForParentType($exc_ref, 'crs')) {
300 $obj = new ilObjCourse($course_ref_id);
301 $participants_class = ilCourseParticipants::class;
302 $parent_ref_id = $course_ref_id;
303 $parent_obj_type = 'crs';
304
305 // check if we have an upper group
306 } elseif ($group_ref_id = $this->tree->checkForParentType($exc_ref, 'grp')) {
307 $obj = new ilObjGroup($group_ref_id);
308 $participants_class = ilGroupParticipants::class;
309 $parent_ref_id = $group_ref_id;
310 $parent_obj_type = 'grp';
311 } else {
312 continue;
313 }
314
315 // get participants
316 $parent_obj_id = $obj->getId();
318 $participants_ids = $participants_class::getInstance($parent_ref_id)->getMembers();
319
320 foreach ($participants_ids as $member_id) {
321 $this->log->debug("submission reminder: ass: $ass_id, member: $member_id.");
322
323 // check read permission
324 if ($this->access->checkAccessOfUser($member_id, "read", "", $exc_ref)) {
326
327 $deadline_day = date("Y-m-d", $state->getOfficialDeadline());
328 $today = date("Y-m-d");
329 $date = new DateTime($deadline_day);
330 $date->sub(new DateInterval('P' . $rem["start"] . 'D'));
331 $send_from = $date->format('Y-m-d');
332 $this->log->debug("today: $today, send from: $send_from, start: " . $rem["start"] . ", submission allowed: " . $state->isSubmissionAllowed());
333
334 // check if user can submit and difference in days is smaller than reminder start
335 if ($state->isSubmissionAllowed() && $send_from <= $today) {
336 $submission = new ilExSubmission($ass_obj, $member_id);
337
338 // check if user has submitted anything
339 if (!$submission->getLastSubmission()) {
340 $member_data = array(
341 "parent_type" => $parent_obj_type,
342 "parent_id" => $parent_obj_id,
343 "exc_id" => $exc_id,
344 "exc_ref" => $exc_ref,
345 "ass_id" => $ass_id,
346 "member_id" => $member_id,
347 "reminder_type" => $rem["type"],
348 "template_id" => $rem["template_id"]
349 );
350 $users_to_remind[] = $member_data;
351 }
352 }
353 }
354 }
355 }
356 }
357 return $users_to_remind;
358 }
359
363 public function parseGradeReminders(array $a_reminders): array
364 {
365 $reminders = $a_reminders;
366 $users_to_remind = array();
367
368 $has_pending_to_grade = false;
369
370 foreach ($reminders as $rem) {
371 //$this->log->debug("---- parse grade reminder with values -> ",$rem);
372 $ass_obj = new ilExAssignment($rem["ass_id"]);
373 $members_data = $ass_obj->getMemberListData();
374
375 //$this->log->debug("--- get members list data => ",$members_data);
376 foreach ($members_data as $assignment_data) {
377 if ($assignment_data["status"] == ilExerciseManagementGUI::GRADE_NOT_GRADED) {
378 //at least there is one submission pending to grade.
379 $has_pending_to_grade = true;
380 }
381 }
382
383 if ($has_pending_to_grade) {
384 //get tutor of this exercise.
386
387 foreach ($users as $user_id) {
388 $exc_refs = ilObject::_getAllReferences($rem["exc_id"]);
389 $unike_usr_id = array();
390 foreach ($exc_refs as $exc_ref) {
391 if ($this->access->checkAccessOfUser($user_id, "write", "", $exc_ref)) {
392 if (!in_array($user_id, $unike_usr_id)) {
393 $member_data = array(
394 "exc_id" => $rem["exc_id"],
395 "exc_ref" => $exc_ref,
396 "ass_id" => $rem["ass_id"],
397 "member_id" => $user_id,
398 "reminder_type" => $rem["type"],
399 "template_id" => $rem["template_id"]
400 );
401 $users_to_remind[] = $member_data;
402 $unike_usr_id[] = $user_id;
403 }
404 }
405 }
406 }
407 }
408 }
409
410 return $users_to_remind;
411 }
412
416 public function parsePeerReminders(array $a_reminders): array
417 {
418 $reminders = $a_reminders;
419 $users_to_remind = array();
420
421 $this->log->debug("Peer Reminders: " . count($a_reminders));
422
423 foreach ($reminders as $reminder) {
424 $this->log->debug("Init peer review: " . $reminder["ass_id"]);
425 $pr = new ilExPeerReview(new ilExAssignment($reminder["ass_id"]));
426 $pr->initPeerReviews();
427 $giver_ids = array_unique(ilExPeerReview::lookupGiversWithPendingFeedback($reminder["ass_id"]));
428 foreach ($giver_ids as $giver_id) {
429 $state = ilExcAssMemberState::getInstanceByIds($reminder["ass_id"], $giver_id);
430 $days_diff = (($state->getPeerReviewDeadline() - time()) / (60 * 60 * 24));
431
432 if ($state->isPeerReviewAllowed() && $days_diff < $reminder["start"]) {
433 $exc_refs = ilObject::_getAllReferences($reminder["exc_id"]);
434 foreach ($exc_refs as $exc_ref) {
435 if ($this->access->checkAccessOfUser($giver_id, "read", "", $exc_ref)) {
436 $member_data = array(
437 "exc_id" => $reminder["exc_id"],
438 "exc_ref" => $exc_ref,
439 "ass_id" => $reminder["ass_id"],
440 "member_id" => $giver_id,
441 "reminder_type" => $reminder["type"],
442 "template_id" => $reminder["template_id"]
443 );
444 $users_to_remind[] = $member_data;
445 }
446 }
447 }
448 }
449 }
450
451 return $users_to_remind;
452 }
453
459 public function checkReminders(): int
460 {
461 $submit_reminders = $this->getReminders(self::SUBMIT_REMINDER);
462 $parsed_submit_reminders = $this->parseSubmissionReminders($submit_reminders);
463
464 $grade_reminders = $this->getReminders(self::GRADE_REMINDER);
465 $parsed_grade_reminders = $this->parseGradeReminders($grade_reminders);
466
467 $peer_reminders = $this->getReminders(self::FEEDBACK_REMINDER);
468 $parsed_peer_reminders = $this->parsePeerReminders($peer_reminders);
469
470 /* //DEBUG
471 $this->log->debug("ALL SUBMIT REMINDERS");
472 $this->log->dump($submit_reminders);
473 $this->log->debug("PARSED SUBMIT REMINDERS");
474 $this->log->dump($parsed_submit_reminders);
475 $this->log->debug("GRADE REMINDERS ARRAY");
476 $this->log->dump($grade_reminders);
477 $this->log->debug("PARSED GRADE REMINDERS");
478 $this->log->dump($parsed_grade_reminders);
479 $this->log->debug("PEER REMINDERS ARRAY");
480 $this->log->dump($peer_reminders);
481 $this->log->debug("PARSED PEER REMINDERS");
482 $this->log->dump($parsed_peer_reminders);
483 */
484
485 $reminders = array_merge($parsed_submit_reminders, $parsed_grade_reminders, $parsed_peer_reminders);
486
487 return $this->sendReminders($reminders);
488 }
489
490 protected function sendReminders(array $reminders): int
491 {
492 global $DIC;
493
494 $tpl = null;
495
496 foreach ($reminders as $reminder) {
497 $template_id = $reminder['template_id'];
498
499 $rmd_type = $reminder["reminder_type"];
500 $this->log->debug("Sending reminder type = " . $rmd_type);
501
502 //if the template exists (can be deleted via Administration/Mail)
503 if ($template_id) {
504 $templateService = $DIC->mail()->textTemplates();
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 $a_message = $this->placeholder_resolver->resolve($context, $a_message, $user, $a_reminder_data);
597 } catch (Exception $e) {
598 ilLoggerFactory::getLogger('mail')->error(__METHOD__ . ' has been called with invalid context.');
599 }
600
601 return $a_message;
602 }
603
604 // Update reminders last_send value with the current timestamp.
605 protected function updateRemindersLastDate(array $a_reminders): void
606 {
607 $today = date("Y-m-d");
608 foreach ($a_reminders as $reminder) {
609 $sql = "UPDATE exc_ass_reminders" .
610 " SET last_send = " . $this->db->quote(time(), 'integer') .
611 " , last_send_day = " . $this->db->quote($today, 'date') .
612 " WHERE type = " . $this->db->quote($reminder["reminder_type"], 'text') .
613 " AND ass_id = " . $this->db->quote($reminder["ass_id"], 'integer') .
614 " AND exc_id = " . $this->db->quote($reminder["exc_id"], 'integer');
615
616 $this->db->manipulate($sql);
617 }
618 }
619
620 // remove reminders from DB when the parent assignment is deleted.
621 public function deleteReminders(int $a_ass_id): void
622 {
623 $sql = "DELETE FROM exc_ass_reminders" .
624 " WHERE ass_id = " . $a_ass_id;
625
626 $this->db->manipulate($sql);
627 }
628}
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)
ilMailTemplatePlaceholderResolver $placeholder_resolver
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)
Exercise submission //TODO: This class has many static methods related to delivered "files".
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)
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
const ANONYMOUS_USER_ID
Definition: constants.php:27
exit
Interface ilAccessHandler This interface combines all available interfaces which can be called via gl...
Interface ilDBInterface.
try
handle Lrs Init
Definition: xapiproxy.php:86
global $DIC
Definition: shib_login.php:26
$context
Definition: webdav.php:31
$message
Definition: xapiexit.php:31