Tinebase_Model_Tree_Node validation for revision and notifiction props
[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']['nodeId'] = $personalContainerNode['id'];
751         $personalContainerNode['revisionProps']['keep'] = true;
752         $personalContainerNode['revisionProps']['keepNum'] = 3;
753         $personalContainerNode['revisionProps']['keepMonth'] = 4;
754         $updatedNode = $this->_getUit()->saveNode($personalContainerNode);
755
756         static::assertTrue(isset($updatedNode['customfields']) && isset($updatedNode['customfields'][$cf->name]),
757             'no customfields in record');
758         static::assertEquals($personalContainerNode['customfields'][$cf->name],
759             $updatedNode['customfields'][$cf->name]);
760
761         static::assertTrue(isset($updatedNode['revisionProps']) && isset($updatedNode['revisionProps']['keep']) &&
762             isset($updatedNode['revisionProps']['keepNum']) && isset($updatedNode['revisionProps']['keepMonth']),
763             'revisionProps not saved: ' . print_r($updatedNode, true));
764         static::assertEquals($personalContainerNode['revisionProps']['nodeId'], $personalContainerNode['id']);
765         static::assertEquals($personalContainerNode['revisionProps']['keep'], true);
766         static::assertEquals($personalContainerNode['revisionProps']['keepNum'], 3);
767         static::assertEquals($personalContainerNode['revisionProps']['keepMonth'], 4);
768     }
769     
770     /**
771      * testRenameDirectoryNodeInPersonalToSameNameAsOtherUsersDir
772      *
773      * @see 0008046: Rename personal folder to personal folder of another user
774      */
775     public function testRenameDirectoryNodeInPersonalToSameNameAsOtherUsersDir()
776     {
777         $personalContainerNode = $this->testCreateContainerNodeInPersonalFolder();
778         
779         $personas = Zend_Registry::get('personas');
780         Tinebase_Core::set(Tinebase_Core::USER, $personas['sclever']);
781         $personalContainerNodeOfsclever = $this->testCreateContainerNodeInPersonalFolder('testcontainer2');
782         
783         $this->assertEquals('/personal/sclever/testcontainer2', $personalContainerNodeOfsclever['path']);
784         
785         // rename
786         $newPath = '/personal/sclever/testcontainer';
787         $result = $this->_getUit()->moveNodes(array($personalContainerNodeOfsclever['path']), array($newPath), false);
788         $this->assertEquals(1, count($result));
789         $this->assertEquals($newPath, $result[0]['path']);
790     }
791     
792     /**
793      * testCopyFolderNodes
794      */
795     public function testCopyFolderNodesToFolder()
796     {
797         $dirsToCopy = $this->testCreateDirectoryNodesInShared();
798         $targetNode = $this->testCreateContainerNodeInPersonalFolder();
799         
800         $result = $this->_getUit()->copyNodes($dirsToCopy, $targetNode['path'], false);
801         $this->assertEquals(2, count($result));
802         $this->assertEquals($targetNode['path'] . '/dir1', $result[0]['path']);
803     }
804
805     /**
806      * testCopyContainerNode
807      */
808     public function testCopyContainerNode()
809     {
810         $sharedContainerNode = $this->testCreateContainerNodeInSharedFolder();
811         $target = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName;
812         $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($target . '/testcontainer');
813         $result = $this->_getUit()->copyNodes($sharedContainerNode['path'], $target, false);
814         $this->assertEquals(1, count($result));
815         $this->assertTrue(isset($result[0]['name']), print_r($result, true));
816         $this->assertEquals('testcontainer', $result[0]['name']);
817     }
818     
819     /**
820      * testCopyFileNodesToFolder
821      * 
822      * @return array target node
823      */
824     public function testCopyFileNodesToFolder()
825     {
826         $filesToCopy = $this->testCreateFileNodes();
827         $targetNode = $this->testCreateContainerNodeInPersonalFolder();
828         
829         $result = $this->_getUit()->copyNodes($filesToCopy, $targetNode['path'], false);
830         $this->assertEquals(2, count($result));
831         $this->assertEquals($targetNode['path'] . '/file1', $result[0]['path']);
832         
833         return $targetNode;
834     }
835
836     /**
837      * testCopyFolderWithNodes
838      */
839     public function testCopyFolderWithNodes()
840     {
841         $filesToCopy = $this->testCreateFileNodes();
842         $target = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName;
843         
844         $result = $this->_getUit()->copyNodes(
845             '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED . '/testcontainer',
846             $target, 
847             false
848         );
849         
850         $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($target . '/testcontainer');
851         $this->assertEquals(1, count($result));
852
853         $filter = array(array(
854             'field'    => 'path', 
855             'operator' => 'equals', 
856             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testcontainer',
857         ), array(
858             'field'    => 'type', 
859             'operator' => 'equals', 
860             'value'    => Tinebase_Model_Tree_FileObject::TYPE_FILE,
861         ));
862         $result = $this->_getUit()->searchNodes($filter, array());
863         $this->assertEquals(2, $result['totalcount']);
864     }
865     
866     /**
867      * testCopyFileWithContentToFolder
868      */
869     public function testCopyFileWithContentToFolder()
870     {
871         $fileToCopy = $this->testCreateFileNodeWithTempfile();
872         $targetNode = $this->testCreateContainerNodeInPersonalFolder();
873         
874         $result = $this->_getUit()->copyNodes($fileToCopy['path'], $targetNode['path'], false);
875         $this->assertEquals(1, count($result));
876         $this->assertEquals($targetNode['path'] . '/test.txt', $result[0]['path']);
877         $this->assertEquals('text/plain', $result[0]['contenttype']);
878     }
879     
880     /**
881      * testCopyFileNodeToFileExisting
882      */
883     public function testCopyFileNodeToFileExisting()
884     {
885         $filesToCopy = $this->testCreateFileNodes();
886         $file1 = $filesToCopy[0];
887         $file2 = $filesToCopy[1];
888         
889         $this->setExpectedException('Filemanager_Exception_NodeExists');
890         $result = $this->_getUit()->copyNodes(array($file1), array($file2), false);
891     }
892     
893     /**
894      * testCopyFileNodeToFileExistingCatchException
895      */
896     public function testCopyFileNodeToFileExistingCatchException()
897     {
898         $filesToCopy = $this->testCreateFileNodes();
899         $file1 = $filesToCopy[0];
900         $file2 = $filesToCopy[1];
901         
902         try {
903             $result = $this->_getUit()->copyNodes(array($file1), array($file2), false);
904         } catch (Filemanager_Exception_NodeExists $fene) {
905             $info = $fene->toArray();
906             $this->assertEquals(1, count($info['existingnodesinfo']));
907             return;
908         }
909         
910         $this->fail('An expected exception has not been raised.');
911     }
912     
913     /**
914      * testMoveFolderNodesToFolder
915      */
916     public function testMoveFolderNodesToFolder()
917     {
918         $dirsToMove = $this->testCreateDirectoryNodesInShared();
919         $targetNode = $this->testCreateContainerNodeInPersonalFolder();
920         
921         $result = $this->_getUit()->moveNodes($dirsToMove, $targetNode['path'], false);
922         $this->assertEquals(2, count($result));
923         $this->assertEquals($targetNode['path'] . '/dir1', $result[0]['path'], 'no new path: ' . print_r($result, true));
924         
925         $filter = array(array(
926             'field'    => 'path', 
927             'operator' => 'equals', 
928             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED . '/testcontainer'
929         ), array(
930             'field'    => 'type', 
931             'operator' => 'equals', 
932             'value'    => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
933         ));
934
935         $result = $this->_getUit()->searchNodes($filter, array());
936         $this->assertEquals(0, $result['totalcount']);
937     }
938     
939     /**
940      * testMoveFolderNodesToFolderExisting
941      * 
942      * @see 0007028: moving a folder to another folder with a folder with the same name
943      */
944     public function testMoveFolderNodesToFolderExisting()
945     {
946         sleep(1);
947         $targetNode = $this->testCreateContainerNodeInPersonalFolder();
948         $testPath = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/dir1';
949         $result = $this->_getUit()->moveNodes(array($targetNode['path']), array($testPath), false);
950         $dirs = $this->testCreateDirectoryNodesInShared();
951         try {
952             $result = $this->_getUit()->moveNodes(array($testPath), '/shared/testcontainer', false);
953             $this->fail('Expected Filemanager_Exception_NodeExists!');
954         } catch (Filemanager_Exception_NodeExists $fene) {
955             $result = $this->_getUit()->moveNodes(array($testPath), '/shared/testcontainer', true);
956             $this->assertEquals(1, count($result));
957             $this->assertEquals('/shared/testcontainer/dir1', $result[0]['path']);
958         }
959     }
960
961     /**
962      * testMoveContainerFolderNodeToExistingContainer
963      * 
964      * @see 0007028: moving a folder to another folder with a folder with the same name
965      */
966     public function testMoveContainerFolderNodeToExistingContainer()
967     {
968         $targetNode = $this->testCreateContainerNodeInPersonalFolder();
969         
970         $testPath = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testcontainer2';
971         $result = $this->_getUit()->createNodes($testPath, Tinebase_Model_Tree_FileObject::TYPE_FOLDER, array(), false);
972         $createdNode = $result[0];
973
974         try {
975             $result = $this->_getUit()->moveNodes(array($targetNode['path']), array($createdNode['path']), false);
976             $this->fail('Expected Filemanager_Exception_NodeExists!');
977         } catch (Filemanager_Exception_NodeExists $fene) {
978             $result = $this->_getUit()->moveNodes(array($targetNode['path']), array($createdNode['path']), true);
979             $this->assertEquals(1, count($result));
980             $this->assertEquals($testPath, $result[0]['path']);
981         }
982     }
983     
984     /**
985     * testMoveFolderNodesToTopLevel
986     */
987     public function testMoveFolderNodesToTopLevel()
988     {
989         // we need the personal folder for the test user
990         $this->_setupTestPath(Tinebase_FileSystem::FOLDER_TYPE_PERSONAL);
991         
992         $dirsToMove = $this->testCreateDirectoryNodesInShared();
993         $targetPath = '/personal/' . Tinebase_Core::getUser()->accountLoginName;
994         $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($targetPath . '/dir1');
995         $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($targetPath . '/dir2');
996         
997         $result = $this->_getUit()->moveNodes($dirsToMove, $targetPath, false);
998         $this->assertEquals(2, count($result));
999         $this->assertEquals($targetPath . '/dir1', $result[0]['path']);
1000     }
1001     
1002     /**
1003      * testMoveContainerFolderNodesToContainerFolder
1004      */
1005     public function testMoveContainerFolderNodesToContainerFolder()
1006     {
1007         $sourceNode = $this->testCreateContainerNodeInPersonalFolder();
1008         
1009         $newPath = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testcontainermoved';
1010         $result = $this->_getUit()->moveNodes($sourceNode['path'], array($newPath), false);
1011         $this->assertEquals(1, count($result));
1012         $this->assertEquals($newPath, $result[0]['path'], 'no new path: ' . print_r($result, true));
1013
1014         $filter = array(array(
1015             'field'    => 'path', 
1016             'operator' => 'equals', 
1017             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName
1018         ), array(
1019             'field'    => 'type', 
1020             'operator' => 'equals', 
1021             'value'    => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
1022         ));
1023         $result = $this->_getUit()->searchNodes($filter, array());
1024         foreach ($result['results'] as $node) {
1025             $this->assertNotEquals($sourceNode['path'], $node['path']);
1026         }
1027     }
1028     
1029     /**
1030      * testMoveContainerFolderNodesToContainerFolderWithChildNodes
1031      */
1032     public function testMoveContainerFolderNodesToContainerFolderWithChildNodes()
1033     {
1034         $children = $this->testCreateDirectoryNodesInPersonal();
1035         
1036         $oldPath = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testcontainer';
1037         $newPath = $oldPath . 'moved';
1038         $result = $this->_getUit()->moveNodes(array($oldPath), array($newPath), false);
1039         $this->assertEquals(1, count($result));
1040         $this->assertEquals($newPath, $result[0]['path']);
1041
1042         $filter = array(array(
1043             'field'    => 'path', 
1044             'operator' => 'equals', 
1045             'value'    => $newPath
1046         ), array(
1047             'field'    => 'type', 
1048             'operator' => 'equals', 
1049             'value'    => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
1050         ));
1051         $result = $this->_getUit()->searchNodes($filter, array());
1052         $this->assertEquals(2, $result['totalcount']);
1053     }
1054     
1055     /**
1056      * testMoveFileNodesToFolder
1057      * 
1058      * @return array target node
1059      */
1060     public function testMoveFileNodesToFolder()
1061     {
1062         $filesToMove = $this->testCreateFileNodes();
1063         $targetNode = $this->testCreateContainerNodeInPersonalFolder();
1064         
1065         $result = $this->_getUit()->moveNodes($filesToMove, $targetNode['path'], false);
1066         $this->assertEquals(2, count($result));
1067         $this->assertEquals($targetNode['path'] . '/file1', $result[0]['path']);
1068
1069         $filter = array(array(
1070             'field'    => 'path', 
1071             'operator' => 'equals', 
1072             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED . '/testcontainer'
1073         ), array(
1074             'field'    => 'type', 
1075             'operator' => 'equals', 
1076             'value'    => Tinebase_Model_Tree_FileObject::TYPE_FILE,
1077         ));
1078         $result = $this->_getUit()->searchNodes($filter, array());
1079         $this->assertEquals(0, $result['totalcount']);
1080         
1081         return $targetNode;
1082     }
1083
1084     /**
1085      * testMoveFileNodesOverwrite
1086      */
1087     public function testMoveFileNodesOverwrite()
1088     {
1089         $targetNode = $this->testCopyFileNodesToFolder();
1090         
1091         $sharedContainerPath = '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED . '/testcontainer/';
1092         $filesToMove = array($sharedContainerPath . 'file1', $sharedContainerPath . 'file2');
1093         $result = $this->_getUit()->moveNodes($filesToMove, $targetNode['path'], true);
1094         
1095         $this->assertEquals(2, count($result));
1096     }
1097     
1098     /**
1099      * testMoveFolderNodeToRoot
1100      */
1101     public function testMoveFolderNodeToRoot()
1102     {
1103         $children = $this->testCreateDirectoryNodesInPersonal();
1104         
1105         $target = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName;
1106         $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($target . '/testcontainer');
1107         $result = $this->_getUit()->moveNodes($children[0], $target, false);
1108         $this->assertEquals(1, count($result));
1109         $this->assertEquals('dir1', $result[0]['name'], print_r($result[0], true));
1110     }
1111
1112     /**
1113      * Test if notes are correctly decorated with path field
1114      */
1115     public function testGetNode()
1116     {
1117         $node = $this->testCreateContainerNodeInPersonalFolder();
1118
1119         $result = Filemanager_Controller_Node::getInstance()->get($node['id']);
1120
1121         $this->assertTrue($result->path != "");
1122         $this->assertEquals('/personal/' . Tinebase_Core::getUser()->accountLoginName . '/testcontainer', $result->path);
1123     }
1124
1125     /**
1126      * testDeleteContainerNode
1127      */
1128     public function testDeleteContainerNode()
1129     {
1130         $sharedContainerNode = $this->testCreateContainerNodeInSharedFolder();
1131         
1132         $this->_getUit()->deleteNodes($sharedContainerNode['path']);
1133
1134         // check if node is deleted
1135         $this->setExpectedException('Tinebase_Exception_NotFound');
1136         $this->_fsController->stat($sharedContainerNode['path']);
1137     }
1138
1139     /**
1140      * testDeleteFileNodes
1141      */
1142     public function testDeleteFileNodes($_addData = false)
1143     {
1144         $filepaths = $this->testCreateFileNodes($_addData);
1145
1146         if (true === $_addData) {
1147             $parentFolder = $this->_fsController->stat(Filemanager_Controller_Node::getInstance()->addBasePath(dirname($filepaths[0])));
1148             static::assertEquals(16, $parentFolder->size, 'two files with 8 bytes each created, excpected 16 bytes folder size');
1149         }
1150         
1151         $this->_getUit()->deleteNodes($filepaths);
1152
1153         if (true === $_addData) {
1154             $parentFolder = $this->_fsController->stat(Filemanager_Controller_Node::getInstance()->addBasePath(dirname($filepaths[0])));
1155             static::assertEquals(0, $parentFolder->size, 'after deletion expected 0 byte folder size');
1156         }
1157
1158         // check if node is deleted
1159         try {
1160             $this->_fsController->stat(Filemanager_Controller_Node::getInstance()->addBasePath($filepaths[0]));
1161             $this->assertTrue(false);
1162         } catch (Tinebase_Exception_NotFound $tenf) {
1163             $this->assertTrue(true);
1164         }
1165     }
1166     
1167     /**
1168      * test cleanup of deleted files (database)
1169      * 
1170      * @see 0008062: add cleanup script for deleted files
1171      */
1172     public function testDeletedFileCleanupFromDatabase()
1173     {
1174         $fileNode = $this->testCreateFileNodeWithTempfile();
1175         
1176         // get "real" filesystem path + unlink
1177         $fileObjectBackend = new Tinebase_Tree_FileObject();
1178         $fileObject = $fileObjectBackend->get($fileNode['object_id']);
1179         unlink($fileObject->getFilesystemPath());
1180         
1181         $result = Tinebase_FileSystem::getInstance()->clearDeletedFilesFromDatabase();
1182         $this->assertEquals(1, $result, 'should cleanup one file');
1183
1184         $result = Tinebase_FileSystem::getInstance()->clearDeletedFilesFromDatabase();
1185         $this->assertEquals(0, $result, 'should cleanup no file');
1186         
1187         // node should no longer be found
1188         try {
1189             $this->_getUit()->getNode($fileNode['id']);
1190             $this->fail('tree node still exists: ' . print_r($fileNode, true));
1191         } catch (Tinebase_Exception_NotFound $tenf) {
1192             $this->assertEquals('Tinebase_Model_Tree_Node record with id = ' . $fileNode['id'] . ' not found!', $tenf->getMessage());
1193         }
1194     }
1195     
1196     /**
1197      * testDeleteDirectoryNodes
1198      */
1199     public function testDeleteDirectoryNodes()
1200     {
1201         $dirpaths = $this->testCreateDirectoryNodesInShared();
1202         
1203         $result = $this->_getUit()->deleteNodes($dirpaths);
1204
1205         // check if node is deleted
1206         $this->setExpectedException('Tinebase_Exception_NotFound');
1207         $node = $this->_fsController->stat(Filemanager_Controller_Node::getInstance()->addBasePath($dirpaths[0]));
1208     }
1209     
1210     /**
1211      * testGetUpdate
1212      * 
1213      * @see 0006736: Create File (Edit)InfoDialog
1214      * @return array
1215      */
1216     public function testGetUpdate()
1217     {
1218         $this->testCreateFileNodes();
1219         $filter = array(array(
1220             'field'    => 'path', 
1221             'operator' => 'equals', 
1222             'value'    => '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED . '/testcontainer'
1223         ));
1224         $result = $this->_getUit()->searchNodes($filter, array());
1225         
1226         $this->assertEquals(2, $result['totalcount']);
1227         $initialNode = $result['results'][0];
1228         
1229         $node = $this->_getUit()->getNode($initialNode['id']);
1230         $this->assertEquals('file', $node['type']);
1231         
1232         $node['description'] = 'UNITTEST';
1233         $node = $this->_getUit()->saveNode($node);
1234         
1235         $this->assertEquals('UNITTEST', $node['description']);
1236         $this->assertEquals($initialNode['contenttype'], $node['contenttype'], 'contenttype  not preserved');
1237
1238         
1239         return $node;
1240     }
1241
1242     /**
1243      * testAttachTag
1244      *
1245      * @see 0012284: file type changes to 'directory' if tag is assigned
1246      */
1247     public function testAttachTagPreserveContentType()
1248     {
1249         $node = $this->testCreateFileNodeWithTempfile();
1250         $node['tags'] = array(array(
1251             'type'          => Tinebase_Model_Tag::TYPE_PERSONAL,
1252             'name'          => 'file tag',
1253         ));
1254         $node['path'] = '';
1255         // remove hash field that the client does not send
1256         unset($node['hash']);
1257         $updatedNode = $this->_getUit()->saveNode($node);
1258
1259         $this->assertEquals(1, count($updatedNode['tags']));
1260         $this->assertEquals($node['contenttype'], $updatedNode['contenttype'], 'contenttype  not preserved');
1261     }
1262
1263     /**
1264      * testSetRelation
1265      * 
1266      * @see 0006736: Create File (Edit)InfoDialog
1267      */
1268     public function testSetRelation()
1269     {
1270         $node = $this->testGetUpdate();
1271         $node['relations'] = array($this->_getRelationData($node));
1272         $node = $this->_getUit()->saveNode($node);
1273         
1274         $this->assertEquals(1, count($node['relations']));
1275         $this->assertEquals('PHPUNIT, ali', $node['relations'][0]['related_record']['n_fileas']);
1276         
1277         $adbJson = new Addressbook_Frontend_Json();
1278         $contact = $adbJson->getContact($node['relations'][0]['related_id']);
1279         $this->assertEquals(1, count($contact['relations']), 'relations are missing');
1280         $this->assertEquals($node['name'], $contact['relations'][0]['related_record']['name']);
1281     }
1282     
1283     /**
1284      * get contact relation data
1285      * 
1286      * @param array $node
1287      * @return array
1288      */
1289     protected function _getRelationData($node)
1290     {
1291         return array(
1292             'own_model'              => 'Filemanager_Model_Node',
1293             'own_backend'            => 'Sql',
1294             'own_id'                 => $node['id'],
1295             'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
1296             'type'                   => 'FILE',
1297             'related_backend'        => 'Sql',
1298             'related_model'          => 'Addressbook_Model_Contact',
1299             'remark'                 => null,
1300             'related_record'         => array(
1301                 'n_given'           => 'ali',
1302                 'n_family'          => 'PHPUNIT',
1303                 'org_name'          => Tinebase_Record_Abstract::generateUID(),
1304                 'tel_cell_private'  => '+49TELCELLPRIVATE',
1305             )
1306         );
1307     }
1308
1309     /**
1310      * testSetRelationToFileInPersonalFolder
1311      * 
1312      * @see 0006736: Create File (Edit)InfoDialog
1313      */
1314     public function testSetRelationToFileInPersonalFolder()
1315     {
1316         $node = $this->testCreateFileNodeWithUTF8Filenames();
1317         $node['relations'] = array($this->_getRelationData($node));
1318         $node = $this->_getUit()->saveNode($node);
1319         
1320         $adbJson = new Addressbook_Frontend_Json();
1321         $contact = $adbJson->getContact($node['relations'][0]['related_id']);
1322         $this->assertEquals(1, count($contact['relations']));
1323         $relatedNode = $contact['relations'][0]['related_record'];
1324         $this->assertEquals($node['name'], $relatedNode['name']);
1325         $pathRegEx = '@^/personal/[a-f0-9-]+/testcontainer/' . preg_quote($relatedNode['name']) . '$@';
1326         $this->assertTrue(preg_match($pathRegEx, $relatedNode['path']) === 1, 'path mismatch: ' . print_r($relatedNode, true) . ' regex: ' . $pathRegEx);
1327     }
1328     
1329     /**
1330      * test renaming a folder in a folder containing a folder with the same name
1331      *
1332      * @see: https://forge.tine20.org/mantisbt/view.php?id=10132
1333      */
1334      public function testRenameFolderInFolderContainingFolderAlready()
1335      {
1336         $path = '/personal/' .Tinebase_Core::getUser()->accountLoginName . '/' . $this->_getPersonalFilemanagerContainer()->name;
1337      
1338         $this->_getUit()->createNode($path . '/Test1', 'folder', null, false);
1339         $this->_getUit()->createNode($path . '/Test1/Test2', 'folder', null, false);
1340         $this->_getUit()->createNode($path . '/Test1/Test3', 'folder', null, false);
1341         
1342         $this->setExpectedException('Filemanager_Exception_NodeExists');
1343         
1344         $this->_getUit()->moveNodes(array($path . '/Test1/Test3'), array($path . '/Test1/Test2'), false);
1345      }
1346     
1347     /**
1348      * tests the recursive filter
1349      */
1350     public function testSearchRecursiveFilter()
1351     {
1352         $fixtures = array(
1353             array('/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testa', 'color-red.gif'),
1354             array('/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testb', 'color-green.gif'),
1355             array('/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testc', 'color-blue.gif'));
1356
1357         $tempFileBackend = new Tinebase_TempFile();
1358         
1359         foreach($fixtures as $path) {
1360             $node = $this->_getUit()->createNode($path[0], Tinebase_Model_Tree_FileObject::TYPE_FOLDER, null, false);
1361             
1362             $this->assertEquals(str_replace('/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/', '', $path[0]), $node['name']);
1363             $this->assertEquals($path[0], $node['path']);
1364             
1365             $this->_objects['paths'][] = Filemanager_Controller_Node::getInstance()->addBasePath($node['path']);
1366     
1367             $filepath = $node['path'] . '/' . $path[1];
1368             // create empty file first (like the js frontend does)
1369             $result = $this->_getUit()->createNode($filepath, Tinebase_Model_Tree_FileObject::TYPE_FILE, array(), false);
1370             $tempFile = $tempFileBackend->createTempFile(dirname(dirname(__FILE__)) . '/files/' . $path[1]);
1371             $result = $this->_getUit()->createNode($filepath, Tinebase_Model_Tree_FileObject::TYPE_FILE, $tempFile->getId(), true);
1372         }
1373         
1374         $filter = array(
1375             array('field' => 'recursive', 'operator' => 'equals',   'value' => 1),
1376             array('field' => 'path',      'operator' => 'equals',   'value' => '/'),
1377             array('field' => 'query',     'operator' => 'contains', 'value' => 'color'),
1378         'AND');
1379         
1380         $result = $this->_getUit()->searchNodes($filter, array('sort' => 'name', 'start' => 0, 'limit' => 0));
1381         $this->assertEquals(3, count($result), '3 files should have been found!');
1382     }
1383     
1384     /**
1385      * test cleanup of deleted files (filesystem)
1386      */
1387     public function testDeletedFileCleanupFromFilesystem()
1388     {
1389         // remove all files with size 0 first
1390         $size0Nodes = Tinebase_FileSystem::getInstance()->searchNodes(new Tinebase_Model_Tree_Node_Filter(array(
1391             array('field' => 'type', 'operator' => 'equals', 'value' => Tinebase_Model_Tree_FileObject::TYPE_FILE),
1392             array('field' => 'size', 'operator' => 'equals', 'value' => 0)
1393         )));
1394         foreach ($size0Nodes as $node) {
1395             Tinebase_FileSystem::getInstance()->deleteFileNode($node);
1396         }
1397         
1398         $this->testDeleteFileNodes();
1399         $result = Tinebase_FileSystem::getInstance()->clearDeletedFilesFromFilesystem();
1400         $this->assertEquals(0, $result, 'should not clean up anything as files with size 0 are not written to disk');
1401         $this->tearDown();
1402         
1403         Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
1404         $this->testDeleteFileNodes(true);
1405         $result = Tinebase_FileSystem::getInstance()->clearDeletedFilesFromFilesystem();
1406         $this->assertEquals(1, $result, 'should cleanup one file');
1407     }
1408     
1409     /**
1410      * test preventing to copy a folder in its subfolder
1411      * 
1412      * @see: https://forge.tine20.org/mantisbt/view.php?id=9990
1413      */
1414     public function testMoveFolderIntoChildFolder()
1415     {
1416         $this->_getUit()->createNode('/shared/Parent', 'folder', null, false);
1417         $this->_getUit()->createNode('/shared/Parent/Child', 'folder', null, false);
1418         
1419         $this->setExpectedException('Filemanager_Exception_DestinationIsOwnChild');
1420         
1421         // this must not work
1422         $this->_getUit()->moveNodes(array('/shared/Parent'), array('/shared/Parent/Child/Parent'), false);
1423     }
1424     
1425     /**
1426      * test exception on moving to the same position
1427      * 
1428      * @see: https://forge.tine20.org/mantisbt/view.php?id=9990
1429      */
1430     public function testMoveFolderToSamePosition()
1431     {
1432         $this->_getUit()->createNode('/shared/Parent', 'folder', null, false);
1433         $this->_getUit()->createNode('/shared/Parent/Child', 'folder', null, false);
1434     
1435         $this->setExpectedException('Filemanager_Exception_DestinationIsSameNode');
1436     
1437         // this must not work
1438         $this->_getUit()->moveNodes(array('/shared/Parent/Child'), array('/shared/Parent/Child'), false);
1439     }
1440
1441     /**
1442      * test to move a folder containing another folder
1443      *
1444      * @see: https://forge.tine20.org/mantisbt/view.php?id=9990
1445      */
1446     public function testMove2FoldersOnToplevel()
1447     {
1448         $path = '/personal/' .Tinebase_Core::getUser()->accountLoginName . '/' . $this->_getPersonalFilemanagerContainer()->name;
1449     
1450         $this->_getUit()->createNode($path . '/Parent', 'folder', null, false);
1451         $this->_getUit()->createNode($path . '/Parent/Child', 'folder', null, false);
1452         $this->_getUit()->createNode('/shared/Another', 'folder', null, false);
1453     
1454         // move forth and back, no exception should occur
1455         $this->_getUit()->moveNodes(array($path . '/Parent'), array('/shared/Parent'), false);
1456         $this->_getUit()->moveNodes(array('/shared/Parent'), array($path . '/Parent'), false);
1457     
1458         try {
1459             $c = Tinebase_Container::getInstance()->getContainerByName('Filemanager', 'Parent', Tinebase_FileSystem::FOLDER_TYPE_SHARED);
1460             $this->fail('Container doesn\'t get deleted');
1461         } catch (Tinebase_Exception_NotFound $e) {
1462         }
1463         
1464         // may be any exception
1465         $e = new Tinebase_Exception('Dog eats cat');
1466     
1467         try {
1468             $this->_getUit()->moveNodes(array($path . '/Parent'), array('/shared/Parent'), false);
1469         } catch (Filemanager_Exception_NodeExists $e) {
1470         }
1471     
1472         // if $e gets overridden, an error occured (the exception Filemanager_Exception_NodeExists must not be thrown)
1473         $this->assertEquals('Tinebase_Exception', get_class($e));
1474     }
1475     
1476     /**
1477      * test creating a folder in a folder with the same name (below personal folders)
1478      *
1479      * @see: https://forge.tine20.org/mantisbt/view.php?id=10132
1480      */
1481     public function testCreateFolderInFolderWithSameName()
1482     {
1483         $path = '/personal/' .Tinebase_Core::getUser()->accountLoginName . '/' . $this->_getPersonalFilemanagerContainer()->name;
1484
1485         $result = $this->_getUit()->createNode($path . '/Test1', 'folder', null, false);
1486         $this->assertTrue(isset($result['id']));
1487         $result = $this->_getUit()->createNode($path . '/Test1/Test1', 'folder', null, false);
1488         $this->assertTrue(isset($result['id']), 'node has not been created');
1489         $e = new Tinebase_Exception('nothing');
1490         try {
1491             $this->_getUit()->createNode($path . '/Test1/Test1/Test2', 'folder', null, false);
1492         } catch (Exception $e) {
1493             $this->fail('The folder couldn\'t be found, so it hasn\'t ben created');
1494         }
1495         
1496         $this->assertEquals('nothing', $e->getMessage());
1497     }
1498     
1499     /**
1500      * get other users container
1501      * 
1502      * @return Tinebase_Model_Container
1503      */
1504     protected function _getOtherUserContainer()
1505     {
1506         if (!$this->_otherUserContainer) {
1507             $sclever = $this->_personas['sclever'];
1508
1509             $path = Tinebase_FileSystem::getInstance()->getApplicationBasePath(
1510                 $this->_application, Tinebase_FileSystem::FOLDER_TYPE_PERSONAL) . '/' . $sclever->getId() . '/clever';
1511             if (Tinebase_FileSystem::getInstance()->fileExists($path)) {
1512                 $this->_otherUserContainer = Tinebase_FileSystem::getInstance()->stat($path);
1513             } else {
1514                 $grants = Tinebase_Model_Grants::getPersonalGrants($sclever);
1515                 $grants->addRecord(new Tinebase_Model_Grants(array(
1516                     'account_type' => Tinebase_Acl_Rights::ACCOUNT_TYPE_ANYONE,
1517                     'account_id' => 0,
1518                     Tinebase_Model_Grants::GRANT_READ => true,
1519                 )));
1520                 $this->_otherUserContainer = Tinebase_FileSystem::getInstance()->createAclNode($path, $grants);
1521             }
1522         }
1523         
1524         return $this->_otherUserContainer;
1525     }
1526     
1527     /**
1528      * get personal container
1529      * 
1530      * @return Tinebase_Model_Tree_Node
1531      */
1532     protected function _getPersonalFilemanagerContainer()
1533     {
1534         if (!$this->_personalContainer) {
1535             $user = Tinebase_Core::getUser();
1536             $this->_personalContainer = Tinebase_FileSystem::getInstance()->getPersonalContainer($user, 'Filemanager', $user)->getFirstRecord();
1537         }
1538         
1539         return $this->_personalContainer;
1540     }
1541     
1542     /**
1543      * get shared container
1544      * 
1545      * @return Tinebase_Model_Container
1546      */
1547     protected function _getSharedContainer()
1548     {
1549         if (!$this->_sharedContainer) {
1550             $path = Tinebase_FileSystem::getInstance()->getApplicationBasePath(
1551                     $this->_application, Tinebase_FileSystem::FOLDER_TYPE_SHARED) . '/shared';
1552             try {
1553                 $this->_sharedContainer = Tinebase_FileSystem::getInstance()->stat($path);
1554             } catch (Tinebase_Exception_NotFound $tenf) {
1555                 $this->_sharedContainer = Tinebase_FileSystem::getInstance()->createAclNode($path);
1556             }
1557         }
1558         
1559         return $this->_sharedContainer;
1560     }
1561     
1562     /**
1563      * setup the test paths
1564      * 
1565      * @param string|array $_types
1566      */
1567     protected function _setupTestPath($_types)
1568     {
1569         $testPaths = array();
1570         $types = (array) $_types;
1571         
1572         foreach ($types as $type) {
1573             switch ($type) {
1574                 case Tinebase_FileSystem::FOLDER_TYPE_PERSONAL:
1575                     $testPaths[] = Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->getId() . '/' 
1576                         . $this->_getPersonalFilemanagerContainer()->name . '/unittestdir_personal';
1577                     break;
1578                 case Tinebase_FileSystem::FOLDER_TYPE_SHARED:
1579                     $testPaths[] = Tinebase_FileSystem::FOLDER_TYPE_SHARED . '/' . $this->_getSharedContainer()->name . '/unittestdir_shared';
1580                     break;
1581                 case Tinebase_Model_Container::TYPE_OTHERUSERS:
1582                     $personas = Zend_Registry::get('personas');
1583                     $testPaths[] = Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . $personas['sclever']->getId() . '/' 
1584                         . $this->_getOtherUserContainer()->name . '/unittestdir_other';
1585                     break;
1586             }
1587         }
1588         
1589         foreach ($testPaths as $path) {
1590             $path = Filemanager_Controller_Node::getInstance()->addBasePath($path);
1591             $this->_objects['paths'][] = $path;
1592             $this->_fsController->mkdir($path);
1593         }
1594     }
1595     
1596     /**
1597      * testSaveDownloadLinkFile
1598      * 
1599      * @return array Filemanager_Model_DownloadLink
1600      */
1601     public function testSaveDownloadLinkFile()
1602     {
1603         $downloadLinkData = $this->_getDownloadLinkData();
1604         $result = $this->_getUit()->saveDownloadLink($downloadLinkData);
1605         
1606         $this->assertTrue(! empty($result['url']));
1607         $this->assertEquals($this->_getDownloadUrl($result['id']), $result['url']);
1608         $this->assertEquals(0, $result['access_count']);
1609         
1610         return $result;
1611     }
1612
1613     protected function _getDownloadUrl($id)
1614     {
1615         return Tinebase_Core::getUrl() . '/download/show/' . $id;
1616     }
1617     
1618     /**
1619      * testSaveDownloadLinkDirectory
1620      *
1621      * @return array Filemanager_Model_DownloadLink
1622      */
1623     public function testSaveDownloadLinkDirectory()
1624     {
1625         $downloadLinkData = $this->_getDownloadLinkData();
1626         $result = $this->_getUit()->saveDownloadLink($downloadLinkData);
1627         
1628         $this->assertTrue(! empty($result['url']));
1629         $this->assertEquals($this->_getDownloadUrl($result['id']), $result['url']);
1630         
1631         return $result;
1632     }
1633     
1634     /**
1635      * get download link data
1636      * 
1637      * @param string $nodeType
1638      * @return array
1639      * @throws Tinebase_Exception_InvalidArgument
1640      */
1641     protected function _getDownloadLinkData($nodeType = Tinebase_Model_Tree_FileObject::TYPE_FILE)
1642     {
1643         // create node first
1644         if ($nodeType === Tinebase_Model_Tree_FileObject::TYPE_FILE) {
1645             $node = $this->testCreateFileNodeWithTempfile();
1646         } else if ($nodeType === Tinebase_Model_Tree_FileObject::TYPE_FOLDER) {
1647             $node = $this->testCreateContainerNodeInPersonalFolder();
1648         } else {
1649             throw new Tinebase_Exception_InvalidArgument('only file and folder nodes are supported');
1650         }
1651         
1652         return array(
1653             'node_id'       => $node['id'],
1654             'expiry_date'   => Tinebase_DateTime::now()->addDay(1)->toString(),
1655             'access_count'  => 7,
1656         );
1657     }
1658     
1659     /**
1660      * testGetDownloadLink
1661      */
1662     public function testGetDownloadLink()
1663     {
1664         $downloadLink = $this->testSaveDownloadLinkFile();
1665         
1666         $this->assertEquals($downloadLink, $this->_getUit()->getDownloadLink($downloadLink['id']));
1667     }
1668     
1669     /**
1670      * testSearchDownloadLinks
1671      */
1672     public function testSearchDownloadLinks()
1673     {
1674         $downloadLink = $this->testSaveDownloadLinkFile();
1675         $filter = array(array(
1676             'field'     => 'id',
1677             'operator'  => 'equals',
1678             'value'     => $downloadLink['id']
1679         ));
1680         $result = $this->_getUit()->searchDownloadLinks($filter, array());
1681         
1682         $this->assertEquals(1, $result['totalcount']);
1683     }
1684
1685     /**
1686      * testDeleteDownloadLinks
1687      */
1688     public function testDeleteDownloadLinks()
1689     {
1690         $downloadLink = $this->testSaveDownloadLinkFile();
1691
1692         $this->_getUit()->deleteDownloadLinks(array($downloadLink['id']));
1693         try {
1694             Filemanager_Controller_DownloadLink::getInstance()->get($downloadLink['id']);
1695             $this->fail('link should have been deleted');
1696         } catch (Exception $e) {
1697             $this->assertTrue($e instanceof Tinebase_Exception_NotFound);
1698         }
1699     }
1700
1701     /**
1702      * @see 0012788: allow acl for all folder nodes
1703      */
1704     public function testNodeAclAndPathResolving()
1705     {
1706         $this->testCreateFileNodes();
1707
1708         // search folders + assert grants
1709         $sharedRoot = '/' . Tinebase_FileSystem::FOLDER_TYPE_SHARED;
1710         $filter = array(array(
1711             'field'    => 'path',
1712             'operator' => 'equals',
1713             'value'    => $sharedRoot
1714         ));
1715         $result = $this->_getUit()->searchNodes($filter, array());
1716
1717         self::assertEquals(1, $result['totalcount']);
1718         $node = $result['results'][0];
1719         self::assertEquals('/shared/testcontainer', $node['path'], 'no path found in node: ' . print_r($node, true));
1720         $this->_assertGrantsInNode($node);
1721
1722         // search files + assert grants
1723         $filter = array(array(
1724             'field'    => 'path',
1725             'operator' => 'equals',
1726             'value'    => $node['path']
1727         ));
1728         $result = $this->_getUit()->searchNodes($filter, array());
1729         self::assertEquals(2, $result['totalcount'], 'no files found in path: ' . print_r($result, true));
1730         $file1Node = $result['results'][0];
1731         self::assertContains('/shared/testcontainer/file', $file1Node['path'], 'no path found in node: ' . print_r($file1Node, true));
1732         $this->_assertGrantsInNode($file1Node);
1733
1734         $file2Node = $this->_getUit()->getNode($result['results'][1]['id']);
1735         self::assertContains('/shared/testcontainer/file', $file2Node['path'], 'no path found in node: ' . print_r($file2Node, true));
1736         $this->_assertGrantsInNode($file2Node);
1737     }
1738
1739     /**
1740      * check if account grants are resolved correctly
1741      *
1742      * @param $nodeArray
1743      */
1744     protected function _assertGrantsInNode($nodeArray)
1745     {
1746         self::assertEquals(2, count($nodeArray['grants']));
1747         self::assertTrue(is_array($nodeArray['grants'][0]['account_name']), 'account_name is not resolved');
1748         self::assertEquals(true, count($nodeArray['account_grants']['adminGrant']));
1749     }
1750
1751     public function testSetNodeAcl()
1752     {
1753         $node = $this->testCreateContainerNodeInSharedFolder();
1754         $node['grants'] = Tinebase_Model_Grants::getPersonalGrants(Tinebase_Core::getUser())->toArray();
1755         $result = $this->_getUit()->saveNode($node);
1756
1757         self::assertEquals(1, count($result['grants']), print_r($result['grants'], true));
1758         self::assertEquals(Tinebase_Acl_Rights::ACCOUNT_TYPE_USER, $result['grants'][0]['account_type']);
1759
1760         return $node;
1761     }
1762
1763     public function testRemoveNodeAclTopLevel()
1764     {
1765         $node = $this->testSetNodeAcl();
1766         $node['grants'] = null;
1767         $result = $this->_getUit()->saveNode($node);
1768
1769         self::assertEquals(1, count($result['grants']), 'it is not allowed to remove top level node grants - '
1770             . print_r($result['grants'], true));
1771     }
1772
1773     public function testRemoveNodeAclChildLevel()
1774     {
1775         $node = $this->testCreateContainerNodeInSharedFolder();
1776         // create child folder node
1777         $testPath = $node['path'] . '/child';
1778         $child = $this->_getUit()->createNode($testPath, Tinebase_Model_Tree_FileObject::TYPE_FOLDER, null, false);
1779
1780         $child['grants'] = Tinebase_Model_Grants::getPersonalGrants(Tinebase_Core::getUser())->toArray();
1781         $child['acl_node'] = $child['id'];
1782         $child = $this->_getUit()->saveNode($child);
1783
1784         self::assertEquals(1, count($child['grants']), 'node should have only personal grants - '
1785             . print_r($child['grants'], true));
1786
1787         $child['acl_node'] = null;
1788         $childWithoutPersonalGrants = $this->_getUit()->saveNode($child);
1789
1790         self::assertEquals(2, count($childWithoutPersonalGrants['grants']), 'node should have parent grants again - '
1791             . print_r($childWithoutPersonalGrants['grants'], true));
1792     }
1793
1794     public function testRecursiveFilter()
1795     {
1796         $folders = $this->testCreateDirectoryNodesInPersonal();
1797         $prefix = Tinebase_FileSystem::getInstance()->getApplicationBasePath('Filemanager') . '/folders';
1798
1799         $i = 0;
1800         foreach($folders as $folder) {
1801             $path = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $folder . '/test.txt');
1802             $handle = Tinebase_FileSystem::getInstance()->fopen($path->statpath, 'w');
1803             $this->assertTrue(is_resource($handle), 'fopen did not return resource');
1804
1805             $written = fwrite($handle, 'RecursiveTest' . (++$i));
1806             $this->assertEquals(14, $written, 'failed to write 14 bytes to ' . $folder . '/test.txt');
1807
1808             $result = Tinebase_FileSystem::getInstance()->fclose($handle);
1809             $this->assertTrue($result, 'fclose did not return true');
1810         }
1811
1812         $path = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testcontainer';
1813         $this->_rmDir[] = $path;
1814         $paths = array($path . '/dir1/test.txt', $path . '/dir2/test.txt');
1815         Tinebase_TransactionManager::getInstance()->commitTransaction($this->_transactionId);
1816         $this->_transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
1817
1818         $result = $this->_getUit()->searchNodes(array(
1819             array(
1820                 'field'    => 'recursive',
1821                 'operator' => 'equals',
1822                 'value'    => 'true'
1823             ),
1824             array(
1825                 'field'    => 'query',
1826                 'operator' => 'contains',
1827                 'value'    => 'RecursiveTe'
1828             ),
1829         ), null);
1830
1831         $this->assertEquals(2, $result['totalcount'], 'did not find expected 2 files: ' . print_r($result, true));
1832         foreach($result['results'] as $result) {
1833             $this->assertTrue(in_array($result['path'], $paths), 'result doesn\'t match expected paths: ' . print_r($result, true) . print_r($paths, true));
1834         }
1835     }
1836
1837     protected function _statPaths($_paths)
1838     {
1839         $fileSystem = Tinebase_FileSystem::getInstance();
1840         $result = array();
1841
1842         /**
1843          * @var  string $key
1844          * @var  Tinebase_Model_Tree_Node_Path $path
1845          */
1846         foreach($_paths as $key => $path) {
1847             $result[$key] = $fileSystem->stat($path->statpath);
1848         }
1849
1850         return $result;
1851     }
1852
1853     protected function _assertRevisionProperties(array $_nodes, array $_defaultResult, array $_resultMap = array())
1854     {
1855         /**
1856          * @var string $key
1857          * @var Tinebase_Model_Tree_Node $node
1858          */
1859         foreach($_nodes as $key => $node) {
1860             $actual = $node->xprops(Tinebase_Model_Tree_Node::XPROPS_REVISION);
1861             if (!empty($actual) && isset($actual[Tinebase_Model_Tree_Node::XPROPS_REVISION_NODE_ID])) {
1862                 unset($actual[Tinebase_Model_Tree_Node::XPROPS_REVISION_NODE_ID]);
1863             }
1864             $expected = isset($_resultMap[$key]) ? $_resultMap[$key] : $_defaultResult;
1865             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));
1866         }
1867     }
1868
1869     protected function _setRevisionProperties(Tinebase_Model_Tree_Node $_node, array $_properties)
1870     {
1871         foreach($_properties as $key => $value) {
1872             $_node->xprops(Tinebase_Model_Tree_Node::XPROPS_REVISION)[$key] = $value;
1873         }
1874         $_node->xprops(Tinebase_Model_Tree_Node::XPROPS_REVISION)[Tinebase_Model_Tree_Node::XPROPS_REVISION_NODE_ID] =
1875             $_node->getId();
1876     }
1877
1878     public function testSetRevisionSettings()
1879     {
1880         $fileSystem = Tinebase_FileSystem::getInstance();
1881         $prefix = $fileSystem->getApplicationBasePath('Filemanager') . '/folders';
1882
1883         $this->testCreateDirectoryNodesInPersonal();
1884         $path = '/' . Tinebase_FileSystem::FOLDER_TYPE_PERSONAL . '/' . Tinebase_Core::getUser()->accountLoginName . '/testcontainer';
1885         $this->_getUit()->createNodes(array($path . '/dir1/subdir11', $path . '/dir1/subdir12'), Tinebase_Model_Tree_FileObject::TYPE_FOLDER, array(), false);
1886         $this->_getUit()->createNodes(array($path . '/dir2/subdir21', $path . '/dir2/subdir22'), Tinebase_Model_Tree_FileObject::TYPE_FOLDER, array(), false);
1887
1888
1889         // NONE of them have revision properties
1890         $paths = array(
1891             'dir1'          => Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir1'),
1892             'subDir11'      => Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir1/subdir11'),
1893             'subDir12'      => Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir1/subdir12'),
1894             'dir2'          => Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2'),
1895             'subDir21'      => Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir21'),
1896             'subDir22'      => Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir22'),
1897             'testContainer' => Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path),
1898         );
1899
1900         $nodes = $this->_statPaths($paths);
1901         $this->_assertRevisionProperties($nodes, array());
1902
1903
1904
1905         // ADD revision properties to the DIR1 subtree
1906         $dir1TreeRevisionProperties = array(
1907             Tinebase_Model_Tree_Node::XPROPS_REVISION_MONTH => 1,
1908             Tinebase_Model_Tree_Node::XPROPS_REVISION_NUM   => 2,
1909             Tinebase_Model_Tree_Node::XPROPS_REVISION_ON    => true
1910         );
1911         $this->_setRevisionProperties($nodes['dir1'], $dir1TreeRevisionProperties);
1912
1913         $this->_getUit()->saveNode($nodes['dir1']->toArray());
1914
1915         $fileSystem->clearStatCache();
1916         $nodes = $this->_statPaths($paths);
1917         $this->_assertRevisionProperties($nodes, array(), array(
1918             'dir1'      => $dir1TreeRevisionProperties,
1919             'subDir11'  => $dir1TreeRevisionProperties,
1920             'subDir12'  => $dir1TreeRevisionProperties
1921         ));
1922
1923
1924
1925         // MOVE DIR1 subtree below SUBDIR21 => nothing should change
1926         $fileSystem->rename($paths['dir1']->statpath, $paths['subDir21']->statpath . '/tmp');
1927
1928         $fileSystem->clearStatCache();
1929         $paths['dir1']     = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir21/tmp');
1930         $paths['subDir11'] = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir21/tmp/subdir11');
1931         $paths['subDir12'] = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir21/tmp/subdir12');
1932         $nodes = $this->_statPaths($paths);
1933         $this->_assertRevisionProperties($nodes, array(), array(
1934             'dir1'      => $dir1TreeRevisionProperties,
1935             'subDir11'  => $dir1TreeRevisionProperties,
1936             'subDir12'  => $dir1TreeRevisionProperties
1937         ));
1938
1939
1940
1941         // ADD revision properties to the SUBDIR22 subtree
1942         $subdir22TreeRevisionProperties = array(
1943             Tinebase_Model_Tree_Node::XPROPS_REVISION_MONTH => 2,
1944             Tinebase_Model_Tree_Node::XPROPS_REVISION_NUM   => 3,
1945             Tinebase_Model_Tree_Node::XPROPS_REVISION_ON    => true
1946         );
1947         $this->_setRevisionProperties($nodes['subDir22'], $subdir22TreeRevisionProperties);
1948
1949         $this->_getUit()->saveNode($nodes['subDir22']->toArray());
1950
1951         // MOVE DIR1 from SUBDIR21 to SUBDIR22 => they should still not change!
1952         $fileSystem->rename($paths['dir1']->statpath, $paths['subDir22']->statpath . '/tmp');
1953
1954         $fileSystem->clearStatCache();
1955         $paths['dir1']     = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir22/tmp');
1956         $paths['subDir11'] = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir22/tmp/subdir11');
1957         $paths['subDir12'] = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir22/tmp/subdir12');
1958         $nodes = $this->_statPaths($paths);
1959         $this->_assertRevisionProperties($nodes, array(), array(
1960             'subDir22'  => $subdir22TreeRevisionProperties,
1961             'dir1'      => $dir1TreeRevisionProperties,
1962             'subDir11'  => $dir1TreeRevisionProperties,
1963             'subDir12'  => $dir1TreeRevisionProperties
1964         ));
1965
1966
1967
1968         // MOVE subDir11 to subDir21 => should change to empty
1969         $fileSystem->rename($paths['subDir11']->statpath, $paths['subDir21']->statpath . '/tmp');
1970
1971         $fileSystem->clearStatCache();
1972         $paths['subDir11'] = Tinebase_Model_Tree_Node_Path::createFromPath($prefix . $path . '/dir2/subdir21/tmp');
1973         $nodes = $this->_statPaths($paths);
1974         $this->_assertRevisionProperties($nodes, array(), array(
1975             'subDir22'  => $subdir22TreeRevisionProperties,
1976             'dir1'      => $dir1TreeRevisionProperties,
1977             'subDir12'  => $dir1TreeRevisionProperties
1978         ));
1979
1980
1981
1982         // reset properties for whole tree
1983         $testContainerRevisionProperties = array(
1984             Tinebase_Model_Tree_Node::XPROPS_REVISION_MONTH => 6,
1985             Tinebase_Model_Tree_Node::XPROPS_REVISION_NUM   => 5,
1986             Tinebase_Model_Tree_Node::XPROPS_REVISION_ON    => false
1987         );
1988         $this->_setRevisionProperties($nodes['testContainer'], $testContainerRevisionProperties);
1989
1990         $this->_getUit()->saveNode($nodes['testContainer']->toArray());
1991
1992         $fileSystem->clearStatCache();
1993         $nodes = $this->_statPaths($paths);
1994         $this->_assertRevisionProperties($nodes, $testContainerRevisionProperties);
1995     }
1996
1997     public function testGetFolderUsage()
1998     {
1999         $result = $this->testCreateFileNodeWithTempfile();
2000
2001         $usageInfo = $this->_getUit()->getFolderUsage($result['parent_id']);
2002         $userId = Tinebase_Core::getUser()->contact_id;
2003
2004         $this->assertEquals(17, $usageInfo['type']['txt']['size']);
2005         $this->assertEquals(17, $usageInfo['type']['txt']['revision_size']);
2006         $this->assertEquals(17, $usageInfo['createdBy'][$userId]['size']);
2007         $this->assertEquals(17, $usageInfo['createdBy'][$userId]['revision_size']);
2008         $this->assertEquals($userId, $usageInfo['contacts'][0]['id']);
2009     }
2010 }