Tinebase_Config: add Quota configuration
[tine20] / tests / tine20 / Filemanager / Frontend / JsonTests.php
1 <?php
2 /**
3  * Tine 2.0 - http://www.tine20.org
4  *
5  * @package     Filemanager
6  * @license     http://www.gnu.org/licenses/agpl.html
7  * @copyright   Copyright (c) 2011-2017 Metaways Infosystems GmbH (http://www.metaways.de)
8  * @author      Philipp Schüle <p.schuele@metaways.de>
9  *
10  */
11
12 /**
13  * Test class for Filemanager_Frontend_Json
14  *
15  * @package     Filemanager
16  */
17 class Filemanager_Frontend_JsonTests extends TestCase
18 {
19     /**
20      * @var array test objects
21      */
22     protected $_objects = array();
23     
24     /**
25      * uit
26      *
27      * @var Filemanager_Frontend_Json
28      */
29     protected $_json = null;
30     
31     /**
32      * fs controller
33      *
34      * @var Tinebase_FileSystem
35      */
36     protected $_fsController;
37     
38     /**
39      * filemanager app
40      *
41      * @var Tinebase_Model_Application
42      */
43     protected $_application;
44     
45     /**
46      * personal container
47      *
48      * @var Tinebase_Model_Container
49      */
50     protected $_personalContainer;
51     
52     /**
53      * shared container
54      *
55      * @var Tinebase_Model_Container
56      */
57     protected $_sharedContainer;
58     
59     /**
60      * other user container
61      *
62      * @var Tinebase_Model_Container
63      */
64     protected $_otherUserContainer;
65
66     /**
67      * folder paths to be deleted
68      *
69      * @var array
70      */
71     protected $_rmDir = array();
72
73     protected $_oldModLog = null;
74     
75     /**
76      * Sets up the fixture.
77      * This method is called before a test is executed.
78      *
79      * @access protected
80      */
81     protected function setUp()
82     {
83         parent::setUp();
84
85         $this->_oldModLog = Tinebase_Core::getConfig()->{Tinebase_Config::FILESYSTEM}->{Tinebase_Config::FILESYSTEM_MODLOGACTIVE};
86         Tinebase_Core::getConfig()->{Tinebase_Config::FILESYSTEM}->{Tinebase_Config::FILESYSTEM_MODLOGACTIVE} = true;
87         $this->_fsController = Tinebase_FileSystem::getInstance();
88         $this->_fsController->resetBackends();
89         $this->_application = Tinebase_Application::getInstance()->getApplicationByName('Filemanager');
90         $this->_rmDir = array();
91
92         // make sure account root node exists
93         $this->_getPersonalFilemanagerContainer();
94     }
95     
96     /**
97      * Tears down the fixture
98      * This method is called after a test is executed.
99      *
100      * @access protected
101      */
102     protected function tearDown()
103     {
104         parent::tearDown();
105
106         if (count($this->_rmDir) > 0) {
107             foreach ($this->_rmDir as $dir) {
108                 $this->_getUit()->deleteNodes($dir);
109             }
110         }
111
112         Tinebase_Core::getConfig()->{Tinebase_Config::FILESYSTEM}->{Tinebase_Config::FILESYSTEM_MODLOGACTIVE} = $this->_oldModLog;
113
114         Tinebase_FileSystem::getInstance()->resetBackends();
115         Tinebase_FileSystem::getInstance()->clearStatCache();
116         Tinebase_FileSystem::getInstance()->clearDeletedFilesFromFilesystem();
117         
118         $this->_personalContainer  = null;
119         $this->_sharedContainer    = null;
120         $this->_otherUserContainer = null;
121     }
122
123     /**
124      * @return Filemanager_Frontend_Json
125      */
126     protected function _getUit()
127     {
128         if ($this->_json === null) {
129             $this->_json = new Filemanager_Frontend_Json();
130         }
131         return $this->_json;
132     }
133
134     /**
135      * test search nodes (personal)
136      */
137     public function testSearchRoot()
138     {
139         $filter = array(array(
140             'field'    => 'path',
141             'operator' => 'equals',
142             'value'    => '/'
143         ));
144         $result = $this->_getUit()->searchNodes($filter, array());
145         $this->_assertRootNodes($result);
146     }
147     
148     /**
149      * assert 3 root nodes
150      *
151      * @param array $searchResult
152      */
153     protected function _assertRootNodes($searchResult)
154     {
155         $translate = Tinebase_Translation::getTranslation('Filemanager');
156         $this->assertEquals(3, $searchResult['totalcount'], 'did not get root nodes: ' . print_r($searchResult, true));
157         $this->assertEquals(array(
158             'id'             => 'myUser',
159             'path'           => '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' .
160                 Tinebase_Core::getUser()->accountLoginName,
161             'name'           => $translate->_('My folders'),
162             'type'           => 'folder',
163             'grants'         => array(),
164             'account_grants' => array(
165                 'account_id' => Tinebase_Core::getUser()->getId(),
166                 'account_type' => Tinebase_Acl_Rights::ACCOUNT_TYPE_USER,
167                 Tinebase_Model_Grants::GRANT_READ => true,
168                 Tinebase_Model_Grants::GRANT_ADD => true,
169                 Tinebase_Model_Grants::GRANT_EDIT => false,
170                 Tinebase_Model_Grants::GRANT_DELETE => false,
171                 Tinebase_Model_Grants::GRANT_EXPORT => true,
172                 Tinebase_Model_Grants::GRANT_SYNC => true,
173                 Tinebase_Model_Grants::GRANT_ADMIN => false,
174                 Tinebase_Model_Grants::GRANT_FREEBUSY => false,
175                 Tinebase_Model_Grants::GRANT_PRIVATE => false,
176                 Tinebase_Model_Grants::GRANT_DOWNLOAD => false,
177                 Tinebase_Model_Grants::GRANT_PUBLISH => false,
178             ),
179             'tags'           => array(),
180             'revisionProps'  => array(),
181             'notificationProps' => array(),
182             ), $searchResult['results'][0], 'my user folder mismatch');
183         $this->assertEquals(array(
184             'id'    => Tinebase_Model_Container::TYPE_SHARED,
185             'path'  => '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED,
186             'name' => $translate->_('Shared folders'),
187             'type' => 'folder',
188             'grants'         => array(),
189             'account_grants' => array(
190                 'account_id' => Tinebase_Core::getUser()->getId(),
191                 'account_type' => Tinebase_Acl_Rights::ACCOUNT_TYPE_USER,
192                 Tinebase_Model_Grants::GRANT_READ => true,
193                 Tinebase_Model_Grants::GRANT_ADD => true,
194                 Tinebase_Model_Grants::GRANT_EDIT => false,
195                 Tinebase_Model_Grants::GRANT_DELETE => false,
196                 Tinebase_Model_Grants::GRANT_EXPORT => true,
197                 Tinebase_Model_Grants::GRANT_SYNC => true,
198                 Tinebase_Model_Grants::GRANT_ADMIN => false,
199                 Tinebase_Model_Grants::GRANT_FREEBUSY => false,
200                 Tinebase_Model_Grants::GRANT_PRIVATE => false,
201                 Tinebase_Model_Grants::GRANT_DOWNLOAD => false,
202                 Tinebase_Model_Grants::GRANT_PUBLISH => false,
203             ),
204             'tags' => array(),
205             'revisionProps'  => array(),
206             'notificationProps' => array(),
207         ), $searchResult['results'][1], 'shared folder mismatch');
208         $this->assertEquals(array(
209             'id'    => Tinebase_Model_Container::TYPE_OTHERUSERS,
210             'path'  => '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL,
211             'name' => $translate->_('Other users folders'),
212             'type' => 'folder',
213             'grants'         => array(),
214             'account_grants' => array(
215                 'account_id' => Tinebase_Core::getUser()->getId(),
216                 'account_type' => Tinebase_Acl_Rights::ACCOUNT_TYPE_USER,
217                 Tinebase_Model_Grants::GRANT_READ => true,
218                 Tinebase_Model_Grants::GRANT_ADD => false,
219                 Tinebase_Model_Grants::GRANT_EDIT => false,
220                 Tinebase_Model_Grants::GRANT_DELETE => false,
221                 Tinebase_Model_Grants::GRANT_EXPORT => false,
222                 Tinebase_Model_Grants::GRANT_SYNC => false,
223                 Tinebase_Model_Grants::GRANT_ADMIN => false,
224                 Tinebase_Model_Grants::GRANT_FREEBUSY => false,
225                 Tinebase_Model_Grants::GRANT_PRIVATE => false,
226                 Tinebase_Model_Grants::GRANT_DOWNLOAD => false,
227                 Tinebase_Model_Grants::GRANT_PUBLISH => false,
228             ),
229             'tags' => array(),
230             'revisionProps'  => array(),
231             'notificationProps' => array(),
232         ), $searchResult['results'][2], 'other user folder mismatch');
233     }
234     
235     /**
236      * test search nodes (personal)
237      */
238     public function testSearchPersonalNodes()
239     {
240         $this->_setupTestPath(Tinebase_FileSystem::FOLDER_TYPE_PERSONAL);
241
242         $path = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/'
243             . Tinebase_Core::getUser()->accountLoginName . '/' . $this->_getPersonalFilemanagerContainer()->name;
244         $filter = array(array(
245             'field'    => 'path',
246             'operator' => 'equals',
247             'value'    => $path
248         ));
249         $result = $this->_searchHelper($filter, 'unittestdir_personal');
250         // check correct path resolving
251         $node = $this->_getNodeByNameFromResult('unittestdir_personal', $result);
252         self::assertEquals($path . '/unittestdir_personal', $node['path']);
253     }
254     
255     /**
256      * search node helper
257      *
258      * @param array $_filter
259      * @param string $_expectedName
260      * @return array search result
261      */
262     protected function _searchHelper($_filter, $_expectedName, $_toplevel = false, $_checkAccountGrants = true)
263     {
264         $result = $this->_getUit()->searchNodes($_filter, array('sort' => 'size'));
265         
266         $this->assertGreaterThanOrEqual(1, $result['totalcount'], 'expected at least one entry');
267         $node = $this->_getNodeByNameFromResult($_expectedName, $result);
268         if ($_toplevel) {
269             $found = false;
270             foreach ($result['results'] as $container) {
271                 // toplevel containers are resolved (array structure below [name])
272                 if ($_expectedName == $container['name']) {
273                     $found = true;
274                     if ($_checkAccountGrants) {
275                         $this->assertTrue(isset($container['account_grants']));
276                         $this->assertEquals(Tinebase_Core::getUser()->getId(),
277                             $container['account_grants']['account_id']);
278                     }
279                 }
280             }
281             $this->assertTrue($found, 'container not found: ' . print_r($result['results'], true));
282         } else {
283             self::assertNotNull($node);
284         }
285
286         if ($_checkAccountGrants) {
287             $this->assertTrue(isset($node['account_grants']), 'account grants missing');
288             $this->assertEquals(Tinebase_Core::getUser()->getId(), $node['account_grants']['account_id']);
289         }
290         
291         return $result;
292     }
293
294     protected function _getNodeByNameFromResult($_expectedName, $_result)
295     {
296         self::assertTrue(isset($_result['results']));
297         foreach ($_result['results'] as $node) {
298             if ($node['name'] === $_expectedName) {
299                 return $node;
300             }
301         }
302
303         return null;
304     }
305     
306     /**
307      * test search nodes (shared)
308      */
309     public function testSearchSharedNodes()
310     {
311         $this->_setupTestPath(Tinebase_FileSystem::FOLDER_TYPE_SHARED);
312         
313         $filter = array(array(
314             'field'    => 'path',
315             'operator' => 'equals',
316             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED . '/' . $this->_getSharedContainer()->name
317         ));
318         $this->_searchHelper($filter, 'unittestdir_shared');
319     }
320     
321     /**
322      * test search nodes (other)
323      */
324     public function testSearchOtherUsersNodes()
325     {
326         $this->_setupTestPath(Tinebase_Model_Container::TYPE_OTHERUSERS);
327         $filter = array(array(
328             'field'    => 'path',
329             'operator' => 'equals',
330             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/sclever/' .
331                 $this->_getOtherUserContainer()->name
332         ));
333         $this->_searchHelper($filter, 'unittestdir_other');
334     }
335     
336     /**
337      * search top level containers of user
338      * 
339      * @see 0007400: Newly created directories disappear
340      */
341     public function testSearchTopLevelContainersOfUser()
342     {
343         $filter = array(array(
344             'field'    => 'path', 
345             'operator' => 'equals', 
346             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName
347         ));
348         $this->_searchHelper($filter, $this->_getPersonalFilemanagerContainer()->name, true);
349         
350         $another = $this->testCreateContainerNodeInPersonalFolder();
351         $this->_searchHelper($filter, $another['name'], true);
352     }
353
354     /**
355      * search shared top level containers 
356      */
357     public function testSearchSharedTopLevelContainers()
358     {
359         $this->_setupTestPath(Tinebase_FileSystem::FOLDER_TYPE_SHARED);
360         
361         $filter = array(array(
362             'field'    => 'path', 
363             'operator' => 'equals', 
364             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED
365         ));
366         $this->_searchHelper($filter, $this->_getSharedContainer()->name, true);
367     }
368
369     /**
370      * search top level containers of other users
371      */
372     public function testSearchTopLevelContainersOfOtherUsers()
373     {
374         $this->_getOtherUserContainer();
375         
376         $filter = array(
377             array(
378                 'field'    => 'path', 
379                 'operator' => 'equals', 
380                 'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL
381             )
382         );
383         $result = $this->_searchHelper(
384             $filter,
385             $this->_personas['sclever']->accountDisplayName,
386             /* $_toplevel */ false,
387             /* $_checkAccountGrants */ false
388         );
389         // make sure, own user is not in other users
390         $found = false;
391         foreach ($result['results'] as $node) {
392             if ($node['path'] === '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName) {
393                 $found = true;
394             }
395         }
396         self::assertFalse($found, 'own personal node found! ' . print_r($result['results'], true));
397         // check correct path resolving
398         $node = $this->_getNodeByNameFromResult($this->_personas['sclever']->accountDisplayName, $result);
399         $path = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . $this->_personas['sclever']->accountDisplayName;
400         self::assertEquals($path, $node['path']);
401         self::assertEquals(1, $result['totalcount'],
402             'only expected sclever personal folder in result. got: ' . print_r($result['results'], true));
403     }
404
405     /**
406      * search containers of other user
407      */
408     public function testSearchContainersOfOtherUser()
409     {
410         $this->_setupTestPath(Tinebase_Model_Container::TYPE_OTHERUSERS);
411         
412         $filter = array(array(
413             'field'    => 'path', 
414             'operator' => 'equals', 
415             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/sclever'
416         ), array(
417             'field'    => 'creation_time', 
418             'operator' => 'within', 
419             'value'    => 'weekThis',
420         ));
421         $result = $this->_searchHelper($filter, $this->_getOtherUserContainer()->name, true);
422
423         $expectedPath = $filter[0]['value'] . '/' . $this->_getOtherUserContainer()->name;
424         $node = $this->_getNodeByNameFromResult($this->_getOtherUserContainer()->name, $result);
425         self::assertNotNull($node);
426         self::assertEquals($expectedPath, $node['path'], 'node path mismatch');
427         self::assertEquals($filter[0]['value'], $result['filter'][0]['value']['path'], 'filter path mismatch');
428     }
429
430     /**
431      * testSearchWithInvalidPath
432      * 
433      * @see 0007110: don't show exception for invalid path filters
434      */
435     public function testSearchWithInvalidPath()
436     {
437         // wrong user
438         $filter = array(array(
439             'field'    => 'path', 
440             'operator' => 'equals', 
441             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/xyz'
442         ));
443         
444         $result = $this->_getUit()->searchNodes($filter, array());
445         $this->_assertRootNodes($result);
446         
447         // wrong type
448         $filter[0]['value'] = '/lala';
449         $result = $this->_getUit()->searchNodes($filter, array());
450         $this->_assertRootNodes($result);
451
452         // no path filter
453         $result = $this->_getUit()->searchNodes(array(), array());
454         $this->_assertRootNodes($result);
455     }
456     
457     /**
458      * create container in personal folder
459      *
460      * @return array created node
461      */
462     public function testCreateContainerNodeInPersonalFolder($containerName = 'testcontainer')
463     {
464         $testPath = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName
465             . '/' . $containerName;
466         $result = $this->_getUit()->createNodes($testPath, Tinebase_Model_Tree_FileObject::TYPE_FOLDER, array(), false);
467         $createdNode = $result[0];
468         
469         $this->assertTrue(isset($createdNode['name']));
470         $this->assertEquals($containerName, $createdNode['name']);
471         $this->assertEquals(Tinebase_Core::getUser()->getId(), $createdNode['created_by']['accountId']);
472         
473         return $createdNode;
474     }
475
476     /**
477      * create container with bad name
478      * 
479      * @see 0006524: Access Problems via Webdav
480      */
481     public function testCreateContainerNodeWithBadName()
482     {
483         $testPath = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testcon/tainer';
484         
485         $this->setExpectedException('Tinebase_Exception_NotFound');
486         $result = $this->_getUit()->createNodes($testPath, Tinebase_Model_Tree_FileObject::TYPE_FOLDER, array(), false);
487     }
488
489     /**
490      * create container in shared folder
491      *
492      * @param string $_name
493      * @return array created node
494      */
495     public function testCreateContainerNodeInSharedFolder($_name = 'testcontainer')
496     {
497         $testPath = '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED . '/' . $_name;
498         $result = $this->_getUit()->createNode($testPath, Tinebase_Model_Tree_FileObject::TYPE_FOLDER, null, false);
499         $createdNode = $result;
500         
501         $this->assertEquals($_name, $createdNode['name']);
502         $this->assertEquals($testPath, $createdNode['path']);
503         
504         return $createdNode;
505     }
506
507     /**
508      * testCreateFileNodes
509      *
510      * @param bool $_addData
511      * @return array file paths
512      */
513     public function testCreateFileNodes($_addData = false)
514     {
515         $sharedContainerNode = $this->testCreateContainerNodeInSharedFolder();
516         
517         $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($sharedContainerNode['path']);
518         
519         $filepaths = array(
520             $sharedContainerNode['path'] . '/file1',
521             $sharedContainerNode['path'] . '/file2',
522         );
523
524         $tempFileIds = array();
525         if (true === $_addData) {
526             for ($i = 0; $i < 2; ++$i) {
527                 $tempPath = Tinebase_TempFile::getTempPath();
528                 $tempFileIds[] = Tinebase_TempFile::getInstance()->createTempFile($tempPath);
529                 file_put_contents($tempPath, 'someData');
530             }
531         }
532
533         $result = $this->_getUit()->createNodes($filepaths, Tinebase_Model_Tree_FileObject::TYPE_FILE, $tempFileIds, false);
534         
535         $this->assertEquals(2, count($result));
536         $this->assertEquals('file1', $result[0]['name']);
537         $this->assertEquals(Tinebase_Model_Tree_FileObject::TYPE_FILE, $result[0]['type']);
538         $this->assertEquals('file2', $result[1]['name']);
539         $this->assertEquals(Tinebase_Model_Tree_FileObject::TYPE_FILE, $result[1]['type']);
540         
541         return $filepaths;
542     }
543
544
545     /**
546      * testCreateFileNodeInPersonalRoot
547      */
548     public function testCreateFileNodeInPersonalRoot()
549     {
550         $testPath = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL
551             . '/' . Tinebase_Core::getUser()->accountLoginName
552             . '/' . 'file1';
553
554
555         $tempPath = Tinebase_TempFile::getTempPath();
556         $tempFileIds = array(Tinebase_TempFile::getInstance()->createTempFile($tempPath));
557         file_put_contents($tempPath, 'someData');
558
559         try {
560             $result = $this->_getUit()->createNodes(array($testPath), Tinebase_Model_Tree_FileObject::TYPE_FILE,
561                 $tempFileIds, false);
562             self::fail('it is not allowed to create new files here');
563         } catch (Tinebase_Exception_AccessDenied $tead) {
564             self::assertContains('No permission to add nodes in path', $tead->getMessage());
565         }
566     }
567
568     /**
569      * testMoveFileNode
570      */
571     public function testMoveFileNode()
572     {
573         $filePaths = $this->testCreateFileNodes(true);
574         $secondFolderNode = $this->testCreateContainerNodeInSharedFolder('fooContainer');
575
576         $file0Path = Filemanager_Controller_Node::getInstance()->addBasePath($filePaths[0]);
577         $targetPath = Filemanager_Controller_Node::getInstance()->addBasePath($secondFolderNode['path']);
578
579         $parentFolder = $this->_fsController->stat(dirname($file0Path));
580         static::assertEquals(16, $parentFolder->size, 'two files with 8 bytes each created, excpected 16 bytes folder size');
581         static::assertEquals(0, $secondFolderNode['size'], 'expect new folder to be empty');
582
583         $this->_getUit()->moveNodes($file0Path, $targetPath, false);
584
585         $parentFolder = $this->_fsController->stat(dirname($file0Path));
586         static::assertEquals(8, $parentFolder->size, 'one file with 8 bytes expected');
587         $secondFolderNode = $this->_fsController->stat($targetPath);
588         static::assertEquals(8, $secondFolderNode->size, 'one file with 8 bytes expected');
589
590     }
591
592     /**
593     * testCreateFileNodeWithUTF8Filenames
594     * 
595     * @see 0006068: No umlauts at beginning of file names / https://forge.tine20.org/mantisbt/view.php?id=6068
596     * @see 0006150: Problem loading files with russian file names / https://forge.tine20.org/mantisbt/view.php?id=6150
597     * 
598     * @return array first created node
599     */
600     public function testCreateFileNodeWithUTF8Filenames()
601     {
602         $personalContainerNode = $this->testCreateContainerNodeInPersonalFolder();
603         
604         $testPaths = array($personalContainerNode['path'] . '/ütest.eml', $personalContainerNode['path'] . '/Безимени.txt');
605         $result = $this->_getUit()->createNodes($testPaths, Tinebase_Model_Tree_FileObject::TYPE_FILE, array(), false);
606     
607         $this->assertEquals(2, count($result));
608         $this->assertEquals('ütest.eml', $result[0]['name']);
609         $this->assertEquals('Безимени.txt', $result[1]['name']);
610         $this->assertEquals(Tinebase_Model_Tree_FileObject::TYPE_FILE, $result[0]['type']);
611         
612         return $result[0];
613     }
614     
615     /**
616      * testCreateFileNodeWithTempfile
617      * 
618      * @return array node
619      */
620     public function testCreateFileNodeWithTempfile()
621     {
622         $sharedContainerNode = $this->testCreateContainerNodeInSharedFolder();
623         
624         $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($sharedContainerNode['path']);
625         
626         $filepath = $sharedContainerNode['path'] . '/test.txt';
627         // create empty file first (like the js frontend does)
628         $result = $this->_getUit()->createNode($filepath, Tinebase_Model_Tree_FileObject::TYPE_FILE, array(), false);
629
630         $tempFileBackend = new Tinebase_TempFile();
631         $tempFile = $tempFileBackend->createTempFile(dirname(dirname(__FILE__)) . '/files/test.txt');
632         $result = $this->_getUit()->createNode($filepath, Tinebase_Model_Tree_FileObject::TYPE_FILE, $tempFile->getId(), true);
633         
634         $this->assertEquals('text/plain', $result['contenttype'], print_r($result, true));
635         $this->assertEquals(17, $result['size']);
636         
637         return $result;
638     }
639     
640     /**
641      * testCreateFileCountTempDir
642      * 
643      * @see 0007370: Unable to upload files
644      */
645     public function testCreateFileCountTempDir()
646     {
647         $tmp = Tinebase_Core::getTempDir();
648         $filecountInTmpBefore = count(scandir($tmp));
649         
650         $this->testCreateFileNodeWithTempfile();
651         
652         // check if tempfile has been created in tine20 tempdir
653         $filecountInTmpAfter = count(scandir($tmp));
654         
655         $this->assertEquals($filecountInTmpBefore + 1, $filecountInTmpAfter, '1 tempfiles should have been created');
656     }
657
658     /**
659      * testCreateDirectoryNodesInShared
660      * 
661      * @return array dir paths
662      */
663     public function testCreateDirectoryNodesInShared()
664     {
665         $sharedContainerNode = $this->testCreateContainerNodeInSharedFolder();
666         
667         $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($sharedContainerNode['path']);
668         
669         $dirpaths = array(
670             $sharedContainerNode['path'] . '/dir1',
671             $sharedContainerNode['path'] . '/dir2',
672         );
673         $result = $this->_getUit()->createNodes($dirpaths, Tinebase_Model_Tree_FileObject::TYPE_FOLDER, array(), false);
674         
675         $this->assertEquals(2, count($result));
676         $this->assertEquals('dir1', $result[0]['name']);
677         $this->assertEquals('dir2', $result[1]['name']);
678         
679         $filter = array(array(
680             'field'    => 'path', 
681             'operator' => 'equals', 
682             'value'    => $sharedContainerNode['path']
683         ), array(
684             'field'    => 'type', 
685             'operator' => 'equals', 
686             'value'    => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
687         ));
688         $result = $this->_getUit()->searchNodes($filter, array('sort' => 'creation_time'));
689         $this->assertEquals(2, $result['totalcount']);
690         
691         return $dirpaths;
692     }
693
694     /**
695      * testCreateDirectoryNodesInPersonal
696      * 
697      * @return array dir paths
698      */
699     public function testCreateDirectoryNodesInPersonal()
700     {
701         $personalContainerNode = $this->testCreateContainerNodeInPersonalFolder();
702         
703         $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($personalContainerNode['path']);
704         
705         $dirpaths = array(
706             $personalContainerNode['path'] . '/dir1',
707             $personalContainerNode['path'] . '/dir2',
708         );
709         $result = $this->_getUit()->createNodes($dirpaths, Tinebase_Model_Tree_FileObject::TYPE_FOLDER, array(), false);
710         
711         $this->assertEquals(2, count($result));
712         $this->assertEquals('dir1', $result[0]['name']);
713         $this->assertEquals('dir2', $result[1]['name']);
714         
715         $filter = array(array(
716             'field'    => 'path', 
717             'operator' => 'equals', 
718             'value'    => $personalContainerNode['path']
719         ), array(
720             'field'    => 'type', 
721             'operator' => 'equals', 
722             'value'    => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
723         ));
724         $result = $this->_getUit()->searchNodes($filter, array('sort' => 'contenttype'));
725         $this->assertEquals(2, $result['totalcount']);
726         
727         return $dirpaths;
728     }
729     
730     /**
731      * testCreateDirectoryNodeInPersonalWithSameNameAsOtherUsersDir
732      * 
733      * @see 0008044: could not create a personal folder with the name of a folder of another user
734      */
735     public function testCreateDirectoryNodeInPersonalWithSameNameAsOtherUsersDir()
736     {
737         $this->testCreateContainerNodeInPersonalFolder();
738         
739         $personas = Zend_Registry::get('personas');
740         Tinebase_Core::set(Tinebase_Core::USER, $personas['sclever']);
741         $personalContainerNodeOfsclever = $this->testCreateContainerNodeInPersonalFolder();
742         
743         $this->assertEquals('/personal/sclever/testcontainer', $personalContainerNodeOfsclever['path']);
744     }
745
746     /**
747      * testUpdateNodeWithCustomfield
748      *
749      * ·@see 0009292: Filemanager Custom Fields not saved
750      */
751     public function testUpdateNodeWithCustomfield()
752     {
753         $cf = $this->_createCustomfield('fmancf', 'Filemanager_Model_Node');
754         $personalContainerNode = $this->testCreateContainerNodeInPersonalFolder();
755
756         $personalContainerNode = $this->_getUit()->getNode($personalContainerNode['id']);
757         $personalContainerNode['customfields'][$cf->name] = 'cf value';
758         $personalContainerNode['revisionProps']['nodeId'] = $personalContainerNode['id'];
759         $personalContainerNode['revisionProps']['keep'] = true;
760         $personalContainerNode['revisionProps']['keepNum'] = 3;
761         $personalContainerNode['revisionProps']['keepMonth'] = 4;
762         $updatedNode = $this->_getUit()->saveNode($personalContainerNode);
763
764         static::assertTrue(isset($updatedNode['customfields']) && isset($updatedNode['customfields'][$cf->name]),
765             'no customfields in record');
766         static::assertEquals($personalContainerNode['customfields'][$cf->name],
767             $updatedNode['customfields'][$cf->name]);
768
769         static::assertTrue(isset($updatedNode['revisionProps']) && isset($updatedNode['revisionProps']['keep']) &&
770             isset($updatedNode['revisionProps']['keepNum']) && isset($updatedNode['revisionProps']['keepMonth']),
771             'revisionProps not saved: ' . print_r($updatedNode, true));
772         static::assertEquals($personalContainerNode['revisionProps']['nodeId'], $personalContainerNode['id']);
773         static::assertEquals($personalContainerNode['revisionProps']['keep'], true);
774         static::assertEquals($personalContainerNode['revisionProps']['keepNum'], 3);
775         static::assertEquals($personalContainerNode['revisionProps']['keepMonth'], 4);
776     }
777     
778     /**
779      * testRenameDirectoryNodeInPersonalToSameNameAsOtherUsersDir
780      *
781      * @see 0008046: Rename personal folder to personal folder of another user
782      */
783     public function testRenameDirectoryNodeInPersonalToSameNameAsOtherUsersDir()
784     {
785         $personalContainerNode = $this->testCreateContainerNodeInPersonalFolder();
786         
787         $personas = Zend_Registry::get('personas');
788         Tinebase_Core::set(Tinebase_Core::USER, $personas['sclever']);
789         $personalContainerNodeOfsclever = $this->testCreateContainerNodeInPersonalFolder('testcontainer2');
790         
791         $this->assertEquals('/personal/sclever/testcontainer2', $personalContainerNodeOfsclever['path']);
792         
793         // rename
794         $newPath = '/personal/sclever/testcontainer';
795         $result = $this->_getUit()->moveNodes(array($personalContainerNodeOfsclever['path']), array($newPath), false);
796         $this->assertEquals(1, count($result));
797         $this->assertEquals($newPath, $result[0]['path']);
798     }
799     
800     /**
801      * testCopyFolderNodes
802      */
803     public function testCopyFolderNodesToFolder()
804     {
805         $dirsToCopy = $this->testCreateDirectoryNodesInShared();
806         $targetNode = $this->testCreateContainerNodeInPersonalFolder();
807         
808         $result = $this->_getUit()->copyNodes($dirsToCopy, $targetNode['path'], false);
809         $this->assertEquals(2, count($result));
810         $this->assertEquals($targetNode['path'] . '/dir1', $result[0]['path']);
811     }
812
813     /**
814      * testCopyContainerNode
815      */
816     public function testCopyContainerNode()
817     {
818         $sharedContainerNode = $this->testCreateContainerNodeInSharedFolder();
819         $target = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName;
820         $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($target . '/testcontainer');
821         $result = $this->_getUit()->copyNodes($sharedContainerNode['path'], $target, false);
822         $this->assertEquals(1, count($result));
823         $this->assertTrue(isset($result[0]['name']), print_r($result, true));
824         $this->assertEquals('testcontainer', $result[0]['name']);
825     }
826     
827     /**
828      * testCopyFileNodesToFolder
829      * 
830      * @return array target node
831      */
832     public function testCopyFileNodesToFolder()
833     {
834         $filesToCopy = $this->testCreateFileNodes();
835         $targetNode = $this->testCreateContainerNodeInPersonalFolder();
836         
837         $result = $this->_getUit()->copyNodes($filesToCopy, $targetNode['path'], false);
838         $this->assertEquals(2, count($result));
839         $this->assertEquals($targetNode['path'] . '/file1', $result[0]['path']);
840         
841         return $targetNode;
842     }
843
844     /**
845      * testCopyFolderWithNodes
846      */
847     public function testCopyFolderWithNodes()
848     {
849         $filesToCopy = $this->testCreateFileNodes();
850         $target = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName;
851         
852         $result = $this->_getUit()->copyNodes(
853             '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED . '/testcontainer',
854             $target, 
855             false
856         );
857         
858         $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($target . '/testcontainer');
859         $this->assertEquals(1, count($result));
860
861         $filter = array(array(
862             'field'    => 'path', 
863             'operator' => 'equals', 
864             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testcontainer',
865         ), array(
866             'field'    => 'type', 
867             'operator' => 'equals', 
868             'value'    => Tinebase_Model_Tree_FileObject::TYPE_FILE,
869         ));
870         $result = $this->_getUit()->searchNodes($filter, array());
871         $this->assertEquals(2, $result['totalcount']);
872     }
873     
874     /**
875      * testCopyFileWithContentToFolder
876      */
877     public function testCopyFileWithContentToFolder()
878     {
879         $fileToCopy = $this->testCreateFileNodeWithTempfile();
880         $targetNode = $this->testCreateContainerNodeInPersonalFolder();
881         
882         $result = $this->_getUit()->copyNodes($fileToCopy['path'], $targetNode['path'], false);
883         $this->assertEquals(1, count($result));
884         $this->assertEquals($targetNode['path'] . '/test.txt', $result[0]['path']);
885         $this->assertEquals('text/plain', $result[0]['contenttype']);
886     }
887     
888     /**
889      * testCopyFileNodeToFileExisting
890      */
891     public function testCopyFileNodeToFileExisting()
892     {
893         $filesToCopy = $this->testCreateFileNodes();
894         $file1 = $filesToCopy[0];
895         $file2 = $filesToCopy[1];
896         
897         $this->setExpectedException('Filemanager_Exception_NodeExists');
898         $result = $this->_getUit()->copyNodes(array($file1), array($file2), false);
899     }
900     
901     /**
902      * testCopyFileNodeToFileExistingCatchException
903      */
904     public function testCopyFileNodeToFileExistingCatchException()
905     {
906         $filesToCopy = $this->testCreateFileNodes();
907         $file1 = $filesToCopy[0];
908         $file2 = $filesToCopy[1];
909         
910         try {
911             $result = $this->_getUit()->copyNodes(array($file1), array($file2), false);
912         } catch (Filemanager_Exception_NodeExists $fene) {
913             $info = $fene->toArray();
914             $this->assertEquals(1, count($info['existingnodesinfo']));
915             return;
916         }
917         
918         $this->fail('An expected exception has not been raised.');
919     }
920     
921     /**
922      * testMoveFolderNodesToFolder
923      */
924     public function testMoveFolderNodesToFolder()
925     {
926         $dirsToMove = $this->testCreateDirectoryNodesInShared();
927         $targetNode = $this->testCreateContainerNodeInPersonalFolder();
928         
929         $result = $this->_getUit()->moveNodes($dirsToMove, $targetNode['path'], false);
930         $this->assertEquals(2, count($result));
931         $this->assertEquals($targetNode['path'] . '/dir1', $result[0]['path'], 'no new path: ' . print_r($result, true));
932         
933         $filter = array(array(
934             'field'    => 'path', 
935             'operator' => 'equals', 
936             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED . '/testcontainer'
937         ), array(
938             'field'    => 'type', 
939             'operator' => 'equals', 
940             'value'    => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
941         ));
942
943         $result = $this->_getUit()->searchNodes($filter, array());
944         $this->assertEquals(0, $result['totalcount']);
945     }
946     
947     /**
948      * testMoveFolderNodesToFolderExisting
949      * 
950      * @see 0007028: moving a folder to another folder with a folder with the same name
951      */
952     public function testMoveFolderNodesToFolderExisting()
953     {
954         $targetNode = $this->testCreateContainerNodeInPersonalFolder();
955         $testPath = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/dir1';
956         $this->_getUit()->moveNodes(array($targetNode['path']), array($testPath), false);
957         $this->testCreateDirectoryNodesInShared();
958         try {
959             $this->_getUit()->moveNodes(array($testPath), '/shared/testcontainer', false);
960             $this->fail('Expected Filemanager_Exception_NodeExists!');
961         } catch (Filemanager_Exception_NodeExists $fene) {
962             $result = $this->_getUit()->moveNodes(array($testPath), '/shared/testcontainer', true);
963             $this->assertEquals(1, count($result));
964             $this->assertEquals('/shared/testcontainer/dir1', $result[0]['path']);
965         }
966     }
967
968     /**
969      * testMoveContainerFolderNodeToExistingContainer
970      * 
971      * @see 0007028: moving a folder to another folder with a folder with the same name
972      */
973     public function testMoveContainerFolderNodeToExistingContainer()
974     {
975         $targetNode = $this->testCreateContainerNodeInPersonalFolder();
976         
977         $testPath = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testcontainer2';
978         $result = $this->_getUit()->createNodes($testPath, Tinebase_Model_Tree_FileObject::TYPE_FOLDER, array(), false);
979         $createdNode = $result[0];
980
981         try {
982             $this->_getUit()->moveNodes(array($targetNode['path']), array($createdNode['path']), false);
983             $this->fail('Expected Filemanager_Exception_NodeExists!');
984         } catch (Filemanager_Exception_NodeExists $fene) {
985             $result = $this->_getUit()->moveNodes(array($targetNode['path']), array($createdNode['path']), true);
986             $this->assertEquals(1, count($result));
987             $this->assertEquals($testPath, $result[0]['path']);
988         }
989     }
990     
991     /**
992     * testMoveFolderNodesToTopLevel
993     */
994     public function testMoveFolderNodesToTopLevel()
995     {
996         // we need the personal folder for the test user
997         $this->_setupTestPath(Tinebase_FileSystem::FOLDER_TYPE_PERSONAL);
998         
999         $dirsToMove = $this->testCreateDirectoryNodesInShared();
1000         $targetPath = '/personal/' . Tinebase_Core::getUser()->accountLoginName;
1001         $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($targetPath . '/dir1');
1002         $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($targetPath . '/dir2');
1003         
1004         $result = $this->_getUit()->moveNodes($dirsToMove, $targetPath, false);
1005         $this->assertEquals(2, count($result));
1006         $this->assertEquals($targetPath . '/dir1', $result[0]['path']);
1007     }
1008     
1009     /**
1010      * testMoveContainerFolderNodesToContainerFolder
1011      */
1012     public function testMoveContainerFolderNodesToContainerFolder()
1013     {
1014         $sourceNode = $this->testCreateContainerNodeInPersonalFolder();
1015         
1016         $newPath = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testcontainermoved';
1017         $result = $this->_getUit()->moveNodes($sourceNode['path'], array($newPath), false);
1018         $this->assertEquals(1, count($result));
1019         $this->assertEquals($newPath, $result[0]['path'], 'no new path: ' . print_r($result, true));
1020
1021         $filter = array(array(
1022             'field'    => 'path', 
1023             'operator' => 'equals', 
1024             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName
1025         ), array(
1026             'field'    => 'type', 
1027             'operator' => 'equals', 
1028             'value'    => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
1029         ));
1030         $result = $this->_getUit()->searchNodes($filter, array());
1031         foreach ($result['results'] as $node) {
1032             $this->assertNotEquals($sourceNode['path'], $node['path']);
1033         }
1034     }
1035     
1036     /**
1037      * testMoveContainerFolderNodesToContainerFolderWithChildNodes
1038      */
1039     public function testMoveContainerFolderNodesToContainerFolderWithChildNodes()
1040     {
1041         $children = $this->testCreateDirectoryNodesInPersonal();
1042         
1043         $oldPath = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testcontainer';
1044         $newPath = $oldPath . 'moved';
1045         $result = $this->_getUit()->moveNodes(array($oldPath), array($newPath), false);
1046         $this->assertEquals(1, count($result));
1047         $this->assertEquals($newPath, $result[0]['path']);
1048
1049         $filter = array(array(
1050             'field'    => 'path', 
1051             'operator' => 'equals', 
1052             'value'    => $newPath
1053         ), array(
1054             'field'    => 'type', 
1055             'operator' => 'equals', 
1056             'value'    => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
1057         ));
1058         $result = $this->_getUit()->searchNodes($filter, array());
1059         $this->assertEquals(2, $result['totalcount']);
1060     }
1061     
1062     /**
1063      * testMoveFileNodesToFolder
1064      * 
1065      * @return array target node
1066      */
1067     public function testMoveFileNodesToFolder()
1068     {
1069         $filesToMove = $this->testCreateFileNodes();
1070         $targetNode = $this->testCreateContainerNodeInPersonalFolder();
1071         
1072         $result = $this->_getUit()->moveNodes($filesToMove, $targetNode['path'], false);
1073         $this->assertEquals(2, count($result));
1074         $this->assertEquals($targetNode['path'] . '/file1', $result[0]['path']);
1075
1076         $filter = array(array(
1077             'field'    => 'path', 
1078             'operator' => 'equals', 
1079             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED . '/testcontainer'
1080         ), array(
1081             'field'    => 'type', 
1082             'operator' => 'equals', 
1083             'value'    => Tinebase_Model_Tree_FileObject::TYPE_FILE,
1084         ));
1085         $result = $this->_getUit()->searchNodes($filter, array());
1086         $this->assertEquals(0, $result['totalcount']);
1087         
1088         return $targetNode;
1089     }
1090
1091     /**
1092      * testMoveFileNodesOverwrite
1093      */
1094     public function testMoveFileNodesOverwrite()
1095     {
1096         $targetNode = $this->testCopyFileNodesToFolder();
1097         
1098         $sharedContainerPath = '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED . '/testcontainer/';
1099         $filesToMove = array($sharedContainerPath . 'file1', $sharedContainerPath . 'file2');
1100         $result = $this->_getUit()->moveNodes($filesToMove, $targetNode['path'], true);
1101         
1102         $this->assertEquals(2, count($result));
1103     }
1104     
1105     /**
1106      * testMoveFolderNodeToRoot
1107      */
1108     public function testMoveFolderNodeToRoot()
1109     {
1110         $children = $this->testCreateDirectoryNodesInPersonal();
1111         
1112         $target = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName;
1113         $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($target . '/testcontainer');
1114         $result = $this->_getUit()->moveNodes($children[0], $target, false);
1115         $this->assertEquals(1, count($result));
1116         $this->assertEquals('dir1', $result[0]['name'], print_r($result[0], true));
1117     }
1118
1119     /**
1120      * Test if notes are correctly decorated with path field
1121      */
1122     public function testGetNode()
1123     {
1124         $node = $this->testCreateContainerNodeInPersonalFolder();
1125
1126         $result = Filemanager_Controller_Node::getInstance()->get($node['id']);
1127
1128         $this->assertTrue($result->path != "");
1129         $this->assertEquals('/personal/' . Tinebase_Core::getUser()->accountLoginName . '/testcontainer', $result->path);
1130     }
1131
1132     /**
1133      * testDeleteContainerNode
1134      */
1135     public function testDeleteContainerNode()
1136     {
1137         $sharedContainerNode = $this->testCreateContainerNodeInSharedFolder();
1138         
1139         $this->_getUit()->deleteNodes($sharedContainerNode['path']);
1140
1141         // check if node is deleted
1142         $this->setExpectedException('Tinebase_Exception_NotFound');
1143         $this->_fsController->stat($sharedContainerNode['path']);
1144     }
1145
1146     /**
1147      * testDeleteFileNodes
1148      */
1149     public function testDeleteFileNodes($_addData = false)
1150     {
1151         $filepaths = $this->testCreateFileNodes($_addData);
1152
1153         if (true === $_addData) {
1154             $parentFolder = $this->_fsController->stat(Filemanager_Controller_Node::getInstance()->addBasePath(dirname($filepaths[0])));
1155             static::assertEquals(16, $parentFolder->size, 'two files with 8 bytes each created, excpected 16 bytes folder size');
1156         }
1157         
1158         $this->_getUit()->deleteNodes($filepaths);
1159
1160         if (true === $_addData) {
1161             $parentFolder = $this->_fsController->stat(Filemanager_Controller_Node::getInstance()->addBasePath(dirname($filepaths[0])));
1162             static::assertEquals(0, $parentFolder->size, 'after deletion expected 0 byte folder size');
1163         }
1164
1165         // check if node is deleted
1166         try {
1167             $this->_fsController->stat(Filemanager_Controller_Node::getInstance()->addBasePath($filepaths[0]));
1168             $this->assertTrue(false);
1169         } catch (Tinebase_Exception_NotFound $tenf) {
1170             $this->assertTrue(true);
1171         }
1172     }
1173     
1174     /**
1175      * test cleanup of deleted files (database)
1176      * 
1177      * @see 0008062: add cleanup script for deleted files
1178      */
1179     public function testDeletedFileCleanupFromDatabase()
1180     {
1181         $fileNode = $this->testCreateFileNodeWithTempfile();
1182         
1183         // get "real" filesystem path + unlink
1184         $fileObjectBackend = new Tinebase_Tree_FileObject();
1185         $fileObject = $fileObjectBackend->get($fileNode['object_id']);
1186         unlink($fileObject->getFilesystemPath());
1187         
1188         $result = Tinebase_FileSystem::getInstance()->clearDeletedFilesFromDatabase();
1189         $this->assertEquals(1, $result, 'should cleanup one file');
1190
1191         $result = Tinebase_FileSystem::getInstance()->clearDeletedFilesFromDatabase();
1192         $this->assertEquals(0, $result, 'should cleanup no file');
1193         
1194         // node should no longer be found
1195         try {
1196             $this->_getUit()->getNode($fileNode['id']);
1197             $this->fail('tree node still exists: ' . print_r($fileNode, true));
1198         } catch (Tinebase_Exception_NotFound $tenf) {
1199             $this->assertEquals('Tinebase_Model_Tree_Node record with id = ' . $fileNode['id'] . ' not found!', $tenf->getMessage());
1200         }
1201     }
1202     
1203     /**
1204      * testDeleteDirectoryNodes
1205      */
1206     public function testDeleteDirectoryNodes()
1207     {
1208         $dirpaths = $this->testCreateDirectoryNodesInShared();
1209         
1210         $result = $this->_getUit()->deleteNodes($dirpaths);
1211
1212         // check if node is deleted
1213         $this->setExpectedException('Tinebase_Exception_NotFound');
1214         $node = $this->_fsController->stat(Filemanager_Controller_Node::getInstance()->addBasePath($dirpaths[0]));
1215     }
1216     
1217     /**
1218      * testGetUpdate
1219      * 
1220      * @see 0006736: Create File (Edit)InfoDialog
1221      * @return array
1222      */
1223     public function testGetUpdate()
1224     {
1225         $this->testCreateFileNodes();
1226         $filter = array(array(
1227             'field'    => 'path', 
1228             'operator' => 'equals', 
1229             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED . '/testcontainer'
1230         ));
1231         $result = $this->_getUit()->searchNodes($filter, array());
1232         
1233         $this->assertEquals(2, $result['totalcount']);
1234         $initialNode = $result['results'][0];
1235         
1236         $node = $this->_getUit()->getNode($initialNode['id']);
1237         $this->assertEquals('file', $node['type']);
1238         
1239         $node['description'] = 'UNITTEST';
1240         $node = $this->_getUit()->saveNode($node);
1241         
1242         $this->assertEquals('UNITTEST', $node['description']);
1243         $this->assertEquals($initialNode['contenttype'], $node['contenttype'], 'contenttype  not preserved');
1244
1245         
1246         return $node;
1247     }
1248
1249     /**
1250      * testAttachTag
1251      *
1252      * @see 0012284: file type changes to 'directory' if tag is assigned
1253      */
1254     public function testAttachTagPreserveContentType()
1255     {
1256         $node = $this->testCreateFileNodeWithTempfile();
1257         $node['tags'] = array(array(
1258             'type'          => Tinebase_Model_Tag::TYPE_PERSONAL,
1259             'name'          => 'file tag',
1260         ));
1261         $node['path'] = '';
1262         // remove hash field that the client does not send
1263         unset($node['hash']);
1264         $updatedNode = $this->_getUit()->saveNode($node);
1265
1266         $this->assertEquals(1, count($updatedNode['tags']));
1267         $this->assertEquals($node['contenttype'], $updatedNode['contenttype'], 'contenttype  not preserved');
1268     }
1269
1270     /**
1271      * testSetRelation
1272      * 
1273      * @see 0006736: Create File (Edit)InfoDialog
1274      */
1275     public function testSetRelation()
1276     {
1277         $node = $this->testGetUpdate();
1278         $node['relations'] = array($this->_getRelationData($node));
1279         $node = $this->_getUit()->saveNode($node);
1280         
1281         $this->assertEquals(1, count($node['relations']));
1282         $this->assertEquals('PHPUNIT, ali', $node['relations'][0]['related_record']['n_fileas']);
1283         
1284         $adbJson = new Addressbook_Frontend_Json();
1285         $contact = $adbJson->getContact($node['relations'][0]['related_id']);
1286         $this->assertEquals(1, count($contact['relations']), 'relations are missing');
1287         $this->assertEquals($node['name'], $contact['relations'][0]['related_record']['name']);
1288     }
1289     
1290     /**
1291      * get contact relation data
1292      * 
1293      * @param array $node
1294      * @return array
1295      */
1296     protected function _getRelationData($node)
1297     {
1298         return array(
1299             'own_model'              => 'Filemanager_Model_Node',
1300             'own_backend'            => 'Sql',
1301             'own_id'                 => $node['id'],
1302             'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
1303             'type'                   => 'FILE',
1304             'related_backend'        => 'Sql',
1305             'related_model'          => 'Addressbook_Model_Contact',
1306             'remark'                 => null,
1307             'related_record'         => array(
1308                 'n_given'           => 'ali',
1309                 'n_family'          => 'PHPUNIT',
1310                 'org_name'          => Tinebase_Record_Abstract::generateUID(),
1311                 'tel_cell_private'  => '+49TELCELLPRIVATE',
1312             )
1313         );
1314     }
1315
1316     /**
1317      * testSetRelationToFileInPersonalFolder
1318      * 
1319      * @see 0006736: Create File (Edit)InfoDialog
1320      */
1321     public function testSetRelationToFileInPersonalFolder()
1322     {
1323         $node = $this->testCreateFileNodeWithUTF8Filenames();
1324         $node['relations'] = array($this->_getRelationData($node));
1325         $node = $this->_getUit()->saveNode($node);
1326         
1327         $adbJson = new Addressbook_Frontend_Json();
1328         $contact = $adbJson->getContact($node['relations'][0]['related_id']);
1329         $this->assertEquals(1, count($contact['relations']));
1330         $relatedNode = $contact['relations'][0]['related_record'];
1331         $this->assertEquals($node['name'], $relatedNode['name']);
1332         $pathRegEx = '@^/personal/[a-f0-9-]+/testcontainer/' . preg_quote($relatedNode['name']) . '$@';
1333         $this->assertTrue(preg_match($pathRegEx, $relatedNode['path']) === 1, 'path mismatch: ' . print_r($relatedNode, true) . ' regex: ' . $pathRegEx);
1334     }
1335     
1336     /**
1337      * test renaming a folder in a folder containing a folder with the same name
1338      *
1339      * @see: https://forge.tine20.org/mantisbt/view.php?id=10132
1340      */
1341      public function testRenameFolderInFolderContainingFolderAlready()
1342      {
1343         $path = '/personal/' .Tinebase_Core::getUser()->accountLoginName . '/' . $this->_getPersonalFilemanagerContainer()->name;
1344      
1345         $this->_getUit()->createNode($path . '/Test1', 'folder', null, false);
1346         $this->_getUit()->createNode($path . '/Test1/Test2', 'folder', null, false);
1347         $this->_getUit()->createNode($path . '/Test1/Test3', 'folder', null, false);
1348         
1349         $this->setExpectedException('Filemanager_Exception_NodeExists');
1350         
1351         $this->_getUit()->moveNodes(array($path . '/Test1/Test3'), array($path . '/Test1/Test2'), false);
1352      }
1353     
1354     /**
1355      * tests the recursive filter
1356      */
1357     public function testSearchRecursiveFilter()
1358     {
1359         $fixtures = array(
1360             array('/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testa', 'color-red.gif'),
1361             array('/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testb', 'color-green.gif'),
1362             array('/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testc', 'color-blue.gif'));
1363
1364         $tempFileBackend = new Tinebase_TempFile();
1365         
1366         foreach($fixtures as $path) {
1367             $node = $this->_getUit()->createNode($path[0], Tinebase_Model_Tree_FileObject::TYPE_FOLDER, null, false);
1368             
1369             $this->assertEquals(str_replace('/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/', '', $path[0]), $node['name']);
1370             $this->assertEquals($path[0], $node['path']);
1371             
1372             $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($node['path']);
1373     
1374             $filepath = $node['path'] . '/' . $path[1];
1375             // create empty file first (like the js frontend does)
1376             $result = $this->_getUit()->createNode($filepath, Tinebase_Model_Tree_FileObject::TYPE_FILE, array(), false);
1377             $tempFile = $tempFileBackend->createTempFile(dirname(dirname(__FILE__)) . '/files/' . $path[1]);
1378             $result = $this->_getUit()->createNode($filepath, Tinebase_Model_Tree_FileObject::TYPE_FILE, $tempFile->getId(), true);
1379         }
1380         
1381         $filter = array(
1382             array('field' => 'recursive', 'operator' => 'equals',   'value' => 1),
1383             array('field' => 'path',      'operator' => 'equals',   'value' => '/'),
1384             array('field' => 'query',     'operator' => 'contains', 'value' => 'color'),
1385             array('field' => 'isIndexed', 'operator' => 'equals',   'value' => 0),
1386         'AND');
1387         
1388         $result = $this->_getUit()->searchNodes($filter, array('sort' => 'name', 'start' => 0, 'limit' => 0));
1389         $this->assertEquals(3, count($result), '3 files should have been found!');
1390     }
1391     
1392     /**
1393      * test cleanup of deleted files (filesystem)
1394      */
1395     public function testDeletedFileCleanupFromFilesystem()
1396     {
1397         Tinebase_Core::getConfig()->{Tinebase_Config::FILESYSTEM}->{Tinebase_Config::FILESYSTEM_MODLOGACTIVE} = false;
1398         $this->_fsController->resetBackends();
1399
1400         // remove all files with size 0 first
1401         // better here than below?
1402         $this->testDeleteFileNodes();
1403
1404         $size0Nodes = Tinebase_FileSystem::getInstance()->searchNodes(new Tinebase_Model_Tree_Node_Filter(array(
1405             array('field' => 'type', 'operator' => 'equals', 'value' => Tinebase_Model_Tree_FileObject::TYPE_FILE),
1406             array('field' => 'size', 'operator' => 'equals', 'value' => 0)
1407         )));
1408         foreach ($size0Nodes as $node) {
1409             Tinebase_FileSystem::getInstance()->deleteFileNode($node);
1410         }
1411
1412         // why here?
1413         //$this->testDeleteFileNodes();
1414         $result = Tinebase_FileSystem::getInstance()->clearDeletedFilesFromFilesystem();
1415         $this->assertEquals(0, $result, 'should not clean up anything as files with size 0 are not written to disk');
1416         $this->tearDown();
1417         
1418         Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
1419         Tinebase_Core::getConfig()->{Tinebase_Config::FILESYSTEM}->{Tinebase_Config::FILESYSTEM_MODLOGACTIVE} = false;
1420         $this->_fsController->resetBackends();
1421         $this->testDeleteFileNodes(true);
1422         $result = Tinebase_FileSystem::getInstance()->clearDeletedFilesFromFilesystem();
1423         $this->assertEquals(1, $result, 'should cleanup one file');
1424     }
1425     
1426     /**
1427      * test preventing to copy a folder in its subfolder
1428      * 
1429      * @see: https://forge.tine20.org/mantisbt/view.php?id=9990
1430      */
1431     public function testMoveFolderIntoChildFolder()
1432     {
1433         $this->_getUit()->createNode('/shared/Parent', 'folder', null, false);
1434         $this->_getUit()->createNode('/shared/Parent/Child', 'folder', null, false);
1435         
1436         $this->setExpectedException('Filemanager_Exception_DestinationIsOwnChild');
1437         
1438         // this must not work
1439         $this->_getUit()->moveNodes(array('/shared/Parent'), array('/shared/Parent/Child/Parent'), false);
1440     }
1441     
1442     /**
1443      * test exception on moving to the same position
1444      * 
1445      * @see: https://forge.tine20.org/mantisbt/view.php?id=9990
1446      */
1447     public function testMoveFolderToSamePosition()
1448     {
1449         $this->_getUit()->createNode('/shared/Parent', 'folder', null, false);
1450         $this->_getUit()->createNode('/shared/Parent/Child', 'folder', null, false);
1451     
1452         $this->setExpectedException('Filemanager_Exception_DestinationIsSameNode');
1453     
1454         // this must not work
1455         $this->_getUit()->moveNodes(array('/shared/Parent/Child'), array('/shared/Parent/Child'), false);
1456     }
1457
1458     /**
1459      * test to move a folder containing another folder
1460      *
1461      * @see: https://forge.tine20.org/mantisbt/view.php?id=9990
1462      */
1463     public function testMove2FoldersOnToplevel()
1464     {
1465         $path = '/personal/' .Tinebase_Core::getUser()->accountLoginName . '/' . $this->_getPersonalFilemanagerContainer()->name;
1466     
1467         $this->_getUit()->createNode($path . '/Parent', 'folder', null, false);
1468         $this->_getUit()->createNode($path . '/Parent/Child', 'folder', null, false);
1469         $this->_getUit()->createNode('/shared/Another', 'folder', null, false);
1470     
1471         // move forth and back, no exception should occur
1472         $this->_getUit()->moveNodes(array($path . '/Parent'), array('/shared/Parent'), false);
1473         $this->_getUit()->moveNodes(array('/shared/Parent'), array($path . '/Parent'), false);
1474     
1475         try {
1476             $c = Tinebase_Container::getInstance()->getContainerByName('Filemanager', 'Parent', Tinebase_FileSystem::FOLDER_TYPE_SHARED);
1477             $this->fail('Container doesn\'t get deleted');
1478         } catch (Tinebase_Exception_NotFound $e) {
1479         }
1480         
1481         // may be any exception
1482         $e = new Tinebase_Exception('Dog eats cat');
1483     
1484         try {
1485             $this->_getUit()->moveNodes(array($path . '/Parent'), array('/shared/Parent'), false);
1486         } catch (Filemanager_Exception_NodeExists $e) {
1487         }
1488     
1489         // if $e gets overridden, an error occured (the exception Filemanager_Exception_NodeExists must not be thrown)
1490         $this->assertEquals('Tinebase_Exception', get_class($e));
1491     }
1492     
1493     /**
1494      * test creating a folder in a folder with the same name (below personal folders)
1495      *
1496      * @see: https://forge.tine20.org/mantisbt/view.php?id=10132
1497      */
1498     public function testCreateFolderInFolderWithSameName()
1499     {
1500         $path = '/personal/' .Tinebase_Core::getUser()->accountLoginName . '/' . $this->_getPersonalFilemanagerContainer()->name;
1501
1502         $result = $this->_getUit()->createNode($path . '/Test1', 'folder', null, false);
1503         $this->assertTrue(isset($result['id']));
1504         $result = $this->_getUit()->createNode($path . '/Test1/Test1', 'folder', null, false);
1505         $this->assertTrue(isset($result['id']), 'node has not been created');
1506         $e = new Tinebase_Exception('nothing');
1507         try {
1508             $this->_getUit()->createNode($path . '/Test1/Test1/Test2', 'folder', null, false);
1509         } catch (Exception $e) {
1510             $this->fail('The folder couldn\'t be found, so it hasn\'t ben created');
1511         }
1512         
1513         $this->assertEquals('nothing', $e->getMessage());
1514     }
1515     
1516     /**
1517      * get other users container
1518      * 
1519      * @return Tinebase_Model_Container
1520      */
1521     protected function _getOtherUserContainer()
1522     {
1523         if (!$this->_otherUserContainer) {
1524             $sclever = $this->_personas['sclever'];
1525
1526             $path = Tinebase_FileSystem::getInstance()->getApplicationBasePath(
1527                 $this->_application, Tinebase_FileSystem::FOLDER_TYPE_PERSONAL) . '/' . $sclever->getId() . '/clever';
1528             if (Tinebase_FileSystem::getInstance()->fileExists($path)) {
1529                 $this->_otherUserContainer = Tinebase_FileSystem::getInstance()->stat($path);
1530             } else {
1531                 $grants = Tinebase_Model_Grants::getPersonalGrants($sclever);
1532                 $grants->addRecord(new Tinebase_Model_Grants(array(
1533                     'account_type' => Tinebase_Acl_Rights::ACCOUNT_TYPE_ANYONE,
1534                     'account_id' => 0,
1535                     Tinebase_Model_Grants::GRANT_READ => true,
1536                 )));
1537                 $this->_otherUserContainer = Tinebase_FileSystem::getInstance()->createAclNode($path, $grants);
1538             }
1539         }
1540         
1541         return $this->_otherUserContainer;
1542     }
1543     
1544     /**
1545      * get personal container
1546      * 
1547      * @return Tinebase_Model_Tree_Node
1548      */
1549     protected function _getPersonalFilemanagerContainer()
1550     {
1551         if (!$this->_personalContainer) {
1552             $user = Tinebase_Core::getUser();
1553             $this->_personalContainer = Tinebase_FileSystem::getInstance()->getPersonalContainer($user, 'Filemanager', $user)->getFirstRecord();
1554         }
1555         
1556         return $this->_personalContainer;
1557     }
1558     
1559     /**
1560      * get shared container
1561      * 
1562      * @return Tinebase_Model_Container
1563      */
1564     protected function _getSharedContainer()
1565     {
1566         if (!$this->_sharedContainer) {
1567             $path = Tinebase_FileSystem::getInstance()->getApplicationBasePath(
1568                     $this->_application, Tinebase_FileSystem::FOLDER_TYPE_SHARED) . '/shared';
1569             try {
1570                 $this->_sharedContainer = Tinebase_FileSystem::getInstance()->stat($path);
1571             } catch (Tinebase_Exception_NotFound $tenf) {
1572                 $this->_sharedContainer = Tinebase_FileSystem::getInstance()->createAclNode($path);
1573             }
1574         }
1575         
1576         return $this->_sharedContainer;
1577     }
1578     
1579     /**
1580      * setup the test paths
1581      * 
1582      * @param string|array $_types
1583      */
1584     protected function _setupTestPath($_types)
1585     {
1586         $testPaths = array();
1587         $types = (array) $_types;
1588         
1589         foreach ($types as $type) {
1590             switch ($type) {
1591                 case Tinebase_FileSystem::FOLDER_TYPE_PERSONAL:
1592                     $testPaths[] = Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->getId() . '/' 
1593                         . $this->_getPersonalFilemanagerContainer()->name . '/unittestdir_personal';
1594                     break;
1595                 case Tinebase_FileSystem::FOLDER_TYPE_SHARED:
1596                     $testPaths[] = Tinebase_FileSystem::FOLDER_TYPE_SHARED . '/' . $this->_getSharedContainer()->name . '/unittestdir_shared';
1597                     break;
1598                 case Tinebase_Model_Container::TYPE_OTHERUSERS:
1599                     $personas = Zend_Registry::get('personas');
1600                     $testPaths[] = Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . $personas['sclever']->getId() . '/' 
1601                         . $this->_getOtherUserContainer()->name . '/unittestdir_other';
1602                     break;
1603             }
1604         }
1605         
1606         foreach ($testPaths as $path) {
1607             $path = Filemanager_Controller_Node::getInstance()->addBasePath($path);
1608             $this->_objects['paths'][] = $path;
1609             $this->_fsController->mkdir($path);
1610         }
1611     }
1612     
1613     /**
1614      * testSaveDownloadLinkFile
1615      * 
1616      * @return array Filemanager_Model_DownloadLink
1617      */
1618     public function testSaveDownloadLinkFile()
1619     {
1620         $downloadLinkData = $this->_getDownloadLinkData();
1621         $result = $this->_getUit()->saveDownloadLink($downloadLinkData);
1622         
1623         $this->assertTrue(! empty($result['url']));
1624         $this->assertEquals($this->_getDownloadUrl($result['id']), $result['url']);
1625         $this->assertEquals(0, $result['access_count']);
1626         
1627         return $result;
1628     }
1629
1630     protected function _getDownloadUrl($id)
1631     {
1632         return Tinebase_Core::getUrl() . '/download/show/' . $id;
1633     }
1634     
1635     /**
1636      * testSaveDownloadLinkDirectory
1637      *
1638      * @return array Filemanager_Model_DownloadLink
1639      */
1640     public function testSaveDownloadLinkDirectory()
1641     {
1642         $downloadLinkData = $this->_getDownloadLinkData();
1643         $result = $this->_getUit()->saveDownloadLink($downloadLinkData);
1644         
1645         $this->assertTrue(! empty($result['url']));
1646         $this->assertEquals($this->_getDownloadUrl($result['id']), $result['url']);
1647         
1648         return $result;
1649     }
1650     
1651     /**
1652      * get download link data
1653      * 
1654      * @param string $nodeType
1655      * @return array
1656      * @throws Tinebase_Exception_InvalidArgument
1657      */
1658     protected function _getDownloadLinkData($nodeType = Tinebase_Model_Tree_FileObject::TYPE_FILE)
1659     {
1660         // create node first
1661         if ($nodeType === Tinebase_Model_Tree_FileObject::TYPE_FILE) {
1662             $node = $this->testCreateFileNodeWithTempfile();
1663         } else if ($nodeType === Tinebase_Model_Tree_FileObject::TYPE_FOLDER) {
1664             $node = $this->testCreateContainerNodeInPersonalFolder();
1665         } else {
1666             throw new Tinebase_Exception_InvalidArgument('only file and folder nodes are supported');
1667         }
1668         
1669         return array(
1670             'node_id'       => $node['id'],
1671             'expiry_date'   => Tinebase_DateTime::now()->addDay(1)->toString(),
1672             'access_count'  => 7,
1673         );
1674     }
1675     
1676     /**
1677      * testGetDownloadLink
1678      */
1679     public function testGetDownloadLink()
1680     {
1681         $downloadLink = $this->testSaveDownloadLinkFile();
1682         
1683         $this->assertEquals($downloadLink, $this->_getUit()->getDownloadLink($downloadLink['id']));
1684     }
1685     
1686     /**
1687      * testSearchDownloadLinks
1688      */
1689     public function testSearchDownloadLinks()
1690     {
1691         $downloadLink = $this->testSaveDownloadLinkFile();
1692         $filter = array(array(
1693             'field'     => 'id',
1694             'operator'  => 'equals',
1695             'value'     => $downloadLink['id']
1696         ));
1697         $result = $this->_getUit()->searchDownloadLinks($filter, array());
1698         
1699         $this->assertEquals(1, $result['totalcount']);
1700     }
1701
1702     /**
1703      * testDeleteDownloadLinks
1704      */
1705     public function testDeleteDownloadLinks()
1706     {
1707         $downloadLink = $this->testSaveDownloadLinkFile();
1708
1709         $this->_getUit()->deleteDownloadLinks(array($downloadLink['id']));
1710         try {
1711             Filemanager_Controller_DownloadLink::getInstance()->get($downloadLink['id']);
1712             $this->fail('link should have been deleted');
1713         } catch (Exception $e) {
1714             $this->assertTrue($e instanceof Tinebase_Exception_NotFound);
1715         }
1716     }
1717
1718     /**
1719      * @see 0012788: allow acl for all folder nodes
1720      */
1721     public function testNodeAclAndPathResolving()
1722     {
1723         $this->testCreateFileNodes();
1724
1725         // search folders + assert grants
1726         $sharedRoot = '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED;
1727         $filter = array(array(
1728             'field'    => 'path',
1729             'operator' => 'equals',
1730             'value'    => $sharedRoot
1731         ));
1732         $result = $this->_getUit()->searchNodes($filter, array());
1733
1734         self::assertEquals(1, $result['totalcount']);
1735         $node = $result['results'][0];
1736         self::assertEquals('/shared/testcontainer', $node['path'], 'no path found in node: ' . print_r($node, true));
1737         $this->_assertGrantsInNode($node);
1738
1739         // search files + assert grants
1740         $filter = array(array(
1741             'field'    => 'path',
1742             'operator' => 'equals',
1743             'value'    => $node['path']
1744         ));
1745         $result = $this->_getUit()->searchNodes($filter, array());
1746         self::assertEquals(2, $result['totalcount'], 'no files found in path: ' . print_r($result, true));
1747         $file1Node = $result['results'][0];
1748         self::assertContains('/shared/testcontainer/file', $file1Node['path'], 'no path found in node: ' . print_r($file1Node, true));
1749         $this->_assertGrantsInNode($file1Node);
1750
1751         $file2Node = $this->_getUit()->getNode($result['results'][1]['id']);
1752         self::assertContains('/shared/testcontainer/file', $file2Node['path'], 'no path found in node: ' . print_r($file2Node, true));
1753         $this->_assertGrantsInNode($file2Node);
1754     }
1755
1756     /**
1757      * check if account grants are resolved correctly
1758      *
1759      * @param $nodeArray
1760      */
1761     protected function _assertGrantsInNode($nodeArray)
1762     {
1763         self::assertEquals(2, count($nodeArray['grants']));
1764         self::assertTrue(is_array($nodeArray['grants'][0]['account_name']), 'account_name is not resolved');
1765         self::assertEquals(true, count($nodeArray['account_grants']['adminGrant']));
1766     }
1767
1768     public function testSetNodeAcl()
1769     {
1770         $node = $this->testCreateContainerNodeInSharedFolder();
1771         $node['grants'] = Tinebase_Model_Grants::getPersonalGrants(Tinebase_Core::getUser())->toArray();
1772         $result = $this->_getUit()->saveNode($node);
1773
1774         self::assertEquals(1, count($result['grants']), print_r($result['grants'], true));
1775         self::assertEquals(Tinebase_Acl_Rights::ACCOUNT_TYPE_USER, $result['grants'][0]['account_type']);
1776
1777         return $node;
1778     }
1779
1780     public function testRemoveNodeAclTopLevel()
1781     {
1782         $node = $this->testSetNodeAcl();
1783         $node['grants'] = null;
1784         $result = $this->_getUit()->saveNode($node);
1785
1786         self::assertEquals(1, count($result['grants']), 'it is not allowed to remove top level node grants - '
1787             . print_r($result['grants'], true));
1788     }
1789
1790     public function testRemoveNodeAclChildLevel()
1791     {
1792         $node = $this->testCreateContainerNodeInSharedFolder();
1793         // create child folder node
1794         $testPath = $node['path'] . '/child';
1795         $child = $this->_getUit()->createNode($testPath, Tinebase_Model_Tree_FileObject::TYPE_FOLDER, null, false);
1796
1797         $child['grants'] = Tinebase_Model_Grants::getPersonalGrants(Tinebase_Core::getUser())->toArray();
1798         $child['acl_node'] = $child['id'];
1799         $child = $this->_getUit()->saveNode($child);
1800
1801         self::assertEquals(1, count($child['grants']), 'node should have only personal grants - '
1802             . print_r($child['grants'], true));
1803
1804         $child['acl_node'] = null;
1805         $childWithoutPersonalGrants = $this->_getUit()->saveNode($child);
1806
1807         self::assertEquals(2, count($childWithoutPersonalGrants['grants']), 'node should have parent grants again - '
1808             . print_r($childWithoutPersonalGrants['grants'], true));
1809     }
1810
1811     /**
1812      * testNodeRoleAcl for personal folders
1813      *
1814      * @throws Tinebase_Exception_InvalidArgument
1815      */
1816     public function testNodeRoleAcl()
1817     {
1818         $node = $this->testCreateContainerNodeInPersonalFolder();
1819
1820         // give sclever role the grants to add nodes
1821         $secretaryRole = Tinebase_Role::getInstance()->getRoleByName('secretary role');
1822         $node['grants'][] = array(
1823             'account_id' => $secretaryRole->getId(),
1824             'account_type' => Tinebase_Acl_Rights::ACCOUNT_TYPE_ROLE,
1825             Tinebase_Model_Grants::GRANT_READ => true,
1826             Tinebase_Model_Grants::GRANT_ADD => true,
1827             Tinebase_Model_Grants::GRANT_EDIT => false,
1828             Tinebase_Model_Grants::GRANT_DELETE => true,
1829             Tinebase_Model_Grants::GRANT_EXPORT => false,
1830             Tinebase_Model_Grants::GRANT_SYNC => false,
1831             Tinebase_Model_Grants::GRANT_ADMIN => false,
1832             Tinebase_Model_Grants::GRANT_FREEBUSY => false,
1833             Tinebase_Model_Grants::GRANT_PRIVATE => false,
1834             Tinebase_Model_Grants::GRANT_DOWNLOAD => false,
1835             Tinebase_Model_Grants::GRANT_PUBLISH => false,
1836         );
1837         $result = $this->_getUit()->saveNode($node);
1838         self::assertEquals(2, count($result['grants']));
1839
1840         // switch to sclever
1841         Tinebase_Core::set(Tinebase_Core::USER, $this->_personas['sclever']);
1842
1843         // add a subfolder
1844         $subfolderPath = $node['path'] . '/subfolder';
1845         $this->_getUit()->createNode($subfolderPath, 'folder');
1846
1847         // delete subfolder
1848         $result = $this->_getUit()->deleteNodes(array($subfolderPath));
1849         self::assertEquals($result['status'], 'success');
1850     }
1851
1852     public function testRecursiveFilter()
1853     {
1854         $folders = $this->testCreateDirectoryNodesInPersonal();
1855         $prefix = Tinebase_FileSystem::getInstance()->getApplicationBasePath('Filemanager') . '/folders';
1856
1857         $i = 0;
1858         foreach($folders as $folder) {
1859             $path = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $folder . '/test.txt');
1860             $handle = Tinebase_FileSystem::getInstance()->fopen($path->statpath, 'w');
1861             $this->assertTrue(is_resource($handle), 'fopen did not return resource');
1862
1863             $written = fwrite($handle, 'RecursiveTest' . (++$i));
1864             $this->assertEquals(14, $written, 'failed to write 14 bytes to ' . $folder . '/test.txt');
1865
1866             $result = Tinebase_FileSystem::getInstance()->fclose($handle);
1867             $this->assertTrue($result, 'fclose did not return true');
1868         }
1869
1870         $path = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testcontainer';
1871         $this->_rmDir[] = $path;
1872         $paths = array($path . '/dir1/test.txt', $path . '/dir2/test.txt');
1873         Tinebase_TransactionManager::getInstance()->commitTransaction($this->_transactionId);
1874         $this->_transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
1875
1876         $result = $this->_getUit()->searchNodes(array(
1877             array(
1878                 'field'    => 'recursive',
1879                 'operator' => 'equals',
1880                 'value'    => 'true'
1881             ),
1882             array(
1883                 'field'    => 'query',
1884                 'operator' => 'contains',
1885                 'value'    => 'RecursiveTe'
1886             ),
1887         ), null);
1888
1889         $this->assertEquals(2, $result['totalcount'], 'did not find expected 2 files: ' . print_r($result, true));
1890         foreach($result['results'] as $result) {
1891             $this->assertTrue(in_array($result['path'], $paths), 'result doesn\'t match expected paths: ' . print_r($result, true) . print_r($paths, true));
1892         }
1893     }
1894
1895     protected function _statPaths($_paths)
1896     {
1897         $fileSystem = Tinebase_FileSystem::getInstance();
1898         $result = array();
1899
1900         /**
1901          * @var  string $key
1902          * @var  Tinebase_Model_Tree_Node_Path $path
1903          */
1904         foreach($_paths as $key => $path) {
1905             $result[$key] = $fileSystem->stat($path->statpath);
1906         }
1907
1908         return $result;
1909     }
1910
1911     protected function _assertRevisionProperties(array $_nodes, array $_defaultResult, array $_resultMap = array())
1912     {
1913         /**
1914          * @var string $key
1915          * @var Tinebase_Model_Tree_Node $node
1916          */
1917         foreach($_nodes as $key => $node) {
1918             $actual = $node->xprops(Tinebase_Model_Tree_Node::XPROPS_REVISION);
1919             if (!empty($actual) && isset($actual[Tinebase_Model_Tree_Node::XPROPS_REVISION_NODE_ID])) {
1920                 unset($actual[Tinebase_Model_Tree_Node::XPROPS_REVISION_NODE_ID]);
1921             }
1922             $expected = isset($_resultMap[$key]) ? $_resultMap[$key] : $_defaultResult;
1923             static::assertTrue($expected == $actual, 'node revisions don\'t match for node: ' . $node->name . ' expected: ' . print_r($expected, true) . ' actual: ' . print_r($node->xprops(Tinebase_Model_Tree_Node::XPROPS_REVISION), true));
1924         }
1925     }
1926
1927     protected function _setRevisionProperties(Tinebase_Model_Tree_Node $_node, array $_properties)
1928     {
1929         foreach($_properties as $key => $value) {
1930             $_node->xprops(Tinebase_Model_Tree_Node::XPROPS_REVISION)[$key] = $value;
1931         }
1932         $_node->xprops(Tinebase_Model_Tree_Node::XPROPS_REVISION)[Tinebase_Model_Tree_Node::XPROPS_REVISION_NODE_ID] =
1933             $_node->getId();
1934     }
1935
1936     public function testSetRevisionSettings()
1937     {
1938         $fileSystem = Tinebase_FileSystem::getInstance();
1939         $prefix = $fileSystem->getApplicationBasePath('Filemanager') . '/folders';
1940
1941         $this->testCreateDirectoryNodesInPersonal();
1942         $path = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testcontainer';
1943         $this->_getUit()->createNodes(array($path . '/dir1/subdir11', $path . '/dir1/subdir12'), Tinebase_Model_Tree_FileObject::TYPE_FOLDER, array(), false);
1944         $this->_getUit()->createNodes(array($path . '/dir2/subdir21', $path . '/dir2/subdir22'), Tinebase_Model_Tree_FileObject::TYPE_FOLDER, array(), false);
1945
1946
1947         // NONE of them have revision properties
1948         $paths = array(
1949             'dir1'          => Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir1'),
1950             'subDir11'      => Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir1/subdir11'),
1951             'subDir12'      => Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir1/subdir12'),
1952             'dir2'          => Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2'),
1953             'subDir21'      => Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir21'),
1954             'subDir22'      => Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir22'),
1955             'testContainer' => Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path),
1956         );
1957
1958         $nodes = $this->_statPaths($paths);
1959         $this->_assertRevisionProperties($nodes, array());
1960
1961
1962
1963         // ADD revision properties to the DIR1 subtree
1964         $dir1TreeRevisionProperties = array(
1965             Tinebase_Model_Tree_Node::XPROPS_REVISION_MONTH => 1,
1966             Tinebase_Model_Tree_Node::XPROPS_REVISION_NUM   => 2,
1967             Tinebase_Model_Tree_Node::XPROPS_REVISION_ON    => true
1968         );
1969         $this->_setRevisionProperties($nodes['dir1'], $dir1TreeRevisionProperties);
1970
1971         $this->_getUit()->saveNode($nodes['dir1']->toArray());
1972
1973         $fileSystem->clearStatCache();
1974         $nodes = $this->_statPaths($paths);
1975         $this->_assertRevisionProperties($nodes, array(), array(
1976             'dir1'      => $dir1TreeRevisionProperties,
1977             'subDir11'  => $dir1TreeRevisionProperties,
1978             'subDir12'  => $dir1TreeRevisionProperties
1979         ));
1980
1981
1982
1983         // MOVE DIR1 subtree below SUBDIR21 => nothing should change
1984         $fileSystem->rename($paths['dir1']->statpath, $paths['subDir21']->statpath . '/tmp');
1985
1986         $fileSystem->clearStatCache();
1987         $paths['dir1']     = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir21/tmp');
1988         $paths['subDir11'] = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir21/tmp/subdir11');
1989         $paths['subDir12'] = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir21/tmp/subdir12');
1990         $nodes = $this->_statPaths($paths);
1991         $this->_assertRevisionProperties($nodes, array(), array(
1992             'dir1'      => $dir1TreeRevisionProperties,
1993             'subDir11'  => $dir1TreeRevisionProperties,
1994             'subDir12'  => $dir1TreeRevisionProperties
1995         ));
1996
1997
1998
1999         // ADD revision properties to the SUBDIR22 subtree
2000         $subdir22TreeRevisionProperties = array(
2001             Tinebase_Model_Tree_Node::XPROPS_REVISION_MONTH => 2,
2002             Tinebase_Model_Tree_Node::XPROPS_REVISION_NUM   => 3,
2003             Tinebase_Model_Tree_Node::XPROPS_REVISION_ON    => true
2004         );
2005         $this->_setRevisionProperties($nodes['subDir22'], $subdir22TreeRevisionProperties);
2006
2007         $this->_getUit()->saveNode($nodes['subDir22']->toArray());
2008
2009         // MOVE DIR1 from SUBDIR21 to SUBDIR22 => they should still not change!
2010         $fileSystem->rename($paths['dir1']->statpath, $paths['subDir22']->statpath . '/tmp');
2011
2012         $fileSystem->clearStatCache();
2013         $paths['dir1']     = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir22/tmp');
2014         $paths['subDir11'] = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir22/tmp/subdir11');
2015         $paths['subDir12'] = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir22/tmp/subdir12');
2016         $nodes = $this->_statPaths($paths);
2017         $this->_assertRevisionProperties($nodes, array(), array(
2018             'subDir22'  => $subdir22TreeRevisionProperties,
2019             'dir1'      => $dir1TreeRevisionProperties,
2020             'subDir11'  => $dir1TreeRevisionProperties,
2021             'subDir12'  => $dir1TreeRevisionProperties
2022         ));
2023
2024
2025
2026         // MOVE subDir11 to subDir21 => should change to empty
2027         $fileSystem->rename($paths['subDir11']->statpath, $paths['subDir21']->statpath . '/tmp');
2028
2029         $fileSystem->clearStatCache();
2030         $paths['subDir11'] = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir21/tmp');
2031         $nodes = $this->_statPaths($paths);
2032         $this->_assertRevisionProperties($nodes, array(), array(
2033             'subDir22'  => $subdir22TreeRevisionProperties,
2034             'dir1'      => $dir1TreeRevisionProperties,
2035             'subDir12'  => $dir1TreeRevisionProperties
2036         ));
2037
2038
2039
2040         // reset properties for whole tree
2041         $testContainerRevisionProperties = array(
2042             Tinebase_Model_Tree_Node::XPROPS_REVISION_MONTH => 6,
2043             Tinebase_Model_Tree_Node::XPROPS_REVISION_NUM   => 5,
2044             Tinebase_Model_Tree_Node::XPROPS_REVISION_ON    => false
2045         );
2046         $this->_setRevisionProperties($nodes['testContainer'], $testContainerRevisionProperties);
2047
2048         $this->_getUit()->saveNode($nodes['testContainer']->toArray());
2049
2050         $fileSystem->clearStatCache();
2051         $nodes = $this->_statPaths($paths);
2052         $this->_assertRevisionProperties($nodes, $testContainerRevisionProperties);
2053     }
2054
2055     public function testGetFolderUsage()
2056     {
2057         $result = $this->testCreateFileNodeWithTempfile();
2058
2059         $usageInfo = $this->_getUit()->getFolderUsage($result['parent_id']);
2060         $userId = Tinebase_Core::getUser()->contact_id;
2061
2062         $this->assertEquals(17, $usageInfo['type']['txt']['size']);
2063         $this->assertEquals(17, $usageInfo['type']['txt']['revision_size']);
2064         $this->assertEquals(17, $usageInfo['createdBy'][$userId]['size']);
2065         $this->assertEquals(17, $usageInfo['createdBy'][$userId]['revision_size']);
2066         $this->assertEquals($userId, $usageInfo['contacts'][0]['id']);
2067     }
2068 }