Exemplo n.º 1
0
 /**
  * singleton
  *
  * @return Calendar_Controller_MSEventFacade
  */
 public static function getInstance()
 {
     if (self::$_instance === NULL) {
         self::$_instance = new Calendar_Controller_MSEventFacade();
     }
     return self::$_instance;
 }
 public function setUp()
 {
     parent::setUp();
     Calendar_Controller_Event::getInstance()->doContainerACLChecks(true);
     $this->_uit = Calendar_Controller_MSEventFacade::getInstance();
     $this->_uit->setEventFilter(new Calendar_Model_EventFilter(array(array('field' => 'attender', 'operator' => 'equals', 'value' => array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => Tinebase_Core::getUser()->contact_id)), array('field' => 'attender_status', 'operator' => 'notin', 'value' => array(Calendar_Model_Attender::STATUS_DECLINED)))));
 }
 /**
  * testConvertAllDayEventWithExdate
  *
  * - exdate is the base event
  */
 public function testConvertAllDayEventWithExdate()
 {
     $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_MACOSX, '10.10.2');
     $vcalendarStream = fopen(dirname(__FILE__) . '/../../../Import/files/apple_calendar_birthday.ics', 'r');
     $updateEvent = $converter->toTine20Model($vcalendarStream);
     $eventWithExdateOnBaseEvent = Calendar_Controller_MSEventFacade::getInstance()->create($updateEvent);
     $this->assertEquals(1, count($eventWithExdateOnBaseEvent->exdate));
     // refetch existing event here and pass it to converter
     $eventWithExdateOnBaseEvent = Calendar_Controller_Event::getInstance()->get($eventWithExdateOnBaseEvent->getId());
     $vcalendarStream2 = fopen(dirname(__FILE__) . '/../../../Import/files/apple_calendar_birthday2.ics', 'r');
     $updateEvent2 = $converter->toTine20Model($vcalendarStream2, $eventWithExdateOnBaseEvent);
     $this->assertEquals(1, count($updateEvent2->exdate), print_r($updateEvent2->toArray(), true));
     $this->assertEquals('2015-04-27 22:00:00', $updateEvent2->rrule_until);
 }
 /**
  * exports calendars as ICS
  *
  * @param Zend_Console_Getopt $_opts
  */
 public function exportICS($_opts)
 {
     Tinebase_Core::set('HOSTNAME', 'localhost');
     $opts = $_opts->getRemainingArgs();
     $container_id = $opts[0];
     $filter = new Calendar_Model_EventFilter(array(array('field' => 'container_id', 'operator' => 'equals', 'value' => $container_id)));
     $result = Calendar_Controller_MSEventFacade::getInstance()->search($filter, null, false, false, 'get');
     if ($result->count() == 0) {
         throw new Tinebase_Exception('this calendar does not contain any records.');
     }
     $converter = Calendar_Convert_Event_VCalendar_Factory::factory("generic");
     $result = $converter->fromTine20RecordSet($result);
     print $result->serialize();
 }
Exemplo n.º 5
0
 /**
  * test getChildren
  * 
  */
 public function testGetChildren()
 {
     $event = $this->testCreateFile()->getRecord();
     // reschedule to match period filter
     $event->dtstart = Tinebase_DateTime::now();
     $event->dtend = Tinebase_DateTime::now()->addMinute(30);
     Calendar_Controller_MSEventFacade::getInstance()->update($event);
     $container = new Calendar_Frontend_WebDAV_Container($this->objects['initialContainer']);
     $children = $container->getChildren();
     $this->assertEquals(1, count($children));
     $this->assertTrue($children[0] instanceof Calendar_Frontend_WebDAV_Event);
 }
Exemplo n.º 6
0
 /**
  * process reply
  * 
  * some attender replied to my request (I'm Organizer) -> update status (seq++) / send notifications!
  * 
  * NOTE: only external replies should be processed here
  *       @todo check silence for internal replies
  *       
  * @param  Calendar_Model_iMIP   $_iMIP
  */
 protected function _processReply(Calendar_Model_iMIP $_iMIP)
 {
     // merge ics into existing event
     $existingEvent = $_iMIP->getExistingEvent();
     $event = $_iMIP->mergeEvent($existingEvent);
     $attendee = $event->attendee[array_search($_iMIP->originator, $existingEvent->attendee->getEmail())];
     // NOTE: if current user has no rights to the calendar, status update is not applied
     Calendar_Controller_MSEventFacade::getInstance()->attenderStatusUpdate($event, $attendee);
 }
 /**
  * process cancel
  *
  * @param  Calendar_Model_iMIP   $_iMIP
  * @param  string                $_status
  */
 protected function _processCancel($_iMIP, $_status)
 {
     // organizer cancelled meeting/recurrence of an existing event -> update event
     // the iMIP is already the notification mail!
     $existingEvent = $this->getExistingEvent($_iMIP, FALSE, TRUE);
     $event = $_iMIP->getEvent();
     if ($existingEvent) {
         if (!$existingEvent->is_deleted) {
             if ($event->status == Calendar_Model_Event::STATUS_CANCELED) {
                 // Event cancelled
                 Calendar_Controller_MSEventFacade::getInstance()->delete($existingEvent->getId());
             } else {
                 // Attendees cancelled
                 Calendar_Controller_MSEventFacade::getInstance()->deleteAttendees($existingEvent, $event);
             }
         }
     } else {
         // create a deleted/cancelled event
         $sendNotifications = Calendar_Controller_Event::getInstance()->sendNotifications(FALSE);
         $event = $_iMIP->event = Calendar_Controller_MSEventFacade::getInstance()->create($event);
         Calendar_Controller_MSEventFacade::getInstance()->delete($event->getId());
         Calendar_Controller_Event::getInstance()->sendNotifications($sendNotifications);
     }
 }
Exemplo n.º 8
0
 /**
  * testInternalInvitationRequestProcess
  */
 public function testInternalInvitationRequestProcess()
 {
     $iMIP = $this->_getiMIP('REQUEST');
     $result = $this->_iMIPFrontendMock->process($iMIP, Calendar_Model_Attender::STATUS_TENTATIVE);
     $event = Calendar_Controller_MSEventFacade::getInstance()->lookupExistingEvent($iMIP->getEvent());
     $attender = Calendar_Model_Attender::getOwnAttender($event->attendee);
     $this->assertEquals(Calendar_Model_Attender::STATUS_TENTATIVE, $attender->status);
 }
 protected function _getController()
 {
     if ($this->_controller === null) {
         $this->_controller = Calendar_Controller_MSEventFacade::getInstance();
     }
     return $this->_controller;
 }
 /**
  * save ics test event
  * 
  * @param string $filename
  * @param string $client
  * @return Calendar_Model_Event
  */
 protected function _saveIcsEvent($filename, $client = Calendar_Convert_Event_VCalendar_Factory::CLIENT_GENERIC)
 {
     $vcalendarStream = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/' . $filename, 'r');
     $this->_converter = Calendar_Convert_Event_VCalendar_Factory::factory($client);
     $event = $this->_converter->toTine20Model($vcalendarStream);
     return Calendar_Controller_MSEventFacade::getInstance()->create($event);
 }
Exemplo n.º 11
0
 /**
  * get existing event record
  *
  * @param boolean $_refetch the event
  * @return Calendar_Model_Event
  */
 public function getExistingEvent($_refetch = FALSE)
 {
     if ($_refetch || !$this->existing_event instanceof Calendar_Model_Event) {
         $this->existing_event = Calendar_Controller_MSEventFacade::getInstance()->lookupExistingEvent($this->getEvent());
     }
     return $this->existing_event;
 }
Exemplo n.º 12
0
 public function setUp()
 {
     parent::setUp();
     $this->_uit = Calendar_Controller_MSEventFacade::getInstance();
 }
 /**
  * the constructor
  *
  * don't use the constructor. use the singleton 
  */
 private function __construct()
 {
     $this->_applicationName = 'Calendar';
     $this->_modelName = 'Calendar_Model_Event';
     $this->_backend = new Calendar_Backend_Sql();
     // set default CU
     $this->setCalendarUser(new Calendar_Model_Attender(array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => Calendar_Controller_MSEventFacade::getCurrentUserContactId())));
 }
Exemplo n.º 14
0
 /**
  * update existing entry
  *
  * @param unknown_type $_collectionId
  * @param string $_id
  * @param SimpleXMLElement $_data
  * @return Tinebase_Record_Abstract
  */
 public function change($_folderId, $_id, SimpleXMLElement $_data)
 {
     if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
         Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " CollectionId: {$_folderId} Id: {$_id}");
     }
     $oldEntry = $this->_contentController->get($_id);
     $entry = $this->toTineModel($_data, $oldEntry);
     $entry->last_modified_time = $this->_syncTimeStamp;
     if ($_folderId != $this->_specialFolderName) {
         $entry->container_id = $_folderId;
     }
     if ($entry->exdate instanceof Tinebase_Record_RecordSet) {
         foreach ($entry->exdate as $exdate) {
             if ($exdate->is_deleted == false) {
                 $exdate->container_id = $entry->container_id;
             }
         }
     }
     if ($oldEntry->organizer == Tinebase_Core::getUser()->contact_id) {
         $entry = $this->_contentController->update($entry);
     } else {
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " current user is not organizer => update attendee status only ");
         }
         $ownAttendee = Calendar_Model_Attender::getOwnAttender($entry->attendee);
         if ($_folderId != $this->_specialFolderName) {
             $ownAttendee->displaycontainer_id = $_folderId;
         }
         $entry = Calendar_Controller_MSEventFacade::getInstance()->attenderStatusUpdate($entry, $ownAttendee);
     }
     if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
         Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " updated entry id " . $entry->getId());
     }
     return $entry;
 }
 /**
  * test calendarQuery with start and end time set
  * 
  * @param boolean $timeRangeEndSet
  * @param boolean $removeOwnAttender
  */
 public function testCalendarQueryPropertyFilter()
 {
     $event1 = $this->testCreateFile()->getRecord();
     $event2 = $this->testCreateFile()->getRecord();
     // reschedule to match period filter
     $event1->dtstart = Tinebase_DateTime::now();
     $event1->dtend = Tinebase_DateTime::now()->addMinute(30);
     Calendar_Controller_MSEventFacade::getInstance()->update($event1);
     $event2->dtstart = Tinebase_DateTime::now();
     $event2->dtend = Tinebase_DateTime::now()->addMinute(30);
     Calendar_Controller_MSEventFacade::getInstance()->update($event2);
     $container = new Calendar_Frontend_WebDAV_Container($this->objects['initialContainer']);
     $urls = $container->calendarQuery(array('name' => 'VCALENDAR', 'comp-filters' => array(array('name' => 'VEVENT', 'prop-filters' => array(array('name' => 'UID', 'text-match' => array('value' => $event1->getId())), array('name' => 'UID', 'text-match' => array('value' => $event2->getId()))))), 'prop-filters' => array(), 'is-not-defined' => false, 'time-range' => null));
     $this->assertContains($event1->getId(), $urls);
     $this->assertContains($event2->getId(), $urls);
     $this->assertEquals(2, count($urls));
 }
 public function testPutEventWithRecurExceptions()
 {
     $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.21) Gecko/20110831 Lightning/1.0b2 Thunderbird/3.1.13';
     $vcalendar = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning_repeating_exdate_mozlastack.ics');
     $id = Tinebase_Record_Abstract::generateUID();
     $targetContainer = $this->objects['initialContainer'];
     $event = Calendar_Frontend_WebDAV_Event::create($targetContainer, "{$id}.ics", $vcalendar);
     $record = $event->getRecord();
     $eventToUpdate = new Calendar_Frontend_WebDAV_Event($targetContainer, $id);
     $vcalendarToUpdate = stream_get_contents($eventToUpdate->get());
     $vcalendarToUpdate = str_replace("abendessen später am heiligabend", "vesper später am heiligabend", $vcalendarToUpdate);
     //        echo $vcalendarToUpdate;
     $eventToUpdate->put($vcalendarToUpdate);
     $updatedRecord = Calendar_Controller_MSEventFacade::getInstance()->get($id);
     $xmas = $updatedRecord->exdate->filter('summary', '/^vesper.*/', true)->getFirstRecord();
     $this->assertNotNull($xmas, print_r($updatedRecord->toArray(), true));
 }
 /**
  * Returns information from a single calendar object, based on it's object uri. 
  * 
  * @param string $calendarId 
  * @param string $objectUri 
  * @return array 
  */
 function getCalendarObject($calendarId, $objectUri)
 {
     if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
         Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' $calendarId: ' . $calendarId . ' $objectUri: ' . $objectUri);
     }
     try {
         $event = Calendar_Controller_MSEventFacade::getInstance()->get($objectUri);
         return $this->_convertCalendarObject($event);
     } catch (Tinebase_Exception_NotFound $e) {
         return array();
     }
 }
 /**
  * NOTE: calendarFilter is based on contentFilter for ActiveSync
  *
  * @param $folderId
  */
 protected function _assertContentControllerParams($folderId)
 {
     try {
         $container = Tinebase_Container::getInstance()->getContainerById($folderId);
     } catch (Exception $e) {
         $containerId = Tinebase_Core::getPreference('ActiveSync')->{$this->_defaultFolder};
         $container = Tinebase_Container::getInstance()->getContainerById($containerId);
     }
     Calendar_Controller_MSEventFacade::getInstance()->assertEventFacadeParams($container, false);
 }
 /**
  * return Calendar_Model_Event and convert contact id to model if needed
  * 
  * @return Calendar_Model_Event
  */
 public function getRecord()
 {
     if (!$this->_event instanceof Calendar_Model_Event) {
         Calendar_Controller_MSEventFacade::getInstance()->assertEventFacadeParams($this->_container);
         $this->_event = Calendar_Controller_MSEventFacade::getInstance()->get($this->_event);
         Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " " . print_r($this->_event->toArray(), true));
     }
     return $this->_event;
 }
 /**
  * asserts correct event filter and calendar user in MSEventFacade
  * 
  * NOTE: this is nessesary as MSEventFacade is a singleton and in some operations (e.g. move) there are 
  *       multiple instances of self
  */
 public function assertEventFacadeParams(Tinebase_Model_Container $container, $setEventFilter = true)
 {
     if (!$this->_currentEventFacadeContainer || $this->_currentEventFacadeContainer->getId() !== $container->getId()) {
         $this->_currentEventFacadeContainer = $container;
         try {
             $calendarUserId = $container->type == Tinebase_Model_Container::TYPE_PERSONAL ? Addressbook_Controller_Contact::getInstance()->getContactByUserId($container->getOwner(), true)->getId() : Tinebase_Core::getUser()->contact_id;
         } catch (Exception $e) {
             $calendarUserId = Calendar_Controller_MSEventFacade::getCurrentUserContactId();
         }
         $calendarUser = new Calendar_Model_Attender(array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $calendarUserId));
         $this->setCalendarUser($calendarUser);
         if ($setEventFilter) {
             $eventFilter = new Calendar_Model_EventFilter(array(array('field' => 'container_id', 'operator' => 'equals', 'value' => $container->getId())));
             $this->setEventFilter($eventFilter);
         }
     }
 }
 /**
  * import the data
  *
  * @param  stream $_resource 
  * @param array $_clientRecordData
  * @return array : 
  *  'results'           => Tinebase_Record_RecordSet, // for dryrun only
  *  'totalcount'        => int,
  *  'failcount'         => int,
  *  'duplicatecount'    => int,
  *  
  *  @throws Calendar_Exception_IcalParser
  *  
  *  @see 0008334: use vcalendar converter for ics import
  */
 public function import($_resource = NULL, $_clientRecordData = array())
 {
     $this->_initImportResult();
     if (!$this->_options['container_id']) {
         throw new Tinebase_Exception_InvalidArgument('you need to define a container_id');
     }
     $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_GENERIC);
     if (isset($this->_options['onlyBasicData'])) {
         $converter->setOptions(array('onlyBasicData' => $this->_options['onlyBasicData']));
     }
     try {
         $events = $converter->toTine20RecordSet($_resource);
     } catch (Exception $e) {
         Tinebase_Exception::log($e);
         $isce = new Calendar_Exception_IcalParser('Can not parse ics file: ' . $e->getMessage());
         $isce->setParseError($e);
         throw $isce;
     }
     try {
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__ . ' ' . ' Trying to find container with ID ' . print_r($this->_options['container_id'], true));
         }
         $container = Tinebase_Container::getInstance()->getContainerById($this->_options['container_id']);
     } catch (Tinebase_Exception_InvalidArgument $e) {
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__ . ' ' . ' Could not found container with Id ' . print_r($this->_options['container_id'], true) . ' assuming this is a container name.');
         }
         $container = new Tinebase_Model_Container(array('name' => $this->_options['container_id'], 'type' => Tinebase_Model_Container::TYPE_PERSONAL, 'backend' => Tinebase_User::SQL, 'color' => '#ffffff', 'application_id' => Tinebase_Application::getInstance()->getApplicationByName('Calendar')->getId(), 'owner_id' => Tinebase_Core::getUser()->getId(), 'model' => 'Calendar_Model_Event'));
         $container = Tinebase_Container::getInstance()->addContainer($container);
     }
     try {
         $this->_options['container_id'] = $container->getId();
     } catch (Exception $ex) {
         throw new Tinebase_Exception_NotFound('Could not find container by ID: ' . $this->_options['container_id']);
     }
     if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
         Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__ . ' ' . ' Import into calendar: ' . print_r($this->_options['container_id'], true));
     }
     $cc = Calendar_Controller_MSEventFacade::getInstance();
     $sendNotifications = Calendar_Controller_Event::getInstance()->sendNotifications(FALSE);
     // search uid's and remove already existing -> only in import cal?
     $existingEventsFilter = new Calendar_Model_EventFilter(array(array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_options['container_id']), array('field' => 'uid', 'operator' => 'in', 'value' => array_unique($events->uid))));
     $existingEvents = $cc->search($existingEventsFilter);
     if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
         Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__ . ' ' . ' Found ' . count($existingEvents) . ' existing events');
     }
     if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
         Tinebase_Core::getLogger()->trace(__METHOD__ . ' ' . __LINE__ . ' ' . ' Filter: ' . print_r($existingEventsFilter->toArray(), true));
     }
     // insert one by one in a single transaction
     $existingEvents->addIndices(array('uid'));
     foreach ($events as $event) {
         $existingEvent = $existingEvents->find('uid', $event->uid);
         try {
             if (!$existingEvent) {
                 $event->container_id = $this->_options['container_id'];
                 $event = $cc->create($event, FALSE);
                 $this->_importResult['totalcount'] += 1;
                 $this->_importResult['results']->addRecord($event);
             } else {
                 if ($this->_options['forceUpdateExisting'] || $this->_options['updateExisting'] && $event->seq > $existingEvent->seq) {
                     $event->id = $existingEvent->getId();
                     $event->last_modified_time = $existingEvent->last_modified_time instanceof Tinebase_DateTime ? clone $existingEvent->last_modified_time : NULL;
                     $cc->update($event, FALSE);
                     $this->_importResult['results']->addRecord($event);
                     $this->_importResult['totalcount'] += 1;
                 } else {
                     $this->_importResult['duplicatecount'] += 1;
                 }
             }
         } catch (Exception $e) {
             if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) {
                 Tinebase_Core::getLogger()->notice(__METHOD__ . ' ' . __LINE__ . ' Import failed for Event ' . $event->summary);
             }
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__ . ' ' . print_r($event->toArray(), TRUE));
             }
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__ . ' ' . $e);
             }
             $this->_importResult['failcount'] += 1;
         }
     }
     Calendar_Controller_Event::getInstance()->sendNotifications($sendNotifications);
     if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
         Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__ . ' ' . ' totalcount: ' . $this->_importResult['totalcount'] . ' / duplicates: ' . $this->_importResult['duplicatecount'] . ' / fails: ' . $this->_importResult['failcount']);
     }
     return $this->_importResult;
 }
 /**
  * test search events (unsyncable)
  * 
  * TODO finish this -> assertion fails atm because the event is found even if it is in an unsyncable folder and has no attendees (but 1 exdate)
  */
 public function _testUnsyncableSearch()
 {
     $this->markTestSkipped();
     $controller = $this->_getController($this->_getDevice(Syncroton_Model_Device::TYPE_WEBOS));
     $xml = simplexml_import_dom($this->_getInputDOMDocument());
     $record = $controller->createEntry($this->_getContainerWithoutSyncGrant()->getId(), $xml->Collections->Collection->Commands->Change[0]->ApplicationData);
     $record->exdate = new Tinebase_Record_RecordSet('Calendar_Model_Event');
     $record->attendee = NULL;
     $this->objects['events'][] = Calendar_Controller_MSEventFacade::getInstance()->update($record);
     $events = $controller->search($this->_specialFolderName, $xml->Collections->Collection->Commands->Change[0]->ApplicationData);
     $this->assertEquals(0, count($events));
 }
 public function testUpdateEntriesIPhone()
 {
     // create event
     $syncrotonFolder = $this->testCreateFolder();
     $syncrotonFolder2 = $this->testCreateFolder();
     //make $syncrotonFolder2 the default
     Tinebase_Core::getPreference('Calendar')->setValue(Calendar_Preference::DEFAULTCALENDAR, $syncrotonFolder2->serverId);
     $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
     list($serverId, $syncrotonEvent) = $this->testCreateEntry($syncrotonFolder);
     // update event
     $syncrotonEventtoUpdate = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
     $syncrotonEventtoUpdate->exceptions[0]->subject = 'update';
     $syncrotonEventtoUpdate->exceptions[0]->startTime->addHour(1);
     $syncrotonEventtoUpdate->exceptions[0]->endTime->addHour(1);
     $syncTimestamp = Calendar_Controller_Event::getInstance()->get($serverId)->last_modified_time;
     $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), $syncTimestamp);
     $serverId = $controller->updateEntry($syncrotonFolder->serverId, $serverId, $syncrotonEventtoUpdate);
     // assert update
     $updatedSyncrotonEvent = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
     $this->assertEquals('update', $updatedSyncrotonEvent->exceptions[0]->subject);
     $this->assertNotEquals($syncrotonEvent->exceptions[0]->startTime->toString(), $updatedSyncrotonEvent->exceptions[0]->startTime->toString());
     $this->assertEquals($syncrotonEventtoUpdate->exceptions[0]->startTime->toString(), $updatedSyncrotonEvent->exceptions[0]->startTime->toString());
     // assert attendee are preserved
     $updatedEvent = Calendar_Controller_MSEventFacade::getInstance()->get($serverId);
     $this->assertNotEmpty($updatedEvent, 'attendee must be preserved during update');
 }