]> source.dussan.org Git - nextcloud-server.git/commitdiff
Added searchByTags to view, storage and cache
authorVincent Petry <pvince81@owncloud.com>
Thu, 4 Dec 2014 13:01:15 +0000 (14:01 +0100)
committerVincent Petry <pvince81@owncloud.com>
Thu, 11 Dec 2014 16:38:50 +0000 (17:38 +0100)
apps/files_sharing/lib/cache.php
apps/files_sharing/tests/cache.php
lib/private/files/cache/cache.php
lib/private/files/cache/wrapper/cachewrapper.php
lib/private/files/filesystem.php
lib/private/files/node/folder.php
lib/private/files/node/nonexistingfolder.php
lib/private/files/view.php
lib/public/files/folder.php
tests/lib/files/cache/cache.php

index e09b64cb0398ab5a42b7cfe708107be4a3f150e5..da8155ec6fac299052b3ac2ac4e451b4a14703d6 100644 (file)
@@ -344,6 +344,46 @@ class Shared_Cache extends Cache {
                return $result;
        }
 
+       /**
+        * search for files by tag
+        *
+        * @param string|int $tag tag to search for
+        * @param string $userId owner of the tags
+        * @return array file data
+        */
+       public function searchByTag($tag, $userId = null) {
+               // TODO: inject this
+               $tagger = \OC::$server->getTagManager()->load('files', null, null, $userId);
+               $result = array();
+               $exploreDirs = array('');
+               // FIXME: this is so wrong and unefficient, need to replace with actual DB queries
+               while (count($exploreDirs) > 0) {
+                       $dir = array_pop($exploreDirs);
+                       $files = $this->getFolderContents($dir);
+                       // no results?
+                       if (!$files) {
+                               // maybe it's a single shared file
+                               $file = $this->get('');
+                               $tags = $tagger->getTagsForObjects(array((int)$file['fileid']));
+                               if (!empty($tags) && in_array($tag, current($tags))) {
+                                       $result[] = $file;
+                               }
+                               continue;
+                       }
+                       foreach ($files as $file) {
+                               if ($file['mimetype'] === 'httpd/unix-directory') {
+                                       $exploreDirs[] = ltrim($dir . '/' . $file['name'], '/');
+                               } else {
+                                       $tags = $tagger->getTagsForObjects(array((int)$file['fileid']));
+                                       if (!empty($tags) && in_array($tag, current($tags))) {
+                                               $result[] = $file;
+                                       }
+                               }
+                       }
+               }
+               return $result;
+       }
+
        /**
         * get the size of a folder and set it in the cache
         *
index aec1983bad3c9b667e4747d29644bf30eb45809b..c40a014d5577adb27118ded10021c75a0785a8cd 100644 (file)
@@ -204,6 +204,39 @@ class Test_Files_Sharing_Cache extends TestCase {
                $this->verifyFiles($check, $results);
        }
 
+       /**
+        * Test searching by tag
+        */
+       function testSearchByTag() {
+               $id1 = $this->sharedCache->get('bar.txt')['fileid'];
+               $id2 = $this->sharedCache->get('subdir/another too.txt')['fileid'];
+               $id3 = $this->sharedCache->get('subdir/not a text file.xml')['fileid'];
+               $id4 = $this->sharedCache->get('subdir/another.txt')['fileid'];
+               $tagManager = \OC::$server->getTagManager()->load('files');
+               $tagManager->tagAs($id1, 'tag1');
+               $tagManager->tagAs($id1, 'tag2');
+               $tagManager->tagAs($id2, 'tag1');
+               $tagManager->tagAs($id3, 'tag1');
+               $tagManager->tagAs($id4, 'tag2');
+               $results = $this->sharedStorage->getCache()->searchByTag('tag1');
+               $check = array(
+                               array(
+                                       'name' => 'bar.txt',
+                                       'path' => 'bar.txt'
+                               ),
+                               array(
+                                       'name' => 'another too.txt',
+                                       'path' => 'subdir/another too.txt'
+                               ),
+                               array(
+                                       'name' => 'not a text file.xml',
+                                       'path' => 'subdir/not a text file.xml'
+                               ),
+                       );
+               $this->verifyFiles($check, $results);
+               $tagManager->delete(array('tag1', 'tag2'));
+       }
+
        function testGetFolderContentsInRoot() {
                $results = $this->user2View->getDirectoryContent('/');
 
index 4157da2281cd7d6d6fb7fcd42f2236bb0d022340..a4ae3a069fe8187830865deb5a5e21fb5face262 100644 (file)
@@ -503,6 +503,54 @@ class Cache {
                return $files;
        }
 
+       /**
+        * Search for files by tag of a given users.
+        *
+        * Note that every user can tag files differently.
+        *
+        * @param string|int $tag name or tag id
+        * @param string $userId owner of the tags
+        * @return array file data
+        */
+       public function searchByTag($tag, $userId = null) {
+               if (is_null($userId)) {
+                       $userId = \OC::$server->getUserSession()->getUser()->getUID(); 
+               }
+               $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, ' .
+                       '`mimetype`, `mimepart`, `size`, `mtime`, ' .
+                       '`encrypted`, `unencrypted_size`, `etag`, `permissions` ' .
+                       'FROM `*PREFIX*filecache` `file`, ' .
+                       '`*PREFIX*vcategory_to_object` `tagmap`, ' .
+                       '`*PREFIX*vcategory` `tag` ' .
+                       // JOIN filecache to vcategory_to_object
+                       'WHERE `file`.`fileid` = `tagmap`.`objid` '.
+                       // JOIN vcategory_to_object to vcategory
+                       'AND `tagmap`.`type` = `tag`.`type` ' .
+                       'AND `tagmap`.`categoryid` = `tag`.`id` ' .
+                       // conditions
+                       'AND `file`.`storage` = ? '.
+                       'AND `tag`.`type` = \'files\' ' .
+                       'AND `tag`.`uid` = ? ';
+               if (is_int($tag)) {
+                       $sql .= 'AND `tag`.`id` = ? ';
+               } else {
+                       $sql .= 'AND `tag`.`category` = ? ';
+               }
+               $result = \OC_DB::executeAudited(
+                       $sql,
+                       array(
+                               $this->getNumericStorageId(),
+                               $userId,
+                               $tag
+                       )
+               );
+               $files = array();
+               while ($row = $result->fetchRow()) {
+                       $files[] = $row;
+               }
+               return $files;
+       }
+
        /**
         * update the folder size and the size of all parent folders
         *
index d3d64e3f0a966b9249b954054ea647aa4403e45b..4da7c7ecf6f36017b942615ef4a12ba3eb5c34d0 100644 (file)
@@ -180,6 +180,18 @@ class CacheWrapper extends Cache {
                return array_map(array($this, 'formatCacheEntry'), $results);
        }
 
+       /**
+        * search for files by tag
+        *
+        * @param string|int $tag name or tag id
+        * @param string $userId owner of the tags
+        * @return array file data
+        */
+       public function searchByTag($tag, $userId = null) {
+               $results = $this->cache->searchByTag($tag, $userId);
+               return array_map(array($this, 'formatCacheEntry'), $results);
+       }
+
        /**
         * update the folder size and the size of all parent folders
         *
index 90643839e22befe993c71251b002c260135317e5..3d55564f0c65dee3a39842e8ffc8fd00eef49803 100644 (file)
@@ -686,6 +686,14 @@ class Filesystem {
                return self::$defaultInstance->searchByMime($query);
        }
 
+       /**
+        * @param string|int $tag name or tag id
+        * @return FileInfo[] array or file info
+        */
+       static public function searchByTag($tag) {
+               return self::$defaultInstance->searchByTag($tag);
+       }
+
        /**
         * check if a file or folder has been updated since $time
         *
index 6fdcff13e1cbb9ccbf0ecd7334fd8b9121032e3d..a65e641388d3dba0c03095316d0f20f1a796362f 100644 (file)
@@ -236,6 +236,16 @@ class Folder extends Node implements \OCP\Files\Folder {
                return $this->searchCommon($mimetype, 'searchByMime');
        }
 
+       /**
+        * search for files by tag
+        *
+        * @param string $tag
+        * @return Node[]
+        */
+       public function searchByTag($tag) {
+               return $this->searchCommon($tag, 'searchByTag');
+       }
+
        /**
         * @param string $query
         * @param string $method
index 0346cbf1e2127456e345a49c8b09343e168a3e43..9d452a94b9cd3760bf58cac61716aa3a4f6189ed 100644 (file)
@@ -99,6 +99,10 @@ class NonExistingFolder extends Folder {
                throw new NotFoundException();
        }
 
+       public function searchByTag($mime) {
+               throw new NotFoundException();
+       }
+
        public function getById($id) {
                throw new NotFoundException();
        }
index 4b3d167f8e9deab08524b89c5fbc5fcaef1b900c..7090e03d40c7d53c123ac58232c362b310ee292d 100644 (file)
@@ -1134,6 +1134,16 @@ class View {
                return $this->searchCommon($mimetype, 'searchByMime');
        }
 
+       /**
+        * search for files by tag
+        *
+        * @param string|int $tag name or tag id
+        * @return FileInfo[]
+        */
+       public function searchByTag($tag) {
+               return $this->searchCommon($tag, 'searchByTag');
+       }
+
        /**
         * @param string $query
         * @param string $method
index 7fec1c529a598f31f9f5e7734568552676776806..f54602d469d54777d2ba1d2f6a0d7ac4c7894d60 100644 (file)
@@ -116,6 +116,14 @@ interface Folder extends Node {
         */
        public function searchByMime($mimetype);
 
+       /**
+        * search for files by tag
+        *
+        * @param string|int $tag tag name or tag id
+        * @return \OCP\Files\Node[]
+        */
+       public function searchByTag($tag);
+
        /**
         * get a file or folder inside the folder by it's internal id
         *
index 7e44cb898ac8fe847d02cd5f22a43235ba8b9f8e..1af8e4da96034ff0fb375ff0d8e8e509a3c257a7 100644 (file)
@@ -270,6 +270,63 @@ class Cache extends \Test\TestCase {
                $this->assertEquals(2, count($this->cache->searchByMime('foo/file')));
        }
 
+       function testSearchByTag() {
+               $userId = $this->getUniqueId('user');
+               \OC_User::createUser($userId, $userId);
+               $this->loginAsUser($userId);
+               $user = new \OC\User\User($userId, null);
+
+               $file1 = 'folder';
+               $file2 = 'folder/foobar';
+               $file3 = 'folder/foo';
+               $file4 = 'folder/foo2';
+               $file5 = 'folder/foo3';
+               $data1 = array('size' => 100, 'mtime' => 50, 'mimetype' => 'foo/folder');
+               $fileData = array();
+               $fileData['foobar'] = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'foo/file');
+               $fileData['foo'] = array('size' => 20, 'mtime' => 25, 'mimetype' => 'foo/file');
+               $fileData['foo2'] = array('size' => 25, 'mtime' => 28, 'mimetype' => 'foo/file');
+               $fileData['foo3'] = array('size' => 88, 'mtime' => 34, 'mimetype' => 'foo/file');
+
+               $id1 = $this->cache->put($file1, $data1);
+               $id2 = $this->cache->put($file2, $fileData['foobar']);
+               $id3 = $this->cache->put($file3, $fileData['foo']);
+               $id4 = $this->cache->put($file4, $fileData['foo2']);
+               $id5 = $this->cache->put($file5, $fileData['foo3']);
+
+               $tagManager = \OC::$server->getTagManager()->load('files', null, null, $userId);
+               $this->assertTrue($tagManager->tagAs($id1, 'tag1'));
+               $this->assertTrue($tagManager->tagAs($id1, 'tag2'));
+               $this->assertTrue($tagManager->tagAs($id2, 'tag2'));
+               $this->assertTrue($tagManager->tagAs($id3, 'tag1'));
+               $this->assertTrue($tagManager->tagAs($id4, 'tag2'));
+
+               // use tag name
+               $results = $this->cache->searchByTag('tag1', $userId);
+
+               $this->assertEquals(2, count($results));
+
+               $this->assertEquals('folder', $results[0]['name']);
+               $this->assertEquals('foo', $results[1]['name']);
+
+               // use tag id
+               $tags = $tagManager->getTagsForUser($userId);
+               $this->assertNotEmpty($tags);
+               $tags = array_filter($tags, function($tag) { return $tag->getName() === 'tag2'; });
+               $results = $this->cache->searchByTag(current($tags)->getId(), $userId);
+               $this->assertEquals(3, count($results));
+
+               $this->assertEquals('folder', $results[0]['name']);
+               $this->assertEquals('foobar', $results[1]['name']);
+               $this->assertEquals('foo2', $results[2]['name']);
+
+               $tagManager->delete('tag1');
+               $tagManager->delete('tag2');
+
+               $this->logout();
+               \OC_User::deleteUser($userId);
+       }
+
        function testMove() {
                $file1 = 'folder';
                $file2 = 'folder/bar';