ILIAS  trunk Revision v11.0_alpha-1713-gd8962da2f67
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator Modules Pages
class.ilTimingsCronReminder.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
24 
26 {
27  private static array $objects_information;
28 
30  private array $users;
31  private int $now;
32 
33  protected ilLogger $log;
34  protected ilLanguage $lng;
36  protected ilDBInterface $db;
38 
42  public function __construct()
43  {
44  global $DIC;
45 
46  $this->log = $DIC->logger()->crs();
47  $this->lng = $DIC->language();
48  $this->lng->loadLanguageModule('crs');
49  $this->db = $DIC->database();
50  $this->obj_data_cache = $DIC['ilObjDataCache'];
51 
52  self::$objects_information = [];
53  $this->users_with_exceeded_timings = [];
54  $this->users = [];
55  $this->now = time();
56  }
57 
58  public function getId(): string
59  {
60  return 'crs_timings_reminder';
61  }
62 
63  public function getTitle(): string
64  {
65  return $this->lng->txt('timings_reminder_notifications');
66  }
67 
68  public function getDescription(): string
69  {
70  return $this->lng->txt('timings_reminder_notifications_info');
71  }
72 
74  {
75  return JobScheduleType::DAILY;
76  }
77 
78  public function getDefaultScheduleValue(): ?int
79  {
80  return null;
81  }
82 
83  public function hasAutoActivation(): bool
84  {
85  return false;
86  }
87 
88  public function hasFlexibleSchedule(): bool
89  {
90  return false;
91  }
92 
93  public function hasCustomSettings(): bool
94  {
95  return false;
96  }
97 
98  public function run(): JobResult
99  {
100  $this->log->debug('Start.');
101 
102  $result = new JobResult();
103 
104  $this->gatherUsers();
108 
109  $result->setStatus(JobResult::STATUS_OK);
110 
111  $this->log->debug('End');
112 
113  return $result;
114  }
115 
119  protected function gatherUsers(): void
120  {
121  $now = time();
122  $query = $this->db->queryF(
123  'SELECT usr_id FROM usr_data WHERE
124  (active = 1 AND time_limit_unlimited = 1) OR
125  (active = 1 AND time_limit_unlimited = 0 AND time_limit_from < %s AND time_limit_until > %s)',
126  ['integer', 'integer'],
127  [$now, $now]
128  );
129  while ($row = $this->db->fetchAssoc($query)) {
130  $usr_id = (int) $row['usr_id'];
131  $this->users[$usr_id] = $usr_id;
132  }
133  $this->log->debug('Found ' . count($this->users) . ' users.');
134  }
135 
136  protected function gatherUsersWithExceededTimings(): void
137  {
138  $this->users_with_exceeded_timings = ilTimingsUser::lookupTimingsExceededByUser($this->users);
139  $this->log->debug('Found ' . count($this->users_with_exceeded_timings) . ' users with exceeded timings.');
140  }
141 
142  protected function getNewExceededObjectForUser(): void
143  {
144  $users_with_exceeded_objects = [];
145 
146  if (is_array($this->users_with_exceeded_timings) && $this->users_with_exceeded_timings !== []) {
147  foreach ($this->users_with_exceeded_timings as $key => $user_id) {
148  $objects = $this->getExceededObjectsForUser($user_id);
149  if (is_array($objects) && $objects !== []) {
150  $obj_data = [];
151  $already_notified = $this->getAlreadySentNotifications($user_id);
152  $objects = array_diff_key($objects, $already_notified);
153  foreach (array_keys($objects) as $ref_id) {
154  $detail_data = $this->getInformationForRefId($ref_id);
155  $obj_data[$ref_id] = $detail_data;
156  }
157  if ($obj_data !== []) {
158  $users_with_exceeded_objects[$user_id] = $obj_data;
159  }
160  }
161  }
162  $this->log->debug('Found ' . count($users_with_exceeded_objects) . ' users with new exceeded timings.');
163 
164  $this->buildExceededMails($users_with_exceeded_objects);
165  }
166  }
167 
168  protected function getFreshlyStartedObjectsForUser(): void
169  {
170  $users_with_new_started_object = [];
171 
172  if (is_array($this->users) && $this->users !== []) {
173  foreach ($this->users as $key => $user_id) {
174  $objects = $this->getObjectsWithTimingsForUser($user_id);
175  if (is_array($objects) && $objects !== []) {
176  $obj_data = [];
177  $already_notified = $this->getAlreadySentNotifications($user_id, false);
178  $this->log->debug('User_id ' . $user_id . ' was already notified for ' . count($already_notified) . ' elements ');
179  $objects = array_diff_key($objects, $already_notified);
180  foreach ($objects as $ref_id => $v) {
181  $obj_data[$ref_id] = $this->getInformationForRefId($ref_id);
182 
183  if (is_array($v)) {
184  if ((isset($v['end']) && isset($v['start'])) && $v['end'] > $this->now) {
185  if ($v['start'] < $this->now) {
186  $users_with_new_started_object[$user_id][$ref_id] = $obj_data[$ref_id];
187  }
188  } else {
189  $this->log->debug('End is already older than today no notification send for user_id ' . $user_id . ' on ref_id ' . $ref_id);
190  }
191  }
192  }
193  }
194  }
195  $this->log->debug('Found ' . count($users_with_new_started_object) . ' users with freshly started timings.');
196 
197  $this->buildFreshlyStartedMails($users_with_new_started_object);
198  }
199  }
200 
201  protected function buildExceededMails(array $users_with_exceeded_objects): void
202  {
203  $this->log->debug('Start.');
204  if (is_array($users_with_exceeded_objects)) {
205  $this->log->debug('...found ' . count($users_with_exceeded_objects));
206  foreach ($users_with_exceeded_objects as $user_id => $exceeded_objects) {
207  $tpl = $this->buildTopMailBody($user_id, 'timings_cron_reminder_exceeded_start');
208  $has_exceeded = $this->fillObjectListForMailBody($exceeded_objects, $tpl);
209 
210  if ($has_exceeded) {
211  $this->sendExceededMail($user_id, $exceeded_objects, $tpl->get());
212  $this->log->debug('start sending exceeded mail to user: ' . $user_id);
213  }
214  }
215  } else {
216  $this->log->warning('no array given.');
217  }
218 
219  $this->log->debug('end.');
220  }
221 
222  protected function buildFreshlyStartedMails(array $users_with_freshly_started_objects): void
223  {
224  $this->log->debug('start.');
225  if (is_array($users_with_freshly_started_objects)) {
226  $this->log->debug('...found ' . count($users_with_freshly_started_objects));
227  foreach ($users_with_freshly_started_objects as $user_id => $freshly_started_objects) {
228  $tpl = $this->buildTopMailBody($user_id, 'timings_cron_reminder_freshly_start');
229  $has_freshly_started = $this->fillObjectListForMailBody($freshly_started_objects, $tpl);
230 
231  if ($has_freshly_started) {
232  $this->sendFreshlyStartedMail($user_id, $freshly_started_objects, $tpl->get());
233  }
234  }
235  } else {
236  $this->log->debug('no array given.');
237  }
238 
239  $this->log->debug('end.');
240  }
241 
242  protected function buildTopMailBody(int $user_id, string $language_variable): ilTemplate
243  {
244  $this->log->debug('start...');
245  $tpl = new ilTemplate('tpl.crs_timings_cron_reminder_mail.html', true, true, 'components/ILIAS/Course');
246 
247  $this->getUserLanguage($user_id);
248  $this->buildMailSalutation($user_id, $tpl);
249  $tpl->setVariable('START_BODY', $this->user_lang->txt($language_variable));
250  $this->log->debug('for user: ' . $user_id . ' end.');
251  return $tpl;
252  }
253 
254  protected function fillObjectListForMailBody(array $objects, ilTemplate $tpl): bool
255  {
256  $has_elements = false;
257  foreach ($objects as $object_id => $object_details) {
258  if ($object_details['type'] != 'fold') {
259  $tpl->setCurrentBlock('items');
260  $tpl->setVariable('HREF', $object_details['url']);
261  $tpl->setVariable('ITEM_TITLE', $object_details['title']);
262  $tpl->parseCurrentBlock();
263  $has_elements = true;
264  }
265  }
266  $tpl->setVariable('INSTALLATION_SIGNATURE', \ilMail::_getInstallationSignature());
267  $this->log->debug('found elements: ' . $has_elements);
268  return $has_elements;
269  }
270 
271  protected function getUserLanguage(int $user_id): void
272  {
273  $this->log->debug('start...');
274  $this->user_lang = ilLanguageFactory::_getLanguageOfUser($user_id);
275  $this->user_lang->loadLanguageModule('crs');
276  $this->user_lang->loadLanguageModule('mail');
277  $this->log->debug('user language for user ' . $user_id . ' is ' . $this->user_lang->getLangKey() . ' end.');
278  }
279 
280  protected function buildMailSalutation(int $user_id, ilTemplate $tpl): void
281  {
282  $name = ilObjUser::_lookupName($user_id);
283  if (is_array($name)) {
284  $salutation = $this->user_lang->txt('mail_salutation_n') . ' ';
285  if (($name['gender'] ?? "") != '') {
286  $salutation .= $this->user_lang->txt('salutation_' . $name['gender']) . ' ';
287  }
288  if ($name['title'] != '') {
289  $salutation .= $name['title'] . ' ';
290  }
291  $tpl->setVariable('SALUTATION', $salutation);
292  $tpl->setVariable('FIRSTNAME', $name['firstname']);
293  $tpl->setVariable('LASTNAME', $name['lastname']);
294  $this->log->debug('Salutation: ' . $salutation . ' Firstname: ' . $name['firstname'] . ' Lastname: ' . $name['lastname']);
295  } else {
296  $this->log->debug('did not get an array from _lookupName.');
297  }
298  }
299 
300  protected function sendExceededMail(int $user_id, array $ref_ids, string $mail_body): void
301  {
302  $login = \ilObjUser::_lookupLogin($user_id);
303  if ($login != '') {
304  $mail = new ilMail(ANONYMOUS_USER_ID);
305  if ($this->hasUserActivatedNotification($user_id)) {
306  $mail->enqueue(
307  $login,
308  '',
309  '',
310  $this->user_lang->txt('timings_cron_reminder_exceeded_subject'),
311  $mail_body,
312  [],
313  true
314  );
315  $this->log->debug('...mail send for user ' . $user_id . ' to mail ' . $login . ' has exceeded timings for ' . $mail_body);
316  $this->markExceededInDatabase($user_id, $ref_ids);
317  } else {
318  $this->log->debug('... no mail was sent because user ' . $user_id . ' has deactivated their notifications and has no coaches assigned.');
319  }
320  } else {
321  $this->log->debug('Not send. User ' . $user_id . ' has no email.');
322  }
323  }
324 
325  protected function sendFreshlyStartedMail(int $user_id, array $ref_ids, string $mail_body): void
326  {
327  $login = \ilObjUser::_lookupLogin($user_id);
328 
329  if ($login != '' && $this->hasUserActivatedNotification($user_id)) {
330  $mail = new ilMail(ANONYMOUS_USER_ID);
331  $mail->enqueue(
332  $login,
333  '',
334  '',
335  $this->user_lang->txt('timings_cron_reminder_started_subject'),
336  $mail_body,
337  [],
338  true
339  );
340  $this->log->debug('...mail send for user ' . $user_id . ' to mail ' . $login . ' has freshly started timings for ' . $mail_body);
341  $this->markFreshlyStartedInDatabase($user_id, $ref_ids);
342  } else {
343  $this->log->debug('Not send. User ' . $user_id . ' has no email.');
344  }
345  }
346 
347  protected function markExceededInDatabase(int $user_id, array $ref_ids): void
348  {
349  foreach (array_keys($ref_ids) as $ref_id) {
350  $this->db->manipulateF(
351  'INSERT INTO ' . ilCourseConstants::CRON_TIMINGS_EXCEEDED_TABLE . ' (user_id, ref_id, sent) VALUES ' .
352  ' (%s,%s,%s)',
353  ['integer', 'integer', 'integer'],
354  [$user_id, $ref_id, $this->now]
355  );
356 
357  $this->log->debug('ilTimingsCronReminder->markExceededInDatabase: Marked exceeded in Database. User ' . $user_id . ' ref_id ' . $ref_id);
358  }
359  }
360 
361  protected function markFreshlyStartedInDatabase(int $user_id, array $ref_ids): void
362  {
363  foreach (array_keys($ref_ids) as $ref_id) {
364  $this->db->manipulateF(
365  'INSERT INTO ' . ilCourseConstants::CRON_TIMINGS_STARTED_TABLE . ' (user_id, ref_id, sent) VALUES ' .
366  ' (%s,%s,%s)',
367  ['integer', 'integer', 'integer'],
368  [$user_id, $ref_id, $this->now]
369  );
370 
371  $this->log->debug('ilTimingsCronReminder->markFreshlyStartedInDatabase: Marked freshly started in Database. User ' . $user_id . ' ref_id ' . $ref_id);
372  }
373  }
374 
375  protected function getAlreadySentNotifications(int $user_id, bool $for_exceeded = true): array
376  {
377  $ref_ids = [];
379 
380  if (!$for_exceeded) {
382  }
383 
384  $result = $this->db->queryF(
385  'SELECT * FROM ' . $table . ' WHERE ' .
386  'user_id = %s',
387  ['integer'],
388  [$user_id]
389  );
390 
391  while ($record = $this->db->fetchAssoc($result)) {
392  $ref_ids[$record['ref_id']] = $record['ref_id'];
393  }
394  return $ref_ids;
395  }
396 
397  protected function getInformationForRefId(int $ref_id): array
398  {
399  if (!array_key_exists($ref_id, self::$objects_information)) {
400  $obj_id = $this->obj_data_cache->lookupObjId($ref_id);
401  $type = $this->obj_data_cache->lookupType($obj_id);
402  $value = [
403  'title' => $this->obj_data_cache->lookupTitle($obj_id),
404  'type' => $type,
405  'url' => ilLink::_getLink($ref_id, $type),
406  'obj_id' => $obj_id
407  ];
408  self::$objects_information[$ref_id] = $value;
409 
410  $this->log->debug('ilTimingsCronReminder->getInformationForRefId: ...cached object information for => ' . $value['type'] . ' => ' . $value['title']);
411  }
412  return self::$objects_information[$ref_id];
413  }
414 
415  protected function getExceededObjectsForUser(int $user_id): array
416  {
417  $tmp = [];
418  return ilTimingsUser::lookupTimings([$user_id], $tmp, true);
419  }
420 
421  protected function getObjectsWithTimingsForUser(int $user_id): array
422  {
423  $meta = [];
424  $timings_obj_list = ilTimingsUser::lookupTimings([$user_id], $meta, false);
425  return $meta[$user_id] ?? [];
426  }
427 
428  protected function hasUserActivatedNotification(int $user_id): bool
429  {
430  return true;
431  }
432 }
parseCurrentBlock(string $part=ilGlobalTemplateInterface::DEFAULT_BLOCK)
const ANONYMOUS_USER_ID
Definition: constants.php:27
buildTopMailBody(int $user_id, string $language_variable)
markExceededInDatabase(int $user_id, array $ref_ids)
gatherUsers()
Read all active users.
static _lookupName(int $a_user_id)
lookup user name
fillObjectListForMailBody(array $objects, ilTemplate $tpl)
buildMailSalutation(int $user_id, ilTemplate $tpl)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
buildExceededMails(array $users_with_exceeded_objects)
$ref_id
Definition: ltiauth.php:65
setVariable($variable, $value='')
Sets a variable value.
Definition: IT.php:544
static _getLanguageOfUser(int $a_usr_id)
Get language object of user.
static lookupTimings(array $a_user_ids, ?array &$a_meta=null, bool $a_only_exceeded=true)
Lookup references, users with exceeded timings.
global $DIC
Definition: shib_login.php:22
sendExceededMail(int $user_id, array $ref_ids, string $mail_body)
buildFreshlyStartedMails(array $users_with_freshly_started_objects)
setCurrentBlock(string $part=ilGlobalTemplateInterface::DEFAULT_BLOCK)
static lookupTimingsExceededByUser(array $a_user_ids)
Check if users currently exceeded ANY object.
markFreshlyStartedInDatabase(int $user_id, array $ref_ids)
sendFreshlyStartedMail(int $user_id, array $ref_ids, string $mail_body)
getAlreadySentNotifications(int $user_id, bool $for_exceeded=true)
static _getInstallationSignature()
static _lookupLogin(int $a_user_id)