/** * libcalendaring::get_next_alarm() */ function test_get_next_alarm() { // alarm 10 minutes before event $date = date('Ymd', strtotime('today + 2 days')); $event = array('start' => new DateTime($date . 'T160000Z'), 'end' => new DateTime($date . 'T180000Z'), 'valarms' => array(array('trigger' => '-PT10M', 'action' => 'DISPLAY'))); $alarm = libcalendaring::get_next_alarm($event); $this->assertEquals($event['valarms'][0]['action'], $alarm['action']); $this->assertEquals(strtotime($date . 'T155000Z'), $alarm['time']); // alarm 1 hour after before event $event['valarms'] = array(array('trigger' => '+PT1H')); $alarm = libcalendaring::get_next_alarm($event); $this->assertEquals('DISPLAY', $alarm['action']); $this->assertEquals(strtotime($date . 'T190000Z'), $alarm['time']); // ignore past alarms $event['start'] = new DateTime('today 22:00:00'); $event['end'] = new DateTime('today 23:00:00'); $event['valarms'] = array(array('trigger' => '-P2D', 'action' => 'EMAIL'), array('trigger' => '-PT30M', 'action' => 'DISPLAY')); $alarm = libcalendaring::get_next_alarm($event); $this->assertEquals('DISPLAY', $alarm['action']); $this->assertEquals(strtotime('today 21:30:00'), $alarm['time']); // absolute alarm date/time $event['valarms'] = array(array('trigger' => new DateTime('today 20:00:00'))); $alarm = libcalendaring::get_next_alarm($event); $this->assertEquals($event['valarms'][0]['trigger']->format('U'), $alarm['time']); // no alarms for cancelled events $event['status'] = 'CANCELLED'; $alarm = libcalendaring::get_next_alarm($event); $this->assertEquals(null, $alarm); }
/** * Handler for pending_alarms plugin hook triggered by the calendar module on keep-alive requests. * This will check for pending notifications and pass them to the client */ public function pending_alarms($p) { $this->load_driver(); $time = $p['time'] ?: time(); if ($alarms = $this->driver->pending_alarms($time)) { foreach ($alarms as $alarm) { $alarm['id'] = 'cal:' . $alarm['id']; // prefix ID with cal: $p['alarms'][] = $alarm; } } // get alarms for birthdays calendar if ($this->rc->config->get('calendar_contact_birthdays') && $this->rc->config->get('calendar_birthdays_alarm_type') == 'DISPLAY') { $cache = $this->rc->get_cache('calendar.birthdayalarms', 'db'); foreach ($this->driver->load_birthday_events($time, $time + 86400 * 60) as $e) { $alarm = libcalendaring::get_next_alarm($e); // overwrite alarm time with snooze value (or null if dismissed) if ($dismissed = $cache->get($e['id'])) { $alarm['time'] = $dismissed['notifyat']; } // add to list if alarm is set if ($alarm && $alarm['time'] && $alarm['time'] <= $time) { $e['id'] = 'cal:bday:' . $e['id']; $e['notifyat'] = $alarm['time']; $p['alarms'][] = $e; } } } return $p; }
/** * Compute absolute time to notify the user */ private function _get_notification($task) { if ($task['alarms'] && $task['complete'] < 1 || strpos($task['alarms'], '@') !== false) { $alarm = libcalendaring::get_next_alarm($task, 'task'); if ($alarm['time'] && $alarm['action'] == 'DISPLAY') { return date('Y-m-d H:i:s', $alarm['time']); } } return null; }
/** * Get a list of pending alarms to be displayed to the user * * @see calendar_driver::pending_alarms() */ public function pending_alarms($time, $calendars = null) { $interval = 300; $time -= $time % 60; $slot = $time; $slot -= $slot % $interval; $last = $time - max(60, $this->rc->config->get('refresh_interval', 0)); $last -= $last % $interval; // only check for alerts once in 5 minutes if ($last == $slot) { return array(); } if ($calendars && is_string($calendars)) { $calendars = explode(',', $calendars); } $time = $slot + $interval; $candidates = array(); $query = array(array('tags', '=', 'x-has-alarms')); foreach ($this->calendars as $cid => $calendar) { // skip calendars with alarms disabled if (!$calendar->alarms || $calendars && !in_array($cid, $calendars)) { continue; } foreach ($calendar->list_events($time, $time + 86400 * 365, null, 1, $query) as $e) { // add to list if alarm is set $alarm = libcalendaring::get_next_alarm($e); if ($alarm && $alarm['time'] && $alarm['time'] >= $last && in_array($alarm['action'], $this->alarm_types)) { $id = $alarm['id']; // use alarm-id as primary identifier $candidates[$id] = array('id' => $id, 'title' => $e['title'], 'location' => $e['location'], 'start' => $e['start'], 'end' => $e['end'], 'notifyat' => $alarm['time'], 'action' => $alarm['action']); } } } // get alarm information stored in local database if (!empty($candidates)) { $alarm_ids = array_map(array($this->rc->db, 'quote'), array_keys($candidates)); $result = $this->rc->db->query("SELECT *" . " FROM " . $this->rc->db->table_name('kolab_alarms', true) . " WHERE `alarm_id` IN (" . join(',', $alarm_ids) . ")" . " AND `user_id` = ?", $this->rc->user->ID); while ($result && ($e = $this->rc->db->fetch_assoc($result))) { $dbdata[$e['alarm_id']] = $e; } } $alarms = array(); foreach ($candidates as $id => $alarm) { // skip dismissed alarms if ($dbdata[$id]['dismissed']) { continue; } // snooze function may have shifted alarm time $notifyat = $dbdata[$id]['notifyat'] ? strtotime($dbdata[$id]['notifyat']) : $alarm['notifyat']; if ($notifyat <= $time) { $alarms[] = $alarm; } } return $alarms; }
/** * Feedback after showing/sending an alarm notification * * @see calendar_driver::dismiss_alarm() */ public function dismiss_alarm($event_id, $snooze = 0) { $notify_at = null; //default $stz = date_default_timezone_get(); date_default_timezone_set($this->cal->timezone->getName()); $event = $this->get_master(array('id' => $event_id)); $dismissed_alarm = $event['notifyat']; $dismissed_alarm = strtotime($dismissed_alarm) <= time() ? $dismissed_alarm : null; if ($snooze > 0) { $notify_at = date(self::DB_DATE_FORMAT, time() + $snooze); } else { if ($event['recurrence'] && $event['id'] == $event_id) { if ($event['recurrence']) { $base_alarm = libcalendaring::get_next_alarm($event); $before = $event['start']->format('U') - $base_alarm['time']; $this->_get_recurrences($event, time() + $before, false, 'alarms'); if ($this->last_clone) { $dismissed = $event['notifyat']; if (substr($event['alarms'], 0, 1) == '@') { $notify_at = null; } else { $notify_at = $this->last_clone['notifyat']; } } } } } $now = gmdate(self::DB_DATE_FORMAT); if ($dismissed_alarm) { $query = $this->rc->db->query("UPDATE " . $this->_get_table($this->db_events) . "\n SET changed=?, alarms=?, notifyat=?, dismissed=?\n WHERE event_id=?\n AND calendar_id IN (" . $this->calendar_ids . ")", $now, $event['alarms'], $notify_at, $dismissed_alarm, $event_id); } else { $query = $this->rc->db->query("UPDATE " . $this->_get_table($this->db_events) . "\n SET changed=?, alarms=?, notifyat=?\n WHERE event_id=?\n AND calendar_id IN (" . $this->calendar_ids . ")", $now, $event['alarms'], $notify_at, $event_id); } date_default_timezone_set($stz); return $this->rc->db->affected_rows($query); }
/** * Get a list of pending alarms to be displayed to the user * * @param integer Current time (unix timestamp) * @param mixed List of list IDs to show alarms for (either as array or comma-separated string) * @return array A list of alarms, each encoded as hash array with task properties * @see tasklist_driver::pending_alarms() */ public function pending_alarms($time, $lists = null) { $interval = 300; $time -= $time % 60; $slot = $time; $slot -= $slot % $interval; $last = $time - max(60, $this->rc->config->get('refresh_interval', 0)); $last -= $last % $interval; // only check for alerts once in 5 minutes if ($last == $slot) { return array(); } if ($lists && is_string($lists)) { $lists = explode(',', $lists); } $time = $slot + $interval; $tasks = array(); $query = array(array('tags', '=', 'x-has-alarms'), array('tags', '!=', 'x-complete')); foreach ($this->lists as $lid => $list) { // skip lists with alarms disabled if (!$list['showalarms'] || $lists && !in_array($lid, $lists)) { continue; } $folder = $this->folders[$lid]; foreach ((array) $folder->select($query) as $record) { if (!$record['alarms']) { // don't trust query :-) continue; } $task = $this->_to_rcube_task($record); // add to list if alarm is set $alarm = libcalendaring::get_next_alarm($task, 'task'); if ($alarm && $alarm['time'] && $alarm['time'] <= $time && $alarm['action'] == 'DISPLAY') { $id = $task['id']; $tasks[$id] = $task; $tasks[$id]['notifyat'] = $alarm['time']; } } } // get alarm information stored in local database if (!empty($tasks)) { $task_ids = array_map(array($this->rc->db, 'quote'), array_keys($tasks)); $result = $this->rc->db->query(sprintf("SELECT * FROM kolab_alarms\n WHERE event_id IN (%s) AND user_id=?", join(',', $task_ids), $this->rc->db->now()), $this->rc->user->ID); while ($result && ($rec = $this->rc->db->fetch_assoc($result))) { $dbdata[$rec['event_id']] = $rec; } } $alarms = array(); foreach ($tasks as $id => $task) { // skip dismissed if ($dbdata[$id]['dismissed']) { continue; } // snooze function may have shifted alarm time $notifyat = $dbdata[$id]['notifyat'] ? strtotime($dbdata[$id]['notifyat']) : $task['notifyat']; if ($notifyat <= $time) { $alarms[] = $task; } } return $alarms; }
/** * Compute absolute time to notify the user */ private function _get_notification($event) { if ($event['valarms'] && $event['start'] > new DateTime()) { $alarm = libcalendaring::get_next_alarm($event); if ($alarm['time'] && in_array($alarm['action'], $this->alarm_types)) { return date('Y-m-d H:i:s', $alarm['time']); } } return null; }
/** * Compute absolute time to notify the user */ private function _get_notification($task) { if ($task['valarms'] && !$this->is_complete($task)) { $alarm = libcalendaring::get_next_alarm($task, 'task'); if ($alarm['time'] && in_array($alarm['action'], $this->alarm_types)) { return date('Y-m-d H:i:s', $alarm['time']); } } return null; }
/** * Get a list of pending alarms to be displayed to the user * * @param integer Current time (unix timestamp) * @param mixed List of list IDs to show alarms for (either as array or comma-separated string) * @return array A list of alarms, each encoded as hash array with task properties * @see tasklist_driver::pending_alarms() */ public function pending_alarms($time, $lists = null) { $interval = 300; $time -= $time % 60; $slot = $time; $slot -= $slot % $interval; $last = $time - max(60, $this->rc->config->get('refresh_interval', 0)); $last -= $last % $interval; // only check for alerts once in 5 minutes if ($last == $slot) { return array(); } if ($lists && is_string($lists)) { $lists = explode(',', $lists); } $time = $slot + $interval; $candidates = array(); $query = array(array('tags', '=', 'x-has-alarms'), array('tags', '!=', 'x-complete')); foreach ($this->lists as $lid => $list) { // skip lists with alarms disabled if (!$list['showalarms'] || $lists && !in_array($lid, $lists)) { continue; } $folder = $this->get_folder($lid); foreach ($folder->select($query) as $record) { if (!($record['valarms'] || $record['alarms']) || $record['status'] == 'COMPLETED' || $record['complete'] == 100) { // don't trust query :-) continue; } $task = $this->_to_rcube_task($record, $lid, false); // add to list if alarm is set $alarm = libcalendaring::get_next_alarm($task, 'task'); if ($alarm && $alarm['time'] && $alarm['time'] <= $time && in_array($alarm['action'], $this->alarm_types)) { $id = $alarm['id']; // use alarm-id as primary identifier $candidates[$id] = array('id' => $id, 'title' => $task['title'], 'date' => $task['date'], 'time' => $task['time'], 'notifyat' => $alarm['time'], 'action' => $alarm['action']); } } } // get alarm information stored in local database if (!empty($candidates)) { $alarm_ids = array_map(array($this->rc->db, 'quote'), array_keys($candidates)); $result = $this->rc->db->query("SELECT *" . " FROM " . $this->rc->db->table_name('kolab_alarms', true) . " WHERE `alarm_id` IN (" . join(',', $alarm_ids) . ")" . " AND `user_id` = ?", $this->rc->user->ID); while ($result && ($rec = $this->rc->db->fetch_assoc($result))) { $dbdata[$rec['alarm_id']] = $rec; } } $alarms = array(); foreach ($candidates as $id => $task) { // skip dismissed if ($dbdata[$id]['dismissed']) { continue; } // snooze function may have shifted alarm time $notifyat = $dbdata[$id]['notifyat'] ? strtotime($dbdata[$id]['notifyat']) : $task['notifyat']; if ($notifyat <= $time) { $alarms[] = $task; } } return $alarms; }