0011516: cope with attendee email changes in sync
authorCornelius Weiß <c.weiss@metaways.de>
Tue, 22 Dec 2015 13:17:58 +0000 (14:17 +0100)
committerPhilipp Schüle <p.schuele@metaways.de>
Mon, 4 Jan 2016 11:20:40 +0000 (12:20 +0100)
email of attendee might have changed in the time an
event was synced to the client till it comes back for
an update.

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

Change-Id: I51a2ea9003c8496f675d152191bc11d6d313807f
Reviewed-on: http://gerrit.tine20.com/customers/2523
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
tine20/Calendar/Model/Attender.php

index b19777e..35a8ee5 100644 (file)
@@ -538,7 +538,33 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
 
         $this->assertEquals('New Event', $record->summary);
     }
-    
+
+    /**
+     * test updating existing event when attendee or organizer email changed in the meantime
+     */
+    public function testPutEventWhenEmailChanged()
+    {
+        $_SERVER['HTTP_USER_AGENT'] = 'CalendarStore/5.0 (1127); iCal/5.0 (1535); Mac OS X/10.7.1 (11B26)';
+
+        $event = $this->testCreateEventWithExternalOrganizer();
+
+        // change email address of organizer / attendee
+        $contact = $event->getRecord()->organizer;
+        $contact->email = 'changed@mail.domain';
+        sleep(1);
+        Addressbook_Controller_Contact::getInstance()->update($contact);
+        Calendar_Model_Attender::clearCache();
+
+        $vcalendar = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics', 'r');
+        $vcalendar = str_replace("lars@kneschke.de", "l.kneschke@metaways.de", $vcalendar);
+        $event->put($vcalendar);
+
+        $record = $event->getRecord();
+
+        $this->assertEquals($contact->getId(), $record->organizer->getId(), 'organizer must not change');
+        $this->assertCount(1, $record->attendee->filter('user_id', $contact->getId()), 'attendee must not change');
+    }
+
     /**
      * test deleting attachment from existing event
      */
index fd5699d..543542c 100644 (file)
@@ -101,7 +101,18 @@ class Calendar_Model_Attender extends Tinebase_Record_Abstract
             array('InArray', array(Calendar_Model_Event::TRANSP_TRANSP, Calendar_Model_Event::TRANSP_OPAQUE))
         ),
     );
-    
+
+    /**
+     * datetime fields
+     *
+     * @var array
+     */
+    protected $_datetimeFields = array(
+        'creation_time',
+        'last_modified_time',
+        'deleted_time',
+    );
+
     /**
      * returns accountId of this attender if present
      * 
@@ -145,11 +156,50 @@ class Calendar_Model_Attender extends Tinebase_Record_Abstract
                 return $resolvedUser->email;
                 break;
             default:
-                throw new Exception("type $type not yet supported");
+                throw new Exception("type {$this->user_type} not yet supported");
                 break;
         }
     }
-    
+
+    /**
+     * get email addresses this attendee had in the past
+     *
+     * @return array
+     */
+    public function getEmailsFromHistory()
+    {
+        $emails = array();
+
+        $typeMap = array(
+            self::USERTYPE_USER        => 'Addressbook_Model_Contact',
+            self::USERTYPE_GROUPMEMBER => 'Addressbook_Model_Contact',
+            self::USERTYPE_RESOURCE    => 'Calendar_Model_Resource',
+        );
+
+        if (isset ($typeMap[$this->user_type])) {
+            $type = $typeMap[$this->user_type];
+            $id = $this->user_id instanceof Tinebase_Record_Abstract ? $this->user_id->getId() : $this->user_id;
+
+            $modifications = Tinebase_Timemachine_ModificationLog::getInstance()->getModifications(
+                Tinebase_Helper::array_value(0, explode('_', $type)),
+                $this->user_id instanceof Tinebase_Record_Abstract ? $this->user_id->getId() : $this->user_id,
+                $type,
+                'Sql',
+                $this->creation_time
+            );
+
+            foreach($modifications as $modification) {
+                if (in_array($modification->modified_attribute, array('email', 'email_home'))) {
+                    if ($modification->old_value) {
+                        $emails[] = $modification->old_value;
+                    }
+                }
+            }
+        }
+
+        return $emails;
+    }
+
     /**
      * get name of attender
      * 
@@ -173,7 +223,7 @@ class Calendar_Model_Attender extends Tinebase_Record_Abstract
                 return $resolvedUser->name ?: $resolvedUser->n_fileas;
                 break;
             default:
-                throw new Exception("type $type not yet supported");
+                throw new Exception("type $this->user_type not yet supported");
                 break;
         }
     }
@@ -308,6 +358,15 @@ class Calendar_Model_Attender extends Tinebase_Record_Abstract
         
         // delete attendees no longer attending from recordset
         foreach ($attendeesToDelete as $attendeeToDelete) {
+            // NOTE: email of attendee might have changed in the meantime
+            //       => get old email adresses from modlog and try to match
+            foreach($attendeeToDelete->getEmailsFromHistory() as $oldEmail) {
+                if (isset($emailsOfNewAttendees[$oldEmail])) {
+                    unset($emailsOfNewAttendees[$oldEmail]);
+                    continue 2;
+                }
+            }
+            
             $_event->attendee->removeRecord($attendeeToDelete);
         }
         
@@ -1026,4 +1085,14 @@ class Calendar_Model_Attender extends Tinebase_Record_Abstract
         $isAttendeeCondition = $_event && $_event->attendee instanceof Tinebase_Record_RecordSet ? self::getAttendee($_event->attendee, $_attendee) : TRUE;
         return ($isAttendeeCondition || $isOrganizerCondition)&& $_attendee->status != Calendar_Model_Attender::STATUS_DECLINED;
     }
+
+    /**
+     * clear in class cache
+     */
+    public static function clearCache()
+    {
+        foreach(self::$_resolvedAttendeesCache as $name => $entries) {
+            self::$_resolvedAttendeesCache[$name] = array();
+        }
+    }
 }