Beispiel #1
0
 /**
  * resolves rrule of given event(s)
  *
  * @param Tinebase_Record_RecordSet|Calendar_Model_Event $_events
  */
 public static function resolveRrule($_events)
 {
     $events = $_events instanceof Tinebase_Record_RecordSet ? $_events : array($_events);
     foreach ($events as $event) {
         if ($event->rrule) {
             $event->rrule = Calendar_Model_Rrule::getRruleFromString($event->rrule);
         }
     }
 }
 /**
  * appends sql to given select statement
  *
  * @param  Zend_Db_Select                    $_select
  * @param  Tinebase_Backend_Sql_Abstract     $_backend
  * 
  * @todo allow multiple role/status filters?
  */
 public function appendFilterSql($_select, $_backend)
 {
     if (!is_array($this->_foreignIds)) {
         $this->_getFilterData();
         $events = $this->_controller->search($this->_filterGroup);
         Calendar_Model_Rrule::mergeAndRemoveNonMatchingRecurrences($events, $this->_filterGroup);
         $this->_getForeignIds($events);
     }
     // this is supposed to run in ContactFilter context
     $contactIdFilter = new Addressbook_Model_ContactIdFilter('id', 'in', $this->_foreignIds);
     $contactIdFilter->appendFilterSql($_select, $_backend);
 }
 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');
 }
 /**
  * export records
  */
 protected function _exportRecords()
 {
     // to support rrule & sorting we can't do pagination in calendar exports
     $records = $this->_controller->search($this->_filter, NULL, $this->_getRelations, false, 'export');
     Calendar_Model_Rrule::mergeAndRemoveNonMatchingRecurrences($records, $this->_filter);
     $this->_sortRecords($records);
     $this->_resolveRecords($records);
     foreach ($records as $idx => $record) {
         $this->processRecord($record, $idx);
     }
     $result = array();
     $this->_onAfterExportRecords($result);
 }
 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');
 }
 /**
  * testImportRruleNormalize
  * 
  * @see 0009856: ics import: recurring events one day earlier
  */
 public function testImportRruleNormalize()
 {
     $importer = new Calendar_Import_Ical(array('container_id' => $this->_getTestCalendar()->getId()));
     $importer->importFile(dirname(__FILE__) . '/files/ni-zsk.ics');
     // fetch first of may in 2014
     $from = new Tinebase_DateTime('2014-04-23 22:00:00');
     $until = new Tinebase_DateTime('2014-05-23 22:00:00');
     $events = Calendar_Controller_Event::getInstance()->search(new Calendar_Model_EventFilter(array(array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()), array('field' => 'period', 'operator' => 'within', 'value' => array('from' => $from->toString(), 'until' => $until->toString())))), NULL);
     Calendar_Model_Rrule::mergeRecurrenceSet($events, $from, $until);
     $firstOfMay2014 = $events[1];
     $this->assertEquals('2014-04-30 22:00:00', $firstOfMay2014->dtstart);
 }
 /**
  * sets rrule until helper field
  *
  * @return void
  */
 public function setRruleUntil()
 {
     if (empty($this->rrule)) {
         $this->rrule_until = NULL;
     } else {
         $rrule = $this->rrule;
         if (!$this->rrule instanceof Calendar_Model_Rrule) {
             $rrule = new Calendar_Model_Rrule(array());
             $rrule->setFromString($this->rrule);
             $this->rrule = $rrule;
         }
         if (isset($rrule->count)) {
             $this->rrule_until = NULL;
             $exdates = $this->exdate;
             $this->exdate = NULL;
             $lastOccurrence = Calendar_Model_Rrule::computeNextOccurrence($this, new Tinebase_Record_RecordSet('Calendar_Model_Event'), $this->dtend, $rrule->count - 1);
             $this->rrule_until = $lastOccurrence->dtend;
             $this->exdate = $exdates;
         } else {
             // set until to end of day in organizers timezone.
             // NOTE: this is in contrast to the iCal spec which says until should be the
             //       dtstart of the last occurence. But as the client with the name of the
             //       spec sets it to the end of the day, we do it also.
             if ($rrule->until instanceof Tinebase_DateTime && !$this->is_all_day_event) {
                 $rrule->until->setTimezone($this->originator_tz);
                 // NOTE: subSecond cause some clients send 00:00:00 for midnight
                 $rrule->until->subSecond(1)->setTime(23, 59, 59);
                 $rrule->until->setTimezone('UTC');
             }
             $this->rrule_until = $rrule->until;
         }
     }
     if ($this->rrule_until && $this->rrule_until->getTimeStamp() - $this->dtstart->getTimeStamp() < -1) {
         throw new Tinebase_Exception_Record_Validation('rrule until must not be before dtstart');
     }
 }
 /**
  * converts Tinebase_Record_RecordSet to external format
  * 
  * @param Tinebase_Record_RecordSet         $_records
  * @param Tinebase_Model_Filter_FilterGroup $_filter
  * @param Tinebase_Model_Pagination         $_pagination
  *
  * @return mixed
  */
 public function fromTine20RecordSet(Tinebase_Record_RecordSet $_records = NULL, $_filter = NULL, $_pagination = NULL)
 {
     if (count($_records) == 0) {
         return array();
     }
     Tinebase_Notes::getInstance()->getMultipleNotesOfRecords($_records);
     Tinebase_Tags::getInstance()->getMultipleTagsOfRecords($_records);
     if (Tinebase_Core::isFilesystemAvailable()) {
         Tinebase_FileSystem_RecordAttachments::getInstance()->getMultipleAttachmentsOfRecords($_records);
     }
     Calendar_Model_Attender::resolveAttendee($_records->attendee, TRUE, $_records);
     Calendar_Convert_Event_Json::resolveRrule($_records);
     Calendar_Controller_Event::getInstance()->getAlarms($_records);
     Calendar_Convert_Event_Json::resolveGrantsOfExternalOrganizers($_records);
     Calendar_Model_Rrule::mergeAndRemoveNonMatchingRecurrences($_records, $_filter);
     $_records->sortByPagination($_pagination);
     Tinebase_Frontend_Json_Abstract::resolveContainersAndTags($_records, array('container_id'));
     $_records->setTimezone(Tinebase_Core::getUserTimezone());
     $_records->convertDates = true;
     $eventsData = $_records->toArray();
     foreach ($eventsData as $idx => $eventData) {
         if (!(isset($eventData[Tinebase_Model_Grants::GRANT_READ]) || array_key_exists(Tinebase_Model_Grants::GRANT_READ, $eventData)) || !$eventData[Tinebase_Model_Grants::GRANT_READ]) {
             $eventsData[$idx] = array_intersect_key($eventsData[$idx], array_flip(array('id', 'dtstart', 'dtend', 'transp', 'is_all_day_event')));
         }
     }
     return $eventsData;
 }
 /**
  * (non-PHPdoc)
  * @see ActiveSync_Frontend_Abstract::toSyncrotonModel()
  * @todo handle BusyStatus
  */
 public function toSyncrotonModel($entry, array $options = array())
 {
     if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
         Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . " calendar data " . print_r($entry->toArray(), true));
     }
     $syncrotonEvent = new Syncroton_Model_Event();
     foreach ($this->_mapping as $syncrotonProperty => $tine20Property) {
         if (empty($entry->{$tine20Property}) && $entry->{$tine20Property} != '0' || count($entry->{$tine20Property}) === 0) {
             continue;
         }
         switch ($tine20Property) {
             case 'alarms':
                 $entry->{$tine20Property}->sort('alarm_time');
                 $alarm = $entry->alarms->getFirstRecord();
                 if ($alarm instanceof Tinebase_Model_Alarm) {
                     // NOTE: option minutes_before is always calculated by Calendar_Controller_Event::_inspectAlarmSet
                     $minutesBefore = (int) $alarm->getOption('minutes_before');
                     // avoid negative alarms which may break phones
                     if ($minutesBefore >= 0) {
                         $syncrotonEvent->{$syncrotonProperty} = $minutesBefore;
                     }
                 }
                 break;
             case 'attendee':
                 if ($this->_device->devicetype === Syncroton_Model_Device::TYPE_IPHONE && $entry->container_id !== $this->_getDefaultContainerId()) {
                     continue;
                 }
                 // fill attendee cache
                 Calendar_Model_Attender::resolveAttendee($entry->{$tine20Property}, FALSE);
                 $attendees = array();
                 foreach ($entry->{$tine20Property} as $attenderObject) {
                     $attendee = new Syncroton_Model_EventAttendee();
                     $attendee->name = $attenderObject->getName();
                     $attendee->email = $attenderObject->getEmail();
                     $acsType = array_search($attenderObject->role, $this->_attendeeTypeMapping);
                     $attendee->attendeeType = $acsType ? $acsType : Syncroton_Model_EventAttendee::ATTENDEE_TYPE_REQUIRED;
                     $acsStatus = array_search($attenderObject->status, $this->_attendeeStatusMapping);
                     $attendee->attendeeStatus = $acsStatus ? $acsStatus : Syncroton_Model_EventAttendee::ATTENDEE_STATUS_UNKNOWN;
                     $attendees[] = $attendee;
                 }
                 $syncrotonEvent->{$syncrotonProperty} = $attendees;
                 // set own status
                 if (($ownAttendee = Calendar_Model_Attender::getOwnAttender($entry->attendee)) !== null && ($busyType = array_search($ownAttendee->status, $this->_busyStatusMapping)) !== false) {
                     $syncrotonEvent->busyStatus = $busyType;
                 }
                 break;
             case 'class':
                 $syncrotonEvent->{$syncrotonProperty} = $entry->{$tine20Property} == Calendar_Model_Event::CLASS_PRIVATE ? 2 : 0;
                 break;
             case 'description':
                 $syncrotonEvent->{$syncrotonProperty} = new Syncroton_Model_EmailBody(array('type' => Syncroton_Model_EmailBody::TYPE_PLAINTEXT, 'data' => $entry->{$tine20Property}));
                 break;
             case 'dtend':
                 if ($entry->{$tine20Property} instanceof DateTime) {
                     if ($entry->is_all_day_event == true) {
                         // whole day events ends at 23:59:59 in Tine 2.0 but 00:00 the next day in AS
                         $dtend = clone $entry->{$tine20Property};
                         $dtend->addSecond($dtend->get('s') == 59 ? 1 : 0);
                         $dtend->addMinute($dtend->get('i') == 59 ? 1 : 0);
                         $syncrotonEvent->{$syncrotonProperty} = $dtend;
                     } else {
                         $syncrotonEvent->{$syncrotonProperty} = $entry->{$tine20Property};
                     }
                 }
                 break;
             case 'dtstart':
                 if ($entry->{$tine20Property} instanceof DateTime) {
                     $syncrotonEvent->{$syncrotonProperty} = $entry->{$tine20Property};
                 }
                 break;
             case 'exdate':
                 // handle exceptions of repeating events
                 if ($entry->{$tine20Property} instanceof Tinebase_Record_RecordSet && $entry->{$tine20Property}->count() > 0) {
                     $exceptions = array();
                     foreach ($entry->exdate as $exdate) {
                         $exception = new Syncroton_Model_EventException();
                         // send the Deleted element only, when needed
                         // HTC devices ignore the value(0 or 1) of the Deleted element
                         if ((int) $exdate->is_deleted === 1) {
                             $exception->deleted = 1;
                         }
                         $exception->exceptionStartTime = $exdate->getOriginalDtStart();
                         if ((int) $exdate->is_deleted === 0) {
                             $exceptionSyncrotonEvent = $this->toSyncrotonModel($exdate);
                             foreach ($exception->getProperties() as $property) {
                                 if (isset($exceptionSyncrotonEvent->{$property})) {
                                     $exception->{$property} = $exceptionSyncrotonEvent->{$property};
                                 }
                             }
                             unset($exceptionSyncrotonEvent);
                         }
                         $exceptions[] = $exception;
                     }
                     $syncrotonEvent->{$syncrotonProperty} = $exceptions;
                 }
                 break;
             case 'rrule':
                 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                     Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " calendar rrule " . $entry->{$tine20Property});
                 }
                 $rrule = Calendar_Model_Rrule::getRruleFromString($entry->{$tine20Property});
                 $recurrence = new Syncroton_Model_EventRecurrence();
                 // required fields
                 switch ($rrule->freq) {
                     case Calendar_Model_Rrule::FREQ_DAILY:
                         $recurrence->type = Syncroton_Model_EventRecurrence::TYPE_DAILY;
                         break;
                     case Calendar_Model_Rrule::FREQ_WEEKLY:
                         $recurrence->type = Syncroton_Model_EventRecurrence::TYPE_WEEKLY;
                         $recurrence->dayOfWeek = $this->_convertDayToBitMask($rrule->byday);
                         break;
                     case Calendar_Model_Rrule::FREQ_MONTHLY:
                         if (!empty($rrule->bymonthday)) {
                             $recurrence->type = Syncroton_Model_EventRecurrence::TYPE_MONTHLY;
                             $recurrence->dayOfMonth = $rrule->bymonthday;
                         } else {
                             $weekOfMonth = (int) substr($rrule->byday, 0, -2);
                             $weekOfMonth = $weekOfMonth == -1 ? 5 : $weekOfMonth;
                             $dayOfWeek = substr($rrule->byday, -2);
                             $recurrence->type = Syncroton_Model_EventRecurrence::TYPE_MONTHLY_DAYN;
                             $recurrence->weekOfMonth = $weekOfMonth;
                             $recurrence->dayOfWeek = $this->_convertDayToBitMask($dayOfWeek);
                         }
                         break;
                     case Calendar_Model_Rrule::FREQ_YEARLY:
                         if (!empty($rrule->bymonthday)) {
                             $recurrence->type = Syncroton_Model_EventRecurrence::TYPE_YEARLY;
                             $recurrence->dayOfMonth = $rrule->bymonthday;
                             $recurrence->monthOfYear = $rrule->bymonth;
                         } else {
                             $weekOfMonth = (int) substr($rrule->byday, 0, -2);
                             $weekOfMonth = $weekOfMonth == -1 ? 5 : $weekOfMonth;
                             $dayOfWeek = substr($rrule->byday, -2);
                             $recurrence->type = Syncroton_Model_EventRecurrence::TYPE_YEARLY_DAYN;
                             $recurrence->weekOfMonth = $weekOfMonth;
                             $recurrence->dayOfWeek = $this->_convertDayToBitMask($dayOfWeek);
                             $recurrence->monthOfYear = $rrule->bymonth;
                         }
                         break;
                 }
                 // required field
                 $recurrence->interval = $rrule->interval ? $rrule->interval : 1;
                 if ($rrule->count) {
                     $recurrence->occurrences = $rrule->count;
                 } else {
                     if ($rrule->until instanceof DateTime) {
                         $recurrence->until = $rrule->until;
                     }
                 }
                 $syncrotonEvent->{$syncrotonProperty} = $recurrence;
                 break;
             case 'tags':
                 $syncrotonEvent->{$syncrotonProperty} = $entry->{$tine20Property}->name;
                 break;
             default:
                 $syncrotonEvent->{$syncrotonProperty} = $entry->{$tine20Property};
                 break;
         }
     }
     $timeZoneConverter = ActiveSync_TimezoneConverter::getInstance(Tinebase_Core::getLogger(), Tinebase_Core::get(Tinebase_Core::CACHE));
     $syncrotonEvent->timezone = $timeZoneConverter->encodeTimezone(Tinebase_Core::getUserTimezone());
     $syncrotonEvent->meetingStatus = 1;
     $syncrotonEvent->dtStamp = $entry->creation_time;
     $syncrotonEvent->uID = $entry->uid;
     $this->_addOrganizer($syncrotonEvent, $entry);
     return $syncrotonEvent;
 }
 /**
  * returns feast days as array containing Tinebase_DateTime objects
  * if the period exceeds the contracts' period(s), the contracts' period(s) will be used
  * 
  * @param HumanResources_Model_Contract|Tinebase_Record_RecordSet $contracts
  * @param Tinebase_DateTime $firstDate
  * @param Tinebase_DateTime $lastDate
  * @return array
  */
 public function getFeastDays($contracts, Tinebase_DateTime $firstDate, Tinebase_DateTime $lastDate)
 {
     $contracts = $this->_convertToRecordSet($contracts);
     $dates = array();
     foreach ($contracts as $contract) {
         $fd = $this->_getFirstDate($contract, $firstDate);
         $ld = $this->_getLastDate($contract, $lastDate);
         // on calendar search we have to do this to get the right interval:
         $fd->subSecond(1);
         $ld->addSecond(1);
         $periodFilter = new Calendar_Model_PeriodFilter(array('field' => 'period', 'operator' => 'within', 'value' => array('from' => $fd, 'until' => $ld)));
         $events = Calendar_Controller_Event::getInstance()->search(new Calendar_Model_EventFilter(array(array('field' => 'container_id', 'operator' => 'equals', 'value' => $contract->feast_calendar_id))));
         Calendar_Model_Rrule::mergeRecurrenceSet($events, $fd, $ld);
         $events->setTimezone(Tinebase_Core::getUserTimezone());
         foreach ($events as $event) {
             if (!$event->isInPeriod($periodFilter)) {
                 continue;
             }
             if ($event->is_all_day_event) {
                 $days = round(($event->dtend->getTimestamp() - $event->dtstart->getTimestamp()) / 86400);
                 $i = 0;
                 while ($i < $days) {
                     $dateOfEvent = clone $event->dtstart;
                     $dateOfEvent->addDay($i);
                     $dates[] = $dateOfEvent;
                     $i++;
                 }
             } else {
                 $dates[] = $event->dtstart;
             }
         }
     }
     return array_unique($dates);
 }
 /**
  * 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));
 }
 protected function _getEventsForPeriodAndCalendar($calendarId, $from, $until)
 {
     $filter = new Calendar_Model_EventFilter(array(array('field' => 'period', 'operator' => 'within', 'value' => array("from" => $from, "until" => $until)), array('field' => 'container_id', 'operator' => 'equals', 'value' => $calendarId)));
     $events = Calendar_Controller_Event::getInstance()->search($filter);
     Calendar_Model_Rrule::mergeAndRemoveNonMatchingRecurrences($events, $filter);
     return $events;
 }
Beispiel #13
0
 /**
  * append event data to xml element
  *
  * @todo handle BusyStatus
  * @todo handle TimeZone data
  * 
  * @param DOMElement  $_domParrent   the parrent xml node
  * @param string      $_folderId  the local folder id
  * @param boolean     $_withBody  retrieve body of entry
  */
 public function appendXML(DOMElement $_domParrent, $_collectionData, $_serverId)
 {
     $data = $_serverId instanceof Tinebase_Record_Abstract ? $_serverId : $this->_contentController->get($_serverId);
     if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
         Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . " calendar data " . print_r($data->toArray(), true));
     }
     // add calendar namespace
     $_domParrent->ownerDocument->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:Calendar', 'uri:Calendar');
     foreach ($this->_mapping as $key => $value) {
         if (!empty($data->{$value}) || $data->{$value} == '0') {
             $nodeContent = null;
             switch ($value) {
                 case 'dtend':
                     if ($data->{$value} instanceof DateTime) {
                         if ($data->is_all_day_event == true) {
                             // whole day events ends at 23:59:59 in Tine 2.0 but 00:00 the next day in AS
                             $dtend = clone $data->dtend;
                             $dtend->addSecond($dtend->get('s') == 59 ? 1 : 0);
                             $dtend->addMinute($dtend->get('i') == 59 ? 1 : 0);
                             $nodeContent = $dtend->format('Ymd\\THis') . 'Z';
                         } else {
                             $nodeContent = $data->dtend->format('Ymd\\THis') . 'Z';
                         }
                     }
                     break;
                 case 'dtstart':
                     if ($data->{$value} instanceof DateTime) {
                         $nodeContent = $data->{$value}->format('Ymd\\THis') . 'Z';
                     }
                     break;
                 default:
                     $nodeContent = $data->{$value};
                     break;
             }
             // skip empty elements
             if ($nodeContent === null || $nodeContent == '') {
                 Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " Value for {$key} is empty. Skip element.");
                 continue;
             }
             // strip off any non printable control characters
             if (!ctype_print($nodeContent)) {
                 $nodeContent = $this->removeControlChars($nodeContent);
             }
             $node = $_domParrent->ownerDocument->createElementNS('uri:Calendar', $key);
             $node->appendChild($_domParrent->ownerDocument->createTextNode($nodeContent));
             $_domParrent->appendChild($node);
         }
     }
     if (!empty($data->description)) {
         if (version_compare($this->_device->acsversion, '12.0', '>=') === true) {
             $body = $_domParrent->appendChild(new DOMElement('Body', null, 'uri:AirSyncBase'));
             $body->appendChild(new DOMElement('Type', 1, 'uri:AirSyncBase'));
             // create a new DOMElement ...
             $dataTag = new DOMElement('Data', null, 'uri:AirSyncBase');
             // ... append it to parent node aka append it to the document ...
             $body->appendChild($dataTag);
             // ... and now add the content (DomText takes care of special chars)
             $dataTag->appendChild(new DOMText($data->description));
         } else {
             // create a new DOMElement ...
             $node = new DOMElement('Body', null, 'uri:Calendar');
             // ... append it to parent node aka append it to the document ...
             $_domParrent->appendChild($node);
             // ... and now add the content (DomText takes care of special chars)
             $node->appendChild(new DOMText($data->description));
         }
     }
     if (!empty($data->alarms)) {
         $alarm = $data->alarms->getFirstRecord();
         if ($alarm instanceof Tinebase_Model_Alarm) {
             // NOTE: option minutes_before is always calculated by Calendar_Controller_Event::_inspectAlarmSet
             $minutesBefore = (int) $alarm->getOption('minutes_before');
             if ($minutesBefore >= 0) {
                 $_domParrent->appendChild(new DOMElement('Reminder', $minutesBefore, 'uri:Calendar'));
             }
         }
     }
     if (!empty($data->rrule)) {
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " calendar rrule " . $data->rrule);
         }
         $rrule = Calendar_Model_Rrule::getRruleFromString($data->rrule);
         $recurrence = $_domParrent->appendChild(new DOMElement('Recurrence', null, 'uri:Calendar'));
         // required fields
         switch ($rrule->freq) {
             case Calendar_Model_Rrule::FREQ_DAILY:
                 $recurrence->appendChild(new DOMElement('Type', self::RECUR_TYPE_DAILY, 'uri:Calendar'));
                 break;
             case Calendar_Model_Rrule::FREQ_WEEKLY:
                 $recurrence->appendChild(new DOMElement('Type', self::RECUR_TYPE_WEEKLY, 'uri:Calendar'));
                 $recurrence->appendChild(new DOMElement('DayOfWeek', $this->_convertDayToBitMask($rrule->byday), 'uri:Calendar'));
                 break;
             case Calendar_Model_Rrule::FREQ_MONTHLY:
                 if (!empty($rrule->bymonthday)) {
                     $recurrence->appendChild(new DOMElement('Type', self::RECUR_TYPE_MONTHLY, 'uri:Calendar'));
                     $recurrence->appendChild(new DOMElement('DayOfMonth', $rrule->bymonthday, 'uri:Calendar'));
                 } else {
                     $weekOfMonth = (int) substr($rrule->byday, 0, -2);
                     $weekOfMonth = $weekOfMonth == -1 ? 5 : $weekOfMonth;
                     $dayOfWeek = substr($rrule->byday, -2);
                     $recurrence->appendChild(new DOMElement('Type', self::RECUR_TYPE_MONTHLY_DAYN, 'uri:Calendar'));
                     $recurrence->appendChild(new DOMElement('WeekOfMonth', $weekOfMonth, 'uri:Calendar'));
                     $recurrence->appendChild(new DOMElement('DayOfWeek', $this->_convertDayToBitMask($dayOfWeek), 'uri:Calendar'));
                 }
                 break;
             case Calendar_Model_Rrule::FREQ_YEARLY:
                 if (!empty($rrule->bymonthday)) {
                     $recurrence->appendChild(new DOMElement('Type', self::RECUR_TYPE_YEARLY, 'uri:Calendar'));
                     $recurrence->appendChild(new DOMElement('DayOfMonth', $rrule->bymonthday, 'uri:Calendar'));
                     $recurrence->appendChild(new DOMElement('MonthOfYear', $rrule->bymonth, 'uri:Calendar'));
                 } else {
                     $weekOfMonth = (int) substr($rrule->byday, 0, -2);
                     $weekOfMonth = $weekOfMonth == -1 ? 5 : $weekOfMonth;
                     $dayOfWeek = substr($rrule->byday, -2);
                     $recurrence->appendChild(new DOMElement('Type', self::RECUR_TYPE_YEARLY_DAYN, 'uri:Calendar'));
                     $recurrence->appendChild(new DOMElement('WeekOfMonth', $weekOfMonth, 'uri:Calendar'));
                     $recurrence->appendChild(new DOMElement('DayOfWeek', $this->_convertDayToBitMask($dayOfWeek), 'uri:Calendar'));
                     $recurrence->appendChild(new DOMElement('MonthOfYear', $rrule->bymonth, 'uri:Calendar'));
                 }
                 break;
         }
         // required field
         $recurrence->appendChild(new DOMElement('Interval', $rrule->interval, 'uri:Calendar'));
         if ($rrule->until instanceof DateTime) {
             $recurrence->appendChild(new DOMElement('Until', $rrule->until->format('Ymd\\THis') . 'Z', 'uri:Calendar'));
         }
         // handle exceptions of repeating events
         if ($data->exdate instanceof Tinebase_Record_RecordSet && $data->exdate->count() > 0) {
             $exceptionsTag = $_domParrent->appendChild(new DOMElement('Exceptions', null, 'uri:Calendar'));
             foreach ($data->exdate as $exception) {
                 $exceptionTag = $exceptionsTag->appendChild(new DOMElement('Exception', null, 'uri:Calendar'));
                 $exceptionTag->appendChild(new DOMElement('Deleted', (int) $exception->is_deleted, 'uri:Calendar'));
                 $exceptionTag->appendChild(new DOMElement('ExceptionStartTime', $exception->getOriginalDtStart()->format('Ymd\\THis') . 'Z', 'uri:Calendar'));
                 if ((int) $exception->is_deleted === 0) {
                     $this->appendXML($exceptionTag, $_collectionData, $exception);
                 }
             }
         }
     }
     if (count($data->attendee) > 0) {
         // fill attendee cache
         Calendar_Model_Attender::resolveAttendee($data->attendee, FALSE);
         $attendees = $_domParrent->ownerDocument->createElementNS('uri:Calendar', 'Attendees');
         foreach ($data->attendee as $attenderObject) {
             $attendee = $attendees->appendChild(new DOMElement('Attendee', null, 'uri:Calendar'));
             $attendee->appendChild(new DOMElement('Name', $attenderObject->getName(), 'uri:Calendar'));
             $attendee->appendChild(new DOMElement('Email', $attenderObject->getEmail(), 'uri:Calendar'));
             if (version_compare($this->_device->acsversion, '12.0', '>=') === true) {
                 $acsType = array_search($attenderObject->role, $this->_attendeeTypeMapping);
                 $attendee->appendChild(new DOMElement('AttendeeType', $acsType ? $acsType : self::ATTENDEE_TYPE_REQUIRED, 'uri:Calendar'));
                 $acsStatus = array_search($attenderObject->status, $this->_attendeeStatusMapping);
                 $attendee->appendChild(new DOMElement('AttendeeStatus', $acsStatus ? $acsStatus : self::ATTENDEE_STATUS_UNKNOWN, 'uri:Calendar'));
             }
         }
         if ($attendees->hasChildNodes()) {
             $_domParrent->appendChild($attendees);
         }
         // set own status
         if (($ownAttendee = Calendar_Model_Attender::getOwnAttender($data->attendee)) !== null && ($busyType = array_search($ownAttendee->status, $this->_busyStatusMapping)) !== false) {
             $_domParrent->appendChild(new DOMElement('BusyStatus', $busyType, 'uri:Calendar'));
         }
     }
     $timeZoneConverter = ActiveSync_TimezoneConverter::getInstance(Tinebase_Core::getLogger(), Tinebase_Core::get(Tinebase_Core::CACHE));
     $_domParrent->appendChild(new DOMElement('Timezone', $timeZoneConverter->encodeTimezone(Tinebase_Core::get(Tinebase_Core::USERTIMEZONE)), 'uri:Calendar'));
     $_domParrent->appendChild(new DOMElement('MeetingStatus', 1, 'uri:Calendar'));
     $_domParrent->appendChild(new DOMElement('Sensitivity', 0, 'uri:Calendar'));
     $_domParrent->appendChild(new DOMElement('DtStamp', $data->creation_time->format('Ymd\\THis') . 'Z', 'uri:Calendar'));
     $_domParrent->appendChild(new DOMElement('UID', $data->uid, 'uri:Calendar'));
     if (!empty($data->organizer)) {
         try {
             $contact = Addressbook_Controller_Contact::getInstance()->get($data->organizer);
             $_domParrent->appendChild(new DOMElement('OrganizerName', $contact->n_fileas, 'uri:Calendar'));
             $_domParrent->appendChild(new DOMElement('OrganizerEmail', $contact->email, 'uri:Calendar'));
         } catch (Tinebase_Exception_AccessDenied $e) {
             // set the current account as organizer
             // if organizer is not set, you can not edit the event on the Motorola Milestone
             $_domParrent->appendChild(new DOMElement('OrganizerName', Tinebase_Core::getUser()->accountFullName, 'uri:Calendar'));
             if (isset(Tinebase_Core::getUser()->accountEmailAddress)) {
                 $_domParrent->appendChild(new DOMElement('OrganizerEmail', Tinebase_Core::getUser()->accountEmailAddress, 'uri:Calendar'));
             }
         }
     } else {
         // set the current account as organizer
         // if organizer is not set, you can not edit the event on the Motorola Milestone
         $_domParrent->appendChild(new DOMElement('OrganizerName', Tinebase_Core::getUser()->accountFullName, 'uri:Calendar'));
         if (isset(Tinebase_Core::getUser()->accountEmailAddress)) {
             $_domParrent->appendChild(new DOMElement('OrganizerEmail', Tinebase_Core::getUser()->accountEmailAddress, 'uri:Calendar'));
         }
     }
     if (isset($data->tags) && count($data->tags) > 0) {
         $categories = $_domParrent->appendChild(new DOMElement('Categories', null, 'uri:Calendar'));
         foreach ($data->tags as $tag) {
             $categories->appendChild(new DOMElement('Category', $tag, 'uri:Calendar'));
         }
     }
 }
 /**
  * test xml generation for IPhone
  * 
  * FIXME fix this test! -> seems to fail depending on the current time / date 
  */
 public function testAppendXml_dailyEvent()
 {
     $imp = new DOMImplementation();
     $dtd = $imp->createDocumentType('AirSync', "-//AIRSYNC//DTD AirSync//EN", "http://www.microsoft.com/");
     $testDom = $imp->createDocument('uri:AirSync', 'Sync', $dtd);
     $testDom->formatOutput = true;
     $testDom->encoding = 'utf-8';
     $testDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:Calendar', 'uri:Calendar');
     $collections = $testDom->documentElement->appendChild($testDom->createElementNS('uri:AirSync', 'Collections'));
     $collection = $collections->appendChild($testDom->createElementNS('uri:AirSync', 'Collection'));
     $commands = $collection->appendChild($testDom->createElementNS('uri:AirSync', 'Commands'));
     $add = $commands->appendChild($testDom->createElementNS('uri:AirSync', 'Add'));
     $appData = $add->appendChild($testDom->createElementNS('uri:AirSync', 'ApplicationData'));
     $controller = new ActiveSync_Controller_Calendar($this->objects['deviceIPhone'], new Tinebase_DateTime());
     $controller->appendXML($appData, null, $this->objects['eventDaily']->getId(), array());
     // namespace === uri:Calendar
     $this->assertEquals(ActiveSync_Controller_Calendar::RECUR_TYPE_DAILY, @$testDom->getElementsByTagNameNS('uri:Calendar', 'Type')->item(0)->nodeValue, $testDom->saveXML());
     $this->assertEquals(4, @$testDom->getElementsByTagNameNS('uri:Calendar', 'Exception')->length, $testDom->saveXML());
     $this->assertEquals(4, @$testDom->getElementsByTagNameNS('uri:Calendar', 'ExceptionStartTime')->length, $testDom->saveXML());
     $this->assertEquals(3, @$testDom->getElementsByTagNameNS('uri:Calendar', 'Subject')->length, $testDom->saveXML());
     $endTime = $this->objects['eventDaily']->dtend->format("Ymd\\THis") . 'Z';
     $this->assertEquals($endTime, @$testDom->getElementsByTagNameNS('uri:Calendar', 'EndTime')->item(0)->nodeValue, $testDom->saveXML());
     $untilTime = Calendar_Model_Rrule::getRruleFromString($this->objects['eventDaily']->rrule)->until->format("Ymd\\THis") . 'Z';
     $this->assertEquals($untilTime, @$testDom->getElementsByTagNameNS('uri:Calendar', 'Until')->item(0)->nodeValue, $testDom->saveXML());
 }
Beispiel #15
0
 /**
  * inspect update of one record
  * 
  * @param   Tinebase_Record_Interface $_record      the update record
  * @param   Tinebase_Record_Interface $_oldRecord   the current persistent record
  * @return  void
  */
 protected function _inspectBeforeUpdate($_record, $_oldRecord)
 {
     // if dtstart of an event changes, we update the originator_tz, alarm times
     if (!$_oldRecord->dtstart->equals($_record->dtstart)) {
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' dtstart changed -> adopting organizer_tz');
         }
         $_record->originator_tz = Tinebase_Core::get(Tinebase_Core::USERTIMEZONE);
         // update exdates and recurids if dtsart of an recurevent changes
         if (!empty($_record->rrule)) {
             $diff = $_oldRecord->dtstart->diff($_record->dtstart);
             // update exceptions
             $exceptions = $this->getRecurExceptions($_record);
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' dtstart of a series changed -> adopting ' . count($exceptions) . ' recurid(s)');
             }
             $exdates = array();
             foreach ($exceptions as $exception) {
                 $exception->recurid = new Tinebase_DateTime(substr($exception->recurid, -19));
                 Calendar_Model_Rrule::addUTCDateDstFix($exception->recurid, $diff, $_record->originator_tz);
                 $exdates[] = $exception->recurid;
                 $exception->setRecurId();
                 $this->_backend->update($exception);
             }
             $_record->exdate = $exdates;
         }
     }
     // delete recur exceptions if update is not longer a recur series
     if (!empty($_oldRecord->rrule) && empty($_record->rrule)) {
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' deleteing recur exceptions as event is no longer a recur series');
         }
         $this->_backend->delete($this->getRecurExceptions($_record));
     }
     // touch base event of a recur series if an persisten exception changes
     if ($_record->recurid) {
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' touch base event of a persisten exception');
         }
         $baseEvent = $this->getRecurBaseEvent($_record);
         $this->_touch($baseEvent, TRUE);
     }
 }
 public function testCreateRecurExceptionWithEditGrantOnly()
 {
     $this->markTestIncomplete('temporarily disabled until fixed');
     // set testuser to have editgrant for sclever
     Tinebase_Container::getInstance()->setGrants($this->_getPersonasDefaultCals('sclever'), new Tinebase_Record_RecordSet('Tinebase_Model_Grants', array(array('account_id' => $this->_getPersona('sclever')->getId(), 'account_type' => 'user', Tinebase_Model_Grants::GRANT_READ => true, Tinebase_Model_Grants::GRANT_ADD => true, Tinebase_Model_Grants::GRANT_EDIT => true, Tinebase_Model_Grants::GRANT_DELETE => true, Tinebase_Model_Grants::GRANT_PRIVATE => true, Tinebase_Model_Grants::GRANT_ADMIN => true, Tinebase_Model_Grants::GRANT_FREEBUSY => true), array('account_id' => Tinebase_Core::getUser()->getId(), 'account_type' => 'user', Tinebase_Model_Grants::GRANT_READ => false, Tinebase_Model_Grants::GRANT_ADD => false, Tinebase_Model_Grants::GRANT_EDIT => true, Tinebase_Model_Grants::GRANT_DELETE => false, Tinebase_Model_Grants::GRANT_PRIVATE => false, Tinebase_Model_Grants::GRANT_ADMIN => false, Tinebase_Model_Grants::GRANT_FREEBUSY => false))), TRUE);
     $persistentEvent = $this->_createEventInPersonasCalendar('sclever', 'sclever');
     $persistentEvent->rrule = 'FREQ=DAILY;INTERVAL=1';
     $updatedEvent = $this->_uit->update($persistentEvent);
     $events = $this->_uit->search(new Calendar_Model_EventFilter(array(array('field' => 'id', 'operator' => 'equals', 'value' => $persistentEvent->getId()))), NULL, FALSE, FALSE);
     $this->assertEquals(1, count($events), 'failed to search fb event');
     Calendar_Model_Rrule::mergeRecurrenceSet($events, $updatedEvent->dtstart, $updatedEvent->dtstart->getClone()->addDay(7));
     $this->assertEquals(8, count($events), 'failed to merge recurrence set');
     $events[3]->summary = 'exception';
     $exception = $this->_uit->createRecurException($events[3]);
     $this->assertEquals('exception', $exception->summary);
 }
Beispiel #17
0
 /**
  * returns multiple records prepared for json transport
  *
  * @param Tinebase_Record_RecordSet $_records Tinebase_Record_Abstract
  * @param Tinebase_Model_Filter_FilterGroup $_filter
  * @param Tinebase_Model_Pagination $_pagination needed for sorting
  * @return array data
  * 
  * @todo perhaps we need to resolveContainerTagsUsers() before  mergeAndRemoveNonMatchingRecurrences(), but i'm not sure about that
  * @todo use Calendar_Convert_Event_Json
  */
 protected function _multipleRecordsToJson(Tinebase_Record_RecordSet $_records, $_filter = NULL, $_pagination = NULL)
 {
     if ($_records->getRecordClassName() == 'Calendar_Model_Event') {
         if (is_null($_filter)) {
             throw new Tinebase_Exception_InvalidArgument('Required argument $_filter is missing');
         }
         Tinebase_Notes::getInstance()->getMultipleNotesOfRecords($_records);
         Calendar_Model_Attender::resolveAttendee($_records->attendee, TRUE, $_records);
         Calendar_Convert_Event_Json::resolveOrganizer($_records);
         Calendar_Convert_Event_Json::resolveRrule($_records);
         Calendar_Controller_Event::getInstance()->getAlarms($_records);
         Calendar_Model_Rrule::mergeAndRemoveNonMatchingRecurrences($_records, $_filter);
         $_records->sortByPagination($_pagination);
         $eventsData = parent::_multipleRecordsToJson($_records);
         foreach ($eventsData as $eventData) {
             if (!array_key_exists(Tinebase_Model_Grants::GRANT_READ, $eventData) || !$eventData[Tinebase_Model_Grants::GRANT_READ]) {
                 $eventData['notes'] = array();
                 $eventData['tags'] = array();
             }
         }
         return $eventsData;
     }
     return parent::_multipleRecordsToJson($_records);
 }
 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);
 }
 /**
  * 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');
 }
Beispiel #20
0
 /**
  * sets rrule until helper field
  *
  * @return void
  */
 public function setRruleUntil()
 {
     if (empty($this->rrule)) {
         $this->rrule_until = NULL;
     } else {
         $rrule = $this->rrule;
         if (!$this->rrule instanceof Calendar_Model_Rrule) {
             $rrule = new Calendar_Model_Rrule(array());
             $rrule->setFromString($this->rrule);
         }
         if (isset($rrule->count)) {
             $this->rrule_until = NULL;
             $exdates = $this->exdate;
             $this->exdate = NULL;
             $lastOccurrence = Calendar_Model_Rrule::computeNextOccurrence($this, new Tinebase_Record_RecordSet('Calendar_Model_Event'), $this->dtend, $rrule->count - 1);
             $this->rrule_until = $lastOccurrence->dtend;
             $this->exdate = $exdates;
         } else {
             $this->rrule_until = $rrule->until;
         }
     }
 }
 /**
  * testAcceptInvitationForRecurringEventException
  * 
  * @see 0009022: can not accept invitation to recurring event exception
  * @see 0009510: is it allowed to have no main vevent in ics?
  */
 public function testAcceptInvitationForRecurringEventException()
 {
     Tinebase_Container::getInstance()->setGrants($this->objects['initialContainer'], new Tinebase_Record_RecordSet('Tinebase_Model_Grants', array($this->_getAllCalendarGrants(), array('account_id' => 0, 'account_type' => 'anyone', Tinebase_Model_Grants::GRANT_READ => true, Tinebase_Model_Grants::GRANT_ADD => false, Tinebase_Model_Grants::GRANT_EDIT => false, Tinebase_Model_Grants::GRANT_DELETE => false, Tinebase_Model_Grants::GRANT_FREEBUSY => true, Tinebase_Model_Grants::GRANT_ADMIN => false))), true);
     $persistentEvent = Calendar_Controller_Event::getInstance()->create(new Calendar_Model_Event(array('container_id' => $this->objects['initialContainer']->getId(), 'rrule' => 'FREQ=WEEKLY;BYDAY=WE', 'dtstart' => new Tinebase_DateTime('20131016T120000'), 'dtend' => new Tinebase_DateTime('20131016T130000'), 'summary' => 'Meeting', 'attendee' => new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(array('user_id' => Tinebase_Core::getUser()->contact_id, 'user_type' => Calendar_Model_Attender::USERTYPE_USER, 'role' => Calendar_Model_Attender::ROLE_REQUIRED, 'status_authkey' => 'e4546f26cb37f69baf59135e7bd379bf94bba429'))), 'uid' => '3ef8b44333aea7c01aa5a9308e2cb014807c60b3')));
     // add pwulf as attender to create exception
     $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
     $exception = Calendar_Model_Rrule::computeNextOccurrence($persistentEvent, $exceptions, new Tinebase_DateTime('20131017T140000'));
     $exception->attendee->addRecord(new Calendar_Model_Attender(array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('pwulf')->getId())));
     $persistentException = Calendar_Controller_Event::getInstance()->createRecurException($exception);
     $persistentEvent = Calendar_Controller_Event::getInstance()->get($persistentEvent->getId());
     // pwulf tries to accept invitation
     Tinebase_Core::set(Tinebase_Core::USER, Tinebase_User::getInstance()->getFullUserByLoginName('pwulf'));
     $_SERVER['HTTP_USER_AGENT'] = 'Mac OS X/10.8.5 (12F45) CalendarAgent/57';
     // this ics only has an exdate vevent
     $vcalendarStream = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/accept_exdate_invite.ics');
     $event = new Calendar_Frontend_WebDAV_Event($this->objects['initialContainer'], $persistentEvent);
     $event->put($vcalendarStream);
     $exdateWebDAVEvent = $event->getRecord()->exdate[0];
     $this->_assertCurrentUserAttender($exdateWebDAVEvent);
     $exdateCalEvent = Calendar_Controller_Event::getInstance()->get($persistentException->getId());
     $this->_assertCurrentUserAttender($exdateCalEvent);
 }
 /**
  * print alarm acknowledgement report (when, ip, client, user, ...)
  * 
  * @param Zend_Console_Getopt $_opts
  */
 public function alarmAckReport(Zend_Console_Getopt $_opts)
 {
     $until = Tinebase_DateTime::now();
     $from = Tinebase_DateTime::now()->subDay(1);
     // get all events for today for current user
     $filter = new Calendar_Model_EventFilter(array(array('field' => 'attender', 'operator' => 'in', 'value' => array(array('user_type' => 'user', 'user_id' => Tinebase_Core::getUser()->contact_id))), array('field' => 'attender_status', 'operator' => 'not', 'value' => Calendar_Model_Attender::STATUS_DECLINED), array('field' => 'period', 'operator' => 'within', 'value' => array("from" => $from, "until" => $until))));
     $events = Calendar_Controller_Event::getInstance()->search($filter);
     Calendar_Model_Rrule::mergeAndRemoveNonMatchingRecurrences($events, $filter);
     Calendar_Controller_Event::getInstance()->getAlarms($events);
     echo "Reporting alarms for events of user " . Tinebase_Core::getUser()->accountLoginName . " (All times in UTC) from " . $from->toString() . ' until ' . $until->toString() . "...\n\n";
     // loop alarms and print alarm ack info
     foreach ($events as $event) {
         if (count($event->alarms) > 0) {
             $this->_printShortEvent($event);
             foreach ($event->alarms as $alarm) {
                 echo "  Alarm " . $alarm->alarm_time . "\n";
                 $ackTime = Calendar_Controller_Alarm::getAcknowledgeTime($alarm);
                 if (empty($ackTime)) {
                     echo "    not acknowledged!";
                 } else {
                     if (is_array($ackTime)) {
                         $ackTime = array_pop($ackTime);
                     }
                     echo "    acknowledged " . $ackTime->toString() . "\n    IP -> " . $alarm->getOption(Tinebase_Model_Alarm::OPTION_ACK_IP) . "\n    Client ->" . $alarm->getOption(Tinebase_Model_Alarm::OPTION_ACK_CLIENT) . "\n";
                 }
                 echo "\n";
             }
             echo "\n";
         }
     }
 }
 public function testGetRecurExceptions()
 {
     $persitentException = $this->testCreateRecurException();
     $baseEvent = $this->_controller->getRecurBaseEvent($persitentException);
     $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
     $nextOccurance = Calendar_Model_Rrule::computeNextOccurrence($baseEvent, $exceptions, $baseEvent->dtstart);
     $this->_controller->createRecurException($nextOccurance, TRUE);
     $exceptions = $this->_controller->getRecurExceptions($persitentException, TRUE);
     $dtstarts = $exceptions->dtstart;
     $this->assertTrue(in_array($nextOccurance->dtstart, $dtstarts), 'deleted instance missing');
     $this->assertTrue(in_array($persitentException->dtstart, $dtstarts), 'exception instance missing');
 }
 /**
  * testSetAlarmOfRecurSeriesException
  */
 public function testSetAlarmOfRecurSeriesException()
 {
     $event = $this->_getEvent();
     $event->rrule = 'FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;INTERVAL=1';
     $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array(new Tinebase_Model_Alarm(array('minutes_before' => 30), TRUE)));
     $persistentEvent = $this->_controller->create($event);
     $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
     $exception = Calendar_Model_Rrule::computeNextOccurrence($persistentEvent, $exceptions, new Tinebase_DateTime());
     $exception->dtstart->subHour(6);
     $exception->dtend->subHour(6);
     $persistentException = $this->_controller->createRecurException($exception);
     $baseEvent = $this->_controller->getRecurBaseEvent($persistentException);
     $this->_controller->getAlarms($baseEvent);
     $exceptions = $this->_controller->getRecurExceptions($persistentException);
     $nextOccurance = Calendar_Model_Rrule::computeNextOccurrence($baseEvent, $exceptions, Tinebase_DateTime::now());
     $nextAlarmEventStart = new Tinebase_DateTime(substr($baseEvent->alarms->getFirstRecord()->getOption('recurid'), -19));
     $this->assertTrue($nextOccurance->dtstart->equals($nextAlarmEventStart), 'next alarm got not adjusted');
     $alarmTime = clone $persistentException->dtstart;
     $alarmTime->subMinute(30);
     $this->assertTrue($alarmTime->equals($persistentException->alarms->getFirstRecord()->alarm_time), 'alarmtime of persistent exception is not correnct/set');
 }
 /**
  * update to 8.3
  * - normalize all rrules
  */
 public function update_2()
 {
     // find all events with rrule
     $eventIds = $this->_db->query("SELECT " . $this->_db->quoteIdentifier('id') . " FROM " . $this->_db->quoteIdentifier(SQL_TABLE_PREFIX . "cal_events") . " WHERE " . $this->_db->quoteIdentifier("rrule") . " IS NOT NULL")->fetchAll(Zend_Db::FETCH_ASSOC);
     // NOTE: we need a generic sql BE to circumvent calendar specific acl issues
     $eventBE = new Tinebase_Backend_Sql(array('modelName' => 'Calendar_Model_Event', 'tableName' => 'cal_events', 'modlogActive' => false));
     foreach ($eventIds as $eventId) {
         $event = $eventBE->get($eventId['id']);
         $oldRruleString = (string) $event->rrule;
         $rrule = Calendar_Model_Rrule::getRruleFromString($oldRruleString);
         $rrule->normalize($event);
         if ($oldRruleString != (string) $rrule) {
             $event->rrule = (string) $rrule;
             try {
                 $eventBE->update($event);
             } catch (Tinebase_Exception_Record_Validation $terv) {
                 Tinebase_Exception::log($terv, null, $event->toArray());
             } catch (Tinebase_Exception_UnexpectedValue $teuv) {
                 Tinebase_Exception::log($teuv, null, $event->toArray());
             }
         }
     }
     $this->setApplicationVersion('Calendar', '8.3');
 }
Beispiel #26
0
 /**
  * @see #5806: thisandfuture range updates with count part fail
  */
 public function testCreateRecurExceptionAllFollowingWithCount()
 {
     $from = new Tinebase_DateTime('2012-02-20 00:00:00');
     $until = new Tinebase_DateTime('2012-02-26 23:59:59');
     $event = new Calendar_Model_Event(array('uid' => Tinebase_Record_Abstract::generateUID(), 'summary' => 'Abendessen', 'dtstart' => '2012-02-21 14:00:00', 'dtend' => '2012-02-21 15:30:00', 'originator_tz' => 'Europe/Berlin', 'rrule' => 'FREQ=DAILY;COUNT=5', 'container_id' => $this->_testCalendar->getId()));
     $persistentEvent = $this->_controller->create($event);
     // create exception
     $weekviewEvents = $this->_controller->search(new Calendar_Model_EventFilter(array(array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId()))));
     Calendar_Model_Rrule::mergeRecurrenceSet($weekviewEvents, $from, $until);
     $weekviewEvents[2]->dtstart->subHour(5);
     $weekviewEvents[2]->dtend->subHour(5);
     $this->_controller->createRecurException($weekviewEvents[2], FALSE, TRUE);
     // load events
     $weekviewEvents = $this->_controller->search(new Calendar_Model_EventFilter(array(array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId()))));
     Calendar_Model_Rrule::mergeRecurrenceSet($weekviewEvents, $from, $until);
     $weekviewEvents->sort('dtstart', 'ASC');
     $this->assertEquals(2, count($weekviewEvents->filter('uid', $weekviewEvents[0]->uid)), 'shorten failed');
     $this->assertEquals(5, count($weekviewEvents), 'wrong total count');
 }
 public function testGetTranslatedRule()
 {
     $locale = new Zend_Locale('en');
     $translation = Tinebase_Translation::getTranslation('Calendar', $locale);
     $asserts = array('FREQ=DAILY;INTERVAL=1' => 'Daily', 'FREQ=DAILY;INTERVAL=3' => 'Every 3rd day', 'FREQ=WEEKLY;INTERVAL=3;WKST=SU;BYDAY=TU,WE,TH' => 'Every 3rd week on Tuesday, Wednesday and Thursday', 'FREQ=MONTHLY;INTERVAL=2;BYDAY=-1FR' => 'Every 2nd month on the last Friday', 'FREQ=MONTHLY;INTERVAL=1;BYDAY=2TH' => 'Monthly every second Thursday', 'FREQ=MONTHLY;INTERVAL=3;BYMONTHDAY=24' => 'Every 3rd month on the 24th', 'FREQ=MONTHLY;INTERVAL=1;BYMONTHDAY=5' => 'Monthly on the 5th', 'FREQ=YEARLY;INTERVAL=1;BYMONTH=7;BYMONTHDAY=10' => 'Yearly on the 10th of July');
     foreach ($asserts as $rruleString => $expected) {
         $translated = Calendar_Model_Rrule::getRruleFromString($rruleString);
         $this->assertEquals($translated, $translated);
     }
 }
 /**
  * converts egw rrule into tine/iCal rrule
  * 
  * @param  array $_egwEventData
  * @return Calendar_Model_Rrule
  */
 protected function _convertRrule($_egwEventData)
 {
     $egwRrule = $_egwEventData['rrule'];
     $rrule = new Calendar_Model_Rrule(array());
     if (!(isset($this->_rruleFreqMap[$egwRrule['recur_type']]) || array_key_exists($egwRrule['recur_type'], $this->_rruleFreqMap))) {
         throw new Exception('unsupported rrule freq');
     }
     $rrule->freq = $this->_rruleFreqMap[$egwRrule['recur_type']];
     $rrule->interval = $egwRrule['recur_interval'];
     $rrule->until = $this->convertDate($egwRrule['recur_enddate']);
     // weekly/monthly by wday
     if ($egwRrule['recur_type'] == 2 || $egwRrule['recur_type'] == 4) {
         $wdays = array();
         foreach ($this->_rruleWdayMap as $egwBit => $iCalString) {
             if ($egwRrule['recur_data'] & $egwBit) {
                 $wdays[] = $iCalString;
             }
         }
         $rrule->byday = implode(',', $wdays);
     }
     // monthly byday/yearly bymonthday
     if ($egwRrule['recur_type'] == 3 || $egwRrule['recur_type'] == 5) {
         $dtstart = $this->convertDate($_egwEventData['cal_start']);
         $dateArray = Calendar_Model_Rrule::date2array($dtstart);
         $rrule->bymonthday = $dateArray['day'];
         if ($egwRrule['recur_type'] == 5) {
             $rrule->bymonth = $dateArray['month'];
         }
     }
     return $rrule;
 }
 /**
  * Computes the Recurrence set of the given event leaving out $_event->exdate and $_exceptions
  * 
  * @todo respect rrule_until!
  *
  * @param  Calendar_Model_Event         $_event
  * @param  Tinebase_Record_RecordSet    $_exceptions
  * @param  Tinebase_DateTime            $_from
  * @param  Tinebase_DateTime            $_until
  * @return Tinebase_Record_RecordSet
  * @throws Tinebase_Exception_UnexpectedValue
  */
 public static function computeRecurrenceSet($_event, $_exceptions, $_from, $_until)
 {
     if (!$_event->dtstart instanceof Tinebase_DateTime) {
         throw new Tinebase_Exception_UnexpectedValue('Event needs DateTime dtstart: ' . print_r($_event->toArray(), TRUE));
     }
     $rrule = new Calendar_Model_Rrule(NULL, TRUE);
     $rrule->setFromString($_event->rrule);
     $exceptionRecurIds = self::getExceptionsRecurIds($_event, $_exceptions);
     $recurSet = new Tinebase_Record_RecordSet('Calendar_Model_Event');
     switch ($rrule->freq) {
         case self::FREQ_DAILY:
             self::_computeRecurDaily($_event, $rrule, $exceptionRecurIds, $_from, $_until, $recurSet);
             break;
         case self::FREQ_WEEKLY:
             // default BYDAY clause
             if (!$rrule->byday) {
                 $rrule->byday = array_search($_event->dtstart->format('w'), self::$WEEKDAY_DIGIT_MAP);
             }
             if (!$rrule->wkst) {
                 $rrule->wkst = self::getWeekStart();
             }
             $weekDays = array_keys(self::$WEEKDAY_DIGIT_MAP);
             array_splice($weekDays, 0, 0, array_splice($weekDays, array_search($rrule->wkst, $weekDays)));
             $dailyrrule = clone $rrule;
             $dailyrrule->freq = self::FREQ_DAILY;
             $dailyrrule->interval = 7 * $rrule->interval;
             $eventLength = $_event->dtstart->diff($_event->dtend);
             foreach (explode(',', $rrule->byday) as $recurWeekDay) {
                 // NOTE: in weekly computation, each wdays base event is a recur instance itself
                 $baseEvent = clone $_event;
                 // NOTE: skipping must be done in organizer_tz
                 $baseEvent->dtstart->setTimezone($_event->originator_tz);
                 $direction = array_search($recurWeekDay, $weekDays) >= array_search(array_search($baseEvent->dtstart->format('w'), self::$WEEKDAY_DIGIT_MAP), $weekDays) ? +1 : -1;
                 self::skipWday($baseEvent->dtstart, $recurWeekDay, $direction, TRUE);
                 $baseEvent->dtstart->setTimezone('UTC');
                 $baseEvent->dtend = clone $baseEvent->dtstart;
                 $baseEvent->dtend->add($eventLength);
                 self::_computeRecurDaily($baseEvent, $dailyrrule, $exceptionRecurIds, $_from, $_until, $recurSet);
                 // check if base event (recur instance) needs to be added to the set
                 if ($baseEvent->dtstart > $_event->dtstart && $baseEvent->dtstart >= $_from && $baseEvent->dtstart < $_until) {
                     if (!in_array($baseEvent->setRecurId($baseEvent->getId()), $exceptionRecurIds)) {
                         self::addRecurrence($baseEvent, $recurSet);
                     }
                 }
             }
             break;
         case self::FREQ_MONTHLY:
             if ($rrule->byday) {
                 self::_computeRecurMonthlyByDay($_event, $rrule, $exceptionRecurIds, $_from, $_until, $recurSet);
             } else {
                 self::_computeRecurMonthlyByMonthDay($_event, $rrule, $exceptionRecurIds, $_from, $_until, $recurSet);
             }
             break;
         case self::FREQ_YEARLY:
             $yearlyrrule = clone $rrule;
             $yearlyrrule->freq = self::FREQ_MONTHLY;
             $yearlyrrule->interval = 12;
             $baseEvent = clone $_event;
             $originatorsDtstart = clone $baseEvent->dtstart;
             $originatorsDtstart->setTimezone($_event->originator_tz);
             // @TODO respect BYMONTH
             if ($rrule->bymonth && $rrule->bymonth != $originatorsDtstart->format('n')) {
                 // adopt
                 $diff = (12 + $rrule->bymonth - $originatorsDtstart->format('n')) % 12;
                 // NOTE: skipping must be done in organizer_tz
                 $baseEvent->dtstart->setTimezone($_event->originator_tz);
                 $baseEvent->dtend->setTimezone($_event->originator_tz);
                 $baseEvent->dtstart->addMonth($diff);
                 $baseEvent->dtend->addMonth($diff);
                 $baseEvent->dtstart->setTimezone('UTC');
                 $baseEvent->dtend->setTimezone('UTC');
                 // check if base event (recur instance) needs to be added to the set
                 if ($baseEvent->dtstart->isLater($_from) && $baseEvent->dtstart->isEarlier($_until)) {
                     if (!in_array($baseEvent->setRecurId($baseEvent->getId()), $exceptionRecurIds)) {
                         self::addRecurrence($baseEvent, $recurSet);
                     }
                 }
             }
             if ($rrule->byday) {
                 self::_computeRecurMonthlyByDay($baseEvent, $yearlyrrule, $exceptionRecurIds, $_from, $_until, $recurSet);
             } else {
                 self::_computeRecurMonthlyByMonthDay($baseEvent, $yearlyrrule, $exceptionRecurIds, $_from, $_until, $recurSet);
             }
             break;
     }
     return $recurSet;
 }
 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);
 }