Save changes in a recurring event as exception to the master event
This commit is contained in:
parent
53c77796dd
commit
91779df09a
7 changed files with 128 additions and 27 deletions
|
@ -1096,6 +1096,7 @@ class calendar extends rcube_plugin
|
|||
$event['recurrence_text'] = $this->_recurrence_text($event['recurrence']);
|
||||
if ($event['recurrence']['UNTIL'])
|
||||
$event['recurrence']['UNTIL'] = $this->lib->adjust_timezone($event['recurrence']['UNTIL'])->format('c');
|
||||
unset($event['recurrence']['EXCEPTIONS']);
|
||||
}
|
||||
|
||||
foreach ((array)$event['attachments'] as $k => $attachment) {
|
||||
|
@ -1109,7 +1110,7 @@ class calendar extends rcube_plugin
|
|||
'title' => strval($event['title']),
|
||||
'description' => strval($event['description']),
|
||||
'location' => strval($event['location']),
|
||||
'className' => ($addcss ? 'fc-event-cal-'.asciiwords($event['calendar'], true).' ' : '') . 'fc-event-cat-' . asciiwords(strtolower($event['categories']), true),
|
||||
'className' => ($addcss ? 'fc-event-cal-'.asciiwords($event['calendar'], true).' ' : '') . 'fc-event-cat-' . asciiwords(strtolower(join('-', (array)$event['categories'])), true),
|
||||
'allDay' => ($event['allday'] == 1),
|
||||
) + $event;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
* 'COUNT' => 1..n, // number of times
|
||||
* // + more properties (see http://www.kanzaki.com/docs/ical/recur.html)
|
||||
* 'EXDATE' => array(), // list of DateTime objects of exception Dates/Times
|
||||
* 'EXCEPTIONS' => array(<event>), list of event objects which denote exceptions in the recurrence chain
|
||||
* ),
|
||||
* 'recurrence_id' => 'ID of the recurrence group', // usually the ID of the starting event
|
||||
* 'categories' => 'Event category',
|
||||
|
|
|
@ -312,7 +312,7 @@ class kolab_calendar
|
|||
* @return boolean True on success, False on error
|
||||
*/
|
||||
|
||||
public function update_event($event)
|
||||
public function update_event($event, $exception_id = null)
|
||||
{
|
||||
$updated = false;
|
||||
$old = $this->storage->get_object($event['id']);
|
||||
|
@ -333,6 +333,11 @@ class kolab_calendar
|
|||
else {
|
||||
$updated = true;
|
||||
$this->events[$event['id']] = $this->_to_rcube_event($object);
|
||||
|
||||
// refresh local cache with recurring instances
|
||||
if ($exception_id) {
|
||||
$this->_get_recurring_events($object, $event['start'], $event['end'], $exception_id);
|
||||
}
|
||||
}
|
||||
|
||||
return $updated;
|
||||
|
@ -413,6 +418,24 @@ class kolab_calendar
|
|||
$end->add(new DateInterval($intvl));
|
||||
}
|
||||
|
||||
// add recurrence exceptions to output
|
||||
$i = 0;
|
||||
$events = array();
|
||||
if (is_array($event['recurrence']['EXCEPTIONS'])) {
|
||||
foreach ($event['recurrence']['EXCEPTIONS'] as $exception) {
|
||||
$rec_event = $this->_to_rcube_event($exception);
|
||||
$rec_event['id'] = $event['uid'] . '-' . ++$i;
|
||||
$rec_event['recurrence_id'] = $event['uid'];
|
||||
$rec_event['_instance'] = $i;
|
||||
$events[] = $rec_event;
|
||||
|
||||
if ($rec_event['id'] == $event_id) {
|
||||
$this->events[$rec_event['id']] = $rec_event;
|
||||
return $events;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// use libkolab to compute recurring events
|
||||
if (class_exists('kolabcalendaring')) {
|
||||
$recurrence = new kolab_date_recurrence($object);
|
||||
|
@ -423,8 +446,6 @@ class kolab_calendar
|
|||
$recurrence = new calendar_recurrence($this->cal, $event);
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
$events = array();
|
||||
while ($next_event = $recurrence->next_instance()) {
|
||||
$rec_start = $next_event['start']->format('U');
|
||||
$rec_end = $next_event['end']->format('U');
|
||||
|
|
|
@ -565,6 +565,8 @@ class kolab_driver extends calendar_driver
|
|||
// keep saved exceptions (not submitted by the client)
|
||||
if ($old['recurrence']['EXDATE'])
|
||||
$event['recurrence']['EXDATE'] = $old['recurrence']['EXDATE'];
|
||||
if ($old['recurrence']['EXCEPTIONS'])
|
||||
$event['recurrence']['EXCEPTIONS'] = $old['recurrence']['EXCEPTIONS'];
|
||||
|
||||
switch ($savemode) {
|
||||
case 'new':
|
||||
|
@ -582,26 +584,11 @@ class kolab_driver extends calendar_driver
|
|||
break;
|
||||
|
||||
case 'current':
|
||||
// modifying the first instance => just move to next occurence
|
||||
if ($master['id'] == $event['id']) {
|
||||
$recurring = reset($storage->_get_recurring_events($event, $event['start'], null, $event['id'].'-1'));
|
||||
$master['start'] = $recurring['start'];
|
||||
$master['end'] = $recurring['end'];
|
||||
if ($master['recurrence']['COUNT'])
|
||||
$master['recurrence']['COUNT']--;
|
||||
}
|
||||
else { // add exception to master event
|
||||
$master['recurrence']['EXDATE'][] = $old['start'];
|
||||
}
|
||||
|
||||
$storage->update_event($master);
|
||||
|
||||
// insert new event for this occurence
|
||||
$event += $old;
|
||||
// save as exception to master event
|
||||
$event['recurrence'] = array();
|
||||
unset($event['recurrence_id']);
|
||||
$event['uid'] = $this->cal->generate_uid();
|
||||
$success = $storage->insert_event($event);
|
||||
$master['recurrence']['EXCEPTIONS'][] = $event;
|
||||
# $master['recurrence']['EXDATE'][] = $event['start'];
|
||||
$success = $storage->update_event($master);
|
||||
break;
|
||||
|
||||
case 'future':
|
||||
|
@ -632,6 +619,17 @@ class kolab_driver extends calendar_driver
|
|||
}
|
||||
|
||||
default: // 'all' is default
|
||||
|
||||
// save properties to a recurrence exception instance
|
||||
if ($old['recurrence_id']) {
|
||||
$i = $old['_instance'] - 1;
|
||||
if (!empty($master['recurrence']['EXCEPTIONS'][$i])) {
|
||||
$master['recurrence']['EXCEPTIONS'][$i] = $event;
|
||||
$success = $storage->update_event($master, $old['id']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$event['id'] = $master['id'];
|
||||
$event['uid'] = $master['uid'];
|
||||
|
||||
|
|
|
@ -107,6 +107,8 @@ class libcalendaring extends rcube_plugin
|
|||
$dt = new DateTime('@'.$td);
|
||||
else if (is_string($dt))
|
||||
$dt = new DateTime($dt);
|
||||
else
|
||||
return $dt;
|
||||
|
||||
$dt->setTimezone($this->timezone);
|
||||
return $dt;
|
||||
|
|
|
@ -30,6 +30,19 @@ class kolab_format_event extends kolab_format_xcal
|
|||
protected $read_func = 'readEvent';
|
||||
protected $write_func = 'writeEvent';
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
function __construct($data = null, $version = 3.0)
|
||||
{
|
||||
parent::__construct(is_string($data) ? $data : null, $version);
|
||||
|
||||
// got an Event object as argument
|
||||
if (is_object($data) && is_a($data, $this->objclass)) {
|
||||
$this->obj = $data;
|
||||
$this->loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones into an instance of libcalendaring's extended EventCal class
|
||||
|
@ -90,6 +103,18 @@ class kolab_format_event extends kolab_format_xcal
|
|||
}
|
||||
$this->obj->setAttachments($vattach);
|
||||
|
||||
// save recurrence exceptions
|
||||
if ($object['recurrence']['EXCEPTIONS']) {
|
||||
$vexceptions = new vectorevent;
|
||||
foreach((array)$object['recurrence']['EXCEPTIONS'] as $exception) {
|
||||
$exevent = new kolab_format_event;
|
||||
$exevent->set($this->compact_exception($exception, $object)); // only save differing values
|
||||
$exevent->obj->setRecurrenceID(self::get_datetime($exception['start'], null, true), false);
|
||||
$vexceptions->push($exevent->obj);
|
||||
}
|
||||
$this->obj->setExceptions($vexceptions);
|
||||
}
|
||||
|
||||
// cache this data
|
||||
$this->data = $object;
|
||||
unset($this->data['_formatobj']);
|
||||
|
@ -160,6 +185,18 @@ class kolab_format_event extends kolab_format_xcal
|
|||
}
|
||||
}
|
||||
|
||||
// read exception event objects
|
||||
if ($exceptions = $this->obj->exceptions()) {
|
||||
for ($i=0; $i < $exceptions->size(); $i++) {
|
||||
if (($exobj = $exceptions->get($i))) {
|
||||
$exception = new kolab_format_event($exobj);
|
||||
if ($exception->is_valid()) {
|
||||
$object['recurrence']['EXCEPTIONS'][] = $this->expand_exception($exception->to_array(), $object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// merge with additional data, e.g. attachments from the message
|
||||
if ($data) {
|
||||
foreach ($data as $idx => $value) {
|
||||
|
@ -195,4 +232,45 @@ class kolab_format_event extends kolab_format_xcal
|
|||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce the exception container to attributes which differ from the master event
|
||||
*/
|
||||
private function compact_exception($exception, $master)
|
||||
{
|
||||
static $mandatory = array('uid','created','start');
|
||||
static $forbidden = array('recurrence','attendees','sequence');
|
||||
|
||||
$out = $exception;
|
||||
foreach ($exception as $prop => $val) {
|
||||
if (in_array($prop, $mandatory))
|
||||
continue;
|
||||
|
||||
if (is_object($exception[$prop]) && is_a($exception[$prop], 'DateTime'))
|
||||
$equals = $exception[$prop] <> $master[$prop];
|
||||
else
|
||||
$equals = $exception[$prop] == $master[$prop];
|
||||
|
||||
if ($equals || in_array($prop, $forbidden)) {
|
||||
unset($out[$prop]);
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy attributes not specified by the exception from the master event
|
||||
*/
|
||||
private function expand_exception($exception, $master)
|
||||
{
|
||||
static $forbidden = array('recurrence');
|
||||
|
||||
foreach ($master as $prop => $value) {
|
||||
if (empty($exception[$prop]) && !in_array($prop, $forbidden))
|
||||
$exception[$prop] = $value;
|
||||
}
|
||||
|
||||
return $exception;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ abstract class kolab_format_xcal extends kolab_format
|
|||
);
|
||||
|
||||
// read organizer and attendees
|
||||
if ($organizer = $this->obj->organizer()) {
|
||||
if (($organizer = $this->obj->organizer()) && ($organizer->email() || $organizer->name())) {
|
||||
$object['organizer'] = array(
|
||||
'email' => $organizer->email(),
|
||||
'name' => $organizer->name(),
|
||||
|
@ -170,9 +170,9 @@ abstract class kolab_format_xcal extends kolab_format
|
|||
$object['recurrence']['BYMONTH'] = join(',', self::vector2array($bymonth));
|
||||
}
|
||||
|
||||
if ($exceptions = $this->obj->exceptionDates()) {
|
||||
for ($i=0; $i < $exceptions->size(); $i++) {
|
||||
if ($exdate = self::php_datetime($exceptions->get($i)))
|
||||
if ($exdates = $this->obj->exceptionDates()) {
|
||||
for ($i=0; $i < $exdates->size(); $i++) {
|
||||
if ($exdate = self::php_datetime($exdates->get($i)))
|
||||
$object['recurrence']['EXDATE'][] = $exdate;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue