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 
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 $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  {
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 $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) {
379  $status = ilCronJobResult::STATUS_OK;
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 }
getFirstAccessibleRefIdBUserAndObjId($a_user_id, $a_obj_id)
$result
This class represents a property form user interface.
global $DIC
Definition: saml.php:7
sendCronForumNotification($res, $notification_type)
Cron job application base class.
addItem($a_item)
Add Item (Property, SectionHeader).
static _getAllReferences($a_id)
get all reference ids of object
addCustomSettingsToForm(ilPropertyFormGUI $a_form)
foreach($_POST as $key=> $value) $res
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.
addToExternalSettingsForm($a_form_id, array &$a_fields, $a_is_active)
setSize($a_size)
Set Size.
settings()
Definition: settings.php:2
static ping($a_job_id)
Keep cron job alive.
global $ilSetting
Definition: privfeed.php:17
global $lng
Definition: privfeed.php:17
global $ilDB
$i
Definition: disco.tpl.php:19
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
Cron job result data container.