Branch 'dev/recurrence-exceptions' - plugins/calendar plugins/libkolab
Thomas Brüderli
bruederli at kolabsys.com
Thu Feb 14 16:17:38 CET 2013
plugins/calendar/calendar_ui.js | 3
plugins/calendar/drivers/kolab/kolab_calendar.php | 76 ++++++++++++++++------
plugins/calendar/drivers/kolab/kolab_driver.php | 53 +++++----------
plugins/libkolab/lib/kolab_format_event.php | 27 ++-----
4 files changed, 88 insertions(+), 71 deletions(-)
New commits:
commit 36bbcc6499f8ead8b5dee0d29060a2c0dc627566
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Thu Feb 14 16:17:02 2013 +0100
Make this-and-future recurrence exceptions work
diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js
index 24d7bd6..f4c7749 100644
--- a/plugins/calendar/calendar_ui.js
+++ b/plugins/calendar/calendar_ui.js
@@ -507,8 +507,9 @@ function rcube_calendar_ui(settings)
// show warning if editing a recurring event
if (event.id && event.recurrence) {
+ var sel = event.thisandfuture ? 'future' : 'all';
$('#edit-recurring-warning').show();
- $('input.edit-recurring-savemode[value="all"]').prop('checked', true);
+ $('input.edit-recurring-savemode[value="'+sel+'"]').prop('checked', true);
}
else
$('#edit-recurring-warning').hide();
diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php
index 53c47ad..764f619 100644
--- a/plugins/calendar/drivers/kolab/kolab_calendar.php
+++ b/plugins/calendar/drivers/kolab/kolab_calendar.php
@@ -422,23 +422,33 @@ class kolab_calendar
$i = 0;
$events = array();
$exdates = array();
+ $futuredata = array();
if (is_array($event['recurrence']['EXCEPTIONS'])) {
- foreach ($event['recurrence']['EXCEPTIONS'] as $exception) {
- $rec_event = $this->_to_rcube_event($exception);
- $rec_event['id'] = $event['uid'] . '-' . ++$i;
- $rec_event['recurrence_id'] = $event['uid'];
- $rec_event['_instance'] = $i;
- $events[] = $rec_event;
-
- // found the specifically requested instance, exiting...
- if ($rec_event['id'] == $event_id) {
- $this->events[$rec_event['id']] = $rec_event;
- return $events;
- }
+ // copy the recurrence rule from the master event (to be used in the UI)
+ $recurrence_rule = $event['recurrence'];
+ unset($recurrence_rule['EXCEPTIONS'], $recurrence_rule['EXDATE']);
+
+ foreach ($event['recurrence']['EXCEPTIONS'] as $exception) {
+ $rec_event = $this->_to_rcube_event($exception);
+ $rec_event['id'] = $event['uid'] . '-' . ++$i;
+ $rec_event['recurrence_id'] = $event['uid'];
+ $rec_event['recurrence'] = $recurrence_rule;
+ $rec_event['_instance'] = $i;
+ $events[] = $rec_event;
- // remember this exception's date
- $exdates[$rec_event['start']->format('Y-m-d')] = $rec_event['id'];
+ // found the specifically requested instance, exiting...
+ if ($rec_event['id'] == $event_id) {
+ $this->events[$rec_event['id']] = $rec_event;
+ return $events;
}
+
+ // remember this exception's date
+ $exdate = $rec_event['start']->format('Y-m-d');
+ $exdates[$exdate] = $rec_event['id'];
+ if ($rec_event['thisandfuture']) {
+ $futuredata[$exdate] = $rec_event;
+ }
+ }
}
// use libkolab to compute recurring events
@@ -446,20 +456,29 @@ class kolab_calendar
$recurrence = new kolab_date_recurrence($object);
}
else {
- // fallback to local recurrence implementation
- require_once($this->cal->home . '/lib/calendar_recurrence.php');
- $recurrence = new calendar_recurrence($this->cal, $event);
+ // fallback to local recurrence implementation
+ require_once($this->cal->home . '/lib/calendar_recurrence.php');
+ $recurrence = new calendar_recurrence($this->cal, $event);
}
while ($next_event = $recurrence->next_instance()) {
// skip if there's an exception at this date
- if ($exdates[$next_event['start']->format('Y-m-d')])
+ $datestr = $next_event['start']->format('Y-m-d');
+ if ($exdates[$datestr]) {
+ // use this event data for future recurring instances
+ if ($futuredata[$datestr])
+ $overlay_data = $futuredata[$datestr];
continue;
+ }
// add to output if in range
$rec_id = $event['uid'] . '-' . ++$i;
if (($next_event['start'] <= $end && $next_event['end'] >= $start) || ($event_id && $rec_id == $event_id)) {
$rec_event = $this->_to_rcube_event($next_event);
+
+ if ($overlay_data) // copy data from a 'this-and-future' exception
+ $this->_merge_event_data($rec_event, $overlay_data);
+
$rec_event['id'] = $rec_id;
$rec_event['recurrence_id'] = $event['uid'];
$rec_event['_instance'] = $i;
@@ -483,6 +502,27 @@ class kolab_calendar
}
/**
+ * Merge certain properties from the overlay event to the base event object
+ *
+ * @param array The event object to be altered
+ * @param array The overlay event object to be merged over $event
+ */
+ private function _merge_event_data(&$event, $overlay)
+ {
+ static $forbidden = array('id','uid','created','changed','recurrence','organizer','attendees','sequence');
+
+ foreach ($overlay as $prop => $value) {
+ // adjust time of the recurring event instance
+ if ($prop == 'start' || $prop == 'end') {
+ if (is_object($event[$prop]) && is_a($event[$prop], 'DateTime'))
+ $event[$prop]->setTime($value->format('G'), intval($value->format('i')), intval($value->format('s')));
+ }
+ else if ($prop[0] != '_' && !in_array($prop, $forbidden))
+ $event[$prop] = $value;
+ }
+ }
+
+ /**
* Convert from Kolab_Format to internal representation
*/
private function _to_rcube_event($record)
diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php
index 869837f..bd4a855 100644
--- a/plugins/calendar/drivers/kolab/kolab_driver.php
+++ b/plugins/calendar/drivers/kolab/kolab_driver.php
@@ -421,6 +421,14 @@ class kolab_driver extends calendar_driver
$savemode = $event['_savemode'];
}
+ // removing an exception instance
+ if ($event['recurrence_id']) {
+ $i = $event['_instance'] - 1;
+ if (!empty($master['recurrence']['EXCEPTIONS'][$i])) {
+ unset($master['recurrence']['EXCEPTIONS'][$i]);
+ }
+ }
+
switch ($savemode) {
case 'current':
$_SESSION['calendar_restore_event_data'] = $master;
@@ -582,43 +590,12 @@ class kolab_driver extends calendar_driver
$success = $storage->insert_event($event);
break;
-
+
+ case 'future':
case 'current':
- // save as exception to master event
+ // recurring instances shall not store recurrence rules
$event['recurrence'] = array();
- $master['recurrence']['EXCEPTIONS'][] = $event;
-# $master['recurrence']['EXDATE'][] = $event['start'];
- $success = $storage->update_event($master);
- break;
-
- case 'future':
- if ($master['id'] != $event['id']) {
- // set until-date on master event
- $master['recurrence']['UNTIL'] = clone $old['start'];
- $master['recurrence']['UNTIL']->sub(new DateInterval('P1D'));
- unset($master['recurrence']['COUNT']);
- $storage->update_event($master);
-
- // save this instance as new recurring event
- $event += $old;
- $event['uid'] = $this->cal->generate_uid();
-
- // if recurrence COUNT, update value to the correct number of future occurences
- if ($event['recurrence']['COUNT']) {
- $event['recurrence']['COUNT'] -= $old['_instance'];
- }
-
- // remove fixed weekday, will be re-set to the new weekday in kolab_calendar::insert_event()
- if (strlen($event['recurrence']['BYDAY']) == 2)
- unset($event['recurrence']['BYDAY']);
- if ($master['recurrence']['BYMONTH'] == $master['start']->format('n'))
- unset($event['recurrence']['BYMONTH']);
-
- $success = $storage->insert_event($event);
- break;
- }
-
- default: // 'all' is default
+ $event['thisandfuture'] = $savemode == 'future';
// save properties to a recurrence exception instance
if ($old['recurrence_id']) {
@@ -630,6 +607,12 @@ class kolab_driver extends calendar_driver
}
}
+ // save as new exception to master event
+ $master['recurrence']['EXCEPTIONS'][] = $event;
+ $success = $storage->update_event($master);
+ break;
+
+ default: // 'all' is default
$event['id'] = $master['id'];
$event['uid'] = $master['uid'];
diff --git a/plugins/libkolab/lib/kolab_format_event.php b/plugins/libkolab/lib/kolab_format_event.php
index 7efd06d..4e2cccc 100644
--- a/plugins/libkolab/lib/kolab_format_event.php
+++ b/plugins/libkolab/lib/kolab_format_event.php
@@ -109,7 +109,7 @@ class kolab_format_event extends kolab_format_xcal
foreach((array)$object['recurrence']['EXCEPTIONS'] as $exception) {
$exevent = new kolab_format_event;
$exevent->set($this->compact_exception($exception, $object)); // only save differing values
- $exevent->obj->setRecurrenceID(self::get_datetime($exception['start'], null, true), false);
+ $exevent->obj->setRecurrenceID(self::get_datetime($exception['start'], null, true), (bool)$exception['thisandfuture']);
$vexceptions->push($exevent->obj);
}
$this->obj->setExceptions($vexceptions);
@@ -186,7 +186,7 @@ class kolab_format_event extends kolab_format_xcal
}
// read exception event objects
- if ($exceptions = $this->obj->exceptions()) {
+ if (($exceptions = $this->obj->exceptions()) && $exceptions->size()) {
for ($i=0; $i < $exceptions->size(); $i++) {
if (($exobj = $exceptions->get($i))) {
$exception = new kolab_format_event($exobj);
@@ -196,6 +196,10 @@ class kolab_format_event extends kolab_format_xcal
}
}
}
+ // this is an exception object
+ else if ($this->obj->recurrenceID()->isValid()) {
+ $object['thisandfuture'] = $this->obj->thisAndFuture();
+ }
// merge with additional data, e.g. attachments from the message
if ($data) {
@@ -233,24 +237,15 @@ class kolab_format_event extends kolab_format_xcal
}
/**
- * Reduce the exception container to attributes which differ from the master event
+ * Remove some attributes from the exception container
*/
private function compact_exception($exception, $master)
{
- static $mandatory = array('uid','created','start');
- static $forbidden = array('recurrence','attendees','sequence');
+ static $forbidden = array('recurrence','organizer','attendees','sequence');
$out = $exception;
foreach ($exception as $prop => $val) {
- if (in_array($prop, $mandatory))
- continue;
-
- if (is_object($exception[$prop]) && is_a($exception[$prop], 'DateTime'))
- $equals = $exception[$prop] <> $master[$prop];
- else
- $equals = $exception[$prop] == $master[$prop];
-
- if ($equals || in_array($prop, $forbidden)) {
+ if (in_array($prop, $forbidden)) {
unset($out[$prop]);
}
}
@@ -263,10 +258,8 @@ class kolab_format_event extends kolab_format_xcal
*/
private function expand_exception($exception, $master)
{
- static $forbidden = array('recurrence');
-
foreach ($master as $prop => $value) {
- if (empty($exception[$prop]) && !in_array($prop, $forbidden))
+ if (empty($exception[$prop]) && !empty($value))
$exception[$prop] = $value;
}
More information about the commits
mailing list