Prepare backend to show alarm notifications; fix event selection when multiple calendars are listed
This commit is contained in:
parent
99d2d842af
commit
34a0911fe8
8 changed files with 186 additions and 55 deletions
|
@ -45,20 +45,6 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
|
|||
// private vars
|
||||
var day_clicked = 0;
|
||||
var ignore_click = false;
|
||||
|
||||
// data loader
|
||||
var load_events = function(calendar, start, end, callback) {
|
||||
$.ajax({
|
||||
url: "./?_task=calendar&_action=plugin.load_events",
|
||||
dataType: 'json',
|
||||
data: {
|
||||
source: calendar,
|
||||
start: Math.round(start.getTime() / 1000),
|
||||
end: Math.round(end.getTime() / 1000)
|
||||
},
|
||||
success: callback
|
||||
});
|
||||
};
|
||||
|
||||
// event details dialog (show only)
|
||||
var event_show_dialog = function(event) {
|
||||
|
@ -438,7 +424,7 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
|
|||
for (var id in rcmail.env.calendars) {
|
||||
cal = rcmail.env.calendars[id];
|
||||
this.calendars[id] = $.extend({
|
||||
events: function(start, end, callback) { load_events(id, start, end, callback); },
|
||||
url: "./?_task=calendar&_action=plugin.load_events&source="+escape(id),
|
||||
editable: !cal.readonly,
|
||||
className: 'fc-event-cal-'+id,
|
||||
id: id
|
||||
|
@ -455,8 +441,9 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
|
|||
}
|
||||
}).data('id', id);
|
||||
$(li).click(function(e){
|
||||
var id = $(this).data('id');
|
||||
rcmail.select_folder(id, me.selected_calendar, 'rcmlical');
|
||||
me.selected_calendar = $(this).data('id');
|
||||
me.selected_calendar = id;
|
||||
}).data('id', id);
|
||||
}
|
||||
|
||||
|
|
|
@ -521,7 +521,9 @@ class calendar extends rcube_plugin
|
|||
*/
|
||||
public static function parse_alaram_value($val)
|
||||
{
|
||||
if (preg_match('/([+-])(\d+)([HMD])/', $val, $m))
|
||||
if ($val[0] == '@')
|
||||
return array(substr($val, 1));
|
||||
else if (preg_match('/([+-])(\d+)([HMD])/', $val, $m))
|
||||
return array($m[2], $m[1].$m[3]);
|
||||
|
||||
return false;
|
||||
|
|
|
@ -131,10 +131,26 @@ abstract class calendar_driver
|
|||
*
|
||||
* @param integer Current time (unix timestamp)
|
||||
* @param mixed List of calendar IDs to show alarms for (either as array or comma-separated string)
|
||||
* @return array A list of alarms
|
||||
* @return array A list of alarms, each encoded as hash array:
|
||||
* id: Event identifier
|
||||
* uid: Unique identifier of this event
|
||||
* calendar: Calendar identifier to add event to (optional)
|
||||
* start: Event start date/time as unix timestamp
|
||||
* end: Event end date/time as unix timestamp
|
||||
* allday: Boolean flag if this is an all-day event
|
||||
* title: Event title/summary
|
||||
* location: Location string
|
||||
*/
|
||||
abstract function pending_alarms($time, $calendars = null);
|
||||
|
||||
/**
|
||||
* (User) feedback after showing an alarm notification
|
||||
* This should mark the alarm as 'shown' or snooze it for the given amount of time
|
||||
*
|
||||
* @param string Event identifier
|
||||
* @param integer Suspend the alarm for this number of seconds
|
||||
*/
|
||||
abstract function confirm_alarm($event_id, $snooze = 0);
|
||||
|
||||
/**
|
||||
* Save an attachment related to the given event
|
||||
|
|
|
@ -139,8 +139,8 @@ class database_driver extends calendar_driver
|
|||
$event = $this->_save_preprocess($event);
|
||||
$query = $this->rc->db->query(sprintf(
|
||||
"INSERT INTO " . $this->db_events . "
|
||||
(calendar_id, created, changed, uid, start, end, all_day, recurrence, title, description, location, categories, free_busy, priority, alarms)
|
||||
VALUES (?, %s, %s, ?, %s, %s, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
(calendar_id, created, changed, uid, start, end, all_day, recurrence, title, description, location, categories, free_busy, priority, alarms, notifyat)
|
||||
VALUES (?, %s, %s, ?, %s, %s, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
$this->rc->db->now(),
|
||||
$this->rc->db->now(),
|
||||
$this->rc->db->fromunixtime($event['start']),
|
||||
|
@ -156,7 +156,8 @@ class database_driver extends calendar_driver
|
|||
strval($event['categories']),
|
||||
intval($event['free_busy']),
|
||||
intval($event['priority']),
|
||||
$event['alarms']
|
||||
$event['alarms'],
|
||||
$event['notifyat']
|
||||
);
|
||||
return $this->rc->db->insert_id($this->sequence_events);
|
||||
}
|
||||
|
@ -176,7 +177,7 @@ class database_driver extends calendar_driver
|
|||
$event = $this->_save_preprocess($event);
|
||||
$query = $this->rc->db->query(sprintf(
|
||||
"UPDATE " . $this->db_events . "
|
||||
SET changed=%s, start=%s, end=%s, all_day=?, recurrence=?, title=?, description=?, location=?, categories=?, free_busy=?, priority=?, alarms=?
|
||||
SET changed=%s, start=%s, end=%s, all_day=?, recurrence=?, title=?, description=?, location=?, categories=?, free_busy=?, priority=?, alarms=?, notifyat=?
|
||||
WHERE event_id=?
|
||||
AND calendar_id IN (" . $this->calendar_ids . ")",
|
||||
$this->rc->db->now(),
|
||||
|
@ -192,6 +193,7 @@ class database_driver extends calendar_driver
|
|||
intval($event['free_busy']),
|
||||
intval($event['priority']),
|
||||
$event['alarms'],
|
||||
$event['notifyat'],
|
||||
$event['id']
|
||||
);
|
||||
return $this->rc->db->affected_rows($query);
|
||||
|
@ -220,11 +222,38 @@ class database_driver extends calendar_driver
|
|||
}
|
||||
else if (is_string($event['recurrence']))
|
||||
$rrule = $event['recurrence'];
|
||||
|
||||
|
||||
$event['recurrence'] = rtrim($rrule, ';');
|
||||
$event['free_busy'] = intval($this->free_busy_map[strtolower($event['free_busy'])]);
|
||||
$event['allday'] = $event['allday'] ? 1 : 0;
|
||||
|
||||
// compute absolute time to notify the user
|
||||
if ($event['alarms']) {
|
||||
list($action, $trigger) = explode(':', $event['alarms']);
|
||||
$notify = calendar::parse_alaram_value($trigger);
|
||||
if (!empty($notify[1])){ // offset
|
||||
$mult = 1;
|
||||
switch ($notify[1]) {
|
||||
case '-M': $mult = -60; break;
|
||||
case '+M': $mult = 60; break;
|
||||
case '-H': $mult = -3600; break;
|
||||
case '+H': $mult = 3600; break;
|
||||
case '-D': $mult = -86400; break;
|
||||
case '+D': $mult = 86400; break;
|
||||
}
|
||||
$offset = $notify[0] * $mult;
|
||||
$refdate = $mult > 0 ? $event['end'] : $event['start'];
|
||||
$notify_at = $refdate + $offset;
|
||||
}
|
||||
else { // absolute timestamp
|
||||
$notify_at = $notify[0];
|
||||
}
|
||||
|
||||
$event['notifyat'] = date('Y-m-d H:i:s', $notify_at);
|
||||
}
|
||||
else
|
||||
$event['notifyat'] = null;
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
|
@ -237,9 +266,10 @@ class database_driver extends calendar_driver
|
|||
public function move_event($event)
|
||||
{
|
||||
if (!empty($this->calendars)) {
|
||||
$event = $this->_save_preprocess($event + (array)$this->get_event($event['id']));
|
||||
$query = $this->rc->db->query(sprintf(
|
||||
"UPDATE " . $this->db_events . "
|
||||
SET changed=%s, start=%s, end=%s, all_day=?
|
||||
SET changed=%s, start=%s, end=%s, all_day=?, notifyat=?
|
||||
WHERE event_id=?
|
||||
AND calendar_id IN (" . $this->calendar_ids . ")",
|
||||
$this->rc->db->now(),
|
||||
|
@ -247,6 +277,7 @@ class database_driver extends calendar_driver
|
|||
$this->rc->db->fromunixtime($event['end'])
|
||||
),
|
||||
$event['allday'] ? 1 : 0,
|
||||
$event['notifyat'],
|
||||
$event['id']
|
||||
);
|
||||
return $this->rc->db->affected_rows($query);
|
||||
|
@ -264,15 +295,17 @@ class database_driver extends calendar_driver
|
|||
public function resize_event($event)
|
||||
{
|
||||
if (!empty($this->calendars)) {
|
||||
$event = $this->_save_preprocess($event + (array)$this->get_event($event['id']));
|
||||
$query = $this->rc->db->query(sprintf(
|
||||
"UPDATE " . $this->db_events . "
|
||||
SET changed=%s, start=%s, end=%s
|
||||
SET changed=%s, start=%s, end=%s, notifyat=?
|
||||
WHERE event_id=?
|
||||
AND calendar_id IN (" . $this->calendar_ids . ")",
|
||||
$this->rc->db->now(),
|
||||
$this->rc->db->fromunixtime($event['start']),
|
||||
$this->rc->db->fromunixtime($event['end'])
|
||||
),
|
||||
$event['notifyat'],
|
||||
$event['id']
|
||||
);
|
||||
return $this->rc->db->affected_rows($query);
|
||||
|
@ -302,6 +335,27 @@ class database_driver extends calendar_driver
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return data of a specific event
|
||||
* @param string Event ID
|
||||
* @return array Hash array with event properties
|
||||
*/
|
||||
public function get_event($id)
|
||||
{
|
||||
$result = $this->rc->db->query(sprintf(
|
||||
"SELECT * FROM " . $this->db_events . "
|
||||
WHERE calendar_id IN (%s)
|
||||
AND event_id=?",
|
||||
$this->calendar_ids
|
||||
),
|
||||
$id);
|
||||
|
||||
if ($result && ($event = $this->rc->db->fetch_assoc($result)))
|
||||
return $this->_read_postprocess($event);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get event data
|
||||
*
|
||||
|
@ -315,48 +369,57 @@ class database_driver extends calendar_driver
|
|||
$calendars = explode(',', $calendars);
|
||||
|
||||
// only allow to select from calendars of this use
|
||||
$calendars = array_intersect($calendars, array_keys($this->calendars));
|
||||
$calendar_ids = array_intersect($calendars, array_keys($this->calendars));
|
||||
array_walk($calendar_ids, array($this->rc->db, 'quote'));
|
||||
|
||||
$events = array();
|
||||
$free_busy_map = array_flip($this->free_busy_map);
|
||||
|
||||
if (!empty($calendars)) {
|
||||
if (!empty($calendar_ids)) {
|
||||
$result = $this->rc->db->query(sprintf(
|
||||
"SELECT * FROM " . $this->db_events . "
|
||||
WHERE calendar_id IN (%s)
|
||||
AND start <= %s AND end >= %s",
|
||||
$this->calendar_ids,
|
||||
join(',', $calendar_ids),
|
||||
$this->rc->db->fromunixtime($end),
|
||||
$this->rc->db->fromunixtime($start)
|
||||
));
|
||||
|
||||
while ($result && ($event = $this->rc->db->fetch_assoc($result))) {
|
||||
$event['id'] = $event['event_id'];
|
||||
$event['start'] = strtotime($event['start']);
|
||||
$event['end'] = strtotime($event['end']);
|
||||
$event['free_busy'] = $free_busy_map[$event['free_busy']];
|
||||
$event['calendar'] = $event['calendar_id'];
|
||||
|
||||
// parse recurrence rule
|
||||
if ($event['recurrence'] && preg_match_all('/([A-Z]+)=([^;]+);?/', $event['recurrence'], $m, PREG_SET_ORDER)) {
|
||||
$event['recurrence'] = array();
|
||||
foreach ($m as $rr) {
|
||||
if (is_numeric($rr[2]))
|
||||
$rr[2] = intval($rr[2]);
|
||||
else if ($rr[1] == 'UNTIL')
|
||||
$rr[2] = strtotime($rr[2]);
|
||||
$event['recurrence'][$rr[1]] = $rr[2];
|
||||
}
|
||||
}
|
||||
|
||||
unset($event['event_id'], $event['calendar_id']);
|
||||
$events[] = $event;
|
||||
$events[] = $this->_read_postprocess($event);
|
||||
}
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert sql record into a rcube style event object
|
||||
*/
|
||||
private function _read_postprocess($event)
|
||||
{
|
||||
$free_busy_map = array_flip($this->free_busy_map);
|
||||
|
||||
$event['id'] = $event['event_id'];
|
||||
$event['start'] = strtotime($event['start']);
|
||||
$event['end'] = strtotime($event['end']);
|
||||
$event['free_busy'] = $free_busy_map[$event['free_busy']];
|
||||
$event['calendar'] = $event['calendar_id'];
|
||||
|
||||
// parse recurrence rule
|
||||
if ($event['recurrence'] && preg_match_all('/([A-Z]+)=([^;]+);?/', $event['recurrence'], $m, PREG_SET_ORDER)) {
|
||||
$event['recurrence'] = array();
|
||||
foreach ($m as $rr) {
|
||||
if (is_numeric($rr[2]))
|
||||
$rr[2] = intval($rr[2]);
|
||||
else if ($rr[1] == 'UNTIL')
|
||||
$rr[2] = strtotime($rr[2]);
|
||||
$event['recurrence'][$rr[1]] = $rr[2];
|
||||
}
|
||||
}
|
||||
|
||||
unset($event['event_id'], $event['calendar_id']);
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search events
|
||||
*
|
||||
|
@ -374,14 +437,63 @@ class database_driver extends calendar_driver
|
|||
*/
|
||||
public function pending_alarms($time, $calendars = null)
|
||||
{
|
||||
// TBD.
|
||||
return array();
|
||||
if (empty($calendars))
|
||||
$calendars = array_keys($this->calendars);
|
||||
else if (is_string($calendars))
|
||||
$calendars = explode(',', $calendars);
|
||||
|
||||
// only allow to select from calendars of this use
|
||||
$calendar_ids = array_intersect($calendars, array_keys($this->calendars));
|
||||
array_walk($calendar_ids, array($this->rc->db, 'quote'));
|
||||
|
||||
$alarms = array();
|
||||
if (!empty($calendar_ids)) {
|
||||
$result = $this->rc->db->query(sprintf(
|
||||
"SELECT * FROM " . $this->db_events . "
|
||||
WHERE calendar_id IN (%s)
|
||||
AND notifyat <= %s",
|
||||
join(',', $calendar_ids),
|
||||
$this->rc->db->fromunixtime($time)
|
||||
));
|
||||
|
||||
while ($result && ($event = $this->rc->db->fetch_assoc($result)))
|
||||
$alarms[] = $this->_read_postprocess($event);
|
||||
}
|
||||
|
||||
return $alarms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Feedback after showing/sending an alarm notification
|
||||
*
|
||||
* @see Driver:confirm_alarm()
|
||||
*/
|
||||
public function confirm_alarm($event_id, $snooze = 0)
|
||||
{
|
||||
// set new notifyat time
|
||||
if ($snooze > 0) {
|
||||
$event = $this->get_event($event_id);
|
||||
$notify_at = date('Y-m-d H:i:s', strtotime($event['notifyat']) + $snooze);
|
||||
}
|
||||
else // unset notifyat value
|
||||
$notify_at = null;
|
||||
|
||||
$query = $this->rc->db->query(sprintf(
|
||||
"UPDATE " . $this->db_events . "
|
||||
SET changed=%s, notifyat=?
|
||||
WHERE event_id=?
|
||||
AND calendar_id IN (" . $this->calendar_ids . ")",
|
||||
$this->rc->db->now()),
|
||||
$notify_at,
|
||||
$event_id
|
||||
);
|
||||
return $this->rc->db->affected_rows($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save an attachment related to the given event
|
||||
*/
|
||||
function add_attachment($attachment, $event_id)
|
||||
public function add_attachment($attachment, $event_id)
|
||||
{
|
||||
// TBD.
|
||||
return false;
|
||||
|
@ -390,7 +502,7 @@ class database_driver extends calendar_driver
|
|||
/**
|
||||
* Remove a specific attachment from the given event
|
||||
*/
|
||||
function remove_attachment($attachment, $event_id)
|
||||
public function remove_attachment($attachment, $event_id)
|
||||
{
|
||||
// TBD.
|
||||
return false;
|
||||
|
|
|
@ -41,6 +41,7 @@ CREATE TABLE `events` (
|
|||
`priority` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`alarms` varchar(255) DEFAULT NULL,
|
||||
`attendees` text DEFAULT NULL,
|
||||
`notifyat` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
|
||||
PRIMARY KEY(`event_id`),
|
||||
CONSTRAINT `fk_events_calendar_id` FOREIGN KEY (`calendar_id`)
|
||||
REFERENCES `calendars`(`calendar_id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
|
|
|
@ -55,7 +55,8 @@ CREATE TABLE events (
|
|||
free_busy smallint NOT NULL DEFAULT 0,
|
||||
priority smallint NOT NULL DEFAULT 1,
|
||||
alarms varchar(255) DEFAULT NULL,
|
||||
attendees text DEFAULT NULL
|
||||
attendees text DEFAULT NULL,
|
||||
notifyat timestamp without time zone DEFAULT now() NOT NULL
|
||||
PRIMARY KEY (event_id)
|
||||
);
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ CREATE TABLE events (
|
|||
priority tinyint(1) NOT NULL default '1',
|
||||
alarms varchar(255) default NULL,
|
||||
attendees text default NULL,
|
||||
notifyat datetime NOT NULL default '1000-01-01 00:00:00',
|
||||
CONSTRAINT fk_events_calendar_id FOREIGN KEY (calendar_id)
|
||||
REFERENCES calendars(calendar_id)
|
||||
);
|
||||
|
|
|
@ -233,6 +233,17 @@ class kolab_driver extends calendar_driver
|
|||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Feedback after showing/sending an alarm notification
|
||||
*
|
||||
* @see Driver:confirm_alarm()
|
||||
*/
|
||||
public function confirm_alarm($event_id, $snooze = 0)
|
||||
{
|
||||
// TBD.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save an attachment related to the given event
|
||||
*/
|
||||
|
|
Loading…
Add table
Reference in a new issue