From 5f06d62ceb982291019a3b3cca47dc2a20e8b836 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Wed, 9 Jan 2013 11:12:19 +0100 Subject: [PATCH 1/2] Fix recurring event handling when first instance is modified and excluded (#1505) --- .../calendar/drivers/kolab/kolab_calendar.php | 26 ++++++++++++++++--- .../calendar/drivers/kolab/kolab_driver.php | 23 ++++++++++++---- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php index 0a3d273e..5200cffd 100644 --- a/plugins/calendar/drivers/kolab/kolab_calendar.php +++ b/plugins/calendar/drivers/kolab/kolab_calendar.php @@ -248,7 +248,21 @@ class kolab_calendar // list events in requested time window if ($event['start'] <= $end && $event['end'] >= $start) { unset($event['_attendees']); - $events[] = $event; + $add = true; + + // skip the first instance of a recurring event if listed in exdate + if ($virtual && !empty($event['recurrence']['EXDATE'])) { + $event_date = $event['start']->format('Ymd'); + foreach ($event['recurrence']['EXDATE'] as $exdate) { + if ($exdate->format('Ymd') == $event_date) { + $add = false; + break; + } + } + } + + if ($add) + $events[] = $event; } // resolve recurring events @@ -409,9 +423,9 @@ class kolab_calendar else if ($next_event['start'] > $end) // stop loop if out of range break; - // avoid endless recursion loops - if ($i > 1000) - break; + // avoid endless recursion loops + if ($i > 1000) + break; } return $events; @@ -458,6 +472,10 @@ class kolab_calendar if (is_array($record['categories'])) $record['categories'] = $record['categories'][0]; + // remove empty recurrence array + if (empty($record['recurrence'])) + unset($record['recurrence']); + // remove internals unset($record['_mailbox'], $record['_msguid'], $record['_formatobj'], $record['_attachments']); diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php index 0d913a36..fe6f3ada 100644 --- a/plugins/calendar/drivers/kolab/kolab_driver.php +++ b/plugins/calendar/drivers/kolab/kolab_driver.php @@ -406,10 +406,10 @@ class kolab_driver extends calendar_driver public function remove_event($event, $force = true) { $success = false; - $_savemode = $event['_savemode']; + $savemode = $event['_savemode']; if (($storage = $this->calendars[$event['calendar']]) && ($event = $storage->get_event($event['id']))) { - $event['_savemode'] = $_savemode; + $event['_savemode'] = $savemode; $savemode = 'all'; $master = $event; @@ -424,7 +424,7 @@ class kolab_driver extends calendar_driver switch ($savemode) { case 'current': $_SESSION['calendar_restore_event_data'] = $master; - + // removing the first instance => just move to next occurence if ($master['id'] == $event['id']) { $limit = clone $event['end']; @@ -584,13 +584,26 @@ class kolab_driver extends calendar_driver break; case 'current': - // add exception to master event - $master['recurrence']['EXDATE'][] = $old['start']; + // modifying the first instance => just move to next occurence + if ($master['id'] == $event['id']) { + $limit = clone $old['end']; + $limit->add(new DateInterval('P370D')); + $recurring = reset($storage->_get_recurring_events($event, $event['start'], $limit, $event['id'].'-1')); + $master['start'] = $recurring['start']; + $master['end'] = $recurring['end']; + if ($master['recurrence']['COUNT']) + $master['recurrence']['COUNT']--; + } + else { // add exception to master event + $master['recurrence']['EXDATE'][] = $old['start']; + } + $storage->update_event($master); // insert new event for this occurence $event += $old; $event['recurrence'] = array(); + unset($event['recurrence_id']); $event['uid'] = $this->cal->generate_uid(); $success = $storage->insert_event($event); break; From 8d3f1803cc75dae08900e9c752c873514641ffb5 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Wed, 9 Jan 2013 11:49:12 +0100 Subject: [PATCH 2/2] Fix modification of recurring events (#1499) --- .../drivers/database/database_driver.php | 4 +-- .../calendar/drivers/kolab/kolab_calendar.php | 25 ++++++++++++++++--- .../calendar/drivers/kolab/kolab_driver.php | 12 +++------ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/plugins/calendar/drivers/database/database_driver.php b/plugins/calendar/drivers/database/database_driver.php index d6a44830..5a518f7e 100644 --- a/plugins/calendar/drivers/database/database_driver.php +++ b/plugins/calendar/drivers/database/database_driver.php @@ -363,11 +363,11 @@ class database_driver extends calendar_driver // use start date from master but try to be smart on time or duration changes $old_start_date = $old['start']->format('Y-m-d'); - $old_start_time = $old['start']->format('H:i'); + $old_start_time = $old['allday'] ? '' : $old['start']->format('H:i'); $old_duration = $old['end']->format('U') - $old['start']->format('U'); $new_start_date = $event['start']->format('Y-m-d'); - $new_start_time = $event['start']->format('H:i'); + $new_start_time = $event['allday'] ? '' : $event['start']->format('H:i'); $new_duration = $event['end']->format('U') - $event['start']->format('U'); $diff = $old_start_date != $new_start_date || $old_start_time != $new_start_time || $old_duration != $new_duration; diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php index 5200cffd..f2c106e1 100644 --- a/plugins/calendar/drivers/kolab/kolab_calendar.php +++ b/plugins/calendar/drivers/kolab/kolab_calendar.php @@ -181,9 +181,7 @@ class kolab_calendar $this->events[$master_id] = $this->_to_rcube_event($record); if (($master = $this->events[$master_id]) && $master['recurrence']) { - $limit = clone $master['start']; - $limit->add(new DateInterval('P10Y')); - $this->_get_recurring_events($record, $master['start'], $limit, $id); + $this->_get_recurring_events($record, $master['start'], null, $id); } } @@ -386,8 +384,14 @@ class kolab_calendar /** * Create instances of a recurring event + * + * @param array Hash array with event properties + * @param object DateTime Start date of the recurrence window + * @param object DateTime End date of the recurrence window + * @param string ID of a specific recurring event instance + * @return array List of recurring event instances */ - public function _get_recurring_events($event, $start, $end, $event_id = null) + public function _get_recurring_events($event, $start, $end = null, $event_id = null) { $object = $event['_formatobj']; if (!$object) { @@ -397,6 +401,19 @@ class kolab_calendar if (!is_object($object)) return array(); + // determine a reasonable end date if none given + if (!$end) { + switch ($event['recurrence']['FREQ']) { + case 'YEARLY': $intvl = 'P100Y'; break; + case 'MONTHLY': $intvl = 'P20Y'; break; + default: $intvl = 'P10Y'; break; + } + + $end = clone $event['start']; + $end->add(new DateInterval($intvl)); + } + + // use libkolab to compute recurring events $recurrence = new kolab_date_recurrence($object); $i = 0; diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php index fe6f3ada..58548400 100644 --- a/plugins/calendar/drivers/kolab/kolab_driver.php +++ b/plugins/calendar/drivers/kolab/kolab_driver.php @@ -427,9 +427,7 @@ class kolab_driver extends calendar_driver // removing the first instance => just move to next occurence if ($master['id'] == $event['id']) { - $limit = clone $event['end']; - $limit->add(new DateInterval('P370D')); - $recurring = reset($storage->_get_recurring_events($event, $event['start'], $limit, $event['id'].'-1')); + $recurring = reset($storage->_get_recurring_events($event, $event['start'], null, $event['id'].'-1')); $master['start'] = $recurring['start']; $master['end'] = $recurring['end']; if ($master['recurrence']['COUNT']) @@ -586,9 +584,7 @@ class kolab_driver extends calendar_driver case 'current': // modifying the first instance => just move to next occurence if ($master['id'] == $event['id']) { - $limit = clone $old['end']; - $limit->add(new DateInterval('P370D')); - $recurring = reset($storage->_get_recurring_events($event, $event['start'], $limit, $event['id'].'-1')); + $recurring = reset($storage->_get_recurring_events($event, $event['start'], null, $event['id'].'-1')); $master['start'] = $recurring['start']; $master['end'] = $recurring['end']; if ($master['recurrence']['COUNT']) @@ -641,11 +637,11 @@ class kolab_driver extends calendar_driver // use start date from master but try to be smart on time or duration changes $old_start_date = $old['start']->format('Y-m-d'); - $old_start_time = $old['start']->format('H:i'); + $old_start_time = $old['allday'] ? '' : $old['start']->format('H:i'); $old_duration = $old['end']->format('U') - $old['start']->format('U'); $new_start_date = $event['start']->format('Y-m-d'); - $new_start_time = $event['start']->format('H:i'); + $new_start_time = $event['allday'] ? '' : $event['start']->format('H:i'); $new_duration = $event['end']->format('U') - $event['start']->format('U'); $diff = $old_start_date != $new_start_date || $old_start_time != $new_start_time || $old_duration != $new_duration;