diff options
192 files changed, 3400 insertions, 459 deletions
diff --git a/.htaccess b/.htaccess index cb2cc9cf7e3..8a24076dcb3 100644 --- a/.htaccess +++ b/.htaccess @@ -14,6 +14,10 @@ Header set X-Robots-Tag "none" Header set X-Frame-Options "SAMEORIGIN" SetEnv modHeadersAvailable true + + # Add CSP header if not set, used for static resources + Header append Content-Security-Policy "" + Header edit Content-Security-Policy "^$" "default-src 'none'; style-src 'self' 'unsafe-inline'; script-src 'self'" </IfModule> # Add cache control for CSS and JS files @@ -53,6 +57,7 @@ RewriteRule ^core/js/oc.js$ index.php/core/js/oc.js [PT,E=PATH_INFO:$1] RewriteRule ^core/preview.png$ index.php/core/preview.png [PT,E=PATH_INFO:$1] RewriteCond %{REQUEST_FILENAME} !\.(css|js|svg|gif|png|html|ttf|woff)$ + RewriteCond %{REQUEST_FILENAME} !core/img/favicon.ico$ RewriteCond %{REQUEST_FILENAME} !/remote.php RewriteCond %{REQUEST_FILENAME} !/public.php RewriteCond %{REQUEST_FILENAME} !/cron.php diff --git a/.mention-bot b/.mention-bot new file mode 100644 index 00000000000..b342edbd214 --- /dev/null +++ b/.mention-bot @@ -0,0 +1,11 @@ +{ + "maxReviewers": 3, + "numFilesToCheck": 5, + "alwaysNotifyForPaths": [ + { + "name": "DeepDiver1975", + "files": ["apps/dav/**"] + } + ], + "userBlacklist": ["owncloud-bot"] +} diff --git a/apps/dav/lib/rootcollection.php b/apps/dav/lib/rootcollection.php index c1635c9cde5..9ee32822bbd 100644 --- a/apps/dav/lib/rootcollection.php +++ b/apps/dav/lib/rootcollection.php @@ -33,6 +33,13 @@ class RootCollection extends SimpleCollection { $caldavBackend = new CalDavBackend($db); $calendarRoot = new CalendarRoot($principalBackend, $caldavBackend, 'principals/users'); $calendarRoot->disableListing = $disableListing; + $systemTagCollection = new SystemTag\SystemTagsByIdCollection( + \OC::$server->getSystemTagManager() + ); + $systemTagRelationsCollection = new SystemTag\SystemTagsRelationsCollection( + \OC::$server->getSystemTagManager(), + \OC::$server->getSystemTagObjectMapper() + ); $usersCardDavBackend = new CardDavBackend($db, $principalBackend); $usersAddressBookRoot = new AddressBookRoot($principalBackend, $usersCardDavBackend, 'principals/users'); @@ -51,6 +58,8 @@ class RootCollection extends SimpleCollection { new SimpleCollection('addressbooks', [ $usersAddressBookRoot, $systemAddressBookRoot]), + $systemTagCollection, + $systemTagRelationsCollection, ]; parent::__construct('root', $children); diff --git a/apps/dav/lib/server.php b/apps/dav/lib/server.php index a031f2c442b..ffcbb02db70 100644 --- a/apps/dav/lib/server.php +++ b/apps/dav/lib/server.php @@ -60,6 +60,9 @@ class Server { // addressbook plugins $this->server->addPlugin(new \OCA\DAV\CardDAV\Plugin()); + // system tags plugins + $this->server->addPlugin(new \OCA\DAV\SystemTag\SystemTagPlugin(\OC::$server->getSystemTagManager())); + // 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/'])) { diff --git a/apps/dav/lib/systemtag/systemtagmappingnode.php b/apps/dav/lib/systemtag/systemtagmappingnode.php new file mode 100644 index 00000000000..cbf8542a4fd --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagmappingnode.php @@ -0,0 +1,102 @@ +<?php +/** + * @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/> + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\NotFound; + +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTagObjectMapper; +use OCP\SystemTag\TagNotFoundException; + +/** + * Mapping node for system tag to object id + */ +class SystemTagMappingNode extends SystemTagNode { + + /** + * @var ISystemTagObjectMapper + */ + private $tagMapper; + + /** + * @var string + */ + private $objectId; + + /** + * @var string + */ + private $objectType; + + /** + * Sets up the node, expects a full path name + * + * @param ISystemTag $tag system tag + * @param string $objectId + * @param string $objectType + * @param ISystemTagManager $tagManager + * @param ISystemTagObjectMapper $tagMapper + */ + public function __construct( + ISystemTag $tag, + $objectId, + $objectType, + ISystemTagManager $tagManager, + ISystemTagObjectMapper $tagMapper + ) { + $this->objectId = $objectId; + $this->objectType = $objectType; + $this->tagMapper = $tagMapper; + parent::__construct($tag, $tagManager); + } + + /** + * Returns the object id of the relationship + * + * @return string object id + */ + public function getObjectId() { + return $this->objectId; + } + + /** + * Returns the object type of the relationship + * + * @return string object type + */ + public function getObjectType() { + return $this->objectType; + } + + /** + * Delete tag to object association + */ + public function delete() { + try { + $this->tagMapper->unassignTags($this->objectId, $this->objectType, $this->tag->getId()); + } catch (TagNotFoundException $e) { + // can happen if concurrent deletion occurred + throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e); + } + } +} diff --git a/apps/dav/lib/systemtag/systemtagnode.php b/apps/dav/lib/systemtag/systemtagnode.php new file mode 100644 index 00000000000..7ab4a8a14f4 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagnode.php @@ -0,0 +1,126 @@ +<?php +/** + * @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/> + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\Exception\Conflict; + +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\TagAlreadyExistsException; + +/** + * DAV node representing a system tag, with the name being the tag id. + */ +class SystemTagNode implements \Sabre\DAV\INode { + + /** + * @var ISystemTag + */ + protected $tag; + + /** + * @var ISystemTagManager + */ + protected $tagManager; + + /** + * Sets up the node, expects a full path name + * + * @param ISystemTag $tag system tag + * @param ISystemTagManager $tagManager + */ + public function __construct(ISystemTag $tag, ISystemTagManager $tagManager) { + $this->tag = $tag; + $this->tagManager = $tagManager; + } + + /** + * Returns the id of the tag + * + * @return string + */ + public function getName() { + return $this->tag->getId(); + } + + /** + * Returns the system tag represented by this node + * + * @return ISystemTag system tag + */ + public function getSystemTag() { + return $this->tag; + } + + /** + * Renames the node + * + * @param string $name The new name + * + * @throws MethodNotAllowed not allowed to rename node + */ + public function setName($name) { + throw new MethodNotAllowed(); + } + + /** + * Update tag + * + * @param string $name new tag name + * @param bool $userVisible user visible + * @param bool $userAssignable user assignable + * @throws NotFound whenever the given tag id does not exist + * @throws Conflict whenever a tag already exists with the given attributes + */ + public function update($name, $userVisible, $userAssignable) { + try { + $this->tagManager->updateTag($this->tag->getId(), $name, $userVisible, $userAssignable); + } catch (TagNotFoundException $e) { + throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist'); + } catch (TagAlreadyExistsException $e) { + throw new Conflict( + 'Tag with the properties "' . $name . '", ' . + $userVisible . ', ' . $userAssignable . ' already exists' + ); + } + } + + /** + * Returns null, not supported + * + */ + public function getLastModified() { + return null; + } + + public function delete() { + try { + $this->tagManager->deleteTags($this->tag->getId()); + } catch (TagNotFoundException $e) { + // can happen if concurrent deletion occurred + throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e); + } + } +} diff --git a/apps/dav/lib/systemtag/systemtagplugin.php b/apps/dav/lib/systemtag/systemtagplugin.php new file mode 100644 index 00000000000..51db0632549 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagplugin.php @@ -0,0 +1,249 @@ +<?php +/** + * @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/> + * + */ +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\PropFind; +use Sabre\DAV\PropPatch; +use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\Exception\UnsupportedMediaType; +use Sabre\DAV\Exception\Conflict; + +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\TagAlreadyExistsException; +use Sabre\HTTP\RequestInterface; +use Sabre\HTTP\ResponseInterface; + +/** + * Sabre plugin to handle system tags: + * + * - makes it possible to create new tags with POST operation + * - get/set Webdav properties for tags + * + */ +class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { + + // namespace + const NS_OWNCLOUD = 'http://owncloud.org/ns'; + const ID_PROPERTYNAME = '{http://owncloud.org/ns}id'; + const DISPLAYNAME_PROPERTYNAME = '{http://owncloud.org/ns}display-name'; + const USERVISIBLE_PROPERTYNAME = '{http://owncloud.org/ns}user-visible'; + const USERASSIGNABLE_PROPERTYNAME = '{http://owncloud.org/ns}user-assignable'; + + /** + * @var \Sabre\DAV\Server $server + */ + private $server; + + /** + * @var ISystemTagManager + */ + protected $tagManager; + + /** + * System tags plugin + * + * @param ISystemTagManager $tagManager tag manager + */ + public function __construct(ISystemTagManager $tagManager) { + $this->tagManager = $tagManager; + } + + /** + * This initializes the plugin. + * + * This function is called by \Sabre\DAV\Server, after + * addPlugin is called. + * + * This method should set up the required event subscriptions. + * + * @param \Sabre\DAV\Server $server + * @return void + */ + public function initialize(\Sabre\DAV\Server $server) { + + $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc'; + + $server->protectedProperties[] = self::ID_PROPERTYNAME; + + $server->on('propFind', array($this, 'handleGetProperties')); + $server->on('propPatch', array($this, 'handleUpdateProperties')); + $server->on('method:POST', [$this, 'httpPost']); + + $this->server = $server; + } + + /** + * POST operation on system tag collections + * + * @param RequestInterface $request request object + * @param ResponseInterface $response response object + * @return null|false + */ + public function httpPost(RequestInterface $request, ResponseInterface $response) { + $path = $request->getPath(); + + // Making sure the node exists + try { + $node = $this->server->tree->getNodeForPath($path); + } catch (NotFound $e) { + return null; + } + + if ($node instanceof SystemTagsByIdCollection || $node instanceof SystemTagsObjectMappingCollection) { + $data = $request->getBodyAsString(); + + $tag = $this->createTag($data, $request->getHeader('Content-Type')); + + if ($node instanceof SystemTagsObjectMappingCollection) { + // also add to collection + $node->createFile($tag->getId()); + $url = $request->getBaseUrl() . 'systemtags/'; + } else { + $url = $request->getUrl(); + } + + if ($url[strlen($url) - 1] !== '/') { + $url .= '/'; + } + + $response->setHeader('Location', $url . $tag->getId()); + + // created + $response->setStatus(201); + return false; + } + } + + /** + * Creates a new tag + * + * @param string $data JSON encoded string containing the properties of the tag to create + * @param string $contentType content type of the data + * @return ISystemTag newly created system tag + * + * @throws BadRequest if a field was missing + * @throws Conflict if a tag with the same properties already exists + * @throws UnsupportedMediaType if the content type is not supported + */ + private function createTag($data, $contentType = 'application/json') { + if ($contentType === 'application/json') { + $data = json_decode($data, true); + } else { + throw new UnsupportedMediaType(); + } + + if (!isset($data['name'])) { + throw new BadRequest('Missing "name" attribute'); + } + + $tagName = $data['name']; + $userVisible = true; + $userAssignable = true; + + if (isset($data['userVisible'])) { + $userVisible = (bool)$data['userVisible']; + } + + if (isset($data['userAssignable'])) { + $userAssignable = (bool)$data['userAssignable']; + } + try { + return $this->tagManager->createTag($tagName, $userVisible, $userAssignable); + } catch (TagAlreadyExistsException $e) { + throw new Conflict('Tag already exists', 0, $e); + } + } + + + /** + * Retrieves system tag properties + * + * @param PropFind $propFind + * @param \Sabre\DAV\INode $node + */ + public function handleGetProperties( + PropFind $propFind, + \Sabre\DAV\INode $node + ) { + if (!($node instanceof SystemTagNode)) { + return; + } + + $propFind->handle(self::ID_PROPERTYNAME, function() use ($node) { + return $node->getSystemTag()->getId(); + }); + + $propFind->handle(self::DISPLAYNAME_PROPERTYNAME, function() use ($node) { + return $node->getSystemTag()->getName(); + }); + + $propFind->handle(self::USERVISIBLE_PROPERTYNAME, function() use ($node) { + return (int)$node->getSystemTag()->isUserVisible(); + }); + + $propFind->handle(self::USERASSIGNABLE_PROPERTYNAME, function() use ($node) { + return (int)$node->getSystemTag()->isUserAssignable(); + }); + } + + /** + * Updates tag attributes + * + * @param string $path + * @param PropPatch $propPatch + * + * @return void + */ + public function handleUpdateProperties($path, PropPatch $propPatch) { + $propPatch->handle([ + self::DISPLAYNAME_PROPERTYNAME, + self::USERVISIBLE_PROPERTYNAME, + self::USERASSIGNABLE_PROPERTYNAME, + ], function($props) use ($path) { + $node = $this->server->tree->getNodeForPath($path); + if (!($node instanceof SystemTagNode)) { + return; + } + + $tag = $node->getSystemTag(); + $name = $tag->getName(); + $userVisible = $tag->isUserVisible(); + $userAssignable = $tag->isUserAssignable(); + + if (isset($props[self::DISPLAYNAME_PROPERTYNAME])) { + $name = $props[self::DISPLAYNAME_PROPERTYNAME]; + } + + if (isset($props[self::USERVISIBLE_PROPERTYNAME])) { + $userVisible = (bool)$props[self::USERVISIBLE_PROPERTYNAME]; + } + + if (isset($props[self::USERASSIGNABLE_PROPERTYNAME])) { + $userAssignable = (bool)$props[self::USERASSIGNABLE_PROPERTYNAME]; + } + + $node->update($name, $userVisible, $userAssignable); + return true; + }); + } +} diff --git a/apps/dav/lib/systemtag/systemtagsbyidcollection.php b/apps/dav/lib/systemtag/systemtagsbyidcollection.php new file mode 100644 index 00000000000..e7b7b6d0acc --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagsbyidcollection.php @@ -0,0 +1,117 @@ +<?php +/** + * @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/> + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\ICollection; + +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\TagNotFoundException; + +class SystemTagsByIdCollection implements ICollection { + + /** + * @var ISystemTagManager + */ + private $tagManager; + + /** + * SystemTagsByIdCollection constructor. + * + * @param ISystemTagManager $tagManager + */ + public function __construct($tagManager) { + $this->tagManager = $tagManager; + } + + function createFile($name, $data = null) { + throw new Forbidden('Cannot create tags by id'); + } + + function createDirectory($name) { + throw new Forbidden('Permission denied to create collections'); + } + + function getChild($name) { + try { + $tags = $this->tagManager->getTagsByIds([$name]); + return $this->makeNode(current($tags)); + } catch (\InvalidArgumentException $e) { + throw new BadRequest('Invalid tag id', 0, $e); + } catch (TagNotFoundException $e) { + throw new NotFound('Tag with id ' . $name . ' not found', 0, $e); + } + } + + function getChildren() { + $tags = $this->tagManager->getAllTags(true); + return array_map(function($tag) { + return $this->makeNode($tag); + }, $tags); + } + + function childExists($name) { + try { + $this->tagManager->getTagsByIds([$name]); + return true; + } catch (\InvalidArgumentException $e) { + throw new BadRequest('Invalid tag id', 0, $e); + } catch (TagNotFoundException $e) { + return false; + } + } + + function delete() { + throw new Forbidden('Permission denied to delete this collection'); + } + + function getName() { + return 'systemtags'; + } + + function setName($name) { + throw new Forbidden('Permission denied to rename this collection'); + } + + /** + * Returns the last modification time, as a unix timestamp + * + * @return int + */ + function getLastModified() { + return null; + } + + /** + * Create a sabre node for the given system tag + * + * @param ISystemTag $tag + * + * @return SystemTagNode + */ + private function makeNode(ISystemTag $tag) { + return new SystemTagNode($tag, $this->tagManager); + } +} diff --git a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php new file mode 100644 index 00000000000..89e8620614b --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php @@ -0,0 +1,160 @@ +<?php +/** + * @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/> + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\Exception\PreconditionFailed; +use Sabre\DAV\ICollection; + +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTagObjectMapper; +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\TagNotFoundException; + +/** + * Collection containing tags by object id + */ +class SystemTagsObjectMappingCollection implements ICollection { + + /** + * @var string + */ + private $objectId; + + /** + * @var string + */ + private $objectType; + + /** + * @var ISystemTagManager + */ + private $tagManager; + + /** + * @var ISystemTagObjectMapper + */ + private $tagMapper; + + /** + * Constructor + * + * @param string $objectId object id + * @param string $objectType object type + * @param ISystemTagManager $tagManager + * @param ISystemTagObjectMapper $tagMapper + */ + public function __construct($objectId, $objectType, $tagManager, $tagMapper) { + $this->tagManager = $tagManager; + $this->tagMapper = $tagMapper; + $this->objectId = $objectId; + $this->objectType = $objectType; + } + + function createFile($tagId, $data = null) { + try { + $this->tagMapper->assignTags($this->objectId, $this->objectType, $tagId); + } catch (TagNotFoundException $e) { + throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign'); + } + } + + function createDirectory($name) { + throw new Forbidden('Permission denied to create collections'); + } + + function getChild($tagId) { + try { + if ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)) { + $tag = $this->tagManager->getTagsByIds([$tagId]); + return $this->makeNode(current($tag)); + } + throw new NotFound('Tag with id ' . $tagId . ' not present for object ' . $this->objectId); + } catch (\InvalidArgumentException $e) { + throw new BadRequest('Invalid tag id', 0, $e); + } catch (TagNotFoundException $e) { + throw new NotFound('Tag with id ' . $tagId . ' not found', 0, $e); + } + } + + function getChildren() { + $tagIds = current($this->tagMapper->getTagIdsForObjects([$this->objectId], $this->objectType)); + if (empty($tagIds)) { + return []; + } + $tags = $this->tagManager->getTagsByIds($tagIds); + return array_values(array_map(function($tag) { + return $this->makeNode($tag); + }, $tags)); + } + + function childExists($tagId) { + try { + return ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)); + } catch (\InvalidArgumentException $e) { + throw new BadRequest('Invalid tag id', 0, $e); + } catch (TagNotFoundException $e) { + return false; + } + } + + function delete() { + throw new Forbidden('Permission denied to delete this collection'); + } + + function getName() { + return $this->objectId; + } + + function setName($name) { + throw new Forbidden('Permission denied to rename this collection'); + } + + /** + * Returns the last modification time, as a unix timestamp + * + * @return int + */ + function getLastModified() { + return null; + } + + /** + * Create a sabre node for the mapping of the + * given system tag to the collection's object + * + * @param ISystemTag $tag + * + * @return SystemTagNode + */ + private function makeNode(ISystemTag $tag) { + return new SystemTagMappingNode( + $tag, + $this->objectId, + $this->objectType, + $this->tagManager, + $this->tagMapper + ); + } +} diff --git a/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php new file mode 100644 index 00000000000..e544073613f --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php @@ -0,0 +1,110 @@ +<?php +/** + * @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/> + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\ICollection; + +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTagObjectMapper; + +/** + * Collection containing object ids by object type + */ +class SystemTagsObjectTypeCollection implements ICollection { + + /** + * @var string + */ + private $objectType; + + /** + * @var ISystemTagManager + */ + private $tagManager; + + /** + * @var ISystemTagObjectMapper + */ + private $tagMapper; + + /** + * Constructor + * + * @param string $objectType object type + * @param ISystemTagManager $tagManager + * @param ISystemTagObjectMapper $tagMapper + */ + public function __construct($objectType, $tagManager, $tagMapper) { + $this->tagManager = $tagManager; + $this->tagMapper = $tagMapper; + $this->objectType = $objectType; + } + + function createFile($name, $data = null) { + throw new Forbidden('Permission denied to create nodes'); + } + + function createDirectory($name) { + throw new Forbidden('Permission denied to create collections'); + } + + function getChild($objectId) { + return new SystemTagsObjectMappingCollection( + $objectId, + $this->objectType, + $this->tagManager, + $this->tagMapper + ); + } + + function getChildren() { + // do not list object ids + throw new MethodNotAllowed(); + } + + function childExists($name) { + return true; + } + + function delete() { + throw new Forbidden('Permission denied to delete this collection'); + } + + function getName() { + return $this->objectType; + } + + function setName($name) { + throw new Forbidden('Permission denied to rename this collection'); + } + + /** + * Returns the last modification time, as a unix timestamp + * + * @return int + */ + function getLastModified() { + return null; + } +} diff --git a/apps/dav/lib/systemtag/systemtagsrelationscollection.php b/apps/dav/lib/systemtag/systemtagsrelationscollection.php new file mode 100644 index 00000000000..44069bca02c --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagsrelationscollection.php @@ -0,0 +1,53 @@ +<?php +/** + * @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/> + * + */ + +namespace OCA\DAV\SystemTag; + +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTagObjectMapper; +use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\SimpleCollection; + +class SystemTagsRelationsCollection extends SimpleCollection { + + /** + * SystemTagsRelationsCollection constructor. + * + * @param ISystemTagManager $tagManager + * @param ISystemTagObjectMapper $tagMapper + */ + public function __construct($tagManager, $tagMapper) { + $children = [ + new SystemTagsObjectTypeCollection('files', $tagManager, $tagMapper), + ]; + + parent::__construct('root', $children); + } + + function getName() { + return 'systemtags-relations'; + } + + function setName($name) { + throw new Forbidden('Permission denied to rename this collection'); + } + +} diff --git a/apps/dav/tests/unit/systemtag/systemtagmappingnode.php b/apps/dav/tests/unit/systemtag/systemtagmappingnode.php new file mode 100644 index 00000000000..849f7c2fa54 --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagmappingnode.php @@ -0,0 +1,84 @@ +<?php +/** + * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\Exception\Conflict; + +use OC\SystemTag\SystemTag; +use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagMappingNode extends SystemTagNode { + + /** + * @var \OCA\DAV\SystemTag\SystemTagMappingNode + */ + private $node; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + /** + * @var \OCP\SystemTag\ISystemTagObjectMapper + */ + private $tagMapper; + + /** + * @var \OCP\SystemTag\ISystemTag + */ + private $tag; + + protected function setUp() { + parent::setUp(); + + $this->tag = new SystemTag(1, 'Test', true, false); + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper'); + + $this->node = new \OCA\DAV\SystemTag\SystemTagMappingNode( + $this->tag, + 123, + 'files', + $this->tagManager, + $this->tagMapper + ); + } + + public function testGetters() { + parent::testGetters(); + $this->assertEquals(123, $this->node->getObjectId()); + $this->assertEquals('files', $this->node->getObjectType()); + } + + public function testDeleteTag() { + $this->tagManager->expects($this->never()) + ->method('deleteTags'); + $this->tagMapper->expects($this->once()) + ->method('unassignTags') + ->with(123, 'files', 1); + + $this->node->delete(); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testDeleteTagNotFound() { + $this->tagMapper->expects($this->once()) + ->method('unassignTags') + ->with(123, 'files', 1) + ->will($this->throwException(new TagNotFoundException())); + + $this->node->delete(); + } +} diff --git a/apps/dav/tests/unit/systemtag/systemtagnode.php b/apps/dav/tests/unit/systemtag/systemtagnode.php new file mode 100644 index 00000000000..a43dda3025d --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagnode.php @@ -0,0 +1,103 @@ +<?php +/** + * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\Exception\Conflict; + +use OC\SystemTag\SystemTag; +use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagNode extends \Test\TestCase { + + /** + * @var \OCA\DAV\SystemTag\SystemTagNode + */ + private $node; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + /** + * @var \OCP\SystemTag\ISystemTag + */ + private $tag; + + protected function setUp() { + parent::setUp(); + + $this->tag = new SystemTag(1, 'Test', true, false); + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + + $this->node = new \OCA\DAV\SystemTag\SystemTagNode($this->tag, $this->tagManager); + } + + public function testGetters() { + $this->assertEquals('1', $this->node->getName()); + $this->assertEquals($this->tag, $this->node->getSystemTag()); + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + public function testSetName() { + $this->node->setName('2'); + } + + public function testUpdateTag() { + $this->tagManager->expects($this->once()) + ->method('updateTag') + ->with(1, 'Renamed', false, true); + $this->node->update('Renamed', false, true); + } + + /** + * @expectedException Sabre\DAV\Exception\Conflict + */ + public function testUpdateTagAlreadyExists() { + $this->tagManager->expects($this->once()) + ->method('updateTag') + ->with(1, 'Renamed', false, true) + ->will($this->throwException(new TagAlreadyExistsException())); + $this->node->update('Renamed', false, true); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testUpdateTagNotFound() { + $this->tagManager->expects($this->once()) + ->method('updateTag') + ->with(1, 'Renamed', false, true) + ->will($this->throwException(new TagNotFoundException())); + $this->node->update('Renamed', false, true); + } + + public function testDeleteTag() { + $this->tagManager->expects($this->once()) + ->method('deleteTags') + ->with('1'); + $this->node->delete(); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testDeleteTagNotFound() { + $this->tagManager->expects($this->once()) + ->method('deleteTags') + ->with('1') + ->will($this->throwException(new TagNotFoundException())); + $this->node->delete(); + } +} diff --git a/apps/dav/tests/unit/systemtag/systemtagplugin.php b/apps/dav/tests/unit/systemtag/systemtagplugin.php new file mode 100644 index 00000000000..48c9aa69f7b --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagplugin.php @@ -0,0 +1,308 @@ +<?php +/** + * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + +use OC\SystemTag\SystemTag; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagPlugin extends \Test\TestCase { + + const ID_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::ID_PROPERTYNAME; + const DISPLAYNAME_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::DISPLAYNAME_PROPERTYNAME; + const USERVISIBLE_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::USERVISIBLE_PROPERTYNAME; + const USERASSIGNABLE_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::USERASSIGNABLE_PROPERTYNAME; + + /** + * @var \Sabre\DAV\Server + */ + private $server; + + /** + * @var \Sabre\DAV\Tree + */ + private $tree; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + /** + * @var \OCA\DAV\Connector\Sabre\TagsPlugin + */ + private $plugin; + + public function setUp() { + parent::setUp(); + $this->tree = $this->getMockBuilder('\Sabre\DAV\Tree') + ->disableOriginalConstructor() + ->getMock(); + + $this->server = new \Sabre\DAV\Server($this->tree); + + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + + $this->plugin = new \OCA\DAV\SystemTag\SystemTagPlugin($this->tagManager); + $this->plugin->initialize($this->server); + } + + public function testGetProperties() { + $systemTag = new SystemTag(1, 'Test', true, true); + $requestedProperties = [ + self::ID_PROPERTYNAME, + self::DISPLAYNAME_PROPERTYNAME, + self::USERVISIBLE_PROPERTYNAME, + self::USERASSIGNABLE_PROPERTYNAME + ]; + $expectedProperties = [ + 200 => [ + self::ID_PROPERTYNAME => '1', + self::DISPLAYNAME_PROPERTYNAME => 'Test', + self::USERVISIBLE_PROPERTYNAME => 1, + self::USERASSIGNABLE_PROPERTYNAME => 1, + ] + ]; + + $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagNode') + ->disableOriginalConstructor() + ->getMock(); + $node->expects($this->any()) + ->method('getSystemTag') + ->will($this->returnValue($systemTag)); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('/systemtag/1') + ->will($this->returnValue($node)); + + $propFind = new \Sabre\DAV\PropFind( + '/systemtag/1', + $requestedProperties, + 0 + ); + + $this->plugin->handleGetProperties( + $propFind, + $node + ); + + $result = $propFind->getResultForMultiStatus(); + + $this->assertEmpty($result[404]); + unset($result[404]); + $this->assertEquals($expectedProperties, $result); + } + + public function testUpdateProperties() { + $systemTag = new SystemTag(1, 'Test', true, false); + $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagNode') + ->disableOriginalConstructor() + ->getMock(); + $node->expects($this->any()) + ->method('getSystemTag') + ->will($this->returnValue($systemTag)); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('/systemtag/1') + ->will($this->returnValue($node)); + + $node->expects($this->once()) + ->method('update') + ->with('Test changed', false, true); + + // properties to set + $propPatch = new \Sabre\DAV\PropPatch(array( + self::DISPLAYNAME_PROPERTYNAME => 'Test changed', + self::USERVISIBLE_PROPERTYNAME => 0, + self::USERASSIGNABLE_PROPERTYNAME => 1, + )); + + $this->plugin->handleUpdateProperties( + '/systemtag/1', + $propPatch + ); + + $propPatch->commit(); + + // all requested properties removed, as they were processed already + $this->assertEmpty($propPatch->getRemainingMutations()); + + $result = $propPatch->getResult(); + $this->assertEquals(200, $result[self::DISPLAYNAME_PROPERTYNAME]); + $this->assertEquals(200, $result[self::USERASSIGNABLE_PROPERTYNAME]); + $this->assertEquals(200, $result[self::USERVISIBLE_PROPERTYNAME]); + } + + public function testCreateTagInByIdCollection() { + $systemTag = new SystemTag(1, 'Test', true, false); + + $requestData = json_encode([ + 'name' => 'Test', + 'userVisible' => true, + 'userAssignable' => false, + ]); + + $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagsByIdCollection') + ->disableOriginalConstructor() + ->getMock(); + $this->tagManager->expects($this->once()) + ->method('createTag') + ->with('Test', true, false) + ->will($this->returnValue($systemTag)); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('/systemtags') + ->will($this->returnValue($node)); + + $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') + ->disableOriginalConstructor() + ->getMock(); + $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface') + ->disableOriginalConstructor() + ->getMock(); + + $request->expects($this->once()) + ->method('getPath') + ->will($this->returnValue('/systemtags')); + + $request->expects($this->once()) + ->method('getBodyAsString') + ->will($this->returnValue($requestData)); + + $request->expects($this->once()) + ->method('getHeader') + ->with('Content-Type') + ->will($this->returnValue('application/json')); + + $request->expects($this->once()) + ->method('getUrl') + ->will($this->returnValue('http://example.com/dav/systemtags')); + + $response->expects($this->once()) + ->method('setHeader') + ->with('Location', 'http://example.com/dav/systemtags/1'); + + $this->plugin->httpPost($request, $response); + } + + public function nodeClassProvider() { + return [ + ['\OCA\DAV\SystemTag\SystemTagsByIdCollection'], + ['\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection'], + ]; + } + + public function testCreateTagInMappingCollection() { + $systemTag = new SystemTag(1, 'Test', true, false); + + $requestData = json_encode([ + 'name' => 'Test', + 'userVisible' => true, + 'userAssignable' => false, + ]); + + $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection') + ->disableOriginalConstructor() + ->getMock(); + + $this->tagManager->expects($this->once()) + ->method('createTag') + ->with('Test', true, false) + ->will($this->returnValue($systemTag)); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('/systemtags-relations/files/12') + ->will($this->returnValue($node)); + + $node->expects($this->once()) + ->method('createFile') + ->with(1); + + $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') + ->disableOriginalConstructor() + ->getMock(); + $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface') + ->disableOriginalConstructor() + ->getMock(); + + $request->expects($this->once()) + ->method('getPath') + ->will($this->returnValue('/systemtags-relations/files/12')); + + $request->expects($this->once()) + ->method('getBodyAsString') + ->will($this->returnValue($requestData)); + + $request->expects($this->once()) + ->method('getHeader') + ->with('Content-Type') + ->will($this->returnValue('application/json')); + + $request->expects($this->once()) + ->method('getBaseUrl') + ->will($this->returnValue('http://example.com/dav/')); + + $response->expects($this->once()) + ->method('setHeader') + ->with('Location', 'http://example.com/dav/systemtags/1'); + + $this->plugin->httpPost($request, $response); + } + + /** + * @dataProvider nodeClassProvider + * @expectedException Sabre\DAV\Exception\Conflict + */ + public function testCreateTagConflict($nodeClass) { + $requestData = json_encode([ + 'name' => 'Test', + 'userVisible' => true, + 'userAssignable' => false, + ]); + + $node = $this->getMockBuilder($nodeClass) + ->disableOriginalConstructor() + ->getMock(); + $this->tagManager->expects($this->once()) + ->method('createTag') + ->with('Test', true, false) + ->will($this->throwException(new TagAlreadyExistsException('Tag already exists'))); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('/systemtags') + ->will($this->returnValue($node)); + + $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') + ->disableOriginalConstructor() + ->getMock(); + $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface') + ->disableOriginalConstructor() + ->getMock(); + + $request->expects($this->once()) + ->method('getPath') + ->will($this->returnValue('/systemtags')); + + $request->expects($this->once()) + ->method('getBodyAsString') + ->will($this->returnValue($requestData)); + + $request->expects($this->once()) + ->method('getHeader') + ->with('Content-Type') + ->will($this->returnValue('application/json')); + + $this->plugin->httpPost($request, $response); + } + +} diff --git a/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php new file mode 100644 index 00000000000..104ce366034 --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php @@ -0,0 +1,147 @@ +<?php +/** + * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + + +use OC\SystemTag\SystemTag; +use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagsByIdCollection extends \Test\TestCase { + + /** + * @var \OCA\DAV\SystemTag\SystemTagsByIdCollection + */ + private $node; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + protected function setUp() { + parent::setUp(); + + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + + $this->node = new \OCA\DAV\SystemTag\SystemTagsByIdCollection($this->tagManager); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testForbiddenCreateFile() { + $this->node->createFile('555'); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testForbiddenCreateDirectory() { + $this->node->createDirectory('789'); + } + + public function testGetChild() { + $tag = new SystemTag(123, 'Test', true, false); + + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with(['123']) + ->will($this->returnValue([$tag])); + + $childNode = $this->node->getChild('123'); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $childNode); + $this->assertEquals('123', $childNode->getName()); + $this->assertEquals($tag, $childNode->getSystemTag()); + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + public function testGetChildInvalidName() { + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with(['invalid']) + ->will($this->throwException(new \InvalidArgumentException())); + + $this->node->getChild('invalid'); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testGetChildNotFound() { + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with(['444']) + ->will($this->throwException(new TagNotFoundException())); + + $this->node->getChild('444'); + } + + public function testGetChildren() { + $tag1 = new SystemTag(123, 'One', true, false); + $tag2 = new SystemTag(456, 'Two', true, true); + + $this->tagManager->expects($this->once()) + ->method('getAllTags') + ->with(true) + ->will($this->returnValue([$tag1, $tag2])); + + $children = $this->node->getChildren(); + + $this->assertCount(2, $children); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $children[0]); + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $children[1]); + $this->assertEquals($tag1, $children[0]->getSystemTag()); + $this->assertEquals($tag2, $children[1]->getSystemTag()); + } + + public function testGetChildrenEmpty() { + $this->tagManager->expects($this->once()) + ->method('getAllTags') + ->with(true) + ->will($this->returnValue([])); + $this->assertCount(0, $this->node->getChildren()); + } + + public function testChildExists() { + $tag = new SystemTag(123, 'One', true, false); + + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with(['123']) + ->will($this->returnValue([$tag])); + + $this->assertTrue($this->node->childExists('123')); + } + + public function testChildExistsNotFound() { + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with(['123']) + ->will($this->throwException(new TagNotFoundException())); + + $this->assertFalse($this->node->childExists('123')); + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + public function testChildExistsBadRequest() { + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with(['invalid']) + ->will($this->throwException(new \InvalidArgumentException())); + + $this->node->childExists('invalid'); + } +} diff --git a/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php new file mode 100644 index 00000000000..6e15bb78e7c --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php @@ -0,0 +1,215 @@ +<?php +/** + * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + + +use OC\SystemTag\SystemTag; +use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagsObjectMappingCollection extends \Test\TestCase { + + /** + * @var \OCA\DAV\SystemTag\SystemTagsObjectTypeCollection + */ + private $node; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + /** + * @var \OCP\SystemTag\ISystemTagMapper + */ + private $tagMapper; + + protected function setUp() { + parent::setUp(); + + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper'); + + $this->node = new \OCA\DAV\SystemTag\SystemTagsObjectMappingCollection ( + 111, + 'files', + $this->tagManager, + $this->tagMapper + ); + } + + public function testAssignTag() { + $this->tagMapper->expects($this->once()) + ->method('assignTags') + ->with(111, 'files', '555'); + + $this->node->createFile('555'); + } + + /** + * @expectedException Sabre\DAV\Exception\PreconditionFailed + */ + public function testAssignTagNotFound() { + $this->tagMapper->expects($this->once()) + ->method('assignTags') + ->with(111, 'files', '555') + ->will($this->throwException(new TagNotFoundException())); + + $this->node->createFile('555'); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testForbiddenCreateDirectory() { + $this->node->createDirectory('789'); + } + + public function testGetChild() { + $tag = new SystemTag(555, 'TheTag', true, false); + + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with([111], 'files', '555', true) + ->will($this->returnValue(true)); + + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with(['555']) + ->will($this->returnValue(['555' => $tag])); + + $childNode = $this->node->getChild('555'); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $childNode); + $this->assertEquals('555', $childNode->getName()); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testGetChildRelationNotFound() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with([111], 'files', '777') + ->will($this->returnValue(false)); + + $this->node->getChild('777'); + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + public function testGetChildInvalidId() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with([111], 'files', 'badid') + ->will($this->throwException(new \InvalidArgumentException())); + + $this->node->getChild('badid'); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testGetChildTagDoesNotExist() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with([111], 'files', '777') + ->will($this->throwException(new TagNotFoundException())); + + $this->node->getChild('777'); + } + + public function testGetChildren() { + $tag1 = new SystemTag(555, 'TagOne', true, false); + $tag2 = new SystemTag(556, 'TagTwo', true, true); + + $this->tagMapper->expects($this->once()) + ->method('getTagIdsForObjects') + ->with([111], 'files') + ->will($this->returnValue(['111' => ['555', '556']])); + + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with(['555', '556']) + ->will($this->returnValue(['555' => $tag1, '666' => $tag2])); + + $children = $this->node->getChildren(); + + $this->assertCount(2, $children); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[0]); + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[1]); + + $this->assertEquals(111, $children[0]->getObjectId()); + $this->assertEquals('files', $children[0]->getObjectType()); + $this->assertEquals($tag1, $children[0]->getSystemTag()); + + $this->assertEquals(111, $children[1]->getObjectId()); + $this->assertEquals('files', $children[1]->getObjectType()); + $this->assertEquals($tag2, $children[1]->getSystemTag()); + } + + public function testChildExists() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with([111], 'files', '555') + ->will($this->returnValue(true)); + + $this->assertTrue($this->node->childExists('555')); + } + + public function testChildExistsNotFound() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with([111], 'files', '555') + ->will($this->returnValue(false)); + + $this->assertFalse($this->node->childExists('555')); + } + + public function testChildExistsTagNotFound() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with([111], 'files', '555') + ->will($this->throwException(new TagNotFoundException())); + + $this->assertFalse($this->node->childExists('555')); + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + public function testChildExistsInvalidId() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with([111], 'files', '555') + ->will($this->throwException(new \InvalidArgumentException())); + + $this->node->childExists('555'); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testDelete() { + $this->node->delete(); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testSetName() { + $this->node->setName('somethingelse'); + } + + public function testGetName() { + $this->assertEquals('111', $this->node->getName()); + } +} diff --git a/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php b/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php new file mode 100644 index 00000000000..39223ff9122 --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php @@ -0,0 +1,90 @@ +<?php +/** + * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + +class SystemTagsObjectTypeCollection extends \Test\TestCase { + + /** + * @var \OCA\DAV\SystemTag\SystemTagsObjectTypeCollection + */ + private $node; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + /** + * @var \OCP\SystemTag\ISystemTagMapper + */ + private $tagMapper; + + protected function setUp() { + parent::setUp(); + + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper'); + + $this->node = new \OCA\DAV\SystemTag\SystemTagsObjectTypeCollection( + 'files', + $this->tagManager, + $this->tagMapper + ); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testForbiddenCreateFile() { + $this->node->createFile('555'); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testForbiddenCreateDirectory() { + $this->node->createDirectory('789'); + } + + public function testGetChild() { + $childNode = $this->node->getChild('files'); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection', $childNode); + $this->assertEquals('files', $childNode->getName()); + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + public function testGetChildren() { + $this->node->getChildren(); + } + + public function testChildExists() { + $this->assertTrue($this->node->childExists('123')); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testDelete() { + $this->node->delete(); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testSetName() { + $this->node->setName('somethingelse'); + } + + public function testGetName() { + $this->assertEquals('files', $this->node->getName()); + } +} diff --git a/apps/files/admin.php b/apps/files/admin.php index 786a8edf2a6..f23f9b52698 100644 --- a/apps/files/admin.php +++ b/apps/files/admin.php @@ -30,9 +30,8 @@ OCP\User::checkAdminUser(); $htaccessWorking=(getenv('htaccessWorking')=='true'); - -$upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize')); -$post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size')); +$upload_max_filesize = OC::$server->getIniWrapper()->getBytes('upload_max_filesize'); +$post_max_size = OC::$server->getIniWrapper()->getBytes('post_max_size'); $maxUploadFilesize = OCP\Util::humanFileSize(min($upload_max_filesize, $post_max_size)); if($_POST && OC_Util::isCallRegistered()) { if(isset($_POST['maxUploadSize'])) { diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php index 18e9cfe6117..14f56a24b4b 100644 --- a/apps/files/ajax/upload.php +++ b/apps/files/ajax/upload.php @@ -114,7 +114,7 @@ foreach ($_FILES['files']['error'] as $error) { $errors = array( UPLOAD_ERR_OK => $l->t('There is no error, the file uploaded with success'), UPLOAD_ERR_INI_SIZE => $l->t('The uploaded file exceeds the upload_max_filesize directive in php.ini: ') - . ini_get('upload_max_filesize'), + . OC::$server->getIniWrapper()->getNumeric('upload_max_filesize'), UPLOAD_ERR_FORM_SIZE => $l->t('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'), UPLOAD_ERR_PARTIAL => $l->t('The uploaded file was only partially uploaded'), UPLOAD_ERR_NO_FILE => $l->t('No file was uploaded'), diff --git a/apps/files_external/command/listcommand.php b/apps/files_external/command/listcommand.php index 4c027ffcb8e..baba9be59f5 100644 --- a/apps/files_external/command/listcommand.php +++ b/apps/files_external/command/listcommand.php @@ -29,7 +29,6 @@ use OCP\IUserManager; use OCP\IUserSession; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\Table; -use Symfony\Component\Console\Helper\TableHelper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; diff --git a/apps/files_external/css/external.css b/apps/files_external/css/external.css new file mode 100644 index 00000000000..bf57ec88053 --- /dev/null +++ b/apps/files_external/css/external.css @@ -0,0 +1,8 @@ +#filestable tbody tr.externalDisabledRow { + background-color: #CCC; +} + + +#filestable tbody tr.externalErroredRow { + background-color: #F2DEDE; +} diff --git a/apps/files_external/js/app.js b/apps/files_external/js/app.js index 1bff3014bd6..d3ce2010ecd 100644 --- a/apps/files_external/js/app.js +++ b/apps/files_external/js/app.js @@ -73,5 +73,42 @@ $(document).ready(function() { $('#app-content-extstoragemounts').on('hide', function() { OCA.External.App.removeList(); }); + + /* Status Manager */ + if ($('#filesApp').val()) { + + $('#app-content-files') + .add('#app-content-extstoragemounts') + .on('changeDirectory', function(e){ + if (e.dir === '/') { + var mount_point = e.previousDir.split('/', 2)[1]; + // Every time that we return to / root folder from a mountpoint, mount_point status is rechecked + OCA.External.StatusManager.getMountPointList(function() { + OCA.External.StatusManager.recheckConnectivityForMount([mount_point], true); + }); + } + }) + .on('fileActionsReady', function(e){ + if ($.isArray(e.$files)) { + if (OCA.External.StatusManager.mountStatus === null || + OCA.External.StatusManager.mountPointList === null || + _.size(OCA.External.StatusManager.mountStatus) !== _.size(OCA.External.StatusManager.mountPointList)) { + // Will be the very first check when the files view will be loaded + OCA.External.StatusManager.launchFullConnectivityCheckOneByOne(); + } else { + // When we change between general files view and external files view + OCA.External.StatusManager.getMountPointList(function(){ + var fileNames = []; + $.each(e.$files, function(key, value){ + fileNames.push(value.attr('data-file')); + }); + // Recheck if launched but work from cache + OCA.External.StatusManager.recheckConnectivityForMount(fileNames, false); + }); + } + } + }); + } + /* End Status Manager */ }); diff --git a/apps/files_external/js/rollingqueue.js b/apps/files_external/js/rollingqueue.js new file mode 100644 index 00000000000..58cb0fb22f0 --- /dev/null +++ b/apps/files_external/js/rollingqueue.js @@ -0,0 +1,137 @@ +/** + * ownCloud + * + * @author Juan Pablo Villafañez Ramos <jvillafanez@owncloud.com> + * @author Jesus Macias Portela <jesus@owncloud.com> + * @copyright (C) 2014 ownCloud, Inc. + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +(function(){ +/** + * Launch several functions at thee same time. The number of functions + * running at the same time is controlled by the queueWindow param + * + * The function list come in the following format: + * + * var flist = [ + * { + * funcName: function () { + * var d = $.Deferred(); + * setTimeout(function(){d.resolve();}, 1000); + * return d; + * } + * }, + * { + * funcName: $.get, + * funcArgs: [ + * OC.filePath('files_external', 'ajax', 'connectivityCheck.php'), + * {}, + * function () { + * console.log('titoooo'); + * } + * ] + * }, + * { + * funcName: $.get, + * funcArgs: [ + * OC.filePath('files_external', 'ajax', 'connectivityCheck.php') + * ], + * done: function () { + * console.log('yuupi'); + * }, + * always: function () { + * console.log('always done'); + * } + * } + *]; + * + * functions MUST implement the deferred interface + * + * @param functionList list of functions that the queue will run + * (check example above for the expected format) + * @param queueWindow specify the number of functions that will + * be executed at the same time + */ +var RollingQueue = function (functionList, queueWindow, callback) { + this.queueWindow = queueWindow || 1; + this.functionList = functionList; + this.callback = callback; + this.counter = 0; + this.runQueue = function() { + this.callbackCalled = false; + this.deferredsList = []; + if (!$.isArray(this.functionList)) { + throw "functionList must be an array"; + } + + for (i = 0; i < this.queueWindow; i++) { + this.launchNext(); + } + }; + + this.hasNext = function() { + return (this.counter in this.functionList); + }; + + this.launchNext = function() { + var currentCounter = this.counter++; + if (currentCounter in this.functionList) { + var funcData = this.functionList[currentCounter]; + if ($.isFunction(funcData.funcName)) { + var defObj = funcData.funcName.apply(funcData.funcName, funcData.funcArgs); + this.deferredsList.push(defObj); + if ($.isFunction(funcData.done)) { + defObj.done(funcData.done); + } + + if ($.isFunction(funcData.fail)) { + defObj.fail(funcData.fail); + } + + if ($.isFunction(funcData.always)) { + defObj.always(funcData.always); + } + + if (this.hasNext()) { + var self = this; + defObj.always(function(){ + _.defer($.proxy(function(){ + self.launchNext(); + }, self)); + }); + } else { + if (!this.callbackCalled) { + this.callbackCalled = true; + if ($.isFunction(this.callback)) { + $.when.apply($, this.deferredsList) + .always($.proxy(function(){ + this.callback(); + }, this) + ); + } + } + } + return defObj; + } + } + return false; + }; +}; + +if (!OCA.External) { + OCA.External = {}; +} + +if (!OCA.External.StatusManager) { + OCA.External.StatusManager = {}; +} + +OCA.External.StatusManager.RollingQueue = RollingQueue; + +})();
\ No newline at end of file diff --git a/apps/files_external/js/statusmanager.js b/apps/files_external/js/statusmanager.js new file mode 100644 index 00000000000..4048bfc31bc --- /dev/null +++ b/apps/files_external/js/statusmanager.js @@ -0,0 +1,539 @@ +/** + * ownCloud + * + * @author Juan Pablo Villafañez Ramos <jvillafanez@owncloud.com> + * @author Jesus Macias Portela <jesus@owncloud.com> + * @copyright (C) 2014 ownCloud, Inc. + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +if (!OCA.External) { + OCA.External = {}; +} + +if (!OCA.External.StatusManager) { + OCA.External.StatusManager = {}; +} + +OCA.External.StatusManager = { + + mountStatus : null, + mountPointList : null, + + /** + * Function + * @param {callback} afterCallback + */ + + getMountStatus : function(afterCallback) { + var self = this; + if (typeof afterCallback !== 'function' || self.isGetMountStatusRunning) { + return; + } + + if (self.mountStatus) { + afterCallback(self.mountStatus); + } + }, + + /** + * Function Check mount point status from cache + * @param {string} mount_point + */ + + getMountPointListElement : function(mount_point) { + var element; + $.each(this.mountPointList, function(key, value){ + if (value.mount_point === mount_point) { + element = value; + return false; + } + }); + return element; + }, + + /** + * Function Check mount point status from cache + * @param {string} mount_point + * @param {string} mount_point + */ + + getMountStatusForMount : function(mountData, afterCallback) { + var self = this; + if (typeof afterCallback !== 'function' || self.isGetMountStatusRunning) { + return $.Deferred().resolve(); + } + + var defObj; + if (self.mountStatus[mountData.mount_point]) { + defObj = $.Deferred(); + afterCallback(mountData, self.mountStatus[mountData.mount_point]); + defObj.resolve(); // not really useful, but it'll keep the same behaviour + } else { + defObj = $.ajax({ + type : 'GET', + url: OC.webroot + '/index.php/apps/files_external/' + ((mountData.type === 'personal') ? 'userstorages' : 'globalstorages') + '/' + mountData.id, + success : function(response) { + if (response && response.status === 0) { + self.mountStatus[mountData.mount_point] = response; + } else { + if (response && response.statusMessage) { + // failure response with error message + self.mountStatus[mountData.mount_point] = { type: mountData.type, + status: 1, + error: response.statusMessage}; + } else { + self.mountStatus[mountData.mount_point] = { type: mountData.type, + status: 1, + error: t('files_external', 'Empty response from the server')}; + } + } + afterCallback(mountData, self.mountStatus[mountData.mount_point]); + }, + error : function(jqxhr, state, error) { + var message; + if(mountData.location === 3){ + // In this case the error is because mount point use Login credentials and don't exist in the session + message = t('files_external', 'Couldn\'t access. Please logout and login to activate this mount point'); + } else { + message = t('files_external', 'Couldn\'t get the information from the ownCloud server: {code} {type}', {code: jqxhr.status, type: error}); + } + self.mountStatus[mountData.mount_point] = { type: mountData.type, + status: 1, + location: mountData.location, + error: message}; + afterCallback(mountData, self.mountStatus[mountData.mount_point]); + } + }); + } + return defObj; + }, + + /** + * Function to get external mount point list from the files_external API + * @param {function} afterCallback function to be executed + */ + + getMountPointList : function(afterCallback) { + var self = this; + if (typeof afterCallback !== 'function' || self.isGetMountPointListRunning) { + return; + } + + if (self.mountPointList) { + afterCallback(self.mountPointList); + } else { + self.isGetMountPointListRunning = true; + $.ajax({ + type : 'GET', + url : OC.linkToOCS('apps/files_external/api/v1') + 'mounts?format=json', + success : function(response) { + self.mountPointList = []; + _.each(response.ocs.data, function(mount){ + var element = {}; + element.mount_point = mount.name; + element.type = mount.scope; + element.location = ""; + element.id = mount.id; + element.backendText = mount.backend; + element.backend = mount.class; + + self.mountPointList.push(element); + }); + afterCallback(self.mountPointList); + }, + error : function(jqxhr, state, error) { + self.mountPointList = []; + OC.Notification.showTemporary(t('files_external', 'Couldn\'t get the list of external mount points: {type}', {type : error})); + }, + complete : function() { + self.isGetMountPointListRunning = false; + } + }); + } + }, + + /** + * Function to manage action when a mountpoint status = 1 (Errored). Show a dialog to be redirected to settings page. + * @param {string} name MountPoint Name + */ + + manageMountPointError : function(name) { + var self = this; + this.getMountStatus($.proxy(function(allMountStatus) { + if (typeof allMountStatus[name] !== 'undefined' || allMountStatus[name].status === 1) { + var mountData = allMountStatus[name]; + if (mountData.type === "system") { + OC.dialogs.confirm(t('files_external', 'There was an error with message: ') + mountData.error + '. Do you want to review mount point config in admin settings page?', t('files_external', 'External mount error'), function(e){ + if(e === true) { + window.location.href = OC.generateUrl('/settings/admin#files_external'); + } + }); + } else { + OC.dialogs.confirm(t('files_external', 'There was an error with message: ') + mountData.error + '. Do you want to review mount point config in personal settings page?', t('files_external', 'External mount error'), function(e){ + if(e === true) { + window.location.href = OC.generateUrl('/settings/personal#' + t('files_external', 'goto-external-storage')); + } + }); + } + } + }, this)); + }, + + /** + * Function to process a mount point in relation with their status, Called from Async Queue. + * @param {object} mountData + * @param {object} mountStatus + */ + + processMountStatusIndividual : function(mountData, mountStatus) { + + var mountPoint = mountData.mount_point; + if (mountStatus.status === 1) { + var trElement = FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(mountPoint)); + + route = OCA.External.StatusManager.Utils.getIconRoute(trElement) + '-error'; + + if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) { + OCA.External.StatusManager.Utils.showIconError(mountPoint, $.proxy(OCA.External.StatusManager.manageMountPointError, OCA.External.StatusManager), route); + } + return false; + } else { + if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) { + OCA.External.StatusManager.Utils.restoreFolder(mountPoint); + OCA.External.StatusManager.Utils.toggleLink(mountPoint, true, true); + } + return true; + } + }, + + /** + * Function to process a mount point in relation with their status + * @param {object} mountData + * @param {object} mountStatus + */ + + processMountList : function(mountList) { + var elementList = null; + $.each(mountList, function(name, value){ + var trElement = $('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(value.mount_point) + '\"]'); //FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(value.mount_point)); + trElement.attr('data-external-backend', value.backend); + if (elementList) { + elementList = elementList.add(trElement); + } else { + elementList = trElement; + } + }); + + if (elementList instanceof $) { + if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) { + // Put their custom icon + OCA.External.StatusManager.Utils.changeFolderIcon(elementList); + // Save default view + OCA.External.StatusManager.Utils.storeDefaultFolderIconAndBgcolor(elementList); + // Disable row until check status + elementList.addClass('externalDisabledRow'); + OCA.External.StatusManager.Utils.toggleLink(elementList.find('a.name'), false, false); + } + } + }, + + /** + * Function to process the whole mount point list in relation with their status (Async queue) + */ + + launchFullConnectivityCheckOneByOne : function() { + var self = this; + this.getMountPointList(function(list){ + // check if we have a list first + if (list === undefined && !self.emptyWarningShown) { + self.emptyWarningShown = true; + OC.Notification.showTemporary(t('files_external', 'Couldn\'t get the list of Windows network drive mount points: empty response from the server')); + return; + } + if (list && list.length > 0) { + self.processMountList(list); + + if (!self.mountStatus) { + self.mountStatus = {}; + } + + var ajaxQueue = []; + $.each(list, function(key, value){ + var queueElement = {funcName: $.proxy(self.getMountStatusForMount, self), + funcArgs: [value, + $.proxy(self.processMountStatusIndividual, self)]}; + ajaxQueue.push(queueElement); + }); + + var rolQueue = new OCA.External.StatusManager.RollingQueue(ajaxQueue, 4, function(){ + if (!self.notificationHasShown) { + var showNotification = false; + $.each(self.mountStatus, function(key, value){ + if (value.status === 1) { + self.notificationHasShown = true; + showNotification = true; + } + }); + if (showNotification) { + OC.Notification.showTemporary(t('files_external', 'Some of the configured external mount points are not connected. Please click on the red row(s) for more information')); + } + } + }); + rolQueue.runQueue(); + } + }); + }, + + + /** + * Function to process a mount point list in relation with their status (Async queue) + * @param {object} mountListData + * @param {boolean} recheck delete cached info and force api call to check mount point status + */ + + launchPartialConnectivityCheck : function(mountListData, recheck) { + if (mountListData.length === 0) { + return; + } + + var self = this; + var ajaxQueue = []; + $.each(mountListData, function(key, value){ + if (recheck && value.mount_point in self.mountStatus) { + delete self.mountStatus[value.mount_point]; + } + var queueElement = {funcName: $.proxy(self.getMountStatusForMount, self), + funcArgs: [value, + $.proxy(self.processMountStatusIndividual, self)]}; + ajaxQueue.push(queueElement); + }); + new OCA.External.StatusManager.RollingQueue(ajaxQueue, 4).runQueue(); + }, + + + /** + * Function to relaunch some mount point status check + * @param {string} mountListNames + * @param {boolean} recheck delete cached info and force api call to check mount point status + */ + + recheckConnectivityForMount : function(mountListNames, recheck) { + if (mountListNames.length === 0) { + return; + } + + var self = this; + var mountListData = []; + var recheckPersonalGlobal = false; + var recheckAdminGlobal = false; + + if (!self.mountStatus) { + self.mountStatus = {}; + } + + $.each(mountListNames, function(key, value){ + var mountData = self.getMountPointListElement(value); + if (mountData) { + mountListData.push(mountData); + } + }); + + // for all mounts in the list, delete the cached status values + if (recheck) { + $.each(mountListData, function(key, value){ + if (value.mount_point in self.mountStatus) { + delete self.mountStatus[value.mount_point]; + } + }); + } + + self.processMountList(mountListData); + self.launchPartialConnectivityCheck(mountListData, recheck); + } +}; + +OCA.External.StatusManager.Utils = { + + showIconError: function(folder, clickAction, errorImageUrl) { + var imageUrl = "url(" + errorImageUrl + ")"; + var trFolder = $('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(folder) + '\"]'); //FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(folder)); + this.changeFolderIcon(folder, imageUrl); + this.toggleLink(folder, false, clickAction); + trFolder.addClass('externalErroredRow'); + }, + + /** + * @param folder string with the folder or jQuery element pointing to the tr element + */ + storeDefaultFolderIconAndBgcolor: function(folder) { + var trFolder; + if (folder instanceof $) { + trFolder = folder; + } else { + trFolder = $('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(folder) + '\"]'); //FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(folder)); //$('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(folder) + '\"]'); + } + trFolder.each(function(){ + var thisElement = $(this); + if (thisElement.data('oldbgcolor') === undefined) { + thisElement.data('oldbgcolor', thisElement.css('background-color')); + } + }); + + var icon = trFolder.find('td:first-child div.thumbnail'); + icon.each(function(){ + var thisElement = $(this); + if (thisElement.data('oldImage') === undefined) { + thisElement.data('oldImage', thisElement.css('background-image')); + } + }); + }, + + /** + * @param folder string with the folder or jQuery element pointing to the tr element + */ + restoreFolder: function(folder) { + var trFolder; + if (folder instanceof $) { + trFolder = folder; + } else { + // cant use here FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(folder)); return incorrect instance of filelist + trFolder = $('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(folder) + '\"]'); + } + trFolder.removeClass('externalErroredRow').removeClass('externalDisabledRow'); + tdChilds = trFolder.find("td:first-child div.thumbnail"); + tdChilds.each(function(){ + var thisElement = $(this); + thisElement.css('background-image', thisElement.data('oldImage')); + }); + }, + + /** + * @param folder string with the folder or jQuery element pointing to the first td element + * of the tr matching the folder name + */ + changeFolderIcon: function(filename) { + var file; + var route; + if (filename instanceof $) { + //trElementList + $.each(filename, function(index){ + route = OCA.External.StatusManager.Utils.getIconRoute($(this)); + $(this).attr("data-icon", route); + $(this).find('td:first-child div.thumbnail').css('background-image', "url(" + route + ")").css('display', 'none').css('display', 'inline'); + }); + } else { + file = $("#fileList tr[data-file=\"" + this.jqSelEscape(filename) + "\"] > td:first-child div.thumbnail"); + parentTr = file.parents('tr:first'); + route = OCA.External.StatusManager.Utils.getIconRoute(parentTr); + parentTr.attr("data-icon", route); + file.css('background-image', "url(" + route + ")").css('display', 'none').css('display', 'inline'); + } + }, + + /** + * @param backend string with the name of the external storage backend + * of the tr matching the folder name + */ + getIconRoute: function(tr) { + var icon = OC.imagePath('core', 'filetypes/folder-external'); + var backend = null; + + if (tr instanceof $) { + backend = tr.attr('data-external-backend'); + } + + switch (backend) { + case 'smb': + icon = OC.imagePath('windows_network_drive', 'folder-windows'); + break; + case 'sharepoint': + icon = OC.imagePath('sharepoint', 'folder-sharepoint'); + break; + case 'amazons3': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + case 'dav': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + case 'dropbox': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + case 'ftp': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + case 'google': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + case 'owncloud': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + case 'sftp': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + case 'swift': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + } + + return icon; + }, + + toggleLink: function(filename, active, action) { + var link; + if (filename instanceof $) { + link = filename; + } else { + link = $("#fileList tr[data-file=\"" + this.jqSelEscape(filename) + "\"] > td:first-child a.name"); + } + if (active) { + link.off('click.connectivity'); + OCA.Files.App.fileList.fileActions.display(link.parent(), true, OCA.Files.App.fileList); + } else { + link.find('.fileactions, .nametext .action').remove(); // from files/js/fileactions (display) + link.off('click.connectivity'); + link.on('click.connectivity', function(e){ + if (action && $.isFunction(action)) { + action(filename); + } + e.preventDefault(); + return false; + }); + } + }, + + isCorrectViewAndRootFolder: function() { + // correct views = files & extstoragemounts + if (OCA.Files.App.getActiveView() === 'files' || OCA.Files.App.getActiveView() === 'extstoragemounts') { + return OCA.Files.App.getCurrentAppContainer().find('#dir').val() === '/'; + } + return false; + }, + + /* escape a selector expression for jQuery */ + jqSelEscape: function(expression) { + if(expression){ + return expression.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~]/g, '\\$&'); + } + return null; + }, + + /* Copied from http://stackoverflow.com/questions/2631001/javascript-test-for-existence-of-nested-object-key */ + checkNested: function(cobj /*, level1, level2, ... levelN*/) { + var args = Array.prototype.slice.call(arguments), + obj = args.shift(); + + for (var i = 0; i < args.length; i++) { + if (!obj || !obj.hasOwnProperty(args[i])) { + return false; + } + obj = obj[args[i]]; + } + return true; + } +}; diff --git a/apps/files_external/l10n/es.js b/apps/files_external/l10n/es.js index 1d49d7b13b8..6d8bf0d3139 100644 --- a/apps/files_external/l10n/es.js +++ b/apps/files_external/l10n/es.js @@ -1,13 +1,23 @@ OC.L10N.register( "files_external", { + "Fetching request tokens failed. Verify that your app key and secret are correct." : "Fallo al acceder a los tokens solicitados. Verfique que su clave de app y la clave secreta son correctas.", + "Fetching access tokens failed. Verify that your app key and secret are correct." : "Fallo al acceder a los tokens solicitados. Verfique que su clave de app y la clave secreta son correctas.", + "Please provide a valid app key and secret." : "Por favor facilite una clave de app y una clave secreta válidas.", "Step 1 failed. Exception: %s" : "El paso 1 falló. Excepción: %s", "Step 2 failed. Exception: %s" : "El paso 2 falló. Excepción: %s", "External storage" : "Almacenamiento externo", "Storage with id \"%i\" not found" : "No se ha encontrado almacenamiento con id \"%i\"", + "Invalid backend or authentication mechanism class" : "Sistema o mecanismo de autentificación inválido", "Invalid mount point" : "Punto de montaje no válido", + "Objectstore forbidden" : "Objeto de almacenaje prohibido", "Invalid storage backend \"%s\"" : "Motor de almacenamiento no válido «%s»", - "Not permitted to use authentication mechanism \"%s\"" : "No está permitido usar el mecanismo de autenticación \"%s\"", + "Not permitted to use backend \"%s\"" : "No se permite usar el mecanismo \"%s\"", + "Not permitted to use authentication mechanism \"%s\"" : "No está permitido usar el mecanismo de autentificación \"%s\"", + "Unsatisfied backend parameters" : "Los parámetros del sistema no son válidos", + "Unsatisfied authentication mechanism parameters" : "Los parámetros del mecanismo de autentificación no son válidos", + "Insufficient data: %s" : "Datos insuficientes: %s", + "%s" : "%s", "Personal" : "Personal", "System" : "Sistema", "Grant access" : "Conceder acceso", @@ -84,7 +94,7 @@ OC.L10N.register( "Scope" : "Ámbito", "External Storage" : "Almacenamiento externo", "Folder name" : "Nombre de la carpeta", - "Authentication" : "Autenticación", + "Authentication" : "Autentificación", "Configuration" : "Configuración", "Available for" : "Disponible para", "Add storage" : "Añadir almacenamiento", diff --git a/apps/files_external/l10n/es.json b/apps/files_external/l10n/es.json index 1c60cd5fdea..bf0624e96db 100644 --- a/apps/files_external/l10n/es.json +++ b/apps/files_external/l10n/es.json @@ -1,11 +1,21 @@ { "translations": { + "Fetching request tokens failed. Verify that your app key and secret are correct." : "Fallo al acceder a los tokens solicitados. Verfique que su clave de app y la clave secreta son correctas.", + "Fetching access tokens failed. Verify that your app key and secret are correct." : "Fallo al acceder a los tokens solicitados. Verfique que su clave de app y la clave secreta son correctas.", + "Please provide a valid app key and secret." : "Por favor facilite una clave de app y una clave secreta válidas.", "Step 1 failed. Exception: %s" : "El paso 1 falló. Excepción: %s", "Step 2 failed. Exception: %s" : "El paso 2 falló. Excepción: %s", "External storage" : "Almacenamiento externo", "Storage with id \"%i\" not found" : "No se ha encontrado almacenamiento con id \"%i\"", + "Invalid backend or authentication mechanism class" : "Sistema o mecanismo de autentificación inválido", "Invalid mount point" : "Punto de montaje no válido", + "Objectstore forbidden" : "Objeto de almacenaje prohibido", "Invalid storage backend \"%s\"" : "Motor de almacenamiento no válido «%s»", - "Not permitted to use authentication mechanism \"%s\"" : "No está permitido usar el mecanismo de autenticación \"%s\"", + "Not permitted to use backend \"%s\"" : "No se permite usar el mecanismo \"%s\"", + "Not permitted to use authentication mechanism \"%s\"" : "No está permitido usar el mecanismo de autentificación \"%s\"", + "Unsatisfied backend parameters" : "Los parámetros del sistema no son válidos", + "Unsatisfied authentication mechanism parameters" : "Los parámetros del mecanismo de autentificación no son válidos", + "Insufficient data: %s" : "Datos insuficientes: %s", + "%s" : "%s", "Personal" : "Personal", "System" : "Sistema", "Grant access" : "Conceder acceso", @@ -82,7 +92,7 @@ "Scope" : "Ámbito", "External Storage" : "Almacenamiento externo", "Folder name" : "Nombre de la carpeta", - "Authentication" : "Autenticación", + "Authentication" : "Autentificación", "Configuration" : "Configuración", "Available for" : "Disponible para", "Add storage" : "Añadir almacenamiento", diff --git a/apps/files_external/l10n/fr.js b/apps/files_external/l10n/fr.js index 8ff4fcdfdd9..8d5f7e911b7 100644 --- a/apps/files_external/l10n/fr.js +++ b/apps/files_external/l10n/fr.js @@ -17,6 +17,7 @@ OC.L10N.register( "Unsatisfied backend parameters" : "Paramètres manquants pour le service", "Unsatisfied authentication mechanism parameters" : "Paramètres manquants pour la méthode d'authentification", "Insufficient data: %s" : "Données insuffisantes : %s", + "%s" : "%s", "Personal" : "Personnel", "System" : "Système", "Grant access" : "Autoriser l'accès", diff --git a/apps/files_external/l10n/fr.json b/apps/files_external/l10n/fr.json index 9a610bd964b..cae66119a4f 100644 --- a/apps/files_external/l10n/fr.json +++ b/apps/files_external/l10n/fr.json @@ -15,6 +15,7 @@ "Unsatisfied backend parameters" : "Paramètres manquants pour le service", "Unsatisfied authentication mechanism parameters" : "Paramètres manquants pour la méthode d'authentification", "Insufficient data: %s" : "Données insuffisantes : %s", + "%s" : "%s", "Personal" : "Personnel", "System" : "Système", "Grant access" : "Autoriser l'accès", diff --git a/apps/files_external/l10n/lt_LT.js b/apps/files_external/l10n/lt_LT.js index dabdeb8bd32..3a871070f45 100644 --- a/apps/files_external/l10n/lt_LT.js +++ b/apps/files_external/l10n/lt_LT.js @@ -3,6 +3,7 @@ OC.L10N.register( { "Fetching request tokens failed. Verify that your app key and secret are correct." : "Nepavyko atsiųsti užklausos žymės. Patikrinkite savo programos raktą ir paslaptį.", "Step 1 failed. Exception: %s" : "1 žingsnio klaida: %s", + "Step 2 failed. Exception: %s" : "2 žingsnio klaida: %s", "External storage" : "Išorinė saugykla", "Personal" : "Asmeniniai", "Grant access" : "Suteikti priėjimą", diff --git a/apps/files_external/l10n/lt_LT.json b/apps/files_external/l10n/lt_LT.json index 2b05c277ee6..854f753acaf 100644 --- a/apps/files_external/l10n/lt_LT.json +++ b/apps/files_external/l10n/lt_LT.json @@ -1,6 +1,7 @@ { "translations": { "Fetching request tokens failed. Verify that your app key and secret are correct." : "Nepavyko atsiųsti užklausos žymės. Patikrinkite savo programos raktą ir paslaptį.", "Step 1 failed. Exception: %s" : "1 žingsnio klaida: %s", + "Step 2 failed. Exception: %s" : "2 žingsnio klaida: %s", "External storage" : "Išorinė saugykla", "Personal" : "Asmeniniai", "Grant access" : "Suteikti priėjimą", diff --git a/apps/files_external/l10n/nl.js b/apps/files_external/l10n/nl.js index 05d1a3f6de5..5051689216f 100644 --- a/apps/files_external/l10n/nl.js +++ b/apps/files_external/l10n/nl.js @@ -17,6 +17,7 @@ OC.L10N.register( "Unsatisfied backend parameters" : "Onvoldoende backend parameters", "Unsatisfied authentication mechanism parameters" : "Onvoldoende authenticatiemechanisme parameters", "Insufficient data: %s" : "Onvoldoende gegevens: %s", + "%s" : "%s", "Personal" : "Persoonlijk", "System" : "Systeem", "Grant access" : "Sta toegang toe", diff --git a/apps/files_external/l10n/nl.json b/apps/files_external/l10n/nl.json index e30870e4ae1..d8a254bad1b 100644 --- a/apps/files_external/l10n/nl.json +++ b/apps/files_external/l10n/nl.json @@ -15,6 +15,7 @@ "Unsatisfied backend parameters" : "Onvoldoende backend parameters", "Unsatisfied authentication mechanism parameters" : "Onvoldoende authenticatiemechanisme parameters", "Insufficient data: %s" : "Onvoldoende gegevens: %s", + "%s" : "%s", "Personal" : "Persoonlijk", "System" : "Systeem", "Grant access" : "Sta toegang toe", diff --git a/apps/files_external/l10n/th_TH.js b/apps/files_external/l10n/th_TH.js index 6c1efa5aacd..bb9c2dc909d 100644 --- a/apps/files_external/l10n/th_TH.js +++ b/apps/files_external/l10n/th_TH.js @@ -17,6 +17,7 @@ OC.L10N.register( "Unsatisfied backend parameters" : "พารามิเตอร์แบ็กเอนด์ไม่ได้รับอนุญาต", "Unsatisfied authentication mechanism parameters" : "การรับรองความถูกต้องไม่เพียงพอ", "Insufficient data: %s" : "ข้อมูลไม่เพียงพอ: %s", + "%s" : "%s", "Personal" : "ส่วนตัว", "System" : "ระบบ", "Grant access" : "อนุญาตให้เข้าถึงได้", diff --git a/apps/files_external/l10n/th_TH.json b/apps/files_external/l10n/th_TH.json index 3de48d733d3..f38d99ae88b 100644 --- a/apps/files_external/l10n/th_TH.json +++ b/apps/files_external/l10n/th_TH.json @@ -15,6 +15,7 @@ "Unsatisfied backend parameters" : "พารามิเตอร์แบ็กเอนด์ไม่ได้รับอนุญาต", "Unsatisfied authentication mechanism parameters" : "การรับรองความถูกต้องไม่เพียงพอ", "Insufficient data: %s" : "ข้อมูลไม่เพียงพอ: %s", + "%s" : "%s", "Personal" : "ส่วนตัว", "System" : "ระบบ", "Grant access" : "อนุญาตให้เข้าถึงได้", diff --git a/apps/files_external/lib/api.php b/apps/files_external/lib/api.php index af9b802e522..f0c9e568c9e 100644 --- a/apps/files_external/lib/api.php +++ b/apps/files_external/lib/api.php @@ -28,7 +28,7 @@ class Api { /** * Formats the given mount config to a mount entry. - * + * * @param string $mountPoint mount point name, relative to the data dir * @param array $mountConfig mount config to format * @@ -59,7 +59,9 @@ class Api { 'type' => 'dir', 'backend' => $mountConfig['backend'], 'scope' => ( $isSystemMount ? 'system' : 'personal' ), - 'permissions' => $permissions + 'permissions' => $permissions, + 'id' => $mountConfig['id'], + 'class' => $mountConfig['class'] ); return $entry; } diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index f58cd9849f2..a94840ead59 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -33,7 +33,6 @@ use Icewind\SMB\Exception\Exception; use Icewind\SMB\Exception\NotFoundException; use Icewind\SMB\NativeServer; use Icewind\SMB\Server; -use Icewind\Streams\CallbackWrapper; use Icewind\Streams\IteratorDirectory; use OC\Files\Filesystem; diff --git a/apps/files_external/lib/storageconfig.php b/apps/files_external/lib/storageconfig.php index 97e0386be73..49a40a9a5d7 100644 --- a/apps/files_external/lib/storageconfig.php +++ b/apps/files_external/lib/storageconfig.php @@ -163,7 +163,7 @@ class StorageConfig implements \JsonSerializable { } /** - * @param Backend + * @param Backend $backend */ public function setBackend(Backend $backend) { $this->backend= $backend; @@ -177,7 +177,7 @@ class StorageConfig implements \JsonSerializable { } /** - * @param AuthMechanism + * @param AuthMechanism $authMechanism */ public function setAuthMechanism(AuthMechanism $authMechanism) { $this->authMechanism = $authMechanism; diff --git a/apps/files_external/lib/swift.php b/apps/files_external/lib/swift.php index e946e7feb77..a64a02a4ed9 100644 --- a/apps/files_external/lib/swift.php +++ b/apps/files_external/lib/swift.php @@ -354,9 +354,18 @@ class Swift extends \OC\Files\Storage\Common { } $tmpFile = \OCP\Files::tmpFile($ext); \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); - if ($this->file_exists($path)) { + // Fetch existing file if required + if ($mode[0] !== 'w' && $this->file_exists($path)) { + if ($mode[0] === 'x') { + // File cannot already exist + return false; + } $source = $this->fopen($path, 'r'); file_put_contents($tmpFile, $source); + // Seek to end if required + if ($mode[0] === 'a') { + fseek($tmpFile, 0, SEEK_END); + } } self::$tmpFiles[$tmpFile] = $path; diff --git a/apps/files_external/list.php b/apps/files_external/list.php index b98db79de89..4bbe5588c26 100644 --- a/apps/files_external/list.php +++ b/apps/files_external/list.php @@ -23,6 +23,11 @@ OCP\User::checkLoggedIn(); $tmpl = new OCP\Template('files_external', 'list', ''); +/* Load Status Manager */ +\OCP\Util::addStyle('files_external', 'external'); +\OCP\Util::addScript('files_external', 'statusmanager'); +\OCP\Util::addScript('files_external', 'rollingqueue'); + OCP\Util::addScript('files_external', 'app'); OCP\Util::addScript('files_external', 'mountsfilelist'); diff --git a/apps/files_external/tests/amazons3migration.php b/apps/files_external/tests/amazons3migration.php index 33fb6119a92..cc47107c7fe 100644 --- a/apps/files_external/tests/amazons3migration.php +++ b/apps/files_external/tests/amazons3migration.php @@ -130,6 +130,9 @@ class AmazonS3Migration extends \Test\TestCase { return $storages; } + /** + * @param string $id + */ public function deleteStorage($id) { $stmt = \OC::$server->getDatabaseConnection()->prepare( 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?' diff --git a/apps/files_external/tests/controller/storagescontrollertest.php b/apps/files_external/tests/controller/storagescontrollertest.php index 8a7acf81009..747bcd46e17 100644 --- a/apps/files_external/tests/controller/storagescontrollertest.php +++ b/apps/files_external/tests/controller/storagescontrollertest.php @@ -48,6 +48,9 @@ abstract class StoragesControllerTest extends \Test\TestCase { \OC_Mount_Config::$skipTest = false; } + /** + * @return \OCA\Files_External\Lib\Backend\Backend + */ protected function getBackendMock($class = '\OCA\Files_External\Lib\Backend\SMB', $storageClass = '\OC\Files\Storage\SMB') { $backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend') ->disableOriginalConstructor() @@ -59,6 +62,9 @@ abstract class StoragesControllerTest extends \Test\TestCase { return $backend; } + /** + * @return \OCA\Files_External\Lib\Auth\AuthMechanism + */ protected function getAuthMechMock($scheme = 'null', $class = '\OCA\Files_External\Lib\Auth\NullMechanism') { $authMech = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism') ->disableOriginalConstructor() diff --git a/apps/files_external/tests/service/backendservicetest.php b/apps/files_external/tests/service/backendservicetest.php index 5097b479a5f..e9cb0e2c368 100644 --- a/apps/files_external/tests/service/backendservicetest.php +++ b/apps/files_external/tests/service/backendservicetest.php @@ -35,6 +35,11 @@ class BackendServiceTest extends \Test\TestCase { $this->l10n = $this->getMock('\OCP\IL10N'); } + /** + * @param string $class + * + * @return \OCA\Files_External\Lib\Backend\Backend + */ protected function getBackendMock($class) { $backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend') ->disableOriginalConstructor() diff --git a/apps/files_sharing/appinfo/application.php b/apps/files_sharing/appinfo/application.php index ffe3a6a513f..6af450405a3 100644 --- a/apps/files_sharing/appinfo/application.php +++ b/apps/files_sharing/appinfo/application.php @@ -25,7 +25,6 @@ namespace OCA\Files_Sharing\AppInfo; -use OCA\Files_Sharing\Helper; use OCA\Files_Sharing\MountProvider; use OCP\AppFramework\App; use OC\AppFramework\Utility\SimpleContainer; diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js index 0b78d200b94..70c1ba5c0c2 100644 --- a/apps/files_sharing/js/public.js +++ b/apps/files_sharing/js/public.js @@ -102,12 +102,12 @@ OCA.Sharing.PublicApp = { // dynamically load image previews var bottomMargin = 350; - var previewWidth = Math.ceil($(window).width() * window.devicePixelRatio); - var previewHeight = Math.ceil(($(window).height() - bottomMargin) * window.devicePixelRatio); + var previewWidth = $(window).width(); + var previewHeight = $(window).height() - bottomMargin; previewHeight = Math.max(200, previewHeight); var params = { - x: previewWidth, - y: previewHeight, + x: Math.ceil(previewWidth * window.devicePixelRatio), + y: Math.ceil(previewHeight * window.devicePixelRatio), a: 'true', file: encodeURIComponent(this.initialDir + $('#filename').val()), t: token, @@ -115,6 +115,10 @@ OCA.Sharing.PublicApp = { }; var img = $('<img class="publicpreview" alt="">'); + img.css({ + 'max-width': previewWidth, + 'max-height': previewHeight + }); var fileSize = parseInt($('#filesize').val(), 10); var maxGifSize = parseInt($('#maxSizeAnimateGif').val(), 10); diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index 2e615e231f1..c9032413783 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -98,7 +98,7 @@ class Shared_Cache extends Cache { /** * get the stored metadata of a file or folder * - * @param string|int $file + * @param string $file * @return array|false */ public function get($file) { diff --git a/apps/files_sharing/lib/controllers/externalsharescontroller.php b/apps/files_sharing/lib/controllers/externalsharescontroller.php index edf065ab476..ec576065669 100644 --- a/apps/files_sharing/lib/controllers/externalsharescontroller.php +++ b/apps/files_sharing/lib/controllers/externalsharescontroller.php @@ -45,7 +45,6 @@ class ExternalSharesController extends Controller { /** * @param string $appName * @param IRequest $request - * @param bool $incomingShareEnabled * @param \OCA\Files_Sharing\External\Manager $externalManager * @param IClientService $clientService */ @@ -84,7 +83,7 @@ class ExternalSharesController extends Controller { * @NoAdminRequired * @NoOutgoingFederatedSharingRequired * - * @param $id + * @param integer $id * @return JSONResponse */ public function destroy($id) { diff --git a/apps/files_sharing/lib/controllers/sharecontroller.php b/apps/files_sharing/lib/controllers/sharecontroller.php index 4b446d79ada..fe7b159449c 100644 --- a/apps/files_sharing/lib/controllers/sharecontroller.php +++ b/apps/files_sharing/lib/controllers/sharecontroller.php @@ -124,7 +124,7 @@ class ShareController extends Controller { * @UseSession * * Authenticates against password-protected shares - * @param $token + * @param string $token * @param string $password * @return RedirectResponse|TemplateResponse */ diff --git a/apps/files_sharing/lib/middleware/sharingcheckmiddleware.php b/apps/files_sharing/lib/middleware/sharingcheckmiddleware.php index 22b9d32a275..04dd28574d6 100644 --- a/apps/files_sharing/lib/middleware/sharingcheckmiddleware.php +++ b/apps/files_sharing/lib/middleware/sharingcheckmiddleware.php @@ -27,7 +27,6 @@ namespace OCA\Files_Sharing\Middleware; use OCP\App\IAppManager; use OCP\AppFramework\Http\NotFoundResponse; use OCP\AppFramework\Middleware; -use OCP\AppFramework\Http\TemplateResponse; use OCP\Files\NotFoundException; use OCP\IConfig; use OCP\AppFramework\Utility\IControllerMethodReflector; diff --git a/apps/files_sharing/lib/sharedmount.php b/apps/files_sharing/lib/sharedmount.php index 275fea97c7f..f205b1e78a5 100644 --- a/apps/files_sharing/lib/sharedmount.php +++ b/apps/files_sharing/lib/sharedmount.php @@ -48,6 +48,12 @@ class SharedMount extends MountPoint implements MoveableMount { */ private $user; + /** + * @param string $storage + * @param string $mountpoint + * @param array|null $arguments + * @param \OCP\Files\Storage\IStorageFactory $loader + */ public function __construct($storage, $mountpoint, $arguments = null, $loader = null) { $this->user = $arguments['user']; $this->recipientView = new View('/' . $this->user . '/files'); @@ -59,6 +65,9 @@ class SharedMount extends MountPoint implements MoveableMount { /** * check if the parent folder exists otherwise move the mount point up + * + * @param array $share + * @return string */ private function verifyMountPoint(&$share) { @@ -121,6 +130,7 @@ class SharedMount extends MountPoint implements MoveableMount { * * @param string $path the absolute path * @return string e.g. turns '/admin/files/test.txt' into '/test.txt' + * @throws \OCA\Files_Sharing\Exceptions\BrokenPath */ protected function stripUserFilesPath($path) { $trimmed = ltrim($path, '/'); @@ -183,7 +193,7 @@ class SharedMount extends MountPoint implements MoveableMount { */ public function removeMount() { $mountManager = \OC\Files\Filesystem::getMountManager(); - /** @var \OC\Files\Storage\Shared */ + /** @var $storage \OC\Files\Storage\Shared */ $storage = $this->getStorage(); $result = $storage->unshareStorage(); $mountManager->removeMount($this->mountPoint); @@ -191,7 +201,12 @@ class SharedMount extends MountPoint implements MoveableMount { return $result; } + /** + * @return array + */ public function getShare() { - return $this->getStorage()->getShare(); + /** @var $storage \OC\Files\Storage\Shared */ + $storage = $this->getStorage(); + return $storage->getShare(); } } diff --git a/apps/files_sharing/lib/sharedstorage.php b/apps/files_sharing/lib/sharedstorage.php index 4807b5ee738..cda3f564d5f 100644 --- a/apps/files_sharing/lib/sharedstorage.php +++ b/apps/files_sharing/lib/sharedstorage.php @@ -32,8 +32,6 @@ namespace OC\Files\Storage; use OC\Files\Filesystem; use OCA\Files_Sharing\ISharedStorage; -use OCA\Files_Sharing\Propagator; -use OCA\Files_Sharing\SharedMount; use OCP\Lock\ILockingProvider; /** diff --git a/apps/files_sharing/tests/api/shareestest.php b/apps/files_sharing/tests/api/shareestest.php index a3e3a6dee6d..96ffe4682c0 100644 --- a/apps/files_sharing/tests/api/shareestest.php +++ b/apps/files_sharing/tests/api/shareestest.php @@ -88,6 +88,11 @@ class ShareesTest extends TestCase { ); } + /** + * @param string $uid + * @param string $displayName + * @return \OCP\IUser|\PHPUnit_Framework_MockObject_MockObject + */ protected function getUserMock($uid, $displayName) { $user = $this->getMockBuilder('OCP\IUser') ->disableOriginalConstructor() @@ -104,6 +109,10 @@ class ShareesTest extends TestCase { return $user; } + /** + * @param string $gid + * @return \OCP\IGroup|\PHPUnit_Framework_MockObject_MockObject + */ protected function getGroupMock($gid) { $group = $this->getMockBuilder('OCP\IGroup') ->disableOriginalConstructor() diff --git a/apps/files_sharing/tests/locking.php b/apps/files_sharing/tests/locking.php index 3b8900f2061..ad7b6b3e8a3 100644 --- a/apps/files_sharing/tests/locking.php +++ b/apps/files_sharing/tests/locking.php @@ -24,7 +24,6 @@ namespace OCA\Files_sharing\Tests; use OC\Files\Filesystem; use OC\Files\View; -use OC\Lock\MemcacheLockingProvider; use OCP\Lock\ILockingProvider; /** diff --git a/apps/files_sharing/tests/share.php b/apps/files_sharing/tests/share.php index b5ba0e3ad51..05013ad2e00 100644 --- a/apps/files_sharing/tests/share.php +++ b/apps/files_sharing/tests/share.php @@ -220,6 +220,10 @@ class Test_Files_Sharing extends OCA\Files_sharing\Tests\TestCase { } + /** + * @param OC\Files\FileInfo[] $content + * @param string[] $expected + */ public function verifyDirContent($content, $expected) { foreach ($content as $c) { if (!in_array($c['name'], $expected)) { diff --git a/apps/files_trashbin/lib/trashbin.php b/apps/files_trashbin/lib/trashbin.php index d492810b95f..bd6798f0eff 100644 --- a/apps/files_trashbin/lib/trashbin.php +++ b/apps/files_trashbin/lib/trashbin.php @@ -147,7 +147,7 @@ class Trashbin { * * @param string $sourcePath * @param string $owner - * @param $targetPath + * @param string $targetPath * @param $user * @param integer $timestamp */ @@ -214,13 +214,13 @@ class Trashbin { /** @var \OC\Files\Storage\Storage $sourceStorage */ list($sourceStorage, $sourceInternalPath) = $ownerView->resolvePath('/files/' . $ownerPath); try { - $sizeOfAddedFiles = $sourceStorage->filesize($sourceInternalPath); + $moveSuccessful = true; if ($trashStorage->file_exists($trashInternalPath)) { $trashStorage->unlink($trashInternalPath); } $trashStorage->moveFromStorage($sourceStorage, $sourceInternalPath, $trashInternalPath); } catch (\OCA\Files_Trashbin\Exceptions\CopyRecursiveException $e) { - $sizeOfAddedFiles = false; + $moveSuccessful = false; if ($trashStorage->file_exists($trashInternalPath)) { $trashStorage->unlink($trashInternalPath); } @@ -234,7 +234,7 @@ class Trashbin { $trashStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $trashInternalPath); - if ($sizeOfAddedFiles !== false) { + if ($moveSuccessful) { $query = \OC_DB::prepare("INSERT INTO `*PREFIX*files_trash` (`id`,`timestamp`,`location`,`user`) VALUES (?,?,?,?)"); $result = $query->execute(array($filename, $timestamp, $location, $owner)); if (!$result) { @@ -258,7 +258,7 @@ class Trashbin { self::scheduleExpire($owner); } - return ($sizeOfAddedFiles === false) ? false : true; + return $moveSuccessful; } /** @@ -268,18 +268,14 @@ class Trashbin { * @param string $owner owner user id * @param string $ownerPath path relative to the owner's home storage * @param integer $timestamp when the file was deleted - * - * @return int size of stored versions */ private static function retainVersions($filename, $owner, $ownerPath, $timestamp) { - $size = 0; if (\OCP\App::isEnabled('files_versions') && !empty($ownerPath)) { $user = \OCP\User::getUser(); $rootView = new \OC\Files\View('/'); if ($rootView->is_dir($owner . '/files_versions/' . $ownerPath)) { - $size += self::calculateSize(new \OC\Files\View('/' . $owner . '/files_versions/' . $ownerPath)); if ($owner !== $user) { self::copy_recursive($owner . '/files_versions/' . $ownerPath, $owner . '/files_trashbin/versions/' . basename($ownerPath) . '.d' . $timestamp, $rootView); } @@ -287,7 +283,6 @@ class Trashbin { } else if ($versions = \OCA\Files_Versions\Storage::getVersions($owner, $ownerPath)) { foreach ($versions as $v) { - $size += $rootView->filesize($owner . '/files_versions/' . $v['path'] . '.v' . $v['version']); if ($owner !== $user) { self::copy($rootView, $owner . '/files_versions' . $v['path'] . '.v' . $v['version'], $owner . '/files_trashbin/versions/' . $v['name'] . '.v' . $v['version'] . '.d' . $timestamp); } @@ -295,8 +290,6 @@ class Trashbin { } } } - - return $size; } /** @@ -417,7 +410,7 @@ class Trashbin { * @param string $uniqueFilename new file name to restore the file without overwriting existing files * @param string $location location if file * @param int $timestamp deletion time - * @return bool + * @return false|null */ private static function restoreVersions(\OC\Files\View $view, $file, $filename, $uniqueFilename, $location, $timestamp) { @@ -507,9 +500,10 @@ class Trashbin { /** * @param \OC\Files\View $view - * @param $file - * @param $filename - * @param $timestamp + * @param string $file + * @param string $filename + * @param integer|null $timestamp + * @param string $user * @return int */ private static function deleteVersions(\OC\Files\View $view, $file, $filename, $timestamp, $user) { @@ -633,18 +627,16 @@ class Trashbin { public static function expire($user) { $trashBinSize = self::getTrashbinSize($user); $availableSpace = self::calculateFreeSpace($trashBinSize, $user); - $size = 0; $dirContent = Helper::getTrashFiles('/', $user, 'mtime'); // delete all files older then $retention_obligation list($delSize, $count) = self::deleteExpiredFiles($dirContent, $user); - $size += $delSize; - $availableSpace += $size; + $availableSpace += $delSize; // delete files from trash until we meet the trash bin size limit again - $size += self::deleteFiles(array_slice($dirContent, $count), $user, $availableSpace); + self::deleteFiles(array_slice($dirContent, $count), $user, $availableSpace); } /** @@ -693,7 +685,7 @@ class Trashbin { * * @param array $files list of files sorted by mtime * @param string $user - * @return array size of deleted files and number of deleted files + * @return integer[] size of deleted files and number of deleted files */ public static function deleteExpiredFiles($files, $user) { $application = new Application(); diff --git a/apps/files_trashbin/tests/trashbin.php b/apps/files_trashbin/tests/trashbin.php index c53ed8d8a9b..db7e7e6e840 100644 --- a/apps/files_trashbin/tests/trashbin.php +++ b/apps/files_trashbin/tests/trashbin.php @@ -248,8 +248,8 @@ class Test_Trashbin extends \Test\TestCase { /** * verify that the array contains the expected results - * @param array $result - * @param array $expected + * @param OCP\Files\FileInfo[] $result + * @param string[] $expected */ private function verifyArray($result, $expected) { $this->assertSame(count($expected), count($result)); @@ -268,6 +268,11 @@ class Test_Trashbin extends \Test\TestCase { } } + /** + * @param OCP\Files\FileInfo[] $files + * @param string $trashRoot + * @param integer $expireDate + */ private function manipulateDeleteTime($files, $trashRoot, $expireDate) { $counter = 0; foreach ($files as &$file) { @@ -627,7 +632,6 @@ class Test_Trashbin extends \Test\TestCase { /** * @param string $user * @param bool $create - * @param bool $password */ public static function loginHelper($user, $create = false) { if ($create) { @@ -650,11 +654,20 @@ class Test_Trashbin extends \Test\TestCase { // just a dummy class to make protected methods available for testing class TrashbinForTesting extends Files_Trashbin\Trashbin { + + /** + * @param OCP\Files\FileInfo[] $files + * @param integer $limit + */ public function dummyDeleteExpiredFiles($files, $limit) { // dummy value for $retention_obligation because it is not needed here return parent::deleteExpiredFiles($files, \Test_Trashbin::TEST_TRASHBIN_USER1, $limit, 0); } + /** + * @param OCP\Files\FileInfo[] $files + * @param integer $availableSpace + */ public function dummyDeleteFiles($files, $availableSpace) { return parent::deleteFiles($files, \Test_Trashbin::TEST_TRASHBIN_USER1, $availableSpace); } diff --git a/apps/files_versions/lib/storage.php b/apps/files_versions/lib/storage.php index 6737bf20f90..29876b3e38a 100644 --- a/apps/files_versions/lib/storage.php +++ b/apps/files_versions/lib/storage.php @@ -649,7 +649,7 @@ class Storage { /** * Expire versions which exceed the quota * - * @param $filename + * @param string $filename * @param int|null $versionsSize * @param int $offset * @return bool|int|null diff --git a/apps/provisioning_api/tests/groupstest.php b/apps/provisioning_api/tests/groupstest.php index d37f4412e20..f4f3b194944 100644 --- a/apps/provisioning_api/tests/groupstest.php +++ b/apps/provisioning_api/tests/groupstest.php @@ -30,13 +30,13 @@ use OCP\IUserSession; use OCP\IRequest; class GroupsTest extends \Test\TestCase { - /** @var IGroupManager */ + /** @var IGroupManager|\PHPUnit_Framework_MockObject_MockObject */ protected $groupManager; - /** @var IUserSession */ + /** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */ protected $userSession; - /** @var IRequest */ + /** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */ protected $request; - /** @var \OC\SubAdmin */ + /** @var \OC\SubAdmin|\PHPUnit_Framework_MockObject_MockObject */ protected $subAdminManager; /** @var \OCA\Provisioning_API\Groups */ protected $api; @@ -58,6 +58,10 @@ class GroupsTest extends \Test\TestCase { ); } + /** + * @param string $gid + * @return \OCP\IGroup|\PHPUnit_Framework_MockObject_MockObject + */ private function createGroup($gid) { $group = $this->getMock('OCP\IGroup'); $group @@ -66,6 +70,10 @@ class GroupsTest extends \Test\TestCase { return $group; } + /** + * @param string $uid + * @return \OCP\IUser|\PHPUnit_Framework_MockObject_MockObject + */ private function createUser($uid) { $user = $this->getMock('OCP\IUser'); $user diff --git a/apps/user_ldap/ajax/testConfiguration.php b/apps/user_ldap/ajax/testConfiguration.php index f5fd5f23b87..47fc776983a 100644 --- a/apps/user_ldap/ajax/testConfiguration.php +++ b/apps/user_ldap/ajax/testConfiguration.php @@ -49,7 +49,7 @@ try { * pass (like e.g. expected syntax error). */ try { - $ldapWrapper->read($connection->getConnectionResource(), 'neverwhere', 'objectClass=*', array('dn')); + $ldapWrapper->read($connection->getConnectionResource(), '', 'objectClass=*', array('dn')); } catch (\Exception $e) { if($e->getCode() === 1) { OCP\JSON::error(array('message' => $l->t('The configuration is invalid: anonymous bind is not allowed.'))); diff --git a/apps/user_ldap/l10n/lt_LT.js b/apps/user_ldap/l10n/lt_LT.js index e27dcc3e8de..c263e952206 100644 --- a/apps/user_ldap/l10n/lt_LT.js +++ b/apps/user_ldap/l10n/lt_LT.js @@ -4,7 +4,9 @@ OC.L10N.register( "Failed to clear the mappings." : "Nepavyko išvalyti sąsajų.", "Failed to delete the server configuration" : "Nepavyko pašalinti serverio konfigūracijos", "The configuration is valid and the connection could be established!" : "Konfigūracija yra tinkama bei prisijungta sėkmingai!", + "The configuration is invalid. Please have a look at the logs for further details." : "Neteisinga konfigūracija. Daugiau informacijos rasite žurnaluose.", "No action specified" : "Nepasirinktas veiksmas", + "No data specified" : "Nepateikta duomenų", "Select groups" : "Pasirinkti grupes", "Do you really want to delete the current Server Configuration?" : "Ar tikrai norite ištrinti dabartinę serverio konfigūraciją?", "Confirm Deletion" : "Patvirtinkite trynimą", diff --git a/apps/user_ldap/l10n/lt_LT.json b/apps/user_ldap/l10n/lt_LT.json index fa1526c0632..64e2bae4670 100644 --- a/apps/user_ldap/l10n/lt_LT.json +++ b/apps/user_ldap/l10n/lt_LT.json @@ -2,7 +2,9 @@ "Failed to clear the mappings." : "Nepavyko išvalyti sąsajų.", "Failed to delete the server configuration" : "Nepavyko pašalinti serverio konfigūracijos", "The configuration is valid and the connection could be established!" : "Konfigūracija yra tinkama bei prisijungta sėkmingai!", + "The configuration is invalid. Please have a look at the logs for further details." : "Neteisinga konfigūracija. Daugiau informacijos rasite žurnaluose.", "No action specified" : "Nepasirinktas veiksmas", + "No data specified" : "Nepateikta duomenų", "Select groups" : "Pasirinkti grupes", "Do you really want to delete the current Server Configuration?" : "Ar tikrai norite ištrinti dabartinę serverio konfigūraciją?", "Confirm Deletion" : "Patvirtinkite trynimą", diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php index 42e57e8296e..667f1076235 100644 --- a/apps/user_ldap/lib/access.php +++ b/apps/user_ldap/lib/access.php @@ -177,7 +177,7 @@ class Access extends LDAPUtility implements user\IUserTools { //in case an error occurs , e.g. object does not exist return false; } - if (empty($attr)) { + if (empty($attr) && ($filter === 'objectclass=*' || $this->ldap->countEntries($cr, $rr) === 1)) { \OCP\Util::writeLog('user_ldap', 'readAttribute: '.$dn.' found', \OCP\Util::DEBUG); return array(); } diff --git a/apps/user_ldap/user_ldap.php b/apps/user_ldap/user_ldap.php index fc8ce361637..0097dda89b5 100644 --- a/apps/user_ldap/user_ldap.php +++ b/apps/user_ldap/user_ldap.php @@ -204,7 +204,7 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn $dn = $user->getDN(); //check if user really still exists by reading its entry - if(!is_array($this->access->readAttribute($dn, ''))) { + if(!is_array($this->access->readAttribute($dn, '', $this->access->connection->ldapUserFilter))) { $lcr = $this->access->connection->getConnectionResource(); if(is_null($lcr)) { throw new \Exception('No LDAP Connection to server ' . $this->access->connection->ldapHost); diff --git a/build/integration/run.sh b/build/integration/run.sh index 76c01068deb..5a222bda3e3 100755 --- a/build/integration/run.sh +++ b/build/integration/run.sh @@ -2,6 +2,9 @@ composer install +SCENARIO_TO_RUN=$1 +HIDE_OC_LOGS=$2 + # avoid port collision on jenkins - use $EXECUTOR_NUMBER if [ -z "$EXECUTOR_NUMBER" ]; then EXECUTOR_NUMBER=0 @@ -21,13 +24,15 @@ echo $PHPPID_FED export TEST_SERVER_URL="http://localhost:$PORT/ocs/" export TEST_SERVER_FED_URL="http://localhost:$PORT_FED/ocs/" -vendor/bin/behat -f junit -f pretty $1 +vendor/bin/behat -f junit -f pretty $SCENARIO_TO_RUN RESULT=$? kill $PHPPID kill $PHPPID_FED -tail "../../data/owncloud.log" +if [ -z $HIDE_OC_LOGS ]; then + tail "../../data/owncloud.log" +fi exit $RESULT diff --git a/config/config.sample.php b/config/config.sample.php index 034a1ebddbf..c3abe3a2b87 100644 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -214,6 +214,14 @@ $CONFIG = array( ), /** + * If your user backend does not allow to reset the password (e.g. when it's a + * read-only user backend like LDAP), you can specify a custom link, where the + * user is redirected to, when clicking the "reset password" link after a failed + * login-attempt. + */ +'lost_password_link' => 'https://example.org/link/to/password/reset', + +/** * Mail Parameters * * These configure the email settings for ownCloud notifications and password diff --git a/core/css/apps.css b/core/css/apps.css index e9abbe0aee1..9afd7044345 100644 --- a/core/css/apps.css +++ b/core/css/apps.css @@ -6,7 +6,7 @@ width: 100%; } #app * { - -moz-box-sizing: border-box; box-sizing: border-box; + box-sizing: border-box; } @@ -21,7 +21,7 @@ width: 250px; height: 100%; float: left; - -moz-box-sizing: border-box; box-sizing: border-box; + box-sizing: border-box; background-color: #fff; padding-bottom: 44px; -webkit-user-select: none; @@ -35,12 +35,12 @@ height: 100%; width: inherit; overflow: auto; - -moz-box-sizing: border-box; box-sizing: border-box; + box-sizing: border-box; } #app-navigation li { position: relative; width: 100%; - -moz-box-sizing: border-box; box-sizing: border-box; + box-sizing: border-box; } #app-navigation .active.with-menu > a, @@ -67,7 +67,7 @@ min-height: 44px; padding: 0 12px; overflow: hidden; - -moz-box-sizing: border-box; box-sizing: border-box; + box-sizing: border-box; white-space: nowrap; text-overflow: ellipsis; color: #000; @@ -109,17 +109,13 @@ } #app-navigation .collapsible .collapse { - -moz-transform: rotate(-90deg); -webkit-transform: rotate(-90deg); -ms-transform:rotate(-90deg); - -o-transform:rotate(-90deg); transform: rotate(-90deg); } #app-navigation .collapsible.open .collapse { - -moz-transform: rotate(0); -webkit-transform: rotate(0); -ms-transform:rotate(0); - -o-transform:rotate(0); transform: rotate(0); } @@ -138,8 +134,6 @@ #app-navigation .collapsible.open { background-image: linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%); - background-image: -o-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%); - background-image: -moz-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%); background-image: -webkit-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%); background-image: -ms-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%); } @@ -209,10 +203,7 @@ /* drag and drop */ #app-navigation .drag-and-drop { - -moz-transition: padding-bottom 500ms ease 0s; - -o-transition: padding-bottom 500ms ease 0s; -webkit-transition: padding-bottom 500ms ease 0s; - -ms-transition: padding-bottom 500ms ease 0s; transition: padding-bottom 500ms ease 0s; padding-bottom: 40px; } @@ -459,8 +450,6 @@ background: #fff; border-left: 1px solid #eee; -webkit-transition: margin-right 300ms; - -moz-transition: margin-right 300ms; - -o-transition: margin-right 300ms; transition: margin-right 300ms; overflow-x: hidden; overflow-y: auto; diff --git a/core/css/header.css b/core/css/header.css index 37f06ef0632..4a5db088f96 100644 --- a/core/css/header.css +++ b/core/css/header.css @@ -39,7 +39,6 @@ height: 45px; line-height: 2.5em; background-color: #1d2d44; - -moz-box-sizing: border-box; box-sizing: border-box; } @@ -54,7 +53,6 @@ padding: 5px; padding-bottom: 0; height: 45px; /* header height */ - -moz-box-sizing: border-box; box-sizing: border-box; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; opacity: 1; @@ -185,7 +183,6 @@ } #navigation, #navigation * { - -moz-box-sizing:border-box; box-sizing:border-box; } #navigation li { @@ -272,7 +269,6 @@ height: 100%; max-width: 80%; white-space: nowrap; - -moz-box-sizing: border-box; box-sizing: border-box; } @@ -330,7 +326,7 @@ border-radius: 3px; border-top-left-radius: 0; border-top-right-radius: 0; - -moz-box-sizing: border-box; box-sizing: border-box; + box-sizing: border-box; } #expanddiv a { display: block; @@ -339,7 +335,6 @@ padding: 4px 12px 0; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; opacity: .7; - -moz-box-sizing: border-box; box-sizing: border-box; } #expanddiv a img { diff --git a/core/css/icons.css b/core/css/icons.css index 14b2101b331..836a84fd70e 100644 --- a/core/css/icons.css +++ b/core/css/icons.css @@ -24,7 +24,6 @@ background-image: url('../img/loading-small.gif'); } .icon-32 { - -webkit-background-size: 32px !important; background-size: 32px !important; } @@ -47,10 +46,12 @@ .icon-checkmark { background-image: url('../img/actions/checkmark.svg'); } - .icon-checkmark-white { background-image: url('../img/actions/checkmark-white.svg'); } +.icon-checkmark-color { + background-image: url('../img/actions/checkmark-color.svg'); +} .icon-close { background-image: url('../img/actions/close.svg'); @@ -82,6 +83,16 @@ background-image: url('../img/actions/edit.svg'); } +.icon-error { + background-image: url('../img/actions/error.svg'); +} +.icon-error-white { + background-image: url('../img/actions/error-white.svg'); +} +.icon-error-color { + background-image: url('../img/actions/error-color.svg'); +} + .icon-external { background-image: url('../img/actions/external.svg'); } diff --git a/core/css/inputs.css b/core/css/inputs.css index 9f440a6c359..fe03af85f61 100644 --- a/core/css/inputs.css +++ b/core/css/inputs.css @@ -55,7 +55,7 @@ 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; + 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, @@ -108,10 +108,26 @@ 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:disabled + label:before { + background-image: url('../img/actions/checkbox-disabled.svg'); +} + +html:not(.ie8) input[type="checkbox"].checkbox:checked:disabled + label:before { + background-image: url('../img/actions/checkbox-checked-disabled.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--white:disabled + label:before { + background-image: url('../img/actions/checkbox-disabled-white.svg'); +} + +html:not(.ie8) input[type="checkbox"].checkbox--white:checked:disabled + label:before { + background-image: url('../img/actions/checkbox-checked-disabled.svg'); +} + html:not(.ie8) input[type="checkbox"].checkbox:hover+label:before, input[type="checkbox"]:focus+label:before { color:#111 !important; } @@ -119,7 +135,7 @@ html:not(.ie8) input[type="checkbox"].checkbox:hover+label:before, input[type="c input[type="time"] { width: initial; height: 31px; - -moz-box-sizing: border-box; box-sizing: border-box; + box-sizing: border-box; } select { diff --git a/core/css/mobile.css b/core/css/mobile.css index 288ae2979de..131907eb09d 100644 --- a/core/css/mobile.css +++ b/core/css/mobile.css @@ -46,7 +46,6 @@ .error-wide { width: 100%; margin-left: 0 !important; - -moz-box-sizing: border-box; box-sizing: border-box; } diff --git a/core/css/share.css b/core/css/share.css index 15f8061b068..55ee5996a75 100644 --- a/core/css/share.css +++ b/core/css/share.css @@ -125,8 +125,6 @@ a.unshare { .shareTabView .error { color: #e9322d; border-color: #e9322d; - -webkit-box-shadow: 0 0 6px #f8b9b7; - -moz-box-shadow: 0 0 6px #f8b9b7; box-shadow: 0 0 6px #f8b9b7; } diff --git a/core/css/styles.css b/core/css/styles.css index 640aab81d2a..62161d69273 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -26,11 +26,8 @@ body { #body-login { text-align: center; background: #1d2d44; /* Old browsers */ - background: -moz-linear-gradient(top, #35537a 0%, #1d2d44 100%); /* FF3.6+ */ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#35537a), color-stop(100%,#1d2d44)); /* Chrome,Safari4+ */ background: -webkit-linear-gradient(top, #35537a 0%,#1d2d44 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, #35537a 0%,#1d2d44 100%); /* Opera11.10+ */ - background: -ms-linear-gradient(top, #35537a 0%,#1d2d44 100%); /* IE10+ */ background: linear-gradient(top, #35537a 0%,#1d2d44 100%); /* W3C */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#35537a', endColorstr='#1d2d44',GradientType=0 ); /* IE6-9 */ } @@ -99,8 +96,6 @@ body { width: 0; cursor: pointer; -webkit-transition: all 100ms; - -moz-transition: all 100ms; - -o-transition: all 100ms; transition: all 100ms; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; opacity: .7; @@ -117,8 +112,6 @@ body { /* CONTENT ------------------------------------------------------------------ */ #controls { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; box-sizing: border-box; position: fixed; top: 45px; @@ -149,8 +142,6 @@ body { #controls input[type='text'], #controls input[type='password'], #controls select { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; box-sizing: border-box; display: inline-block; height: 36px; @@ -175,7 +166,6 @@ body { width: 100%; overflow-x: hidden; /* prevent horizontal scrollbar */ padding-top: 45px; - -moz-box-sizing:border-box; box-sizing:border-box; } /* allow horizontal scrollbar for personal and admin settings */ @@ -807,7 +797,7 @@ span.ui-icon {float: left; margin: 3px 7px 30px 0;} width: 100%; height: 30px; } #tagsdialog .bottombuttons * { float:left;} -#tagsdialog .taglist li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; -moz-transition:background-color 500ms; -o-transition:background-color 500ms; transition:background-color 500ms; } +#tagsdialog .taglist li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; transition:background-color 500ms; } #tagsdialog .taglist li:hover, #tagsdialog .taglist li:active { background:#eee; } #tagsdialog .addinput { width: 90%; clear: both; } @@ -826,9 +816,9 @@ span.ui-icon {float: left; margin: 3px 7px 30px 0;} .popup .close { position:absolute; top:0.2em; right:0.2em; height:20px; width:20px; background:url('../img/actions/close.svg') no-repeat center; } .popup h2 { font-size:20px; } .arrow { border-bottom:10px solid white; border-left:10px solid transparent; border-right:10px solid transparent; display:block; height:0; position:absolute; width:0; z-index:201; } -.arrow.left { left:-13px; bottom:1.2em; -webkit-transform:rotate(270deg); -moz-transform:rotate(270deg); -o-transform:rotate(270deg); -ms-transform:rotate(270deg); transform:rotate(270deg); } +.arrow.left { left:-13px; bottom:1.2em; -webkit-transform:rotate(270deg); -ms-transform:rotate(270deg); transform:rotate(270deg); } .arrow.up { top:-8px; right:6px; } -.arrow.down { -webkit-transform:rotate(180deg); -moz-transform:rotate(180deg); -o-transform:rotate(180deg); -ms-transform:rotate(180deg); transform:rotate(180deg); } +.arrow.down { -webkit-transform:rotate(180deg); -ms-transform:rotate(180deg); transform:rotate(180deg); } /* ---- BREADCRUMB ---- */ diff --git a/core/img/actions/add.svg b/core/img/actions/add.svg index ecbab6f13ac..c97431782fb 100644 --- a/core/img/actions/add.svg +++ b/core/img/actions/add.svg @@ -1,5 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> - <g transform="matrix(-0.70711,-0.70711,0.70711,-0.70711,-724.84998,753.15998)"> - <path d="m3.7547,1041.6,1.4142-1.4142,3.5355,3.5355,3.5355-3.5355,1.4142,1.4142-3.5355,3.5355,3.5355,3.5356-1.4142,1.4142-3.5355-3.5356-3.5164,3.5547-1.4333-1.4333,3.5355-3.5356z"/> + <g transform="matrix(-.70711 -.70711 .70711 -.70711 -724.85 753.16)"> + <path d="m3.7547 1041.6 1.4142-1.4142 3.5355 3.5355 3.5355-3.5355 1.4142 1.4142-3.5355 3.5355 3.5355 3.5356-1.4142 1.4142-3.5355-3.5356-3.5164 3.5547-1.4333-1.4333 3.5355-3.5356z"/> </g> </svg> diff --git a/core/img/actions/checkbox-checked-disabled.png b/core/img/actions/checkbox-checked-disabled.png Binary files differnew file mode 100644 index 00000000000..55980ba730d --- /dev/null +++ b/core/img/actions/checkbox-checked-disabled.png diff --git a/core/img/actions/checkbox-checked-disabled.svg b/core/img/actions/checkbox-checked-disabled.svg new file mode 100644 index 00000000000..de89df039dd --- /dev/null +++ b/core/img/actions/checkbox-checked-disabled.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + <path d="m2.5 2.5h11v11h-11z" fill="#fff"/> + <path d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm8.924 2.0664l1.433 1.4316-6.3648 6.365-4.2422-4.2439 1.4141-1.414 2.8281 2.8301 4.9318-4.9688z" fill="#969696"/> +</svg> diff --git a/core/img/actions/checkbox-checked.svg b/core/img/actions/checkbox-checked.svg index c5aa3cd73bb..c648957429e 100644 --- a/core/img/actions/checkbox-checked.svg +++ b/core/img/actions/checkbox-checked.svg @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> <path d="m2.5 2.5h11v11h-11z" fill="#fff"/> - <path fill="#55739a" d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm8.924 2.0664l1.433 1.4316-6.3648 6.365-4.2422-4.2439 1.4141-1.414 2.8281 2.8301 4.9318-4.9688z"/> + <path d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm8.924 2.0664l1.433 1.4316-6.3648 6.365-4.2422-4.2439 1.4141-1.414 2.8281 2.8301 4.9318-4.9688z" fill="#55739a"/> </svg> diff --git a/core/img/actions/checkbox-disabled-white.png b/core/img/actions/checkbox-disabled-white.png Binary files differnew file mode 100644 index 00000000000..e1f48439d27 --- /dev/null +++ b/core/img/actions/checkbox-disabled-white.png diff --git a/core/img/actions/checkbox-disabled-white.svg b/core/img/actions/checkbox-disabled-white.svg new file mode 100644 index 00000000000..52c2fee3b16 --- /dev/null +++ b/core/img/actions/checkbox-disabled-white.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + <path d="m2.5 2.5h11v11h-11z" fill="#dcdcdc"/> + <path d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm0 1h10v10h-10v-10z" fill="#fff"/> +</svg> diff --git a/core/img/actions/checkbox-disabled.png b/core/img/actions/checkbox-disabled.png Binary files differnew file mode 100644 index 00000000000..a2ead209965 --- /dev/null +++ b/core/img/actions/checkbox-disabled.png diff --git a/core/img/actions/checkbox-disabled.svg b/core/img/actions/checkbox-disabled.svg new file mode 100644 index 00000000000..48d31f591fd --- /dev/null +++ b/core/img/actions/checkbox-disabled.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + <path d="m2.5 2.5h11v11h-11z" fill="#dcdcdc"/> + <path d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm0 1h10v10h-10v-10z" fill="#969696"/> +</svg> diff --git a/core/img/actions/checkbox-mixed.svg b/core/img/actions/checkbox-mixed.svg index 7f3642912da..5f873d6a96e 100644 --- a/core/img/actions/checkbox-mixed.svg +++ b/core/img/actions/checkbox-mixed.svg @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> <path d="m2.5 2.5h11v11h-11z" fill="#fff"/> - <path fill="#969696" d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm1 5h8v2h-8v-2z"/> + <path d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm1 5h8v2h-8v-2z" fill="#969696"/> </svg> diff --git a/core/img/actions/checkbox.svg b/core/img/actions/checkbox.svg index fe8f727b899..bfb83e3708c 100644 --- a/core/img/actions/checkbox.svg +++ b/core/img/actions/checkbox.svg @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> <path d="m2.5 2.5h11v11h-11z" fill="#fff"/> - <path fill="#969696" d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm0 1h10v10h-10v-10z"/> + <path d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm0 1h10v10h-10v-10z" fill="#969696"/> </svg> diff --git a/core/img/actions/checkmark-color.png b/core/img/actions/checkmark-color.png Binary files differnew file mode 100644 index 00000000000..a8ab849cad7 --- /dev/null +++ b/core/img/actions/checkmark-color.png diff --git a/core/img/actions/checkmark-color.svg b/core/img/actions/checkmark-color.svg new file mode 100644 index 00000000000..584997f0ac3 --- /dev/null +++ b/core/img/actions/checkmark-color.svg @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="16px" viewBox="-0.5 -0.5 16 16" width="16px" version="1.1" y="0px" x="0px" xmlns:cc="http://creativecommons.org/ns#" enable-background="new -0.5 -0.5 16 16" overflow="visible" xmlns:dc="http://purl.org/dc/elements/1.1/"><g transform="matrix(-1 0 0 -1 17.451 1056.3)" fill="#00d400"><path d="m11.362 1043.8 4.9497 4.9499-1.4141 1.4141-3.5356-3.5355-6.3448 6.3831-1.4333-1.4333z" fill="#00d400"/></g></svg> diff --git a/core/img/actions/checkmark-white.svg b/core/img/actions/checkmark-white.svg index e6b63a4d599..964624a9ce4 100644 --- a/core/img/actions/checkmark-white.svg +++ b/core/img/actions/checkmark-white.svg @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" overflow="visible" height="16px" width="16px" version="1.1" y="0px" x="0px" xmlns:cc="http://creativecommons.org/ns#" enable-background="new -0.5 -0.5 16 16" viewBox="-0.5 -0.5 16 16" xmlns:dc="http://purl.org/dc/elements/1.1/"> -<path transform="translate(-.5 -.5)" d="m12.438 3.6875c-0.363 0-0.726 0.1314-1 0.4063l-4.5005 4.5-1.9687-2c-0.5498-0.5484-1.4489-0.5498-2 0l-0.5 0.5c-0.5512 0.5496-0.5512 1.4502 0 2l2.9687 2.9682c0.0063 0.007-0.0065 0.025 0 0.032l0.5 0.5c0.5497 0.55 1.4503 0.55 2 0l0.5-0.5 0.1875-0.219 5.313-5.2812c0.549-0.5498 0.549-1.4503 0-2l-0.5-0.5c-0.275-0.2749-0.638-0.4063-1-0.4063z" fill="#fff"/> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="16px" viewBox="-0.5 -0.5 16 16" width="16px" version="1.1" y="0px" x="0px" xmlns:cc="http://creativecommons.org/ns#" enable-background="new -0.5 -0.5 16 16" overflow="visible" xmlns:dc="http://purl.org/dc/elements/1.1/"> +<path fill="#fff" transform="translate(-.5 -.5)" d="m12.438 3.6875c-0.363 0-0.726 0.1314-1 0.4063l-4.5005 4.5-1.9687-2c-0.5498-0.5484-1.4489-0.5498-2 0l-0.5 0.5c-0.5512 0.5496-0.5512 1.4502 0 2l2.9687 2.9682c0.0063 0.007-0.0065 0.025 0 0.032l0.5 0.5c0.5497 0.55 1.4503 0.55 2 0l0.5-0.5 0.1875-0.219 5.313-5.2812c0.549-0.5498 0.549-1.4503 0-2l-0.5-0.5c-0.275-0.2749-0.638-0.4063-1-0.4063z"/> </svg> diff --git a/core/img/actions/checkmark.svg b/core/img/actions/checkmark.svg index 3fa2a3f1bab..e41472c8ef7 100644 --- a/core/img/actions/checkmark.svg +++ b/core/img/actions/checkmark.svg @@ -1,2 +1,2 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg xml:space="preserve" overflow="visible" height="16px" viewBox="-0.5 -0.5 16 16" xmlns:dc="http://purl.org/dc/elements/1.1/" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" y="0px" x="0px" enable-background="new -0.5 -0.5 16 16"><g transform="matrix(-1 0 0 -1 17.451 1056.3)"><path d="m11.362 1043.8 4.9497 4.9499-1.4141 1.4141-3.5356-3.5355-6.3448 6.3831-1.4333-1.4333z"/></g></svg> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="16px" viewBox="-0.5 -0.5 16 16" width="16px" version="1.1" y="0px" x="0px" xmlns:cc="http://creativecommons.org/ns#" enable-background="new -0.5 -0.5 16 16" overflow="visible" xmlns:dc="http://purl.org/dc/elements/1.1/"><g transform="matrix(-1 0 0 -1 17.451 1056.3)"><path d="m11.362 1043.8 4.9497 4.9499-1.4141 1.4141-3.5356-3.5355-6.3448 6.3831-1.4333-1.4333z"/></g></svg> diff --git a/core/img/actions/close.svg b/core/img/actions/close.svg index e060da3f8bb..fb49c6ac893 100644 --- a/core/img/actions/close.svg +++ b/core/img/actions/close.svg @@ -5,6 +5,6 @@ <feGaussianBlur stdDeviation="1.2386625"/> </filter> </defs> - <path d="m12.95 11.536-1.414 1.414-3.536-3.5358-3.5355 3.5358-1.4142-1.414 3.5355-3.536-3.5355-3.5356 1.4142-1.4142 3.5355 3.5356 3.516-3.5547 1.434 1.4333-3.5357 3.5356z" filter="url(#a)" stroke="#fff" stroke-width="2" fill="#fff"/> + <path filter="url(#a)" stroke="#fff" stroke-width="2" d="m12.95 11.536-1.414 1.414-3.536-3.5358-3.5355 3.5358-1.4142-1.414 3.5355-3.536-3.5355-3.5356 1.4142-1.4142 3.5355 3.5356 3.516-3.5547 1.434 1.4333-3.5357 3.5356z" fill="#fff"/> <path d="m12.95 11.536-1.414 1.414-3.536-3.5358-3.5355 3.5358-1.4142-1.414 3.5355-3.536-3.5355-3.5356 1.4142-1.4142 3.5355 3.5356 3.516-3.5547 1.434 1.4333-3.5357 3.5356z"/> </svg> diff --git a/core/img/actions/delete-hover.png b/core/img/actions/delete-hover.png Binary files differindex 3f8cb6eff92..ed12640df71 100644 --- a/core/img/actions/delete-hover.png +++ b/core/img/actions/delete-hover.png diff --git a/core/img/actions/delete-hover.svg b/core/img/actions/delete-hover.svg index 9583ec15b32..ecc6139a5e6 100644 --- a/core/img/actions/delete-hover.svg +++ b/core/img/actions/delete-hover.svg @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> - <path d="m6.5 1-0.5 1h-3c-0.554 0-1 0.446-1 1v1h12v-1c0-0.554-0.446-1-1-1h-3l-0.5-1zm-3.5 4 0.875 9c0.061 0.549 0.5729 1 1.125 1h6c0.55232 0 1.064-0.45102 1.125-1l0.875-9z" fill-rule="evenodd" fill="#d40000"/> + <path fill="#d40000" d="m6.5 1-0.5 1h-3c-0.554 0-1 0.446-1 1v1h12v-1c0-0.554-0.446-1-1-1h-3l-0.5-1zm-3.5 4 0.875 9c0.061 0.549 0.5729 1 1.125 1h6c0.55232 0 1.064-0.45102 1.125-1l0.875-9z" fill-rule="evenodd"/> </svg> diff --git a/core/img/actions/delete.png b/core/img/actions/delete.png Binary files differindex e891b370cca..20e894c7f74 100644 --- a/core/img/actions/delete.png +++ b/core/img/actions/delete.png diff --git a/core/img/actions/download.svg b/core/img/actions/download.svg index 0d698bca8dc..f8513b63f78 100644 --- a/core/img/actions/download.svg +++ b/core/img/actions/download.svg @@ -1,5 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> <g transform="translate(0 -1036.4)"> - <path d="m6,1037.4,4,0,0,7,5,0-7,7-7-7,5,0z"/> + <path d="m6 1037.4h4v7h5l-7 7-7-7h5z"/> </g> </svg> diff --git a/core/img/actions/error-color.png b/core/img/actions/error-color.png Binary files differnew file mode 100644 index 00000000000..7d00282312a --- /dev/null +++ b/core/img/actions/error-color.png diff --git a/core/img/actions/error-color.svg b/core/img/actions/error-color.svg new file mode 100644 index 00000000000..93cb9ffe0ad --- /dev/null +++ b/core/img/actions/error-color.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + <path d="m5.5156 2l-3.5156 3.5156v4.9684l3.5156 3.516h4.9684l3.516-3.516v-4.9684l-3.516-3.5156h-4.9684zm1.4844 2h2v5h-2v-5zm0 6h2v2h-2v-2z" fill="#d40000"/> +</svg> diff --git a/core/img/actions/error-white.png b/core/img/actions/error-white.png Binary files differnew file mode 100644 index 00000000000..6e15865401d --- /dev/null +++ b/core/img/actions/error-white.png diff --git a/core/img/actions/error-white.svg b/core/img/actions/error-white.svg new file mode 100644 index 00000000000..38c57f6e9c7 --- /dev/null +++ b/core/img/actions/error-white.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + <path d="m5.5156 2l-3.5156 3.5156v4.9684l3.5156 3.516h4.9684l3.516-3.516v-4.9684l-3.516-3.5156h-4.9684zm1.4844 2h2v5h-2v-5zm0 6h2v2h-2v-2z" fill="#fff"/> +</svg> diff --git a/core/img/actions/error.png b/core/img/actions/error.png Binary files differnew file mode 100644 index 00000000000..61df76b53ea --- /dev/null +++ b/core/img/actions/error.png diff --git a/core/img/actions/error.svg b/core/img/actions/error.svg new file mode 100644 index 00000000000..38e4053c333 --- /dev/null +++ b/core/img/actions/error.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + <path d="m5.5156 2l-3.5156 3.5156v4.9684l3.5156 3.516h4.9684l3.516-3.516v-4.9684l-3.516-3.5156h-4.9684zm1.4844 2h2v5h-2v-5zm0 6h2v2h-2v-2z"/> +</svg> diff --git a/core/img/actions/logout.png b/core/img/actions/logout.png Binary files differindex bada7a12616..ad230de98f4 100644 --- a/core/img/actions/logout.png +++ b/core/img/actions/logout.png diff --git a/core/img/actions/logout.svg b/core/img/actions/logout.svg index 1a0ee167184..96bd2072849 100644 --- a/core/img/actions/logout.svg +++ b/core/img/actions/logout.svg @@ -1,58 +1,4 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - height="16" - width="16" - version="1.0" - id="svg2" - inkscape:version="0.48.4 r9939" - sodipodi:docname="logout.svg" - inkscape:export-filename="logout.png" - inkscape:export-xdpi="179.59" - inkscape:export-ydpi="179.59"> - <metadata - id="metadata12"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs10" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1920" - inkscape:window-height="1002" - id="namedview8" - showgrid="false" - inkscape:zoom="22.5" - inkscape:cx="8" - inkscape:cy="8" - inkscape:window-x="0" - inkscape:window-y="34" - inkscape:window-maximized="1" - inkscape:current-layer="svg2" /> - <path - style="text-indent:0;text-transform:none;block-progression:tb;color:#000000;fill:#ffffff" - d="m 8.0001,4.5e-4 c -0.4714,0 -0.96103,0.5419 -0.95,1 v 6 c -0.00747,0.52831 0.42163,1 0.95,1 0.52837,0 0.95747,-0.47169 0.95,-1 v -6 c 0.014622,-0.6051 -0.4786,-1 -0.95,-1 z m -3.3438,2.5 C 4.569114,2.519744 4.48467,2.551409 4.4063,2.5942 1.4068,4.1657 0.4879,7.3921 1.2813,10.063 2.0747,12.733 4.5612,15 7.9688,15 11.328,15 13.846,12.851 14.688,10.219 15.529,7.5869 14.63,4.3956 11.563,2.625 11.129,2.3714 10.504,2.5351 10.25,2.9687 c -0.2536,0.4336 -0.09,1.0589 0.344,1.3125 2.3908,1.3798 2.8825,3.4944 2.2812,5.375 -0.6012,1.8806 -2.344,3.4375 -4.9062,3.4375 -2.5759,0 -4.2976,-1.6502 -4.875,-3.5938 C 2.5164,7.5563 3.047,5.4518 5.2813,4.2811 5.66,4.0748 5.8604,3.5886 5.7371,3.1754 5.6139,2.7621 5.1799,2.4651 4.7501,2.4999 4.7188,2.4984 4.6875,2.4984 4.6563,2.4999 z" - id="path6" - inkscape:connector-curvature="0" /> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.0" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + <path style="block-progression:tb;color:#000000;text-transform:none;text-indent:0" fill="#fff" d="m8.0001 0.00045c-0.4714 0-0.96103 0.5419-0.95 1v6c-0.00747 0.52831 0.42163 1 0.95 1s0.95747-0.47169 0.95-1v-6c0.014622-0.6051-0.4786-1-0.95-1zm-3.3438 2.5c-0.0872 0.0193-0.1716 0.051-0.25 0.0938-2.9995 1.5715-3.9184 4.7979-3.125 7.4688 0.7934 2.67 3.2799 4.937 6.6875 4.937 3.3592 0 5.8772-2.149 6.7192-4.781 0.841-2.6321-0.058-5.8234-3.125-7.594-0.434-0.2536-1.059-0.0899-1.313 0.3437-0.2536 0.4336-0.09 1.0589 0.344 1.3125 2.3908 1.3798 2.8825 3.4944 2.2812 5.375-0.6012 1.8806-2.344 3.4375-4.9062 3.4375-2.5759 0-4.2976-1.6502-4.875-3.5938-0.5776-1.9436-0.047-4.0481 2.1873-5.2188 0.3787-0.2063 0.5791-0.6925 0.4558-1.1057-0.1232-0.4133-0.5572-0.7103-0.987-0.6755-0.0313-0.0015-0.0626-0.0015-0.0938 0z"/> </svg> diff --git a/core/img/actions/menu.svg b/core/img/actions/menu.svg index f0e33df3737..24a057aac77 100644 --- a/core/img/actions/menu.svg +++ b/core/img/actions/menu.svg @@ -1,12 +1,4 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> - <metadata> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - <dc:title/> - </cc:Work> - </rdf:RDF> - </metadata> - <path d="m2,2,0,2,12,0,0-2zm0,5,0,2,12,0,0-2zm0,5,0,2,12,0,0-2z"/> + <path d="m2 2v2h12v-2zm0 5v2h12v-2zm0 5v2h12v-2z"/> </svg> diff --git a/core/img/actions/public.svg b/core/img/actions/public.svg index 99a71c6cb5b..7721c9e3408 100644 --- a/core/img/actions/public.svg +++ b/core/img/actions/public.svg @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> <g transform="matrix(.67042 -.67042 .67042 .67042 .62542 93.143)"> - <path style="block-progression:tb;text-indent:0;color:#000000;text-transform:none" d="m69.5-61.5c-1.9217 0-3.5 1.5783-3.5 3.5 0 0.17425 0.0062 0.33232 0.03125 0.5h2.0625c-0.053-0.156-0.094-0.323-0.094-0.5 0-0.8483 0.6517-1.5 1.5-1.5h5c0.8483 0 1.5 0.6517 1.5 1.5s-0.6517 1.5-1.5 1.5h-1.6875c-0.28733 0.79501-0.78612 1.4793-1.4375 2h3.125c1.9217 0 3.5-1.5783 3.5-3.5s-1.5783-3.5-3.5-3.5h-5z"/> - <path style="block-progression:tb;text-indent:0;color:#000000;text-transform:none" d="m68.5-54.5c1.9217 0 3.5-1.5783 3.5-3.5 0-0.17425-0.0062-0.33232-0.03125-0.5h-2.0625c0.053 0.156 0.094 0.323 0.094 0.5 0 0.8483-0.6517 1.5-1.5 1.5h-5c-0.8483 0-1.5-0.6517-1.5-1.5s0.6517-1.5 1.5-1.5h1.6875c0.28733-0.79501 0.78612-1.4793 1.4375-2h-3.125c-1.9217 0-3.5 1.5783-3.5 3.5s1.5783 3.5 3.5 3.5h5z"/> + <path style="block-progression:tb;color:#000000;text-transform:none;text-indent:0" d="m69.5-61.5c-1.9217 0-3.5 1.5783-3.5 3.5 0 0.17425 0.0062 0.33232 0.03125 0.5h2.0625c-0.053-0.156-0.094-0.323-0.094-0.5 0-0.8483 0.6517-1.5 1.5-1.5h5c0.8483 0 1.5 0.6517 1.5 1.5s-0.6517 1.5-1.5 1.5h-1.6875c-0.28733 0.79501-0.78612 1.4793-1.4375 2h3.125c1.9217 0 3.5-1.5783 3.5-3.5s-1.5783-3.5-3.5-3.5h-5z"/> + <path style="block-progression:tb;color:#000000;text-transform:none;text-indent:0" d="m68.5-54.5c1.9217 0 3.5-1.5783 3.5-3.5 0-0.17425-0.0062-0.33232-0.03125-0.5h-2.0625c0.053 0.156 0.094 0.323 0.094 0.5 0 0.8483-0.6517 1.5-1.5 1.5h-5c-0.8483 0-1.5-0.6517-1.5-1.5s0.6517-1.5 1.5-1.5h1.6875c0.28733-0.79501 0.78612-1.4793 1.4375-2h-3.125c-1.9217 0-3.5 1.5783-3.5 3.5s1.5783 3.5 3.5 3.5h5z"/> </g> </svg> diff --git a/core/img/actions/radio-checked-disabled.png b/core/img/actions/radio-checked-disabled.png Binary files differnew file mode 100644 index 00000000000..09abc410f61 --- /dev/null +++ b/core/img/actions/radio-checked-disabled.png diff --git a/core/img/actions/radio-checked-disabled.svg b/core/img/actions/radio-checked-disabled.svg new file mode 100644 index 00000000000..294f8a74773 --- /dev/null +++ b/core/img/actions/radio-checked-disabled.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + <path d="m8 1.5c-3.5899 0-6.5 2.9101-6.5 6.5s2.9101 6.5 6.5 6.5 6.5-2.9101 6.5-6.5-2.91-6.5-6.5-6.5z" fill="#fff"/> + <path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 1a6 6 0 0 1 6 6 6 6 0 0 1 -6 6 6 6 0 0 1 -6 -6 6 6 0 0 1 6 -6zm0 2c-2.2091 0-4 1.7909-4 4 0 2.209 1.7909 4 4 4 2.209 0 4-1.791 4-4 0-2.2091-1.791-4-4-4z" fill="#969696"/> +</svg> diff --git a/core/img/actions/radio-checked.png b/core/img/actions/radio-checked.png Binary files differnew file mode 100644 index 00000000000..94933b7b69c --- /dev/null +++ b/core/img/actions/radio-checked.png diff --git a/core/img/actions/radio-checked.svg b/core/img/actions/radio-checked.svg new file mode 100644 index 00000000000..31011c0ea22 --- /dev/null +++ b/core/img/actions/radio-checked.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + <path d="m8 1.5c-3.5899 0-6.5 2.9101-6.5 6.5s2.9101 6.5 6.5 6.5 6.5-2.9101 6.5-6.5-2.91-6.5-6.5-6.5z" fill="#fff"/> + <path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 1a6 6 0 0 1 6 6 6 6 0 0 1 -6 6 6 6 0 0 1 -6 -6 6 6 0 0 1 6 -6zm0 2c-2.2091 0-4 1.7909-4 4 0 2.209 1.7909 4 4 4 2.209 0 4-1.791 4-4 0-2.2091-1.791-4-4-4z" fill="#55739a"/> +</svg> diff --git a/core/img/actions/radio-disabled.png b/core/img/actions/radio-disabled.png Binary files differnew file mode 100644 index 00000000000..ac7f49ed533 --- /dev/null +++ b/core/img/actions/radio-disabled.png diff --git a/core/img/actions/radio-disabled.svg b/core/img/actions/radio-disabled.svg new file mode 100644 index 00000000000..6058bb73fc5 --- /dev/null +++ b/core/img/actions/radio-disabled.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + <path d="m8 1.5c-3.5899 0-6.5 2.9101-6.5 6.5s2.9101 6.5 6.5 6.5 6.5-2.9101 6.5-6.5-2.91-6.5-6.5-6.5z" fill="#dcdcdc"/> + <path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 1a6 6 0 0 1 6 6 6 6 0 0 1 -6 6 6 6 0 0 1 -6 -6 6 6 0 0 1 6 -6z" fill="#969696"/> +</svg> diff --git a/core/img/actions/radio-white.png b/core/img/actions/radio-white.png Binary files differnew file mode 100644 index 00000000000..04beefdff01 --- /dev/null +++ b/core/img/actions/radio-white.png diff --git a/core/img/actions/radio-white.svg b/core/img/actions/radio-white.svg new file mode 100644 index 00000000000..57611f4cdd0 --- /dev/null +++ b/core/img/actions/radio-white.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + <path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 1a6 6 0 0 1 6 6 6 6 0 0 1 -6 6 6 6 0 0 1 -6 -6 6 6 0 0 1 6 -6z" fill="#fff"/> +</svg> diff --git a/core/img/actions/radio.png b/core/img/actions/radio.png Binary files differnew file mode 100644 index 00000000000..70ac4741b97 --- /dev/null +++ b/core/img/actions/radio.png diff --git a/core/img/actions/radio.svg b/core/img/actions/radio.svg new file mode 100644 index 00000000000..9df89251763 --- /dev/null +++ b/core/img/actions/radio.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + <path d="m8 1.5c-3.5899 0-6.5 2.9101-6.5 6.5s2.9101 6.5 6.5 6.5 6.5-2.9101 6.5-6.5-2.91-6.5-6.5-6.5z" fill="#fff"/> + <path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 1a6 6 0 0 1 6 6 6 6 0 0 1 -6 6 6 6 0 0 1 -6 -6 6 6 0 0 1 6 -6z" fill="#969696"/> +</svg> diff --git a/core/img/actions/starred.svg b/core/img/actions/starred.svg index 130bab366a2..07e38827b2d 100644 --- a/core/img/actions/starred.svg +++ b/core/img/actions/starred.svg @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="22" width="22" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> <g transform="matrix(.068322 0 0 .068322 -10.114 -50.902)"> - <path d="m330.36 858.43 43.111 108.06 117.64 9.2572-89.445 74.392 27.55 114.75-98.391-62.079-100.62 61.66 28.637-112.76-89.734-76.638 116.09-7.6094z" transform="translate(-21.071,-112.5)" fill="#FC0"/> + <path fill="#FC0" d="m330.36 858.43 43.111 108.06 117.64 9.2572-89.445 74.392 27.55 114.75-98.391-62.079-100.62 61.66 28.637-112.76-89.734-76.638 116.09-7.6094z" transform="translate(-21.071,-112.5)"/> </g> </svg> diff --git a/core/img/actions/toggle.svg b/core/img/actions/toggle.svg index 730464a72ca..c426ab8099e 100644 --- a/core/img/actions/toggle.svg +++ b/core/img/actions/toggle.svg @@ -1,2 +1,2 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 16 9" xml:space="preserve" overflow="visible" height="16" width="16" version="1.1" y="0px" x="0px" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 16 16"><path fill="#222" d="m8 3c-3.109 0-5.927 1.719-8 4.5 2.073 2.781 4.891 4.5 8 4.5 3.111 0 5.927-1.719 8-4.5-2.073-2.781-4.891-4.5-8-4.5zm0 1.5c1.657 0 3 1.343 3 3s-1.343 3-3 3-3-1.343-3-3 1.343-3 3-3zm0 1.5c-0.8284 0-1.5 0.6716-1.5 1.5s0.6716 1.5 1.5 1.5 1.5-0.6716 1.5-1.5-0.6716-1.5-1.5-1.5z"/></svg> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="16" viewBox="0 0 16 16" width="16" version="1.1" y="0px" x="0px" xmlns:cc="http://creativecommons.org/ns#" enable-background="new 0 0 16 9" overflow="visible" xmlns:dc="http://purl.org/dc/elements/1.1/"><path d="m8 3c-3.109 0-5.927 1.719-8 4.5 2.073 2.781 4.891 4.5 8 4.5 3.111 0 5.927-1.719 8-4.5-2.073-2.781-4.891-4.5-8-4.5zm0 1.5c1.657 0 3 1.343 3 3s-1.343 3-3 3-3-1.343-3-3 1.343-3 3-3zm0 1.5c-0.8284 0-1.5 0.6716-1.5 1.5s0.6716 1.5 1.5 1.5 1.5-0.6716 1.5-1.5-0.6716-1.5-1.5-1.5z" fill="#222"/></svg> diff --git a/core/img/actions/view-close.png b/core/img/actions/view-close.png Binary files differindex 0874381a576..eae9acc7a43 100644 --- a/core/img/actions/view-close.png +++ b/core/img/actions/view-close.png diff --git a/core/img/actions/view-close.svg b/core/img/actions/view-close.svg index 2b91e382eb1..e7dde9b79bb 100644 --- a/core/img/actions/view-close.svg +++ b/core/img/actions/view-close.svg @@ -5,6 +5,6 @@ <feGaussianBlur stdDeviation="2.2386623"/> </filter> </defs> - <path d="m24.955 23.538-1.414 1.414-7.536-7.5358-7.5355 7.5358-1.4142-1.414 7.5355-7.536-7.5355-7.5356 1.4142-1.4142 7.5355 7.5356 7.516-7.5547 1.434 1.4333-7.5357 7.5356z" filter="url(#a)" stroke="#000" stroke-width="2"/> + <path filter="url(#a)" stroke="#000" stroke-width="2" d="m24.955 23.538-1.414 1.414-7.536-7.5358-7.5355 7.5358-1.4142-1.414 7.5355-7.536-7.5355-7.5356 1.4142-1.4142 7.5355 7.5356 7.516-7.5547 1.434 1.4333-7.5357 7.5356z"/> <path d="m24.955 23.538-1.414 1.414-7.536-7.5358-7.5355 7.5358-1.4142-1.414 7.5355-7.536-7.5355-7.5356 1.4142-1.4142 7.5355 7.5356 7.516-7.5547 1.434 1.4333-7.5357 7.5356z" fill="#fff"/> </svg> diff --git a/core/img/actions/view-next.png b/core/img/actions/view-next.png Binary files differindex d8c749bec9b..be8cc15cecd 100644 --- a/core/img/actions/view-next.png +++ b/core/img/actions/view-next.png diff --git a/core/img/actions/view-next.svg b/core/img/actions/view-next.svg index 4b719842efd..713d1bc7574 100644 --- a/core/img/actions/view-next.svg +++ b/core/img/actions/view-next.svg @@ -5,6 +5,6 @@ <feGaussianBlur stdDeviation="2.4158278"/> </filter> </defs> - <path d="m10.414 28.952-1.414-1.414 11.535-11.536-11.535-11.536 1.414-1.4138 12.95 12.95z" filter="url(#a)" stroke="#000" stroke-width="2"/> + <path filter="url(#a)" stroke="#000" stroke-width="2" d="m10.414 28.952-1.414-1.414 11.535-11.536-11.535-11.536 1.414-1.4138 12.95 12.95z"/> <path d="m10.414 28.952-1.414-1.414 11.535-11.536-11.535-11.536 1.414-1.4138 12.95 12.95z" fill="#fff"/> </svg> diff --git a/core/img/actions/view-pause.png b/core/img/actions/view-pause.png Binary files differindex 87a18128ade..94cd1a5dc6c 100644 --- a/core/img/actions/view-pause.png +++ b/core/img/actions/view-pause.png diff --git a/core/img/actions/view-pause.svg b/core/img/actions/view-pause.svg index e9ff43be0bf..8945bf4565a 100644 --- a/core/img/actions/view-pause.svg +++ b/core/img/actions/view-pause.svg @@ -5,10 +5,10 @@ <feGaussianBlur stdDeviation="2.5"/> </filter> </defs> - <g transform="matrix(.9 0 0 .9 1.6 -916.76)" filter="url(#a)" stroke="#000" stroke-width="2.2222"> - <path d="m6 1026.4v20h8v-20h-8zm12 0v20h8v-20h-8z" stroke="#000" stroke-width="2.2222"/> + <g filter="url(#a)" stroke="#000" stroke-width="2.2222" transform="matrix(.9 0 0 .9 1.6 -916.76)"> + <path stroke="#000" stroke-width="2.2222" d="m6 1026.4v20h8v-20h-8zm12 0v20h8v-20h-8z"/> </g> <g transform="matrix(.9 0 0 .9 1.6 -916.76)"> - <path fill="#fff" d="m6 1026.4v20h8v-20h-8zm12 0v20h8v-20h-8z"/> + <path d="m6 1026.4v20h8v-20h-8zm12 0v20h8v-20h-8z" fill="#fff"/> </g> </svg> diff --git a/core/img/actions/view-play.png b/core/img/actions/view-play.png Binary files differindex b07c6de3cfd..a8398d5758f 100644 --- a/core/img/actions/view-play.png +++ b/core/img/actions/view-play.png diff --git a/core/img/actions/view-play.svg b/core/img/actions/view-play.svg index e617e29cb01..6359e6d018f 100644 --- a/core/img/actions/view-play.svg +++ b/core/img/actions/view-play.svg @@ -5,10 +5,10 @@ <feGaussianBlur stdDeviation="3"/> </filter> </defs> - <g transform="matrix(.83333 0 0 .83333 2.6667 -847.67)" filter="url(#a)" stroke="#000" stroke-width="2.4"> - <path d="m4 1024.4 24 12-24 12z" stroke="#000" stroke-width="2.4"/> + <g filter="url(#a)" stroke="#000" stroke-width="2.4" transform="matrix(.83333 0 0 .83333 2.6667 -847.67)"> + <path stroke="#000" stroke-width="2.4" d="m4 1024.4 24 12-24 12z"/> </g> <g transform="matrix(.83333 0 0 .83333 2.6667 -847.67)"> - <path fill="#fff" d="m4 1024.4 24 12-24 12z"/> + <path d="m4 1024.4 24 12-24 12z" fill="#fff"/> </g> </svg> diff --git a/core/img/actions/view-previous.png b/core/img/actions/view-previous.png Binary files differindex f601ec2ba44..86e2a809626 100644 --- a/core/img/actions/view-previous.png +++ b/core/img/actions/view-previous.png diff --git a/core/img/actions/view-previous.svg b/core/img/actions/view-previous.svg index 8a5013aad40..60f6cd59285 100644 --- a/core/img/actions/view-previous.svg +++ b/core/img/actions/view-previous.svg @@ -5,6 +5,6 @@ <feGaussianBlur stdDeviation="2.4158278"/> </filter> </defs> - <path d="m10.414 28.952-1.414-1.414 11.535-11.536-11.535-11.536 1.414-1.4138 12.95 12.95z" transform="matrix(-1 0 0 1 32.364 0)" filter="url(#a)" stroke="#000" stroke-width="2"/> + <path filter="url(#a)" stroke="#000" stroke-width="2" d="m10.414 28.952-1.414-1.414 11.535-11.536-11.535-11.536 1.414-1.4138 12.95 12.95z" transform="matrix(-1 0 0 1 32.364 0)"/> <path d="m21.95 28.952 1.414-1.414-11.536-11.536 11.536-11.536-1.414-1.4138-12.95 12.95z" fill="#fff"/> </svg> diff --git a/core/js/config.php b/core/js/config.php index 463e334ef26..e51ae903729 100644 --- a/core/js/config.php +++ b/core/js/config.php @@ -136,11 +136,12 @@ $array = array( "firstDay" => json_encode($l->getFirstWeekDay()) , "oc_config" => json_encode( array( - 'session_lifetime' => min(\OCP\Config::getSystemValue('session_lifetime', ini_get('session.gc_maxlifetime')), ini_get('session.gc_maxlifetime')), + 'session_lifetime' => min(\OCP\Config::getSystemValue('session_lifetime', OC::$server->getIniWrapper()->getNumeric('session.gc_maxlifetime')), OC::$server->getIniWrapper()->getNumeric('session.gc_maxlifetime')), 'session_keepalive' => \OCP\Config::getSystemValue('session_keepalive', true), 'version' => implode('.', OC_Util::getVersion()), 'versionstring' => OC_Util::getVersionString(), 'enable_avatars' => \OC::$server->getConfig()->getSystemValue('enable_avatars', true), + 'lost_password_link'=> \OC::$server->getConfig()->getSystemValue('lost_password_link', null), 'modRewriteWorking' => (getenv('front_controller_active') === 'true'), ) ), diff --git a/core/js/js.js b/core/js/js.js index cbdffd0f016..2937d3f6eb1 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -174,7 +174,6 @@ var OC={ * @param {string} type the type of the file to link to (e.g. css,img,ajax.template) * @param {string} file the filename * @return {string} Absolute URL for a file in an app - * @deprecated use OC.generateUrl() instead */ filePath:function(app,type,file){ var isCore=OC.coreApps.indexOf(app)!==-1, diff --git a/core/js/lostpassword.js b/core/js/lostpassword.js index 294a9d8c1cf..df28c2308cb 100644 --- a/core/js/lostpassword.js +++ b/core/js/lostpassword.js @@ -13,22 +13,26 @@ OC.Lostpassword = { resetErrorMsg : t('core', 'Password can not be changed. Please contact your administrator.'), init : function() { - $('#lost-password').click(OC.Lostpassword.sendLink); + $('#lost-password').click(OC.Lostpassword.resetLink); $('#reset-password #submit').click(OC.Lostpassword.resetPassword); }, - sendLink : function(event){ + resetLink : function(event){ event.preventDefault(); if (!$('#user').val().length){ $('#submit').trigger('click'); } else { - $.post( + if (OC.config['lost_password_link']) { + window.location = OC.config['lost_password_link']; + } else { + $.post( OC.generateUrl('/lostpassword/email'), { user : $('#user').val() }, OC.Lostpassword.sendLinkDone - ); + ); + } } }, diff --git a/core/js/sharedialoglinkshareview.js b/core/js/sharedialoglinkshareview.js index 29dce21486c..452599fb7f2 100644 --- a/core/js/sharedialoglinkshareview.js +++ b/core/js/sharedialoglinkshareview.js @@ -48,7 +48,7 @@ ' {{/if}}' + '{{else}}' + // FIXME: this doesn't belong in this view - '<input id="shareWith-{{cid}}" class="shareWithField" type="text" placeholder="{{noSharingPlaceholder}}" disabled="disabled"/>' + + '{{#if noSharingPlaceholder}}<input id="shareWith-{{cid}}" class="shareWithField" type="text" placeholder="{{noSharingPlaceholder}}" disabled="disabled"/>{{/if}}' + '{{/if}}' ; @@ -238,15 +238,18 @@ render: function() { var linkShareTemplate = this.template(); + var resharingAllowed = this.model.sharePermissionPossible(); - if( !this.model.sharePermissionPossible() + if(!resharingAllowed || !this.showLink || !this.configModel.isShareWithLinkAllowed()) { - this.$el.html(linkShareTemplate({ - shareAllowed: false, - noSharingPlaceholder: t('core', 'Resharing is not allowed') - })); + var templateData = {shareAllowed: false}; + if (!resharingAllowed) { + // add message + templateData.noSharingPlaceholder = t('core', 'Resharing is not allowed'); + } + this.$el.html(linkShareTemplate(templateData)); return this; } diff --git a/core/js/sharedialogshareelistview.js b/core/js/sharedialogshareelistview.js index dfe5789e774..daed8a439bb 100644 --- a/core/js/sharedialogshareelistview.js +++ b/core/js/sharedialogshareelistview.js @@ -245,12 +245,14 @@ onUnshare: function(event) { var $element = $(event.target); - console.log($element); + if (!$element.is('a')) { + $element = $element.closest('a'); + } - var $loading = $element.siblings('.icon-loading-small').eq(0); + var $loading = $element.find('.icon-loading-small').eq(0); if(!$loading.hasClass('hidden')) { // in process - return; + return false; } $loading.removeClass('hidden'); diff --git a/core/js/tests/specs/sharedialogviewSpec.js b/core/js/tests/specs/sharedialogviewSpec.js index 6d5243b0e86..bfd3d987866 100644 --- a/core/js/tests/specs/sharedialogviewSpec.js +++ b/core/js/tests/specs/sharedialogviewSpec.js @@ -218,6 +218,7 @@ describe('OC.Share.ShareDialogView', function() { dialog.render(); expect(dialog.$el.find('.linkCheckbox').length).toEqual(0); + expect(dialog.$el.find('.shareWithField').length).toEqual(1); }); it('shows populated link share when a link share exists', function() { // this is how the OC.Share class does it... diff --git a/core/js/update.js b/core/js/update.js index 090f8fa5d23..1626b6f2c49 100644 --- a/core/js/update.js +++ b/core/js/update.js @@ -84,7 +84,7 @@ .append(t('core', 'The update was successful. Redirecting you to ownCloud now.')) .appendTo($el); setTimeout(function () { - OC.redirect(OC.webroot); + OC.redirect(OC.webroot + '/'); }, 3000); } }); diff --git a/core/l10n/fr.js b/core/l10n/fr.js index 9dae27cd459..4bb7aa82c97 100644 --- a/core/l10n/fr.js +++ b/core/l10n/fr.js @@ -191,6 +191,7 @@ OC.L10N.register( "Couldn't reset password because the token is invalid" : "Impossible de réinitialiser le mot de passe car le jeton n'est pas valable.", "Couldn't reset password because the token is expired" : "Impossible de réinitialiser le mot de passe car le jeton a expiré.", "Couldn't send reset email. Please make sure your username is correct." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez vérifier que votre nom d'utilisateur est correct.", + "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation car il n'y a aucune adresse de courriel pour cet utilisateur. Veuillez contacter votre administrateur.", "%s password reset" : "Réinitialisation de votre mot de passe %s", "Use the following link to reset your password: {link}" : "Utilisez le lien suivant pour réinitialiser votre mot de passe : {link}", "New password" : "Nouveau mot de passe", diff --git a/core/l10n/fr.json b/core/l10n/fr.json index ee8f44595e2..02347de1707 100644 --- a/core/l10n/fr.json +++ b/core/l10n/fr.json @@ -189,6 +189,7 @@ "Couldn't reset password because the token is invalid" : "Impossible de réinitialiser le mot de passe car le jeton n'est pas valable.", "Couldn't reset password because the token is expired" : "Impossible de réinitialiser le mot de passe car le jeton a expiré.", "Couldn't send reset email. Please make sure your username is correct." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez vérifier que votre nom d'utilisateur est correct.", + "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation car il n'y a aucune adresse de courriel pour cet utilisateur. Veuillez contacter votre administrateur.", "%s password reset" : "Réinitialisation de votre mot de passe %s", "Use the following link to reset your password: {link}" : "Utilisez le lien suivant pour réinitialiser votre mot de passe : {link}", "New password" : "Nouveau mot de passe", diff --git a/core/l10n/nl.js b/core/l10n/nl.js index ffff693e95c..9e2bc2d345e 100644 --- a/core/l10n/nl.js +++ b/core/l10n/nl.js @@ -18,6 +18,8 @@ OC.L10N.register( "Repair error: " : "Reparatiefout:", "Set log level to debug - current level: \"%s\"" : "Instellen logniveau op debug - huidige niveau: \"%s\"", "Reset log level to \"%s\"" : "Terugzetten logniveau op \"#%s\"", + "Starting code integrity check" : "Starten code betrouwbaarheidscontrole", + "Finished code integrity check" : "Gereed met code betrouwbaarheidscontrole", "%s (3rdparty)" : "%s (3rdparty)", "%s (incompatible)" : "%s (incompatibel)", "Following apps have been disabled: %s" : "De volgende apps zijn gedeactiveerd: %s", @@ -77,6 +79,7 @@ OC.L10N.register( "Oct." : "Okt.", "Nov." : "Nov.", "Dec." : "Dec.", + "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Er traden problemen op tijdens de code betrouwbaarheidscontrole. Meer informatie…</a>", "Settings" : "Instellingen", "Saving..." : "Opslaan", "seconds ago" : "seconden geleden", @@ -116,6 +119,7 @@ OC.L10N.register( "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "UwPHP versie ({version}) wordt niet langer <a href=\"{phpLink}\">ondersteund door PHP</a>. We adviseren u om uw PHP versie te upgraden voor betere prestaties en security updates geleverd door PHP.", "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "De reverse proxy headerconfiguratie is onjuist, of u hebt toegang tot ownCloud via een vertrouwde proxy. Als u ownCloud niet via een vertrouwde proxy benadert, dan levert dan een beveiligingsrisico op, waardoor een aanvaller het IP-adres dat ownCloud ziet kan spoofen. Meer informatie is te vinden in onze <a href=\"{docLink}\">documentatie</a>.", "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached is geconfigureerd als gedistribueerde cache, maar de verkeerde PHP module \"memcache\" is geïnstalleerd. \\OC\\Memcache\\Memcached ondersteunt alleen \"memcached\" en niet \"memcache\". Zie de <a href=\"{wikiLink}\">memcached wiki over beide modules</a>.", + "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Sommige bestanden kwamen niet door de code betrouwbaarheidscontrole. Meer informatie over het oplossen van dit probleem kan worden gevonden in onze <a href=\"{docLink}\">documentatie</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Lijst met ongeldige bestanden…</a> / <a href=\"{rescanEndpoint}\">Opnieuw…</a>)", "Error occurred while checking server setup" : "Een fout trad op bij checken serverconfiguratie", "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "De \"{header}\" HTTP header is niet overeenkomstig met \"{expected}\" geconfigureerd. Dit is een potentieel security of privacy risico en we adviseren om deze instelling te wijzigen.", "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "De \"Strict-Transport-Security\" HTTP header is niet geconfigureerd als minimaal \"{seconds}\" seconden. Voor verbeterde beveiliging adviseren we HSTS in te schakelen zoals beschreven in onze <a href=\"{docUrl}\">security tips</a>.", @@ -187,6 +191,7 @@ OC.L10N.register( "Couldn't reset password because the token is invalid" : "Kon het wachtwoord niet herstellen, omdat het token ongeldig is", "Couldn't reset password because the token is expired" : "Kon het wachtwoord niet herstellen, omdat het token verlopen is", "Couldn't send reset email. Please make sure your username is correct." : "Kon e-mail niet versturen. Verifieer of uw gebruikersnaam correct is.", + "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Kon geen herstel e-mail versturen, omdat er geen e-mailadres bekend is bij deze gebruikersnaam. Neem contact op met uw beheerder.", "%s password reset" : "%s wachtwoord reset", "Use the following link to reset your password: {link}" : "Gebruik de volgende link om uw wachtwoord te resetten: {link}", "New password" : "Nieuw wachtwoord", diff --git a/core/l10n/nl.json b/core/l10n/nl.json index a387d496092..d565545ce38 100644 --- a/core/l10n/nl.json +++ b/core/l10n/nl.json @@ -16,6 +16,8 @@ "Repair error: " : "Reparatiefout:", "Set log level to debug - current level: \"%s\"" : "Instellen logniveau op debug - huidige niveau: \"%s\"", "Reset log level to \"%s\"" : "Terugzetten logniveau op \"#%s\"", + "Starting code integrity check" : "Starten code betrouwbaarheidscontrole", + "Finished code integrity check" : "Gereed met code betrouwbaarheidscontrole", "%s (3rdparty)" : "%s (3rdparty)", "%s (incompatible)" : "%s (incompatibel)", "Following apps have been disabled: %s" : "De volgende apps zijn gedeactiveerd: %s", @@ -75,6 +77,7 @@ "Oct." : "Okt.", "Nov." : "Nov.", "Dec." : "Dec.", + "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Er traden problemen op tijdens de code betrouwbaarheidscontrole. Meer informatie…</a>", "Settings" : "Instellingen", "Saving..." : "Opslaan", "seconds ago" : "seconden geleden", @@ -114,6 +117,7 @@ "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "UwPHP versie ({version}) wordt niet langer <a href=\"{phpLink}\">ondersteund door PHP</a>. We adviseren u om uw PHP versie te upgraden voor betere prestaties en security updates geleverd door PHP.", "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "De reverse proxy headerconfiguratie is onjuist, of u hebt toegang tot ownCloud via een vertrouwde proxy. Als u ownCloud niet via een vertrouwde proxy benadert, dan levert dan een beveiligingsrisico op, waardoor een aanvaller het IP-adres dat ownCloud ziet kan spoofen. Meer informatie is te vinden in onze <a href=\"{docLink}\">documentatie</a>.", "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached is geconfigureerd als gedistribueerde cache, maar de verkeerde PHP module \"memcache\" is geïnstalleerd. \\OC\\Memcache\\Memcached ondersteunt alleen \"memcached\" en niet \"memcache\". Zie de <a href=\"{wikiLink}\">memcached wiki over beide modules</a>.", + "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Sommige bestanden kwamen niet door de code betrouwbaarheidscontrole. Meer informatie over het oplossen van dit probleem kan worden gevonden in onze <a href=\"{docLink}\">documentatie</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Lijst met ongeldige bestanden…</a> / <a href=\"{rescanEndpoint}\">Opnieuw…</a>)", "Error occurred while checking server setup" : "Een fout trad op bij checken serverconfiguratie", "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "De \"{header}\" HTTP header is niet overeenkomstig met \"{expected}\" geconfigureerd. Dit is een potentieel security of privacy risico en we adviseren om deze instelling te wijzigen.", "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "De \"Strict-Transport-Security\" HTTP header is niet geconfigureerd als minimaal \"{seconds}\" seconden. Voor verbeterde beveiliging adviseren we HSTS in te schakelen zoals beschreven in onze <a href=\"{docUrl}\">security tips</a>.", @@ -185,6 +189,7 @@ "Couldn't reset password because the token is invalid" : "Kon het wachtwoord niet herstellen, omdat het token ongeldig is", "Couldn't reset password because the token is expired" : "Kon het wachtwoord niet herstellen, omdat het token verlopen is", "Couldn't send reset email. Please make sure your username is correct." : "Kon e-mail niet versturen. Verifieer of uw gebruikersnaam correct is.", + "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Kon geen herstel e-mail versturen, omdat er geen e-mailadres bekend is bij deze gebruikersnaam. Neem contact op met uw beheerder.", "%s password reset" : "%s wachtwoord reset", "Use the following link to reset your password: {link}" : "Gebruik de volgende link om uw wachtwoord te resetten: {link}", "New password" : "Nieuw wachtwoord", diff --git a/core/templates/login.php b/core/templates/login.php index 03be6258fdf..e87b871c67e 100644 --- a/core/templates/login.php +++ b/core/templates/login.php @@ -12,7 +12,7 @@ script('core', [ <form method="post" name="login"> <fieldset> <?php if (!empty($_['redirect_url'])) { - print_unescaped('<input type="hidden" name="redirect_url" value="' . OC_Util::sanitizeHTML($_['redirect_url']) . '">'); + print_unescaped('<input type="hidden" name="redirect_url" value="' . \OCP\Util::sanitizeHTML($_['redirect_url']) . '">'); } ?> <?php if (isset($_['apacheauthfailed']) && ($_['apacheauthfailed'])): ?> <div class="warning"> @@ -56,11 +56,15 @@ script('core', [ <input type="submit" id="submit" class="login primary icon-confirm svg" title="<?php p($l->t('Log in')); ?>" value="" disabled="disabled"/> </p> - <?php if (isset($_['invalidpassword']) && ($_['invalidpassword'])): ?> + <?php if (!empty($_['invalidpassword']) && !empty($_['canResetPassword'])) { ?> <a id="lost-password" class="warning" href=""> <?php p($l->t('Wrong password. Reset it?')); ?> </a> - <?php endif; ?> + <?php } else if (!empty($_['invalidpassword'])) { ?> + <p class="warning"> + <?php p($l->t('Wrong password.')); ?> + </p> + <?php } ?> <?php if ($_['rememberLoginAllowed'] === true) : ?> <div class="remember-login-container"> <input type="checkbox" name="remember_login" value="1" id="remember_login" class="checkbox checkbox--white"> diff --git a/lib/l10n/fr.js b/lib/l10n/fr.js index 9660650b4f1..014b6c24e59 100644 --- a/lib/l10n/fr.js +++ b/lib/l10n/fr.js @@ -146,6 +146,10 @@ OC.L10N.register( "Data directory (%s) is invalid" : "Le répertoire (%s) n'est pas valide", "Please check that the data directory contains a file \".ocdata\" in its root." : "Veuillez vérifier que le répertoire de données contient un fichier \".ocdata\" à sa racine.", "Could not obtain lock type %d on \"%s\"." : "Impossible d'obtenir le verrouillage de type %d sur \"%s\".", - "Storage not available" : "Support de stockage non disponible" + "Storage unauthorized. %s" : "Espace de stockage non autorisé. %s", + "Storage incomplete configuration. %s" : "Configuration de l'espace de stockage incomplète. %s", + "Storage connection error. %s" : "Erreur de connexion à l'espace stockage. %s", + "Storage not available" : "Support de stockage non disponible", + "Storage connection timeout. %s" : "Le délai d'attente pour la connexion à l'espace de stockage a été dépassé. %s" }, "nplurals=2; plural=(n > 1);"); diff --git a/lib/l10n/fr.json b/lib/l10n/fr.json index a388630993e..feaae43bf41 100644 --- a/lib/l10n/fr.json +++ b/lib/l10n/fr.json @@ -144,6 +144,10 @@ "Data directory (%s) is invalid" : "Le répertoire (%s) n'est pas valide", "Please check that the data directory contains a file \".ocdata\" in its root." : "Veuillez vérifier que le répertoire de données contient un fichier \".ocdata\" à sa racine.", "Could not obtain lock type %d on \"%s\"." : "Impossible d'obtenir le verrouillage de type %d sur \"%s\".", - "Storage not available" : "Support de stockage non disponible" + "Storage unauthorized. %s" : "Espace de stockage non autorisé. %s", + "Storage incomplete configuration. %s" : "Configuration de l'espace de stockage incomplète. %s", + "Storage connection error. %s" : "Erreur de connexion à l'espace stockage. %s", + "Storage not available" : "Support de stockage non disponible", + "Storage connection timeout. %s" : "Le délai d'attente pour la connexion à l'espace de stockage a été dépassé. %s" },"pluralForm" :"nplurals=2; plural=(n > 1);" }
\ No newline at end of file diff --git a/lib/l10n/lt_LT.js b/lib/l10n/lt_LT.js index f73b1fdc871..402167cb3c6 100644 --- a/lib/l10n/lt_LT.js +++ b/lib/l10n/lt_LT.js @@ -4,7 +4,9 @@ OC.L10N.register( "Cannot write into \"config\" directory!" : "Negalima rašyti į \"config\" aplanką!", "This can usually be fixed by giving the webserver write access to the config directory" : "Tai gali būti ištaisyta suteikiant web serveriui rašymo teises į config aplanką", "See %s" : "Žiūrėk %s", + "Sample configuration detected" : "Aptiktas konfigūracijos pavyzdys", "PHP %s or higher is required." : "Reikalinga PHP %s arba aukštesnė.", + "Following databases are supported: %s" : "Palaikomos duomenų bazės: %s", "Help" : "Pagalba", "Personal" : "Asmeniniai", "Users" : "Vartotojai", diff --git a/lib/l10n/lt_LT.json b/lib/l10n/lt_LT.json index e9acd6f2950..c4efe386655 100644 --- a/lib/l10n/lt_LT.json +++ b/lib/l10n/lt_LT.json @@ -2,7 +2,9 @@ "Cannot write into \"config\" directory!" : "Negalima rašyti į \"config\" aplanką!", "This can usually be fixed by giving the webserver write access to the config directory" : "Tai gali būti ištaisyta suteikiant web serveriui rašymo teises į config aplanką", "See %s" : "Žiūrėk %s", + "Sample configuration detected" : "Aptiktas konfigūracijos pavyzdys", "PHP %s or higher is required." : "Reikalinga PHP %s arba aukštesnė.", + "Following databases are supported: %s" : "Palaikomos duomenų bazės: %s", "Help" : "Pagalba", "Personal" : "Asmeniniai", "Users" : "Vartotojai", diff --git a/lib/l10n/nl.js b/lib/l10n/nl.js index 24e087a50f5..f4201778f7e 100644 --- a/lib/l10n/nl.js +++ b/lib/l10n/nl.js @@ -147,6 +147,10 @@ OC.L10N.register( "Data directory (%s) is invalid" : "Data directory (%s) is ongeldig", "Please check that the data directory contains a file \".ocdata\" in its root." : "Verifieer dat de data directory een bestand \".ocdata\" in de hoofdmap heeft.", "Could not obtain lock type %d on \"%s\"." : "Kon geen lock type %d krijgen op \"%s\".", - "Storage not available" : "Opslag niet beschikbaar" + "Storage unauthorized. %s" : "Opslag niet toegestaan. %s", + "Storage incomplete configuration. %s" : "Incomplete opslagconfiguratie. %s", + "Storage connection error. %s" : "Opslagverbindingsfout. %s", + "Storage not available" : "Opslag niet beschikbaar", + "Storage connection timeout. %s" : "Opslagverbinding time-out. %s" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/nl.json b/lib/l10n/nl.json index 691f3e08240..c8981f8fd4c 100644 --- a/lib/l10n/nl.json +++ b/lib/l10n/nl.json @@ -145,6 +145,10 @@ "Data directory (%s) is invalid" : "Data directory (%s) is ongeldig", "Please check that the data directory contains a file \".ocdata\" in its root." : "Verifieer dat de data directory een bestand \".ocdata\" in de hoofdmap heeft.", "Could not obtain lock type %d on \"%s\"." : "Kon geen lock type %d krijgen op \"%s\".", - "Storage not available" : "Opslag niet beschikbaar" + "Storage unauthorized. %s" : "Opslag niet toegestaan. %s", + "Storage incomplete configuration. %s" : "Incomplete opslagconfiguratie. %s", + "Storage connection error. %s" : "Opslagverbindingsfout. %s", + "Storage not available" : "Opslag niet beschikbaar", + "Storage connection timeout. %s" : "Opslagverbinding time-out. %s" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/pt_BR.js b/lib/l10n/pt_BR.js index 8078d369b76..2595d5dfd38 100644 --- a/lib/l10n/pt_BR.js +++ b/lib/l10n/pt_BR.js @@ -147,6 +147,10 @@ OC.L10N.register( "Data directory (%s) is invalid" : "Diretório de dados (%s) é inválido", "Please check that the data directory contains a file \".ocdata\" in its root." : "Por favor, verifique se o diretório de dados contém um arquivo \".ocdata\" em sua raiz.", "Could not obtain lock type %d on \"%s\"." : "Não foi possível obter tipo de bloqueio %d em \"%s\".", - "Storage not available" : "Armazanamento não disponível" + "Storage unauthorized. %s" : "Armazenamento não autorizado. %s", + "Storage incomplete configuration. %s" : "Incompleta configuração de armazenamento. %s", + "Storage connection error. %s" : "Erro na conexão de armazenamento. %s", + "Storage not available" : "Armazanamento não disponível", + "Storage connection timeout. %s" : "Tempo limite de conexão de armazenamento. %s" }, "nplurals=2; plural=(n > 1);"); diff --git a/lib/l10n/pt_BR.json b/lib/l10n/pt_BR.json index 5987c1e2ac7..0da54181b3f 100644 --- a/lib/l10n/pt_BR.json +++ b/lib/l10n/pt_BR.json @@ -145,6 +145,10 @@ "Data directory (%s) is invalid" : "Diretório de dados (%s) é inválido", "Please check that the data directory contains a file \".ocdata\" in its root." : "Por favor, verifique se o diretório de dados contém um arquivo \".ocdata\" em sua raiz.", "Could not obtain lock type %d on \"%s\"." : "Não foi possível obter tipo de bloqueio %d em \"%s\".", - "Storage not available" : "Armazanamento não disponível" + "Storage unauthorized. %s" : "Armazenamento não autorizado. %s", + "Storage incomplete configuration. %s" : "Incompleta configuração de armazenamento. %s", + "Storage connection error. %s" : "Erro na conexão de armazenamento. %s", + "Storage not available" : "Armazanamento não disponível", + "Storage connection timeout. %s" : "Tempo limite de conexão de armazenamento. %s" },"pluralForm" :"nplurals=2; plural=(n > 1);" }
\ No newline at end of file diff --git a/lib/private/app.php b/lib/private/app.php index c6e235eda4d..abf12264c58 100644 --- a/lib/private/app.php +++ b/lib/private/app.php @@ -361,37 +361,6 @@ class OC_App { } /** - * marks a navigation entry as active - * - * @param string $id id of the entry - * @return bool - * - * This function sets a navigation entry as active and removes the 'active' - * property from all other entries. The templates can use this for - * highlighting the current position of the user. - * - * @deprecated Use \OC::$server->getNavigationManager()->setActiveEntry() instead - */ - public static function setActiveNavigationEntry($id) { - OC::$server->getNavigationManager()->setActiveEntry($id); - return true; - } - - /** - * gets the active Menu entry - * - * @return string id or empty string - * - * This function returns the id of the active navigation entry (set by - * setActiveNavigationEntry - * - * @deprecated Use \OC::$server->getNavigationManager()->getActiveEntry() instead - */ - public static function getActiveNavigationEntry() { - return OC::$server->getNavigationManager()->getActiveEntry(); - } - - /** * Returns the Settings Navigation * * @return string[] @@ -505,9 +474,13 @@ class OC_App { * search for an app in all app-directories * * @param string $appId - * @return mixed (bool|string) + * @return false|string */ protected static function findAppInDirectories($appId) { + $sanitizedAppId = self::cleanAppId($appId); + if($sanitizedAppId !== $appId) { + return false; + } static $app_dir = array(); if (isset($app_dir[$appId])) { diff --git a/lib/private/app/infoparser.php b/lib/private/app/infoparser.php index 789f01e5bc4..22f705884bc 100644 --- a/lib/private/app/infoparser.php +++ b/lib/private/app/infoparser.php @@ -61,7 +61,7 @@ class InfoParser { if ($xml == false) { return null; } - $array = $this->xmlToArray($xml, false); + $array = $this->xmlToArray($xml); if (is_null($array)) { return null; } diff --git a/lib/private/appframework/utility/simplecontainer.php b/lib/private/appframework/utility/simplecontainer.php index bcae351e023..e55d4e20a81 100644 --- a/lib/private/appframework/utility/simplecontainer.php +++ b/lib/private/appframework/utility/simplecontainer.php @@ -29,9 +29,7 @@ namespace OC\AppFramework\Utility; use ReflectionClass; use ReflectionException; use Closure; - use Pimple\Container; - use OCP\AppFramework\QueryException; use OCP\IContainer; diff --git a/lib/private/apphelper.php b/lib/private/apphelper.php index 9084d2b8ab4..478787b21d8 100644 --- a/lib/private/apphelper.php +++ b/lib/private/apphelper.php @@ -36,6 +36,12 @@ class AppHelper implements \OCP\IHelper { * @deprecated 8.1.0 Use \OCP\IServerContainer::getHTTPClientService */ public function getUrlContent($url) { - return \OC_Util::getUrlContent($url); + try { + $client = \OC::$server->getHTTPClientService()->newClient(); + $response = $client->get($url); + return $response->getBody(); + } catch (\Exception $e) { + return false; + } } } diff --git a/lib/private/db/querybuilder/querybuilder.php b/lib/private/db/querybuilder/querybuilder.php index 02d8ee4344d..741da4efc27 100644 --- a/lib/private/db/querybuilder/querybuilder.php +++ b/lib/private/db/querybuilder/querybuilder.php @@ -325,6 +325,28 @@ class QueryBuilder implements IQueryBuilder { } /** + * Specifies an item that is to be returned uniquely in the query result. + * + * <code> + * $qb = $conn->getQueryBuilder() + * ->selectDistinct('type') + * ->from('users'); + * </code> + * + * @param mixed $select The selection expressions. + * + * @return \OCP\DB\QueryBuilder\IQueryBuilder This QueryBuilder instance. + */ + public function selectDistinct($select) { + + $this->queryBuilder->addSelect( + 'DISTINCT ' . $this->helper->quoteColumnName($select) + ); + + return $this; + } + + /** * Adds an item that is to be returned in the query result. * * <code> @@ -1024,14 +1046,46 @@ class QueryBuilder implements IQueryBuilder { } /** + * Used to get the id of the last inserted element + * @return int + * @throws \BadMethodCallException When being called before an insert query has been run. + */ + public function getLastInsertId() { + $from = $this->getQueryPart('from'); + + if ($this->getType() === \Doctrine\DBAL\Query\QueryBuilder::INSERT && !empty($from)) { + return (int) $this->connection->lastInsertId($from['table']); + } + + throw new \BadMethodCallException('Invalid call to getLastInsertId without using insert() before.'); + } + + /** + * Returns the table name quoted and with database prefix as needed by the implementation + * * @param string $table * @return string */ - private function getTableName($table) { + public function getTableName($table) { if ($this->automaticTablePrefix === false || strpos($table, '*PREFIX*') === 0) { return $this->helper->quoteColumnName($table); } return $this->helper->quoteColumnName('*PREFIX*' . $table); } + + /** + * Returns the column name quoted and with table alias prefix as needed by the implementation + * + * @param string $column + * @param string $tableAlias + * @return string + */ + public function getColumnName($column, $tableAlias = '') { + if ($tableAlias !== '') { + $tableAlias .= '.'; + } + + return $this->helper->quoteColumnName($tableAlias . $column); + } } diff --git a/lib/private/db/querybuilder/quotehelper.php b/lib/private/db/querybuilder/quotehelper.php index 4b62fee6a6c..5ceb76bbf93 100644 --- a/lib/private/db/querybuilder/quotehelper.php +++ b/lib/private/db/querybuilder/quotehelper.php @@ -61,7 +61,7 @@ class QuoteHelper { } if (substr_count($string, '.')) { - list($alias, $columnName) = explode('.', $string); + list($alias, $columnName) = explode('.', $string, 2); if ($columnName === '*') { return $string; diff --git a/lib/private/files.php b/lib/private/files.php index af10f3e1e32..1cda28496cb 100644 --- a/lib/private/files.php +++ b/lib/private/files.php @@ -115,7 +115,7 @@ class OC_Files { self::lockFiles($view, $dir, $files); $streamer->sendHeaders($name); - $executionTime = intval(ini_get('max_execution_time')); + $executionTime = intval(OC::$server->getIniWrapper()->getNumeric('max_execution_time')); set_time_limit(0); if ($getType === self::ZIP_FILES) { foreach ($files as $file) { diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php index 9f243c15a4c..9d1b7150687 100644 --- a/lib/private/files/filesystem.php +++ b/lib/private/files/filesystem.php @@ -58,7 +58,6 @@ namespace OC\Files; -use OC\Cache\File; use OC\Files\Config\MountProviderCollection; use OC\Files\Storage\StorageFactory; use OCP\Files\Config\IMountProvider; diff --git a/lib/private/files/view.php b/lib/private/files/view.php index 7854790d0e5..6abefff4198 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -1427,13 +1427,9 @@ class View { if ($mimetype_filter) { $files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) { if (strpos($mimetype_filter, '/')) { - if ($file->getMimetype() === $mimetype_filter) { - $result[] = $file; - } + return $file->getMimetype() === $mimetype_filter; } else { - if ($file->getMimePart() === $mimetype_filter) { - $result[] = $file; - } + return $file->getMimePart() === $mimetype_filter; } }); } diff --git a/lib/private/helper.php b/lib/private/helper.php index 3cad77e6667..78a567638ef 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -441,7 +441,7 @@ class OC_Helper { // Default check will be done with $path directories : $dirs = explode(PATH_SEPARATOR, $path); // WARNING : We have to check if open_basedir is enabled : - $obd = ini_get('open_basedir'); + $obd = OC::$server->getIniWrapper()->getString('open_basedir'); if ($obd != "none") { $obd_values = explode(PATH_SEPARATOR, $obd); if (count($obd_values) > 0 and $obd_values[0]) { @@ -701,8 +701,9 @@ class OC_Helper { * @return int PHP upload file size limit */ public static function uploadLimit() { - $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize')); - $post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size')); + $ini = \OC::$server->getIniWrapper(); + $upload_max_filesize = OCP\Util::computerFileSize($ini->get('upload_max_filesize')); + $post_max_size = OCP\Util::computerFileSize($ini->get('post_max_size')); if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) { return INF; } elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) { @@ -722,12 +723,13 @@ class OC_Helper { if (!function_exists($function_name)) { return false; } - $disabled = explode(',', ini_get('disable_functions')); + $ini = \OC::$server->getIniWrapper(); + $disabled = explode(',', $ini->get('disable_functions')); $disabled = array_map('trim', $disabled); if (in_array($function_name, $disabled)) { return false; } - $disabled = explode(',', ini_get('suhosin.executor.func.blacklist')); + $disabled = explode(',', $ini->get('suhosin.executor.func.blacklist')); $disabled = array_map('trim', $disabled); if (in_array($function_name, $disabled)) { return false; diff --git a/lib/private/l10n.php b/lib/private/l10n.php index 86335bce92f..7835285bd49 100644 --- a/lib/private/l10n.php +++ b/lib/private/l10n.php @@ -116,13 +116,17 @@ class OC_L10N implements \OCP\IL10N { $preferred_language = str_replace('-', '_', $preferred_language); foreach ($available as $available_language) { if ($preferred_language === strtolower($available_language)) { - self::$language = $available_language; + if (!self::$language) { + self::$language = $available_language; + } return $available_language; } } foreach ($available as $available_language) { if (substr($preferred_language, 0, 2) === $available_language) { - self::$language = $available_language; + if (!self::$language) { + self::$language = $available_language; + } return $available_language; } } @@ -407,7 +411,7 @@ class OC_L10N implements \OCP\IL10N { * If nothing works it returns 'en' */ public static function findLanguage($app = null) { - if(self::$language != '') { + if (self::$language != '' && self::languageExists($app, self::$language)) { return self::$language; } diff --git a/lib/private/memcache/apc.php b/lib/private/memcache/apc.php index f768cdc1c6e..e38b4bd3a39 100644 --- a/lib/private/memcache/apc.php +++ b/lib/private/memcache/apc.php @@ -115,9 +115,9 @@ class APC extends Cache implements IMemcache { static public function isAvailable() { if (!extension_loaded('apc')) { return false; - } elseif (!ini_get('apc.enabled')) { + } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enabled')) { return false; - } elseif (!ini_get('apc.enable_cli') && \OC::$CLI) { + } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) { return false; } else { return true; diff --git a/lib/private/memcache/apcu.php b/lib/private/memcache/apcu.php index 9a8da2ae60c..84147233ef0 100644 --- a/lib/private/memcache/apcu.php +++ b/lib/private/memcache/apcu.php @@ -28,9 +28,9 @@ class APCu extends APC { static public function isAvailable() { if (!extension_loaded('apcu')) { return false; - } elseif (!ini_get('apc.enabled')) { + } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enabled')) { return false; - } elseif (!ini_get('apc.enable_cli') && \OC::$CLI) { + } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) { return false; } elseif (version_compare(phpversion('apc'), '4.0.6') === -1) { return false; diff --git a/lib/private/memcache/xcache.php b/lib/private/memcache/xcache.php index a6265ed5622..0d2e43a1c18 100644 --- a/lib/private/memcache/xcache.php +++ b/lib/private/memcache/xcache.php @@ -118,13 +118,13 @@ class XCache extends Cache implements IMemcache { if (\OC::$CLI && !getenv('XCACHE_TEST')) { return false; } - if (!function_exists('xcache_unset_by_prefix') && ini_get('xcache.admin.enable_auth')) { + if (!function_exists('xcache_unset_by_prefix') && \OC::$server->getIniWrapper()->getBool('xcache.admin.enable_auth')) { // We do not want to use XCache if we can not clear it without // using the administration function xcache_clear_cache() // AND administration functions are password-protected. return false; } - $var_size = (int)ini_get('xcache.var_size'); + $var_size = \OC::$server->getIniWrapper()->getNumeric('xcache.var_size'); if (!$var_size) { return false; } diff --git a/lib/private/repair.php b/lib/private/repair.php index f6ac7ebe65b..d870b472c4f 100644 --- a/lib/private/repair.php +++ b/lib/private/repair.php @@ -40,7 +40,6 @@ use OC\Repair\SqliteAutoincrement; use OC\Repair\DropOldTables; use OC\Repair\FillETags; use OC\Repair\InnoDB; -use OC\Repair\RepairConfig; use OC\Repair\RepairLegacyStorages; use OC\Repair\RepairMimeTypes; use OC\Repair\SearchLuceneTables; @@ -107,7 +106,6 @@ class Repair extends BasicEmitter { return [ new RepairMimeTypes(\OC::$server->getConfig()), new RepairLegacyStorages(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()), - new RepairConfig(), new AssetCache(), new FillETags(\OC::$server->getDatabaseConnection()), new CleanTags(\OC::$server->getDatabaseConnection()), @@ -138,13 +136,12 @@ class Repair extends BasicEmitter { * @return array of RepairStep instances */ public static function getBeforeUpgradeRepairSteps() { - $steps = array( + $steps = [ new InnoDB(), new Collation(\OC::$server->getConfig(), \OC_DB::getConnection()), new SqliteAutoincrement(\OC_DB::getConnection()), new SearchLuceneTables(), - new RepairConfig() - ); + ]; //There is no need to delete all previews on every single update //only 7.0.0 through 7.0.2 generated broken previews diff --git a/lib/private/security/trusteddomainhelper.php b/lib/private/security/trusteddomainhelper.php index 6dbaadfdb60..c1a397dd52d 100644 --- a/lib/private/security/trusteddomainhelper.php +++ b/lib/private/security/trusteddomainhelper.php @@ -74,16 +74,11 @@ class TrustedDomainHelper { return false; } - // TODO: Workaround for older instances still with port applied. Remove for ownCloud 9. - if(in_array($domainWithPort, $trustedList)) { - return true; - } - // Always allow access from localhost if (preg_match(Request::REGEX_LOCALHOST, $domain) === 1) { return true; } - return in_array($domain, $trustedList); + return in_array($domain, $trustedList, true); } } diff --git a/lib/private/session/cryptowrapper.php b/lib/private/session/cryptowrapper.php index c79778587e0..177f11ffb70 100644 --- a/lib/private/session/cryptowrapper.php +++ b/lib/private/session/cryptowrapper.php @@ -23,7 +23,6 @@ namespace OC\Session; -use OCP\AppFramework\Utility\ITimeFactory; use OCP\IConfig; use OCP\IRequest; use OCP\ISession; diff --git a/lib/private/share/mailnotifications.php b/lib/private/share/mailnotifications.php index f45d80b37ca..4d282158ba4 100644 --- a/lib/private/share/mailnotifications.php +++ b/lib/private/share/mailnotifications.php @@ -176,10 +176,12 @@ class MailNotifications { $subject = (string)$this->l->t('%s shared »%s« with you', [$this->senderDisplayName, $filename]); list($htmlBody, $textBody) = $this->createMailBody($filename, $link, $expiration); + $recipient = str_replace([', ', '; ', ',', ';', ' '], ',', $recipient); + $recipients = explode(',', $recipient); try { $message = $this->mailer->createMessage(); $message->setSubject($subject); - $message->setTo([$recipient]); + $message->setTo($recipients); $message->setHtmlBody($htmlBody); $message->setPlainBody($textBody); $message->setFrom([ diff --git a/lib/private/share/share.php b/lib/private/share/share.php index 70f9a6e8920..8899df25636 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -745,10 +745,8 @@ class Share extends Constants { // The check for each user in the group is done inside the put() function if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) { - // Only allow the same share to occur again if it is the same - // owner and is not a group share, this use case is for increasing - // permissions for a specific user - if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) { + + if ($checkExists['share_with'] === $shareWith && $checkExists['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) { $message = 'Sharing %s failed, because this item is already shared with %s'; $message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith)); \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG); diff --git a/lib/private/systemtag/systemtagmanager.php b/lib/private/systemtag/systemtagmanager.php index 8caf10d69da..7f239dc84cf 100644 --- a/lib/private/systemtag/systemtagmanager.php +++ b/lib/private/systemtag/systemtagmanager.php @@ -63,7 +63,7 @@ class SystemTagManager implements ISystemTagManager { /** * {@inheritdoc} */ - public function getTagsById($tagIds) { + public function getTagsByIds($tagIds) { if (!is_array($tagIds)) { $tagIds = [$tagIds]; } @@ -242,7 +242,7 @@ class SystemTagManager implements ISystemTagManager { $tagNotFoundException = null; try { - $this->getTagsById($tagIds); + $this->getTagsByIds($tagIds); } catch (TagNotFoundException $e) { $tagNotFoundException = $e; } diff --git a/lib/private/systemtag/systemtagobjectmapper.php b/lib/private/systemtag/systemtagobjectmapper.php index 75f2631a010..988fa66d77e 100644 --- a/lib/private/systemtag/systemtagobjectmapper.php +++ b/lib/private/systemtag/systemtagobjectmapper.php @@ -171,6 +171,10 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper { public function haveTag($objIds, $objectType, $tagId, $all = true) { $this->assertTagsExist([$tagId]); + if (!is_array($objIds)) { + $objIds = [$objIds]; + } + $query = $this->connection->getQueryBuilder(); if (!$all) { @@ -209,7 +213,7 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper { * @throws \OCP\SystemTag\TagNotFoundException if at least one tag did not exist */ private function assertTagsExist($tagIds) { - $tags = $this->tagManager->getTagsById($tagIds); + $tags = $this->tagManager->getTagsByIds($tagIds); if (count($tags) !== count($tagIds)) { // at least one tag missing, bail out $foundTagIds = array_map( diff --git a/lib/private/template.php b/lib/private/template.php index 1476a964ef3..d794dacac23 100644 --- a/lib/private/template.php +++ b/lib/private/template.php @@ -226,12 +226,12 @@ class OC_Template extends \OC\Template\Base { // Add custom headers $headers = ''; foreach(OC_Util::$headers as $header) { - $headers .= '<'.OC_Util::sanitizeHTML($header['tag']); + $headers .= '<'.\OCP\Util::sanitizeHTML($header['tag']); foreach($header['attributes'] as $name=>$value) { - $headers .= ' '.OC_Util::sanitizeHTML($name).'="'.OC_Util::sanitizeHTML($value).'"'; + $headers .= ' '.\OCP\Util::sanitizeHTML($name).'="'.\OCP\Util::sanitizeHTML($value).'"'; } if ($header['text'] !== null) { - $headers .= '>'.OC_Util::sanitizeHTML($header['text']).'</'.OC_Util::sanitizeHTML($header['tag']).'>'; + $headers .= '>'.\OCP\Util::sanitizeHTML($header['text']).'</'.\OCP\Util::sanitizeHTML($header['tag']).'>'; } else { $headers .= '/>'; } diff --git a/lib/private/template/functions.php b/lib/private/template/functions.php index 79d18632d2f..d156d26f9ce 100644 --- a/lib/private/template/functions.php +++ b/lib/private/template/functions.php @@ -33,7 +33,7 @@ * @param string $string the string which will be escaped and printed */ function p($string) { - print(OC_Util::sanitizeHTML($string)); + print(\OCP\Util::sanitizeHTML($string)); } /** @@ -262,7 +262,7 @@ function html_select_options($options, $selected, $params=array()) { $label = $label[$label_name]; } $select = in_array($value, $selected) ? ' selected="selected"' : ''; - $html .= '<option value="' . OC_Util::sanitizeHTML($value) . '"' . $select . '>' . OC_Util::sanitizeHTML($label) . '</option>'."\n"; + $html .= '<option value="' . \OCP\Util::sanitizeHTML($value) . '"' . $select . '>' . \OCP\Util::sanitizeHTML($label) . '</option>'."\n"; } return $html; } diff --git a/lib/private/tempmanager.php b/lib/private/tempmanager.php index 365d639389f..ac44b76d683 100644 --- a/lib/private/tempmanager.php +++ b/lib/private/tempmanager.php @@ -213,7 +213,7 @@ class TempManager implements ITempManager { if ($temp = $this->config->getSystemValue('tempdirectory', null)) { $directories[] = $temp; } - if ($temp = ini_get('upload_tmp_dir')) { + if ($temp = \OC::$server->getIniWrapper()->get('upload_tmp_dir')) { $directories[] = $temp; } if ($temp = getenv('TMP')) { diff --git a/lib/private/util.php b/lib/private/util.php index ac42b96de2d..eb188b649e8 100644 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -947,6 +947,14 @@ class OC_Util { $parameters['redirect_url'] = $_REQUEST['redirect_url']; } + $parameters['canResetPassword'] = true; + if (!\OC::$server->getSystemConfig()->getValue('lost_password_link')) { + $user = \OC::$server->getUserManager()->get($_REQUEST['user']); + if ($user instanceof IUser) { + $parameters['canResetPassword'] = $user->canChangePassword(); + } + } + $parameters['alt_login'] = OC_App::getAlternativeLogIns(); $parameters['rememberLoginAllowed'] = self::rememberLoginAllowed(); \OC_Hook::emit('OC_Util', 'pre_displayLoginPage', array('parameters' => $parameters)); @@ -1169,14 +1177,16 @@ class OC_Util { * This function is used to sanitize HTML and should be applied on any * string or array of strings before displaying it on a web page. * - * @param string|array &$value + * @param string|array $value * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter. */ - public static function sanitizeHTML(&$value) { + public static function sanitizeHTML($value) { if (is_array($value)) { - array_walk_recursive($value, 'OC_Util::sanitizeHTML'); + $value = array_map(function($value) { + return self::sanitizeHTML($value); + }, $value); } else { - //Specify encoding for PHP<5.4 + // Specify encoding for PHP<5.4 $value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'); } return $value; @@ -1237,7 +1247,11 @@ class OC_Util { // accessing the file via http $url = OC_Helper::makeURLAbsolute(OC::$WEBROOT . '/data' . $fileName); - $content = self::getUrlContent($url); + try { + $content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody(); + } catch (\Exception $e) { + $content = false; + } // cleanup @unlink($testFile); @@ -1313,23 +1327,6 @@ class OC_Util { } /** - * Get URL content - * @param string $url Url to get content - * @throws Exception If the URL does not start with http:// or https:// - * @return string of the response or false on error - * This function get the content of a page via curl, if curl is enabled. - * If not, file_get_contents is used. - * @deprecated Use \OC::$server->getHTTPClientService()->newClient()->get($url); - */ - public static function getUrlContent($url) { - try { - return \OC::$server->getHTTPHelper()->getUrlContent($url); - } catch (\Exception $e) { - throw $e; - } - } - - /** * Checks whether the server is running on Windows * * @return bool true if running on Windows, false otherwise @@ -1418,7 +1415,7 @@ class OC_Util { } // XCache if (function_exists('xcache_clear_cache')) { - if (ini_get('xcache.admin.enable_auth')) { + if (\OC::$server->getIniWrapper()->getBool('xcache.admin.enable_auth')) { \OCP\Util::writeLog('core', 'XCache opcode cache will not be cleared because "xcache.admin.enable_auth" is enabled.', \OCP\Util::WARN); } else { @xcache_clear_cache(XC_TYPE_PHP, 0); diff --git a/lib/public/app.php b/lib/public/app.php index c66d988c315..cc414842628 100644 --- a/lib/public/app.php +++ b/lib/public/app.php @@ -82,7 +82,8 @@ class App { * @since 4.0.0 */ public static function setActiveNavigationEntry( $id ) { - return \OC_App::setActiveNavigationEntry( $id ); + \OC::$server->getNavigationManager()->setActiveEntry($id); + return true; } /** diff --git a/lib/public/db/querybuilder/iquerybuilder.php b/lib/public/db/querybuilder/iquerybuilder.php index beb922b7feb..dd3ee7da5f5 100644 --- a/lib/public/db/querybuilder/iquerybuilder.php +++ b/lib/public/db/querybuilder/iquerybuilder.php @@ -257,6 +257,22 @@ interface IQueryBuilder { public function selectAlias($select, $alias); /** + * Specifies an item that is to be returned uniquely in the query result. + * + * <code> + * $qb = $conn->getQueryBuilder() + * ->selectDistinct('type') + * ->from('users'); + * </code> + * + * @param mixed $select The selection expressions. + * + * @return \OCP\DB\QueryBuilder\IQueryBuilder This QueryBuilder instance. + * @since 9.0.0 + */ + public function selectDistinct($select); + + /** * Adds an item that is to be returned in the query result. * * <code> @@ -796,4 +812,31 @@ interface IQueryBuilder { * @since 8.2.0 */ public function createFunction($call); + + /** + * Used to get the id of the last inserted element + * @return int + * @throws \BadMethodCallException When being called before an insert query has been run. + * @since 9.0.0 + */ + public function getLastInsertId(); + + /** + * Returns the table name quoted and with database prefix as needed by the implementation + * + * @param string $table + * @return string + * @since 9.0.0 + */ + public function getTableName($table); + + /** + * Returns the column name quoted and with table alias prefix as needed by the implementation + * + * @param string $column + * @param string $tableAlias + * @return string + * @since 9.0.0 + */ + public function getColumnName($column, $tableAlias = ''); } diff --git a/lib/public/systemtag/isystemtagmanager.php b/lib/public/systemtag/isystemtagmanager.php index 4e3b263e56c..6e8fed36dce 100644 --- a/lib/public/systemtag/isystemtagmanager.php +++ b/lib/public/systemtag/isystemtagmanager.php @@ -41,7 +41,7 @@ interface ISystemTagManager { * * @since 9.0.0 */ - public function getTagsById($tagIds); + public function getTagsByIds($tagIds); /** * Returns the tag object matching the given attributes. diff --git a/lib/public/util.php b/lib/public/util.php index 110028368d0..4e783b764ed 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -497,11 +497,11 @@ class Util { * string or array of strings before displaying it on a web page. * * @param string|array $value - * @return string|array an array of sanitized strings or a single sinitized string, depends on the input parameter. + * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter. * @since 4.5.0 */ - public static function sanitizeHTML( $value ) { - return(\OC_Util::sanitizeHTML($value)); + public static function sanitizeHTML($value) { + return \OC_Util::sanitizeHTML($value); } /** diff --git a/lib/repair/repairconfig.php b/lib/repair/repairconfig.php deleted file mode 100644 index 66fdd47269e..00000000000 --- a/lib/repair/repairconfig.php +++ /dev/null @@ -1,80 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @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 OC\Repair; - -use OC\Hooks\BasicEmitter; -use OC\RepairStep; -use Sabre\DAV\Exception; - -/** - * Class RepairConfig - * - * @package OC\Repair - */ -class RepairConfig extends BasicEmitter implements RepairStep { - - /** - * @return string - */ - public function getName() { - return 'Repair config'; - } - - /** - * Updates the configuration after running an update - */ - public function run() { - $this->addSecret(); - $this->removePortsFromTrustedDomains(); - } - - /** - * Adds a secret to config.php - */ - private function addSecret() { - if(\OC::$server->getConfig()->getSystemValue('secret', null) === null) { - $secret = \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(48); - \OC::$server->getConfig()->setSystemValue('secret', $secret); - } - } - - - /** - * Remove ports from existing trusted domains in config.php - */ - private function removePortsFromTrustedDomains() { - $trustedDomains = \OC::$server->getConfig()->getSystemValue('trusted_domains', array()); - $newTrustedDomains = array(); - foreach($trustedDomains as $domain) { - $pos = strrpos($domain, ':'); - if ($pos !== false) { - $port = substr($domain, $pos + 1); - if (is_numeric($port)) { - $domain = substr($domain, 0, $pos); - } - } - $newTrustedDomains[] = $domain; - } - \OC::$server->getConfig()->setSystemValue('trusted_domains', $newTrustedDomains); - } -} diff --git a/settings/admin.php b/settings/admin.php index bccb1171743..ae4340cf14f 100644 --- a/settings/admin.php +++ b/settings/admin.php @@ -33,7 +33,7 @@ use OC\Lock\NoopLockingProvider; OC_Util::checkAdminUser(); -OC_App::setActiveNavigationEntry("admin"); +\OC::$server->getNavigationManager()->setActiveEntry("admin"); $template = new OC_Template('settings', 'admin', 'user'); $l = \OC::$server->getL10N('settings'); diff --git a/settings/application.php b/settings/application.php index f9ee0121db0..729e61b5925 100644 --- a/settings/application.php +++ b/settings/application.php @@ -136,7 +136,8 @@ class Application extends App { $c->query('Mailer'), $c->query('DefaultMailAddress'), $c->query('URLGenerator'), - $c->query('OCP\\App\\IAppManager') + $c->query('OCP\\App\\IAppManager'), + $c->query('OCP\\IAvatarManager') ); }); $container->registerService('LogSettingsController', function(IContainer $c) { diff --git a/settings/controller/userscontroller.php b/settings/controller/userscontroller.php index 827f74c4c83..8ad975fd664 100644 --- a/settings/controller/userscontroller.php +++ b/settings/controller/userscontroller.php @@ -27,7 +27,6 @@ namespace OC\Settings\Controller; use OC\AppFramework\Http; -use OC\Settings\Factory\SubAdminFactory; use OC\User\User; use OCP\App\IAppManager; use OCP\AppFramework\Controller; @@ -43,6 +42,7 @@ use OCP\IUser; use OCP\IUserManager; use OCP\IUserSession; use OCP\Mail\IMailer; +use OCP\IAvatarManager; /** * @package OC\Settings\Controller @@ -74,6 +74,8 @@ class UsersController extends Controller { private $isEncryptionAppEnabled; /** @var bool contains the state of the admin recovery setting */ private $isRestoreEnabled = false; + /** @var IAvatarManager */ + private $avatarManager; /** * @param string $appName @@ -104,7 +106,8 @@ class UsersController extends Controller { IMailer $mailer, $fromMailAddress, IURLGenerator $urlGenerator, - IAppManager $appManager) { + IAppManager $appManager, + IAvatarManager $avatarManager) { parent::__construct($appName, $request); $this->userManager = $userManager; $this->groupManager = $groupManager; @@ -117,6 +120,7 @@ class UsersController extends Controller { $this->mailer = $mailer; $this->fromMailAddress = $fromMailAddress; $this->urlGenerator = $urlGenerator; + $this->avatarManager = $avatarManager; // check for encryption state - TODO see formatUserForIndex $this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption'); @@ -168,6 +172,12 @@ class UsersController extends Controller { if (is_null($displayName)) { $displayName = ''; } + + $avatarAvailable = false; + if ($this->config->getSystemValue('enable_avatars', true) === true) { + $avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists(); + } + return [ 'name' => $user->getUID(), 'displayname' => $user->getDisplayName(), @@ -179,6 +189,7 @@ class UsersController extends Controller { 'backend' => $user->getBackendClassName(), 'email' => $displayName, 'isRestoreDisabled' => !$restorePossible, + 'isAvatarAvailable' => $avatarAvailable, ]; } diff --git a/settings/help.php b/settings/help.php index aa89277d883..60719a3df92 100644 --- a/settings/help.php +++ b/settings/help.php @@ -30,7 +30,7 @@ OC_Util::checkLoggedIn(); // Load the files we need OC_Util::addStyle( "settings", "settings" ); -OC_App::setActiveNavigationEntry( "help" ); +\OC::$server->getNavigationManager()->setActiveEntry('help'); if(isset($_GET['mode']) and $_GET['mode'] === 'admin') { diff --git a/settings/js/users/users.js b/settings/js/users/users.js index aeecac7b243..2f8a964bafb 100644 --- a/settings/js/users/users.js +++ b/settings/js/users/users.js @@ -64,8 +64,12 @@ var UserList = { /** * Avatar or placeholder */ - if ($tr.find('div.avatardiv').length){ - $('div.avatardiv', $tr).avatar(user.name, 32, undefined, undefined, undefined, user.displayname); + if ($tr.find('div.avatardiv').length) { + if (user.isAvatarAvailable === true) { + $('div.avatardiv', $tr).avatar(user.name, 32, undefined, undefined, undefined, user.displayname); + } else { + $('div.avatardiv', $tr).imageplaceholder(user.displayname); + } } /** diff --git a/settings/personal.php b/settings/personal.php index 6c2ac351456..9a714393585 100644 --- a/settings/personal.php +++ b/settings/personal.php @@ -165,6 +165,7 @@ $l = \OC::$server->getL10N('settings'); $formsAndMore = []; $formsAndMore[]= ['anchor' => 'clientsbox', 'section-name' => $l->t('Sync clients')]; $formsAndMore[]= ['anchor' => 'passwordform', 'section-name' => $l->t('Personal info')]; +$formsAndMore[]= ['anchor' => 'groups', 'section-name' => $l->t('Groups')]; $forms=OC_App::getForms('personal'); diff --git a/settings/templates/admin.php b/settings/templates/admin.php index 0721c0e0afb..f3de51a23c3 100644 --- a/settings/templates/admin.php +++ b/settings/templates/admin.php @@ -56,7 +56,7 @@ if ($_['mail_smtpmode'] == 'qmail') { if (isset($form['anchor'])) { $anchor = '#' . $form['anchor']; $sectionName = $form['section-name']; - print_unescaped(sprintf("<li><a href='%s'>%s</a></li>", OC_Util::sanitizeHTML($anchor), OC_Util::sanitizeHTML($sectionName))); + print_unescaped(sprintf("<li><a href='%s'>%s</a></li>", \OCP\Util::sanitizeHTML($anchor), \OCP\Util::sanitizeHTML($sectionName))); } }?> </ul> diff --git a/settings/templates/personal.php b/settings/templates/personal.php index 0eba71d77d1..09194ea3e39 100644 --- a/settings/templates/personal.php +++ b/settings/templates/personal.php @@ -14,7 +14,7 @@ if (isset($form['anchor'])) { $anchor = '#' . $form['anchor']; $sectionName = $form['section-name']; - print_unescaped(sprintf("<li><a href='%s'>%s</a></li>", OC_Util::sanitizeHTML($anchor), OC_Util::sanitizeHTML($sectionName))); + print_unescaped(sprintf("<li><a href='%s'>%s</a></li>", \OCP\Util::sanitizeHTML($anchor), \OCP\Util::sanitizeHTML($sectionName))); } }?> </ul> diff --git a/settings/users.php b/settings/users.php index 2795032a161..ccf1bcd9e1a 100644 --- a/settings/users.php +++ b/settings/users.php @@ -35,7 +35,7 @@ OC_Util::checkSubAdminUser(); -OC_App::setActiveNavigationEntry( 'core_users' ); +\OC::$server->getNavigationManager()->setActiveEntry('core_users'); $userManager = \OC_User::getManager(); $groupManager = \OC_Group::getManager(); diff --git a/tests/core/avatar/avatarcontrollertest.php b/tests/core/avatar/avatarcontrollertest.php index efe41763ff7..a113add72b9 100644 --- a/tests/core/avatar/avatarcontrollertest.php +++ b/tests/core/avatar/avatarcontrollertest.php @@ -23,14 +23,11 @@ namespace OC\Core\Avatar; use OC; use OC\Core\Application; use OCP\AppFramework\IAppContainer; -use OC\Files\Filesystem; 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; /** diff --git a/tests/karma.config.js b/tests/karma.config.js index dc621ae0f74..df09ee1b310 100644 --- a/tests/karma.config.js +++ b/tests/karma.config.js @@ -67,7 +67,8 @@ module.exports = function(config) { // up with the global namespace/classes/state 'apps/files_external/js/app.js', 'apps/files_external/js/mountsfilelist.js', - 'apps/files_external/js/settings.js' + 'apps/files_external/js/settings.js', + 'apps/files_external/js/statusmanager.js' ], testFiles: ['apps/files_external/tests/js/*.js'] }, diff --git a/tests/lib/appframework/http/RequestTest.php b/tests/lib/appframework/http/RequestTest.php index 92a2cc01dd2..32603d0da59 100644 --- a/tests/lib/appframework/http/RequestTest.php +++ b/tests/lib/appframework/http/RequestTest.php @@ -10,7 +10,6 @@ namespace OC\AppFramework\Http; -use OC\Security\Crypto; use OCP\Security\ISecureRandom; use OCP\IConfig; diff --git a/tests/lib/db/querybuilder/querybuildertest.php b/tests/lib/db/querybuilder/querybuildertest.php index ca3901ad049..c8e029d9e40 100644 --- a/tests/lib/db/querybuilder/querybuildertest.php +++ b/tests/lib/db/querybuilder/querybuildertest.php @@ -48,12 +48,12 @@ class QueryBuilderTest extends \Test\TestCase { $this->queryBuilder = new QueryBuilder($this->connection); } - protected function createTestingRows() { + protected function createTestingRows($appId = 'testFirstResult') { $qB = $this->connection->getQueryBuilder(); for ($i = 1; $i < 10; $i++) { $qB->insert('*PREFIX*appconfig') ->values([ - 'appid' => $qB->expr()->literal('testFirstResult'), + 'appid' => $qB->expr()->literal($appId), 'configkey' => $qB->expr()->literal('testing' . $i), 'configvalue' => $qB->expr()->literal(100 - $i), ]) @@ -80,11 +80,11 @@ class QueryBuilderTest extends \Test\TestCase { return $rows; } - protected function deleteTestingRows() { + protected function deleteTestingRows($appId = 'testFirstResult') { $qB = $this->connection->getQueryBuilder(); $qB->delete('*PREFIX*appconfig') - ->where($qB->expr()->eq('appid', $qB->expr()->literal('testFirstResult'))) + ->where($qB->expr()->eq('appid', $qB->expr()->literal($appId))) ->execute(); } @@ -272,6 +272,34 @@ class QueryBuilderTest extends \Test\TestCase { $this->deleteTestingRows(); } + public function testSelectDistinct() { + $this->deleteTestingRows('testFirstResult1'); + $this->deleteTestingRows('testFirstResult2'); + $this->createTestingRows('testFirstResult1'); + $this->createTestingRows('testFirstResult2'); + + $this->queryBuilder->selectDistinct('appid'); + + $this->queryBuilder->from('*PREFIX*appconfig') + ->where($this->queryBuilder->expr()->in( + 'appid', + [$this->queryBuilder->expr()->literal('testFirstResult1'), $this->queryBuilder->expr()->literal('testFirstResult2')] + )) + ->orderBy('appid', 'DESC'); + + $query = $this->queryBuilder->execute(); + $rows = $query->fetchAll(); + $query->closeCursor(); + + $this->assertEquals( + [['appid' => 'testFirstResult2'], ['appid' => 'testFirstResult1']], + $rows + ); + + $this->deleteTestingRows('testFirstResult1'); + $this->deleteTestingRows('testFirstResult2'); + } + public function dataAddSelect() { $queryBuilder = new QueryBuilder(\OC::$server->getDatabaseConnection()); return [ @@ -1086,6 +1114,31 @@ class QueryBuilderTest extends \Test\TestCase { ); } + public function testGetLastInsertId() { + $qB = $this->connection->getQueryBuilder(); + + try { + $qB->getLastInsertId(); + $this->fail('getLastInsertId() should throw an exception, when being called before insert()'); + } catch (\BadMethodCallException $e) { + $this->assertTrue(true); + } + + $qB->insert('appconfig') + ->values([ + 'appid' => $qB->expr()->literal('testFirstResult'), + 'configkey' => $qB->expr()->literal('testing' . 50), + 'configvalue' => $qB->expr()->literal(100 - 50), + ]) + ->execute(); + + $actual = $qB->getLastInsertId(); + + $this->assertNotNull($actual); + $this->assertInternalType('int', $actual); + $this->assertEquals($this->connection->lastInsertId('*PREFIX*appconfig'), $actual); + } + public function dataGetTableName() { return [ ['*PREFIX*table', null, '`*PREFIX*table`'], @@ -1112,7 +1165,27 @@ class QueryBuilderTest extends \Test\TestCase { $this->assertSame( $expected, - $this->invokePrivate($this->queryBuilder, 'getTableName', [$tableName]) + $this->queryBuilder->getTableName($tableName) + ); + } + + public function dataGetColumnName() { + return [ + ['column', '', '`column`'], + ['column', 'a', 'a.`column`'], + ]; + } + + /** + * @dataProvider dataGetColumnName + * @param string $column + * @param string $prefix + * @param string $expected + */ + public function testGetColumnName($column, $prefix, $expected) { + $this->assertSame( + $expected, + $this->queryBuilder->getColumnName($column, $prefix) ); } } diff --git a/tests/lib/files/view.php b/tests/lib/files/view.php index 186cf28d7c3..1fc4b9ab684 100644 --- a/tests/lib/files/view.php +++ b/tests/lib/files/view.php @@ -2389,4 +2389,39 @@ class View extends \Test\TestCase { $view = new \OC\Files\View('/' . $this->user . '/files'); $this->assertEquals('foo', $view->rmdir('mount')); } + + public function mimeFilterProvider() { + return [ + [null, ['test1.txt', 'test2.txt', 'test3.md', 'test4.png']], + ['text/plain', ['test1.txt', 'test2.txt']], + ['text/markdown', ['test3.md']], + ['text', ['test1.txt', 'test2.txt', 'test3.md']], + ]; + } + + /** + * @param string $filter + * @param string[] $expected + * @dataProvider mimeFilterProvider + */ + public function testGetDirectoryContentMimeFilter($filter, $expected) { + $storage1 = new Temporary(); + $root = $this->getUniqueID('/'); + \OC\Files\Filesystem::mount($storage1, array(), $root . '/'); + $view = new \OC\Files\View($root); + + $view->file_put_contents('test1.txt', 'asd'); + $view->file_put_contents('test2.txt', 'asd'); + $view->file_put_contents('test3.md', 'asd'); + $view->file_put_contents('test4.png', ''); + + $content = $view->getDirectoryContent('', $filter); + + $files = array_map(function(FileInfo $info) { + return $info->getName(); + }, $content); + sort($files); + + $this->assertEquals($expected, $files); + } } diff --git a/tests/lib/security/trusteddomainhelper.php b/tests/lib/security/trusteddomainhelper.php index c8d5ffa587b..52a8f1be630 100644 --- a/tests/lib/security/trusteddomainhelper.php +++ b/tests/lib/security/trusteddomainhelper.php @@ -64,6 +64,8 @@ class TrustedDomainHelperTest extends \Test\TestCase { // do not trust invalid localhosts [$trustedHostTestList, 'localhost:1:2', false], [$trustedHostTestList, 'localhost: evil.host', false], + // do not trust casting + [[1], '1', false], ]; } diff --git a/tests/lib/share/MailNotificationsTest.php b/tests/lib/share/MailNotificationsTest.php index 2124a8bf13b..8684886e798 100644 --- a/tests/lib/share/MailNotificationsTest.php +++ b/tests/lib/share/MailNotificationsTest.php @@ -123,7 +123,23 @@ class MailNotificationsTest extends \Test\TestCase { $this->assertSame([], $mailNotifications->sendLinkShareMail('lukas@owncloud.com', 'MyFile', 'https://owncloud.com/file/?foo=bar', 3600)); } - public function testSendLinkShareMailWithReplyTo() { + public function dataSendLinkShareMailWithReplyTo() { + return [ + ['lukas@owncloud.com', ['lukas@owncloud.com']], + ['lukas@owncloud.com nickvergessen@owncloud.com', ['lukas@owncloud.com', 'nickvergessen@owncloud.com']], + ['lukas@owncloud.com,nickvergessen@owncloud.com', ['lukas@owncloud.com', 'nickvergessen@owncloud.com']], + ['lukas@owncloud.com, nickvergessen@owncloud.com', ['lukas@owncloud.com', 'nickvergessen@owncloud.com']], + ['lukas@owncloud.com;nickvergessen@owncloud.com', ['lukas@owncloud.com', 'nickvergessen@owncloud.com']], + ['lukas@owncloud.com; nickvergessen@owncloud.com', ['lukas@owncloud.com', 'nickvergessen@owncloud.com']], + ]; + } + + /** + * @dataProvider dataSendLinkShareMailWithReplyTo + * @param string $to + * @param array $expectedTo + */ + public function testSendLinkShareMailWithReplyTo($to, array $expectedTo) { $message = $this->getMockBuilder('\OC\Mail\Message') ->disableOriginalConstructor()->getMock(); @@ -134,7 +150,7 @@ class MailNotificationsTest extends \Test\TestCase { $message ->expects($this->once()) ->method('setTo') - ->with(['lukas@owncloud.com']); + ->with($expectedTo); $message ->expects($this->once()) ->method('setHtmlBody'); @@ -167,7 +183,7 @@ class MailNotificationsTest extends \Test\TestCase { $this->logger, $this->defaults ); - $this->assertSame([], $mailNotifications->sendLinkShareMail('lukas@owncloud.com', 'MyFile', 'https://owncloud.com/file/?foo=bar', 3600)); + $this->assertSame([], $mailNotifications->sendLinkShareMail($to, 'MyFile', 'https://owncloud.com/file/?foo=bar', 3600)); } public function testSendLinkShareMailException() { diff --git a/tests/lib/systemtag/systemtagmanagertest.php b/tests/lib/systemtag/systemtagmanagertest.php index 8498b85519f..97c072f33f6 100644 --- a/tests/lib/systemtag/systemtagmanagertest.php +++ b/tests/lib/systemtag/systemtagmanagertest.php @@ -250,7 +250,7 @@ class SystemTagManagerTest extends TestCase { $tag1 = $this->tagManager->createTag('one', true, false); $tag2 = $this->tagManager->createTag('two', false, true); - $tagList = $this->tagManager->getTagsById([$tag1->getId(), $tag2->getId()]); + $tagList = $this->tagManager->getTagsByIds([$tag1->getId(), $tag2->getId()]); $this->assertCount(2, $tagList); @@ -270,7 +270,7 @@ class SystemTagManagerTest extends TestCase { */ public function testGetNonExistingTagsById() { $tag1 = $this->tagManager->createTag('one', true, false); - $this->tagManager->getTagsById([$tag1->getId(), 100, 101]); + $this->tagManager->getTagsByIds([$tag1->getId(), 100, 101]); } /** @@ -278,7 +278,7 @@ class SystemTagManagerTest extends TestCase { */ public function testGetInvalidTagIdFormat() { $tag1 = $this->tagManager->createTag('one', true, false); - $this->tagManager->getTagsById([$tag1->getId() . 'suffix']); + $this->tagManager->getTagsByIds([$tag1->getId() . 'suffix']); } public function updateTagProvider() { diff --git a/tests/lib/systemtag/systemtagobjectmappertest.php b/tests/lib/systemtag/systemtagobjectmappertest.php index 43d0b8c6960..4ea80c216ed 100644 --- a/tests/lib/systemtag/systemtagobjectmappertest.php +++ b/tests/lib/systemtag/systemtagobjectmappertest.php @@ -74,7 +74,7 @@ class SystemTagObjectMapperTest extends TestCase { $this->tag3 = new SystemTag(3, 'testtag3', false, false); $this->tagManager->expects($this->any()) - ->method('getTagsById') + ->method('getTagsByIds') ->will($this->returnCallback(function($tagIds) { $result = []; if (in_array(1, $tagIds)) { diff --git a/tests/lib/util.php b/tests/lib/util.php index 9b82be36955..fa559c17c80 100644 --- a/tests/lib/util.php +++ b/tests/lib/util.php @@ -95,16 +95,22 @@ class Test_Util extends \Test\TestCase { } function testSanitizeHTML() { - $badArray = array( + $badArray = [ 'While it is unusual to pass an array', 'this function actually <blink>supports</blink> it.', - 'And therefore there needs to be a <script>alert("Unit"+\'test\')</script> for it!' - ); - $goodArray = array( + 'And therefore there needs to be a <script>alert("Unit"+\'test\')</script> for it!', + [ + 'And It Even May <strong>Nest</strong>', + ], + ]; + $goodArray = [ 'While it is unusual to pass an array', 'this function actually <blink>supports</blink> it.', - 'And therefore there needs to be a <script>alert("Unit"+'test')</script> for it!' - ); + 'And therefore there needs to be a <script>alert("Unit"+'test')</script> for it!', + [ + 'And It Even May <strong>Nest</strong>' + ], + ]; $result = OC_Util::sanitizeHTML($badArray); $this->assertEquals($goodArray, $result); diff --git a/tests/settings/controller/userscontrollertest.php b/tests/settings/controller/userscontrollertest.php index b52d6c66aad..e1e3c4d4b6b 100644 --- a/tests/settings/controller/userscontrollertest.php +++ b/tests/settings/controller/userscontrollertest.php @@ -54,6 +54,30 @@ class UsersControllerTest extends \Test\TestCase { ->disableOriginalConstructor()->getMock(); $this->container['OCP\\App\\IAppManager'] = $this->getMockBuilder('OCP\\App\\IAppManager') ->disableOriginalConstructor()->getMock(); + + + /* + * Set default avtar behaviour for whole testsuite + */ + $this->container['OCP\\IAvatarManager'] = $this->getMock('OCP\IAvatarManager'); + + $avatarExists = $this->getMock('OCP\IAvatar'); + $avatarExists->method('exists')->willReturn(true); + $avatarNotExists = $this->getMock('OCP\IAvatar'); + $avatarNotExists->method('exists')->willReturn(false); + $this->container['OCP\\IAvatarManager'] + ->method('getAvatar') + ->will($this->returnValueMap([ + ['foo', $avatarExists], + ['bar', $avatarExists], + ['admin', $avatarNotExists], + ])); + + $this->container['Config'] + ->method('getSystemValue') + ->with('enable_avatars', true) + ->willReturn(true); + } public function testIndexAdmin() { @@ -62,7 +86,7 @@ class UsersControllerTest extends \Test\TestCase { $foo = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $foo - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('foo')); $foo @@ -86,7 +110,7 @@ class UsersControllerTest extends \Test\TestCase { $admin = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $admin - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('admin')); $admin @@ -112,7 +136,7 @@ class UsersControllerTest extends \Test\TestCase { $bar = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $bar - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('bar')); $bar @@ -188,7 +212,6 @@ class UsersControllerTest extends \Test\TestCase { ->method('getSubAdmin') ->will($this->returnValue($subadmin)); - $expectedResponse = new DataResponse( array( 0 => array( @@ -202,6 +225,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => 'OC_User_Database', 'email' => 'foo@bar.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), 1 => array( 'name' => 'admin', @@ -214,6 +238,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => '\Test\Util\User\Dummy', 'email' => 'admin@bar.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => false, ), 2 => array( 'name' => 'bar', @@ -226,6 +251,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => '\Test\Util\User\Dummy', 'email' => 'bar@dummy.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), ) ); @@ -246,7 +272,7 @@ class UsersControllerTest extends \Test\TestCase { $foo = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $foo - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('foo')); $foo @@ -270,7 +296,7 @@ class UsersControllerTest extends \Test\TestCase { $admin = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $admin - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('admin')); $admin @@ -296,7 +322,7 @@ class UsersControllerTest extends \Test\TestCase { $bar = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $bar - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('bar')); $bar @@ -401,6 +427,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => '\Test\Util\User\Dummy', 'email' => 'bar@dummy.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ], 1=> [ 'name' => 'foo', @@ -413,6 +440,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => 'OC_User_Database', 'email' => 'foo@bar.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ], 2 => [ 'name' => 'admin', @@ -425,6 +453,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => '\Test\Util\User\Dummy', 'email' => 'admin@bar.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => false, ], ] ); @@ -443,7 +472,7 @@ class UsersControllerTest extends \Test\TestCase { $foo = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $foo - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('foo')); $foo @@ -467,7 +496,7 @@ class UsersControllerTest extends \Test\TestCase { $admin = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $admin - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('admin')); $admin @@ -493,7 +522,7 @@ class UsersControllerTest extends \Test\TestCase { $bar = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $bar - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('bar')); $bar @@ -553,6 +582,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => 'OC_User_Database', 'email' => 'foo@bar.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), 1 => array( 'name' => 'admin', @@ -565,6 +595,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => '\Test\Util\User\Dummy', 'email' => 'admin@bar.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => false, ), 2 => array( 'name' => 'bar', @@ -577,6 +608,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => '\Test\Util\User\Dummy', 'email' => 'bar@dummy.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), ) ); @@ -590,7 +622,7 @@ class UsersControllerTest extends \Test\TestCase { $user = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $user - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('foo')); $user @@ -648,6 +680,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => 'OC_User_Database', 'email' => null, 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ) ) ); @@ -719,6 +752,7 @@ class UsersControllerTest extends \Test\TestCase { 'subadmin' => array(), 'email' => null, 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), Http::STATUS_CREATED ); @@ -807,6 +841,7 @@ class UsersControllerTest extends \Test\TestCase { 'subadmin' => [], 'email' => null, 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), Http::STATUS_CREATED ); @@ -889,6 +924,7 @@ class UsersControllerTest extends \Test\TestCase { 'subadmin' => array(), 'email' => null, 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), Http::STATUS_CREATED ); @@ -984,6 +1020,7 @@ class UsersControllerTest extends \Test\TestCase { 'subadmin' => [], 'email' => null, 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), Http::STATUS_CREATED ); @@ -1480,6 +1517,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => $backend, 'email' => null, 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ]; return [$user, $result]; |