* @var array
*/
protected $_rmDir = array();
+
+ protected $_oldModLog = null;
/**
* Sets up the fixture.
{
parent::setUp();
+ $this->_oldModLog = Tinebase_Core::getConfig()->{Tinebase_Config::FILESYSTEM}->{Tinebase_Config::FILESYSTEM_MODLOGACTIVE};
+ Tinebase_Core::getConfig()->{Tinebase_Config::FILESYSTEM}->{Tinebase_Config::FILESYSTEM_MODLOGACTIVE} = true;
$this->_fsController = Tinebase_FileSystem::getInstance();
+ $this->_fsController->resetBackends();
$this->_application = Tinebase_Application::getInstance()->getApplicationByName('Filemanager');
$this->_rmDir = array();
$this->_getUit()->deleteNodes($dir);
}
}
-
+
+ Tinebase_Core::getConfig()->{Tinebase_Config::FILESYSTEM}->{Tinebase_Config::FILESYSTEM_MODLOGACTIVE} = $this->_oldModLog;
+
+ Tinebase_FileSystem::getInstance()->resetBackends();
Tinebase_FileSystem::getInstance()->clearStatCache();
Tinebase_FileSystem::getInstance()->clearDeletedFilesFromFilesystem();
*/
public function testMoveFolderNodesToFolderExisting()
{
- sleep(1);
$targetNode = $this->testCreateContainerNodeInPersonalFolder();
$testPath = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/dir1';
- $result = $this->_getUit()->moveNodes(array($targetNode['path']), array($testPath), false);
- $dirs = $this->testCreateDirectoryNodesInShared();
+ $this->_getUit()->moveNodes(array($targetNode['path']), array($testPath), false);
+ $this->testCreateDirectoryNodesInShared();
try {
- $result = $this->_getUit()->moveNodes(array($testPath), '/shared/testcontainer', false);
+ $this->_getUit()->moveNodes(array($testPath), '/shared/testcontainer', false);
$this->fail('Expected Filemanager_Exception_NodeExists!');
} catch (Filemanager_Exception_NodeExists $fene) {
$result = $this->_getUit()->moveNodes(array($testPath), '/shared/testcontainer', true);
$createdNode = $result[0];
try {
- $result = $this->_getUit()->moveNodes(array($targetNode['path']), array($createdNode['path']), false);
+ $this->_getUit()->moveNodes(array($targetNode['path']), array($createdNode['path']), false);
$this->fail('Expected Filemanager_Exception_NodeExists!');
} catch (Filemanager_Exception_NodeExists $fene) {
$result = $this->_getUit()->moveNodes(array($targetNode['path']), array($createdNode['path']), true);
*/
public function testDeletedFileCleanupFromFilesystem()
{
+ Tinebase_Core::getConfig()->{Tinebase_Config::FILESYSTEM}->{Tinebase_Config::FILESYSTEM_MODLOGACTIVE} = false;
+ $this->_fsController->resetBackends();
+
// remove all files with size 0 first
+ // better here than below?
+ $this->testDeleteFileNodes();
+
$size0Nodes = Tinebase_FileSystem::getInstance()->searchNodes(new Tinebase_Model_Tree_Node_Filter(array(
array('field' => 'type', 'operator' => 'equals', 'value' => Tinebase_Model_Tree_FileObject::TYPE_FILE),
array('field' => 'size', 'operator' => 'equals', 'value' => 0)
foreach ($size0Nodes as $node) {
Tinebase_FileSystem::getInstance()->deleteFileNode($node);
}
-
- $this->testDeleteFileNodes();
+
+ // why here?
+ //$this->testDeleteFileNodes();
$result = Tinebase_FileSystem::getInstance()->clearDeletedFilesFromFilesystem();
$this->assertEquals(0, $result, 'should not clean up anything as files with size 0 are not written to disk');
$this->tearDown();
Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
+ Tinebase_Core::getConfig()->{Tinebase_Config::FILESYSTEM}->{Tinebase_Config::FILESYSTEM_MODLOGACTIVE} = false;
+ $this->_fsController->resetBackends();
$this->testDeleteFileNodes(true);
$result = Tinebase_FileSystem::getInstance()->clearDeletedFilesFromFilesystem();
$this->assertEquals(1, $result, 'should cleanup one file');
$this->_rmDir = array();
$this->_oldNotification = Tinebase_Core::getConfig()->{Tinebase_Config::FILESYSTEM}->{Tinebase_Config::FILESYSTEM_ENABLE_NOTIFICATIONS};
$this->_oldModLog = Tinebase_Core::getConfig()->{Tinebase_Config::FILESYSTEM}->{Tinebase_Config::FILESYSTEM_MODLOGACTIVE};
+ Tinebase_Core::getConfig()->{Tinebase_Config::FILESYSTEM}->{Tinebase_Config::FILESYSTEM_MODLOGACTIVE} = true;
$this->_oldIndexContent = Tinebase_Core::getConfig()->{Tinebase_Config::FILESYSTEM}->{Tinebase_Config::FILESYSTEM_INDEX_CONTENT};
$this->_oldCreatePreview = Tinebase_Config::getInstance()->{Tinebase_Config::FILESYSTEM}->{Tinebase_Config::FILESYSTEM_CREATE_PREVIEWS};
$this->assertTrue($result, 'wrong result for rmdir command');
$this->assertFalse($this->_controller->fileExists($testPath), 'failed to delete directory');
+
+ return $testPath;
+ }
+
+ public function testRecreateDir()
+ {
+ $testPath = $this->testRmdir();
+
+ $node = $this->_controller->mkdir($testPath);
+ $this->assertTrue($this->_controller->isDir($testPath), 'path created by mkdir is not a directory');
+
+ $this->assertEquals(1, $node->revision);
}
public function testScandir()
$this->assertTrue(!in_array('phpunit.txt', $children));
}
+
+ public function testRecreateFile()
+ {
+ $this->testDeleteFile();
+
+ $path = $this->_basePath . '/PHPUNIT/phpunit.txt';
+
+ $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);
+
+ $children = $this->_controller->scanDir($this->_basePath . '/PHPUNIT')->name;
+
+ $this->assertContains('phpunit.txt', $children);
+ $handle = $this->_controller->fopen($path, 'r');
+ $contents = stream_get_contents($handle);
+ $this->_controller->fclose($handle);
+ $this->assertEquals('somethingNew', $contents);
+ }
+
+ public function testCopyRecreateFile()
+ {
+ $destinationPath = $this->_basePath . '/TESTCOPY2/phpunit.txt';
+ $this->_controller->mkdir($this->_basePath . '/TESTCOPY2');
+ $handle = $this->_controller->fopen($destinationPath, 'w');
+ $this->assertEquals('resource', gettype($handle), 'opening file failed');
+ $written = fwrite($handle, 'somethingNew');
+ $this->assertEquals(12, $written);
+ $this->_controller->fclose($handle);
+ $node = $this->_controller->stat($destinationPath);
+ $this->_controller->deleteFileNode($node);
+
+ $this->testCopyFileToExistingDirectory();
+ }
public function testGetFileSize()
{
// mail foo?
// check mail
$messages = $mailer->getMessages();
- $this->assertEquals(2, count($messages));
+ $this->assertEquals(1, count($messages));
$headers = $messages[0]->getHeaders();
$this->assertEquals('filemanager notification', $headers['Subject'][0]);
$this->assertTrue(strpos($headers['To'][0], Tinebase_Core::getUser()->accountEmailAddress) !== false);
$smd = Tinebase_Server_Json::getServiceMap();
$smdArray = $smd->toArray();
- $this->assertTrue(isset($smdArray['services']['Tinebase.ping']));
+ $this->assertTrue(isset($smdArray['services']['Tinebase.ping']), 'Tinebase.ping missing from service map: '
+ . print_r($smdArray, true));
}
/**
*/
protected $_recordIds = array();
+ protected $_oldFileSystemConfig = null;
+
/**
* Runs the test methods of this class.
{
Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
+ $this->_oldFileSystemConfig = clone Tinebase_Config::getInstance()->{Tinebase_Config::FILESYSTEM};
+
$now = new Tinebase_DateTime();
$this->_modLogClass = Tinebase_Timemachine_ModificationLog::getInstance();
$this->_persistantLogEntries = new Tinebase_Record_RecordSet('Tinebase_Model_ModificationLog');
*/
protected function tearDown()
{
+ Tinebase_Config::getInstance()->{Tinebase_Config::FILESYSTEM} = $this->_oldFileSystemConfig;
+
Tinebase_TransactionManager::getInstance()->rollBack();
}
public function testFileManagerReplication()
{
- $modifications = Tinebase_Timemachine_ModificationLog::getInstance()->getReplicationModificationsByInstanceSeq(-1, 10000);
+ Tinebase_Config::getInstance()->{Tinebase_Config::FILESYSTEM}
+ ->{Tinebase_Config::FILESYSTEM_MODLOGACTIVE} = true;
+ $modifications = Tinebase_Timemachine_ModificationLog::getInstance()->
+ getReplicationModificationsByInstanceSeq(-1, 10000);
$instance_seq = $modifications->getLastRecord()->instance_seq;
- $testPath = '/' . Tinebase_Model_Container::TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/unittestTestPath';
+ $testPath = '/' . Tinebase_Model_Container::TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName
+ . '/unittestTestPath';
$fmController = Filemanager_Controller_Node::getInstance();
$filesystem = Tinebase_FileSystem::getInstance();
+ $filesystem->resetBackends();
// create two folders
- $fmController->createNodes(array($testPath, $testPath . '/subfolder'), Tinebase_Model_Tree_FileObject::TYPE_FOLDER);
+ $fmController->createNodes(array($testPath, $testPath . '/subfolder'),
+ Tinebase_Model_Tree_FileObject::TYPE_FOLDER);
+
// set Grants
$testPathNode = $filesystem->stat(Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/subfolder'))->statpath);
$grantRecord->id = null;
$testPathNode->grants = new Tinebase_Record_RecordSet('Tinebase_Model_Grants', array($grantRecord));
$testPathNode->acl_node = $testPathNode->getId();
- $fmController->update($testPathNode);
+ $testNodeGrants = $fmController->update($testPathNode);
+ Tinebase_Tree_NodeGrants::getInstance()->getGrantsForRecord($testNodeGrants);
// unset Grants
$testPathNode->acl_node = null;
$fmController->update($testPathNode);
// move subfolder to new name
- /*$newSubFolderNode = */$fmController->moveNodes(array($testPath . '/subfolder'), array($testPath . '/newsubfolder'))->getFirstRecord();
+ $fmController->moveNodes(array($testPath . '/subfolder'), array($testPath . '/newsubfolder'))->getFirstRecord();
// copy it back to old name
- /*$subFolderNode = */$fmController->copyNodes(array($testPath . '/newsubfolder'), array($testPath . '/subfolder'))->getFirstRecord();
+ $fmController->copyNodes(array($testPath . '/newsubfolder'), array($testPath . '/subfolder'))->getFirstRecord();
+
+ // create file
+ $tempPath = Tinebase_TempFile::getTempPath();
+ $tempFileId = Tinebase_TempFile::getInstance()->createTempFile($tempPath);
+ file_put_contents($tempPath, 'someData');
+ $fmController->createNodes(array($testPath . '/newsubfolder/testFile'),
+ Tinebase_Model_Tree_FileObject::TYPE_FILE, array($tempFileId));
+
+ // delete file
+ $fmController->deleteNodes(array($testPath . '/newsubfolder/testFile'));
+
+ // recreate file
+ $tempPath = Tinebase_TempFile::getTempPath();
+ $tempFileId = Tinebase_TempFile::getInstance()->createTempFile($tempPath);
+ file_put_contents($tempPath, 'otherData');
+ $fmController->createNodes(array($testPath . '/newsubfolder/testFile'),
+ Tinebase_Model_Tree_FileObject::TYPE_FILE, array($tempFileId));
//this is not supported for folders!
//$fmController->delete($subFolderNode->getId());
$modifications = Tinebase_Timemachine_ModificationLog::getInstance()->getReplicationModificationsByInstanceSeq($instance_seq);
$fmModifications = $modifications->filter('record_type', 'Filemanager_Model_Node');
- $this->assertEquals($modifications->count(), $fmModifications->count(), 'other changes thatn to Filemanager_Model_Node detected');
+ $fnModifications = $modifications->filter('record_type', 'Tinebase_Model_Tree_Node');
+ $foModifications = $modifications->filter('record_type', 'Tinebase_Model_Tree_FileObject');
+ $this->assertEquals($modifications->count(), $fmModifications->count() + $fnModifications->count() +
+ $foModifications->count(), 'other changes than to Tinebase_Model_Tree_Node or Filemanager_Model_Node detected');
// rollback
Tinebase_TransactionManager::getInstance()->rollBack();
$this->assertTrue($notFound, 'roll back did not work...');
// create first folder
- $mod = $fmModifications->getFirstRecord();
- $fmModifications->removeRecord($mod);
+ // create 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');
+ // 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');
+ // 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');
+ // 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');
$filesystem->stat(Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath))->statpath);
// create second folder
- $mod = $fmModifications->getFirstRecord();
- $fmModifications->removeRecord($mod);
+ // create 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');
+ // 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');
$filesystem->stat(Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/subfolder'))->statpath);
// set grants
- $mod = $fmModifications->getFirstRecord();
- $fmModifications->removeRecord($mod);
+ $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');
+ $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');
+ $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');
+ $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');
+ Tinebase_Tree_NodeGrants::getInstance()->getGrantsForRecord($testPathNode);
+ static::assertEquals($testNodeGrants->grants, $testPathNode->grants);
// unset grants
- $mod = $fmModifications->getFirstRecord();
- $fmModifications->removeRecord($mod);
+ $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');
+ $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');
+ $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');
// move subfolder to new name
- $mod = $fmModifications->getFirstRecord();
- $fmModifications->removeRecord($mod);
+ $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');
+ $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');
+ $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');
$filesystem->stat(Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/newsubfolder'))->statpath);
$notFound = false;
try {
+ $filesystem->clearStatCache();
$filesystem->stat(Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/subfolder'))->statpath);
} catch (Tinebase_Exception_NotFound $tenf) {
$notFound = true;
$this->assertTrue($notFound, 'move did not work...');
// copy it back to old name
- $mod = $fmModifications->getFirstRecord();
- $fmModifications->removeRecord($mod);
+ $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');
$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);
+ // 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');
+ $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');
+ $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');
+ $path = Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/newsubfolder/testFile'));
+ $node = $filesystem->stat($path->statpath);
+ static::assertEquals('someData', $filesystem->getNodeContents($node->getId()));
+
+ // delete 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');
+ $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');
+ $path = Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/newsubfolder/testFile'));
+ static::assertFalse($filesystem->fileExists($path->statpath));
+
+ // recreate 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');
+ $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');
+ $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');
+ $path = Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/newsubfolder/testFile'));
+ $node = $filesystem->stat($path->statpath);
+ static::assertEquals('otherData', $filesystem->getNodeContents($node->getId()));
+
// delete new subfolder
- $mod = $fmModifications->getFirstRecord();
- $fmModifications->removeRecord($mod);
+ $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');
+ $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');
+ $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');
+ $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');
$filesystem->stat(Tinebase_Model_Tree_Node_Path::createFromPath($fmController->addBasePath($testPath . '/subfolder'))->statpath);
$this->assertTrue($notFound, 'delete did not work...');
// delete new folder
- $mod = $fmModifications->getFirstRecord();
- $fmModifications->removeRecord($mod);
+ $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');
+ $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');
+ $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');
+ $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');
$notFound = false;
$notFound = true;
}
$this->assertTrue($notFound, 'delete did not work...');
+
+ $this->assertEquals(0, $modifications->count(), 'not all modifications processed');
}
}
* @var string
*/
protected $_modelName = 'Filemanager_Model_Node';
-
+
/**
- * TODO handle modlog
- *
- * attention, this NEEDS to be off / true for replication!
- *
* @var boolean
*/
- protected $_omitModLog = true;
+ protected $_omitModLog = false;
/**
* holds the total count of the last recursive search
$_record->{Tinebase_Model_Tree_Node::XPROPS_REVISION} = $_oldRecord->{Tinebase_Model_Tree_Node::XPROPS_REVISION};
}
- $nodePath = null;
- if (Tinebase_Model_Tree_FileObject::TYPE_FOLDER === $_record->type) {
- $nodePath = Tinebase_Model_Tree_Node_Path::createFromStatPath($this->_backend->getPathOfNode($_record->getId(), true));
- $modlogNode = new Filemanager_Model_Node(array(
- 'id' => $_record->getId(),
- 'path' => $nodePath->statpath,
- 'type' => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
- Tinebase_Model_Tree_Node::XPROPS_NOTIFICATION => $_record->xprops(Tinebase_Model_Tree_Node::XPROPS_NOTIFICATION),
- // do not set acl_node, this will be calculated on the client side
- ), true);
- if (isset($_record->xprops(Tinebase_Model_Tree_Node::XPROPS_REVISION)[Tinebase_Model_Tree_Node::XPROPS_REVISION_NODE_ID]) &&
- $_record->xprops(Tinebase_Model_Tree_Node::XPROPS_REVISION)[Tinebase_Model_Tree_Node::XPROPS_REVISION_NODE_ID] === $_record->getId() &&
- $_record->xprops(Tinebase_Model_Tree_Node::XPROPS_REVISION) != $_oldRecord->xprops(Tinebase_Model_Tree_Node::XPROPS_REVISION)) {
- $revisions = $_record->xprops(Tinebase_Model_Tree_Node::XPROPS_REVISION);
- unset($revisions[Tinebase_Model_Tree_Node::XPROPS_REVISION_NODE_ID]);
- $modlogNode->{Tinebase_Model_Tree_Node::XPROPS_REVISION} = $revisions;
- }
- $modlogOldNode = new Filemanager_Model_Node(array(
- 'id' => $_record->getId(),
- 'path' => $nodePath->statpath,
- 'type' => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
- Tinebase_Model_Tree_Node::XPROPS_NOTIFICATION => $_oldRecord->xprops(Tinebase_Model_Tree_Node::XPROPS_NOTIFICATION),
- ), true);
- $this->_omitModLog = false;
- $this->_writeModLog($modlogNode, $modlogOldNode);
- $this->_omitModLog = true;
- }
-
// update node acl
$aclNode = $_oldRecord->acl_node;
if (Tinebase_Model_Tree_FileObject::TYPE_FOLDER === $_record->type
&& Tinebase_Core::getUser()->hasGrant($_record, Tinebase_Model_Grants::GRANT_ADMIN, 'Tinebase_Model_Tree_Node')
) {
+ $nodePath = Tinebase_Model_Tree_Node_Path::createFromStatPath($this->_backend->getPathOfNode($_record->getId(), true));
if (! $nodePath->isSystemPath()) {
- $modlogOldNode = $modlogNode = null;
if ($_record->acl_node === null && ! $nodePath->isToplevelPath()) {
// acl_node === null -> remove acl
$node = $this->_backend->setAclFromParent($nodePath->statpath);
$aclNode = $node->acl_node;
- $modlogNode = new Filemanager_Model_Node(array(
- 'id' => $_record->getId(),
- 'path' => $nodePath->statpath,
- 'type' => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
- 'grants' => 'unset'
- // do not set acl_node, this will be calculated on the client side
- ), true);
- $modlogOldNode = new Filemanager_Model_Node(array(
- 'id' => $_record->getId(),
- 'type' => Tinebase_Model_Tree_FileObject::TYPE_FOLDER
- ), true);
-
} elseif ($_record->acl_node === $_record->getId() && isset($_record->grants)) {
$oldGrants = Tinebase_Tree_NodeGrants::getInstance()->getGrantsForRecord($_oldRecord);
if (is_array($_record->grants)) {
$diff = $_record->grants->diff($oldGrants);
if (!$diff->isEmpty() || $_oldRecord->acl_node !== $_record->acl_node) {
$this->_backend->setGrantsForNode($_record, $_record->grants);
- $modlogNode = new Filemanager_Model_Node(array(
- 'id' => $_record->getId(),
- 'path' => $nodePath->statpath,
- 'type' => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
- 'grants' => $_record->grants
- // do not set acl_node, this will be calculated on the client side
- ), true);
- $modlogOldNode = new Filemanager_Model_Node(array(
- 'id' => $_record->getId(),
- 'type' => Tinebase_Model_Tree_FileObject::TYPE_FOLDER
- ), true);
}
$aclNode = $_record->acl_node;
}
-
- if (null !== $modlogNode) {
- $this->_omitModLog = false;
- $this->_writeModLog($modlogNode, $modlogOldNode);
- $this->_omitModLog = true;
- }
}
}
// reset node acl value to prevent spoofing
$newNodePath = $parentPathRecord->statpath . '/' . $path->name;
$newNode = $this->_createNodeInBackend($newNodePath, $_type, $_tempFileId);
- $this->_writeModlogForNewNode($newNode, /*$existingNode,*/ $_type, $_path);
$this->resolvePath($newNode, $parentPathRecord);
$this->resolveGrants($newNode);
return $newNode;
}
-
- /**
- * @param Tinebase_Model_Tree_Node $_newNode
- * @param string $_type
- * @param string $_path
- */
- protected function _writeModlogForNewNode($_newNode, /*$_existingNode,*/ $_type, $_path)
- {
- if (Tinebase_Model_Tree_FileObject::TYPE_FOLDER === $_type && false === $this->_inCopyOrMoveNode) {
- $modlogNode = new Filemanager_Model_Node(array(
- 'id' => $_newNode->getId(),
- 'path' => ($_path instanceof Tinebase_Model_Tree_Node_Path) ? $this->removeBasePath($_path->flatpath) : $_path,
- 'type' => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
- // no grants, no acl_node, it will all be handled on client side
- //'grants' => Tinebase_Tree_NodeGrants::getInstance()->getGrantsForRecord($_newNode)
- ), true);
- $this->_omitModLog = false;
- $this->_writeModLog($modlogNode, null);
- $this->_omitModLog = true;
- }
- }
/**
* create node in backend
if ($node instanceof Tinebase_Record_Abstract) {
$result->addRecord($node);
-
- if (Tinebase_Model_Tree_FileObject::TYPE_FOLDER === $node->type) {
- $modlogNode = new Filemanager_Model_Node(array(
- 'id' => $node->getId(),
- 'path' => is_array($_destinationFilenames) ? array($_destinationFilenames[$idx]) : $_destinationFilenames,
- 'type' => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
- 'name' => $_action,
- // do not set acl_node, this will be calculated on the client side
- ), true);
- $modlogOldNode = new Filemanager_Model_Node(array(
- 'id' => $node->getId(),
- 'path' => $_sourceFilenames[$idx],
- ), true);
- $this->_omitModLog = false;
- $this->_writeModLog($modlogNode, $modlogOldNode);
- $this->_omitModLog = true;
- }
-
} else {
if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__
. ' Could not copy or move node to destination ' . $destinationPathRecord->flatpath);
break;
case Tinebase_Model_Tree_FileObject::TYPE_FOLDER:
$success = $this->_backend->rmdir($_path->statpath, TRUE);
-
- if (FALSE !== $success && false === $this->_inCopyOrMoveNode) {
- $modlogNode = new Filemanager_Model_Node(array(
- 'id' => $node->getId(),
- 'path' => $_flatpath,
- 'type' => Tinebase_Model_Tree_FileObject::TYPE_FOLDER
- ), true);
- $this->_omitModLog = false;
- $this->_writeModLog(null, $modlogNode);
- $this->_omitModLog = true;
- }
break;
}
*/
public function applyReplicationModificationLog(Tinebase_Model_ModificationLog $modification)
{
- switch ($modification->change_type) {
- case Tinebase_Timemachine_ModificationLog::CREATED:
- $diff = new Tinebase_Record_Diff(json_decode($modification->new_value, true));
- $this->createNodes(array($diff->diff['path']), $diff->diff['type']);
- break;
-
- case Tinebase_Timemachine_ModificationLog::UPDATED:
- $diff = new Tinebase_Record_Diff(json_decode($modification->new_value, true));
- if (isset($diff->diff['name'])) {
- $this->_copyOrMoveNodes(array($diff->oldData['path']), $diff->diff['path'], $diff->diff['name']);
- } elseif(isset($diff->diff['grants'])) {
- $record = $this->_backend->stat($diff->diff['path']);
- if ('unset' === $diff->diff['grants']) {
- $this->_backend->removeAclFromNode($record);
- } else {
- $this->_backend->setGrantsForNode($record, $diff->diff['grants']);
- }
- } else {
- throw new Tinebase_Exception_InvalidArgument('update modlogs need the property name containing copy or move or grants for grants update');
- }
- break;
-
- case Tinebase_Timemachine_ModificationLog::DELETED:
- $diff = new Tinebase_Record_Diff(json_decode($modification->new_value, true));
- $this->deleteNodes(array($diff->oldData['path']));
- break;
-
- default:
- throw new Tinebase_Exception('unknown Tinebase_Model_ModificationLog->old_value: ' . $modification->old_value);
- }
+ Tinebase_Tree::getInstance()->applyReplicationModificationLog($modification);
}
/**
$idArray = (! is_array($_id)) ? array(Tinebase_Record_Abstract::convertId($_id, $this->_modelName)) : $_id;
$identifier = $this->_getRecordIdentifier();
+ $this->_inspectBeforeSoftDelete($idArray);
+
$where = array(
$this->_db->quoteInto($this->_db->quoteIdentifier($identifier) . ' IN (?)', $idArray)
);
return $this->_db->update($this->_tablePrefix . $this->_tableName, array('is_deleted' => 1), $where);
}
+
+ /**
+ * @param array $_ids
+ */
+ protected function _inspectBeforeSoftDelete(array $_ids)
+ {
+ }
/**
* Deletes entries
$grant->sanitizeAccountIdAndFillWithAllGrants();
$record->grants->addRecord($grant);
}
-
+
+ /**
+ * @param string $recordId
+ */
+ public function deleteGrantsOfRecord($recordId)
+ {
+ $this->_grantsBackend->deleteByProperty($recordId, 'record_id');
+ }
+
/**
* this function creates a new record with default grants during inital setup
*
/**
* write modlog
*
- * @param Tinebase_Record_Interface $_newRecord
- * @param Tinebase_Record_Interface $_oldRecord
+ * @param Tinebase_Record_Interface|null $_newRecord
+ * @param Tinebase_Record_Interface|null $_oldRecord
* @return NULL|Tinebase_Record_RecordSet
* @throws Tinebase_Exception_InvalidArgument
*/
));
}
+ /**
+ * @return Tinebase_Tree_FileObject
+ */
+ public function getFileObjectBackend()
+ {
+ return $this->_fileObjectBackend;
+ }
+
public function setStreamOptionForNextOperation($_key, $_value)
{
$this->_streamOptionsForNextOperation[$_key] = $_value;
return $node;
}
- protected function _getTreeNodeBackend()
+ public function _getTreeNodeBackend()
{
if ($this->_treeNodeBackend === null) {
$this->_treeNodeBackend = new Tinebase_Tree_Node(null, /* options */ array(
'modelName' => $this->_treeNodeModel,
- Tinebase_Config::FILESYSTEM_ENABLE_NOTIFICATIONS => $this->_notificationActive
+ Tinebase_Config::FILESYSTEM_ENABLE_NOTIFICATIONS => $this->_notificationActive,
+ Tinebase_Config::FILESYSTEM_MODLOGACTIVE => $this->_modLogActive,
));
}
$parentNode = $this->get($node->parent_id);
$node->acl_node = $parentNode->acl_node;
$this->update($node);
+ $this->_nodeAclController->deleteGrantsOfRecord($node->getId());
Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId);
$transactionId = null;
throw new Tinebase_Exception_UnexpectedValue("Source path and destination path must be different.");
}
+ if (null !== ($deletedNode = $this->_getTreeNodeBackend()
+ ->getChild($parentNode, $destinationNodeName, true, false)) && $deletedNode->is_deleted) {
+ $this->_updateDeletedNodeName($deletedNode);
+ }
+
// set new node properties
$destinationNode->setId(null);
$destinationNode->parent_id = $parentNode->getId();
. ' revision_size should not become smaller than 0: ' . $fileObject->size . ' for object id: ' . $fileObject->getId());
$fileObject->revision_size = 0;
}
- $this->_fileObjectBackend->update($fileObject);
+ $this->_fileObjectBackend->update($fileObject, false);
}
}
}
$node->name = basename($newPath);
}
+ try {
+ $deletedNewPathNode = $this->stat($newPath, null, true);
+ $this->_updateDeletedNodeName($deletedNewPathNode);
+ } catch (Tinebase_Exception_NotFound $tenf) {}
+
$node = $this->_getTreeNodeBackend()->update($node, true);
$transactionManager->commitTransaction($transactionId);
}
}
}
+
+ protected function _updateDeletedNodeName(Tinebase_Model_Tree_Node $_node)
+ {
+ $treeNodeBackend = $this->_getTreeNodeBackend();
+ $parentId = $_node->parent_id;
+ do {
+ $id = uniqid();
+ $name = $_node->name . $id;
+ if (($len = mb_strlen($name)) > 255) {
+ $name = mb_substr($name, $len - 255);
+ }
+ } while (null !== $treeNodeBackend->getChild($parentId, $name, true, false));
+ $_node->name = $name;
+ $this->_getTreeNodeBackend()->update($_node, true);
+ }
/**
* create directory
$this->_updateFolderSizesUpToRoot(new Tinebase_Record_RecordSet('Tinebase_Model_Tree_Node', array($node)),
0 - (int)$node->size, 0 - (int)$node->revision_size);
}
- $this->_getTreeNodeBackend()->delete($node->getId());
+ $this->_getTreeNodeBackend()->softDelete($node->getId());
$this->clearStatCache($path);
// delete object only, if no other tree node refers to it
*
* @param string $path
* @param int|null $revision
+ * @param boolean $getDeleted
* @return Tinebase_Model_Tree_Node
* @throws Tinebase_Exception_NotFound
*/
- public function stat($path, $revision = null)
+ public function stat($path, $revision = null, $getDeleted = false)
{
$transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
$missingPathParts = array_diff_assoc($this->_splitPath($path), $pathParts);
foreach ($missingPathParts as $pathPart) {
- $node = $this->_getTreeNodeBackend()->getChild($parentNode, $pathPart);
+ $node = $this->_getTreeNodeBackend()->getChild($parentNode, $pathPart, $getDeleted);
+
+ if ($node->is_deleted && null !== $parentNode && $parentNode->is_deleted) {
+ throw new Tinebase_Exception_NotFound('cascading deleted nodes');
+ }
// keep track of current path position
array_push($pathParts, $pathPart);
$parentNode = $node;
}
+
+
if (null !== $revision) {
try {
$this->_getTreeNodeBackend()->setRevision($revision);
$transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
try {
$parentId = $_parentId instanceof Tinebase_Model_Tree_Node ? $_parentId->getId() : $_parentId;
- $parentNode = $_parentId instanceof Tinebase_Model_Tree_Node
- ? $_parentId
- : ($_parentId ? $this->get($_parentId) : null);
-
- $directoryObject = new Tinebase_Model_Tree_FileObject(array(
- 'type' => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
- 'contentytype' => null,
- 'hash' => Tinebase_Record_Abstract::generateUID(),
- 'size' => 0
- ));
- Tinebase_Timemachine_ModificationLog::setRecordMetaData($directoryObject, 'create');
- $directoryObject = $this->_fileObjectBackend->create($directoryObject);
-
- $treeNode = new Tinebase_Model_Tree_Node(array(
- 'name' => $name,
- 'object_id' => $directoryObject->getId(),
- 'parent_id' => $parentId,
- 'acl_node' => $parentNode && !empty($parentNode->acl_node) ? $parentNode->acl_node : null,
- Tinebase_Model_Tree_Node::XPROPS_REVISION
- => $parentNode && !empty($parentNode->{Tinebase_Model_Tree_Node::XPROPS_REVISION}) ? $parentNode->{Tinebase_Model_Tree_Node::XPROPS_REVISION} : null
- ));
- $treeNode = $this->_getTreeNodeBackend()->create($treeNode);
+
+ if (null !== ($deletedNode = $this->_getTreeNodeBackend()->getChild($parentId, $name, true, false)) &&
+ $deletedNode->is_deleted) {
+ $deletedNode->is_deleted = 0;
+ $object = $this->_fileObjectBackend->get($deletedNode->object_id, true);
+ if ($object->is_deleted) {
+ $object->is_deleted = 0;
+ $this->_fileObjectBackend->update($object);
+ }
+ //we can use _treeNodeBackend as we called get further up
+ $treeNode = $this->_treeNodeBackend->update($deletedNode);
+ } else {
+
+ $parentNode = $_parentId instanceof Tinebase_Model_Tree_Node
+ ? $_parentId
+ : ($_parentId ? $this->get($_parentId) : null);
+
+ $directoryObject = new Tinebase_Model_Tree_FileObject(array(
+ 'type' => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
+ 'contentytype' => null,
+ 'hash' => Tinebase_Record_Abstract::generateUID(),
+ 'size' => 0
+ ));
+ Tinebase_Timemachine_ModificationLog::setRecordMetaData($directoryObject, 'create');
+ $directoryObject = $this->_fileObjectBackend->create($directoryObject);
+
+ $treeNode = new Tinebase_Model_Tree_Node(array(
+ 'name' => $name,
+ 'object_id' => $directoryObject->getId(),
+ 'parent_id' => $parentId,
+ 'acl_node' => $parentNode && !empty($parentNode->acl_node) ? $parentNode->acl_node : null,
+ Tinebase_Model_Tree_Node::XPROPS_REVISION => $parentNode &&
+ !empty($parentNode->{Tinebase_Model_Tree_Node::XPROPS_REVISION}) ?
+ $parentNode->{Tinebase_Model_Tree_Node::XPROPS_REVISION} : null
+ ));
+ $treeNode = $this->_getTreeNodeBackend()->create($treeNode);
+ }
Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId);
$transactionId = null;
$transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
try {
$parentId = $_parentId instanceof Tinebase_Model_Tree_Node ? $_parentId->getId() : $_parentId;
- $parentNode = $_parentId instanceof Tinebase_Model_Tree_Node ? $_parentId : $this->get($parentId);
- $fileObject = new Tinebase_Model_Tree_FileObject(array(
- 'type' => $_fileType,
- 'contentytype' => null,
- ));
- Tinebase_Timemachine_ModificationLog::setRecordMetaData($fileObject, 'create');
+ if (null !== ($deletedNode = $this->_getTreeNodeBackend()->getChild($parentId, $_name, true, false)) &&
+ $deletedNode->is_deleted) {
+ $deletedNode->is_deleted = 0;
+ /** @var Tinebase_Model_Tree_FileObject $object */
+ $object = $this->_fileObjectBackend->get($deletedNode->object_id, true);
+ if (isset($_SERVER['HTTP_X_OC_MTIME'])) {
+ $object->creation_time = new Tinebase_DateTime($_SERVER['HTTP_X_OC_MTIME']);
+ $object->last_modified_time = new Tinebase_DateTime($_SERVER['HTTP_X_OC_MTIME']);
+ Tinebase_Server_WebDAV::getResponse()->setHeader('X-OC-MTime', 'accepted');
+ if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
+ Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " using X-OC-MTIME: {$object->last_modified_time->format(Tinebase_Record_Abstract::ISO8601LONG)} for {$_name}");
+ }
+ }
+ $object->hash = Tinebase_Record_Abstract::generateUID();
+ $object->size = 0;
+ $object->is_deleted = 0;
+ $object->type = $_fileType;
+ $object->preview_count = 0;
+ $this->_fileObjectBackend->update($object);
+ //we can use _treeNodeBackend as we called get further up
+ $treeNode = $this->_treeNodeBackend->update($deletedNode);
+ } else {
- // quick hack for 2014.11 - will be resolved correctly in 2015.11-develop
- if (isset($_SERVER['HTTP_X_OC_MTIME'])) {
- $fileObject->creation_time = new Tinebase_DateTime($_SERVER['HTTP_X_OC_MTIME']);
- $fileObject->last_modified_time = new Tinebase_DateTime($_SERVER['HTTP_X_OC_MTIME']);
- Tinebase_Server_WebDAV::getResponse()->setHeader('X-OC-MTime', 'accepted');
- if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG))
- Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " using X-OC-MTIME: {$fileObject->last_modified_time->format(Tinebase_Record_Abstract::ISO8601LONG)} for {$_name}");
+ $parentNode = $_parentId instanceof Tinebase_Model_Tree_Node ? $_parentId : $this->get($parentId);
- }
+ $fileObject = new Tinebase_Model_Tree_FileObject(array(
+ 'type' => $_fileType,
+ 'contentytype' => null,
+ ));
+ Tinebase_Timemachine_ModificationLog::setRecordMetaData($fileObject, 'create');
+
+ // quick hack for 2014.11 - will be resolved correctly in 2015.11-develop
+ if (isset($_SERVER['HTTP_X_OC_MTIME'])) {
+ $fileObject->creation_time = new Tinebase_DateTime($_SERVER['HTTP_X_OC_MTIME']);
+ $fileObject->last_modified_time = new Tinebase_DateTime($_SERVER['HTTP_X_OC_MTIME']);
+ Tinebase_Server_WebDAV::getResponse()->setHeader('X-OC-MTime', 'accepted');
+ if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
+ Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " using X-OC-MTIME: {$fileObject->last_modified_time->format(Tinebase_Record_Abstract::ISO8601LONG)} for {$_name}");
+ }
- $fileObject = $this->_fileObjectBackend->create($fileObject);
+ }
- $treeNode = new Tinebase_Model_Tree_Node(array(
- 'name' => $_name,
- 'object_id' => $fileObject->getId(),
- 'parent_id' => $parentId,
- 'acl_node' => $parentNode && empty($parentNode->acl_node) ? null : $parentNode->acl_node,
- ));
+ $fileObject = $this->_fileObjectBackend->create($fileObject);
- if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ .
- ' ' . print_r($treeNode->toArray(), true));
+ $treeNode = new Tinebase_Model_Tree_Node(array(
+ 'name' => $_name,
+ 'object_id' => $fileObject->getId(),
+ 'parent_id' => $parentId,
+ 'acl_node' => $parentNode && empty($parentNode->acl_node) ? null : $parentNode->acl_node,
+ ));
- $treeNode = $this->_getTreeNodeBackend()->create($treeNode);
+ if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
+ Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ .
+ ' ' . print_r($treeNode->toArray(), true));
+ }
+
+ $treeNode = $this->_getTreeNodeBackend()->create($treeNode);
+ }
Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId);
$transactionId = null;
$this->_recursiveInheritPropertyUpdate($_node, Tinebase_Model_Tree_Node::XPROPS_REVISION, $newValue, $oldValue, false);
}
- $newNode = $this->_getTreeNodeBackend()->update($_node);
+ /** @var Tinebase_Model_Tree_Node $newNode */
+ $newNode = $this->_getTreeNodeBackend()->update($_node, false);
+
+ if (isset($_node->grants)) {
+ $newNode->grants = $_node->grants;
+ }
$this->_getTreeNodeBackend()->updated($newNode, $currentNodeObject);
* @param string $_property
* @param string $_newValue
* @param string $_oldValue
+ * @param bool $_ignoreACL
*/
- protected function _recursiveInheritPropertyUpdate(Tinebase_Model_Tree_Node $_node, $_property, $_newValue, $_oldValue)
+ protected function _recursiveInheritPropertyUpdate(Tinebase_Model_Tree_Node $_node, $_property, $_newValue, $_oldValue, $_ignoreACL = true)
{
$childIds = $this->getAllChildIds(array($_node->getId()), array(array(
'field' => $_property,
'operator' => 'equals',
'value' => $_oldValue
- )));
+ )), $_ignoreACL);
if (count($childIds) > 0) {
$this->_getTreeNodeBackend()->updateMultiple($childIds, array($_property => $_newValue));
}
$hashes = array();
}
+ // hard delete is ok here
$this->_fileObjectBackend->delete($toDeleteIds);
if (true === $this->_indexingActive) {
Tinebase_Fulltext_Indexer::getInstance()->removeFileContentsFromIndex($toDeleteIds);
$invalidHashes = array();
$created = 0;
$deleted = 0;
- $transactionManager = Tinebase_TransactionManager::getInstance();
foreach($treeNodeBackend->search(
new Tinebase_Model_Tree_Node_Filter(array(
continue;
}
- foreach ($node->available_revisions as $revision) {
+ $availableRevisions = $node->available_revisions;
+ if (!is_array($availableRevisions)) {
+ $availableRevisions = explode(',', $availableRevisions);
+ }
+ foreach ($availableRevisions as $revision) {
if ($node->revision != $revision) {
$treeNodeBackend->setRevision($revision);
try {
return $result;
}
+
+ /**
+ * returns the replication modification logs
+ *
+ * @param $hash
+ * @return array
+ * @throws Tinebase_Exception_AccessDenied
+ */
+ public function getBlob($hash)
+ {
+ if (! Tinebase_Core::getUser()->hasRight('Tinebase', Tinebase_Acl_Rights::REPLICATION)) {
+ throw new Tinebase_Exception_AccessDenied('you do not have access to blobs');
+ }
+
+ $fileObject = new Tinebase_Model_Tree_FileObject(array('hash' => $hash), true);
+ $path = $fileObject->getFilesystemPath();
+ $result = '';
+ if (is_file($path)) {
+ $result = file_get_contents($path);
+ }
+
+ return $result;
+ }
}
'last_modified_time',
'deleted_time'
);
+
+ /**
+ * name of fields that should be omitted from modlog
+ *
+ * @var array list of modlog omit fields
+ */
+ protected $_modlogOmitFields = array('indexed_hash', 'preview_count', 'revision_size', 'available_revisions');
+
+ protected static $_isReplicable = true;
/**
* converts a string or Addressbook_Model_List to a list id
parent::runConvertToRecord();
}
+
+ /**
+ * @param bool $value
+ * @return bool
+ */
+ public static function setReplicable($value)
+ {
+ $return = static::$_isReplicable;
+ static::$_isReplicable = $value;
+ return $return;
+ }
+
+ /**
+ * returns true if this record should be replicated
+ *
+ * @return bool
+ */
+ public function isReplicable()
+ {
+ return static::$_isReplicable && (self::TYPE_FILE === $this->type || self::TYPE_FOLDER === $this->type);
+ }
}
*
* @var array list of modlog omit fields
*/
- protected $_modlogOmitFields = array('hash', 'available_revisions', 'revision_size', 'path', 'indexed_hash');
+ protected $_modlogOmitFields = array('revision', 'contenttype', 'description', 'revision_size', 'indexed_hash',
+ 'hash', 'size', 'preview_count', 'available_revisions', 'path');
/**
* if foreign Id fields should be resolved on search and get from json
return parent::isValid($_throwExceptionOnInvalidData);
}
+ /**
+ * returns true if this record should be replicated
+ *
+ * @return boolean
+ */
+ public function isReplicable()
+ {
+ return $this->type === Tinebase_Model_Tree_FileObject::TYPE_FILE || $this->type ===
+ Tinebase_Model_Tree_FileObject::TYPE_FOLDER;
+ }
}
),
'isIndexed' => array(
'filter' => 'Tinebase_Model_Tree_Node_IsIndexedFilter',
+ ),
+ 'is_deleted' => array(
+ 'filter' => 'Tinebase_Model_Filter_Bool'
)
);
* @return array
*/
public function getFields();
+
+ /**
+ * returns modlog omit fields
+ *
+ * @return array
+ */
+ public function getModlogOmitFields();
}
$this->setApplicationVersion('Tinebase', '10.30');
}
+
+ /**
+ * update to 10.31
+ *
+ * add is_deleted column to tree nodes
+ */
+ public function update_30()
+ {
+ if (! $this->_backend->columnExists('is_deleted', 'tree_nodes')) {
+ $declaration = new Setup_Backend_Schema_Field_Xml('<field>
+ <name>is_deleted</name>
+ <type>boolean</type>
+ <default>false</default>
+ <notnull>true</notnull>
+ </field>');
+ $this->_backend->addCol('tree_nodes', $declaration);
+
+ $this->setTableVersion('tree_nodes', 4);
+ }
+
+ $this->setApplicationVersion('Tinebase', '10.31');
+ }
}
<?xml version="1.0" encoding="utf-8"?>
<application>
<name>Tinebase</name>
- <version>10.30</version>
+ <version>10.31</version>
<tables>
<table>
<name>applications</name>
<table>
<name>tree_nodes</name>
- <version>3</version>
+ <version>4</version>
<declaration>
<field>
<name>id</name>
<type>text</type>
<length>65535</length>
</field>
+ <field>
+ <name>is_deleted</name>
+ <type>boolean</type>
+ <default>false</default>
+ <notnull>true</notnull>
+ </field>
<index>
<name>id</name>
<primary>true</primary>
'creation_time',
'last_modified_by',
'last_modified_time',
- 'is_deleted',
+ //'is_deleted',
'deleted_time',
'deleted_by',
'seq',
return array_keys($result);
}
+ public function fetchBlobFromMaster($hash)
+ {
+ $slaveConfiguration = Tinebase_Config::getInstance()->{Tinebase_Config::REPLICATION_SLAVE};
+ $tine20Url = $slaveConfiguration->{Tinebase_Config::MASTER_URL};
+ $tine20LoginName = $slaveConfiguration->{Tinebase_Config::MASTER_USERNAME};
+ $tine20Password = $slaveConfiguration->{Tinebase_Config::MASTER_PASSWORD};
+
+ // check if we are a replication slave
+ if (empty($tine20Url) || empty($tine20LoginName) || empty($tine20Password)) {
+ return true;
+ }
+
+ $tine20Service = new Zend_Service_Tine20($tine20Url);
+
+ $authResponse = $tine20Service->login($tine20LoginName, $tine20Password);
+ if (!is_array($authResponse) || !isset($authResponse['success']) || $authResponse['success'] !== true) {
+ throw new Tinebase_Exception_AccessDenied('login failed');
+ }
+ unset($authResponse);
+
+ $tinebaseProxy = $tine20Service->getProxy('Tinebase');
+ /** @noinspection PhpUndefinedMethodInspection */
+ $result = $tinebaseProxy->getBlob($hash);
+
+ $fileObject = new Tinebase_Model_Tree_FileObject(array('hash' => $hash), true);
+ $path = $fileObject->getFilesystemPath();
+ if (!is_dir(dirname($path))) {
+ mkdir(dirname($path));
+ }
+ file_put_contents($path, $result);
+ }
+
/**
* @return bool
* @throws Tinebase_Exception_AccessDenied
{
return Filemanager_Controller_Node::getInstance()->get($_id);
}
+
+ public function applyReplicationModificationLog(Tinebase_Model_ModificationLog $_modification)
+ {
+ $treeBackend = Tinebase_FileSystem::getInstance()->_getTreeNodeBackend();
+ switch($_modification->change_type) {
+ case Tinebase_Timemachine_ModificationLog::CREATED:
+ $diff = new Tinebase_Record_Diff(json_decode($_modification->new_value, true));
+ $node = new Tinebase_Model_Tree_Node($diff->diff);
+ $this->_prepareReplicationRecord($node);
+ /**
+ * things that can go wrong:
+ * * name not unique...
+ * * parent_id was deleted
+ * * revisionProps, notificationProps, acl_node
+ */
+ $treeBackend->create($node);
+ break;
+
+ case Tinebase_Timemachine_ModificationLog::UPDATED:
+ $diff = new Tinebase_Record_Diff(json_decode($_modification->new_value, true));
+ /** @var Tinebase_Model_Tree_Node $record */
+ $record = $treeBackend->get($_modification->record_id, true);
+ if (isset($diff->diff['grants'])) {
+ Tinebase_Tree_NodeGrants::getInstance()->getGrantsForRecord($record);
+ }
+ $record->applyDiff($diff);
+ $this->_prepareReplicationRecord($record);
+ $treeBackend->update($record);
+ if (isset($diff->diff['grants']) && $record->acl_node === $record->getId()) {
+ Tinebase_FileSystem::getInstance()->setGrantsForNode($record, $record->grants);
+ //Tinebase_Tree_NodeGrants::getInstance()->setGrants($record);
+ }
+ break;
+
+ case Tinebase_Timemachine_ModificationLog::DELETED:
+ $treeBackend->softDelete(array($_modification->record_id));
+ break;
+
+ default:
+ throw new Tinebase_Exception_UnexpectedValue('change_type ' . $_modification->change_type . ' unknown');
+ }
+ }
+
+ /**
+ * @param Tinebase_Model_Tree_Node $_record
+ */
+ protected function _prepareReplicationRecord(Tinebase_Model_Tree_Node $_record)
+ {
+ // unset properties that are maintained only locally
+ $_record->preview_count = null;
+ }
}
\ No newline at end of file
*/
class Tinebase_Tree_FileObject extends Tinebase_Backend_Sql_Abstract
{
+ use Tinebase_Controller_Record_ModlogTrait;
+
/**
* Table name without prefix
*
protected $_revision = null;
/**
+ * the singleton pattern
+ *
+ * @return Tinebase_Tree_FileObject
+ */
+ public static function getInstance()
+ {
+ return Tinebase_FileSystem::getInstance()->getFileObjectBackend();
+ }
+
+ /**
* the constructor
*
* allowed options:
if (empty($_record->hash)) {
return;
}
-
+
$createRevision = $this->_keepOldRevisions || $_mode === 'create';
- $updateRevision = FALSE;
+ $updateRevision = false;
// do not create a revision if the hash did not change! What point in creating a revision if the file in the filesystem is still the same?
if ($_mode !== 'create') {
/** @var Tinebase_Model_Tree_FileObject $currentRecord */
- $currentRecord = $this->get($_record);
- if ($currentRecord->hash !== NULL && !empty($currentRecord->revision)) {
+ $currentRecord = $this->get($_record, true);
+ if ($currentRecord->hash !== null && !empty($currentRecord->revision)) {
if ($currentRecord->hash === $_record->hash && (int)$currentRecord->size === (int)$_record->size) {
return;
}
- $updateRevision = TRUE;
+ $updateRevision = true;
if (Tinebase_Model_Tree_FileObject::TYPE_FOLDER === $_record->type) {
- $createRevision = FALSE;
+ $createRevision = false;
}
} else {
- $createRevision = TRUE;
+ $createRevision = true;
}
}
-
- if (! $createRevision && ! $updateRevision) {
+
+ if (!$createRevision && !$updateRevision) {
return;
}
+ if (!empty($_record->hash) && is_file($_record->getFilesystemPath())) {
+ if (false === ($_record->size = filesize($_record->getFilesystemPath()))) {
+ $_record->size = 0;
+ }
+ } elseif(empty($_record->size)) {
+ $_record->size = 0;
+ }
+
$data = array(
'creation_time' => Tinebase_DateTime::now()->toString(Tinebase_Record_Abstract::ISO8601LONG),
- 'created_by' => is_object(Tinebase_Core::getUser()) ? Tinebase_Core::getUser()->getId() : null,
- 'hash' => $_record->hash,
- 'size' => $_record->size,
+ 'created_by' => is_object(Tinebase_Core::getUser()) ? Tinebase_Core::getUser()->getId() : null,
+ 'hash' => $_record->hash,
+ 'size' => $_record->size,
'preview_count' => (int)$_record->preview_count,
- 'revision' => false === $createRevision && Tinebase_Model_Tree_FileObject::TYPE_FOLDER === $_record->type ? 1 : $this->_getNextRevision($_record),
+ 'revision' => false === $createRevision && Tinebase_Model_Tree_FileObject::TYPE_FOLDER === $_record->type ? 1 : $this->_getNextRevision($_record),
);
-
+
if ($createRevision) {
$data['id'] = $_record->getId();
$this->_db->insert($this->_tablePrefix . 'tree_filerevisions', $data);
// update total size
$this->_db->update($this->_tablePrefix . $this->_tableName,
array('revision_size' => new Zend_Db_Expr($this->_db->quoteIdentifier('revision_size') . ' + ' . (int)$_record->size)),
- $this->_db->quoteInto($this->_db->quoteIdentifier($this->_tablePrefix . $this->_tableName . '.id') . ' = ?', $_record->getId()));
+ $this->_db->quoteInto($this->_db->quoteIdentifier($this->_tablePrefix . $this->_tableName . '.id') . ' = ?',
+ $_record->getId()));
}
} elseif ($updateRevision) {
);
$this->_db->update($this->_tablePrefix . 'tree_filerevisions', $data, $where);
- if (Tinebase_Model_Tree_FileObject::TYPE_FILE === $_record->type && (int)$_record->revision_size !== (int) $_record->size) {
+ if (Tinebase_Model_Tree_FileObject::TYPE_FILE === $_record->type && (int)$_record->revision_size !== (int)$_record->size) {
// update total size
$this->_db->update($this->_tablePrefix . $this->_tableName,
array('revision_size' => $_record->size),
- $this->_db->quoteInto($this->_db->quoteIdentifier($this->_tablePrefix . $this->_tableName . '.id') . ' = ?', $_record->getId()));
+ $this->_db->quoteInto($this->_db->quoteIdentifier($this->_tablePrefix . $this->_tableName . '.id') . ' = ?',
+ $_record->getId()));
+ }
+ }
+ }
+
+ /**
+ * do something after creation of record
+ *
+ * @param Tinebase_Record_Interface $_newRecord
+ * @param Tinebase_Record_Interface $_recordToCreate
+ * @return void
+ */
+ protected function _inspectAfterCreate(Tinebase_Record_Interface $_newRecord, Tinebase_Record_Interface $_recordToCreate)
+ {
+ $this->_writeModLog($_newRecord, null);
+ Tinebase_Notes::getInstance()->addSystemNote($_newRecord, Tinebase_Core::getUser(), Tinebase_Model_Note::SYSTEM_NOTE_NAME_CREATED);
+ }
+
+ /**
+ * Updates existing entry
+ *
+ * @param Tinebase_Record_Interface $_record
+ * @param boolean $_isReplicable
+ * @throws Tinebase_Exception_Record_Validation|Tinebase_Exception_InvalidArgument
+ * @return Tinebase_Record_Interface Record|NULL
+ */
+ public function update(Tinebase_Record_Interface $_record, $_isReplicable = true)
+ {
+ $oldIsReplicable = Tinebase_Model_Tree_FileObject::setReplicable($_isReplicable);
+
+ $oldRecord = $this->get($_record->getId(), true);
+ $newRecord = parent::update($_record);
+
+ $currentMods = $this->_writeModLog($newRecord, $oldRecord);
+ if (null !== $currentMods && $currentMods->count() > 0) {
+ Tinebase_Notes::getInstance()->addSystemNote($newRecord, Tinebase_Core::getUser(), Tinebase_Model_Note::SYSTEM_NOTE_NAME_CHANGED, $currentMods);
+ }
+
+ Tinebase_Model_Tree_FileObject::setReplicable($oldIsReplicable);
+
+ return $newRecord;
+ }
+
+ /**
+ * @param array $_ids
+ */
+ protected function _inspectBeforeSoftDelete(array $_ids)
+ {
+ if (!empty($_ids)) {
+ foreach($this->getMultiple($_ids) as $object) {
+ $this->_writeModLog(null, $object);
}
}
}
return $stmt->rowCount();
}
+
+ /**
+ * @param Tinebase_Model_ModificationLog $_modification
+ * @throws Tinebase_Exception_UnexpectedValue
+ */
+ public function applyReplicationModificationLog(Tinebase_Model_ModificationLog $_modification)
+ {
+ switch($_modification->change_type) {
+ case Tinebase_Timemachine_ModificationLog::CREATED:
+ $diff = new Tinebase_Record_Diff(json_decode($_modification->new_value, true));
+ $record = new Tinebase_Model_Tree_FileObject($diff->diff);
+ $this->_prepareReplicationRecord($record);
+ $this->create($record);
+ if (Tinebase_Model_Tree_FileObject::TYPE_FILE === $record->type && null !== $record->hash &&
+ !is_file($record->getFilesystemPath())) {
+ Tinebase_Timemachine_ModificationLog::getInstance()->fetchBlobFromMaster($record->hash);
+ }
+ break;
+
+ case Tinebase_Timemachine_ModificationLog::UPDATED:
+ $diff = new Tinebase_Record_Diff(json_decode($_modification->new_value, true));
+ /** @var Tinebase_Model_Tree_FileObject $record */
+ $record = $this->get($_modification->record_id, true);
+ $oldHash = $record->hash;
+ $record->applyDiff($diff);
+ $this->_prepareReplicationRecord($record);
+ if (Tinebase_Model_Tree_FileObject::TYPE_FILE === $record->type && $oldHash !== $record->hash &&
+ null !== $record->hash && !is_file($record->getFilesystemPath())) {
+ Tinebase_Timemachine_ModificationLog::getInstance()->fetchBlobFromMaster($record->hash);
+ }
+ $this->update($record);
+ break;
+
+ case Tinebase_Timemachine_ModificationLog::DELETED:
+ $this->softDelete(array($_modification->record_id));
+ break;
+
+ default:
+ throw new Tinebase_Exception_UnexpectedValue('change_type ' . $_modification->change_type . ' unknown');
+ }
+ }
+
+ /**
+ * @param Tinebase_Model_Tree_FileObject $_record
+ */
+ protected function _prepareReplicationRecord(Tinebase_Model_Tree_FileObject $_record)
+ {
+ // unset properties that are maintained only locally
+ $_record->indexed_hash = null;
+ }
}
*/
public function __construct($_dbAdapter = NULL, $_options = array())
{
- // we don't use modlog here because the name is unique. If the only do a soft delete, it is not possible to create the same node again!
if (isset($_options[Tinebase_Config::FILESYSTEM_ENABLE_NOTIFICATIONS]) && true === $_options[Tinebase_Config::FILESYSTEM_ENABLE_NOTIFICATIONS]) {
$this->_notificationActive = $_options[Tinebase_Config::FILESYSTEM_ENABLE_NOTIFICATIONS];
}
+ if (isset($_options[Tinebase_Config::FILESYSTEM_MODLOGACTIVE]) && true === $_options[Tinebase_Config::FILESYSTEM_MODLOGACTIVE]) {
+ $this->_modlogActive = $_options[Tinebase_Config::FILESYSTEM_MODLOGACTIVE];
+ } else {
+ $this->_omitModLog = true;
+ }
+
+
parent::__construct($_dbAdapter, $_options);
}
* Updates existing entry
*
* @param Tinebase_Record_Interface $_record
+ * @param boolean $_doModLog
* @throws Tinebase_Exception_Record_Validation|Tinebase_Exception_InvalidArgument
* @return Tinebase_Record_Interface Record|NULL
*/
- public function update(Tinebase_Record_Interface $_record, $_doModLog = false)
+ public function update(Tinebase_Record_Interface $_record, $_doModLog = true)
{
- $oldRecord = $this->get($_record->getId());
+ $oldRecord = $this->get($_record->getId(), true);
$newRecord = parent::update($_record);
if (true === $_doModLog) {
$currentMods = $this->_writeModLog($newRecord, $oldRecord);
- if ($currentMods->count() > 0) {
+ if (null !== $currentMods && $currentMods->count() > 0) {
Tinebase_Notes::getInstance()->addSystemNote($newRecord, Tinebase_Core::getUser(), Tinebase_Model_Note::SYSTEM_NOTE_NAME_CHANGED, $currentMods);
}
}
public function updated(Tinebase_Record_Interface $_newRecord, Tinebase_Record_Interface $_oldRecord)
{
$currentMods = $this->_writeModLog($_newRecord, $_oldRecord);
- if ($currentMods->count() > 0) {
+ if (null !== $currentMods && $currentMods->count() > 0) {
Tinebase_Notes::getInstance()->addSystemNote($_newRecord, Tinebase_Core::getUser(), Tinebase_Model_Note::SYSTEM_NOTE_NAME_CHANGED, $currentMods);
if (true === $this->_notificationActive && Tinebase_Model_Tree_FileObject::TYPE_FILE === $_newRecord->type) {
}
/**
+ * Updates multiple entries
+ *
+ * @param array $_ids to update
+ * @param array $_data
+ * @return integer number of affected rows
+ * @throws Tinebase_Exception_Record_Validation|Tinebase_Exception_InvalidArgument
+ */
+ public function updateMultiple($_ids, $_data)
+ {
+ $oldRecords = null;
+ if ($this->_omitModLog === true) {
+ $oldRecords = $this->getMultiple($_ids);
+ }
+
+ $result = parent::updateMultiple($_ids, $_data);
+
+ if (null !== $oldRecords) {
+ foreach ($oldRecords as $oldRecord) {
+ $newRecord = $this->get($oldRecord->getId());
+ $currentMods = $this->_writeModLog($newRecord, $oldRecord);
+ if (null !== $currentMods && $currentMods->count() > 0) {
+ Tinebase_Notes::getInstance()->addSystemNote($newRecord, Tinebase_Core::getUser(),
+ Tinebase_Model_Note::SYSTEM_NOTE_NAME_CHANGED, $currentMods);
+
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * @param array $_ids
+ */
+ protected function _inspectBeforeSoftDelete(array $_ids)
+ {
+ if (!empty($_ids)) {
+ foreach($this->getMultiple($_ids) as $node) {
+ $this->_writeModLog(null, $node);
+ }
+ }
+ }
+
+ /**
* @param Tinebase_Model_Tree_Node $_newRecord
* @param Tinebase_Model_Tree_Node|null $_oldRecord
*/
*
* @param string|Tinebase_Model_Tree_Node $parentId the id of the parent node
* @param string|Tinebase_Model_Tree_Node $childName the name of the child node
+ * @param boolean $getDeleted = false
+ * @param boolean $throw = true
* @throws Tinebase_Exception_NotFound
* @return Tinebase_Model_Tree_Node
*/
- public function getChild($parentId, $childName)
+ public function getChild($parentId, $childName, $getDeleted = false, $throw = true)
{
$parentId = $parentId instanceof Tinebase_Model_Tree_Node ? $parentId->getId() : $parentId;
$childName = $childName instanceof Tinebase_Model_Tree_Node ? $childName->name : $childName;
'value' => $childName
)
), Tinebase_Model_Filter_FilterGroup::CONDITION_AND, array('ignoreAcl' => true));
+ if (true === $getDeleted) {
+ $searchFilter->addFilter(new Tinebase_Model_Filter_Bool('is_deleted', 'equals',
+ Tinebase_Model_Filter_Bool::VALUE_NOTSET));
+ }
$child = $this->search($searchFilter)->getFirstRecord();
if (!$child || $childName !== $child->name) {
- throw new Tinebase_Exception_NotFound('child: ' . $childName . ' not found!');
+ if (true === $throw) {
+ throw new Tinebase_Exception_NotFound('child: ' . $childName . ' not found!');
+ }
+ return null;
}
return $child;
/**
* @param Tinebase_Tree_FileObject $_fileObjectBackend
* @param array $_folderIds
- * @param bool
+ * @return bool
*/
protected function _recalculateFolderSize(Tinebase_Tree_FileObject $_fileObjectBackend, array $_folderIds)
{