0011232: support ATTENDEE in OSX 10.10
authorCornelius Weiß <mail@corneliusweiss.de>
Thu, 13 Aug 2015 15:02:59 +0000 (17:02 +0200)
committerPhilipp Schüle <p.schuele@metaways.de>
Fri, 14 Aug 2015 10:08:26 +0000 (12:08 +0200)
* In yosemite iCal adds organiser with role "chair" but has no roles for
other attendee
* In mavericks iCal adds organiser as attendee without role

https://forge.tine20.org/view.php?id=11232

Change-Id: Ie645a6a574ef9c94fa0803333e25f3c89835a432
Reviewed-on: http://gerrit.tine20.com/customers/2108
Reviewed-by: Philipp Schüle <p.schuele@metaways.de>
Tested-by: Philipp Schüle <p.schuele@metaways.de>
tests/tine20/Calendar/Convert/Event/VCalendar/MacOSXTest.php
tests/tine20/Calendar/Import/files/apple_calendar_yosemite_attendee.ics [new file with mode: 0644]
tests/tine20/bootstrap.php
tine20/Calendar/Controller/MSEventFacade.php
tine20/Calendar/Convert/Event/VCalendar/Abstract.php
tine20/Calendar/Convert/Event/VCalendar/MacOSX.php

index bc34e77..ade3009 100644 (file)
@@ -116,4 +116,14 @@ class Calendar_Convert_Event_VCalendar_MacOSXTest extends Calendar_TestCase
         $this->assertEquals(1, count($updateEvent2->exdate), print_r($updateEvent2->toArray(), true));
         $this->assertEquals('2015-04-27 21:59:59', $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');
+    }
 }
diff --git a/tests/tine20/Calendar/Import/files/apple_calendar_yosemite_attendee.ics b/tests/tine20/Calendar/Import/files/apple_calendar_yosemite_attendee.ics
new file mode 100644 (file)
index 0000000..9109c12
--- /dev/null
@@ -0,0 +1,39 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//Mac OS X 10.10.4//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:Europe/Berlin
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0100
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+DTSTART:19810329T020000
+TZNAME:MESZ
+TZOFFSETTO:+0200
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0200
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+DTSTART:19961027T030000
+TZNAME:MEZ
+TZOFFSETTO:+0100
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+CREATED:20150813T073304Z
+UID:A5A4AB18-B59F-48DE-96CC-33ABC440B828
+DTEND;TZID=Europe/Berlin:20150814T144500
+TRANSP:OPAQUE
+ATTENDEE;CN="Admin Account, Tine 2.0";CUTYPE=INDIVIDUAL;EMAIL="unittest@
+ tine20.org";PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:unittest@tine20.org
+ATTENDEE;CN="Clever, Susan";CUTYPE=INDIVIDUAL;EMAIL="sclever@tine20.org"
+ ;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:sclever@tine20.org
+ATTENDEE;CN="Wulf, Paul";CUTYPE=INDIVIDUAL;EMAIL="pwulf@tine20.org";PART
+ STAT=NEEDS-ACTION;RSVP=TRUE:mailto:pwulf@tine20.org
+SUMMARY:TEST20
+DTSTART;TZID=Europe/Berlin:20150814T134500
+DTSTAMP:20150813T073304Z
+ORGANIZER;CN="Admin Account, Tine 2.0":mailto:unittest@tine20.org
+SEQUENCE:0
+END:VEVENT
+END:VCALENDAR
\ No newline at end of file
index 51968a6..9fa42fa 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-require_once '../../tine20/bootstrap.php';
+require_once __DIR__ . '/../../tine20/bootstrap.php';
 
 // add path the local directory
 $autoloader->add('', array(__DIR__));
index 3cea2c7..d5fc199 100644 (file)
@@ -334,7 +334,14 @@ class Calendar_Controller_MSEventFacade implements Tinebase_Controller_Record_In
         }
         $currentOriginEvent = $this->_eventController->get($_event->getId());
         $this->_fromiTIP($_event, $currentOriginEvent);
-        
+
+        // NOTE:  create an update must be handled equally as apple devices do not fetch events after creation.
+        //        an update from the creating device would change defaults otherwise
+        // NOTE2: Being organizer without attending is not possible when sync is in use as every update
+        //        from a sync device of the organizer adds the organizer as attendee :-(
+        //        -> in the sync world this is scenario is called delegation and handled differently
+        //        -> it might be consequent to have the same behavior (organizer is always attendee with role chair)
+        //           in tine20 in general. This is how Thunderbird handles it as well
         $_event->assertAttendee($this->getCalendarUser());
         
         $exceptions = $_event->exdate instanceof Tinebase_Record_RecordSet ? $_event->exdate : new Tinebase_Record_RecordSet('Calendar_Model_Event');
index 6cd11f0..0c0d8a4 100644 (file)
@@ -345,7 +345,7 @@ class Calendar_Convert_Event_VCalendar_Abstract extends Tinebase_Convert_VCalend
         }
         
         Calendar_Model_Attender::resolveAttendee($event->attendee, FALSE, $event);
-        
+
         foreach($event->attendee as $eventAttendee) {
             $attendeeEmail = $eventAttendee->getEmail();
             
index 88daafe..f3513c3 100644 (file)
@@ -54,14 +54,19 @@ class Calendar_Convert_Event_VCalendar_MacOSX extends Calendar_Convert_Event_VCa
      */
     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;
             }
         }
@@ -70,6 +75,52 @@ class Calendar_Convert_Event_VCalendar_MacOSX extends Calendar_Convert_Event_VCa
     }
 
     /**
+     * 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