0013306: Tinebase_Filesystem - undo filesystem actions
authorPaul Mehrer <p.mehrer@metaways.de>
Wed, 28 Jun 2017 12:56:18 +0000 (14:56 +0200)
committerPhilipp Schüle <p.schuele@metaways.de>
Thu, 6 Jul 2017 10:44:49 +0000 (12:44 +0200)
Tinebase_Filesystem - undo filesystem actions

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

Change-Id: I782c135a6f8a60bb1f5ec0323923fd052e6089e5
Reviewed-on: http://gerrit.tine20.com/customers/4980
Reviewed-by: Philipp Schüle <p.schuele@metaways.de>
Tested-by: Philipp Schüle <p.schuele@metaways.de>
tests/tine20/Tinebase/FileSystemTest.php
tests/tine20/Tinebase/Timemachine/ModificationLogTest.php
tine20/Filemanager/Controller/Node.php
tine20/Tinebase/Backend/Sql/Abstract.php
tine20/Tinebase/Core.php
tine20/Tinebase/FileSystem.php
tine20/Tinebase/Model/Tree/FileObjectFilter.php
tine20/Tinebase/Timemachine/ModificationLog.php
tine20/Tinebase/Tree.php
tine20/Tinebase/Tree/FileObject.php

index 2299bd7..5ea3627 100644 (file)
@@ -472,6 +472,9 @@ class Tinebase_FileSystemTest extends TestCase
     {
         $this->testDeleteFile();
 
+        $modifications = Tinebase_Timemachine_ModificationLog::getInstance()->getReplicationModificationsByInstanceSeq(0, 10000);
+        $instanceSeq = $modifications->getLastRecord()->instance_seq - 2;
+
         $path = $this->_basePath . '/PHPUNIT/phpunit.txt';
 
         $handle = $this->_controller->fopen($path, 'w');
@@ -487,6 +490,41 @@ class Tinebase_FileSystemTest extends TestCase
         $contents = stream_get_contents($handle);
         $this->_controller->fclose($handle);
         $this->assertEquals('somethingNew', $contents);
+
+        $node = $this->_controller->stat($path);
+        Tinebase_Timemachine_ModificationLog::getInstance()->undo(new Tinebase_Model_ModificationLogFilter(array(
+            array('field' => 'record_id', 'operator' => 'in', 'value' => array($node->getId(), $node->object_id)),
+            array('field' => 'instance_seq', 'operator' => 'greater', 'value' => $instanceSeq)
+        )));
+
+        clearstatcache();
+        $this->_controller->clearStatCache();
+        $handle = $this->_controller->fopen($path, 'r');
+        $contents = stream_get_contents($handle);
+        $this->_controller->fclose($handle);
+        $this->assertEquals('phpunit', $contents);
+
+        $handle = $this->_controller->fopen($path, 'w');
+        $this->assertEquals('resource', gettype($handle), 'opening file failed');
+        $written = fwrite($handle, 'somethingVeryNew');
+        $this->assertEquals(16, $written);
+        $this->_controller->fclose($handle);
+
+        $handle = $this->_controller->fopen($path, 'r');
+        $contents = stream_get_contents($handle);
+        $this->_controller->fclose($handle);
+        $this->assertEquals('somethingVeryNew', $contents);
+
+        $handle = $this->_controller->fopen($path, 'w');
+        $this->assertEquals('resource', gettype($handle), 'opening file failed');
+        $written = fwrite($handle, 'somethingNew');
+        $this->assertEquals(12, $written);
+        $this->_controller->fclose($handle);
+
+        $handle = $this->_controller->fopen($path, 'r');
+        $contents = stream_get_contents($handle);
+        $this->_controller->fclose($handle);
+        $this->assertEquals('somethingNew', $contents);
     }
 
     public function testCopyRecreateFile()
index 1de2f7a..daed19e 100644 (file)
@@ -404,7 +404,7 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $this->assertTrue($notFound, 'roll back did not work...');
 
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs($roleModifications);
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
 
         $newRole = $roleController->get($role->getId());
 
@@ -425,7 +425,7 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod->new_value = json_encode($diff->toArray());
 
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
 
         /** @var Tinebase_Model_Role $newRole */
         $newRole = $roleController->get($role->getId());
@@ -484,7 +484,7 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         static::assertNotNull($mod);
         $containerModifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        static::assertTrue($result, 'applyReplactionModLogs failed');
+        static::assertTrue($result, 'applyReplicationModLogs failed');
         // avoid Cache, so use get, not getContainerById
         /** @var Tinebase_Model_Container $newContainer */
         $newContainer = $containerController->get($container->getId());
@@ -496,14 +496,14 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         static::assertNotNull($mod);
         $containerModifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        static::assertTrue($result, 'applyReplactionModLogs failed');
+        static::assertTrue($result, 'applyReplicationModLogs failed');
 
         // change color
         $mod = $containerModifications->getFirstRecord();
         static::assertNotNull($mod);
         $containerModifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        static::assertTrue($result, 'applyReplactionModLogs failed');
+        static::assertTrue($result, 'applyReplicationModLogs failed');
         // avoid Cache, so use get, not getContainerById
         $newContainer = $containerController->get($container->getId());
         static::assertEquals('#FFFFFF', $newContainer->color, 'color not set properly');
@@ -513,7 +513,7 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         static::assertNotNull($mod);
         $containerModifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $grants = $containerController->getGrantsOfContainer($container->getId(), true);
         static::assertEquals(2, $grants->count(), 'should find 2 grant records');
         $grant = $grants->filter('account_type', 'anyone')->getFirstRecord();
@@ -573,7 +573,7 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $groupModifications->getFirstRecord();
         $groupModifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $newGroup = $groupController->getGroupById($group->getId());
         $this->assertEquals($group->name, $newGroup->name);
         $this->assertEmpty($groupController->getGroupMembers($newGroup->getId()), 'group members not empty');
@@ -582,21 +582,21 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $groupModifications->getFirstRecord();
         $groupModifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $this->assertEquals(1, count($groupController->getGroupMembers($newGroup->getId())), 'group members not created');
 
         // remove group members
         $mod = $groupModifications->getFirstRecord();
         $groupModifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $this->assertEmpty($groupController->getGroupMembers($newGroup->getId()), 'group members not deleted');
 
         // update group description
         $mod = $groupModifications->getFirstRecord();
         $groupModifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $newGroup = $groupController->getGroupById($group->getId());
         $this->assertEquals('test description', $newGroup->description);
 
@@ -604,7 +604,7 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $groupModifications->getFirstRecord();
         $groupModifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $notFound = false;
         try {
             $groupController->getGroupById($group->getId());
@@ -671,7 +671,7 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $userModifications->removeRecord($mod);
         $mods[] = $mod;
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', $mods));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $replicationUser = $userController->getUserById($newUser->getId(), 'Tinebase_Model_FullUser');
         $this->assertEquals($replicationUser->name, $newUser->name);
 
@@ -679,7 +679,7 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $userModifications->getFirstRecord();
         $userModifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         /** @var Tinebase_Model_FullUser $replicationUser */
         $replicationUser = $userController->getUserById($newUser->getId(), 'Tinebase_Model_FullUser');
         $authBackend = Tinebase_Auth_Factory::factory('Sql');
@@ -693,7 +693,7 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $userModifications->getFirstRecord();
         $userModifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         /** @var Tinebase_Model_FullUser $replicationUser */
         $replicationUser = $userController->getUserById($newUser->getId(), 'Tinebase_Model_FullUser');
         $this->assertEquals(Tinebase_Model_User::ACCOUNT_STATUS_EXPIRED, $replicationUser->accountStatus);
@@ -702,7 +702,7 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $userModifications->getFirstRecord();
         $userModifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         /** @var Tinebase_Model_FullUser $replicationUser */
         $replicationUser = $userController->getUserById($newUser->getId(), 'Tinebase_Model_FullUser');
         $this->assertEquals(Tinebase_Model_User::ACCOUNT_STATUS_ENABLED, $replicationUser->accountStatus);
@@ -711,7 +711,7 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $userModifications->getFirstRecord();
         $userModifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         /** @var Tinebase_Model_FullUser $replicationUser */
         $replicationUser = $userController->getUserById($newUser->getId(), 'Tinebase_Model_FullUser');
         $this->assertTrue($expiryDate->equals($replicationUser->accountExpires));
@@ -720,7 +720,7 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $userModifications->getFirstRecord();
         $userModifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         /** @var Tinebase_Model_FullUser $replicationUser */
         $replicationUser = $userController->getUserById($newUser->getId(), 'Tinebase_Model_FullUser');
         $this->assertEquals('shoo', $replicationUser->accountFirstName);
@@ -729,7 +729,7 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $userModifications->getFirstRecord();
         $userModifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $notFound = false;
         try {
             $userController->getUserById($newUser->getId());
@@ -752,6 +752,20 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $fmController = Filemanager_Controller_Node::getInstance();
         $filesystem = Tinebase_FileSystem::getInstance();
         $filesystem->resetBackends();
+        Tinebase_Core::clearAppInstanceCache();
+
+        $nodes = $filesystem->_getTreeNodeBackend()->search(new Tinebase_Model_Tree_Node_Filter(array(
+            array('field' => 'is_deleted', 'operator' => 'equals', 'value' => true)
+        )));
+        if ($nodes->count() > 0) {
+            $filesystem->_getTreeNodeBackend()->delete($nodes->getId());
+        }
+        $objects = $filesystem->getFileObjectBackend()->search(new Tinebase_Model_Tree_FileObjectFilter(array(
+            array('field' => 'is_deleted', 'operator' => 'equals', 'value' => true)
+        )));
+        if ($objects->count() > 0) {
+            $filesystem->_getTreeNodeBackend()->delete($objects->getId());
+        }
 
         // create two folders
         $fmController->createNodes(array($testPath, $testPath . '/subfolder'),
@@ -826,22 +840,22 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         // create FileNode
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         // update hash of FileObject
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         // update acl_node of FileNode
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $filesystem->stat(Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath))->statpath);
 
         // create second folder
@@ -849,27 +863,27 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         // create FileNode
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $filesystem->stat(Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/subfolder'))->statpath);
 
         // set grants
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $filesystem->clearStatCache();
         $testPathNode = $filesystem->stat(Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/subfolder'))->statpath);
         static::assertEquals($testPathNode->getId(), $testPathNode->acl_node, 'grants not set');
@@ -880,11 +894,11 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $filesystem->clearStatCache();
         $testPathNode = $filesystem->stat(Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/subfolder'))->statpath);
         static::assertNotEquals($testPathNode->getId(), $testPathNode->acl_node, 'grants still set');
@@ -893,15 +907,15 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $filesystem->stat(Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/newsubfolder'))->statpath);
         $notFound = false;
         try {
@@ -916,7 +930,7 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed (copy)');
         $filesystem->stat(Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/newsubfolder'))->statpath);
         $filesystem->stat(Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/subfolder'))->statpath);
 
@@ -924,15 +938,15 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed (create file)');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed (create file)');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed (create file)');
         $path = Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/newsubfolder/testFile'));
         $node = $filesystem->stat($path->statpath);
         static::assertEquals('someData', $filesystem->getNodeContents($node->getId()));
@@ -941,11 +955,11 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed (delete 1)');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed (delete 2)');
         $path = Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/newsubfolder/testFile'));
         static::assertFalse($filesystem->fileExists($path->statpath));
 
@@ -953,15 +967,15 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed (recreate)');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed (recreate)');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed (recreate)');
         $path = Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/newsubfolder/testFile'));
         $node = $filesystem->stat($path->statpath);
         static::assertEquals('otherData', $filesystem->getNodeContents($node->getId()));
@@ -970,19 +984,19 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed (delete subfolder)');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed (delete subfolder)');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed (delete subfolder)');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed (delete subfolder)');
         $filesystem->stat(Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/subfolder'))->statpath);
         $notFound = false;
         try {
@@ -996,19 +1010,19 @@ class Tinebase_Timemachine_ModificationLogTest extends PHPUnit_Framework_TestCas
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $mod = $modifications->getFirstRecord();
         $modifications->removeRecord($mod);
         $result = Tinebase_Timemachine_ModificationLog::getInstance()->applyReplicationModLogs(new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog', array($mod)));
-        $this->assertTrue($result, 'applyReplactionModLogs failed');
+        $this->assertTrue($result, 'applyReplicationModLogs failed');
         $notFound = false;
         try {
             $filesystem->stat(Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/subfolder'))->statpath);
index d874748..c45316c 100644 (file)
@@ -1398,6 +1398,15 @@ class Filemanager_Controller_Node extends Tinebase_Controller_Record_Abstract
     }
 
     /**
+     * @param Tinebase_Model_ModificationLog $_modification
+     * @param bool $_dryRun
+     */
+    public function undoReplicationModificationLog(Tinebase_Model_ModificationLog $_modification, $_dryRun)
+    {
+        Tinebase_Tree::getInstance()->undoReplicationModificationLog($_modification, $_dryRun);
+    }
+
+    /**
      * Return usage array of a folder
      *
      * @param $_id
index 393c334..1a6fb47 100644 (file)
@@ -733,9 +733,9 @@ abstract class Tinebase_Backend_Sql_Abstract extends Tinebase_Backend_Abstract i
     protected function _checkTracing(Zend_Db_Select $select)
     {
         /** @noinspection PhpUndefinedFieldInspection */
-        $config = Tinebase_Core::getConfig();
-        if ( Tinebase_Core::isLogLevel(Zend_Log::TRACE) && $config && isset($config->logger)) {
-            if ($config->logger->traceQueryOrigins) {
+        $config = Tinebase_Config::getInstance();
+        if (Tinebase_Core::isLogLevel(Zend_Log::TRACE) && $config && isset($config->logger)) {
+            if (isset($config->logger->traceQueryOrigins) && $config->logger->traceQueryOrigins) {
                 $e = new Exception();
                 Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . "\n" . 
                     "BACKTRACE: \n" . $e->getTraceAsString() . "\n" . 
index 90b36d6..5833e1b 100644 (file)
@@ -1834,6 +1834,14 @@ class Tinebase_Core
         }
     }
 
+    /**
+     * clear application instance cache
+     */
+    public static function clearAppInstanceCache()
+    {
+        self::$appInstanceCache = array();
+    }
+
     public static function getDelegate($applicationName, $configKey, $interfaceName)
     {
         if (!isset(static::$_delegatorCache[$configKey])) {
index a1b1aa4..4a70909 100644 (file)
@@ -146,7 +146,7 @@ class Tinebase_FileSystem implements
 
     public function resetBackends()
     {
-        $config = Tinebase_Core::getConfig()->{Tinebase_Config::FILESYSTEM};
+        $config = Tinebase_Config::getInstance()->{Tinebase_Config::FILESYSTEM};
         $this->_modLogActive = true === $config->{Tinebase_Config::FILESYSTEM_MODLOGACTIVE};
         $this->_indexingActive = true === $config->{Tinebase_Config::FILESYSTEM_INDEX_CONTENT};
         $this->_notificationActive = true === $config->{Tinebase_Config::FILESYSTEM_ENABLE_NOTIFICATIONS};
@@ -154,7 +154,7 @@ class Tinebase_FileSystem implements
 
         $this->_treeNodeBackend = null;
 
-        $this->_fileObjectBackend  = new Tinebase_Tree_FileObject(null, array(
+        $this->_fileObjectBackend = new Tinebase_Tree_FileObject(null, array(
             Tinebase_Config::FILESYSTEM_MODLOGACTIVE => $this->_modLogActive
         ));
     }
index 7843d2c..f0d4910 100644 (file)
@@ -6,7 +6,7 @@
  * @subpackage  Filter
  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
  * @author      Paul Mehrer <p.mehrer@metaways.de>
- * @copyright   Copyright (c) 2016 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2016-2017 Metaways Infosystems GmbH (http://www.metaways.de)
  *
  */
 
@@ -39,5 +39,8 @@ class Tinebase_Model_Tree_FileObjectFilter extends Tinebase_Model_Filter_FilterG
      * @var array filter model fieldName => definition
      */
     protected $_filterModel = array(
+        'is_deleted'            => array(
+            'filter'                => 'Tinebase_Model_Filter_Bool'
+        )
     );
 }
index 59eba3b..811de7c 100644 (file)
@@ -994,34 +994,42 @@ class Tinebase_Timemachine_ModificationLog implements Tinebase_Controller_Interf
             }
 
             try {
-                $record = $controller->get($modlog->record_id, NULL, TRUE, $isDeleted);
 
                 if (empty($modifiedAttribute)) {
                     // new handling using diff!
 
                     $updateCount++;
 
-                    if (Tinebase_Timemachine_ModificationLog::CREATED === $modlog->change_type) {
-                        if (!$dryrun) {
-                            $controller->delete($record->getId());
-                        }
-                    } elseif (true === $isDeleted) {
-                        if (!$dryrun) {
-                            $controller->unDelete($record);
-                        }
+                    if (method_exists($controller, 'undoReplicationModificationLog')) {
+                        $controller->undoReplicationModificationLog($modlog, $dryrun);
                     } else {
-                        /** TODO this is not finished YET! see $notUndoableFields below etc.! */
-                        $diff = new Tinebase_Record_Diff(json_decode($modlog->new_value, true));
-                        $record->undo($diff);
 
-                        if (!$dryrun) {
-                            $controller->update($record);
+                        $record = $controller->get($modlog->record_id, NULL, TRUE, $isDeleted);
+
+                        if (Tinebase_Timemachine_ModificationLog::CREATED === $modlog->change_type) {
+                            if (!$dryrun) {
+                                $controller->delete($record->getId());
+                            }
+                        } elseif (true === $isDeleted) {
+                            if (!$dryrun) {
+                                $controller->unDelete($record);
+                            }
+                        } else {
+                            /** TODO this is not finished YET! see $notUndoableFields below etc.! */
+                            $diff = new Tinebase_Record_Diff(json_decode($modlog->new_value, true));
+                            $record->undo($diff);
+
+                            if (!$dryrun) {
+                                $controller->update($record);
+                            }
                         }
                     }
 
                     // this is the legacy code for old data in existing installations
                 } else {
 
+                    $record = $controller->get($modlog->record_id, NULL, TRUE, $isDeleted);
+
                     if (!in_array($modlog->modified_attribute, $notUndoableFields) && ($overwrite || $record->seq === $modlog->seq)) {
                         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ .
                             ' Reverting change id ' . $modlog->getId());
index 4b8012f..b6f49cc 100644 (file)
@@ -109,4 +109,43 @@ class Tinebase_Tree implements Tinebase_Controller_Interface
         // unset properties that are maintained only locally
         $_record->preview_count = null;
     }
+
+    /**
+     * @param Tinebase_Model_ModificationLog $_modification
+     * @param bool $_dryRun
+     */
+    public function undoReplicationModificationLog(Tinebase_Model_ModificationLog $_modification, $_dryRun)
+    {
+        $treeBackend = Tinebase_FileSystem::getInstance()->_getTreeNodeBackend();
+        switch($_modification->change_type) {
+            case Tinebase_Timemachine_ModificationLog::CREATED:
+                if (true === $_dryRun) {
+                    return;
+                }
+                $treeBackend->softDelete($_modification->record_id);
+                break;
+
+            case Tinebase_Timemachine_ModificationLog::UPDATED:
+                $node = $treeBackend->get($_modification->record_id);
+                $diff = new Tinebase_Record_Diff(json_decode($_modification->new_value, true));
+                $node->undo($diff);
+
+                if (true !== $_dryRun) {
+                    $treeBackend->update($node);
+                }
+                break;
+
+            case Tinebase_Timemachine_ModificationLog::DELETED:
+                if (true === $_dryRun) {
+                    return;
+                }
+                $node = $treeBackend->get($_modification->record_id, true);
+                $node->is_deleted = false;
+                $treeBackend->update($node);
+                break;
+
+            default:
+                throw new Tinebase_Exception_UnexpectedValue('change_type ' . $_modification->change_type . ' unknown');
+        }
+    }
 }
\ No newline at end of file
index 822fd46..01ce517 100644 (file)
@@ -60,6 +60,8 @@ class Tinebase_Tree_FileObject extends Tinebase_Backend_Sql_Abstract
 
     protected $_revision = null;
 
+    protected $_allowSetRevision = false;
+
     /**
      * the singleton pattern
      *
@@ -165,24 +167,32 @@ class Tinebase_Tree_FileObject extends Tinebase_Backend_Sql_Abstract
         
         $transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
 
-        $select = $this->_db->select()
-            ->from($this->_tablePrefix . $this->_tableName)
+        // lock row first
+        $select = $this->_db->select()->from($this->_tablePrefix . $this->_tableName)
             ->where($this->_db->quoteIdentifier($this->_tablePrefix . $this->_tableName . '.id') . ' = ?', $objectId);
-        
-        // lock row
         $stmt = $this->_db->query($select);
         $stmt->fetchAll();
-        
-        // increase revision
-        $where = $this->_db->quoteInto($this->_db->quoteIdentifier('id') . ' = ?', $objectId);
-        $data  = array('revision' => new Zend_Db_Expr($this->_db->quoteIdentifier('revision') . ' + 1'));
-        $this->_db->update($this->_tablePrefix . $this->_tableName, $data, $where);
 
-        // fetch updated revision
+        $select = $this->_db->select()
+            ->from($this->_tablePrefix . $this->_revisionsTableName, new Zend_Db_Expr('MAX(' .
+                $this->_db->quoteIdentifier('revision') . ') + 1 AS ' . $this->_db->quoteIdentifier('revision')))
+            ->where($this->_db->quoteIdentifier($this->_tablePrefix . $this->_revisionsTableName . '.id') . ' = ?', $objectId);
+
         $stmt = $this->_db->query($select);
         $queryResult = $stmt->fetchAll();
-        
-        $revision = $queryResult[0]['revision'];
+        if (empty($queryResult)) {
+            $revision = 1;
+        } else {
+            $revision = (int)$queryResult[0]['revision'];
+            if (0 === $revision) {
+                $revision = 1;
+            }
+        }
+
+        // increase revision
+        $where = $this->_db->quoteInto($this->_db->quoteIdentifier('id') . ' = ?', $objectId);
+        $data  = array('revision' => $revision);
+        $this->_db->update($this->_tablePrefix . $this->_tableName, $data, $where);
         
         // store new revisionid and unlock row
         Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId);
@@ -199,9 +209,11 @@ class Tinebase_Tree_FileObject extends Tinebase_Backend_Sql_Abstract
     protected function _recordToRawData(Tinebase_Record_Interface $_record)
     {
         $record = parent::_recordToRawData($_record);
-        
-        // get updated by _getNextRevision only
-        unset($record['revision']);
+
+        if (false === $this->_allowSetRevision) {
+            // get updated by _getNextRevision only
+            unset($record['revision']);
+        }
         
         return $record;
     }
@@ -226,6 +238,9 @@ class Tinebase_Tree_FileObject extends Tinebase_Backend_Sql_Abstract
         if ($_mode !== 'create') {
             /** @var Tinebase_Model_Tree_FileObject $currentRecord */
             $currentRecord = $this->get($_record, true);
+            if (true === $this->_allowSetRevision && $_record->revision < $currentRecord->revision) {
+                return;
+            }
             if ($currentRecord->hash !== null && !empty($currentRecord->revision)) {
                 if ($currentRecord->hash === $_record->hash && (int)$currentRecord->size === (int)$_record->size) {
                     return;
@@ -600,4 +615,58 @@ class Tinebase_Tree_FileObject extends Tinebase_Backend_Sql_Abstract
         // unset properties that are maintained only locally
         $_record->indexed_hash = null;
     }
+
+    /**
+     * @param Tinebase_Model_ModificationLog $_modification
+     * @param bool $_dryRun
+     */
+    public function undoReplicationModificationLog(Tinebase_Model_ModificationLog $_modification, $_dryRun)
+    {
+        switch($_modification->change_type) {
+            case Tinebase_Timemachine_ModificationLog::CREATED:
+                if (true === $_dryRun) {
+                    return;
+                }
+                $this->softDelete($_modification->record_id);
+                break;
+
+            case Tinebase_Timemachine_ModificationLog::UPDATED:
+                $object = $this->get($_modification->record_id);
+                $diff = new Tinebase_Record_Diff(json_decode($_modification->new_value, true));
+                $object->undo($diff);
+
+                if (true !== $_dryRun) {
+                    $oldAllowSetRevision = $this->setAllowRevisionUpdate(true);
+                    try {
+                        $this->update($object);
+                    } finally {
+                        $this->_allowSetRevision = $oldAllowSetRevision;
+                    }
+                }
+                break;
+
+            case Tinebase_Timemachine_ModificationLog::DELETED:
+                if (true === $_dryRun) {
+                    return;
+                }
+                $object = $this->get($_modification->record_id, true);
+                $object->is_deleted = false;
+                $this->update($object);
+                break;
+
+            default:
+                throw new Tinebase_Exception_UnexpectedValue('change_type ' . $_modification->change_type . ' unknown');
+        }
+    }
+
+    /**
+     * @param bool $_value
+     * @return bool
+     */
+    public function setAllowRevisionUpdate($_value)
+    {
+        $oldValue = $this->_allowSetRevision;
+        $this->_allowSetRevision = $_value;
+        return $oldValue;
+    }
 }