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