diff options
104 files changed, 2842 insertions, 900 deletions
diff --git a/apps/dav/appinfo/v1/publicwebdav.php b/apps/dav/appinfo/v1/publicwebdav.php index 5bdfd94e658..cf0488038d3 100644 --- a/apps/dav/appinfo/v1/publicwebdav.php +++ b/apps/dav/appinfo/v1/publicwebdav.php @@ -39,7 +39,8 @@ $serverFactory = new OCA\DAV\Connector\Sabre\ServerFactory( \OC::$server->getUserSession(), \OC::$server->getMountManager(), \OC::$server->getTagManager(), - \OC::$server->getEventDispatcher() + \OC::$server->getEventDispatcher(), + \OC::$server->getRequest() ); $requestUri = \OC::$server->getRequest()->getRequestUri(); diff --git a/apps/dav/appinfo/v1/webdav.php b/apps/dav/appinfo/v1/webdav.php index f28736f1f01..8324f962b8e 100644 --- a/apps/dav/appinfo/v1/webdav.php +++ b/apps/dav/appinfo/v1/webdav.php @@ -40,7 +40,8 @@ $serverFactory = new \OCA\DAV\Connector\Sabre\ServerFactory( \OC::$server->getUserSession(), \OC::$server->getMountManager(), \OC::$server->getTagManager(), - \OC::$server->getEventDispatcher() + \OC::$server->getEventDispatcher(), + \OC::$server->getRequest() ); // Backends diff --git a/apps/dav/lib/connector/sabre/fakelockerplugin.php b/apps/dav/lib/connector/sabre/fakelockerplugin.php new file mode 100644 index 00000000000..493d3b0ade4 --- /dev/null +++ b/apps/dav/lib/connector/sabre/fakelockerplugin.php @@ -0,0 +1,159 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * + * @copyright Copyright (c) 2015, 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\Connector\Sabre; + +use Sabre\DAV\Locks\LockInfo; +use Sabre\DAV\Property\LockDiscovery; +use Sabre\DAV\Property\SupportedLock; +use Sabre\DAV\ServerPlugin; +use Sabre\HTTP\RequestInterface; +use Sabre\HTTP\ResponseInterface; +use Sabre\DAV\PropFind; +use Sabre\DAV\INode; + +/** + * Class FakeLockerPlugin is a plugin only used when connections come in from + * OS X via Finder. The fake locking plugin does emulate Class 2 WebDAV support + * (locking of files) which allows Finder to access the storage in write mode as + * well. + * + * No real locking is performed, instead the plugin just returns always positive + * responses. + * + * @see https://github.com/owncloud/core/issues/17732 + * @package OCA\DAV\Connector\Sabre + */ +class FakeLockerPlugin extends ServerPlugin { + /** @var \Sabre\DAV\Server */ + private $server; + + /** {@inheritDoc} */ + public function initialize(\Sabre\DAV\Server $server) { + $this->server = $server; + $this->server->on('method:LOCK', [$this, 'fakeLockProvider'], 1); + $this->server->on('method:UNLOCK', [$this, 'fakeUnlockProvider'], 1); + $server->on('propFind', [$this, 'propFind']); + $server->on('validateTokens', [$this, 'validateTokens']); + } + + /** + * Indicate that we support LOCK and UNLOCK + * + * @param string $path + * @return array + */ + public function getHTTPMethods($path) { + return [ + 'LOCK', + 'UNLOCK', + ]; + } + + /** + * Indicate that we support locking + * + * @return array + */ + function getFeatures() { + return [2]; + } + + /** + * Return some dummy response for PROPFIND requests with regard to locking + * + * @param PropFind $propFind + * @param INode $node + * @return void + */ + function propFind(PropFind $propFind, INode $node) { + $propFind->handle('{DAV:}supportedlock', function() { + return new SupportedLock(true); + }); + $propFind->handle('{DAV:}lockdiscovery', function() use ($propFind) { + return new LockDiscovery([]); + }); + } + + /** + * Mark a locking token always as valid + * + * @param RequestInterface $request + * @param array $conditions + */ + public function validateTokens(RequestInterface $request, &$conditions) { + foreach($conditions as &$fileCondition) { + if(isset($fileCondition['tokens'])) { + foreach($fileCondition['tokens'] as &$token) { + if(isset($token['token'])) { + if(substr($token['token'], 0, 16) === 'opaquelocktoken:') { + $token['validToken'] = true; + } + } + } + } + } + } + + /** + * Fakes a successful LOCK + * + * @param RequestInterface $request + * @param ResponseInterface $response + * @return bool + */ + public function fakeLockProvider(RequestInterface $request, + ResponseInterface $response) { + $dom = new \DOMDocument('1.0', 'utf-8'); + $prop = $dom->createElementNS('DAV:', 'd:prop'); + $dom->appendChild($prop); + + $lockDiscovery = $dom->createElementNS('DAV:', 'd:lockdiscovery'); + $prop->appendChild($lockDiscovery); + + $lockInfo = new LockInfo(); + $lockInfo->token = md5($request->getPath()); + $lockInfo->uri = $request->getPath(); + $lockInfo->depth = \Sabre\DAV\Server::DEPTH_INFINITY; + $lockInfo->timeout = 1800; + + $lockObj = new LockDiscovery([$lockInfo]); + $lockObj->serialize($this->server, $lockDiscovery); + + $response->setBody($dom->saveXML()); + + return false; + } + + /** + * Fakes a successful LOCK + * + * @param RequestInterface $request + * @param ResponseInterface $response + * @return bool + */ + public function fakeUnlockProvider(RequestInterface $request, + ResponseInterface $response) { + $response->setStatus(204); + $response->setHeader('Content-Length', '0'); + return false; + } +} diff --git a/apps/dav/lib/connector/sabre/serverfactory.php b/apps/dav/lib/connector/sabre/serverfactory.php index f67e949e802..a33acc9f00b 100644 --- a/apps/dav/lib/connector/sabre/serverfactory.php +++ b/apps/dav/lib/connector/sabre/serverfactory.php @@ -26,12 +26,41 @@ use OCP\Files\Mount\IMountManager; use OCP\IConfig; use OCP\IDBConnection; use OCP\ILogger; +use OCP\IRequest; use OCP\ITagManager; use OCP\IUserSession; use Sabre\DAV\Auth\Backend\BackendInterface; +use Sabre\DAV\Locks\Plugin; use Symfony\Component\EventDispatcher\EventDispatcherInterface; class ServerFactory { + /** @var IConfig */ + private $config; + /** @var ILogger */ + private $logger; + /** @var IDBConnection */ + private $databaseConnection; + /** @var IUserSession */ + private $userSession; + /** @var IMountManager */ + private $mountManager; + /** @var ITagManager */ + private $tagManager; + /** @var EventDispatcherInterface */ + private $dispatcher; + /** @var IRequest */ + private $request; + + /** + * @param IConfig $config + * @param ILogger $logger + * @param IDBConnection $databaseConnection + * @param IUserSession $userSession + * @param IMountManager $mountManager + * @param ITagManager $tagManager + * @param EventDispatcherInterface $dispatcher + * @param IRequest $request + */ public function __construct( IConfig $config, ILogger $logger, @@ -39,7 +68,8 @@ class ServerFactory { IUserSession $userSession, IMountManager $mountManager, ITagManager $tagManager, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, + IRequest $request ) { $this->config = $config; $this->logger = $logger; @@ -48,6 +78,7 @@ class ServerFactory { $this->mountManager = $mountManager; $this->tagManager = $tagManager; $this->dispatcher = $dispatcher; + $this->request = $request; } /** @@ -57,7 +88,10 @@ class ServerFactory { * @param callable $viewCallBack callback that should return the view for the dav endpoint * @return Server */ - public function createServer($baseUri, $requestUri, BackendInterface $authBackend, callable $viewCallBack) { + public function createServer($baseUri, + $requestUri, + BackendInterface $authBackend, + callable $viewCallBack) { // Fire up server $objectTree = new \OCA\DAV\Connector\Sabre\ObjectTree(); $server = new \OCA\DAV\Connector\Sabre\Server($objectTree); @@ -75,6 +109,11 @@ class ServerFactory { $server->addPlugin(new \OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin('webdav', $this->logger)); $server->addPlugin(new \OCA\DAV\Connector\Sabre\LockPlugin($objectTree)); $server->addPlugin(new \OCA\DAV\Connector\Sabre\ListenerPlugin($this->dispatcher)); + // Finder on OS X requires Class 2 WebDAV support (locking), since we do + // not provide locking we emulate it using a fake locking plugin. + if($this->request->isUserAgent(['/WebDAVFS/'])) { + $server->addPlugin(new \OCA\DAV\Connector\Sabre\FakeLockerPlugin()); + } // wait with registering these until auth is handled and the filesystem is setup $server->on('beforeMethod', function () use ($server, $objectTree, $viewCallBack) { diff --git a/apps/dav/lib/server.php b/apps/dav/lib/server.php index a92c9980f54..395544761ab 100644 --- a/apps/dav/lib/server.php +++ b/apps/dav/lib/server.php @@ -37,6 +37,12 @@ class Server { $this->server->addPlugin(new \Sabre\CardDAV\Plugin()); + // Finder on OS X requires Class 2 WebDAV support (locking), since we do + // not provide locking we emulate it using a fake locking plugin. + if($request->isUserAgent(['/WebDAVFS/'])) { + $this->server->addPlugin(new \OCA\DAV\Connector\Sabre\FakeLockerPlugin()); + } + // wait with registering these until auth is handled and the filesystem is setup $this->server->on('beforeMethod', function () { // custom properties plugin must be the last one diff --git a/apps/dav/tests/unit/connector/sabre/FakeLockerPluginTest.php b/apps/dav/tests/unit/connector/sabre/FakeLockerPluginTest.php new file mode 100644 index 00000000000..dfe8cc220a3 --- /dev/null +++ b/apps/dav/tests/unit/connector/sabre/FakeLockerPluginTest.php @@ -0,0 +1,173 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * + * @copyright Copyright (c) 2015, 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\Connector\Sabre; + +use OCA\DAV\Connector\Sabre\FakeLockerPlugin; +use Test\TestCase; + +/** + * Class FakeLockerPluginTest + * + * @package OCA\DAV\Tests\Unit\Connector\Sabre + */ +class FakeLockerPluginTest extends TestCase { + /** @var FakeLockerPlugin */ + private $fakeLockerPlugin; + + public function setUp() { + parent::setUp(); + $this->fakeLockerPlugin = new FakeLockerPlugin(); + } + + public function testInitialize() { + /** @var \Sabre\DAV\Server $server */ + $server = $this->getMock('\Sabre\DAV\Server'); + $server + ->expects($this->at(0)) + ->method('on') + ->with('method:LOCK', [$this->fakeLockerPlugin, 'fakeLockProvider'], 1); + $server + ->expects($this->at(1)) + ->method('on') + ->with('method:UNLOCK', [$this->fakeLockerPlugin, 'fakeUnlockProvider'], 1); + $server + ->expects($this->at(2)) + ->method('on') + ->with('propFind', [$this->fakeLockerPlugin, 'propFind']); + $server + ->expects($this->at(3)) + ->method('on') + ->with('validateTokens', [$this->fakeLockerPlugin, 'validateTokens']); + + $this->fakeLockerPlugin->initialize($server); + } + + public function testGetHTTPMethods() { + $expected = [ + 'LOCK', + 'UNLOCK', + ]; + $this->assertSame($expected, $this->fakeLockerPlugin->getHTTPMethods('Test')); + } + + public function testGetFeatures() { + $expected = [ + 2, + ]; + $this->assertSame($expected, $this->fakeLockerPlugin->getFeatures()); + } + + public function testPropFind() { + $propFind = $this->getMockBuilder('\Sabre\DAV\PropFind') + ->disableOriginalConstructor() + ->getMock(); + $node = $this->getMock('\Sabre\DAV\INode'); + + $propFind->expects($this->at(0)) + ->method('handle') + ->with('{DAV:}supportedlock'); + $propFind->expects($this->at(1)) + ->method('handle') + ->with('{DAV:}lockdiscovery'); + + $this->fakeLockerPlugin->propFind($propFind, $node); + } + + public function tokenDataProvider() { + return [ + [ + [ + [ + 'tokens' => [ + [ + 'token' => 'aToken', + 'validToken' => false, + ], + [], + [ + 'token' => 'opaquelocktoken:asdf', + 'validToken' => false, + ] + ], + ] + ], + [ + [ + 'tokens' => [ + [ + 'token' => 'aToken', + 'validToken' => false, + ], + [], + [ + 'token' => 'opaquelocktoken:asdf', + 'validToken' => true, + ] + ], + ] + ], + ] + ]; + } + + /** + * @dataProvider tokenDataProvider + * @param array $input + * @param array $expected + */ + public function testValidateTokens(array $input, array $expected) { + $request = $this->getMock('\Sabre\HTTP\RequestInterface'); + $this->fakeLockerPlugin->validateTokens($request, $input); + $this->assertSame($expected, $input); + } + + public function testFakeLockProvider() { + $request = $this->getMock('\Sabre\HTTP\RequestInterface'); + $response = $this->getMock('\Sabre\HTTP\ResponseInterface'); + $server = $this->getMock('\Sabre\DAV\Server'); + $this->fakeLockerPlugin->initialize($server); + + $request->expects($this->exactly(2)) + ->method('getPath') + ->will($this->returnValue('MyPath')); + $response->expects($this->once()) + ->method('setBody') + ->with('<?xml version="1.0" encoding="utf-8"?> +<d:prop xmlns:d="DAV:"><d:lockdiscovery><d:activelock><d:lockscope><d:exclusive/></d:lockscope><d:locktype><d:write/></d:locktype><d:lockroot><d:href>MyPath</d:href></d:lockroot><d:depth>infinity</d:depth><d:timeout>Second-1800</d:timeout><d:locktoken><d:href>opaquelocktoken:fe4f7f2437b151fbcb4e9f5c8118c6b1</d:href></d:locktoken><d:owner/></d:activelock></d:lockdiscovery></d:prop> +'); + + $this->assertSame(false, $this->fakeLockerPlugin->fakeLockProvider($request, $response)); + } + + public function testFakeUnlockProvider() { + $request = $this->getMock('\Sabre\HTTP\RequestInterface'); + $response = $this->getMock('\Sabre\HTTP\ResponseInterface'); + + $response->expects($this->once()) + ->method('setStatus') + ->with('204'); + $response->expects($this->once()) + ->method('setHeader') + ->with('Content-Length', '0'); + + $this->assertSame(false, $this->fakeLockerPlugin->fakeUnlockProvider($request, $response)); + } +} diff --git a/apps/dav/tests/unit/connector/sabre/requesttest/requesttest.php b/apps/dav/tests/unit/connector/sabre/requesttest/requesttest.php index d90cf6e19bc..a83f25c1585 100644 --- a/apps/dav/tests/unit/connector/sabre/requesttest/requesttest.php +++ b/apps/dav/tests/unit/connector/sabre/requesttest/requesttest.php @@ -46,7 +46,8 @@ abstract class RequestTest extends TestCase { \OC::$server->getUserSession(), \OC::$server->getMountManager(), \OC::$server->getTagManager(), - \OC::$server->getEventDispatcher() + \OC::$server->getEventDispatcher(), + $this->getMock('\OCP\IRequest') ); } @@ -67,6 +68,7 @@ abstract class RequestTest extends TestCase { * @param resource|string|null $body * @param array|null $headers * @return \Sabre\HTTP\Response + * @throws \Exception */ protected function request($view, $user, $password, $method, $url, $body = null, $headers = null) { if (is_string($body)) { diff --git a/apps/files/appinfo/app.php b/apps/files/appinfo/app.php index 40b194ab882..c752b5e7d72 100644 --- a/apps/files/appinfo/app.php +++ b/apps/files/appinfo/app.php @@ -25,12 +25,14 @@ */ \OCP\App::registerAdmin('files', 'admin'); + \OC::$server->getNavigationManager()->add(function () { + $urlGenerator = \OC::$server->getURLGenerator(); $l = \OC::$server->getL10N('files'); return [ 'id' => 'files_index', 'order' => 0, - 'href' => \OCP\Util::linkTo('files', 'index.php'), + 'href' => $urlGenerator->linkToRoute('files.view.index'), 'icon' => \OCP\Util::imagePath('core', 'places/files.svg'), 'name' => $l->t('Files'), ]; diff --git a/apps/files/appinfo/routes.php b/apps/files/appinfo/routes.php index d52dfaab21c..2bb913c30a6 100644 --- a/apps/files/appinfo/routes.php +++ b/apps/files/appinfo/routes.php @@ -48,14 +48,17 @@ $application->registerRoutes( 'verb' => 'GET', 'requirements' => array('tagName' => '.+'), ), + [ + 'name' => 'view#index', + 'url' => '/', + 'verb' => 'GET', + ], ) ) ); /** @var $this \OC\Route\Router */ -$this->create('files_index', '/') - ->actionInclude('files/index.php'); $this->create('files_ajax_delete', 'ajax/delete.php') ->actionInclude('files/ajax/delete.php'); $this->create('files_ajax_download', 'ajax/download.php') diff --git a/apps/files/controller/viewcontroller.php b/apps/files/controller/viewcontroller.php new file mode 100644 index 00000000000..c274680e525 --- /dev/null +++ b/apps/files/controller/viewcontroller.php @@ -0,0 +1,224 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * + * @copyright Copyright (c) 2015, 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\Files\Controller; + +use OC\AppFramework\Http\Request; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\RedirectResponse; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\IL10N; +use OCP\INavigationManager; +use OCP\IRequest; +use OCP\IURLGenerator; +use OCP\IConfig; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; + +/** + * Class ViewController + * + * @package OCA\Files\Controller + */ +class ViewController extends Controller { + /** @var string */ + protected $appName; + /** @var IRequest */ + protected $request; + /** @var IURLGenerator */ + protected $urlGenerator; + /** @var INavigationManager */ + protected $navigationManager; + /** @var IL10N */ + protected $l10n; + /** @var IConfig */ + protected $config; + /** @var EventDispatcherInterface */ + protected $eventDispatcher; + + /** + * @param string $appName + * @param IRequest $request + * @param IURLGenerator $urlGenerator + * @param INavigationManager $navigationManager + * @param IL10N $l10n + * @param IConfig $config + * @param EventDispatcherInterface $eventDispatcherInterface + */ + public function __construct($appName, + IRequest $request, + IURLGenerator $urlGenerator, + INavigationManager $navigationManager, + IL10N $l10n, + IConfig $config, + EventDispatcherInterface $eventDispatcherInterface) { + parent::__construct($appName, $request); + $this->appName = $appName; + $this->request = $request; + $this->urlGenerator = $urlGenerator; + $this->navigationManager = $navigationManager; + $this->l10n = $l10n; + $this->config = $config; + $this->eventDispatcher = $eventDispatcherInterface; + } + + /** + * @param string $appName + * @param string $scriptName + * @return string + */ + protected function renderScript($appName, $scriptName) { + $content = ''; + $appPath = \OC_App::getAppPath($appName); + $scriptPath = $appPath . '/' . $scriptName; + if (file_exists($scriptPath)) { + // TODO: sanitize path / script name ? + ob_start(); + include $scriptPath; + $content = ob_get_contents(); + @ob_end_clean(); + } + return $content; + } + + /** + * FIXME: Replace with non static code + * + * @return array + * @throws \OCP\Files\NotFoundException + */ + protected function getStorageInfo() { + $dirInfo = \OC\Files\Filesystem::getFileInfo('/', false); + return \OC_Helper::getStorageInfo('/', $dirInfo); + } + + /** + * @NoCSRFRequired + * @NoAdminRequired + * + * @param string $dir + * @param string $view + * @return TemplateResponse + * @throws \OCP\Files\NotFoundException + */ + public function index($dir = '', $view = '') { + // Load the files we need + \OCP\Util::addStyle('files', 'files'); + \OCP\Util::addStyle('files', 'upload'); + \OCP\Util::addStyle('files', 'mobile'); + \OCP\Util::addscript('files', 'app'); + \OCP\Util::addscript('files', 'file-upload'); + \OCP\Util::addscript('files', 'newfilemenu'); + \OCP\Util::addscript('files', 'jquery.iframe-transport'); + \OCP\Util::addscript('files', 'jquery.fileupload'); + \OCP\Util::addscript('files', 'jquery-visibility'); + \OCP\Util::addscript('files', 'fileinfomodel'); + \OCP\Util::addscript('files', 'filesummary'); + \OCP\Util::addscript('files', 'breadcrumb'); + \OCP\Util::addscript('files', 'filelist'); + \OCP\Util::addscript('files', 'search'); + + \OCP\Util::addScript('files', 'favoritesfilelist'); + \OCP\Util::addScript('files', 'tagsplugin'); + \OCP\Util::addScript('files', 'favoritesplugin'); + + \OCP\Util::addScript('files', 'detailfileinfoview'); + \OCP\Util::addScript('files', 'detailtabview'); + \OCP\Util::addScript('files', 'mainfileinfodetailview'); + \OCP\Util::addScript('files', 'detailsview'); + \OCP\Util::addStyle('files', 'detailsView'); + + \OC_Util::addVendorScript('core', 'handlebars/handlebars'); + + \OCP\Util::addscript('files', 'fileactions'); + \OCP\Util::addscript('files', 'fileactionsmenu'); + \OCP\Util::addscript('files', 'files'); + \OCP\Util::addscript('files', 'keyboardshortcuts'); + \OCP\Util::addscript('files', 'navigation'); + + // if IE8 and "?dir=path&view=someview" was specified, reformat the URL to use a hash like "#?dir=path&view=someview" + $isIE8 = $this->request->isUserAgent([Request::USER_AGENT_IE_8]); + if ($isIE8 && ($dir !== '' || $view !== '')) { + $dir = !empty($dir) ? $dir : '/'; + $view = !empty($view) ? $view : 'files'; + $hash = '#?dir=' . \OCP\Util::encodePath($dir); + if ($view !== 'files') { + $hash .= '&view=' . urlencode($view); + } + return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.index') . $hash); + } + + // mostly for the home storage's free space + // FIXME: Make non static + $storageInfo = $this->getStorageInfo(); + + $nav = new \OCP\Template('files', 'appnavigation', ''); + + \OCA\Files\App::getNavigationManager()->add( + [ + 'id' => 'favorites', + 'appname' => 'files', + 'script' => 'simplelist.php', + 'order' => 5, + 'name' => $this->l10n->t('Favorites') + ] + ); + + $navItems = \OCA\Files\App::getNavigationManager()->getAll(); + usort($navItems, function($item1, $item2) { + return $item1['order'] - $item2['order']; + }); + $nav->assign('navigationItems', $navItems); + + $contentItems = []; + + // render the container content for every navigation item + foreach ($navItems as $item) { + $content = ''; + if (isset($item['script'])) { + $content = $this->renderScript($item['appname'], $item['script']); + } + $contentItem = []; + $contentItem['id'] = $item['id']; + $contentItem['content'] = $content; + $contentItems[] = $contentItem; + } + + $this->eventDispatcher->dispatch('OCA\Files::loadAdditionalScripts'); + + $params = []; + $params['usedSpacePercent'] = (int)$storageInfo['relative']; + $params['owner'] = $storageInfo['owner']; + $params['ownerDisplayName'] = $storageInfo['ownerDisplayName']; + $params['isPublic'] = false; + $params['mailNotificationEnabled'] = $this->config->getAppValue('core', 'shareapi_allow_mail_notification', 'no'); + $params['mailPublicNotificationEnabled'] = $this->config->getAppValue('core', 'shareapi_allow_public_notification', 'no'); + $params['allowShareWithLink'] = $this->config->getAppValue('core', 'shareapi_allow_links', 'yes'); + $params['appNavigation'] = $nav; + $params['appContents'] = $contentItems; + $this->navigationManager->setActiveEntry('files_index'); + + return new TemplateResponse( + $this->appName, + 'index', + $params + ); + } +} diff --git a/apps/files/index.php b/apps/files/index.php deleted file mode 100644 index cc007ebdb07..00000000000 --- a/apps/files/index.php +++ /dev/null @@ -1,161 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Frank Karlitschek <frank@owncloud.org> - * @author Jakob Sack <mail@jakobsack.de> - * @author Jan-Christoph Borchardt <hey@jancborchardt.net> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Roman Geber <rgeber@owncloudapps.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2015, 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/> - * - */ - -// Check if we are a user -OCP\User::checkLoggedIn(); - -// Load the files we need -OCP\Util::addStyle('files', 'files'); -OCP\Util::addStyle('files', 'upload'); -OCP\Util::addStyle('files', 'mobile'); -OCP\Util::addscript('files', 'app'); -OCP\Util::addscript('files', 'file-upload'); -OCP\Util::addscript('files', 'newfilemenu'); -OCP\Util::addscript('files', 'jquery.iframe-transport'); -OCP\Util::addscript('files', 'jquery.fileupload'); -OCP\Util::addscript('files', 'jquery-visibility'); -OCP\Util::addscript('files', 'fileinfomodel'); -OCP\Util::addscript('files', 'filesummary'); -OCP\Util::addscript('files', 'breadcrumb'); -OCP\Util::addscript('files', 'filelist'); -OCP\Util::addscript('files', 'search'); - -\OCP\Util::addScript('files', 'favoritesfilelist'); -\OCP\Util::addScript('files', 'tagsplugin'); -\OCP\Util::addScript('files', 'favoritesplugin'); - -\OCP\Util::addScript('files', 'detailfileinfoview'); -\OCP\Util::addScript('files', 'detailtabview'); -\OCP\Util::addScript('files', 'mainfileinfodetailview'); -\OCP\Util::addScript('files', 'detailsview'); -\OCP\Util::addStyle('files', 'detailsView'); - -\OC_Util::addVendorScript('core', 'handlebars/handlebars'); - -OCP\App::setActiveNavigationEntry('files_index'); - -$l = \OC::$server->getL10N('files'); - -$isIE8 = false; -preg_match('/MSIE (.*?);/', $_SERVER['HTTP_USER_AGENT'], $matches); -if (count($matches) > 0 && $matches[1] <= 9) { - $isIE8 = true; -} - -// if IE8 and "?dir=path&view=someview" was specified, reformat the URL to use a hash like "#?dir=path&view=someview" -if ($isIE8 && (isset($_GET['dir']) || isset($_GET['view']))) { - $hash = '#?'; - $dir = isset($_GET['dir']) ? $_GET['dir'] : '/'; - $view = isset($_GET['view']) ? $_GET['view'] : 'files'; - $hash = '#?dir=' . \OCP\Util::encodePath($dir); - if ($view !== 'files') { - $hash .= '&view=' . urlencode($view); - } - header('Location: ' . OCP\Util::linkTo('files', 'index.php') . $hash); - exit(); -} - -$user = OC_User::getUser(); - -$config = \OC::$server->getConfig(); - -// mostly for the home storage's free space -$dirInfo = \OC\Files\Filesystem::getFileInfo('/', false); -$storageInfo=OC_Helper::getStorageInfo('/', $dirInfo); - -$nav = new OCP\Template('files', 'appnavigation', ''); - -function sortNavigationItems($item1, $item2) { - return $item1['order'] - $item2['order']; -} - -\OCA\Files\App::getNavigationManager()->add( - array( - 'id' => 'favorites', - 'appname' => 'files', - 'script' => 'simplelist.php', - 'order' => 5, - 'name' => $l->t('Favorites') - ) -); - -$navItems = \OCA\Files\App::getNavigationManager()->getAll(); -usort($navItems, 'sortNavigationItems'); -$nav->assign('navigationItems', $navItems); - -$contentItems = array(); - -function renderScript($appName, $scriptName) { - $content = ''; - $appPath = OC_App::getAppPath($appName); - $scriptPath = $appPath . '/' . $scriptName; - if (file_exists($scriptPath)) { - // TODO: sanitize path / script name ? - ob_start(); - include $scriptPath; - $content = ob_get_contents(); - @ob_end_clean(); - } - return $content; -} - -// render the container content for every navigation item -foreach ($navItems as $item) { - $content = ''; - if (isset($item['script'])) { - $content = renderScript($item['appname'], $item['script']); - } - $contentItem = array(); - $contentItem['id'] = $item['id']; - $contentItem['content'] = $content; - $contentItems[] = $contentItem; -} - -OCP\Util::addscript('files', 'fileactions'); -OCP\Util::addscript('files', 'fileactionsmenu'); -OCP\Util::addscript('files', 'files'); -OCP\Util::addscript('files', 'navigation'); -OCP\Util::addscript('files', 'keyboardshortcuts'); - -\OC::$server->getEventDispatcher()->dispatch('OCA\Files::loadAdditionalScripts'); - -$tmpl = new OCP\Template('files', 'index', 'user'); -$tmpl->assign('usedSpacePercent', (int)$storageInfo['relative']); -$tmpl->assign('owner', $storageInfo['owner']); -$tmpl->assign('ownerDisplayName', $storageInfo['ownerDisplayName']); -$tmpl->assign('isPublic', false); -$tmpl->assign("mailNotificationEnabled", $config->getAppValue('core', 'shareapi_allow_mail_notification', 'no')); -$tmpl->assign("mailPublicNotificationEnabled", $config->getAppValue('core', 'shareapi_allow_public_notification', 'no')); -$tmpl->assign("allowShareWithLink", $config->getAppValue('core', 'shareapi_allow_links', 'yes')); -$tmpl->assign('appNavigation', $nav); -$tmpl->assign('appContents', $contentItems); - -$tmpl->printPage(); diff --git a/apps/files/l10n/cs_CZ.js b/apps/files/l10n/cs_CZ.js index f93b1f5d7a1..3c6bdc05a1b 100644 --- a/apps/files/l10n/cs_CZ.js +++ b/apps/files/l10n/cs_CZ.js @@ -106,6 +106,8 @@ OC.L10N.register( "Maximum upload size" : "Maximální velikost pro odesílání", "max. possible: " : "největší možná: ", "Save" : "Uložit", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "Při použití PHP-FPM může změna nastavení trvat až 5 minut od uložení.", + "Missing permissions to edit from here." : "Pro úpravy v aktuálním náhledu chybí oprávnění.", "Settings" : "Nastavení", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Použijte tuto adresu pro <a href=\"%s\" target=\"_blank\">přístup k vašim souborům přes WebDAV</a>", diff --git a/apps/files/l10n/cs_CZ.json b/apps/files/l10n/cs_CZ.json index 7daf7a492da..bf9170f2ee3 100644 --- a/apps/files/l10n/cs_CZ.json +++ b/apps/files/l10n/cs_CZ.json @@ -104,6 +104,8 @@ "Maximum upload size" : "Maximální velikost pro odesílání", "max. possible: " : "největší možná: ", "Save" : "Uložit", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "Při použití PHP-FPM může změna nastavení trvat až 5 minut od uložení.", + "Missing permissions to edit from here." : "Pro úpravy v aktuálním náhledu chybí oprávnění.", "Settings" : "Nastavení", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Použijte tuto adresu pro <a href=\"%s\" target=\"_blank\">přístup k vašim souborům přes WebDAV</a>", diff --git a/apps/files/l10n/el.js b/apps/files/l10n/el.js index 36066e9fe9c..6c8e2cbff33 100644 --- a/apps/files/l10n/el.js +++ b/apps/files/l10n/el.js @@ -106,6 +106,8 @@ OC.L10N.register( "Maximum upload size" : "Μέγιστο μέγεθος αποστολής", "max. possible: " : "μέγιστο δυνατό:", "Save" : "Αποθήκευση", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "Με PHP-FPM μπορεί να χρειαστούν μέχρι και 5 λεπτά για να ενεργοποιηθούν οι αλλαγές.", + "Missing permissions to edit from here." : "Δεν υπάρχουν τα απαραίτητα δικαιώματα για να γίνει τροποποιήση σε αυτό το σημείο.", "Settings" : "Ρυθμίσεις", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Χρησιμοποιήστε αυτήν την διεύθυνση για να αποκτήσετε <a href=\"%s\" target=\"_blank\">πρόσβαση στα αρχεία σας μέσω WebDAV</a>", diff --git a/apps/files/l10n/el.json b/apps/files/l10n/el.json index 7f0ce4dfe38..ee9e4ebde54 100644 --- a/apps/files/l10n/el.json +++ b/apps/files/l10n/el.json @@ -104,6 +104,8 @@ "Maximum upload size" : "Μέγιστο μέγεθος αποστολής", "max. possible: " : "μέγιστο δυνατό:", "Save" : "Αποθήκευση", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "Με PHP-FPM μπορεί να χρειαστούν μέχρι και 5 λεπτά για να ενεργοποιηθούν οι αλλαγές.", + "Missing permissions to edit from here." : "Δεν υπάρχουν τα απαραίτητα δικαιώματα για να γίνει τροποποιήση σε αυτό το σημείο.", "Settings" : "Ρυθμίσεις", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Χρησιμοποιήστε αυτήν την διεύθυνση για να αποκτήσετε <a href=\"%s\" target=\"_blank\">πρόσβαση στα αρχεία σας μέσω WebDAV</a>", diff --git a/apps/files/l10n/fi_FI.js b/apps/files/l10n/fi_FI.js index 447350e024f..79f3321577f 100644 --- a/apps/files/l10n/fi_FI.js +++ b/apps/files/l10n/fi_FI.js @@ -106,6 +106,7 @@ OC.L10N.register( "Maximum upload size" : "Lähetettävän tiedoston suurin sallittu koko", "max. possible: " : "suurin mahdollinen:", "Save" : "Tallenna", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "PHP-FPM:tä käyttäen muutoksien voimaantulossa saattaa kestää 5 minuuttia.", "Settings" : "Asetukset", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Käytä tätä osoitetta <a href=\"%s\" target=\"_blank\">käyttääksesi tiedostojasi WebDAVin kautta</a>", diff --git a/apps/files/l10n/fi_FI.json b/apps/files/l10n/fi_FI.json index aa30ccd433e..e46327c83fa 100644 --- a/apps/files/l10n/fi_FI.json +++ b/apps/files/l10n/fi_FI.json @@ -104,6 +104,7 @@ "Maximum upload size" : "Lähetettävän tiedoston suurin sallittu koko", "max. possible: " : "suurin mahdollinen:", "Save" : "Tallenna", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "PHP-FPM:tä käyttäen muutoksien voimaantulossa saattaa kestää 5 minuuttia.", "Settings" : "Asetukset", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Käytä tätä osoitetta <a href=\"%s\" target=\"_blank\">käyttääksesi tiedostojasi WebDAVin kautta</a>", diff --git a/apps/files/l10n/fr.js b/apps/files/l10n/fr.js index d00f33391d4..e068b3c45ba 100644 --- a/apps/files/l10n/fr.js +++ b/apps/files/l10n/fr.js @@ -106,6 +106,8 @@ OC.L10N.register( "Maximum upload size" : "Taille max. d'envoi", "max. possible: " : "Max. possible :", "Save" : "Sauvegarder", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "Avec PHP-FPM il peut se passer 5 minutes pour que les changements soient appliqués.", + "Missing permissions to edit from here." : "Manque de permissions pour éditer à partir d'ici.", "Settings" : "Paramètres", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Utilisez cette adresse pour <a href=\"%s\" target=\"_blank\">accéder à vos fichiers par WebDAV</a>", diff --git a/apps/files/l10n/fr.json b/apps/files/l10n/fr.json index 9d30823e265..a297b3525d1 100644 --- a/apps/files/l10n/fr.json +++ b/apps/files/l10n/fr.json @@ -104,6 +104,8 @@ "Maximum upload size" : "Taille max. d'envoi", "max. possible: " : "Max. possible :", "Save" : "Sauvegarder", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "Avec PHP-FPM il peut se passer 5 minutes pour que les changements soient appliqués.", + "Missing permissions to edit from here." : "Manque de permissions pour éditer à partir d'ici.", "Settings" : "Paramètres", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Utilisez cette adresse pour <a href=\"%s\" target=\"_blank\">accéder à vos fichiers par WebDAV</a>", diff --git a/apps/files/l10n/it.js b/apps/files/l10n/it.js index 7fdd7170887..4c6033e6caf 100644 --- a/apps/files/l10n/it.js +++ b/apps/files/l10n/it.js @@ -106,6 +106,8 @@ OC.L10N.register( "Maximum upload size" : "Dimensione massima caricamento", "max. possible: " : "numero mass.: ", "Save" : "Salva", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "Con PHP-FPM potrebbe richiedere 5 minuti perché le modifiche siano applicate.", + "Missing permissions to edit from here." : "Permessi mancanti per modificare da qui.", "Settings" : "Impostazioni", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Utilizza questo indirizzo per <a href=\"%s\" target=\"_blank\">accedere ai tuoi file con WebDAV</a>", diff --git a/apps/files/l10n/it.json b/apps/files/l10n/it.json index 9e5bee70191..239b8dc399c 100644 --- a/apps/files/l10n/it.json +++ b/apps/files/l10n/it.json @@ -104,6 +104,8 @@ "Maximum upload size" : "Dimensione massima caricamento", "max. possible: " : "numero mass.: ", "Save" : "Salva", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "Con PHP-FPM potrebbe richiedere 5 minuti perché le modifiche siano applicate.", + "Missing permissions to edit from here." : "Permessi mancanti per modificare da qui.", "Settings" : "Impostazioni", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Utilizza questo indirizzo per <a href=\"%s\" target=\"_blank\">accedere ai tuoi file con WebDAV</a>", diff --git a/apps/files/l10n/ja.js b/apps/files/l10n/ja.js index 53eb8dca351..be441c15ca1 100644 --- a/apps/files/l10n/ja.js +++ b/apps/files/l10n/ja.js @@ -106,6 +106,8 @@ OC.L10N.register( "Maximum upload size" : "最大アップロードサイズ", "max. possible: " : "最大容量: ", "Save" : "保存", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "PHP-FPM の場合は値を変更後、反映されるのに5分程度かかります。", + "Missing permissions to edit from here." : "ここから編集するための権限がありません。", "Settings" : "設定", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "<a href=\"%s\" target=\"_blank\">WebDAV経由でのファイルアクセス</a>にはこのアドレスを利用してください", diff --git a/apps/files/l10n/ja.json b/apps/files/l10n/ja.json index 36983beafc2..58b4870369c 100644 --- a/apps/files/l10n/ja.json +++ b/apps/files/l10n/ja.json @@ -104,6 +104,8 @@ "Maximum upload size" : "最大アップロードサイズ", "max. possible: " : "最大容量: ", "Save" : "保存", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "PHP-FPM の場合は値を変更後、反映されるのに5分程度かかります。", + "Missing permissions to edit from here." : "ここから編集するための権限がありません。", "Settings" : "設定", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "<a href=\"%s\" target=\"_blank\">WebDAV経由でのファイルアクセス</a>にはこのアドレスを利用してください", diff --git a/apps/files/l10n/pt_BR.js b/apps/files/l10n/pt_BR.js index 158ef08608d..b7a2196db63 100644 --- a/apps/files/l10n/pt_BR.js +++ b/apps/files/l10n/pt_BR.js @@ -106,6 +106,8 @@ OC.L10N.register( "Maximum upload size" : "Tamanho máximo para envio", "max. possible: " : "max. possível:", "Save" : "Salvar", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "Com PHP-FPM pode demorar 5 minutos para que as alterações sejam aplicadas.", + "Missing permissions to edit from here." : "Faltando permissões para editar a partir daqui.", "Settings" : "Configurações", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Use este endereço <a href=\"%s\" target=\"_blank\">para ter acesso aos seus Arquivos via WebDAV</a>", diff --git a/apps/files/l10n/pt_BR.json b/apps/files/l10n/pt_BR.json index af539480d95..335b50a2d7d 100644 --- a/apps/files/l10n/pt_BR.json +++ b/apps/files/l10n/pt_BR.json @@ -104,6 +104,8 @@ "Maximum upload size" : "Tamanho máximo para envio", "max. possible: " : "max. possível:", "Save" : "Salvar", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "Com PHP-FPM pode demorar 5 minutos para que as alterações sejam aplicadas.", + "Missing permissions to edit from here." : "Faltando permissões para editar a partir daqui.", "Settings" : "Configurações", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Use este endereço <a href=\"%s\" target=\"_blank\">para ter acesso aos seus Arquivos via WebDAV</a>", diff --git a/apps/files/l10n/sq.js b/apps/files/l10n/sq.js index 9428855d9ee..5f0b3a8c936 100644 --- a/apps/files/l10n/sq.js +++ b/apps/files/l10n/sq.js @@ -70,6 +70,7 @@ OC.L10N.register( "Your storage is full, files can not be updated or synced anymore!" : "Depozita juaj është plot, kartelat s’mund të përditësohen ose njëkohësohen më!", "Storage of {owner} is almost full ({usedSpacePercent}%)" : "Depozita e {owner} është thuasje plot ({usedSpacePercent}%)", "Your storage is almost full ({usedSpacePercent}%)" : "Depozita juaj është thuajse plot ({usedSpacePercent}%)", + "_matches '{filter}'_::_match '{filter}'_" : ["ka përputhje me '{filter}'","ka përputhje me '{filter}'"], "Path" : "Shteg", "_%n byte_::_%n bytes_" : ["%n bajt","%n bajte"], "Favorited" : "U kalua e parapëlqyer", @@ -105,6 +106,8 @@ OC.L10N.register( "Maximum upload size" : "Madhësi maksimale ngarkimi", "max. possible: " : "maks. i mundshëm: ", "Save" : "Ruaje", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "Me PHP-FPM mund të duhen 5 minuta që ndryshimet të hyjnë në fuqi.", + "Missing permissions to edit from here." : "Mungojnë lejet për të përpunuar që këtu.", "Settings" : "Rregullime", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Përdorni këtë adresë për <a href=\"%s\" target=\"_blank\">të hyrë te Kartelat tuaja përmes WebDAV-it</a>", diff --git a/apps/files/l10n/sq.json b/apps/files/l10n/sq.json index 65e87f42c1b..fceac2c5376 100644 --- a/apps/files/l10n/sq.json +++ b/apps/files/l10n/sq.json @@ -68,6 +68,7 @@ "Your storage is full, files can not be updated or synced anymore!" : "Depozita juaj është plot, kartelat s’mund të përditësohen ose njëkohësohen më!", "Storage of {owner} is almost full ({usedSpacePercent}%)" : "Depozita e {owner} është thuasje plot ({usedSpacePercent}%)", "Your storage is almost full ({usedSpacePercent}%)" : "Depozita juaj është thuajse plot ({usedSpacePercent}%)", + "_matches '{filter}'_::_match '{filter}'_" : ["ka përputhje me '{filter}'","ka përputhje me '{filter}'"], "Path" : "Shteg", "_%n byte_::_%n bytes_" : ["%n bajt","%n bajte"], "Favorited" : "U kalua e parapëlqyer", @@ -103,6 +104,8 @@ "Maximum upload size" : "Madhësi maksimale ngarkimi", "max. possible: " : "maks. i mundshëm: ", "Save" : "Ruaje", + "With PHP-FPM it might take 5 minutes for changes to be applied." : "Me PHP-FPM mund të duhen 5 minuta që ndryshimet të hyjnë në fuqi.", + "Missing permissions to edit from here." : "Mungojnë lejet për të përpunuar që këtu.", "Settings" : "Rregullime", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Përdorni këtë adresë për <a href=\"%s\" target=\"_blank\">të hyrë te Kartelat tuaja përmes WebDAV-it</a>", diff --git a/apps/files/l10n/zh_TW.js b/apps/files/l10n/zh_TW.js index aba0261047a..c38488d3087 100644 --- a/apps/files/l10n/zh_TW.js +++ b/apps/files/l10n/zh_TW.js @@ -7,7 +7,7 @@ OC.L10N.register( "Could not move %s - File with this name already exists" : "無法移動 %s ,同名的檔案已經存在", "Could not move %s" : "無法移動 %s", "Permission denied" : "存取被拒", - "The target folder has been moved or deleted." : "目標資料夾已經被搬移或刪除。", + "The target folder has been moved or deleted." : "目標資料夾已經被搬移或刪除", "The name %s is already used in the folder %s. Please choose a different name." : "%s 已經被使用於資料夾 %s ,請換一個名字", "Error when creating the file" : "建立檔案失敗", "Error when creating the folder" : "建立資料夾失敗", @@ -62,7 +62,7 @@ OC.L10N.register( "_%n file_::_%n files_" : ["%n 個檔案"], "{dirs} and {files}" : "{dirs} 和 {files}", "You don’t have permission to upload or create files here" : "您沒有權限在這裡上傳或建立檔案", - "_Uploading %n file_::_Uploading %n files_" : ["%n 個檔案正在上傳"], + "_Uploading %n file_::_Uploading %n files_" : ["正在上傳 %n 個檔案"], "New" : "新增", "\"{name}\" is an invalid file name." : "{name} 是無效的檔名", "File name cannot be empty." : "檔名不能為空", @@ -94,11 +94,11 @@ OC.L10N.register( "%2$s changed %1$s" : "%2$s 已變更了 %1$s", "You deleted %1$s" : "您刪除了 %1$s", "%2$s deleted %1$s" : "%2$s 已刪除 %1$s", - "You restored %1$s" : "您恢復了 %1$s", - "%2$s restored %1$s" : "%2$s 已恢復了 %1$s", + "You restored %1$s" : "您還原了 %1$s", + "%2$s restored %1$s" : "%2$s 還原了 %1$s", "Changed by %2$s" : "由 %2$s 改動", "Deleted by %2$s" : "由 %2$s 刪除", - "Restored by %2$s" : "由 %2$s 復原", + "Restored by %2$s" : "由 %2$s 還原", "%s could not be renamed as it has been deleted" : "%s 已經被刪除了所以無法重新命名", "%s could not be renamed" : "無法重新命名 %s", "Upload (max. %s)" : "上傳(至多 %s)", @@ -115,8 +115,8 @@ OC.L10N.register( "No entries found in this folder" : "在此資料夾中沒有任何項目", "Select all" : "全選", "Upload too large" : "上傳過大", - "The files you are trying to upload exceed the maximum size for file uploads on this server." : "您試圖上傳的檔案大小超過伺服器的限制。", - "Files are being scanned, please wait." : "正在掃描檔案,請稍等。", + "The files you are trying to upload exceed the maximum size for file uploads on this server." : "您試圖上傳的檔案大小超過伺服器的限制", + "Files are being scanned, please wait." : "正在掃描檔案,請稍等", "Currently scanning" : "正在掃描", "No favorites" : "沒有最愛", "Files and folders you mark as favorite will show up here" : "您標記為最愛的檔案與資料夾將會顯示在這裡" diff --git a/apps/files/l10n/zh_TW.json b/apps/files/l10n/zh_TW.json index 4e4f7d0a871..8a408b5ffad 100644 --- a/apps/files/l10n/zh_TW.json +++ b/apps/files/l10n/zh_TW.json @@ -5,7 +5,7 @@ "Could not move %s - File with this name already exists" : "無法移動 %s ,同名的檔案已經存在", "Could not move %s" : "無法移動 %s", "Permission denied" : "存取被拒", - "The target folder has been moved or deleted." : "目標資料夾已經被搬移或刪除。", + "The target folder has been moved or deleted." : "目標資料夾已經被搬移或刪除", "The name %s is already used in the folder %s. Please choose a different name." : "%s 已經被使用於資料夾 %s ,請換一個名字", "Error when creating the file" : "建立檔案失敗", "Error when creating the folder" : "建立資料夾失敗", @@ -60,7 +60,7 @@ "_%n file_::_%n files_" : ["%n 個檔案"], "{dirs} and {files}" : "{dirs} 和 {files}", "You don’t have permission to upload or create files here" : "您沒有權限在這裡上傳或建立檔案", - "_Uploading %n file_::_Uploading %n files_" : ["%n 個檔案正在上傳"], + "_Uploading %n file_::_Uploading %n files_" : ["正在上傳 %n 個檔案"], "New" : "新增", "\"{name}\" is an invalid file name." : "{name} 是無效的檔名", "File name cannot be empty." : "檔名不能為空", @@ -92,11 +92,11 @@ "%2$s changed %1$s" : "%2$s 已變更了 %1$s", "You deleted %1$s" : "您刪除了 %1$s", "%2$s deleted %1$s" : "%2$s 已刪除 %1$s", - "You restored %1$s" : "您恢復了 %1$s", - "%2$s restored %1$s" : "%2$s 已恢復了 %1$s", + "You restored %1$s" : "您還原了 %1$s", + "%2$s restored %1$s" : "%2$s 還原了 %1$s", "Changed by %2$s" : "由 %2$s 改動", "Deleted by %2$s" : "由 %2$s 刪除", - "Restored by %2$s" : "由 %2$s 復原", + "Restored by %2$s" : "由 %2$s 還原", "%s could not be renamed as it has been deleted" : "%s 已經被刪除了所以無法重新命名", "%s could not be renamed" : "無法重新命名 %s", "Upload (max. %s)" : "上傳(至多 %s)", @@ -113,8 +113,8 @@ "No entries found in this folder" : "在此資料夾中沒有任何項目", "Select all" : "全選", "Upload too large" : "上傳過大", - "The files you are trying to upload exceed the maximum size for file uploads on this server." : "您試圖上傳的檔案大小超過伺服器的限制。", - "Files are being scanned, please wait." : "正在掃描檔案,請稍等。", + "The files you are trying to upload exceed the maximum size for file uploads on this server." : "您試圖上傳的檔案大小超過伺服器的限制", + "Files are being scanned, please wait." : "正在掃描檔案,請稍等", "Currently scanning" : "正在掃描", "No favorites" : "沒有最愛", "Files and folders you mark as favorite will show up here" : "您標記為最愛的檔案與資料夾將會顯示在這裡" diff --git a/apps/files/templates/appnavigation.php b/apps/files/templates/appnavigation.php index 512300e3a58..d05a02ee7db 100644 --- a/apps/files/templates/appnavigation.php +++ b/apps/files/templates/appnavigation.php @@ -16,9 +16,7 @@ </button> </div> <div id="app-settings-content"> - <h2> - <label for="webdavurl"><?php p($l->t('WebDAV'));?></label> - </h2> + <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">access your Files via WebDAV</a>', array(link_to_docs('user-webdav'))));?></em> </div> diff --git a/apps/files/tests/controller/ViewControllerTest.php b/apps/files/tests/controller/ViewControllerTest.php new file mode 100644 index 00000000000..028dfce8c58 --- /dev/null +++ b/apps/files/tests/controller/ViewControllerTest.php @@ -0,0 +1,250 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * + * @copyright Copyright (c) 2015, 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\Files\Tests\Controller; + +use OCA\Files\Controller\ViewController; +use OCP\AppFramework\Http; +use OCP\Template; +use Test\TestCase; +use OCP\IRequest; +use OCP\IURLGenerator; +use OCP\AppFramework\Http\RedirectResponse; +use OCP\INavigationManager; +use OCP\IL10N; +use OCP\IConfig; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; + +/** + * Class ViewControllerTest + * + * @package OCA\Files\Tests\Controller + */ +class ViewControllerTest extends TestCase { + /** @var IRequest */ + private $request; + /** @var IURLGenerator */ + private $urlGenerator; + /** @var INavigationManager */ + private $navigationManager; + /** @var IL10N */ + private $l10n; + /** @var IConfig */ + private $config; + /** @var EventDispatcherInterface */ + private $eventDispatcher; + /** @var ViewController */ + private $viewController; + + public function setUp() { + parent::setUp(); + $this->request = $this->getMock('\OCP\IRequest'); + $this->urlGenerator = $this->getMock('\OCP\IURLGenerator'); + $this->navigationManager = $this->getMock('\OCP\INavigationManager'); + $this->l10n = $this->getMock('\OCP\IL10N'); + $this->config = $this->getMock('\OCP\IConfig'); + $this->eventDispatcher = $this->getMock('\Symfony\Component\EventDispatcher\EventDispatcherInterface'); + $this->viewController = $this->getMockBuilder('\OCA\Files\Controller\ViewController') + ->setConstructorArgs([ + 'files', + $this->request, + $this->urlGenerator, + $this->navigationManager, + $this->l10n, + $this->config, + $this->eventDispatcher + ]) + ->setMethods([ + 'getStorageInfo', + 'renderScript' + ]) + ->getMock(); + } + + public function testIndexWithIE8RedirectAndDirDefined() { + $this->request + ->expects($this->once()) + ->method('isUserAgent') + ->with(['/MSIE 8.0/']) + ->will($this->returnValue(true)); + $this->urlGenerator + ->expects($this->once()) + ->method('linkToRoute') + ->with('files.view.index') + ->will($this->returnValue('/apps/files/')); + + $expected = new Http\RedirectResponse('/apps/files/#?dir=MyDir'); + $this->assertEquals($expected, $this->viewController->index('MyDir')); + } + + public function testIndexWithIE8RedirectAndViewDefined() { + $this->request + ->expects($this->once()) + ->method('isUserAgent') + ->with(['/MSIE 8.0/']) + ->will($this->returnValue(true)); + $this->urlGenerator + ->expects($this->once()) + ->method('linkToRoute') + ->with('files.view.index') + ->will($this->returnValue('/apps/files/')); + + $expected = new Http\RedirectResponse('/apps/files/#?dir=/&view=MyView'); + $this->assertEquals($expected, $this->viewController->index('', 'MyView')); + } + + public function testIndexWithIE8RedirectAndViewAndDirDefined() { + $this->request + ->expects($this->once()) + ->method('isUserAgent') + ->with(['/MSIE 8.0/']) + ->will($this->returnValue(true)); + $this->urlGenerator + ->expects($this->once()) + ->method('linkToRoute') + ->with('files.view.index') + ->will($this->returnValue('/apps/files/')); + + $expected = new RedirectResponse('/apps/files/#?dir=MyDir&view=MyView'); + $this->assertEquals($expected, $this->viewController->index('MyDir', 'MyView')); + } + + public function testIndexWithRegularBrowser() { + $this->request + ->expects($this->once()) + ->method('isUserAgent') + ->with(['/MSIE 8.0/']) + ->will($this->returnValue(false)); + $this->viewController + ->expects($this->once()) + ->method('getStorageInfo') + ->will($this->returnValue([ + 'relative' => 123, + 'owner' => 'MyName', + 'ownerDisplayName' => 'MyDisplayName', + ])); + + $this->config + ->expects($this->any()) + ->method('getAppValue') + ->will($this->returnArgument(2)); + + $nav = new Template('files', 'appnavigation'); + $nav->assign('navigationItems', [ + 0 => [ + 'id' => 'files', + 'appname' => 'files', + 'script' => 'list.php', + 'order' => 0, + 'name' => new \OC_L10N_String(new \OC_L10N('files'), 'All files', []), + 'active' => false, + 'icon' => '', + ], + 1 => [ + 'id' => 'favorites', + 'appname' => 'files', + 'script' => 'simplelist.php', + 'order' => 5, + 'name' => null, + 'active' => false, + 'icon' => '', + ], + 2 => [ + 'id' => 'sharingin', + 'appname' => 'files_sharing', + 'script' => 'list.php', + 'order' => 10, + 'name' => new \OC_L10N_String(new \OC_L10N('files_sharing'), 'Shared with you', []), + 'active' => false, + 'icon' => '', + ], + 3 => [ + 'id' => 'sharingout', + 'appname' => 'files_sharing', + 'script' => 'list.php', + 'order' => 15, + 'name' => new \OC_L10N_String(new \OC_L10N('files_sharing'), 'Shared with others', []), + 'active' => false, + 'icon' => '', + ], + 4 => [ + 'id' => 'sharinglinks', + 'appname' => 'files_sharing', + 'script' => 'list.php', + 'order' => 20, + 'name' => new \OC_L10N_String(new \OC_L10N('files_sharing'), 'Shared by link', []), + 'active' => false, + 'icon' => '', + ], + 5 => [ + 'id' => 'trashbin', + 'appname' => 'files_trashbin', + 'script' => 'list.php', + 'order' => 50, + 'name' => new \OC_L10N_String(new \OC_L10N('files_trashbin'), 'Deleted files', []), + 'active' => false, + 'icon' => '', + ], + ]); + + $expected = new Http\TemplateResponse( + 'files', + 'index', + [ + 'usedSpacePercent' => 123, + 'owner' => 'MyName', + 'ownerDisplayName' => 'MyDisplayName', + 'isPublic' => false, + 'mailNotificationEnabled' => 'no', + 'mailPublicNotificationEnabled' => 'no', + 'allowShareWithLink' => 'yes', + 'appNavigation' => $nav, + 'appContents' => [ + 0 => [ + 'id' => 'files', + 'content' => null, + ], + 1 => [ + 'id' => 'favorites', + 'content' => null, + ], + 2 => [ + 'id' => 'sharingin', + 'content' => null, + ], + 3 => [ + 'id' => 'sharingout', + 'content' => null, + ], + 4 => [ + 'id' => 'sharinglinks', + 'content' => null, + ], + 5 => [ + 'id' => 'trashbin', + 'content' => null, + ], + ], + ] + ); + $this->assertEquals($expected, $this->viewController->index('MyDir', 'MyView')); + } +} diff --git a/apps/files_external/lib/sftp.php b/apps/files_external/lib/sftp.php index 5dcc7686ca3..f8651727fd2 100644 --- a/apps/files_external/lib/sftp.php +++ b/apps/files_external/lib/sftp.php @@ -52,27 +52,37 @@ class SFTP extends \OC\Files\Storage\Common { protected $client; /** + * @param string $host protocol://server:port + * @return array [$server, $port] + */ + private function splitHost($host) { + $input = $host; + if (strpos($host, '://') === false) { + // add a protocol to fix parse_url behavior with ipv6 + $host = 'http://' . $host; + } + + $parsed = parse_url($host); + if(is_array($parsed) && isset($parsed['port'])) { + return [$parsed['host'], $parsed['port']]; + } else if (is_array($parsed)) { + return [$parsed['host'], 22]; + } else { + return [$input, 22]; + } + } + + /** * {@inheritdoc} */ public function __construct($params) { // Register sftp:// Stream::register(); - $this->host = $params['host']; + $parsedHost = $this->splitHost($params['host']); - //deals with sftp://server example - $proto = strpos($this->host, '://'); - if ($proto != false) { - $this->host = substr($this->host, $proto+3); - } - - //deals with server:port - $hasPort = strpos($this->host,':'); - if($hasPort != false) { - $pieces = explode(":", $this->host); - $this->host = $pieces[0]; - $this->port = $pieces[1]; - } + $this->host = $parsedHost[0]; + $this->port = $parsedHost[1]; $this->user = $params['user']; diff --git a/apps/files_external/tests/backends/sftp.php b/apps/files_external/tests/backends/sftp.php index da2c0ac6ba2..aaed2b3460a 100644 --- a/apps/files_external/tests/backends/sftp.php +++ b/apps/files_external/tests/backends/sftp.php @@ -26,6 +26,11 @@ namespace Test\Files\Storage; class SFTP extends Storage { + /** + * @var \OC\Files\Storage\SFTP instance + */ + protected $instance; + private $config; protected function setUp() { @@ -103,6 +108,39 @@ class SFTP extends Storage { ], 'sftp::someuser@somehost:8822//remotedir/subdir/', ], + [ + // ipv6 with port + [ + 'run' => true, + 'host' => 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329', + 'user' => 'someuser', + 'password' => 'somepassword', + 'root' => 'remotedir/subdir/', + ], + 'sftp::someuser@FE80:0000:0000:0000:0202:B3FF:FE1E:8329//remotedir/subdir/', + ], + [ + // ipv6 without port + [ + 'run' => true, + 'host' => 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329:8822', + 'user' => 'someuser', + 'password' => 'somepassword', + 'root' => 'remotedir/subdir/', + ], + 'sftp::someuser@FE80:0000:0000:0000:0202:B3FF:FE1E:8329:8822//remotedir/subdir/', + ], + [ + // collapsed ipv6 with port + [ + 'run' => true, + 'host' => 'FE80::0202:B3FF:FE1E:8329:8822', + 'user' => 'someuser', + 'password' => 'somepassword', + 'root' => 'remotedir/subdir/', + ], + 'sftp::someuser@FE80::0202:B3FF:FE1E:8329:8822//remotedir/subdir/', + ], ]; } } diff --git a/apps/files_sharing/api/ocssharewrapper.php b/apps/files_sharing/api/ocssharewrapper.php index 8c0d8f7d150..3ce2901dfb4 100644 --- a/apps/files_sharing/api/ocssharewrapper.php +++ b/apps/files_sharing/api/ocssharewrapper.php @@ -35,15 +35,16 @@ class OCSShareWrapper { \OC::$server->getUserFolder(), new \OC\Share20\DefaultShareProvider( \OC::$server->getDatabaseConnection(), - \OC::$server->getUserManager(), - \OC::$server->getGroupManager(), - \OC::$server->getUserFolder() + \OC::$server->getUserManager(), + \OC::$server->getGroupManager(), + \OC::$server->getUserFolder() ) ), \OC::$server->getGroupManager(), \OC::$server->getUserManager(), \OC::$server->getRequest(), - \OC::$server->getUserFolder()); + \OC::$server->getUserFolder(), + \OC::$server->getURLGenerator()); } public function getAllShares($params) { @@ -55,7 +56,8 @@ class OCSShareWrapper { } public function getShare($params) { - return \OCA\Files_Sharing\API\Local::getShare($params); + $id = $params['id']; + return $this->getShare20OCS()->getShare($id); } public function updateShare($params) { @@ -63,7 +65,7 @@ class OCSShareWrapper { } public function deleteShare($params) { - $id = (int)$params['id']; + $id = $params['id']; return $this->getShare20OCS()->deleteShare($id); } } diff --git a/apps/files_sharing/api/share20ocs.php b/apps/files_sharing/api/share20ocs.php index 8a7f90c0023..aaf5a3c72b6 100644 --- a/apps/files_sharing/api/share20ocs.php +++ b/apps/files_sharing/api/share20ocs.php @@ -20,39 +20,125 @@ */ namespace OCA\Files_Sharing\API; +use OC\Share20\IShare; + class Share20OCS { - /** @var OC\Share20\Manager */ + /** @var \OC\Share20\Manager */ private $shareManager; - /** @var OCP\IGroupManager */ + /** @var \OCP\IGroupManager */ private $groupManager; - /** @var OCP\IUserManager */ + /** @var \OCP\IUserManager */ private $userManager; - /** @var OCP\IRequest */ + /** @var \OCP\IRequest */ private $request; - /** @var OCP\Files\Folder */ + /** @var \OCP\Files\Folder */ private $userFolder; public function __construct(\OC\Share20\Manager $shareManager, \OCP\IGroupManager $groupManager, \OCP\IUserManager $userManager, \OCP\IRequest $request, - \OCP\Files\Folder $userFolder) { + \OCP\Files\Folder $userFolder, + \OCP\IURLGenerator $urlGenerator) { $this->shareManager = $shareManager; $this->userManager = $userManager; $this->groupManager = $groupManager; $this->request = $request; $this->userFolder = $userFolder; + $this->urlGenerator = $urlGenerator; + } + + /** + * Convert an IShare to an array for OCS output + * + * @param IShare $share + * @return array + */ + protected function formatShare($share) { + $result = [ + 'id' => $share->getId(), + 'share_type' => $share->getShareType(), + 'uid_owner' => $share->getSharedBy()->getUID(), + 'displayname_owner' => $share->getSharedBy()->getDisplayName(), + 'permissions' => $share->getPermissions(), + 'stime' => $share->getShareTime(), + 'parent' => $share->getParent(), + 'expiration' => null, + 'token' => null, + ]; + + $path = $share->getPath(); + $result['path'] = $this->userFolder->getRelativePath($path->getPath()); + if ($path instanceOf \OCP\Files\Folder) { + $result['item_type'] = 'folder'; + } else { + $result['item_type'] = 'file'; + } + $result['storage_id'] = $path->getStorage()->getId(); + $result['storage'] = \OC\Files\Cache\Storage::getNumericStorageId($path->getStorage()->getId()); + $result['item_source'] = $path->getId(); + $result['file_source'] = $path->getId(); + $result['file_parent'] = $path->getParent()->getId(); + $result['file_target'] = $share->getTarget(); + + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { + $sharedWith = $share->getSharedWith(); + $result['share_with'] = $sharedWith->getUID(); + $result['share_with_displayname'] = $sharedWith->getDisplayName(); + } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { + $sharedWith = $share->getSharedWith(); + $result['share_with'] = $sharedWith->getGID(); + $result['share_with_displayname'] = $sharedWith->getGID(); + } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) { + + $result['share_with'] = $share->getPassword(); + $result['share_with_displayname'] = $share->getPassword(); + + $result['token'] = $share->getToken(); + $result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]); + + $expiration = $share->getExpirationDate(); + if ($expiration !== null) { + $result['expiration'] = $expiration->format('Y-m-d 00:00:00'); + } + + } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) { + $result['share_with'] = $share->getSharedWith(); + $result['share_with_displayname'] = $share->getSharedWith(); + $result['token'] = $share->getToken(); + } + + $result['mail_send'] = $share->getMailSend() ? 1 : 0; + + return $result; + } + + /** + * Get a specific share by id + * + * @param string $id + * @return \OC_OCS_Result + */ + public function getShare($id) { + try { + $share = $this->shareManager->getShareById($id); + } catch (\OC\Share20\Exception\ShareNotFound $e) { + return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.'); + } + + $share = $this->formatShare($share); + return new \OC_OCS_Result($share); } /** * Delete a share * - * @param int $id + * @param string $id * @return \OC_OCS_Result */ public function deleteShare($id) { diff --git a/apps/files_sharing/tests/api/share20ocstest.php b/apps/files_sharing/tests/api/share20ocstest.php index 9c4377a2a7f..f74585eb47d 100644 --- a/apps/files_sharing/tests/api/share20ocstest.php +++ b/apps/files_sharing/tests/api/share20ocstest.php @@ -39,6 +39,9 @@ class Share20OCSTest extends \Test\TestCase { /** @var OCP\Files\Folder */ private $userFolder; + /** @var OCP\IURLGenerator */ + private $urlGenerator; + /** @var OCS */ private $ocs; @@ -46,24 +49,18 @@ class Share20OCSTest extends \Test\TestCase { $this->shareManager = $this->getMockBuilder('OC\Share20\Manager') ->disableOriginalConstructor() ->getMock(); - $this->groupManager = $this->getMockBuilder('OCP\IGroupManager') - ->disableOriginalConstructor() - ->getMock(); - $this->userManager = $this->getMockBuilder('OCP\IUserManager') - ->disableOriginalConstructor() - ->getMock(); - $this->request = $this->getMockBuilder('OCP\IRequest') - ->disableOriginalConstructor() - ->getMock(); - $this->userFolder = $this->getMockBuilder('OCP\Files\Folder') - ->disableOriginalConstructor() - ->getMock(); + $this->groupManager = $this->getMock('OCP\IGroupManager'); + $this->userManager = $this->getMock('OCP\IUserManager'); + $this->request = $this->getMock('OCP\IRequest'); + $this->userFolder = $this->getMock('OCP\Files\Folder'); + $this->urlGenerator = $this->getMock('OCP\IURLGenerator'); $this->ocs = new Share20OCS($this->shareManager, $this->groupManager, $this->userManager, $this->request, - $this->userFolder); + $this->userFolder, + $this->urlGenerator); } public function testDeleteShareShareNotFound() { @@ -110,4 +107,240 @@ class Share20OCSTest extends \Test\TestCase { $expected = new \OC_OCS_Result(); $this->assertEquals($expected, $this->ocs->deleteShare(42)); } + + public function testGetGetShareNotExists() { + $this->shareManager + ->expects($this->once()) + ->method('getShareById') + ->with(42) + ->will($this->throwException(new \OC\Share20\Exception\ShareNotFound())); + + $expected = new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.'); + $this->assertEquals($expected, $this->ocs->getShare(42)); + } + + public function createShare($id, $shareType, $sharedWith, $sharedBy, $path, $permissions, + $shareTime, $expiration, $parent, $target, $mail_send, $token=null, + $password=null) { + $share = $this->getMock('OC\Share20\IShare'); + $share->method('getId')->willReturn($id); + $share->method('getShareType')->willReturn($shareType); + $share->method('getSharedWith')->willReturn($sharedWith); + $share->method('getSharedBy')->willReturn($sharedBy); + $share->method('getPath')->willReturn($path); + $share->method('getPermissions')->willReturn($permissions); + $share->method('getShareTime')->willReturn($shareTime); + $share->method('getExpirationDate')->willReturn($expiration); + $share->method('getParent')->willReturn($parent); + $share->method('getTarget')->willReturn($target); + $share->method('getMailSend')->willReturn($mail_send); + $share->method('getToken')->willReturn($token); + $share->method('getPassword')->willReturn($password); + + return $share; + } + + public function dataGetShare() { + $data = []; + + $owner = $this->getMock('OCP\IUser'); + $owner->method('getUID')->willReturn('ownerId'); + $owner->method('getDisplayName')->willReturn('ownerDisplay'); + + $user = $this->getMock('OCP\IUser'); + $user->method('getUID')->willReturn('userId'); + $user->method('getDisplayName')->willReturn('userDisplay'); + + $group = $this->getMock('OCP\IGroup'); + $group->method('getGID')->willReturn('groupId'); + + $storage = $this->getMock('OCP\Files\Storage'); + $storage->method('getId')->willReturn('STORAGE'); + + $parentFolder = $this->getMock('OCP\Files\Folder'); + $parentFolder->method('getId')->willReturn(3); + + $file = $this->getMock('OCP\Files\File'); + $file->method('getId')->willReturn(1); + $file->method('getPath')->willReturn('file'); + $file->method('getStorage')->willReturn($storage); + $file->method('getParent')->willReturn($parentFolder); + + $folder = $this->getMock('OCP\Files\Folder'); + $folder->method('getId')->willReturn(2); + $folder->method('getPath')->willReturn('folder'); + $folder->method('getStorage')->willReturn($storage); + $folder->method('getParent')->willReturn($parentFolder); + + // File shared with user + $share = $this->createShare(100, + \OCP\Share::SHARE_TYPE_USER, + $user, + $owner, + $file, + 4, + 5, + null, + 6, + 'target', + 0); + $expected = [ + 'id' => 100, + 'share_type' => \OCP\Share::SHARE_TYPE_USER, + 'share_with' => 'userId', + 'share_with_displayname' => 'userDisplay', + 'uid_owner' => 'ownerId', + 'displayname_owner' => 'ownerDisplay', + 'item_type' => 'file', + 'item_source' => 1, + 'file_source' => 1, + 'file_target' => 'target', + 'file_parent' => 3, + 'token' => null, + 'expiration' => null, + 'permissions' => 4, + 'stime' => 5, + 'parent' => 6, + 'storage_id' => 'STORAGE', + 'path' => 'file', + 'storage' => null, // HACK around static function + 'mail_send' => 0, + ]; + $data[] = [$share, $expected]; + + // Folder shared with group + $share = $this->createShare(101, + \OCP\Share::SHARE_TYPE_GROUP, + $group, + $owner, + $folder, + 4, + 5, + null, + 6, + 'target', + 0); + $expected = [ + 'id' => 101, + 'share_type' => \OCP\Share::SHARE_TYPE_GROUP, + 'share_with' => 'groupId', + 'share_with_displayname' => 'groupId', + 'uid_owner' => 'ownerId', + 'displayname_owner' => 'ownerDisplay', + 'item_type' => 'folder', + 'item_source' => 2, + 'file_source' => 2, + 'file_target' => 'target', + 'file_parent' => 3, + 'token' => null, + 'expiration' => null, + 'permissions' => 4, + 'stime' => 5, + 'parent' => 6, + 'storage_id' => 'STORAGE', + 'path' => 'folder', + 'storage' => null, // HACK around static function + 'mail_send' => 0, + ]; + $data[] = [$share, $expected]; + + // Folder shared with remote + $share = $this->createShare(101, + \OCP\Share::SHARE_TYPE_REMOTE, + 'user@remote.com', + $owner, + $folder, + 4, + 5, + null, + 6, + 'target', + 0); + $expected = [ + 'id' => 101, + 'share_type' => \OCP\Share::SHARE_TYPE_REMOTE, + 'share_with' => 'user@remote.com', + 'share_with_displayname' => 'user@remote.com', + 'uid_owner' => 'ownerId', + 'displayname_owner' => 'ownerDisplay', + 'item_type' => 'folder', + 'item_source' => 2, + 'file_source' => 2, + 'file_target' => 'target', + 'file_parent' => 3, + 'token' => null, + 'expiration' => null, + 'permissions' => 4, + 'stime' => 5, + 'parent' => 6, + 'storage_id' => 'STORAGE', + 'path' => 'folder', + 'storage' => null, // HACK around static function + 'mail_send' => 0, + ]; + $data[] = [$share, $expected]; + + // File shared by link with Expire + $expire = \DateTime::createFromFormat('Y-m-d h:i:s', '2000-01-02 01:02:03'); + $share = $this->createShare(101, + \OCP\Share::SHARE_TYPE_LINK, + null, + $owner, + $folder, + 4, + 5, + $expire, + 6, + 'target', + 0, + 'token', + 'password'); + $expected = [ + 'id' => 101, + 'share_type' => \OCP\Share::SHARE_TYPE_LINK, + 'share_with' => 'password', + 'share_with_displayname' => 'password', + 'uid_owner' => 'ownerId', + 'displayname_owner' => 'ownerDisplay', + 'item_type' => 'folder', + 'item_source' => 2, + 'file_source' => 2, + 'file_target' => 'target', + 'file_parent' => 3, + 'token' => 'token', + 'expiration' => '2000-01-02 00:00:00', + 'permissions' => 4, + 'stime' => 5, + 'parent' => 6, + 'storage_id' => 'STORAGE', + 'path' => 'folder', + 'storage' => null, // HACK around static function + 'mail_send' => 0, + 'url' => 'url', + ]; + $data[] = [$share, $expected]; + + return $data; + } + + /** + * @dataProvider dataGetShare + */ + public function testGetShare(\OC\Share20\IShare $share, array $result) { + $this->shareManager + ->expects($this->once()) + ->method('getShareById') + ->with($share->getId()) + ->willReturn($share); + + $this->userFolder + ->method('getRelativePath') + ->will($this->returnArgument(0)); + + $this->urlGenerator + ->method('linkToRouteAbsolute') + ->willReturn('url'); + + $expected = new \OC_OCS_Result($result); + $this->assertEquals($expected->getData(), $this->ocs->getShare($share->getId())->getData()); } } diff --git a/apps/provisioning_api/appinfo/routes.php b/apps/provisioning_api/appinfo/routes.php index dcf18e0e53b..22a923f5c20 100644 --- a/apps/provisioning_api/appinfo/routes.php +++ b/apps/provisioning_api/appinfo/routes.php @@ -37,7 +37,7 @@ $users = new \OCA\Provisioning_API\Users( \OC::$server->getLogger() ); API::register('get', '/cloud/users', [$users, 'getUsers'], 'provisioning_api', API::SUBADMIN_AUTH); -API::register('post', '/cloud/users', [$users, 'addUser'], 'provisioning_api', API::ADMIN_AUTH); +API::register('post', '/cloud/users', [$users, 'addUser'], 'provisioning_api', API::SUBADMIN_AUTH); API::register('get', '/cloud/users/{userid}', [$users, 'getUser'], 'provisioning_api', API::USER_AUTH); API::register('put', '/cloud/users/{userid}', [$users, 'editUser'], 'provisioning_api', API::USER_AUTH); API::register('delete', '/cloud/users/{userid}', [$users, 'deleteUser'], 'provisioning_api', API::SUBADMIN_AUTH); @@ -51,7 +51,8 @@ API::register('get', '/cloud/users/{userid}/subadmins', [$users, 'getUserSubAdmi // Groups $groups = new \OCA\Provisioning_API\Groups( \OC::$server->getGroupManager(), - \OC::$server->getUserSession() + \OC::$server->getUserSession(), + \OC::$server->getRequest() ); API::register('get', '/cloud/groups', [$groups, 'getGroups'], 'provisioning_api', API::SUBADMIN_AUTH); API::register('post', '/cloud/groups', [$groups, 'addGroup'], 'provisioning_api', API::SUBADMIN_AUTH); diff --git a/apps/provisioning_api/lib/groups.php b/apps/provisioning_api/lib/groups.php index c28db35972f..7c35caca5fd 100644 --- a/apps/provisioning_api/lib/groups.php +++ b/apps/provisioning_api/lib/groups.php @@ -37,14 +37,20 @@ class Groups{ /** @var \OCP\IUserSession */ private $userSession; + /** @var \OCP\IRequest */ + private $request; + /** * @param \OCP\IGroupManager $groupManager * @param \OCP\IUserSession $userSession + * @param \OCP\IRequest $request */ public function __construct(\OCP\IGroupManager $groupManager, - \OCP\IUserSession $userSession) { + \OCP\IUserSession $userSession, + \OCP\IRequest $request) { $this->groupManager = $groupManager; $this->userSession = $userSession; + $this->request = $request; } /** @@ -54,9 +60,16 @@ class Groups{ * @return OC_OCS_Result */ public function getGroups($parameters) { - $search = !empty($_GET['search']) ? $_GET['search'] : ''; - $limit = !empty($_GET['limit']) ? $_GET['limit'] : null; - $offset = !empty($_GET['offset']) ? $_GET['offset'] : null; + $search = $this->request->getParam('search', ''); + $limit = $this->request->getParam('limit'); + $offset = $this->request->getParam('offset'); + + if ($limit !== null) { + $limit = (int)$limit; + } + if ($offset !== null) { + $offset = (int)$offset; + } $groups = $this->groupManager->search($search, $limit, $offset); $groups = array_map(function($group) { @@ -80,21 +93,23 @@ class Groups{ return new OC_OCS_Result(null, \OCP\API::RESPOND_UNAUTHORISED); } + $groupId = $parameters['groupid']; + // Check the group exists - if(!$this->groupManager->groupExists($parameters['groupid'])) { + if(!$this->groupManager->groupExists($groupId)) { return new OC_OCS_Result(null, \OCP\API::RESPOND_NOT_FOUND, 'The requested group could not be found'); } $isSubadminOfGroup = false; - $targetGroupObject =$this->groupManager->get($parameters['groupid']); - if($targetGroupObject !== null) { - $isSubadminOfGroup =$this->groupManager->getSubAdmin()->isSubAdminofGroup($user, $targetGroupObject); + $group = $this->groupManager->get($groupId); + if ($group !== null) { + $isSubadminOfGroup =$this->groupManager->getSubAdmin()->isSubAdminofGroup($user, $group); } // Check subadmin has access to this group if($this->groupManager->isAdmin($user->getUID()) || $isSubadminOfGroup) { - $users = $this->groupManager->get($parameters['groupid'])->getUsers(); + $users = $this->groupManager->get($groupId)->getUsers(); $users = array_map(function($user) { /** @var IUser $user */ return $user->getUID(); @@ -114,7 +129,7 @@ class Groups{ */ public function addGroup($parameters) { // Validate name - $groupId = isset($_POST['groupid']) ? $_POST['groupid'] : ''; + $groupId = $this->request->getParam('groupid', ''); if( preg_match( '/[^a-zA-Z0-9 _\.@\-]/', $groupId ) || empty($groupId)){ \OCP\Util::writeLog('provisioning_api', 'Attempt made to create group using invalid characters.', \OCP\Util::ERROR); return new OC_OCS_Result(null, 101, 'Invalid group name'); diff --git a/apps/provisioning_api/lib/users.php b/apps/provisioning_api/lib/users.php index 304fe901cfd..a2568425d0f 100644 --- a/apps/provisioning_api/lib/users.php +++ b/apps/provisioning_api/lib/users.php @@ -117,19 +117,50 @@ class Users { public function addUser() { $userId = isset($_POST['userid']) ? $_POST['userid'] : null; $password = isset($_POST['password']) ? $_POST['password'] : null; + $groups = isset($_POST['groups']) ? $_POST['groups'] : null; + $user = $this->userSession->getUser(); + $isAdmin = $this->groupManager->isAdmin($user->getUID()); + $subAdminManager = $this->groupManager->getSubAdmin(); + + if (!$isAdmin && !$subAdminManager->isSubAdmin($user)) { + return new OC_OCS_Result(null, \OCP\API::RESPOND_UNAUTHORISED); + } + if($this->userManager->userExists($userId)) { $this->logger->error('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']); return new OC_OCS_Result(null, 102, 'User already exists'); + } + + if(is_array($groups)) { + foreach ($groups as $group) { + if(!$this->groupManager->groupExists($group)){ + return new OC_OCS_Result(null, 104, 'group '.$group.' does not exist'); + } + if(!$isAdmin && !$subAdminManager->isSubAdminofGroup($user, $this->groupManager->get($group))) { + return new OC_OCS_Result(null, 105, 'insufficient privileges for group '. $group); + } + } } else { - try { - $this->userManager->createUser($userId, $password); - $this->logger->info('Successful addUser call with userid: '.$_POST['userid'], ['app' => 'ocs_api']); - return new OC_OCS_Result(null, 100); - } catch (\Exception $e) { - $this->logger->error('Failed addUser attempt with exception: '.$e->getMessage(), ['app' => 'ocs_api']); - return new OC_OCS_Result(null, 101, 'Bad request'); + if(!$isAdmin) { + return new OC_OCS_Result(null, 106, 'no group specified (required for subadmins)'); } } + + try { + $newUser = $this->userManager->createUser($userId, $password); + $this->logger->info('Successful addUser call with userid: '.$userId, ['app' => 'ocs_api']); + + if (is_array($groups)) { + foreach ($groups as $group) { + $this->groupManager->get($group)->addUser($newUser); + $this->logger->info('Added userid '.$userId.' to group '.$group, ['app' => 'ocs_api']); + } + } + return new OC_OCS_Result(null, 100); + } catch (\Exception $e) { + $this->logger->error('Failed addUser attempt with exception: '.$e->getMessage(), ['app' => 'ocs_api']); + return new OC_OCS_Result(null, 101, 'Bad request'); + } } /** diff --git a/apps/provisioning_api/tests/groupstest.php b/apps/provisioning_api/tests/groupstest.php index f67ed1c36ae..7d4beb6a368 100644 --- a/apps/provisioning_api/tests/groupstest.php +++ b/apps/provisioning_api/tests/groupstest.php @@ -25,79 +25,131 @@ namespace OCA\Provisioning_API\Tests; -use OCP\IUserManager; use OCP\IGroupManager; use OCP\IUserSession; +use OCP\IRequest; -class GroupsTest extends TestCase { - /** @var IUserManager */ - protected $userManager; +class GroupsTest extends \Test\TestCase { /** @var IGroupManager */ protected $groupManager; /** @var IUserSession */ protected $userSession; + /** @var IRequest */ + protected $request; + /** @var \OC\SubAdmin */ + protected $subAdminManager; /** @var \OCA\Provisioning_API\Groups */ protected $api; protected function setup() { - parent::setup(); + $this->subAdminManager = $this->getMockBuilder('OC\SubAdmin')->disableOriginalConstructor()->getMock(); - $this->userManager = \OC::$server->getUserManager(); - $this->groupManager = \OC::$server->getGroupManager(); - $this->userSession = \OC::$server->getUserSession(); + $this->groupManager = $this->getMockBuilder('OC\Group\Manager')->disableOriginalConstructor()->getMock(); + $this->groupManager + ->method('getSubAdmin') + ->willReturn($this->subAdminManager); + + $this->userSession = $this->getMock('OCP\IUserSession'); + $this->request = $this->getMock('OCP\IRequest'); $this->api = new \OCA\Provisioning_API\Groups( $this->groupManager, - $this->userSession + $this->userSession, + $this->request ); } - public function testGetGroups() { - $groups = []; - $id = $this->getUniqueID(); + private function createGroup($gid) { + $group = $this->getMock('OCP\IGroup'); + $group + ->method('getGID') + ->willReturn($gid); + return $group; + } - for ($i=0; $i < 10; $i++) { - $groups[] = $this->groupManager->createGroup($id . '_' . $i); - } + private function createUser($uid) { + $user = $this->getMock('OCP\IUser'); + $user + ->method('getUID') + ->willReturn($uid); + return $user; + } - $_GET = []; - $result = $this->api->getGroups([]); - $this->assertInstanceOf('OC_OCS_Result', $result); - $this->assertTrue($result->succeeded()); - $this->assertCount(count($this->groupManager->search('')), $result->getData()['groups']); - $this->assertContains('admin', $result->getData()['groups']); - foreach ($groups as $group) { - $this->assertContains($group->getGID(), $result->getData()['groups']); - } - - $_GET = [ - 'search' => $id, - 'limit' => 5, - 'offset' => 2 + private function asUser() { + $user = $this->createUser('user'); + $this->userSession + ->method('getUser') + ->willReturn($user); + } + + private function asAdmin() { + $user = $this->createUser('admin'); + $this->userSession + ->method('getUser') + ->willReturn($user); + + $this->groupManager + ->method('isAdmin') + ->with('admin') + ->willReturn(true); + } + + private function asSubAdminOfGroup($group) { + $user = $this->createUser('subAdmin'); + $this->userSession + ->method('getUser') + ->willReturn($user); + + $this->subAdminManager + ->method('isSubAdminOfGroup') + ->will($this->returnCallback(function($_user, $_group) use ($user, $group) { + if ($_user === $user && $_group === $group) { + return true; + } + return false; + })); + } + + public function dataGetGroups() { + return [ + [null, null, null], + ['foo', null, null], + [null, 1, null], + [null, null, 2], + ['foo', 1, 2], ]; + } + + /** + * @dataProvider dataGetGroups + */ + public function testGetGroups($search, $limit, $offset) { + $this->request + ->expects($this->exactly(3)) + ->method('getParam') + ->will($this->returnValueMap([ + ['search', '', $search], + ['limit', null, $limit], + ['offset', null, $offset], + ])); + + $groups = [$this->createGroup('group1'), $this->createGroup('group2')]; + + $search = $search === null ? '' : $search; + + $this->groupManager + ->expects($this->once()) + ->method('search') + ->with($search, $limit, $offset) + ->willReturn($groups); + $result = $this->api->getGroups([]); $this->assertInstanceOf('OC_OCS_Result', $result); $this->assertTrue($result->succeeded()); - $this->assertCount(5, $result->getData()['groups']); - foreach (array_splice($groups, 2, 5) as $group) { - $this->assertContains($group->getGID(), $result->getData()['groups']); - } - - foreach ($groups as $group) { - $group->delete(); - } + $this->assertEquals(['group1', 'group2'], $result->getData()['groups']); } public function testGetGroupAsUser() { - - $users = $this->generateUsers(2); - $this->userSession->setUser($users[0]); - - $group = $this->groupManager->createGroup($this->getUniqueID()); - $group->addUser($users[1]); - - $result = $this->api->getGroup(array( - 'groupid' => $group->getGID(), - )); + $result = $this->api->getGroup([]); $this->assertInstanceOf('OC_OCS_Result', $result); $this->assertFalse($result->succeeded()); @@ -106,80 +158,91 @@ class GroupsTest extends TestCase { } public function testGetGroupAsSubadmin() { - - $users = $this->generateUsers(2); - $this->userSession->setUser($users[0]); - - $group = $this->groupManager->createGroup($this->getUniqueID()); - $group->addUser($users[0]); - $group->addUser($users[1]); - - $this->groupManager->getSubAdmin()->createSubAdmin($users[0], $group); + $group = $this->createGroup('group'); + $this->asSubAdminOfGroup($group); + + $this->groupManager + ->method('get') + ->with('group') + ->willReturn($group); + $this->groupManager + ->method('groupExists') + ->with('group') + ->willReturn(true); + $group + ->method('getUsers') + ->willReturn([ + $this->createUser('user1'), + $this->createUser('user2') + ]); $result = $this->api->getGroup([ - 'groupid' => $group->getGID(), + 'groupid' => 'group', ]); $this->assertInstanceOf('OC_OCS_Result', $result); $this->assertTrue($result->succeeded()); $this->assertEquals(1, sizeof($result->getData()), 'Asserting the result data array only has the "users" key'); $this->assertArrayHasKey('users', $result->getData()); - $resultData = $result->getData(); - $resultData = $resultData['users']; - - $users = array_map(function($user) { - return $user->getUID(); - }, $users); - - sort($users); - sort($resultData); - $this->assertEquals($users, $resultData); - + $this->assertEquals(['user1', 'user2'], $result->getData()['users']); } public function testGetGroupAsIrrelevantSubadmin() { - - $users = $this->generateUsers(2); - $this->userSession->setUser($users[0]); - - $group1 = $this->groupManager->createGroup($this->getUniqueID()); - $group2 = $this->groupManager->createGroup($this->getUniqueID()); - $group1->addUser($users[1]); - $group2->addUser($users[0]); - - $this->groupManager->getSubAdmin()->createSubAdmin($users[0], $group2); + $group = $this->createGroup('group'); + $otherGroup = $this->createGroup('otherGroup'); + $this->asSubAdminOfGroup($otherGroup); + + $this->groupManager + ->method('get') + ->with('group') + ->willReturn($group); + $this->groupManager + ->method('groupExists') + ->with('group') + ->willReturn(true); $result = $this->api->getGroup([ - 'groupid' => $group1->getGID(), + 'groupid' => 'group', ]); $this->assertInstanceOf('OC_OCS_Result', $result); $this->assertFalse($result->succeeded()); $this->assertEquals(\OCP\API::RESPOND_UNAUTHORISED, $result->getStatusCode()); - } public function testGetGroupAsAdmin() { - - $users = $this->generateUsers(2); - $this->userSession->setUser($users[0]); - - $group = $this->groupManager->createGroup($this->getUniqueID()); - - $group->addUser($users[1]); - $this->groupManager->get('admin')->addUser($users[0]); + $group = $this->createGroup('group'); + $this->asAdmin(); + + $this->groupManager + ->method('get') + ->with('group') + ->willReturn($group); + $this->groupManager + ->method('groupExists') + ->with('group') + ->willReturn(true); + $group + ->method('getUsers') + ->willReturn([ + $this->createUser('user1'), + $this->createUser('user2') + ]); $result = $this->api->getGroup([ - 'groupid' => $group->getGID(), + 'groupid' => 'group', ]); $this->assertInstanceOf('OC_OCS_Result', $result); $this->assertTrue($result->succeeded()); - $this->assertEquals(['users' => [$users[1]->getUID()]], $result->getData()); - + $this->assertEquals(1, sizeof($result->getData()), 'Asserting the result data array only has the "users" key'); + $this->assertArrayHasKey('users', $result->getData()); + $this->assertEquals(['user1', 'user2'], $result->getData()['users']); } public function testGetGroupNonExisting() { + $this->asUser(); + $result = $this->api->getGroup([ 'groupid' => $this->getUniqueId() ]); @@ -190,35 +253,72 @@ class GroupsTest extends TestCase { $this->assertEquals('The requested group could not be found', $result->getMeta()['message']); } + public function testGetSubAdminsOfGroupsNotExists() { + $result = $this->api->getSubAdminsOfGroup([ + 'groupid' => 'NonExistingGroup', + ]); + + $this->assertInstanceOf('OC_OCS_Result', $result); + $this->assertFalse($result->succeeded()); + $this->assertEquals(101, $result->getStatusCode()); + $this->assertEquals('Group does not exist', $result->getMeta()['message']); + } + public function testGetSubAdminsOfGroup() { - $user1 = $this->generateUsers(); - $user2 = $this->generateUsers(); - $this->userSession->setUser($user1); - $this->groupManager->get('admin')->addUser($user1); - $group1 = $this->groupManager->createGroup($this->getUniqueID()); - $this->groupManager->getSubAdmin()->createSubAdmin($user2, $group1); + $group = $this->createGroup('GroupWithSubAdmins'); + $this->groupManager + ->method('get') + ->with('GroupWithSubAdmins') + ->willReturn($group); + + $this->subAdminManager + ->expects($this->once()) + ->method('getGroupsSubAdmins') + ->with($group) + ->willReturn([ + $this->createUser('SubAdmin1'), + $this->createUser('SubAdmin2'), + ]); + $result = $this->api->getSubAdminsOfGroup([ - 'groupid' => $group1->getGID(), + 'groupid' => 'GroupWithSubAdmins', ]); + $this->assertInstanceOf('OC_OCS_Result', $result); $this->assertTrue($result->succeeded()); - $data = $result->getData(); - $this->assertEquals($user2->getUID(), reset($data)); - $group1->delete(); + $this->assertEquals(['SubAdmin1', 'SubAdmin2'], $result->getData()); + } + + public function testGetSubAdminsOfGroupEmptyList() { + $group = $this->createGroup('GroupWithOutSubAdmins'); + $this->groupManager + ->method('get') + ->with('GroupWithOutSubAdmins') + ->willReturn($group); + + $this->subAdminManager + ->expects($this->once()) + ->method('getGroupsSubAdmins') + ->with($group) + ->willReturn([ + ]); - $user1 = $this->generateUsers(); - $this->userSession->setUser($user1); - $this->groupManager->get('admin')->addUser($user1); $result = $this->api->getSubAdminsOfGroup([ - 'groupid' => $this->getUniqueID(), + 'groupid' => 'GroupWithOutSubAdmins', ]); + $this->assertInstanceOf('OC_OCS_Result', $result); $this->assertFalse($result->succeeded()); - $this->assertEquals(101, $result->getStatusCode()); + $this->assertEquals(102, $result->getStatusCode()); + $this->assertEquals('Unknown error occured', $result->getMeta()['message']); } public function testAddGroupEmptyGroup() { - $_POST = []; + $this->request + ->method('getParam') + ->with('groupid') + ->willReturn(''); + $result = $this->api->addGroup([]); $this->assertInstanceOf('OC_OCS_Result', $result); @@ -228,40 +328,47 @@ class GroupsTest extends TestCase { } public function testAddGroupExistingGroup() { - $group = $this->groupManager->createGroup($this->getUniqueID()); + $this->request + ->method('getParam') + ->with('groupid') + ->willReturn('ExistingGroup'); + + $this->groupManager + ->method('groupExists') + ->with('ExistingGroup') + ->willReturn(true); - $_POST = [ - 'groupid' => $group->getGID() - ]; $result = $this->api->addGroup([]); $this->assertInstanceOf('OC_OCS_Result', $result); $this->assertFalse($result->succeeded()); $this->assertEquals(102, $result->getStatusCode()); - - $group->delete(); } public function testAddGroup() { - $group = $this->getUniqueId(); + $this->request + ->method('getParam') + ->with('groupid') + ->willReturn('NewGroup'); - $_POST = [ - 'groupid' => $group - ]; + $this->groupManager + ->method('groupExists') + ->with('NewGroup') + ->willReturn(false); + + $this->groupManager + ->expects($this->once()) + ->method('createGroup') + ->with('NewGroup'); $result = $this->api->addGroup([]); $this->assertInstanceOf('OC_OCS_Result', $result); $this->assertTrue($result->succeeded()); - $this->assertTrue($this->groupManager->groupExists($group)); - - $this->groupManager->get($group)->delete(); } public function testDeleteGroupNonExisting() { - $group = $this->getUniqueId(); - $result = $this->api->deleteGroup([ - 'groupid' => $group + 'groupid' => 'NonExistingGroup' ]); $this->assertInstanceOf('OC_OCS_Result', $result); $this->assertFalse($result->succeeded()); @@ -269,6 +376,11 @@ class GroupsTest extends TestCase { } public function testDeleteAdminGroup() { + $this->groupManager + ->method('groupExists') + ->with('admin') + ->willReturn('true'); + $result = $this->api->deleteGroup([ 'groupid' => 'admin' ]); @@ -278,13 +390,25 @@ class GroupsTest extends TestCase { } public function testDeleteGroup() { - $group = $this->groupManager->createGroup($this->getUniqueId()); + $this->groupManager + ->method('groupExists') + ->with('ExistingGroup') + ->willReturn('true'); + + $group = $this->createGroup('ExistingGroup'); + $this->groupManager + ->method('get') + ->with('ExistingGroup') + ->willReturn($group); + $group + ->expects($this->once()) + ->method('delete') + ->willReturn(true); $result = $this->api->deleteGroup([ - 'groupid' => $group->getGID() + 'groupid' => 'ExistingGroup', ]); $this->assertInstanceOf('OC_OCS_Result', $result); $this->assertTrue($result->succeeded()); - $this->assertFalse($this->groupManager->groupExists($group->getGID())); } } diff --git a/apps/provisioning_api/tests/userstest.php b/apps/provisioning_api/tests/userstest.php index ba4ed8a2e2f..63180eb3472 100644 --- a/apps/provisioning_api/tests/userstest.php +++ b/apps/provisioning_api/tests/userstest.php @@ -218,11 +218,95 @@ class UsersTest extends OriginalTest { ->expects($this->once()) ->method('error') ->with('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']); + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('adminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('adminUser') + ->willReturn(true); $expected = new \OC_OCS_Result(null, 102, 'User already exists'); $this->assertEquals($expected, $this->api->addUser()); } + public function testAddUserNonExistingGroup() { + $_POST['userid'] = 'NewUser'; + $_POST['groups'] = ['NonExistingGroup']; + $this->userManager + ->expects($this->once()) + ->method('userExists') + ->with('NewUser') + ->willReturn(false); + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('adminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('adminUser') + ->willReturn(true); + $this->groupManager + ->expects($this->once()) + ->method('groupExists') + ->with('NonExistingGroup') + ->willReturn(false); + + $expected = new \OC_OCS_Result(null, 104, 'group NonExistingGroup does not exist'); + $this->assertEquals($expected, $this->api->addUser()); + } + + public function testAddUserExistingGroupNonExistingGroup() { + $_POST['userid'] = 'NewUser'; + $_POST['groups'] = ['ExistingGroup', 'NonExistingGroup']; + $this->userManager + ->expects($this->once()) + ->method('userExists') + ->with('NewUser') + ->willReturn(false); + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('adminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('adminUser') + ->willReturn(true); + $this->groupManager + ->expects($this->exactly(2)) + ->method('groupExists') + ->withConsecutive( + ['ExistingGroup'], + ['NonExistingGroup'] + ) + ->will($this->returnValueMap([ + ['ExistingGroup', true], + ['NonExistingGroup', false] + ])); + + $expected = new \OC_OCS_Result(null, 104, 'group NonExistingGroup does not exist'); + $this->assertEquals($expected, $this->api->addUser()); + } + public function testAddUserSuccessful() { $_POST['userid'] = 'NewUser'; $_POST['password'] = 'PasswordOfTheNewUser'; @@ -239,6 +323,76 @@ class UsersTest extends OriginalTest { ->expects($this->once()) ->method('info') ->with('Successful addUser call with userid: NewUser', ['app' => 'ocs_api']); + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('adminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('adminUser') + ->willReturn(true); + + $expected = new \OC_OCS_Result(null, 100); + $this->assertEquals($expected, $this->api->addUser()); + } + + public function testAddUserExistingGroup() { + $_POST['userid'] = 'NewUser'; + $_POST['password'] = 'PasswordOfTheNewUser'; + $_POST['groups'] = ['ExistingGroup']; + $this->userManager + ->expects($this->once()) + ->method('userExists') + ->with('NewUser') + ->willReturn(false); + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('adminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('adminUser') + ->willReturn(true); + $this->groupManager + ->expects($this->once()) + ->method('groupExists') + ->with('ExistingGroup') + ->willReturn(true); + $user = $this->getMock('\OCP\IUser'); + $this->userManager + ->expects($this->once()) + ->method('createUser') + ->with('NewUser', 'PasswordOfTheNewUser') + ->willReturn($user); + $group = $this->getMock('\OCP\IGroup'); + $group + ->expects($this->once()) + ->method('addUser') + ->with($user); + $this->groupManager + ->expects($this->once()) + ->method('get') + ->with('ExistingGroup') + ->willReturn($group); + $this->logger + ->expects($this->exactly(2)) + ->method('info') + ->withConsecutive( + ['Successful addUser call with userid: NewUser', ['app' => 'ocs_api']], + ['Added userid NewUser to group ExistingGroup', ['app' => 'ocs_api']] + ); $expected = new \OC_OCS_Result(null, 100); $this->assertEquals($expected, $this->api->addUser()); @@ -261,11 +415,238 @@ class UsersTest extends OriginalTest { ->expects($this->once()) ->method('error') ->with('Failed addUser attempt with exception: User backend not found.', ['app' => 'ocs_api']); + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('adminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('adminUser') + ->willReturn(true); $expected = new \OC_OCS_Result(null, 101, 'Bad request'); $this->assertEquals($expected, $this->api->addUser()); } + public function testAddUserAsRegularUser() { + $_POST['userid'] = 'NewUser'; + $_POST['password'] = 'PasswordOfTheNewUser'; + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('regularUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('regularUser') + ->willReturn(false); + $subAdminManager = $this->getMockBuilder('\OC\Subadmin') + ->disableOriginalConstructor()->getMock(); + $subAdminManager + ->expects($this->once()) + ->method('isSubAdmin') + ->with($loggedInUser) + ->willReturn(false); + $this->groupManager + ->expects($this->once()) + ->method('getSubAdmin') + ->with() + ->willReturn($subAdminManager); + + $expected = new \OC_OCS_Result(null, \OCP\API::RESPOND_UNAUTHORISED); + $this->assertEquals($expected, $this->api->addUser()); + } + + public function testAddUserAsSubAdminNoGroup() { + $_POST['userid'] = 'NewUser'; + $_POST['password'] = 'PasswordOfTheNewUser'; + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('regularUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('regularUser') + ->willReturn(false); + $subAdminManager = $this->getMockBuilder('\OC\Subadmin') + ->disableOriginalConstructor()->getMock(); + $subAdminManager + ->expects($this->once()) + ->method('isSubAdmin') + ->with($loggedInUser) + ->willReturn(true); + $this->groupManager + ->expects($this->once()) + ->method('getSubAdmin') + ->with() + ->willReturn($subAdminManager); + + $expected = new \OC_OCS_Result(null, 106, 'no group specified (required for subadmins)'); + $this->assertEquals($expected, $this->api->addUser()); + } + + public function testAddUserAsSubAdminValidGroupNotSubAdmin() { + $_POST['userid'] = 'NewUser'; + $_POST['password'] = 'PasswordOfTheNewUser'; + $_POST['groups'] = ['ExistingGroup']; + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('regularUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('regularUser') + ->willReturn(false); + $existingGroup = $this->getMock('\OCP\IGroup'); + $this->groupManager + ->expects($this->once()) + ->method('get') + ->with('ExistingGroup') + ->willReturn($existingGroup); + $subAdminManager = $this->getMockBuilder('\OC\Subadmin') + ->disableOriginalConstructor()->getMock(); + $subAdminManager + ->expects($this->once()) + ->method('isSubAdmin') + ->with($loggedInUser) + ->willReturn(true); + $subAdminManager + ->expects($this->once()) + ->method('isSubAdminOfGroup') + ->with($loggedInUser, $existingGroup) + ->wilLReturn(false); + $this->groupManager + ->expects($this->once()) + ->method('getSubAdmin') + ->with() + ->willReturn($subAdminManager); + $this->groupManager + ->expects($this->once()) + ->method('groupExists') + ->with('ExistingGroup') + ->willReturn(true); + + $expected = new \OC_OCS_Result(null, 105, 'insufficient privileges for group ExistingGroup'); + $this->assertEquals($expected, $this->api->addUser()); + } + + public function testAddUserAsSubAdminExistingGroups() { + $_POST['userid'] = 'NewUser'; + $_POST['password'] = 'PasswordOfTheNewUser'; + $_POST['groups'] = ['ExistingGroup1', 'ExistingGroup2']; + $this->userManager + ->expects($this->once()) + ->method('userExists') + ->with('NewUser') + ->willReturn(false); + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('subAdminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('subAdminUser') + ->willReturn(false); + $this->groupManager + ->expects($this->exactly(2)) + ->method('groupExists') + ->withConsecutive( + ['ExistingGroup1'], + ['ExistingGroup2'] + ) + ->willReturn(true); + $user = $this->getMock('\OCP\IUser'); + $this->userManager + ->expects($this->once()) + ->method('createUser') + ->with('NewUser', 'PasswordOfTheNewUser') + ->willReturn($user); + $existingGroup1 = $this->getMock('\OCP\IGroup'); + $existingGroup2 = $this->getMock('\OCP\IGroup'); + $existingGroup1 + ->expects($this->once()) + ->method('addUser') + ->with($user); + $existingGroup2 + ->expects($this->once()) + ->method('addUser') + ->with($user); + $this->groupManager + ->expects($this->exactly(4)) + ->method('get') + ->withConsecutive( + ['ExistingGroup1'], + ['ExistingGroup2'], + ['ExistingGroup1'], + ['ExistingGroup2'] + ) + ->will($this->returnValueMap([ + ['ExistingGroup1', $existingGroup1], + ['ExistingGroup2', $existingGroup2] + ])); + $this->logger + ->expects($this->exactly(3)) + ->method('info') + ->withConsecutive( + ['Successful addUser call with userid: NewUser', ['app' => 'ocs_api']], + ['Added userid NewUser to group ExistingGroup1', ['app' => 'ocs_api']], + ['Added userid NewUser to group ExistingGroup2', ['app' => 'ocs_api']] + ); + $subAdminManager = $this->getMockBuilder('\OC\Subadmin') + ->disableOriginalConstructor()->getMock(); + $this->groupManager + ->expects($this->once()) + ->method('getSubAdmin') + ->willReturn($subAdminManager); + $subAdminManager + ->expects($this->once()) + ->method('isSubAdmin') + ->with($loggedInUser) + ->willReturn(true); + $subAdminManager + ->expects($this->exactly(2)) + ->method('isSubAdminOfGroup') + ->withConsecutive( + [$loggedInUser, $existingGroup1], + [$loggedInUser, $existingGroup2] + ) + ->wilLReturn(true); + + + $expected = new \OC_OCS_Result(null, 100); + $this->assertEquals($expected, $this->api->addUser()); + } + + public function testGetUserNotLoggedIn() { $this->userSession ->expects($this->once()) diff --git a/apps/user_ldap/l10n/cs_CZ.js b/apps/user_ldap/l10n/cs_CZ.js index 6aa15ebc918..e78755719b7 100644 --- a/apps/user_ldap/l10n/cs_CZ.js +++ b/apps/user_ldap/l10n/cs_CZ.js @@ -24,6 +24,7 @@ OC.L10N.register( "Could not detect Base DN, please enter it manually." : "Nelze automaticky detekovat Base DN, zadejte prosím ručně.", "{nthServer}. Server" : "{nthServer}. Server", "No object found in the given Base DN. Please revise." : "V zadané Base DN nebyl objekt nalezen. Ověřte.", + "More than 1,000 directory entries available." : "Je dostupných více než 1000 adresářů.", " entries available within the provided Base DN" : "záznamů dostupných v zadané Base DN", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Došlo k chybě. Ověře prosím Base DN společně s nastavením připojení a přihlašovacími údaji.", "Do you really want to delete the current Server Configuration?" : "Opravdu si přejete smazat současné nastavení serveru?", diff --git a/apps/user_ldap/l10n/cs_CZ.json b/apps/user_ldap/l10n/cs_CZ.json index a2eae7dae20..37e56cda1a7 100644 --- a/apps/user_ldap/l10n/cs_CZ.json +++ b/apps/user_ldap/l10n/cs_CZ.json @@ -22,6 +22,7 @@ "Could not detect Base DN, please enter it manually." : "Nelze automaticky detekovat Base DN, zadejte prosím ručně.", "{nthServer}. Server" : "{nthServer}. Server", "No object found in the given Base DN. Please revise." : "V zadané Base DN nebyl objekt nalezen. Ověřte.", + "More than 1,000 directory entries available." : "Je dostupných více než 1000 adresářů.", " entries available within the provided Base DN" : "záznamů dostupných v zadané Base DN", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Došlo k chybě. Ověře prosím Base DN společně s nastavením připojení a přihlašovacími údaji.", "Do you really want to delete the current Server Configuration?" : "Opravdu si přejete smazat současné nastavení serveru?", diff --git a/apps/user_ldap/l10n/el.js b/apps/user_ldap/l10n/el.js index d8f825b8288..7ea629e673d 100644 --- a/apps/user_ldap/l10n/el.js +++ b/apps/user_ldap/l10n/el.js @@ -24,6 +24,7 @@ OC.L10N.register( "Could not detect Base DN, please enter it manually." : "Αδυναμία ανίχνευσης Base DN, παρακαλώ να το εισάγετε χειροκίνητα.", "{nthServer}. Server" : "{nthServer}. Διακομιστής", "No object found in the given Base DN. Please revise." : "Δεν βρέθηκε αντικείμενο στο δηλωθέν Base DN. Παρακαλώ αναθεωρήστε.", + "More than 1,000 directory entries available." : "Είναι διαθέσιμες περισσότερες από 1.000 εγγραφές καταλόγου.", " entries available within the provided Base DN" : "διαθέσιμες καταχωρήσεις εντός του δηλωθέντος ", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Παρουσιάστηκε σφάλμα. Παρακαλούμε ελέγξτε το Base DN καθώς και τις ρυθμίσεις και τα διαπιστευτήρια σύνδεσης.", "Do you really want to delete the current Server Configuration?" : "Θέλετε να διαγράψετε τις τρέχουσες ρυθμίσεις του διακομιστή;", diff --git a/apps/user_ldap/l10n/el.json b/apps/user_ldap/l10n/el.json index 142ca58d844..338b0b8bad9 100644 --- a/apps/user_ldap/l10n/el.json +++ b/apps/user_ldap/l10n/el.json @@ -22,6 +22,7 @@ "Could not detect Base DN, please enter it manually." : "Αδυναμία ανίχνευσης Base DN, παρακαλώ να το εισάγετε χειροκίνητα.", "{nthServer}. Server" : "{nthServer}. Διακομιστής", "No object found in the given Base DN. Please revise." : "Δεν βρέθηκε αντικείμενο στο δηλωθέν Base DN. Παρακαλώ αναθεωρήστε.", + "More than 1,000 directory entries available." : "Είναι διαθέσιμες περισσότερες από 1.000 εγγραφές καταλόγου.", " entries available within the provided Base DN" : "διαθέσιμες καταχωρήσεις εντός του δηλωθέντος ", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Παρουσιάστηκε σφάλμα. Παρακαλούμε ελέγξτε το Base DN καθώς και τις ρυθμίσεις και τα διαπιστευτήρια σύνδεσης.", "Do you really want to delete the current Server Configuration?" : "Θέλετε να διαγράψετε τις τρέχουσες ρυθμίσεις του διακομιστή;", diff --git a/apps/user_ldap/l10n/fi_FI.js b/apps/user_ldap/l10n/fi_FI.js index 5091cb1d88e..96ed6a00c7d 100644 --- a/apps/user_ldap/l10n/fi_FI.js +++ b/apps/user_ldap/l10n/fi_FI.js @@ -22,6 +22,8 @@ OC.L10N.register( "Available groups" : "Käytettävissä olevat ryhmät", "Selected groups" : "Valitut ryhmät", "LDAP Filter:" : "LDAP-suodatin:", + "LDAP / AD Username:" : "LDAP-/AD-käyttäjätunnus:", + "LDAP / AD Email Address:" : "LDAP-/AD-sähköpostiosoite:", "Verify settings" : "Vahvista asetukset", "1. Server" : "1. Palvelin", "%s. Server:" : "%s. Palvelin:", @@ -34,6 +36,7 @@ OC.L10N.register( "Password" : "Salasana", "For anonymous access, leave DN and Password empty." : "Jos haluat mahdollistaa anonyymin pääsyn, jätä DN ja Salasana tyhjäksi ", "You can specify Base DN for users and groups in the Advanced tab" : "Voit määrittää käyttäjien ja ryhmien oletus DN:n (distinguished name) 'tarkemmat asetukset'-välilehdeltä ", + "Verify settings and count users" : "Vahvista asetukset ja laske käyttäjät", "Saving" : "Tallennetaan", "Back" : "Takaisin", "Continue" : "Jatka", diff --git a/apps/user_ldap/l10n/fi_FI.json b/apps/user_ldap/l10n/fi_FI.json index 54e12650166..e34fefaf93d 100644 --- a/apps/user_ldap/l10n/fi_FI.json +++ b/apps/user_ldap/l10n/fi_FI.json @@ -20,6 +20,8 @@ "Available groups" : "Käytettävissä olevat ryhmät", "Selected groups" : "Valitut ryhmät", "LDAP Filter:" : "LDAP-suodatin:", + "LDAP / AD Username:" : "LDAP-/AD-käyttäjätunnus:", + "LDAP / AD Email Address:" : "LDAP-/AD-sähköpostiosoite:", "Verify settings" : "Vahvista asetukset", "1. Server" : "1. Palvelin", "%s. Server:" : "%s. Palvelin:", @@ -32,6 +34,7 @@ "Password" : "Salasana", "For anonymous access, leave DN and Password empty." : "Jos haluat mahdollistaa anonyymin pääsyn, jätä DN ja Salasana tyhjäksi ", "You can specify Base DN for users and groups in the Advanced tab" : "Voit määrittää käyttäjien ja ryhmien oletus DN:n (distinguished name) 'tarkemmat asetukset'-välilehdeltä ", + "Verify settings and count users" : "Vahvista asetukset ja laske käyttäjät", "Saving" : "Tallennetaan", "Back" : "Takaisin", "Continue" : "Jatka", diff --git a/apps/user_ldap/l10n/fr.js b/apps/user_ldap/l10n/fr.js index 4a7b2631b79..a013589cff2 100644 --- a/apps/user_ldap/l10n/fr.js +++ b/apps/user_ldap/l10n/fr.js @@ -24,6 +24,7 @@ OC.L10N.register( "Could not detect Base DN, please enter it manually." : "Impossible de détecter le DN de base, veuillez le spécifier manuellement", "{nthServer}. Server" : "{nthServer}. Serveur", "No object found in the given Base DN. Please revise." : "Aucun objet trouvé dans le DN de base spécifié. Veuillez le vérifier.", + "More than 1,000 directory entries available." : "Il y a plus de 1 000 entrées de répertoire disponibles.", " entries available within the provided Base DN" : "entrées disponibles dans le DN de base spécifié", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Une erreur est survenue. Veuillez vérifier le DN de base, ainsi que les paramètres de connexion et les informations d'identification", "Do you really want to delete the current Server Configuration?" : "Êtes-vous sûr de vouloir effacer la configuration serveur actuelle ?", diff --git a/apps/user_ldap/l10n/fr.json b/apps/user_ldap/l10n/fr.json index 344bbaf7282..0b6c076f0d3 100644 --- a/apps/user_ldap/l10n/fr.json +++ b/apps/user_ldap/l10n/fr.json @@ -22,6 +22,7 @@ "Could not detect Base DN, please enter it manually." : "Impossible de détecter le DN de base, veuillez le spécifier manuellement", "{nthServer}. Server" : "{nthServer}. Serveur", "No object found in the given Base DN. Please revise." : "Aucun objet trouvé dans le DN de base spécifié. Veuillez le vérifier.", + "More than 1,000 directory entries available." : "Il y a plus de 1 000 entrées de répertoire disponibles.", " entries available within the provided Base DN" : "entrées disponibles dans le DN de base spécifié", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Une erreur est survenue. Veuillez vérifier le DN de base, ainsi que les paramètres de connexion et les informations d'identification", "Do you really want to delete the current Server Configuration?" : "Êtes-vous sûr de vouloir effacer la configuration serveur actuelle ?", diff --git a/apps/user_ldap/l10n/it.js b/apps/user_ldap/l10n/it.js index 88a5ceea447..8bb42e1a72a 100644 --- a/apps/user_ldap/l10n/it.js +++ b/apps/user_ldap/l10n/it.js @@ -24,6 +24,7 @@ OC.L10N.register( "Could not detect Base DN, please enter it manually." : "Impossibile rilevare il DN base, digitalo manualmente.", "{nthServer}. Server" : "{nthServer}. server", "No object found in the given Base DN. Please revise." : "Nessun oggetto trovato nel DN base specificato. Controlla.", + "More than 1,000 directory entries available." : "Più di 1.000 cartelle disponibili.", " entries available within the provided Base DN" : "voci disponibili all'interno del DN base", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Si è verificato un errore. Controlla il DN base, così come le impostazioni di connessione e le credenziali.", "Do you really want to delete the current Server Configuration?" : "Vuoi davvero eliminare la configurazione attuale del server?", diff --git a/apps/user_ldap/l10n/it.json b/apps/user_ldap/l10n/it.json index cb8f6b11d73..73234261016 100644 --- a/apps/user_ldap/l10n/it.json +++ b/apps/user_ldap/l10n/it.json @@ -22,6 +22,7 @@ "Could not detect Base DN, please enter it manually." : "Impossibile rilevare il DN base, digitalo manualmente.", "{nthServer}. Server" : "{nthServer}. server", "No object found in the given Base DN. Please revise." : "Nessun oggetto trovato nel DN base specificato. Controlla.", + "More than 1,000 directory entries available." : "Più di 1.000 cartelle disponibili.", " entries available within the provided Base DN" : "voci disponibili all'interno del DN base", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Si è verificato un errore. Controlla il DN base, così come le impostazioni di connessione e le credenziali.", "Do you really want to delete the current Server Configuration?" : "Vuoi davvero eliminare la configurazione attuale del server?", diff --git a/apps/user_ldap/l10n/ja.js b/apps/user_ldap/l10n/ja.js index 3ba8bd8f2f3..e138c46e08e 100644 --- a/apps/user_ldap/l10n/ja.js +++ b/apps/user_ldap/l10n/ja.js @@ -24,6 +24,7 @@ OC.L10N.register( "Could not detect Base DN, please enter it manually." : "ベース DN を検出できませんでした。手動で入力してください。", "{nthServer}. Server" : "{nthServer}. サーバー", "No object found in the given Base DN. Please revise." : "指定されたベース DN でオブジェクトを見つけることができませんでした。修正をお願いします。", + "More than 1,000 directory entries available." : "1,000以上のディレクトリエントリが利用可能です。", " entries available within the provided Base DN" : "入力されたベースDNでエントリーが利用可能", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "エラーが発生しました。ベースDNをチェックし、接続設定と権限についても同様に確認してください。", "Do you really want to delete the current Server Configuration?" : "現在のサーバー設定を本当に削除してもよろしいですか?", diff --git a/apps/user_ldap/l10n/ja.json b/apps/user_ldap/l10n/ja.json index 64d40cd8e4a..ef69c48adcc 100644 --- a/apps/user_ldap/l10n/ja.json +++ b/apps/user_ldap/l10n/ja.json @@ -22,6 +22,7 @@ "Could not detect Base DN, please enter it manually." : "ベース DN を検出できませんでした。手動で入力してください。", "{nthServer}. Server" : "{nthServer}. サーバー", "No object found in the given Base DN. Please revise." : "指定されたベース DN でオブジェクトを見つけることができませんでした。修正をお願いします。", + "More than 1,000 directory entries available." : "1,000以上のディレクトリエントリが利用可能です。", " entries available within the provided Base DN" : "入力されたベースDNでエントリーが利用可能", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "エラーが発生しました。ベースDNをチェックし、接続設定と権限についても同様に確認してください。", "Do you really want to delete the current Server Configuration?" : "現在のサーバー設定を本当に削除してもよろしいですか?", diff --git a/apps/user_ldap/l10n/nl.js b/apps/user_ldap/l10n/nl.js index f546cfd8150..27f6dd9ffc7 100644 --- a/apps/user_ldap/l10n/nl.js +++ b/apps/user_ldap/l10n/nl.js @@ -24,6 +24,7 @@ OC.L10N.register( "Could not detect Base DN, please enter it manually." : "Kon basis DN niet vaststellen, voer de gegevens handmatig in.", "{nthServer}. Server" : "{nthServer}. Server", "No object found in the given Base DN. Please revise." : "Geen object gevonden in de basis DN. Review instellingen.", + "More than 1,000 directory entries available." : "Meer dan 1000 directory namen beschikbaar.", " entries available within the provided Base DN" : "accounts beschikbaar binnen de provider Basis DN", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Er trad een fout op. Controleer de Basis DN en de verbindingsinstellingen en inloggegevens.", "Do you really want to delete the current Server Configuration?" : "Wilt u werkelijk de huidige Serverconfiguratie verwijderen?", diff --git a/apps/user_ldap/l10n/nl.json b/apps/user_ldap/l10n/nl.json index fc58e43347d..c98d7aa64dc 100644 --- a/apps/user_ldap/l10n/nl.json +++ b/apps/user_ldap/l10n/nl.json @@ -22,6 +22,7 @@ "Could not detect Base DN, please enter it manually." : "Kon basis DN niet vaststellen, voer de gegevens handmatig in.", "{nthServer}. Server" : "{nthServer}. Server", "No object found in the given Base DN. Please revise." : "Geen object gevonden in de basis DN. Review instellingen.", + "More than 1,000 directory entries available." : "Meer dan 1000 directory namen beschikbaar.", " entries available within the provided Base DN" : "accounts beschikbaar binnen de provider Basis DN", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Er trad een fout op. Controleer de Basis DN en de verbindingsinstellingen en inloggegevens.", "Do you really want to delete the current Server Configuration?" : "Wilt u werkelijk de huidige Serverconfiguratie verwijderen?", diff --git a/apps/user_ldap/l10n/pt_BR.js b/apps/user_ldap/l10n/pt_BR.js index 3254610be2a..e027c930ceb 100644 --- a/apps/user_ldap/l10n/pt_BR.js +++ b/apps/user_ldap/l10n/pt_BR.js @@ -24,6 +24,7 @@ OC.L10N.register( "Could not detect Base DN, please enter it manually." : "Não foi possível detectar a Base DN, por favor entre manualmente.", "{nthServer}. Server" : "Servidor {nthServer}.", "No object found in the given Base DN. Please revise." : "Nenhum objeto encontrado ba Base DN informada. Por favor revise.", + "More than 1,000 directory entries available." : "Mais de 1.000 entradas disponíveis no diretório.", " entries available within the provided Base DN" : "entradas disponíveis na Base DN disponibilizada", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Um erro ocorreu. Por favor verifique a Base DN, e também a conexção e credenciais.", "Do you really want to delete the current Server Configuration?" : "Você quer realmente deletar as atuais Configurações de Servidor?", diff --git a/apps/user_ldap/l10n/pt_BR.json b/apps/user_ldap/l10n/pt_BR.json index de03f9778d0..8251fa082a6 100644 --- a/apps/user_ldap/l10n/pt_BR.json +++ b/apps/user_ldap/l10n/pt_BR.json @@ -22,6 +22,7 @@ "Could not detect Base DN, please enter it manually." : "Não foi possível detectar a Base DN, por favor entre manualmente.", "{nthServer}. Server" : "Servidor {nthServer}.", "No object found in the given Base DN. Please revise." : "Nenhum objeto encontrado ba Base DN informada. Por favor revise.", + "More than 1,000 directory entries available." : "Mais de 1.000 entradas disponíveis no diretório.", " entries available within the provided Base DN" : "entradas disponíveis na Base DN disponibilizada", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Um erro ocorreu. Por favor verifique a Base DN, e também a conexção e credenciais.", "Do you really want to delete the current Server Configuration?" : "Você quer realmente deletar as atuais Configurações de Servidor?", diff --git a/apps/user_ldap/l10n/sq.js b/apps/user_ldap/l10n/sq.js index 4ec40ef5957..4f0d1d3697c 100644 --- a/apps/user_ldap/l10n/sq.js +++ b/apps/user_ldap/l10n/sq.js @@ -24,6 +24,7 @@ OC.L10N.register( "Could not detect Base DN, please enter it manually." : "S’u zbulua dot DN Bazë, ju lutemi, jepeni dorazi.", "{nthServer}. Server" : "{nthServer}. Shërbyes", "No object found in the given Base DN. Please revise." : "Në DN Bazë të dhën s’u gjet objekt. Ju lutemi, rishikojeni.", + "More than 1,000 directory entries available." : "Më shumë se 1000 zëra të gatshëm.", " entries available within the provided Base DN" : " zëra të gatshëm brenda DN-së Bazë të dhënë", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Ndodhi një gabim. Ju lutemi, kontrolloni DN-në Bazë, sie dhe rregullimet për lidhjen dhe kredencialet.", "Do you really want to delete the current Server Configuration?" : "Doni vërtet të fshihet Formësimi i tanishëm i Shërbyesit?", diff --git a/apps/user_ldap/l10n/sq.json b/apps/user_ldap/l10n/sq.json index 2e50290f18c..6045b61f57d 100644 --- a/apps/user_ldap/l10n/sq.json +++ b/apps/user_ldap/l10n/sq.json @@ -22,6 +22,7 @@ "Could not detect Base DN, please enter it manually." : "S’u zbulua dot DN Bazë, ju lutemi, jepeni dorazi.", "{nthServer}. Server" : "{nthServer}. Shërbyes", "No object found in the given Base DN. Please revise." : "Në DN Bazë të dhën s’u gjet objekt. Ju lutemi, rishikojeni.", + "More than 1,000 directory entries available." : "Më shumë se 1000 zëra të gatshëm.", " entries available within the provided Base DN" : " zëra të gatshëm brenda DN-së Bazë të dhënë", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Ndodhi një gabim. Ju lutemi, kontrolloni DN-në Bazë, sie dhe rregullimet për lidhjen dhe kredencialet.", "Do you really want to delete the current Server Configuration?" : "Doni vërtet të fshihet Formësimi i tanishëm i Shërbyesit?", diff --git a/bower.json b/bower.json index 1fe270d9f3c..e8bb9a35f32 100644 --- a/bower.json +++ b/bower.json @@ -24,7 +24,7 @@ "select2": "~3.4.8", "zxcvbn": "*", "snapjs": "~2.0.0-rc1", - "strengthify": "0.4.1", + "strengthify": "0.4.2", "underscore": "~1.8.0", "bootstrap": "~3.3.5", "backbone": "~1.2.1" diff --git a/build/integration/features/bootstrap/FeatureContext.php b/build/integration/features/bootstrap/FeatureContext.php index 4a0299d6e49..46c86f1300b 100644 --- a/build/integration/features/bootstrap/FeatureContext.php +++ b/build/integration/features/bootstrap/FeatureContext.php @@ -562,7 +562,30 @@ class FeatureContext implements Context, SnippetAcceptingContext { * @param \Behat\Gherkin\Node\TableNode|null $formData */ public function createPublicShare($body) { - $this->sendingToWith("POST", "/apps/files_sharing/api/v1/shares", $body); + $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v1/shares"; + $client = new Client(); + $options = []; + if ($this->currentUser === 'admin') { + $options['auth'] = $this->adminUser; + } else { + $options['auth'] = [$this->currentUser, $this->regularUser]; + } + + if ($body instanceof \Behat\Gherkin\Node\TableNode) { + $fd = $body->getRowsHash(); + if (array_key_exists('expireDate', $fd)){ + $dateModification = $fd['expireDate']; + $fd['expireDate'] = date('Y-m-d', strtotime($dateModification)); + } + $options['body'] = $fd; + } + + try { + $this->response = $client->send($client->createRequest("POST", $fullUrl, $options)); + } catch (\GuzzleHttp\Exception\ClientException $ex) { + $this->response = $ex->getResponse(); + } + $this->lastShareData = $this->response->xml(); } @@ -572,7 +595,12 @@ class FeatureContext implements Context, SnippetAcceptingContext { public function checkPublicSharedFile($filename) { $client = new Client(); $options = []; - $url = $this->lastShareData->data[0]->url; + if (count($this->lastShareData->data->element) > 0){ + $url = $this->lastShareData->data[0]->url; + } + else{ + $url = $this->lastShareData->data->url; + } $fullUrl = $url . "/download"; $options['save_to'] = "./$filename"; $this->response = $client->get($fullUrl, $options); @@ -590,7 +618,13 @@ class FeatureContext implements Context, SnippetAcceptingContext { public function checkPublicSharedFileWithPassword($filename, $password) { $client = new Client(); $options = []; - $token = $this->lastShareData->data[0]->token; + if (count($this->lastShareData->data->element) > 0){ + $token = $this->lastShareData->data[0]->token; + } + else{ + $token = $this->lastShareData->data->token; + } + $fullUrl = substr($this->baseUrl, 0, -4) . "public.php/webdav"; $options['auth'] = [$token, $password]; $options['save_to'] = "./$filename"; @@ -622,6 +656,40 @@ class FeatureContext implements Context, SnippetAcceptingContext { PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode()); } + /** + * @When /^Updating last share with$/ + * @param \Behat\Gherkin\Node\TableNode|null $formData + */ + public function updatingLastShare($body) { + $share_id = $this->lastShareData->data[0]->id; + $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares/$share_id"; + $client = new Client(); + $options = []; + if ($this->currentUser === 'admin') { + $options['auth'] = $this->adminUser; + } else { + $options['auth'] = [$this->currentUser, $this->regularUser]; + } + + if ($body instanceof \Behat\Gherkin\Node\TableNode) { + $fd = $body->getRowsHash(); + if (array_key_exists('expireDate', $fd)){ + $dateModification = $fd['expireDate']; + $fd['expireDate'] = date('Y-m-d', strtotime($dateModification)); + } + $options['body'] = $fd; + } + + try { + $this->response = $client->send($client->createRequest("PUT", $fullUrl, $options)); + } catch (\GuzzleHttp\Exception\ClientException $ex) { + $this->response = $ex->getResponse(); + } + + PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode()); + } + + public function createShare($user, $path = null, $shareType = null, @@ -669,17 +737,49 @@ class FeatureContext implements Context, SnippetAcceptingContext { } - public function isFieldInResponse($field, $content_expected){ + public function isExpectedUrl($possibleUrl, $finalPart){ + $baseUrlChopped = substr($this->baseUrl, 0, -4); + $endCharacter = strlen($baseUrlChopped) + strlen($finalPart); + return (substr($possibleUrl,0,$endCharacter) == "$baseUrlChopped" . "$finalPart"); + } + + public function isFieldInResponse($field, $contentExpected){ $data = $this->response->xml()->data[0]; - foreach($data as $element) { - if ($content_expected == "A_NUMBER"){ - return is_numeric((string)$element->$field); - } - elseif ($element->$field == $content_expected){ - return True; + if ((string)$field == 'expiration'){ + $contentExpected = date('Y-m-d', strtotime($contentExpected)) . " 00:00:00"; + } + if (count($data->element) > 0){ + foreach($data as $element) { + if ($contentExpected == "A_TOKEN"){ + return (strlen((string)$element->$field) == 15); + } + elseif ($contentExpected == "A_NUMBER"){ + return is_numeric((string)$element->$field); + } + elseif($contentExpected == "AN_URL"){ + return $this->isExpectedUrl((string)$element->$field, "index.php/s/"); + } + elseif ($element->$field == $contentExpected){ + return True; + } + } + + return False; + } else { + if ($contentExpected == "A_TOKEN"){ + return (strlen((string)$data->$field) == 15); + } + elseif ($contentExpected == "A_NUMBER"){ + return is_numeric((string)$data->$field); + } + elseif($contentExpected == "AN_URL"){ + return $this->isExpectedUrl((string)$data->$field, "index.php/s/"); + } + elseif ($data->$field == $contentExpected){ + return True; } + return False; } - return False; } /** @@ -767,6 +867,7 @@ class FeatureContext implements Context, SnippetAcceptingContext { public function checkShareFields($body){ if ($body instanceof \Behat\Gherkin\Node\TableNode) { $fd = $body->getRowsHash(); + foreach($fd as $field => $value) { PHPUnit_Framework_Assert::assertEquals(True, $this->isFieldInResponse($field, $value)); } @@ -786,6 +887,9 @@ class FeatureContext implements Context, SnippetAcceptingContext { for ($i=0; $i<5; $i++){ file_put_contents("../../core/skeleton/" . "textfile" . "$i" . ".txt", "ownCloud test text file\n"); } + if (!file_exists("../../core/skeleton/FOLDER")) { + mkdir("../../core/skeleton/FOLDER", 0777, true); + } } @@ -796,6 +900,9 @@ class FeatureContext implements Context, SnippetAcceptingContext { for ($i=0; $i<5; $i++){ self::removeFile("../../core/skeleton/", "textfile" . "$i" . ".txt"); } + if (!is_dir("../../core/skeleton/FOLDER")) { + rmdir("../../core/skeleton/FOLDER"); + } } /** diff --git a/build/integration/features/sharing-v1.feature b/build/integration/features/sharing-v1.feature index 36e729d2a13..07c05af2f54 100644 --- a/build/integration/features/sharing-v1.feature +++ b/build/integration/features/sharing-v1.feature @@ -46,6 +46,25 @@ Feature: sharing And the HTTP status code should be "200" And Public shared file "welcome.txt" with password "publicpw" can be downloaded + Scenario: Creating a new public share of a folder + Given user "user0" exists + And As an "user0" + When creating a public share with + | path | FOLDER | + | shareType | 3 | + | password | publicpw | + | expireDate | +3 days | + | publicUpload | true | + | permissions | 7 | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And Share fields of last share match with + | id | A_NUMBER | + | permissions | 7 | + | expiration | +3 days | + | url | AN_URL | + | token | A_TOKEN | + Scenario: Creating a new public share with password and adding an expiration date Given user "user0" exists And As an "user0" @@ -53,11 +72,129 @@ Feature: sharing | path | welcome.txt | | shareType | 3 | | password | publicpw | - And Adding expiration date to last share + And Updating last share with + | expireDate | +3 days | Then the OCS status code should be "100" And the HTTP status code should be "200" And Public shared file "welcome.txt" with password "publicpw" can be downloaded + Scenario: Creating a new public share, updating its expiration date and getting its info + Given user "user0" exists + And As an "user0" + When creating a public share with + | path | FOLDER | + | shareType | 3 | + And Updating last share with + | expireDate | +3 days | + And Getting info of last share + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And Share fields of last share match with + | id | A_NUMBER | + | item_type | folder | + | item_source | A_NUMBER | + | share_type | 3 | + | file_source | A_NUMBER | + | file_target | /FOLDER | + | permissions | 1 | + | stime | A_NUMBER | + | expiration | +3 days | + | token | A_TOKEN | + | storage | A_NUMBER | + | mail_send | 0 | + | uid_owner | user0 | + | storage_id | home::user0 | + | file_parent | A_NUMBER | + | displayname_owner | user0 | + | url | AN_URL | + + Scenario: Creating a new public share, updating its password and getting its info + Given user "user0" exists + And As an "user0" + When creating a public share with + | path | FOLDER | + | shareType | 3 | + And Updating last share with + | password | publicpw | + And Getting info of last share + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And Share fields of last share match with + | id | A_NUMBER | + | item_type | folder | + | item_source | A_NUMBER | + | share_type | 3 | + | file_source | A_NUMBER | + | file_target | /FOLDER | + | permissions | 1 | + | stime | A_NUMBER | + | token | A_TOKEN | + | storage | A_NUMBER | + | mail_send | 0 | + | uid_owner | user0 | + | storage_id | home::user0 | + | file_parent | A_NUMBER | + | displayname_owner | user0 | + | url | AN_URL | + + Scenario: Creating a new public share, updating its permissions and getting its info + Given user "user0" exists + And As an "user0" + When creating a public share with + | path | FOLDER | + | shareType | 3 | + And Updating last share with + | permissions | 7 | + And Getting info of last share + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And Share fields of last share match with + | id | A_NUMBER | + | item_type | folder | + | item_source | A_NUMBER | + | share_type | 3 | + | file_source | A_NUMBER | + | file_target | /FOLDER | + | permissions | 7 | + | stime | A_NUMBER | + | token | A_TOKEN | + | storage | A_NUMBER | + | mail_send | 0 | + | uid_owner | user0 | + | storage_id | home::user0 | + | file_parent | A_NUMBER | + | displayname_owner | user0 | + | url | AN_URL | + + Scenario: Creating a new public share, updating publicUpload option and getting its info + Given user "user0" exists + And As an "user0" + When creating a public share with + | path | FOLDER | + | shareType | 3 | + And Updating last share with + | publicUpload | true | + And Getting info of last share + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And Share fields of last share match with + | id | A_NUMBER | + | item_type | folder | + | item_source | A_NUMBER | + | share_type | 3 | + | file_source | A_NUMBER | + | file_target | /FOLDER | + | permissions | 7 | + | stime | A_NUMBER | + | token | A_TOKEN | + | storage | A_NUMBER | + | mail_send | 0 | + | uid_owner | user0 | + | storage_id | home::user0 | + | file_parent | A_NUMBER | + | displayname_owner | user0 | + | url | AN_URL | + Scenario: getting all shares of a user using that user Given user "user0" exists And user "user1" exists diff --git a/core/css/apps.css b/core/css/apps.css index ac2be40ac5b..e9abbe0aee1 100644 --- a/core/css/apps.css +++ b/core/css/apps.css @@ -563,16 +563,19 @@ button.loading { #app-content > .section:first-child { border-top: none; } -.section h2 { + +/* heading styles */ +h2 { font-size: 20px; - margin-bottom: 12px; font-weight: 300; + margin-bottom: 12px; } -.section h3 { +h3 { font-size: 15px; font-weight: 300; margin: 12px 0; } + /* slight position correction of checkboxes and radio buttons */ .section input[type="checkbox"], .section input[type="radio"] { diff --git a/core/css/inputs.css b/core/css/inputs.css new file mode 100644 index 00000000000..9f440a6c359 --- /dev/null +++ b/core/css/inputs.css @@ -0,0 +1,232 @@ +/* INPUTS */ + +/* specifically override browser styles */ +input, textarea, select, button { + font-family: 'Open Sans', Frutiger, Calibri, 'Myriad Pro', Myriad, sans-serif; +} + +input[type="text"], +input[type="password"], +input[type="search"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="time"], +input[type="date"], +textarea, +select, +button, .button, +input[type="submit"], +input[type="button"], +#quota, +.pager li a { + width: 130px; + margin: 3px 3px 3px 0; + padding: 7px 6px 5px; + font-size: 13px; + background-color: #fff; + color: #333; + border: 1px solid #ddd; + outline: none; + border-radius: 3px; +} +input[type="hidden"] { + height: 0; + width: 0; +} +input[type="text"], +input[type="password"], +input[type="search"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="time"], +textarea { + background: #fff; + color: #555; + cursor: text; + font-family: inherit; /* use default ownCloud font instead of default textarea monospace */ +} +input[type="text"], +input[type="password"], +input[type="search"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="time"] { + -webkit-appearance:textfield; -moz-appearance:textfield; + -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box; +} +input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active, +input[type="password"]:hover, input[type="password"]:focus, input[type="password"]:active, +input[type="number"]:hover, input[type="number"]:focus, input[type="number"]:active, +input[type="search"]:hover, input[type="search"]:focus, input[type="search"]:active, +input[type="email"]:hover, input[type="email"]:focus, input[type="email"]:active, +input[type="url"]:hover, input[type="url"]:focus, input[type="url"]:active, +input[type="time"]:hover, input[type="time"]:focus, input[type="time"]:active, +textarea:hover, textarea:focus, textarea:active { + color: #333; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; + opacity: 1; +} + +.ie8 input[type="checkbox"] { margin:0; padding:0; height:auto; width:auto; } +.ie8 input[type="checkbox"]:hover+label, input[type="checkbox"]:focus+label { color:#111 !important; } + +/* ie8 doesn't support :checked */ +html:not(.ie8) input[type="checkbox"].checkbox { + position: absolute; + left:-10000px; + top: auto; + width: 1px; + height: 1px; + overflow: hidden; +} + +html:not(.ie8) input[type="checkbox"].checkbox + label:before { + content: ""; + display: inline-block; + + height: 20px; + width: 20px; + vertical-align: middle; + + background: url('../img/actions/checkbox.svg') left top no-repeat; + opacity: 0.7; +} + +html:not(.ie8) input[type="checkbox"].checkbox:disabled +label:before { opacity: .6; } + +html:not(.ie8) input[type="checkbox"].checkbox.u-left +label:before { float: left; } +html:not(.ie8) input[type="checkbox"].checkbox.u-hidden + label:before { display: none; } + +html:not(.ie8) input[type="checkbox"].checkbox--white + label:before { + background-image: url('../img/actions/checkbox-white.svg'); +} + +html:not(.ie8) input[type="checkbox"].checkbox:checked + label:before { + background-image: url('../img/actions/checkbox-checked.svg'); +} + +html:not(.ie8) input[type="checkbox"].checkbox--white:checked + label:before { + background-image: url('../img/actions/checkbox-checked-white.svg'); +} + +html:not(.ie8) input[type="checkbox"].checkbox:hover+label:before, input[type="checkbox"]:focus+label:before { + color:#111 !important; +} + +input[type="time"] { + width: initial; + height: 31px; + -moz-box-sizing: border-box; box-sizing: border-box; +} + +select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background: url('../../core/img/actions/triangle-s.svg') no-repeat right 8px center rgba(240, 240, 240, 0.90); + outline: 0; + padding-right: 24px !important; +} + +select:hover { + background-color: #fefefe; +} + +.select2-choices { + border: 1px solid #ddd; + border-radius: 3px; + color: #333; + background-image: none; +} +.select2-dropdown-open .select2-choices { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border: 1px solid #3875d7; +} + +/* correctly align images inside of buttons */ +input img, button img, .button img { + vertical-align: text-bottom; +} + +input[type="submit"].enabled { + background-color: #66f866; + border: 1px solid #5e5; +} + +.input-button-inline { + position: absolute !important; + right: 0; + background-color: transparent !important; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)"; + opacity: .3; +} + + +/* BUTTONS */ +input[type="submit"], input[type="button"], +button, .button, +#quota, select, .pager li a { + width: auto; + min-width: 25px; + padding: 5px; + background-color: rgba(240,240,240,.9); + font-weight: 600; + color: #555; + border: 1px solid rgba(240,240,240,.9); + cursor: pointer; +} +select, .button.multiselect { + font-weight: 400; +} +input[type="submit"]:hover, input[type="submit"]:focus, +input[type="button"]:hover, input[type="button"]:focus, +button:hover, button:focus, +.button:hover, .button:focus, +.button a:focus, +select:hover, select:focus, select:active { + background-color: rgba(255, 255, 255, .95); + color: #111; +} +input[type="submit"] img, input[type="button"] img, button img, .button img { cursor:pointer; } +#header .button { + border: none; + box-shadow: none; +} + +/* disabled input fields and buttons */ +input:disabled, input:disabled:hover, input:disabled:focus, +button:disabled, button:disabled:hover, button:disabled:focus, +.button:disabled, .button:disabled:hover, .button:disabled:focus, +a.disabled, a.disabled:hover, a.disabled:focus, +textarea:disabled { + background-color: rgba(230,230,230,.9); + color: #999; + cursor: default; +} +input:disabled+label, input:disabled:hover+label, input:disabled:focus+label { + color: #999 !important; + cursor: default; +} + +/* Primary action button, use sparingly */ +.primary, input[type="submit"].primary, input[type="button"].primary, button.primary, .button.primary { + border: 1px solid #1d2d44; + background-color: #35537a; + color: #ddd; +} +.primary:hover, input[type="submit"].primary:hover, input[type="button"].primary:hover, button.primary:hover, .button.primary:hover, +.primary:focus, input[type="submit"].primary:focus, input[type="button"].primary:focus, button.primary:focus, .button.primary:focus { + background-color: #304d76; + color: #fff; +} +.primary:active, input[type="submit"].primary:active, input[type="button"].primary:active, button.primary:active, .button.primary:active, +.primary:disabled, input[type="submit"].primary:disabled, input[type="button"].primary:disabled, button.primary:disabled, .button.primary:disabled, +.primary:disabled:hover, input[type="submit"].primary:disabled:hover, input[type="button"].primary:disabled:hover, button.primary:disabled:hover, .button.primary:disabled:hover, +.primary:disabled:focus, input[type="submit"].primary:disabled:focus, input[type="button"].primary:disabled:focus, button.primary:disabled:focus, .button.primary:disabled:focus { + background-color: #1d2d44; + color: #bbb; +} diff --git a/core/css/styles.css b/core/css/styles.css index 066087cc433..75bbb78fe52 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -12,18 +12,6 @@ table, td, th { vertical-align:middle; } a { border:0; color:#000; text-decoration:none;} a, a *, input, input *, select, .button span, label { cursor:pointer; } ul { list-style:none; } -select { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - background: url('../../core/img/actions/triangle-s.svg') no-repeat right 8px center rgba(240, 240, 240, 0.90); - outline: 0; - padding-right: 24px !important; -} - -select:hover { - background-color: #fefefe; -} body { background-color: #ffffff; @@ -85,155 +73,6 @@ body { color: #ddd; } - - -/* INPUTS */ - -/* specifically override browser styles */ -input, textarea, select, button { - font-family: 'Open Sans', Frutiger, Calibri, 'Myriad Pro', Myriad, sans-serif; -} - -input[type="text"], -input[type="password"], -input[type="search"], -input[type="number"], -input[type="email"], -input[type="url"], -input[type="time"], -input[type="date"], -textarea, -select, -button, .button, -input[type="submit"], -input[type="button"], -#quota, -.pager li a { - width: 130px; - margin: 3px 3px 3px 0; - padding: 7px 6px 5px; - font-size: 13px; - background-color: #fff; - color: #333; - border: 1px solid #ddd; - outline: none; - border-radius: 3px; -} -input[type="hidden"] { - height: 0; - width: 0; -} -input[type="text"], -input[type="password"], -input[type="search"], -input[type="number"], -input[type="email"], -input[type="url"], -input[type="time"], -textarea { - background: #fff; - color: #555; - cursor: text; - font-family: inherit; /* use default ownCloud font instead of default textarea monospace */ -} -input[type="text"], -input[type="password"], -input[type="search"], -input[type="number"], -input[type="email"], -input[type="url"], -input[type="time"] { - -webkit-appearance:textfield; -moz-appearance:textfield; - -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box; -} -input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active, -input[type="password"]:hover, input[type="password"]:focus, input[type="password"]:active, -input[type="number"]:hover, input[type="number"]:focus, input[type="number"]:active, -.searchbox input[type="search"]:hover, .searchbox input[type="search"]:focus, .searchbox input[type="search"]:active, -input[type="email"]:hover, input[type="email"]:focus, input[type="email"]:active, -input[type="url"]:hover, input[type="url"]:focus, input[type="url"]:active, -input[type="time"]:hover, input[type="time"]:focus, input[type="time"]:active, -textarea:hover, textarea:focus, textarea:active { - color: #333; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; - opacity: 1; -} - -.ie8 input[type="checkbox"] { margin:0; padding:0; height:auto; width:auto; } -.ie8 input[type="checkbox"]:hover+label, input[type="checkbox"]:focus+label { color:#111 !important; } - -/* ie8 doesn't support :checked */ -html:not(.ie8) input[type="checkbox"].checkbox { - position: absolute; - left:-10000px; - top: auto; - width: 1px; - height: 1px; - overflow: hidden; -} - -html:not(.ie8) input[type="checkbox"].checkbox + label:before { - content: ""; - display: inline-block; - - height: 20px; - width: 20px; - vertical-align: middle; - - background: url('../img/actions/checkbox.svg') left top no-repeat; - opacity: 0.7; -} - -html:not(.ie8) input[type="checkbox"].checkbox:disabled +label:before { opacity: .6; } - -html:not(.ie8) input[type="checkbox"].checkbox.u-left +label:before { float: left; } -html:not(.ie8) input[type="checkbox"].checkbox.u-hidden + label:before { display: none; } - -html:not(.ie8) input[type="checkbox"].checkbox--white + label:before { - background-image: url('../img/actions/checkbox-white.svg'); -} - -html:not(.ie8) input[type="checkbox"].checkbox:checked + label:before { - background-image: url('../img/actions/checkbox-checked.svg'); -} - -html:not(.ie8) input[type="checkbox"].checkbox--white:checked + label:before { - background-image: url('../img/actions/checkbox-checked-white.svg'); -} - -html:not(.ie8) input[type="checkbox"].checkbox:hover+label:before, input[type="checkbox"]:focus+label:before { - color:#111 !important; -} - -input[type="time"] { - width: initial; - height: 31px; - -moz-box-sizing: border-box; box-sizing: border-box; -} - -.select2-choices { - border: 1px solid #ddd; - border-radius: 3px; - color: #333; - background-image: none; -} -.select2-dropdown-open .select2-choices { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - border: 1px solid #3875d7; -} - -/* correctly align images inside of buttons */ -input img, button img, .button img { - vertical-align: text-bottom; -} - -#quota { - cursor: default; - margin: 30px; -} - - /* SCROLLING */ ::-webkit-scrollbar { width: 8px; @@ -245,72 +84,6 @@ input img, button img, .button img { background: #ddd; } - -/* BUTTONS */ -input[type="submit"], input[type="button"], -button, .button, -#quota, select, .pager li a { - width: auto; - min-width: 25px; - padding: 5px; - background-color: rgba(240,240,240,.9); - font-weight: 600; - color: #555; - border: 1px solid rgba(240,240,240,.9); - cursor: pointer; -} -select, .button.multiselect { - font-weight: 400; -} -input[type="submit"]:hover, input[type="submit"]:focus, -input[type="button"]:hover, input[type="button"]:focus, -button:hover, button:focus, -.button:hover, .button:focus, -.button a:focus, -select:hover, select:focus, select:active { - background-color: rgba(255, 255, 255, .95); - color: #111; -} -input[type="submit"] img, input[type="button"] img, button img, .button img { cursor:pointer; } -#header .button { - border: none; - box-shadow: none; -} - -/* disabled input fields and buttons */ -input:disabled, input:disabled:hover, input:disabled:focus, -button:disabled, button:disabled:hover, button:disabled:focus, -.button:disabled, .button:disabled:hover, .button:disabled:focus, -a.disabled, a.disabled:hover, a.disabled:focus, -textarea:disabled { - background-color: rgba(230,230,230,.9); - color: #999; - cursor: default; -} -input:disabled+label, input:disabled:hover+label, input:disabled:focus+label { - color: #999 !important; - cursor: default; -} - -/* Primary action button, use sparingly */ -.primary, input[type="submit"].primary, input[type="button"].primary, button.primary, .button.primary { - border: 1px solid #1d2d44; - background-color: #35537a; - color: #ddd; -} - .primary:hover, input[type="submit"].primary:hover, input[type="button"].primary:hover, button.primary:hover, .button.primary:hover, - .primary:focus, input[type="submit"].primary:focus, input[type="button"].primary:focus, button.primary:focus, .button.primary:focus { - background-color: #304d76; - color: #fff; - } - .primary:active, input[type="submit"].primary:active, input[type="button"].primary:active, button.primary:active, .button.primary:active, - .primary:disabled, input[type="submit"].primary:disabled, input[type="button"].primary:disabled, button.primary:disabled, .button.primary:disabled, - .primary:disabled:hover, input[type="submit"].primary:disabled:hover, input[type="button"].primary:disabled:hover, button.primary:disabled:hover, .button.primary:disabled:hover, - .primary:disabled:focus, input[type="submit"].primary:disabled:focus, input[type="button"].primary:disabled:focus, button.primary:disabled:focus, .button.primary:disabled:focus { - background-color: #1d2d44; - color: #bbb; - } - /* Searchbox */ .searchbox input[type="search"] { position: relative; @@ -342,21 +115,6 @@ input:disabled+label, input:disabled:hover+label, input:disabled:focus+label { background-color: #112; } -input[type="submit"].enabled { - background-color: #66f866; - border: 1px solid #5e5; -} - -.input-button-inline { - position: absolute !important; - right: 0; - background-color: transparent !important; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)"; - opacity: .3; -} - - - /* CONTENT ------------------------------------------------------------------ */ #controls { -moz-box-sizing: border-box; @@ -437,7 +195,6 @@ input[type="submit"].enabled { #emptycontent h2, .emptycontent h2 { font-weight: 600; - font-size: 22px; margin-bottom: 10px; } #emptycontent [class^="icon-"], @@ -483,7 +240,6 @@ input[type="submit"].enabled { } #body-login .update h2 { - font-size: 20px; line-height: 130%; margin-bottom: 30px; } @@ -941,6 +697,8 @@ tbody tr:active { code { font-family:"Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", monospace; } #quota { + cursor: default; + margin: 30px; position: relative; padding: 0; } diff --git a/core/js/js.js b/core/js/js.js index 07320a1d225..57c9871233b 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -119,10 +119,12 @@ var OC={ /** * Gets the base path for the given OCS API service. * @param {string} service name + * @param {int} version OCS API version * @return {string} OCS API base path */ - linkToOCS: function(service) { - return window.location.protocol + '//' + window.location.host + OC.webroot + '/ocs/v1.php/' + service + '/'; + linkToOCS: function(service, version) { + version = (version !== 2) ? 1 : 2; + return window.location.protocol + '//' + window.location.host + OC.webroot + '/ocs/v' + version + '.php/' + service + '/'; }, /** diff --git a/core/l10n/cs_CZ.js b/core/l10n/cs_CZ.js index 086b100f0b4..8f6f3b38d9e 100644 --- a/core/l10n/cs_CZ.js +++ b/core/l10n/cs_CZ.js @@ -269,6 +269,7 @@ OC.L10N.register( "Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktujte prosím správce systému, pokud se tato zpráva objevuje opakovaně nebo nečekaně.", "Thank you for your patience." : "Děkujeme za vaši trpělivost.", "You are accessing the server from an untrusted domain." : "Přistupujete na server z nedůvěryhodné domény.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Kontaktujte prosím svého správce. Pokud spravujete tuto instalaci, nastavte \"trusted_domains\" v souboru config/config.php. Příklad konfigurace najdete v souboru config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "V závislosti na vaší konfiguraci vám může být, jako správci, umožněno použití tlačítka níže k označení této domény jako důvěryhodné.", "Add \"%s\" as trusted domain" : "Přidat \"%s\" jako důvěryhodnou doménu", "App update required" : "Vyžadována aktualizace aplikace", diff --git a/core/l10n/cs_CZ.json b/core/l10n/cs_CZ.json index 8f6430785a5..024e00159b3 100644 --- a/core/l10n/cs_CZ.json +++ b/core/l10n/cs_CZ.json @@ -267,6 +267,7 @@ "Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktujte prosím správce systému, pokud se tato zpráva objevuje opakovaně nebo nečekaně.", "Thank you for your patience." : "Děkujeme za vaši trpělivost.", "You are accessing the server from an untrusted domain." : "Přistupujete na server z nedůvěryhodné domény.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Kontaktujte prosím svého správce. Pokud spravujete tuto instalaci, nastavte \"trusted_domains\" v souboru config/config.php. Příklad konfigurace najdete v souboru config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "V závislosti na vaší konfiguraci vám může být, jako správci, umožněno použití tlačítka níže k označení této domény jako důvěryhodné.", "Add \"%s\" as trusted domain" : "Přidat \"%s\" jako důvěryhodnou doménu", "App update required" : "Vyžadována aktualizace aplikace", diff --git a/core/l10n/el.js b/core/l10n/el.js index b4a4b2efef7..2f264730565 100644 --- a/core/l10n/el.js +++ b/core/l10n/el.js @@ -269,6 +269,7 @@ OC.L10N.register( "Contact your system administrator if this message persists or appeared unexpectedly." : "Επικοινωνήστε με το διαχειριστή του συστήματος αν αυτό το μήνυμα συνεχίζει να εμφανίζεται ή εμφανίστηκε απρόσμενα.", "Thank you for your patience." : "Σας ευχαριστούμε για την υπομονή σας.", "You are accessing the server from an untrusted domain." : "Η προσπέλαση του διακομιστή γίνεται από μη έμπιστο τομέα.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Παρακαλώ επικοινωνήστε με το διαχειριστή του συστήματος. Αν είστε ο διαχειριστής, ρυθμίστε την επιλογή \"trusted_domain\" στο αρχείο config/config.php. Μπορείτε να βρείτε παράδειγμα στο αρχείο config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Ανάλογα με τις ρυθμίσεις σας, σαν διαχειριστής θα μπορούσατε επίσης να χρησιμοποιήσετε το παρακάτω κουμπί για να εμπιστευθείτε αυτή την περιοχή.", "Add \"%s\" as trusted domain" : "Προσθήκη \"%s\" ως αξιόπιστη περιοχή", "App update required" : "Απαιτείται ενημέρωση εφαρμογής", diff --git a/core/l10n/el.json b/core/l10n/el.json index dfa81965cbc..cafa289fc32 100644 --- a/core/l10n/el.json +++ b/core/l10n/el.json @@ -267,6 +267,7 @@ "Contact your system administrator if this message persists or appeared unexpectedly." : "Επικοινωνήστε με το διαχειριστή του συστήματος αν αυτό το μήνυμα συνεχίζει να εμφανίζεται ή εμφανίστηκε απρόσμενα.", "Thank you for your patience." : "Σας ευχαριστούμε για την υπομονή σας.", "You are accessing the server from an untrusted domain." : "Η προσπέλαση του διακομιστή γίνεται από μη έμπιστο τομέα.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Παρακαλώ επικοινωνήστε με το διαχειριστή του συστήματος. Αν είστε ο διαχειριστής, ρυθμίστε την επιλογή \"trusted_domain\" στο αρχείο config/config.php. Μπορείτε να βρείτε παράδειγμα στο αρχείο config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Ανάλογα με τις ρυθμίσεις σας, σαν διαχειριστής θα μπορούσατε επίσης να χρησιμοποιήσετε το παρακάτω κουμπί για να εμπιστευθείτε αυτή την περιοχή.", "Add \"%s\" as trusted domain" : "Προσθήκη \"%s\" ως αξιόπιστη περιοχή", "App update required" : "Απαιτείται ενημέρωση εφαρμογής", diff --git a/core/l10n/fi_FI.js b/core/l10n/fi_FI.js index 28b9c98db67..6e4a2c438d9 100644 --- a/core/l10n/fi_FI.js +++ b/core/l10n/fi_FI.js @@ -269,6 +269,7 @@ OC.L10N.register( "Contact your system administrator if this message persists or appeared unexpectedly." : "Ota yhteys järjestelmän ylläpitäjään, jos tämä viesti ilmenee uudelleen tai odottamatta.", "Thank you for your patience." : "Kiitos kärsivällisyydestäsi.", "You are accessing the server from an untrusted domain." : "Olet yhteydessä palvelimeen epäluotettavasta verkko-osoitteesta.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Ota yhteys ylläpitoon. Jos olet tämän asennuksen ylläpitäjä, määritä \"trusted_domains\"-asetus config/config.php-tiedostossa. Esimerkkimääritys on tarjolla tiedostossa config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Riippuen määrityksistä, ylläpitäjänä saatat kyetä käyttämään alla olevaa painiketta luodaksesi luottamussuhteen tähän toimialueeseen.", "Add \"%s\" as trusted domain" : "Lisää \"%s\" luotetuksi toimialueeksi", "App update required" : "Sovelluksen päivittäminen vaaditaan", diff --git a/core/l10n/fi_FI.json b/core/l10n/fi_FI.json index 1a84873e6cc..bf88973a83c 100644 --- a/core/l10n/fi_FI.json +++ b/core/l10n/fi_FI.json @@ -267,6 +267,7 @@ "Contact your system administrator if this message persists or appeared unexpectedly." : "Ota yhteys järjestelmän ylläpitäjään, jos tämä viesti ilmenee uudelleen tai odottamatta.", "Thank you for your patience." : "Kiitos kärsivällisyydestäsi.", "You are accessing the server from an untrusted domain." : "Olet yhteydessä palvelimeen epäluotettavasta verkko-osoitteesta.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Ota yhteys ylläpitoon. Jos olet tämän asennuksen ylläpitäjä, määritä \"trusted_domains\"-asetus config/config.php-tiedostossa. Esimerkkimääritys on tarjolla tiedostossa config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Riippuen määrityksistä, ylläpitäjänä saatat kyetä käyttämään alla olevaa painiketta luodaksesi luottamussuhteen tähän toimialueeseen.", "Add \"%s\" as trusted domain" : "Lisää \"%s\" luotetuksi toimialueeksi", "App update required" : "Sovelluksen päivittäminen vaaditaan", diff --git a/core/l10n/fr.js b/core/l10n/fr.js index e25840a7afc..5a73540f141 100644 --- a/core/l10n/fr.js +++ b/core/l10n/fr.js @@ -269,6 +269,7 @@ OC.L10N.register( "Contact your system administrator if this message persists or appeared unexpectedly." : "Veuillez contacter votre administrateur système si ce message persiste ou apparaît de façon inattendue.", "Thank you for your patience." : "Merci de votre patience.", "You are accessing the server from an untrusted domain." : "Vous accédez au serveur à partir d'un domaine non approuvé.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Veuillez contacter votre administrateur. Si vous être l'administrateur de cette instance, il faut configurer la variable \"trusted_domains\" dans le fichier config/config.php. Un exemple de configuration est fournit dans le fichier config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "En fonction de votre configuration, en tant qu'administrateur vous pouvez également utiliser le bouton ci-dessous pour approuver ce domaine.", "Add \"%s\" as trusted domain" : "Ajouter \"%s\" à la liste des domaines approuvés", "App update required" : "Mise à jour de l'application nécessaire", diff --git a/core/l10n/fr.json b/core/l10n/fr.json index 0d86fa37d5a..088381169db 100644 --- a/core/l10n/fr.json +++ b/core/l10n/fr.json @@ -267,6 +267,7 @@ "Contact your system administrator if this message persists or appeared unexpectedly." : "Veuillez contacter votre administrateur système si ce message persiste ou apparaît de façon inattendue.", "Thank you for your patience." : "Merci de votre patience.", "You are accessing the server from an untrusted domain." : "Vous accédez au serveur à partir d'un domaine non approuvé.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Veuillez contacter votre administrateur. Si vous être l'administrateur de cette instance, il faut configurer la variable \"trusted_domains\" dans le fichier config/config.php. Un exemple de configuration est fournit dans le fichier config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "En fonction de votre configuration, en tant qu'administrateur vous pouvez également utiliser le bouton ci-dessous pour approuver ce domaine.", "Add \"%s\" as trusted domain" : "Ajouter \"%s\" à la liste des domaines approuvés", "App update required" : "Mise à jour de l'application nécessaire", diff --git a/core/l10n/it.js b/core/l10n/it.js index d95b02b2841..873c8fb4fea 100644 --- a/core/l10n/it.js +++ b/core/l10n/it.js @@ -269,6 +269,7 @@ OC.L10N.register( "Contact your system administrator if this message persists or appeared unexpectedly." : "Contatta il tuo amministratore di sistema se questo messaggio persiste o appare inaspettatamente.", "Thank you for your patience." : "Grazie per la pazienza.", "You are accessing the server from an untrusted domain." : "Stai accedendo al server da un dominio non attendibile.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Contatta il tuo amministratore di sistema. Se sei un amministratore di questa istanza, configura l'impostazione \"trusted_domains\" in config/config.php. Una configurazione di esempio è disponibile in config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "In base alla tua configurazione, come amministratore potrai utilizzare anche il pulsante in basso per rendere attendibile questo dominio.", "Add \"%s\" as trusted domain" : "Aggiungi \"%s\" come dominio attendibile", "App update required" : "Aggiornamento dell'applicazione richiesto", diff --git a/core/l10n/it.json b/core/l10n/it.json index 944a615653a..8dffade7400 100644 --- a/core/l10n/it.json +++ b/core/l10n/it.json @@ -267,6 +267,7 @@ "Contact your system administrator if this message persists or appeared unexpectedly." : "Contatta il tuo amministratore di sistema se questo messaggio persiste o appare inaspettatamente.", "Thank you for your patience." : "Grazie per la pazienza.", "You are accessing the server from an untrusted domain." : "Stai accedendo al server da un dominio non attendibile.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Contatta il tuo amministratore di sistema. Se sei un amministratore di questa istanza, configura l'impostazione \"trusted_domains\" in config/config.php. Una configurazione di esempio è disponibile in config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "In base alla tua configurazione, come amministratore potrai utilizzare anche il pulsante in basso per rendere attendibile questo dominio.", "Add \"%s\" as trusted domain" : "Aggiungi \"%s\" come dominio attendibile", "App update required" : "Aggiornamento dell'applicazione richiesto", diff --git a/core/l10n/ja.js b/core/l10n/ja.js index c1fef991cc5..225948366f6 100644 --- a/core/l10n/ja.js +++ b/core/l10n/ja.js @@ -269,6 +269,7 @@ OC.L10N.register( "Contact your system administrator if this message persists or appeared unexpectedly." : "このメッセージが引き続きもしくは予期せず現れる場合は、システム管理者に問い合わせてください。", "Thank you for your patience." : "しばらくお待ちください。", "You are accessing the server from an untrusted domain." : "信頼されていないドメインからサーバーにアクセスしています。", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "管理者に問い合わせてください。このサーバーの管理者の場合は、\"trusted_domain\" の設定を config/config.php に設定してください。config/config.sample.php にサンプルの設定方法が記載してあります。", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "環境により、下のボタンで信頼するドメインに追加する必要があるかもしれません。", "Add \"%s\" as trusted domain" : "\"%s\" を信頼するドメイン名に追加", "App update required" : "アプリの更新が必要", diff --git a/core/l10n/ja.json b/core/l10n/ja.json index 99dfb583ccc..21cd77dacbb 100644 --- a/core/l10n/ja.json +++ b/core/l10n/ja.json @@ -267,6 +267,7 @@ "Contact your system administrator if this message persists or appeared unexpectedly." : "このメッセージが引き続きもしくは予期せず現れる場合は、システム管理者に問い合わせてください。", "Thank you for your patience." : "しばらくお待ちください。", "You are accessing the server from an untrusted domain." : "信頼されていないドメインからサーバーにアクセスしています。", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "管理者に問い合わせてください。このサーバーの管理者の場合は、\"trusted_domain\" の設定を config/config.php に設定してください。config/config.sample.php にサンプルの設定方法が記載してあります。", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "環境により、下のボタンで信頼するドメインに追加する必要があるかもしれません。", "Add \"%s\" as trusted domain" : "\"%s\" を信頼するドメイン名に追加", "App update required" : "アプリの更新が必要", diff --git a/core/l10n/pt_BR.js b/core/l10n/pt_BR.js index 44850a9f00b..4c5528163ec 100644 --- a/core/l10n/pt_BR.js +++ b/core/l10n/pt_BR.js @@ -269,6 +269,7 @@ OC.L10N.register( "Contact your system administrator if this message persists or appeared unexpectedly." : "Contacte o seu administrador do sistema se esta mensagem persistir ou aparecer inesperadamente.", "Thank you for your patience." : "Obrigado pela sua paciência.", "You are accessing the server from an untrusted domain." : "Você está acessando o servidor a partir de um domínio não confiável.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Por favor entre em contato com o administrador. Se você é um administrador deste exemplo, configure a definição \"trusted_domains\" em config/config.php. Um exemplo de configuração é fornecido em config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Dependendo da configuração, como administrador, você também pode ser capaz de usar o botão abaixo para confiar neste domínio.", "Add \"%s\" as trusted domain" : "Adicionar \"%s\" como um domínio confiavel", "App update required" : "Atualização de aplicativo é requerida", diff --git a/core/l10n/pt_BR.json b/core/l10n/pt_BR.json index 20300cf2343..023119c0fb1 100644 --- a/core/l10n/pt_BR.json +++ b/core/l10n/pt_BR.json @@ -267,6 +267,7 @@ "Contact your system administrator if this message persists or appeared unexpectedly." : "Contacte o seu administrador do sistema se esta mensagem persistir ou aparecer inesperadamente.", "Thank you for your patience." : "Obrigado pela sua paciência.", "You are accessing the server from an untrusted domain." : "Você está acessando o servidor a partir de um domínio não confiável.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Por favor entre em contato com o administrador. Se você é um administrador deste exemplo, configure a definição \"trusted_domains\" em config/config.php. Um exemplo de configuração é fornecido em config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Dependendo da configuração, como administrador, você também pode ser capaz de usar o botão abaixo para confiar neste domínio.", "Add \"%s\" as trusted domain" : "Adicionar \"%s\" como um domínio confiavel", "App update required" : "Atualização de aplicativo é requerida", diff --git a/core/l10n/ru.js b/core/l10n/ru.js index 2df910a6aa4..39302e9a18e 100644 --- a/core/l10n/ru.js +++ b/core/l10n/ru.js @@ -177,6 +177,7 @@ OC.L10N.register( "Hello {name}" : "Здравствуйте {name}", "_download %n file_::_download %n files_" : ["скачать %n файл","скачать %n файла","скачать %n файлов","скачать %n файлов"], "{version} is available. Get more information on how to update." : "Доступна версия {version}. Получить дополнительную информацию о порядке обновления.", + "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "Идет обновление. Покидая эту страницу, вы можете прервать процесс обновления.", "Updating {productName} to version {version}, this may take a while." : "Идет обновление {productName} до версии {version}, пожалуйста, подождите.", "An error occurred." : "Произошла ошибка.", "Please reload the page." : "Обновите страницу.", @@ -268,6 +269,7 @@ OC.L10N.register( "Contact your system administrator if this message persists or appeared unexpectedly." : "Обратитесь к вашему системному администратору если это сообщение не исчезает или появляется неожиданно.", "Thank you for your patience." : "Спасибо за терпение.", "You are accessing the server from an untrusted domain." : "Вы пытаетесь получить доступ к серверу с неподтверждённого домена.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Пожалуйста, обратитесь к администратору. Если вы являетесь администратором этого экземпляра, настроить параметры \"trusted_domains\" можно в config/config.php. Пример настройки можно найти в config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "В зависимости от конфигурации, как администратор вы можете также внести домен в доверенные с помощью кнопки ниже.", "Add \"%s\" as trusted domain" : "Добавить \"%s\" как доверенный домен", "App update required" : "Требуется обновление приложения", diff --git a/core/l10n/ru.json b/core/l10n/ru.json index 66d3b463899..a24ee0831a0 100644 --- a/core/l10n/ru.json +++ b/core/l10n/ru.json @@ -175,6 +175,7 @@ "Hello {name}" : "Здравствуйте {name}", "_download %n file_::_download %n files_" : ["скачать %n файл","скачать %n файла","скачать %n файлов","скачать %n файлов"], "{version} is available. Get more information on how to update." : "Доступна версия {version}. Получить дополнительную информацию о порядке обновления.", + "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "Идет обновление. Покидая эту страницу, вы можете прервать процесс обновления.", "Updating {productName} to version {version}, this may take a while." : "Идет обновление {productName} до версии {version}, пожалуйста, подождите.", "An error occurred." : "Произошла ошибка.", "Please reload the page." : "Обновите страницу.", @@ -266,6 +267,7 @@ "Contact your system administrator if this message persists or appeared unexpectedly." : "Обратитесь к вашему системному администратору если это сообщение не исчезает или появляется неожиданно.", "Thank you for your patience." : "Спасибо за терпение.", "You are accessing the server from an untrusted domain." : "Вы пытаетесь получить доступ к серверу с неподтверждённого домена.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Пожалуйста, обратитесь к администратору. Если вы являетесь администратором этого экземпляра, настроить параметры \"trusted_domains\" можно в config/config.php. Пример настройки можно найти в config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "В зависимости от конфигурации, как администратор вы можете также внести домен в доверенные с помощью кнопки ниже.", "Add \"%s\" as trusted domain" : "Добавить \"%s\" как доверенный домен", "App update required" : "Требуется обновление приложения", diff --git a/core/l10n/sq.js b/core/l10n/sq.js index 7a3ba05abef..a40e56b9907 100644 --- a/core/l10n/sq.js +++ b/core/l10n/sq.js @@ -269,6 +269,7 @@ OC.L10N.register( "Contact your system administrator if this message persists or appeared unexpectedly." : "Nëse ky mesazh shfaqet vazhdimisht ose u shfaq papritmas, lidhuni me përgjegjësin e sistemit.", "Thank you for your patience." : "Ju faleminderit për durimin.", "You are accessing the server from an untrusted domain." : "Po hyni në shërbyes nga një përkatësi jo e besuar.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Ju lutemi, lidhuni me përgjegjësin tuaj. Nëse jeni një përgjegjës në këtë instancë, formësoni rregullimin \"trusted_domains\" te config/config.php. Një formësim shembull jepet te config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Në varësi të formësimit tuaj, si administrator mundet gjithashtu të jeni në gjendje të përdorni butonin më poshtë për ta besuar këtë përkatësi.", "Add \"%s\" as trusted domain" : "Shtojeni \"%s\" si përkatësi të besuar", "App update required" : "Lypset përditësim aplikacioni", diff --git a/core/l10n/sq.json b/core/l10n/sq.json index 057510bfe94..4284bb9a40e 100644 --- a/core/l10n/sq.json +++ b/core/l10n/sq.json @@ -267,6 +267,7 @@ "Contact your system administrator if this message persists or appeared unexpectedly." : "Nëse ky mesazh shfaqet vazhdimisht ose u shfaq papritmas, lidhuni me përgjegjësin e sistemit.", "Thank you for your patience." : "Ju faleminderit për durimin.", "You are accessing the server from an untrusted domain." : "Po hyni në shërbyes nga një përkatësi jo e besuar.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Ju lutemi, lidhuni me përgjegjësin tuaj. Nëse jeni një përgjegjës në këtë instancë, formësoni rregullimin \"trusted_domains\" te config/config.php. Një formësim shembull jepet te config/config.sample.php.", "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Në varësi të formësimit tuaj, si administrator mundet gjithashtu të jeni në gjendje të përdorni butonin më poshtë për ta besuar këtë përkatësi.", "Add \"%s\" as trusted domain" : "Shtojeni \"%s\" si përkatësi të besuar", "App update required" : "Lypset përditësim aplikacioni", diff --git a/core/shipped.json b/core/shipped.json index 49a649f3c9e..cd1fca4d9fe 100644 --- a/core/shipped.json +++ b/core/shipped.json @@ -31,7 +31,8 @@ "user_external", "user_ldap", "user_shibboleth", - "windows_network_drive" + "windows_network_drive", + "password_policy" ], "alwaysEnabled": [ "files", diff --git a/core/vendor/strengthify/.bower.json b/core/vendor/strengthify/.bower.json index b86b43f17b7..d0baec6ed73 100644 --- a/core/vendor/strengthify/.bower.json +++ b/core/vendor/strengthify/.bower.json @@ -1,6 +1,6 @@ { "name": "strengthify", - "version": "0.4.1", + "version": "0.4.2", "homepage": "https://github.com/MorrisJobke/strengthify", "authors": [ "Morris Jobke <hey@morrisjobke.de>" @@ -8,13 +8,13 @@ "description": "Combine jQuery and zxcvbn to create a password strength meter.", "main": "jquery.strengthify.js", "license": "MIT", - "_release": "0.4.1", + "_release": "0.4.2", "_resolution": { "type": "version", - "tag": "0.4.1", - "commit": "fe9d1c80156d3fcdd16434ebc789007d045c1d1f" + "tag": "v0.4.2", + "commit": "b3df9344d829063564cdced3c6328b001bc4bad1" }, "_source": "git://github.com/MorrisJobke/strengthify.git", - "_target": "0.4.1", + "_target": "0.4.2", "_originalSource": "strengthify" }
\ No newline at end of file diff --git a/core/vendor/strengthify/LICENSE b/core/vendor/strengthify/LICENSE index 3c04738f789..b249b595978 100644 --- a/core/vendor/strengthify/LICENSE +++ b/core/vendor/strengthify/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013 Morris Jobke +Copyright (c) 2013-2015 Morris Jobke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/core/vendor/strengthify/jquery.strengthify.js b/core/vendor/strengthify/jquery.strengthify.js index 4fcc4d7c7c4..26d06a5d301 100644 --- a/core/vendor/strengthify/jquery.strengthify.js +++ b/core/vendor/strengthify/jquery.strengthify.js @@ -1,15 +1,15 @@ /** * Strengthify - show the weakness of a password (uses zxcvbn for this) - * https://github.com/kabum/strengthify + * https://github.com/MorrisJobke/strengthify * - * Version: 0.4.1 - * Author: Morris Jobke (github.com/kabum) + * Version: 0.4.2 + * Author: Morris Jobke (github.com/MorrisJobke) * * License: * * The MIT License (MIT) * - * Copyright (c) 2013 Morris Jobke <morris.jobke@gmail.com> + * Copyright (c) 2013-2015 Morris Jobke <morris.jobke@gmail.com> * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in @@ -43,23 +43,9 @@ 'Perfect' ] }, - options = $.extend(defaults, paramOptions); - - // add elements - $('.strengthify-wrapper') - .append('<div class="strengthify-bg" />') - .append('<div class="strengthify-container" />') - .append('<div class="strengthify-separator" style="left: 25%" />') - .append('<div class="strengthify-separator" style="left: 50%" />') - .append('<div class="strengthify-separator" style="left: 75%" />'); - - $.ajax({ - cache: true, - dataType: 'script', - url: options.zxcvbn - }).done(function() { - me.bind('keyup input change', function() { - var password = $(this).val(), + options = $.extend(defaults, paramOptions), + drawStrengthify = function() { + var password = $(me).val(), // hide strengthigy if no input is provided opacity = (password === '') ? 0 : 1, // calculate result @@ -107,15 +93,15 @@ $wrapper.attr( 'title', options.titles[result.score] - ).tipsy({ + ).tooltip({ + placement: 'bottom', trigger: 'manual', - opacity: opacity - }).tipsy( + }).tooltip( 'show' ); if(opacity === 0) { - $wrapper.tipsy( + $wrapper.tooltip( 'hide' ); } @@ -125,7 +111,24 @@ $container.css('width', 0); } - }); + }; + + // add elements + $('.strengthify-wrapper') + .append('<div class="strengthify-bg" />') + .append('<div class="strengthify-container" />') + .append('<div class="strengthify-separator" style="left: 25%" />') + .append('<div class="strengthify-separator" style="left: 50%" />') + .append('<div class="strengthify-separator" style="left: 75%" />'); + + me.parents().on('scroll', drawStrengthify); + + $.ajax({ + cache: true, + dataType: 'script', + url: options.zxcvbn + }).done(function() { + me.bind('keyup input change', drawStrengthify); }); return me; diff --git a/core/vendor/strengthify/strengthify.css b/core/vendor/strengthify/strengthify.css index 9340270ecfb..5555cbdf334 100644 --- a/core/vendor/strengthify/strengthify.css +++ b/core/vendor/strengthify/strengthify.css @@ -1,7 +1,7 @@ /** * Strengthify - show the weakness of a password (uses zxcvbn for this) - * https://github.com/kabum/strengthify - * Version: 0.3 + * https://github.com/MorrisJobke/strengthify + * Version: 0.4.2 * License: The MIT License (MIT) * Copyright (c) 2013 Morris Jobke <morris.jobke@gmail.com> */ @@ -45,4 +45,4 @@ } .password-good { background-color: #3C3; -}
\ No newline at end of file +} diff --git a/lib/private/appframework/dependencyinjection/dicontainer.php b/lib/private/appframework/dependencyinjection/dicontainer.php index b0be4045541..a32d32fefc5 100644 --- a/lib/private/appframework/dependencyinjection/dicontainer.php +++ b/lib/private/appframework/dependencyinjection/dicontainer.php @@ -226,6 +226,10 @@ class DIContainer extends SimpleContainer implements IAppContainer { return $this->getServer(); }); + $this->registerService('Symfony\Component\EventDispatcher\EventDispatcherInterface', function ($c) { + return $this->getServer()->getEventDispatcher(); + }); + $this->registerService('OCP\\AppFramework\\IAppContainer', function ($c) { return $c; }); diff --git a/lib/private/notification/action.php b/lib/private/notification/action.php index 6de8a1a4bbc..958b085b38e 100644 --- a/lib/private/notification/action.php +++ b/lib/private/notification/action.php @@ -39,6 +39,9 @@ class Action implements IAction { /** @var string */ protected $icon; + /** @var bool */ + protected $primary; + /** * Constructor */ @@ -95,6 +98,27 @@ class Action implements IAction { } /** + * @param $primary bool + * @throws \InvalidArgumentException if $primary is invalid + * @since 9.0.0 + */ + public function setPrimary($primary) { + if (!is_bool($primary)) { + throw new \InvalidArgumentException('The given primary option is invalid'); + } + + $this->primary = $primary; + } + + /** + * @return bool + * @since 9.0.0 + */ + public function isPrimary() { + return $this->primary; + } + + /** * @param string $link * @param string $requestType * @return $this @@ -130,28 +154,6 @@ class Action implements IAction { } /** - * @param string $icon - * @return $this - * @throws \InvalidArgumentException if the icon is invalid - * @since 8.2.0 - */ - public function setIcon($icon) { - if (!is_string($icon) || $icon === '' || isset($icon[64])) { - throw new \InvalidArgumentException('The given icon is invalid'); - } - $this->icon = $icon; - return $this; - } - - /** - * @return string - * @since 8.2.0 - */ - public function getIcon() { - return $this->icon; - } - - /** * @return bool */ public function isValid() { diff --git a/lib/private/notification/iaction.php b/lib/private/notification/iaction.php index da6728f5c52..4aed2e92517 100644 --- a/lib/private/notification/iaction.php +++ b/lib/private/notification/iaction.php @@ -61,6 +61,19 @@ interface IAction { public function getParsedLabel(); /** + * @param $primary bool + * @throws \InvalidArgumentException if $primary is invalid + * @since 9.0.0 + */ + public function setPrimary($primary); + + /** + * @return bool + * @since 9.0.0 + */ + public function isPrimary(); + + /** * @param string $link * @param string $requestType * @return $this @@ -82,20 +95,6 @@ interface IAction { public function getRequestType(); /** - * @param string $icon - * @return $this - * @throws \InvalidArgumentException if the icon is invalid - * @since 8.2.0 - */ - public function setIcon($icon); - - /** - * @return string - * @since 8.2.0 - */ - public function getIcon(); - - /** * @return bool * @since 8.2.0 */ diff --git a/lib/private/notification/inotification.php b/lib/private/notification/inotification.php index faf5db1d24c..a8bf5b110ab 100644 --- a/lib/private/notification/inotification.php +++ b/lib/private/notification/inotification.php @@ -180,20 +180,6 @@ interface INotification { public function getLink(); /** - * @param string $icon - * @return $this - * @throws \InvalidArgumentException if the icon are invalid - * @since 8.2.0 - */ - public function setIcon($icon); - - /** - * @return string - * @since 8.2.0 - */ - public function getIcon(); - - /** * @return IAction * @since 8.2.0 */ diff --git a/lib/private/notification/notification.php b/lib/private/notification/notification.php index 40fe39a956e..01df659d4a1 100644 --- a/lib/private/notification/notification.php +++ b/lib/private/notification/notification.php @@ -68,6 +68,12 @@ class Notification implements INotification { /** @var array */ protected $actionsParsed; + /** @var bool */ + protected $hasPrimaryAction; + + /** @var bool */ + protected $hasPrimaryParsedAction; + /** * Constructor */ @@ -330,28 +336,6 @@ class Notification implements INotification { } /** - * @param string $icon - * @return $this - * @throws \InvalidArgumentException if the icon are invalid - * @since 8.2.0 - */ - public function setIcon($icon) { - if (!is_string($icon) || $icon === '' || isset($icon[64])) { - throw new \InvalidArgumentException('The given icon is invalid'); - } - $this->icon = $icon; - return $this; - } - - /** - * @return string - * @since 8.2.0 - */ - public function getIcon() { - return $this->icon; - } - - /** * @return IAction * @since 8.2.0 */ @@ -369,6 +353,15 @@ class Notification implements INotification { if (!$action->isValid()) { throw new \InvalidArgumentException('The given action is invalid'); } + + if ($action->isPrimary()) { + if ($this->hasPrimaryAction) { + throw new \InvalidArgumentException('The notification already has a primary action'); + } + + $this->hasPrimaryAction = true; + } + $this->actions[] = $action; return $this; } @@ -391,6 +384,15 @@ class Notification implements INotification { if (!$action->isValidParsed()) { throw new \InvalidArgumentException('The given parsed action is invalid'); } + + if ($action->isPrimary()) { + if ($this->hasPrimaryParsedAction) { + throw new \InvalidArgumentException('The notification already has a primary action'); + } + + $this->hasPrimaryParsedAction = true; + } + $this->actionsParsed[] = $action; return $this; } diff --git a/lib/private/share20/defaultshareprovider.php b/lib/private/share20/defaultshareprovider.php index 79bc809b9b2..7f21d3aadf5 100644 --- a/lib/private/share20/defaultshareprovider.php +++ b/lib/private/share20/defaultshareprovider.php @@ -235,17 +235,16 @@ class DefaultShareProvider implements IShareProvider { $share->setId((int)$data['id']) ->setShareType((int)$data['share_type']) ->setPermissions((int)$data['permissions']) - ->setTarget($data['file_target']); + ->setTarget($data['file_target']) + ->setShareTime((int)$data['stime']) + ->setMailSend((bool)$data['mail_send']); if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { $share->setSharedWith($this->userManager->get($data['share_with'])); } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { $share->setSharedWith($this->groupManager->get($data['share_with'])); } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) { - /* - * TODO: Clean this up, this should be set as password not sharedWith - */ - $share->setSharedWith($data['share_with']); + $share->setPassword($data['share_with']); $share->setToken($data['token']); } else { $share->setSharedWith($data['share_with']); diff --git a/lib/private/share20/ishare.php b/lib/private/share20/ishare.php index fa7c1ea614c..a80abebd71c 100644 --- a/lib/private/share20/ishare.php +++ b/lib/private/share20/ishare.php @@ -134,6 +134,13 @@ interface IShare { public function setPassword($password); /** + * Is a password set for this share + * + * @return string + */ + public function getPassword(); + + /** * Get the token * * @return string @@ -153,4 +160,18 @@ interface IShare { * @return string */ public function getTarget(); + + /** + * Get the timestamp this share was created + * + * @return int + */ + public function getSharetime(); + + /** + * Get mailSend + * + * @return bool + */ + public function getMailSend(); } diff --git a/lib/private/share20/share.php b/lib/private/share20/share.php index 989edd3c079..4200816799e 100644 --- a/lib/private/share20/share.php +++ b/lib/private/share20/share.php @@ -28,39 +28,32 @@ class Share implements IShare { /** @var string */ private $id; - /** @var Node */ private $path; - /** @var int */ private $shareType; - /** @var IUser|IGroup|string */ private $sharedWith; - /** @var IUser|string */ private $sharedBy; - /** @var IUser|string */ private $shareOwner; - /** @var int */ private $permissions; - /** @var \DateTime */ private $expireDate; - /** @var string */ private $password; - /** @var string */ private $token; - /** @var int */ private $parent; - /** @var string */ private $target; + /** @var int */ + private $shareTime; + /** @var bool */ + private $mailSend; /** * Set the id of the share @@ -252,7 +245,7 @@ class Share implements IShare { * * @return string */ - public function getPassword($password) { + public function getPassword() { return $this->password; } @@ -315,4 +308,44 @@ class Share implements IShare { public function getTarget() { return $this->target; } + + /** + * Set the time this share was created + * + * @param int $shareTime + * @return Share The modified object + */ + public function setShareTime($shareTime) { + $this->shareTime = $shareTime; + return $this; + } + + /** + * Get the timestamp this share was created + * + * @return int + */ + public function getSharetime() { + return $this->shareTime; + } + + /** + * Set mailSend + * + * @param bool $mailSend + * @return Share The modified object + */ + public function setMailSend($mailSend) { + $this->mailSend = $mailSend; + return $this; + } + + /** + * Get mailSend + * + * @return bool + */ + public function getMailSend() { + return $this->mailSend; + } } diff --git a/lib/private/template.php b/lib/private/template.php index 722194dc764..97666f0b8dc 100644 --- a/lib/private/template.php +++ b/lib/private/template.php @@ -114,6 +114,7 @@ class OC_Template extends \OC\Template\Base { OC_Util::addStyle("icons",null,true); OC_Util::addStyle("mobile",null,true); OC_Util::addStyle("header",null,true); + OC_Util::addStyle("inputs",null,true); OC_Util::addStyle("styles",null,true); // avatars diff --git a/tests/core/avatar/avatarcontrollertest.php b/tests/core/avatar/avatarcontrollertest.php index 929a4e5f91d..948a432d2ed 100644 --- a/tests/core/avatar/avatarcontrollertest.php +++ b/tests/core/avatar/avatarcontrollertest.php @@ -28,6 +28,10 @@ use OCP\AppFramework\Http; use OCP\Image; use OCP\Files\Folder; use OCP\Files\File; +use OCP\IUser; +use OCP\IAvatar; + +use Test\Traits\UserTrait; /** * Overwrite is_uploaded_file in this namespace to allow proper unit testing of @@ -43,79 +47,53 @@ function is_uploaded_file($filename) { * @package OC\Core\Avatar */ class AvatarControllerTest extends \Test\TestCase { + use UserTrait; /** @var IAppContainer */ private $container; - /** @var string */ - private $user; - /** @var string */ - private $oldUser; /** @var AvatarController */ private $avatarController; - + /** @var IAvatar */ private $avatarMock; - + /** @var IUser */ private $userMock; - + protected function setUp() { + parent::setUp(); + $this->createUser('userid', 'pass'); + $this->loginAsUser('userid'); + $app = new Application; $this->container = $app->getContainer(); $this->container['AppName'] = 'core'; - $this->container['AvatarManager'] = $this->getMockBuilder('OCP\IAvatarManager') - ->disableOriginalConstructor()->getMock(); + $this->container['AvatarManager'] = $this->getMock('OCP\IAvatarManager'); $this->container['Cache'] = $this->getMockBuilder('OC\Cache\File') ->disableOriginalConstructor()->getMock(); - $this->container['L10N'] = $this->getMockBuilder('OCP\IL10N') - ->disableOriginalConstructor()->getMock(); + $this->container['L10N'] = $this->getMock('OCP\IL10N'); $this->container['L10N']->method('t')->will($this->returnArgument(0)); - $this->container['UserManager'] = $this->getMockBuilder('OCP\IUserManager') - ->disableOriginalConstructor()->getMock(); - $this->container['UserSession'] = $this->getMockBuilder('OCP\IUserSession') - ->disableOriginalConstructor()->getMock(); - $this->container['Request'] = $this->getMockBuilder('OCP\IRequest') - ->disableOriginalConstructor()->getMock(); - $this->container['UserFolder'] = $this->getMockBuilder('OCP\Files\Folder') - ->disableOriginalConstructor()->getMock(); - $this->container['Logger'] = $this->getMockBuilder('OCP\ILogger') - ->disableOriginalConstructor()->getMock(); + $this->container['UserManager'] = $this->getMock('OCP\IUserManager'); + $this->container['UserSession'] = $this->getMock('OCP\IUserSession'); + $this->container['Request'] = $this->getMock('OCP\IRequest'); + $this->container['UserFolder'] = $this->getMock('OCP\Files\Folder'); + $this->container['Logger'] = $this->getMock('OCP\ILogger'); - $this->avatarMock = $this->getMockBuilder('OCP\IAvatar') - ->disableOriginalConstructor()->getMock(); - $this->userMock = $this->getMockBuilder('OCP\IUser') - ->disableOriginalConstructor()->getMock(); + $this->avatarMock = $this->getMock('OCP\IAvatar'); + $this->userMock = $this->getMock('OCP\IUser'); $this->avatarController = $this->container['AvatarController']; - // Store current User - $this->oldUser = \OC_User::getUser(); - - // Create a dummy user - $this->user = $this->getUniqueID('user'); - - OC::$server->getUserManager()->createUser($this->user, $this->user); - $this->loginAsUser($this->user); - // Configure userMock - $this->userMock->method('getDisplayName')->willReturn($this->user); - $this->userMock->method('getUID')->willReturn($this->user); + $this->userMock->method('getDisplayName')->willReturn('displayName'); + $this->userMock->method('getUID')->willReturn('userId'); $this->container['UserManager']->method('get') - ->willReturnMap([[$this->user, $this->userMock]]); + ->willReturnMap([['userId', $this->userMock]]); $this->container['UserSession']->method('getUser')->willReturn($this->userMock); } public function tearDown() { - \OC_Util::tearDownFS(); - \OC_User::setUserId(''); - Filesystem::tearDown(); - OC::$server->getUserManager()->get($this->user)->delete(); - \OC_User::setIncognitoMode(false); - - \OC::$server->getSession()->set('public_link_authenticated', ''); - - // Set old user - \OC_User::setUserId($this->oldUser); - \OC_Util::setupFS($this->oldUser); + $this->logout(); + parent::tearDown(); } /** @@ -123,29 +101,32 @@ class AvatarControllerTest extends \Test\TestCase { */ public function testGetAvatarNoAvatar() { $this->container['AvatarManager']->method('getAvatar')->willReturn($this->avatarMock); - $response = $this->avatarController->getAvatar($this->user, 32); + $response = $this->avatarController->getAvatar('userId', 32); //Comment out until JS is fixed //$this->assertEquals(Http::STATUS_NOT_FOUND, $response->getStatus()); $this->assertEquals(Http::STATUS_OK, $response->getStatus()); - $this->assertEquals($this->user, $response->getData()['data']['displayname']); + $this->assertEquals('displayName', $response->getData()['data']['displayname']); } /** * Fetch the user's avatar */ public function testGetAvatar() { - $image = new Image(OC::$SERVERROOT.'/tests/data/testimage.jpg'); + $image = $this->getMock('OCP\IImage'); + $image->method('data')->willReturn('image data'); + $image->method('mimeType')->willReturn('image type'); + $this->avatarMock->method('get')->willReturn($image); $this->container['AvatarManager']->method('getAvatar')->willReturn($this->avatarMock); - $response = $this->avatarController->getAvatar($this->user, 32); + $response = $this->avatarController->getAvatar('userId', 32); $this->assertEquals(Http::STATUS_OK, $response->getStatus()); + $this->assertArrayHasKey('Content-Type', $response->getHeaders()); + $this->assertEquals('image type', $response->getHeaders()['Content-Type']); - $image2 = new Image($response->getData()); - $this->assertEquals($image->mimeType(), $image2->mimeType()); - $this->assertEquals(crc32($response->getData()), $response->getEtag()); + $this->assertEquals(crc32('image data'), $response->getEtag()); } /** @@ -155,7 +136,7 @@ class AvatarControllerTest extends \Test\TestCase { $this->avatarMock->method('get')->willReturn(null); $this->container['AvatarManager']->method('getAvatar')->willReturn($this->avatarMock); - $response = $this->avatarController->getAvatar($this->user . 'doesnotexist', 32); + $response = $this->avatarController->getAvatar('userDoesnotexist', 32); //Comment out until JS is fixed //$this->assertEquals(Http::STATUS_NOT_FOUND, $response->getStatus()); @@ -173,7 +154,7 @@ class AvatarControllerTest extends \Test\TestCase { $this->container['AvatarManager']->method('getAvatar')->willReturn($this->avatarMock); - $this->avatarController->getAvatar($this->user, 32); + $this->avatarController->getAvatar('userId', 32); } /** @@ -186,7 +167,7 @@ class AvatarControllerTest extends \Test\TestCase { $this->container['AvatarManager']->method('getAvatar')->willReturn($this->avatarMock); - $this->avatarController->getAvatar($this->user, 0); + $this->avatarController->getAvatar('userId', 0); } /** @@ -199,7 +180,7 @@ class AvatarControllerTest extends \Test\TestCase { $this->container['AvatarManager']->method('getAvatar')->willReturn($this->avatarMock); - $this->avatarController->getAvatar($this->user, 2049); + $this->avatarController->getAvatar('userId', 2049); } /** diff --git a/tests/lib/helper.php b/tests/lib/helper.php index bd527de160d..ca3e0e46d82 100644 --- a/tests/lib/helper.php +++ b/tests/lib/helper.php @@ -353,18 +353,24 @@ class Test_Helper extends \Test\TestCase { $this->assertEquals($expectedResult, $result); } + /** + * @return array + */ public function provideDocRootAppUrlParts() { return array( - array('files', 'index.php', array(), '/index.php/apps/files'), - array('files', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), '/index.php/apps/files?trut=trat&dut=dat'), + array('files', 'ajax/list.php', array(), '/index.php/apps/files/ajax/list.php'), + array('files', 'ajax/list.php', array('trut' => 'trat', 'dut' => 'dat'), '/index.php/apps/files/ajax/list.php?trut=trat&dut=dat'), array('', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), '/index.php?trut=trat&dut=dat'), ); } + /** + * @return array + */ public function provideSubDirAppUrlParts() { return array( - array('files', 'index.php', array(), '/owncloud/index.php/apps/files'), - array('files', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), '/owncloud/index.php/apps/files?trut=trat&dut=dat'), + array('files', 'ajax/list.php', array(), '/owncloud/index.php/apps/files/ajax/list.php'), + array('files', 'ajax/list.php', array('trut' => 'trat', 'dut' => 'dat'), '/owncloud/index.php/apps/files/ajax/list.php?trut=trat&dut=dat'), array('', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), '/owncloud/index.php?trut=trat&dut=dat'), ); } @@ -393,18 +399,24 @@ class Test_Helper extends \Test\TestCase { $this->assertEquals($expectedResult, $result); } + /** + * @return array + */ public function provideDocRootAppAbsoluteUrlParts() { return array( - array('files', 'index.php', array(), 'http://localhost/index.php/apps/files'), - array('files', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), 'http://localhost/index.php/apps/files?trut=trat&dut=dat'), + array('files', 'ajax/list.php', array(), 'http://localhost/index.php/apps/files/ajax/list.php'), + array('files', 'ajax/list.php', array('trut' => 'trat', 'dut' => 'dat'), 'http://localhost/index.php/apps/files/ajax/list.php?trut=trat&dut=dat'), array('', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), 'http://localhost/index.php?trut=trat&dut=dat'), ); } + /** + * @return array + */ public function provideSubDirAppAbsoluteUrlParts() { return array( - array('files', 'index.php', array(), 'http://localhost/owncloud/index.php/apps/files'), - array('files', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), 'http://localhost/owncloud/index.php/apps/files?trut=trat&dut=dat'), + array('files', 'ajax/list.php', array(), 'http://localhost/owncloud/index.php/apps/files/ajax/list.php'), + array('files', 'ajax/list.php', array('trut' => 'trat', 'dut' => 'dat'), 'http://localhost/owncloud/index.php/apps/files/ajax/list.php?trut=trat&dut=dat'), array('', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), 'http://localhost/owncloud/index.php?trut=trat&dut=dat'), ); } diff --git a/tests/lib/notification/actiontest.php b/tests/lib/notification/actiontest.php index e319c250cc7..a6157d6c56e 100644 --- a/tests/lib/notification/actiontest.php +++ b/tests/lib/notification/actiontest.php @@ -171,47 +171,6 @@ class ActionTest extends TestCase { $this->action->setLink($link, $type); } - public function dataSetIcon() { - return [ - ['test1'], - [str_repeat('a', 1)], - [str_repeat('a', 64)], - ]; - } - - /** - * @dataProvider dataSetIcon - * @param string $icon - */ - public function testSetIcon($icon) { - $this->assertSame('', $this->action->getIcon()); - $this->action->setIcon($icon); - $this->assertSame($icon, $this->action->getIcon()); - } - - public function dataSetIconInvalid() { - return [ - [true], - [false], - [0], - [1], - [''], - [str_repeat('a', 65)], - [[]], - [[str_repeat('a', 65)]], - ]; - } - - /** - * @dataProvider dataSetIconInvalid - * @param string $icon - * - * @expectedException \InvalidArgumentException - */ - public function testSetIconInvalid($icon) { - $this->action->setIcon($icon); - } - public function testIsValid() { $this->assertFalse($this->action->isValid()); $this->assertFalse($this->action->isValidParsed()); diff --git a/tests/lib/notification/notificationtest.php b/tests/lib/notification/notificationtest.php index a790a53eaa7..8be49ebdc17 100644 --- a/tests/lib/notification/notificationtest.php +++ b/tests/lib/notification/notificationtest.php @@ -371,34 +371,6 @@ class NotificationTest extends TestCase { $this->notification->setLink($link); } - public function dataSetIcon() { - return $this->dataValidString(64); - } - - /** - * @dataProvider dataSetIcon - * @param string $icon - */ - public function testSetIcon($icon) { - $this->assertSame('', $this->notification->getIcon()); - $this->notification->setIcon($icon); - $this->assertSame($icon, $this->notification->getIcon()); - } - - public function dataSetIconInvalid() { - return $this->dataInvalidString(64); - } - - /** - * @dataProvider dataSetIconInvalid - * @param mixed $icon - * - * @expectedException \InvalidArgumentException - */ - public function testSetIconInvalid($icon) { - $this->notification->setIcon($icon); - } - public function testCreateAction() { $action = $this->notification->createAction(); $this->assertInstanceOf('OC\Notification\IAction', $action); @@ -438,6 +410,24 @@ class NotificationTest extends TestCase { $this->notification->addAction($action); } + public function testAddActionSecondPrimary() { + /** @var \OC\Notification\IAction|\PHPUnit_Framework_MockObject_MockObject $action */ + $action = $this->getMockBuilder('OC\Notification\IAction') + ->disableOriginalConstructor() + ->getMock(); + $action->expects($this->exactly(2)) + ->method('isValid') + ->willReturn(true); + $action->expects($this->exactly(2)) + ->method('isPrimary') + ->willReturn(true); + + $this->notification->addAction($action); + + $this->setExpectedException('\InvalidArgumentException'); + $this->notification->addAction($action); + } + public function testAddParsedAction() { /** @var \OC\Notification\IAction|\PHPUnit_Framework_MockObject_MockObject $action */ $action = $this->getMockBuilder('OC\Notification\IAction') @@ -472,6 +462,24 @@ class NotificationTest extends TestCase { $this->notification->addParsedAction($action); } + public function testAddActionSecondParsedPrimary() { + /** @var \OC\Notification\IAction|\PHPUnit_Framework_MockObject_MockObject $action */ + $action = $this->getMockBuilder('OC\Notification\IAction') + ->disableOriginalConstructor() + ->getMock(); + $action->expects($this->exactly(2)) + ->method('isValidParsed') + ->willReturn(true); + $action->expects($this->exactly(2)) + ->method('isPrimary') + ->willReturn(true); + + $this->notification->addParsedAction($action); + + $this->setExpectedException('\InvalidArgumentException'); + $this->notification->addParsedAction($action); + } + public function dataIsValid() { return [ [false, '', false], diff --git a/tests/lib/share20/defaultshareprovidertest.php b/tests/lib/share20/defaultshareprovidertest.php index e99290f6724..f8b6f98be7c 100644 --- a/tests/lib/share20/defaultshareprovidertest.php +++ b/tests/lib/share20/defaultshareprovidertest.php @@ -266,7 +266,7 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->assertEquals($id, $share->getId()); $this->assertEquals(\OCP\Share::SHARE_TYPE_LINK, $share->getShareType()); - $this->assertEquals('sharedWith', $share->getSharedWith()); + $this->assertEquals('sharedWith', $share->getPassword()); $this->assertEquals($sharedBy, $share->getSharedBy()); $this->assertEquals($shareOwner, $share->getShareOwner()); $this->assertEquals($path, $share->getPath()); diff --git a/tests/lib/urlgenerator.php b/tests/lib/urlgenerator.php index 60e1a86f16a..a5ab483109f 100644 --- a/tests/lib/urlgenerator.php +++ b/tests/lib/urlgenerator.php @@ -53,23 +53,23 @@ class Test_Urlgenerator extends \Test\TestCase { public function provideRoutes() { return array( - array('files_index', 'http://localhost/owncloud/index.php/apps/files/'), + array('files_ajax_list', 'http://localhost/owncloud/index.php/apps/files/ajax/list.php'), array('core_ajax_preview', 'http://localhost/owncloud/index.php/core/preview.png'), ); } public function provideDocRootAppUrlParts() { return array( - array('files', 'index.php', array(), '/index.php/apps/files'), - array('files', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), '/index.php/apps/files?trut=trat&dut=dat'), + array('files', 'ajax/list.php', array(), '/index.php/apps/files/ajax/list.php'), + array('files', 'ajax/list.php', array('trut' => 'trat', 'dut' => 'dat'), '/index.php/apps/files/ajax/list.php?trut=trat&dut=dat'), array('', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), '/index.php?trut=trat&dut=dat'), ); } public function provideSubDirAppUrlParts() { return array( - array('files', 'index.php', array(), '/owncloud/index.php/apps/files'), - array('files', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), '/owncloud/index.php/apps/files?trut=trat&dut=dat'), + array('files', 'ajax/list.php', array(), '/owncloud/index.php/apps/files/ajax/list.php'), + array('files', 'ajax/list.php', array('trut' => 'trat', 'dut' => 'dat'), '/owncloud/index.php/apps/files/ajax/list.php?trut=trat&dut=dat'), array('', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), '/owncloud/index.php?trut=trat&dut=dat'), ); } |