Merge branch '2013.10' into 2014.11
authorPhilipp Schüle <p.schuele@metaways.de>
Tue, 22 Sep 2015 13:25:05 +0000 (15:25 +0200)
committerPhilipp Schüle <p.schuele@metaways.de>
Tue, 22 Sep 2015 13:25:05 +0000 (15:25 +0200)
Conflicts:
tests/tine20/Calendar/Convert/Event/VCalendar/MacOSXTest.php

Change-Id: I19bca261578d8c7af1149c2e4e5d494875805414

1  2 
tests/tine20/Calendar/Convert/Event/VCalendar/MacOSXTest.php
tine20/Calendar/Convert/Event/VCalendar/MacOSX.php

@@@ -117,13 -117,13 +117,23 @@@ class Calendar_Convert_Event_VCalendar_
          $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');
 +    }
++
+     public function testConvertToTine20ModelYosemiteRecurringAllDayWithUntil()
+     {
+         $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_MACOSX, '10.10.5');
+         $vcalendarStream = fopen(dirname(__FILE__) . '/../../../Import/files/apple_calendar_10.10_birthday02-PUT-quit-old.ics', 'r');
+         $event = $converter->toTine20Model($vcalendarStream);
+         $this->assertEquals('FREQ=YEARLY;INTERVAL=1;UNTIL=2016-09-17 22:00:00', $event->rrule);
+     }
  }
@@@ -54,19 -54,14 +54,19 @@@ class Calendar_Convert_Event_VCalendar_
       */
      protected function _getAttendee(\Sabre\VObject\Property\ICalendar\CalAddress $calAddress)
      {
 -        
          $newAttendee = parent::_getAttendee($calAddress);
 -        
 -        // beginning with mavericks iCal adds organiser as attedee without role
 -        // so we remove attendee without role 
 -        // @TODO check if this attendee is currentuser & organizer?
 -        if (version_compare($this->_version, '10.9', '>=')) {
 -            if (! isset($calAddress['ROLE'])) {
 +
 +        // skip implicit organizer attendee.
 +        // NOTE: when the organizer edits the event he becomes attendee anyway, see comments in MSEventFacade::update
 +
 +        // in mavericks iCal adds organiser as attendee without role
 +        if (version_compare($this->_version, '10.9', '>=') && version_compare($this->_version, '10.10', '<')) {
 +            if (!isset($calAddress['ROLE'])) {
 +                return NULL;
 +            }
 +        // in yosemite iCal adds organiser with role "chair" but has no roles for other attendee
 +        } else if (version_compare($this->_version, '10.10', '>=')) {
 +            if (isset($calAddress['ROLE']) && $calAddress['ROLE'] == 'CHAIR') {
                  return NULL;
              }
          }
      }
  
      /**
 +     * add event attendee to VEVENT object
 +     *
 +     * @param \Sabre\VObject\Component\VEvent $vevent
 +     * @param Calendar_Model_Event            $event
 +     */
 +    protected function _addEventAttendee(\Sabre\VObject\Component\VEvent $vevent, Calendar_Model_Event $event)
 +    {
 +        parent::_addEventAttendee($vevent, $event);
 +
 +        if (empty($event->attendee)) {
 +            return;
 +        }
 +
 +        // add organizer as CHAIR Attendee if he's no organizer, otherwise yosemite would add an attendee
 +        // when editing the event again.
 +        // NOTE: when the organizer edits the event he becomes attendee anyway, see comments in MSEventFacade::update
 +        if (version_compare($this->_version, '10.10', '>=')) {
 +            if (!empty($event->organizer)) {
 +                $organizerContact = $event->resolveOrganizer();
 +
 +                if ($organizerContact instanceof Addressbook_Model_Contact) {
 +
 +                    $organizerAttendee = Calendar_Model_Attender::getAttendee($event->attendee, new Calendar_Model_Attender(array(
 +                        'user_id' => $organizerContact->getId(),
 +                        'user_type' => Calendar_Model_Attender::USERTYPE_USER
 +                    )));
 +
 +                    if (! $organizerAttendee) {
 +                        $parameters = array(
 +                            'CN'       => $organizerContact->n_fileas,
 +                            'CUTYPE'   => 'INDIVIDUAL',
 +                            'PARTSTAT' => 'ACCEPTED',
 +                            'ROLE'     => 'CHAIR',
 +                        );
 +                        $organizerEmail = $organizerContact->email;
 +                        if (strpos($organizerEmail, '@') !== false) {
 +                            $parameters['EMAIL'] = $organizerEmail;
 +                        }
 +                        $vevent->add('ATTENDEE', (strpos($organizerEmail, '@') !== false ? 'mailto:' : 'urn:uuid:') . $organizerEmail, $parameters);
 +                    }
 +                }
 +            }
 +        }
 +
 +    }
 +    /**
       * do version specific magic here
       *
       * @param \Sabre\VObject\Component\VCalendar $vcalendar
       */
      protected function _convertVevent(\Sabre\VObject\Component\VEvent $vevent, Calendar_Model_Event $event, $options)
      {
          $return = parent::_convertVevent($vevent, $event, $options);
  
          // NOTE: 10.7 sometimes uses (internal?) int's
                  Calendar_Model_Event::CLASS_PRIVATE;
          }
  
+         // 10.10 sends UNTIL in wrong timezone for all day events
+         if ($event->is_all_day_event && version_compare($this->_version, '10.10', '>=')) {
+             $event->rrule = preg_replace_callback('/UNTIL=([\d :-]{19})(?=;?)/', function($matches) use ($vevent) {
+                 // refetch UNTIL from vevent and drop timepart
+                 preg_match('/UNTIL=([\dTZ]+)(?=;?)/', $vevent->RRULE, $matches);
+                 $dtUntil = Calendar_Convert_Event_VCalendar_Abstract::getUTCDateFromStringInUsertime(substr($matches[1], 0, 8));
+                 return 'UNTIL=' . $dtUntil->format(Tinebase_Record_Abstract::ISO8601LONG);
+             }, $event->rrule);
+         }
          return $return;
      }