Allow an event updates on iTip request without SEQUENCE bump (Bifrost#T27883)

We're detecting if something changed in description, title, url,
location or attendees. These are properties that could be changed
by the organizer without SEQUENCE bump. If that is detected
we display "Update in my calendar" button.

TODO: display a diff of changes, so user can take a decission
      if he want's to overwrite his copy of the event.
This commit is contained in:
Aleksander Machniak 2017-09-14 13:19:32 +02:00
parent a1cd95152c
commit 16a71fccdc
2 changed files with 72 additions and 5 deletions

View file

@ -374,7 +374,7 @@ class libcalendaring_itip
{
$action = $event['rsvp'] ? 'rsvp' : '';
$status = $event['fallback'];
$latest = $resheduled = false;
$latest = $rescheduled = false;
$html = '';
if (is_numeric($event['changed']))
@ -404,7 +404,7 @@ class libcalendaring_itip
if (!$latest) {
// FIXME: This is probably to simplistic, or maybe we should just check
// attendee's RSVP flag in the new event?
$resheduled = $existing['start'] != $event['start'] || $existing['end'] > $event['end'];
$rescheduled = $existing['start'] != $event['start'] || $existing['end'] > $event['end'];
}
}
else {
@ -428,10 +428,16 @@ class libcalendaring_itip
else if (!$existing && !$rsvp) {
$action = 'import';
}
else if ($resheduled) {
else if ($rescheduled) {
$action = 'rsvp';
}
else if ($status_lc != 'needs-action') {
// check if there are any changes
if ($latest) {
$diff = $this->get_itip_diff($event, $existing);
$latest = empty($diff);
}
$action = !$latest ? 'update' : '';
}
@ -485,11 +491,69 @@ class libcalendaring_itip
'latest' => $latest,
'status' => $status,
'action' => $action,
'resheduled' => $resheduled,
'rescheduled' => $rescheduled,
'html' => $html,
);
}
protected function get_itip_diff($event, $existing)
{
if (empty($event) || empty($existing) || empty($event['message_uid'])) {
return;
}
$itip = $this->lib->mail_get_itip_object($event['mbox'], $event['message_uid'], $event['mime_id'],
$event['task'] == 'calendar' ? 'event' : 'task');
if ($itip) {
// List of properties that could change without SEQUENCE bump
$attrs = array('description', 'title', 'location', 'url');
$diff = array();
foreach ($attrs as $attr) {
if (isset($itip[$attr]) && $itip[$attr] != $existing[$attr]) {
$diff[$attr] = array(
'new' => $itip[$attr],
'old' => $existing[$attr]
);
}
}
$status = array();
$itip_attendees = array();
$existing_attendees = array();
$emails = $this->lib->get_user_emails();
// Compare list of attendees (ignoring current user status)
foreach ((array) $existing['attendees'] as $idx => $attendee) {
if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) {
$status[strtolower($attendee['email'])] = $attendee['status'];
}
if ($attendee['role'] == 'ORGANIZER') {
$attendee['status'] = 'ACCEPTED'; // sometimes is not set for exceptions
$existing['attendees'][$idx] = $attendee;
}
$existing_attendees[] = $attendee['email'].$attendee['name'];
}
foreach ((array) $itip['attendees'] as $idx => $attendee) {
if ($attendee['email'] && ($_status = $status[strtolower($attendee['email'])])) {
$attendee['status'] = $_status;
$itip['attendees'][$idx] = $attendee;
}
$itip_attendees[] = $attendee['email'].$attendee['name'];
}
if ($itip_attendees != $existing_attendees) {
$diff['attendees'] = array(
'new' => $itip['attendees'],
'old' => $existing['attendees']
);
}
return $diff;
}
}
/**
* Build inline UI elements for iTip messages
*/
@ -508,6 +572,7 @@ class libcalendaring_itip
'sequence' => intval($event['sequence']),
'method' => $method,
'task' => $task,
'mime_id' => $mime_id,
);
// create buttons to be activated from async request checking existence of this event in local calendars

View file

@ -1325,6 +1325,8 @@ rcube_libcalendaring.decline_attendee_reply = function(mime_id, task)
*/
rcube_libcalendaring.fetch_itip_object_status = function(p)
{
p.mbox = rcmail.env.mailbox;
p.message_uid = rcmail.env.uid;
rcmail.http_post(p.task + '/itip-status', { data: p });
};
@ -1356,7 +1358,7 @@ rcube_libcalendaring.update_itip_object_status = function(p)
$('#'+p.action+'-'+p.id).show().find('input.button').last().after(p.select);
// highlight date if date change detected
if (p.resheduled)
if (p.rescheduled)
$('.calendar-eventdetails td.date').addClass('modified');
// show itip box appendix after replacing the given placeholders