diff options
32 files changed, 285 insertions, 407 deletions
diff --git a/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php b/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php index 5b96f4f0f64..4df5f8b80e5 100644 --- a/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php +++ b/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php @@ -39,6 +39,7 @@ use OCP\Files\Folder; use OCP\IGroupManager; use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\TagNotFoundException; +use OCP\ITagManager; class FilesReportPlugin extends ServerPlugin { @@ -75,6 +76,13 @@ class FilesReportPlugin extends ServerPlugin { private $tagMapper; /** + * Manager for private tags + * + * @var ITagManager + */ + private $fileTagger; + + /** * @var IUserSession */ private $userSession; @@ -92,11 +100,18 @@ class FilesReportPlugin extends ServerPlugin { /** * @param Tree $tree * @param View $view + * @param ISystemTagManager $tagManager + * @param ISystemTagObjectMapper $tagMapper + * @param ITagManager $fileTagger manager for private tags + * @param IUserSession $userSession + * @param IGroupManager $groupManager + * @param Folder $userfolder */ public function __construct(Tree $tree, View $view, ISystemTagManager $tagManager, ISystemTagObjectMapper $tagMapper, + ITagManager $fileTagger, IUserSession $userSession, IGroupManager $groupManager, Folder $userFolder @@ -105,6 +120,7 @@ class FilesReportPlugin extends ServerPlugin { $this->fileView = $view; $this->tagManager = $tagManager; $this->tagMapper = $tagMapper; + $this->fileTagger = $fileTagger; $this->userSession = $userSession; $this->groupManager = $groupManager; $this->userFolder = $userFolder; @@ -215,12 +231,38 @@ class FilesReportPlugin extends ServerPlugin { $ns = '{' . $this::NS_OWNCLOUD . '}'; $resultFileIds = null; $systemTagIds = []; + $favoriteFilter = null; foreach ($filterRules as $filterRule) { if ($filterRule['name'] === $ns . 'systemtag') { $systemTagIds[] = $filterRule['value']; } + if ($filterRule['name'] === $ns . 'favorite') { + $favoriteFilter = true; + } } + if ($favoriteFilter !== null) { + $resultFileIds = $this->fileTagger->load('files')->getFavorites(); + if (empty($resultFileIds)) { + return []; + } + } + + if (!empty($systemTagIds)) { + $fileIds = $this->getSystemTagFileIds($systemTagIds); + if (empty($resultFileIds)) { + $resultFileIds = $fileIds; + } else { + $resultFileIds = array_intersect($fileIds, $resultFileIds); + } + } + + return $resultFileIds; + } + + private function getSystemTagFileIds($systemTagIds) { + $resultFileIds = null; + // check user permissions, if applicable if (!$this->isAdmin()) { // check visibility/permission diff --git a/apps/dav/lib/Connector/Sabre/ServerFactory.php b/apps/dav/lib/Connector/Sabre/ServerFactory.php index 644f0f28f57..6d9f9b1bc8b 100644 --- a/apps/dav/lib/Connector/Sabre/ServerFactory.php +++ b/apps/dav/lib/Connector/Sabre/ServerFactory.php @@ -177,6 +177,7 @@ class ServerFactory { $view, \OC::$server->getSystemTagManager(), \OC::$server->getSystemTagObjectMapper(), + \OC::$server->getTagManager(), $this->userSession, \OC::$server->getGroupManager(), $userFolder diff --git a/apps/dav/lib/Connector/Sabre/ShareTypeList.php b/apps/dav/lib/Connector/Sabre/ShareTypeList.php index fd9ba3f7267..4d9179b6651 100644 --- a/apps/dav/lib/Connector/Sabre/ShareTypeList.php +++ b/apps/dav/lib/Connector/Sabre/ShareTypeList.php @@ -66,7 +66,11 @@ class ShareTypeList implements Element { static function xmlDeserialize(Reader $reader) { $shareTypes = []; - foreach ($reader->parseInnerTree() as $elem) { + $tree = $reader->parseInnerTree(); + if ($tree === null) { + return null; + } + foreach ($tree as $elem) { if ($elem['name'] === '{' . self::NS_OWNCLOUD . '}share-type') { $shareTypes[] = (int)$elem['value']; } diff --git a/apps/dav/lib/Connector/Sabre/TagList.php b/apps/dav/lib/Connector/Sabre/TagList.php index 23576171262..2f514112a43 100644 --- a/apps/dav/lib/Connector/Sabre/TagList.php +++ b/apps/dav/lib/Connector/Sabre/TagList.php @@ -85,7 +85,11 @@ class TagList implements Element { static function xmlDeserialize(Reader $reader) { $tags = []; - foreach ($reader->parseInnerTree() as $elem) { + $tree = $reader->parseInnerTree(); + if ($tree === null) { + return null; + } + foreach ($tree as $elem) { if ($elem['name'] === '{' . self::NS_OWNCLOUD . '}tag') { $tags[] = $elem['value']; } diff --git a/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php index 336a33058bf..2097777c8fd 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php @@ -26,12 +26,15 @@ namespace OCA\DAV\Tests\unit\Connector\Sabre; use OCA\DAV\Connector\Sabre\FilesReportPlugin as FilesReportPluginImplementation; use OCP\IPreview; +use OCP\ITagManager; +use OCP\IUserSession; use Sabre\DAV\Exception\NotFound; use OCP\SystemTag\ISystemTagObjectMapper; use OC\Files\View; use OCP\Files\Folder; use OCP\IGroupManager; use OCP\SystemTag\ISystemTagManager; +use OCP\ITags; class FilesReportPluginTest extends \Test\TestCase { /** @var \Sabre\DAV\Server|\PHPUnit_Framework_MockObject_MockObject */ @@ -46,6 +49,9 @@ class FilesReportPluginTest extends \Test\TestCase { /** @var ISystemTagManager|\PHPUnit_Framework_MockObject_MockObject */ private $tagManager; + /** @var ITags|\PHPUnit_Framework_MockObject_MockObject */ + private $privateTags; + /** @var \OCP\IUserSession */ private $userSession; @@ -87,20 +93,20 @@ class FilesReportPluginTest extends \Test\TestCase { ->disableOriginalConstructor() ->getMock(); - $this->tagManager = $this->getMockBuilder('\OCP\SystemTag\ISystemTagManager') - ->disableOriginalConstructor() - ->getMock(); - $this->tagMapper = $this->getMockBuilder('\OCP\SystemTag\ISystemTagObjectMapper') - ->disableOriginalConstructor() - ->getMock(); - $this->userSession = $this->getMockBuilder('\OCP\IUserSession') - ->disableOriginalConstructor() - ->getMock(); - $this->previewManager = $this->getMockBuilder('\OCP\IPreview') ->disableOriginalConstructor() ->getMock(); + $this->tagManager = $this->createMock(ISystemTagManager::class); + $this->tagMapper = $this->createMock(ISystemTagObjectMapper::class); + $this->userSession = $this->createMock(IUserSession::class); + $this->privateTags = $this->createMock(ITags::class); + $privateTagManager = $this->createMock(ITagManager::class); + $privateTagManager->expects($this->any()) + ->method('load') + ->with('files') + ->will($this->returnValue($this->privateTags)); + $user = $this->getMockBuilder('\OCP\IUser') ->disableOriginalConstructor() ->getMock(); @@ -116,6 +122,7 @@ class FilesReportPluginTest extends \Test\TestCase { $this->view, $this->tagManager, $this->tagMapper, + $privateTagManager, $this->userSession, $this->groupManager, $this->userFolder @@ -652,4 +659,16 @@ class FilesReportPluginTest extends \Test\TestCase { $this->assertEquals(['222'], array_values($this->invokePrivate($this->plugin, 'processFilterRules', [$rules]))); } + + public function testProcessFavoriteFilter() { + $rules = [ + ['name' => '{http://owncloud.org/ns}favorite', 'value' => '1'], + ]; + + $this->privateTags->expects($this->once()) + ->method('getFavorites') + ->will($this->returnValue(['456', '789'])); + + $this->assertEquals(['456', '789'], array_values($this->invokePrivate($this->plugin, 'processFilterRules', [$rules]))); + } } diff --git a/apps/files/appinfo/routes.php b/apps/files/appinfo/routes.php index 6237e8413ed..49dbe553435 100644 --- a/apps/files/appinfo/routes.php +++ b/apps/files/appinfo/routes.php @@ -45,12 +45,6 @@ $application->registerRoutes( 'requirements' => array('path' => '.+'), ), array( - 'name' => 'API#getFilesByTag', - 'url' => '/api/v1/tags/{tagName}/files', - 'verb' => 'GET', - 'requirements' => array('tagName' => '.+'), - ), - array( 'name' => 'API#getRecentFiles', 'url' => '/api/v1/recent/', 'verb' => 'GET' diff --git a/apps/files/css/upload.css b/apps/files/css/upload.css index f0ffb9ac99e..abc09c3e99c 100644 --- a/apps/files/css/upload.css +++ b/apps/files/css/upload.css @@ -91,6 +91,7 @@ -moz-user-select: none; -ms-user-select: none; user-select: none; + margin-bottom: 30px; } .oc-dialog .fileexists .conflict .filename, diff --git a/apps/files/js/favoritesfilelist.js b/apps/files/js/favoritesfilelist.js index e6532ab188c..380689be10b 100644 --- a/apps/files/js/favoritesfilelist.js +++ b/apps/files/js/favoritesfilelist.js @@ -75,24 +75,25 @@ $(document).ready(function() { // there is only root this._setCurrentDir('/', false); - this._reloadCall = $.ajax({ - url: OC.generateUrl('/apps/files/api/v1/tags/{tagName}/files', {tagName: tagName}), - type: 'GET', - dataType: 'json' - }); + this._reloadCall = this.filesClient.getFilteredFiles( + { + favorite: true + }, + { + properties: this._getWebdavProperties() + } + ); var callBack = this.reloadCallback.bind(this); return this._reloadCall.then(callBack, callBack); }, - reloadCallback: function(result) { - delete this._reloadCall; - this.hideMask(); - - if (result.files) { - this.setFiles(result.files.sort(this._sortComparator)); - return true; + reloadCallback: function(status, result) { + if (result) { + // prepend empty dir info because original handler + result.unshift({}); } - return false; + + return OCA.Files.FileList.prototype.reloadCallback.call(this, status, result); } }); diff --git a/apps/files/lib/Controller/ApiController.php b/apps/files/lib/Controller/ApiController.php index 7ce83bfca15..d6f88581b96 100644 --- a/apps/files/lib/Controller/ApiController.php +++ b/apps/files/lib/Controller/ApiController.php @@ -174,23 +174,6 @@ class ApiController extends Controller { } /** - * Returns a list of all files tagged with the given tag. - * - * @NoAdminRequired - * - * @param string $tagName tag name to filter by - * @return DataResponse - */ - public function getFilesByTag($tagName) { - $nodes = $this->tagService->getFilesByTag($tagName); - $files = $this->formatNodes($nodes); - foreach ($files as &$file) { - $file['tags'] = [$tagName]; - } - return new DataResponse(['files' => $files]); - } - - /** * Returns a list of recently modifed files. * * @NoAdminRequired diff --git a/apps/files/lib/Service/TagService.php b/apps/files/lib/Service/TagService.php index 04e962b5e17..4482fb45371 100644 --- a/apps/files/lib/Service/TagService.php +++ b/apps/files/lib/Service/TagService.php @@ -90,26 +90,5 @@ class TagService { // list is up to date, in case of concurrent changes ? return $tags; } - - /** - * Get all files for the given tag - * - * @param string $tagName tag name to filter by - * @return Node[] list of matching files - * @throws \Exception if the tag does not exist - */ - public function getFilesByTag($tagName) { - try { - $fileIds = $this->tagger->getIdsForTag($tagName); - } catch (\Exception $e) { - return []; - } - - $allNodes = []; - foreach ($fileIds as $fileId) { - $allNodes = array_merge($allNodes, $this->homeFolder->getById((int) $fileId)); - } - return $allNodes; - } } diff --git a/apps/files/tests/Controller/ApiControllerTest.php b/apps/files/tests/Controller/ApiControllerTest.php index 9bfc6d6f5e8..4b7bec065a0 100644 --- a/apps/files/tests/Controller/ApiControllerTest.php +++ b/apps/files/tests/Controller/ApiControllerTest.php @@ -103,182 +103,6 @@ class ApiControllerTest extends TestCase { ); } - public function testGetFilesByTagEmpty() { - $tagName = 'MyTagName'; - $this->tagService->expects($this->once()) - ->method('getFilesByTag') - ->with($this->equalTo([$tagName])) - ->will($this->returnValue([])); - - $expected = new DataResponse(['files' => []]); - $this->assertEquals($expected, $this->apiController->getFilesByTag([$tagName])); - } - - public function testGetFilesByTagSingle() { - $tagName = 'MyTagName'; - $fileInfo = new FileInfo( - '/root.txt', - $this->getMockBuilder('\OC\Files\Storage\Storage') - ->disableOriginalConstructor() - ->getMock(), - '/var/www/root.txt', - [ - 'mtime' => 55, - 'mimetype' => 'application/pdf', - 'permissions' => 31, - 'size' => 1234, - 'etag' => 'MyEtag', - ], - $this->getMockBuilder('\OCP\Files\Mount\IMountPoint') - ->disableOriginalConstructor() - ->getMock() - ); - $node = $this->getMockBuilder('\OC\Files\Node\File') - ->disableOriginalConstructor() - ->getMock(); - $node->expects($this->once()) - ->method('getFileInfo') - ->will($this->returnValue($fileInfo)); - $this->tagService->expects($this->once()) - ->method('getFilesByTag') - ->with($this->equalTo([$tagName])) - ->will($this->returnValue([$node])); - - $this->shareManager->expects($this->any()) - ->method('getSharesBy') - ->with( - $this->equalTo('user1'), - $this->anything(), - $node, - $this->equalTo(false), - $this->equalTo(1) - ) - ->will($this->returnCallback(function($userId, $shareType) { - if ($shareType === \OCP\Share::SHARE_TYPE_USER || $shareType === \OCP\Share::SHARE_TYPE_LINK) { - return ['dummy_share']; - } - return []; - })); - - $expected = new DataResponse([ - 'files' => [ - [ - 'id' => null, - 'parentId' => null, - 'mtime' => 55000, - 'name' => 'root.txt', - 'permissions' => 31, - 'mimetype' => 'application/pdf', - 'size' => 1234, - 'type' => 'file', - 'etag' => 'MyEtag', - 'path' => '/', - 'tags' => [ - [ - 'MyTagName' - ] - ], - 'shareTypes' => [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_LINK] - ], - ], - ]); - $this->assertEquals($expected, $this->apiController->getFilesByTag([$tagName])); - } - - public function testGetFilesByTagMultiple() { - $tagName = 'MyTagName'; - $fileInfo1 = new FileInfo( - '/root.txt', - $this->getMockBuilder('\OC\Files\Storage\Storage') - ->disableOriginalConstructor() - ->getMock(), - '/var/www/root.txt', - [ - 'mtime' => 55, - 'mimetype' => 'application/pdf', - 'permissions' => 31, - 'size' => 1234, - 'etag' => 'MyEtag', - ], - $this->getMockBuilder('\OCP\Files\Mount\IMountPoint') - ->disableOriginalConstructor() - ->getMock() - ); - $fileInfo2 = new FileInfo( - '/root.txt', - $this->getMockBuilder('\OC\Files\Storage\Storage') - ->disableOriginalConstructor() - ->getMock(), - '/var/www/some/sub.txt', - [ - 'mtime' => 999, - 'mimetype' => 'application/binary', - 'permissions' => 31, - 'size' => 9876, - 'etag' => 'SubEtag', - ], - $this->getMockBuilder('\OCP\Files\Mount\IMountPoint') - ->disableOriginalConstructor() - ->getMock() - ); - $node1 = $this->getMockBuilder('\OC\Files\Node\File') - ->disableOriginalConstructor() - ->getMock(); - $node1->expects($this->once()) - ->method('getFileInfo') - ->will($this->returnValue($fileInfo1)); - $node2 = $this->getMockBuilder('\OC\Files\Node\File') - ->disableOriginalConstructor() - ->getMock(); - $node2->expects($this->once()) - ->method('getFileInfo') - ->will($this->returnValue($fileInfo2)); - $this->tagService->expects($this->once()) - ->method('getFilesByTag') - ->with($this->equalTo([$tagName])) - ->will($this->returnValue([$node1, $node2])); - - $expected = new DataResponse([ - 'files' => [ - [ - 'id' => null, - 'parentId' => null, - 'mtime' => 55000, - 'name' => 'root.txt', - 'permissions' => 31, - 'mimetype' => 'application/pdf', - 'size' => 1234, - 'type' => 'file', - 'etag' => 'MyEtag', - 'path' => '/', - 'tags' => [ - [ - 'MyTagName' - ] - ], - ], - [ - 'id' => null, - 'parentId' => null, - 'mtime' => 999000, - 'name' => 'root.txt', - 'permissions' => 31, - 'mimetype' => 'application/binary', - 'size' => 9876, - 'type' => 'file', - 'etag' => 'SubEtag', - 'path' => '/', - 'tags' => [ - [ - 'MyTagName' - ] - ], - ] - ], - ]); - $this->assertEquals($expected, $this->apiController->getFilesByTag([$tagName])); - } - public function testUpdateFileTagsEmpty() { $expected = new DataResponse([]); $this->assertEquals($expected, $this->apiController->updateFileTags('/path.txt')); diff --git a/apps/files/tests/js/favoritesfilelistspec.js b/apps/files/tests/js/favoritesfilelistspec.js index 1c833d334e2..db890927ed4 100644 --- a/apps/files/tests/js/favoritesfilelistspec.js +++ b/apps/files/tests/js/favoritesfilelistspec.js @@ -41,13 +41,9 @@ describe('OCA.Files.FavoritesFileList tests', function() { '</div>' ); }); - afterEach(function() { - fileList.destroy(); - fileList = undefined; - }); describe('loading file list', function() { - var response; + var fetchStub; beforeEach(function() { fileList = new OCA.Files.FavoritesFileList( @@ -55,36 +51,31 @@ describe('OCA.Files.FavoritesFileList tests', function() { ); OCA.Files.FavoritesPlugin.attach(fileList); - fileList.reload(); - - /* jshint camelcase: false */ - response = { - files: [{ - id: 7, - name: 'test.txt', - path: '/somedir', - size: 123, - mtime: 11111000, - tags: [OC.TAG_FAVORITE], - permissions: OC.PERMISSION_ALL, - mimetype: 'text/plain' - }] - }; + fetchStub = sinon.stub(fileList.filesClient, 'getFilteredFiles'); + }); + afterEach(function() { + fetchStub.restore(); + fileList.destroy(); + fileList = undefined; }); it('render files', function() { - var request; + var deferred = $.Deferred(); + fetchStub.returns(deferred.promise()); - expect(fakeServer.requests.length).toEqual(1); - request = fakeServer.requests[0]; - expect(request.url).toEqual( - OC.generateUrl('apps/files/api/v1/tags/{tagName}/files', {tagName: OC.TAG_FAVORITE}) - ); + fileList.reload(); - fakeServer.requests[0].respond( - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(response) - ); + expect(fetchStub.calledOnce).toEqual(true); + + deferred.resolve(207, [{ + id: 7, + name: 'test.txt', + path: '/somedir', + size: 123, + mtime: 11111000, + tags: [OC.TAG_FAVORITE], + permissions: OC.PERMISSION_ALL, + mimetype: 'text/plain' + }]); var $rows = fileList.$el.find('tbody tr'); var $tr = $rows.eq(0); diff --git a/core/css/jquery.ocdialog.css b/core/css/jquery.ocdialog.css index a19fa4c52b5..0e46ff20152 100644 --- a/core/css/jquery.ocdialog.css +++ b/core/css/jquery.ocdialog.css @@ -1,7 +1,7 @@ .oc-dialog { - background: white; - color: #333333; - border-radius: 3px; box-shadow: 0 0 7px #888888; + background: #fff; + color: #333; + border-radius: 3px; box-shadow: 0 0 7px #888; padding: 15px; z-index: 1000; font-size: 100%; @@ -11,26 +11,26 @@ min-width: 200px; } .oc-dialog-title { - background: white; - font-weight: bold; - font-size: 110%; - margin-bottom: 5px; - margin-top: -9px; + background: #fff; + margin-left: 12px; } .oc-dialog-content { z-index: 1000; - background: white; } .oc-dialog-separator { } .oc-dialog-buttonrow { - background: white; - float: right; - position: relative; - bottom: 5px; display: block; - margin-top: 10px; + background: transparent; + position: absolute; + right: 0; + bottom: 0; + padding: 10px; + box-sizing: border-box; width: 100%; + background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 1)); + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; } /* align primary button to right, other buttons to left */ .oc-dialog-buttonrow.twobuttons button:nth-child(1) { @@ -45,10 +45,11 @@ } .oc-dialog-close { - position:absolute; - top:7px; right:7px; - height:20px; width:20px; - background:url('../img/actions/close.svg') no-repeat center; + position: absolute; + top: 0; + right: 0; + padding: 25px; + background: url('../img/actions/close.svg') no-repeat center; } .oc-dialog-dim { diff --git a/core/css/mobile.css b/core/css/mobile.css index 0ef6a08c24f..b0f8421345c 100644 --- a/core/css/mobile.css +++ b/core/css/mobile.css @@ -141,6 +141,7 @@ table.multiselect thead { /* do not show dates in filepicker */ +#oc-dialog-filepicker-content .filelist .filesize, #oc-dialog-filepicker-content .filelist .date { display: none; } diff --git a/core/css/styles.css b/core/css/styles.css index 8fa7691ca7a..94e60562ad8 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -774,39 +774,48 @@ a.bookmarklet { background-color:#ddd; border:1px solid #ccc; padding:5px;paddin #oc-dialog-filepicker-content .dirtree span:not(:last-child) { cursor: pointer; } #oc-dialog-filepicker-content .dirtree span:last-child { font-weight: bold; } #oc-dialog-filepicker-content .dirtree span:not(:last-child)::after { content: '>'; padding: 3px;} +#oc-dialog-filepicker-content .filelist-container { + box-sizing: border-box; + display: inline-block; + overflow-y: auto; + height: 321px; + width: 100%; + padding-bottom: 55px; +} #oc-dialog-filepicker-content .filelist { - overflow-y:auto; - height: 290px; background-color:white; width:100%; } - -#oc-dialog-filepicker-content .filelist li:first-child { - border-top: 1px solid #eee; +#oc-dialog-filepicker-content #filestable.filelist { + /* prevent the filepicker to overflow */ + min-width: initial; } -#oc-dialog-filepicker-content .filelist li { - position: relative; - height: 40px; - padding: 5px; + +#oc-dialog-filepicker-content .filelist td { + padding: 14px; border-bottom: 1px solid #eee; } +#oc-dialog-filepicker-content .filelist tr:last-child td { + border-bottom: none; +} #oc-dialog-filepicker-content .filelist .filename { - position: absolute; - padding-top: 9px; - max-width: 60%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; + background-size: 32px; + background-repeat: no-repeat; + padding-left: 51px; + background-position: 7px 7px; + cursor: pointer; } -#oc-dialog-filepicker-content .filelist img { - margin: 2px 1em 0 4px; - width: 32px; -} + +#oc-dialog-filepicker-content .filelist .filesize, #oc-dialog-filepicker-content .filelist .date { - float: right; - margin-right: 10px; - margin-top: 0; - padding-top: 9px; + width: 80px; +} + +#oc-dialog-filepicker-content .filelist .filesize { + text-align: right; } #oc-dialog-filepicker-content .filepicker_element_selected { background-color:lightblue;} .ui-dialog {position:fixed !important;} diff --git a/core/js/files/client.js b/core/js/files/client.js index a195258afbb..572f7879e17 100644 --- a/core/js/files/client.js +++ b/core/js/files/client.js @@ -437,6 +437,7 @@ * * @param {Object} filter filter criteria * @param {Object} [filter.systemTagIds] list of system tag ids to filter by + * @param {bool} [filter.favorite] set it to filter by favorites * @param {Object} [options] options * @param {Array} [options.properties] list of Webdav properties to retrieve * @@ -454,7 +455,7 @@ properties = options.properties; } - if (!filter || !filter.systemTagIds || !filter.systemTagIds.length) { + if (!filter || (!filter.systemTagIds && _.isUndefined(filter.favorite))) { throw 'Missing filter argument'; } @@ -480,6 +481,9 @@ _.each(filter.systemTagIds, function(systemTagIds) { body += ' <oc:systemtag>' + escapeHTML(systemTagIds) + '</oc:systemtag>\n'; }); + if (filter.favorite) { + body += ' <oc:favorite>' + (filter.favorite ? '1': '0') + '</oc:favorite>\n'; + } body += ' </oc:filter-rules>\n'; // end of root diff --git a/core/js/integritycheck-failed-notification.js b/core/js/integritycheck-failed-notification.js index 5bc758d54cb..9f7c59b9089 100644 --- a/core/js/integritycheck-failed-notification.js +++ b/core/js/integritycheck-failed-notification.js @@ -31,6 +31,7 @@ $(document).ready(function(){ OC.Notification.showHtml( text, { + type: 'error', isHTML: true } ); diff --git a/core/js/jquery.ocdialog.js b/core/js/jquery.ocdialog.js index 15b58f9e086..66c7d9bd7f1 100644 --- a/core/js/jquery.ocdialog.js +++ b/core/js/jquery.ocdialog.js @@ -101,9 +101,9 @@ if(this.$title) { this.$title.text(value); } else { - var $title = $('<h3 class="oc-dialog-title">' + var $title = $('<h2 class="oc-dialog-title">' + value - + '</h3>'); + + '</h2>'); this.$title = $title.prependTo(this.$dialog); } this._setSizes(); @@ -184,11 +184,11 @@ if (content_height> 0) { this.element.css({ height: content_height + 'px', - width: this.$dialog.innerWidth()-20 + 'px' + width: this.$dialog.innerWidth() - 30 + 'px' }); } else { this.element.css({ - width : this.$dialog.innerWidth() - 20 + 'px' + width : this.$dialog.innerWidth() - 30 + 'px' }); } }, diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js index 87d16a1394a..7a7876bf30f 100644 --- a/core/js/oc-dialogs.js +++ b/core/js/oc-dialogs.js @@ -148,6 +148,7 @@ var OCdialogs = { return; } this.filepicker.loading = true; + this.filepicker.filesClient = OC.Files.getClient(); $.when(this._getFilePickerTemplate()).then(function($tmpl) { self.filepicker.loading = false; var dialogName = 'oc-dialog-filepicker-content'; @@ -172,10 +173,10 @@ var OCdialogs = { $('body').append(self.$filePicker); self.$filePicker.ready(function() { - self.$filelist = self.$filePicker.find('.filelist'); + self.$filelist = self.$filePicker.find('.filelist tbody'); self.$dirTree = self.$filePicker.find('.dirtree'); self.$dirTree.on('click', 'div:not(:last-child)', self, self._handleTreeListSelect.bind(self)); - self.$filelist.on('click', 'li', function(event) { + self.$filelist.on('click', 'tr', function(event) { self._handlePickerClick(event, $(this)); }); self._fillFilePicker(''); @@ -187,12 +188,12 @@ var OCdialogs = { var datapath; if (multiselect === true) { datapath = []; - self.$filelist.find('.filepicker_element_selected .filename').each(function(index, element) { - datapath.push(self.$filePicker.data('path') + '/' + $(element).text()); + self.$filelist.find('tr.filepicker_element_selected').each(function(index, element) { + datapath.push(self.$filePicker.data('path') + '/' + $(element).data('entryname')); }); } else { datapath = self.$filePicker.data('path'); - datapath += '/' + self.$filelist.find('.filepicker_element_selected .filename').text(); + datapath += '/' + self.$filelist.find('tr.filepicker_element_selected').data('entryname'); } callback(datapath); self.$filePicker.ocdialog('close'); @@ -223,7 +224,11 @@ var OCdialogs = { // Hence this is one of the approach to get the choose button. var getOcDialog = self.$filePicker.closest('.oc-dialog'); var buttonEnableDisable = getOcDialog.find('.primary'); - buttonEnableDisable.prop("disabled", "true"); + if (self.$filePicker.data('mimetype') === "httpd/unix-directory") { + buttonEnableDisable.prop("disabled", false); + } else { + buttonEnableDisable.prop("disabled", true); + } if (!OC.Util.hasSVGSupport()) { OC.Util.replaceSVG(self.$filePicker.parent()); @@ -680,7 +685,7 @@ var OCdialogs = { var self = this; $.get(OC.filePath('core', 'templates', 'filepicker.html'), function(tmpl) { self.$filePickerTemplate = $(tmpl); - self.$listTmpl = self.$filePickerTemplate.find('.filelist li:first-child').detach(); + self.$listTmpl = self.$filePickerTemplate.find('.filelist tr:first-child').detach(); defer.resolve(self.$filePickerTemplate); }) .fail(function(jqXHR, textStatus, errorThrown) { @@ -723,7 +728,7 @@ var OCdialogs = { } return defer.promise(); }, - _getFileList: function(dir, mimeType) { + _getFileList: function(dir, mimeType) { //this is only used by the spreedme app atm if (typeof(mimeType) === "string") { mimeType = [mimeType]; } @@ -741,50 +746,62 @@ var OCdialogs = { * fills the filepicker with files */ _fillFilePicker:function(dir) { - var dirs = []; - var others = []; var self = this; this.$filelist.empty().addClass('icon-loading'); this.$filePicker.data('path', dir); - $.when(this._getFileList(dir, this.$filePicker.data('mimetype'))).then(function(response) { - - $.each(response.data.files, function(index, file) { - if (file.type === 'dir') { - dirs.push(file); + var filter = this.$filePicker.data('mimetype'); + if (typeof(filter) === "string") { + filter = [filter]; + } + self.filepicker.filesClient.getFolderContents(dir).then(function(status, files) { + if (filter) { + files = files.filter(function (file) { + return filter == [] || file.type === 'dir' || filter.indexOf(file.mimetype) !== -1; + }); + } + files = files.sort(function(a, b) { + if (a.type === 'dir' && b.type !== 'dir') { + return -1; + } else if(a.type !== 'dir' && b.type === 'dir') { + return 1; } else { - others.push(file); + return 0; } }); self._fillSlug(); - var sorted = dirs.concat(others); - $.each(sorted, function(idx, entry) { + $.each(files, function(idx, entry) { entry.icon = OC.MimeType.getIconUrl(entry.mimetype); - var $li = self.$listTmpl.octemplate({ + if (typeof(entry.size) !== 'undefined' && entry.size >= 0) { + var simpleSize = humanFileSize(parseInt(entry.size, 10), true); + var sizeColor = Math.round(160 - Math.pow((entry.size / (1024 * 1024)), 2)); + } else { + simpleSize = t('files', 'Pending'); + } + var $row = self.$listTmpl.octemplate({ type: entry.type, dir: dir, filename: entry.name, - date: OC.Util.relativeModifiedDate(entry.mtime) + date: OC.Util.relativeModifiedDate(entry.mtime), + size: simpleSize, + sizeColor: sizeColor, + icon: entry.icon }); if (entry.type === 'file') { var urlSpec = { file: dir + '/' + entry.name, }; - $li.find('img').attr('src', OC.MimeType.getIconUrl(entry.mimetype)); var img = new Image(); var previewUrl = OC.generateUrl('/core/preview.png?') + $.param(urlSpec); img.onload = function() { if (img.width > 5) { - $li.find('img').attr('src', previewUrl); + $row.find('td.filename').attr('style', 'background-image:url(' + previewUrl + ')'); } }; img.src = previewUrl; } - else { - $li.find('img').attr('src', OC.Util.replaceSVGIcon(entry.icon)); - } - self.$filelist.append($li); + self.$filelist.append($row); }); self.$filelist.removeClass('icon-loading'); @@ -829,7 +846,7 @@ var OCdialogs = { self._fillFilePicker(dir); var getOcDialog = (event.target).closest('.oc-dialog'); var buttonEnableDisable = $('.primary', getOcDialog); - if (this.$filePicker.data('mimetype') === "http/unix-directory") { + if (this.$filePicker.data('mimetype') === "httpd/unix-directory") { buttonEnableDisable.prop("disabled", false); } else { buttonEnableDisable.prop("disabled", true); diff --git a/core/js/tests/specs/files/clientSpec.js b/core/js/tests/specs/files/clientSpec.js index 7673ec6e0fc..f75998029a9 100644 --- a/core/js/tests/specs/files/clientSpec.js +++ b/core/js/tests/specs/files/clientSpec.js @@ -461,9 +461,7 @@ describe('OC.Files.Client tests', function() { it('throws exception if arguments are missing', function() { var thrown = null; try { - client.getFilteredFiles({ - systemTagIds: [] - }); + client.getFilteredFiles({}); } catch (e) { thrown = true; } diff --git a/core/templates/filepicker.html b/core/templates/filepicker.html index 46d1ca3d52d..b665ca26893 100644 --- a/core/templates/filepicker.html +++ b/core/templates/filepicker.html @@ -1,10 +1,19 @@ <div id="{dialog_name}" title="{title}"> <span class="dirtree breadcrumb"></span> - <ul class="filelist"> - <li data-entryname="{filename}" data-type="{type}"> - <img /> - <span class="filename">{filename}</span> - <span class="date">{date}</span> - </li> - </ul> + <div class="filelist-container"> + <table id="filestable" class="filelist"> + <tbody> + <tr data-entryname="{filename}" data-type="{type}"> + <td class="filename" + style="background-image:url({icon})">{filename} + </td> + <td class="filesize" + style="color:rgb({sizeColor}, {sizeColor}, {sizeColor})"> + {size} + </td> + <td class="date">{date}</td> + </tr> + </tbody> + </table> + </div> </div> diff --git a/settings/img/admin.png b/settings/img/admin.png Binary files differdeleted file mode 100644 index 2a1f1eb257b..00000000000 --- a/settings/img/admin.png +++ /dev/null diff --git a/settings/img/apps.png b/settings/img/apps.png Binary files differdeleted file mode 100644 index 9afec98a460..00000000000 --- a/settings/img/apps.png +++ /dev/null diff --git a/settings/img/help.png b/settings/img/help.png Binary files differdeleted file mode 100644 index 69cb269d91b..00000000000 --- a/settings/img/help.png +++ /dev/null diff --git a/settings/img/personal.png b/settings/img/personal.png Binary files differdeleted file mode 100644 index 10e502faa9f..00000000000 --- a/settings/img/personal.png +++ /dev/null diff --git a/settings/img/trans.png b/settings/img/trans.png Binary files differdeleted file mode 100644 index ef57510d530..00000000000 --- a/settings/img/trans.png +++ /dev/null diff --git a/settings/img/users.png b/settings/img/users.png Binary files differdeleted file mode 100644 index 14a0d5d03c2..00000000000 --- a/settings/img/users.png +++ /dev/null diff --git a/tests/lib/AppConfigTest.php b/tests/lib/AppConfigTest.php index 520dbf66d36..c4da7507752 100644 --- a/tests/lib/AppConfigTest.php +++ b/tests/lib/AppConfigTest.php @@ -40,7 +40,7 @@ class AppConfigTest extends TestCase { $sql->delete('appconfig'); $sql->execute(); - $this->registerAppConfig(new \OC\AppConfig($this->connection)); + $this->overwriteService('AppConfig', new \OC\AppConfig($this->connection)); $sql = $this->connection->getQueryBuilder(); $sql->insert('appconfig') @@ -130,21 +130,10 @@ class AppConfigTest extends TestCase { $sql->execute(); } - $this->registerAppConfig(new \OC\AppConfig(\OC::$server->getDatabaseConnection())); + $this->restoreService('AppConfig'); parent::tearDown(); } - /** - * Register an app config object for testing purposes. - * - * @param \OCP\IAppConfig $appConfig - */ - protected function registerAppConfig($appConfig) { - \OC::$server->registerService('AppConfig', function () use ($appConfig) { - return $appConfig; - }); - } - public function testGetApps() { $config = new \OC\AppConfig(\OC::$server->getDatabaseConnection()); diff --git a/tests/lib/AppTest.php b/tests/lib/AppTest.php index ac4fb913beb..ea4f328b63a 100644 --- a/tests/lib/AppTest.php +++ b/tests/lib/AppTest.php @@ -493,24 +493,22 @@ class AppTest extends \Test\TestCase { * @param IAppConfig $appConfig app config mock */ private function registerAppConfig(IAppConfig $appConfig) { - \OC::$server->registerService('AppConfig', function ($c) use ($appConfig) { - return $appConfig; - }); - \OC::$server->registerService('AppManager', function (\OC\Server $c) use ($appConfig) { - return new \OC\App\AppManager($c->getUserSession(), $appConfig, $c->getGroupManager(), $c->getMemCacheFactory(), $c->getEventDispatcher()); - }); + $this->overwriteService('AppConfig', $appConfig); + $this->overwriteService('AppManager', new \OC\App\AppManager( + \OC::$server->getUserSession(), + $appConfig, + \OC::$server->getGroupManager(), + \OC::$server->getMemCacheFactory(), + \OC::$server->getEventDispatcher() + )); } /** * Restore the original app config service. */ private function restoreAppConfig() { - \OC::$server->registerService('AppConfig', function (\OC\Server $c) { - return new \OC\AppConfig($c->getDatabaseConnection()); - }); - \OC::$server->registerService('AppManager', function (\OC\Server $c) { - return new \OC\App\AppManager($c->getUserSession(), $c->getAppConfig(), $c->getGroupManager(), $c->getMemCacheFactory(), $c->getEventDispatcher()); - }); + $this->restoreService('AppConfig'); + $this->restoreService('AppManager'); // Remove the cache of the mocked apps list with a forceRefresh \OC_App::getEnabledApps(); diff --git a/tests/lib/Share/ShareTest.php b/tests/lib/Share/ShareTest.php index 42adee21d0c..63289529843 100644 --- a/tests/lib/Share/ShareTest.php +++ b/tests/lib/Share/ShareTest.php @@ -119,12 +119,6 @@ class ShareTest extends \Test\TestCase { parent::tearDown(); } - protected function setHttpHelper($httpHelper) { - \OC::$server->registerService('HTTPHelper', function () use ($httpHelper) { - return $httpHelper; - }); - } - public function testShareInvalidShareType() { $message = 'Share type foobar is not valid for test.txt'; try { @@ -1046,11 +1040,10 @@ class ShareTest extends \Test\TestCase { * @param string $urlHost */ public function testRemoteShareUrlCalls($shareWith, $urlHost) { - $oldHttpHelper = \OC::$server->query('HTTPHelper'); - $httpHelperMock = $this->getMockBuilder('OC\HttpHelper') + $httpHelperMock = $this->getMockBuilder('OC\HTTPHelper') ->disableOriginalConstructor() ->getMock(); - $this->setHttpHelper($httpHelperMock); + $this->overwriteService('HTTPHelper', $httpHelperMock); $httpHelperMock->expects($this->at(0)) ->method('post') @@ -1075,7 +1068,7 @@ class ShareTest extends \Test\TestCase { ->willReturn(['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 100]]])]); \OCP\Share::unshare('test', 'test.txt', \OCP\Share::SHARE_TYPE_REMOTE, $shareWith); - $this->setHttpHelper($oldHttpHelper); + $this->restoreService('HTTPHelper'); } /** @@ -1473,11 +1466,10 @@ class ShareTest extends \Test\TestCase { * Make sure that a user cannot have multiple identical shares to remote users */ public function testOnlyOneRemoteShare() { - $oldHttpHelper = \OC::$server->query('HTTPHelper'); - $httpHelperMock = $this->getMockBuilder('OC\HttpHelper') + $httpHelperMock = $this->getMockBuilder('OC\HTTPHelper') ->disableOriginalConstructor() ->getMock(); - $this->setHttpHelper($httpHelperMock); + $this->overwriteService('HTTPHelper', $httpHelperMock); $httpHelperMock->expects($this->at(0)) ->method('post') @@ -1502,7 +1494,7 @@ class ShareTest extends \Test\TestCase { ->willReturn(['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 100]]])]); \OCP\Share::unshare('test', 'test.txt', \OCP\Share::SHARE_TYPE_REMOTE, 'foo@localhost'); - $this->setHttpHelper($oldHttpHelper); + $this->restoreService('HTTPHelper'); } /** diff --git a/tests/lib/TestCase.php b/tests/lib/TestCase.php index 7ccff382357..61372d4ae90 100644 --- a/tests/lib/TestCase.php +++ b/tests/lib/TestCase.php @@ -102,6 +102,16 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase { return false; } + public function restoreAllServices() { + if (!empty($this->services)) { + if (!empty($this->services)) { + foreach ($this->services as $name => $service) { + $this->restoreService($name); + } + } + } + } + protected function getTestTraits() { $traits = []; $class = $this; @@ -132,9 +142,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase { // overwrite the command bus with one we can run ourselves $this->commandBus = new QueueBus(); - \OC::$server->registerService('AsyncCommandBus', function () { - return $this->commandBus; - }); + $this->overwriteService('AsyncCommandBus', $this->commandBus); $traits = $this->getTestTraits(); foreach ($traits as $trait) { @@ -145,7 +153,22 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase { } } + protected function onNotSuccessfulTest($e) { + $this->restoreAllServices(); + + // restore database connection + if (!$this->IsDatabaseAccessAllowed()) { + \OC::$server->registerService('DatabaseConnection', function () { + return self::$realDatabase; + }); + } + + parent::onNotSuccessfulTest($e); + } + protected function tearDown() { + $this->restoreAllServices(); + // restore database connection if (!$this->IsDatabaseAccessAllowed()) { \OC::$server->registerService('DatabaseConnection', function () { diff --git a/tests/lib/UtilTest.php b/tests/lib/UtilTest.php index 619963a2abf..a1671191ab8 100644 --- a/tests/lib/UtilTest.php +++ b/tests/lib/UtilTest.php @@ -87,24 +87,17 @@ class UtilTest extends \Test\TestCase { function testFormatDateWithTZFromSession($offset, $expected, $expectedTimeZone) { date_default_timezone_set("UTC"); - $oldDateTimeFormatter = \OC::$server->query('DateTimeFormatter'); \OC::$server->getSession()->set('timezone', $offset); $selectedTimeZone = \OC::$server->getDateTimeZone()->getTimeZone(1350129205); $this->assertEquals($expectedTimeZone, $selectedTimeZone->getName()); $newDateTimeFormatter = new \OC\DateTimeFormatter($selectedTimeZone, new \OC_L10N('lib', 'en')); - $this->setDateFormatter($newDateTimeFormatter); + $this->overwriteService('DateTimeFormatter', $newDateTimeFormatter); $result = OC_Util::formatDate(1350129205, false); $this->assertEquals($expected, $result); - $this->setDateFormatter($oldDateTimeFormatter); - } - - protected function setDateFormatter($formatter) { - \OC::$server->registerService('DateTimeFormatter', function ($c) use ($formatter) { - return $formatter; - }); + $this->restoreService('DateTimeFormatter'); } function testSanitizeHTML() { |