ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
class.ilForumCronNotification.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4include_once "Services/Cron/classes/class.ilCronJob.php";
5include_once "./Modules/Forum/classes/class.ilForumMailNotification.php";
6
14{
16
20 protected $settings;
21
25 protected $logger;
26
30 public static $providerObject = array();
31
35 protected static $deleted_ids_cache = array();
36
40 protected static $ref_ids_by_obj_id = array();
41
45 protected static $accessible_ref_ids_by_user = array();
46
50 protected $num_sent_messages = 0;
51
55 public function __construct()
56 {
57 $this->settings = new ilSetting('frma');
58 }
59
60 public function getId()
61 {
62 return "frm_notification";
63 }
64
65 public function getTitle()
66 {
67 global $DIC;
68
69 return $DIC->language()->txt("cron_forum_notification");
70 }
71
72 public function getDescription()
73 {
74 global $DIC;
75
76 return $DIC->language()->txt("cron_forum_notification_crob_desc");
77 }
78
79 public function getDefaultScheduleType()
80 {
82 }
83
84 public function getDefaultScheduleValue()
85 {
86 return 1;
87 }
88
89 public function hasAutoActivation()
90 {
91 return false;
92 }
93
94 public function hasFlexibleSchedule()
95 {
96 return true;
97 }
98
102 public function hasCustomSettings()
103 {
104 return true;
105 }
106
110 public function keepAlive()
111 {
112 $this->logger->debug('Sending ping to cron manager ...');
113 \ilCronManager::ping($this->getId());
114 $this->logger->debug(sprintf('Current memory usage: %s', memory_get_usage(true)));
115 }
116
120 public function run()
121 {
122 global $DIC;
123
124 $ilDB = $DIC->database();
125 $ilSetting = $DIC->settings();
126 $lng = $DIC->language();
127
128 $this->logger = $DIC->logger()->frm();
129
131
132 $lng->loadLanguageModule('forum');
133
134 $this->logger->info('Started forum notification job ...');
135
136 if (!($last_run_datetime = $ilSetting->get('cron_forum_notification_last_date'))) {
137 $last_run_datetime = null;
138 }
139
140 $this->num_sent_messages = 0;
141 $cj_start_date = date('Y-m-d H:i:s');
142
143 if ($last_run_datetime != null &&
144 checkDate(date('m', strtotime($last_run_datetime)), date('d', strtotime($last_run_datetime)), date('Y', strtotime($last_run_datetime)))) {
145 $threshold = max(strtotime($last_run_datetime), strtotime('-' . (int) $this->settings->get('max_notification_age', 30) . ' days', time()));
146 } else {
147 $threshold = strtotime('-' . (int) $this->settings->get('max_notification_age', 30) . ' days', time());
148 }
149
150 $this->logger->info(sprintf('Threshold for forum event determination is: %s', date('Y-m-d H:i:s', $threshold)));
151
152 $threshold_date = date('Y-m-d H:i:s', $threshold);
153 $new_posts_condition = '
154 frm_posts.pos_status = %s AND (
155 (frm_posts.pos_date >= %s AND frm_posts.pos_date = frm_posts.pos_activation_date) OR
156 (frm_posts.pos_activation_date >= %s AND frm_posts.pos_date < frm_posts.pos_activation_date)
157 ) ';
158 $types = array('integer', 'timestamp', 'timestamp');
159 $values = array(1, $threshold_date, $threshold_date);
160
161 /*** new posts ***/
162 $res = $ilDB->queryf(
163 '
164 SELECT frm_threads.thr_subject thr_subject,
165 frm_data.top_name top_name,
166 frm_data.top_frm_fk obj_id,
167 frm_notification.user_id user_id,
168 frm_threads.thr_pk thread_id,
169 frm_posts.*
170 FROM frm_notification, frm_posts, frm_threads, frm_data
171 WHERE frm_posts.pos_thr_fk = frm_threads.thr_pk AND ' . $new_posts_condition . '
172 AND ((frm_threads.thr_top_fk = frm_data.top_pk AND frm_data.top_frm_fk = frm_notification.frm_id)
173 OR (frm_threads.thr_pk = frm_notification.thread_id
174 AND frm_data.top_pk = frm_threads.thr_top_fk) )
175 AND frm_posts.pos_display_user_id != frm_notification.user_id
176 ORDER BY frm_posts.pos_date ASC',
177 $types,
178 $values
179 );
180
181 $numRows = $ilDB->numRows($res);
182 if ($numRows > 0) {
183 $this->logger->info(sprintf('Sending notifications for %s "new posting" events ...', $numRows));
185 $this->logger->info(sprintf('Sent notifications for new postings ...'));
186 }
187
188 $this->keepAlive();
189
190 /*** updated posts ***/
191 $updated_condition = '
192 frm_posts.pos_cens = %s AND frm_posts.pos_status = %s AND
193 (frm_posts.pos_update > frm_posts.pos_date AND frm_posts.pos_update >= %s) ';
194 $types = array('integer', 'integer', 'timestamp');
195 $values = array(0, 1, $threshold_date);
196
197 $res = $ilDB->queryf(
198 '
199 SELECT frm_threads.thr_subject thr_subject,
200 frm_data.top_name top_name,
201 frm_data.top_frm_fk obj_id,
202 frm_notification.user_id user_id,
203 frm_threads.thr_pk thread_id,
204 frm_posts.*
205 FROM frm_notification, frm_posts, frm_threads, frm_data
206 WHERE frm_posts.pos_thr_fk = frm_threads.thr_pk AND ' . $updated_condition . '
207 AND ((frm_threads.thr_top_fk = frm_data.top_pk AND frm_data.top_frm_fk = frm_notification.frm_id)
208 OR (frm_threads.thr_pk = frm_notification.thread_id
209 AND frm_data.top_pk = frm_threads.thr_top_fk) )
210 AND frm_posts.pos_display_user_id != frm_notification.user_id
211 ORDER BY frm_posts.pos_date ASC',
212 $types,
213 $values
214 );
215
216 $numRows = $ilDB->numRows($res);
217 if ($numRows > 0) {
218 $this->logger->info(sprintf('Sending notifications for %s "updated posting" events ...', $numRows));
220 $this->logger->info(sprintf('Sent notifications for updated postings ...'));
221 }
222
223 $this->keepAlive();
224
225 /*** censored posts ***/
226 $censored_condition = '
227 frm_posts.pos_cens = %s AND frm_posts.pos_status = %s AND
228 (frm_posts.pos_cens_date >= %s AND frm_posts.pos_cens_date > frm_posts.pos_activation_date ) ';
229 $types = array('integer', 'integer', 'timestamp');
230 $values = array(1, 1, $threshold_date);
231
232 $res = $ilDB->queryf(
233 '
234 SELECT frm_threads.thr_subject thr_subject,
235 frm_data.top_name top_name,
236 frm_data.top_frm_fk obj_id,
237 frm_notification.user_id user_id,
238 frm_threads.thr_pk thread_id,
239 frm_posts.*
240 FROM frm_notification, frm_posts, frm_threads, frm_data
241 WHERE frm_posts.pos_thr_fk = frm_threads.thr_pk AND ' . $censored_condition . '
242 AND ((frm_threads.thr_top_fk = frm_data.top_pk AND frm_data.top_frm_fk = frm_notification.frm_id)
243 OR (frm_threads.thr_pk = frm_notification.thread_id
244 AND frm_data.top_pk = frm_threads.thr_top_fk) )
245 AND (frm_posts.pos_display_user_id != frm_notification.user_id)
246 ORDER BY frm_posts.pos_date ASC',
247 $types,
248 $values
249 );
250
251 $numRows = $ilDB->numRows($res);
252 if ($numRows > 0) {
253 $this->logger->info(sprintf('Sending notifications for %s "censored posting" events ...', $numRows));
255 $this->logger->info(sprintf('Sent notifications for new censored ...'));
256 }
257
258 $this->keepAlive();
259
260 /*** uncensored posts ***/
261 $uncensored_condition = '
262 frm_posts.pos_cens = %s AND frm_posts.pos_status = %s AND
263 (frm_posts.pos_cens_date >= %s AND frm_posts.pos_cens_date > frm_posts.pos_activation_date ) ';
264 $types = array('integer', 'integer', 'timestamp');
265 $values = array(0, 1, $threshold_date);
266
267 $res = $ilDB->queryf(
268 '
269 SELECT frm_threads.thr_subject thr_subject,
270 frm_data.top_name top_name,
271 frm_data.top_frm_fk obj_id,
272 frm_notification.user_id user_id,
273 frm_threads.thr_pk thread_id,
274 frm_posts.*
275 FROM frm_notification, frm_posts, frm_threads, frm_data
276 WHERE frm_posts.pos_thr_fk = frm_threads.thr_pk AND ' . $uncensored_condition . '
277 AND ((frm_threads.thr_top_fk = frm_data.top_pk AND frm_data.top_frm_fk = frm_notification.frm_id)
278 OR (frm_threads.thr_pk = frm_notification.thread_id
279 AND frm_data.top_pk = frm_threads.thr_top_fk) )
280 AND frm_posts.pos_display_user_id != frm_notification.user_id
281 ORDER BY frm_posts.pos_date ASC',
282 $types,
283 $values
284 );
285
286 $numRows = $ilDB->numRows($res);
287 if ($numRows > 0) {
288 $this->logger->info(sprintf('Sending notifications for %s "uncensored posting" events ...', $numRows));
290 $this->logger->info(sprintf('Sent notifications for uncensored postings ...'));
291 }
292
293 $this->keepAlive();
294
295 /*** deleted threads ***/
296 $res = $ilDB->queryF(
297 '
298 SELECT frm_posts_deleted.thread_title thr_subject,
299 frm_posts_deleted.forum_title top_name,
300 frm_posts_deleted.obj_id obj_id,
301 frm_notification.user_id user_id,
302 frm_posts_deleted.pos_display_user_id,
303 frm_posts_deleted.pos_usr_alias,
304 frm_posts_deleted.deleted_id,
305 frm_posts_deleted.post_date pos_date,
306 frm_posts_deleted.post_title pos_subject,
307 frm_posts_deleted.post_message pos_message,
308 frm_posts_deleted.deleted_by
309
310 FROM frm_notification, frm_posts_deleted
311
312 WHERE ( frm_posts_deleted.obj_id = frm_notification.frm_id
313 OR frm_posts_deleted.thread_id = frm_notification.thread_id)
314 AND frm_posts_deleted.pos_display_user_id != frm_notification.user_id
315 AND frm_posts_deleted.is_thread_deleted = %s
316 ORDER BY frm_posts_deleted.post_date ASC',
317 array('integer'),
318 array(1)
319 );
320 $numRows = $ilDB->numRows($res);
321 if ($numRows > 0) {
322 $this->logger->info(sprintf('Sending notifications for %s "deleted threads" events ...', $numRows));
324 if (count(self::$deleted_ids_cache) > 0) {
325 $ilDB->manipulate('DELETE FROM frm_posts_deleted WHERE ' . $ilDB->in('deleted_id', self::$deleted_ids_cache, false, 'integer'));
326 $this->logger->info('Deleted obsolete entries of table "frm_posts_deleted" ...');
327 }
328 $this->logger->info(sprintf('Sent notifications for deleted threads ...'));
329 }
330
331 $this->keepAlive();
332
333 /*** deleted posts ***/
334 $res = $ilDB->queryF(
335 '
336 SELECT frm_posts_deleted.thread_title thr_subject,
337 frm_posts_deleted.forum_title top_name,
338 frm_posts_deleted.obj_id obj_id,
339 frm_notification.user_id user_id,
340 frm_posts_deleted.pos_display_user_id,
341 frm_posts_deleted.pos_usr_alias,
342 frm_posts_deleted.deleted_id,
343 frm_posts_deleted.post_date pos_date,
344 frm_posts_deleted.post_title pos_subject,
345 frm_posts_deleted.post_message pos_message,
346 frm_posts_deleted.deleted_by
347
348 FROM frm_notification, frm_posts_deleted
349
350 WHERE ( frm_posts_deleted.obj_id = frm_notification.frm_id
351 OR frm_posts_deleted.thread_id = frm_notification.thread_id)
352 AND frm_posts_deleted.pos_display_user_id != frm_notification.user_id
353 AND frm_posts_deleted.is_thread_deleted = %s
354 ORDER BY frm_posts_deleted.post_date ASC',
355 array('integer'),
356 array(0)
357 );
358
359 $numRows = $ilDB->numRows($res);
360 if ($numRows > 0) {
361 $this->logger->info(sprintf('Sending notifications for %s "deleted postings" events ...', $numRows));
363 if (count(self::$deleted_ids_cache) > 0) {
364 $ilDB->manipulate('DELETE FROM frm_posts_deleted WHERE ' . $ilDB->in('deleted_id', self::$deleted_ids_cache, false, 'integer'));
365 $this->logger->info('Deleted entries from table "frm_posts_deleted" ...');
366 }
367 $this->logger->info(sprintf('Sent notifications for deleted postings ...'));
368 }
369
370 $ilSetting->set('cron_forum_notification_last_date', $cj_start_date);
371
372 $mess = 'Sent ' . $this->num_sent_messages . ' messages.';
373
374 $this->logger->info($mess);
375 $this->logger->info('Finished forum notification job');
376
377 $result = new ilCronJobResult();
378 if ($this->num_sent_messages) {
380 $result->setMessage($mess);
381 };
382 $result->setStatus($status);
383 return $result;
384 }
385
390 protected function getRefIdsByObjId($a_obj_id)
391 {
392 if (!array_key_exists($a_obj_id, self::$ref_ids_by_obj_id)) {
393 self::$ref_ids_by_obj_id[$a_obj_id] = ilObject::_getAllReferences($a_obj_id);
394 }
395
396 return (array) self::$ref_ids_by_obj_id[$a_obj_id];
397 }
398
404 protected function getFirstAccessibleRefIdBUserAndObjId($a_user_id, $a_obj_id)
405 {
406 global $DIC;
407 $ilAccess = $DIC->access();
408
409 if (!array_key_exists($a_user_id, self::$accessible_ref_ids_by_user)) {
410 self::$accessible_ref_ids_by_user[$a_user_id] = array();
411 }
412
413 if (!array_key_exists($a_obj_id, self::$accessible_ref_ids_by_user[$a_user_id])) {
414 $accessible_ref_id = 0;
415 foreach ($this->getRefIdsByObjId($a_obj_id) as $ref_id) {
416 if ($ilAccess->checkAccessOfUser($a_user_id, 'read', '', $ref_id)) {
417 $accessible_ref_id = $ref_id;
418 break;
419 }
420 }
421 self::$accessible_ref_ids_by_user[$a_user_id][$a_obj_id] = $accessible_ref_id;
422 }
423
424 return (int) self::$accessible_ref_ids_by_user[$a_user_id][$a_obj_id];
425 }
426
431 public function sendCronForumNotification($res, $notification_type)
432 {
433 global $DIC;
434 $ilDB = $DIC->database();
435
436 include_once './Modules/Forum/classes/class.ilForumCronNotificationDataProvider.php';
437 include_once './Modules/Forum/classes/class.ilForumMailNotification.php';
438
439 while ($row = $ilDB->fetchAssoc($res)) {
440 if ($notification_type == ilForumMailNotification::TYPE_POST_DELETED
441 || $notification_type == ilForumMailNotification::TYPE_THREAD_DELETED) {
442 // important! save the deleted_id to cache before proceeding getFirstAccessibleRefIdBUserAndObjId !
443 self::$deleted_ids_cache[$row['deleted_id']] = $row['deleted_id'];
444 }
445
446 $ref_id = $this->getFirstAccessibleRefIdBUserAndObjId($row['user_id'], $row['obj_id']);
447 if ($ref_id < 1) {
448 $this->logger->debug(sprintf(
449 'The recipient with id %s has no "read" permission for object with id %s',
450 $row['user_id'],
451 $row['obj_id']
452 ));
453 continue;
454 }
455
456 $row['ref_id'] = $ref_id;
457
458 if ($this->existsProviderObject($row['pos_pk'])) {
459 self::$providerObject[$row['pos_pk']]->addRecipient($row['user_id']);
460 } else {
461 $this->addProviderObject($row);
462 }
463 }
464
465 $usrIdsToPreload = array();
466 foreach (self::$providerObject as $provider) {
467 if ($provider->getPosAuthorId()) {
468 $usrIdsToPreload[$provider->getPosAuthorId()] = $provider->getPosAuthorId();
469 }
470 if ($provider->getPosDisplayUserId()) {
471 $usrIdsToPreload[$provider->getPosDisplayUserId()] = $provider->getPosDisplayUserId();
472 }
473 if ($provider->getPostUpdateUserId()) {
474 $usrIdsToPreload[$provider->getPostUpdateUserId()] = $provider->getPostUpdateUserId();
475 }
476 }
477
478 require_once 'Modules/Forum/classes/class.ilForumAuthorInformationCache.php';
479 ilForumAuthorInformationCache::preloadUserObjects(array_unique($usrIdsToPreload));
480
481 $i = 0;
482 foreach (self::$providerObject as $provider) {
483 if ($i > 0 && ($i % self::KEEP_ALIVE_CHUNK_SIZE) == 0) {
484 $this->keepAlive();
485 }
486
487 $recipients = array_unique($provider->getCronRecipients());
488
489 $this->logger->info(sprintf(
490 'Trying to send forum notifications for posting id "%s", type "%s" and recipients: %s',
491 $provider->getPostId(),
492 $notification_type,
493 implode(', ', $recipients)
494 ));
495
496 $mailNotification = new ilForumMailNotification($provider, $this->logger);
497 $mailNotification->setIsCronjob(true);
498 $mailNotification->setType($notification_type);
499 $mailNotification->setRecipients($recipients);
500
501 $mailNotification->send();
502
503 $this->num_sent_messages += count($provider->getCronRecipients());
504 $this->logger->info(sprintf("Sent notifications ... "));
505
506 ++$i;
507 }
508
509 $this->resetProviderCache();
510 }
511
516 public function existsProviderObject($post_id)
517 {
518 if (isset(self::$providerObject[$post_id])) {
519 return true;
520 }
521 return false;
522 }
523
527 private function addProviderObject($row)
528 {
529 $tmp_provider = new ilForumCronNotificationDataProvider($row);
530
531 self::$providerObject[$row['pos_pk']] = $tmp_provider;
532 self::$providerObject[$row['pos_pk']]->addRecipient($row['user_id']);
533 }
534
538 private function resetProviderCache()
539 {
540 self::$providerObject = array();
541 }
542
548 public function addToExternalSettingsForm($a_form_id, array &$a_fields, $a_is_active)
549 {
550 global $DIC;
551 $lng = $DIC->language();
552
553 switch ($a_form_id) {
555 $a_fields['cron_forum_notification'] = $a_is_active ?
556 $lng->txt('enabled') :
557 $lng->txt('disabled');
558 break;
559 }
560 }
561
565 public function activationWasToggled($a_currently_active)
566 {
567 global $DIC;
568
569 // propagate cron-job setting to object setting
570 if ((bool) $a_currently_active) {
571 $DIC->settings()->set('forum_notification', 2);
572 } else {
573 $DIC->settings()->set('forum_notification', 1);
574 }
575 }
576
581 {
582 global $DIC;
583 $lng = $DIC->language();
584
585 $lng->loadLanguageModule('forum');
586
587 $max_notification_age = new ilNumberInputGUI($lng->txt('frm_max_notification_age'), 'max_notification_age');
588 $max_notification_age->setSize(5);
589 $max_notification_age->setSuffix($lng->txt('frm_max_notification_age_unit'));
590 $max_notification_age->setRequired(true);
591 $max_notification_age->allowDecimals(false);
592 $max_notification_age->setMinValue(1);
593 $max_notification_age->setInfo($lng->txt('frm_max_notification_age_info'));
594 $max_notification_age->setValue($this->settings->get('max_notification_age', 30));
595
596 $a_form->addItem($max_notification_age);
597 }
598
603 public function saveCustomSettings(ilPropertyFormGUI $a_form)
604 {
605 $this->settings->set('max_notification_age', $a_form->getInput('max_notification_age'));
606 return true;
607 }
608}
memory_get_usage(true)/1024/1024)
sprintf('%.4f', $callTime)
date( 'd-M-Y', $objPHPExcel->getProperties() ->getCreated())
$result
An exception for terminatinating execution or to throw for unit testing.
Cron job result data container.
Cron job application base class.
const SCHEDULE_TYPE_IN_HOURS
static ping($a_job_id)
Keep cron job alive.
saveCustomSettings(ilPropertyFormGUI $a_form)
addCustomSettingsToForm(ilPropertyFormGUI $a_form)
sendCronForumNotification($res, $notification_type)
getDefaultScheduleValue()
Get schedule value.
getFirstAccessibleRefIdBUserAndObjId($a_user_id, $a_obj_id)
hasAutoActivation()
Is to be activated on "installation".
hasFlexibleSchedule()
Can the schedule be configured?
addToExternalSettingsForm($a_form_id, array &$a_fields, $a_is_active)
This class represents a number property in a property form.
static _getAllReferences($a_id)
get all reference ids of object
This class represents a property form user interface.
addItem($a_item)
Add Item (Property, SectionHeader).
getInput($a_post_var, $ensureValidation=true)
Returns the value of a HTTP-POST variable, identified by the passed id.
ILIAS Setting Class.
$i
Definition: disco.tpl.php:19
global $lng
Definition: privfeed.php:17
global $ilSetting
Definition: privfeed.php:17
global $DIC
Definition: saml.php:7
foreach($_POST as $key=> $value) $res
settings()
Definition: settings.php:2
global $ilDB