plugins/libcalendaring plugins/libkolab

Thomas Brüderli bruederli at kolabsys.com
Tue Jul 8 17:20:07 CEST 2014


 plugins/libcalendaring/lib/libcalendaring_itip.php |   16 +++++++++++-
 plugins/libcalendaring/localization/en_US.inc      |    7 +++++
 plugins/libkolab/lib/kolab_format_event.php        |    2 +
 plugins/libkolab/lib/kolab_format_task.php         |    2 +
 plugins/libkolab/lib/kolab_format_xcal.php         |   26 +++++++++++++++++----
 5 files changed, 47 insertions(+), 6 deletions(-)

New commits:
commit afb64c39485b12a2aafda83489b4c2f0614905d6
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Tue Jul 8 17:14:14 2014 +0200

    Improve iTip REQUEST workflow:
    - only increase sequence on significant changes that affect scheduling (acc. RFC 5545)
    - show RSVP buttons only for higher sequence updates (#1678)
    - provide a button to simply update the local copy otherwise

diff --git a/plugins/libcalendaring/lib/libcalendaring_itip.php b/plugins/libcalendaring/lib/libcalendaring_itip.php
index 849140b..63284c2 100644
--- a/plugins/libcalendaring/lib/libcalendaring_itip.php
+++ b/plugins/libcalendaring/lib/libcalendaring_itip.php
@@ -285,7 +285,7 @@ class libcalendaring_itip
           $action = 'import';
         }
         else if (in_array(strtolower($status), $this->rsvp_status)) {
-          $html = html::div('rsvp-status ' . strtolower($status), $this->gettext('youhave'.strtolower($status)));
+          $html = html::div('rsvp-status ' . strtolower($status), $this->gettext(($latest ? 'youhave' : 'youhavepreviously') . strtolower($status)));
 
           if ($existing && ($existing['sequence'] > $event['sequence'] || (!$event['sequence'] && $existing['changed'] && $existing['changed'] > $event['changed']))) {
             $action = '';  // nothing to do here, outdated invitation
@@ -293,6 +293,9 @@ class libcalendaring_itip
           else if (!$existing && !$rsvp) {
             $action = 'import';
           }
+          else if ($latest) {
+            $action = 'update';
+          }
         }
       }
       // determine action for REPLY
@@ -419,7 +422,15 @@ class libcalendaring_itip
                 ));
             }
 
-            // 2. Simply import the event without replying
+            // 2. update the local copy with minor changes
+            $update_button = html::tag('input', array(
+                'type' => 'button',
+                'class' => 'button',
+                'onclick' => "rcube_libcalendaring.add_from_itip_mail('" . JQ($mime_id) . "', '$task')",
+                'value' => $this->gettext('updatemycopy'),
+            ));
+
+            // 3. Simply import the event without replying
             $import_button = html::tag('input', array(
                 'type' => 'button',
                 'class' => 'button',
@@ -441,6 +452,7 @@ class libcalendaring_itip
             $rsvp_buttons .= html::div('itip-reply-controls', $this->itip_rsvp_options_ui($dom_id));
 
             $buttons[] = html::div(array('id' => 'rsvp-'.$dom_id, 'class' => 'rsvp-buttons', 'style' => 'display:none'), $rsvp_buttons);
+            $buttons[] = html::div(array('id' => 'update-'.$dom_id, 'style' => 'display:none'), $update_button);
         }
         // for CANCEL messages, we can:
         else if ($method == 'CANCEL') {
diff --git a/plugins/libcalendaring/localization/en_US.inc b/plugins/libcalendaring/localization/en_US.inc
index 505b1dc..3d30c11 100644
--- a/plugins/libcalendaring/localization/en_US.inc
+++ b/plugins/libcalendaring/localization/en_US.inc
@@ -99,6 +99,13 @@ $labels['youhavetentative'] = 'You have tentatively accepted this invitation';
 $labels['youhavedeclined'] = 'You have declined this invitation';
 $labels['youhavedelegated'] = 'You have delegated this invitation';
 $labels['youhaveneeds-action'] = 'You have copied this invitation into your calendar';
+
+$labels['youhavepreviouslyaccepted'] = 'You have previously accepted this invitation';
+$labels['youhavepreviouslytentative'] = 'You have previously accepted this invitation tentatively';
+$labels['youhavepreviouslydeclined'] = 'You have previously declined this invitation';
+$labels['youhavepreviouslydelegated'] = 'You have previously delegated this invitation';
+$labels['youhavepreviouslyneeds-action'] = 'You have copied this invitation into your calendar';
+
 $labels['attendeeaccepted'] = 'Participant has accepted';
 $labels['attendeetentative'] = 'Participant has tentatively accepted';
 $labels['attendeedeclined'] = 'Participant has declined';
diff --git a/plugins/libkolab/lib/kolab_format_event.php b/plugins/libkolab/lib/kolab_format_event.php
index c9a1c9f..2d6a784 100644
--- a/plugins/libkolab/lib/kolab_format_event.php
+++ b/plugins/libkolab/lib/kolab_format_event.php
@@ -26,6 +26,8 @@ class kolab_format_event extends kolab_format_xcal
 {
     public $CTYPEv2 = 'application/x-vnd.kolab.event';
 
+    public static $scheduling_properties = array('start', 'end', 'allday', 'location');
+
     protected $objclass = 'Event';
     protected $read_func = 'readEvent';
     protected $write_func = 'writeEvent';
diff --git a/plugins/libkolab/lib/kolab_format_task.php b/plugins/libkolab/lib/kolab_format_task.php
index 87c3df9..ee0ca6a 100644
--- a/plugins/libkolab/lib/kolab_format_task.php
+++ b/plugins/libkolab/lib/kolab_format_task.php
@@ -26,6 +26,8 @@ class kolab_format_task extends kolab_format_xcal
 {
     public $CTYPEv2 = 'application/x-vnd.kolab.task';
 
+    public static $scheduling_properties = array('start', 'due', 'summary', 'status');
+
     protected $objclass = 'Todo';
     protected $read_func = 'readTodo';
     protected $write_func = 'writeTodo';
diff --git a/plugins/libkolab/lib/kolab_format_xcal.php b/plugins/libkolab/lib/kolab_format_xcal.php
index c9e06ac..d3ff583 100644
--- a/plugins/libkolab/lib/kolab_format_xcal.php
+++ b/plugins/libkolab/lib/kolab_format_xcal.php
@@ -29,6 +29,7 @@ abstract class kolab_format_xcal extends kolab_format
     public $CTYPE = 'application/calendar+xml';
 
     public static $fulltext_cols = array('title', 'description', 'location', 'attendees:name', 'attendees:email', 'categories');
+    public static $scheduling_properties = array('start', 'end', 'location');
 
     protected $sensitivity_map = array(
         'public'       => kolabformat::ClassPublic,
@@ -302,10 +303,27 @@ abstract class kolab_format_xcal extends kolab_format
         // set common object properties
         parent::set($object);
 
-        // increment sequence on updates
-        if (empty($object['sequence']))
-            $object['sequence'] = !$is_new ? $this->obj->sequence()+1 : 0;
-        $this->obj->setSequence($object['sequence']);
+        // set sequence value
+        if (!isset($object['sequence'])) {
+            if ($is_new) {
+                $object['sequence'] = 0;
+            }
+            else {
+                $object['sequence'] = $this->obj->sequence();
+                $old = $this->data['uid'] ? $this->data : $this->to_array();
+
+                // increment sequence when updating properties relevant for scheduling.
+                // RFC 5545: "It is incremented [...] each time the Organizer makes a significant revision to the calendar component."
+                // TODO: make the list of properties considered 'significant' for scheduling configurable
+                foreach (self::$scheduling_properties as $prop) {
+                    if ($object[$prop] != $old[$prop]) {
+                        $object['sequence']++;
+                        break;
+                    }
+                }
+            }
+        }
+        $this->obj->setSequence(intval($object['sequence']));
 
         $this->obj->setSummary($object['title']);
         $this->obj->setLocation($object['location']);




More information about the commits mailing list