/**
  * 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);
 }
 /**
  * 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);
 }
 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);
 }
 /**
  * @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');
 }
 /**
  * returns freebusy information for given period and given attendee
  * 
  * @todo merge overlapping events to one freebusy entry
  * 
  * @param  array of array with from and until                   $_periods
  * @param  Tinebase_Record_RecordSet of Calendar_Model_Attender $_attendee
  * @param  array of UIDs                                        $_ignoreUIDs
  * @return Tinebase_Record_RecordSet of Calendar_Model_FreeBusy
  */
 public function getFreeBusyInfo($_periods, $_attendee, $_ignoreUIDs = array())
 {
     $fbInfoSet = new Tinebase_Record_RecordSet('Calendar_Model_FreeBusy');
     // map groupmembers to users
     $attendee = clone $_attendee;
     $attendee->addIndices(array('user_type'));
     $groupmembers = $attendee->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER);
     $groupmembers->user_type = Calendar_Model_Attender::USERTYPE_USER;
     // base filter data
     $filterData = array(array('field' => 'attender', 'operator' => 'in', 'value' => $_attendee), array('field' => 'transp', 'operator' => 'equals', 'value' => Calendar_Model_Event::TRANSP_OPAQUE));
     // add all periods to filterdata
     $periodFilters = array();
     foreach ($_periods as $period) {
         $periodFilters[] = array('field' => 'period', 'operator' => 'within', 'value' => array('from' => $period['from'], 'until' => $period['until']));
     }
     $filterData[] = array('condition' => 'OR', 'filters' => $periodFilters);
     // finaly create filter
     $filter = new Calendar_Model_EventFilter($filterData);
     if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
         Tinebase_Core::getLogger()->trace(__METHOD__ . ' ' . __LINE__ . ' free/busy filter: ' . print_r($filter->toArray(), true));
     }
     $events = $this->search($filter, new Tinebase_Model_Pagination(), FALSE, FALSE);
     foreach ($_periods as $period) {
         Calendar_Model_Rrule::mergeRecurrenceSet($events, $period['from'], $period['until']);
     }
     if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
         Tinebase_Core::getLogger()->trace(__METHOD__ . ' ' . __LINE__ . ' value: ' . print_r($events->toArray(), true));
     }
     // create a typemap
     $typeMap = array();
     foreach ($attendee as $attender) {
         if (!(isset($typeMap[$attender['user_type']]) || array_key_exists($attender['user_type'], $typeMap))) {
             $typeMap[$attender['user_type']] = array();
         }
         $typeMap[$attender['user_type']][$attender['user_id']] = array();
     }
     if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
         Tinebase_Core::getLogger()->trace(__METHOD__ . ' ' . __LINE__ . ' value: ' . print_r($typeMap, true));
     }
     // generate freeBusyInfos
     foreach ($events as $event) {
         // skip events with ignoreUID
         if (in_array($event->uid, $_ignoreUIDs)) {
             continue;
         }
         // check if event is conflicting one of the given periods
         $conflicts = FALSE;
         foreach ($_periods as $period) {
             if ($event->dtstart->isEarlier($period['until']) && $event->dtend->isLater($period['from'])) {
                 $conflicts = TRUE;
                 break;
             }
         }
         if (!$conflicts) {
             continue;
         }
         // map groupmembers to users
         $event->attendee->addIndices(array('user_type'));
         $groupmembers = $event->attendee->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER);
         $groupmembers->user_type = Calendar_Model_Attender::USERTYPE_USER;
         foreach ($event->attendee as $attender) {
             // skip declined/transp events
             if ($attender->status == Calendar_Model_Attender::STATUS_DECLINED || $attender->transp == Calendar_Model_Event::TRANSP_TRANSP) {
                 continue;
             }
             if ((isset($typeMap[$attender->user_type]) || array_key_exists($attender->user_type, $typeMap)) && (isset($typeMap[$attender->user_type][$attender->user_id]) || array_key_exists($attender->user_id, $typeMap[$attender->user_type]))) {
                 $fbInfo = new Calendar_Model_FreeBusy(array('user_type' => $attender->user_type, 'user_id' => $attender->user_id, 'dtstart' => clone $event->dtstart, 'dtend' => clone $event->dtend, 'type' => Calendar_Model_FreeBusy::FREEBUSY_BUSY), true);
                 if ($event->{Tinebase_Model_Grants::GRANT_READ}) {
                     $fbInfo->event = clone $event;
                     unset($fbInfo->event->attendee);
                 }
                 //$typeMap[$attender->user_type][$attender->user_id][] = $fbInfo;
                 $fbInfoSet->addRecord($fbInfo);
             }
         }
     }
     return $fbInfoSet;
 }
 /**
  * returns conflicting periods
  *
  * @param Calendar_Model_EventFilter $periodCandidates
  * @param Calendar_Model_EventFilter $conflictCriteria
  * @param bool                       $getAll
  * @return array
  */
 public function getConflictingPeriods($periodCandidates, $conflictCriteria, $getAll = false)
 {
     $conflictFilter = clone $conflictCriteria;
     $conflictFilter->addFilterGroup($periodCandidates);
     $conflictCandidates = $this->search($conflictFilter);
     $from = Tinebase_DateTime::now();
     $until = Tinebase_DateTime::now();
     foreach ($periodCandidates as $periodFilter) {
         $period = $periodFilter->getValue();
         $from = min($from, $period['from']);
         $until = max($until, $period['until']);
         //            Calendar_Model_Rrule::mergeRecurrenceSet($conflictCandidates, $period['from'], $period['until']);
     }
     Calendar_Model_Rrule::mergeRecurrenceSet($conflictCandidates, $from, $until);
     $conflicts = array();
     foreach ($periodCandidates as $periodFilter) {
         $period = $periodFilter->getValue();
         foreach ($conflictCandidates as $event) {
             if ($event->dtstart->isEarlier($period['until']) && $event->dtend->isLater($period['from'])) {
                 $conflicts[] = array('from' => $period['from'], 'until' => $period['until'], 'event' => $event);
                 if (!$getAll) {
                     break;
                 }
             }
         }
     }
     return $conflicts;
 }