aggregate freebusy periods and fix off by one sec due to whole-day events

This commit is contained in:
Ralf Becker 2017-09-29 09:39:47 +02:00
parent 50697efe55
commit d75ca6ad13

View File

@ -2488,6 +2488,7 @@ class calendar_ical extends calendar_boupdate
$component->getAllAttributes('DTEND'), $component->getAllAttributes('DTEND'),
$component->getAllAttributes('DURATION')) as $attributes) $component->getAllAttributes('DURATION')) as $attributes)
{ {
error_log(__METHOD__."() attribute=".array2string($attributes));
switch ($attributes['name']) switch ($attributes['name'])
{ {
case 'DTSTART': case 'DTSTART':
@ -3347,16 +3348,18 @@ class calendar_ical extends calendar_boupdate
{ {
$vfreebusy->setAttribute($attr, $value); $vfreebusy->setAttribute($attr, $value);
} }
$fbdata = parent::search(array( $events = parent::search(array(
'start' => $start, 'start' => $start,
'end' => $end, 'end' => $end,
'users' => $user, 'users' => $user,
'date_format' => 'server', 'date_format' => 'server',
'show_rejected' => false, 'show_rejected' => false,
)); ));
if (is_array($fbdata)) if (is_array($events))
{ {
foreach ($fbdata as $event) $fbdata = array();
foreach ($events as $event)
{ {
if ($event['non_blocking']) continue; if ($event['non_blocking']) continue;
if ($event['uid'] === $extra['X-CALENDARSERVER-MASK-UID']) continue; if ($event['uid'] === $extra['X-CALENDARSERVER-MASK-UID']) continue;
@ -3367,19 +3370,30 @@ class calendar_ical extends calendar_boupdate
$fbtype = $status == 'T' ? 'BUSY-TENTATIVE' : 'BUSY'; $fbtype = $status == 'T' ? 'BUSY-TENTATIVE' : 'BUSY';
if ($utc) // hack to fix end-time to be non-inclusive
// all-day events end in our data-model at 23:59:59 (of given TZ)
if (date('is', $event['end']) == '5959') ++$event['end'];
$fbdata[$fbtype][] = $event;
}
foreach($fbdata as $fbtype => $events)
{
foreach($this->aggregate_periods($events, $start, $end) as $event)
{ {
$vfreebusy->setAttribute('FREEBUSY',array(array( if ($utc)
'start' => $event['start'], {
'end' => $event['end'], $vfreebusy->setAttribute('FREEBUSY',array(array(
)), array('FBTYPE' => $fbtype)); 'start' => $event['start'],
} 'end' => $event['end'],
else )), array('FBTYPE' => $fbtype));
{ }
$vfreebusy->setAttribute('FREEBUSY',array(array( else
'start' => date('Ymd\THis',$event['start']), {
'end' => date('Ymd\THis',$event['end']), $vfreebusy->setAttribute('FREEBUSY',array(array(
)), array('FBTYPE' => $fbtype)); 'start' => date('Ymd\THis',$event['start']),
'end' => date('Ymd\THis',$event['end']),
)), array('FBTYPE' => $fbtype));
}
} }
} }
} }
@ -3387,4 +3401,61 @@ class calendar_ical extends calendar_boupdate
return $vcal->exportvCalendar($charset); return $vcal->exportvCalendar($charset);
} }
/**
* Aggregate multiple, possibly overlapping events cliped by $start and $end
*
* @param array $events array with values for keys "start" and "end"
* @param int $start
* @param int $end
* @return array of array with values for keys "start" and "end"
*/
public function aggregate_periods(array $events, $start, $end)
{
// sort by start datetime
uasort($events, function($a, $b)
{
$diff = $a['start'] < $b['start'];
return !$diff ? 0 : ($diff < 0 ? -1 : 1);
});
$fbdata = array();
foreach($events as $event)
{
error_log(__METHOD__."(..., $start, $end) event[start]=$event[start], event[end]=$event[end], fbdata=".array2string($fbdata));
if ($event['end'] <= $start || $event['start'] >= $end) continue;
if (!$fbdata)
{
$fbdata[] = array(
'start' => $event['start'] < $start ? $start : $event['start'],
'end' => $event['end'],
);
continue;
}
$last =& $fbdata[count($fbdata)-1];
if ($last['end'] >= $event['start'])
{
if ($last['end'] < $event['end'])
{
$last['end'] = $event['end'];
}
}
else
{
$fbdata[] = array(
'start' => $event['start'],
'end' => $event['end'],
);
}
}
$last =& $fbdata[count($fbdata)-1];
if ($last['end'] > $end) $last['end'] = $end;
error_log(__METHOD__."(..., $start, $end) returning ".array2string($fbdata));
return $fbdata;
}
} }