From 549eb70bdec4fffbadca371064f9bc0884e9d36e Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 17 Mar 2016 16:33:18 +0100 Subject: [PATCH] Fix merging attachments list on event/task update from iTip (#5342) Reviewers: #roundcube_kolab_plugins_developers, vanmeeuwen Reviewed By: #roundcube_kolab_plugins_developers, vanmeeuwen Subscribers: vanmeeuwen Projects: #roundcube_kolab_plugins Differential Revision: https://git.kolab.org/D96 --- plugins/calendar/calendar.php | 7 ++ .../calendar/drivers/kolab/kolab_driver.php | 41 +----------- plugins/libkolab/lib/kolab_format.php | 64 +++++++++++++++++++ .../drivers/kolab/tasklist_kolab_driver.php | 42 +----------- plugins/tasklist/tasklist.php | 9 +++ 5 files changed, 83 insertions(+), 80 deletions(-) diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index a6a3a20f..815d74d6 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -2994,6 +2994,13 @@ class calendar extends rcube_plugin // set status=CANCELLED on CANCEL messages if ($event['_method'] == 'CANCEL') $event['status'] = 'CANCELLED'; + + // update attachments list, allow attachments update only on REQUEST (#5342) + if ($event['_method'] == 'REQUEST') + $event['deleted_attachments'] = true; + else + unset($event['attachments']); + // show me as free when declined (#1670) if ($status == 'declined' || $event['status'] == 'CANCELLED' || $event_attendee['role'] == 'NON-PARTICIPANT') $event['free_busy'] = 'free'; diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php index b4c2978c..61dc5938 100644 --- a/plugins/calendar/drivers/kolab/kolab_driver.php +++ b/plugins/calendar/drivers/kolab/kolab_driver.php @@ -1953,46 +1953,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']) || !empty($event['deleted_attachments'])) { - $event['_attachments'] = array(); - - foreach ($event['attachments'] as $attachment) { - $key = null; - // Roundcube ID has nothing to do with the storage ID, remove it - if ($attachment['content'] || $attachment['path']) { - unset($attachment['id']); - } - else { - foreach ((array)$old['_attachments'] as $cid => $oldatt) { - if ($attachment['id'] == $oldatt['id']) - $key = $cid; - } - } - - // flagged for deletion => set to false - if ($attachment['_deleted'] || in_array($attachment['id'], (array)$event['deleted_attachments'])) { - $event['_attachments'][$key] = false; - } - // replace existing entry - else if ($key) { - $event['_attachments'][$key] = $attachment; - } - // append as new attachment - else { - $event['_attachments'][] = $attachment; - } - } - - $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; - } - } - } + kolab_format::merge_attachments($event, $old); return $event; } diff --git a/plugins/libkolab/lib/kolab_format.php b/plugins/libkolab/lib/kolab_format.php index 5041dd38..27b8956e 100644 --- a/plugins/libkolab/lib/kolab_format.php +++ b/plugins/libkolab/lib/kolab_format.php @@ -704,4 +704,68 @@ abstract class kolab_format $this->obj->setAttachments($vattach); } } + + /** + * Unified way of updating/deleting attachments of edited object + * + * @param array $object Kolab object data + * @param array $old Old version of Kolab object + */ + public static function merge_attachments(&$object, $old) + { + $object['_attachments'] = (array) $old['_attachments']; + + // delete existing attachment(s) + if (!empty($object['deleted_attachments'])) { + foreach ($object['_attachments'] as $idx => $att) { + if ($object['deleted_attachments'] === true || in_array($att['id'], $object['deleted_attachments'])) { + $object['_attachments'][$idx] = false; + } + } + } + + // in kolab_storage attachments are indexed by content-id + foreach ((array) $object['attachments'] as $attachment) { + $key = null; + + // Roundcube ID has nothing to do with the storage ID, remove it + // for uploaded/new attachments + // FIXME: Roundcube uses 'data', kolab_format uses 'content' + if ($attachment['content'] || $attachment['path'] || $attachment['data']) { + unset($attachment['id']); + } + + if ($attachment['id']) { + foreach ((array) $object['_attachments'] as $cid => $att) { + if ($att && $attachment['id'] == $att['id']) { + $key = $cid; + } + } + } + else { + // find attachment by name, so we can update it if exists + // and make sure there are no duplicates + foreach ((array) $object['_attachments'] as $cid => $att) { + if ($att && $attachment['name'] == $att['name']) { + $key = $cid; + } + } + } + + if ($key && $attachment['_deleted']) { + $object['_attachments'][$key] = false; + } + // replace existing entry + else if ($key) { + $object['_attachments'][$key] = $attachment; + } + // append as new attachment + else { + $object['_attachments'][] = $attachment; + } + } + + unset($object['attachments']); + unset($object['deleted_attachments']); + } } diff --git a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php index 556fdc72..80f16696 100644 --- a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php +++ b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php @@ -1287,46 +1287,8 @@ class tasklist_kolab_driver extends tasklist_driver $object['recurrence'] = $old['recurrence']; } - // delete existing attachment(s) - if (!empty($task['deleted_attachments'])) { - foreach ($task['deleted_attachments'] as $attachment) { - if (is_array($object['_attachments'])) { - foreach ($object['_attachments'] as $idx => $att) { - if ($att['id'] == $attachment) - $object['_attachments'][$idx] = false; - } - } - } - unset($task['deleted_attachments']); - } - - // in kolab_storage attachments are indexed by content-id - if (is_array($task['attachments'])) { - foreach ($task['attachments'] as $idx => $attachment) { - $key = null; - // Roundcube ID has nothing to do with the storage ID, remove it - if ($attachment['content'] || $attachment['path']) { - unset($attachment['id']); - } - else { - foreach ((array)$old['_attachments'] as $cid => $oldatt) { - if ($oldatt && $attachment['id'] == $oldatt['id']) - $key = $cid; - } - } - - // replace existing entry - if ($key) { - $object['_attachments'][$key] = $attachment; - } - // append as new attachment - else { - $object['_attachments'][] = $attachment; - } - } - - unset($object['attachments']); - } + unset($task['attachments']); + kolab_format::merge_attachments($object, $old); // allow sequence increments if I'm the organizer if ($this->plugin->is_organizer($object) && empty($object['_method'])) { diff --git a/plugins/tasklist/tasklist.php b/plugins/tasklist/tasklist.php index b7df7a9a..042c76d3 100644 --- a/plugins/tasklist/tasklist.php +++ b/plugins/tasklist/tasklist.php @@ -2080,6 +2080,15 @@ class tasklist extends rcube_plugin if ($task['_method'] == 'CANCEL') { $task['status'] = 'CANCELLED'; } + + // update attachments list, allow attachments update only on REQUEST (#5342) + if ($task['_method'] == 'REQUEST') { + $task['deleted_attachments'] = true; + } + else { + unset($task['attachments']); + } + // show me as free when declined (#1670) if ($status == 'declined' || $task['status'] == 'CANCELLED') { $task['free_busy'] = 'free';