diff options
111 files changed, 905 insertions, 249 deletions
diff --git a/apps/comments/activity/extension.php b/apps/comments/activity/extension.php index 6bf7cae5882..ef800e88abc 100644 --- a/apps/comments/activity/extension.php +++ b/apps/comments/activity/extension.php @@ -80,7 +80,10 @@ class Extension implements IExtension { $l = $this->getL10N($languageCode); return array( - self::APP_NAME => (string) $l->t('<strong>Comments</strong> for files'), + self::APP_NAME => [ + 'desc' => (string) $l->t('<strong>Comments</strong> for files <em>(always listed in stream)</em>'), + 'methods' => [self::METHOD_MAIL], // self::METHOD_STREAM is forced true by the default value + ], ); } @@ -274,7 +277,11 @@ class Extension implements IExtension { */ public function filterNotificationTypes($types, $filter) { if ($filter === self::APP_NAME) { - return array_intersect($types, [self::APP_NAME]); + return [self::APP_NAME]; + } + if (in_array($filter, ['all', 'by', 'self', 'filter'])) { + $types[] = self::APP_NAME; + return $types; } return false; } diff --git a/apps/dav/lib/connector/sabre/filesplugin.php b/apps/dav/lib/connector/sabre/filesplugin.php index 686d0863f91..dd4670da5fa 100644 --- a/apps/dav/lib/connector/sabre/filesplugin.php +++ b/apps/dav/lib/connector/sabre/filesplugin.php @@ -39,6 +39,7 @@ use Sabre\DAV\Tree; use \Sabre\HTTP\RequestInterface; use \Sabre\HTTP\ResponseInterface; use OCP\Files\StorageNotAvailableException; +use OCP\IConfig; class FilesPlugin extends ServerPlugin { @@ -55,6 +56,7 @@ class FilesPlugin extends ServerPlugin { const OWNER_ID_PROPERTYNAME = '{http://owncloud.org/ns}owner-id'; const OWNER_DISPLAY_NAME_PROPERTYNAME = '{http://owncloud.org/ns}owner-display-name'; const CHECKSUMS_PROPERTYNAME = '{http://owncloud.org/ns}checksums'; + const DATA_FINGERPRINT_PROPERTYNAME = '{http://owncloud.org/ns}data-fingerprint'; /** * Reference to main server object @@ -87,6 +89,11 @@ class FilesPlugin extends ServerPlugin { private $downloadAttachment; /** + * @var IConfig + */ + private $config; + + /** * @param Tree $tree * @param View $view * @param bool $isPublic @@ -94,10 +101,12 @@ class FilesPlugin extends ServerPlugin { */ public function __construct(Tree $tree, View $view, + IConfig $config, $isPublic = false, $downloadAttachment = true) { $this->tree = $tree; $this->fileView = $view; + $this->config = $config; $this->isPublic = $isPublic; $this->downloadAttachment = $downloadAttachment; } @@ -125,6 +134,7 @@ class FilesPlugin extends ServerPlugin { $server->protectedProperties[] = self::OWNER_ID_PROPERTYNAME; $server->protectedProperties[] = self::OWNER_DISPLAY_NAME_PROPERTYNAME; $server->protectedProperties[] = self::CHECKSUMS_PROPERTYNAME; + $server->protectedProperties[] = self::DATA_FINGERPRINT_PROPERTYNAME; // normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH $allowedProperties = ['{DAV:}getetag']; @@ -272,6 +282,18 @@ class FilesPlugin extends ServerPlugin { $displayName = $owner->getDisplayName(); return $displayName; }); + + $propFind->handle(self::DATA_FINGERPRINT_PROPERTYNAME, function() use ($node) { + if ($node->getPath() === '/') { + return $this->config->getSystemValue('data-fingerprint', ''); + } + }); + } + + if ($node instanceof \OCA\DAV\Files\FilesHome) { + $propFind->handle(self::DATA_FINGERPRINT_PROPERTYNAME, function() use ($node) { + return $this->config->getSystemValue('data-fingerprint', ''); + }); } if ($node instanceof \OCA\DAV\Connector\Sabre\File) { diff --git a/apps/dav/lib/connector/sabre/serverfactory.php b/apps/dav/lib/connector/sabre/serverfactory.php index cab7a85d19f..5853370778d 100644 --- a/apps/dav/lib/connector/sabre/serverfactory.php +++ b/apps/dav/lib/connector/sabre/serverfactory.php @@ -137,8 +137,15 @@ class ServerFactory { } $objectTree->init($root, $view, $this->mountManager); - $server->addPlugin(new \OCA\DAV\Connector\Sabre\FilesPlugin($objectTree, $view, false, - !$this->config->getSystemValue('debug', false))); + $server->addPlugin( + new \OCA\DAV\Connector\Sabre\FilesPlugin( + $objectTree, + $view, + $this->config, + false, + !$this->config->getSystemValue('debug', false) + ) + ); $server->addPlugin(new \OCA\DAV\Connector\Sabre\QuotaPlugin($view)); if($this->userSession->isLoggedIn()) { diff --git a/apps/dav/lib/hookmanager.php b/apps/dav/lib/hookmanager.php index 4a4704ff2a2..687e6718db3 100644 --- a/apps/dav/lib/hookmanager.php +++ b/apps/dav/lib/hookmanager.php @@ -100,26 +100,26 @@ class HookManager { public function postLogin($params) { $user = $this->userManager->get($params['uid']); - - $principal = 'principals/users/' . $user->getUID(); - $calendars = $this->calDav->getCalendarsForUser($principal); - if (empty($calendars)) { - try { - $this->calDav->createCalendar($principal, 'personal', [ - 'displayname' => 'Personal']); - } catch (\Exception $ex) { - \OC::$server->getLogger()->logException($ex); + if (!is_null($user)) { + $principal = 'principals/users/' . $user->getUID(); + $calendars = $this->calDav->getCalendarsForUser($principal); + if (empty($calendars)) { + try { + $this->calDav->createCalendar($principal, 'personal', [ + '{DAV:}displayname' => 'Personal']); + } catch (\Exception $ex) { + \OC::$server->getLogger()->logException($ex); + } } - } - $books = $this->cardDav->getAddressBooksForUser($principal); - if (empty($books)) { - try { - $this->cardDav->createAddressBook($principal, 'contacts', [ - 'displayname' => 'Contacts']); - } catch (\Exception $ex) { - \OC::$server->getLogger()->logException($ex); + $books = $this->cardDav->getAddressBooksForUser($principal); + if (empty($books)) { + try { + $this->cardDav->createAddressBook($principal, 'contacts', [ + '{DAV:}displayname' => 'Contacts']); + } catch (\Exception $ex) { + \OC::$server->getLogger()->logException($ex); + } } } - } } diff --git a/apps/dav/lib/server.php b/apps/dav/lib/server.php index e6668556448..73e24c9a292 100644 --- a/apps/dav/lib/server.php +++ b/apps/dav/lib/server.php @@ -132,8 +132,15 @@ class Server { $user = \OC::$server->getUserSession()->getUser(); if (!is_null($user)) { $view = \OC\Files\Filesystem::getView(); - $this->server->addPlugin(new FilesPlugin($this->server->tree, $view, false, - !\OC::$server->getConfig()->getSystemValue('debug', false))); + $this->server->addPlugin( + new FilesPlugin( + $this->server->tree, + $view, + \OC::$server->getConfig(), + false, + !\OC::$server->getConfig()->getSystemValue('debug', false) + ) + ); $this->server->addPlugin( new \Sabre\DAV\PropertyStorage\Plugin( diff --git a/apps/dav/tests/unit/connector/sabre/filesplugin.php b/apps/dav/tests/unit/connector/sabre/filesplugin.php index 63ee5a53c17..fb5d658b39c 100644 --- a/apps/dav/tests/unit/connector/sabre/filesplugin.php +++ b/apps/dav/tests/unit/connector/sabre/filesplugin.php @@ -43,6 +43,7 @@ class FilesPlugin extends TestCase { const DOWNLOADURL_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::DOWNLOADURL_PROPERTYNAME; const OWNER_ID_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::OWNER_ID_PROPERTYNAME; const OWNER_DISPLAY_NAME_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME; + const DATA_FINGERPRINT_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME; /** * @var \Sabre\DAV\Server | \PHPUnit_Framework_MockObject_MockObject @@ -64,6 +65,11 @@ class FilesPlugin extends TestCase { */ private $view; + /** + * @var \OCP\IConfig | \PHPUnit_Framework_MockObject_MockObject + */ + private $config; + public function setUp() { parent::setUp(); $this->server = $this->getMockBuilder('\Sabre\DAV\Server') @@ -75,8 +81,16 @@ class FilesPlugin extends TestCase { $this->view = $this->getMockBuilder('\OC\Files\View') ->disableOriginalConstructor() ->getMock(); - - $this->plugin = new \OCA\DAV\Connector\Sabre\FilesPlugin($this->tree, $this->view); + $this->config = $this->getMock('\OCP\IConfig'); + $this->config->method('getSystemValue') + ->with($this->equalTo('data-fingerprint'), $this->equalTo('')) + ->willReturn('my_fingerprint'); + + $this->plugin = new \OCA\DAV\Connector\Sabre\FilesPlugin( + $this->tree, + $this->view, + $this->config + ); $this->plugin->initialize($this->server); } @@ -128,7 +142,8 @@ class FilesPlugin extends TestCase { self::PERMISSIONS_PROPERTYNAME, self::DOWNLOADURL_PROPERTYNAME, self::OWNER_ID_PROPERTYNAME, - self::OWNER_DISPLAY_NAME_PROPERTYNAME + self::OWNER_DISPLAY_NAME_PROPERTYNAME, + self::DATA_FINGERPRINT_PROPERTYNAME, ), 0 ); @@ -166,7 +181,7 @@ class FilesPlugin extends TestCase { $this->assertEquals('http://example.com/', $propFind->get(self::DOWNLOADURL_PROPERTYNAME)); $this->assertEquals('foo', $propFind->get(self::OWNER_ID_PROPERTYNAME)); $this->assertEquals('M. Foo', $propFind->get(self::OWNER_DISPLAY_NAME_PROPERTYNAME)); - $this->assertEquals(array(self::SIZE_PROPERTYNAME), $propFind->get404Properties()); + $this->assertEquals([self::SIZE_PROPERTYNAME, self::DATA_FINGERPRINT_PROPERTYNAME], $propFind->get404Properties()); } public function testGetPropertiesForFileHome() { @@ -185,7 +200,8 @@ class FilesPlugin extends TestCase { self::PERMISSIONS_PROPERTYNAME, self::DOWNLOADURL_PROPERTYNAME, self::OWNER_ID_PROPERTYNAME, - self::OWNER_DISPLAY_NAME_PROPERTYNAME + self::OWNER_DISPLAY_NAME_PROPERTYNAME, + self::DATA_FINGERPRINT_PROPERTYNAME, ), 0 ); @@ -217,6 +233,7 @@ class FilesPlugin extends TestCase { '{http://owncloud.org/ns}owner-id', '{http://owncloud.org/ns}owner-display-name' ], $propFind->get404Properties()); + $this->assertEquals('my_fingerprint', $propFind->get(self::DATA_FINGERPRINT_PROPERTYNAME)); } public function testGetPropertiesStorageNotAvailable() { @@ -244,7 +261,11 @@ class FilesPlugin extends TestCase { } public function testGetPublicPermissions() { - $this->plugin = new \OCA\DAV\Connector\Sabre\FilesPlugin($this->tree, $this->view, true); + $this->plugin = new \OCA\DAV\Connector\Sabre\FilesPlugin( + $this->tree, + $this->view, + $this->config, + true); $this->plugin->initialize($this->server); $propFind = new PropFind( @@ -281,6 +302,7 @@ class FilesPlugin extends TestCase { self::SIZE_PROPERTYNAME, self::PERMISSIONS_PROPERTYNAME, self::DOWNLOADURL_PROPERTYNAME, + self::DATA_FINGERPRINT_PROPERTYNAME, ), 0 ); @@ -299,7 +321,30 @@ class FilesPlugin extends TestCase { $this->assertEquals(1025, $propFind->get(self::SIZE_PROPERTYNAME)); $this->assertEquals('DWCKMSR', $propFind->get(self::PERMISSIONS_PROPERTYNAME)); $this->assertEquals(null, $propFind->get(self::DOWNLOADURL_PROPERTYNAME)); - $this->assertEquals(array(self::DOWNLOADURL_PROPERTYNAME), $propFind->get404Properties()); + $this->assertEquals([self::DOWNLOADURL_PROPERTYNAME, self::DATA_FINGERPRINT_PROPERTYNAME], $propFind->get404Properties()); + } + + public function testGetPropertiesForRootDirectory() { + /** @var \OCA\DAV\Connector\Sabre\Directory | \PHPUnit_Framework_MockObject_MockObject $node */ + $node = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\Directory') + ->disableOriginalConstructor() + ->getMock(); + $node->method('getPath')->willReturn('/'); + + $propFind = new PropFind( + '/', + [ + self::DATA_FINGERPRINT_PROPERTYNAME, + ], + 0 + ); + + $this->plugin->handleGetProperties( + $propFind, + $node + ); + + $this->assertEquals('my_fingerprint', $propFind->get(self::DATA_FINGERPRINT_PROPERTYNAME)); } public function testUpdateProps() { diff --git a/apps/dav/tests/unit/connector/sabre/filesreportplugin.php b/apps/dav/tests/unit/connector/sabre/filesreportplugin.php index 87973ef0071..ffe1a19ee56 100644 --- a/apps/dav/tests/unit/connector/sabre/filesreportplugin.php +++ b/apps/dav/tests/unit/connector/sabre/filesreportplugin.php @@ -336,7 +336,15 @@ class FilesReportPlugin extends \Test\TestCase { ->method('getSize') ->will($this->returnValue(1024)); - $this->server->addPlugin(new \OCA\DAV\Connector\Sabre\FilesPlugin($this->tree, $this->view)); + $config = $this->getMock('\OCP\IConfig'); + + $this->server->addPlugin( + new \OCA\DAV\Connector\Sabre\FilesPlugin( + $this->tree, + $this->view, + $config + ) + ); $this->plugin->initialize($this->server); $responses = $this->plugin->prepareResponses($requestedProps, [$node1, $node2]); diff --git a/apps/dav/tests/unit/dav/HookManagerTest.php b/apps/dav/tests/unit/dav/HookManagerTest.php new file mode 100644 index 00000000000..bec4c240ce8 --- /dev/null +++ b/apps/dav/tests/unit/dav/HookManagerTest.php @@ -0,0 +1,71 @@ +<?php + +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCA\DAV\Tests\Unit\DAV; + +use OCA\DAV\CalDAV\CalDavBackend; +use OCA\DAV\CardDAV\CardDavBackend; +use OCA\DAV\CardDAV\SyncService; +use OCA\DAV\HookManager; +use OCP\IUserManager; +use Test\TestCase; + +class HookManagerTest extends TestCase { + public function test() { + $user = $this->getMockBuilder('\OCP\IUser') + ->disableOriginalConstructor() + ->getMock(); + $user->expects($this->once())->method('getUID')->willReturn('newUser'); + + /** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject $userManager */ + $userManager = $this->getMockBuilder('\OCP\IUserManager') + ->disableOriginalConstructor() + ->getMock(); + $userManager->expects($this->once())->method('get')->willReturn($user); + + /** @var SyncService | \PHPUnit_Framework_MockObject_MockObject $syncService */ + $syncService = $this->getMockBuilder('OCA\DAV\CardDAV\SyncService') + ->disableOriginalConstructor() + ->getMock(); + + /** @var CalDavBackend | \PHPUnit_Framework_MockObject_MockObject $cal */ + $cal = $this->getMockBuilder('OCA\DAV\CalDAV\CalDavBackend') + ->disableOriginalConstructor() + ->getMock(); + $cal->expects($this->once())->method('getCalendarsForUser')->willReturn([]); + $cal->expects($this->once())->method('createCalendar')->with( + 'principals/users/newUser', + 'personal', ['{DAV:}displayname' => 'Personal']); + + /** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject $card */ + $card = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend') + ->disableOriginalConstructor() + ->getMock(); + $card->expects($this->once())->method('getAddressBooksForUser')->willReturn([]); + $card->expects($this->once())->method('createAddressBook')->with( + 'principals/users/newUser', + 'contacts', ['{DAV:}displayname' => 'Contacts']); + + $hm = new HookManager($userManager, $syncService, $cal, $card); + $hm->postLogin(['uid' => 'newUser']); + } +} diff --git a/apps/encryption/hooks/userhooks.php b/apps/encryption/hooks/userhooks.php index 62acd168909..bde4d5869b4 100644 --- a/apps/encryption/hooks/userhooks.php +++ b/apps/encryption/hooks/userhooks.php @@ -24,6 +24,7 @@ namespace OCA\Encryption\Hooks; +use OC\Files\Filesystem; use OCP\IUserManager; use OCP\Util as OCUtil; use OCA\Encryption\Hooks\Contracts\IHook; @@ -243,6 +244,7 @@ class UserHooks implements IHook { // used to decrypt it has changed } else { // admin changed the password for a different user, create new keys and re-encrypt file keys $user = $params['uid']; + $this->initMountPoints($user); $recoveryPassword = isset($params['recoveryPassword']) ? $params['recoveryPassword'] : null; // we generate new keys if... @@ -281,6 +283,15 @@ class UserHooks implements IHook { } } + /** + * init mount points for given user + * + * @param string $user + * @throws \OC\User\NoUserException + */ + protected function initMountPoints($user) { + Filesystem::initMountPoints($user); + } /** diff --git a/apps/encryption/lib/crypto/encryption.php b/apps/encryption/lib/crypto/encryption.php index 907a6437f5b..6eff66e72be 100644 --- a/apps/encryption/lib/crypto/encryption.php +++ b/apps/encryption/lib/crypto/encryption.php @@ -547,4 +547,17 @@ class Encryption implements IEncryptionModule { return $path; } + /** + * Check if the module is ready to be used by that specific user. + * In case a module is not ready - because e.g. key pairs have not been generated + * upon login this method can return false before any operation starts and might + * cause issues during operations. + * + * @param string $user + * @return boolean + * @since 9.1.0 + */ + public function isReadyForUser($user) { + return $this->keyManager->userHasKeys($user); + } } diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/keymanager.php index 12fa5f92bd5..0accfb7900a 100644 --- a/apps/encryption/lib/keymanager.php +++ b/apps/encryption/lib/keymanager.php @@ -493,6 +493,7 @@ class KeyManager { */ public function userHasKeys($userId) { $privateKey = $publicKey = true; + $exception = null; try { $this->getPrivateKey($userId); diff --git a/apps/encryption/tests/hooks/UserHooksTest.php b/apps/encryption/tests/hooks/UserHooksTest.php index 08d1981266c..d2a7d4f2d04 100644 --- a/apps/encryption/tests/hooks/UserHooksTest.php +++ b/apps/encryption/tests/hooks/UserHooksTest.php @@ -29,6 +29,12 @@ use OCA\Encryption\Crypto\Crypt; use OCA\Encryption\Hooks\UserHooks; use Test\TestCase; +/** + * Class UserHooksTest + * + * @group DB + * @package OCA\Encryption\Tests\Hooks + */ class UserHooksTest extends TestCase { /** * @var \PHPUnit_Framework_MockObject_MockObject @@ -190,6 +196,23 @@ class UserHooksTest extends TestCase { ->willReturnOnConsecutiveCalls(true, false); + $this->instance = $this->getMockBuilder('OCA\Encryption\Hooks\UserHooks') + ->setConstructorArgs( + [ + $this->keyManagerMock, + $this->userManagerMock, + $this->loggerMock, + $this->userSetupMock, + $this->userSessionMock, + $this->utilMock, + $this->sessionMock, + $this->cryptMock, + $this->recoveryMock + ] + )->setMethods(['initMountPoints'])->getMock(); + + $this->instance->expects($this->exactly(3))->method('initMountPoints'); + // Test first if statement $this->assertNull($this->instance->setPassphrase($this->params)); @@ -236,16 +259,20 @@ class UserHooksTest extends TestCase { ->with('testUser') ->willReturn(false); - $userHooks = new UserHooks($this->keyManagerMock, - $this->userManagerMock, - $this->loggerMock, - $this->userSetupMock, - $userSessionMock, - $this->utilMock, - $this->sessionMock, - $this->cryptMock, - $this->recoveryMock - ); + $userHooks = $this->getMockBuilder('OCA\Encryption\Hooks\UserHooks') + ->setConstructorArgs( + [ + $this->keyManagerMock, + $this->userManagerMock, + $this->loggerMock, + $this->userSetupMock, + $userSessionMock, + $this->utilMock, + $this->sessionMock, + $this->cryptMock, + $this->recoveryMock + ] + )->setMethods(['initMountPoints'])->getMock(); $this->assertNull($userHooks->setPassphrase($this->params)); } diff --git a/apps/files/appinfo/routes.php b/apps/files/appinfo/routes.php index 6ad938101a2..2291b48e3c5 100644 --- a/apps/files/appinfo/routes.php +++ b/apps/files/appinfo/routes.php @@ -54,6 +54,11 @@ $application->registerRoutes( 'url' => '/api/v1/sorting', 'verb' => 'POST' ), + array( + 'name' => 'API#showHiddenFiles', + 'url' => '/api/v1/showhidden', + 'verb' => 'POST' + ), [ 'name' => 'view#index', 'url' => '/', diff --git a/apps/files/command/transferownership.php b/apps/files/command/transferownership.php index 6bf2fae6bdf..1f46efdde0d 100644 --- a/apps/files/command/transferownership.php +++ b/apps/files/command/transferownership.php @@ -97,6 +97,12 @@ class TransferOwnership extends Command { $output->writeln("<error>Unknown destination user $this->destinationUser</error>"); return; } + + // target user has to be ready + if (!\OC::$server->getEncryptionManager()->isReadyForUser($this->destinationUser)) { + $output->writeln("<error>The target user is not ready to accept files. The user has at least to be logged in once.</error>"); + return; + } $date = date('c'); $this->finalTarget = "$this->destinationUser/files/transferred from $this->sourceUser on $date"; diff --git a/apps/files/controller/apicontroller.php b/apps/files/controller/apicontroller.php index 43d426476fe..072498c7b5f 100644 --- a/apps/files/controller/apicontroller.php +++ b/apps/files/controller/apicontroller.php @@ -224,4 +224,16 @@ class ApiController extends Controller { return new Response(); } + /** + * Toggle default for showing/hiding hidden files + * + * @NoAdminRequired + * + * @param bool $show + */ + public function showHiddenFiles($show) { + $this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'show_hidden', (int) $show); + return new Response(); + } + } diff --git a/apps/files/controller/viewcontroller.php b/apps/files/controller/viewcontroller.php index 6c5f4c6d2a0..9fe34521332 100644 --- a/apps/files/controller/viewcontroller.php +++ b/apps/files/controller/viewcontroller.php @@ -67,6 +67,7 @@ class ViewController extends Controller { * @param IL10N $l10n * @param IConfig $config * @param EventDispatcherInterface $eventDispatcherInterface + * @param IUserSession $userSession */ public function __construct($appName, IRequest $request, @@ -222,6 +223,8 @@ class ViewController extends Controller { $user = $this->userSession->getUser()->getUID(); $params['defaultFileSorting'] = $this->config->getUserValue($user, 'files', 'file_sorting', 'name'); $params['defaultFileSortingDirection'] = $this->config->getUserValue($user, 'files', 'file_sorting_direction', 'asc'); + $showHidden = (bool) $this->config->getUserValue($this->userSession->getUser()->getUID(), 'files', 'show_hidden', false); + $params['showHiddenFiles'] = $showHidden ? 1 : 0; $params['appNavigation'] = $nav; $params['appContents'] = $contentItems; $this->navigationManager->setActiveEntry('files_index'); diff --git a/apps/files/css/files.css b/apps/files/css/files.css index d20ab102ba5..373739071e9 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -2,6 +2,11 @@ This file is licensed under the Affero General Public License version 3 or later. See the COPYING-README file. */ +/* SETTINGS */ +#files-setting-showhidden { + padding-bottom: 8px; +} + /* FILE MENU */ .actions { padding:5px; height:32px; display: inline-block; float: left; } .actions input, .actions button, .actions .button { margin:0; float:left; } diff --git a/apps/files/js/app.js b/apps/files/js/app.js index 4ed805d2681..eac080a009d 100644 --- a/apps/files/js/app.js +++ b/apps/files/js/app.js @@ -11,7 +11,7 @@ * */ -/* global dragOptions, folderDropOptions */ +/* global dragOptions, folderDropOptions, OC */ (function() { if (!OCA.Files) { @@ -41,10 +41,22 @@ fileList: null, /** + * Backbone model for storing files preferences + */ + _filesConfig: null, + + /** * Initializes the files app */ initialize: function() { this.navigation = new OCA.Files.Navigation($('#app-navigation')); + this.$showHiddenFiles = $('input#showhiddenfilesToggle'); + var showHidden = $('#showHiddenFiles').val() === "1"; + this.$showHiddenFiles.prop('checked', showHidden); + + this._filesConfig = new OC.Backbone.Model({ + showhidden: showHidden + }); var urlParams = OC.Util.History.parseUrlQuery(); var fileActions = new OCA.Files.FileActions(); @@ -76,7 +88,8 @@ sorting: { mode: $('#defaultFileSorting').val(), direction: $('#defaultFileSortingDirection').val() - } + }, + config: this._filesConfig, } ); this.files.initialize(); @@ -90,6 +103,8 @@ this._setupEvents(); // trigger URL change event handlers this._onPopState(urlParams); + + this._debouncedPersistShowHiddenFilesState = _.debounce(this._persistShowHiddenFilesState, 1200); }, /** @@ -144,6 +159,14 @@ }, /** + * + * @returns {Backbone.Model} + */ + getFilesConfig: function() { + return this._filesConfig; + }, + + /** * Setup events based on URL changes */ _setupEvents: function() { @@ -154,6 +177,30 @@ $('#app-content').delegate('>div', 'changeViewerMode', _.bind(this._onChangeViewerMode, this)); $('#app-navigation').on('itemChanged', _.bind(this._onNavigationChanged, this)); + this.$showHiddenFiles.on('change', _.bind(this._onShowHiddenFilesChange, this)); + }, + + /** + * Toggle showing hidden files according to the settings checkbox + * + * @returns {undefined} + */ + _onShowHiddenFilesChange: function() { + var show = this.$showHiddenFiles.is(':checked'); + this._filesConfig.set('showhidden', show); + this._debouncedPersistShowHiddenFilesState(); + }, + + /** + * Persist show hidden preference on ther server + * + * @returns {undefined} + */ + _persistShowHiddenFilesState: function() { + var show = this._filesConfig.get('showhidden'); + $.post(OC.generateUrl('/apps/files/api/v1/showhidden'), { + show: show + }); }, /** diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 7de64f8ade3..79dc42da8f1 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -145,6 +145,11 @@ _filter: '', /** + * @type Backbone.Model + */ + _filesConfig: null, + + /** * Sort attribute * @type String */ @@ -198,6 +203,15 @@ return; } + if (options.config) { + this._filesConfig = options.config; + } else { + this._filesConfig = OCA.Files.App.getFilesConfig(); + } + this._filesConfig.on('change:showhidden', function() { + self.setFiles(self.files); + }); + if (options.dragOptions) { this._dragOptions = options.dragOptions; } @@ -847,6 +861,10 @@ * @return array of DOM elements of the newly added files */ _nextPage: function(animate) { + // Save full files list while rendering + var allFiles = this.files; + this.files = this._filterHiddenFiles(this.files); + var index = this.$fileList.children().length, count = this.pageSize(), hidden, @@ -893,6 +911,10 @@ } }, 0); } + + // Restore full files list after rendering + this.files = allFiles; + return newTrs; }, @@ -930,18 +952,25 @@ // clear "Select all" checkbox this.$el.find('.select-all').prop('checked', false); + // Save full files list while rendering + var allFiles = this.files; + this.files = this._filterHiddenFiles(this.files); + this.isEmpty = this.files.length === 0; this._nextPage(); this.updateEmptyContent(); - this.fileSummary.calculate(filesArray); + this.fileSummary.calculate(this.files); this._selectedFiles = {}; this._selectionSummary.clear(); this.updateSelectionSummary(); $(window).scrollTop(0); + // Restore full files list after rendering + this.files = allFiles; + this.$fileList.trigger(jQuery.Event('updated')); _.defer(function() { self.$el.closest('#app-content').trigger(jQuery.Event('apprendered')); @@ -949,6 +978,21 @@ }, /** + * Filter hidden files of the given filesArray (dot-files) + * + * @param filesArray files to be filtered + * @returns {array} + */ + _filterHiddenFiles: function(files) { + if (this._filesConfig.get('showhidden')) { + return files; + } + return _.filter(files, function(file) { + return file.name.indexOf('.') !== 0; + }); + }, + + /** * Returns the icon URL matching the given file info * * @param {OC.Files.FileInfo} fileInfo file info diff --git a/apps/files/templates/appnavigation.php b/apps/files/templates/appnavigation.php index 39a5875f3d0..9c79f806713 100644 --- a/apps/files/templates/appnavigation.php +++ b/apps/files/templates/appnavigation.php @@ -16,9 +16,13 @@ </button> </div> <div id="app-settings-content"> - <label for="webdavurl"><?php p($l->t('WebDAV'));?></label> - <input id="webdavurl" type="text" readonly="readonly" value="<?php p(\OCP\Util::linkToRemote('webdav')); ?>" /> - <em><?php print_unescaped($l->t('Use this address to <a href="%s" target="_blank" rel="noreferrer">access your Files via WebDAV</a>', array(link_to_docs('user-webdav'))));?></em> + <div id="files-setting-showhidden"> + <input class="checkbox" id="showhiddenfilesToggle" checked="checked" type="checkbox"> + <label for="showhiddenfilesToggle"><?php p($l->t('Show hidden files')); ?></label> + </div> + <label for="webdavurl"><?php p($l->t('WebDAV'));?></label> + <input id="webdavurl" type="text" readonly="readonly" value="<?php p(\OCP\Util::linkToRemote('webdav')); ?>" /> + <em><?php print_unescaped($l->t('Use this address to <a href="%s" target="_blank" rel="noreferrer">access your Files via WebDAV</a>', array(link_to_docs('user-webdav'))));?></em> </div> </div> </div> diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index db464ad2eca..7281edd3aec 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -20,4 +20,5 @@ <input type="hidden" name="allowShareWithLink" id="allowShareWithLink" value="<?php p($_['allowShareWithLink']) ?>" /> <input type="hidden" name="defaultFileSorting" id="defaultFileSorting" value="<?php p($_['defaultFileSorting']) ?>" /> <input type="hidden" name="defaultFileSortingDirection" id="defaultFileSortingDirection" value="<?php p($_['defaultFileSortingDirection']) ?>" /> +<input type="hidden" name="showHiddenFiles" id="showHiddenFiles" value="<?php p($_['showHiddenFiles']); ?>" /> <?php endif; diff --git a/apps/files/tests/controller/ViewControllerTest.php b/apps/files/tests/controller/ViewControllerTest.php index 0446cc8982c..420e635b4b9 100644 --- a/apps/files/tests/controller/ViewControllerTest.php +++ b/apps/files/tests/controller/ViewControllerTest.php @@ -155,11 +155,12 @@ class ViewControllerTest extends TestCase { 'owner' => 'MyName', 'ownerDisplayName' => 'MyDisplayName', ])); - $this->config->expects($this->exactly(2)) + $this->config->expects($this->exactly(3)) ->method('getUserValue') ->will($this->returnValueMap([ [$this->user->getUID(), 'files', 'file_sorting', 'name', 'name'], - [$this->user->getUID(), 'files', 'file_sorting_direction', 'asc', 'asc'] + [$this->user->getUID(), 'files', 'file_sorting_direction', 'asc', 'asc'], + [$this->user->getUID(), 'files', 'show_hidden', false, false], ])); $this->config @@ -244,6 +245,7 @@ class ViewControllerTest extends TestCase { 'isPublic' => false, 'defaultFileSorting' => 'name', 'defaultFileSortingDirection' => 'asc', + 'showHiddenFiles' => false, 'mailNotificationEnabled' => 'no', 'mailPublicNotificationEnabled' => 'no', 'allowShareWithLink' => 'yes', diff --git a/apps/files/tests/controller/apicontrollertest.php b/apps/files/tests/controller/apicontrollertest.php index 59f53e8ee81..2eba7d62feb 100644 --- a/apps/files/tests/controller/apicontrollertest.php +++ b/apps/files/tests/controller/apicontrollertest.php @@ -1,4 +1,5 @@ <?php + /** * @author Christoph Wurst <christoph@winzerhof-wurst.at> * @author Lukas Reschke <lukas@owncloud.com> @@ -382,4 +383,17 @@ class ApiControllerTest extends TestCase { $this->assertEquals($expected, $result); } + public function testShowHiddenFiles() { + $show = false; + + $this->config->expects($this->once()) + ->method('setUserValue') + ->with($this->user->getUID(), 'files', 'show_hidden', $show); + + $expected = new Http\Response(); + $actual = $this->apiController->showHiddenFiles($show); + + $this->assertEquals($expected, $actual); + } + } diff --git a/apps/files_sharing/js/app.js b/apps/files_sharing/js/app.js index af198208de2..6f12b3d4456 100644 --- a/apps/files_sharing/js/app.js +++ b/apps/files_sharing/js/app.js @@ -33,7 +33,8 @@ OCA.Sharing.App = { id: 'shares.self', scrollContainer: $('#app-content'), sharedWithUser: true, - fileActions: this._createFileActions() + fileActions: this._createFileActions(), + config: OCA.Files.App.getFilesConfig() } ); @@ -55,7 +56,8 @@ OCA.Sharing.App = { id: 'shares.others', scrollContainer: $('#app-content'), sharedWithUser: false, - fileActions: this._createFileActions() + fileActions: this._createFileActions(), + config: OCA.Files.App.getFilesConfig() } ); @@ -77,7 +79,8 @@ OCA.Sharing.App = { id: 'shares.link', scrollContainer: $('#app-content'), linksOnly: true, - fileActions: this._createFileActions() + fileActions: this._createFileActions(), + config: OCA.Files.App.getFilesConfig() } ); diff --git a/apps/files_sharing/tests/testcase.php b/apps/files_sharing/tests/testcase.php index d30782e5074..0950c2a62f5 100644 --- a/apps/files_sharing/tests/testcase.php +++ b/apps/files_sharing/tests/testcase.php @@ -87,7 +87,7 @@ abstract class TestCase extends \Test\TestCase { $backend->createUser(self::TEST_FILES_SHARING_API_USER4, self::TEST_FILES_SHARING_API_USER4); // create group - $groupBackend = new \OC_Group_Dummy(); + $groupBackend = new \Test\Util\Group\Dummy(); $groupBackend->createGroup(self::TEST_FILES_SHARING_API_GROUP1); $groupBackend->createGroup('group'); $groupBackend->createGroup('group1'); diff --git a/apps/files_trashbin/js/app.js b/apps/files_trashbin/js/app.js index 771ea90bc16..fd3d5db32ff 100644 --- a/apps/files_trashbin/js/app.js +++ b/apps/files_trashbin/js/app.js @@ -29,7 +29,8 @@ OCA.Trashbin.App = { scrollContainer: $('#app-content'), fileActions: this._createFileActions(), detailsViewEnabled: false, - scrollTo: urlParams.scrollto + scrollTo: urlParams.scrollto, + config: OCA.Files.App.getFilesConfig() } ); }, diff --git a/apps/systemtags/js/app.js b/apps/systemtags/js/app.js index d28514358c1..e027c0be123 100644 --- a/apps/systemtags/js/app.js +++ b/apps/systemtags/js/app.js @@ -28,7 +28,8 @@ { id: 'systemtags', scrollContainer: $('#app-content'), - fileActions: this._createFileActions() + fileActions: this._createFileActions(), + config: OCA.Files.App.getFilesConfig() } ); diff --git a/config/config.sample.php b/config/config.sample.php index b54bbf6a7b9..db662cfd74f 100644 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -1210,6 +1210,19 @@ $CONFIG = array( 'debug' => false, /** + * Sets the data-fingerprint of the current data served + * + * This is a property used by the clients to find out if a backup has been + * restored on the server. Once a backup is restored run + * ./occ maintenance:data-fingerprint + * To set this to a new value. + * + * Updating/Deleting this value can make connected clients stall until + * the user has resolved conflicts. + */ +'data-fingerprint' => '', + +/** * This entry is just here to show a warning in case somebody copied the sample * configuration. DO NOT ADD THIS SWITCH TO YOUR CONFIGURATION! * diff --git a/console.php b/console.php index fc571b03f1e..9d2271db9f2 100644 --- a/console.php +++ b/console.php @@ -42,6 +42,11 @@ if (version_compare(PHP_VERSION, '5.4.0') === -1) { return; } +function exceptionHandler($exception) { + echo "An unhandled exception has been thrown:" . PHP_EOL; + echo $exception; + exit(1); +} try { require_once 'lib/base.php'; @@ -53,6 +58,8 @@ try { exit(0); } + set_exception_handler('exceptionHandler'); + if (!OC_Util::runningOnWindows()) { if (!function_exists('posix_getuid')) { echo "The posix extensions are required - see http://php.net/manual/en/book.posix.php" . PHP_EOL; @@ -87,7 +94,5 @@ try { $application->loadCommands(new ArgvInput(), new ConsoleOutput()); $application->run(); } catch (Exception $ex) { - echo "An unhandled exception has been thrown:" . PHP_EOL; - echo $ex; - exit(1); + exceptionHandler($ex); } diff --git a/core/Command/Maintenance/DataFingerprint.php b/core/Command/Maintenance/DataFingerprint.php new file mode 100644 index 00000000000..38f490fd12a --- /dev/null +++ b/core/Command/Maintenance/DataFingerprint.php @@ -0,0 +1,53 @@ +<?php +/** + * @author Roeland Jago Douma <rullzer@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ +namespace OC\Core\Command\Maintenance; + +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\IConfig; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + + +class DataFingerprint extends Command { + + /** @var IConfig */ + protected $config; + /** @var ITimeFactory */ + protected $timeFactory; + + public function __construct(IConfig $config, + ITimeFactory $timeFactory) { + $this->config = $config; + $this->timeFactory = $timeFactory; + parent::__construct(); + } + + protected function configure() { + $this + ->setName('maintenance:data-fingerprint') + ->setDescription('update the systems data-fingerprint after a backup is restored'); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $this->config->setSystemValue('data-fingerprint', md5($this->timeFactory->getTime())); + } +} diff --git a/core/js/core.json b/core/js/core.json index 555c683f6f7..03c72e9b3ff 100644 --- a/core/js/core.json +++ b/core/js/core.json @@ -32,6 +32,7 @@ "sharedialogview.js", "sharedialogexpirationview.js", "sharedialoglinkshareview.js", + "sharedialogmailview.js", "sharedialogresharerinfoview.js", "sharedialogshareelistview.js", "octemplate.js", diff --git a/core/js/sharedialoglinkshareview.js b/core/js/sharedialoglinkshareview.js index 1d158ccec16..2fc6f657b02 100644 --- a/core/js/sharedialoglinkshareview.js +++ b/core/js/sharedialoglinkshareview.js @@ -40,12 +40,6 @@ '<label for="sharingDialogAllowPublicUpload-{{cid}}">{{publicUploadLabel}}</label>' + '</div>' + ' {{/if}}' + - ' {{#if mailPublicNotificationEnabled}}' + - '<form id="emailPrivateLink" class="emailPrivateLinkForm">' + - ' <input id="email" class="emailField" value="" placeholder="{{mailPrivatePlaceholder}}" type="text" />' + - ' <input id="emailButton" class="emailButton" type="submit" value="{{mailButtonText}}" />' + - '</form>' + - ' {{/if}}' + '{{else}}' + // FIXME: this doesn't belong in this view '{{#if noSharingPlaceholder}}<input id="shareWith-{{cid}}" class="shareWithField" type="text" placeholder="{{noSharingPlaceholder}}" disabled="disabled"/>{{/if}}' + @@ -76,7 +70,6 @@ showLink: true, events: { - 'submit .emailPrivateLinkForm': '_onEmailPrivateLink', 'focusout input.linkPassText': 'onPasswordEntered', 'keyup input.linkPassText': 'onPasswordKeyUp', 'click .linkCheckbox': 'onLinkCheckBoxChange', @@ -112,7 +105,6 @@ _.bindAll( this, - '_onEmailPrivateLink', 'onLinkCheckBoxChange', 'onPasswordEntered', 'onPasswordKeyUp', @@ -218,34 +210,6 @@ }); }, - _onEmailPrivateLink: function(event) { - event.preventDefault(); - - var $emailField = this.$el.find('.emailField'); - var $emailButton = this.$el.find('.emailButton'); - var email = $emailField.val(); - if (email !== '') { - $emailField.prop('disabled', true); - $emailButton.prop('disabled', true); - $emailField.val(t('core', 'Sending ...')); - this.model.sendEmailPrivateLink(email).done(function() { - $emailField.css('font-weight', 'bold').val(t('core','Email sent')); - setTimeout(function() { - $emailField.val(''); - $emailField.css('font-weight', 'normal'); - $emailField.prop('disabled', false); - $emailButton.prop('disabled', false); - }, 2000); - }).fail(function() { - $emailField.val(email); - $emailField.css('font-weight', 'normal'); - $emailField.prop('disabled', false); - $emailButton.prop('disabled', false); - }); - } - return false; - }, - render: function() { var linkShareTemplate = this.template(); var resharingAllowed = this.model.sharePermissionPossible(); @@ -299,39 +263,6 @@ mailButtonText: t('core', 'Send') })); - var $emailField = this.$el.find('.emailField'); - if (isLinkShare && $emailField.length !== 0) { - $emailField.autocomplete({ - minLength: 1, - source: function (search, response) { - $.get( - OC.generateUrl('core/ajax/share.php'), { - fetch: 'getShareWithEmail', - search: search.term - }, function(result) { - if (result.status == 'success' && result.data.length > 0) { - response(result.data); - } - }); - }, - select: function( event, item ) { - $emailField.val(item.item.email); - return false; - } - }) - .data("ui-autocomplete")._renderItem = function( ul, item ) { - return $('<li>') - .append('<a>' + escapeHTML(item.displayname) + "<br>" + escapeHTML(item.email) + '</a>' ) - .appendTo( ul ); - }; - } - - // TODO drop with IE8 drop - if($('html').hasClass('ie8')) { - this.$el.find('#linkPassText').removeAttr('placeholder'); - this.$el.find('#linkPassText').val(''); - } - this.delegateEvents(); return this; diff --git a/core/js/sharedialogmailview.js b/core/js/sharedialogmailview.js new file mode 100644 index 00000000000..84e3f3242ad --- /dev/null +++ b/core/js/sharedialogmailview.js @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2016 + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +(function() { + if (!OC.Share) { + OC.Share = {}; + } + + var TEMPLATE = + '{{#if shareAllowed}}' + + ' {{#if mailPublicNotificationEnabled}}' + + '<form id="emailPrivateLink" class="emailPrivateLinkForm">' + + ' <input id="email" class="emailField" value="{{email}}" placeholder="{{mailPrivatePlaceholder}}" type="text" />' + + ' <input id="emailButton" class="emailButton" type="submit" value="{{mailButtonText}}" />' + + '</form>' + + ' {{/if}}' + + '{{/if}}' + ; + + /** + * @class OCA.Share.ShareDialogMailView + * @member {OC.Share.ShareItemModel} model + * @member {jQuery} $el + * @memberof OCA.Sharing + * @classdesc + * + * Represents the GUI of the share dialogue + * + */ + var ShareDialogMailView = OC.Backbone.View.extend({ + /** @type {string} **/ + id: 'shareDialogMailView', + + /** @type {OC.Share.ShareConfigModel} **/ + configModel: undefined, + + /** @type {Function} **/ + _template: undefined, + + /** @type {boolean} **/ + showLink: true, + + events: { + 'submit .emailPrivateLinkForm': '_onEmailPrivateLink' + }, + + initialize: function(options) { + var view = this; + + this.model.on('change:linkShare', function() { + view.render(); + }); + + if(!_.isUndefined(options.configModel)) { + this.configModel = options.configModel; + } else { + throw 'missing OC.Share.ShareConfigModel'; + } + + _.bindAll( + this, + '_onEmailPrivateLink' + ); + }, + + _onEmailPrivateLink: function(event) { + event.preventDefault(); + + var $emailField = this.$el.find('.emailField'); + var $emailButton = this.$el.find('.emailButton'); + var email = $emailField.val(); + if (email !== '') { + $emailField.prop('disabled', true); + $emailButton.prop('disabled', true); + $emailField.val(t('core', 'Sending ...')); + this.model.sendEmailPrivateLink(email).done(function() { + $emailField.css('font-weight', 'bold').val(t('core','Email sent')); + setTimeout(function() { + $emailField.val(''); + $emailField.css('font-weight', 'normal'); + $emailField.prop('disabled', false); + $emailButton.prop('disabled', false); + }, 2000); + }).fail(function() { + $emailField.val(email); + $emailField.css('font-weight', 'normal'); + $emailField.prop('disabled', false); + $emailButton.prop('disabled', false); + }); + } + return false; + }, + + render: function() { + var linkShareTemplate = this.template(); + var resharingAllowed = this.model.sharePermissionPossible(); + var email = this.$el.find('.emailField').val(); + + if(!resharingAllowed + || !this.showLink + || !this.configModel.isShareWithLinkAllowed()) + { + var templateData = {shareAllowed: false}; + if (!resharingAllowed) { + // add message + templateData.noSharingPlaceholder = t('core', 'Resharing is not allowed'); + } + this.$el.html(linkShareTemplate(templateData)); + return this; + } + + var isLinkShare = this.model.get('linkShare').isLinkShare; + + this.$el.html(linkShareTemplate({ + cid: this.cid, + shareAllowed: true, + mailPublicNotificationEnabled: isLinkShare && this.configModel.isMailPublicNotificationEnabled(), + mailPrivatePlaceholder: t('core', 'Email link to person'), + mailButtonText: t('core', 'Send link via email'), + email: email + })); + + var $emailField = this.$el.find('.emailField'); + if (isLinkShare && $emailField.length !== 0) { + $emailField.autocomplete({ + minLength: 1, + source: function (search, response) { + $.get( + OC.generateUrl('core/ajax/share.php'), { + fetch: 'getShareWithEmail', + search: search.term + }, function(result) { + if (result.status == 'success' && result.data.length > 0) { + response(result.data); + } + }); + }, + select: function( event, item ) { + $emailField.val(item.item.email); + return false; + } + }) + .data("ui-autocomplete")._renderItem = function( ul, item ) { + return $('<li>') + .append('<a>' + escapeHTML(item.displayname) + "<br>" + escapeHTML(item.email) + '</a>' ) + .appendTo( ul ); + }; + } + this.delegateEvents(); + + return this; + }, + + /** + * @returns {Function} from Handlebars + * @private + */ + template: function () { + if (!this._template) { + this._template = Handlebars.compile(TEMPLATE); + } + return this._template; + } + + }); + + OC.Share.ShareDialogMailView = ShareDialogMailView; + +})();
\ No newline at end of file diff --git a/core/js/sharedialogview.js b/core/js/sharedialogview.js index 56f53caddae..a4bfde1777b 100644 --- a/core/js/sharedialogview.js +++ b/core/js/sharedialogview.js @@ -26,6 +26,7 @@ '<div class="shareeListView subView"></div>' + '<div class="linkShareView subView"></div>' + '<div class="expirationView subView"></div>' + + '<div class="mailView subView"></div>' + '<div class="loading hidden" style="height: 50px"></div>'; var TEMPLATE_REMOTE_SHARE_INFO = @@ -67,6 +68,9 @@ /** @type {object} **/ shareeListView: undefined, + /** @type {object} **/ + mailView: undefined, + events: { 'input .shareWithField': 'onShareWithFieldChanged' }, @@ -103,7 +107,8 @@ resharerInfoView: 'ShareDialogResharerInfoView', linkShareView: 'ShareDialogLinkShareView', expirationView: 'ShareDialogExpirationView', - shareeListView: 'ShareDialogShareeListView' + shareeListView: 'ShareDialogShareeListView', + mailView: 'ShareDialogMailView' }; for(var name in subViews) { @@ -360,6 +365,9 @@ this.shareeListView.$el = this.$el.find('.shareeListView'); this.shareeListView.render(); + this.mailView.$el = this.$el.find('.mailView'); + this.mailView.render(); + this.$el.find('.hasTooltip').tooltip(); return this; diff --git a/core/l10n/de.js b/core/l10n/de.js index b7c3e2d419f..a4a81239e40 100644 --- a/core/l10n/de.js +++ b/core/l10n/de.js @@ -26,6 +26,7 @@ OC.L10N.register( "Error favoriting" : "Fehler beim Favorisieren", "Error unfavoriting" : "Fehler beim Entfernen aus den Favoriten", "Couldn't send mail to following users: %s " : "Die E-Mail konnte nicht an folgende Benutzer gesendet werden: %s", + "Updates need to be installed. Please use the command line updater." : "Updates müssen installiert werden. Bitte nutze den Updater über die Kommandozeile.", "[%d / %d]: %s" : "[%d / %d]: %s", "[%d / %d]: Checking table %s" : "[%d / %d]: Überprüfe Tabelle %s", "Turned on maintenance mode" : "Wartungsmodus eingeschaltet", @@ -304,6 +305,10 @@ OC.L10N.register( "Start update" : "Aktualisierung starten", "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Zur Vermeidung von Zeitüberschreitungen bei größeren Installationen kannst Du stattdessen den folgenden Befehl in Deinem Installationsverzeichnis ausführen:", "Detailed logs" : "Detaillierte Fehlermeldungen", + "Update needed" : "Update wird benötigt", + "Please use the command line updater because you have a big instance." : "Da du eine große Instanz von Owncloud besitzt, nutze bitte den Updater über die Kommandozeile.", + "Please use the command line updater because automatic updating is disabled in the config.php." : "Da automatische Updates in der config.php deaktivert sind, nutze bitte den Updater über die Kommandozeile.", + "For help, see the <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">documentation</a>." : "Für weitere Hilfen, schaue bitte in die <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">Dokumentation</a>.", "This %s instance is currently in maintenance mode, which may take a while." : "Diese %s-Instanz befindet sich gerade im Wartungsmodus, was eine Weile dauern kann.", "This page will refresh itself when the %s instance is available again." : "Diese Seite aktualisiert sich automatisch, wenn die %s-Instanz wieder verfügbar ist." }, diff --git a/core/l10n/de.json b/core/l10n/de.json index 70151c619c7..d5657e1b851 100644 --- a/core/l10n/de.json +++ b/core/l10n/de.json @@ -24,6 +24,7 @@ "Error favoriting" : "Fehler beim Favorisieren", "Error unfavoriting" : "Fehler beim Entfernen aus den Favoriten", "Couldn't send mail to following users: %s " : "Die E-Mail konnte nicht an folgende Benutzer gesendet werden: %s", + "Updates need to be installed. Please use the command line updater." : "Updates müssen installiert werden. Bitte nutze den Updater über die Kommandozeile.", "[%d / %d]: %s" : "[%d / %d]: %s", "[%d / %d]: Checking table %s" : "[%d / %d]: Überprüfe Tabelle %s", "Turned on maintenance mode" : "Wartungsmodus eingeschaltet", @@ -302,6 +303,10 @@ "Start update" : "Aktualisierung starten", "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Zur Vermeidung von Zeitüberschreitungen bei größeren Installationen kannst Du stattdessen den folgenden Befehl in Deinem Installationsverzeichnis ausführen:", "Detailed logs" : "Detaillierte Fehlermeldungen", + "Update needed" : "Update wird benötigt", + "Please use the command line updater because you have a big instance." : "Da du eine große Instanz von Owncloud besitzt, nutze bitte den Updater über die Kommandozeile.", + "Please use the command line updater because automatic updating is disabled in the config.php." : "Da automatische Updates in der config.php deaktivert sind, nutze bitte den Updater über die Kommandozeile.", + "For help, see the <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">documentation</a>." : "Für weitere Hilfen, schaue bitte in die <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">Dokumentation</a>.", "This %s instance is currently in maintenance mode, which may take a while." : "Diese %s-Instanz befindet sich gerade im Wartungsmodus, was eine Weile dauern kann.", "This page will refresh itself when the %s instance is available again." : "Diese Seite aktualisiert sich automatisch, wenn die %s-Instanz wieder verfügbar ist." },"pluralForm" :"nplurals=2; plural=(n != 1);" diff --git a/core/l10n/de_DE.js b/core/l10n/de_DE.js index 9a71cca43a5..6100e4eb93a 100644 --- a/core/l10n/de_DE.js +++ b/core/l10n/de_DE.js @@ -26,6 +26,7 @@ OC.L10N.register( "Error favoriting" : "Fehler beim Hinzufügen zu den Favoriten", "Error unfavoriting" : "Fehler beim Entfernen aus den Favoriten", "Couldn't send mail to following users: %s " : "An folgende Benutzer konnte keine E-Mail gesendet werden: %s", + "Updates need to be installed. Please use the command line updater." : "Updates müssen installiert werden. Bitte nutzen Sie den Updater über die Kommandozeile.", "[%d / %d]: %s" : "[%d / %d]: %s", "[%d / %d]: Checking table %s" : "[%d / %d]: Überprüfe Tabelle %s", "Turned on maintenance mode" : "Wartungsmodus eingeschaltet ", @@ -304,6 +305,10 @@ OC.L10N.register( "Start update" : "Aktualisierung starten", "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Zur Vermeidung von Zeitüberschreitungen bei größeren Installationen können Sie stattdessen den folgenden Befehl in Ihrem Installationsverzeichnis ausführen:", "Detailed logs" : "Detaillierte Fehlermeldungen", + "Update needed" : "Update erforderlich", + "Please use the command line updater because you have a big instance." : "Da Sie eine große Instanz von Owncloud besitzt, nutzen Sie bitte den Updater über die Kommandozeile.", + "Please use the command line updater because automatic updating is disabled in the config.php." : "Da automatische Updates in der config.php deaktivert sind, nutzen Sie bitte den Updater über die Kommandozeile.", + "For help, see the <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">documentation</a>." : "Für weitere Hilfen, schauen Sie bitte in die <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">Dokumentation</a>.", "This %s instance is currently in maintenance mode, which may take a while." : "Diese %s-Instanz befindet sich gerade im Wartungsmodus, was eine Weile dauern kann.", "This page will refresh itself when the %s instance is available again." : "Diese Seite aktualisiert sich automatisch, wenn die %s-Instanz wieder verfügbar ist." }, diff --git a/core/l10n/de_DE.json b/core/l10n/de_DE.json index 5580ca1bc8b..c9731d285c7 100644 --- a/core/l10n/de_DE.json +++ b/core/l10n/de_DE.json @@ -24,6 +24,7 @@ "Error favoriting" : "Fehler beim Hinzufügen zu den Favoriten", "Error unfavoriting" : "Fehler beim Entfernen aus den Favoriten", "Couldn't send mail to following users: %s " : "An folgende Benutzer konnte keine E-Mail gesendet werden: %s", + "Updates need to be installed. Please use the command line updater." : "Updates müssen installiert werden. Bitte nutzen Sie den Updater über die Kommandozeile.", "[%d / %d]: %s" : "[%d / %d]: %s", "[%d / %d]: Checking table %s" : "[%d / %d]: Überprüfe Tabelle %s", "Turned on maintenance mode" : "Wartungsmodus eingeschaltet ", @@ -302,6 +303,10 @@ "Start update" : "Aktualisierung starten", "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Zur Vermeidung von Zeitüberschreitungen bei größeren Installationen können Sie stattdessen den folgenden Befehl in Ihrem Installationsverzeichnis ausführen:", "Detailed logs" : "Detaillierte Fehlermeldungen", + "Update needed" : "Update erforderlich", + "Please use the command line updater because you have a big instance." : "Da Sie eine große Instanz von Owncloud besitzt, nutzen Sie bitte den Updater über die Kommandozeile.", + "Please use the command line updater because automatic updating is disabled in the config.php." : "Da automatische Updates in der config.php deaktivert sind, nutzen Sie bitte den Updater über die Kommandozeile.", + "For help, see the <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">documentation</a>." : "Für weitere Hilfen, schauen Sie bitte in die <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">Dokumentation</a>.", "This %s instance is currently in maintenance mode, which may take a while." : "Diese %s-Instanz befindet sich gerade im Wartungsmodus, was eine Weile dauern kann.", "This page will refresh itself when the %s instance is available again." : "Diese Seite aktualisiert sich automatisch, wenn die %s-Instanz wieder verfügbar ist." },"pluralForm" :"nplurals=2; plural=(n != 1);" diff --git a/core/l10n/fi_FI.js b/core/l10n/fi_FI.js index d440408bbd2..9763d90fe5c 100644 --- a/core/l10n/fi_FI.js +++ b/core/l10n/fi_FI.js @@ -26,6 +26,7 @@ OC.L10N.register( "Error favoriting" : "Suosituksen kirjoitusvirhe", "Error unfavoriting" : "Suosituksen poisto virhe", "Couldn't send mail to following users: %s " : "Sähköpostin lähetys seuraaville käyttäjille epäonnistui: %s", + "Updates need to be installed. Please use the command line updater." : "Päivitykset tulee asentaa. Käytä komentorivipäivitintä.", "[%d / %d]: %s" : "[%d / %d]: %s", "[%d / %d]: Checking table %s" : "[%d / %d]: Tarkistetaan taulua %s", "Turned on maintenance mode" : "Siirrytty huoltotilaan", @@ -295,6 +296,8 @@ OC.L10N.register( "Start update" : "Käynnistä päivitys", "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Välttääksesi aikakatkaisuja suurikokoisten asennusten kanssa, voit suorittaa vaihtoehtoisesti seuraavan komennon asennushakemistossa:", "Detailed logs" : "Yksityiskohtainen loki", + "Update needed" : "Päivitys vaaditaan", + "Please use the command line updater because you have a big instance." : "Käytä komentorivipäivitintä, koska käyttämäsi ownCloud on sen verran suuri.", "This %s instance is currently in maintenance mode, which may take a while." : "Tämä %s-instanssi on parhaillaan huoltotilassa, huollossa saattaa kestää hetki.", "This page will refresh itself when the %s instance is available again." : "Tämä sivu päivittää itsensä, kun %s on jälleen käytettävissä." }, diff --git a/core/l10n/fi_FI.json b/core/l10n/fi_FI.json index e62c0af1bc9..0253a823fd9 100644 --- a/core/l10n/fi_FI.json +++ b/core/l10n/fi_FI.json @@ -24,6 +24,7 @@ "Error favoriting" : "Suosituksen kirjoitusvirhe", "Error unfavoriting" : "Suosituksen poisto virhe", "Couldn't send mail to following users: %s " : "Sähköpostin lähetys seuraaville käyttäjille epäonnistui: %s", + "Updates need to be installed. Please use the command line updater." : "Päivitykset tulee asentaa. Käytä komentorivipäivitintä.", "[%d / %d]: %s" : "[%d / %d]: %s", "[%d / %d]: Checking table %s" : "[%d / %d]: Tarkistetaan taulua %s", "Turned on maintenance mode" : "Siirrytty huoltotilaan", @@ -293,6 +294,8 @@ "Start update" : "Käynnistä päivitys", "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Välttääksesi aikakatkaisuja suurikokoisten asennusten kanssa, voit suorittaa vaihtoehtoisesti seuraavan komennon asennushakemistossa:", "Detailed logs" : "Yksityiskohtainen loki", + "Update needed" : "Päivitys vaaditaan", + "Please use the command line updater because you have a big instance." : "Käytä komentorivipäivitintä, koska käyttämäsi ownCloud on sen verran suuri.", "This %s instance is currently in maintenance mode, which may take a while." : "Tämä %s-instanssi on parhaillaan huoltotilassa, huollossa saattaa kestää hetki.", "This page will refresh itself when the %s instance is available again." : "Tämä sivu päivittää itsensä, kun %s on jälleen käytettävissä." },"pluralForm" :"nplurals=2; plural=(n != 1);" diff --git a/core/l10n/nl.js b/core/l10n/nl.js index c0000229886..c94d585eee9 100644 --- a/core/l10n/nl.js +++ b/core/l10n/nl.js @@ -302,6 +302,7 @@ OC.L10N.register( "Start update" : "Begin de update", "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Om time-outs tijdens grotere installaties te voorkomen, kunt u in plaats hiervan de volgende opdracht geven vanaf uw installatiedirectory:", "Detailed logs" : "Gedetailleerde logs", + "Update needed" : "Update vereist", "This %s instance is currently in maintenance mode, which may take a while." : "Deze %s staat momenteel in de onderhoudsstand, dat kan enige tijd duren.", "This page will refresh itself when the %s instance is available again." : "Deze pagina wordt ververst als de %s-installatie weer beschikbaar is." }, diff --git a/core/l10n/nl.json b/core/l10n/nl.json index 84ee2935acf..f0d1c248684 100644 --- a/core/l10n/nl.json +++ b/core/l10n/nl.json @@ -300,6 +300,7 @@ "Start update" : "Begin de update", "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Om time-outs tijdens grotere installaties te voorkomen, kunt u in plaats hiervan de volgende opdracht geven vanaf uw installatiedirectory:", "Detailed logs" : "Gedetailleerde logs", + "Update needed" : "Update vereist", "This %s instance is currently in maintenance mode, which may take a while." : "Deze %s staat momenteel in de onderhoudsstand, dat kan enige tijd duren.", "This page will refresh itself when the %s instance is available again." : "Deze pagina wordt ververst als de %s-installatie weer beschikbaar is." },"pluralForm" :"nplurals=2; plural=(n != 1);" diff --git a/core/l10n/pt_BR.js b/core/l10n/pt_BR.js index 2e88bb16a53..387d16b850b 100644 --- a/core/l10n/pt_BR.js +++ b/core/l10n/pt_BR.js @@ -26,6 +26,7 @@ OC.L10N.register( "Error favoriting" : "Erro colocando nos favoritos", "Error unfavoriting" : "Erro retirando do favoritos", "Couldn't send mail to following users: %s " : "Não foi possível enviar e-mail para os seguintes usuários: %s", + "Updates need to be installed. Please use the command line updater." : "Atualizações precisam ser instaladas. Por favor, use a atualização de linha de comando.", "[%d / %d]: %s" : "[%d / %d]: %s", "[%d / %d]: Checking table %s" : "[%d / %d]: Verificando tabela %s", "Turned on maintenance mode" : "Ativar modo de manutenção", @@ -304,6 +305,10 @@ OC.L10N.register( "Start update" : "Iniciar atualização", "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Para evitar tempos de espera com instalações maiores, você pode em vez disso executar o seguinte comando a partir do diretório de instalação:", "Detailed logs" : "Logs detalhados", + "Update needed" : "Atualização necessária", + "Please use the command line updater because you have a big instance." : "Por favor, use a atualização de linha de comando, porque você tem um grande exemplo.", + "Please use the command line updater because automatic updating is disabled in the config.php." : "Por favor, use a atualização de linha de comando, porque a atualização automática está desativado no config.php.", + "For help, see the <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">documentation</a>." : "Para obter ajuda, consulte a <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">documentação</a>.", "This %s instance is currently in maintenance mode, which may take a while." : "Esta instância %s está em modo de manutenção, o que pode demorar um pouco.", "This page will refresh itself when the %s instance is available again." : "Esta página será atualizada automaticamente quando esta instância %s estiver disponível novamente." }, diff --git a/core/l10n/pt_BR.json b/core/l10n/pt_BR.json index 025d0bbbebb..cb865b13ac8 100644 --- a/core/l10n/pt_BR.json +++ b/core/l10n/pt_BR.json @@ -24,6 +24,7 @@ "Error favoriting" : "Erro colocando nos favoritos", "Error unfavoriting" : "Erro retirando do favoritos", "Couldn't send mail to following users: %s " : "Não foi possível enviar e-mail para os seguintes usuários: %s", + "Updates need to be installed. Please use the command line updater." : "Atualizações precisam ser instaladas. Por favor, use a atualização de linha de comando.", "[%d / %d]: %s" : "[%d / %d]: %s", "[%d / %d]: Checking table %s" : "[%d / %d]: Verificando tabela %s", "Turned on maintenance mode" : "Ativar modo de manutenção", @@ -302,6 +303,10 @@ "Start update" : "Iniciar atualização", "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Para evitar tempos de espera com instalações maiores, você pode em vez disso executar o seguinte comando a partir do diretório de instalação:", "Detailed logs" : "Logs detalhados", + "Update needed" : "Atualização necessária", + "Please use the command line updater because you have a big instance." : "Por favor, use a atualização de linha de comando, porque você tem um grande exemplo.", + "Please use the command line updater because automatic updating is disabled in the config.php." : "Por favor, use a atualização de linha de comando, porque a atualização automática está desativado no config.php.", + "For help, see the <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">documentation</a>." : "Para obter ajuda, consulte a <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">documentação</a>.", "This %s instance is currently in maintenance mode, which may take a while." : "Esta instância %s está em modo de manutenção, o que pode demorar um pouco.", "This page will refresh itself when the %s instance is available again." : "Esta página será atualizada automaticamente quando esta instância %s estiver disponível novamente." },"pluralForm" :"nplurals=2; plural=(n > 1);" diff --git a/core/l10n/sq.js b/core/l10n/sq.js index ec072ddd52b..788070d5f9a 100644 --- a/core/l10n/sq.js +++ b/core/l10n/sq.js @@ -26,6 +26,7 @@ OC.L10N.register( "Error favoriting" : "Gabim në ruajtjen si të parapëlqyer", "Error unfavoriting" : "Gabim në heqjen nga të parapëlqyerat", "Couldn't send mail to following users: %s " : "S’u dërgua dot e-mail përdoruesve vijues: %s ", + "Updates need to be installed. Please use the command line updater." : "Lypset të instalohen përditësime. Ju lutemi, përdorni përditësuesin e rreshtit të urdhrave.", "[%d / %d]: %s" : "[%d / %d]: %s", "[%d / %d]: Checking table %s" : "[%d / %d]: Po kontrollohet tabela %s", "Turned on maintenance mode" : "Mënyra e mirëmbajtjes u aktivizua", @@ -303,6 +304,10 @@ OC.L10N.register( "Start update" : "Fillo përditësimin", "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Për të shmangur çaste bllokimi pune me instalime të mëdha, mundeni të ekzekutoni urdhrin vijues që nga drejtoria juaj e instalimit:", "Detailed logs" : "Regjistrime të hollësishme", + "Update needed" : "Lyp përditësim", + "Please use the command line updater because you have a big instance." : "Ju lutemi, përdorni përditësuesin e rreshtit të urdhrave, sepse keni një instalim të madh.", + "Please use the command line updater because automatic updating is disabled in the config.php." : "Ju lutemi, përdorni përditësuesin e rreshtit të urdhrave, sepse përditësimi i vetvetishëm është i çaktivizuar te config.php.", + "For help, see the <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">documentation</a>." : "Për ndihmë, shihni <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">dokumentimin</a>.", "This %s instance is currently in maintenance mode, which may take a while." : "Kjo instancë %s hëpërhë gjendet nën mënyrën mirëmbajtje, çka mund të zgjasë ca.", "This page will refresh itself when the %s instance is available again." : "Kjo faqe do të rifreskohet vetiu, sapo instanca %s të jetë sërish gati." }, diff --git a/core/l10n/sq.json b/core/l10n/sq.json index dbe19187efc..ed725ab7330 100644 --- a/core/l10n/sq.json +++ b/core/l10n/sq.json @@ -24,6 +24,7 @@ "Error favoriting" : "Gabim në ruajtjen si të parapëlqyer", "Error unfavoriting" : "Gabim në heqjen nga të parapëlqyerat", "Couldn't send mail to following users: %s " : "S’u dërgua dot e-mail përdoruesve vijues: %s ", + "Updates need to be installed. Please use the command line updater." : "Lypset të instalohen përditësime. Ju lutemi, përdorni përditësuesin e rreshtit të urdhrave.", "[%d / %d]: %s" : "[%d / %d]: %s", "[%d / %d]: Checking table %s" : "[%d / %d]: Po kontrollohet tabela %s", "Turned on maintenance mode" : "Mënyra e mirëmbajtjes u aktivizua", @@ -301,6 +302,10 @@ "Start update" : "Fillo përditësimin", "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Për të shmangur çaste bllokimi pune me instalime të mëdha, mundeni të ekzekutoni urdhrin vijues që nga drejtoria juaj e instalimit:", "Detailed logs" : "Regjistrime të hollësishme", + "Update needed" : "Lyp përditësim", + "Please use the command line updater because you have a big instance." : "Ju lutemi, përdorni përditësuesin e rreshtit të urdhrave, sepse keni një instalim të madh.", + "Please use the command line updater because automatic updating is disabled in the config.php." : "Ju lutemi, përdorni përditësuesin e rreshtit të urdhrave, sepse përditësimi i vetvetishëm është i çaktivizuar te config.php.", + "For help, see the <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">documentation</a>." : "Për ndihmë, shihni <a target=\"_blank\" rel=\"noreferrer\" href=\"%s\">dokumentimin</a>.", "This %s instance is currently in maintenance mode, which may take a while." : "Kjo instancë %s hëpërhë gjendet nën mënyrën mirëmbajtje, çka mund të zgjasë ca.", "This page will refresh itself when the %s instance is available again." : "Kjo faqe do të rifreskohet vetiu, sapo instanca %s të jetë sërish gati." },"pluralForm" :"nplurals=2; plural=(n != 1);" diff --git a/core/register_command.php b/core/register_command.php index 17bd573133a..90a54233e66 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -108,6 +108,7 @@ if (\OC::$server->getConfig()->getSystemValue('installed', false)) { ); $application->add(new OC\Core\Command\Encryption\ShowKeyStorageRoot($util)); + $application->add(new OC\Core\Command\Maintenance\DataFingerprint(\OC::$server->getConfig(), new \OC\AppFramework\Utility\TimeFactory())); $application->add(new OC\Core\Command\Maintenance\Mimetype\UpdateDB(\OC::$server->getMimeTypeDetector(), \OC::$server->getMimeTypeLoader())); $application->add(new OC\Core\Command\Maintenance\Mimetype\UpdateJS(\OC::$server->getMimeTypeDetector())); $application->add(new OC\Core\Command\Maintenance\Mode(\OC::$server->getConfig())); diff --git a/core/vendor/.gitignore b/core/vendor/.gitignore index ee891aa70eb..58a231c4bb4 100644 --- a/core/vendor/.gitignore +++ b/core/vendor/.gitignore @@ -125,12 +125,14 @@ backbone/backbone-min* # davclient.js davclient.js/** -!davclient.js/lib/* +!davclient.js/lib !davclient.js/LICENSE # es6-promise es6-promise/** !es6-promise/LICENSE +!es6-promise/dist +es6-promise/dist/* !es6-promise/dist/es6-promise.js # base64 diff --git a/core/vendor/es6-promise/.bower.json b/core/vendor/es6-promise/.bower.json deleted file mode 100644 index f8c28b04e53..00000000000 --- a/core/vendor/es6-promise/.bower.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "es6-promise", - "namespace": "Promise", - "version": "2.3.0", - "description": "A polyfill for ES6-style Promises, tracking rsvp", - "authors": [ - "Stefan Penner <stefan.penner@gmail.com>" - ], - "main": "dist/es6-promise.js", - "keywords": [ - "promise" - ], - "repository": { - "type": "git", - "url": "git://github.com/jakearchibald/ES6-Promises.git" - }, - "bugs": { - "url": "https://github.com/jakearchibald/ES6-Promises/issues" - }, - "license": "MIT", - "ignore": [ - "node_modules", - "bower_components", - "test", - "tests", - "vendor", - "tasks" - ], - "homepage": "https://github.com/jakearchibald/es6-promise", - "_release": "2.3.0", - "_resolution": { - "type": "version", - "tag": "2.3.0", - "commit": "fcbab11a1a981eb2290bfff89017cb764335a2a5" - }, - "_source": "https://github.com/jakearchibald/es6-promise.git", - "_target": "~2.3.0", - "_originalSource": "https://github.com/jakearchibald/es6-promise.git", - "_direct": true -}
\ No newline at end of file diff --git a/core/vendor/es6-promise/.npmignore b/core/vendor/es6-promise/.npmignore deleted file mode 100644 index 7a758111e9e..00000000000 --- a/core/vendor/es6-promise/.npmignore +++ /dev/null @@ -1,11 +0,0 @@ -/node_modules/ -/tmp -/tasks -/test -/vendor -/.jshintrc -/.npmignore -/.travis.yml -/Gruntfile.js -/component.json -/index.html diff --git a/core/vendor/es6-promise/.release.json b/core/vendor/es6-promise/.release.json deleted file mode 100644 index dee8cbc5d92..00000000000 --- a/core/vendor/es6-promise/.release.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "non-interactive": true, - "dry-run": false, - "verbose": false, - "force": false, - "pkgFiles": ["package.json", "bower.json"], - "increment": "patch", - "commitMessage": "Release %s", - "tagName": "%s", - "tagAnnotation": "Release %s", - "buildCommand": "npm run-script build-all", - "distRepo": "git@github.com:components/rsvp.js.git", - "distStageDir": "tmp/stage", - "distBase": "dist", - "distFiles": ["**/*", "../package.json", "../bower.json"], - "publish": false -} diff --git a/core/vendor/es6-promise/.spmignore b/core/vendor/es6-promise/.spmignore deleted file mode 100644 index 7a758111e9e..00000000000 --- a/core/vendor/es6-promise/.spmignore +++ /dev/null @@ -1,11 +0,0 @@ -/node_modules/ -/tmp -/tasks -/test -/vendor -/.jshintrc -/.npmignore -/.travis.yml -/Gruntfile.js -/component.json -/index.html diff --git a/lib/base.php b/lib/base.php index 26be1161ba3..8ea164a5007 100644 --- a/lib/base.php +++ b/lib/base.php @@ -545,14 +545,9 @@ class OC { OC_Util::isSetLocaleWorking(); if (!defined('PHPUNIT_RUN')) { - $logger = \OC::$server->getLogger(); - OC\Log\ErrorHandler::setLogger($logger); - if (\OC::$server->getConfig()->getSystemValue('debug', false)) { - OC\Log\ErrorHandler::register(true); - set_exception_handler(array('OC_Template', 'printExceptionErrorPage')); - } else { - OC\Log\ErrorHandler::register(); - } + OC\Log\ErrorHandler::setLogger(\OC::$server->getLogger()); + $debug = \OC::$server->getConfig()->getSystemValue('debug', false); + OC\Log\ErrorHandler::register($debug); } // register the stream wrappers diff --git a/lib/l10n/nl.js b/lib/l10n/nl.js index e772d083dea..2682696bd81 100644 --- a/lib/l10n/nl.js +++ b/lib/l10n/nl.js @@ -7,10 +7,6 @@ OC.L10N.register( "This can usually be fixed by %sgiving the webserver write access to the config directory%s." : "Dit kan hersteld worden door de webserver %sschrijfrechten te geven op de de config directory%s", "Sample configuration detected" : "Voorbeeldconfiguratie gevonden", "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "Blijkbaar is de voorbeeldconfiguratie gekopieerd. Dit kan uw installatie beschadigen en wordt niet dan ook ondersteund. Lees de documentatie voordat u wijzigingen aan config.php doorvoert", - "You are not allowed to share %s" : "U bent niet bevoegd om %s te delen", - "Cannot increase permissions of %s" : "Kan de rechten van %s niet verruimen", - "Expiration date is in the past" : "De vervaldatum ligt in het verleden", - "Cannot set expiration date more than %s days in the future" : "Kan vervaldatum niet verder dan %s dagen in de toekomst instellen", "PHP %s or higher is required." : "PHP %s of hoger vereist.", "PHP with a version lower than %s is required." : "PHP met een versie lager dan %s is vereist.", "Following databases are supported: %s" : "De volgende databases worden ondersteund: %s", @@ -21,11 +17,16 @@ OC.L10N.register( "Following platforms are supported: %s" : "De volgende platformen worden ondersteund: %s", "ownCloud %s or higher is required." : "ownCloud %s of hoger vereist.", "ownCloud %s or lower is required." : "ownCloud %s of lager vereist.", + "You are not allowed to share %s" : "U bent niet bevoegd om %s te delen", + "Cannot increase permissions of %s" : "Kan de rechten van %s niet verruimen", + "Expiration date is in the past" : "De vervaldatum ligt in het verleden", + "Cannot set expiration date more than %s days in the future" : "Kan vervaldatum niet verder dan %s dagen in de toekomst instellen", "Help" : "Help", "Personal" : "Persoonlijk", "Users" : "Gebruikers", "Admin" : "Beheerder", "Recommended" : "Aanbevolen", + "App \"%s\" cannot be installed because appinfo file cannot be read." : "App \"%s\" kan niet worden geïnstalleerd, omdat het appinfo bestand niet gelezen kan worden.", "App \"%s\" cannot be installed because it is not compatible with this version of ownCloud." : "App \"%s\" kan niet worden geïnstalleerd, omdat deze niet compatible is met deze versie van ownCloud.", "App \"%s\" cannot be installed because the following dependencies are not fulfilled: %s" : "App \"%s\" kan niet worden geïnstalleerd, omdat de volgende afhankelijkheden niet zijn ingevuld: %s", "No app name specified" : "Geen app naam opgegeven.", diff --git a/lib/l10n/nl.json b/lib/l10n/nl.json index cc3e455e222..3bb84e7e98b 100644 --- a/lib/l10n/nl.json +++ b/lib/l10n/nl.json @@ -5,10 +5,6 @@ "This can usually be fixed by %sgiving the webserver write access to the config directory%s." : "Dit kan hersteld worden door de webserver %sschrijfrechten te geven op de de config directory%s", "Sample configuration detected" : "Voorbeeldconfiguratie gevonden", "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "Blijkbaar is de voorbeeldconfiguratie gekopieerd. Dit kan uw installatie beschadigen en wordt niet dan ook ondersteund. Lees de documentatie voordat u wijzigingen aan config.php doorvoert", - "You are not allowed to share %s" : "U bent niet bevoegd om %s te delen", - "Cannot increase permissions of %s" : "Kan de rechten van %s niet verruimen", - "Expiration date is in the past" : "De vervaldatum ligt in het verleden", - "Cannot set expiration date more than %s days in the future" : "Kan vervaldatum niet verder dan %s dagen in de toekomst instellen", "PHP %s or higher is required." : "PHP %s of hoger vereist.", "PHP with a version lower than %s is required." : "PHP met een versie lager dan %s is vereist.", "Following databases are supported: %s" : "De volgende databases worden ondersteund: %s", @@ -19,11 +15,16 @@ "Following platforms are supported: %s" : "De volgende platformen worden ondersteund: %s", "ownCloud %s or higher is required." : "ownCloud %s of hoger vereist.", "ownCloud %s or lower is required." : "ownCloud %s of lager vereist.", + "You are not allowed to share %s" : "U bent niet bevoegd om %s te delen", + "Cannot increase permissions of %s" : "Kan de rechten van %s niet verruimen", + "Expiration date is in the past" : "De vervaldatum ligt in het verleden", + "Cannot set expiration date more than %s days in the future" : "Kan vervaldatum niet verder dan %s dagen in de toekomst instellen", "Help" : "Help", "Personal" : "Persoonlijk", "Users" : "Gebruikers", "Admin" : "Beheerder", "Recommended" : "Aanbevolen", + "App \"%s\" cannot be installed because appinfo file cannot be read." : "App \"%s\" kan niet worden geïnstalleerd, omdat het appinfo bestand niet gelezen kan worden.", "App \"%s\" cannot be installed because it is not compatible with this version of ownCloud." : "App \"%s\" kan niet worden geïnstalleerd, omdat deze niet compatible is met deze versie van ownCloud.", "App \"%s\" cannot be installed because the following dependencies are not fulfilled: %s" : "App \"%s\" kan niet worden geïnstalleerd, omdat de volgende afhankelijkheden niet zijn ingevuld: %s", "No app name specified" : "Geen app naam opgegeven.", diff --git a/lib/private/console/application.php b/lib/private/Console/Application.php index 7f12db4eca6..7f12db4eca6 100644 --- a/lib/private/console/application.php +++ b/lib/private/Console/Application.php diff --git a/lib/private/console/timestampformatter.php b/lib/private/Console/TimestampFormatter.php index 3beac5e2f9f..3beac5e2f9f 100644 --- a/lib/private/console/timestampformatter.php +++ b/lib/private/Console/TimestampFormatter.php diff --git a/lib/private/diagnostics/event.php b/lib/private/Diagnostics/Event.php index 8b5bb7e3bd8..8b5bb7e3bd8 100644 --- a/lib/private/diagnostics/event.php +++ b/lib/private/Diagnostics/Event.php diff --git a/lib/private/diagnostics/eventlogger.php b/lib/private/Diagnostics/EventLogger.php index 3d909ce79cd..3d909ce79cd 100644 --- a/lib/private/diagnostics/eventlogger.php +++ b/lib/private/Diagnostics/EventLogger.php diff --git a/lib/private/diagnostics/nulleventlogger.php b/lib/private/Diagnostics/NullEventLogger.php index 1b5e7af3ac9..1b5e7af3ac9 100644 --- a/lib/private/diagnostics/nulleventlogger.php +++ b/lib/private/Diagnostics/NullEventLogger.php diff --git a/lib/private/diagnostics/nullquerylogger.php b/lib/private/Diagnostics/NullQueryLogger.php index 98ddef2e783..98ddef2e783 100644 --- a/lib/private/diagnostics/nullquerylogger.php +++ b/lib/private/Diagnostics/NullQueryLogger.php diff --git a/lib/private/diagnostics/query.php b/lib/private/Diagnostics/Query.php index 567bc83ed4b..567bc83ed4b 100644 --- a/lib/private/diagnostics/query.php +++ b/lib/private/Diagnostics/Query.php diff --git a/lib/private/diagnostics/querylogger.php b/lib/private/Diagnostics/QueryLogger.php index 66a65b71d04..66a65b71d04 100644 --- a/lib/private/diagnostics/querylogger.php +++ b/lib/private/Diagnostics/QueryLogger.php diff --git a/lib/private/mail/mailer.php b/lib/private/Mail/Mailer.php index 742ff554892..742ff554892 100644 --- a/lib/private/mail/mailer.php +++ b/lib/private/Mail/Mailer.php diff --git a/lib/private/mail/message.php b/lib/private/Mail/Message.php index 0e33e6383f7..0e33e6383f7 100644 --- a/lib/private/mail/message.php +++ b/lib/private/Mail/Message.php diff --git a/lib/private/preview/bmp.php b/lib/private/Preview/BMP.php index da13cd9e5b8..da13cd9e5b8 100644 --- a/lib/private/preview/bmp.php +++ b/lib/private/Preview/BMP.php diff --git a/lib/private/preview/bitmap.php b/lib/private/Preview/Bitmap.php index 34bc2f93fc7..34bc2f93fc7 100644 --- a/lib/private/preview/bitmap.php +++ b/lib/private/Preview/Bitmap.php diff --git a/lib/private/preview/font.php b/lib/private/Preview/Font.php index caac2923789..caac2923789 100644 --- a/lib/private/preview/font.php +++ b/lib/private/Preview/Font.php diff --git a/lib/private/preview/gif.php b/lib/private/Preview/GIF.php index 0716a6f4406..0716a6f4406 100644 --- a/lib/private/preview/gif.php +++ b/lib/private/Preview/GIF.php diff --git a/lib/private/preview/illustrator.php b/lib/private/Preview/Illustrator.php index ef8448d7b53..ef8448d7b53 100644 --- a/lib/private/preview/illustrator.php +++ b/lib/private/Preview/Illustrator.php diff --git a/lib/private/preview/image.php b/lib/private/Preview/Image.php index 3ea99d6963a..3ea99d6963a 100644 --- a/lib/private/preview/image.php +++ b/lib/private/Preview/Image.php diff --git a/lib/private/preview/jpeg.php b/lib/private/Preview/JPEG.php index 2ee5dd24419..2ee5dd24419 100644 --- a/lib/private/preview/jpeg.php +++ b/lib/private/Preview/JPEG.php diff --git a/lib/private/preview/mp3.php b/lib/private/Preview/MP3.php index c7b70457afe..c7b70457afe 100644 --- a/lib/private/preview/mp3.php +++ b/lib/private/Preview/MP3.php diff --git a/lib/private/preview/msoffice2003.php b/lib/private/Preview/MSOffice2003.php index 20dbe13543a..20dbe13543a 100644 --- a/lib/private/preview/msoffice2003.php +++ b/lib/private/Preview/MSOffice2003.php diff --git a/lib/private/preview/msoffice2007.php b/lib/private/Preview/MSOffice2007.php index ef6758843f1..ef6758843f1 100644 --- a/lib/private/preview/msoffice2007.php +++ b/lib/private/Preview/MSOffice2007.php diff --git a/lib/private/preview/msofficedoc.php b/lib/private/Preview/MSOfficeDoc.php index 05d839d508f..05d839d508f 100644 --- a/lib/private/preview/msofficedoc.php +++ b/lib/private/Preview/MSOfficeDoc.php diff --git a/lib/private/preview/markdown.php b/lib/private/Preview/MarkDown.php index 394af6576c7..394af6576c7 100644 --- a/lib/private/preview/markdown.php +++ b/lib/private/Preview/MarkDown.php diff --git a/lib/private/preview/movie.php b/lib/private/Preview/Movie.php index 43a8d674fc9..43a8d674fc9 100644 --- a/lib/private/preview/movie.php +++ b/lib/private/Preview/Movie.php diff --git a/lib/private/preview/office.php b/lib/private/Preview/Office.php index 6496e091b1d..6496e091b1d 100644 --- a/lib/private/preview/office.php +++ b/lib/private/Preview/Office.php diff --git a/lib/private/preview/opendocument.php b/lib/private/Preview/OpenDocument.php index 0da1e88cafa..0da1e88cafa 100644 --- a/lib/private/preview/opendocument.php +++ b/lib/private/Preview/OpenDocument.php diff --git a/lib/private/preview/pdf.php b/lib/private/Preview/PDF.php index 6ddf33cdea2..6ddf33cdea2 100644 --- a/lib/private/preview/pdf.php +++ b/lib/private/Preview/PDF.php diff --git a/lib/private/preview/png.php b/lib/private/Preview/PNG.php index 5dd9ae484a5..5dd9ae484a5 100644 --- a/lib/private/preview/png.php +++ b/lib/private/Preview/PNG.php diff --git a/lib/private/preview/photoshop.php b/lib/private/Preview/Photoshop.php index df91247f072..df91247f072 100644 --- a/lib/private/preview/photoshop.php +++ b/lib/private/Preview/Photoshop.php diff --git a/lib/private/preview/postscript.php b/lib/private/Preview/Postscript.php index edfd43968c2..edfd43968c2 100644 --- a/lib/private/preview/postscript.php +++ b/lib/private/Preview/Postscript.php diff --git a/lib/private/preview/provider.php b/lib/private/Preview/Provider.php index 738d13d7fc8..738d13d7fc8 100644 --- a/lib/private/preview/provider.php +++ b/lib/private/Preview/Provider.php diff --git a/lib/private/preview/svg.php b/lib/private/Preview/SVG.php index 6618c1fbf82..6618c1fbf82 100644 --- a/lib/private/preview/svg.php +++ b/lib/private/Preview/SVG.php diff --git a/lib/private/preview/staroffice.php b/lib/private/Preview/StarOffice.php index 6ea4efa5144..6ea4efa5144 100644 --- a/lib/private/preview/staroffice.php +++ b/lib/private/Preview/StarOffice.php diff --git a/lib/private/preview/tiff.php b/lib/private/Preview/TIFF.php index 006ced6aec0..006ced6aec0 100644 --- a/lib/private/preview/tiff.php +++ b/lib/private/Preview/TIFF.php diff --git a/lib/private/preview/txt.php b/lib/private/Preview/TXT.php index a27517c9f39..a27517c9f39 100644 --- a/lib/private/preview/txt.php +++ b/lib/private/Preview/TXT.php diff --git a/lib/private/preview/xbitmap.php b/lib/private/Preview/XBitmap.php index 604a51a6a83..604a51a6a83 100644 --- a/lib/private/preview/xbitmap.php +++ b/lib/private/Preview/XBitmap.php diff --git a/lib/private/encryption/manager.php b/lib/private/encryption/manager.php index d45bbf07ee9..8714d161807 100644 --- a/lib/private/encryption/manager.php +++ b/lib/private/encryption/manager.php @@ -117,6 +117,25 @@ class Manager implements IManager { } /** + * @param string $user + */ + public function isReadyForUser($user) { + if (!$this->isReady()) { + return false; + } + + foreach ($this->getEncryptionModules() as $module) { + /** @var IEncryptionModule $m */ + $m = call_user_func($module['callback']); + if (!$m->isReadyForUser($user)) { + return false; + } + } + + return true; + } + + /** * Registers an callback function which must return an encryption module instance * * @param string $id diff --git a/lib/private/files/cache/scanner.php b/lib/private/files/cache/scanner.php index 5ca32548fe0..c16e8515b01 100644 --- a/lib/private/files/cache/scanner.php +++ b/lib/private/files/cache/scanner.php @@ -195,6 +195,8 @@ class Scanner extends BasicEmitter implements IScanner { $fileId = -1; } if (!empty($newData)) { + // Reset the checksum if the data has changed + $newData['checksum'] = ''; $data['fileid'] = $this->addToCache($file, $newData, $fileId); } if (isset($cacheData['size'])) { diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php index 1add4d7fd0a..02da978a700 100644 --- a/lib/private/files/storage/wrapper/encryption.php +++ b/lib/private/files/storage/wrapper/encryption.php @@ -627,9 +627,10 @@ class Encryption extends Wrapper { * @param string $sourceInternalPath * @param string $targetInternalPath * @param bool $preserveMtime + * @param bool $isRename * @return bool */ - public function copyFromStorage(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) { + public function copyFromStorage(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false, $isRename = false) { // TODO clean this up once the underlying moveFromStorage in OC\Files\Storage\Wrapper\Common is fixed: // - call $this->storage->copyFromStorage() instead of $this->copyBetweenStorage @@ -637,7 +638,7 @@ class Encryption extends Wrapper { // - copy the copyKeys() call from $this->copyBetweenStorage to this method // - remove $this->copyBetweenStorage - return $this->copyBetweenStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, false); + return $this->copyBetweenStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename); } /** @@ -732,7 +733,7 @@ class Encryption extends Wrapper { if (is_resource($dh)) { while ($result and ($file = readdir($dh)) !== false) { if (!Filesystem::isIgnoredDir($file)) { - $result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file); + $result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file, false, $isRename); } } } diff --git a/lib/private/log/errorhandler.php b/lib/private/log/errorhandler.php index 27cde4aa242..8899bcfcb03 100644 --- a/lib/private/log/errorhandler.php +++ b/lib/private/log/errorhandler.php @@ -44,6 +44,9 @@ class ErrorHandler { if ($debug) { set_error_handler(array($handler, 'onAll'), E_ALL); + if (\OC::$CLI) { + set_exception_handler(array('OC_Template', 'printExceptionErrorPage')); + } } else { set_error_handler(array($handler, 'onError')); } diff --git a/lib/private/setup/mysql.php b/lib/private/setup/mysql.php index ba1b2ca854c..18b6dab4ff8 100644 --- a/lib/private/setup/mysql.php +++ b/lib/private/setup/mysql.php @@ -43,7 +43,7 @@ class MySQL extends AbstractDatabase { $query='select count(*) from information_schema.tables where table_schema=? AND table_name = ?'; $result = $connection->executeQuery($query, [$this->dbName, $this->tablePrefix.'users']); $row = $result->fetch(); - if(!$result or $row[0]==0) { + if (!$row or $row['count(*)'] === '0') { \OC_DB::createDbFromStructure($this->dbDefinitionFile); } } diff --git a/lib/private/share/share.php b/lib/private/share/share.php index 2125767cabb..5b61f418a4d 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -90,6 +90,7 @@ class Share extends Constants { \OC_Util::addScript('core', 'shareitemmodel'); \OC_Util::addScript('core', 'sharedialogresharerinfoview'); \OC_Util::addScript('core', 'sharedialoglinkshareview'); + \OC_Util::addScript('core', 'sharedialogmailview'); \OC_Util::addScript('core', 'sharedialogexpirationview'); \OC_Util::addScript('core', 'sharedialogshareelistview'); \OC_Util::addScript('core', 'sharedialogview'); diff --git a/lib/public/encryption/iencryptionmodule.php b/lib/public/encryption/iencryptionmodule.php index df30dd57cee..8d20a1ab57d 100644 --- a/lib/public/encryption/iencryptionmodule.php +++ b/lib/public/encryption/iencryptionmodule.php @@ -168,4 +168,16 @@ interface IEncryptionModule { */ public function prepareDecryptAll(InputInterface $input, OutputInterface $output, $user = ''); + /** + * Check if the module is ready to be used by that specific user. + * In case a module is not ready - because e.g. key pairs have not been generated + * upon login this method can return false before any operation starts and might + * cause issues during operations. + * + * @param string $user + * @return boolean + * @since 9.1.0 + */ + public function isReadyForUser($user); + } diff --git a/settings/admin.php b/settings/admin.php index e0d3a907f47..cfb7eb5c541 100644 --- a/settings/admin.php +++ b/settings/admin.php @@ -41,6 +41,8 @@ OC_Util::addScript('settings', 'certificates'); OC_Util::addScript('files', 'jquery.iframe-transport'); OC_Util::addScript('files', 'jquery.fileupload'); +\OC::$server->getEventDispatcher()->dispatch('OC\Settings\Admin::loadAdditionalScripts'); + $showLog = (\OC::$server->getConfig()->getSystemValue('log_type', 'owncloud') === 'owncloud'); $numEntriesToLoad = 3; $entries = OC_Log_Owncloud::getEntries($numEntriesToLoad + 1); diff --git a/settings/l10n/nl.js b/settings/l10n/nl.js index 10db457d3cf..3e1fa89cf4d 100644 --- a/settings/l10n/nl.js +++ b/settings/l10n/nl.js @@ -63,6 +63,7 @@ OC.L10N.register( "Experimental" : "Experimenteel", "All" : "Alle", "No apps found for your version" : "Geen apps gevonden voor uw versie", + "The app will be downloaded from the app store" : "De app zal worden gedownload van de app store", "Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "Officiële apps zijn ontwikkeld door en binnen de ownCloud community. Ze bieden functionaliteit binnen ownCloud en zijn klaar voor gebruik in een productie omgeving.", "Approved apps are developed by trusted developers and have passed a cursory security check. They are actively maintained in an open code repository and their maintainers deem them to be stable for casual to normal use." : "Goedgekeurde apps zijn ontwikkeld door vertrouwde ontwikkelaars en hebben een beveiligingscontrole ondergaan. Ze worden actief onderhouden in een open code repository en hun ontwikkelaars vinden ze stabiel genoeg voor informeel of normaal gebruik.", "This app is not checked for security issues and is new or known to be unstable. Install at your own risk." : "Deze app is niet gecontroleerd op beveiligingsproblemen en is nieuw is is bekend als onstabiel. Installeren op eigen risico.", diff --git a/settings/l10n/nl.json b/settings/l10n/nl.json index c84492182e3..78b2cad9956 100644 --- a/settings/l10n/nl.json +++ b/settings/l10n/nl.json @@ -61,6 +61,7 @@ "Experimental" : "Experimenteel", "All" : "Alle", "No apps found for your version" : "Geen apps gevonden voor uw versie", + "The app will be downloaded from the app store" : "De app zal worden gedownload van de app store", "Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "Officiële apps zijn ontwikkeld door en binnen de ownCloud community. Ze bieden functionaliteit binnen ownCloud en zijn klaar voor gebruik in een productie omgeving.", "Approved apps are developed by trusted developers and have passed a cursory security check. They are actively maintained in an open code repository and their maintainers deem them to be stable for casual to normal use." : "Goedgekeurde apps zijn ontwikkeld door vertrouwde ontwikkelaars en hebben een beveiligingscontrole ondergaan. Ze worden actief onderhouden in een open code repository en hun ontwikkelaars vinden ze stabiel genoeg voor informeel of normaal gebruik.", "This app is not checked for security issues and is new or known to be unstable. Install at your own risk." : "Deze app is niet gecontroleerd op beveiligingsproblemen en is nieuw is is bekend als onstabiel. Installeren op eigen risico.", diff --git a/settings/personal.php b/settings/personal.php index 62a718985f8..90b8bb2fbbb 100644 --- a/settings/personal.php +++ b/settings/personal.php @@ -54,6 +54,8 @@ if ($config->getSystemValue('enable_avatars', true) === true) { \OC_Util::addVendorStyle('jcrop/css/jquery.Jcrop'); } +\OC::$server->getEventDispatcher()->dispatch('OC\Settings\Personal::loadAdditionalScripts'); + // Highlight navigation entry OC::$server->getNavigationManager()->setActiveEntry('personal'); diff --git a/settings/templates/apps.php b/settings/templates/apps.php index ce6dcef842c..ecb00fb27c3 100644 --- a/settings/templates/apps.php +++ b/settings/templates/apps.php @@ -25,7 +25,7 @@ script( <script id="categories-template" type="text/x-handlebars-template"> {{#each this}} <li id="app-category-{{ident}}" data-category-id="{{ident}}" tabindex="0"> - <a>{{displayName}}</a> + <a href="#">{{displayName}}</a> </li> {{/each}} @@ -94,8 +94,8 @@ script( </p> {{/if}} </div><!-- end app-description-container --> - <div class="app-description-toggle-show"><?php p($l->t("Show description …"));?></div> - <div class="app-description-toggle-hide hidden"><?php p($l->t("Hide description …"));?></div> + <div class="app-description-toggle-show" role="link"><?php p($l->t("Show description …"));?></div> + <div class="app-description-toggle-hide hidden" role="link"><?php p($l->t("Hide description …"));?></div> <div class="app-dependencies update hidden"> <p><?php p($l->t('This app has an update available.')); ?></p> diff --git a/tests/core/command/maintenance/datafingerprinttest.php b/tests/core/command/maintenance/datafingerprinttest.php new file mode 100644 index 00000000000..4d661b5c027 --- /dev/null +++ b/tests/core/command/maintenance/datafingerprinttest.php @@ -0,0 +1,64 @@ +<?php +/** + * @author Roeland Jago Douma <rullzer@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace Tests\Core\Command\Maintenance; + +use OC\Core\Command\Maintenance\DataFingerprint; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\IConfig; +use Test\TestCase; + +class DataFingerprintTest extends TestCase { + /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ + protected $config; + /** @var \PHPUnit_Framework_MockObject_MockObject */ + protected $consoleInput; + /** @var \PHPUnit_Framework_MockObject_MockObject */ + protected $consoleOutput; + /** @var ITimeFactory|\PHPUnit_Framework_MockObject_MockObject */ + protected $timeFactory; + + /** @var \Symfony\Component\Console\Command\Command */ + protected $command; + + protected function setUp() { + parent::setUp(); + + $this->config = $this->getMock('OCP\IConfig'); + $this->timeFactory = $this->getMock('OCP\AppFramework\Utility\ITimeFactory'); + $this->consoleInput = $this->getMock('Symfony\Component\Console\Input\InputInterface'); + $this->consoleOutput = $this->getMock('Symfony\Component\Console\Output\OutputInterface'); + + /** @var \OCP\IConfig $config */ + $this->command = new DataFingerprint($this->config, $this->timeFactory); + } + + public function testSetFingerPrint() { + $this->timeFactory->expects($this->once()) + ->method('getTime') + ->willReturn(42); + $this->config->expects($this->once()) + ->method('setSystemValue') + ->with('data-fingerprint', md5(42)); + + self::invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]); + } +} diff --git a/tests/lib/files/storage/wrapper/encryption.php b/tests/lib/files/storage/wrapper/encryption.php index 651299a3eab..21f7d9f09b9 100644 --- a/tests/lib/files/storage/wrapper/encryption.php +++ b/tests/lib/files/storage/wrapper/encryption.php @@ -5,6 +5,7 @@ namespace Test\Files\Storage\Wrapper; use OC\Encryption\Util; use OC\Files\Storage\Temporary; use OC\Files\View; +use OC\User\Manager; use Test\Files\Storage\Storage; class Encryption extends Storage { @@ -118,7 +119,7 @@ class Encryption extends Storage { $this->util = $this->getMock( '\OC\Encryption\Util', ['getUidAndFilename', 'isFile', 'isExcluded'], - [new View(), new \OC\User\Manager(), $this->groupManager, $this->config, $this->arrayCache]); + [new View(), new Manager(), $this->groupManager, $this->config, $this->arrayCache]); $this->util->expects($this->any()) ->method('getUidAndFilename') ->willReturnCallback(function ($path) { @@ -200,7 +201,7 @@ class Encryption extends Storage { protected function buildMockModule() { $this->encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule') ->disableOriginalConstructor() - ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll']) + ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser']) ->getMock(); $this->encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE'); @@ -543,7 +544,7 @@ class Encryption extends Storage { ->setConstructorArgs( [ new View(), - new \OC\User\Manager(), + new Manager(), $this->groupManager, $this->config, $this->arrayCache @@ -608,7 +609,7 @@ class Encryption extends Storage { ->disableOriginalConstructor()->getMock(); $util = $this->getMockBuilder('\OC\Encryption\Util') - ->setConstructorArgs([new View(), new \OC\User\Manager(), $this->groupManager, $this->config, $this->arrayCache]) + ->setConstructorArgs([new View(), new Manager(), $this->groupManager, $this->config, $this->arrayCache]) ->getMock(); $cache = $this->getMockBuilder('\OC\Files\Cache\Cache') diff --git a/tests/lib/files/stream/encryption.php b/tests/lib/files/stream/encryption.php index afb31f2822d..20a4100d2ff 100644 --- a/tests/lib/files/stream/encryption.php +++ b/tests/lib/files/stream/encryption.php @@ -311,7 +311,7 @@ class Encryption extends \Test\TestCase { protected function buildMockModule() { $encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule') ->disableOriginalConstructor() - ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll']) + ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser']) ->getMock(); $encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE'); diff --git a/tests/lib/files/view.php b/tests/lib/files/view.php index 3e88a5306f8..86413c61aa1 100644 --- a/tests/lib/files/view.php +++ b/tests/lib/files/view.php @@ -2424,4 +2424,24 @@ class View extends \Test\TestCase { $this->assertEquals($expected, $files); } + + public function testFilePutContentsClearsChecksum() { + $storage = new Temporary(array()); + $scanner = $storage->getScanner(); + $storage->file_put_contents('foo.txt', 'bar'); + \OC\Files\Filesystem::mount($storage, array(), '/test/'); + $scanner->scan(''); + + $view = new \OC\Files\View('/test/foo.txt'); + $view->putFileInfo('.', ['checksum' => '42']); + + $this->assertEquals('bar', $view->file_get_contents('')); + $fh = tmpfile(); + fwrite($fh, 'fooo'); + rewind($fh); + $view->file_put_contents('', $fh); + $this->assertEquals('fooo', $view->file_get_contents('')); + $data = $view->getFileInfo('.'); + $this->assertEquals('', $data->getChecksum()); + } } diff --git a/tests/lib/group.php b/tests/lib/group.php index 4bb888ed725..d3ac6d8d69e 100644 --- a/tests/lib/group.php +++ b/tests/lib/group.php @@ -32,7 +32,7 @@ class Test_Group extends \Test\TestCase { public function testSingleBackend() { $userBackend = new \Test\Util\User\Dummy(); \OC::$server->getUserManager()->registerBackend($userBackend); - OC_Group::useBackend(new OC_Group_Dummy()); + OC_Group::useBackend(new \Test\Util\Group\Dummy()); $group1 = $this->getUniqueID(); $group2 = $this->getUniqueID(); @@ -72,7 +72,7 @@ class Test_Group extends \Test\TestCase { public function testNoEmptyGIDs() { - OC_Group::useBackend(new OC_Group_Dummy()); + OC_Group::useBackend(new \Test\Util\Group\Dummy()); $emptyGroup = null; $this->assertFalse(OC_Group::createGroup($emptyGroup)); @@ -80,7 +80,7 @@ class Test_Group extends \Test\TestCase { public function testNoGroupsTwice() { - OC_Group::useBackend(new OC_Group_Dummy()); + OC_Group::useBackend(new \Test\Util\Group\Dummy()); $group = $this->getUniqueID(); OC_Group::createGroup($group); @@ -92,7 +92,7 @@ class Test_Group extends \Test\TestCase { public function testDontDeleteAdminGroup() { - OC_Group::useBackend(new OC_Group_Dummy()); + OC_Group::useBackend(new \Test\Util\Group\Dummy()); $adminGroup = 'admin'; OC_Group::createGroup($adminGroup); @@ -102,7 +102,7 @@ class Test_Group extends \Test\TestCase { public function testDontAddUserToNonexistentGroup() { - OC_Group::useBackend(new OC_Group_Dummy()); + OC_Group::useBackend(new \Test\Util\Group\Dummy()); $groupNonExistent = 'notExistent'; $user = $this->getUniqueID(); @@ -111,7 +111,7 @@ class Test_Group extends \Test\TestCase { } public function testUsersInGroup() { - OC_Group::useBackend(new OC_Group_Dummy()); + OC_Group::useBackend(new \Test\Util\Group\Dummy()); $userBackend = new \Test\Util\User\Dummy(); \OC::$server->getUserManager()->registerBackend($userBackend); @@ -143,8 +143,8 @@ class Test_Group extends \Test\TestCase { public function testMultiBackend() { $userBackend = new \Test\Util\User\Dummy(); \OC::$server->getUserManager()->registerBackend($userBackend); - $backend1 = new OC_Group_Dummy(); - $backend2 = new OC_Group_Dummy(); + $backend1 = new \Test\Util\Group\Dummy(); + $backend2 = new \Test\Util\Group\Dummy(); OC_Group::useBackend($backend1); OC_Group::useBackend($backend2); diff --git a/tests/lib/group/dummy.php b/tests/lib/group/dummy.php index 6836f89d3fe..eaa299c39af 100644 --- a/tests/lib/group/dummy.php +++ b/tests/lib/group/dummy.php @@ -28,6 +28,6 @@ class Test_Group_Dummy extends Test_Group_Backend { protected function setUp() { parent::setUp(); - $this->backend=new OC_Group_Dummy(); + $this->backend=new \Test\Util\Group\Dummy(); } } diff --git a/tests/lib/group/manager.php b/tests/lib/group/manager.php index 6cf473b9156..410e11114c4 100644 --- a/tests/lib/group/manager.php +++ b/tests/lib/group/manager.php @@ -65,7 +65,7 @@ class Manager extends \Test\TestCase { } public function testGetDeleted() { - $backend = new \OC_Group_Dummy(); + $backend = new \Test\Util\Group\Dummy(); $backend->createGroup('group1'); /** diff --git a/tests/lib/share/share.php b/tests/lib/share/share.php index 1965d80c580..a07e90effc3 100644 --- a/tests/lib/share/share.php +++ b/tests/lib/share/share.php @@ -63,7 +63,7 @@ class Test_Share extends \Test\TestCase { \OC::$server->getUserManager()->createUser($this->groupAndUser, 'pass'); OC_User::setUserId($this->user1); OC_Group::clearBackends(); - OC_Group::useBackend(new OC_Group_Dummy); + OC_Group::useBackend(new \Test\Util\Group\Dummy()); $this->group1 = $this->getUniqueID('group1_'); $this->group2 = $this->getUniqueID('group2_'); OC_Group::createGroup($this->group1); diff --git a/lib/private/group/dummy.php b/tests/lib/util/group/dummy.php index 74a19a90592..e72be827d8a 100644 --- a/lib/private/group/dummy.php +++ b/tests/lib/util/group/dummy.php @@ -27,10 +27,14 @@ * */ +namespace Test\Util\Group; + +use OC_Group_Backend; + /** * dummy group backend, does not keep state, only for testing use */ -class OC_Group_Dummy extends OC_Group_Backend { +class Dummy extends OC_Group_Backend { private $groups=array(); /** * Try to create a new group |