T1523: Support shared calendars in iTip handling
This commit is contained in:
parent
12cf79adaa
commit
4a9e42a026
6 changed files with 118 additions and 66 deletions
|
@ -2521,12 +2521,22 @@ class calendar extends rcube_plugin
|
|||
/**
|
||||
* Find an event in user calendars
|
||||
*/
|
||||
protected function find_event($event)
|
||||
protected function find_event($event, &$mode)
|
||||
{
|
||||
$this->load_driver();
|
||||
|
||||
// We search for writeable calendars in personal namespace by default
|
||||
return $this->driver->get_event($event, calendar_driver::FILTER_WRITEABLE | calendar_driver::FILTER_PERSONAL);
|
||||
$mode = calendar_driver::FILTER_WRITEABLE | calendar_driver::FILTER_PERSONAL;
|
||||
$result = $this->driver->get_event($event, $mode);
|
||||
// ... now check shared folders if not found
|
||||
if (!$result) {
|
||||
$result = $this->driver->get_event($event, calendar_driver::FILTER_WRITEABLE | calendar_driver::FILTER_SHARED);
|
||||
if ($result) {
|
||||
$mode |= calendar_driver::FILTER_SHARED;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2538,14 +2548,18 @@ class calendar extends rcube_plugin
|
|||
|
||||
$this->load_driver();
|
||||
|
||||
// find local copy of the referenced event
|
||||
$existing = $this->find_event($data);
|
||||
$itip = $this->load_itip();
|
||||
$response = $itip->get_itip_status($data, $existing);
|
||||
// find local copy of the referenced event (in personal namespace)
|
||||
$existing = $this->find_event($data, $mode);
|
||||
$is_shared = $mode & calendar_driver::FILTER_SHARED;
|
||||
$itip = $this->load_itip();
|
||||
$response = $itip->get_itip_status($data, $existing);
|
||||
|
||||
// get a list of writeable calendars to save new events to
|
||||
if (!$existing && !$data['nosave'] && $response['action'] == 'rsvp' || $response['action'] == 'import') {
|
||||
$calendars = $this->driver->list_calendars(calendar_driver::FILTER_WRITEABLE | calendar_driver::FILTER_PERSONAL);
|
||||
if ((!$existing || $is_shared)
|
||||
&& !$data['nosave']
|
||||
&& ($response['action'] == 'rsvp' || $response['action'] == 'import')
|
||||
) {
|
||||
$calendars = $this->driver->list_calendars($mode);
|
||||
$calendar_select = new html_select(array('name' => 'calendar', 'id' => 'itip-saveto', 'is_escaped' => true));
|
||||
$calendar_select->add('--', '');
|
||||
$numcals = 0;
|
||||
|
@ -2562,7 +2576,7 @@ class calendar extends rcube_plugin
|
|||
if ($calendar_select) {
|
||||
$default_calendar = $this->get_default_calendar($data['sensitivity'], $calendars);
|
||||
$response['select'] = html::span('folder-select', $this->gettext('saveincalendar') . ' ' .
|
||||
$calendar_select->show($default_calendar['id']));
|
||||
$calendar_select->show($is_shared ? $existing['calendar'] : $default_calendar['id']));
|
||||
}
|
||||
else if ($data['nosave']) {
|
||||
$response['select'] = html::tag('input', array('type' => 'hidden', 'name' => 'calendar', 'id' => 'itip-saveto', 'value' => ''));
|
||||
|
@ -2884,15 +2898,19 @@ class calendar extends rcube_plugin
|
|||
$event['free_busy'] = 'free';
|
||||
}
|
||||
|
||||
$mode = calendar_driver::FILTER_PERSONAL
|
||||
| calendar_driver::FILTER_SHARED
|
||||
| calendar_driver::FILTER_WRITEABLE;
|
||||
|
||||
// find writeable calendar to store event
|
||||
$cal_id = !empty($_REQUEST['_folder']) ? rcube_utils::get_input_value('_folder', rcube_utils::INPUT_POST) : null;
|
||||
$dontsave = ($_REQUEST['_folder'] === '' && $event['_method'] == 'REQUEST');
|
||||
$calendars = $this->driver->list_calendars(calendar_driver::FILTER_PERSONAL);
|
||||
$calendar = $calendars[$cal_id];
|
||||
$cal_id = rcube_utils::get_input_value('_folder', rcube_utils::INPUT_POST);
|
||||
$dontsave = $cal_id === '' && $event['_method'] == 'REQUEST';
|
||||
$calendars = $this->driver->list_calendars($mode);
|
||||
$calendar = $calendars[$cal_id];
|
||||
|
||||
// select default calendar except user explicitly selected 'none'
|
||||
if (!$calendar && !$dontsave)
|
||||
$calendar = $this->get_default_calendar($event['sensitivity']);
|
||||
$calendar = $this->get_default_calendar($event['sensitivity'], $calendars);
|
||||
|
||||
$metadata = array(
|
||||
'uid' => $event['uid'],
|
||||
|
@ -2940,9 +2958,16 @@ class calendar extends rcube_plugin
|
|||
// save to calendar
|
||||
if ($calendar && $calendar['editable']) {
|
||||
// check for existing event with the same UID
|
||||
$existing = $this->find_event($event);
|
||||
$existing = $this->find_event($event, $mode);
|
||||
|
||||
// we'll create a new copy if user decided to change the calendar
|
||||
if ($existing && $cal_id && $calendar && $calendar['id'] != $existing['calendar']) {
|
||||
$existing = null;
|
||||
}
|
||||
|
||||
if ($existing) {
|
||||
$calendar = $calendars[$existing['calendar']];
|
||||
|
||||
// forward savemode for correct updates of recurring events
|
||||
$existing['_savemode'] = $savemode ?: $event['_savemode'];
|
||||
|
||||
|
@ -3015,10 +3040,9 @@ class calendar extends rcube_plugin
|
|||
$event['id'] = $existing['id'];
|
||||
$event['calendar'] = $existing['calendar'];
|
||||
|
||||
// preserve my participant status for regular updates
|
||||
if (empty($status)) {
|
||||
$this->lib->merge_attendees($event, $existing);
|
||||
}
|
||||
// merge attendees status
|
||||
// e.g. preserve my participant status for regular updates
|
||||
$this->lib->merge_attendees($event, $existing, $status);
|
||||
|
||||
// set status=CANCELLED on CANCEL messages
|
||||
if ($event['_method'] == 'CANCEL')
|
||||
|
|
|
@ -101,6 +101,7 @@ abstract class calendar_driver
|
|||
const FILTER_PERSONAL = 8;
|
||||
const FILTER_PRIVATE = 16;
|
||||
const FILTER_CONFIDENTIAL = 32;
|
||||
const FILTER_SHARED = 64;
|
||||
const BIRTHDAY_CALENDAR_ID = '__bdays__';
|
||||
|
||||
// features supported by backend
|
||||
|
|
|
@ -296,16 +296,15 @@ class kolab_driver extends calendar_driver
|
|||
'list' => $this->calendars,
|
||||
'calendars' => $calendars,
|
||||
'filter' => $filter,
|
||||
'editable' => ($filter & self::FILTER_WRITEABLE),
|
||||
'insert' => ($filter & self::FILTER_INSERTABLE),
|
||||
'active' => ($filter & self::FILTER_ACTIVE),
|
||||
'personal' => ($filter & self::FILTER_PERSONAL)
|
||||
));
|
||||
|
||||
if ($plugin['abort']) {
|
||||
return $plugin['calendars'];
|
||||
}
|
||||
|
||||
$personal = $filter & self::FILTER_PERSONAL;
|
||||
$shared = $filter & self::FILTER_SHARED;
|
||||
|
||||
foreach ($this->calendars as $cal) {
|
||||
if (!$cal->ready) {
|
||||
continue;
|
||||
|
@ -325,9 +324,13 @@ class kolab_driver extends calendar_driver
|
|||
if (($filter & self::FILTER_CONFIDENTIAL) && $cal->subtype != 'confidential') {
|
||||
continue;
|
||||
}
|
||||
if (($filter & self::FILTER_PERSONAL) && $cal->get_namespace() != 'personal') {
|
||||
continue;
|
||||
if ($personal || $shared) {
|
||||
$ns = $cal->get_namespace();
|
||||
if (!(($personal && $ns == 'personal') || ($shared && $ns == 'shared'))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$calendars[$cal->id] = $cal;
|
||||
}
|
||||
|
||||
|
|
|
@ -783,10 +783,19 @@ class kolab_delegation_engine
|
|||
*/
|
||||
public function delegator_folder_filter(&$args)
|
||||
{
|
||||
$context = $this->delegator_context();
|
||||
$context = $this->delegator_context();
|
||||
|
||||
if (empty($context)) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
$storage = $this->rc->get_storage();
|
||||
$other_ns = $storage->get_namespace('other');
|
||||
$delim = $storage->get_hierarchy_delimiter();
|
||||
$editable = $filter & calendar_driver::FILTER_WRITEABLE;
|
||||
$active = $filter & calendar_driver::FILTER_ACTIVE;
|
||||
$personal = $filter & calendar_driver::FILTER_PERSONAL;
|
||||
$shared = $filter & calendar_driver::FILTER_SHARED;
|
||||
$calendars = array();
|
||||
|
||||
// code parts derived from kolab_driver::filter_calendars()
|
||||
|
@ -794,25 +803,19 @@ class kolab_delegation_engine
|
|||
if (!$cal->ready) {
|
||||
continue;
|
||||
}
|
||||
if ($args['writeable'] && $cal->readonly) {
|
||||
if ($editable && !$cal->editable) {
|
||||
continue;
|
||||
}
|
||||
if ($args['active'] && !$cal->storage->is_active()) {
|
||||
if ($active && !$cal->storage->is_active()) {
|
||||
continue;
|
||||
}
|
||||
if ($args['personal']) {
|
||||
if ($personal || $shared) {
|
||||
$ns = $cal->get_namespace();
|
||||
|
||||
if (empty($context)) {
|
||||
if ($ns != 'personal') {
|
||||
continue;
|
||||
}
|
||||
if ($personal && $ns == 'personal') {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
if ($ns != 'other') {
|
||||
continue;
|
||||
}
|
||||
|
||||
else if ($personal && $ns == 'other') {
|
||||
$found = false;
|
||||
foreach ($other_ns as $ns) {
|
||||
$folder = $ns[0] . $context . $delim;
|
||||
|
@ -825,6 +828,9 @@ class kolab_delegation_engine
|
|||
continue;
|
||||
}
|
||||
}
|
||||
else if (!$shared || $ns != 'shared') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$calendars[$cal->id] = $cal;
|
||||
|
|
|
@ -406,8 +406,8 @@ class libcalendaring_itip
|
|||
else if (!$existing && !$rsvp) {
|
||||
$action = 'import';
|
||||
}
|
||||
else if ($latest && $status_lc != 'needs-action') {
|
||||
$action = 'update';
|
||||
else if ($status_lc != 'needs-action') {
|
||||
$action = !$latest ? 'update' : '';
|
||||
}
|
||||
|
||||
$html = html::div('rsvp-status ' . $status_lc, $status_text);
|
||||
|
|
|
@ -1565,43 +1565,61 @@ class libcalendaring extends rcube_plugin
|
|||
* Merge attendees of the old and new event version
|
||||
* with keeping current user and his delegatees status
|
||||
*
|
||||
* @param array &$new New object data
|
||||
* @param array $old Old object data
|
||||
* @param array &$new New object data
|
||||
* @param array $old Old object data
|
||||
* @param bool $status New status of the current user
|
||||
*/
|
||||
public function merge_attendees(&$new, $old)
|
||||
public function merge_attendees(&$new, $old, $status = null)
|
||||
{
|
||||
$emails = $this->get_user_emails();
|
||||
$delegates = array();
|
||||
$attendees = array();
|
||||
if (empty($status)) {
|
||||
$emails = $this->get_user_emails();
|
||||
$delegates = array();
|
||||
$attendees = array();
|
||||
|
||||
// keep attendee status of the current user
|
||||
foreach ((array) $new['attendees'] as $i => $attendee) {
|
||||
if (empty($attendee['email'])) {
|
||||
continue;
|
||||
// keep attendee status of the current user
|
||||
foreach ((array) $new['attendees'] as $i => $attendee) {
|
||||
if (empty($attendee['email'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attendees[] = $email = strtolower($attendee['email']);
|
||||
|
||||
if (in_array($email, $emails)) {
|
||||
foreach ($old['attendees'] as $_attendee) {
|
||||
if ($attendee['email'] == $_attendee['email']) {
|
||||
$new['attendees'][$i] = $_attendee;
|
||||
if ($_attendee['status'] == 'DELEGATED' && ($email = $_attendee['delegated-to'])) {
|
||||
$delegates[] = strtolower($email);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$attendees[] = $email = strtolower($attendee['email']);
|
||||
|
||||
if (in_array($email, $emails)) {
|
||||
foreach ($old['attendees'] as $_attendee) {
|
||||
if ($attendee['email'] == $_attendee['email']) {
|
||||
$new['attendees'][$i] = $_attendee;
|
||||
if ($_attendee['status'] == 'DELEGATED' && ($email = $_attendee['delegated-to'])) {
|
||||
$delegates[] = strtolower($email);
|
||||
// make sure delegated attendee is not lost
|
||||
foreach ($delegates as $delegatee) {
|
||||
if (!in_array($delegatee, $attendees)) {
|
||||
foreach ((array) $old['attendees'] as $attendee) {
|
||||
if ($attendee['email'] && ($email = strtolower($attendee['email'])) && $email == $delegatee) {
|
||||
$new['attendees'][] = $attendee;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make sure delegated attendee is not lost
|
||||
foreach ($delegates as $delegatee) {
|
||||
if (!in_array($delegatee, $attendees)) {
|
||||
foreach ((array) $old['attendees'] as $attendee) {
|
||||
if ($attendee['email'] && ($email = strtolower($attendee['email'])) && $email == $delegatee) {
|
||||
$new['attendees'][] = $attendee;
|
||||
// We also make sure that status of any attendee
|
||||
// is not overriden by NEEDS-ACTION if it was already set
|
||||
// which could happen if you work with shared events
|
||||
foreach ((array) $new['attendees'] as $i => $attendee) {
|
||||
if ($attendee['email'] && $attendee['status'] == 'NEEDS-ACTION') {
|
||||
foreach ($old['attendees'] as $_attendee) {
|
||||
if ($attendee['email'] == $_attendee['email']) {
|
||||
$new['attendees'][$i]['status'] = $_attendee['status'];
|
||||
unset($new['attendees'][$i]['rsvp']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue