Consider a change in recurrence rule significant for rescheduling (#4366)
This commit is contained in:
parent
f09948eefe
commit
12591358e6
6 changed files with 65 additions and 32 deletions
|
@ -993,7 +993,7 @@ class calendar extends rcube_plugin
|
||||||
if ($success = $this->driver->edit_rsvp($event, $status)) {
|
if ($success = $this->driver->edit_rsvp($event, $status)) {
|
||||||
$noreply = rcube_utils::get_input_value('noreply', rcube_utils::INPUT_GPC);
|
$noreply = rcube_utils::get_input_value('noreply', rcube_utils::INPUT_GPC);
|
||||||
$noreply = intval($noreply) || $status == 'needs-action' || $itip_sending === 0;
|
$noreply = intval($noreply) || $status == 'needs-action' || $itip_sending === 0;
|
||||||
$reload = $event['calendar'] != $ev['calendar'] ? 2 : 1;
|
$reload = $event['calendar'] != $ev['calendar'] || $event['recurrence'] ? 2 : 1;
|
||||||
$organizer = null;
|
$organizer = null;
|
||||||
$emails = $this->get_user_emails();
|
$emails = $this->get_user_emails();
|
||||||
|
|
||||||
|
@ -1131,8 +1131,6 @@ class calendar extends rcube_plugin
|
||||||
// make sure we have the complete record
|
// make sure we have the complete record
|
||||||
$event = $action == 'remove' ? $old : $this->driver->get_event($event);
|
$event = $action == 'remove' ? $old : $this->driver->get_event($event);
|
||||||
|
|
||||||
// TODO: on change of a recurring (main) event, also send updates to differing attendess of recurrence exceptions
|
|
||||||
|
|
||||||
// only notify if data really changed (TODO: do diff check on client already)
|
// only notify if data really changed (TODO: do diff check on client already)
|
||||||
if (!$old || $action == 'remove' || self::event_diff($event, $old)) {
|
if (!$old || $action == 'remove' || self::event_diff($event, $old)) {
|
||||||
$sent = $this->notify_attendees($event, $old, $action, $event['_comment']);
|
$sent = $this->notify_attendees($event, $old, $action, $event['_comment']);
|
||||||
|
@ -1990,6 +1988,8 @@ class calendar extends rcube_plugin
|
||||||
$sent = -100;
|
$sent = -100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: on change of a recurring (main) event, also send updates to differing attendess of recurrence exceptions
|
||||||
|
|
||||||
// send CANCEL message to removed attendees
|
// send CANCEL message to removed attendees
|
||||||
foreach ((array)$old['attendees'] as $attendee) {
|
foreach ((array)$old['attendees'] as $attendee) {
|
||||||
if ($attendee['ROLE'] == 'ORGANIZER' || !$attendee['email'] || in_array(strtolower($attendee['email']), $current))
|
if ($attendee['ROLE'] == 'ORGANIZER' || !$attendee['email'] || in_array(strtolower($attendee['email']), $current))
|
||||||
|
@ -2215,7 +2215,7 @@ class calendar extends rcube_plugin
|
||||||
public static function event_diff($a, $b)
|
public static function event_diff($a, $b)
|
||||||
{
|
{
|
||||||
$diff = array();
|
$diff = array();
|
||||||
$ignore = array('changed' => 1, 'attachments' => 1, 'recurrence' => 1, '_notify' => 1, '_owner' => 1);
|
$ignore = array('changed' => 1, 'attachments' => 1, '_notify' => 1, '_owner' => 1, '_savemode' => 1);
|
||||||
foreach (array_unique(array_merge(array_keys($a), array_keys($b))) as $key) {
|
foreach (array_unique(array_merge(array_keys($a), array_keys($b))) as $key) {
|
||||||
if (!$ignore[$key] && $a[$key] != $b[$key])
|
if (!$ignore[$key] && $a[$key] != $b[$key])
|
||||||
$diff[] = $key;
|
$diff[] = $key;
|
||||||
|
|
|
@ -1035,26 +1035,13 @@ class kolab_driver extends calendar_driver
|
||||||
*/
|
*/
|
||||||
public function check_scheduling(&$event, $old, $update = true)
|
public function check_scheduling(&$event, $old, $update = true)
|
||||||
{
|
{
|
||||||
$reschedule = false;
|
|
||||||
|
|
||||||
// skip this check when importing iCal/iTip events
|
// skip this check when importing iCal/iTip events
|
||||||
if (isset($event['sequence']) || !empty($event['_method'])) {
|
if (isset($event['sequence']) || !empty($event['_method'])) {
|
||||||
return $reschedule;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate through the list of properties considered 'significant' for scheduling
|
// iterate through the list of properties considered 'significant' for scheduling
|
||||||
foreach (kolab_format_event::$scheduling_properties as $prop) {
|
$reschedule = kolab_format_event::check_rescheduling($event, $old);
|
||||||
$a = $old[$prop];
|
|
||||||
$b = $event[$prop];
|
|
||||||
if ($event['allday'] && ($prop == 'start' || $prop == 'end') && $a instanceof DateTime && $b instanceof DateTime) {
|
|
||||||
$a = $a->format('Y-m-d');
|
|
||||||
$b = $b->format('Y-m-d');
|
|
||||||
}
|
|
||||||
if ($a != $b) {
|
|
||||||
$reschedule = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset all attendee status to needs-action (#4360)
|
// reset all attendee status to needs-action (#4360)
|
||||||
if ($update && $reschedule && is_array($event['attendees'])) {
|
if ($update && $reschedule && is_array($event['attendees'])) {
|
||||||
|
|
|
@ -41,7 +41,7 @@ $config['kolab_messages_cache_bypass'] = 0;
|
||||||
|
|
||||||
// These event properties contribute to a significant revision to the calendar component
|
// These event properties contribute to a significant revision to the calendar component
|
||||||
// and if changed will increment the sequence number relevant for scheduling according to RFC 5545
|
// and if changed will increment the sequence number relevant for scheduling according to RFC 5545
|
||||||
$config['kolab_event_scheduling_properties'] = array('start', 'end', 'allday', 'location', 'status', 'cancelled');
|
$config['kolab_event_scheduling_properties'] = array('start', 'end', 'allday', 'recurrence', 'location', 'status', 'cancelled');
|
||||||
|
|
||||||
// These task properties contribute to a significant revision to the calendar component
|
// These task properties contribute to a significant revision to the calendar component
|
||||||
// and if changed will increment the sequence number relevant for scheduling according to RFC 5545
|
// and if changed will increment the sequence number relevant for scheduling according to RFC 5545
|
||||||
|
|
|
@ -26,7 +26,7 @@ class kolab_format_event extends kolab_format_xcal
|
||||||
{
|
{
|
||||||
public $CTYPEv2 = 'application/x-vnd.kolab.event';
|
public $CTYPEv2 = 'application/x-vnd.kolab.event';
|
||||||
|
|
||||||
public static $scheduling_properties = array('start', 'end', 'allday', 'location', 'status', 'cancelled');
|
public static $scheduling_properties = array('start', 'end', 'allday', 'recurrence', 'location', 'status', 'cancelled');
|
||||||
|
|
||||||
protected $objclass = 'Event';
|
protected $objclass = 'Event';
|
||||||
protected $read_func = 'readEvent';
|
protected $read_func = 'readEvent';
|
||||||
|
@ -100,6 +100,7 @@ class kolab_format_event extends kolab_format_xcal
|
||||||
foreach((array)$object['recurrence']['EXCEPTIONS'] as $i => $exception) {
|
foreach((array)$object['recurrence']['EXCEPTIONS'] as $i => $exception) {
|
||||||
$exevent = new kolab_format_event;
|
$exevent = new kolab_format_event;
|
||||||
$exevent->set(($compacted = $this->compact_exception($exception, $object))); // only save differing values
|
$exevent->set(($compacted = $this->compact_exception($exception, $object))); // only save differing values
|
||||||
|
console('COMPACTED', $compacted);
|
||||||
|
|
||||||
// get value for recurrence-id
|
// get value for recurrence-id
|
||||||
if (!empty($exception['recurrence_date']) && is_a($exception['recurrence_date'], 'DateTime')) {
|
if (!empty($exception['recurrence_date']) && is_a($exception['recurrence_date'], 'DateTime')) {
|
||||||
|
@ -274,4 +275,13 @@ class kolab_format_event extends kolab_format_xcal
|
||||||
return $exception;
|
return $exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identify changes considered relevant for scheduling
|
||||||
|
*
|
||||||
|
* @see kolab_format_xcal::check_rescheduling()
|
||||||
|
*/
|
||||||
|
public static function check_rescheduling($object, $old, $checks = null)
|
||||||
|
{
|
||||||
|
return parent::check_rescheduling($object, $old, $checks ?: self::$scheduling_properties);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,4 +126,14 @@ class kolab_format_task extends kolab_format_xcal
|
||||||
|
|
||||||
return $tags;
|
return $tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identify changes considered relevant for scheduling
|
||||||
|
*
|
||||||
|
* @see kolab_format_xcal::check_rescheduling()
|
||||||
|
*/
|
||||||
|
public static function check_rescheduling($object, $old, $checks = null)
|
||||||
|
{
|
||||||
|
return parent::check_rescheduling($object, $old, $checks ?: self::$scheduling_properties);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -321,17 +321,8 @@ abstract class kolab_format_xcal extends kolab_format
|
||||||
|
|
||||||
// increment sequence when updating properties relevant for scheduling.
|
// 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."
|
// RFC 5545: "It is incremented [...] each time the Organizer makes a significant revision to the calendar component."
|
||||||
foreach (self::$scheduling_properties as $prop) {
|
if (self::check_rescheduling($object, $old)) {
|
||||||
$a = $old[$prop];
|
$object['sequence']++;
|
||||||
$b = $object[$prop];
|
|
||||||
if ($object['allday'] && ($prop == 'start' || $prop == 'end') && $a instanceof DateTime && $b instanceof DateTime) {
|
|
||||||
$a = $a->format('Y-m-d');
|
|
||||||
$b = $b->format('Y-m-d');
|
|
||||||
}
|
|
||||||
if ($a != $b) {
|
|
||||||
$object['sequence']++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -637,4 +628,39 @@ abstract class kolab_format_xcal extends kolab_format
|
||||||
|
|
||||||
return $tags;
|
return $tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identify changes considered relevant for scheduling
|
||||||
|
*
|
||||||
|
* @param array Hash array with NEW object properties
|
||||||
|
* @param array Hash array with OLD object properties
|
||||||
|
* @param array List of object properties to check for changes
|
||||||
|
*
|
||||||
|
* @return boolean True if changes affect scheduling, False otherwise
|
||||||
|
*/
|
||||||
|
public static function check_rescheduling($object, $old, $checks = null)
|
||||||
|
{
|
||||||
|
$reschedule = false;
|
||||||
|
|
||||||
|
foreach ($checks ?: self::$scheduling_properties as $prop) {
|
||||||
|
$a = $old[$prop];
|
||||||
|
$b = $object[$prop];
|
||||||
|
if ($object['allday'] && ($prop == 'start' || $prop == 'end') && $a instanceof DateTime && $b instanceof DateTime) {
|
||||||
|
$a = $a->format('Y-m-d');
|
||||||
|
$b = $b->format('Y-m-d');
|
||||||
|
}
|
||||||
|
if ($prop == 'recurrence') {
|
||||||
|
unset($a['EXCEPTIONS']);
|
||||||
|
unset($b['EXCEPTIONS']);
|
||||||
|
$a = array_filter($a);
|
||||||
|
$b = array_filter($b);
|
||||||
|
}
|
||||||
|
if ($a != $b) {
|
||||||
|
$reschedule = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $reschedule;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue