diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index a4d3f48d..51381cb4 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -1836,6 +1836,7 @@ class calendar extends rcube_plugin // convert dates into DateTime objects in user's current timezone $event['start'] = new DateTime($event['start'], $this->timezone); $event['end'] = new DateTime($event['end'], $this->timezone); + $event['allday'] = (bool)$event['allday']; // start/end is all we need for 'move' action (#1480) if ($action == 'move') { @@ -2211,7 +2212,7 @@ class calendar extends rcube_plugin public static function event_diff($a, $b) { $diff = array(); - $ignore = array('changed' => 1, 'attachments' => 1); + $ignore = array('changed' => 1, 'attachments' => 1, 'recurrence' => 1, '_notify' => 1, '_owner' => 1); foreach (array_unique(array_merge(array_keys($a), array_keys($b))) as $key) { if (!$ignore[$key] && $a[$key] != $b[$key]) $diff[] = $key; diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php index 0d5b9ab5..98318f25 100644 --- a/plugins/calendar/drivers/kolab/kolab_driver.php +++ b/plugins/calendar/drivers/kolab/kolab_driver.php @@ -883,6 +883,9 @@ class kolab_driver extends calendar_driver $savemode = $event['_savemode']; } + // check if update affects scheduling and update attendee status accordingly + $reschedule = $this->check_scheduling($event, $old, true); + // keep saved exceptions (not submitted by the client) if ($old['recurrence']['EXDATE'] && !isset($event['recurrence']['EXDATE'])) $event['recurrence']['EXDATE'] = $old['recurrence']['EXDATE']; @@ -914,7 +917,10 @@ class kolab_driver extends calendar_driver $event['recurrence'] = array(); $event['thisandfuture'] = $savemode == 'future'; - // TODO: increment sequence if scheduling is affected + // increment sequence of this instance if scheduling is affected + if ($reschedule) { + $event['sequence'] = $old['sequence'] + 1; + } // remove some internal properties which should not be saved unset($event['id'], $event['_savemode'], $event['_fromcalendar'], $event['_identity'], $event['_notify']); @@ -991,7 +997,8 @@ class kolab_driver extends calendar_driver } // adjust recurrence-id when start changed and therefore the entire recurrence chain changes - if (($old_start_date != $new_start_date || $old_start_time != $new_start_time) && is_array($event['recurrence']['EXCEPTIONS']) && !$with_exceptions) { + if (($old_start_date != $new_start_date || $old_start_time != $new_start_time) && + is_array($event['recurrence']) && is_array($event['recurrence']['EXCEPTIONS']) && !$with_exceptions) { $recurrence_id_format = $event['allday'] ? 'Ymd' : 'Ymd\THis'; foreach ($event['recurrence']['EXCEPTIONS'] as $i => $exception) { $recurrence_id = is_a($exception['recurrence_date'], 'DateTime') ? $exception['recurrence_date'] : @@ -1017,6 +1024,56 @@ class kolab_driver extends calendar_driver return $success; } + /** + * Determine whether the current change affects scheduling and reset attendee status accordingly + */ + public function check_scheduling(&$event, $old, $update = true) + { + $reschedule = false; + + // skip this check when importing iCal/iTip events + if (isset($event['sequence']) || !empty($event['_method'])) { + return $reschedule; + } + + // iterate through the list of properties considered 'significant' for scheduling + foreach (kolab_format_event::$scheduling_properties as $prop) { + $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) + if ($update && $reschedule && is_array($event['attendees'])) { + $is_organizer = false; + $emails = $this->cal->get_user_emails(); + $attendees = $event['attendees']; + foreach ($attendees as $i => $attendee) { + if ($attendee['role'] == 'ORGANIZER' && $attendee['email'] && in_array(strtolower($attendee['email']), $emails)) { + $is_organizer = true; + } + else if ($attendee['role'] != 'ORGANIZER' && $attendee['role'] != 'NON-PARTICIPANT' && $attendee['status'] != 'DELEGATED') { + $attendees[$i]['status'] = 'NEEDS-ACTION'; + $attendees[$i]['rsvp'] = true; + } + } + + // update attendees only if I'm the organizer + if ($is_organizer || ($event['organizer'] && in_array(strtolower($event['organizer']['email']), $emails))) { + $event['attendees'] = $attendees; + } + } + + return $reschedule; + } + /** * Get events from source. *