diff options
Diffstat (limited to 'apps')
152 files changed, 2634 insertions, 1076 deletions
diff --git a/apps/comments/appinfo/app.php b/apps/comments/appinfo/app.php index cd1ccb2d7d3..b060a5db1ca 100644 --- a/apps/comments/appinfo/app.php +++ b/apps/comments/appinfo/app.php @@ -51,3 +51,10 @@ $managerListener = function(\OCP\Comments\CommentsEvent $event) use ($activityMa }; $eventDispatcher->addListener(\OCP\Comments\CommentsEvent::EVENT_ADD, $managerListener); + +$eventDispatcher->addListener(\OCP\Comments\CommentsEntityEvent::EVENT_ENTITY, function(\OCP\Comments\CommentsEntityEvent $event) { + $event->addEntityCollection('files', function($name) { + $nodes = \OC::$server->getUserFolder()->getById(intval($name)); + return !empty($nodes); + }); +}); diff --git a/apps/comments/l10n/ar.js b/apps/comments/l10n/ar.js index ec211e25e43..3d8f9c0165a 100644 --- a/apps/comments/l10n/ar.js +++ b/apps/comments/l10n/ar.js @@ -1,8 +1,23 @@ OC.L10N.register( "comments", { + "Type in a new comment..." : "اكتب تعليق جديد...", + "Delete comment" : "حذف التعليق", + "Post" : "مشاركة", "Cancel" : "إلغاء", + "Edit comment" : "تعديل التعليق", + "[Deleted user]" : "[مستخدم محذوف]", + "Comments" : "تعليقات", + "No other comments available" : "لا يوجد تعليقات أخرى متاحة", + "More comments..." : "مزيد من التعليقات...", "Save" : "حفظ", - "Comment" : "تعليق" + "Allowed characters {count} of {max}" : "عدد الأحرف المسموح بها {عدد} من {العدد الأقصى}", + "{count} unread comments" : "{عدد} الرسائل الغير مقروءة", + "Comment" : "تعليق", + "<strong>Comments</strong> for files <em>(always listed in stream)</em>" : "<strong>تعليقات</strong> للملفات <em>(دائماً مصنف في جدول)</em>", + "You commented" : "قمت بكتابة تعليق", + "%1$s commented" : "%1$s قام بكتابة تعليق", + "You commented on %2$s" : "انت قمت بكتابة تعليق على %2$s", + "%1$s commented on %2$s" : "%1$s قام بكتابة تعليق على %2$s" }, "nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"); diff --git a/apps/comments/l10n/ar.json b/apps/comments/l10n/ar.json index 8f601e76e16..9c7e9919103 100644 --- a/apps/comments/l10n/ar.json +++ b/apps/comments/l10n/ar.json @@ -1,6 +1,21 @@ { "translations": { + "Type in a new comment..." : "اكتب تعليق جديد...", + "Delete comment" : "حذف التعليق", + "Post" : "مشاركة", "Cancel" : "إلغاء", + "Edit comment" : "تعديل التعليق", + "[Deleted user]" : "[مستخدم محذوف]", + "Comments" : "تعليقات", + "No other comments available" : "لا يوجد تعليقات أخرى متاحة", + "More comments..." : "مزيد من التعليقات...", "Save" : "حفظ", - "Comment" : "تعليق" + "Allowed characters {count} of {max}" : "عدد الأحرف المسموح بها {عدد} من {العدد الأقصى}", + "{count} unread comments" : "{عدد} الرسائل الغير مقروءة", + "Comment" : "تعليق", + "<strong>Comments</strong> for files <em>(always listed in stream)</em>" : "<strong>تعليقات</strong> للملفات <em>(دائماً مصنف في جدول)</em>", + "You commented" : "قمت بكتابة تعليق", + "%1$s commented" : "%1$s قام بكتابة تعليق", + "You commented on %2$s" : "انت قمت بكتابة تعليق على %2$s", + "%1$s commented on %2$s" : "%1$s قام بكتابة تعليق على %2$s" },"pluralForm" :"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;" }
\ No newline at end of file diff --git a/apps/dav/lib/Comments/EntityCollection.php b/apps/dav/lib/Comments/EntityCollection.php index a55a18c00c0..8fa13da6162 100644 --- a/apps/dav/lib/Comments/EntityCollection.php +++ b/apps/dav/lib/Comments/EntityCollection.php @@ -22,11 +22,12 @@ namespace OCA\DAV\Comments; use OCP\Comments\ICommentsManager; -use OCP\Files\Folder; +use OCP\Comments\NotFoundException; use OCP\ILogger; use OCP\IUserManager; use OCP\IUserSession; use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\IProperties; use Sabre\DAV\PropPatch; /** @@ -37,12 +38,9 @@ use Sabre\DAV\PropPatch; * * @package OCA\DAV\Comments */ -class EntityCollection extends RootCollection implements \Sabre\DAV\IProperties { +class EntityCollection extends RootCollection implements IProperties { const PROPERTY_NAME_READ_MARKER = '{http://owncloud.org/ns}readMarker'; - /** @var Folder */ - protected $fileRoot; - /** @var string */ protected $id; @@ -53,7 +51,6 @@ class EntityCollection extends RootCollection implements \Sabre\DAV\IProperties * @param string $id * @param string $name * @param ICommentsManager $commentsManager - * @param Folder $fileRoot * @param IUserManager $userManager * @param IUserSession $userSession * @param ILogger $logger @@ -62,7 +59,6 @@ class EntityCollection extends RootCollection implements \Sabre\DAV\IProperties $id, $name, ICommentsManager $commentsManager, - Folder $fileRoot, IUserManager $userManager, IUserSession $userSession, ILogger $logger @@ -76,7 +72,6 @@ class EntityCollection extends RootCollection implements \Sabre\DAV\IProperties $this->id = $id; $this->name = $name; $this->commentsManager = $commentsManager; - $this->fileRoot = $fileRoot; $this->logger = $logger; $this->userManager = $userManager; $this->userSession = $userSession; @@ -111,7 +106,7 @@ class EntityCollection extends RootCollection implements \Sabre\DAV\IProperties $this->userSession, $this->logger ); - } catch (\OCP\Comments\NotFoundException $e) { + } catch (NotFoundException $e) { throw new NotFound(); } } @@ -159,7 +154,7 @@ class EntityCollection extends RootCollection implements \Sabre\DAV\IProperties try { $this->commentsManager->get($name); return true; - } catch (\OCP\Comments\NotFoundException $e) { + } catch (NotFoundException $e) { return false; } } diff --git a/apps/dav/lib/Comments/EntityTypeCollection.php b/apps/dav/lib/Comments/EntityTypeCollection.php index 6bc42484207..66fdb7f8de6 100644 --- a/apps/dav/lib/Comments/EntityTypeCollection.php +++ b/apps/dav/lib/Comments/EntityTypeCollection.php @@ -22,7 +22,6 @@ namespace OCA\DAV\Comments; use OCP\Comments\ICommentsManager; -use OCP\Files\Folder; use OCP\ILogger; use OCP\IUserManager; use OCP\IUserSession; @@ -41,27 +40,31 @@ use Sabre\DAV\Exception\NotFound; * @package OCA\DAV\Comments */ class EntityTypeCollection extends RootCollection { - /** @var Folder */ - protected $fileRoot; /** @var ILogger */ protected $logger; + /** @var IUserManager */ + protected $userManager; + + /** @var \Closure */ + protected $childExistsFunction; + /** * @param string $name * @param ICommentsManager $commentsManager - * @param Folder $fileRoot * @param IUserManager $userManager * @param IUserSession $userSession * @param ILogger $logger + * @param \Closure $childExistsFunction */ public function __construct( $name, ICommentsManager $commentsManager, - Folder $fileRoot, IUserManager $userManager, IUserSession $userSession, - ILogger $logger + ILogger $logger, + \Closure $childExistsFunction ) { $name = trim($name); if(empty($name) || !is_string($name)) { @@ -69,10 +72,10 @@ class EntityTypeCollection extends RootCollection { } $this->name = $name; $this->commentsManager = $commentsManager; - $this->fileRoot = $fileRoot; $this->logger = $logger; $this->userManager = $userManager; $this->userSession = $userSession; + $this->childExistsFunction = $childExistsFunction; } /** @@ -93,7 +96,6 @@ class EntityTypeCollection extends RootCollection { $name, $this->name, $this->commentsManager, - $this->fileRoot, $this->userManager, $this->userSession, $this->logger @@ -117,9 +119,7 @@ class EntityTypeCollection extends RootCollection { * @return bool */ function childExists($name) { - $nodes = $this->fileRoot->getById(intval($name)); - return !empty($nodes); + return call_user_func($this->childExistsFunction, $name); } - } diff --git a/apps/dav/lib/Comments/RootCollection.php b/apps/dav/lib/Comments/RootCollection.php index cda666f7162..b02532b0674 100644 --- a/apps/dav/lib/Comments/RootCollection.php +++ b/apps/dav/lib/Comments/RootCollection.php @@ -21,8 +21,8 @@ namespace OCA\DAV\Comments; +use OCP\Comments\CommentsEntityEvent; use OCP\Comments\ICommentsManager; -use OCP\Files\IRootFolder; use OCP\ILogger; use OCP\IUserManager; use OCP\IUserSession; @@ -30,11 +30,12 @@ use Sabre\DAV\Exception\NotAuthenticated; use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\ICollection; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; class RootCollection implements ICollection { - /** @var EntityTypeCollection[] */ - private $entityTypeCollections = []; + /** @var EntityTypeCollection[]|null */ + private $entityTypeCollections; /** @var ICommentsManager */ protected $commentsManager; @@ -47,34 +48,32 @@ class RootCollection implements ICollection { /** @var IUserManager */ protected $userManager; - /** - * @var IUserSession - */ + + /** @var IUserSession */ protected $userSession; - /** - * @var IRootFolder - */ - protected $rootFolder; + + /** @var EventDispatcherInterface */ + protected $dispatcher; /** * @param ICommentsManager $commentsManager * @param IUserManager $userManager * @param IUserSession $userSession - * @param IRootFolder $rootFolder + * @param EventDispatcherInterface $dispatcher * @param ILogger $logger */ public function __construct( ICommentsManager $commentsManager, IUserManager $userManager, IUserSession $userSession, - IRootFolder $rootFolder, + EventDispatcherInterface $dispatcher, ILogger $logger) { $this->commentsManager = $commentsManager; $this->logger = $logger; $this->userManager = $userManager; $this->userSession = $userSession; - $this->rootFolder = $rootFolder; + $this->dispatcher = $dispatcher; } /** @@ -85,22 +84,28 @@ class RootCollection implements ICollection { * @throws NotAuthenticated */ protected function initCollections() { - if(!empty($this->entityTypeCollections)) { + if($this->entityTypeCollections !== null) { return; } $user = $this->userSession->getUser(); if(is_null($user)) { throw new NotAuthenticated(); } - $userFolder = $this->rootFolder->getUserFolder($user->getUID()); - $this->entityTypeCollections['files'] = new EntityTypeCollection( - 'files', - $this->commentsManager, - $userFolder, - $this->userManager, - $this->userSession, - $this->logger - ); + + $event = new CommentsEntityEvent(CommentsEntityEvent::EVENT_ENTITY); + $this->dispatcher->dispatch(CommentsEntityEvent::EVENT_ENTITY, $event); + + $this->entityTypeCollections = []; + foreach ($event->getEntityCollections() as $entity => $entityExistsFunction) { + $this->entityTypeCollections[$entity] = new EntityTypeCollection( + $entity, + $this->commentsManager, + $this->userManager, + $this->userSession, + $this->logger, + $entityExistsFunction + ); + } } /** diff --git a/apps/dav/lib/Connector/Sabre/Auth.php b/apps/dav/lib/Connector/Sabre/Auth.php index b8047e779f5..69301096b49 100644 --- a/apps/dav/lib/Connector/Sabre/Auth.php +++ b/apps/dav/lib/Connector/Sabre/Auth.php @@ -103,6 +103,7 @@ class Auth extends AbstractBasic { return true; } else { \OC_Util::setUpFS(); //login hooks may need early access to the filesystem + // TODO: do not allow basic auth if the user is 2FA enforced if($this->userSession->login($username, $password)) { $this->userSession->createSessionToken($this->request, $username, $password); \OC_Util::setUpFS($this->userSession->getUser()->getUID()); diff --git a/apps/dav/lib/Connector/Sabre/CommentPropertiesPlugin.php b/apps/dav/lib/Connector/Sabre/CommentPropertiesPlugin.php index a8d5f771122..e9559e361b8 100644 --- a/apps/dav/lib/Connector/Sabre/CommentPropertiesPlugin.php +++ b/apps/dav/lib/Connector/Sabre/CommentPropertiesPlugin.php @@ -99,13 +99,13 @@ class CommentPropertiesPlugin extends ServerPlugin { */ public function getCommentsLink(Node $node) { $href = $this->server->getBaseUri(); - $entryPoint = strrpos($href, '/webdav/'); + $entryPoint = strpos($href, '/remote.php/'); if($entryPoint === false) { // in case we end up somewhere else, unexpectedly. return null; } - $href = substr_replace($href, '/dav/', $entryPoint); - $href .= 'comments/files/' . rawurldecode($node->getId()); + $commentsPart = 'dav/comments/files/' . rawurldecode($node->getId()); + $href = substr_replace($href, $commentsPart, $entryPoint + strlen('/remote.php/')); return $href; } diff --git a/apps/dav/lib/RootCollection.php b/apps/dav/lib/RootCollection.php index b6e1747e990..f18bfaf496d 100644 --- a/apps/dav/lib/RootCollection.php +++ b/apps/dav/lib/RootCollection.php @@ -77,7 +77,7 @@ class RootCollection extends SimpleCollection { \OC::$server->getCommentsManager(), \OC::$server->getUserManager(), \OC::$server->getUserSession(), - \OC::$server->getRootFolder(), + \OC::$server->getEventDispatcher(), \OC::$server->getLogger() ); diff --git a/apps/dav/lib/SystemTag/SystemTagMappingNode.php b/apps/dav/lib/SystemTag/SystemTagMappingNode.php index bb2936c13dc..09a3c79c757 100644 --- a/apps/dav/lib/SystemTag/SystemTagMappingNode.php +++ b/apps/dav/lib/SystemTag/SystemTagMappingNode.php @@ -24,21 +24,22 @@ namespace OCA\DAV\SystemTag; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\MethodNotAllowed; use OCP\SystemTag\ISystemTag; use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\ISystemTagObjectMapper; use OCP\SystemTag\TagNotFoundException; +use OCP\IUser; /** * Mapping node for system tag to object id */ -class SystemTagMappingNode extends SystemTagNode { - +class SystemTagMappingNode implements \Sabre\DAV\INode { /** - * @var ISystemTagObjectMapper + * @var ISystemTag */ - private $tagMapper; + protected $tag; /** * @var string @@ -51,12 +52,29 @@ class SystemTagMappingNode extends SystemTagNode { private $objectType; /** + * User + * + * @var IUser + */ + protected $user; + + /** + * @var ISystemTagManager + */ + protected $tagManager; + + /** + * @var ISystemTagObjectMapper + */ + private $tagMapper; + + /** * Sets up the node, expects a full path name * * @param ISystemTag $tag system tag * @param string $objectId * @param string $objectType - * @param bool $isAdmin whether to allow permissions for admin + * @param IUser $user user * @param ISystemTagManager $tagManager * @param ISystemTagObjectMapper $tagMapper */ @@ -64,14 +82,16 @@ class SystemTagMappingNode extends SystemTagNode { ISystemTag $tag, $objectId, $objectType, - $isAdmin, + IUser $user, ISystemTagManager $tagManager, ISystemTagObjectMapper $tagMapper ) { + $this->tag = $tag; $this->objectId = $objectId; $this->objectType = $objectType; + $this->user = $user; + $this->tagManager = $tagManager; $this->tagMapper = $tagMapper; - parent::__construct($tag, $isAdmin, $tagManager); } /** @@ -93,17 +113,52 @@ class SystemTagMappingNode extends SystemTagNode { } /** + * Returns the system tag represented by this node + * + * @return ISystemTag system tag + */ + public function getSystemTag() { + return $this->tag; + } + + /** + * Returns the id of the tag + * + * @return string + */ + public function getName() { + return $this->tag->getId(); + } + + /** + * Renames the node + * + * @param string $name The new name + * + * @throws MethodNotAllowed not allowed to rename node + */ + public function setName($name) { + throw new MethodNotAllowed(); + } + + /** + * Returns null, not supported + * + */ + public function getLastModified() { + return null; + } + + /** * Delete tag to object association */ public function delete() { try { - if (!$this->isAdmin) { - if (!$this->tag->isUserVisible()) { - throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found'); - } - if (!$this->tag->isUserAssignable()) { - throw new Forbidden('No permission to unassign tag ' . $this->tag->getId()); - } + if (!$this->tagManager->canUserSeeTag($this->tag, $this->user)) { + throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found'); + } + if (!$this->tagManager->canUserAssignTag($this->tag, $this->user)) { + throw new Forbidden('No permission to unassign tag ' . $this->tag->getId()); } $this->tagMapper->unassignTags($this->objectId, $this->objectType, $this->tag->getId()); } catch (TagNotFoundException $e) { diff --git a/apps/dav/lib/SystemTag/SystemTagNode.php b/apps/dav/lib/SystemTag/SystemTagNode.php index 500e1a3adea..f139a3335c8 100644 --- a/apps/dav/lib/SystemTag/SystemTagNode.php +++ b/apps/dav/lib/SystemTag/SystemTagNode.php @@ -32,6 +32,7 @@ use OCP\SystemTag\ISystemTag; use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\TagNotFoundException; use OCP\SystemTag\TagAlreadyExistsException; +use OCP\IUser; /** * DAV node representing a system tag, with the name being the tag id. @@ -49,6 +50,13 @@ class SystemTagNode implements \Sabre\DAV\INode { protected $tagManager; /** + * User + * + * @var IUser + */ + protected $user; + + /** * Whether to allow permissions for admins * * @var bool @@ -59,11 +67,13 @@ class SystemTagNode implements \Sabre\DAV\INode { * Sets up the node, expects a full path name * * @param ISystemTag $tag system tag + * @param IUser $user user * @param bool $isAdmin whether to allow operations for admins - * @param ISystemTagManager $tagManager + * @param ISystemTagManager $tagManager tag manager */ - public function __construct(ISystemTag $tag, $isAdmin, ISystemTagManager $tagManager) { + public function __construct(ISystemTag $tag, IUser $user, $isAdmin, ISystemTagManager $tagManager) { $this->tag = $tag; + $this->user = $user; $this->isAdmin = $isAdmin; $this->tagManager = $tagManager; } @@ -109,14 +119,15 @@ class SystemTagNode implements \Sabre\DAV\INode { */ public function update($name, $userVisible, $userAssignable) { try { - if (!$this->isAdmin) { - if (!$this->tag->isUserVisible()) { - throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist'); - } - if (!$this->tag->isUserAssignable()) { - throw new Forbidden('No permission to update tag ' . $this->tag->getId()); - } + if (!$this->tagManager->canUserSeeTag($this->tag, $this->user)) { + throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist'); + } + if (!$this->tagManager->canUserAssignTag($this->tag, $this->user)) { + throw new Forbidden('No permission to update tag ' . $this->tag->getId()); + } + // only admin is able to change permissions, regular users can only rename + if (!$this->isAdmin) { // only renaming is allowed for regular users if ($userVisible !== $this->tag->isUserVisible() || $userAssignable !== $this->tag->isUserAssignable() @@ -124,6 +135,7 @@ class SystemTagNode implements \Sabre\DAV\INode { throw new Forbidden('No permission to update permissions for tag ' . $this->tag->getId()); } } + $this->tagManager->updateTag($this->tag->getId(), $name, $userVisible, $userAssignable); } catch (TagNotFoundException $e) { throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist'); @@ -145,14 +157,13 @@ class SystemTagNode implements \Sabre\DAV\INode { public function delete() { try { - if (!$this->isAdmin) { - if (!$this->tag->isUserVisible()) { - throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found'); - } - if (!$this->tag->isUserAssignable()) { - throw new Forbidden('No permission to delete tag ' . $this->tag->getId()); - } + if (!$this->tagManager->canUserSeeTag($this->tag, $this->user)) { + throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found'); } + if (!$this->tagManager->canUserAssignTag($this->tag, $this->user)) { + throw new Forbidden('No permission to delete tag ' . $this->tag->getId()); + } + $this->tagManager->deleteTags($this->tag->getId()); } catch (TagNotFoundException $e) { // can happen if concurrent deletion occurred diff --git a/apps/dav/lib/SystemTag/SystemTagPlugin.php b/apps/dav/lib/SystemTag/SystemTagPlugin.php index a266b4a1214..af683954b87 100644 --- a/apps/dav/lib/SystemTag/SystemTagPlugin.php +++ b/apps/dav/lib/SystemTag/SystemTagPlugin.php @@ -24,18 +24,20 @@ namespace OCA\DAV\SystemTag; use OCP\IGroupManager; use OCP\IUserSession; -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 Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\UnsupportedMediaType; use OCP\SystemTag\ISystemTag; use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\TagAlreadyExistsException; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; +use OCA\DAV\SystemTag\SystemTagMappingNode; /** * Sabre plugin to handle system tags: @@ -52,6 +54,8 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { 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'; + const GROUPS_PROPERTYNAME = '{http://owncloud.org/ns}groups'; + const CANASSIGN_PROPERTYNAME = '{http://owncloud.org/ns}can-assign'; /** * @var \Sabre\DAV\Server $server @@ -181,14 +185,26 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { $userAssignable = (bool)$data['userAssignable']; } - if($userVisible === false || $userAssignable === false) { + $groups = []; + if (isset($data['groups'])) { + $groups = $data['groups']; + if (is_string($groups)) { + $groups = explode('|', $groups); + } + } + + if($userVisible === false || $userAssignable === false || !empty($groups)) { if(!$this->userSession->isLoggedIn() || !$this->groupManager->isAdmin($this->userSession->getUser()->getUID())) { throw new BadRequest('Not sufficient permissions'); } } try { - return $this->tagManager->createTag($tagName, $userVisible, $userAssignable); + $tag = $this->tagManager->createTag($tagName, $userVisible, $userAssignable); + if (!empty($groups)) { + $this->tagManager->setTagGroups($tag, $groups); + } + return $tag; } catch (TagAlreadyExistsException $e) { throw new Conflict('Tag already exists', 0, $e); } @@ -205,7 +221,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { PropFind $propFind, \Sabre\DAV\INode $node ) { - if (!($node instanceof SystemTagNode)) { + if (!($node instanceof SystemTagNode) && !($node instanceof SystemTagMappingNode)) { return; } @@ -222,8 +238,27 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { }); $propFind->handle(self::USERASSIGNABLE_PROPERTYNAME, function() use ($node) { + // this is the tag's inherent property "is user assignable" return $node->getSystemTag()->isUserAssignable() ? 'true' : 'false'; }); + + $propFind->handle(self::CANASSIGN_PROPERTYNAME, function() use ($node) { + // this is the effective permission for the current user + return $this->tagManager->canUserAssignTag($node->getSystemTag(), $this->userSession->getUser()) ? 'true' : 'false'; + }); + + $propFind->handle(self::GROUPS_PROPERTYNAME, function() use ($node) { + if (!$this->groupManager->isAdmin($this->userSession->getUser()->getUID())) { + // property only available for admins + throw new Forbidden(); + } + $groups = []; + // no need to retrieve groups for namespaces that don't qualify + if ($node->getSystemTag()->isUserVisible() && !$node->getSystemTag()->isUserAssignable()) { + $groups = $this->tagManager->getTagGroups($node->getSystemTag()); + } + return implode('|', $groups); + }); } /** @@ -239,6 +274,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { self::DISPLAYNAME_PROPERTYNAME, self::USERVISIBLE_PROPERTYNAME, self::USERASSIGNABLE_PROPERTYNAME, + self::GROUPS_PROPERTYNAME, ], function($props) use ($path) { $node = $this->server->tree->getNodeForPath($path); if (!($node instanceof SystemTagNode)) { @@ -250,22 +286,42 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { $userVisible = $tag->isUserVisible(); $userAssignable = $tag->isUserAssignable(); + $updateTag = false; + if (isset($props[self::DISPLAYNAME_PROPERTYNAME])) { $name = $props[self::DISPLAYNAME_PROPERTYNAME]; + $updateTag = true; } if (isset($props[self::USERVISIBLE_PROPERTYNAME])) { $propValue = $props[self::USERVISIBLE_PROPERTYNAME]; $userVisible = ($propValue !== 'false' && $propValue !== '0'); + $updateTag = true; } if (isset($props[self::USERASSIGNABLE_PROPERTYNAME])) { $propValue = $props[self::USERASSIGNABLE_PROPERTYNAME]; $userAssignable = ($propValue !== 'false' && $propValue !== '0'); + $updateTag = true; + } + + if (isset($props[self::GROUPS_PROPERTYNAME])) { + if (!$this->groupManager->isAdmin($this->userSession->getUser()->getUID())) { + // property only available for admins + throw new Forbidden(); + } + + $propValue = $props[self::GROUPS_PROPERTYNAME]; + $groupIds = explode('|', $propValue); + $this->tagManager->setTagGroups($tag, $groupIds); + } + + if ($updateTag) { + $node->update($name, $userVisible, $userAssignable); } - $node->update($name, $userVisible, $userAssignable); return true; }); + } } diff --git a/apps/dav/lib/SystemTag/SystemTagsByIdCollection.php b/apps/dav/lib/SystemTag/SystemTagsByIdCollection.php index 298902501ab..2b24bce9f35 100644 --- a/apps/dav/lib/SystemTag/SystemTagsByIdCollection.php +++ b/apps/dav/lib/SystemTag/SystemTagsByIdCollection.php @@ -32,6 +32,7 @@ use OCP\SystemTag\ISystemTag; use OCP\SystemTag\TagNotFoundException; use OCP\IGroupManager; use OCP\IUserSession; +use OC\User\NoUserException; class SystemTagsByIdCollection implements ICollection { @@ -69,6 +70,8 @@ class SystemTagsByIdCollection implements ICollection { /** * Returns whether the currently logged in user is an administrator + * + * @return bool true if the user is an admin */ private function isAdmin() { $user = $this->userSession->getUser(); @@ -101,7 +104,7 @@ class SystemTagsByIdCollection implements ICollection { try { $tag = $this->tagManager->getTagsByIds([$name]); $tag = current($tag); - if (!$this->isAdmin() && !$tag->isUserVisible()) { + if (!$this->tagManager->canUserSeeTag($tag, $this->userSession->getUser())) { throw new NotFound('Tag with id ' . $name . ' not found'); } return $this->makeNode($tag); @@ -131,7 +134,7 @@ class SystemTagsByIdCollection implements ICollection { try { $tag = $this->tagManager->getTagsByIds([$name]); $tag = current($tag); - if (!$this->isAdmin() && !$tag->isUserVisible()) { + if (!$this->tagManager->canUserSeeTag($tag, $this->userSession->getUser())) { return false; } return true; @@ -171,6 +174,6 @@ class SystemTagsByIdCollection implements ICollection { * @return SystemTagNode */ private function makeNode(ISystemTag $tag) { - return new SystemTagNode($tag, $this->isAdmin(), $this->tagManager); + return new SystemTagNode($tag, $this->userSession->getUser(), $this->isAdmin(), $this->tagManager); } } diff --git a/apps/dav/lib/SystemTag/SystemTagsObjectMappingCollection.php b/apps/dav/lib/SystemTag/SystemTagsObjectMappingCollection.php index eb75ed06393..c4c45dc76d6 100644 --- a/apps/dav/lib/SystemTag/SystemTagsObjectMappingCollection.php +++ b/apps/dav/lib/SystemTag/SystemTagsObjectMappingCollection.php @@ -31,6 +31,7 @@ use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\ISystemTagObjectMapper; use OCP\SystemTag\ISystemTag; use OCP\SystemTag\TagNotFoundException; +use OCP\IUser; /** * Collection containing tags by object id @@ -58,11 +59,11 @@ class SystemTagsObjectMappingCollection implements ICollection { private $tagMapper; /** - * Whether to return results only visible for admins + * User * - * @var bool + * @var IUser */ - private $isAdmin; + private $user; /** @@ -70,30 +71,35 @@ class SystemTagsObjectMappingCollection implements ICollection { * * @param string $objectId object id * @param string $objectType object type - * @param bool $isAdmin whether to return results visible only for admins - * @param ISystemTagManager $tagManager - * @param ISystemTagObjectMapper $tagMapper + * @param IUser $user user + * @param ISystemTagManager $tagManager tag manager + * @param ISystemTagObjectMapper $tagMapper tag mapper */ - public function __construct($objectId, $objectType, $isAdmin, $tagManager, $tagMapper) { + public function __construct( + $objectId, + $objectType, + IUser $user, + ISystemTagManager $tagManager, + ISystemTagObjectMapper $tagMapper + ) { $this->tagManager = $tagManager; $this->tagMapper = $tagMapper; $this->objectId = $objectId; $this->objectType = $objectType; - $this->isAdmin = $isAdmin; + $this->user = $user; } function createFile($tagId, $data = null) { try { - if (!$this->isAdmin) { - $tag = $this->tagManager->getTagsByIds($tagId); - $tag = current($tag); - if (!$tag->isUserVisible()) { - throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign'); - } - if (!$tag->isUserAssignable()) { - throw new Forbidden('No permission to assign tag ' . $tag->getId()); - } + $tags = $this->tagManager->getTagsByIds([$tagId]); + $tag = current($tags); + if (!$this->tagManager->canUserSeeTag($tag, $this->user)) { + throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign'); } + if (!$this->tagManager->canUserAssignTag($tag, $this->user)) { + throw new Forbidden('No permission to assign tag ' . $tagId); + } + $this->tagMapper->assignTags($this->objectId, $this->objectType, $tagId); } catch (TagNotFoundException $e) { throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign'); @@ -109,7 +115,7 @@ class SystemTagsObjectMappingCollection implements ICollection { if ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)) { $tag = $this->tagManager->getTagsByIds([$tagId]); $tag = current($tag); - if ($this->isAdmin || $tag->isUserVisible()) { + if ($this->tagManager->canUserSeeTag($tag, $this->user)) { return $this->makeNode($tag); } } @@ -127,12 +133,12 @@ class SystemTagsObjectMappingCollection implements ICollection { return []; } $tags = $this->tagManager->getTagsByIds($tagIds); - if (!$this->isAdmin) { - // filter out non-visible tags - $tags = array_filter($tags, function($tag) { - return $tag->isUserVisible(); - }); - } + + // filter out non-visible tags + $tags = array_filter($tags, function($tag) { + return $this->tagManager->canUserSeeTag($tag, $this->user); + }); + return array_values(array_map(function($tag) { return $this->makeNode($tag); }, $tags)); @@ -141,17 +147,16 @@ class SystemTagsObjectMappingCollection implements ICollection { function childExists($tagId) { try { $result = ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)); - if ($this->isAdmin || !$result) { - return $result; - } - // verify if user is allowed to see this tag - $tag = $this->tagManager->getTagsByIds($tagId); - $tag = current($tag); - if (!$tag->isUserVisible()) { - return false; + if ($result) { + $tags = $this->tagManager->getTagsByIds([$tagId]); + $tag = current($tags); + if (!$this->tagManager->canUserSeeTag($tag, $this->user)) { + return false; + } } - return true; + + return $result; } catch (\InvalidArgumentException $e) { throw new BadRequest('Invalid tag id', 0, $e); } catch (TagNotFoundException $e) { @@ -193,7 +198,7 @@ class SystemTagsObjectMappingCollection implements ICollection { $tag, $this->objectId, $this->objectType, - $this->isAdmin, + $this->user, $this->tagManager, $this->tagMapper ); diff --git a/apps/dav/lib/SystemTag/SystemTagsObjectTypeCollection.php b/apps/dav/lib/SystemTag/SystemTagsObjectTypeCollection.php index bdbc73c4e32..ae4b9d51a1b 100644 --- a/apps/dav/lib/SystemTag/SystemTagsObjectTypeCollection.php +++ b/apps/dav/lib/SystemTag/SystemTagsObjectTypeCollection.php @@ -95,17 +95,6 @@ class SystemTagsObjectTypeCollection implements ICollection { } /** - * Returns whether the currently logged in user is an administrator - */ - private function isAdmin() { - $user = $this->userSession->getUser(); - if ($user !== null) { - return $this->groupManager->isAdmin($user->getUID()); - } - return false; - } - - /** * @param string $name * @param resource|string $data Initial payload * @throws Forbidden @@ -132,7 +121,7 @@ class SystemTagsObjectTypeCollection implements ICollection { return new SystemTagsObjectMappingCollection( $objectId, $this->objectType, - $this->isAdmin(), + $this->userSession->getUser(), $this->tagManager, $this->tagMapper ); diff --git a/apps/dav/tests/unit/comments/entitycollection.php b/apps/dav/tests/unit/comments/entitycollection.php index 5bf155f12ba..bc009e92549 100644 --- a/apps/dav/tests/unit/comments/entitycollection.php +++ b/apps/dav/tests/unit/comments/entitycollection.php @@ -23,18 +23,21 @@ namespace OCA\DAV\Tests\Unit\Comments; class EntityCollection extends \Test\TestCase { + /** @var \OCP\Comments\ICommentsManager|\PHPUnit_Framework_MockObject_MockObject */ protected $commentsManager; - protected $folder; + /** @var \OCP\IUserManager|\PHPUnit_Framework_MockObject_MockObject */ protected $userManager; + /** @var \OCP\ILogger|\PHPUnit_Framework_MockObject_MockObject */ protected $logger; + /** @var \OCA\DAV\Comments\EntityCollection */ protected $collection; + /** @var \OCP\IUserSession|\PHPUnit_Framework_MockObject_MockObject */ protected $userSession; public function setUp() { parent::setUp(); $this->commentsManager = $this->getMock('\OCP\Comments\ICommentsManager'); - $this->folder = $this->getMock('\OCP\Files\Folder'); $this->userManager = $this->getMock('\OCP\IUserManager'); $this->userSession = $this->getMock('\OCP\IUserSession'); $this->logger = $this->getMock('\OCP\ILogger'); @@ -43,7 +46,6 @@ class EntityCollection extends \Test\TestCase { '19', 'files', $this->commentsManager, - $this->folder, $this->userManager, $this->userSession, $this->logger diff --git a/apps/dav/tests/unit/comments/entitytypecollection.php b/apps/dav/tests/unit/comments/entitytypecollection.php index f3aa2dbd71f..96b1cad8373 100644 --- a/apps/dav/tests/unit/comments/entitytypecollection.php +++ b/apps/dav/tests/unit/comments/entitytypecollection.php @@ -25,52 +25,52 @@ use OCA\DAV\Comments\EntityCollection as EntityCollectionImplemantation; class EntityTypeCollection extends \Test\TestCase { + /** @var \OCP\Comments\ICommentsManager|\PHPUnit_Framework_MockObject_MockObject */ protected $commentsManager; - protected $folder; + /** @var \OCP\IUserManager|\PHPUnit_Framework_MockObject_MockObject */ protected $userManager; + /** @var \OCP\ILogger|\PHPUnit_Framework_MockObject_MockObject */ protected $logger; + /** @var \OCA\DAV\Comments\EntityTypeCollection */ protected $collection; + /** @var \OCP\IUserSession|\PHPUnit_Framework_MockObject_MockObject */ protected $userSession; + protected $childMap = []; + public function setUp() { parent::setUp(); $this->commentsManager = $this->getMock('\OCP\Comments\ICommentsManager'); - $this->folder = $this->getMock('\OCP\Files\Folder'); $this->userManager = $this->getMock('\OCP\IUserManager'); $this->userSession = $this->getMock('\OCP\IUserSession'); $this->logger = $this->getMock('\OCP\ILogger'); + $instance = $this; + $this->collection = new \OCA\DAV\Comments\EntityTypeCollection( 'files', $this->commentsManager, - $this->folder, $this->userManager, $this->userSession, - $this->logger + $this->logger, + function ($child) use ($instance) { + return !empty($instance->childMap[$child]); + } ); } public function testChildExistsYes() { - $this->folder->expects($this->once()) - ->method('getById') - ->with('17') - ->will($this->returnValue([$this->getMock('\OCP\Files\Node')])); + $this->childMap[17] = true; $this->assertTrue($this->collection->childExists('17')); } public function testChildExistsNo() { - $this->folder->expects($this->once()) - ->method('getById') - ->will($this->returnValue([])); $this->assertFalse($this->collection->childExists('17')); } public function testGetChild() { - $this->folder->expects($this->once()) - ->method('getById') - ->with('17') - ->will($this->returnValue([$this->getMock('\OCP\Files\Node')])); + $this->childMap[17] = true; $ec = $this->collection->getChild('17'); $this->assertTrue($ec instanceof EntityCollectionImplemantation); @@ -80,11 +80,6 @@ class EntityTypeCollection extends \Test\TestCase { * @expectedException \Sabre\DAV\Exception\NotFound */ public function testGetChildException() { - $this->folder->expects($this->once()) - ->method('getById') - ->with('17') - ->will($this->returnValue([])); - $this->collection->getChild('17'); } diff --git a/apps/dav/tests/unit/comments/rootcollection.php b/apps/dav/tests/unit/comments/rootcollection.php index 369006e7159..a59482fba73 100644 --- a/apps/dav/tests/unit/comments/rootcollection.php +++ b/apps/dav/tests/unit/comments/rootcollection.php @@ -22,15 +22,24 @@ namespace OCA\DAV\Tests\Unit\Comments; use OCA\DAV\Comments\EntityTypeCollection as EntityTypeCollectionImplementation; +use OCP\Comments\CommentsEntityEvent; +use Symfony\Component\EventDispatcher\EventDispatcher; class RootCollection extends \Test\TestCase { + /** @var \OCP\Comments\ICommentsManager|\PHPUnit_Framework_MockObject_MockObject */ protected $commentsManager; + /** @var \OCP\IUserManager|\PHPUnit_Framework_MockObject_MockObject */ protected $userManager; + /** @var \OCP\ILogger|\PHPUnit_Framework_MockObject_MockObject */ protected $logger; + /** @var \OCA\DAV\Comments\RootCollection */ protected $collection; + /** @var \OCP\IUserSession|\PHPUnit_Framework_MockObject_MockObject */ protected $userSession; - protected $rootFolder; + /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface */ + protected $dispatcher; + /** @var \OCP\IUser|\PHPUnit_Framework_MockObject_MockObject */ protected $user; public function setUp() { @@ -41,14 +50,14 @@ class RootCollection extends \Test\TestCase { $this->commentsManager = $this->getMock('\OCP\Comments\ICommentsManager'); $this->userManager = $this->getMock('\OCP\IUserManager'); $this->userSession = $this->getMock('\OCP\IUserSession'); - $this->rootFolder = $this->getMock('\OCP\Files\IRootFolder'); + $this->dispatcher = new EventDispatcher(); $this->logger = $this->getMock('\OCP\ILogger'); $this->collection = new \OCA\DAV\Comments\RootCollection( $this->commentsManager, $this->userManager, $this->userSession, - $this->rootFolder, + $this->dispatcher, $this->logger ); } @@ -62,10 +71,11 @@ class RootCollection extends \Test\TestCase { ->method('getUser') ->will($this->returnValue($this->user)); - $this->rootFolder->expects($this->once()) - ->method('getUserFolder') - ->with('alice') - ->will($this->returnValue($this->getMock('\OCP\Files\Folder'))); + $this->dispatcher->addListener(CommentsEntityEvent::EVENT_ENTITY, function(CommentsEntityEvent $event) { + $event->addEntityCollection('files', function() { + return true; + }); + }); } /** diff --git a/apps/dav/tests/unit/connector/sabre/commentpropertiesplugin.php b/apps/dav/tests/unit/connector/sabre/commentpropertiesplugin.php index f915c83c4a7..f7f87e01544 100644 --- a/apps/dav/tests/unit/connector/sabre/commentpropertiesplugin.php +++ b/apps/dav/tests/unit/connector/sabre/commentpropertiesplugin.php @@ -84,7 +84,8 @@ class CommentsPropertiesPlugin extends \Test\TestCase { public function baseUriProvider() { return [ ['owncloud/remote.php/webdav/', '4567', 'owncloud/remote.php/dav/comments/files/4567'], - ['owncloud/remote.php/wicked/', '4567', null] + ['owncloud/remote.php/files/', '4567', 'owncloud/remote.php/dav/comments/files/4567'], + ['owncloud/wicked.php/files/', '4567', null] ]; } diff --git a/apps/dav/tests/unit/systemtag/systemtagmappingnode.php b/apps/dav/tests/unit/systemtag/systemtagmappingnode.php index 7f2ff7d6616..f0e1c3bc567 100644 --- a/apps/dav/tests/unit/systemtag/systemtagmappingnode.php +++ b/apps/dav/tests/unit/systemtag/systemtagmappingnode.php @@ -24,6 +24,7 @@ namespace OCA\DAV\Tests\Unit\SystemTag; use Sabre\DAV\Exception\NotFound; use OC\SystemTag\SystemTag; use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\ISystemTag; class SystemTagMappingNode extends \Test\TestCase { @@ -37,14 +38,20 @@ class SystemTagMappingNode extends \Test\TestCase { */ private $tagMapper; + /** + * @var \OCP\IUser + */ + private $user; + protected function setUp() { parent::setUp(); $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper'); + $this->user = $this->getMock('\OCP\IUser'); } - public function getMappingNode($isAdmin = true, $tag = null) { + public function getMappingNode($tag = null) { if ($tag === null) { $tag = new SystemTag(1, 'Test', true, true); } @@ -52,7 +59,7 @@ class SystemTagMappingNode extends \Test\TestCase { $tag, 123, 'files', - $isAdmin, + $this->user, $this->tagManager, $this->tagMapper ); @@ -60,28 +67,30 @@ class SystemTagMappingNode extends \Test\TestCase { public function testGetters() { $tag = new SystemTag(1, 'Test', true, false); - $node = $this->getMappingNode(true, $tag); + $node = $this->getMappingNode($tag); $this->assertEquals('1', $node->getName()); $this->assertEquals($tag, $node->getSystemTag()); $this->assertEquals(123, $node->getObjectId()); $this->assertEquals('files', $node->getObjectType()); } - public function adminFlagProvider() { - return [[true], [false]]; - } - - /** - * @dataProvider adminFlagProvider - */ - public function testDeleteTag($isAdmin) { + public function testDeleteTag() { + $node = $this->getMappingNode(); + $this->tagManager->expects($this->once()) + ->method('canUserSeeTag') + ->with($node->getSystemTag()) + ->will($this->returnValue(true)); + $this->tagManager->expects($this->once()) + ->method('canUserAssignTag') + ->with($node->getSystemTag()) + ->will($this->returnValue(true)); $this->tagManager->expects($this->never()) ->method('deleteTags'); $this->tagMapper->expects($this->once()) ->method('unassignTags') ->with(123, 'files', 1); - $this->getMappingNode($isAdmin)->delete(); + $node->delete(); } public function tagNodeDeleteProviderPermissionException() { @@ -102,7 +111,15 @@ class SystemTagMappingNode extends \Test\TestCase { /** * @dataProvider tagNodeDeleteProviderPermissionException */ - public function testDeleteTagExpectedException($tag, $expectedException) { + public function testDeleteTagExpectedException(ISystemTag $tag, $expectedException) { + $this->tagManager->expects($this->any()) + ->method('canUserSeeTag') + ->with($tag) + ->will($this->returnValue($tag->isUserVisible())); + $this->tagManager->expects($this->any()) + ->method('canUserAssignTag') + ->with($tag) + ->will($this->returnValue($tag->isUserAssignable())); $this->tagManager->expects($this->never()) ->method('deleteTags'); $this->tagMapper->expects($this->never()) @@ -110,7 +127,7 @@ class SystemTagMappingNode extends \Test\TestCase { $thrown = null; try { - $this->getMappingNode(false, $tag)->delete(); + $this->getMappingNode($tag)->delete(); } catch (\Exception $e) { $thrown = $e; } @@ -122,11 +139,22 @@ class SystemTagMappingNode extends \Test\TestCase { * @expectedException Sabre\DAV\Exception\NotFound */ public function testDeleteTagNotFound() { + // assuming the tag existed at the time the node was created, + // but got deleted concurrently in the database + $tag = new SystemTag(1, 'Test', true, true); + $this->tagManager->expects($this->once()) + ->method('canUserSeeTag') + ->with($tag) + ->will($this->returnValue($tag->isUserVisible())); + $this->tagManager->expects($this->once()) + ->method('canUserAssignTag') + ->with($tag) + ->will($this->returnValue($tag->isUserAssignable())); $this->tagMapper->expects($this->once()) ->method('unassignTags') ->with(123, 'files', 1) ->will($this->throwException(new TagNotFoundException())); - $this->getMappingNode()->delete(); + $this->getMappingNode($tag)->delete(); } } diff --git a/apps/dav/tests/unit/systemtag/systemtagnode.php b/apps/dav/tests/unit/systemtag/systemtagnode.php index 5184b74e5c8..d9e088a7d90 100644 --- a/apps/dav/tests/unit/systemtag/systemtagnode.php +++ b/apps/dav/tests/unit/systemtag/systemtagnode.php @@ -28,6 +28,7 @@ use Sabre\DAV\Exception\Conflict; use OC\SystemTag\SystemTag; use OCP\SystemTag\TagNotFoundException; use OCP\SystemTag\TagAlreadyExistsException; +use OCP\SystemTag\ISystemTag; class SystemTagNode extends \Test\TestCase { @@ -36,10 +37,16 @@ class SystemTagNode extends \Test\TestCase { */ private $tagManager; + /** + * @var \OCP\IUser + */ + private $user; + protected function setUp() { parent::setUp(); $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + $this->user = $this->getMock('\OCP\IUser'); } protected function getTagNode($isAdmin = true, $tag = null) { @@ -48,6 +55,7 @@ class SystemTagNode extends \Test\TestCase { } return new \OCA\DAV\SystemTag\SystemTagNode( $tag, + $this->user, $isAdmin, $this->tagManager ); @@ -102,6 +110,14 @@ class SystemTagNode extends \Test\TestCase { */ public function testUpdateTag($isAdmin, $originalTag, $changedArgs) { $this->tagManager->expects($this->once()) + ->method('canUserSeeTag') + ->with($originalTag) + ->will($this->returnValue($originalTag->isUserVisible() || $isAdmin)); + $this->tagManager->expects($this->once()) + ->method('canUserAssignTag') + ->with($originalTag) + ->will($this->returnValue($originalTag->isUserAssignable() || $isAdmin)); + $this->tagManager->expects($this->once()) ->method('updateTag') ->with(1, $changedArgs[0], $changedArgs[1], $changedArgs[2]); $this->getTagNode($isAdmin, $originalTag) @@ -153,6 +169,14 @@ class SystemTagNode extends \Test\TestCase { * @dataProvider tagNodeProviderPermissionException */ public function testUpdateTagPermissionException($originalTag, $changedArgs, $expectedException = null) { + $this->tagManager->expects($this->any()) + ->method('canUserSeeTag') + ->with($originalTag) + ->will($this->returnValue($originalTag->isUserVisible())); + $this->tagManager->expects($this->any()) + ->method('canUserAssignTag') + ->with($originalTag) + ->will($this->returnValue($originalTag->isUserAssignable())); $this->tagManager->expects($this->never()) ->method('updateTag'); @@ -172,32 +196,59 @@ class SystemTagNode extends \Test\TestCase { * @expectedException Sabre\DAV\Exception\Conflict */ public function testUpdateTagAlreadyExists() { + $tag = new SystemTag(1, 'tag1', true, true); + $this->tagManager->expects($this->any()) + ->method('canUserSeeTag') + ->with($tag) + ->will($this->returnValue(true)); + $this->tagManager->expects($this->any()) + ->method('canUserAssignTag') + ->with($tag) + ->will($this->returnValue(true)); $this->tagManager->expects($this->once()) ->method('updateTag') - ->with(1, 'Renamed', false, true) + ->with(1, 'Renamed', true, true) ->will($this->throwException(new TagAlreadyExistsException())); - $this->getTagNode()->update('Renamed', false, true); + $this->getTagNode(false, $tag)->update('Renamed', true, true); } /** * @expectedException Sabre\DAV\Exception\NotFound */ public function testUpdateTagNotFound() { + $tag = new SystemTag(1, 'tag1', true, true); + $this->tagManager->expects($this->any()) + ->method('canUserSeeTag') + ->with($tag) + ->will($this->returnValue(true)); + $this->tagManager->expects($this->any()) + ->method('canUserAssignTag') + ->with($tag) + ->will($this->returnValue(true)); $this->tagManager->expects($this->once()) ->method('updateTag') - ->with(1, 'Renamed', false, true) + ->with(1, 'Renamed', true, true) ->will($this->throwException(new TagNotFoundException())); - $this->getTagNode()->update('Renamed', false, true); + $this->getTagNode(false, $tag)->update('Renamed', true, true); } /** * @dataProvider adminFlagProvider */ public function testDeleteTag($isAdmin) { + $tag = new SystemTag(1, 'tag1', true, true); + $this->tagManager->expects($this->once()) + ->method('canUserSeeTag') + ->with($tag) + ->will($this->returnValue(true)); + $this->tagManager->expects($this->once()) + ->method('canUserAssignTag') + ->with($tag) + ->will($this->returnValue(true)); $this->tagManager->expects($this->once()) ->method('deleteTags') ->with('1'); - $this->getTagNode($isAdmin)->delete(); + $this->getTagNode($isAdmin, $tag)->delete(); } public function tagNodeDeleteProviderPermissionException() { @@ -218,7 +269,15 @@ class SystemTagNode extends \Test\TestCase { /** * @dataProvider tagNodeDeleteProviderPermissionException */ - public function testDeleteTagPermissionException($tag, $expectedException) { + public function testDeleteTagPermissionException(ISystemTag $tag, $expectedException) { + $this->tagManager->expects($this->any()) + ->method('canUserSeeTag') + ->with($tag) + ->will($this->returnValue($tag->isUserVisible())); + $this->tagManager->expects($this->any()) + ->method('canUserAssignTag') + ->with($tag) + ->will($this->returnValue($tag->isUserAssignable())); $this->tagManager->expects($this->never()) ->method('deleteTags'); @@ -235,10 +294,19 @@ class SystemTagNode extends \Test\TestCase { * @expectedException Sabre\DAV\Exception\NotFound */ public function testDeleteTagNotFound() { + $tag = new SystemTag(1, 'tag1', true, true); + $this->tagManager->expects($this->any()) + ->method('canUserSeeTag') + ->with($tag) + ->will($this->returnValue($tag->isUserVisible())); + $this->tagManager->expects($this->any()) + ->method('canUserAssignTag') + ->with($tag) + ->will($this->returnValue($tag->isUserAssignable())); $this->tagManager->expects($this->once()) ->method('deleteTags') ->with('1') ->will($this->throwException(new TagNotFoundException())); - $this->getTagNode()->delete(); + $this->getTagNode(false, $tag)->delete(); } } diff --git a/apps/dav/tests/unit/systemtag/systemtagplugin.php b/apps/dav/tests/unit/systemtag/systemtagplugin.php index 4466533f1e0..da82bc8904a 100644 --- a/apps/dav/tests/unit/systemtag/systemtagplugin.php +++ b/apps/dav/tests/unit/systemtag/systemtagplugin.php @@ -27,6 +27,8 @@ use OC\SystemTag\SystemTag; use OCP\IGroupManager; use OCP\IUserSession; use OCP\SystemTag\TagAlreadyExistsException; +use OCP\IUser; +use OCP\SystemTag\ISystemTag; class SystemTagPlugin extends \Test\TestCase { @@ -34,6 +36,8 @@ class SystemTagPlugin extends \Test\TestCase { 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; + const CANASSIGN_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::CANASSIGN_PROPERTYNAME; + const GROUPS_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::GROUPS_PROPERTYNAME; /** * @var \Sabre\DAV\Server @@ -61,6 +65,11 @@ class SystemTagPlugin extends \Test\TestCase { private $userSession; /** + * @var IUser + */ + private $user; + + /** * @var \OCA\DAV\SystemTag\SystemTagPlugin */ private $plugin; @@ -75,7 +84,16 @@ class SystemTagPlugin extends \Test\TestCase { $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); $this->groupManager = $this->getMock('\OCP\IGroupManager'); + $this->user = $this->getMock('\OCP\IUser'); $this->userSession = $this->getMock('\OCP\IUserSession'); + $this->userSession + ->expects($this->any()) + ->method('getUser') + ->willReturn($this->user); + $this->userSession + ->expects($this->any()) + ->method('isLoggedIn') + ->willReturn(true); $this->plugin = new \OCA\DAV\SystemTag\SystemTagPlugin( $this->tagManager, @@ -85,22 +103,84 @@ class SystemTagPlugin extends \Test\TestCase { $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 => 'true', - self::USERASSIGNABLE_PROPERTYNAME => 'true', - ] + public function getPropertiesDataProvider() { + return [ + [ + new SystemTag(1, 'Test', true, true), + [], + [ + self::ID_PROPERTYNAME, + self::DISPLAYNAME_PROPERTYNAME, + self::USERVISIBLE_PROPERTYNAME, + self::USERASSIGNABLE_PROPERTYNAME, + self::CANASSIGN_PROPERTYNAME, + ], + [ + self::ID_PROPERTYNAME => '1', + self::DISPLAYNAME_PROPERTYNAME => 'Test', + self::USERVISIBLE_PROPERTYNAME => 'true', + self::USERASSIGNABLE_PROPERTYNAME => 'true', + self::CANASSIGN_PROPERTYNAME => 'true', + ] + ], + [ + new SystemTag(1, 'Test', true, false), + [], + [ + self::ID_PROPERTYNAME, + self::DISPLAYNAME_PROPERTYNAME, + self::USERVISIBLE_PROPERTYNAME, + self::USERASSIGNABLE_PROPERTYNAME, + self::CANASSIGN_PROPERTYNAME, + ], + [ + self::ID_PROPERTYNAME => '1', + self::DISPLAYNAME_PROPERTYNAME => 'Test', + self::USERVISIBLE_PROPERTYNAME => 'true', + self::USERASSIGNABLE_PROPERTYNAME => 'false', + self::CANASSIGN_PROPERTYNAME => 'false', + ] + ], + [ + new SystemTag(1, 'Test', true, false), + ['group1', 'group2'], + [ + self::ID_PROPERTYNAME, + self::GROUPS_PROPERTYNAME, + ], + [ + self::ID_PROPERTYNAME => '1', + self::GROUPS_PROPERTYNAME => 'group1|group2', + ] + ], + [ + new SystemTag(1, 'Test', true, true), + ['group1', 'group2'], + [ + self::ID_PROPERTYNAME, + self::GROUPS_PROPERTYNAME, + ], + [ + self::ID_PROPERTYNAME => '1', + // groups only returned when userAssignable is false + self::GROUPS_PROPERTYNAME => '', + ] + ], ]; + } + + /** + * @dataProvider getPropertiesDataProvider + */ + public function testGetProperties(ISystemTag $systemTag, $groups, $requestedProperties, $expectedProperties) { + $this->user->expects($this->any()) + ->method('getUID') + ->willReturn('admin'); + $this->groupManager + ->expects($this->any()) + ->method('isAdmin') + ->with('admin') + ->willReturn(true); $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagNode') ->disableOriginalConstructor() @@ -109,6 +189,14 @@ class SystemTagPlugin extends \Test\TestCase { ->method('getSystemTag') ->will($this->returnValue($systemTag)); + $this->tagManager->expects($this->any()) + ->method('canUserAssignTag') + ->will($this->returnValue($systemTag->isUserAssignable())); + + $this->tagManager->expects($this->any()) + ->method('getTagGroups') + ->will($this->returnValue($groups)); + $this->tree->expects($this->any()) ->method('getNodeForPath') ->with('/systemtag/1') @@ -128,12 +216,62 @@ class SystemTagPlugin extends \Test\TestCase { $result = $propFind->getResultForMultiStatus(); $this->assertEmpty($result[404]); - unset($result[404]); - $this->assertEquals($expectedProperties, $result); + $this->assertEquals($expectedProperties, $result[200]); } - public function testUpdateProperties() { + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + public function testGetPropertiesForbidden() { $systemTag = new SystemTag(1, 'Test', true, false); + $requestedProperties = [ + self::ID_PROPERTYNAME, + self::GROUPS_PROPERTYNAME, + ]; + $this->user->expects($this->once()) + ->method('getUID') + ->willReturn('admin'); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('admin') + ->willReturn(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)); + + $propFind = new \Sabre\DAV\PropFind( + '/systemtag/1', + $requestedProperties, + 0 + ); + + $this->plugin->handleGetProperties( + $propFind, + $node + ); + } + + public function testUpdatePropertiesAdmin() { + $systemTag = new SystemTag(1, 'Test', true, false); + $this->user->expects($this->any()) + ->method('getUID') + ->willReturn('admin'); + $this->groupManager + ->expects($this->any()) + ->method('isAdmin') + ->with('admin') + ->willReturn(true); + $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagNode') ->disableOriginalConstructor() ->getMock(); @@ -150,11 +288,16 @@ class SystemTagPlugin extends \Test\TestCase { ->method('update') ->with('Test changed', false, true); + $this->tagManager->expects($this->once()) + ->method('setTagGroups') + ->with($systemTag, ['group1', 'group2']); + // properties to set $propPatch = new \Sabre\DAV\PropPatch(array( self::DISPLAYNAME_PROPERTYNAME => 'Test changed', self::USERVISIBLE_PROPERTYNAME => 'false', self::USERASSIGNABLE_PROPERTYNAME => 'true', + self::GROUPS_PROPERTYNAME => 'group1|group2', )); $this->plugin->handleUpdateProperties( @@ -174,102 +317,89 @@ class SystemTagPlugin extends \Test\TestCase { } /** - * @expectedException \Sabre\DAV\Exception\BadRequest - * @expectedExceptionMessage Not sufficient permissions + * @expectedException \Sabre\DAV\Exception\Forbidden */ - public function testCreateNotAssignableTagAsRegularUser() { - $user = $this->getMock('\OCP\IUser'); - $user->expects($this->once()) + public function testUpdatePropertiesForbidden() { + $systemTag = new SystemTag(1, 'Test', true, false); + $this->user->expects($this->any()) ->method('getUID') ->willReturn('admin'); - $this->userSession - ->expects($this->once()) - ->method('isLoggedIn') - ->willReturn(true); - $this->userSession - ->expects($this->once()) - ->method('getUser') - ->willReturn($user); $this->groupManager - ->expects($this->once()) + ->expects($this->any()) ->method('isAdmin') ->with('admin') ->willReturn(false); - $requestData = json_encode([ - 'name' => 'Test', - 'userVisible' => true, - 'userAssignable' => false, - ]); - - $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagsByIdCollection') + $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagNode') ->disableOriginalConstructor() ->getMock(); - $this->tagManager->expects($this->never()) - ->method('createTag'); + $node->expects($this->any()) + ->method('getSystemTag') + ->will($this->returnValue($systemTag)); $this->tree->expects($this->any()) ->method('getNodeForPath') - ->with('/systemtags') + ->with('/systemtag/1') ->will($this->returnValue($node)); - $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') - ->disableOriginalConstructor() - ->getMock(); - $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface') - ->disableOriginalConstructor() - ->getMock(); + $node->expects($this->never()) + ->method('update'); - $request->expects($this->once()) - ->method('getPath') - ->will($this->returnValue('/systemtags')); + $this->tagManager->expects($this->never()) + ->method('setTagGroups'); - $request->expects($this->once()) - ->method('getBodyAsString') - ->will($this->returnValue($requestData)); + // properties to set + $propPatch = new \Sabre\DAV\PropPatch(array( + self::GROUPS_PROPERTYNAME => 'group1|group2', + )); - $request->expects($this->once()) - ->method('getHeader') - ->with('Content-Type') - ->will($this->returnValue('application/json')); + $this->plugin->handleUpdateProperties( + '/systemtag/1', + $propPatch + ); - $this->plugin->httpPost($request, $response); + $propPatch->commit(); } + public function createTagInsufficientPermissionsProvider() { + return [ + [true, false, ''], + [false, true, ''], + [true, true, 'group1|group2'], + ]; + } /** + * @dataProvider createTagInsufficientPermissionsProvider * @expectedException \Sabre\DAV\Exception\BadRequest * @expectedExceptionMessage Not sufficient permissions */ - public function testCreateInvisibleTagAsRegularUser() { - $user = $this->getMock('\OCP\IUser'); - $user->expects($this->once()) + public function testCreateNotAssignableTagAsRegularUser($userVisible, $userAssignable, $groups) { + $this->user->expects($this->once()) ->method('getUID') ->willReturn('admin'); - $this->userSession - ->expects($this->once()) - ->method('isLoggedIn') - ->willReturn(true); - $this->userSession - ->expects($this->once()) - ->method('getUser') - ->willReturn($user); $this->groupManager ->expects($this->once()) ->method('isAdmin') ->with('admin') ->willReturn(false); - $requestData = json_encode([ + $requestData = [ 'name' => 'Test', - 'userVisible' => false, - 'userAssignable' => true, - ]); + 'userVisible' => $userVisible, + 'userAssignable' => $userAssignable, + ]; + if (!empty($groups)) { + $requestData['groups'] = $groups; + } + $requestData = json_encode($requestData); $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagsByIdCollection') ->disableOriginalConstructor() ->getMock(); $this->tagManager->expects($this->never()) ->method('createTag'); + $this->tagManager->expects($this->never()) + ->method('setTagGroups'); $this->tree->expects($this->any()) ->method('getNodeForPath') @@ -352,19 +482,21 @@ class SystemTagPlugin extends \Test\TestCase { $this->plugin->httpPost($request, $response); } - public function testCreateTagInByIdCollection() { - $user = $this->getMock('\OCP\IUser'); - $user->expects($this->once()) + public function createTagProvider() { + return [ + [true, false, ''], + [false, false, ''], + [true, false, 'group1|group2'], + ]; + } + + /** + * @dataProvider createTagProvider + */ + public function testCreateTagInByIdCollection($userVisible, $userAssignable, $groups) { + $this->user->expects($this->once()) ->method('getUID') ->willReturn('admin'); - $this->userSession - ->expects($this->once()) - ->method('isLoggedIn') - ->willReturn(true); - $this->userSession - ->expects($this->once()) - ->method('getUser') - ->willReturn($user); $this->groupManager ->expects($this->once()) ->method('isAdmin') @@ -373,19 +505,33 @@ class SystemTagPlugin extends \Test\TestCase { $systemTag = new SystemTag(1, 'Test', true, false); - $requestData = json_encode([ + $requestData = [ 'name' => 'Test', - 'userVisible' => true, - 'userAssignable' => false, - ]); + 'userVisible' => $userVisible, + 'userAssignable' => $userAssignable, + ]; + if (!empty($groups)) { + $requestData['groups'] = $groups; + } + $requestData = json_encode($requestData); $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagsByIdCollection') ->disableOriginalConstructor() ->getMock(); $this->tagManager->expects($this->once()) ->method('createTag') - ->with('Test', true, false) + ->with('Test', $userVisible, $userAssignable) ->will($this->returnValue($systemTag)); + + if (!empty($groups)) { + $this->tagManager->expects($this->once()) + ->method('setTagGroups') + ->with($systemTag, explode('|', $groups)) + ->will($this->returnValue($systemTag)); + } else { + $this->tagManager->expects($this->never()) + ->method('setTagGroups'); + } $this->tree->expects($this->any()) ->method('getNodeForPath') @@ -431,18 +577,9 @@ class SystemTagPlugin extends \Test\TestCase { } public function testCreateTagInMappingCollection() { - $user = $this->getMock('\OCP\IUser'); - $user->expects($this->once()) + $this->user->expects($this->once()) ->method('getUID') ->willReturn('admin'); - $this->userSession - ->expects($this->once()) - ->method('isLoggedIn') - ->willReturn(true); - $this->userSession - ->expects($this->once()) - ->method('getUser') - ->willReturn($user); $this->groupManager ->expects($this->once()) ->method('isAdmin') @@ -510,8 +647,6 @@ class SystemTagPlugin extends \Test\TestCase { * @expectedException \Sabre\DAV\Exception\NotFound */ public function testCreateTagToUnknownNode() { - $systemTag = new SystemTag(1, 'Test', true, false); - $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection') ->disableOriginalConstructor() ->getMock(); @@ -545,18 +680,9 @@ class SystemTagPlugin extends \Test\TestCase { * @expectedException \Sabre\DAV\Exception\Conflict */ public function testCreateTagConflict($nodeClass) { - $user = $this->getMock('\OCP\IUser'); - $user->expects($this->once()) + $this->user->expects($this->once()) ->method('getUID') ->willReturn('admin'); - $this->userSession - ->expects($this->once()) - ->method('isLoggedIn') - ->willReturn(true); - $this->userSession - ->expects($this->once()) - ->method('getUser') - ->willReturn($user); $this->groupManager ->expects($this->once()) ->method('isAdmin') diff --git a/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php index a2bf571ab68..5aa28d1a254 100644 --- a/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php +++ b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php @@ -32,6 +32,11 @@ class SystemTagsByIdCollection extends \Test\TestCase { */ private $tagManager; + /** + * @var \OCP\IUser + */ + private $user; + protected function setUp() { parent::setUp(); @@ -39,14 +44,14 @@ class SystemTagsByIdCollection extends \Test\TestCase { } public function getNode($isAdmin = true) { - $user = $this->getMock('\OCP\IUser'); - $user->expects($this->any()) + $this->user = $this->getMock('\OCP\IUser'); + $this->user->expects($this->any()) ->method('getUID') ->will($this->returnValue('testuser')); $userSession = $this->getMock('\OCP\IUserSession'); $userSession->expects($this->any()) ->method('getUser') - ->will($this->returnValue($user)); + ->will($this->returnValue($this->user)); $groupManager = $this->getMock('\OCP\IGroupManager'); $groupManager->expects($this->any()) ->method('isAdmin') @@ -77,35 +82,19 @@ class SystemTagsByIdCollection extends \Test\TestCase { $this->getNode()->createDirectory('789'); } - public function getChildProvider() { - return [ - [ - true, - true, - ], - [ - true, - false, - ], - [ - false, - true, - ], - ]; - } - - /** - * @dataProvider getChildProvider - */ - public function testGetChild($isAdmin, $userVisible) { - $tag = new SystemTag(123, 'Test', $userVisible, false); + public function testGetChild() { + $tag = new SystemTag(123, 'Test', true, false); + $this->tagManager->expects($this->once()) + ->method('canUserSeeTag') + ->with($tag) + ->will($this->returnValue(true)); $this->tagManager->expects($this->once()) ->method('getTagsByIds') ->with(['123']) ->will($this->returnValue([$tag])); - $childNode = $this->getNode($isAdmin)->getChild('123'); + $childNode = $this->getNode()->getChild('123'); $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $childNode); $this->assertEquals('123', $childNode->getName()); @@ -198,27 +187,27 @@ class SystemTagsByIdCollection extends \Test\TestCase { public function childExistsProvider() { return [ - // admins, always visible - [true, true, true], - [true, false, true], - // non-admins, depends on flag - [false, true, true], - [false, false, false], + [true, true], + [false, false], ]; } /** * @dataProvider childExistsProvider */ - public function testChildExists($isAdmin, $userVisible, $expectedResult) { + public function testChildExists($userVisible, $expectedResult) { $tag = new SystemTag(123, 'One', $userVisible, false); + $this->tagManager->expects($this->once()) + ->method('canUserSeeTag') + ->with($tag) + ->will($this->returnValue($userVisible)); $this->tagManager->expects($this->once()) ->method('getTagsByIds') ->with(['123']) ->will($this->returnValue([$tag])); - $this->assertEquals($expectedResult, $this->getNode($isAdmin)->childExists('123')); + $this->assertEquals($expectedResult, $this->getNode()->childExists('123')); } public function testChildExistsNotFound() { diff --git a/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php index df97acd846b..9adc5b88c41 100644 --- a/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php +++ b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php @@ -37,45 +37,50 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { */ private $tagMapper; + /** + * @var \OCP\IUser + */ + private $user; + protected function setUp() { parent::setUp(); $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper'); + + $this->user = $this->getMock('\OCP\IUser'); } - public function getNode($isAdmin = true) { + public function getNode() { return new \OCA\DAV\SystemTag\SystemTagsObjectMappingCollection ( 111, 'files', - $isAdmin, + $this->user, $this->tagManager, $this->tagMapper ); } - public function testAssignTagAsAdmin() { - $this->tagManager->expects($this->never()) - ->method('getTagsByIds'); - $this->tagMapper->expects($this->once()) - ->method('assignTags') - ->with(111, 'files', '555'); - - $this->getNode(true)->createFile('555'); - } - - public function testAssignTagAsUser() { + public function testAssignTag() { $tag = new SystemTag('1', 'Test', true, true); + $this->tagManager->expects($this->once()) + ->method('canUserSeeTag') + ->with($tag) + ->will($this->returnValue(true)); + $this->tagManager->expects($this->once()) + ->method('canUserAssignTag') + ->with($tag) + ->will($this->returnValue(true)); $this->tagManager->expects($this->once()) ->method('getTagsByIds') - ->with('555') + ->with(['555']) ->will($this->returnValue([$tag])); $this->tagMapper->expects($this->once()) ->method('assignTags') ->with(111, 'files', '555'); - $this->getNode(false)->createFile('555'); + $this->getNode()->createFile('555'); } public function permissionsProvider() { @@ -90,19 +95,27 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { /** * @dataProvider permissionsProvider */ - public function testAssignTagAsUserNoPermission($userVisible, $userAssignable, $expectedException) { + public function testAssignTagNoPermission($userVisible, $userAssignable, $expectedException) { $tag = new SystemTag('1', 'Test', $userVisible, $userAssignable); + $this->tagManager->expects($this->once()) + ->method('canUserSeeTag') + ->with($tag) + ->will($this->returnValue($userVisible)); + $this->tagManager->expects($this->any()) + ->method('canUserAssignTag') + ->with($tag) + ->will($this->returnValue($userAssignable)); $this->tagManager->expects($this->once()) ->method('getTagsByIds') - ->with('555') + ->with(['555']) ->will($this->returnValue([$tag])); $this->tagMapper->expects($this->never()) ->method('assignTags'); $thrown = null; try { - $this->getNode(false)->createFile('555'); + $this->getNode()->createFile('555'); } catch (\Exception $e) { $thrown = $e; } @@ -114,9 +127,9 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { * @expectedException Sabre\DAV\Exception\PreconditionFailed */ public function testAssignTagNotFound() { - $this->tagMapper->expects($this->once()) - ->method('assignTags') - ->with(111, 'files', '555') + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with(['555']) ->will($this->throwException(new TagNotFoundException())); $this->getNode()->createFile('555'); @@ -129,28 +142,12 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { $this->getNode()->createDirectory('789'); } - public function getChildProvider() { - return [ - [ - true, - true, - ], - [ - true, - false, - ], - [ - false, - true, - ], - ]; - } - - /** - * @dataProvider getChildProvider - */ - public function testGetChild($isAdmin, $userVisible) { - $tag = new SystemTag(555, 'TheTag', $userVisible, false); + public function testGetChild() { + $tag = new SystemTag(555, 'TheTag', true, false); + $this->tagManager->expects($this->once()) + ->method('canUserSeeTag') + ->with($tag) + ->will($this->returnValue(true)); $this->tagMapper->expects($this->once()) ->method('haveTag') @@ -162,17 +159,21 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { ->with(['555']) ->will($this->returnValue(['555' => $tag])); - $childNode = $this->getNode($isAdmin)->getChild('555'); + $childNode = $this->getNode()->getChild('555'); - $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $childNode); + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $childNode); $this->assertEquals('555', $childNode->getName()); } /** * @expectedException \Sabre\DAV\Exception\NotFound */ - public function testGetChildUserNonVisible() { + public function testGetChildNonVisible() { $tag = new SystemTag(555, 'TheTag', false, false); + $this->tagManager->expects($this->once()) + ->method('canUserSeeTag') + ->with($tag) + ->will($this->returnValue(false)); $this->tagMapper->expects($this->once()) ->method('haveTag') @@ -184,7 +185,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { ->with(['555']) ->will($this->returnValue(['555' => $tag])); - $this->getNode(false)->getChild('555'); + $this->getNode()->getChild('555'); } /** @@ -223,7 +224,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { $this->getNode()->getChild('777'); } - public function testGetChildrenAsAdmin() { + public function testGetChildren() { $tag1 = new SystemTag(555, 'TagOne', true, false); $tag2 = new SystemTag(556, 'TagTwo', true, true); $tag3 = new SystemTag(557, 'InvisibleTag', false, true); @@ -238,43 +239,13 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { ->with(['555', '556', '557']) ->will($this->returnValue(['555' => $tag1, '556' => $tag2, '557' => $tag3])); - $children = $this->getNode(true)->getChildren(); - - $this->assertCount(3, $children); - - $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[0]); - $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[1]); - $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[2]); - - $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()); + $this->tagManager->expects($this->exactly(3)) + ->method('canUserSeeTag') + ->will($this->returnCallback(function($tag) { + return $tag->isUserVisible(); + })); - $this->assertEquals(111, $children[2]->getObjectId()); - $this->assertEquals('files', $children[2]->getObjectType()); - $this->assertEquals($tag3, $children[2]->getSystemTag()); - } - - public function testGetChildrenAsUser() { - $tag1 = new SystemTag(555, 'TagOne', true, false); - $tag2 = new SystemTag(556, 'TagTwo', true, true); - $tag3 = new SystemTag(557, 'InvisibleTag', false, true); - - $this->tagMapper->expects($this->once()) - ->method('getTagIdsForObjects') - ->with([111], 'files') - ->will($this->returnValue(['111' => ['555', '556', '557']])); - - $this->tagManager->expects($this->once()) - ->method('getTagsByIds') - ->with(['555', '556', '557']) - ->will($this->returnValue(['555' => $tag1, '556' => $tag2, '557' => $tag3])); - - $children = $this->getNode(false)->getChildren(); + $children = $this->getNode()->getChildren(); $this->assertCount(2, $children); @@ -290,16 +261,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { $this->assertEquals($tag2, $children[1]->getSystemTag()); } - public function testChildExistsAsAdmin() { - $this->tagMapper->expects($this->once()) - ->method('haveTag') - ->with([111], 'files', '555') - ->will($this->returnValue(true)); - - $this->assertTrue($this->getNode(true)->childExists('555')); - } - - public function testChildExistsWithVisibleTagAsUser() { + public function testChildExistsWithVisibleTag() { $tag = new SystemTag(555, 'TagOne', true, false); $this->tagMapper->expects($this->once()) @@ -308,14 +270,19 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { ->will($this->returnValue(true)); $this->tagManager->expects($this->once()) + ->method('canUserSeeTag') + ->with($tag) + ->will($this->returnValue(true)); + + $this->tagManager->expects($this->once()) ->method('getTagsByIds') - ->with('555') + ->with(['555']) ->will($this->returnValue([$tag])); - $this->assertTrue($this->getNode(false)->childExists('555')); + $this->assertTrue($this->getNode()->childExists('555')); } - public function testChildExistsWithInvisibleTagAsUser() { + public function testChildExistsWithInvisibleTag() { $tag = new SystemTag(555, 'TagOne', false, false); $this->tagMapper->expects($this->once()) @@ -325,10 +292,10 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { $this->tagManager->expects($this->once()) ->method('getTagsByIds') - ->with('555') + ->with(['555']) ->will($this->returnValue([$tag])); - $this->assertFalse($this->getNode(false)->childExists('555')); + $this->assertFalse($this->getNode()->childExists('555')); } public function testChildExistsNotFound() { diff --git a/apps/encryption/l10n/ro.js b/apps/encryption/l10n/ro.js index 88af06692ac..93a7358cfce 100644 --- a/apps/encryption/l10n/ro.js +++ b/apps/encryption/l10n/ro.js @@ -3,23 +3,48 @@ OC.L10N.register( { "Missing recovery key password" : "Lipsește parola cheii de recuperare", "Please repeat the recovery key password" : "Te rog repetă parola cheii de recuperare", - "Recovery key successfully enabled" : "Cheia de recupeare a fost activata cu succes", - "Could not enable recovery key. Please check your recovery key password!" : "Nu s-a putut activa cheia de recuperare. Verifica parola de recuperare!", - "Recovery key successfully disabled" : "Cheia de recuperare dezactivata cu succes", - "Could not disable recovery key. Please check your recovery key password!" : "Nu am putut dezactiva cheia de recuperare. Verifica parola de recuperare!", + "Repeated recovery key password does not match the provided recovery key password" : "Parolele cheii de recuperare nu se potrivesc", + "Recovery key successfully enabled" : "Cheia de recuperare a fost activată cu succes", + "Could not enable recovery key. Please check your recovery key password!" : "Nu s-a putut activa cheia de recuperare. Verifică-ți parola de recuperare!", + "Recovery key successfully disabled" : "Cheia de recuperare dezactivată cu succes", + "Could not disable recovery key. Please check your recovery key password!" : "Nu s-a putut dezactiva cheia de recuperare. Verifică-ți parola cheii de recuperare!", + "Missing parameters" : "Parametri lipsă", "Please provide the old recovery password" : "Te rog oferă parola de recuperare veche", "Please provide a new recovery password" : "Te rog oferă o nouă parolă de recuperare", "Please repeat the new recovery password" : "Te rog repetă noua parolă de recuperare", "Password successfully changed." : "Parola a fost modificată cu succes.", - "Could not change the password. Maybe the old password was not correct." : "Parola nu a putut fi schimbata. Poate ca parola veche este incorecta.", + "Could not change the password. Maybe the old password was not correct." : "Parola nu a putut fi schimbată. Poate ca parola veche este incorectă.", + "Recovery Key disabled" : "Cheia de recuperare a fost dezactivată", "Recovery Key enabled" : "Cheie de recuperare activată", "Could not enable the recovery key, please try again or contact your administrator" : "Nu poate fi activată cheia de recuperare, te rog încearcă din nou sau contactează administratorul", - "Private key password successfully updated." : "Cheia privata a fost actualizata cu succes", - "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." : "Cheie privată nevalidă pentru aplicația Încriptare. Te rog, actualizează-ți parola cheii private folosind setările personale pentru a reaccesa fișierele tale încriptate.", - "Encryption App is enabled but your keys are not initialized, please log-out and log-in again" : "Aplicatia de criptare este activata dar tastatura nu este initializata , va rugam deconectati-va si reconectati-va", + "Could not update the private key password." : "Nu a putut fi actualizată parola cheii private.", + "The old password was not correct, please try again." : "Parola veche nu este cea corectă, încearcă din nou.", + "The current log-in password was not correct, please try again." : "Parola curentă de autentificare nu este corectă, încearcă din nou.", + "Private key password successfully updated." : "Parola cheii private a fost actualizată cu succes.", + "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please run 'occ encryption:migrate' or contact your administrator" : "Este necesar să migrezi cheile de criptare de la vechiul algoritm (ownCloud <= 8.0) la cel nou. Rulează 'occ encryption:migrate' sau contactează-ți administratorul.", + "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." : "Cheie privată invalidă pentru aplicația de criptare. Actualizează-ți parola cheii private folosind setările personale pentru a redobândi accesul la fișierele tale criptate.", + "Encryption App is enabled but your keys are not initialized, please log-out and log-in again" : "Aplicația de criptare este activată dar cheile nu sunt inițializate, te rugăm reautentifică-te", + "Encryption App is enabled and ready" : "Aplicația de criptare este activată", + "Bad Signature" : "Semnătură greșită", + "Missing Signature" : "Semnătură lipsă", "The share will expire on %s." : "Partajarea va expira în data de %s.", + "Cheers!" : "Noroc!", + "Enable recovery key" : "Activează cheia de recuperare", + "Disable recovery key" : "Dezactivează cheia de recuperare", + "Recovery key password" : "Parola cheii de recuperare", + "Repeat recovery key password" : "Repetă parola cheii de recuperare", + "Change recovery key password:" : "Schimbă parola cheii de recuperare:", + "Old recovery key password" : "Parola veche a cheii de recuperare", + "New recovery key password" : "Parola nouă a cheii de recuperare", + "Repeat new recovery key password" : "Repetă parola nouă a cheii de recuperare", "Change Password" : "Schimbă parola", - "ownCloud basic encryption module" : "modul de ecnriptie bazic ownCloud", + "ownCloud basic encryption module" : "modulul ownCloud de bază pentru criptare", + "Your private key password no longer matches your log-in password." : "Parola cheii tale private nu se mai potrivește cu parola pentru autentificare.", + "Old log-in password" : "Parola veche pentru autentificare", + "Current log-in password" : "Parola curentă pentru autentificare", + "Update Private Key Password" : "Actualizează parola cheii private", + "Enable password recovery:" : "Activează recuperarea parolei:", + "Enabling this option will allow you to reobtain access to your encrypted files in case of password loss" : "Activarea acestei opțiuni îți va permite să redobândești accesul la fișierele tale criptate în cazul pierderii parolei", "Enabled" : "Activat", "Disabled" : "Dezactivat" }, diff --git a/apps/encryption/l10n/ro.json b/apps/encryption/l10n/ro.json index 9251037e35f..985cb2c55ad 100644 --- a/apps/encryption/l10n/ro.json +++ b/apps/encryption/l10n/ro.json @@ -1,23 +1,48 @@ { "translations": { "Missing recovery key password" : "Lipsește parola cheii de recuperare", "Please repeat the recovery key password" : "Te rog repetă parola cheii de recuperare", - "Recovery key successfully enabled" : "Cheia de recupeare a fost activata cu succes", - "Could not enable recovery key. Please check your recovery key password!" : "Nu s-a putut activa cheia de recuperare. Verifica parola de recuperare!", - "Recovery key successfully disabled" : "Cheia de recuperare dezactivata cu succes", - "Could not disable recovery key. Please check your recovery key password!" : "Nu am putut dezactiva cheia de recuperare. Verifica parola de recuperare!", + "Repeated recovery key password does not match the provided recovery key password" : "Parolele cheii de recuperare nu se potrivesc", + "Recovery key successfully enabled" : "Cheia de recuperare a fost activată cu succes", + "Could not enable recovery key. Please check your recovery key password!" : "Nu s-a putut activa cheia de recuperare. Verifică-ți parola de recuperare!", + "Recovery key successfully disabled" : "Cheia de recuperare dezactivată cu succes", + "Could not disable recovery key. Please check your recovery key password!" : "Nu s-a putut dezactiva cheia de recuperare. Verifică-ți parola cheii de recuperare!", + "Missing parameters" : "Parametri lipsă", "Please provide the old recovery password" : "Te rog oferă parola de recuperare veche", "Please provide a new recovery password" : "Te rog oferă o nouă parolă de recuperare", "Please repeat the new recovery password" : "Te rog repetă noua parolă de recuperare", "Password successfully changed." : "Parola a fost modificată cu succes.", - "Could not change the password. Maybe the old password was not correct." : "Parola nu a putut fi schimbata. Poate ca parola veche este incorecta.", + "Could not change the password. Maybe the old password was not correct." : "Parola nu a putut fi schimbată. Poate ca parola veche este incorectă.", + "Recovery Key disabled" : "Cheia de recuperare a fost dezactivată", "Recovery Key enabled" : "Cheie de recuperare activată", "Could not enable the recovery key, please try again or contact your administrator" : "Nu poate fi activată cheia de recuperare, te rog încearcă din nou sau contactează administratorul", - "Private key password successfully updated." : "Cheia privata a fost actualizata cu succes", - "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." : "Cheie privată nevalidă pentru aplicația Încriptare. Te rog, actualizează-ți parola cheii private folosind setările personale pentru a reaccesa fișierele tale încriptate.", - "Encryption App is enabled but your keys are not initialized, please log-out and log-in again" : "Aplicatia de criptare este activata dar tastatura nu este initializata , va rugam deconectati-va si reconectati-va", + "Could not update the private key password." : "Nu a putut fi actualizată parola cheii private.", + "The old password was not correct, please try again." : "Parola veche nu este cea corectă, încearcă din nou.", + "The current log-in password was not correct, please try again." : "Parola curentă de autentificare nu este corectă, încearcă din nou.", + "Private key password successfully updated." : "Parola cheii private a fost actualizată cu succes.", + "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please run 'occ encryption:migrate' or contact your administrator" : "Este necesar să migrezi cheile de criptare de la vechiul algoritm (ownCloud <= 8.0) la cel nou. Rulează 'occ encryption:migrate' sau contactează-ți administratorul.", + "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." : "Cheie privată invalidă pentru aplicația de criptare. Actualizează-ți parola cheii private folosind setările personale pentru a redobândi accesul la fișierele tale criptate.", + "Encryption App is enabled but your keys are not initialized, please log-out and log-in again" : "Aplicația de criptare este activată dar cheile nu sunt inițializate, te rugăm reautentifică-te", + "Encryption App is enabled and ready" : "Aplicația de criptare este activată", + "Bad Signature" : "Semnătură greșită", + "Missing Signature" : "Semnătură lipsă", "The share will expire on %s." : "Partajarea va expira în data de %s.", + "Cheers!" : "Noroc!", + "Enable recovery key" : "Activează cheia de recuperare", + "Disable recovery key" : "Dezactivează cheia de recuperare", + "Recovery key password" : "Parola cheii de recuperare", + "Repeat recovery key password" : "Repetă parola cheii de recuperare", + "Change recovery key password:" : "Schimbă parola cheii de recuperare:", + "Old recovery key password" : "Parola veche a cheii de recuperare", + "New recovery key password" : "Parola nouă a cheii de recuperare", + "Repeat new recovery key password" : "Repetă parola nouă a cheii de recuperare", "Change Password" : "Schimbă parola", - "ownCloud basic encryption module" : "modul de ecnriptie bazic ownCloud", + "ownCloud basic encryption module" : "modulul ownCloud de bază pentru criptare", + "Your private key password no longer matches your log-in password." : "Parola cheii tale private nu se mai potrivește cu parola pentru autentificare.", + "Old log-in password" : "Parola veche pentru autentificare", + "Current log-in password" : "Parola curentă pentru autentificare", + "Update Private Key Password" : "Actualizează parola cheii private", + "Enable password recovery:" : "Activează recuperarea parolei:", + "Enabling this option will allow you to reobtain access to your encrypted files in case of password loss" : "Activarea acestei opțiuni îți va permite să redobândești accesul la fișierele tale criptate în cazul pierderii parolei", "Enabled" : "Activat", "Disabled" : "Dezactivat" },"pluralForm" :"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));" diff --git a/apps/federatedfilesharing/appinfo/app.php b/apps/federatedfilesharing/appinfo/app.php index 4666d343f7e..c33a887c6d6 100644 --- a/apps/federatedfilesharing/appinfo/app.php +++ b/apps/federatedfilesharing/appinfo/app.php @@ -20,4 +20,21 @@ */ $app = new \OCA\FederatedFileSharing\AppInfo\Application('federatedfilesharing'); + +use OCA\FederatedFileSharing\Notifier; + +$l = \OC::$server->getL10N('files_sharing'); + $app->registerSettings(); + +$manager = \OC::$server->getNotificationManager(); +$manager->registerNotifier(function() { + return new Notifier( + \OC::$server->getL10NFactory() + ); +}, function() use ($l) { + return [ + 'id' => 'files_sharing', + 'name' => $l->t('Federated sharing'), + ]; +}); diff --git a/apps/federatedfilesharing/appinfo/database.xml b/apps/federatedfilesharing/appinfo/database.xml new file mode 100644 index 00000000000..1dbe8ee2ec9 --- /dev/null +++ b/apps/federatedfilesharing/appinfo/database.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> + +<!-- +Keep a mapping of the share ID stored in the local oc_share table +and the share ID stored in the remote servers oc_share table. +This is needed in order to send updates in both directions between +the servers (e.g. permissions change, unshare,...) +--> + +<database> + <name>*dbname*</name> + <create>true</create> + <overwrite>false</overwrite> + <charset>utf8</charset> + <table> + <name>*dbprefix*federated_reshares</name> + <declaration> + <field> + <name>share_id</name> + <type>integer</type> + <notnull>true</notnull> + <length>4</length> + </field> + <field> + <name>remote_id</name> + <type>integer</type> + <notnull>true</notnull> + <length>4</length> + <comments>share ID at the remote server</comments> + </field> + <index> + <name>share_id_index</name> + <unique>true</unique> + <field> + <name>share_id</name> + <sorting>ascending</sorting> + </field> + </index> + </declaration> + </table> +</database> diff --git a/apps/federatedfilesharing/appinfo/info.xml b/apps/federatedfilesharing/appinfo/info.xml index 643281bd145..5cf4039f196 100644 --- a/apps/federatedfilesharing/appinfo/info.xml +++ b/apps/federatedfilesharing/appinfo/info.xml @@ -5,7 +5,7 @@ <description>Provide federated file sharing across ownCloud servers</description> <licence>AGPL</licence> <author>Bjoern Schiessle, Roeland Jago Douma</author> - <version>0.2.0</version> + <version>0.3.0</version> <namespace>FederatedFileSharing</namespace> <category>other</category> <dependencies> diff --git a/apps/federatedfilesharing/l10n/cs_CZ.js b/apps/federatedfilesharing/l10n/cs_CZ.js index 2a5790b4584..02055fb06f3 100644 --- a/apps/federatedfilesharing/l10n/cs_CZ.js +++ b/apps/federatedfilesharing/l10n/cs_CZ.js @@ -10,7 +10,7 @@ OC.L10N.register( "Federated Cloud Sharing" : "Propojené cloudové sdílení", "Open documentation" : "Otevřít dokumentaci", "Allow users on this server to send shares to other servers" : "Povolit uživatelům z tohoto serveru zasílat sdílení na jiné servery", - "Allow users on this server to receive shares from other servers" : "Povolit uživatelům z tohoto serveru přijímat sdílení z jiných serverů", + "Allow users on this server to receive shares from other servers" : "Povolit uživatelům na tomto serveru přijímat sdílení z jiných serverů", "Federated Cloud" : "Sdružený cloud", "Your Federated Cloud ID:" : "Vaše sdružené cloud ID:", "Share it:" : "Sdílet:", diff --git a/apps/federatedfilesharing/l10n/cs_CZ.json b/apps/federatedfilesharing/l10n/cs_CZ.json index f3c057af1b0..165848afeb2 100644 --- a/apps/federatedfilesharing/l10n/cs_CZ.json +++ b/apps/federatedfilesharing/l10n/cs_CZ.json @@ -8,7 +8,7 @@ "Federated Cloud Sharing" : "Propojené cloudové sdílení", "Open documentation" : "Otevřít dokumentaci", "Allow users on this server to send shares to other servers" : "Povolit uživatelům z tohoto serveru zasílat sdílení na jiné servery", - "Allow users on this server to receive shares from other servers" : "Povolit uživatelům z tohoto serveru přijímat sdílení z jiných serverů", + "Allow users on this server to receive shares from other servers" : "Povolit uživatelům na tomto serveru přijímat sdílení z jiných serverů", "Federated Cloud" : "Sdružený cloud", "Your Federated Cloud ID:" : "Vaše sdružené cloud ID:", "Share it:" : "Sdílet:", diff --git a/apps/federatedfilesharing/lib/AppInfo/Application.php b/apps/federatedfilesharing/lib/AppInfo/Application.php index 5a213aec8e2..d1b0646ba5b 100644 --- a/apps/federatedfilesharing/lib/AppInfo/Application.php +++ b/apps/federatedfilesharing/lib/AppInfo/Application.php @@ -81,7 +81,8 @@ class Application extends App { \OC::$server->getL10N('federatedfilesharing'), \OC::$server->getLogger(), \OC::$server->getLazyRootFolder(), - \OC::$server->getConfig() + \OC::$server->getConfig(), + \OC::$server->getUserManager() ); } diff --git a/apps/federatedfilesharing/lib/BackgroundJob/UnShare.php b/apps/federatedfilesharing/lib/BackgroundJob/RetryJob.php index b056db4eac7..109a607bff0 100644 --- a/apps/federatedfilesharing/lib/BackgroundJob/UnShare.php +++ b/apps/federatedfilesharing/lib/BackgroundJob/RetryJob.php @@ -32,26 +32,26 @@ use OCP\BackgroundJob\IJobList; use OCP\ILogger; /** - * Class UnShare + * Class RetryJob * - * Background job to re-send the un-share notification to the remote server in + * Background job to re-send update of federated re-shares to the remote server in * case the server was not available on the first try * * @package OCA\FederatedFileSharing\BackgroundJob */ -class UnShare extends Job { +class RetryJob extends Job { /** @var bool */ private $retainJob = true; - + /** @var Notifications */ private $notifications; - /** @var int max number of attempts to send the un-share request */ - private $maxTry = 10; + /** @var int max number of attempts to send the request */ + private $maxTry = 20; - /** @var int how much time should be between two tries (12 hours) */ - private $interval = 43200; + /** @var int how much time should be between two tries (10 minutes) */ + private $interval = 600; /** * UnShare constructor. @@ -77,7 +77,7 @@ class UnShare extends Job { \OC::$server->getJobList() ); } - + } /** @@ -99,12 +99,14 @@ class UnShare extends Job { protected function run($argument) { $remote = $argument['remote']; - $id = (int)$argument['id']; + $remoteId = $argument['remoteId']; $token = $argument['token']; + $action = $argument['action']; + $data = json_decode($argument['data'], true); $try = (int)$argument['try'] + 1; - $result = $this->notifications->sendRemoteUnShare($remote, $id, $token, $try); - + $result = $this->notifications->sendUpdateToRemote($remote, $remoteId, $token, $action, $data, $try); + if ($result === true || $try > $this->maxTry) { $this->retainJob = false; } @@ -117,11 +119,13 @@ class UnShare extends Job { * @param array $argument */ protected function reAddJob(IJobList $jobList, array $argument) { - $jobList->add('OCA\FederatedFileSharing\BackgroundJob\UnShare', + $jobList->add('OCA\FederatedFileSharing\BackgroundJob\RetryJob', [ 'remote' => $argument['remote'], - 'id' => $argument['id'], + 'remoteId' => $argument['remoteId'], 'token' => $argument['token'], + 'data' => $argument['data'], + 'action' => $argument['action'], 'try' => (int)$argument['try'] + 1, 'lastRun' => time() ] diff --git a/apps/federatedfilesharing/lib/FederatedShareProvider.php b/apps/federatedfilesharing/lib/FederatedShareProvider.php index d014a6219a3..76fed01c308 100644 --- a/apps/federatedfilesharing/lib/FederatedShareProvider.php +++ b/apps/federatedfilesharing/lib/FederatedShareProvider.php @@ -25,10 +25,10 @@ namespace OCA\FederatedFileSharing; use OC\Share20\Share; use OCP\Files\IRootFolder; -use OCP\IAppConfig; use OCP\IConfig; use OCP\IL10N; use OCP\ILogger; +use OCP\IUserManager; use OCP\Share\IShare; use OCP\Share\IShareProvider; use OC\Share20\Exception\InvalidShare; @@ -70,6 +70,12 @@ class FederatedShareProvider implements IShareProvider { /** @var IConfig */ private $config; + /** @var string */ + private $externalShareTable = 'share_external'; + + /** @var IUserManager */ + private $userManager; + /** * DefaultShareProvider constructor. * @@ -81,6 +87,7 @@ class FederatedShareProvider implements IShareProvider { * @param ILogger $logger * @param IRootFolder $rootFolder * @param IConfig $config + * @param IUserManager $userManager */ public function __construct( IDBConnection $connection, @@ -90,7 +97,8 @@ class FederatedShareProvider implements IShareProvider { IL10N $l10n, ILogger $logger, IRootFolder $rootFolder, - IConfig $config + IConfig $config, + IUserManager $userManager ) { $this->dbConnection = $connection; $this->addressHandler = $addressHandler; @@ -100,6 +108,7 @@ class FederatedShareProvider implements IShareProvider { $this->logger = $logger; $this->rootFolder = $rootFolder; $this->config = $config; + $this->userManager = $userManager; } /** @@ -124,10 +133,9 @@ class FederatedShareProvider implements IShareProvider { $shareWith = $share->getSharedWith(); $itemSource = $share->getNodeId(); $itemType = $share->getNodeType(); - $uidOwner = $share->getShareOwner(); $permissions = $share->getPermissions(); $sharedBy = $share->getSharedBy(); - + /* * Check if file is not already shared with the remote user */ @@ -151,31 +159,136 @@ class FederatedShareProvider implements IShareProvider { throw new \Exception($message_t); } - $token = $this->tokenHandler->generateToken(); + $share->setSharedWith($user . '@' . $remote); + + try { + $remoteShare = $this->getShareFromExternalShareTable($share); + } catch (ShareNotFound $e) { + $remoteShare = null; + } - $shareWith = $user . '@' . $remote; + if ($remoteShare) { + try { + $uidOwner = $remoteShare['owner'] . '@' . $remoteShare['remote']; + $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, 'tmp_token_' . time()); + $share->setId($shareId); + list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId); + // remote share was create successfully if we get a valid token as return + $send = is_string($token) && $token !== ''; + } catch (\Exception $e) { + // fall back to old re-share behavior if the remote server + // doesn't support flat re-shares (was introduced with ownCloud 9.1) + $this->removeShareFromTable($share); + $shareId = $this->createFederatedShare($share); + } + if ($send) { + $this->updateSuccessfulReshare($shareId, $token); + $this->storeRemoteId($shareId, $remoteId); + } else { + $this->removeShareFromTable($share); + $message_t = $this->l->t('File is already shared with %s', [$shareWith]); + throw new \Exception($message_t); + } - $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token); + } else { + $shareId = $this->createFederatedShare($share); + } + $data = $this->getRawShare($shareId); + return $this->createShareObject($data); + } + + /** + * create federated share and inform the recipient + * + * @param IShare $share + * @return int + * @throws ShareNotFound + * @throws \Exception + */ + protected function createFederatedShare(IShare $share) { + $token = $this->tokenHandler->generateToken(); + $shareId = $this->addShareToDB( + $share->getNodeId(), + $share->getNodeType(), + $share->getSharedWith(), + $share->getSharedBy(), + $share->getShareOwner(), + $share->getPermissions(), + $token + ); + $sharedByFederatedId = $share->getSharedBy(); + if ($this->userManager->userExists($sharedByFederatedId)) { + $sharedByFederatedId = $sharedByFederatedId . '@' . $this->addressHandler->generateRemoteURL(); + } $send = $this->notifications->sendRemoteShare( $token, - $shareWith, + $share->getSharedWith(), $share->getNode()->getName(), $shareId, - $share->getSharedBy() + $share->getShareOwner(), + $share->getShareOwner() . '@' . $this->addressHandler->generateRemoteURL(), + $share->getSharedBy(), + $sharedByFederatedId ); - $data = $this->getRawShare($shareId); - $share = $this->createShare($data); - if ($send === false) { - $this->delete($share); + $data = $this->getRawShare($shareId); + $share = $this->createShareObject($data); + $this->removeShareFromTable($share); $message_t = $this->l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable.', - [$share->getNode()->getName(), $shareWith]); + [$share->getNode()->getName(), $share->getSharedWith()]); throw new \Exception($message_t); } - return $share; + return $shareId; + } + + /** + * @param string $shareWith + * @param IShare $share + * @param string $shareId internal share Id + * @return array + * @throws \Exception + */ + protected function askOwnerToReShare($shareWith, IShare $share, $shareId) { + + $remoteShare = $this->getShareFromExternalShareTable($share); + $token = $remoteShare['share_token']; + $remoteId = $remoteShare['remote_id']; + $remote = $remoteShare['remote']; + + list($token, $remoteId) = $this->notifications->requestReShare( + $token, + $remoteId, + $shareId, + $remote, + $shareWith, + $share->getPermissions() + ); + + return [$token, $remoteId]; + } + + /** + * get federated share from the share_external table but exclude mounted link shares + * + * @param IShare $share + * @return array + * @throws ShareNotFound + */ + protected function getShareFromExternalShareTable(IShare $share) { + $query = $this->dbConnection->getQueryBuilder(); + $query->select('*')->from($this->externalShareTable) + ->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner()))) + ->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget()))); + $result = $query->execute()->fetchAll(); + + if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) { + return $result[0]; + } + + throw new ShareNotFound('share not found in share_external table'); } /** @@ -234,10 +347,86 @@ class FederatedShareProvider implements IShareProvider { ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy())) ->execute(); + // send the updated permission to the owner/initiator, if they are not the same + if ($share->getShareOwner() !== $share->getSharedBy()) { + $this->sendPermissionUpdate($share); + } + return $share; } /** + * send the updated permission to the owner/initiator, if they are not the same + * + * @param IShare $share + * @throws ShareNotFound + * @throws \OC\HintException + */ + protected function sendPermissionUpdate(IShare $share) { + $remoteId = $this->getRemoteId($share); + // if the local user is the owner we send the permission change to the initiator + if ($this->userManager->userExists($share->getShareOwner())) { + list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); + } else { // ... if not we send the permission change to the owner + list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner()); + } + $this->notifications->sendPermissionChange($remote, $remoteId, $share->getToken(), $share->getPermissions()); + } + + + /** + * update successful reShare with the correct token + * + * @param int $shareId + * @param string $token + */ + protected function updateSuccessfulReShare($shareId, $token) { + $query = $this->dbConnection->getQueryBuilder(); + $query->update('share') + ->where($query->expr()->eq('id', $query->createNamedParameter($shareId))) + ->set('token', $query->createNamedParameter($token)) + ->execute(); + } + + /** + * store remote ID in federated reShare table + * + * @param $shareId + * @param $remoteId + */ + public function storeRemoteId($shareId, $remoteId) { + $query = $this->dbConnection->getQueryBuilder(); + $query->insert('federated_reshares') + ->values( + [ + 'share_id' => $query->createNamedParameter($shareId), + 'remote_id' => $query->createNamedParameter($remoteId), + ] + ); + $query->execute(); + } + + /** + * get share ID on remote server for federated re-shares + * + * @param IShare $share + * @return int + * @throws ShareNotFound + */ + public function getRemoteId(IShare $share) { + $query = $this->dbConnection->getQueryBuilder(); + $query->select('remote_id')->from('federated_reshares') + ->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId()))); + $data = $query->execute()->fetch(); + + if (!is_array($data) || !isset($data['remote_id'])) { + throw new ShareNotFound(); + } + + return (int)$data['remote_id']; + } + + /** * @inheritdoc */ public function move(IShare $share, $recipient) { @@ -266,7 +455,7 @@ class FederatedShareProvider implements IShareProvider { $cursor = $qb->execute(); while($data = $cursor->fetch()) { - $children[] = $this->createShare($data); + $children[] = $this->createShareObject($data); } $cursor->closeCursor(); @@ -274,18 +463,77 @@ class FederatedShareProvider implements IShareProvider { } /** - * Delete a share + * Delete a share (owner unShares the file) * * @param IShare $share */ public function delete(IShare $share) { + + list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedWith()); + + $isOwner = false; + + // if the local user is the owner we can send the unShare request directly... + if ($this->userManager->userExists($share->getShareOwner())) { + $this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken()); + $this->revokeShare($share, true); + $isOwner = true; + } else { // ... if not we need to correct ID for the unShare request + $remoteId = $this->getRemoteId($share); + $this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken()); + $this->revokeShare($share, false); + } + + // send revoke notification to the other user, if initiator and owner are not the same user + if ($share->getShareOwner() !== $share->getSharedBy()) { + $remoteId = $this->getRemoteId($share); + if ($isOwner) { + list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); + } else { + list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner()); + } + $this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken()); + } + + $this->removeShareFromTable($share); + } + + /** + * in case of a re-share we need to send the other use (initiator or owner) + * a message that the file was unshared + * + * @param IShare $share + * @param bool $isOwner the user can either be the owner or the user who re-sahred it + * @throws ShareNotFound + * @throws \OC\HintException + */ + protected function revokeShare($share, $isOwner) { + // also send a unShare request to the initiator, if this is a different user than the owner + if ($share->getShareOwner() !== $share->getSharedBy()) { + if ($isOwner) { + list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); + } else { + list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner()); + } + $remoteId = $this->getRemoteId($share); + $this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken()); + } + } + + /** + * remove share from table + * + * @param IShare $share + */ + public function removeShareFromTable(IShare $share) { $qb = $this->dbConnection->getQueryBuilder(); $qb->delete('share') ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))); $qb->execute(); - list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedWith()); - $this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken()); + $qb->delete('federated_reshares') + ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($share->getId()))); + $qb->execute(); } /** @@ -348,7 +596,7 @@ class FederatedShareProvider implements IShareProvider { $cursor = $qb->execute(); $shares = []; while($data = $cursor->fetch()) { - $shares[] = $this->createShare($data); + $shares[] = $this->createShareObject($data); } $cursor->closeCursor(); @@ -375,7 +623,7 @@ class FederatedShareProvider implements IShareProvider { } try { - $share = $this->createShare($data); + $share = $this->createShareObject($data); } catch (InvalidShare $e) { throw new ShareNotFound(); } @@ -400,7 +648,7 @@ class FederatedShareProvider implements IShareProvider { $shares = []; while($data = $cursor->fetch()) { - $shares[] = $this->createShare($data); + $shares[] = $this->createShareObject($data); } $cursor->closeCursor(); @@ -439,7 +687,7 @@ class FederatedShareProvider implements IShareProvider { $cursor = $qb->execute(); while($data = $cursor->fetch()) { - $shares[] = $this->createShare($data); + $shares[] = $this->createShareObject($data); } $cursor->closeCursor(); @@ -470,7 +718,7 @@ class FederatedShareProvider implements IShareProvider { } try { - $share = $this->createShare($data); + $share = $this->createShareObject($data); } catch (InvalidShare $e) { throw new ShareNotFound(); } @@ -512,9 +760,9 @@ class FederatedShareProvider implements IShareProvider { * @throws InvalidShare * @throws ShareNotFound */ - private function createShare($data) { + private function createShareObject($data) { - $share = new Share($this->rootFolder); + $share = new Share($this->rootFolder, $this->userManager); $share->setId((int)$data['id']) ->setShareType((int)$data['share_type']) ->setPermissions((int)$data['permissions']) diff --git a/apps/federatedfilesharing/lib/Notifications.php b/apps/federatedfilesharing/lib/Notifications.php index 9cdc7760361..bf9e0fc9634 100644 --- a/apps/federatedfilesharing/lib/Notifications.php +++ b/apps/federatedfilesharing/lib/Notifications.php @@ -23,6 +23,7 @@ namespace OCA\FederatedFileSharing; +use OCP\AppFramework\Http; use OCP\BackgroundJob\IJobList; use OCP\Http\Client\IClientService; @@ -67,9 +68,14 @@ class Notifications { * @param string $name * @param int $remote_id * @param string $owner + * @param string $ownerFederatedId + * @param string $sharedBy + * @param string $sharedByFederatedId * @return bool + * @throws \OC\HintException + * @throws \OC\ServerNotAvailableException */ - public function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner) { + public function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner, $ownerFederatedId, $sharedBy, $sharedByFederatedId) { list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith); @@ -83,6 +89,9 @@ class Notifications { 'name' => $name, 'remoteId' => $remote_id, 'owner' => $owner, + 'ownerFederatedId' => $ownerFederatedId, + 'sharedBy' => $sharedBy, + 'sharedByFederatedId' => $sharedByFederatedId, 'remote' => $local, ); @@ -101,34 +110,142 @@ class Notifications { } /** + * ask owner to re-share the file with the given user + * + * @param string $token + * @param int $id remote Id + * @param int $shareId internal share Id + * @param string $remote remote address of the owner + * @param string $shareWith + * @param int $permission + * @return bool + * @throws \OC\HintException + * @throws \OC\ServerNotAvailableException + */ + public function requestReShare($token, $id, $shareId, $remote, $shareWith, $permission) { + + $fields = array( + 'shareWith' => $shareWith, + 'token' => $token, + 'permission' => $permission, + 'remoteId' => $shareId + ); + + $url = $this->addressHandler->removeProtocolFromUrl($remote); + $result = $this->tryHttpPostToShareEndpoint(rtrim($url, '/'), '/' . $id . '/reshare', $fields); + $status = json_decode($result['result'], true); + + $httpRequestSuccessful = $result['success']; + $ocsCallSuccessful = $status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200; + $validToken = isset($status['ocs']['data']['token']) && is_string($status['ocs']['data']['token']); + $validRemoteId = isset($status['ocs']['data']['remoteId']); + + if ($httpRequestSuccessful && $ocsCallSuccessful && $validToken && $validRemoteId) { + return [ + $status['ocs']['data']['token'], + (int)$status['ocs']['data']['remoteId'] + ]; + } + + return false; + } + + /** * send server-to-server unshare to remote server * * @param string $remote url * @param int $id share id * @param string $token - * @param int $try how often did we already tried to send the un-share request * @return bool */ - public function sendRemoteUnShare($remote, $id, $token, $try = 0) { - $url = rtrim($remote, '/'); - $fields = array('token' => $token, 'format' => 'json'); - $url = $this->addressHandler->removeProtocolFromUrl($url); - $result = $this->tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields); + public function sendRemoteUnShare($remote, $id, $token) { + $this->sendUpdateToRemote($remote, $id, $token, 'unshare'); + } + + /** + * send server-to-server unshare to remote server + * + * @param string $remote url + * @param int $id share id + * @param string $token + * @return bool + */ + public function sendRevokeShare($remote, $id, $token) { + $this->sendUpdateToRemote($remote, $id, $token, 'revoke'); + } + + /** + * send notification to remote server if the permissions was changed + * + * @param string $remote + * @param int $remoteId + * @param string $token + * @param int $permissions + * @return bool + */ + public function sendPermissionChange($remote, $remoteId, $token, $permissions) { + $this->sendUpdateToRemote($remote, $remoteId, $token, 'permissions', ['permissions' => $permissions]); + } + + /** + * forward accept reShare to remote server + * + * @param string $remote + * @param int $remoteId + * @param string $token + */ + public function sendAcceptShare($remote, $remoteId, $token) { + $this->sendUpdateToRemote($remote, $remoteId, $token, 'accept'); + } + + /** + * forward decline reShare to remote server + * + * @param string $remote + * @param int $remoteId + * @param string $token + */ + public function sendDeclineShare($remote, $remoteId, $token) { + $this->sendUpdateToRemote($remote, $remoteId, $token, 'decline'); + } + + /** + * inform remote server whether server-to-server share was accepted/declined + * + * @param string $remote + * @param string $token + * @param int $remoteId Share id on the remote host + * @param string $action possible actions: accept, decline, unshare, revoke, permissions + * @param array $data + * @param int $try + * @return boolean + */ + public function sendUpdateToRemote($remote, $remoteId, $token, $action, $data = [], $try = 0) { + + $fields = array('token' => $token); + foreach ($data as $key => $value) { + $fields[$key] = $value; + } + + $url = $this->addressHandler->removeProtocolFromUrl($remote); + $result = $this->tryHttpPostToShareEndpoint(rtrim($url, '/'), '/' . $remoteId . '/' . $action, $fields); $status = json_decode($result['result'], true); - if ($result['success'] && - ($status['ocs']['meta']['statuscode'] === 100 || + if ($result['success'] && + ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200 ) ) { return true; } elseif ($try === 0) { // only add new job on first try - $this->jobList->add('OCA\FederatedFileSharing\BackgroundJob\UnShare', + $this->jobList->add('OCA\FederatedFileSharing\BackgroundJob\RetryJob', [ 'remote' => $remote, - 'id' => $id, + 'remoteId' => $remoteId, 'token' => $token, + 'action' => $action, + 'data' => json_encode($data), 'try' => $try, 'lastRun' => $this->getTimestamp() ] @@ -138,6 +255,7 @@ class Notifications { return false; } + /** * return current timestamp * @@ -154,6 +272,7 @@ class Notifications { * @param string $urlSuffix * @param array $fields post parameters * @return array + * @throws \Exception */ protected function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) { $client = $this->httpClientService->newClient(); @@ -174,6 +293,12 @@ class Notifications { $result['success'] = true; break; } catch (\Exception $e) { + // if flat re-sharing is not supported by the remote server + // we re-throw the exception and fall back to the old behaviour. + // (flat re-shares has been introduced in ownCloud 9.1) + if ($e->getCode() === Http::STATUS_INTERNAL_SERVER_ERROR) { + throw $e; + } $try++; $protocol = 'http://'; } diff --git a/apps/federatedfilesharing/lib/RequestHandler.php b/apps/federatedfilesharing/lib/RequestHandler.php new file mode 100644 index 00000000000..01ab96822d8 --- /dev/null +++ b/apps/federatedfilesharing/lib/RequestHandler.php @@ -0,0 +1,580 @@ +<?php +/** + * @author Arthur Schiwon <blizzz@owncloud.com> + * @author Björn Schießle <schiessle@owncloud.com> + * @author Joas Schilling <nickvergessen@owncloud.com> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCA\FederatedFileSharing; + +use OCA\Files_Sharing\Activity; +use OCP\AppFramework\Http; +use OCP\Constants; +use OCP\Files\NotFoundException; +use OCP\IDBConnection; +use OCP\IRequest; +use OCP\IUserManager; +use OCP\Share; + +/** + * Class RequestHandler + * + * handles OCS Request to the federated share API + * + * @package OCA\FederatedFileSharing\API + */ +class RequestHandler { + + /** @var FederatedShareProvider */ + private $federatedShareProvider; + + /** @var IDBConnection */ + private $connection; + + /** @var Share\IManager */ + private $shareManager; + + /** @var IRequest */ + private $request; + + /** @var Notifications */ + private $notifications; + + /** @var AddressHandler */ + private $addressHandler; + + /** @var IUserManager */ + private $userManager; + + /** @var string */ + private $shareTable = 'share'; + + /** + * Server2Server constructor. + * + * @param FederatedShareProvider $federatedShareProvider + * @param IDBConnection $connection + * @param Share\IManager $shareManager + * @param IRequest $request + * @param Notifications $notifications + * @param AddressHandler $addressHandler + * @param IUserManager $userManager + */ + public function __construct(FederatedShareProvider $federatedShareProvider, + IDBConnection $connection, + Share\IManager $shareManager, + IRequest $request, + Notifications $notifications, + AddressHandler $addressHandler, + IUserManager $userManager + ) { + $this->federatedShareProvider = $federatedShareProvider; + $this->connection = $connection; + $this->shareManager = $shareManager; + $this->request = $request; + $this->notifications = $notifications; + $this->addressHandler = $addressHandler; + $this->userManager = $userManager; + } + + /** + * create a new share + * + * @param array $params + * @return \OC_OCS_Result + */ + public function createShare($params) { + + if (!$this->isS2SEnabled(true)) { + return new \OC_OCS_Result(null, 503, 'Server does not support federated cloud sharing'); + } + + $remote = isset($_POST['remote']) ? $_POST['remote'] : null; + $token = isset($_POST['token']) ? $_POST['token'] : null; + $name = isset($_POST['name']) ? $_POST['name'] : null; + $owner = isset($_POST['owner']) ? $_POST['owner'] : null; + $sharedBy = isset($_POST['sharedBy']) ? $_POST['sharedBy'] : null; + $shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null; + $remoteId = isset($_POST['remoteId']) ? (int)$_POST['remoteId'] : null; + $sharedByFederatedId = isset($_POST['sharedByFederatedId']) ? $_POST['sharedByFederatedId'] : null; + $ownerFederatedId = isset($_POST['ownerFederatedId']) ? $_POST['ownerFederatedId'] : null; + + if ($remote && $token && $name && $owner && $remoteId && $shareWith) { + + if(!\OCP\Util::isValidFileName($name)) { + return new \OC_OCS_Result(null, 400, 'The mountpoint name contains invalid characters.'); + } + + // FIXME this should be a method in the user management instead + \OCP\Util::writeLog('files_sharing', 'shareWith before, ' . $shareWith, \OCP\Util::DEBUG); + \OCP\Util::emitHook( + '\OCA\Files_Sharing\API\Server2Server', + 'preLoginNameUsedAsUserName', + array('uid' => &$shareWith) + ); + \OCP\Util::writeLog('files_sharing', 'shareWith after, ' . $shareWith, \OCP\Util::DEBUG); + + if (!\OCP\User::userExists($shareWith)) { + return new \OC_OCS_Result(null, 400, 'User does not exists'); + } + + \OC_Util::setupFS($shareWith); + + $discoveryManager = new DiscoveryManager( + \OC::$server->getMemCacheFactory(), + \OC::$server->getHTTPClientService() + ); + $externalManager = new \OCA\Files_Sharing\External\Manager( + \OC::$server->getDatabaseConnection(), + \OC\Files\Filesystem::getMountManager(), + \OC\Files\Filesystem::getLoader(), + \OC::$server->getHTTPHelper(), + \OC::$server->getNotificationManager(), + $discoveryManager, + $shareWith + ); + + try { + $externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId); + $shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external'); + + if ($ownerFederatedId === null) { + $ownerFederatedId = $owner . '@' . $this->cleanupRemote($remote); + } + // if the owner of the share and the initiator are the same user + // we also complete the federated share ID for the initiator + if ($sharedByFederatedId === null && $owner === $sharedBy) { + $sharedByFederatedId = $ownerFederatedId; + } + + \OC::$server->getActivityManager()->publishActivity( + Activity::FILES_SHARING_APP, Activity::SUBJECT_REMOTE_SHARE_RECEIVED, array($ownerFederatedId, trim($name, '/')), '', array(), + '', '', $shareWith, Activity::TYPE_REMOTE_SHARE, Activity::PRIORITY_LOW); + + $urlGenerator = \OC::$server->getURLGenerator(); + + $notificationManager = \OC::$server->getNotificationManager(); + $notification = $notificationManager->createNotification(); + $notification->setApp('files_sharing') + ->setUser($shareWith) + ->setDateTime(new \DateTime()) + ->setObject('remote_share', $shareId) + ->setSubject('remote_share', [$ownerFederatedId, $sharedByFederatedId, trim($name, '/')]); + + $declineAction = $notification->createAction(); + $declineAction->setLabel('decline') + ->setLink($urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'ocs/v1.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE'); + $notification->addAction($declineAction); + + $acceptAction = $notification->createAction(); + $acceptAction->setLabel('accept') + ->setLink($urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'ocs/v1.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST'); + $notification->addAction($acceptAction); + + $notificationManager->notify($notification); + + return new \OC_OCS_Result(); + } catch (\Exception $e) { + \OCP\Util::writeLog('files_sharing', 'server can not add remote share, ' . $e->getMessage(), \OCP\Util::ERROR); + return new \OC_OCS_Result(null, 500, 'internal server error, was not able to add share from ' . $remote); + } + } + + return new \OC_OCS_Result(null, 400, 'server can not add remote share, missing parameter'); + } + + /** + * create re-share on behalf of another user + * + * @param $params + * @return \OC_OCS_Result + */ + public function reShare($params) { + + $id = isset($params['id']) ? (int)$params['id'] : null; + $token = $this->request->getParam('token', null); + $shareWith = $this->request->getParam('shareWith', null); + $permission = (int)$this->request->getParam('permission', null); + $remoteId = (int)$this->request->getParam('remoteId', null); + + if ($id === null || + $token === null || + $shareWith === null || + $permission === null || + $remoteId === null + ) { + return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST); + } + + try { + $share = $this->federatedShareProvider->getShareById($id); + } catch (Share\Exceptions\ShareNotFound $e) { + return new \OC_OCS_Result(null, Http::STATUS_NOT_FOUND); + } + + // don't allow to share a file back to the owner + list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith); + $owner = $share->getShareOwner(); + $currentServer = $this->addressHandler->generateRemoteURL(); + if ($this->addressHandler->compareAddresses($user, $remote,$owner , $currentServer)) { + return new \OC_OCS_Result(null, Http::STATUS_FORBIDDEN); + } + + if ($this->verifyShare($share, $token)) { + + // check if re-sharing is allowed + if ($share->getPermissions() | ~Constants::PERMISSION_SHARE) { + $share->setPermissions($share->getPermissions() & $permission); + // the recipient of the initial share is now the initiator for the re-share + $share->setSharedBy($share->getSharedWith()); + $share->setSharedWith($shareWith); + try { + $result = $this->federatedShareProvider->create($share); + $this->federatedShareProvider->storeRemoteId((int)$result->getId(), $remoteId); + return new \OC_OCS_Result(['token' => $result->getToken(), 'remoteId' => $result->getId()]); + } catch (\Exception $e) { + return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST); + } + } else { + return new \OC_OCS_Result(null, Http::STATUS_FORBIDDEN); + } + } + return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST); + + } + + /** + * accept server-to-server share + * + * @param array $params + * @return \OC_OCS_Result + */ + public function acceptShare($params) { + + if (!$this->isS2SEnabled()) { + return new \OC_OCS_Result(null, 503, 'Server does not support federated cloud sharing'); + } + + $id = $params['id']; + $token = isset($_POST['token']) ? $_POST['token'] : null; + + try { + $share = $this->federatedShareProvider->getShareById($id); + } catch (Share\Exceptions\ShareNotFound $e) { + return new \OC_OCS_Result(); + } + + if ($this->verifyShare($share, $token)) { + $this->executeAcceptShare($share); + if ($share->getShareOwner() !== $share->getSharedBy()) { + list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); + $remoteId = $this->federatedShareProvider->getRemoteId($share); + $this->notifications->sendAcceptShare($remote, $remoteId, $share->getToken()); + } + } + + return new \OC_OCS_Result(); + } + + protected function executeAcceptShare(Share\IShare $share) { + list($file, $link) = $this->getFile($this->getCorrectUid($share), $share->getNode()->getId()); + + $event = \OC::$server->getActivityManager()->generateEvent(); + $event->setApp(Activity::FILES_SHARING_APP) + ->setType(Activity::TYPE_REMOTE_SHARE) + ->setAffectedUser($this->getCorrectUid($share)) + ->setSubject(Activity::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share->getSharedWith(), basename($file)]) + ->setObject('files', $share->getNode()->getId(), $file) + ->setLink($link); + \OC::$server->getActivityManager()->publish($event); + } + + /** + * decline server-to-server share + * + * @param array $params + * @return \OC_OCS_Result + */ + public function declineShare($params) { + + if (!$this->isS2SEnabled()) { + return new \OC_OCS_Result(null, 503, 'Server does not support federated cloud sharing'); + } + + $id = (int)$params['id']; + $token = isset($_POST['token']) ? $_POST['token'] : null; + + try { + $share = $this->federatedShareProvider->getShareById($id); + } catch (Share\Exceptions\ShareNotFound $e) { + return new \OC_OCS_Result(); + } + + if($this->verifyShare($share, $token)) { + if ($share->getShareOwner() !== $share->getSharedBy()) { + list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); + $remoteId = $this->federatedShareProvider->getRemoteId($share); + $this->notifications->sendDeclineShare($remote, $remoteId, $share->getToken()); + } + $this->executeDeclineShare($share); + } + + return new \OC_OCS_Result(); + } + + /** + * delete declined share and create a activity + * + * @param Share\IShare $share + */ + protected function executeDeclineShare(Share\IShare $share) { + $this->federatedShareProvider->removeShareFromTable($share); + list($file, $link) = $this->getFile($this->getCorrectUid($share), $share->getNode()->getId()); + + $event = \OC::$server->getActivityManager()->generateEvent(); + $event->setApp(Activity::FILES_SHARING_APP) + ->setType(Activity::TYPE_REMOTE_SHARE) + ->setAffectedUser($this->getCorrectUid($share)) + ->setSubject(Activity::SUBJECT_REMOTE_SHARE_DECLINED, [$share->getSharedWith(), basename($file)]) + ->setObject('files', $share->getNode()->getId(), $file) + ->setLink($link); + \OC::$server->getActivityManager()->publish($event); + + } + + /** + * check if we are the initiator or the owner of a re-share and return the correct UID + * + * @param Share\IShare $share + * @return string + */ + protected function getCorrectUid(Share\IShare $share) { + if($this->userManager->userExists($share->getShareOwner())) { + return $share->getShareOwner(); + } + + return $share->getSharedBy(); + } + + /** + * remove server-to-server share if it was unshared by the owner + * + * @param array $params + * @return \OC_OCS_Result + */ + public function unshare($params) { + + if (!$this->isS2SEnabled()) { + return new \OC_OCS_Result(null, 503, 'Server does not support federated cloud sharing'); + } + + $id = $params['id']; + $token = isset($_POST['token']) ? $_POST['token'] : null; + + $query = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share_external` WHERE `remote_id` = ? AND `share_token` = ?'); + $query->execute(array($id, $token)); + $share = $query->fetchRow(); + + if ($token && $id && !empty($share)) { + + $remote = $this->cleanupRemote($share['remote']); + + $owner = $share['owner'] . '@' . $remote; + $mountpoint = $share['mountpoint']; + $user = $share['user']; + + $query = \OCP\DB::prepare('DELETE FROM `*PREFIX*share_external` WHERE `remote_id` = ? AND `share_token` = ?'); + $query->execute(array($id, $token)); + + if ($share['accepted']) { + $path = trim($mountpoint, '/'); + } else { + $path = trim($share['name'], '/'); + } + + $notificationManager = \OC::$server->getNotificationManager(); + $notification = $notificationManager->createNotification(); + $notification->setApp('files_sharing') + ->setUser($share['user']) + ->setObject('remote_share', (int) $share['id']); + $notificationManager->markProcessed($notification); + + \OC::$server->getActivityManager()->publishActivity( + Activity::FILES_SHARING_APP, Activity::SUBJECT_REMOTE_SHARE_UNSHARED, array($owner, $path), '', array(), + '', '', $user, Activity::TYPE_REMOTE_SHARE, Activity::PRIORITY_MEDIUM); + } + + return new \OC_OCS_Result(); + } + + private function cleanupRemote($remote) { + $remote = substr($remote, strpos($remote, '://') + 3); + + return rtrim($remote, '/'); + } + + + /** + * federated share was revoked, either by the owner or the re-sharer + * + * @param $params + * @return \OC_OCS_Result + */ + public function revoke($params) { + $id = (int)$params['id']; + $token = $this->request->getParam('token'); + + $share = $this->federatedShareProvider->getShareById($id); + + if ($this->verifyShare($share, $token)) { + $this->federatedShareProvider->removeShareFromTable($share); + return new \OC_OCS_Result(); + } + + return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST); + + } + + /** + * get share + * + * @param int $id + * @param string $token + * @return array|bool + */ + protected function getShare($id, $token) { + $query = $this->connection->getQueryBuilder(); + $query->select('*')->from($this->shareTable) + ->where($query->expr()->eq('token', $query->createNamedParameter($token))) + ->andWhere($query->expr()->eq('share_type', $query->createNamedParameter(FederatedShareProvider::SHARE_TYPE_REMOTE))) + ->andWhere($query->expr()->eq('id', $query->createNamedParameter($id))); + + $result = $query->execute()->fetchAll(); + + if (!empty($result) && isset($result[0])) { + return $result[0]; + } + + return false; + } + + /** + * get file + * + * @param string $user + * @param int $fileSource + * @return array with internal path of the file and a absolute link to it + */ + private function getFile($user, $fileSource) { + \OC_Util::setupFS($user); + + try { + $file = \OC\Files\Filesystem::getPath($fileSource); + } catch (NotFoundException $e) { + $file = null; + } + $args = \OC\Files\Filesystem::is_dir($file) ? array('dir' => $file) : array('dir' => dirname($file), 'scrollto' => $file); + $link = \OCP\Util::linkToAbsolute('files', 'index.php', $args); + + return array($file, $link); + + } + + /** + * check if server-to-server sharing is enabled + * + * @param bool $incoming + * @return bool + */ + private function isS2SEnabled($incoming = false) { + + $result = \OCP\App::isEnabled('files_sharing'); + + if ($incoming) { + $result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled(); + } else { + $result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled(); + } + + return $result; + } + + /** + * check if we got the right share + * + * @param Share\IShare $share + * @param string $token + * @return bool + */ + protected function verifyShare(Share\IShare $share, $token) { + if ( + $share->getShareType() === FederatedShareProvider::SHARE_TYPE_REMOTE && + $share->getToken() === $token + ) { + return true; + } + + return false; + } + + /** + * update share information to keep federated re-shares in sync + * + * @param array $params + * @return \OC_OCS_Result + */ + public function updatePermissions($params) { + $id = (int)$params['id']; + $token = $this->request->getParam('token', null); + $permissions = $this->request->getParam('permissions', null); + + try { + $share = $this->federatedShareProvider->getShareById($id); + } catch (Share\Exceptions\ShareNotFound $e) { + return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST); + } + + $validPermission = ctype_digit($permissions); + $validToken = $this->verifyShare($share, $token); + if ($validPermission && $validToken) { + $this->updatePermissionsInDatabase($share, (int)$permissions); + } else { + return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST); + } + + return new \OC_OCS_Result(); + } + + /** + * update permissions in database + * + * @param IShare $share + * @param int $permissions + */ + protected function updatePermissionsInDatabase(IShare $share, $permissions) { + $query = $this->connection->getQueryBuilder(); + $query->update('share') + ->where($query->expr()->eq('id', $query->createNamedParameter($share->getId()))) + ->set('permissions', $query->createNamedParameter($permissions)) + ->execute(); + } + +} diff --git a/apps/files_sharing/lib/notifier.php b/apps/federatedfilesharing/lib/notifier.php index 27e4e2565f2..1c8d92c7eca 100644 --- a/apps/files_sharing/lib/notifier.php +++ b/apps/federatedfilesharing/lib/notifier.php @@ -19,7 +19,7 @@ * */ -namespace OCA\Files_Sharing; +namespace OCA\FederatedFileSharing; use OCP\Notification\INotification; @@ -54,9 +54,15 @@ class Notifier implements INotifier { // Deal with known subjects case 'remote_share': $params = $notification->getSubjectParameters(); - $notification->setParsedSubject( - (string) $l->t('You received "/%2$s" as a remote share from %1$s', $params) - ); + if ($params[0] !== $params[1] && $params[1] !== null) { + $notification->setParsedSubject( + (string) $l->t('You received "/%3$s" as a remote share from %1$s (on behalf of %2$s)', $params) + ); + } else { + $notification->setParsedSubject( + (string)$l->t('You received "/%3$s" as a remote share from %1$s', $params) + ); + } // Deal with the actions for a known subject foreach ($notification->getActions() as $action) { diff --git a/apps/federatedfilesharing/tests/AddressHandlerTest.php b/apps/federatedfilesharing/tests/AddressHandlerTest.php index 9f7d8c49b4d..bb1c2c5a25a 100644 --- a/apps/federatedfilesharing/tests/AddressHandlerTest.php +++ b/apps/federatedfilesharing/tests/AddressHandlerTest.php @@ -27,9 +27,8 @@ namespace OCA\FederatedFileSharing\Tests; use OCA\FederatedFileSharing\AddressHandler; use OCP\IL10N; use OCP\IURLGenerator; -use Test\TestCase; -class AddressHandlerTest extends TestCase { +class AddressHandlerTest extends \Test\TestCase { /** @var AddressHandler */ private $addressHandler; diff --git a/apps/federatedfilesharing/tests/DiscoveryManagerTest.php b/apps/federatedfilesharing/tests/DiscoveryManagerTest.php index 9ae62b1ae4d..5af6b394dd2 100644 --- a/apps/federatedfilesharing/tests/DiscoveryManagerTest.php +++ b/apps/federatedfilesharing/tests/DiscoveryManagerTest.php @@ -26,9 +26,8 @@ use OCP\Http\Client\IClient; use OCP\Http\Client\IClientService; use OCP\ICache; use OCP\ICacheFactory; -use Test\TestCase; -class DiscoveryManagerTest extends TestCase { +class DiscoveryManagerTest extends \Test\TestCase { /** @var ICache */ private $cache; /** @var IClient */ diff --git a/apps/federatedfilesharing/tests/FederatedShareProviderTest.php b/apps/federatedfilesharing/tests/FederatedShareProviderTest.php index 1fbae90a46f..9b3edf0398d 100644 --- a/apps/federatedfilesharing/tests/FederatedShareProviderTest.php +++ b/apps/federatedfilesharing/tests/FederatedShareProviderTest.php @@ -30,8 +30,8 @@ use OCP\IConfig; use OCP\IDBConnection; use OCP\IL10N; use OCP\ILogger; +use OCP\IUserManager; use OCP\Share\IManager; -use Test\TestCase; /** * Class FederatedShareProviderTest @@ -39,7 +39,7 @@ use Test\TestCase; * @package OCA\FederatedFileSharing\Tests * @group DB */ -class FederatedShareProviderTest extends TestCase { +class FederatedShareProviderTest extends \Test\TestCase { /** @var IDBConnection */ protected $connection; @@ -57,6 +57,8 @@ class FederatedShareProviderTest extends TestCase { protected $rootFolder; /** @var IConfig | \PHPUnit_Framework_MockObject_MockObject */ protected $config; + /** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject */ + protected $userManager; /** @var IManager */ protected $shareManager; @@ -82,7 +84,11 @@ class FederatedShareProviderTest extends TestCase { $this->logger = $this->getMock('OCP\ILogger'); $this->rootFolder = $this->getMock('OCP\Files\IRootFolder'); $this->config = $this->getMock('OCP\IConfig'); - $this->addressHandler = new AddressHandler(\OC::$server->getURLGenerator(), $this->l); + $this->userManager = $this->getMock('OCP\IUserManager'); + //$this->addressHandler = new AddressHandler(\OC::$server->getURLGenerator(), $this->l); + $this->addressHandler = $this->getMockBuilder('OCA\FederatedFileSharing\AddressHandler')->disableOriginalConstructor()->getMock(); + + $this->userManager->expects($this->any())->method('userExists')->willReturn(true); $this->provider = new FederatedShareProvider( $this->connection, @@ -92,7 +98,8 @@ class FederatedShareProviderTest extends TestCase { $this->l, $this->logger, $this->rootFolder, - $this->config + $this->config, + $this->userManager ); $this->shareManager = \OC::$server->getShareManager(); @@ -119,6 +126,11 @@ class FederatedShareProviderTest extends TestCase { $this->tokenHandler->method('generateToken')->willReturn('token'); + $this->addressHandler->expects($this->any())->method('generateRemoteURL') + ->willReturn('http://localhost/'); + $this->addressHandler->expects($this->any())->method('splitUserRemote') + ->willReturn(['user', 'server.com']); + $this->notifications->expects($this->once()) ->method('sendRemoteShare') ->with( @@ -126,7 +138,10 @@ class FederatedShareProviderTest extends TestCase { $this->equalTo('user@server.com'), $this->equalTo('myFile'), $this->anything(), - 'sharedBy' + 'shareOwner', + 'shareOwner@http://localhost/', + 'sharedBy', + 'sharedBy@http://localhost/' )->willReturn(true); $this->rootFolder->expects($this->never())->method($this->anything()); @@ -182,6 +197,11 @@ class FederatedShareProviderTest extends TestCase { $this->tokenHandler->method('generateToken')->willReturn('token'); + $this->addressHandler->expects($this->any())->method('generateRemoteURL') + ->willReturn('http://localhost/'); + $this->addressHandler->expects($this->any())->method('splitUserRemote') + ->willReturn(['user', 'server.com']); + $this->notifications->expects($this->once()) ->method('sendRemoteShare') ->with( @@ -189,7 +209,10 @@ class FederatedShareProviderTest extends TestCase { $this->equalTo('user@server.com'), $this->equalTo('myFile'), $this->anything(), - 'sharedBy' + 'shareOwner', + 'shareOwner@http://localhost/', + 'sharedBy', + 'sharedBy@http://localhost/' )->willReturn(false); $this->rootFolder->expects($this->once()) @@ -226,7 +249,10 @@ class FederatedShareProviderTest extends TestCase { $node->method('getId')->willReturn(42); $node->method('getName')->willReturn('myFile'); - $shareWith = 'sharedBy@' . $this->addressHandler->generateRemoteURL(); + $this->addressHandler->expects($this->any())->method('compareAddresses') + ->willReturn(true); + + $shareWith = 'sharedBy@localhost'; $share->setSharedWith($shareWith) ->setSharedBy('sharedBy') @@ -262,6 +288,10 @@ class FederatedShareProviderTest extends TestCase { $node->method('getId')->willReturn(42); $node->method('getName')->willReturn('myFile'); + + $this->addressHandler->expects($this->any())->method('splitUserRemote') + ->willReturn(['user', 'server.com']); + $share->setSharedWith('user@server.com') ->setSharedBy('sharedBy') ->setShareOwner('shareOwner') @@ -270,6 +300,9 @@ class FederatedShareProviderTest extends TestCase { $this->tokenHandler->method('generateToken')->willReturn('token'); + $this->addressHandler->expects($this->any())->method('generateRemoteURL') + ->willReturn('http://localhost/'); + $this->notifications->expects($this->once()) ->method('sendRemoteShare') ->with( @@ -277,7 +310,10 @@ class FederatedShareProviderTest extends TestCase { $this->equalTo('user@server.com'), $this->equalTo('myFile'), $this->anything(), - 'sharedBy' + 'shareOwner', + 'shareOwner@http://localhost/', + 'sharedBy', + 'sharedBy@http://localhost/' )->willReturn(true); $this->rootFolder->expects($this->never())->method($this->anything()); @@ -291,20 +327,46 @@ class FederatedShareProviderTest extends TestCase { } } - public function testUpdate() { + /** + * @dataProvider datatTestUpdate + * + */ + public function testUpdate($owner, $sharedBy) { + + $this->provider = $this->getMockBuilder('OCA\FederatedFileSharing\FederatedShareProvider') + ->setConstructorArgs( + [ + $this->connection, + $this->addressHandler, + $this->notifications, + $this->tokenHandler, + $this->l, + $this->logger, + $this->rootFolder, + $this->config, + $this->userManager + ] + )->setMethods(['sendPermissionUpdate'])->getMock(); + $share = $this->shareManager->newShare(); $node = $this->getMock('\OCP\Files\File'); $node->method('getId')->willReturn(42); $node->method('getName')->willReturn('myFile'); + + $this->addressHandler->expects($this->any())->method('splitUserRemote') + ->willReturn(['user', 'server.com']); + $share->setSharedWith('user@server.com') - ->setSharedBy('sharedBy') - ->setShareOwner('shareOwner') + ->setSharedBy($sharedBy) + ->setShareOwner($owner) ->setPermissions(19) ->setNode($node); $this->tokenHandler->method('generateToken')->willReturn('token'); + $this->addressHandler->expects($this->any())->method('generateRemoteURL') + ->willReturn('http://localhost/'); $this->notifications->expects($this->once()) ->method('sendRemoteShare') @@ -313,9 +375,18 @@ class FederatedShareProviderTest extends TestCase { $this->equalTo('user@server.com'), $this->equalTo('myFile'), $this->anything(), - 'sharedBy' + $owner, + $owner . '@http://localhost/', + $sharedBy, + $sharedBy . '@http://localhost/' )->willReturn(true); + if($owner === $sharedBy) { + $this->provider->expects($this->never())->method('sendPermissionUpdate'); + } else { + $this->provider->expects($this->once())->method('sendPermissionUpdate'); + } + $this->rootFolder->expects($this->never())->method($this->anything()); $share = $this->provider->create($share); @@ -328,11 +399,24 @@ class FederatedShareProviderTest extends TestCase { $this->assertEquals(1, $share->getPermissions()); } + public function datatTestUpdate() { + return [ + ['sharedBy', 'shareOwner'], + ['shareOwner', 'shareOwner'] + ]; + } + public function testGetSharedBy() { $node = $this->getMock('\OCP\Files\File'); $node->method('getId')->willReturn(42); $node->method('getName')->willReturn('myFile'); + $this->addressHandler->expects($this->at(0))->method('splitUserRemote') + ->willReturn(['user', 'server.com']); + + $this->addressHandler->expects($this->at(1))->method('splitUserRemote') + ->willReturn(['user2', 'server.com']); + $this->tokenHandler->method('generateToken')->willReturn('token'); $this->notifications ->method('sendRemoteShare') @@ -439,6 +523,14 @@ class FederatedShareProviderTest extends TestCase { $node->method('getId')->willReturn(42); $node->method('getName')->willReturn('myFile'); + $this->addressHandler->expects($this->any())->method('splitUserRemote') + ->willReturnCallback(function ($uid) { + if ($uid === 'user@server.com') { + return ['user', 'server.com']; + } + return ['user2', 'server.com']; + }); + $this->tokenHandler->method('generateToken')->willReturn('token'); $this->notifications ->method('sendRemoteShare') diff --git a/apps/federatedfilesharing/tests/NotificationsTest.php b/apps/federatedfilesharing/tests/NotificationsTest.php index bde69a82bad..50a62e9829e 100644 --- a/apps/federatedfilesharing/tests/NotificationsTest.php +++ b/apps/federatedfilesharing/tests/NotificationsTest.php @@ -28,9 +28,8 @@ use OCA\FederatedFileSharing\DiscoveryManager; use OCA\FederatedFileSharing\Notifications; use OCP\BackgroundJob\IJobList; use OCP\Http\Client\IClientService; -use Test\TestCase; -class NotificationsTest extends TestCase { +class NotificationsTest extends \Test\TestCase { /** @var AddressHandler | \PHPUnit_Framework_MockObject_MockObject */ private $addressHandler; @@ -85,14 +84,15 @@ class NotificationsTest extends TestCase { return $instance; } + /** - * @dataProvider dataTestSendRemoteUnShare + * @dataProvider dataTestSendUpdateToRemote * * @param int $try * @param array $httpRequestResult * @param bool $expected */ - public function testSendRemoteUnShare($try, $httpRequestResult, $expected) { + public function testSendUpdateToRemote($try, $httpRequestResult, $expected) { $remote = 'remote'; $id = 42; $timestamp = 63576; @@ -102,20 +102,22 @@ class NotificationsTest extends TestCase { $instance->expects($this->any())->method('getTimestamp')->willReturn($timestamp); $instance->expects($this->once())->method('tryHttpPostToShareEndpoint') - ->with($remote, '/'.$id.'/unshare', ['token' => $token, 'format' => 'json']) + ->with($remote, '/'.$id.'/unshare', ['token' => $token, 'data1Key' => 'data1Value']) ->willReturn($httpRequestResult); $this->addressHandler->expects($this->once())->method('removeProtocolFromUrl') ->with($remote)->willReturn($remote); - + // only add background job on first try if ($try === 0 && $expected === false) { $this->jobList->expects($this->once())->method('add') ->with( - 'OCA\FederatedFileSharing\BackgroundJob\UnShare', + 'OCA\FederatedFileSharing\BackgroundJob\RetryJob', [ 'remote' => $remote, - 'id' => $id, + 'remoteId' => $id, + 'action' => 'unshare', + 'data' => json_encode(['data1Key' => 'data1Value']), 'token' => $token, 'try' => $try, 'lastRun' => $timestamp @@ -124,14 +126,15 @@ class NotificationsTest extends TestCase { } else { $this->jobList->expects($this->never())->method('add'); } - + $this->assertSame($expected, - $instance->sendRemoteUnShare($remote, $id, $token, $try) + $instance->sendUpdateToRemote($remote, $id, $token, 'unshare', ['data1Key' => 'data1Value'], $try) ); - + } - - public function dataTestSendRemoteUnshare() { + + + public function dataTestSendUpdateToRemote() { return [ // test if background job is added correctly [0, ['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 200]]])], true], diff --git a/apps/files_sharing/tests/server2server.php b/apps/federatedfilesharing/tests/RequestHandlerTest.php index 1c8b5ed7a17..14da756a0ef 100644 --- a/apps/files_sharing/tests/server2server.php +++ b/apps/federatedfilesharing/tests/RequestHandlerTest.php @@ -23,14 +23,22 @@ * */ -use OCA\Files_Sharing\Tests\TestCase; +namespace OCA\FederatedFileSharing\Tests; + +use OC\Files\Filesystem; +use OCA\FederatedFileSharing\DiscoveryManager; +use OCA\FederatedFileSharing\FederatedShareProvider; +use OCA\FederatedFileSharing\RequestHandler; +use OCP\IUserManager; +use OCP\Share\IShare; /** - * Class Test_Files_Sharing_Api + * Class RequestHandlerTest * + * @package OCA\FederatedFileSharing\Tests * @group DB */ -class Test_Files_Sharing_S2S_OCS_API extends TestCase { +class RequestHandlerTest extends TestCase { const TEST_FOLDER_NAME = '/folder_share_api_test'; @@ -40,13 +48,25 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase { private $connection; /** - * @var \OCA\Files_Sharing\API\Server2Server + * @var RequestHandler */ private $s2s; /** @var \OCA\FederatedFileSharing\FederatedShareProvider | PHPUnit_Framework_MockObject_MockObject */ private $federatedShareProvider; + /** @var \OCA\FederatedFileSharing\Notifications | PHPUnit_Framework_MockObject_MockObject */ + private $notifications; + + /** @var \OCA\FederatedFileSharing\AddressHandler | PHPUnit_Framework_MockObject_MockObject */ + private $addressHandler; + + /** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject */ + private $userManager; + + /** @var IShare | \PHPUnit_Framework_MockObject_MockObject */ + private $share; + protected function setUp() { parent::setUp(); @@ -60,16 +80,33 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase { ->setConstructorArgs([$config, $clientService]) ->getMock(); $httpHelperMock->expects($this->any())->method('post')->with($this->anything())->will($this->returnValue(true)); + $this->share = $this->getMock('\OCP\Share\IShare'); $this->federatedShareProvider = $this->getMockBuilder('OCA\FederatedFileSharing\FederatedShareProvider') ->disableOriginalConstructor()->getMock(); $this->federatedShareProvider->expects($this->any()) ->method('isOutgoingServer2serverShareEnabled')->willReturn(true); $this->federatedShareProvider->expects($this->any()) ->method('isIncomingServer2serverShareEnabled')->willReturn(true); + $this->federatedShareProvider->expects($this->any())->method('getShareById') + ->willReturn($this->share); + $this->notifications = $this->getMockBuilder('OCA\FederatedFileSharing\Notifications') + ->disableOriginalConstructor()->getMock(); + $this->addressHandler = $this->getMockBuilder('OCA\FederatedFileSharing\AddressHandler') + ->disableOriginalConstructor()->getMock(); + $this->userManager = $this->getMock('OCP\IUserManager'); + $this->registerHttpHelper($httpHelperMock); - $this->s2s = new \OCA\Files_Sharing\API\Server2Server($this->federatedShareProvider); + $this->s2s = new RequestHandler( + $this->federatedShareProvider, + \OC::$server->getDatabaseConnection(), + \OC::$server->getShareManager(), + \OC::$server->getRequest(), + $this->notifications, + $this->addressHandler, + $this->userManager + ); $this->connection = \OC::$server->getDatabaseConnection(); } @@ -78,6 +115,9 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase { $query = \OCP\DB::prepare('DELETE FROM `*PREFIX*share_external`'); $query->execute(); + $query = \OCP\DB::prepare('DELETE FROM `*PREFIX*share`'); + $query->execute(); + $this->restoreHttpHelper(); parent::tearDown(); @@ -135,28 +175,34 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase { function testDeclineShare() { - $dummy = \OCP\DB::prepare(' - INSERT INTO `*PREFIX*share` - (`share_type`, `uid_owner`, `item_type`, `item_source`, `item_target`, `file_source`, `file_target`, `permissions`, `stime`, `token`, `share_with`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - '); - $dummy->execute(array(\OCP\Share::SHARE_TYPE_REMOTE, self::TEST_FILES_SHARING_API_USER1, 'test', '1', '/1', '1', '/test.txt', '1', time(), 'token', 'foo@bar')); - $verify = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share`'); - $result = $verify->execute(); - $data = $result->fetchAll(); - $this->assertSame(1, count($data)); + $this->s2s = $this->getMockBuilder('\OCA\FederatedFileSharing\RequestHandler') + ->setConstructorArgs( + [ + $this->federatedShareProvider, + \OC::$server->getDatabaseConnection(), + \OC::$server->getShareManager(), + \OC::$server->getRequest(), + $this->notifications, + $this->addressHandler, + $this->userManager + ] + )->setMethods(['executeDeclineShare', 'verifyShare'])->getMock(); + + $this->s2s->expects($this->once())->method('executeDeclineShare'); + + $this->s2s->expects($this->any())->method('verifyShare')->willReturn(true); $_POST['token'] = 'token'; - $this->s2s->declineShare(array('id' => $data[0]['id'])); - $verify = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share`'); - $result = $verify->execute(); - $data = $result->fetchAll(); - $this->assertEmpty($data); + $this->s2s->declineShare(array('id' => 42)); + } - function testDeclineShareMultiple() { + function XtestDeclineShareMultiple() { + + $this->share->expects($this->any())->method('verifyShare')->willReturn(true); + $dummy = \OCP\DB::prepare(' INSERT INTO `*PREFIX*share` (`share_type`, `uid_owner`, `item_type`, `item_source`, `item_target`, `file_source`, `file_target`, `permissions`, `stime`, `token`, `share_with`) @@ -194,14 +240,14 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase { function testDeleteUser($toDelete, $expected, $remainingUsers) { $this->createDummyS2SShares(); - $discoveryManager = new \OCA\FederatedFileSharing\DiscoveryManager( + $discoveryManager = new DiscoveryManager( \OC::$server->getMemCacheFactory(), \OC::$server->getHTTPClientService() ); - $manager = new OCA\Files_Sharing\External\Manager( + $manager = new \OCA\Files_Sharing\External\Manager( \OC::$server->getDatabaseConnection(), - \OC\Files\Filesystem::getMountManager(), - \OC\Files\Filesystem::getLoader(), + Filesystem::getMountManager(), + Filesystem::getLoader(), \OC::$server->getHTTPHelper(), \OC::$server->getNotificationManager(), $discoveryManager, @@ -260,4 +306,76 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase { $this->assertSame(10, count($dummyEntries)); } + /** + * @dataProvider dataTestGetShare + * + * @param bool $found + * @param bool $correctId + * @param bool $correctToken + */ + public function testGetShare($found, $correctId, $correctToken) { + + $connection = \OC::$server->getDatabaseConnection(); + $query = $connection->getQueryBuilder(); + $stime = time(); + $query->insert('share') + ->values( + [ + 'share_type' => $query->createNamedParameter(FederatedShareProvider::SHARE_TYPE_REMOTE), + 'uid_owner' => $query->createNamedParameter(self::TEST_FILES_SHARING_API_USER1), + 'uid_initiator' => $query->createNamedParameter(self::TEST_FILES_SHARING_API_USER2), + 'item_type' => $query->createNamedParameter('test'), + 'item_source' => $query->createNamedParameter('1'), + 'item_target' => $query->createNamedParameter('/1'), + 'file_source' => $query->createNamedParameter('1'), + 'file_target' => $query->createNamedParameter('/test.txt'), + 'permissions' => $query->createNamedParameter('1'), + 'stime' => $query->createNamedParameter($stime), + 'token' => $query->createNamedParameter('token'), + 'share_with' => $query->createNamedParameter('foo@bar'), + ] + )->execute(); + $id = $query->getLastInsertId(); + + $expected = [ + 'share_type' => (string)FederatedShareProvider::SHARE_TYPE_REMOTE, + 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, + 'item_type' => 'test', + 'item_source' => '1', + 'item_target' => '/1', + 'file_source' => '1', + 'file_target' => '/test.txt', + 'permissions' => '1', + 'stime' => (string)$stime, + 'token' => 'token', + 'share_with' => 'foo@bar', + 'id' => (string)$id, + 'uid_initiator' => self::TEST_FILES_SHARING_API_USER2, + 'parent' => null, + 'accepted' => '0', + 'expiration' => null, + 'mail_send' => '0' + ]; + + $searchToken = $correctToken ? 'token' : 'wrongToken'; + $searchId = $correctId ? $id : -1; + + $result = $this->invokePrivate($this->s2s, 'getShare', [$searchId, $searchToken]); + + if ($found) { + $this->assertEquals($expected, $result); + } else { + $this->assertSame(false, $result); + } + } + + public function dataTestGetShare() { + return [ + [true, true, true], + [false, false, true], + [false, true, false], + [false, false, false], + ]; + } + } diff --git a/apps/federatedfilesharing/tests/TestCase.php b/apps/federatedfilesharing/tests/TestCase.php new file mode 100644 index 00000000000..64c6d045598 --- /dev/null +++ b/apps/federatedfilesharing/tests/TestCase.php @@ -0,0 +1,132 @@ +<?php +/** + * @author Björn Schießle <schiessle@owncloud.com> + * @author Joas Schilling <nickvergessen@owncloud.com> + * @author Jörn Friedrich Dreyer <jfd@butonic.de> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Robin Appelman <icewind@owncloud.com> + * @author Robin McCorkell <robin@mccorkell.me.uk> + * @author Roeland Jago Douma <rullzer@owncloud.com> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * @author Vincent Petry <pvince81@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCA\FederatedFileSharing\Tests; + +use OC\Files\Filesystem; +use OCA\Files\Share; + +/** + * Class Test_Files_Sharing_Base + * + * @group DB + * + * Base class for sharing tests. + */ +abstract class TestCase extends \Test\TestCase { + + const TEST_FILES_SHARING_API_USER1 = "test-share-user1"; + const TEST_FILES_SHARING_API_USER2 = "test-share-user2"; + + public static function setUpBeforeClass() { + parent::setUpBeforeClass(); + + // reset backend + \OC_User::clearBackends(); + \OC_Group::clearBackends(); + + // create users + $backend = new \Test\Util\User\Dummy(); + \OC_User::useBackend($backend); + $backend->createUser(self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER1); + $backend->createUser(self::TEST_FILES_SHARING_API_USER2, self::TEST_FILES_SHARING_API_USER2); + } + + protected function setUp() { + parent::setUp(); + + //login as user1 + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + } + + public static function tearDownAfterClass() { + // cleanup users + $user = \OC::$server->getUserManager()->get(self::TEST_FILES_SHARING_API_USER1); + if ($user !== null) { + $user->delete(); + } + $user = \OC::$server->getUserManager()->get(self::TEST_FILES_SHARING_API_USER2); + if ($user !== null) { + $user->delete(); + } + + \OC_Util::tearDownFS(); + \OC_User::setUserId(''); + Filesystem::tearDown(); + + // reset backend + \OC_User::clearBackends(); + \OC_User::useBackend('database'); + \OC_Group::clearBackends(); + \OC_Group::useBackend(new \OC_Group_Database()); + + parent::tearDownAfterClass(); + } + + /** + * @param string $user + * @param bool $create + * @param bool $password + */ + protected static function loginHelper($user, $create = false, $password = false) { + + if ($password === false) { + $password = $user; + } + + if ($create) { + \OC::$server->getUserManager()->createUser($user, $password); + \OC_Group::createGroup('group'); + \OC_Group::addToGroup($user, 'group'); + } + + self::resetStorage(); + + \OC_Util::tearDownFS(); + \OC::$server->getUserSession()->setUser(null); + \OC\Files\Filesystem::tearDown(); + \OC::$server->getUserSession()->login($user, $password); + \OC::$server->getUserFolder($user); + + \OC_Util::setupFS($user); + } + + /** + * reset init status for the share storage + */ + protected static function resetStorage() { + $storage = new \ReflectionClass('\OC\Files\Storage\Shared'); + $isInitialized = $storage->getProperty('initialized'); + $isInitialized->setAccessible(true); + $isInitialized->setValue($storage, false); + $isInitialized->setAccessible(false); + } + +} diff --git a/apps/federatedfilesharing/tests/TokenHandlerTest.php b/apps/federatedfilesharing/tests/TokenHandlerTest.php index 490c0d95d7b..004a3a61933 100644 --- a/apps/federatedfilesharing/tests/TokenHandlerTest.php +++ b/apps/federatedfilesharing/tests/TokenHandlerTest.php @@ -26,9 +26,8 @@ namespace OCA\FederatedFileSharing\Tests; use OCA\FederatedFileSharing\TokenHandler; use OCP\Security\ISecureRandom; -use Test\TestCase; -class TokenHandlerTest extends TestCase { +class TokenHandlerTest extends \Test\TestCase { /** @var TokenHandler */ private $tokenHandler; diff --git a/apps/federation/api/ocsauthapi.php b/apps/federation/lib/API/OCSAuthAPI.php index 1c4e73cc8de..1c4e73cc8de 100644 --- a/apps/federation/api/ocsauthapi.php +++ b/apps/federation/lib/API/OCSAuthAPI.php diff --git a/apps/federation/appinfo/application.php b/apps/federation/lib/AppInfo/Application.php index 74185345329..74185345329 100644 --- a/apps/federation/appinfo/application.php +++ b/apps/federation/lib/AppInfo/Application.php diff --git a/apps/federation/backgroundjob/getsharedsecret.php b/apps/federation/lib/BackgroundJob/GetSharedSecret.php index 66ab082c1a2..66ab082c1a2 100644 --- a/apps/federation/backgroundjob/getsharedsecret.php +++ b/apps/federation/lib/BackgroundJob/GetSharedSecret.php diff --git a/apps/federation/backgroundjob/requestsharedsecret.php b/apps/federation/lib/BackgroundJob/RequestSharedSecret.php index 040e8e1d8e2..040e8e1d8e2 100644 --- a/apps/federation/backgroundjob/requestsharedsecret.php +++ b/apps/federation/lib/BackgroundJob/RequestSharedSecret.php diff --git a/apps/federation/command/syncfederationaddressbooks.php b/apps/federation/lib/Command/SyncFederationAddressBooks.php index 879d38f8c22..879d38f8c22 100644 --- a/apps/federation/command/syncfederationaddressbooks.php +++ b/apps/federation/lib/Command/SyncFederationAddressBooks.php diff --git a/apps/federation/controller/settingscontroller.php b/apps/federation/lib/Controller/SettingsController.php index 3adb6fced66..3adb6fced66 100644 --- a/apps/federation/controller/settingscontroller.php +++ b/apps/federation/lib/Controller/SettingsController.php diff --git a/apps/federation/dav/fedauth.php b/apps/federation/lib/DAV/FedAuth.php index bb1041adcdf..bb1041adcdf 100644 --- a/apps/federation/dav/fedauth.php +++ b/apps/federation/lib/DAV/FedAuth.php diff --git a/apps/federation/lib/dbhandler.php b/apps/federation/lib/DbHandler.php index 8720560efc6..8720560efc6 100644 --- a/apps/federation/lib/dbhandler.php +++ b/apps/federation/lib/DbHandler.php diff --git a/apps/federation/lib/hooks.php b/apps/federation/lib/Hooks.php index b7f63d27f55..b7f63d27f55 100644 --- a/apps/federation/lib/hooks.php +++ b/apps/federation/lib/Hooks.php diff --git a/apps/federation/middleware/addservermiddleware.php b/apps/federation/lib/Middleware/AddServerMiddleware.php index 15781251349..4b752f51ee4 100644 --- a/apps/federation/middleware/addservermiddleware.php +++ b/apps/federation/lib/Middleware/AddServerMiddleware.php @@ -20,7 +20,7 @@ * */ -namespace OCA\Federation\Middleware ; +namespace OCA\Federation\Middleware; use OC\HintException; use OCP\AppFramework\Http; diff --git a/apps/federation/lib/syncfederationaddressbooks.php b/apps/federation/lib/SyncFederationAddressBooks.php index 209094266ca..209094266ca 100644 --- a/apps/federation/lib/syncfederationaddressbooks.php +++ b/apps/federation/lib/SyncFederationAddressBooks.php diff --git a/apps/federation/lib/syncjob.php b/apps/federation/lib/SyncJob.php index 2b904813b92..2b904813b92 100644 --- a/apps/federation/lib/syncjob.php +++ b/apps/federation/lib/SyncJob.php diff --git a/apps/federation/lib/trustedservers.php b/apps/federation/lib/TrustedServers.php index 3b356ea2a49..3b356ea2a49 100644 --- a/apps/federation/lib/trustedservers.php +++ b/apps/federation/lib/TrustedServers.php diff --git a/apps/federation/tests/api/ocsauthapitest.php b/apps/federation/tests/API/OCSAuthAPITest.php index d3e61c0641a..d3e61c0641a 100644 --- a/apps/federation/tests/api/ocsauthapitest.php +++ b/apps/federation/tests/API/OCSAuthAPITest.php diff --git a/apps/federation/tests/backgroundjob/getsharedsecrettest.php b/apps/federation/tests/BackgroundJob/GetSharedSecretTest.php index 25f7502741d..25f7502741d 100644 --- a/apps/federation/tests/backgroundjob/getsharedsecrettest.php +++ b/apps/federation/tests/BackgroundJob/GetSharedSecretTest.php diff --git a/apps/federation/tests/backgroundjob/requestsharedsecrettest.php b/apps/federation/tests/BackgroundJob/RequestSharedSecretTest.php index 5b4a1f87a5f..2fc4fe881a6 100644 --- a/apps/federation/tests/backgroundjob/requestsharedsecrettest.php +++ b/apps/federation/tests/BackgroundJob/RequestSharedSecretTest.php @@ -24,7 +24,13 @@ namespace OCA\Federation\Tests\BackgroundJob; use OCA\Federation\BackgroundJob\RequestSharedSecret; +use OCA\Federation\DbHandler; +use OCA\Federation\TrustedServers; use OCP\AppFramework\Http; +use OCP\BackgroundJob\IJobList; +use OCP\Http\Client\IClient; +use OCP\Http\Client\IResponse; +use OCP\IURLGenerator; use Test\TestCase; class RequestSharedSecretTest extends TestCase { diff --git a/apps/federation/tests/controller/settingscontrollertest.php b/apps/federation/tests/Controller/SettingsControllerTest.php index 65f7d5f91d3..65f7d5f91d3 100644 --- a/apps/federation/tests/controller/settingscontrollertest.php +++ b/apps/federation/tests/Controller/SettingsControllerTest.php diff --git a/apps/federation/tests/dav/fedauthtest.php b/apps/federation/tests/DAV/FedAuthTest.php index b716084a45d..b716084a45d 100644 --- a/apps/federation/tests/dav/fedauthtest.php +++ b/apps/federation/tests/DAV/FedAuthTest.php diff --git a/apps/federation/tests/lib/dbhandlertest.php b/apps/federation/tests/DbHandlerTest.php index 3ded486d36a..6e5b8f2f06c 100644 --- a/apps/federation/tests/lib/dbhandlertest.php +++ b/apps/federation/tests/DbHandlerTest.php @@ -21,7 +21,7 @@ */ -namespace OCA\Federation\Tests\lib; +namespace OCA\Federation\Tests; use OCA\Federation\DbHandler; diff --git a/apps/federation/tests/lib/hookstest.php b/apps/federation/tests/HooksTest.php index 71569226dd2..014829d9cf6 100644 --- a/apps/federation/tests/lib/hookstest.php +++ b/apps/federation/tests/HooksTest.php @@ -20,7 +20,7 @@ */ -namespace OCA\Federation\Tests\lib; +namespace OCA\Federation\Tests; use OCA\Federation\Hooks; diff --git a/apps/federation/tests/middleware/addservermiddlewaretest.php b/apps/federation/tests/Middleware/AddServerMiddlewareTest.php index be1d97c4035..be1d97c4035 100644 --- a/apps/federation/tests/middleware/addservermiddlewaretest.php +++ b/apps/federation/tests/Middleware/AddServerMiddlewareTest.php diff --git a/apps/federation/tests/lib/syncfederationaddressbookstest.php b/apps/federation/tests/SyncFederationAddressbooksTest.php index aa2bd9ac2cb..4c266fae3a0 100644 --- a/apps/federation/tests/lib/syncfederationaddressbookstest.php +++ b/apps/federation/tests/SyncFederationAddressbooksTest.php @@ -20,7 +20,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/> * */ -namespace OCA\Federation\Tests\lib; +namespace OCA\Federation\Tests; use OCA\Federation\DbHandler; use OCA\Federation\SyncFederationAddressBooks; @@ -52,6 +52,7 @@ class SyncFederationAddressbooksTest extends \Test\TestCase { $syncService->expects($this->once())->method('syncRemoteAddressBook') ->willReturn(1); + /** @var \OCA\DAV\CardDAV\SyncService $syncService */ $s = new SyncFederationAddressBooks($dbHandler, $syncService); $s->syncThemAll(function($url, $ex) { $this->callBacks[] = [$url, $ex]; @@ -79,6 +80,7 @@ class SyncFederationAddressbooksTest extends \Test\TestCase { $syncService->expects($this->once())->method('syncRemoteAddressBook') ->willThrowException(new \Exception('something did not work out')); + /** @var \OCA\DAV\CardDAV\SyncService $syncService */ $s = new SyncFederationAddressBooks($dbHandler, $syncService); $s->syncThemAll(function($url, $ex) { $this->callBacks[] = [$url, $ex]; diff --git a/apps/federation/tests/lib/trustedserverstest.php b/apps/federation/tests/TrustedServersTest.php index a8c7c7afb1f..e49db2556be 100644 --- a/apps/federation/tests/lib/trustedserverstest.php +++ b/apps/federation/tests/TrustedServersTest.php @@ -21,7 +21,7 @@ */ -namespace OCA\Federation\Tests\lib; +namespace OCA\Federation\Tests; use OCA\Federation\DbHandler; @@ -38,7 +38,7 @@ use Test\TestCase; class TrustedServersTest extends TestCase { - /** @var TrustedServers */ + /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers */ private $trustedServers; /** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */ @@ -101,7 +101,7 @@ class TrustedServersTest extends TestCase { * @param bool $success */ public function testAddServer($success) { - /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers $trustedServer */ + /** @var \PHPUnit_Framework_MockObject_MockObject|TrustedServers $trustedServers */ $trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers') ->setConstructorArgs( [ @@ -172,7 +172,7 @@ class TrustedServersTest extends TestCase { ->with('federation', 'autoAddServers', '1')->willReturn($status); $this->assertSame($expected, - $this->trustedServers->getAutoAddServers($status) + $this->trustedServers->getAutoAddServers() ); } @@ -208,6 +208,7 @@ class TrustedServersTest extends TestCase { function($eventId, $event) { $this->assertSame($eventId, 'OCP\Federation\TrustedServerEvent::remove'); $this->assertInstanceOf('Symfony\Component\EventDispatcher\GenericEvent', $event); + /** @var \Symfony\Component\EventDispatcher\GenericEvent $event */ $this->assertSame('url_hash', $event->getSubject()); } ); @@ -215,9 +216,10 @@ class TrustedServersTest extends TestCase { } public function testGetServers() { - $this->dbHandler->expects($this->once())->method('getAllServer')->willReturn(true); + $this->dbHandler->expects($this->once())->method('getAllServer')->willReturn(['servers']); - $this->assertTrue( + $this->assertEquals( + ['servers'], $this->trustedServers->getServers() ); } @@ -257,7 +259,7 @@ class TrustedServersTest extends TestCase { $server = 'server1'; - /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers $trustedServer */ + /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers $trustedServers */ $trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers') ->setConstructorArgs( [ diff --git a/apps/files/l10n/cs_CZ.js b/apps/files/l10n/cs_CZ.js index d1bcb699e7a..3299e21d293 100644 --- a/apps/files/l10n/cs_CZ.js +++ b/apps/files/l10n/cs_CZ.js @@ -15,7 +15,7 @@ OC.L10N.register( "Missing a temporary folder" : "Chybí adresář pro dočasné soubory", "Failed to write to disk" : "Zápis na disk selhal", "Not enough storage available" : "Nedostatek dostupného úložného prostoru", - "The target folder has been moved or deleted." : "Cílová složka byla přesunuta nebo smazána.", + "The target folder has been moved or deleted." : "Cílový adresář byl přesunuta nebo smazán.", "Upload failed. Could not find uploaded file" : "Nahrávání selhalo. Nepodařilo se nalézt nahraný soubor.", "Upload failed. Could not get file info." : "Nahrávání selhalo. Nepodařilo se získat informace o souboru.", "Invalid directory." : "Neplatný adresář", @@ -36,10 +36,10 @@ OC.L10N.register( "{hours}:{minutes}h" : "{hours}:{minutes}h", "{minutes}:{seconds} minute{plural_s} left" : "zbývá {minutes}:{seconds} minute{plural_s}", "{minutes}:{seconds}m" : "{minutes}:{seconds}m", - "{seconds} second{plural_s} left" : "\t!", + "{seconds} second{plural_s} left" : "{seconds} sekund{plural_s} zbývá", "{seconds}s" : "{seconds}s", "Any moment now..." : "Každou chvíli...", - "Soon..." : "Za chvíli...", + "Soon..." : "Brzy...", "{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} z {totalSize} ({bitrate})", "File upload is in progress. Leaving the page now will cancel the upload." : "Probíhá odesílání souboru. Opuštění stránky způsobí zrušení nahrávání.", "Actions" : "Činnosti", @@ -69,7 +69,7 @@ OC.L10N.register( "Name" : "Název", "Size" : "Velikost", "Modified" : "Upraveno", - "_%n folder_::_%n folders_" : ["%n složka","%n složky","%n složek"], + "_%n folder_::_%n folders_" : ["%n adresář","%n adresáře","%n adresářů"], "_%n file_::_%n files_" : ["%n soubor","%n soubory","%n souborů"], "{dirs} and {files}" : "{dirs} a {files}", "You don’t have permission to upload or create files here" : "Nemáte oprávnění sem nahrávat nebo vytvářet soubory", @@ -87,16 +87,16 @@ OC.L10N.register( "Favorited" : "Přidáno k oblíbeným", "Favorite" : "Oblíbené", "Local link" : "Místní odkaz", - "Folder" : "Složka", - "New folder" : "Nová složka", + "Folder" : "Adresář", + "New folder" : "Nový adresář", "{newname} already exists" : "{newname} již existuje", "Upload" : "Odeslat", "An error occurred while trying to update the tags" : "Při pokusu o úpravu tagů nastala chyba", - "A new file or folder has been <strong>created</strong>" : "Byl <strong>vytvořen</strong> nový soubor nebo složka", - "A file or folder has been <strong>changed</strong>" : "Soubor nebo složka byla <strong>změněna</strong>", + "A new file or folder has been <strong>created</strong>" : "Byl <strong>vytvořen</strong> nový soubor nebo adresář", + "A file or folder has been <strong>changed</strong>" : "Soubor nebo adresář byl <strong>změněn</strong>", "Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>" : "Limit oznámení o tvorbě a změnách vašich <strong>oblíbených souborů</strong> <em>(Pouze streamovat)</em>", - "A file or folder has been <strong>deleted</strong>" : "Soubor nebo složka byla <strong>smazána</strong>", - "A file or folder has been <strong>restored</strong>" : "Soubor nebo složka byla <strong>obnovena</strong>", + "A file or folder has been <strong>deleted</strong>" : "Soubor nebo adresář byl <strong>smazán</strong>", + "A file or folder has been <strong>restored</strong>" : "Soubor nebo adresář byla <strong>obnoven</strong>", "You created %1$s" : "Vytvořili jste %1$s", "%2$s created %1$s" : "%2$s vytvořil(a) %1$s", "%1$s was created in a public folder" : "%1$s byl vytvořen ve veřejném adresáři", @@ -122,7 +122,7 @@ OC.L10N.register( "Use this address to <a href=\"%s\" target=\"_blank\" rel=\"noreferrer\">access your Files via WebDAV</a>" : "Použijte tuto adresu pro <a href=\"%s\" target=\"_blank\" rel=\"noreferrer\">přístup ke svým Souborům přes WebDAV</a>", "No files in here" : "Žádné soubory", "Upload some content or sync with your devices!" : "Nahrajte nějaký obsah nebo synchronizujte se svými přístroji!", - "No entries found in this folder" : "V této složce nebylo nic nalezeno", + "No entries found in this folder" : "V tomto adresáři nebylo nic nalezeno", "Select all" : "Vybrat vše", "Upload too large" : "Odesílaný soubor je příliš velký", "The files you are trying to upload exceed the maximum size for file uploads on this server." : "Soubory, které se snažíte odeslat, překračují limit velikosti odesílání na tomto serveru.", diff --git a/apps/files/l10n/cs_CZ.json b/apps/files/l10n/cs_CZ.json index a9d03d923ab..5e138e22596 100644 --- a/apps/files/l10n/cs_CZ.json +++ b/apps/files/l10n/cs_CZ.json @@ -13,7 +13,7 @@ "Missing a temporary folder" : "Chybí adresář pro dočasné soubory", "Failed to write to disk" : "Zápis na disk selhal", "Not enough storage available" : "Nedostatek dostupného úložného prostoru", - "The target folder has been moved or deleted." : "Cílová složka byla přesunuta nebo smazána.", + "The target folder has been moved or deleted." : "Cílový adresář byl přesunuta nebo smazán.", "Upload failed. Could not find uploaded file" : "Nahrávání selhalo. Nepodařilo se nalézt nahraný soubor.", "Upload failed. Could not get file info." : "Nahrávání selhalo. Nepodařilo se získat informace o souboru.", "Invalid directory." : "Neplatný adresář", @@ -34,10 +34,10 @@ "{hours}:{minutes}h" : "{hours}:{minutes}h", "{minutes}:{seconds} minute{plural_s} left" : "zbývá {minutes}:{seconds} minute{plural_s}", "{minutes}:{seconds}m" : "{minutes}:{seconds}m", - "{seconds} second{plural_s} left" : "\t!", + "{seconds} second{plural_s} left" : "{seconds} sekund{plural_s} zbývá", "{seconds}s" : "{seconds}s", "Any moment now..." : "Každou chvíli...", - "Soon..." : "Za chvíli...", + "Soon..." : "Brzy...", "{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} z {totalSize} ({bitrate})", "File upload is in progress. Leaving the page now will cancel the upload." : "Probíhá odesílání souboru. Opuštění stránky způsobí zrušení nahrávání.", "Actions" : "Činnosti", @@ -67,7 +67,7 @@ "Name" : "Název", "Size" : "Velikost", "Modified" : "Upraveno", - "_%n folder_::_%n folders_" : ["%n složka","%n složky","%n složek"], + "_%n folder_::_%n folders_" : ["%n adresář","%n adresáře","%n adresářů"], "_%n file_::_%n files_" : ["%n soubor","%n soubory","%n souborů"], "{dirs} and {files}" : "{dirs} a {files}", "You don’t have permission to upload or create files here" : "Nemáte oprávnění sem nahrávat nebo vytvářet soubory", @@ -85,16 +85,16 @@ "Favorited" : "Přidáno k oblíbeným", "Favorite" : "Oblíbené", "Local link" : "Místní odkaz", - "Folder" : "Složka", - "New folder" : "Nová složka", + "Folder" : "Adresář", + "New folder" : "Nový adresář", "{newname} already exists" : "{newname} již existuje", "Upload" : "Odeslat", "An error occurred while trying to update the tags" : "Při pokusu o úpravu tagů nastala chyba", - "A new file or folder has been <strong>created</strong>" : "Byl <strong>vytvořen</strong> nový soubor nebo složka", - "A file or folder has been <strong>changed</strong>" : "Soubor nebo složka byla <strong>změněna</strong>", + "A new file or folder has been <strong>created</strong>" : "Byl <strong>vytvořen</strong> nový soubor nebo adresář", + "A file or folder has been <strong>changed</strong>" : "Soubor nebo adresář byl <strong>změněn</strong>", "Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>" : "Limit oznámení o tvorbě a změnách vašich <strong>oblíbených souborů</strong> <em>(Pouze streamovat)</em>", - "A file or folder has been <strong>deleted</strong>" : "Soubor nebo složka byla <strong>smazána</strong>", - "A file or folder has been <strong>restored</strong>" : "Soubor nebo složka byla <strong>obnovena</strong>", + "A file or folder has been <strong>deleted</strong>" : "Soubor nebo adresář byl <strong>smazán</strong>", + "A file or folder has been <strong>restored</strong>" : "Soubor nebo adresář byla <strong>obnoven</strong>", "You created %1$s" : "Vytvořili jste %1$s", "%2$s created %1$s" : "%2$s vytvořil(a) %1$s", "%1$s was created in a public folder" : "%1$s byl vytvořen ve veřejném adresáři", @@ -120,7 +120,7 @@ "Use this address to <a href=\"%s\" target=\"_blank\" rel=\"noreferrer\">access your Files via WebDAV</a>" : "Použijte tuto adresu pro <a href=\"%s\" target=\"_blank\" rel=\"noreferrer\">přístup ke svým Souborům přes WebDAV</a>", "No files in here" : "Žádné soubory", "Upload some content or sync with your devices!" : "Nahrajte nějaký obsah nebo synchronizujte se svými přístroji!", - "No entries found in this folder" : "V této složce nebylo nic nalezeno", + "No entries found in this folder" : "V tomto adresáři nebylo nic nalezeno", "Select all" : "Vybrat vše", "Upload too large" : "Odesílaný soubor je příliš velký", "The files you are trying to upload exceed the maximum size for file uploads on this server." : "Soubory, které se snažíte odeslat, překračují limit velikosti odesílání na tomto serveru.", diff --git a/apps/files/l10n/es.js b/apps/files/l10n/es.js index 433945d7c60..ca13a127ad7 100644 --- a/apps/files/l10n/es.js +++ b/apps/files/l10n/es.js @@ -32,10 +32,15 @@ OC.L10N.register( "Could not get result from server." : "No se pudo obtener respuesta del servidor.", "Uploading..." : "Subiendo...", "..." : "...", + "{hours}:{minutes}:{seconds} hour{plural_s} left" : "{hours}:{minutes}:{seconds} hora{plural_s} pendiente", "{hours}:{minutes}h" : "{hours}:{minutes}h", + "{minutes}:{seconds} minute{plural_s} left" : "{minutes}:{seconds} minuto{plural_s} pendiente", + "{minutes}:{seconds}m" : "{minutes}:{seconds}m", + "{seconds} second{plural_s} left" : "{seconds} segundo{plural_s} pendiente", "{seconds}s" : "{seconds}s", "Any moment now..." : "En cualquier momento...", "Soon..." : "Dentro de poco...", + "{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} de {totalSize} ({bitrate})", "File upload is in progress. Leaving the page now will cancel the upload." : "La subida del archivo está en proceso. Si sale de la página ahora, la subida será cancelada.", "Actions" : "Acciones", "Download" : "Descargar", diff --git a/apps/files/l10n/es.json b/apps/files/l10n/es.json index 57a6905a497..fd70a4da0e6 100644 --- a/apps/files/l10n/es.json +++ b/apps/files/l10n/es.json @@ -30,10 +30,15 @@ "Could not get result from server." : "No se pudo obtener respuesta del servidor.", "Uploading..." : "Subiendo...", "..." : "...", + "{hours}:{minutes}:{seconds} hour{plural_s} left" : "{hours}:{minutes}:{seconds} hora{plural_s} pendiente", "{hours}:{minutes}h" : "{hours}:{minutes}h", + "{minutes}:{seconds} minute{plural_s} left" : "{minutes}:{seconds} minuto{plural_s} pendiente", + "{minutes}:{seconds}m" : "{minutes}:{seconds}m", + "{seconds} second{plural_s} left" : "{seconds} segundo{plural_s} pendiente", "{seconds}s" : "{seconds}s", "Any moment now..." : "En cualquier momento...", "Soon..." : "Dentro de poco...", + "{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} de {totalSize} ({bitrate})", "File upload is in progress. Leaving the page now will cancel the upload." : "La subida del archivo está en proceso. Si sale de la página ahora, la subida será cancelada.", "Actions" : "Acciones", "Download" : "Descargar", diff --git a/apps/files/l10n/ja.js b/apps/files/l10n/ja.js index ff3b14dc2b4..e093a46c8aa 100644 --- a/apps/files/l10n/ja.js +++ b/apps/files/l10n/ja.js @@ -77,6 +77,7 @@ OC.L10N.register( "_%n byte_::_%n bytes_" : ["%n バイト"], "Favorited" : "お気に入り済", "Favorite" : "お気に入り", + "Local link" : "ローカルリンク", "Folder" : "フォルダー", "New folder" : "新しいフォルダー", "{newname} already exists" : "{newname} はすでに存在します", diff --git a/apps/files/l10n/ja.json b/apps/files/l10n/ja.json index 2719e9d50a5..0995d3b1e81 100644 --- a/apps/files/l10n/ja.json +++ b/apps/files/l10n/ja.json @@ -75,6 +75,7 @@ "_%n byte_::_%n bytes_" : ["%n バイト"], "Favorited" : "お気に入り済", "Favorite" : "お気に入り", + "Local link" : "ローカルリンク", "Folder" : "フォルダー", "New folder" : "新しいフォルダー", "{newname} already exists" : "{newname} はすでに存在します", diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index 55c12cc0ac9..8d2cb52d67c 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -33,8 +33,12 @@ var MOUNT_OPTIONS_DROPDOWN_TEMPLATE = ' <option value="1" selected="selected">{{t "files_external" "Once every direct access"}}</option>' + ' </select>' + ' </div>' + + ' <div class="optionRow">' + + ' <input id="mountOptionsEncoding" name="encoding_compatibility" type="checkbox" value="true"/>' + + ' <label for="mountOptionsEncoding">{{mountOptionsEncodingLabel}}</label>' + + ' </div>' + '</div>'; - + /** * Returns the selection of applicable users in the given configuration row * @@ -476,9 +480,9 @@ MountOptionsDropdown.prototype = { * * @param {Object} $container container * @param {Object} mountOptions mount options - * @param {Array} enabledOptions enabled mount options + * @param {Array} visibleOptions enabled mount options */ - show: function($container, mountOptions, enabledOptions) { + show: function($container, mountOptions, visibleOptions) { if (MountOptionsDropdown._last) { MountOptionsDropdown._last.hide(); } @@ -489,10 +493,12 @@ MountOptionsDropdown.prototype = { MountOptionsDropdown._template = template; } - var $el = $(template()); + var $el = $(template({ + mountOptionsEncodingLabel: t('files_external', 'Compatibility with Mac NFD encoding (slow)') + })); this.$el = $el; - this.setOptions(mountOptions, enabledOptions); + this.setOptions(mountOptions, visibleOptions); this.$el.appendTo($container); MountOptionsDropdown._last = this; @@ -538,9 +544,9 @@ MountOptionsDropdown.prototype = { * Sets the mount options to the dropdown controls * * @param {Object} options mount options - * @param {Array} enabledOptions enabled mount options + * @param {Array} visibleOptions enabled mount options */ - setOptions: function(options, enabledOptions) { + setOptions: function(options, visibleOptions) { var $el = this.$el; _.each(options, function(value, key) { var $optionEl = $el.find('input, select').filterAttr('name', key); @@ -556,7 +562,7 @@ MountOptionsDropdown.prototype = { $el.find('.optionRow').each(function(i, row){ var $row = $(row); var optionId = $row.find('input, select').attr('name'); - if (enabledOptions.indexOf(optionId) === -1) { + if (visibleOptions.indexOf(optionId) === -1) { $row.hide(); } else { $row.show(); @@ -883,7 +889,8 @@ MountConfigListView.prototype = _.extend({ 'encrypt': true, 'previews': true, 'enable_sharing': false, - 'filesystem_check_changes': 1 + 'filesystem_check_changes': 1, + 'encoding_compatibility': false })); } @@ -1253,11 +1260,16 @@ MountConfigListView.prototype = _.extend({ var storage = this.getStorageConfig($tr); var $toggle = $tr.find('.mountOptionsToggle'); var dropDown = new MountOptionsDropdown(); - var enabledOptions = ['previews', 'filesystem_check_changes', 'enable_sharing']; + var visibleOptions = [ + 'previews', + 'filesystem_check_changes', + 'enable_sharing', + 'encoding_compatibility' + ]; if (this._encryptionEnabled) { - enabledOptions.push('encrypt'); + visibleOptions.push('encrypt'); } - dropDown.show($toggle, storage.mountOptions || [], enabledOptions); + dropDown.show($toggle, storage.mountOptions || [], visibleOptions); $('body').on('mouseup.mountOptionsDropdown', function(event) { var $target = $(event.target); if ($toggle.has($target).length) { diff --git a/apps/files_external/l10n/cs_CZ.js b/apps/files_external/l10n/cs_CZ.js index 9906a0ce123..fdbddce7e53 100644 --- a/apps/files_external/l10n/cs_CZ.js +++ b/apps/files_external/l10n/cs_CZ.js @@ -113,7 +113,7 @@ OC.L10N.register( "Never" : "Nikdy", "Once every direct access" : "Jednou pro každý přímý přístup", "External Storage" : "Externí úložiště", - "Folder name" : "Název složky", + "Folder name" : "Název adresáře", "Authentication" : "Ověření", "Configuration" : "Nastavení", "Available for" : "Dostupné pro", diff --git a/apps/files_external/l10n/cs_CZ.json b/apps/files_external/l10n/cs_CZ.json index 69c9224c071..b485584ea6d 100644 --- a/apps/files_external/l10n/cs_CZ.json +++ b/apps/files_external/l10n/cs_CZ.json @@ -111,7 +111,7 @@ "Never" : "Nikdy", "Once every direct access" : "Jednou pro každý přímý přístup", "External Storage" : "Externí úložiště", - "Folder name" : "Název složky", + "Folder name" : "Název adresáře", "Authentication" : "Ověření", "Configuration" : "Nastavení", "Available for" : "Dostupné pro", diff --git a/apps/files_external/l10n/sl.js b/apps/files_external/l10n/sl.js index 5b58901b372..544ebf6f1ea 100644 --- a/apps/files_external/l10n/sl.js +++ b/apps/files_external/l10n/sl.js @@ -19,6 +19,7 @@ OC.L10N.register( "Insufficient data: %s" : "Nepopolni podatki: %s", "%s" : "%s", "Storage with id \"%i\" is not user editable" : "Shramba z ID \"%i\" ni uporabniško uredljiva.", + "Dropbox App Configuration" : "Nastavitve programa Dropbox", "Google Drive App Configuration" : "Nastavitve programa Google Drive", "Personal" : "Osebno", "System" : "Sistem", diff --git a/apps/files_external/l10n/sl.json b/apps/files_external/l10n/sl.json index 2bf8565b7e2..864817b4b17 100644 --- a/apps/files_external/l10n/sl.json +++ b/apps/files_external/l10n/sl.json @@ -17,6 +17,7 @@ "Insufficient data: %s" : "Nepopolni podatki: %s", "%s" : "%s", "Storage with id \"%i\" is not user editable" : "Shramba z ID \"%i\" ni uporabniško uredljiva.", + "Dropbox App Configuration" : "Nastavitve programa Dropbox", "Google Drive App Configuration" : "Nastavitve programa Google Drive", "Personal" : "Osebno", "System" : "Sistem", diff --git a/apps/files_external/tests/js/settingsSpec.js b/apps/files_external/tests/js/settingsSpec.js index 462407e9540..7aa49b2c82a 100644 --- a/apps/files_external/tests/js/settingsSpec.js +++ b/apps/files_external/tests/js/settingsSpec.js @@ -370,7 +370,8 @@ describe('OCA.External.Settings tests', function() { encrypt: true, previews: true, enable_sharing: false, - filesystem_check_changes: 0 + filesystem_check_changes: 0, + encoding_compatibility: false }); }); }); diff --git a/apps/files_sharing/api/server2server.php b/apps/files_sharing/api/server2server.php deleted file mode 100644 index 034ec5105e4..00000000000 --- a/apps/files_sharing/api/server2server.php +++ /dev/null @@ -1,325 +0,0 @@ -<?php -/** - * @author Arthur Schiwon <blizzz@owncloud.com> - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OCA\Files_Sharing\API; - -use OCA\FederatedFileSharing\DiscoveryManager; -use OCA\FederatedFileSharing\FederatedShareProvider; -use OCA\Files_Sharing\Activity; -use OCP\Files\NotFoundException; - -class Server2Server { - - /** @var FederatedShareProvider */ - private $federatedShareProvider; - - - /** - * Server2Server constructor. - * - * @param FederatedShareProvider $federatedShareProvider - */ - public function __construct(FederatedShareProvider $federatedShareProvider) { - $this->federatedShareProvider = $federatedShareProvider; - } - - /** - * create a new share - * - * @param array $params - * @return \OC_OCS_Result - */ - public function createShare($params) { - - if (!$this->isS2SEnabled(true)) { - return new \OC_OCS_Result(null, 503, 'Server does not support federated cloud sharing'); - } - - $remote = isset($_POST['remote']) ? $_POST['remote'] : null; - $token = isset($_POST['token']) ? $_POST['token'] : null; - $name = isset($_POST['name']) ? $_POST['name'] : null; - $owner = isset($_POST['owner']) ? $_POST['owner'] : null; - $shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null; - $remoteId = isset($_POST['remoteId']) ? (int)$_POST['remoteId'] : null; - - if ($remote && $token && $name && $owner && $remoteId && $shareWith) { - - if(!\OCP\Util::isValidFileName($name)) { - return new \OC_OCS_Result(null, 400, 'The mountpoint name contains invalid characters.'); - } - - // FIXME this should be a method in the user management instead - \OCP\Util::writeLog('files_sharing', 'shareWith before, ' . $shareWith, \OCP\Util::DEBUG); - \OCP\Util::emitHook( - '\OCA\Files_Sharing\API\Server2Server', - 'preLoginNameUsedAsUserName', - array('uid' => &$shareWith) - ); - \OCP\Util::writeLog('files_sharing', 'shareWith after, ' . $shareWith, \OCP\Util::DEBUG); - - if (!\OCP\User::userExists($shareWith)) { - return new \OC_OCS_Result(null, 400, 'User does not exists'); - } - - \OC_Util::setupFS($shareWith); - - $discoveryManager = new DiscoveryManager( - \OC::$server->getMemCacheFactory(), - \OC::$server->getHTTPClientService() - ); - $externalManager = new \OCA\Files_Sharing\External\Manager( - \OC::$server->getDatabaseConnection(), - \OC\Files\Filesystem::getMountManager(), - \OC\Files\Filesystem::getLoader(), - \OC::$server->getHTTPHelper(), - \OC::$server->getNotificationManager(), - $discoveryManager, - $shareWith - ); - - try { - $externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId); - $shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external'); - - $user = $owner . '@' . $this->cleanupRemote($remote); - - \OC::$server->getActivityManager()->publishActivity( - Activity::FILES_SHARING_APP, Activity::SUBJECT_REMOTE_SHARE_RECEIVED, array($user, trim($name, '/')), '', array(), - '', '', $shareWith, Activity::TYPE_REMOTE_SHARE, Activity::PRIORITY_LOW); - - $urlGenerator = \OC::$server->getURLGenerator(); - - $notificationManager = \OC::$server->getNotificationManager(); - $notification = $notificationManager->createNotification(); - $notification->setApp('files_sharing') - ->setUser($shareWith) - ->setDateTime(new \DateTime()) - ->setObject('remote_share', $shareId) - ->setSubject('remote_share', [$user, trim($name, '/')]); - - $declineAction = $notification->createAction(); - $declineAction->setLabel('decline') - ->setLink($urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'ocs/v1.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE'); - $notification->addAction($declineAction); - - $acceptAction = $notification->createAction(); - $acceptAction->setLabel('accept') - ->setLink($urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'ocs/v1.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST'); - $notification->addAction($acceptAction); - - $notificationManager->notify($notification); - - return new \OC_OCS_Result(); - } catch (\Exception $e) { - \OCP\Util::writeLog('files_sharing', 'server can not add remote share, ' . $e->getMessage(), \OCP\Util::ERROR); - return new \OC_OCS_Result(null, 500, 'internal server error, was not able to add share from ' . $remote); - } - } - - return new \OC_OCS_Result(null, 400, 'server can not add remote share, missing parameter'); - } - - /** - * accept server-to-server share - * - * @param array $params - * @return \OC_OCS_Result - */ - public function acceptShare($params) { - - if (!$this->isS2SEnabled()) { - return new \OC_OCS_Result(null, 503, 'Server does not support federated cloud sharing'); - } - - $id = $params['id']; - $token = isset($_POST['token']) ? $_POST['token'] : null; - $share = self::getShare($id, $token); - - if ($share) { - list($file, $link) = self::getFile($share['uid_owner'], $share['file_source']); - - $event = \OC::$server->getActivityManager()->generateEvent(); - $event->setApp(Activity::FILES_SHARING_APP) - ->setType(Activity::TYPE_REMOTE_SHARE) - ->setAffectedUser($share['uid_owner']) - ->setSubject(Activity::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share['share_with'], basename($file)]) - ->setObject('files', $share['file_source'], $file) - ->setLink($link); - \OC::$server->getActivityManager()->publish($event); - } - - return new \OC_OCS_Result(); - } - - /** - * decline server-to-server share - * - * @param array $params - * @return \OC_OCS_Result - */ - public function declineShare($params) { - - if (!$this->isS2SEnabled()) { - return new \OC_OCS_Result(null, 503, 'Server does not support federated cloud sharing'); - } - - $id = $params['id']; - $token = isset($_POST['token']) ? $_POST['token'] : null; - - $share = $this->getShare($id, $token); - - if ($share) { - // userId must be set to the user who unshares - \OCP\Share::unshare($share['item_type'], $share['item_source'], $share['share_type'], $share['share_with'], $share['uid_owner']); - - list($file, $link) = $this->getFile($share['uid_owner'], $share['file_source']); - - $event = \OC::$server->getActivityManager()->generateEvent(); - $event->setApp(Activity::FILES_SHARING_APP) - ->setType(Activity::TYPE_REMOTE_SHARE) - ->setAffectedUser($share['uid_owner']) - ->setSubject(Activity::SUBJECT_REMOTE_SHARE_DECLINED, [$share['share_with'], basename($file)]) - ->setObject('files', $share['file_source'], $file) - ->setLink($link); - \OC::$server->getActivityManager()->publish($event); - } - - return new \OC_OCS_Result(); - } - - /** - * remove server-to-server share if it was unshared by the owner - * - * @param array $params - * @return \OC_OCS_Result - */ - public function unshare($params) { - - if (!$this->isS2SEnabled()) { - return new \OC_OCS_Result(null, 503, 'Server does not support federated cloud sharing'); - } - - $id = $params['id']; - $token = isset($_POST['token']) ? $_POST['token'] : null; - - $query = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share_external` WHERE `remote_id` = ? AND `share_token` = ?'); - $query->execute(array($id, $token)); - $share = $query->fetchRow(); - - if ($token && $id && !empty($share)) { - - $remote = $this->cleanupRemote($share['remote']); - - $owner = $share['owner'] . '@' . $remote; - $mountpoint = $share['mountpoint']; - $user = $share['user']; - - $query = \OCP\DB::prepare('DELETE FROM `*PREFIX*share_external` WHERE `remote_id` = ? AND `share_token` = ?'); - $query->execute(array($id, $token)); - - if ($share['accepted']) { - $path = trim($mountpoint, '/'); - } else { - $path = trim($share['name'], '/'); - } - - $notificationManager = \OC::$server->getNotificationManager(); - $notification = $notificationManager->createNotification(); - $notification->setApp('files_sharing') - ->setUser($share['user']) - ->setObject('remote_share', (int) $share['id']); - $notificationManager->markProcessed($notification); - - \OC::$server->getActivityManager()->publishActivity( - Activity::FILES_SHARING_APP, Activity::SUBJECT_REMOTE_SHARE_UNSHARED, array($owner, $path), '', array(), - '', '', $user, Activity::TYPE_REMOTE_SHARE, Activity::PRIORITY_MEDIUM); - } - - return new \OC_OCS_Result(); - } - - private function cleanupRemote($remote) { - $remote = substr($remote, strpos($remote, '://') + 3); - - return rtrim($remote, '/'); - } - - /** - * get share - * - * @param int $id - * @param string $token - * @return array - */ - private function getShare($id, $token) { - $query = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `id` = ? AND `token` = ? AND `share_type` = ?'); - $query->execute(array($id, $token, \OCP\Share::SHARE_TYPE_REMOTE)); - $share = $query->fetchRow(); - - return $share; - } - - /** - * get file - * - * @param string $user - * @param int $fileSource - * @return array with internal path of the file and a absolute link to it - */ - private function getFile($user, $fileSource) { - \OC_Util::setupFS($user); - - try { - $file = \OC\Files\Filesystem::getPath($fileSource); - } catch (NotFoundException $e) { - $file = null; - } - $args = \OC\Files\Filesystem::is_dir($file) ? array('dir' => $file) : array('dir' => dirname($file), 'scrollto' => $file); - $link = \OCP\Util::linkToAbsolute('files', 'index.php', $args); - - return array($file, $link); - - } - - /** - * check if server-to-server sharing is enabled - * - * @param bool $incoming - * @return bool - */ - private function isS2SEnabled($incoming = false) { - - $result = \OCP\App::isEnabled('files_sharing'); - - if ($incoming) { - $result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled(); - } else { - $result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled(); - } - - return $result; - } - -} diff --git a/apps/files_sharing/api/share20ocs.php b/apps/files_sharing/api/share20ocs.php index af762845326..28166b943b8 100644 --- a/apps/files_sharing/api/share20ocs.php +++ b/apps/files_sharing/api/share20ocs.php @@ -99,7 +99,15 @@ class Share20OCS { */ protected function formatShare(\OCP\Share\IShare $share) { $sharedBy = $this->userManager->get($share->getSharedBy()); - $shareOwner = $this->userManager->get($share->getShareOwner()); + // for federated shares the owner can be a remote user, in this + // case we use the initiator + if ($this->userManager->userExists($share->getShareOwner())) { + $shareOwner = $this->userManager->get($share->getShareOwner()); + $localUser = $share->getShareOwner(); + } else { + $shareOwner = $this->userManager->get($share->getSharedBy()); + $localUser = $share->getSharedBy(); + } $result = [ 'id' => $share->getId(), 'share_type' => $share->getShareType(), @@ -115,7 +123,7 @@ class Share20OCS { ]; $node = $share->getNode(); - $result['path'] = $this->rootFolder->getUserFolder($share->getShareOwner())->getRelativePath($node->getPath()); + $result['path'] = $this->rootFolder->getUserFolder($localUser)->getRelativePath($node->getPath()); if ($node instanceOf \OCP\Files\Folder) { $result['item_type'] = 'folder'; } else { diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php index da573d11ec5..32eee9b6c9c 100644 --- a/apps/files_sharing/appinfo/app.php +++ b/apps/files_sharing/appinfo/app.php @@ -103,15 +103,3 @@ if ($config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes') { } } } - -$manager = \OC::$server->getNotificationManager(); -$manager->registerNotifier(function() { - return new \OCA\Files_Sharing\Notifier( - \OC::$server->getL10NFactory() - ); -}, function() use ($l) { - return [ - 'id' => 'files_sharing', - 'name' => $l->t('Federated sharing'), - ]; -}); diff --git a/apps/files_sharing/l10n/cs_CZ.js b/apps/files_sharing/l10n/cs_CZ.js index f6e937a723d..aba62f0811b 100644 --- a/apps/files_sharing/l10n/cs_CZ.js +++ b/apps/files_sharing/l10n/cs_CZ.js @@ -9,16 +9,16 @@ OC.L10N.register( "Storage not valid" : "Úložiště není platné", "Couldn't add remote share" : "Nelze přidat vzdálené úložiště", "Share API is disabled" : "Sdílení API je zakázané", - "Wrong share ID, share doesn't exist" : "Špatné sdílení ID, sdílení neexistuje", + "Wrong share ID, share doesn't exist" : "Špatné ID sdílení, sdílení neexistuje", "Could not delete share" : "Nelze smazat sdílení", - "Please specify a file or folder path" : "Prosím zadejte cestu složky nebo souboru", - "Wrong path, file/folder doesn't exist" : "Špatná cesta, soubor/složka neexistuje", + "Please specify a file or folder path" : "Prosím zadejte cestu adresáře nebo souboru", + "Wrong path, file/folder doesn't exist" : "Špatná cesta, soubor/adresář neexistuje", "Please specify a valid user" : "Prosím zadejte platného uživatele", "Group sharing is disabled by the administrator" : "Skupinové sdílení bylo zakázáno administrátorem", "Please specify a valid group" : "Prosím zadejte platnou skupinu", "Public link sharing is disabled by the administrator" : "Veřejný odkaz sdílení je zakázán administrátorem", "Public upload disabled by the administrator" : "Veřejné nahrávání zakázáno administrátorem", - "Public upload is only possible for publicly shared folders" : "Veřejné nahrávání je možné pouze pro sdílení veřejných složek", + "Public upload is only possible for publicly shared folders" : "Veřejné nahrávání je možné pouze do veřejně sdílených adresářů", "Invalid date, date format must be YYYY-MM-DD" : "Neplatné datum, formát data musí být YYY-MM-DD", "Sharing %s failed because the back end does not allow shares from type %s" : "Sdílení %s selhalo, podpůrná vrstva nepodporuje typ sdílení %s", "Unknown share type" : "Neznámý typ sdílení", @@ -47,8 +47,8 @@ OC.L10N.register( "Invalid ownCloud url" : "Neplatná ownCloud url", "Shared by" : "Sdílí", "Sharing" : "Sdílení", - "A file or folder has been <strong>shared</strong>" : "Soubor nebo složka byla <strong>nasdílena</strong>", - "A file or folder was shared from <strong>another server</strong>" : "Soubor nebo složka byla nasdílena z <strong>jiného serveru</strong>", + "A file or folder has been <strong>shared</strong>" : "Soubor nebo adresář byl <strong>nasdílen</strong>", + "A file or folder was shared from <strong>another server</strong>" : "Soubor nebo adresář byl nasdílen z <strong>jiného serveru</strong>", "A public shared file or folder was <strong>downloaded</strong>" : "Byl <strong>stažen</strong> veřejně sdílený soubor nebo adresář", "You received a new remote share %2$s from %1$s" : "Obdrželi jste nové vzdálené sdílení %2$s od uživatele %1$s", "You received a new remote share from %s" : "Obdrželi jste nové vzdálené sdílení z %s", diff --git a/apps/files_sharing/l10n/cs_CZ.json b/apps/files_sharing/l10n/cs_CZ.json index 45c81e4e4e0..74877e2f2fa 100644 --- a/apps/files_sharing/l10n/cs_CZ.json +++ b/apps/files_sharing/l10n/cs_CZ.json @@ -7,16 +7,16 @@ "Storage not valid" : "Úložiště není platné", "Couldn't add remote share" : "Nelze přidat vzdálené úložiště", "Share API is disabled" : "Sdílení API je zakázané", - "Wrong share ID, share doesn't exist" : "Špatné sdílení ID, sdílení neexistuje", + "Wrong share ID, share doesn't exist" : "Špatné ID sdílení, sdílení neexistuje", "Could not delete share" : "Nelze smazat sdílení", - "Please specify a file or folder path" : "Prosím zadejte cestu složky nebo souboru", - "Wrong path, file/folder doesn't exist" : "Špatná cesta, soubor/složka neexistuje", + "Please specify a file or folder path" : "Prosím zadejte cestu adresáře nebo souboru", + "Wrong path, file/folder doesn't exist" : "Špatná cesta, soubor/adresář neexistuje", "Please specify a valid user" : "Prosím zadejte platného uživatele", "Group sharing is disabled by the administrator" : "Skupinové sdílení bylo zakázáno administrátorem", "Please specify a valid group" : "Prosím zadejte platnou skupinu", "Public link sharing is disabled by the administrator" : "Veřejný odkaz sdílení je zakázán administrátorem", "Public upload disabled by the administrator" : "Veřejné nahrávání zakázáno administrátorem", - "Public upload is only possible for publicly shared folders" : "Veřejné nahrávání je možné pouze pro sdílení veřejných složek", + "Public upload is only possible for publicly shared folders" : "Veřejné nahrávání je možné pouze do veřejně sdílených adresářů", "Invalid date, date format must be YYYY-MM-DD" : "Neplatné datum, formát data musí být YYY-MM-DD", "Sharing %s failed because the back end does not allow shares from type %s" : "Sdílení %s selhalo, podpůrná vrstva nepodporuje typ sdílení %s", "Unknown share type" : "Neznámý typ sdílení", @@ -45,8 +45,8 @@ "Invalid ownCloud url" : "Neplatná ownCloud url", "Shared by" : "Sdílí", "Sharing" : "Sdílení", - "A file or folder has been <strong>shared</strong>" : "Soubor nebo složka byla <strong>nasdílena</strong>", - "A file or folder was shared from <strong>another server</strong>" : "Soubor nebo složka byla nasdílena z <strong>jiného serveru</strong>", + "A file or folder has been <strong>shared</strong>" : "Soubor nebo adresář byl <strong>nasdílen</strong>", + "A file or folder was shared from <strong>another server</strong>" : "Soubor nebo adresář byl nasdílen z <strong>jiného serveru</strong>", "A public shared file or folder was <strong>downloaded</strong>" : "Byl <strong>stažen</strong> veřejně sdílený soubor nebo adresář", "You received a new remote share %2$s from %1$s" : "Obdrželi jste nové vzdálené sdílení %2$s od uživatele %1$s", "You received a new remote share from %s" : "Obdrželi jste nové vzdálené sdílení z %s", diff --git a/apps/files_sharing/l10n/es.js b/apps/files_sharing/l10n/es.js index 503529b7a5b..961cf47b2f1 100644 --- a/apps/files_sharing/l10n/es.js +++ b/apps/files_sharing/l10n/es.js @@ -17,10 +17,15 @@ OC.L10N.register( "Group sharing is disabled by the administrator" : "Compartir en grupo está deshabilitado por el administrador", "Please specify a valid group" : "Por favor, especifica un grupo válido", "Public link sharing is disabled by the administrator" : "Compartir enlaces de forma pública está deshabilitado por el administrador", + "Public upload disabled by the administrator" : "La subida pública está deshabilitado por el administrador", + "Public upload is only possible for publicly shared folders" : "La subida publica solo es posible poara las carpetas publicas compartidas", "Invalid date, date format must be YYYY-MM-DD" : "Fecha inválida, el formato de las fechas debe ser YYYY-MM-DD", + "Sharing %s failed because the back end does not allow shares from type %s" : "Compartir %s ha fallado porque el repositorio no admite compartidos del tipo %s", "Unknown share type" : "Tipo desconocido de recurso compartido", "Not a directory" : "No es un directorio", + "Could not lock path" : "No se ha podido bloquear la ruta", "Can't change permissions for public share links" : "No se pueden cambiar los permisos para los enlaces de recursos compartidos públicos", + "Wrong or no update parameter given" : "No se ha suministrado un parametro correcto", "Cannot increase permissions" : "No es posible aumentar permisos", "Shared with you" : "Compartido contigo", "Shared with others" : "Compartido con otros", diff --git a/apps/files_sharing/l10n/es.json b/apps/files_sharing/l10n/es.json index ca2f1aa196f..1acacc064e7 100644 --- a/apps/files_sharing/l10n/es.json +++ b/apps/files_sharing/l10n/es.json @@ -15,10 +15,15 @@ "Group sharing is disabled by the administrator" : "Compartir en grupo está deshabilitado por el administrador", "Please specify a valid group" : "Por favor, especifica un grupo válido", "Public link sharing is disabled by the administrator" : "Compartir enlaces de forma pública está deshabilitado por el administrador", + "Public upload disabled by the administrator" : "La subida pública está deshabilitado por el administrador", + "Public upload is only possible for publicly shared folders" : "La subida publica solo es posible poara las carpetas publicas compartidas", "Invalid date, date format must be YYYY-MM-DD" : "Fecha inválida, el formato de las fechas debe ser YYYY-MM-DD", + "Sharing %s failed because the back end does not allow shares from type %s" : "Compartir %s ha fallado porque el repositorio no admite compartidos del tipo %s", "Unknown share type" : "Tipo desconocido de recurso compartido", "Not a directory" : "No es un directorio", + "Could not lock path" : "No se ha podido bloquear la ruta", "Can't change permissions for public share links" : "No se pueden cambiar los permisos para los enlaces de recursos compartidos públicos", + "Wrong or no update parameter given" : "No se ha suministrado un parametro correcto", "Cannot increase permissions" : "No es posible aumentar permisos", "Shared with you" : "Compartido contigo", "Shared with others" : "Compartido con otros", diff --git a/apps/files_sharing/l10n/sl.js b/apps/files_sharing/l10n/sl.js index c181742df7a..0b55cb1240b 100644 --- a/apps/files_sharing/l10n/sl.js +++ b/apps/files_sharing/l10n/sl.js @@ -60,6 +60,7 @@ OC.L10N.register( "You removed the share of %2$s for %1$s" : "Odstranili ste mapo v souporabi %2$s za %1$s", "You shared %1$s with group %2$s" : "Omogočili ste souporabo %1$s s skupino %2$s", "You shared %1$s via link" : "Omogočili ste souporabo %1$s preko povezave", + "Your public link for %1$s expired" : "Javna povezava za %1$s je časovno potekla!", "%2$s shared %1$s with you" : "Uporabnik %2$s je omogočil souporabo %1$s", "Downloaded via public link" : "Prejeto preko javne povezave", "Shared with %2$s" : "V souporabi z %2$s", diff --git a/apps/files_sharing/l10n/sl.json b/apps/files_sharing/l10n/sl.json index aab8c565335..947a9d609e5 100644 --- a/apps/files_sharing/l10n/sl.json +++ b/apps/files_sharing/l10n/sl.json @@ -58,6 +58,7 @@ "You removed the share of %2$s for %1$s" : "Odstranili ste mapo v souporabi %2$s za %1$s", "You shared %1$s with group %2$s" : "Omogočili ste souporabo %1$s s skupino %2$s", "You shared %1$s via link" : "Omogočili ste souporabo %1$s preko povezave", + "Your public link for %1$s expired" : "Javna povezava za %1$s je časovno potekla!", "%2$s shared %1$s with you" : "Uporabnik %2$s je omogočil souporabo %1$s", "Downloaded via public link" : "Prejeto preko javne povezave", "Shared with %2$s" : "V souporabi z %2$s", diff --git a/apps/files_sharing/lib/external/manager.php b/apps/files_sharing/lib/external/manager.php index 7dc9f66f114..5b7a13f1eb1 100644 --- a/apps/files_sharing/lib/external/manager.php +++ b/apps/files_sharing/lib/external/manager.php @@ -325,6 +325,10 @@ class Manager { } public function removeShare($mountPoint) { + + $mountPointObj = $this->mountManager->find($mountPoint); + $id = $mountPointObj->getStorage()->getCache()->getId(); + $mountPoint = $this->stripPath($mountPoint); $hash = md5($mountPoint); @@ -338,13 +342,43 @@ class Manager { $share = $getShare->fetch(); $this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'decline'); } + $getShare->closeCursor(); $query = $this->connection->prepare(' DELETE FROM `*PREFIX*share_external` WHERE `mountpoint_hash` = ? AND `user` = ? '); - return (bool)$query->execute(array($hash, $this->uid)); + $result = (bool)$query->execute(array($hash, $this->uid)); + + if($result) { + $this->removeReShares($id); + } + + return $result; + } + + /** + * remove re-shares from share table and mapping in the federated_reshares table + * + * @param $mountPointId + */ + protected function removeReShares($mountPointId) { + $selectQuery = $this->connection->getQueryBuilder(); + $query = $this->connection->getQueryBuilder(); + $selectQuery->select('id')->from('share') + ->where($selectQuery->expr()->eq('file_source', $query->createNamedParameter($mountPointId))); + $select = $selectQuery->getSQL(); + + + $query->delete('federated_reshares') + ->where($query->expr()->in('share_id', $query->createFunction('(' . $select . ')'))); + $query->execute(); + + $deleteReShares = $this->connection->getQueryBuilder(); + $deleteReShares->delete('share') + ->where($deleteReShares->expr()->eq('file_source', $deleteReShares->createNamedParameter($mountPointId))); + $deleteReShares->execute(); } /** diff --git a/apps/files_sharing/tests/api/share20ocstest.php b/apps/files_sharing/tests/api/share20ocstest.php index ffb74da2af7..96ce34f963c 100644 --- a/apps/files_sharing/tests/api/share20ocstest.php +++ b/apps/files_sharing/tests/api/share20ocstest.php @@ -82,6 +82,8 @@ class Share20OCSTest extends \Test\TestCase { $this->currentUser = $this->getMock('OCP\IUser'); $this->currentUser->method('getUID')->willReturn('currentUser'); + $this->userManager->expects($this->any())->method('userExists')->willReturn(true); + $this->l = $this->getMock('\OCP\IL10N'); $this->l->method('t') ->will($this->returnCallback(function($text, $parameters = []) { diff --git a/apps/files_trashbin/l10n/cs_CZ.js b/apps/files_trashbin/l10n/cs_CZ.js index 22c33690420..712076402f4 100644 --- a/apps/files_trashbin/l10n/cs_CZ.js +++ b/apps/files_trashbin/l10n/cs_CZ.js @@ -13,7 +13,7 @@ OC.L10N.register( "restored" : "obnoveno", "No deleted files" : "Žádné smazané soubory", "You will be able to recover deleted files from here" : "Odtud budete moci obnovovat odstraněné soubory", - "No entries found in this folder" : "V této složce nebylo nic nalezeno", + "No entries found in this folder" : "V tomto adresáři nebylo nic nalezeno", "Select all" : "Vybrat vše", "Name" : "Název", "Deleted" : "Smazáno" diff --git a/apps/files_trashbin/l10n/cs_CZ.json b/apps/files_trashbin/l10n/cs_CZ.json index a4a13942fd1..06c3b2ce096 100644 --- a/apps/files_trashbin/l10n/cs_CZ.json +++ b/apps/files_trashbin/l10n/cs_CZ.json @@ -11,7 +11,7 @@ "restored" : "obnoveno", "No deleted files" : "Žádné smazané soubory", "You will be able to recover deleted files from here" : "Odtud budete moci obnovovat odstraněné soubory", - "No entries found in this folder" : "V této složce nebylo nic nalezeno", + "No entries found in this folder" : "V tomto adresáři nebylo nic nalezeno", "Select all" : "Vybrat vše", "Name" : "Název", "Deleted" : "Smazáno" diff --git a/apps/files_trashbin/lib/Storage.php b/apps/files_trashbin/lib/Storage.php index c4c523810ac..b621c511db7 100644 --- a/apps/files_trashbin/lib/Storage.php +++ b/apps/files_trashbin/lib/Storage.php @@ -150,7 +150,7 @@ class Storage extends Wrapper { return false; } - $normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path); + $normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path, true, false, true); $result = true; $view = Filesystem::getView(); if (!isset($this->deletedFiles[$normalized]) && $view instanceof View) { diff --git a/apps/systemtags/js/systemtagsinfoview.js b/apps/systemtags/js/systemtagsinfoview.js index 2f01ca7db34..a7320a3956f 100644 --- a/apps/systemtags/js/systemtagsinfoview.js +++ b/apps/systemtags/js/systemtagsinfoview.js @@ -12,7 +12,7 @@ function modelToSelection(model) { var data = model.toJSON(); - if (!OC.isUserAdmin() && !data.userAssignable) { + if (!OC.isUserAdmin() && !data.canAssign) { data.locked = true; } return data; diff --git a/apps/systemtags/l10n/cs_CZ.js b/apps/systemtags/l10n/cs_CZ.js index 763335f74b2..2af8db9f183 100644 --- a/apps/systemtags/l10n/cs_CZ.js +++ b/apps/systemtags/l10n/cs_CZ.js @@ -21,10 +21,10 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "%1$s přiřadil systémový tag %3$s na %2$s", "You unassigned system tag %3$s from %2$s" : "Odebrali jste systémový tag %3$s z %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s odebral systémový tag %3$s ze %2$s", - "%s (not-assignable)" : "%s (nepřiřaditelný)", + "%s (restricted)" : "%s (omezeno)", "%s (invisible)" : "%s (neviditelný)", "No files in here" : "Žádné soubory", - "No entries found in this folder" : "V této složce nebylo nic nalezeno", + "No entries found in this folder" : "V tomto adresáři nebylo nic nalezeno", "Name" : "Název", "Size" : "Velikost", "Modified" : "Upraveno" diff --git a/apps/systemtags/l10n/cs_CZ.json b/apps/systemtags/l10n/cs_CZ.json index f5ba8bee780..c2c6536daa5 100644 --- a/apps/systemtags/l10n/cs_CZ.json +++ b/apps/systemtags/l10n/cs_CZ.json @@ -19,10 +19,10 @@ "%1$s assigned system tag %3$s to %2$s" : "%1$s přiřadil systémový tag %3$s na %2$s", "You unassigned system tag %3$s from %2$s" : "Odebrali jste systémový tag %3$s z %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s odebral systémový tag %3$s ze %2$s", - "%s (not-assignable)" : "%s (nepřiřaditelný)", + "%s (restricted)" : "%s (omezeno)", "%s (invisible)" : "%s (neviditelný)", "No files in here" : "Žádné soubory", - "No entries found in this folder" : "V této složce nebylo nic nalezeno", + "No entries found in this folder" : "V tomto adresáři nebylo nic nalezeno", "Name" : "Název", "Size" : "Velikost", "Modified" : "Upraveno" diff --git a/apps/systemtags/l10n/de.js b/apps/systemtags/l10n/de.js index a711863c905..d87807c0eed 100644 --- a/apps/systemtags/l10n/de.js +++ b/apps/systemtags/l10n/de.js @@ -21,7 +21,7 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "%1$s hat System-Tag %3$s an %2$s angebracht", "You unassigned system tag %3$s from %2$s" : "Du hast den System-Tag %3$s von %2$s entfernt", "%1$s unassigned system tag %3$s from %2$s" : "%1$s hat den System-Tag %3$s von %2$s entfernt", - "%s (not-assignable)" : "%s (nicht anbringbar)", + "%s (restricted)" : "%s (eingeschränkt)", "%s (invisible)" : "%s (unsichtbar)", "No files in here" : "Keine Dateien vorhanden", "No entries found in this folder" : "Keine Einträge in diesem Ordner gefunden", diff --git a/apps/systemtags/l10n/de.json b/apps/systemtags/l10n/de.json index ea38da7a0b7..ec5f81576c9 100644 --- a/apps/systemtags/l10n/de.json +++ b/apps/systemtags/l10n/de.json @@ -19,7 +19,7 @@ "%1$s assigned system tag %3$s to %2$s" : "%1$s hat System-Tag %3$s an %2$s angebracht", "You unassigned system tag %3$s from %2$s" : "Du hast den System-Tag %3$s von %2$s entfernt", "%1$s unassigned system tag %3$s from %2$s" : "%1$s hat den System-Tag %3$s von %2$s entfernt", - "%s (not-assignable)" : "%s (nicht anbringbar)", + "%s (restricted)" : "%s (eingeschränkt)", "%s (invisible)" : "%s (unsichtbar)", "No files in here" : "Keine Dateien vorhanden", "No entries found in this folder" : "Keine Einträge in diesem Ordner gefunden", diff --git a/apps/systemtags/l10n/de_DE.js b/apps/systemtags/l10n/de_DE.js index 28bbf48b1a7..9a5566f7572 100644 --- a/apps/systemtags/l10n/de_DE.js +++ b/apps/systemtags/l10n/de_DE.js @@ -21,7 +21,7 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "%1$s hat System-Tag %3$s an %2$s angebracht", "You unassigned system tag %3$s from %2$s" : "Sie haben den System-Tag %3$s von %2$s entfernt", "%1$s unassigned system tag %3$s from %2$s" : "%1$s hat den System-Tag %3$s von %2$s entfernt", - "%s (not-assignable)" : "%s (nicht anbringbar)", + "%s (restricted)" : "%s (eingeschränkt)", "%s (invisible)" : "%s (unsichtbar)", "No files in here" : "Keine Dateien vorhanden", "No entries found in this folder" : "Keine Einträge in diesem Ordner gefunden", diff --git a/apps/systemtags/l10n/de_DE.json b/apps/systemtags/l10n/de_DE.json index dacab53df53..77a5bbf0354 100644 --- a/apps/systemtags/l10n/de_DE.json +++ b/apps/systemtags/l10n/de_DE.json @@ -19,7 +19,7 @@ "%1$s assigned system tag %3$s to %2$s" : "%1$s hat System-Tag %3$s an %2$s angebracht", "You unassigned system tag %3$s from %2$s" : "Sie haben den System-Tag %3$s von %2$s entfernt", "%1$s unassigned system tag %3$s from %2$s" : "%1$s hat den System-Tag %3$s von %2$s entfernt", - "%s (not-assignable)" : "%s (nicht anbringbar)", + "%s (restricted)" : "%s (eingeschränkt)", "%s (invisible)" : "%s (unsichtbar)", "No files in here" : "Keine Dateien vorhanden", "No entries found in this folder" : "Keine Einträge in diesem Ordner gefunden", diff --git a/apps/systemtags/l10n/en_GB.js b/apps/systemtags/l10n/en_GB.js index 69ac64e5d0b..c5b5b5c0415 100644 --- a/apps/systemtags/l10n/en_GB.js +++ b/apps/systemtags/l10n/en_GB.js @@ -21,7 +21,6 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "%1$s assigned system tag %3$s to %2$s", "You unassigned system tag %3$s from %2$s" : "You unassigned system tag %3$s from %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s unassigned system tag %3$s from %2$s", - "%s (not-assignable)" : "%s (not-assignable)", "%s (invisible)" : "%s (invisible)", "No files in here" : "No files in here", "No entries found in this folder" : "No entries found in this folder", diff --git a/apps/systemtags/l10n/en_GB.json b/apps/systemtags/l10n/en_GB.json index b8700a848bf..daac670bce4 100644 --- a/apps/systemtags/l10n/en_GB.json +++ b/apps/systemtags/l10n/en_GB.json @@ -19,7 +19,6 @@ "%1$s assigned system tag %3$s to %2$s" : "%1$s assigned system tag %3$s to %2$s", "You unassigned system tag %3$s from %2$s" : "You unassigned system tag %3$s from %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s unassigned system tag %3$s from %2$s", - "%s (not-assignable)" : "%s (not-assignable)", "%s (invisible)" : "%s (invisible)", "No files in here" : "No files in here", "No entries found in this folder" : "No entries found in this folder", diff --git a/apps/systemtags/l10n/eo.js b/apps/systemtags/l10n/eo.js index c54bab71d92..6d92e4c48f9 100644 --- a/apps/systemtags/l10n/eo.js +++ b/apps/systemtags/l10n/eo.js @@ -14,7 +14,6 @@ OC.L10N.register( "%1$s updated system tag %3$s to %2$s" : "%1$s ĝisdatigis sistemetikedon %3$s al %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s atribuis sistemetikedon %3$s al %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s malatribuis sistemetikedon %3$s el %2$s", - "%s (not-assignable)" : "%s (neatribuebla)", "%s (invisible)" : "%s (nevidebla)", "No files in here" : "Neniu dosiero estas ĉi tie", "No entries found in this folder" : "Neniu enigo troviĝis en ĉi tiu dosierujo", diff --git a/apps/systemtags/l10n/eo.json b/apps/systemtags/l10n/eo.json index 5adb00df52b..e4457bb1dc3 100644 --- a/apps/systemtags/l10n/eo.json +++ b/apps/systemtags/l10n/eo.json @@ -12,7 +12,6 @@ "%1$s updated system tag %3$s to %2$s" : "%1$s ĝisdatigis sistemetikedon %3$s al %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s atribuis sistemetikedon %3$s al %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s malatribuis sistemetikedon %3$s el %2$s", - "%s (not-assignable)" : "%s (neatribuebla)", "%s (invisible)" : "%s (nevidebla)", "No files in here" : "Neniu dosiero estas ĉi tie", "No entries found in this folder" : "Neniu enigo troviĝis en ĉi tiu dosierujo", diff --git a/apps/systemtags/l10n/es.js b/apps/systemtags/l10n/es.js index 95183d5c827..d9701e07a42 100644 --- a/apps/systemtags/l10n/es.js +++ b/apps/systemtags/l10n/es.js @@ -21,7 +21,7 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "%1$s asignó la etiqueta de sistema %3$s a %2$s", "You unassigned system tag %3$s from %2$s" : "Desasignaste la etiqueta del sistema a %3$s de %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s eliminó la asignación de etiqueta de sistema %3$s de %2$s", - "%s (not-assignable)" : "%s (no asignable)", + "%s (restricted)" : "%s (restringido)", "%s (invisible)" : "%s (invisible)", "No files in here" : "Aquí no hay archivos", "No entries found in this folder" : "No hay entradas en esta carpeta", diff --git a/apps/systemtags/l10n/es.json b/apps/systemtags/l10n/es.json index 4bc5a63dd83..c310a231202 100644 --- a/apps/systemtags/l10n/es.json +++ b/apps/systemtags/l10n/es.json @@ -19,7 +19,7 @@ "%1$s assigned system tag %3$s to %2$s" : "%1$s asignó la etiqueta de sistema %3$s a %2$s", "You unassigned system tag %3$s from %2$s" : "Desasignaste la etiqueta del sistema a %3$s de %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s eliminó la asignación de etiqueta de sistema %3$s de %2$s", - "%s (not-assignable)" : "%s (no asignable)", + "%s (restricted)" : "%s (restringido)", "%s (invisible)" : "%s (invisible)", "No files in here" : "Aquí no hay archivos", "No entries found in this folder" : "No hay entradas en esta carpeta", diff --git a/apps/systemtags/l10n/et_EE.js b/apps/systemtags/l10n/et_EE.js index 0bc585a4284..9852a8adaf1 100644 --- a/apps/systemtags/l10n/et_EE.js +++ b/apps/systemtags/l10n/et_EE.js @@ -4,7 +4,6 @@ OC.L10N.register( "Tags" : "Sildid", "Tagged files" : "Sildistatud failid", "Select tags to filter by" : "Vali sildid, mille järgi filtreerida", - "%s (not-assignable)" : "%s (pole määratav)", "%s (invisible)" : "%s (nähtamatu)", "No files in here" : "Siin ei ole faile", "No entries found in this folder" : "Selles kaustast ei leitud kirjeid", diff --git a/apps/systemtags/l10n/et_EE.json b/apps/systemtags/l10n/et_EE.json index 51a1da71faf..94d6ec71d47 100644 --- a/apps/systemtags/l10n/et_EE.json +++ b/apps/systemtags/l10n/et_EE.json @@ -2,7 +2,6 @@ "Tags" : "Sildid", "Tagged files" : "Sildistatud failid", "Select tags to filter by" : "Vali sildid, mille järgi filtreerida", - "%s (not-assignable)" : "%s (pole määratav)", "%s (invisible)" : "%s (nähtamatu)", "No files in here" : "Siin ei ole faile", "No entries found in this folder" : "Selles kaustast ei leitud kirjeid", diff --git a/apps/systemtags/l10n/fr.js b/apps/systemtags/l10n/fr.js index 7ee906c5eda..eb16e88a2ec 100644 --- a/apps/systemtags/l10n/fr.js +++ b/apps/systemtags/l10n/fr.js @@ -21,7 +21,6 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "%1$s a attribué l'étiquette système %3$s à %2$s", "You unassigned system tag %3$s from %2$s" : "Vous avez retiré l'étiquette système %3$s de %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s a retiré l'étiquette système %3$s à %2$s", - "%s (not-assignable)" : "%s (non assignable)", "%s (invisible)" : "%s (invisible)", "No files in here" : "Aucun fichier", "No entries found in this folder" : "Aucune entrée trouvée dans ce dossier", diff --git a/apps/systemtags/l10n/fr.json b/apps/systemtags/l10n/fr.json index 2591bd356b0..a4f4770b06b 100644 --- a/apps/systemtags/l10n/fr.json +++ b/apps/systemtags/l10n/fr.json @@ -19,7 +19,6 @@ "%1$s assigned system tag %3$s to %2$s" : "%1$s a attribué l'étiquette système %3$s à %2$s", "You unassigned system tag %3$s from %2$s" : "Vous avez retiré l'étiquette système %3$s de %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s a retiré l'étiquette système %3$s à %2$s", - "%s (not-assignable)" : "%s (non assignable)", "%s (invisible)" : "%s (invisible)", "No files in here" : "Aucun fichier", "No entries found in this folder" : "Aucune entrée trouvée dans ce dossier", diff --git a/apps/systemtags/l10n/he.js b/apps/systemtags/l10n/he.js index 13a5a6040d0..4de8c3535cc 100644 --- a/apps/systemtags/l10n/he.js +++ b/apps/systemtags/l10n/he.js @@ -14,7 +14,6 @@ OC.L10N.register( "%1$s updated system tag %3$s to %2$s" : "%1$s עדכן/עדכנה תגית מערכת %3$s ל- %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s שייך/שייכה תגית מערכת %3$s ל- %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s הסיר/ה שיוך תגית מערכת %3$s מ- %2$s", - "%s (not-assignable)" : "%s (לא ניתן לשיוך)", "%s (invisible)" : "%s (נסתר)", "No files in here" : "אין כאן קבצים", "No entries found in this folder" : "לא נמצאו כניסות לתיקייה זו", diff --git a/apps/systemtags/l10n/he.json b/apps/systemtags/l10n/he.json index 3aa1e7a87fd..75cf6e1b05b 100644 --- a/apps/systemtags/l10n/he.json +++ b/apps/systemtags/l10n/he.json @@ -12,7 +12,6 @@ "%1$s updated system tag %3$s to %2$s" : "%1$s עדכן/עדכנה תגית מערכת %3$s ל- %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s שייך/שייכה תגית מערכת %3$s ל- %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s הסיר/ה שיוך תגית מערכת %3$s מ- %2$s", - "%s (not-assignable)" : "%s (לא ניתן לשיוך)", "%s (invisible)" : "%s (נסתר)", "No files in here" : "אין כאן קבצים", "No entries found in this folder" : "לא נמצאו כניסות לתיקייה זו", diff --git a/apps/systemtags/l10n/hu_HU.js b/apps/systemtags/l10n/hu_HU.js index 173b8ead188..13d1705ff1c 100644 --- a/apps/systemtags/l10n/hu_HU.js +++ b/apps/systemtags/l10n/hu_HU.js @@ -21,7 +21,6 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "%1$s hozzárendelte ezt a rendszer címkét: %3$s neki: %2$s", "You unassigned system tag %3$s from %2$s" : "%3$s rendszer címke hozzárendelést elvette tőle: %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s elvette ezt a rendszer címkét %3$s tőle: %2$s", - "%s (not-assignable)" : "%s (nem hozzárendelhető)", "%s (invisible)" : "%s (láthatatlan)", "No files in here" : "Itt nincsenek fájlok", "No entries found in this folder" : "Nincsenek bejegyzések ebben a könyvtárban", diff --git a/apps/systemtags/l10n/hu_HU.json b/apps/systemtags/l10n/hu_HU.json index 6e26da1767b..6408b3a5314 100644 --- a/apps/systemtags/l10n/hu_HU.json +++ b/apps/systemtags/l10n/hu_HU.json @@ -19,7 +19,6 @@ "%1$s assigned system tag %3$s to %2$s" : "%1$s hozzárendelte ezt a rendszer címkét: %3$s neki: %2$s", "You unassigned system tag %3$s from %2$s" : "%3$s rendszer címke hozzárendelést elvette tőle: %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s elvette ezt a rendszer címkét %3$s tőle: %2$s", - "%s (not-assignable)" : "%s (nem hozzárendelhető)", "%s (invisible)" : "%s (láthatatlan)", "No files in here" : "Itt nincsenek fájlok", "No entries found in this folder" : "Nincsenek bejegyzések ebben a könyvtárban", diff --git a/apps/systemtags/l10n/is.js b/apps/systemtags/l10n/is.js index bbabce076c4..079fb251f82 100644 --- a/apps/systemtags/l10n/is.js +++ b/apps/systemtags/l10n/is.js @@ -14,7 +14,6 @@ OC.L10N.register( "%1$s updated system tag %3$s to %2$s" : "%1$s uppfærði kerfismerki %3$s í %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s úthlutaði kerfismerki %3$s á %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s tók kerfismerki %3$s af %2$s", - "%s (not-assignable)" : "%s (ekki úthlutanlegt)", "%s (invisible)" : "%s (ósýnilegt)", "No files in here" : "Engar skrár hér", "No entries found in this folder" : "Engar skrár fundust í þessari möppu", diff --git a/apps/systemtags/l10n/is.json b/apps/systemtags/l10n/is.json index 5a370136580..c51cc851932 100644 --- a/apps/systemtags/l10n/is.json +++ b/apps/systemtags/l10n/is.json @@ -12,7 +12,6 @@ "%1$s updated system tag %3$s to %2$s" : "%1$s uppfærði kerfismerki %3$s í %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s úthlutaði kerfismerki %3$s á %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s tók kerfismerki %3$s af %2$s", - "%s (not-assignable)" : "%s (ekki úthlutanlegt)", "%s (invisible)" : "%s (ósýnilegt)", "No files in here" : "Engar skrár hér", "No entries found in this folder" : "Engar skrár fundust í þessari möppu", diff --git a/apps/systemtags/l10n/it.js b/apps/systemtags/l10n/it.js index d4dab4e9ee8..4a2dfc93a79 100644 --- a/apps/systemtags/l10n/it.js +++ b/apps/systemtags/l10n/it.js @@ -21,7 +21,7 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "%1$s ha assegnato il tag di sistema %3$s a %2$s", "You unassigned system tag %3$s from %2$s" : "Hai rimosso il tag di sistema %3$s da %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s ha rimosso il tag di sistema %3$s da %2$s", - "%s (not-assignable)" : "%s (non assegnabile)", + "%s (restricted)" : "%s (limitato)", "%s (invisible)" : "%s (invisibile)", "No files in here" : "Qui non c'è alcun file", "No entries found in this folder" : "Nessuna voce trovata in questa cartella", diff --git a/apps/systemtags/l10n/it.json b/apps/systemtags/l10n/it.json index 896df988962..78c96549406 100644 --- a/apps/systemtags/l10n/it.json +++ b/apps/systemtags/l10n/it.json @@ -19,7 +19,7 @@ "%1$s assigned system tag %3$s to %2$s" : "%1$s ha assegnato il tag di sistema %3$s a %2$s", "You unassigned system tag %3$s from %2$s" : "Hai rimosso il tag di sistema %3$s da %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s ha rimosso il tag di sistema %3$s da %2$s", - "%s (not-assignable)" : "%s (non assegnabile)", + "%s (restricted)" : "%s (limitato)", "%s (invisible)" : "%s (invisibile)", "No files in here" : "Qui non c'è alcun file", "No entries found in this folder" : "Nessuna voce trovata in questa cartella", diff --git a/apps/systemtags/l10n/ja.js b/apps/systemtags/l10n/ja.js index 125e2a434cb..7460665f018 100644 --- a/apps/systemtags/l10n/ja.js +++ b/apps/systemtags/l10n/ja.js @@ -21,7 +21,6 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "%1$s は、%2$s に タグ %3$s を追加", "You unassigned system tag %3$s from %2$s" : "%2$s から タグ %3$s を解除", "%1$s unassigned system tag %3$s from %2$s" : "%1$s は%2$s から タグ %3$s を解除", - "%s (not-assignable)" : "%s (追加できない)", "%s (invisible)" : "%s (不可視)", "No files in here" : "ファイルがありません", "No entries found in this folder" : "このフォルダーにはエントリーがありません", diff --git a/apps/systemtags/l10n/ja.json b/apps/systemtags/l10n/ja.json index 0b4aff337ca..6c16af20328 100644 --- a/apps/systemtags/l10n/ja.json +++ b/apps/systemtags/l10n/ja.json @@ -19,7 +19,6 @@ "%1$s assigned system tag %3$s to %2$s" : "%1$s は、%2$s に タグ %3$s を追加", "You unassigned system tag %3$s from %2$s" : "%2$s から タグ %3$s を解除", "%1$s unassigned system tag %3$s from %2$s" : "%1$s は%2$s から タグ %3$s を解除", - "%s (not-assignable)" : "%s (追加できない)", "%s (invisible)" : "%s (不可視)", "No files in here" : "ファイルがありません", "No entries found in this folder" : "このフォルダーにはエントリーがありません", diff --git a/apps/systemtags/l10n/nb_NO.js b/apps/systemtags/l10n/nb_NO.js index aeecadc80fe..06ac7b1d52c 100644 --- a/apps/systemtags/l10n/nb_NO.js +++ b/apps/systemtags/l10n/nb_NO.js @@ -14,7 +14,6 @@ OC.L10N.register( "%1$s updated system tag %3$s to %2$s" : "%1$s oppdaterte system-merkelapp %3$s til %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s festet system-merkelapp %3$s på %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s fjernet system-merkelapp %3$s fra %2$s", - "%s (not-assignable)" : "%s (ikke-brukbar)", "%s (invisible)" : "%s (usynlig)", "No files in here" : "Ingen filer her", "No entries found in this folder" : "Ingen oppføringer funnet i denne mappen", diff --git a/apps/systemtags/l10n/nb_NO.json b/apps/systemtags/l10n/nb_NO.json index 8431ea65616..35fd6643a9f 100644 --- a/apps/systemtags/l10n/nb_NO.json +++ b/apps/systemtags/l10n/nb_NO.json @@ -12,7 +12,6 @@ "%1$s updated system tag %3$s to %2$s" : "%1$s oppdaterte system-merkelapp %3$s til %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s festet system-merkelapp %3$s på %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s fjernet system-merkelapp %3$s fra %2$s", - "%s (not-assignable)" : "%s (ikke-brukbar)", "%s (invisible)" : "%s (usynlig)", "No files in here" : "Ingen filer her", "No entries found in this folder" : "Ingen oppføringer funnet i denne mappen", diff --git a/apps/systemtags/l10n/nl.js b/apps/systemtags/l10n/nl.js index f8c98435abc..3b4aa7eb56d 100644 --- a/apps/systemtags/l10n/nl.js +++ b/apps/systemtags/l10n/nl.js @@ -21,7 +21,6 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "%1$s wees systeem tag %3$s aan %2$s toe", "You unassigned system tag %3$s from %2$s" : "Je maakte toewijzing systeem tag %3$s van %2$s ongedaan", "%1$s unassigned system tag %3$s from %2$s" : "%1$s verwijderde systeem tag %3$s van %2$s", - "%s (not-assignable)" : "%s (niet toewijsbaar)", "%s (invisible)" : "%s (onzichtbaar)", "No files in here" : "Hier geen bestanden", "No entries found in this folder" : "Niets gevonden in deze map", diff --git a/apps/systemtags/l10n/nl.json b/apps/systemtags/l10n/nl.json index 0803a5a19f0..f941ce3a4a6 100644 --- a/apps/systemtags/l10n/nl.json +++ b/apps/systemtags/l10n/nl.json @@ -19,7 +19,6 @@ "%1$s assigned system tag %3$s to %2$s" : "%1$s wees systeem tag %3$s aan %2$s toe", "You unassigned system tag %3$s from %2$s" : "Je maakte toewijzing systeem tag %3$s van %2$s ongedaan", "%1$s unassigned system tag %3$s from %2$s" : "%1$s verwijderde systeem tag %3$s van %2$s", - "%s (not-assignable)" : "%s (niet toewijsbaar)", "%s (invisible)" : "%s (onzichtbaar)", "No files in here" : "Hier geen bestanden", "No entries found in this folder" : "Niets gevonden in deze map", diff --git a/apps/systemtags/l10n/pl.js b/apps/systemtags/l10n/pl.js index 1b665ee4f36..fc3616bff26 100644 --- a/apps/systemtags/l10n/pl.js +++ b/apps/systemtags/l10n/pl.js @@ -12,7 +12,6 @@ OC.L10N.register( "%1$s updated system tag %3$s to %2$s" : "%1$s zaktualizowany system etykiet%3$s do %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s przypisywalny system etykiet%3$s do %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s nieprzypisany system etykiet %3$s z %2$s", - "%s (not-assignable)" : "%s (nieprzypisalny)", "%s (invisible)" : "%s (niewidoczny)", "No files in here" : "Brak plików", "No entries found in this folder" : "Brak wpisów w tym folderze", diff --git a/apps/systemtags/l10n/pl.json b/apps/systemtags/l10n/pl.json index 781d4539f5a..543aa3be58c 100644 --- a/apps/systemtags/l10n/pl.json +++ b/apps/systemtags/l10n/pl.json @@ -10,7 +10,6 @@ "%1$s updated system tag %3$s to %2$s" : "%1$s zaktualizowany system etykiet%3$s do %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s przypisywalny system etykiet%3$s do %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s nieprzypisany system etykiet %3$s z %2$s", - "%s (not-assignable)" : "%s (nieprzypisalny)", "%s (invisible)" : "%s (niewidoczny)", "No files in here" : "Brak plików", "No entries found in this folder" : "Brak wpisów w tym folderze", diff --git a/apps/systemtags/l10n/pt_BR.js b/apps/systemtags/l10n/pt_BR.js index a66e437a17a..4032720d406 100644 --- a/apps/systemtags/l10n/pt_BR.js +++ b/apps/systemtags/l10n/pt_BR.js @@ -21,7 +21,6 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "%1$s etiqueta de sistema atribuída %3$s para %2$s", "You unassigned system tag %3$s from %2$s" : "Você eliminou a atribuição da etiqueta do sistema %3$s de %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s etiqueta de sistema não atribuída %3$s de %2$s", - "%s (not-assignable)" : "%s (intransferível)", "%s (invisible)" : "%s (invisivel)", "No files in here" : "Nenhum arquivo aqui", "No entries found in this folder" : "Nenhuma entrada foi encontrada nesta pasta", diff --git a/apps/systemtags/l10n/pt_BR.json b/apps/systemtags/l10n/pt_BR.json index 270216ef0ac..564eddead9d 100644 --- a/apps/systemtags/l10n/pt_BR.json +++ b/apps/systemtags/l10n/pt_BR.json @@ -19,7 +19,6 @@ "%1$s assigned system tag %3$s to %2$s" : "%1$s etiqueta de sistema atribuída %3$s para %2$s", "You unassigned system tag %3$s from %2$s" : "Você eliminou a atribuição da etiqueta do sistema %3$s de %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s etiqueta de sistema não atribuída %3$s de %2$s", - "%s (not-assignable)" : "%s (intransferível)", "%s (invisible)" : "%s (invisivel)", "No files in here" : "Nenhum arquivo aqui", "No entries found in this folder" : "Nenhuma entrada foi encontrada nesta pasta", diff --git a/apps/systemtags/l10n/pt_PT.js b/apps/systemtags/l10n/pt_PT.js index da277cef515..60d38d6b298 100644 --- a/apps/systemtags/l10n/pt_PT.js +++ b/apps/systemtags/l10n/pt_PT.js @@ -14,7 +14,6 @@ OC.L10N.register( "%1$s updated system tag %3$s to %2$s" : "%1$s atualizou a etiqueta %3$s para %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s atribuiu a etiqueta %3$s a %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s retirou a etiqueta %3$s a %2$s", - "%s (not-assignable)" : "%s (não atribuível)", "%s (invisible)" : "%s (invisível)", "No files in here" : "Nenhuns ficheiros aqui", "No entries found in this folder" : "Não foram encontradas entradas nesta pasta", diff --git a/apps/systemtags/l10n/pt_PT.json b/apps/systemtags/l10n/pt_PT.json index 90f7064bc26..8d5db102870 100644 --- a/apps/systemtags/l10n/pt_PT.json +++ b/apps/systemtags/l10n/pt_PT.json @@ -12,7 +12,6 @@ "%1$s updated system tag %3$s to %2$s" : "%1$s atualizou a etiqueta %3$s para %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s atribuiu a etiqueta %3$s a %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s retirou a etiqueta %3$s a %2$s", - "%s (not-assignable)" : "%s (não atribuível)", "%s (invisible)" : "%s (invisível)", "No files in here" : "Nenhuns ficheiros aqui", "No entries found in this folder" : "Não foram encontradas entradas nesta pasta", diff --git a/apps/systemtags/l10n/ro.js b/apps/systemtags/l10n/ro.js index 42bdbfef600..ebc68938d8c 100644 --- a/apps/systemtags/l10n/ro.js +++ b/apps/systemtags/l10n/ro.js @@ -21,7 +21,6 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "%1$s a atribuit eticheta de sistem %3$s la %2$s", "You unassigned system tag %3$s from %2$s" : "Ai înlăturat eticheta de sistem %3$s de la %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s a înlăturat eticheta de sistem %3$s de la %2$s", - "%s (not-assignable)" : "%s (nu este atribuibil)", "%s (invisible)" : "%s (invizibil)", "No files in here" : "Niciun fișier aici", "No entries found in this folder" : "Niciun element găsit în acest director", diff --git a/apps/systemtags/l10n/ro.json b/apps/systemtags/l10n/ro.json index cf5f378c44e..b5d8951e21c 100644 --- a/apps/systemtags/l10n/ro.json +++ b/apps/systemtags/l10n/ro.json @@ -19,7 +19,6 @@ "%1$s assigned system tag %3$s to %2$s" : "%1$s a atribuit eticheta de sistem %3$s la %2$s", "You unassigned system tag %3$s from %2$s" : "Ai înlăturat eticheta de sistem %3$s de la %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s a înlăturat eticheta de sistem %3$s de la %2$s", - "%s (not-assignable)" : "%s (nu este atribuibil)", "%s (invisible)" : "%s (invizibil)", "No files in here" : "Niciun fișier aici", "No entries found in this folder" : "Niciun element găsit în acest director", diff --git a/apps/systemtags/l10n/ru.js b/apps/systemtags/l10n/ru.js index 23080dbf5eb..8e7e6ae24c6 100644 --- a/apps/systemtags/l10n/ru.js +++ b/apps/systemtags/l10n/ru.js @@ -21,7 +21,6 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "%1$s назначил системную метку %3$s для %2$s", "You unassigned system tag %3$s from %2$s" : "Вы назначили системный тег %3$s из %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s отсоединил системную метку %3$s для %2$s", - "%s (not-assignable)" : "%s (неназначаемые)", "%s (invisible)" : "%s (невидимые)", "No files in here" : "Здесь нет файлов", "No entries found in this folder" : "Нет элементов в этом каталоге", diff --git a/apps/systemtags/l10n/ru.json b/apps/systemtags/l10n/ru.json index e7e42366aaf..2f583c4216d 100644 --- a/apps/systemtags/l10n/ru.json +++ b/apps/systemtags/l10n/ru.json @@ -19,7 +19,6 @@ "%1$s assigned system tag %3$s to %2$s" : "%1$s назначил системную метку %3$s для %2$s", "You unassigned system tag %3$s from %2$s" : "Вы назначили системный тег %3$s из %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s отсоединил системную метку %3$s для %2$s", - "%s (not-assignable)" : "%s (неназначаемые)", "%s (invisible)" : "%s (невидимые)", "No files in here" : "Здесь нет файлов", "No entries found in this folder" : "Нет элементов в этом каталоге", diff --git a/apps/systemtags/l10n/sl.js b/apps/systemtags/l10n/sl.js index cd67abe627c..727f03b8eb0 100644 --- a/apps/systemtags/l10n/sl.js +++ b/apps/systemtags/l10n/sl.js @@ -21,7 +21,7 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "Uporabnik %1$s je dodelil sistemsko oznako %3$s za %2$s", "You unassigned system tag %3$s from %2$s" : "Odstranili ste sistemsko oznako %3$s od %2$s", "%1$s unassigned system tag %3$s from %2$s" : "Uporabnik %1$s je prevzel sistemsko oznako %3$s od %2$s", - "%s (not-assignable)" : "%s (nedodeljivo)", + "%s (restricted)" : "%s (omejeno)", "%s (invisible)" : "%s (nevidno)", "No files in here" : "V mapi ni datotek", "No entries found in this folder" : "V tej mapi ni najdenih predmetov.", diff --git a/apps/systemtags/l10n/sl.json b/apps/systemtags/l10n/sl.json index e90a925ee36..6ec3bf25957 100644 --- a/apps/systemtags/l10n/sl.json +++ b/apps/systemtags/l10n/sl.json @@ -19,7 +19,7 @@ "%1$s assigned system tag %3$s to %2$s" : "Uporabnik %1$s je dodelil sistemsko oznako %3$s za %2$s", "You unassigned system tag %3$s from %2$s" : "Odstranili ste sistemsko oznako %3$s od %2$s", "%1$s unassigned system tag %3$s from %2$s" : "Uporabnik %1$s je prevzel sistemsko oznako %3$s od %2$s", - "%s (not-assignable)" : "%s (nedodeljivo)", + "%s (restricted)" : "%s (omejeno)", "%s (invisible)" : "%s (nevidno)", "No files in here" : "V mapi ni datotek", "No entries found in this folder" : "V tej mapi ni najdenih predmetov.", diff --git a/apps/systemtags/l10n/sq.js b/apps/systemtags/l10n/sq.js index f7773feed9e..573c444a83e 100644 --- a/apps/systemtags/l10n/sq.js +++ b/apps/systemtags/l10n/sq.js @@ -21,7 +21,6 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "%1$s caktoi etiketën e sistemit %3$s si %2$s", "You unassigned system tag %3$s from %2$s" : "I hoqët %2$s etiketën e sistemit %3$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s hoqi prej %2$s etiketën e sistemit %3$s", - "%s (not-assignable)" : "%s (e pacaktushme)", "%s (invisible)" : "%s (e padukshme)", "No files in here" : "S’ka kartela këtu", "No entries found in this folder" : "S’u gjetën zëra në këtë dosje", diff --git a/apps/systemtags/l10n/sq.json b/apps/systemtags/l10n/sq.json index 122b4e96ca3..82095e22c63 100644 --- a/apps/systemtags/l10n/sq.json +++ b/apps/systemtags/l10n/sq.json @@ -19,7 +19,6 @@ "%1$s assigned system tag %3$s to %2$s" : "%1$s caktoi etiketën e sistemit %3$s si %2$s", "You unassigned system tag %3$s from %2$s" : "I hoqët %2$s etiketën e sistemit %3$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s hoqi prej %2$s etiketën e sistemit %3$s", - "%s (not-assignable)" : "%s (e pacaktushme)", "%s (invisible)" : "%s (e padukshme)", "No files in here" : "S’ka kartela këtu", "No entries found in this folder" : "S’u gjetën zëra në këtë dosje", diff --git a/apps/systemtags/l10n/sr.js b/apps/systemtags/l10n/sr.js index d4a5abdf3ed..623fdf3bfa4 100644 --- a/apps/systemtags/l10n/sr.js +++ b/apps/systemtags/l10n/sr.js @@ -9,7 +9,6 @@ OC.L10N.register( "%1$s deleted system tag %2$s" : "%1$s обриса системску ознаку %2$s", "%1$s updated system tag %3$s to %2$s" : "%1$s ажурира системску ознаку %3$s на %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s додели системску ознаку %3$s на %2$s", - "%s (not-assignable)" : "%s (недодељива)", "%s (invisible)" : "%s (невидљива)", "No files in here" : "Овде нема фајлова", "No entries found in this folder" : "Нема ничега у овој фасцикли", diff --git a/apps/systemtags/l10n/sr.json b/apps/systemtags/l10n/sr.json index d4a5bd1cd9a..2ea8c679e9e 100644 --- a/apps/systemtags/l10n/sr.json +++ b/apps/systemtags/l10n/sr.json @@ -7,7 +7,6 @@ "%1$s deleted system tag %2$s" : "%1$s обриса системску ознаку %2$s", "%1$s updated system tag %3$s to %2$s" : "%1$s ажурира системску ознаку %3$s на %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s додели системску ознаку %3$s на %2$s", - "%s (not-assignable)" : "%s (недодељива)", "%s (invisible)" : "%s (невидљива)", "No files in here" : "Овде нема фајлова", "No entries found in this folder" : "Нема ничега у овој фасцикли", diff --git a/apps/systemtags/l10n/th_TH.js b/apps/systemtags/l10n/th_TH.js index b0712f32051..065d22ad448 100644 --- a/apps/systemtags/l10n/th_TH.js +++ b/apps/systemtags/l10n/th_TH.js @@ -21,7 +21,6 @@ OC.L10N.register( "%1$s assigned system tag %3$s to %2$s" : "%1$s ได้ถูกกำหนดแท็กระบบ %3$s เป็น %2$s", "You unassigned system tag %3$s from %2$s" : "คุณยังไม่ได้ได้กำหนดแท็กระบบจาก %3$s เป็น %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s ไม่ได้ถูกกำหนดแท็กระบบ %3$s เป็น %2$s", - "%s (not-assignable)" : "%s (ไม่สามารถกำหนดได้)", "%s (invisible)" : "%s (มองไม่เห็น)", "No files in here" : "ไม่มีไฟล์ที่นี่", "No entries found in this folder" : "ไม่พบรายการในโฟลเดอร์นี้", diff --git a/apps/systemtags/l10n/th_TH.json b/apps/systemtags/l10n/th_TH.json index ddefa10e6f6..ca5f7e35611 100644 --- a/apps/systemtags/l10n/th_TH.json +++ b/apps/systemtags/l10n/th_TH.json @@ -19,7 +19,6 @@ "%1$s assigned system tag %3$s to %2$s" : "%1$s ได้ถูกกำหนดแท็กระบบ %3$s เป็น %2$s", "You unassigned system tag %3$s from %2$s" : "คุณยังไม่ได้ได้กำหนดแท็กระบบจาก %3$s เป็น %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s ไม่ได้ถูกกำหนดแท็กระบบ %3$s เป็น %2$s", - "%s (not-assignable)" : "%s (ไม่สามารถกำหนดได้)", "%s (invisible)" : "%s (มองไม่เห็น)", "No files in here" : "ไม่มีไฟล์ที่นี่", "No entries found in this folder" : "ไม่พบรายการในโฟลเดอร์นี้", diff --git a/apps/systemtags/l10n/tr.js b/apps/systemtags/l10n/tr.js index a2f91dc69d4..eeb72403018 100644 --- a/apps/systemtags/l10n/tr.js +++ b/apps/systemtags/l10n/tr.js @@ -14,7 +14,6 @@ OC.L10N.register( "%1$s updated system tag %3$s to %2$s" : "%1$s, %3$s sistem etiketini %2$s olarak güncelledi", "%1$s assigned system tag %3$s to %2$s" : "%1$s, %3$s sistem etiketini %2$s etiketine atadı", "%1$s unassigned system tag %3$s from %2$s" : "%1$s, %3$s sistem etiketinin %2$s atamasını kaldırdı", - "%s (not-assignable)" : "%s (atanamaz)", "%s (invisible)" : "%s (gizli)", "No files in here" : "Burada hiç dosya yok", "No entries found in this folder" : "Bu klasörde hiçbir girdi bulunamadı", diff --git a/apps/systemtags/l10n/tr.json b/apps/systemtags/l10n/tr.json index fed4afaa130..4d29b328fde 100644 --- a/apps/systemtags/l10n/tr.json +++ b/apps/systemtags/l10n/tr.json @@ -12,7 +12,6 @@ "%1$s updated system tag %3$s to %2$s" : "%1$s, %3$s sistem etiketini %2$s olarak güncelledi", "%1$s assigned system tag %3$s to %2$s" : "%1$s, %3$s sistem etiketini %2$s etiketine atadı", "%1$s unassigned system tag %3$s from %2$s" : "%1$s, %3$s sistem etiketinin %2$s atamasını kaldırdı", - "%s (not-assignable)" : "%s (atanamaz)", "%s (invisible)" : "%s (gizli)", "No files in here" : "Burada hiç dosya yok", "No entries found in this folder" : "Bu klasörde hiçbir girdi bulunamadı", diff --git a/apps/systemtags/l10n/zh_CN.js b/apps/systemtags/l10n/zh_CN.js index cc83347bf01..7ab6541475c 100644 --- a/apps/systemtags/l10n/zh_CN.js +++ b/apps/systemtags/l10n/zh_CN.js @@ -14,7 +14,6 @@ OC.L10N.register( "%1$s updated system tag %3$s to %2$s" : "%1$s 更新了系统标签 %3$s 为 %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s 分配了系统标签 %3$s 到 %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s 取消分配系统标签 %3$s 从 %2$s", - "%s (not-assignable)" : "%s (不可分配)", "%s (invisible)" : "%s (不可见)", "No files in here" : "无文件", "No entries found in this folder" : "此文件夹中无项目", diff --git a/apps/systemtags/l10n/zh_CN.json b/apps/systemtags/l10n/zh_CN.json index d20c4c72469..b5dec5282ab 100644 --- a/apps/systemtags/l10n/zh_CN.json +++ b/apps/systemtags/l10n/zh_CN.json @@ -12,7 +12,6 @@ "%1$s updated system tag %3$s to %2$s" : "%1$s 更新了系统标签 %3$s 为 %2$s", "%1$s assigned system tag %3$s to %2$s" : "%1$s 分配了系统标签 %3$s 到 %2$s", "%1$s unassigned system tag %3$s from %2$s" : "%1$s 取消分配系统标签 %3$s 从 %2$s", - "%s (not-assignable)" : "%s (不可分配)", "%s (invisible)" : "%s (不可见)", "No files in here" : "无文件", "No entries found in this folder" : "此文件夹中无项目", diff --git a/apps/systemtags/lib/Activity/Extension.php b/apps/systemtags/lib/Activity/Extension.php index 8c101a6f550..6bb83e37cfc 100644 --- a/apps/systemtags/lib/Activity/Extension.php +++ b/apps/systemtags/lib/Activity/Extension.php @@ -324,7 +324,7 @@ class Extension implements IExtension { case 'assignable': return '<parameter>' . $matches[1] . '</parameter>'; case 'not-assignable': - return '<parameter>' . $l->t('%s (not-assignable)', $matches[1]) . '</parameter>'; + return '<parameter>' . $l->t('%s (restricted)', $matches[1]) . '</parameter>'; case 'invisible': return '<parameter>' . $l->t('%s (invisible)', $matches[1]) . '</parameter>'; } diff --git a/apps/systemtags/tests/js/systemtagsinfoviewSpec.js b/apps/systemtags/tests/js/systemtagsinfoviewSpec.js index 27724822c2e..449dfd859d7 100644 --- a/apps/systemtags/tests/js/systemtagsinfoviewSpec.js +++ b/apps/systemtags/tests/js/systemtagsinfoviewSpec.js @@ -62,9 +62,9 @@ describe('OCA.SystemTags.SystemTagsInfoView tests', function() { fetchStub.yieldTo('success', view.selectedTagsCollection); expect(setDataStub.calledOnce).toEqual(true); expect(setDataStub.getCall(0).args[0]).toEqual([{ - id: '1', name: 'test1', userVisible: true, userAssignable: true + id: '1', name: 'test1', userVisible: true, userAssignable: true, canAssign: true }, { - id: '3', name: 'test3', userVisible: true, userAssignable: true + id: '3', name: 'test3', userVisible: true, userAssignable: true, canAssign: true }]); expect(view.$el.hasClass('hidden')).toEqual(false); @@ -79,7 +79,7 @@ describe('OCA.SystemTags.SystemTagsInfoView tests', function() { view = new OCA.SystemTags.SystemTagsInfoView(); view.selectedTagsCollection.add([ {id: '1', name: 'test1'}, - {id: '3', name: 'test3', userVisible: false, userAssignable: false} + {id: '3', name: 'test3', userVisible: false, userAssignable: false, canAssign: false} ]); var callback = sinon.stub(); @@ -87,9 +87,9 @@ describe('OCA.SystemTags.SystemTagsInfoView tests', function() { expect(callback.calledOnce).toEqual(true); expect(callback.getCall(0).args[0]).toEqual([{ - id: '1', name: 'test1', userVisible: true, userAssignable: true + id: '1', name: 'test1', userVisible: true, userAssignable: true, canAssign: true }, { - id: '3', name: 'test3', userVisible: false, userAssignable: false + id: '3', name: 'test3', userVisible: false, userAssignable: false, canAssign: false }]); inputViewSpy.restore(); @@ -103,7 +103,7 @@ describe('OCA.SystemTags.SystemTagsInfoView tests', function() { view = new OCA.SystemTags.SystemTagsInfoView(); view.selectedTagsCollection.add([ {id: '1', name: 'test1'}, - {id: '3', name: 'test3', userAssignable: false} + {id: '3', name: 'test3', userAssignable: false, canAssign: false} ]); var callback = sinon.stub(); @@ -111,9 +111,33 @@ describe('OCA.SystemTags.SystemTagsInfoView tests', function() { expect(callback.calledOnce).toEqual(true); expect(callback.getCall(0).args[0]).toEqual([{ - id: '1', name: 'test1', userVisible: true, userAssignable: true + id: '1', name: 'test1', userVisible: true, userAssignable: true, canAssign: true }, { - id: '3', name: 'test3', userVisible: true, userAssignable: false, locked: true + id: '3', name: 'test3', userVisible: true, userAssignable: false, canAssign: false, locked: true + }]); + + inputViewSpy.restore(); + }); + it('does not set locked flag on non-assignable tags when canAssign overrides it with true', function() { + isAdminStub.returns(false); + + var inputViewSpy = sinon.spy(OC.SystemTags, 'SystemTagsInputField'); + var element = $('<input type="hidden" val="1,4"/>'); + view.remove(); + view = new OCA.SystemTags.SystemTagsInfoView(); + view.selectedTagsCollection.add([ + {id: '1', name: 'test1'}, + {id: '4', name: 'test4', userAssignable: false, canAssign: true} + ]); + + var callback = sinon.stub(); + inputViewSpy.getCall(0).args[0].initSelection(element, callback); + + expect(callback.calledOnce).toEqual(true); + expect(callback.getCall(0).args[0]).toEqual([{ + id: '1', name: 'test1', userVisible: true, userAssignable: true, canAssign: true + }, { + id: '4', name: 'test4', userVisible: true, userAssignable: false, canAssign: true }]); inputViewSpy.restore(); @@ -152,7 +176,8 @@ describe('OCA.SystemTags.SystemTagsInfoView tests', function() { id: '2', name: 'test2', userVisible: true, - userAssignable: true + userAssignable: true, + canAssign: true }); createStub.restore(); diff --git a/apps/user_ldap/l10n/cs_CZ.js b/apps/user_ldap/l10n/cs_CZ.js index 0392c27f2b4..7a58411c6e4 100644 --- a/apps/user_ldap/l10n/cs_CZ.js +++ b/apps/user_ldap/l10n/cs_CZ.js @@ -5,7 +5,7 @@ OC.L10N.register( "Failed to delete the server configuration" : "Selhalo smazání nastavení serveru", "The configuration is invalid: anonymous bind is not allowed." : "Tato konfigurace není platná: anonymní bind není povolen.", "The configuration is valid and the connection could be established!" : "Nastavení je v pořádku a spojení bylo navázáno.", - "The configuration is valid, but the Bind failed. Please check the server settings and credentials." : "Konfigurace je v pořádku, ale spojení selhalo. Zkontrolujte, prosím, nastavení serveru a přihlašovací údaje.", + "The configuration is valid, but the Bind failed. Please check the server settings and credentials." : "Konfigurace je v pořádku, ale spojení selhalo. Zkontrolujte prosím nastavení serveru a přihlašovací údaje.", "The configuration is invalid. Please have a look at the logs for further details." : "Konfigurace je neplatná. Pro bližší informace se podívejte do logu.", "No action specified" : "Neurčena žádná akce", "No configuration specified" : "Neurčena žádná konfigurace", @@ -107,7 +107,7 @@ OC.L10N.register( "Expert" : "Expertní", "Advanced" : "Pokročilé", "<b>Warning:</b> Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behavior. Please ask your system administrator to disable one of them." : "<b>Varování:</b> Aplikace user_ldap a user_webdavauth jsou vzájemně nekompatibilní. Můžete zaznamenat neočekávané chování. Požádejte prosím svého správce systému o zakázání jedné z nich.", - "<b>Warning:</b> The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." : "<b>Varování:</b> není nainstalován LDAP modul pro PHP, podpůrná vrstva nebude fungovat. Požádejte, prosím, správce systému, aby jej nainstaloval.", + "<b>Warning:</b> The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." : "<b>Varování:</b> není nainstalován LDAP modul pro PHP, podpůrná vrstva nebude fungovat. Požádejte prosím správce systému, aby jej nainstaloval.", "Connection Settings" : "Nastavení spojení", "Configuration Active" : "Nastavení aktivní", "When unchecked, this configuration will be skipped." : "Pokud není zaškrtnuto, bude toto nastavení přeskočeno.", @@ -146,7 +146,7 @@ OC.L10N.register( "Quota Default" : "Výchozí kvóta", "in bytes" : "v bajtech", "Email Field" : "Pole emailu", - "User Home Folder Naming Rule" : "Pravidlo pojmenování domovské složky uživatele", + "User Home Folder Naming Rule" : "Pravidlo pojmenování domovského adresáře uživatele", "Leave empty for user name (default). Otherwise, specify an LDAP/AD attribute." : "Ponechte prázdné pro uživatelské jméno (výchozí). Jinak uveďte LDAP/AD parametr.", "Internal Username" : "Interní uživatelské jméno", "By default the internal username will be created from the UUID attribute. It makes sure that the username is unique and characters do not need to be converted. The internal username has the restriction that only these characters are allowed: [ a-zA-Z0-9_.@- ]. Other characters are replaced with their ASCII correspondence or simply omitted. On collisions a number will be added/increased. The internal username is used to identify a user internally. It is also the default name for the user home folder. It is also a part of remote URLs, for instance for all *DAV services. With this setting, the default behavior can be overridden. To achieve a similar behavior as before ownCloud 5 enter the user display name attribute in the following field. Leave it empty for default behavior. Changes will have effect only on newly mapped (added) LDAP users." : "Ve výchozím nastavení bude uživatelské jméno vytvořeno z UUID atributu. To zajistí unikátnost uživatelského jména a není potřeba provádět konverzi znaků. Interní uživatelské jméno je omezeno na znaky: [ a-zA-Z0-9_.@- ]. Ostatní znaky jsou nahrazeny jejich ASCII ekvivalentem nebo jednoduše vynechány. V případě kolize uživatelských jmen bude přidáno/navýšeno číslo. Interní uživatelské jméno je používáno k interní identifikaci uživatele. Je také výchozím názvem uživatelského domovského adresáře. Je také součástí URL pro vzdálený přístup, například všech *DAV služeb. S tímto nastavením může být výchozí chování změněno. Pro dosažení podobného chování jako před ownCloudem 5 uveďte atribut zobrazovaného jména do pole níže. Ponechte prázdné pro výchozí chování. Změna bude mít vliv jen na nově namapované (přidané) uživatele z LDAP.", diff --git a/apps/user_ldap/l10n/cs_CZ.json b/apps/user_ldap/l10n/cs_CZ.json index 4bf061691c2..d8948505050 100644 --- a/apps/user_ldap/l10n/cs_CZ.json +++ b/apps/user_ldap/l10n/cs_CZ.json @@ -3,7 +3,7 @@ "Failed to delete the server configuration" : "Selhalo smazání nastavení serveru", "The configuration is invalid: anonymous bind is not allowed." : "Tato konfigurace není platná: anonymní bind není povolen.", "The configuration is valid and the connection could be established!" : "Nastavení je v pořádku a spojení bylo navázáno.", - "The configuration is valid, but the Bind failed. Please check the server settings and credentials." : "Konfigurace je v pořádku, ale spojení selhalo. Zkontrolujte, prosím, nastavení serveru a přihlašovací údaje.", + "The configuration is valid, but the Bind failed. Please check the server settings and credentials." : "Konfigurace je v pořádku, ale spojení selhalo. Zkontrolujte prosím nastavení serveru a přihlašovací údaje.", "The configuration is invalid. Please have a look at the logs for further details." : "Konfigurace je neplatná. Pro bližší informace se podívejte do logu.", "No action specified" : "Neurčena žádná akce", "No configuration specified" : "Neurčena žádná konfigurace", @@ -105,7 +105,7 @@ "Expert" : "Expertní", "Advanced" : "Pokročilé", "<b>Warning:</b> Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behavior. Please ask your system administrator to disable one of them." : "<b>Varování:</b> Aplikace user_ldap a user_webdavauth jsou vzájemně nekompatibilní. Můžete zaznamenat neočekávané chování. Požádejte prosím svého správce systému o zakázání jedné z nich.", - "<b>Warning:</b> The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." : "<b>Varování:</b> není nainstalován LDAP modul pro PHP, podpůrná vrstva nebude fungovat. Požádejte, prosím, správce systému, aby jej nainstaloval.", + "<b>Warning:</b> The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." : "<b>Varování:</b> není nainstalován LDAP modul pro PHP, podpůrná vrstva nebude fungovat. Požádejte prosím správce systému, aby jej nainstaloval.", "Connection Settings" : "Nastavení spojení", "Configuration Active" : "Nastavení aktivní", "When unchecked, this configuration will be skipped." : "Pokud není zaškrtnuto, bude toto nastavení přeskočeno.", @@ -144,7 +144,7 @@ "Quota Default" : "Výchozí kvóta", "in bytes" : "v bajtech", "Email Field" : "Pole emailu", - "User Home Folder Naming Rule" : "Pravidlo pojmenování domovské složky uživatele", + "User Home Folder Naming Rule" : "Pravidlo pojmenování domovského adresáře uživatele", "Leave empty for user name (default). Otherwise, specify an LDAP/AD attribute." : "Ponechte prázdné pro uživatelské jméno (výchozí). Jinak uveďte LDAP/AD parametr.", "Internal Username" : "Interní uživatelské jméno", "By default the internal username will be created from the UUID attribute. It makes sure that the username is unique and characters do not need to be converted. The internal username has the restriction that only these characters are allowed: [ a-zA-Z0-9_.@- ]. Other characters are replaced with their ASCII correspondence or simply omitted. On collisions a number will be added/increased. The internal username is used to identify a user internally. It is also the default name for the user home folder. It is also a part of remote URLs, for instance for all *DAV services. With this setting, the default behavior can be overridden. To achieve a similar behavior as before ownCloud 5 enter the user display name attribute in the following field. Leave it empty for default behavior. Changes will have effect only on newly mapped (added) LDAP users." : "Ve výchozím nastavení bude uživatelské jméno vytvořeno z UUID atributu. To zajistí unikátnost uživatelského jména a není potřeba provádět konverzi znaků. Interní uživatelské jméno je omezeno na znaky: [ a-zA-Z0-9_.@- ]. Ostatní znaky jsou nahrazeny jejich ASCII ekvivalentem nebo jednoduše vynechány. V případě kolize uživatelských jmen bude přidáno/navýšeno číslo. Interní uživatelské jméno je používáno k interní identifikaci uživatele. Je také výchozím názvem uživatelského domovského adresáře. Je také součástí URL pro vzdálený přístup, například všech *DAV služeb. S tímto nastavením může být výchozí chování změněno. Pro dosažení podobného chování jako před ownCloudem 5 uveďte atribut zobrazovaného jména do pole níže. Ponechte prázdné pro výchozí chování. Změna bude mít vliv jen na nově namapované (přidané) uživatele z LDAP.", diff --git a/apps/user_ldap/l10n/ro.js b/apps/user_ldap/l10n/ro.js index 292deb7ec63..dc0b56edcfd 100644 --- a/apps/user_ldap/l10n/ro.js +++ b/apps/user_ldap/l10n/ro.js @@ -3,51 +3,81 @@ OC.L10N.register( { "Failed to clear the mappings." : "Ștergerea mapărilor a eșuat.", "Failed to delete the server configuration" : "Ștergerea configurației serverului a eșuat.", - "The configuration is valid and the connection could be established!" : "Configuraţia este valida şi s-a stabilit conectarea", - "No action specified" : "Nu este specificata nici o acţiune ", - "No configuration specified" : "Nu este specificata nici o configurare ", - "No data specified" : "Nici o dată specificată", + "The configuration is valid and the connection could be established!" : "Configurația este validă și conexiunea a putut fi stabilită!", + "No action specified" : "Nu este specificată nicio acțiune ", + "No configuration specified" : "Nu este specificată nicio configurație", + "No data specified" : "Nu au fost specificate date", " Could not set configuration %s" : "Nu a putut fi setată configurația %s", "Action does not exist" : "Acțiunea nu există", + "The Base DN appears to be wrong" : "DN-ul de bază pare a fi greșit", "Testing configuration…" : "Se testează configurația...", - "Configuration incorrect" : "Configuraţie incorecta ", - "Configuration incomplete" : "Configuraţie incompleta ", - "Configuration OK" : "Configuraţie valida", - "Select groups" : "Selectaţi grupuri ", - "Do you really want to delete the current Server Configuration?" : "Sunteţi sigur ca vreţi sa ştergeţi configuraţia actuala a serverului ?", - "Confirm Deletion" : "Confirmaţi Ştergerea ", + "Configuration incorrect" : "Configurație incorectă", + "Configuration incomplete" : "Configurație incompletă", + "Configuration OK" : "Configurație validă", + "Select groups" : "Selectează grupuri ", + "Select object classes" : "Selectează clase de obiecte", + "Please check the credentials, they seem to be wrong." : "Verifică datele de autentificare, ele par a fi greșite.", + "Please specify the port, it could not be auto-detected." : "Specifică portul, nu a putut fi detectat automat.", + "Base DN could not be auto-detected, please revise credentials, host and port." : "DN-ul de bază nu a putut fi detectat automat, te rugăm revizuiește datele de autentificare, gazda și portul.", + "Could not detect Base DN, please enter it manually." : "DN-ul de bază nu a putut fi detectat, introdu-l manual.", + "{nthServer}. Server" : "{nthServer}. Server", + "More than 1,000 directory entries available." : "Mai mult de 1000 de directoare disponibile.", + "Do you really want to delete the current Server Configuration?" : "Sigur vrei să ștergi configurația curentă a serverului?", + "Confirm Deletion" : "Confirmă ștergerea", + "Mappings cleared successfully!" : "Asocierile au fost șterse!", + "Error while clearing the mappings." : "Eroare la ștergerea asocierilor.", "Select attributes" : "Selectaţi caracteristici", "_%s group found_::_%s groups found_" : ["%s grup găsit.","%s grupuri găsite.","%s grupuri găsite."], "_%s user found_::_%s users found_" : ["%s utilizator găsit.","%s utilizatori găsiți.","%s utilizatori găsiți."], + "Could not find the desired feature" : "Nu s-a putut găsi funcționalitatea dorită.", "Invalid Host" : "Host invalid", "Server" : "Server", "Users" : "Utilizatori", + "Login Attributes" : "Atribute de autentificare", "Groups" : "Grupuri", "Test Configuration" : "Configurare test", "Help" : "Ajutor", + "Available groups" : "Grupuri disponibile", + "Selected groups" : "Grupurile selectate", + "LDAP Filter:" : "Filtru LDAP:", "Other Attributes:" : "Alte caracteristici :", + "Verify settings" : "Verifică setările", + "1. Server" : "1. Server", + "%s. Server:" : "%s. Server:", + "Add a new and blank configuration" : "Adaugă o configurație nouă goală", + "Delete the current configuration" : "Șterge configurația curentă", "Host" : "Gazdă", "You can omit the protocol, except you require SSL. Then start with ldaps://" : "Puteți omite protocolul, decât dacă folosiți SSL. Atunci se începe cu ldaps://", "Port" : "Portul", - "User DN" : "DN al utilizatorului", - "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." : "DN-ul clientului utilizator cu care se va efectua conectarea, d.e. uid=agent,dc=example,dc=com. Pentru acces anonim, lăsăți DN și Parolă libere.", + "Detect Port" : "Detectează portul", + "User DN" : "DN-ul utilizatorului", + "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." : "DN-ul utilizatorului cu care se va efectua asocierea, de exemplu uid=agent,dc=example,dc=com. Pentru acces anonim, lasă DN-ul și parola libere.", "Password" : "Parolă", - "For anonymous access, leave DN and Password empty." : "Pentru acces anonim, lăsați DN și Parolă libere.", - "One Base DN per line" : "Un Base DN pe linie", - "You can specify Base DN for users and groups in the Advanced tab" : "Puteți să specificați DN de bază pentru utilizatori și grupuri în fila Avansat", + "For anonymous access, leave DN and Password empty." : "Pentru acces anonim, lasă DN-ul și parola libere.", + "One Base DN per line" : "Un DN de bază pe linie", + "You can specify Base DN for users and groups in the Advanced tab" : "Poți specifica DN-ul de bază pentru utilizatori și grupuri în fila Avansat", + "Detect Base DN" : "Detectează DN-ul de bază", + "Test Base DN" : "Testează DN-ul de bază", + "Avoids automatic LDAP requests. Better for bigger setups, but requires some LDAP knowledge." : "Evită solicitările LDAP automate. De preferat pentru instalările mai complexe, dar necesită câteva cunoștințe LDAP.", + "Manually enter LDAP filters (recommended for large directories)" : "Introdu filtrele LDAP manual (recomandat pentru medii LDAP largi)", + "Verify settings and count users" : "Verifică setările și numără utilizatorii", + "Saving" : "Se salvează", "Back" : "Înapoi", "Continue" : "Continuă", + "LDAP" : "LDAP", + "Expert" : "Expert", "Advanced" : "Avansat", "<b>Warning:</b> The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." : "<b>Atenție</b> Modulul PHP LDAP nu este instalat, infrastructura nu va funcționa. Contactează administratorul sistemului pentru al instala.", "Connection Settings" : "Setările de conexiune", - "Configuration Active" : "Configuraţie activa ", + "Configuration Active" : "Configurație activă", + "When unchecked, this configuration will be skipped." : "Dacă este debifat, se va sări peste această configurație.", "Disable Main Server" : "Dezactivaţi serverul principal", "Turn off SSL certificate validation." : "Oprește validarea certificatelor SSL ", "in seconds. A change empties the cache." : "în secunde. O schimbare curăță memoria tampon.", "Directory Settings" : "Setările directorului", "User Display Name Field" : "Câmpul cu numele vizibil al utilizatorului", - "Base User Tree" : "Arborele de bază al Utilizatorilor", - "One User Base DN per line" : "Un User Base DN pe linie", + "Base User Tree" : "Arborele de bază al utilizatorilor", + "One User Base DN per line" : "Un DN utilizator de bază pe linie", "Group Display Name Field" : "Câmpul cu numele grupului", "Base Group Tree" : "Arborele de bază al Grupurilor", "One Group Base DN per line" : "Un Group Base DN pe linie", diff --git a/apps/user_ldap/l10n/ro.json b/apps/user_ldap/l10n/ro.json index 1992542fd88..80f0c5752e9 100644 --- a/apps/user_ldap/l10n/ro.json +++ b/apps/user_ldap/l10n/ro.json @@ -1,51 +1,81 @@ { "translations": { "Failed to clear the mappings." : "Ștergerea mapărilor a eșuat.", "Failed to delete the server configuration" : "Ștergerea configurației serverului a eșuat.", - "The configuration is valid and the connection could be established!" : "Configuraţia este valida şi s-a stabilit conectarea", - "No action specified" : "Nu este specificata nici o acţiune ", - "No configuration specified" : "Nu este specificata nici o configurare ", - "No data specified" : "Nici o dată specificată", + "The configuration is valid and the connection could be established!" : "Configurația este validă și conexiunea a putut fi stabilită!", + "No action specified" : "Nu este specificată nicio acțiune ", + "No configuration specified" : "Nu este specificată nicio configurație", + "No data specified" : "Nu au fost specificate date", " Could not set configuration %s" : "Nu a putut fi setată configurația %s", "Action does not exist" : "Acțiunea nu există", + "The Base DN appears to be wrong" : "DN-ul de bază pare a fi greșit", "Testing configuration…" : "Se testează configurația...", - "Configuration incorrect" : "Configuraţie incorecta ", - "Configuration incomplete" : "Configuraţie incompleta ", - "Configuration OK" : "Configuraţie valida", - "Select groups" : "Selectaţi grupuri ", - "Do you really want to delete the current Server Configuration?" : "Sunteţi sigur ca vreţi sa ştergeţi configuraţia actuala a serverului ?", - "Confirm Deletion" : "Confirmaţi Ştergerea ", + "Configuration incorrect" : "Configurație incorectă", + "Configuration incomplete" : "Configurație incompletă", + "Configuration OK" : "Configurație validă", + "Select groups" : "Selectează grupuri ", + "Select object classes" : "Selectează clase de obiecte", + "Please check the credentials, they seem to be wrong." : "Verifică datele de autentificare, ele par a fi greșite.", + "Please specify the port, it could not be auto-detected." : "Specifică portul, nu a putut fi detectat automat.", + "Base DN could not be auto-detected, please revise credentials, host and port." : "DN-ul de bază nu a putut fi detectat automat, te rugăm revizuiește datele de autentificare, gazda și portul.", + "Could not detect Base DN, please enter it manually." : "DN-ul de bază nu a putut fi detectat, introdu-l manual.", + "{nthServer}. Server" : "{nthServer}. Server", + "More than 1,000 directory entries available." : "Mai mult de 1000 de directoare disponibile.", + "Do you really want to delete the current Server Configuration?" : "Sigur vrei să ștergi configurația curentă a serverului?", + "Confirm Deletion" : "Confirmă ștergerea", + "Mappings cleared successfully!" : "Asocierile au fost șterse!", + "Error while clearing the mappings." : "Eroare la ștergerea asocierilor.", "Select attributes" : "Selectaţi caracteristici", "_%s group found_::_%s groups found_" : ["%s grup găsit.","%s grupuri găsite.","%s grupuri găsite."], "_%s user found_::_%s users found_" : ["%s utilizator găsit.","%s utilizatori găsiți.","%s utilizatori găsiți."], + "Could not find the desired feature" : "Nu s-a putut găsi funcționalitatea dorită.", "Invalid Host" : "Host invalid", "Server" : "Server", "Users" : "Utilizatori", + "Login Attributes" : "Atribute de autentificare", "Groups" : "Grupuri", "Test Configuration" : "Configurare test", "Help" : "Ajutor", + "Available groups" : "Grupuri disponibile", + "Selected groups" : "Grupurile selectate", + "LDAP Filter:" : "Filtru LDAP:", "Other Attributes:" : "Alte caracteristici :", + "Verify settings" : "Verifică setările", + "1. Server" : "1. Server", + "%s. Server:" : "%s. Server:", + "Add a new and blank configuration" : "Adaugă o configurație nouă goală", + "Delete the current configuration" : "Șterge configurația curentă", "Host" : "Gazdă", "You can omit the protocol, except you require SSL. Then start with ldaps://" : "Puteți omite protocolul, decât dacă folosiți SSL. Atunci se începe cu ldaps://", "Port" : "Portul", - "User DN" : "DN al utilizatorului", - "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." : "DN-ul clientului utilizator cu care se va efectua conectarea, d.e. uid=agent,dc=example,dc=com. Pentru acces anonim, lăsăți DN și Parolă libere.", + "Detect Port" : "Detectează portul", + "User DN" : "DN-ul utilizatorului", + "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." : "DN-ul utilizatorului cu care se va efectua asocierea, de exemplu uid=agent,dc=example,dc=com. Pentru acces anonim, lasă DN-ul și parola libere.", "Password" : "Parolă", - "For anonymous access, leave DN and Password empty." : "Pentru acces anonim, lăsați DN și Parolă libere.", - "One Base DN per line" : "Un Base DN pe linie", - "You can specify Base DN for users and groups in the Advanced tab" : "Puteți să specificați DN de bază pentru utilizatori și grupuri în fila Avansat", + "For anonymous access, leave DN and Password empty." : "Pentru acces anonim, lasă DN-ul și parola libere.", + "One Base DN per line" : "Un DN de bază pe linie", + "You can specify Base DN for users and groups in the Advanced tab" : "Poți specifica DN-ul de bază pentru utilizatori și grupuri în fila Avansat", + "Detect Base DN" : "Detectează DN-ul de bază", + "Test Base DN" : "Testează DN-ul de bază", + "Avoids automatic LDAP requests. Better for bigger setups, but requires some LDAP knowledge." : "Evită solicitările LDAP automate. De preferat pentru instalările mai complexe, dar necesită câteva cunoștințe LDAP.", + "Manually enter LDAP filters (recommended for large directories)" : "Introdu filtrele LDAP manual (recomandat pentru medii LDAP largi)", + "Verify settings and count users" : "Verifică setările și numără utilizatorii", + "Saving" : "Se salvează", "Back" : "Înapoi", "Continue" : "Continuă", + "LDAP" : "LDAP", + "Expert" : "Expert", "Advanced" : "Avansat", "<b>Warning:</b> The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." : "<b>Atenție</b> Modulul PHP LDAP nu este instalat, infrastructura nu va funcționa. Contactează administratorul sistemului pentru al instala.", "Connection Settings" : "Setările de conexiune", - "Configuration Active" : "Configuraţie activa ", + "Configuration Active" : "Configurație activă", + "When unchecked, this configuration will be skipped." : "Dacă este debifat, se va sări peste această configurație.", "Disable Main Server" : "Dezactivaţi serverul principal", "Turn off SSL certificate validation." : "Oprește validarea certificatelor SSL ", "in seconds. A change empties the cache." : "în secunde. O schimbare curăță memoria tampon.", "Directory Settings" : "Setările directorului", "User Display Name Field" : "Câmpul cu numele vizibil al utilizatorului", - "Base User Tree" : "Arborele de bază al Utilizatorilor", - "One User Base DN per line" : "Un User Base DN pe linie", + "Base User Tree" : "Arborele de bază al utilizatorilor", + "One User Base DN per line" : "Un DN utilizator de bază pe linie", "Group Display Name Field" : "Câmpul cu numele grupului", "Base Group Tree" : "Arborele de bază al Grupurilor", "One Group Base DN per line" : "Un Group Base DN pe linie", |