improve default attendee for CalDAV/ActiveSync
authorCornelius Weiß <mail@corneliusweiss.de>
Fri, 22 Aug 2014 16:11:50 +0000 (18:11 +0200)
committerPhilipp Schüle <p.schuele@metaways.de>
Thu, 4 Sep 2014 09:26:45 +0000 (11:26 +0200)
* always add calendar owner as attendee for personal calendars
* change calendar perspective to calendar owner for personal calendars

Change-Id: Id6ba9216d61a098ff9af85932eae591bd05d7382
Reviewed-on: http://gerrit.tine20.com/customers/1038
Reviewed-by: Philipp Schüle <p.schuele@metaways.de>
Tested-by: Philipp Schüle <p.schuele@metaways.de>
tests/tine20/Calendar/Frontend/WebDAV/EventTest.php
tests/tine20/Calendar/Import/files/apple_caldendar_repeating.ics
tine20/Calendar/Controller/MSEventFacade.php
tine20/Calendar/Frontend/WebDAV/Event.php
tine20/Calendar/Model/Event.php

index 47f2aaf..047de41 100644 (file)
@@ -264,27 +264,42 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
         $this->assertEquals($this->_personasDefaultCals['pwulf']->getId(), $pwulf->displaycontainer_id, 'event not in pwulfs personal calendar');
     }
     
-    public function testCreateEventMissingOwnAttendee()
+    /**
+     * _testEventMissingAttendee helper
+     * 
+     * @param Tinebase_Model_Container $container
+     * @param Calendar_Model_Attender $assertionAttendee
+     * @param boolean $assertMissing
+     */
+    public function _testEventMissingAttendee($container, $assertionAttendee, $assertMissing = false)
     {
+        $not = $assertMissing ? '' : 'not ';
+        $assertFn = $assertMissing ? 'assertFalse' : 'assertTrue';
+        
         $_SERVER['HTTP_USER_AGENT'] = 'CalendarStore/5.0 (1127); iCal/5.0 (1535); Mac OS X/10.7.1 (11B26)';
         
         $vcalendar = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/apple_caldendar_repeating.ics');
         
         
         $id = Tinebase_Record_Abstract::generateUID();
-        $event = Calendar_Frontend_WebDAV_Event::create($this->objects['initialContainer'], "$id.ics", $vcalendar);
+
+        $event = Calendar_Frontend_WebDAV_Event::create($container, "$id.ics", $vcalendar);
         
-        $this->assertTrue(!! Calendar_Model_Attender::getOwnAttender($event->getRecord()->attendee), 'own attendee has not been added');
-        $this->assertTrue(!! Calendar_Model_Attender::getOwnAttender($event->getRecord()->exdate->getFirstRecord()->attendee), 'own attendee has not been added to exdate');
+        $this->$assertFn(!! Calendar_Model_Attender::getAttendee($event->getRecord()->attendee, $assertionAttendee),
+                "attendee has {$not}been added: " . print_r($event->getRecord()->attendee->toArray(), true));
+        $this->$assertFn(!! Calendar_Model_Attender::getAttendee($event->getRecord()->exdate->getFirstRecord()->attendee, $assertionAttendee),
+                "attendee has {$not}been added to exdate");
         
         // Simulate OSX which updates w.o. fetching first
         $vcalendarStream = fopen(dirname(__FILE__) . '/../../Import/files/apple_caldendar_repeating.ics', 'r');
         
-        $event = new Calendar_Frontend_WebDAV_Event($this->objects['initialContainer'], $event->getRecord()->getId());
+        $event = new Calendar_Frontend_WebDAV_Event($container, $event->getRecord()->getId());
         $event->put($vcalendarStream);
         
-        $this->assertTrue(!! Calendar_Model_Attender::getOwnAttender($event->getRecord()->attendee), 'own attendee has not been preserved');
-        $this->assertTrue(!! Calendar_Model_Attender::getOwnAttender($event->getRecord()->exdate->getFirstRecord()->attendee), 'own attendee has not been preserved in exdate');
+        $this->$assertFn(!! Calendar_Model_Attender::getAttendee($event->getRecord()->attendee, $assertionAttendee),
+                "attendee has {$not}been preserved: " . print_r($event->getRecord()->attendee->toArray(), true));
+        $this->$assertFn(!! Calendar_Model_Attender::getAttendee($event->getRecord()->exdate->getFirstRecord()->attendee, $assertionAttendee),
+                "attendee has {$not}been preserved in exdate");
         
         // create new exception from client w.o. fetching first
         Calendar_Controller_Event::getInstance()->purgeRecords(TRUE);
@@ -293,12 +308,58 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
         
         $vcalendarStream = fopen(dirname(__FILE__) . '/../../Import/files/apple_caldendar_repeating.ics', 'r');
         
-        $event = new Calendar_Frontend_WebDAV_Event($this->objects['initialContainer'], $event->getRecord()->getId());
+        $event = new Calendar_Frontend_WebDAV_Event($container, $event->getRecord()->getId());
         $event->put($vcalendarStream);
         
-        $this->assertTrue(!! Calendar_Model_Attender::getOwnAttender($event->getRecord()->attendee), 'own attendee has not been created in exdate');
-        $this->assertTrue(!! Calendar_Model_Attender::getOwnAttender($event->getRecord()->exdate->getFirstRecord()->attendee), 'own attendee has not been created in exdate');
+        $this->$assertFn(!! Calendar_Model_Attender::getAttendee($event->getRecord()->attendee, $assertionAttendee),
+                "attendee has {$not}been created in exdate");
+        $this->$assertFn(!! Calendar_Model_Attender::getAttendee($event->getRecord()->exdate->getFirstRecord()->attendee, $assertionAttendee),
+                "attendee has {$not}been created in exdate");
+    }
+    
+    /**
+     * testEventMissingAttendeeOwnCalendar
+     *
+     * validate test user is added for event in own container
+     */
+    public function testEventMissingAttendeeOwnCalendar()
+    {
+        $this->_testEventMissingAttendee($this->objects['initialContainer'], new Calendar_Model_Attender(array(
+            'user_type'    => Calendar_Model_Attender::USERTYPE_USER,
+            'user_id'      => Tinebase_Core::getUser()->contact_id,
+        )));
+    }
+    /**
+     * testEventMissingAttendeeOtherCalendar
+     *
+     * validate calendar owner is added for event in other user container
+     */
+    public function testEventMissingAttendeeOtherCalendar()
+    {
+        $egt = new Calendar_Controller_EventGrantsTests();
+        $egt->setup();
+        
+        $pwulfPersonalCal = $this->_personasDefaultCals['sclever'];
+        $pwulf = new Calendar_Model_Attender(array(
+            'user_type'    => Calendar_Model_Attender::USERTYPE_USER,
+            'user_id'      => $this->_personasContacts['sclever']->getId(),
+        ));
         
+        $this->_testEventMissingAttendee($pwulfPersonalCal, $pwulf);
+    }
+    
+    /**
+     * testEventMissingAttendeeSharedCalendar
+     * 
+     * validate no attendee is implicitly added for shared calendars
+     */
+    public function testEventMissingAttendeeSharedCalendar()
+    {
+        $this->markTestSkipped('not yet active');
+        $this->_testEventMissingAttendee($this->objects['sharedContainer'], new Calendar_Model_Attender(array(
+                'user_type'    => Calendar_Model_Attender::USERTYPE_USER,
+                'user_id'      => Tinebase_Core::getUser()->contact_id,
+        )), true);
     }
     
     public function testFilterRepeatingException()
@@ -602,13 +663,12 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
         
         $vcalendar = file_get_contents(dirname(__FILE__) . '/../../Import/files/lightning.ics');
         
-        $currentCU = Calendar_Controller_MSEventFacade::getInstance()->setCalendarUser(new Calendar_Model_Attender(array(
-            'user_type' => Calendar_Model_Attender::USERTYPE_USER,
-            'user_id'   => 'someoneelse'
-        )));
+        $egt = new Calendar_Controller_EventGrantsTests();
+        $egt->setup();
+        
+        $pwulfPersonalCal = $this->_personasDefaultCals['sclever'];
         $id = Tinebase_Record_Abstract::generateUID();
-        $event = Calendar_Frontend_WebDAV_Event::create($this->objects['sharedContainer'], "$id.ics", $vcalendar);
-        Calendar_Controller_MSEventFacade::getInstance()->setCalendarUser($currentCU);
+        $event = Calendar_Frontend_WebDAV_Event::create($pwulfPersonalCal, "$id.ics", $vcalendar);
         
         $loadedEvent = new Calendar_Frontend_WebDAV_Event($this->objects['sharedContainer'], "$id.ics");
         $ics = stream_get_contents($loadedEvent->get());
index fe03c7b..ac29a22 100644 (file)
@@ -32,6 +32,8 @@ SEQUENCE:4
 END:VEVENT
 BEGIN:VEVENT
 CREATED:20111109T144059Z
+ATTENDEE;CN="Clever, Susan";CUTYPE=INDIVIDUAL;EMAIL="sclever@tine20.org"
+ ;PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT:mailto:sclever@tine20.org
 UID:552866D2-6C3C-4AB0-893C-F9F0F5764880
 DTEND;TZID=Europe/Berlin:20111111T113000
 TRANSP:OPAQUE
index b3dfafc..52f4312 100644 (file)
@@ -254,7 +254,7 @@ class Calendar_Controller_MSEventFacade implements Tinebase_Controller_Record_In
         $exceptions = $_event->exdate;
         $_event->exdate = NULL;
         
-        $_event->assertCurrentUserAsAttendee();
+        $_event->assertAttendee($this->getCalendarUser());
         $savedEvent = $this->_eventController->create($_event);
         
         if ($exceptions instanceof Tinebase_Record_RecordSet) {
@@ -262,7 +262,7 @@ class Calendar_Controller_MSEventFacade implements Tinebase_Controller_Record_In
                 . ' About to create ' . count($exceptions) . ' exdates for event ' . $_event->summary . ' (' . $_event->dtstart . ')');
             
             foreach ($exceptions as $exception) {
-                $exception->assertCurrentUserAsAttendee();
+                $exception->assertAttendee($this->getCalendarUser());
                 $this->_prepareException($savedEvent, $exception);
                 $this->_eventController->createRecurException($exception, !!$exception->is_deleted);
             }
@@ -291,7 +291,7 @@ class Calendar_Controller_MSEventFacade implements Tinebase_Controller_Record_In
         $currentOriginEvent = $this->_eventController->get($_event->getId());
         $this->_fromiTIP($_event, $currentOriginEvent);
         
-        $_event->assertCurrentUserAsAttendee(TRUE, TRUE);
+        $_event->assertAttendee($this->getCalendarUser());
         
         $exceptions = $_event->exdate instanceof Tinebase_Record_RecordSet ? $_event->exdate : new Tinebase_Record_RecordSet('Calendar_Model_Event');
         $exceptions->addIndices(array('is_deleted'));
@@ -312,7 +312,7 @@ class Calendar_Controller_MSEventFacade implements Tinebase_Controller_Record_In
             . ' Found ' . count($migration['toCreate']) . ' exceptions to create and ' . count($migration['toUpdate']) . ' to update.');
         
         foreach ($migration['toCreate'] as $exception) {
-            $exception->assertCurrentUserAsAttendee(TRUE, TRUE);
+            $exception->assertAttendee($this->getCalendarUser());
             $this->_prepareException($updatedBaseEvent, $exception);
             $this->_eventController->createRecurException($exception, !!$exception->is_deleted);
         }
@@ -321,7 +321,7 @@ class Calendar_Controller_MSEventFacade implements Tinebase_Controller_Record_In
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' '
                 . ' Update exdate ' . $exception->getId() . ' at ' . $exception->dtstart->toString());
             
-            $exception->assertCurrentUserAsAttendee(TRUE, TRUE);
+            $exception->assertAttendee($this->getCalendarUser());
             $this->_prepareException($updatedBaseEvent, $exception);
             $this->_addStatusAuthkeyForOwnAttender($exception);
             
@@ -497,6 +497,9 @@ class Calendar_Controller_MSEventFacade implements Tinebase_Controller_Record_In
      */
     public function setCalendarUser(Calendar_Model_Attender $_calUser)
     {
+        if (! in_array($_calUser->user_type, array(Calendar_Model_Attender::USERTYPE_USER, Calendar_Model_Attender::USERTYPE_GROUPMEMBER))) {
+            throw new Tinebase_Exception_UnexpectedValue('Calendar user must be a contact');
+        }
         $oldUser = $this->_calendarUser;
         $this->_calendarUser = $_calUser;
         
@@ -731,7 +734,7 @@ class Calendar_Controller_MSEventFacade implements Tinebase_Controller_Record_In
         }
         
         // assert organizer
-        $_event->organizer = $_event->organizer ?: ($_currentEvent->organizer ?: Tinebase_Core::getUser()->contact_id);
+        $_event->organizer = $_event->organizer ?: ($_currentEvent->organizer ?: $this->_calendarUser->user_id);
         
         $this->_addAttendeeWithoutEmail($_event, $_currentEvent);
         
index 73c067c..2aaf705 100644 (file)
@@ -60,10 +60,7 @@ class Calendar_Frontend_WebDAV_Event extends Sabre\DAV\File implements Sabre\Cal
         
         list($backend, $version) = Calendar_Convert_Event_VCalendar_Factory::parseUserAgent($_SERVER['HTTP_USER_AGENT']);
         
-        $this->_eventFilter = new Calendar_Model_EventFilter(array(
-            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_container->getId())
-        ));
-        $this->_assertEventFilter();
+        $this->_assertEventFacadeParams($this->_container);
         
         $this->_converter = Calendar_Convert_Event_VCalendar_Factory::factory($backend, $version);
     }
@@ -140,10 +137,7 @@ class Calendar_Frontend_WebDAV_Event extends Sabre\DAV\File implements Sabre\Cal
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
             . " Event to create: " . print_r($event->toArray(), TRUE));
         
-        $filter =  new Calendar_Model_EventFilter(array(
-            array('field' => 'container_id', 'operator' => 'equals', 'value' => $container->getId())
-        ));
-        Calendar_Controller_MSEventFacade::getInstance()->setEventFilter($filter);
+        self::_assertEventFacadeParams($container);
         
         // check if there is already an existing event with this ID
         // this can happen when the invitation email is faster then the caldav update or
@@ -202,7 +196,7 @@ class Calendar_Frontend_WebDAV_Event extends Sabre\DAV\File implements Sabre\Cal
         sleep(1);
         
         // (re) fetch event as tree move does not refresh src node before delete
-        $this->_assertEventFilter();
+        $this->_assertEventFacadeParams($this->_container);
         $event = Calendar_Controller_MSEventFacade::getInstance()->get($this->_event);
         
         // disallow event cleanup in the past
@@ -379,7 +373,7 @@ class Calendar_Frontend_WebDAV_Event extends Sabre\DAV\File implements Sabre\Cal
      */
     public function put($cardData) 
     {
-        $this->_assertEventFilter();
+        $this->_assertEventFacadeParams($this->_container);
         if (get_class($this->_converter) == 'Calendar_Convert_Event_VCalendar_Generic') {
             if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) 
                 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . " update by generic client not allowed. See Calendar_Convert_Event_VCalendar_Factory for supported clients.");
@@ -487,14 +481,32 @@ class Calendar_Frontend_WebDAV_Event extends Sabre\DAV\File implements Sabre\Cal
     }
     
     /**
-     * asserts correct event filter in MSEventFacade
+     * asserts correct event filter and calendar user in MSEventFacade
      * 
      * NOTE: this is nessesary as MSEventFacade is a singleton and in some operations (e.g. move) there are 
      *       multiple instances of self
      */
-    protected function _assertEventFilter()
+    protected static function _assertEventFacadeParams($container)
     {
-        Calendar_Controller_MSEventFacade::getInstance()->setEventFilter(clone $this->_eventFilter);
+        $eventFilter = new Calendar_Model_EventFilter(array(
+                array('field' => 'container_id', 'operator' => 'equals', 'value' => $container->getId())
+        ));
+        
+        try {
+            $calendarUserId = $container->type == Tinebase_Model_Container::TYPE_PERSONAL ?
+            Addressbook_Controller_Contact::getInstance()->getContactByUserId($container->getOwner(), true)->getId() :
+            Tinebase_Core::getUser()->contact_id;
+        } catch (Exception $e) {
+            $calendarUserId = Tinebase_Core::getUser()->contact_id;
+        }
+        
+        $calendarUser = new Calendar_Model_Attender(array(
+            'user_type' => Calendar_Model_Attender::USERTYPE_USER,
+            'user_id'   => $calendarUserId,
+        ));
+        
+        Calendar_Controller_MSEventFacade::getInstance()->setEventFilter($eventFilter);
+        Calendar_Controller_MSEventFacade::getInstance()->setCalendarUser($calendarUser);
     }
     
     /**
@@ -518,7 +530,7 @@ class Calendar_Frontend_WebDAV_Event extends Sabre\DAV\File implements Sabre\Cal
     public function getRecord()
     {
         if (! $this->_event instanceof Calendar_Model_Event) {
-            $this->_assertEventFilter();
+            $this->_assertEventFacadeParams($this->_container);
             $this->_event = Calendar_Controller_MSEventFacade::getInstance()->get($this->_event);
             
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " " . print_r($this->_event->toArray(), true));
index 15945f1..8bbb97e 100644 (file)
@@ -263,34 +263,50 @@ class Calendar_Model_Event extends Tinebase_Record_Abstract
         return $diff;
     }
     /**
-     * add current user to attendee if he's organizer
+     * add given attendee if not present under given conditions
      * 
-     * @param bool $ifOrganizer      only add current user if he's organizer
-     * @param bool $ifNoOtherAttendee  only add current user if no other attendee are present
+     * @param Calendar_Model_Attender $attendee
+     * @param bool                    $ifOrganizer        only add attendee if he's organizer
+     * @param bool                    $ifNoOtherAttendee  only add attendee if no other attendee are present
+     * @param bool                    $personalOnly       only for personal containers
      */
-    public function assertCurrentUserAsAttendee($ifOrganizer = TRUE, $ifNoOtherAttendee = FALSE)
+    public function assertAttendee($attendee, $ifOrganizer = true, $ifNoOtherAttendee = false, $personalOnly = false)
     {
+        if ($personalOnly) {
+            try {
+                $container = Tinebase_Container::getInstance()->getContainerById($this->container_id);
+                if ($container->type != Tinebase_Model_Container::TYPE_PERSONAL) {
+                    if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
+                            __METHOD__ . '::' . __LINE__ . " not adding attendee as container is not personal.");
+                    return;
+                }
+            } catch (Exception $e) {
+                Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " cannot get container: $e");
+            }
+        }
+        
+        
         if ($ifNoOtherAttendee && $this->attendee instanceof Tinebase_Record_RecordSet && $this->attendee->count() > 0) {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
-                    __METHOD__ . '::' . __LINE__ . " not adding current user as attendee as other attendee are present.");
+                    __METHOD__ . '::' . __LINE__ . " not adding attendee as other attendee are present.");
             return;
         }
         
-        $ownAttender = Calendar_Model_Attender::getOwnAttender($this->attendee);
+        $assertionAttendee = Calendar_Model_Attender::getAttendee($this->attendee, $attendee);
         
-        if (! $ownAttender) {
-            if ($ifOrganizer && $this->organizer && $this->organizer != Tinebase_Core::getUser()->contact_id) {
+        if (! $assertionAttendee) {
+            if ($ifOrganizer && ! $this->isOrganizer($attendee)) {
                 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
-                    __METHOD__ . '::' . __LINE__ . " not adding current user as attendee as current user is not organizer.");
+                    __METHOD__ . '::' . __LINE__ . " not adding attendee as he is not organizer.");
             }
             
             else {
                 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
-                    __METHOD__ . '::' . __LINE__ . " adding current user as attendee.");
+                    __METHOD__ . '::' . __LINE__ . " adding attendee.");
                 
                 $newAttender = new Calendar_Model_Attender(array(
-                    'user_id'   => Tinebase_Core::getUser()->contact_id,
-                    'user_type' => Calendar_Model_Attender::USERTYPE_USER,
+                    'user_id'   => $attendee->user_id,
+                    'user_type' => $attendee->user_type,
                     'status'    => Calendar_Model_Attender::STATUS_ACCEPTED,
                     'role'      => Calendar_Model_Attender::ROLE_REQUIRED
                 ));