Refactor identification of recurring event instances (#4722):
- All instances of a recurring series have -YmdTHis appended to their ID - In 'all' savemode, the master event identified by UID is loaded and updated - kolab_driver::update_event() returns the UID of the master event in 'all' mode. This is then used to send iTip messages for the entire series
This commit is contained in:
parent
414a571af0
commit
94260b2aeb
3 changed files with 127 additions and 112 deletions
|
@ -1175,9 +1175,13 @@ class calendar extends rcube_plugin
|
|||
$event['attendees'] = $master['attendees']; // this tricks us into the next if clause
|
||||
}
|
||||
|
||||
// delete old reference if saved as new
|
||||
if ($event['_savemode'] == 'future' || $event['_savemode'] == 'new') {
|
||||
$old = null;
|
||||
}
|
||||
|
||||
$event['id'] = $success;
|
||||
$event['_savemode'] = 'all';
|
||||
$old = null;
|
||||
}
|
||||
|
||||
// send out notifications
|
||||
|
@ -1566,6 +1570,9 @@ class calendar extends rcube_plugin
|
|||
$filename = asciiwords(html_entity_decode($filename)); // to 7bit ascii
|
||||
if (!empty($event_id)) {
|
||||
if ($event = $this->driver->get_event(array('calendar' => $calid, 'id' => $event_id))) {
|
||||
if ($event['recurrence_id']) {
|
||||
$event = $this->driver->get_event(array('calendar' => $calid, 'id' => $event['recurrence_id']));
|
||||
}
|
||||
$events = array($event);
|
||||
$filename = asciiwords($event['title']);
|
||||
if (empty($filename))
|
||||
|
@ -2276,9 +2283,9 @@ class calendar extends rcube_plugin
|
|||
public static function event_diff($a, $b)
|
||||
{
|
||||
$diff = array();
|
||||
$ignore = array('changed' => 1, 'attachments' => 1, '_notify' => 1, '_owner' => 1, '_savemode' => 1);
|
||||
$ignore = array('changed' => 1, 'attachments' => 1);
|
||||
foreach (array_unique(array_merge(array_keys($a), array_keys($b))) as $key) {
|
||||
if (!$ignore[$key] && $a[$key] != $b[$key])
|
||||
if (!$ignore[$key] && $key[0] != '_' && $a[$key] != $b[$key])
|
||||
$diff[] = $key;
|
||||
}
|
||||
|
||||
|
|
|
@ -187,7 +187,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
{
|
||||
// directly access storage object
|
||||
if (!$this->events[$id] && ($record = $this->storage->get_object($id)))
|
||||
$this->events[$id] = $this->_to_rcube_event($record);
|
||||
$this->events[$id] = $this->_to_driver_event($record, true);
|
||||
|
||||
// event not found, maybe a recurring instance is requested
|
||||
if (!$this->events[$id]) {
|
||||
|
@ -195,17 +195,16 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
$instance_id = substr($id, strlen($master_id) + 1);
|
||||
|
||||
if ($master_id != $id && ($record = $this->storage->get_object($master_id))) {
|
||||
$master = $this->events[$master_id] = $this->_to_rcube_event($record);
|
||||
$master = $this->_to_driver_event($record);
|
||||
}
|
||||
|
||||
// check for match on the first instance already
|
||||
if ($master['_instance'] && $master['_instance'] == $instance_id) {
|
||||
$this->events[$id] = $this->events[$master_id];
|
||||
$this->events[$id] = $master;
|
||||
}
|
||||
// check for match in top-level exceptions (aka loose single occurrences)
|
||||
else if ($master && $master['_formatobj'] && ($instance = $master['_formatobj']->get_instance($instance_id))) {
|
||||
$instance = $this->_to_rcube_event($instance);
|
||||
$this->events[$instance['id']] = $instance;
|
||||
$this->events[$id] = $this->_to_driver_event($instance);
|
||||
}
|
||||
else if ($master && is_array($master['recurrence'])) {
|
||||
$this->get_recurring_events($record, $master['start'], null, $id);
|
||||
|
@ -294,12 +293,13 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
|
||||
$events = array();
|
||||
foreach ($this->storage->select($query) as $record) {
|
||||
$event = $this->_to_rcube_event($record);
|
||||
$this->events[$event['id']] = $event;
|
||||
$event = $this->_to_driver_event($record, !$virtual);
|
||||
|
||||
// remember seen categories
|
||||
if ($event['categories'])
|
||||
$this->categories[$event['categories']]++;
|
||||
if ($event['categories']) {
|
||||
$cat = is_array($event['categories']) ? $event['categories'][0] : $event['categories'];
|
||||
$this->categories[$cat]++;
|
||||
}
|
||||
|
||||
// list events in requested time window
|
||||
if ($event['start'] <= $end && $event['end'] >= $start) {
|
||||
|
@ -321,11 +321,11 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
|
||||
// find and merge exception for the first instance
|
||||
if ($virtual && !empty($event['recurrence']) && is_array($event['recurrence']['EXCEPTIONS'])) {
|
||||
$event_date = $event['start']->format('Ymd');
|
||||
foreach ($event['recurrence']['EXCEPTIONS'] as $exception) {
|
||||
$exdate = $exception['recurrence_date'] ? $exception['recurrence_date']->format('Ymd') : substr($exception['_instance'], 0, 8);
|
||||
if ($exdate == $event_date) {
|
||||
$event['_instance'] = $exception['_instance'];
|
||||
if ($event['_instance'] == $exception['_instance']) {
|
||||
// clone date objects from main event before adjusting them with exception data
|
||||
if (is_object($event['start'])) $event['start'] = clone $record['start'];
|
||||
if (is_object($event['end'])) $event['end'] = clone $record['end'];
|
||||
kolab_driver::merge_exception_data($event, $exception);
|
||||
}
|
||||
}
|
||||
|
@ -342,7 +342,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
// add top-level exceptions (aka loose single occurrences)
|
||||
else if (is_array($record['exceptions'])) {
|
||||
foreach ($record['exceptions'] as $ex) {
|
||||
$component = $this->_to_rcube_event($ex);
|
||||
$component = $this->_to_driver_event($ex);
|
||||
if ($component['start'] <= $end && $component['end'] >= $start) {
|
||||
$events[] = $component;
|
||||
}
|
||||
|
@ -445,7 +445,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
unset($event['links']);
|
||||
|
||||
//generate new event from RC input
|
||||
$object = $this->_from_rcube_event($event);
|
||||
$object = $this->_from_driver_event($event);
|
||||
$saved = $this->storage->save($object, 'event');
|
||||
|
||||
if (!$saved) {
|
||||
|
@ -460,8 +460,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
// save links in configuration.relation object
|
||||
$this->save_links($event['uid'], $links);
|
||||
|
||||
$event['id'] = $event['uid'];
|
||||
$this->events = array($event['uid'] => $this->_to_rcube_event($object));
|
||||
$this->events = array($event['uid'] => $this->_to_driver_event($object, true));
|
||||
}
|
||||
|
||||
return $saved;
|
||||
|
@ -485,7 +484,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
$links = $event['links'];
|
||||
unset($event['links']);
|
||||
|
||||
$object = $this->_from_rcube_event($event, $old);
|
||||
$object = $this->_from_driver_event($event, $old);
|
||||
$saved = $this->storage->save($object, 'event', $old['uid']);
|
||||
|
||||
if (!$saved) {
|
||||
|
@ -500,7 +499,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
$this->save_links($event['uid'], $links);
|
||||
|
||||
$updated = true;
|
||||
$this->events = array($event['id'] => $this->_to_rcube_event($object));
|
||||
$this->events = array($event['uid'] => $this->_to_driver_event($object, true));
|
||||
|
||||
// refresh local cache with recurring instances
|
||||
if ($exception_id) {
|
||||
|
@ -626,7 +625,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
else if (!$exception['_instance'] && is_a($exception['start'], 'DateTime'))
|
||||
$exception['_instance'] = $exception['start']->format($recurrence_id_format);
|
||||
|
||||
$rec_event = $this->_to_rcube_event($exception);
|
||||
$rec_event = $this->_to_driver_event($exception);
|
||||
$rec_event['id'] = $event['uid'] . '-' . $exception['_instance'];
|
||||
$rec_event['isexception'] = 1;
|
||||
|
||||
|
@ -675,7 +674,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
// add to output if in range
|
||||
$rec_id = $event['uid'] . '-' . $instance_id;
|
||||
if (($next_event['start'] <= $end && $next_event['end'] >= $start) || ($event_id && $rec_id == $event_id)) {
|
||||
$rec_event = $this->_to_rcube_event($next_event);
|
||||
$rec_event = $this->_to_driver_event($next_event);
|
||||
$rec_event['_instance'] = $instance_id;
|
||||
$rec_event['_count'] = $i + 1;
|
||||
|
||||
|
@ -707,7 +706,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
/**
|
||||
* Convert from Kolab_Format to internal representation
|
||||
*/
|
||||
private function _to_rcube_event($record)
|
||||
private function _to_driver_event($record, $noinst = false)
|
||||
{
|
||||
$record['calendar'] = $this->id;
|
||||
$record['links'] = $this->get_links($record['uid']);
|
||||
|
@ -717,17 +716,31 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
$record = kolab_driver::add_partstat_class($record, array('NEEDS-ACTION','DECLINED'), $this->get_owner());
|
||||
}
|
||||
|
||||
return kolab_driver::to_rcube_event($record);
|
||||
// add instance identifier to first occurrence (master event)
|
||||
$recurrence_id_format = $record['allday'] ? 'Ymd' : 'Ymd\THis';
|
||||
if (!$noinst && $record['recurrence'] && !$record['recurrence_id'] && !$record['_instance']) {
|
||||
$record['_instance'] = $record['start']->format($recurrence_id_format);
|
||||
}
|
||||
else if (is_a($record['recurrence_date'], 'DateTime')) {
|
||||
$record['_instance'] = $record['recurrence_date']->format($recurrence_id_format);
|
||||
}
|
||||
|
||||
// clean up exception data
|
||||
if ($record['recurrence'] && is_array($record['recurrence']['EXCEPTIONS'])) {
|
||||
array_walk($record['recurrence']['EXCEPTIONS'], function(&$exception) {
|
||||
unset($exception['_mailbox'], $exception['_msguid'], $exception['_formatobj'], $exception['_attachments']);
|
||||
});
|
||||
}
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given event record into a data structure that can be passed to Kolab_Storage backend for saving
|
||||
* (opposite of self::_to_rcube_event())
|
||||
* (opposite of self::_to_driver_event())
|
||||
*/
|
||||
private function _from_rcube_event($event, $old = array())
|
||||
private function _from_driver_event($event, $old = array())
|
||||
{
|
||||
$event = kolab_driver::from_rcube_event($event, $old);
|
||||
|
||||
// set current user as ORGANIZER
|
||||
$identity = $this->cal->rc->user->list_emails(true);
|
||||
if (empty($event['attendees']) && $identity['email'])
|
||||
|
@ -750,8 +763,18 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
$event['comment'] = $old['comment'];
|
||||
}
|
||||
|
||||
// clean up exception data
|
||||
if (is_array($event['exceptions'])) {
|
||||
array_walk($event['exceptions'], function(&$exception) {
|
||||
unset($exception['_mailbox'], $exception['_msguid'], $exception['_formatobj'], $exception['_attachments'],
|
||||
$event['attachments'], $event['deleted_attachments'], $event['recurrence_id']);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// remove some internal properties which should not be saved
|
||||
unset($event['_savemode'], $event['_fromcalendar'], $event['_identity'], $event['_folder_id'], $event['className']);
|
||||
unset($event['_savemode'], $event['_fromcalendar'], $event['_identity'], $event['_folder_id'],
|
||||
$event['recurrence_id'], $event['attachments'], $event['deleted_attachments'], $event['className']);
|
||||
|
||||
// copy meta data (starting with _) from old object
|
||||
foreach ((array)$old as $key => $val) {
|
||||
|
|
|
@ -549,9 +549,7 @@ class kolab_driver extends calendar_driver
|
|||
if ($cal) {
|
||||
if ($storage = $this->get_calendar($cal)) {
|
||||
$result = $storage->get_event($id);
|
||||
if (is_array($result))
|
||||
self::clean_rcube_event_out($result);
|
||||
return $result;
|
||||
return self::to_rcube_event($result);
|
||||
}
|
||||
// get event from the address books birthday calendar
|
||||
else if ($cal == self::BIRTHDAY_CALENDAR_ID) {
|
||||
|
@ -562,8 +560,7 @@ class kolab_driver extends calendar_driver
|
|||
else {
|
||||
foreach ($this->filter_calendars($writeable, $active, $personal) as $calendar) {
|
||||
if ($result = $calendar->get_event($id)) {
|
||||
self::clean_rcube_event_out($result);
|
||||
return $result;
|
||||
return self::to_rcube_event($result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -581,10 +578,12 @@ class kolab_driver extends calendar_driver
|
|||
if (!$this->validate($event))
|
||||
return false;
|
||||
|
||||
$event = self::from_rcube_event($event);
|
||||
|
||||
$cid = $event['calendar'] ? $event['calendar'] : reset(array_keys($this->calendars));
|
||||
if ($storage = $this->get_calendar($cid)) {
|
||||
// if this is a recurrence instance, append as exception to an already existing object for this UID
|
||||
if (!empty($event['recurrence_date']) && ($master = $this->get_event($event['uid']))) {
|
||||
if (!empty($event['recurrence_date']) && ($master = $storage->get_event($event['uid']))) {
|
||||
self::add_exception($master, $event);
|
||||
$success = $storage->update_event($master);
|
||||
}
|
||||
|
@ -611,7 +610,10 @@ class kolab_driver extends calendar_driver
|
|||
*/
|
||||
public function edit_event($event)
|
||||
{
|
||||
return $this->update_event($event);
|
||||
if (!($storage = $this->get_calendar($event['calendar'])))
|
||||
return false;
|
||||
|
||||
return $this->update_event(self::from_rcube_event($event, $storage->get_event($event['id'])));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -630,12 +632,16 @@ class kolab_driver extends calendar_driver
|
|||
if ($storage = $this->get_calendar($event['calendar'])) {
|
||||
$update_event = $storage->get_event($event['recurrence_id']);
|
||||
$update_event['_savemode'] = $event['_savemode'];
|
||||
$update_event['id'] = $update_event['uid'];
|
||||
unset($update_event['recurrence_id']);
|
||||
self::merge_attendee_data($update_event, $attendees);
|
||||
}
|
||||
}
|
||||
|
||||
if (($ret = $this->update_attendees($update_event, $attendees)) && $this->rc->config->get('kolab_invitation_calendars')) {
|
||||
// replace with master event (for iTip reply)
|
||||
$event = self::to_rcube_event($update_event);
|
||||
|
||||
// re-assign to the according (virtual) calendar
|
||||
if (strtoupper($status) == 'DECLINED')
|
||||
$event['calendar'] = self::INVITATIONS_CALENDAR_DECLINED;
|
||||
|
@ -668,7 +674,7 @@ class kolab_driver extends calendar_driver
|
|||
$saved = false;
|
||||
foreach ($master['recurrence']['EXCEPTIONS'] as $i => $exception) {
|
||||
// merge the new event properties onto future exceptions
|
||||
if ($exception['_instance'] >= $event['_instance']) {
|
||||
if ($exception['_instance'] >= strval($event['_instance'])) {
|
||||
self::merge_attendee_data($master['recurrence']['EXCEPTIONS'][$i], $attendees);
|
||||
}
|
||||
// update a specific instance
|
||||
|
@ -741,7 +747,7 @@ class kolab_driver extends calendar_driver
|
|||
{
|
||||
$success = false;
|
||||
$savemode = $event['_savemode'];
|
||||
$decline = $event['decline'];
|
||||
$decline = $event['_decline'];
|
||||
|
||||
if (($storage = $this->get_calendar($event['calendar'])) && ($event = $storage->get_event($event['id']))) {
|
||||
$event['_savemode'] = $savemode;
|
||||
|
@ -752,7 +758,7 @@ class kolab_driver extends calendar_driver
|
|||
|
||||
// read master if deleting a recurring event
|
||||
if ($event['recurrence'] || $event['recurrence_id'] || $event['isexception']) {
|
||||
$master = $event['recurrence_id'] || $event['isexception'] ? $storage->get_event($event['uid']) : $event;
|
||||
$master = $storage->get_event($event['uid']);
|
||||
$savemode = $event['_savemode'] ?: ($event['_instance'] || $event['isexception'] ? 'current' : 'all');
|
||||
|
||||
// force 'current' mode for single occurrences stored as exception
|
||||
|
@ -768,7 +774,6 @@ class kolab_driver extends calendar_driver
|
|||
// set event date back to the actual occurrence
|
||||
if ($exception['recurrence_date'])
|
||||
$event['start'] = $exception['recurrence_date'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -782,7 +787,8 @@ class kolab_driver extends calendar_driver
|
|||
$_SESSION['calendar_restore_event_data'] = $master;
|
||||
|
||||
// removing the first instance => just move to next occurence
|
||||
if ($master['id'] == $event['id'] && $master['recurrence']) {
|
||||
$recurrence_id_format = $master['allday'] ? 'Ymd' : 'Ymd\THis';
|
||||
if ($master['recurrence'] && $event['_instance'] == $master['start']->format($recurrence_id_format)) {
|
||||
$recurring = reset($storage->get_recurring_events($event, $event['start'], null, $event['id'].'-1'));
|
||||
|
||||
// no future instances found: delete the master event (bug #1677)
|
||||
|
@ -840,7 +846,7 @@ class kolab_driver extends calendar_driver
|
|||
|
||||
default: // 'all' is default
|
||||
// removing the master event with loose exceptions (not recurring though)
|
||||
if (!empty($event['recurrence_date']) && !empty($master['exceptions'])) {
|
||||
if (!empty($event['recurrence_date']) && empty($master['recurrence']) && !empty($master['exceptions'])) {
|
||||
// make the first exception the new master
|
||||
$newmaster = array_shift($master['exceptions']);
|
||||
$newmaster['exceptions'] = $master['exceptions'];
|
||||
|
@ -906,9 +912,12 @@ class kolab_driver extends calendar_driver
|
|||
if (!($fromcalendar = $this->get_calendar($event['_fromcalendar'])))
|
||||
return false;
|
||||
|
||||
$old = $fromcalendar->get_event($event['id']);
|
||||
|
||||
if ($event['_savemode'] != 'new') {
|
||||
if (!$fromcalendar->storage->move($event['id'], $storage->storage))
|
||||
if (!$fromcalendar->storage->move($old['uid'], $storage->storage)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$fromcalendar = $storage;
|
||||
}
|
||||
|
@ -919,7 +928,7 @@ class kolab_driver extends calendar_driver
|
|||
$success = false;
|
||||
$savemode = 'all';
|
||||
$attachments = array();
|
||||
$old = $master = $fromcalendar->get_event($event['id']);
|
||||
$old = $master = $storage->get_event($event['id']);
|
||||
|
||||
if (!$old || !$old['start']) {
|
||||
rcube::raise_error(array(
|
||||
|
@ -930,45 +939,14 @@ class kolab_driver extends calendar_driver
|
|||
return false;
|
||||
}
|
||||
|
||||
// delete existing attachment(s)
|
||||
if (!empty($event['deleted_attachments'])) {
|
||||
foreach ($event['deleted_attachments'] as $attachment) {
|
||||
if (!empty($old['attachments'])) {
|
||||
foreach ($old['attachments'] as $idx => $att) {
|
||||
if ($att['id'] == $attachment) {
|
||||
$old['attachments'][$idx]['_deleted'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($event['deleted_attachments']);
|
||||
}
|
||||
|
||||
// handle attachments to add
|
||||
if (!empty($event['attachments'])) {
|
||||
foreach ($event['attachments'] as $attachment) {
|
||||
// skip entries without content (could be existing ones)
|
||||
if (!$attachment['data'] && !$attachment['path'])
|
||||
continue;
|
||||
|
||||
$attachments[] = array(
|
||||
'name' => $attachment['name'],
|
||||
'mimetype' => $attachment['mimetype'],
|
||||
'content' => $attachment['data'],
|
||||
'path' => $attachment['path'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$event['attachments'] = array_merge((array)$old['attachments'], $attachments);
|
||||
|
||||
// modify a recurring event, check submitted savemode to do the right things
|
||||
if ($old['recurrence'] || $old['recurrence_id'] || $old['isexception']) {
|
||||
$master = $old['recurrence_id'] || $old['isexception'] ? $fromcalendar->get_event($old['uid']) : $old;
|
||||
$master = $storage->get_event($old['uid']);
|
||||
$savemode = $event['_savemode'] ?: ($old['recurrence_id'] || $old['isexception'] ? 'current' : 'all');
|
||||
|
||||
// this-and-future on the first instance equals to 'all'
|
||||
if (!$old['recurrence_id'] && $savemode == 'future')
|
||||
$recurrence_id_format = $master['allday'] ? 'Ymd' : 'Ymd\THis';
|
||||
if ($savemode == 'future' && $master['start'] && $old['_instance'] == $master['start']->format($recurrence_id_format))
|
||||
$savemode = 'all';
|
||||
// force 'current' mode for single occurrences stored as exception
|
||||
else if (!$old['recurrence'] && !$old['recurrence_id'] && $old['isexception'])
|
||||
|
@ -1021,7 +999,7 @@ class kolab_driver extends calendar_driver
|
|||
|
||||
// remove recurrence exceptions on re-scheduling
|
||||
if ($reschedule) {
|
||||
unset($event['recurrence']['EXCEPTIONS'], $master['recurrence']['EXDATE']);
|
||||
unset($event['recurrence']['EXCEPTIONS'], $event['exceptions'], $master['recurrence']['EXDATE']);
|
||||
}
|
||||
else if (is_array($event['recurrence']['EXCEPTIONS'])) {
|
||||
// only keep relevant exceptions
|
||||
|
@ -1033,6 +1011,8 @@ class kolab_driver extends calendar_driver
|
|||
return $exdate > $event['start'];
|
||||
});
|
||||
}
|
||||
// set link to top-level exceptions
|
||||
$event['exceptions'] = &$event['recurrence']['EXCEPTIONS'];
|
||||
}
|
||||
|
||||
// compute remaining occurrences
|
||||
|
@ -1060,6 +1040,8 @@ class kolab_driver extends calendar_driver
|
|||
$master['recurrence']['EXCEPTIONS'] = array_filter($master['recurrence']['EXCEPTIONS'], function($exception) use ($event) {
|
||||
return $exception['start'] < $event['start'];
|
||||
});
|
||||
// set link to top-level exceptions
|
||||
$master['exceptions'] = &$master['recurrence']['EXCEPTIONS'];
|
||||
}
|
||||
if (is_array($master['recurrence']['EXDATE'])) {
|
||||
$master['recurrence']['EXDATE'] = array_filter($master['recurrence']['EXDATE'], function($exdate) use ($event) {
|
||||
|
@ -1102,7 +1084,7 @@ class kolab_driver extends calendar_driver
|
|||
$add_exception = true;
|
||||
|
||||
// adjust matching RDATE entry if dates changed
|
||||
if ($savemode == 'current' && $master['recurrence']['RDATE'] && ($old_date = $old['start']->format('Ymd')) != $event['start']->format('Ymd')) {
|
||||
if (is_array($master['recurrence']['RDATE']) && ($old_date = $old['start']->format('Ymd')) != $event['start']->format('Ymd')) {
|
||||
foreach ($master['recurrence']['RDATE'] as $j => $rdate) {
|
||||
if ($rdate->format('Ymd') == $old_date) {
|
||||
$master['recurrence']['RDATE'][$j] = $event['start'];
|
||||
|
@ -1122,7 +1104,7 @@ class kolab_driver extends calendar_driver
|
|||
break;
|
||||
|
||||
default: // 'all' is default
|
||||
$event['id'] = $master['id'];
|
||||
$event['id'] = $master['uid'];
|
||||
$event['uid'] = $master['uid'];
|
||||
|
||||
// use start date from master but try to be smart on time or duration changes
|
||||
|
@ -1152,7 +1134,7 @@ class kolab_driver extends calendar_driver
|
|||
}
|
||||
}
|
||||
// dates did not change, use the ones from master
|
||||
else if ($event['start'] == $old['start'] && $event['end'] == $old['end']) {
|
||||
else if ($new_start_date . $new_start_time == $old_start_date . $old_start_time) {
|
||||
$event['start'] = $master['start'];
|
||||
$event['end'] = $master['end'];
|
||||
}
|
||||
|
@ -1198,12 +1180,15 @@ class kolab_driver extends calendar_driver
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set link to top-level exceptions
|
||||
$event['exceptions'] = &$event['recurrence']['EXCEPTIONS'];
|
||||
}
|
||||
|
||||
// unset _dateonly flags in (cached) date objects
|
||||
unset($event['start']->_dateonly, $event['end']->_dateonly);
|
||||
|
||||
$success = $storage->update_event($event);
|
||||
$success = $storage->update_event($event) ? $event['id'] : false; // return master UID
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1500,7 +1485,7 @@ class kolab_driver extends calendar_driver
|
|||
$this->rc->user->save_prefs(array('calendar_categories' => $old_categories));
|
||||
}
|
||||
|
||||
array_walk($events, 'kolab_driver::clean_rcube_event_out');
|
||||
array_walk($events, 'kolab_driver::to_rcube_event');
|
||||
return $events;
|
||||
}
|
||||
|
||||
|
@ -1663,8 +1648,8 @@ class kolab_driver extends calendar_driver
|
|||
|
||||
$event = $storage->get_event($event['id']);
|
||||
|
||||
if ($event && !empty($event['attachments'])) {
|
||||
foreach ($event['attachments'] as $att) {
|
||||
if ($event && !empty($event['_attachments'])) {
|
||||
foreach ($event['_attachments'] as $att) {
|
||||
if ($att['id'] == $id) {
|
||||
return $att;
|
||||
}
|
||||
|
@ -1878,12 +1863,22 @@ class kolab_driver extends calendar_driver
|
|||
|
||||
|
||||
/**
|
||||
* Convert from Kolab_Format to internal representation
|
||||
* Convert from driver format to external caledar app data
|
||||
*/
|
||||
public static function to_rcube_event($record)
|
||||
public static function to_rcube_event(&$record)
|
||||
{
|
||||
if (!is_array($record))
|
||||
return $record;
|
||||
|
||||
$record['id'] = $record['uid'];
|
||||
|
||||
if ($record['_instance']) {
|
||||
$record['id'] .= '-' . $record['_instance'];
|
||||
|
||||
if (!$record['recurrence_id'] && !empty($record['recurrence']))
|
||||
$record['recurrence_id'] = $record['uid'];
|
||||
}
|
||||
|
||||
// all-day events go from 12:00 - 13:00
|
||||
if (is_a($record['start'], 'DateTime') && $record['end'] <= $record['start'] && $record['allday']) {
|
||||
$record['end'] = clone $record['start'];
|
||||
|
@ -1932,17 +1927,6 @@ class kolab_driver extends calendar_driver
|
|||
if (empty($record['recurrence']))
|
||||
unset($record['recurrence']);
|
||||
|
||||
// add instance identifier to first occurrence (master event)
|
||||
// do not add 'recurrence_date' though in order to keep the master even being exported as such
|
||||
$recurrence_id_format = $record['allday'] ? 'Ymd' : 'Ymd\THis';
|
||||
if ($record['recurrence'] && !$record['recurrence_id'] && !$record['_instance']) {
|
||||
$record['_instance'] = $record['start']->format($recurrence_id_format);
|
||||
}
|
||||
else if (is_a($record['recurrence_date'], 'DateTime')) {
|
||||
$record['_instance'] = $record['recurrence_date']->format($recurrence_id_format);
|
||||
$record['id'] = $record['uid'] . '-' . $record['_instance'];
|
||||
}
|
||||
|
||||
// clean up exception data
|
||||
if (is_array($record['recurrence']['EXCEPTIONS'])) {
|
||||
array_walk($record['recurrence']['EXCEPTIONS'], function(&$exception) {
|
||||
|
@ -1950,16 +1934,10 @@ class kolab_driver extends calendar_driver
|
|||
});
|
||||
}
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove some internal properties before sending to event out to the calendar app
|
||||
*/
|
||||
public static function clean_rcube_event_out(&$record)
|
||||
{
|
||||
unset($record['_mailbox'], $record['_msguid'], $record['_type'], $record['_size'],
|
||||
$record['_formatobj'], $record['_attachments'], $record['exceptions'], $record['x-custom']);
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1968,7 +1946,7 @@ class kolab_driver extends calendar_driver
|
|||
public static function from_rcube_event($event, $old = array())
|
||||
{
|
||||
// in kolab_storage attachments are indexed by content-id
|
||||
if (is_array($event['attachments'])) {
|
||||
if (is_array($event['attachments']) || !empty($event['deleted_attachments'])) {
|
||||
$event['_attachments'] = array();
|
||||
|
||||
foreach ($event['attachments'] as $attachment) {
|
||||
|
@ -1985,7 +1963,7 @@ class kolab_driver extends calendar_driver
|
|||
}
|
||||
|
||||
// flagged for deletion => set to false
|
||||
if ($attachment['_deleted']) {
|
||||
if ($attachment['_deleted'] || in_array($attachment['id'], (array)$event['deleted_attachments'])) {
|
||||
$event['_attachments'][$key] = false;
|
||||
}
|
||||
// replace existing entry
|
||||
|
@ -1998,7 +1976,14 @@ class kolab_driver extends calendar_driver
|
|||
}
|
||||
}
|
||||
|
||||
unset($event['attachments']);
|
||||
$event['_attachments'] = array_merge((array)$old['_attachments'], $event['_attachments']);
|
||||
|
||||
// attachments flagged for deletion => set to false
|
||||
foreach ($event['_attachments'] as $key => $attachment) {
|
||||
if ($attachment['_deleted'] || in_array($attachment['id'], (array)$event['deleted_attachments'])) {
|
||||
$event['_attachments'][$key] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $event;
|
||||
|
|
Loading…
Add table
Reference in a new issue