summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Petry <pvince81@owncloud.com>2014-12-04 14:01:15 +0100
committerVincent Petry <pvince81@owncloud.com>2014-12-11 17:38:50 +0100
commit25dde7e93bc648ec8cd14b8f2711d50f77d8d1bf (patch)
treef45b35dd647870b6c3aeded3e8e11faa41effcba
parent745d8706b973ff0494af54f183acc0da361f0e83 (diff)
downloadnextcloud-server-25dde7e93bc648ec8cd14b8f2711d50f77d8d1bf.tar.gz
nextcloud-server-25dde7e93bc648ec8cd14b8f2711d50f77d8d1bf.zip
Added searchByTags to view, storage and cache
-rw-r--r--apps/files_sharing/lib/cache.php40
-rw-r--r--apps/files_sharing/tests/cache.php33
-rw-r--r--lib/private/files/cache/cache.php48
-rw-r--r--lib/private/files/cache/wrapper/cachewrapper.php12
-rw-r--r--lib/private/files/filesystem.php8
-rw-r--r--lib/private/files/node/folder.php10
-rw-r--r--lib/private/files/node/nonexistingfolder.php4
-rw-r--r--lib/private/files/view.php10
-rw-r--r--lib/public/files/folder.php8
-rw-r--r--tests/lib/files/cache/cache.php57
10 files changed, 230 insertions, 0 deletions
diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php
index e09b64cb039..da8155ec6fa 100644
--- a/apps/files_sharing/lib/cache.php
+++ b/apps/files_sharing/lib/cache.php
@@ -345,6 +345,46 @@ class Shared_Cache extends Cache {
}
/**
+ * 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
*
* @param string $path
diff --git a/apps/files_sharing/tests/cache.php b/apps/files_sharing/tests/cache.php
index aec1983bad3..c40a014d557 100644
--- a/apps/files_sharing/tests/cache.php
+++ b/apps/files_sharing/tests/cache.php
@@ -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('/');
diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php
index 4157da2281c..a4ae3a069fe 100644
--- a/lib/private/files/cache/cache.php
+++ b/lib/private/files/cache/cache.php
@@ -504,6 +504,54 @@ class Cache {
}
/**
+ * 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
*
* @param string|boolean $path
diff --git a/lib/private/files/cache/wrapper/cachewrapper.php b/lib/private/files/cache/wrapper/cachewrapper.php
index d3d64e3f0a9..4da7c7ecf6f 100644
--- a/lib/private/files/cache/wrapper/cachewrapper.php
+++ b/lib/private/files/cache/wrapper/cachewrapper.php
@@ -181,6 +181,18 @@ class CacheWrapper extends Cache {
}
/**
+ * 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
*
* @param string|boolean $path
diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php
index 90643839e22..3d55564f0c6 100644
--- a/lib/private/files/filesystem.php
+++ b/lib/private/files/filesystem.php
@@ -687,6 +687,14 @@ class Filesystem {
}
/**
+ * @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
*
* @param string $path
diff --git a/lib/private/files/node/folder.php b/lib/private/files/node/folder.php
index 6fdcff13e1c..a65e641388d 100644
--- a/lib/private/files/node/folder.php
+++ b/lib/private/files/node/folder.php
@@ -237,6 +237,16 @@ class Folder extends Node implements \OCP\Files\Folder {
}
/**
+ * 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
* @return \OC\Files\Node\Node[]
diff --git a/lib/private/files/node/nonexistingfolder.php b/lib/private/files/node/nonexistingfolder.php
index 0346cbf1e21..9d452a94b9c 100644
--- a/lib/private/files/node/nonexistingfolder.php
+++ b/lib/private/files/node/nonexistingfolder.php
@@ -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();
}
diff --git a/lib/private/files/view.php b/lib/private/files/view.php
index 4b3d167f8e9..7090e03d40c 100644
--- a/lib/private/files/view.php
+++ b/lib/private/files/view.php
@@ -1135,6 +1135,16 @@ class View {
}
/**
+ * 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
* @return FileInfo[]
diff --git a/lib/public/files/folder.php b/lib/public/files/folder.php
index 7fec1c529a5..f54602d469d 100644
--- a/lib/public/files/folder.php
+++ b/lib/public/files/folder.php
@@ -117,6 +117,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
*
* @param int $id
diff --git a/tests/lib/files/cache/cache.php b/tests/lib/files/cache/cache.php
index 7e44cb898ac..1af8e4da960 100644
--- a/tests/lib/files/cache/cache.php
+++ b/tests/lib/files/cache/cache.php
@@ -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';