Merge branch '2013.10' into 2014.11
authorPhilipp Schüle <p.schuele@metaways.de>
Tue, 25 Aug 2015 16:12:08 +0000 (18:12 +0200)
committerPhilipp Schüle <p.schuele@metaways.de>
Tue, 25 Aug 2015 16:12:08 +0000 (18:12 +0200)
1  2 
tests/tine20/Calendar/Controller/RecurTest.php
tests/tine20/Calendar/Convert/Event/VCalendar/MacOSXTest.php
tine20/Calendar/Model/Event.php

@@@ -35,7 -35,7 +35,7 @@@ class Calendar_Controller_RecurTest ext
              'dtend'         => '2012-06-01 18:30:00',
              'originator_tz' => 'Europe/Berlin',
              'rrule'         => 'FREQ=DAILY;INTERVAL=1;UNTIL=2011-05-31 17:30:00',
 -            'container_id'  => $this->_testCalendar->getId(),
 +            'container_id'  => $this->_getTestCalendar()->getId(),
          ));
          
          $this->setExpectedException('Tinebase_Exception_Record_Validation');
@@@ -85,7 -85,7 +85,7 @@@
              'dtend'         => '2011-04-20 15:30:00',
              'originator_tz' => 'Europe/Berlin',
              'rrule'         => 'FREQ=WEEKLY;INTERVAL=3;WKST=SU;BYDAY=TU,TH',
 -            'container_id'  => $this->_testCalendar->getId(),
 +            'container_id'  => $this->_getTestCalendar()->getId(),
              Tinebase_Model_Grants::GRANT_EDIT     => true,
          ));
          
@@@ -98,7 -98,7 +98,7 @@@
          $persistentEventException = $this->_controller->createRecurException($eventException);
          
          $weekviewEvents = $this->_controller->search(new Calendar_Model_EventFilter(array(
 -            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId()),
 +            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()),
          )));
          
          Calendar_Model_Rrule::mergeRecurrenceSet($weekviewEvents, $from, $until);
          $firstInstanceException->location = $location;
      
          $result = $this->_controller->update($firstInstanceException, FALSE, Calendar_Model_Event::RANGE_THISANDFUTURE);
 -        $this->assertEquals($result->location, $location);
 +        $this->assertEquals($location, $result->location);
      }
  
      /**
                  'dtend'         => '2012-02-22 15:30:00',
                  'originator_tz' => 'Europe/Berlin',
                  'rrule'         => 'FREQ=DAILY;COUNT=3',
 -                'container_id'  => $this->_testCalendar->getId(),
 +                'container_id'  => $this->_getTestCalendar()->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()),
 +            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()),
          )));
          Calendar_Model_Rrule::mergeRecurrenceSet($weekviewEvents, $from, $until);
          $weekviewEvents[2]->dtstart->subHour(5);
          
          // load series
          $weekviewEvents = $this->_controller->search(new Calendar_Model_EventFilter(array(
 -            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId()),
 +            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()),
          )));
          Calendar_Model_Rrule::mergeRecurrenceSet($weekviewEvents, $from, $until);
          $weekviewEvents->sort('dtstart', 'ASC');
              'is_all_day_event'  => true,
              'originator_tz' => 'Europe/Berlin',
              'rrule'         => 'FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH',
 -            'container_id'  => $this->_testCalendar->getId(),
 +            'container_id'  => $this->_getTestCalendar()->getId(),
              Tinebase_Model_Grants::GRANT_EDIT     => true,
          ));
          
          $persistentEvent = $this->_controller->create($event);
          
          $weekviewEvents = $this->_controller->search(new Calendar_Model_EventFilter(array(
 -            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId()),
 +            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()),
          )));
          
          Calendar_Model_Rrule::mergeRecurrenceSet($weekviewEvents, $from, $until);
          $persistentEventException = $this->_controller->createRecurException($exception, TRUE);
          
          $weekviewEvents = $this->_controller->search(new Calendar_Model_EventFilter(array(
 -            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId()),
 +            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()),
          )));
          
          Calendar_Model_Rrule::mergeRecurrenceSet($weekviewEvents, $from, $until);
              'originator_tz' => 'Europe/Berlin',
              'rrule'         => 'FREQ=DAILY;INTERVAL=1;UNTIL=2009-03-31 17:30:00',
              'exdate'        => '2009-03-27 18:00:00,2009-03-29 17:00:00',
 -            'container_id'  => $this->_testCalendar->getId(),
 +            'container_id'  => $this->_getTestCalendar()->getId(),
              Tinebase_Model_Grants::GRANT_EDIT     => true,
          ));
          $event->attendee = $this->_getAttendee();
              'dtend'         => '2011-04-20 15:30:00',
              'originator_tz' => 'Europe/Berlin',
              'rrule'         => 'FREQ=WEEKLY;INTERVAL=3;WKST=SU;BYDAY=TU,TH',
 -            'container_id'  => $this->_testCalendar->getId(),
 +            'container_id'  => $this->_getTestCalendar()->getId(),
              Tinebase_Model_Grants::GRANT_EDIT     => true,
          ));
          $event->attendee = $this->_getAttendee();
          $this->_controller->attenderStatusCreateRecurException(clone $persistentEvent, $attendee, $attendee->status_authkey);
          
          $weekviewEvents = $this->_controller->search(new Calendar_Model_EventFilter(array(
 -            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId()),
 +            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()),
          )));
          
          Calendar_Model_Rrule::mergeRecurrenceSet($weekviewEvents, $from, $until);
          $event->dtstart = '2010-05-20 06:00:00';
          $event->dtend = '2010-05-20 06:15:00';
          $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
 -            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_personasContacts['sclever']->getId()),
 -            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_personasContacts['pwulf']->getId())
 +            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('sclever')->getId()),
 +            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('pwulf')->getId())
          ));
          $this->_controller->create($event);
  
          $event1 = $this->_getRecurEvent();
          $event1->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
 -            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_personasContacts['sclever']->getId()),
 -            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_personasContacts['pwulf']->getId())
 +            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('sclever')->getId()),
 +            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('pwulf')->getId())
          ));
          
          $this->setExpectedException('Calendar_Exception_AttendeeBusy');
          $event->dtstart = '2010-05-20 06:00:00';
          $event->dtend = '2010-05-20 06:15:00';
          $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
 -            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_personasContacts['sclever']->getId()),
 -            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_personasContacts['pwulf']->getId())
 +            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('sclever')->getId()),
 +            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('pwulf')->getId())
          ));
          $this->_controller->create($event);
  
          $event1 = $this->_getRecurEvent();
          $event1->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
 -            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_personasContacts['sclever']->getId()),
 -            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_personasContacts['pwulf']->getId())
 +            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('sclever')->getId()),
 +            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('pwulf')->getId())
          ));
          
          $event1 = $this->_controller->create($event1);
          $event = $this->_getRecurEvent();
          $event->rrule = "FREQ=MONTHLY;INTERVAL=1;BYDAY=3TH";
          $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
 -            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_personasContacts['sclever']->getId()),
 -            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_personasContacts['pwulf']->getId())
 +            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('sclever')->getId()),
 +            array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('pwulf')->getId())
          ));
          
          $persistentRecurEvent = $this->_controller->create($event);
                  'dtstart'       => '2012-03-13 09:00:00',
                  'dtend'         => '2012-03-13 10:00:00',
                  'rrule'         => 'FREQ=DAILY;INTERVAL=1',
 -                'container_id'  => $this->_testCalendar->getId(),
 +                'container_id'  => $this->_getTestCalendar()->getId(),
                  'attendee'      => $this->_getAttendee(),
          ));
          
              'dtend'         => '2011-04-21 12:00:00',
              'originator_tz' => 'Europe/Berlin',
              'rrule'         => 'FREQ=DAILY;INTERVAL=1;UNTIL=2011-04-27 21:59:59',
 -            'container_id'  => $this->_testCalendar->getId()
 +            'container_id'  => $this->_getTestCalendar()->getId()
          ));
          
          $persistentEvent = $this->_controller->create($event);
          $newBaseEvent = $this->_controller->createRecurException($recurSet[3], FALSE, TRUE);
          
          $events = $this->_controller->search(new Calendar_Model_EventFilter(array(
 -            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId()),
 +            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()),
              array('field' => 'period', 'operator' => 'within', 'value' => array('from' => $from, 'until' => $until),
          ))));
          
              new Tinebase_DateTime('2011-04-27 12:00:00'),
          )), 'dtstart of new series');
      }
-     
+     public function testCreateRecurExceptionAllFollowingAllDay()
+     {
+         $from = new Tinebase_DateTime('2015-07-01 00:00:00');
+         $until = new Tinebase_DateTime('2015-09-29 23:59:59');
+         $event = new Calendar_Model_Event(array(
+             'summary'           => 'Mettwoch',
+             'dtstart'           => '2015-02-10 23:00:00',
+             'dtend'             => '2015-02-11 22:59:59',
+             'is_all_day_event'  => 1,
+             'description'       => '2 Pfund Mett. 15 Brotchen. 1ne Zwiebel',
+             'rrule'             => 'FREQ=MONTHLY;INTERVAL=1;BYDAY=2WE',
+             'container_id'      => method_exists($this, '_getTestCalendar') ?
+                 $this->_getTestCalendar()->getId() :
+                 $this->_testCalendar->getId(),
+             'attendee'          => $this->_getAttendee(),
+         ));
+         $persistentEvent = $this->_controller->create($event);
+         $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
+         $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($persistentEvent, $exceptions, $from, $until);
+         $recurSet[1]->description = '4 Pfund Mett. 15 Brotchen. 2 Zwiebeln';
+         $newBaseEvent = $this->_controller->createRecurException($recurSet[1], FALSE, TRUE);
+         $oldBaseEvent = $this->_controller->get($persistentEvent->getId());
+         $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
+         $oldRecurSet = Calendar_Model_Rrule::computeRecurrenceSet($oldBaseEvent, $exceptions, $from, $until);
+         $this->assertCount(1, $oldRecurSet, 'one event should be left in given period ');
+         $this->assertEquals('2015-07-07 22:00:00', $oldRecurSet[0]->dtstart);
+     }
      /**
       * if not resheduled, attendee status must be preserved
       */
              'dtstart'       => '2012-02-03 09:00:00',
              'dtend'         => '2012-02-03 10:00:00',
              'rrule'         => 'FREQ=DAILY;INTERVAL=1',
 -            'container_id'  => $this->_testCalendar->getId(),
 +            'container_id'  => $this->_getTestCalendar()->getId(),
              'attendee'      => $this->_getAttendee(),
          ));
          
              'dtend'         => '2012-06-01 12:00:00',
              'originator_tz' => 'Europe/Berlin',
              'rrule'         => 'FREQ=WEEKLY;INTERVAL=1',
 -            'container_id'  => $this->_testCalendar->getId()
 +            'container_id'  => $this->_getTestCalendar()->getId()
          ));
          
          $persistentEvent = $this->_controller->create($event);
              'dtstart'       => '2012-02-03 09:00:00',
              'dtend'         => '2012-02-03 10:00:00',
              'rrule'         => 'FREQ=DAILY;INTERVAL=1',
 -            'container_id'  => $this->_testCalendar->getId(),
 +            'container_id'  => $this->_getTestCalendar()->getId(),
              'attendee'      => $this->_getAttendee(),
          ));
          
          $this->_controller->attenderStatusCreateRecurException($start, $sclever, $sclever->status_authkey, TRUE);
          
          $events = $this->_controller->search(new Calendar_Model_EventFilter(array(
 -            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId())
 +            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId())
          )))->sort('dtstart', 'ASC');
          
          // assert two baseEvents
          $this->assertFalse($events[1]->rrule_until instanceof Tinebase_DateTime, 'rrule_until of second baseEvent must not be set');
          $this->assertEquals(Calendar_Model_Attender::STATUS_ACCEPTED, Calendar_Model_Attender::getAttendee($events[1]->attendee, $event->attendee[1])->status, 'second baseEvent status is not touched');
      }
 -    
 +
 +    public function testCreateRecurException()
 +    {
 +        $event = $this->_getEvent();
 +        $event->rrule = 'FREQ=DAILY;INTERVAL=1;UNTIL=2009-04-30 13:30:00';
 +        $persistentEvent = $this->_controller->create($event);
 +
 +        $exception = clone $persistentEvent;
 +        $exception->dtstart->addDay(3);
 +        $exception->dtend->addDay(3);
 +        $exception->summary = 'Abendbrot';
 +        $exception->recurid = $exception->uid . '-' . $exception->dtstart->get(Tinebase_Record_Abstract::ISO8601LONG);
 +        $persistentException = $this->_controller->createRecurException($exception);
 +
 +        $persistentEvent = $this->_controller->get($persistentEvent->getId());
 +        $this->assertEquals(1, count($persistentEvent->exdate));
 +
 +        $events = $this->_controller->search(new Calendar_Model_EventFilter(array(
 +            array('field' => 'uid',     'operator' => 'equals', 'value' => $persistentEvent->uid),
 +        )));
 +        $this->assertEquals(2, count($events));
 +
 +        return $persistentException;
 +    }
 +
 +    public function testGetRecurExceptions()
 +    {
 +        $persistentException = $this->testCreateRecurException();
 +
 +        $baseEvent = $this->_controller->getRecurBaseEvent($persistentException);
 +
 +        $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
 +        $nextOccurance = Calendar_Model_Rrule::computeNextOccurrence($baseEvent, $exceptions, $baseEvent->dtend);
 +        $this->_controller->createRecurException($nextOccurance, TRUE);
 +
 +        $exceptions = $this->_controller->getRecurExceptions($persistentException, TRUE);
 +        $dtstarts = $exceptions->dtstart;
 +
 +        $this->assertTrue(in_array($nextOccurance->dtstart, $dtstarts), 'deleted instance missing');
 +        $this->assertTrue(in_array($persistentException->dtstart, $dtstarts), 'exception instance missing');
 +    }
 +
 +    /**
 +     * testUpdateEventWithRruleAndRecurId
 +     *
 +     * @see 0008696: do not allow both rrule and recurId in event
 +     */
 +    public function testUpdateEventWithRruleAndRecurId()
 +    {
 +        $persistentRecurEvent = $this->testCreateRecurException();
 +        $persistentRecurEvent->rrule = 'FREQ=DAILY;INTERVAL=1';
 +
 +        $updatedEvent = $this->_controller->update($persistentRecurEvent);
 +
 +        $this->assertEquals(NULL, $updatedEvent->rrule);
 +    }
 +
     /**
      * @see {http://forge.tine20.org/mantisbt/view.php?id=5686}
      */
          
          $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
          $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($persistentEvent, $exceptions, $from, $until);
 +
 +        $pwulf = new Calendar_Model_Attender(array(
 +            'user_type'   => Calendar_Model_Attender::USERTYPE_USER,
 +            'user_id'     => $this->_getPersonasContacts('pwulf')->getId()
 +        ));
 +        $recurSet[5]->attendee->addRecord($pwulf);
 +        
 +        $updatedPersistentEvent = $this->_controller->createRecurException($recurSet[5], FALSE, TRUE);
 +        
 +        $this->assertEquals(3, count($updatedPersistentEvent->attendee));
 +
 +        $persistentPwulf = Calendar_Model_Attender::getAttendee($updatedPersistentEvent->attendee, $pwulf);
 +        $this->assertNotNull($persistentPwulf->displaycontainer_id);
 +    }
 +    
 +    /**
 +     * Events don't show up in attendees personal calendar
 +     */
 +    public function testCreateRecurExceptionAllFollowingAttendeeAdd2()
 +    {
 +        $from = new Tinebase_DateTime('2014-04-01 00:00:00');
 +        $until = new Tinebase_DateTime('2014-04-29 23:59:59');
 +        
 +        $persistentEvent = $this->_getDailyEvent(new Tinebase_DateTime('2014-04-03 09:00:00'));
 +        
 +        $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
 +        $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($persistentEvent, $exceptions, $from, $until);
          
          $recurSet[5]->attendee->addRecord(new Calendar_Model_Attender(array(
 -            'user_type'   => Calendar_Model_Attender::USERTYPE_USER,
 -            'user_id'     => $this->_personasContacts['pwulf']->getId()
 +                'user_type'   => Calendar_Model_Attender::USERTYPE_USER,
 +                'user_id'     => $this->_getPersonasContacts('pwulf')->getId()
          )));
          
          $updatedPersistentEvent = $this->_controller->createRecurException($recurSet[5], FALSE, TRUE);
 -        
          $this->assertEquals(3, count($updatedPersistentEvent->attendee));
 +        
 +        $filter = new Calendar_Model_EventFilter(array(
 +                array('field' => 'container_id',             'operator' => 'equals', 'value' => $this->_personasDefaultCals['pwulf']->id),
 +                array('field' => 'attender_status', 'operator' => 'not',    'value' => Calendar_Model_Attender::STATUS_DECLINED),
 +        ));
 +        
 +        $events = $this->_controller->search($filter);
 +        $this->assertEquals(1, count($events), 'event should be found, but is not');
      }
      
      /**
              'dtstart'       => $dtstart->toString(),
              'dtend'         => $dtstart->addHour(1)->toString(),
              'rrule'         => 'FREQ=DAILY;INTERVAL=1',
 -            'container_id'  => $this->_testCalendar->getId(),
 +            'container_id'  => $this->_getTestCalendar()->getId(),
              'attendee'      => $this->_getAttendee(),
          ));
          return $this->_controller->create($event);
              'dtend'         => '2012-02-21 15:30:00',
              'originator_tz' => 'Europe/Berlin',
              'rrule'         => 'FREQ=DAILY;COUNT=5',
 -            'container_id'  => $this->_testCalendar->getId(),
 +            'container_id'  => $this->_getTestCalendar()->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()),
 +            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()),
          )));
          Calendar_Model_Rrule::mergeRecurrenceSet($weekviewEvents, $from, $until);
          $weekviewEvents[2]->dtstart->subHour(5);
          
          // load events
          $weekviewEvents = $this->_controller->search(new Calendar_Model_EventFilter(array(
 -            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId()),
 +            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->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 testCreateRecurExceptionAllFollowingContainerMove()
 +    {
 +        $this->markTestSkipped('exdate container move not yet forbidden');
 +        $exception = $this->testCreateRecurException();
 +        $baseEvent = $this->_controller->getRecurBaseEvent($exception);
 +
 +        $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
 +        $from = $baseEvent->dtstart;
 +        $until = $baseEvent->dtstart->getClone()->addDay(1);
 +        $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($baseEvent, $exceptions, $from, $until);
 +
 +        $recurSet->getFirstRecord()->container_id = $this->_getTestContainer('Calendar')->getId();
 +        $newSeries = $this->_controller->createRecurException($recurSet->getFirstRecord(), false, true);
 +        $newExceptions = $this->_controller->getRecurExceptions($newSeries);
 +
 +//        print_r($newSeries->toArray());
 +//        print_r($newExceptions->toArray());
 +    }
 +
      /**
       * testMoveRecurException
       * 
          $this->setExpectedException('Tinebase_Timemachine_Exception_ConcurrencyConflict');
          $updatedPersistentEvent = $this->_controller->createRecurException($updatedPersistentEvent);
      }
 -    
 +
 +    public function testExdateContainerMoveCreateException()
 +    {
 +        $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);
 +
 +        $this->setExpectedException('Calendar_Exception_ExdateContainer');
 +
 +        $recurSet[2]->container_id = $this->_getTestContainer('Calendar')->getId();
 +        $this->_controller->createRecurException($recurSet[2]);
 +    }
 +
 +    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);
 +
 +    }
 +
      /**
       * returns a simple recure event
       *
              'dtend'       => '2010-05-20 06:15:00',
              'description' => 'Breakfast',
              'rrule'       => 'FREQ=DAILY;INTERVAL=1',    
 -            'container_id' => $this->_testCalendar->getId(),
 +            'container_id' => $this->_getTestCalendar()->getId(),
              Tinebase_Model_Grants::GRANT_EDIT    => true,
          ));
      }
@@@ -114,16 -114,6 +114,16 @@@ class Calendar_Convert_Event_VCalendar_
          $updateEvent2 = $converter->toTine20Model($vcalendarStream2, $eventWithExdateOnBaseEvent);
  
          $this->assertEquals(1, count($updateEvent2->exdate), print_r($updateEvent2->toArray(), true));
-         $this->assertEquals('2015-04-27 21:59:59', $updateEvent2->rrule_until);
+         $this->assertEquals('2015-04-27 22:00:00', $updateEvent2->rrule_until);
      }
 +
 +    public function testConvertToTine20ModelYosemite()
 +    {
 +        $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_MACOSX, '10.10.4');
 +
 +        $vcalendarStream = fopen(dirname(__FILE__) . '/../../../Import/files/apple_calendar_yosemite_attendee.ics', 'r');
 +        $event = $converter->toTine20Model($vcalendarStream);
 +
 +        $this->assertCount(2, $event->attendee, 'CHAIR should be skipped, Attendee should be recognised');
 +    }
  }
@@@ -123,7 -123,6 +123,7 @@@ class Calendar_Model_Event extends Tine
          // ical scheduleable interface fields
          'dtstart'               => array(Zend_Filter_Input::ALLOW_EMPTY => true         ),
          'recurid'               => array(Zend_Filter_Input::ALLOW_EMPTY => true         ),
 +        'base_event_id'         => array(Zend_Filter_Input::ALLOW_EMPTY => true         ),
          // ical scheduleable interface fields with multiple appearance
          'exdate'                => array(Zend_Filter_Input::ALLOW_EMPTY => true         ), //  array of Tinebase_DateTimeTinebase_DateTime's
          //'exrule'                => array(Zend_Filter_Input::ALLOW_EMPTY => true         ),
       * 
       * @return string recurid which was set
       */
 -    public function setRecurId()
 +    public function setRecurId($baseEventId)
      {
          if (! ($this->uid && $this->dtstart)) {
              throw new Exception ('uid _and_ dtstart must be set to generate recurid');
          $dtstart->setTimezone('UTC');
          
          $this->recurid = $this->uid . '-' . $dtstart->get(Tinebase_Record_Abstract::ISO8601LONG);
 -        
 +        $this->base_event_id = $baseEventId;
 +
          return $this->recurid;
      }
      
                  // 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) {
+                 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);