ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
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 
4 include_once "Services/Cron/classes/class.ilCronJob.php";
5 include_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 $lng;
68 
69  return $lng->txt("cron_forum_notification");
70  }
71 
72  public function getDescription()
73  {
74  global $lng;
75 
76  return $lng->txt("cron_forum_notification_crob_desc");
77  }
78 
79  public function getDefaultScheduleType()
80  {
81  return self::SCHEDULE_TYPE_IN_HOURS;
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 $ilDB, $ilSetting, $lng;
123 
124  $this->logger = $GLOBALS['DIC']->logger()->frm();
125 
127 
128  $lng->loadLanguageModule('forum');
129 
130  $this->logger->info('Started forum notification job ...');
131 
132  if(!($last_run_datetime = $ilSetting->get('cron_forum_notification_last_date')))
133  {
134  $last_run_datetime = null;
135  }
136 
137  $this->num_sent_messages = 0;
138  $cj_start_date = date('Y-m-d H:i:s');
139 
140  if($last_run_datetime != null &&
141  checkDate(date('m', strtotime($last_run_datetime)), date('d', strtotime($last_run_datetime)), date('Y', strtotime($last_run_datetime))))
142  {
143  $threshold = max(strtotime($last_run_datetime), strtotime('-' . (int)$this->settings->get('max_notification_age', 30) . ' days', time()));
144  }
145  else
146  {
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  SELECT frm_threads.thr_subject thr_subject,
164  frm_data.top_name top_name,
165  frm_data.top_frm_fk obj_id,
166  frm_notification.user_id user_id,
167  frm_threads.thr_pk thread_id,
168  frm_posts.*
169  FROM frm_notification, frm_posts, frm_threads, frm_data
170  WHERE frm_posts.pos_thr_fk = frm_threads.thr_pk AND '.$new_posts_condition.'
171  AND ((frm_threads.thr_top_fk = frm_data.top_pk AND frm_data.top_frm_fk = frm_notification.frm_id)
172  OR (frm_threads.thr_pk = frm_notification.thread_id
173  AND frm_data.top_pk = frm_threads.thr_top_fk) )
174  AND frm_posts.pos_display_user_id != frm_notification.user_id
175  ORDER BY frm_posts.pos_date ASC',
176  $types,
177  $values
178  );
179 
180  $numRows = $ilDB->numRows($res);
181  if($numRows > 0)
182  {
183  $this->logger->info(sprintf('Sending notifications for %s "new posting" events ...', $numRows));
184  $this->sendCronForumNotification($res, ilForumMailNotification::TYPE_POST_NEW);
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  SELECT frm_threads.thr_subject thr_subject,
199  frm_data.top_name top_name,
200  frm_data.top_frm_fk obj_id,
201  frm_notification.user_id user_id,
202  frm_threads.thr_pk thread_id,
203  frm_posts.*
204  FROM frm_notification, frm_posts, frm_threads, frm_data
205  WHERE frm_posts.pos_thr_fk = frm_threads.thr_pk AND '.$updated_condition.'
206  AND ((frm_threads.thr_top_fk = frm_data.top_pk AND frm_data.top_frm_fk = frm_notification.frm_id)
207  OR (frm_threads.thr_pk = frm_notification.thread_id
208  AND frm_data.top_pk = frm_threads.thr_top_fk) )
209  AND frm_posts.pos_display_user_id != frm_notification.user_id
210  ORDER BY frm_posts.pos_date ASC',
211  $types,
212  $values
213  );
214 
215  $numRows = $ilDB->numRows($res);
216  if($numRows > 0)
217  {
218  $this->logger->info(sprintf('Sending notifications for %s "updated posting" events ...', $numRows));
219  $this->sendCronForumNotification($res, ilForumMailNotification::TYPE_POST_UPDATED);
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  SELECT frm_threads.thr_subject thr_subject,
234  frm_data.top_name top_name,
235  frm_data.top_frm_fk obj_id,
236  frm_notification.user_id user_id,
237  frm_threads.thr_pk thread_id,
238  frm_posts.*
239  FROM frm_notification, frm_posts, frm_threads, frm_data
240  WHERE frm_posts.pos_thr_fk = frm_threads.thr_pk AND '.$censored_condition.'
241  AND ((frm_threads.thr_top_fk = frm_data.top_pk AND frm_data.top_frm_fk = frm_notification.frm_id)
242  OR (frm_threads.thr_pk = frm_notification.thread_id
243  AND frm_data.top_pk = frm_threads.thr_top_fk) )
244  AND (frm_posts.pos_display_user_id != frm_notification.user_id)
245  ORDER BY frm_posts.pos_date ASC',
246  $types,
247  $values
248  );
249 
250  $numRows = $ilDB->numRows($res);
251  if($numRows > 0)
252  {
253  $this->logger->info(sprintf('Sending notifications for %s "censored posting" events ...', $numRows));
254  $this->sendCronForumNotification($res, ilForumMailNotification::TYPE_POST_CENSORED);
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  SELECT frm_threads.thr_subject thr_subject,
269  frm_data.top_name top_name,
270  frm_data.top_frm_fk obj_id,
271  frm_notification.user_id user_id,
272  frm_threads.thr_pk thread_id,
273  frm_posts.*
274  FROM frm_notification, frm_posts, frm_threads, frm_data
275  WHERE frm_posts.pos_thr_fk = frm_threads.thr_pk AND '.$uncensored_condition.'
276  AND ((frm_threads.thr_top_fk = frm_data.top_pk AND frm_data.top_frm_fk = frm_notification.frm_id)
277  OR (frm_threads.thr_pk = frm_notification.thread_id
278  AND frm_data.top_pk = frm_threads.thr_top_fk) )
279  AND frm_posts.pos_display_user_id != frm_notification.user_id
280  ORDER BY frm_posts.pos_date ASC',
281  $types,
282  $values
283  );
284 
285  $numRows = $ilDB->numRows($res);
286  if($numRows > 0)
287  {
288  $this->logger->info(sprintf('Sending notifications for %s "uncensored posting" events ...', $numRows));
289  $this->sendCronForumNotification($res, ilForumMailNotification::TYPE_POST_UNCENSORED);
290  $this->logger->info(sprintf('Sent notifications for uncensored postings ...'));
291  }
292 
293  $this->keepAlive();
294 
295  /*** deleted threads ***/
296  $res = $ilDB->queryF('
297  SELECT frm_posts_deleted.thread_title thr_subject,
298  frm_posts_deleted.forum_title top_name,
299  frm_posts_deleted.obj_id obj_id,
300  frm_notification.user_id user_id,
301  frm_posts_deleted.pos_display_user_id,
302  frm_posts_deleted.pos_usr_alias,
303  frm_posts_deleted.deleted_id,
304  frm_posts_deleted.post_date pos_date,
305  frm_posts_deleted.post_title pos_subject,
306  frm_posts_deleted.post_message pos_message
307 
308  FROM frm_notification, frm_posts_deleted
309 
310  WHERE ( frm_posts_deleted.obj_id = frm_notification.frm_id
311  OR frm_posts_deleted.thread_id = frm_notification.thread_id)
312  AND frm_posts_deleted.pos_display_user_id != frm_notification.user_id
313  AND frm_posts_deleted.is_thread_deleted = %s
314  ORDER BY frm_posts_deleted.post_date ASC',
315  array('integer'), array(1));
316  $numRows = $ilDB->numRows($res);
317  if($numRows > 0)
318  {
319  $this->logger->info(sprintf('Sending notifications for %s "deleted threads" events ...', $numRows));
320  $this->sendCronForumNotification($res, ilForumMailNotification::TYPE_THREAD_DELETED);
321  if(count(self::$deleted_ids_cache) > 0)
322  {
323  $ilDB->manipulate('DELETE FROM frm_posts_deleted WHERE '. $ilDB->in('deleted_id', self::$deleted_ids_cache, false, 'integer'));
324  $this->logger->info('Deleted obsolete entries of table "frm_posts_deleted" ...');
325  }
326  $this->logger->info(sprintf('Sent notifications for deleted threads ...'));
327  }
328 
329  $this->keepAlive();
330 
331  /*** deleted posts ***/
332  $res = $ilDB->queryF('
333  SELECT frm_posts_deleted.thread_title thr_subject,
334  frm_posts_deleted.forum_title top_name,
335  frm_posts_deleted.obj_id obj_id,
336  frm_notification.user_id user_id,
337  frm_posts_deleted.pos_display_user_id,
338  frm_posts_deleted.pos_usr_alias,
339  frm_posts_deleted.deleted_id,
340  frm_posts_deleted.post_date pos_date,
341  frm_posts_deleted.post_title pos_subject,
342  frm_posts_deleted.post_message pos_message
343 
344  FROM frm_notification, frm_posts_deleted
345 
346  WHERE ( frm_posts_deleted.obj_id = frm_notification.frm_id
347  OR frm_posts_deleted.thread_id = frm_notification.thread_id)
348  AND frm_posts_deleted.pos_display_user_id != frm_notification.user_id
349  AND frm_posts_deleted.is_thread_deleted = %s
350  ORDER BY frm_posts_deleted.post_date ASC',
351  array('integer'), array(0));
352 
353  $numRows = $ilDB->numRows($res);
354  if($numRows > 0)
355  {
356  $this->logger->info(sprintf('Sending notifications for %s "deleted postings" events ...', $numRows));
357  $this->sendCronForumNotification($res, ilForumMailNotification::TYPE_POST_DELETED);
358  if(count(self::$deleted_ids_cache) > 0)
359  {
360  $ilDB->manipulate('DELETE FROM frm_posts_deleted WHERE '. $ilDB->in('deleted_id', self::$deleted_ids_cache, false, 'integer'));
361  $this->logger->info('Deleted entries from table "frm_posts_deleted" ...');
362  }
363  $this->logger->info(sprintf('Sent notifications for deleted postings ...'));
364  }
365 
366  $ilSetting->set('cron_forum_notification_last_date', $cj_start_date);
367 
368  $mess = 'Sent '.$this->num_sent_messages.' messages.';
369 
370  $this->logger->info($mess);
371  $this->logger->info('Finished forum notification job');
372 
373  $result = new ilCronJobResult();
374  if($this->num_sent_messages)
375  {
376  $status = ilCronJobResult::STATUS_OK;
377  $result->setMessage($mess);
378  };
379  $result->setStatus($status);
380  return $result;
381  }
382 
387  protected function getRefIdsByObjId($a_obj_id)
388  {
389  if(!array_key_exists($a_obj_id, self::$ref_ids_by_obj_id))
390  {
391  self::$ref_ids_by_obj_id[$a_obj_id] = ilObject::_getAllReferences($a_obj_id);
392  }
393 
394  return (array)self::$ref_ids_by_obj_id[$a_obj_id];
395  }
396 
402  protected function getFirstAccessibleRefIdBUserAndObjId($a_user_id, $a_obj_id)
403  {
407  global $ilAccess;
408 
409  if(!array_key_exists($a_user_id, self::$accessible_ref_ids_by_user))
410  {
411  self::$accessible_ref_ids_by_user[$a_user_id] = array();
412  }
413 
414  if(!array_key_exists($a_obj_id, self::$accessible_ref_ids_by_user[$a_user_id]))
415  {
416  $accessible_ref_id = 0;
417  foreach($this->getRefIdsByObjId($a_obj_id) as $ref_id)
418  {
419  if($ilAccess->checkAccessOfUser($a_user_id, 'read', '', $ref_id))
420  {
421  $accessible_ref_id = $ref_id;
422  break;
423  }
424  }
425  self::$accessible_ref_ids_by_user[$a_user_id][$a_obj_id] = $accessible_ref_id;
426  }
427 
428  return (int)self::$accessible_ref_ids_by_user[$a_user_id][$a_obj_id];
429  }
430 
435  public function sendCronForumNotification($res, $notification_type)
436  {
440  global $ilDB;
441 
442  include_once './Modules/Forum/classes/class.ilForumCronNotificationDataProvider.php';
443  include_once './Modules/Forum/classes/class.ilForumMailNotification.php';
444 
445  while($row = $ilDB->fetchAssoc($res))
446  {
447  if($notification_type == ilForumMailNotification::TYPE_POST_DELETED
448  || $notification_type == ilForumMailNotification::TYPE_THREAD_DELETED)
449  {
450  // important! save the deleted_id to cache before proceeding getFirstAccessibleRefIdBUserAndObjId !
451  self::$deleted_ids_cache[$row['deleted_id']] = $row['deleted_id'];
452  }
453 
454  $ref_id = $this->getFirstAccessibleRefIdBUserAndObjId($row['user_id'], $row['obj_id']);
455  if($ref_id < 1)
456  {
457  $this->logger->debug(sprintf(
458  'The recipient with id %s has no "read" permission for object with id %s',
459  $row['user_id'], $row['obj_id']
460  ));
461  continue;
462  }
463 
464  $row['ref_id'] = $ref_id;
465 
466  if($this->existsProviderObject($row['pos_pk']))
467  {
468  self::$providerObject[$row['pos_pk']]->addRecipient($row['user_id']);
469  }
470  else
471  {
472  $this->addProviderObject($row);
473  }
474  }
475 
476  $usrIdsToPreload = array();
477  foreach (self::$providerObject as $provider) {
478  if ($provider->getPosAuthorId()) {
479  $usrIdsToPreload[$provider->getPosAuthorId()] = $provider->getPosAuthorId();
480  }
481  if ($provider->getPosDisplayUserId()) {
482  $usrIdsToPreload[$provider->getPosDisplayUserId()] = $provider->getPosDisplayUserId();
483  }
484  if ($provider->getPostUpdateUserId()) {
485  $usrIdsToPreload[$provider->getPostUpdateUserId()] = $provider->getPostUpdateUserId();
486  }
487  }
488 
489  require_once 'Modules/Forum/classes/class.ilForumAuthorInformationCache.php';
490  ilForumAuthorInformationCache::preloadUserObjects(array_unique($usrIdsToPreload));
491 
492  $i = 0;
493  foreach(self::$providerObject as $provider)
494  {
495  if ($i > 0 && ($i % self::KEEP_ALIVE_CHUNK_SIZE) == 0) {
496  $this->keepAlive();
497  }
498 
499  $recipients = array_unique($provider->getCronRecipients());
500 
501  $this->logger->info(sprintf(
502  'Trying to send forum notifications for posting id "%s", type "%s" and recipients: %s',
503  $provider->getPostId(), $notification_type, implode(', ', $recipients)
504  ));
505 
506  $mailNotification = new ilForumMailNotification($provider, $this->logger);
507  $mailNotification->setIsCronjob(true);
508  $mailNotification->setType($notification_type);
509  $mailNotification->setRecipients($recipients);
510 
511  $mailNotification->send();
512 
513  $this->num_sent_messages += count($provider->getCronRecipients());
514  $this->logger->info(sprintf("Sent notifications ... "));
515 
516  ++$i;
517  }
518 
519  $this->resetProviderCache();
520  }
521 
526  public function existsProviderObject($post_id)
527  {
528  if(isset(self::$providerObject[$post_id]))
529  {
530  return true;
531  }
532  return false;
533  }
534 
538  private function addProviderObject($row)
539  {
540  $tmp_provider = new ilForumCronNotificationDataProvider($row);
541 
542  self::$providerObject[$row['pos_pk']] = $tmp_provider;
543  self::$providerObject[$row['pos_pk']]->addRecipient($row['user_id']);
544  }
545 
549  private function resetProviderCache()
550  {
551  self::$providerObject = array();
552  }
553 
559  public function addToExternalSettingsForm($a_form_id, array &$a_fields, $a_is_active)
560  {
564  global $lng;
565 
566  switch($a_form_id)
567  {
569  $a_fields['cron_forum_notification'] = $a_is_active ?
570  $lng->txt('enabled') :
571  $lng->txt('disabled');
572  break;
573  }
574  }
575 
579  public function activationWasToggled($a_currently_active)
580  {
581  global $ilSetting;
582 
583  // propagate cron-job setting to object setting
584  if((bool)$a_currently_active)
585  {
586  $ilSetting->set('forum_notification', 2);
587  }
588  else
589  {
590  $ilSetting->set('forum_notification', 1);
591  }
592  }
593 
597  public function addCustomSettingsToForm(ilPropertyFormGUI $a_form)
598  {
602  global $lng;
603 
604  $lng->loadLanguageModule('forum');
605 
606  $max_notification_age = new ilNumberInputGUI($lng->txt('frm_max_notification_age'), 'max_notification_age');
607  $max_notification_age->setSize(5);
608  $max_notification_age->setSuffix($lng->txt('frm_max_notification_age_unit'));
609  $max_notification_age->setRequired(true);
610  $max_notification_age->allowDecimals(false);
611  $max_notification_age->setMinValue(1);
612  $max_notification_age->setInfo($lng->txt('frm_max_notification_age_info'));
613  $max_notification_age->setValue($this->settings->get('max_notification_age', 30));
614 
615  $a_form->addItem($max_notification_age);
616  }
617 
622  public function saveCustomSettings(ilPropertyFormGUI $a_form)
623  {
624  $this->settings->set('max_notification_age', $a_form->getInput('max_notification_age'));
625  return true;
626  }
627 }
ILIAS Setting Class.
$result
This class represents a property form user interface.
addToExternalSettingsForm($a_form_id, array &$a_fields, $a_is_active)
Add external settings to form.
Cron job application base class.
$GLOBALS['loaded']
Global hash that tracks already loaded includes.
addItem($a_item)
Add Item (Property, SectionHeader).
static _getAllReferences($a_id)
get all reference ids of object
addCustomSettingsToForm(ilPropertyFormGUI $a_form)
Add custom settings to form.
This class represents a number property in a property form.
date( 'd-M-Y', $objPHPExcel->getProperties() ->getCreated())
saveCustomSettings(ilPropertyFormGUI $a_form)
getInput($a_post_var, $ensureValidation=true)
Returns the value of a HTTP-POST variable, identified by the passed id.
Create styles array
The data for the language used.
setSize($a_size)
Set Size.
settings()
Definition: settings.php:2
static ping($a_job_id)
Keep cron job alive.
$ref_id
Definition: sahs_server.php:39
global $ilSetting
Definition: privfeed.php:17
global $lng
Definition: privfeed.php:17
global $ilDB
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
Cron job result data container.