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