Exemplo n.º 1
0
 /**
  * (non-PHPdoc)
  * @see ActiveSync/ActiveSync_TestCase::setUp()
  */
 protected function setUp()
 {
     parent::setUp();
     // replace email to make current user organizer and attendee
     $this->_testXMLInput = str_replace('*****@*****.**', Tinebase_Core::getUser()->accountEmailAddress, $this->_testXMLInput);
     $event = new Calendar_Model_Event(array('uid' => Tinebase_Record_Abstract::generateUID(), 'summary' => 'SyncTest', 'dtstart' => Tinebase_DateTime::now()->addMonth(1)->toString(Tinebase_Record_Abstract::ISO8601LONG), 'dtend' => Tinebase_DateTime::now()->addMonth(1)->addHour(1)->toString(Tinebase_Record_Abstract::ISO8601LONG), 'originator_tz' => 'Europe/Berlin', 'container_id' => $this->_getContainerWithSyncGrant()->getId(), Tinebase_Model_Grants::GRANT_EDIT => true, 'attendee' => new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(array('user_id' => Tinebase_Core::getUser()->contact_id, 'user_type' => Calendar_Model_Attender::USERTYPE_USER, 'status' => Calendar_Model_Attender::STATUS_ACCEPTED)))));
     $event = Calendar_Controller_Event::getInstance()->create($event);
     $this->objects['event'] = $event;
     $event2MonthsBack = new Calendar_Model_Event(array('uid' => Tinebase_Record_Abstract::generateUID(), 'summary' => 'SyncTest', 'dtstart' => Tinebase_DateTime::now()->subMonth(2)->toString(Tinebase_Record_Abstract::ISO8601LONG), 'dtend' => Tinebase_DateTime::now()->subMonth(2)->addHour(1)->toString(Tinebase_Record_Abstract::ISO8601LONG), 'originator_tz' => 'Europe/Berlin', 'container_id' => $this->_getContainerWithSyncGrant()->getId(), Tinebase_Model_Grants::GRANT_EDIT => true));
     $event = Calendar_Controller_Event::getInstance()->create($event2MonthsBack);
     $this->objects['event2MonthsBack'] = $event;
     $eventDaily = new Calendar_Model_Event(array('uid' => Tinebase_Record_Abstract::generateUID(), 'summary' => 'SyncTest', 'dtstart' => Tinebase_DateTime::now()->addMonth(1)->toString(Tinebase_Record_Abstract::ISO8601LONG), 'dtend' => Tinebase_DateTime::now()->addMonth(1)->addHour(1)->toString(Tinebase_Record_Abstract::ISO8601LONG), 'originator_tz' => 'Europe/Berlin', 'rrule' => 'FREQ=DAILY;INTERVAL=1;UNTIL=' . Tinebase_DateTime::now()->addMonth(1)->addDay(6)->setHour(22)->setMinute(59)->setSecond(59)->toString(Tinebase_Record_Abstract::ISO8601LONG), 'container_id' => $this->_getContainerWithSyncGrant()->getId(), Tinebase_Model_Grants::GRANT_EDIT => true));
     $eventDaily = Calendar_Controller_Event::getInstance()->create($eventDaily);
     // compute recurset
     $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($eventDaily, new Tinebase_Record_RecordSet('Calendar_Model_Event'), $eventDaily->dtstart, $eventDaily->rrule_until);
     // first deleted instance
     Calendar_Controller_Event::getInstance()->createRecurException($recurSet[0], true);
     // second deleted instance
     Calendar_Controller_Event::getInstance()->createRecurException($recurSet[1], true);
     // first exception instance
     $recurSet[2]->dtstart->addHour(2);
     $recurSet[2]->dtend->addHour(2);
     $recurSet[2]->summary = 'Test Exception 1';
     Calendar_Controller_Event::getInstance()->createRecurException($recurSet[2]);
     // first exception instance
     $recurSet[3]->dtstart->addHour(3);
     $recurSet[3]->dtend->addHour(3);
     $recurSet[3]->summary = 'Test Exception 2';
     Calendar_Controller_Event::getInstance()->createRecurException($recurSet[3]);
     // reread event from database again
     $eventDaily = Calendar_Controller_Event::getInstance()->get($eventDaily);
     #var_dump($eventDaily->toArray());
     $this->objects['eventDaily'] = $eventDaily;
     Tinebase_Core::getPreference('ActiveSync')->setValue(ActiveSync_Preference::DEFAULTCALENDAR, $this->_getContainerWithSyncGrant()->getId());
     ########### define test filter
     $filterBackend = new Tinebase_PersistentFilter_Backend_Sql();
     try {
         $filter = $filterBackend->getByProperty('Calendar Sync Test', 'name');
     } catch (Tinebase_Exception_NotFound $e) {
         $filter = new Tinebase_Model_PersistentFilter(array('application_id' => Tinebase_Application::getInstance()->getApplicationByName('Calendar')->getId(), 'account_id' => Tinebase_Core::getUser()->getId(), 'model' => 'Calendar_Model_EventFilter', 'filters' => array(array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getContainerWithSyncGrant()->getId())), 'name' => 'Calendar Sync Test', 'description' => 'Created by unit test'));
         $filter = $filterBackend->create($filter);
     }
     $this->objects['filter'] = $filter;
     ########### define test devices
     $palm = ActiveSync_Backend_DeviceTests::getTestDevice(Syncope_Model_Device::TYPE_WEBOS);
     $palm->owner_id = $this->_testUser->getId();
     $palm->calendarfilter_id = $this->objects['filter']->getId();
     $this->objects['deviceWebOS'] = ActiveSync_Controller_Device::getInstance()->create($palm);
     $iphone = ActiveSync_Backend_DeviceTests::getTestDevice(Syncope_Model_Device::TYPE_IPHONE);
     $iphone->owner_id = $this->_testUser->getId();
     $iphone->calendarfilter_id = $this->objects['filter']->getId();
     $this->objects['deviceIPhone'] = ActiveSync_Controller_Device::getInstance()->create($iphone);
 }
 public function testExportRecurSet()
 {
     $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
     $from = clone $this->_testEvent->dtstart;
     $until = clone $this->_testEvent->dtend;
     $until->addDay(2);
     $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($this->_testEvent, $exceptions, $from, $until);
     $this->_testEvent->exdate = array($recurSet->dtstart[0]);
     $eventSet = new Tinebase_Record_RecordSet('Calendar_Model_Event', array($this->_testEvent, $recurSet[1]));
     $exporter = new Calendar_Export_Ical();
     $ics = $exporter->eventToIcal($eventSet);
     $this->assertEquals(2, preg_match_all('/BEGIN:VEVENT\\r\\n/', $ics, $matches), 'There should be exactly 2 VEVENT compontents');
 }
 /**
  * merges Recurrences of given events into the given event set
  * 
  * @param  Tinebase_Record_RecordSet    $_events
  * @param  Tinebase_DateTime                    $_from
  * @param  Tinebase_DateTime                    $_until
  * @return void
  */
 public static function mergeRecurrenceSet($_events, $_from, $_until)
 {
     if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
         Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . " from: {$_from} until: {$_until}");
     }
     //compute recurset
     $candidates = $_events->filter('rrule', "/^FREQ.*/", TRUE);
     foreach ($candidates as $candidate) {
         try {
             $exceptions = $_events->filter('recurid', "/^{$candidate->uid}-.*/", TRUE);
             $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($candidate, $exceptions, $_from, $_until);
             foreach ($recurSet as $event) {
                 $_events->addRecord($event);
             }
             // check if candidate/baseEvent has an exception itself -> in this case remove baseEvent from set
             if (is_array($candidate->exdate) && in_array($candidate->dtstart, $candidate->exdate)) {
                 $_events->removeRecord($candidate);
             }
         } catch (Exception $e) {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Could not compute recurSet of event: {$candidate->getId()}");
             }
             Tinebase_Exception::log($e);
             continue;
         }
     }
 }
 public function testAlarmAdjust()
 {
     $event = new Calendar_Model_Event(array('uid' => Tinebase_Record_Abstract::generateUID(), 'summary' => 'custom alarm', 'dtstart' => '2011-12-30 10:30:00', 'dtend' => '2011-12-30 12:30:00', 'rrule' => 'FREQ=YEARLY', 'originator_tz' => 'Europe/Berlin', 'alarms' => array(array('alarm_time' => '2011-12-20 10:30:00', 'minutes_before' => 'custom', 'options' => Zend_Json::encode(array('minutes_before' => 14400, 'recurid' => NULL, 'custom' => TRUE)))), Tinebase_Model_Grants::GRANT_EDIT => true));
     $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
     $from = new Tinebase_DateTime('2012-01-01 00:00:00');
     $until = new Tinebase_DateTime('2012-12-31 23:59:59');
     $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($event, $exceptions, $from, $until);
     $this->assertEquals(1, count($recurSet), 'recur set failed');
     $this->assertEquals('2012-12-20 10:30:00', (string) $recurSet->getFirstRecord()->alarms->getFirstRecord()->alarm_time);
 }
Exemplo n.º 5
0
 public function testUpdateRecurDtstartOverDst()
 {
     // note: 2009-03-29 Europe/Berlin switched to DST
     $event = new Calendar_Model_Event(array('uid' => Tinebase_Record_Abstract::generateUID(), 'summary' => 'Abendessen', 'dtstart' => '2009-03-25 18:00:00', 'dtend' => '2009-03-25 18:30:00', 'originator_tz' => 'Europe/Berlin', 'rrule' => 'FREQ=DAILY;INTERVAL=1;UNTIL=2009-04-02 17:30:00', 'exdate' => '2009-03-27 18:00:00,2009-03-31 17:00:00', 'container_id' => $this->_testCalendar->getId(), Tinebase_Model_Grants::GRANT_EDIT => true));
     $persistentEvent = $this->_controller->create($event);
     $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
     $from = new Tinebase_DateTime('2009-03-26 00:00:00');
     $until = new Tinebase_DateTime('2009-04-03 23:59:59');
     $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($persistentEvent, $exceptions, $from, $until);
     // 9 days
     // skip 27(exception), 31(exception), 03(until)
     $this->assertEquals(6, count($recurSet));
     $exceptionBeforeDstBoundary = clone $recurSet[1];
     // 28.
     $persistentExceptionBeforeDstBoundary = $this->_controller->createRecurException($exceptionBeforeDstBoundary);
     $exceptionAfterDstBoundary = clone $recurSet[5];
     // 02.
     $persistentExceptionAfterDstBoundary = $this->_controller->createRecurException($exceptionAfterDstBoundary);
     $persistentEvent->dtstart->addDay(5);
     //30.
     $persistentEvent->dtend->addDay(5);
     $from->addDay(5);
     //31
     $until->addDay(5);
     //08
     $updatedPersistenEvent = $this->_controller->update($persistentEvent);
     $persistentEvents = $this->_controller->search(new Calendar_Model_EventFilter(array(array('field' => 'period', 'operator' => 'within', 'value' => array('from' => $from, 'until' => $until)), array('field' => 'uid', 'operator' => 'equals', 'value' => $persistentEvent->uid))));
     //print_r($persistentEvents->toArray());
     // we don't 'see' the persistent exception from 28/
     $this->assertEquals(2, count($persistentEvents));
     $exceptions = $persistentEvents->filter('recurid', "/^{$persistentEvent->uid}-.*/", TRUE);
     $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($updatedPersistenEvent, $exceptions, $from, $until);
     // until is not adopted
     $this->assertEquals(2, count($recurSet));
 }
 /**
  * testUpdatePreserveAlarmProperties
  * 
  * @see #7430: Calendar sends too much alarms for recurring events
  */
 public function testUpdatePreserveAlarmProperties()
 {
     $alarm30 = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array(array('minutes_before' => 30)), TRUE);
     $event = $this->_getEvent();
     $event->dtstart = Tinebase_DateTime::now()->subDay(1)->addMinute(15);
     $event->dtend = clone $event->dtstart;
     $event->dtend->addHour(2);
     $event->rrule = 'FREQ=DAILY;INTERVAL=1;COUNT=3';
     $event->alarms = clone $alarm30;
     $event->organizer = Tinebase_Core::getUser()->contact_id;
     $event = Calendar_Controller_Event::getInstance()->create($event);
     $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
     $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($event, $exceptions, $event->dtstart, Tinebase_DateTime::now()->addDay(1));
     $exceptionEvent = Calendar_Controller_Event::getInstance()->createRecurException($recurSet->getFirstRecord());
     Tinebase_Alarm::getInstance()->sendPendingAlarms("Tinebase_Event_Async_Minutely");
     Calendar_Controller_EventNotificationsTests::flushMailer();
     $event = $this->_uit->get($event->getId());
     $persistentAlarm = $event->exdate[0]->alarms->getFirstRecord();
     $event->alarms = $event->alarms = clone $alarm30;
     Calendar_Controller_Alarm::setAcknowledgeTime($event->alarms, Tinebase_DateTime::now());
     foreach ($event->exdate as $exdate) {
         $exdate->alarms = clone $alarm30;
     }
     $updatedEvent = $this->_uit->update($event);
     $updatedAlarm = $updatedEvent->exdate[0]->alarms->getFirstRecord();
     $this->assertNotNull($persistentAlarm);
     $diff = $persistentAlarm->diff($updatedAlarm);
     $this->assertTrue($diff->isEmpty(), 'no diff');
     $this->assertTrue(Calendar_Controller_Alarm::getAcknowledgeTime($updatedEvent->alarms->getFirstRecord()) instanceof Tinebase_DateTime, 'ack time missing');
 }
 /**
  * testRecuringAlarmWithThisAndFutureSplit
  * 
  * @see 0008386: alarm is sent for recur series that is already over
  */
 public function testRecuringAlarmWithThisAndFutureSplit()
 {
     $this->markTestSkipped('@see 0009816: fix failing testRecuringAlarmWithThisAndFutureSplit test');
     $event = $this->_getEvent();
     // lets flush mailer so next flushing ist faster!
     Tinebase_Alarm::getInstance()->sendPendingAlarms("Tinebase_Event_Async_Minutely");
     self::flushMailer();
     // make sure next occurence contains now
     $event->dtstart = Tinebase_DateTime::now()->subMonth(1)->addDay(1)->subHour(2);
     $event->dtend = clone $event->dtstart;
     $event->dtend->addMinute(60);
     $event->rrule = 'FREQ=MONTHLY;INTERVAL=1;BYMONTHDAY=' . $event->dtstart->format('d');
     $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array(new Tinebase_Model_Alarm(array('minutes_before' => 2880), TRUE)));
     $persistentEvent = $this->_eventController->create($event);
     // make sure, next alarm is for next month's event
     Tinebase_Alarm::getInstance()->sendPendingAlarms("Tinebase_Event_Async_Minutely");
     self::flushMailer();
     // split THISANDFUTURE, alarm of old series should be set to SUCCESS because it no longer should be sent
     $from = $event->dtstart;
     $until = $event->dtend->addMonth(2);
     $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
     $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($persistentEvent, $exceptions, $from, $until);
     $recurEvent = count($recurSet) > 1 ? $recurSet[1] : $recurSet[0];
     // next month
     $recurEvent->summary = 'split series';
     $newPersistentEvent = $this->_eventController->createRecurException($recurEvent, FALSE, TRUE);
     // check alarms
     $oldSeriesAlarm = Tinebase_Alarm::getInstance()->getAlarmsOfRecord('Calendar_Model_Event', $persistentEvent->getId())->getFirstRecord();
     $this->assertEquals(Tinebase_Model_Alarm::STATUS_SUCCESS, $oldSeriesAlarm->sent_status, 'no pending alarm should exist for old series: ' . print_r($oldSeriesAlarm->toArray(), TRUE));
 }
Exemplo n.º 8
0
 /**
  * @see {http://forge.tine20.org/mantisbt/view.php?id=5686}
  */
 public function testCreateRecurExceptionAllFollowingAttendeeAdd()
 {
     $from = new Tinebase_DateTime('2012-02-01 00:00:00');
     $until = new Tinebase_DateTime('2012-02-29 23:59:59');
     $event = new Calendar_Model_Event(array('summary' => 'Some Daily Event', 'dtstart' => '2012-02-03 09:00:00', 'dtend' => '2012-02-03 10:00:00', 'rrule' => 'FREQ=DAILY;INTERVAL=1', 'container_id' => $this->_testCalendar->getId(), 'attendee' => $this->_getAttendee()));
     $persistentEvent = $this->_controller->create($event);
     $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
     $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($persistentEvent, $exceptions, $from, $until);
     $recurSet[5]->attendee->addRecord(new Calendar_Model_Attender(array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_personasContacts['pwulf']->getId())));
     $updatedPersistentEvent = $this->_controller->createRecurException($recurSet[5], FALSE, TRUE);
     $this->assertEquals(3, count($updatedPersistentEvent->attendee));
 }
 public function testExdateContainerMoveUpdateException()
 {
     $this->markTestSkipped('exdate container move not yet forbidden');
     $event = $this->_getDailyEvent(new Tinebase_DateTime('2014-02-03 09:00:00'));
     $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
     $from = new Tinebase_DateTime('2014-02-01 00:00:00');
     $until = new Tinebase_DateTime('2014-02-29 23:59:59');
     $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($event, $exceptions, $from, $until);
     $recurSet[2]->summary = 'exdate';
     $updatedPersistentEvent = $this->_controller->createRecurException($recurSet[2]);
     $this->setExpectedException('Calendar_Exception_ExdateContainer');
     $updatedPersistentEvent->container_id = $this->_getTestContainer('Calendar')->getId();
     $this->_controller->update($updatedPersistentEvent);
 }
 /**
  * creates an exception instance of a recurring event
  *
  * NOTE: deleting persistent exceptions is done via a normal delete action
  *       and handled in the deleteInspection
  * 
  * @param  Calendar_Model_Event  $_event
  * @param  bool                  $_deleteInstance
  * @param  bool                  $_allFollowing
  * @param  bool                  $_checkBusyConflicts
  * @return Calendar_Model_Event  exception Event | updated baseEvent
  * 
  * @todo replace $_allFollowing param with $range
  * @deprecated replace with create/update/delete
  */
 public function createRecurException($_event, $_deleteInstance = FALSE, $_allFollowing = FALSE, $_checkBusyConflicts = FALSE)
 {
     $baseEvent = $this->getRecurBaseEvent($_event);
     if ($baseEvent->last_modified_time != $_event->last_modified_time) {
         if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) {
             Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . " It is not allowed to create recur instance if it is clone of base event");
         }
         throw new Tinebase_Timemachine_Exception_ConcurrencyConflict('concurrency conflict!');
     }
     //        // Maybe Later
     //        // exdates needs to stay in baseEvents container
     //        if ($_event->container_id != $baseEvent->container_id) {
     //            throw new Calendar_Exception_ExdateContainer();
     //        }
     // check if this is an exception to the first occurence
     if ($baseEvent->getId() == $_event->getId()) {
         if ($_allFollowing) {
             throw new Exception('please edit or delete complete series!');
         }
         // NOTE: if the baseEvent gets a time change, we can't compute the recurdid w.o. knowing the original dtstart
         $recurid = $baseEvent->setRecurId($baseEvent->getId());
         unset($baseEvent->recurid);
         $_event->recurid = $recurid;
     }
     // just do attender status update if user has no edit grant
     if ($this->_doContainerACLChecks && !$baseEvent->{Tinebase_Model_Grants::GRANT_EDIT}) {
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " user has no editGrant for event: '{$baseEvent->getId()}'. Only creating exception for attendee status");
         }
         if ($_event->attendee instanceof Tinebase_Record_RecordSet) {
             foreach ($_event->attendee as $attender) {
                 if ($attender->status_authkey) {
                     $exceptionAttender = $this->attenderStatusCreateRecurException($_event, $attender, $attender->status_authkey, $_allFollowing);
                 }
             }
         }
         if (!isset($exceptionAttender)) {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG) && $_event->attendee instanceof Tinebase_Record_RecordSet) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Failed to update attendee: " . print_r($_event->attendee->toArray(), true));
             }
             throw new Tinebase_Exception_AccessDenied('Failed to update attendee, status authkey might be missing');
         }
         return $this->get($exceptionAttender->cal_event_id);
     }
     // NOTE: recurid is computed by rrule recur computations and therefore is already part of the event.
     if (empty($_event->recurid)) {
         throw new Exception('recurid must be present to create exceptions!');
     }
     // we do notifications ourself
     $sendNotifications = $this->sendNotifications(FALSE);
     // EDIT for baseEvent is checked above, CREATE, DELETE for recur exceptions is implied with it
     $doContainerACLChecks = $this->doContainerACLChecks(FALSE);
     $db = $this->_backend->getAdapter();
     $transactionId = Tinebase_TransactionManager::getInstance()->startTransaction($db);
     $exdate = new Tinebase_DateTime(substr($_event->recurid, -19));
     $exdates = is_array($baseEvent->exdate) ? $baseEvent->exdate : array();
     $originalDtstart = $_event->getOriginalDtStart();
     $originalEvent = Calendar_Model_Rrule::computeNextOccurrence($baseEvent, new Tinebase_Record_RecordSet('Calendar_Model_Event'), $originalDtstart);
     if ($_allFollowing != TRUE) {
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Adding exdate for: '{$_event->recurid}'");
         }
         array_push($exdates, $exdate);
         $baseEvent->exdate = $exdates;
         $updatedBaseEvent = $this->update($baseEvent, FALSE);
         if ($_deleteInstance == FALSE) {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Creating persistent exception for: '{$_event->recurid}'");
             }
             if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
                 Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . " Recur exception: " . print_r($_event->toArray(), TRUE));
             }
             $_event->base_event_id = $baseEvent->getId();
             $_event->setId(NULL);
             unset($_event->rrule);
             unset($_event->exdate);
             foreach (array('attendee', 'notes', 'alarms') as $prop) {
                 if ($_event->{$prop} instanceof Tinebase_Record_RecordSet) {
                     $_event->{$prop}->setId(NULL);
                 }
             }
             $originalDtstart = $_event->getOriginalDtStart();
             $dtStartHasDiff = $originalDtstart->compare($_event->dtstart) != 0;
             // php52 compat
             if (!$dtStartHasDiff) {
                 $attendees = $_event->attendee;
                 unset($_event->attendee);
             }
             $note = $_event->notes;
             unset($_event->notes);
             $persistentExceptionEvent = $this->create($_event, $_checkBusyConflicts);
             if (!$dtStartHasDiff) {
                 // we save attendee seperatly to preserve their attributes
                 if ($attendees instanceof Tinebase_Record_RecordSet) {
                     $attendees->cal_event_id = $persistentExceptionEvent->getId();
                     $calendar = Tinebase_Container::getInstance()->getContainerById($_event->container_id);
                     foreach ($attendees as $attendee) {
                         $this->_createAttender($attendee, $_event, TRUE, $calendar);
                         $this->_increaseDisplayContainerContentSequence($attendee, $persistentExceptionEvent, Tinebase_Model_ContainerContent::ACTION_CREATE);
                     }
                 }
             }
             // @todo save notes and add a update note -> what was updated? -> modlog is also missing
             $persistentExceptionEvent = $this->get($persistentExceptionEvent->getId());
         }
     } else {
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " shorten recur series for/to: '{$_event->recurid}'");
         }
         // split past/future exceptions
         $pastExdates = array();
         $futureExdates = array();
         foreach ($exdates as $exdate) {
             $exdate->isLater($_event->dtstart) ? $futureExdates[] = $exdate : ($pastExdates[] = $exdate);
         }
         $persistentExceptionEvents = $this->getRecurExceptions($_event);
         $pastPersistentExceptionEvents = new Tinebase_Record_RecordSet('Calendar_Model_Event');
         $futurePersistentExceptionEvents = new Tinebase_Record_RecordSet('Calendar_Model_Event');
         foreach ($persistentExceptionEvents as $persistentExceptionEvent) {
             $persistentExceptionEvent->getOriginalDtStart()->isLater($_event->dtstart) ? $futurePersistentExceptionEvents->addRecord($persistentExceptionEvent) : $pastPersistentExceptionEvents->addRecord($persistentExceptionEvent);
         }
         // update baseEvent
         $rrule = Calendar_Model_Rrule::getRruleFromString($baseEvent->rrule);
         if (isset($rrule->count)) {
             // get all occurences and find the split
             $exdate = $baseEvent->exdate;
             $baseEvent->exdate = NULL;
             //$baseCountOccurrence = Calendar_Model_Rrule::computeNextOccurrence($baseEvent, new Tinebase_Record_RecordSet('Calendar_Model_Event'), $baseEvent->rrule_until, $baseCount);
             $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($baseEvent, new Tinebase_Record_RecordSet('Calendar_Model_Event'), $baseEvent->dtstart, $baseEvent->rrule_until);
             $baseEvent->exdate = $exdate;
             $originalDtstart = $_event->getOriginalDtStart();
             foreach ($recurSet as $idx => $rInstance) {
                 if ($rInstance->dtstart >= $originalDtstart) {
                     break;
                 }
             }
             $rrule->count = $idx + 1;
         } else {
             $lastBaseOccurence = Calendar_Model_Rrule::computeNextOccurrence($baseEvent, new Tinebase_Record_RecordSet('Calendar_Model_Event'), $_event->getOriginalDtStart()->subSecond(1), -1);
             $rrule->until = $lastBaseOccurence ? $lastBaseOccurence->getOriginalDtStart() : $baseEvent->dtstart;
         }
         $baseEvent->rrule = (string) $rrule;
         $baseEvent->exdate = $pastExdates;
         // NOTE: we don't want implicit attendee updates
         //$updatedBaseEvent = $this->update($baseEvent, FALSE);
         $this->_inspectEvent($baseEvent);
         $updatedBaseEvent = parent::update($baseEvent);
         if ($_deleteInstance == TRUE) {
             // delete all future persistent events
             $this->delete($futurePersistentExceptionEvents->getId());
         } else {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " create new recur series for/at: '{$_event->recurid}'");
             }
             // NOTE: in order to move exceptions correctly in time we need to find out the original dtstart
             //       and create the new baseEvent with this time. A following update also updates its exceptions
             $originalDtstart = new Tinebase_DateTime(substr($_event->recurid, -19));
             $adoptedDtstart = clone $_event->dtstart;
             $dtStartHasDiff = $adoptedDtstart->compare($originalDtstart) != 0;
             // php52 compat
             $eventLength = $_event->dtstart->diff($_event->dtend);
             $_event->dtstart = clone $originalDtstart;
             $_event->dtend = clone $originalDtstart;
             $_event->dtend->add($eventLength);
             // adopt count
             if (isset($rrule->count)) {
                 $baseCount = $rrule->count;
                 $rrule = Calendar_Model_Rrule::getRruleFromString($_event->rrule);
                 $rrule->count = $rrule->count - $baseCount;
                 $_event->rrule = (string) $rrule;
             }
             $_event->setId(Tinebase_Record_Abstract::generateUID());
             $_event->uid = $futurePersistentExceptionEvents->uid = Tinebase_Record_Abstract::generateUID();
             $_event->setId(Tinebase_Record_Abstract::generateUID());
             $futurePersistentExceptionEvents->setRecurId($_event->getId());
             unset($_event->recurid);
             unset($_event->base_event_id);
             foreach (array('attendee', 'notes', 'alarms') as $prop) {
                 if ($_event->{$prop} instanceof Tinebase_Record_RecordSet) {
                     $_event->{$prop}->setId(NULL);
                 }
             }
             $_event->exdate = $futureExdates;
             $attendees = $_event->attendee;
             unset($_event->attendee);
             $note = $_event->notes;
             unset($_event->notes);
             $persistentExceptionEvent = $this->create($_event, $_checkBusyConflicts && $dtStartHasDiff);
             // we save attendee separately to preserve their attributes
             if ($attendees instanceof Tinebase_Record_RecordSet) {
                 foreach ($attendees as $attendee) {
                     $this->_createAttender($attendee, $persistentExceptionEvent, true);
                 }
             }
             // @todo save notes and add a update note -> what was updated? -> modlog is also missing
             $persistentExceptionEvent = $this->get($persistentExceptionEvent->getId());
             foreach ($futurePersistentExceptionEvents as $futurePersistentExceptionEvent) {
                 $this->update($futurePersistentExceptionEvent, FALSE);
             }
             if ($dtStartHasDiff) {
                 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                     Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " new recur series has adpted dtstart -> update to adopt exceptions'");
                 }
                 $persistentExceptionEvent->dtstart = clone $adoptedDtstart;
                 $persistentExceptionEvent->dtend = clone $adoptedDtstart;
                 $persistentExceptionEvent->dtend->add($eventLength);
                 $persistentExceptionEvent = $this->update($persistentExceptionEvent, $_checkBusyConflicts);
             }
         }
     }
     Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId);
     // restore original notification handling
     $this->sendNotifications($sendNotifications);
     $notificationAction = $_deleteInstance ? 'deleted' : 'changed';
     $notificationEvent = $_deleteInstance ? $_event : $persistentExceptionEvent;
     // restore acl
     $this->doContainerACLChecks($doContainerACLChecks);
     // send notifications
     if ($this->_sendNotifications && $_event->mute != 1) {
         // NOTE: recur exception is a fake event from client.
         //       this might lead to problems, so we wrap the calls
         try {
             if (count($_event->attendee) > 0) {
                 $_event->attendee->bypassFilters = TRUE;
             }
             $_event->created_by = $baseEvent->created_by;
             $this->doSendNotifications($notificationEvent, Tinebase_Core::getUser(), $notificationAction, $originalEvent);
         } catch (Exception $e) {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " " . $e->getTraceAsString());
             }
             Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . " could not send notification {$e->getMessage()}");
         }
     }
     return $_deleteInstance ? $updatedBaseEvent : $persistentExceptionEvent;
 }
 public function testAdoptAlarmDSTBoundary()
 {
     $event = $this->_getEvent();
     $event->rrule = 'FREQ=DAILY;INTERVAL=1';
     $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array(new Tinebase_Model_Alarm(array('minutes_before' => 30), TRUE)));
     $persistentEvent = $this->_eventController->create($event);
     // prepare alarm for last non DST instance
     $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
     $from = new Tinebase_DateTime('2012-03-24 00:00:00');
     $until = new Tinebase_DateTime('2012-03-24 23:59:59');
     $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($persistentEvent, $exceptions, $from, $until);
     $alarm = $persistentEvent->alarms->getFirstRecord();
     $alarm->setOption('recurid', $recurSet[0]->recurid);
     Tinebase_Alarm::getInstance()->update($alarm);
     $loadedBaseEvent = $this->_eventController->get($persistentEvent->getId());
     $alarm = $loadedBaseEvent->alarms->getFirstRecord();
     $this->assertEquals('2012-03-24', substr($alarm->getOption('recurid'), -19, -9), 'precondition failed');
     // adopt alarm
     $this->_eventController->adoptAlarmTime($loadedBaseEvent, $alarm, 'instance');
     $this->assertEquals('2012-03-25', substr($alarm->getOption('recurid'), -19, -9), 'alarm adoption failed');
 }