mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-22 23:00:56 +01:00
* Calendar/Mail: handle meeting requests for single recurrences and exceptions
This commit is contained in:
parent
36726c7400
commit
8e419f1c1a
@ -1042,9 +1042,10 @@ class calendar_bo
|
|||||||
* @param string $date_format ='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in servertime, 'array'=array, or string with date-format
|
* @param string $date_format ='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in servertime, 'array'=array, or string with date-format
|
||||||
* @param array|int $clear_private_infos_users =null if not null, return events with self::ACL_FREEBUSY too,
|
* @param array|int $clear_private_infos_users =null if not null, return events with self::ACL_FREEBUSY too,
|
||||||
* but call clear_private_infos() with the given users
|
* but call clear_private_infos() with the given users
|
||||||
|
* @param boolean $read_recurrence =false true: read the exception, not the series master (only for recur_date && $ids='<uid>'!)
|
||||||
* @return boolean|array event or array of id => event pairs, false if the acl-check went wrong, null if $ids not found
|
* @return boolean|array event or array of id => event pairs, false if the acl-check went wrong, null if $ids not found
|
||||||
*/
|
*/
|
||||||
function read($ids,$date=null,$ignore_acl=False,$date_format='ts',$clear_private_infos_users=null)
|
function read($ids,$date=null, $ignore_acl=False, $date_format='ts', $clear_private_infos_users=null, $read_recurrence=false)
|
||||||
{
|
{
|
||||||
if (!$ids) return false;
|
if (!$ids) return false;
|
||||||
|
|
||||||
@ -1056,10 +1057,10 @@ class calendar_bo
|
|||||||
if ($ignore_acl || is_array($ids) || ($return = $this->check_perms($check,$ids,0,$date_format,$date)))
|
if ($ignore_acl || is_array($ids) || ($return = $this->check_perms($check,$ids,0,$date_format,$date)))
|
||||||
{
|
{
|
||||||
if (is_array($ids) || !isset(self::$cached_event['id']) || self::$cached_event['id'] != $ids ||
|
if (is_array($ids) || !isset(self::$cached_event['id']) || self::$cached_event['id'] != $ids ||
|
||||||
self::$cached_event_date_format != $date_format ||
|
self::$cached_event_date_format != $date_format || $read_recurrence ||
|
||||||
self::$cached_event['recur_type'] != MCAL_RECUR_NONE && self::$cached_event_date != $date)
|
self::$cached_event['recur_type'] != MCAL_RECUR_NONE && self::$cached_event_date != $date)
|
||||||
{
|
{
|
||||||
$events = $this->so->read($ids,$date ? $this->date2ts($date,true) : 0);
|
$events = $this->so->read($ids,$date ? $this->date2ts($date,true) : 0, $read_recurrence);
|
||||||
|
|
||||||
if ($events)
|
if ($events)
|
||||||
{
|
{
|
||||||
|
@ -1995,10 +1995,10 @@ class calendar_boupdate extends calendar_bo
|
|||||||
*
|
*
|
||||||
* @param array $event
|
* @param array $event
|
||||||
* @param array $old_event
|
* @param array $old_event
|
||||||
* @param Api\DateTime $instance_date For recurring events, this is the date we
|
* @param Api\DateTime|int|null $instance_date For recurring events, this is the date we
|
||||||
* are dealing with
|
* are dealing with
|
||||||
*/
|
*/
|
||||||
function check_move_alarms(Array &$event, Array $old_event = null, Api\DateTime $instance_date = null)
|
function check_move_alarms(Array &$event, Array $old_event = null, $instance_date = null)
|
||||||
{
|
{
|
||||||
if ($old_event !== null && $event['start'] == $old_event['start']) return;
|
if ($old_event !== null && $event['start'] == $old_event['start']) return;
|
||||||
|
|
||||||
@ -2008,11 +2008,20 @@ class calendar_boupdate extends calendar_bo
|
|||||||
$event['alarm'] = $this->so->read_alarms($event['id']);
|
$event['alarm'] = $this->so->read_alarms($event['id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_object($instance_date))
|
||||||
|
{
|
||||||
|
if (!is_a($instance_date, 'EGroupware\\Api\\DateTime'))
|
||||||
|
{
|
||||||
|
throw new Api\Exception\WrongParameter('$instance_date must be integer or Api\DateTime!');
|
||||||
|
}
|
||||||
|
$instance_date = $instance_date->format('ts');
|
||||||
|
}
|
||||||
|
|
||||||
foreach($event['alarm'] as &$alarm)
|
foreach($event['alarm'] as &$alarm)
|
||||||
{
|
{
|
||||||
if($event['recur_type'] != MCAL_RECUR_NONE && is_object($instance_date))
|
if($event['recur_type'] != MCAL_RECUR_NONE && $instance_date)
|
||||||
{
|
{
|
||||||
calendar_so::shift_alarm($event, $alarm, $instance_date->format('ts'));
|
calendar_so::shift_alarm($event, $alarm, $instance_date);
|
||||||
}
|
}
|
||||||
else if ($alarm['time'] !== $time->format('ts') - $alarm['offset'])
|
else if ($alarm['time'] !== $time->format('ts') - $alarm['offset'])
|
||||||
{
|
{
|
||||||
|
@ -307,9 +307,10 @@ class calendar_so
|
|||||||
*
|
*
|
||||||
* @param int|array|string $ids id or array of id's of the entries to read, or string with a single uid
|
* @param int|array|string $ids id or array of id's of the entries to read, or string with a single uid
|
||||||
* @param int $recur_date =0 if set read the next recurrence at or after the timestamp, default 0 = read the initital one
|
* @param int $recur_date =0 if set read the next recurrence at or after the timestamp, default 0 = read the initital one
|
||||||
|
* @param boolean $read_recurrence =false true: read the exception, not the series master (only for recur_date && $ids='<uid>'!)
|
||||||
* @return array|boolean array with cal_id => event array pairs or false if entry not found
|
* @return array|boolean array with cal_id => event array pairs or false if entry not found
|
||||||
*/
|
*/
|
||||||
function read($ids,$recur_date=0)
|
function read($ids, $recur_date=0, $read_recurrence=false)
|
||||||
{
|
{
|
||||||
//error_log(__METHOD__.'('.array2string($ids).",$recur_date) ".function_backtrace());
|
//error_log(__METHOD__.'('.array2string($ids).",$recur_date) ".function_backtrace());
|
||||||
$cols = self::get_columns('calendar', $this->cal_table);
|
$cols = self::get_columns('calendar', $this->cal_table);
|
||||||
@ -322,7 +323,15 @@ class calendar_so
|
|||||||
{
|
{
|
||||||
// We want only the parents to match
|
// We want only the parents to match
|
||||||
$where['cal_uid'] = $ids;
|
$where['cal_uid'] = $ids;
|
||||||
$where['cal_reference'] = 0;
|
$where[] = 'cal_deleted IS NULL';
|
||||||
|
if ($read_recurrence)
|
||||||
|
{
|
||||||
|
$where['cal_recurrence'] = $recur_date;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$where['cal_reference'] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
elseif(is_array($ids) && isset($ids[count($ids)-1]) || is_scalar($ids)) // one or more cal_id's
|
elseif(is_array($ids) && isset($ids[count($ids)-1]) || is_scalar($ids)) // one or more cal_id's
|
||||||
{
|
{
|
||||||
@ -340,7 +349,7 @@ class calendar_so
|
|||||||
));
|
));
|
||||||
unset($where['cal_id']);
|
unset($where['cal_id']);
|
||||||
}
|
}
|
||||||
if ((int) $recur_date)
|
if ((int) $recur_date && !$read_recurrence)
|
||||||
{
|
{
|
||||||
$where[] = 'cal_start >= '.(int)$recur_date;
|
$where[] = 'cal_start >= '.(int)$recur_date;
|
||||||
$group_by = 'GROUP BY '.$cols;
|
$group_by = 'GROUP BY '.$cols;
|
||||||
@ -355,6 +364,12 @@ class calendar_so
|
|||||||
|
|
||||||
$events =& $this->get_events($this->db->select($this->cal_table, $cols, $where, __LINE__, __FILE__, false, $group_by, 'calendar', 0, $join), $recur_date);
|
$events =& $this->get_events($this->db->select($this->cal_table, $cols, $where, __LINE__, __FILE__, false, $group_by, 'calendar', 0, $join), $recur_date);
|
||||||
|
|
||||||
|
// if we wanted to read the real recurrence, but we have eg. only a virtual one, we need to try again without $read_recurrence
|
||||||
|
if ((!$events || ($e = current($events)) && $e['deleted']) && $recur_date && $read_recurrence)
|
||||||
|
{
|
||||||
|
return $this->read($ids, $recur_date);
|
||||||
|
}
|
||||||
|
|
||||||
return $events ? $events : false;
|
return $events ? $events : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1991,7 +1991,8 @@ class calendar_uiforms extends calendar_ui
|
|||||||
// convert event from servertime returned by calendar_ical to user-time
|
// convert event from servertime returned by calendar_ical to user-time
|
||||||
$this->bo->server2usertime($event);
|
$this->bo->server2usertime($event);
|
||||||
|
|
||||||
if (($existing_event = $this->bo->read($event['uid'])) && !$existing_event['deleted'])
|
if (($existing_event = $this->bo->read($event['uid'], $event['recurrence'], false, 'ts', null, true)) && // true = read the exception
|
||||||
|
!$existing_event['deleted'])
|
||||||
{
|
{
|
||||||
switch(strtolower($ical_method))
|
switch(strtolower($ical_method))
|
||||||
{
|
{
|
||||||
@ -2113,23 +2114,72 @@ class calendar_uiforms extends calendar_ui
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// set status and send notification / meeting response
|
// do we need to update the event itself
|
||||||
if ($this->bo->set_status($event['id'], $user, $status))
|
elseif (self::event_changed($event, $event['old']))
|
||||||
{
|
{
|
||||||
if (!$msg) $msg = lang('Status changed');
|
// check if we are allowed to update the event
|
||||||
|
if($this->bo->check_perms(Acl::EDIT, $event['old']))
|
||||||
|
{
|
||||||
|
if ($event['recurrence'] && !$event['old']['reference'] && ($recur_event = $this->bo->read($event['id'])))
|
||||||
|
{
|
||||||
|
// first we need to add the exception to the recurrence master
|
||||||
|
$recur_event['recur_exception'][] = $event['recurrence'];
|
||||||
|
// check if we need to move the alarms, because they are next on that exception
|
||||||
|
$this->bo->check_move_alarms($recur_event, null, $event['recurrence']);
|
||||||
|
unset($recur_event['start']); unset($recur_event['end']); // no update necessary
|
||||||
|
unset($recur_event['alarm']); // unsetting alarms too, as they cant be updated without start!
|
||||||
|
$this->bo->update($recur_event, $ignore_conflicts=true, true, false, true, $msg, true);
|
||||||
|
|
||||||
|
// then we need to create the exception as new event
|
||||||
|
unset($event['id']);
|
||||||
|
$event['reference'] = $event['old']['id'];
|
||||||
|
$event['caldav_name'] = $event['old']['caldav_name'];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// keep all EGroupware only values of existing events plus alarms
|
||||||
|
unset($event['alarm']);
|
||||||
|
$event = array_merge($event['old'], $event);
|
||||||
|
}
|
||||||
|
unset($event['old']);
|
||||||
|
|
||||||
|
if (($event['id'] = $this->bo->update($event, $ignore_conflicts=true, true, false, true, $msg, true)))
|
||||||
|
{
|
||||||
|
$msg[] = lang('Event saved');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$msg[] = lang('Error saving the event!');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$event['id'] = $event['old']['id'];
|
||||||
|
$msg[] = lang('Not enough rights to update the event!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$event['id'] = $event['old']['id'];
|
||||||
|
}
|
||||||
|
// set status and send notification / meeting response
|
||||||
|
if ($this->bo->set_status($event['id'], $user, $status, $event['recurrence']))
|
||||||
|
{
|
||||||
|
$msg[] = lang('Status changed');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'apply':
|
case 'apply':
|
||||||
// set status and send notification / meeting response
|
// set status and send notification / meeting response
|
||||||
if ($this->bo->set_status($event['id'], $event['ical_sender_uid'], $event['ical_sender_status']))
|
if ($this->bo->set_status($event['id'], $event['ical_sender_uid'], $event['ical_sender_status'], $event['recurrence']))
|
||||||
{
|
{
|
||||||
$msg = lang('Status changed');
|
$msg = lang('Status changed');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'cancel':
|
case 'cancel':
|
||||||
if ($event['id'] && $this->bo->set_status($event['id'], $user, 'R'))
|
if ($event['id'] && $this->bo->set_status($event['id'], $user, 'R', $event['recurrence']))
|
||||||
{
|
{
|
||||||
$msg = lang('Status changed');
|
$msg = lang('Status changed');
|
||||||
}
|
}
|
||||||
@ -2155,7 +2205,29 @@ class calendar_uiforms extends calendar_ui
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$tpl = new Etemplate('calendar.meeting');
|
$tpl = new Etemplate('calendar.meeting');
|
||||||
$tpl->exec('calendar.calendar_uiforms.meeting', $event, array(), $readonlys, $event, 2);
|
$tpl->exec('calendar.calendar_uiforms.meeting', $event, array(), $readonlys, $event+array(
|
||||||
|
'old' => $existing_event,
|
||||||
|
), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an event changed and need to be updated
|
||||||
|
*
|
||||||
|
* @param array $_a
|
||||||
|
* @param array $_b
|
||||||
|
* @return boolean true if there are some changes, false if not
|
||||||
|
*/
|
||||||
|
function event_changed($_a, $_b)
|
||||||
|
{
|
||||||
|
static $keys_to_check = array('start', 'end', 'title', 'description', 'location', 'participants',
|
||||||
|
'recur_type', 'recur_data', 'recur_interval', 'recur_exception');
|
||||||
|
|
||||||
|
$a = array_intersect_key($_a, array_flip($keys_to_check));
|
||||||
|
$b = array_intersect_key($_b, array_flip($keys_to_check));
|
||||||
|
|
||||||
|
$ret = $a != $b;
|
||||||
|
error_log(__METHOD__."() returning ".array2string($ret)." diff=".array2string(array_diff_key($a, $b)));
|
||||||
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -825,7 +825,7 @@ class calendar_zpush implements activesync_plugin_write, activesync_plugin_meeti
|
|||||||
{
|
{
|
||||||
$event['recur_enddate'] = Api\DateTime::server2user($message->recurrence->until);
|
$event['recur_enddate'] = Api\DateTime::server2user($message->recurrence->until);
|
||||||
}
|
}
|
||||||
$event['recur_exceptions'] = array();
|
$event['recur_exception'] = array();
|
||||||
if ($message->exceptions)
|
if ($message->exceptions)
|
||||||
{
|
{
|
||||||
foreach($message->exceptions as $exception)
|
foreach($message->exceptions as $exception)
|
||||||
|
Loading…
Reference in New Issue
Block a user