summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Bruederli <bruederli@kolabsys.com>2014-07-08 15:14:14 (GMT)
committerThomas Bruederli <bruederli@kolabsys.com>2014-07-08 15:14:14 (GMT)
commitafb64c39485b12a2aafda83489b4c2f0614905d6 (patch)
treefc4861f89287387ed8745b0982e1502a7b3be5c1
parent0c5465c2ad73e330dda104fcb9ef779ed9e1df0f (diff)
downloadroundcubemail-plugins-kolab-afb64c39485b12a2aafda83489b4c2f0614905d6.tar.gz
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
-rw-r--r--plugins/libcalendaring/lib/libcalendaring_itip.php16
-rw-r--r--plugins/libcalendaring/localization/en_US.inc7
-rw-r--r--plugins/libkolab/lib/kolab_format_event.php2
-rw-r--r--plugins/libkolab/lib/kolab_format_task.php2
-rw-r--r--plugins/libkolab/lib/kolab_format_xcal.php26
5 files changed, 47 insertions, 6 deletions
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']);