0009528: fix concurrency handling in CalDAV Frontend
authorCornelius Weiß <mail@corneliusweiss.de>
Wed, 15 Jan 2014 13:42:21 +0000 (14:42 +0100)
committerPhilipp Schüle <p.schuele@metaways.de>
Wed, 15 Jan 2014 14:37:49 +0000 (15:37 +0100)
- start sequence with 1 like the clients do
- take modlog properties from existing records
  when updateing from xDAV cause concurrency
  is prevented by etags

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

Change-Id: I689412dac2ecddbb31ef443a28ca5d239ca88c7a
Reviewed-on: https://gerrit.tine20.org/tine20/2718
Tested-by: jenkins user
Reviewed-by: Philipp Schüle <p.schuele@metaways.de>
15 files changed:
tests/tine20/Calendar/Controller/EventTests.php
tests/tine20/Calendar/Controller/MSEventFacadeTest.php
tests/tine20/Calendar/Convert/Event/VCalendar/GenericTest.php
tests/tine20/Calendar/JsonTests.php
tests/tine20/Tinebase/ContainerTest.php
tests/tine20/Tinebase/Timemachine/ModificationLogTest.php
tine20/Addressbook/Convert/Contact/VCard/Abstract.php
tine20/Addressbook/Convert/Contact/VCard/Akonadi.php
tine20/Addressbook/Convert/Contact/VCard/Sogo.php
tine20/Addressbook/Frontend/WebDAV/Contact.php
tine20/Calendar/Convert/Event/VCalendar/Abstract.php
tine20/Calendar/Frontend/WebDAV/Event.php
tine20/Tasks/Convert/Task/VCalendar/Abstract.php
tine20/Tasks/Frontend/WebDAV/Task.php
tine20/Tinebase/Timemachine/ModificationLog.php

index 7007c2e..39fa6b4 100644 (file)
@@ -945,7 +945,7 @@ class Calendar_Controller_EventTests extends Calendar_TestCase
         $until->addDay(5); //08
         
         $currentPersistentEvent = $this->_controller->get($persistentEvent);
-        $persistentEvent->seq = 2; // satisfy modlog
+        $persistentEvent->seq = 3; // satisfy modlog
         $updatedPersistenEvent = $this->_controller->update($persistentEvent);
         
         $persistentEvents = $this->_controller->search(new Calendar_Model_EventFilter(array(
index 9f06d5c..82323d5 100644 (file)
@@ -189,7 +189,7 @@ class Calendar_Controller_MSEventFacadeTest extends Calendar_TestCase
      */
     protected function _fixConcurrency($event)
     {
-        $event->seq = 2;
+        $event->seq = 3;
     }
     
     /**
index e637729..f23961f 100644 (file)
@@ -122,7 +122,11 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
         $this->assertEquals('9320E052-6AF0-45E7-9352-04BBEC898D47', $event->uid);
         $this->assertEquals(2, count($event->attendee));
         $this->assertTrue(!empty($event->organizer));
-    
+        $this->assertEquals('2012-02-27 15:56:00', $event->creation_time->toString(), 'CREATED not taken from ics');
+        $this->assertEquals('2012-02-27 15:56:20', $event->last_modified_time, 'DTSTAMP not taken from ics');
+        $this->assertEquals(3, $event->seq, 'SEQUENCE not taken from ics');
+        
+        
         return $event;
     }
     
@@ -380,15 +384,23 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
         $event->attendee[0]->quantity = 10;
         
         $vcalendar = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning.ics');
+        
         // remove alarm part from vcalendar
         $vcalendar = preg_replace('/BEGIN:VALARM.*END:VALARM(\n|\r\n)/s', null, $vcalendar);
         
-        $event = $this->_converter->toTine20Model($vcalendar, $event);
+        // add a sequence
+        $vcalendar = preg_replace('/DTSTAMP:20111007T160719Z(\n|\r\n)/s', "DTSTAMP:20121007T160719Z\nSEQUENCE:5\n", $vcalendar);
+        
+        $event = $this->_converter->toTine20Model($vcalendar, $event, array(
+            Calendar_Convert_Event_VCalendar_Abstract::OPTION_USE_SERVER_MODLOG => true
+        ));
         
         $this->assertEquals(10, $event->attendee[0]->quantity);
         $this->assertTrue($event->alarms instanceof Tinebase_Record_RecordSet);
         $this->assertEquals(0, count($event->alarms));
-    }    
+        $this->assertEquals(1, $event->seq, 'seq should be preserved');
+        $this->assertEquals('2011-10-07 16:07:19', $event->last_modified_time->toString(), 'last_modified_time should be preserved');
+    }
 
     /**
      * @depends testConvertToTine20Model
index 20f1b4a..db328de 100644 (file)
@@ -581,7 +581,7 @@ class Calendar_JsonTests extends Calendar_TestCase
         $someRecurInstance['dtstart'] = '2009-04-08 10:00:00';
         $someRecurInstance['dtend']   = '2009-04-08 12:30:00';
         
-        $someRecurInstance['seq'] = 2;
+        $someRecurInstance['seq'] = 3;
         $this->_uit->updateRecurSeries($someRecurInstance, FALSE, FALSE);
         
         $searchResultData = $this->_searchRecurSeries($recurSet[0]);
@@ -1337,7 +1337,7 @@ class Calendar_JsonTests extends Calendar_TestCase
         $eventData['attendee'][$adminIndex]['status'] = Calendar_Model_Attender::STATUS_TENTATIVE;
         $event = $this->_uit->saveEvent($eventData);
         
-        $loggedMods = Tinebase_Timemachine_ModificationLog::getInstance()->getModificationsBySeq(new Calendar_Model_Attender($eventData['attendee'][$adminIndex]), 1);
+        $loggedMods = Tinebase_Timemachine_ModificationLog::getInstance()->getModificationsBySeq(new Calendar_Model_Attender($eventData['attendee'][$adminIndex]), 2);
         $this->assertEquals(1, count($loggedMods), 'attender modification has not been logged');
         
         $eventData['attendee'] = $currentAttendee;
index a459326..8ef0c7a 100644 (file)
@@ -145,7 +145,7 @@ class Tinebase_ContainerTest extends PHPUnit_Framework_TestCase
         
         $this->assertEquals('Tinebase_Model_Container', get_class($container), 'wrong type');
         $this->assertEquals('renamed container', $container->name);
-        $this->assertEquals(1, $container->seq);
+        $this->assertEquals(2, $container->seq);
         $this->_validateOwnerId($container);
         $this->_validatePath($container);
     }
index d168a21..b6148d1 100644 (file)
@@ -267,7 +267,7 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $modlog = $this->_modLogClass->getModifications('Addressbook', $contact->getId(), NULL, 'Sql',
             Tinebase_DateTime::now()->subSecond(5), Tinebase_DateTime::now())->getFirstRecord();
         $this->assertTrue($modlog !== NULL);
-        $this->assertEquals(1, $modlog->seq);
+        $this->assertEquals(2, $modlog->seq);
         $this->assertEquals('+491234', $modlog->old_value);
         
         $filter = new Tinebase_Model_ModificationLogFilter(array(
@@ -326,8 +326,8 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $task->due = Tinebase_DateTime::now();
         $updatedTask = Tasks_Controller_Task::getInstance()->update($task);
         
-        $task->seq = 0;
-        $modlog = $this->_modLogClass->getModificationsBySeq($task, 1);
+        $task->seq = 1;
+        $modlog = $this->_modLogClass->getModificationsBySeq($task, 2);
         
         $this->assertEquals(1, count($modlog));
         $this->assertEquals((string) $task->due, (string) $modlog->getFirstRecord()->new_value, 'new value mismatch: ' . print_r($modlog->toArray(), TRUE));
index 16131f6..c93eb85 100644 (file)
 abstract class Addressbook_Convert_Contact_VCard_Abstract implements Tinebase_Convert_Interface
 {
     /**
+     * use servers modlogProperties instead of given DTSTAMP & SEQUENCE
+     * use this if the concurrency checks are done differntly like in CardDAV 
+     * where the etag is checked
+     */
+    const OPTION_USE_SERVER_MODLOG = 'useServerModlog';
+    
+    /**
      * the version string
      * 
      * @var string
@@ -54,11 +61,12 @@ abstract class Addressbook_Convert_Contact_VCard_Abstract implements Tinebase_Co
     /**
      * converts vcard to Addressbook_Model_Contact
      * 
-     * @param  \Sabre\VObject\Component|stream|string  $blob    the vcard to parse
-     * @param  Tinebase_Record_Abstract                $_record  update existing contact
+     * @param  \Sabre\VObject\Component|stream|string  $blob       the vcard to parse
+     * @param  Tinebase_Record_Abstract                $_record    update existing contact
+     * @param  array                                   $options    array of options
      * @return Addressbook_Model_Contact
      */
-    public function toTine20Model($blob, Tinebase_Record_Abstract $_record = null)
+    public function toTine20Model($blob, Tinebase_Record_Abstract $_record = null, $options = array())
     {
         $vcard = self::getVObject($blob);
         
@@ -205,6 +213,12 @@ abstract class Addressbook_Convert_Contact_VCard_Abstract implements Tinebase_Co
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) 
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' data ' . print_r($contact->toArray(), true));
         
+        if (isset($options[self::OPTION_USE_SERVER_MODLOG]) && $options[self::OPTION_USE_SERVER_MODLOG] === true) {
+            $contact->creation_time = $_record->creation_time;
+            $contact->last_modified_time = $_record->last_modified_time;
+            $contact->seq = $_record->seq;
+        }
+        
         return $contact;
     }
 
index f365385..9a649af 100644 (file)
@@ -78,16 +78,13 @@ class Addressbook_Convert_Contact_VCard_Akonadi extends Addressbook_Convert_Cont
     );
         
     /**
-     * converts vcard to Addressbook_Model_Contact
-     * 
-     * @param  \Sabre\VObject\Component|stream|string  $blob    the vcard to parse
-     * @param  Tinebase_Record_Abstract                $_record  update existing contact
-     * @return Addressbook_Model_Contact
+     * (non-PHPdoc)
+     * @see Addressbook_Convert_Contact_VCard_Abstract::toTine20Model()
      */
-    public function toTine20Model($blob, Tinebase_Record_Abstract $_record = null)
+    public function toTine20Model($blob, Tinebase_Record_Abstract $_record = null, $options = array())
     {
         $vcard = self::getVObject($blob);
-        $contact = parent::toTine20Model($blob, $_record);
+        $contact = parent::toTine20Model($blob, $_record, $options);
         
         foreach ($vcard->children() as $property) {
             switch ($property->name) {
index 8cc9d80..56415aa 100644 (file)
@@ -82,9 +82,9 @@ class Addressbook_Convert_Contact_VCard_Sogo extends Addressbook_Convert_Contact
      * (non-PHPdoc)
      * @see Addressbook_Convert_Contact_VCard_Abstract::toTine20Model()
      */
-    public function toTine20Model($_blob, Tinebase_Record_Abstract $_record = null)
+    public function toTine20Model($_blob, Tinebase_Record_Abstract $_record = null, $options = array())
     {
-        $contact = parent::toTine20Model($_blob, $_record);
+        $contact = parent::toTine20Model($_blob, $_record, $options);
         
         if (!empty($contact->url)) {
             $contact->url = strtr($contact->url, array('http\:' => 'http:'));
index cab89be..d262366 100644 (file)
@@ -248,7 +248,9 @@ class Addressbook_Frontend_WebDAV_Contact extends Sabre\DAV\File implements Sabr
             throw new DAV\Exception\Forbidden('Update denied for unknow client');
         }
         
-        $contact = $this->_converter->toTine20Model($cardData, $this->getRecord());
+        $contact = $this->_converter->toTine20Model($cardData, $this->getRecord(), array(
+            Addressbook_Convert_Contact_VCard_Abstract::OPTION_USE_SERVER_MODLOG => true,
+        ));
         
         $this->_contact = Addressbook_Controller_Contact::getInstance()->update($contact, false);
         $this->_vcard   = null;
index 836d0da..7ecb666 100644 (file)
  */
 class Calendar_Convert_Event_VCalendar_Abstract implements Tinebase_Convert_Interface
 {
+    /**
+     * use servers modlogProperties instead of given DTSTAMP & SEQUENCE
+     * use this if the concurrency checks are done differently like in CalDAV
+     * where the etag is checked
+     */
+    const OPTION_USE_SERVER_MODLOG = 'useServerModlog';
+    
     public static $cutypeMap = array(
         Calendar_Model_Attender::USERTYPE_USER          => 'INDIVIDUAL',
         Calendar_Model_Attender::USERTYPE_GROUPMEMBER   => 'INDIVIDUAL',
@@ -345,11 +352,12 @@ class Calendar_Convert_Event_VCalendar_Abstract implements Tinebase_Convert_Inte
     /**
      * converts vcalendar to Calendar_Model_Event
      * 
-     * @param  mixed                 $_blob   the VCALENDAR to parse
+     * @param  mixed                 $_blob    the VCALENDAR to parse
      * @param  Calendar_Model_Event  $_record  update existing event
+     * @param  array                 $options  array of options
      * @return Calendar_Model_Event
      */
-    public function toTine20Model($blob, Tinebase_Record_Abstract $_record = null)
+    public function toTine20Model($blob, Tinebase_Record_Abstract $_record = null, $options = array())
     {
         $vcalendar = self::getVObject($blob);
         
@@ -373,16 +381,17 @@ class Calendar_Convert_Event_VCalendar_Abstract implements Tinebase_Convert_Inte
         $baseVevent = null;
         foreach ($vcalendar->VEVENT as $vevent) {
             if (! isset($vevent->{'RECURRENCE-ID'})) {
-                $this->_convertVevent($vevent, $event);
-                $baseVevent = $vevent;
                 
+                $this->_convertVevent($vevent, $event, $options);
+                $baseVevent = $vevent;
                 break;
             }
         }
         
         // TODO only do this for events with rrule?
         // if (! empty($event->rrule)) {
-        $this->_parseEventExceptions($event, $vcalendar, $baseVevent);
+        $this->_parseEventExceptions($event, $vcalendar, $baseVevent, $options);
+
         $event->isValid(true);
         
         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) 
@@ -397,8 +406,9 @@ class Calendar_Convert_Event_VCalendar_Abstract implements Tinebase_Convert_Inte
      * @param  Calendar_Model_Event                $event
      * @param  \Sabre\VObject\Component\VCalendar  $vcalendar
      * @param  \Sabre\VObject\Component\VCalendar  $baseVevent
+     * @param  array                               $options
      */
-    protected function _parseEventExceptions(Calendar_Model_Event $event, \Sabre\VObject\Component\VCalendar $vcalendar, $baseVevent = null)
+    protected function _parseEventExceptions(Calendar_Model_Event $event, \Sabre\VObject\Component\VCalendar $vcalendar, $baseVevent = null, $options = array())
     {
         $oldExdates = $event->exdate instanceof Tinebase_Record_RecordSet ? $event->exdate->filter('is_deleted', false) : new Tinebase_Record_RecordSet('Calendar_Model_Event');
         
@@ -425,7 +435,7 @@ class Calendar_Convert_Event_VCalendar_Abstract implements Tinebase_Convert_Inte
                     $this->_adaptBaseEventProperties($vevent, $baseVevent);
                 }
                 
-                $this->_convertVevent($vevent, $recurException);
+                $this->_convertVevent($vevent, $recurException, $options);
                 
                 if (! $event->exdate instanceof Tinebase_Record_RecordSet) {
                     $event->exdate = new Tinebase_Record_RecordSet('Calendar_Model_Event');
@@ -455,9 +465,10 @@ class Calendar_Convert_Event_VCalendar_Abstract implements Tinebase_Convert_Inte
      * convert VCALENDAR to Tinebase_Record_RecordSet of Calendar_Model_Event
      * 
      * @param  mixed  $blob  the vcalendar to parse
+     * @param  array  $options
      * @return Tinebase_Record_RecordSet
      */
-    public function toTine20RecordSet($blob)
+    public function toTine20RecordSet($blob, $options = array())
     {
         $vcalendar = self::getVObject($blob);
         
@@ -466,9 +477,9 @@ class Calendar_Convert_Event_VCalendar_Abstract implements Tinebase_Convert_Inte
         foreach ($vcalendar->VEVENT as $vevent) {
             if (! isset($vevent->{'RECURRENCE-ID'})) {
                 $event = new Calendar_Model_Event();
-                $this->_convertVevent($vevent, $event);
+                $this->_convertVevent($vevent, $event, $options);
                 if (! empty($event->rrule)) {
-                    $this->_parseEventExceptions($event, $vcalendar);
+                    $this->_parseEventExceptions($event, $vcalendar, $options);
                 }
                 $result->addRecord($event);
             }
@@ -678,28 +689,23 @@ class Calendar_Convert_Event_VCalendar_Abstract implements Tinebase_Convert_Inte
      * 
      * @param  \Sabre\VObject\Component\VEvent  $vevent  the VEVENT to parse
      * @param  Calendar_Model_Event             $event   the Tine 2.0 event to update
+     * @param  array                            $options
      */
-    protected function _convertVevent(\Sabre\VObject\Component\VEvent $vevent, Calendar_Model_Event $event)
+    protected function _convertVevent(\Sabre\VObject\Component\VEvent $vevent, Calendar_Model_Event $event, $options)
     {
         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) 
             Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' vevent ' . $vevent->serialize());
         
         $newAttendees = array();
-        
-        // unset supported fields
-        foreach ($this->_supportedFields as $field) {
-            if ($field == 'alarms') {
-                $event->$field = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm');
-            } else {
-                $event->$field = null;
-            }
-        }
+        $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm');
         
         foreach ($vevent->children() as $property) {
             switch ($property->name) {
                 case 'CREATED':
                 case 'DTSTAMP':
-                    // do nothing
+                    if (! isset($options[self::OPTION_USE_SERVER_MODLOG]) || $options[self::OPTION_USE_SERVER_MODLOG] !== true) {
+                        $event->{$property->name == 'CREATED' ? 'creation_time' : 'last_modified_time'} = $this->_convertToTinebaseDateTime($property);
+                    }
                     break;
                     
                 case 'LAST-MODIFIED':
@@ -764,7 +770,9 @@ class Calendar_Convert_Event_VCalendar_Abstract implements Tinebase_Convert_Inte
                     break;
                     
                 case 'SEQUENCE':
-                    $event->seq = $property->getValue();
+                    if (! isset($options[self::OPTION_USE_SERVER_MODLOG]) || $options[self::OPTION_USE_SERVER_MODLOG] !== true) {
+                        $event->seq = $property->getValue();
+                    }
                     break;
                     
                 case 'DESCRIPTION':
@@ -984,7 +992,7 @@ class Calendar_Convert_Event_VCalendar_Abstract implements Tinebase_Convert_Inte
         Calendar_Model_Attender::emailsToAttendee($event, $newAttendees);
         
         if (empty($event->seq)) {
-            $event->seq = 0;
+            $event->seq = 1;
         }
         
         if (empty($event->class)) {
index 1b86a45..c481ac4 100644 (file)
@@ -366,16 +366,10 @@ class Calendar_Frontend_WebDAV_Event extends Sabre\DAV\File implements Sabre\Cal
         // keep old record for reference
         $recordBeforeUpdate = clone $this->getRecord();
         
-        $event = $this->_converter->toTine20Model($vobject, $this->getRecord());
-        
-        // concurrency management is based on etag in CalDAV, so we set last_modified to
-        // now to circumvent internal concurrency checks
-        $event->last_modified_time = Tinebase_DateTime::now();
-        if ($event->exdate instanceof Tinebase_Record_RecordSet) {
-            foreach ($event->exdate as $idx => $exdate) {
-                $exdate->last_modified_time = $event->last_modified_time;
-            }
-        }
+        // concurrency management is based on etag in CalDAV
+        $event = $this->_converter->toTine20Model($vobject, $this->getRecord(), array(
+            Calendar_Convert_Event_VCalendar_Abstract::OPTION_USE_SERVER_MODLOG => true,
+        ));
         
         $currentContainer = Tinebase_Container::getInstance()->getContainerById($this->getRecord()->container_id);
         
index b03337e..f50c146 100644 (file)
  */
 class Tasks_Convert_Task_VCalendar_Abstract implements Tinebase_Convert_Interface
 {
+    /**
+     * use servers modlogProperties instead of given DTSTAMP & SEQUENCE
+     * use this if the concurrency checks are done differntly like in CalDAV
+     * where the etag is checked
+     */
+    const OPTION_USE_SERVER_MODLOG = 'useServerModlog';
+    
     public static $cutypeMap = array(
         //Tasks_Model_Attender::USERTYPE_USER          => 'INDIVIDUAL',
         //Tasks_Model_Attender::USERTYPE_GROUPMEMBER   => 'INDIVIDUAL',
@@ -295,9 +302,10 @@ class Tasks_Convert_Task_VCalendar_Abstract implements Tinebase_Convert_Interfac
      * 
      * @param  mixed                 $_blob   the vcalendar to parse
      * @param  Calendar_Model_Event  $_record  update existing event
+     * @param  array                 $options
      * @return Calendar_Model_Event
      */
-    public function toTine20Model($_blob, Tinebase_Record_Abstract $_record = null)
+    public function toTine20Model($_blob, Tinebase_Record_Abstract $_record = null, $options = array())
     {
         $vcalendar = self::getVObject($_blob);
         
@@ -330,7 +338,7 @@ class Tasks_Convert_Task_VCalendar_Abstract implements Tinebase_Convert_Interfac
         // find the main event - the main event has no RECURRENCE-ID
         foreach($vcalendar->VTODO as $vtodo) {
             if(!isset($vtodo->{"RECURRENCE-ID"})) {
-                $this->_convertVtodo($vtodo, $task);
+                $this->_convertVtodo($vtodo, $task, $options);
                 
                 break;
             }
@@ -496,33 +504,16 @@ class Tasks_Convert_Task_VCalendar_Abstract implements Tinebase_Convert_Interfac
      * @param  \Sabre\VObject\Component\VTodo  $_vevent  the VTODO to parse
      * @param  Tasks_Model_Task     $_vtodo   the Tine 2.0 event to update
      */
-    protected function _convertVtodo(\Sabre\VObject\Component\VTodo $_vtodo, Tasks_Model_Task $_task)
+    protected function _convertVtodo(\Sabre\VObject\Component\VTodo $_vtodo, Tasks_Model_Task $_task, $options)
     {
         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' vevent ' . $_vtodo->serialize());  
         
         $task = $_task;
         
-        // unset supported fields
-        foreach ($this->_supportedFields as $field) {
-            switch ($field) {
-                case 'alarms':
-                    $task->$field = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm');
-                    break;
-                    
-                case 'priority':
-                     $task->$field = 'NORMAL';
-                     break;
-                     
-                case 'status':
-                     $task->$field = 'NEEDS-ACTION';
-                     break;
-                     
-                default:
-                     $task->$field = null;
-                     break;
-            }
-        }
-
+        $task->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm');
+        $task->priority = 'NORMAL';
+        $task->status = 'NEEDS-ACTION';
+        
         foreach($_vtodo->children() as $property) {
             switch($property->name) {
                 case 'CREATED':
@@ -603,7 +594,9 @@ class Tasks_Convert_Task_VCalendar_Abstract implements Tinebase_Convert_Interfac
                     break;
                            
                 case 'SEQUENCE':
-                    $task->seq = $property->getValue();
+                    if (! isset($options[self::OPTION_USE_SERVER_MODLOG]) || $options[self::OPTION_USE_SERVER_MODLOG] !== true) {
+                        $task->seq = $property->getValue();
+                    }
                     
                     break;
                     
index e39c1b3..3303b64 100644 (file)
@@ -371,7 +371,9 @@ class Tasks_Frontend_WebDAV_Task extends Sabre\DAV\File implements Sabre\CalDAV\
         // keep old record for reference
         $recordBeforeUpdate = clone $this->getRecord();
         
-        $task = $this->_converter->toTine20Model($vobject, $this->getRecord());
+        $task = $this->_converter->toTine20Model($vobject, $this->getRecord(), array(
+            Tasks_Convert_Task_VCalendar_Abstract::OPTION_USE_SERVER_MODLOG => true,
+        ));
         
         // iCal does sends back an old value, because it does not refresh the vcalendar after 
         // update. Therefor we must reapply the value of last_modified_time after the convert
index ab317aa..26e641f 100644 (file)
@@ -817,7 +817,7 @@ class Tinebase_Timemachine_ModificationLog
                 $_newRecord->created_by    = $currentAccountId;
                 $_newRecord->creation_time = $currentTime;
                 if ($_newRecord->has('seq')) {
-                    $_newRecord->seq       = 0;
+                    $_newRecord->seq       = 1;
                 }
                 break;
             case 'update':