summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/comments/appinfo/app.php7
-rw-r--r--apps/dav/lib/Comments/EntityCollection.php15
-rw-r--r--apps/dav/lib/Comments/EntityTypeCollection.php22
-rw-r--r--apps/dav/lib/Comments/RootCollection.php51
-rw-r--r--apps/dav/lib/RootCollection.php2
-rw-r--r--apps/dav/tests/unit/comments/entitycollection.php8
-rw-r--r--apps/dav/tests/unit/comments/entitytypecollection.php35
-rw-r--r--apps/dav/tests/unit/comments/rootcollection.php24
-rw-r--r--apps/federatedfilesharing/appinfo/app.php17
-rw-r--r--apps/federatedfilesharing/appinfo/database.xml41
-rw-r--r--apps/federatedfilesharing/appinfo/info.xml2
-rw-r--r--apps/federatedfilesharing/lib/AppInfo/Application.php3
-rw-r--r--apps/federatedfilesharing/lib/BackgroundJob/RetryJob.php (renamed from apps/federatedfilesharing/lib/BackgroundJob/UnShare.php)32
-rw-r--r--apps/federatedfilesharing/lib/FederatedShareProvider.php300
-rw-r--r--apps/federatedfilesharing/lib/Notifications.php147
-rw-r--r--apps/federatedfilesharing/lib/RequestHandler.php580
-rw-r--r--apps/federatedfilesharing/lib/notifier.php (renamed from apps/files_sharing/lib/notifier.php)14
-rw-r--r--apps/federatedfilesharing/tests/AddressHandlerTest.php3
-rw-r--r--apps/federatedfilesharing/tests/DiscoveryManagerTest.php3
-rw-r--r--apps/federatedfilesharing/tests/FederatedShareProviderTest.php116
-rw-r--r--apps/federatedfilesharing/tests/NotificationsTest.php29
-rw-r--r--apps/federatedfilesharing/tests/RequestHandlerTest.php (renamed from apps/files_sharing/tests/server2server.php)168
-rw-r--r--apps/federatedfilesharing/tests/TestCase.php132
-rw-r--r--apps/federatedfilesharing/tests/TokenHandlerTest.php3
-rw-r--r--apps/federation/lib/API/OCSAuthAPI.php (renamed from apps/federation/api/ocsauthapi.php)0
-rw-r--r--apps/federation/lib/AppInfo/Application.php (renamed from apps/federation/appinfo/application.php)0
-rw-r--r--apps/federation/lib/BackgroundJob/GetSharedSecret.php (renamed from apps/federation/backgroundjob/getsharedsecret.php)0
-rw-r--r--apps/federation/lib/BackgroundJob/RequestSharedSecret.php (renamed from apps/federation/backgroundjob/requestsharedsecret.php)0
-rw-r--r--apps/federation/lib/Command/SyncFederationAddressBooks.php (renamed from apps/federation/command/syncfederationaddressbooks.php)0
-rw-r--r--apps/federation/lib/Controller/SettingsController.php (renamed from apps/federation/controller/settingscontroller.php)0
-rw-r--r--apps/federation/lib/DAV/FedAuth.php (renamed from apps/federation/dav/fedauth.php)0
-rw-r--r--apps/federation/lib/DbHandler.php (renamed from apps/federation/lib/dbhandler.php)0
-rw-r--r--apps/federation/lib/Hooks.php (renamed from apps/federation/lib/hooks.php)0
-rw-r--r--apps/federation/lib/Middleware/AddServerMiddleware.php (renamed from apps/federation/middleware/addservermiddleware.php)2
-rw-r--r--apps/federation/lib/SyncFederationAddressBooks.php (renamed from apps/federation/lib/syncfederationaddressbooks.php)0
-rw-r--r--apps/federation/lib/SyncJob.php (renamed from apps/federation/lib/syncjob.php)0
-rw-r--r--apps/federation/lib/TrustedServers.php (renamed from apps/federation/lib/trustedservers.php)0
-rw-r--r--apps/federation/tests/API/OCSAuthAPITest.php (renamed from apps/federation/tests/api/ocsauthapitest.php)0
-rw-r--r--apps/federation/tests/BackgroundJob/GetSharedSecretTest.php (renamed from apps/federation/tests/backgroundjob/getsharedsecrettest.php)0
-rw-r--r--apps/federation/tests/BackgroundJob/RequestSharedSecretTest.php (renamed from apps/federation/tests/backgroundjob/requestsharedsecrettest.php)6
-rw-r--r--apps/federation/tests/Controller/SettingsControllerTest.php (renamed from apps/federation/tests/controller/settingscontrollertest.php)0
-rw-r--r--apps/federation/tests/DAV/FedAuthTest.php (renamed from apps/federation/tests/dav/fedauthtest.php)0
-rw-r--r--apps/federation/tests/DbHandlerTest.php (renamed from apps/federation/tests/lib/dbhandlertest.php)2
-rw-r--r--apps/federation/tests/HooksTest.php (renamed from apps/federation/tests/lib/hookstest.php)2
-rw-r--r--apps/federation/tests/Middleware/AddServerMiddlewareTest.php (renamed from apps/federation/tests/middleware/addservermiddlewaretest.php)0
-rw-r--r--apps/federation/tests/SyncFederationAddressbooksTest.php (renamed from apps/federation/tests/lib/syncfederationaddressbookstest.php)4
-rw-r--r--apps/federation/tests/TrustedServersTest.php (renamed from apps/federation/tests/lib/trustedserverstest.php)16
-rw-r--r--apps/files_external/js/settings.js36
-rw-r--r--apps/files_external/tests/js/settingsSpec.js3
-rw-r--r--apps/files_sharing/api/server2server.php325
-rw-r--r--apps/files_sharing/api/share20ocs.php12
-rw-r--r--apps/files_sharing/appinfo/app.php12
-rw-r--r--apps/files_sharing/lib/external/manager.php36
-rw-r--r--apps/files_sharing/tests/api/share20ocstest.php2
-rw-r--r--apps/files_trashbin/lib/Storage.php2
-rw-r--r--core/Command/Db/ConvertType.php70
-rw-r--r--lib/private/Authentication/Token/DefaultToken.php10
-rw-r--r--lib/private/Authentication/Token/DefaultTokenMapper.php13
-rw-r--r--lib/private/Authentication/Token/DefaultTokenProvider.php12
-rw-r--r--lib/private/Authentication/Token/IProvider.php13
-rw-r--r--lib/private/Authentication/Token/IToken.php6
-rw-r--r--lib/private/Files/Cache/Scanner.php49
-rw-r--r--lib/private/Files/Storage/Wrapper/Encoding.php533
-rw-r--r--lib/private/Server.php3
-rw-r--r--lib/private/Share20/DefaultShareProvider.php2
-rw-r--r--lib/private/Share20/Manager.php15
-rw-r--r--lib/private/Share20/ProviderFactory.php3
-rw-r--r--lib/private/Share20/Share.php17
-rw-r--r--lib/private/URLGenerator.php23
-rw-r--r--lib/private/legacy/util.php7
-rw-r--r--lib/public/Comments/CommentsEntityEvent.php76
-rw-r--r--ocs/routes.php42
-rw-r--r--settings/Application.php18
-rw-r--r--settings/Controller/AuthSettingsController.php151
-rw-r--r--settings/css/settings.css33
-rw-r--r--settings/js/authtoken.js33
-rw-r--r--settings/js/authtoken_collection.js52
-rw-r--r--settings/js/authtoken_view.js242
-rw-r--r--settings/js/personal.js7
-rw-r--r--settings/personal.php5
-rw-r--r--settings/routes.php3
-rw-r--r--settings/templates/personal.php41
-rw-r--r--tests/Core/Command/Config/App/DeleteConfigTest.php (renamed from tests/core/command/config/app/deleteconfigtest.php)0
-rw-r--r--tests/Core/Command/Config/App/GetConfigTest.php (renamed from tests/core/command/config/app/getconfigtest.php)0
-rw-r--r--tests/Core/Command/Config/App/SetConfigTest.php (renamed from tests/core/command/config/app/setconfigtest.php)0
-rw-r--r--tests/Core/Command/Config/ImportTest.php (renamed from tests/core/command/config/importtest.php)0
-rw-r--r--tests/Core/Command/Config/ListConfigsTest.php (renamed from tests/core/command/config/listconfigstest.php)0
-rw-r--r--tests/Core/Command/Config/System/DeleteConfigTest.php (renamed from tests/core/command/config/system/deleteconfigtest.php)0
-rw-r--r--tests/Core/Command/Config/System/GetConfigTest.php (renamed from tests/core/command/config/system/getconfigtest.php)0
-rw-r--r--tests/Core/Command/Config/System/SetConfigTest.php (renamed from tests/core/command/config/system/setconfigtest.php)0
-rw-r--r--tests/Core/Command/Encryption/ChangeKeyStorageRootTest.php (renamed from tests/core/command/encryption/changekeystorageroottest.php)0
-rw-r--r--tests/Core/Command/Encryption/DecryptAllTest.php (renamed from tests/core/command/encryption/decryptalltest.php)0
-rw-r--r--tests/Core/Command/Encryption/DisableTest.php (renamed from tests/core/command/encryption/disabletest.php)0
-rw-r--r--tests/Core/Command/Encryption/EnableTest.php (renamed from tests/core/command/encryption/enabletest.php)0
-rw-r--r--tests/Core/Command/Encryption/EncryptAllTest.php (renamed from tests/core/command/encryption/encryptalltest.php)0
-rw-r--r--tests/Core/Command/Encryption/SetDefaultModuleTest.php (renamed from tests/core/command/encryption/setdefaultmoduletest.php)0
-rw-r--r--tests/Core/Command/Log/ManageTest.php (renamed from tests/core/command/log/managetest.php)0
-rw-r--r--tests/Core/Command/Log/OwnCloudTest.php (renamed from tests/core/command/log/owncloudtest.php)0
-rw-r--r--tests/Core/Command/Maintenance/DataFingerprintTest.php (renamed from tests/core/command/maintenance/datafingerprinttest.php)0
-rw-r--r--tests/Core/Command/Maintenance/Mimetype/UpdateDBTest.php (renamed from tests/core/command/maintenance/mimetype/updatedbtest.php)0
-rw-r--r--tests/Core/Command/Maintenance/SingleUserTest.php (renamed from tests/core/command/maintenance/singleusertest.php)0
-rw-r--r--tests/Core/Command/User/DeleteTest.php (renamed from tests/core/command/user/deletetest.php)0
-rw-r--r--tests/Core/Command/User/LastSeenTest.php (renamed from tests/core/command/user/lastseentest.php)0
-rw-r--r--tests/Core/Controller/AvatarControllerTest.php (renamed from tests/core/controller/avatarcontrollertest.php)33
-rw-r--r--tests/Core/Controller/LoginControllerTest.php (renamed from tests/core/controller/LoginControllerTest.php)3
-rw-r--r--tests/Core/Controller/LostControllerTest.php (renamed from tests/core/controller/lostcontrollertest.php)3
-rw-r--r--tests/Core/Controller/TokenControllerTest.php (renamed from tests/core/controller/TokenControllerTest.php)3
-rw-r--r--tests/Core/Templates/TemplatesTest.php (renamed from tests/core/templates/templates.php)2
-rw-r--r--tests/Settings/Controller/AppSettingsControllerTest.php (renamed from tests/settings/controller/AppSettingsControllerTest.php)5
-rw-r--r--tests/Settings/Controller/CertificateControllerTest.php (renamed from tests/settings/controller/CertificateControllerTest.php)5
-rw-r--r--tests/Settings/Controller/CheckSetupControllerTest.php (renamed from tests/settings/controller/CheckSetupControllerTest.php)5
-rw-r--r--tests/Settings/Controller/EncryptionControllerTest.php (renamed from tests/settings/controller/EncryptionControllerTest.php)5
-rw-r--r--tests/Settings/Controller/GroupsControllerTest.php (renamed from tests/settings/controller/groupscontrollertest.php)6
-rw-r--r--tests/Settings/Controller/LogSettingsControllerTest.php (renamed from tests/settings/controller/logsettingscontrollertest.php)5
-rw-r--r--tests/Settings/Controller/MailSettingsControllerTest.php (renamed from tests/settings/controller/mailsettingscontrollertest.php)7
-rw-r--r--tests/Settings/Controller/SecuritySettingsControllerTest.php (renamed from tests/settings/controller/securitysettingscontrollertest.php)5
-rw-r--r--tests/Settings/Controller/UsersControllerTest.php (renamed from tests/settings/controller/userscontrollertest.php)5
-rw-r--r--tests/Settings/Middleware/SubadminMiddlewareTest.php (renamed from tests/settings/middleware/subadminmiddlewaretest.php)5
-rw-r--r--tests/lib/Authentication/Token/DefaultTokenMapperTest.php27
-rw-r--r--tests/lib/Authentication/Token/DefaultTokenProviderTest.php11
-rw-r--r--tests/lib/Share20/DefaultShareProviderTest.php8
-rw-r--r--tests/lib/Share20/ManagerTest.php5
-rw-r--r--tests/lib/Share20/ShareTest.php3
-rw-r--r--tests/lib/files/storage/wrapper/Encoding.php203
-rw-r--r--tests/settings/controller/AuthSettingsControllerTest.php156
125 files changed, 3536 insertions, 667 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/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/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/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/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/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_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/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/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/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/core/Command/Db/ConvertType.php b/core/Command/Db/ConvertType.php
index 864499dcce0..8c8b6350fac 100644
--- a/core/Command/Db/ConvertType.php
+++ b/core/Command/Db/ConvertType.php
@@ -105,6 +105,13 @@ class ConvertType extends Command {
InputOption::VALUE_NONE,
'whether to create schema for all apps instead of only installed apps'
)
+ ->addOption(
+ 'chunk-size',
+ null,
+ InputOption::VALUE_REQUIRED,
+ 'the maximum number of database rows to handle in a single query, bigger tables will be handled in chunks of this size. Lower this if the process runs out of memory during conversion.',
+ 1000
+ )
;
}
@@ -246,25 +253,60 @@ class ConvertType extends Command {
}
protected function copyTable(Connection $fromDB, Connection $toDB, $table, InputInterface $input, OutputInterface $output) {
+ $chunkSize = $input->getOption('chunk-size');
+
/** @var $progress \Symfony\Component\Console\Helper\ProgressHelper */
$progress = $this->getHelperSet()->get('progress');
- $query = 'SELECT COUNT(*) FROM '.$table;
- $count = $fromDB->fetchColumn($query);
- $query = 'SELECT * FROM '.$table;
- $statement = $fromDB->executeQuery($query);
+
+ $query = $fromDB->getQueryBuilder();
+ $query->automaticTablePrefix(false);
+ $query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries')
+ ->from($table);
+ $result = $query->execute();
+ $count = $result->fetchColumn();
+ $result->closeCursor();
+
+ $numChunks = ceil($count/$chunkSize);
+ if ($numChunks > 1) {
+ $output->writeln('chunked query, ' . $numChunks . ' chunks');
+ }
+
$progress->start($output, $count);
- $progress->setRedrawFrequency($count > 100 ? 5 : 1);
- while($row = $statement->fetch()) {
- $progress->advance();
- if ($input->getArgument('type') === 'oci') {
- $data = $row;
- } else {
- $data = array();
- foreach ($row as $columnName => $value) {
- $data[$toDB->quoteIdentifier($columnName)] = $value;
+ $redraw = $count > $chunkSize ? 100 : ($count > 100 ? 5 : 1);
+ $progress->setRedrawFrequency($redraw);
+
+
+ $query = $fromDB->getQueryBuilder();
+ $query->automaticTablePrefix(false);
+ $query->select('*')
+ ->from($table)
+ ->setMaxResults($chunkSize);
+
+ $insertQuery = $toDB->getQueryBuilder();
+ $insertQuery->automaticTablePrefix(false);
+ $insertQuery->insert($table);
+ $parametersCreated = false;
+
+ for ($chunk = 0; $chunk < $numChunks; $chunk++) {
+ $query->setFirstResult($chunk * $chunkSize);
+
+ $result = $query->execute();
+
+ while ($row = $result->fetch()) {
+ $progress->advance();
+ if (!$parametersCreated) {
+ foreach ($row as $key => $value) {
+ $insertQuery->setValue($key, $insertQuery->createParameter($key));
+ }
+ $parametersCreated = true;
+ }
+
+ foreach ($row as $key => $value) {
+ $insertQuery->setParameter($key, $value);
}
+ $insertQuery->execute();
}
- $toDB->insert($table, $data);
+ $result->closeCursor();
}
$progress->finish();
}
diff --git a/lib/private/Authentication/Token/DefaultToken.php b/lib/private/Authentication/Token/DefaultToken.php
index 08451a46151..4a64eacb247 100644
--- a/lib/private/Authentication/Token/DefaultToken.php
+++ b/lib/private/Authentication/Token/DefaultToken.php
@@ -28,7 +28,6 @@ use OCP\AppFramework\Db\Entity;
* @method void setId(int $id)
* @method void setUid(string $uid);
* @method void setPassword(string $password)
- * @method string getPassword()
* @method void setName(string $name)
* @method string getName()
* @method void setToken(string $token)
@@ -87,4 +86,13 @@ class DefaultToken extends Entity implements IToken {
return parent::getPassword();
}
+ public function jsonSerialize() {
+ return [
+ 'id' => $this->id,
+ 'name' => $this->name,
+ 'lastActivity' => $this->lastActivity,
+ 'type' => $this->type,
+ ];
+ }
+
}
diff --git a/lib/private/Authentication/Token/DefaultTokenMapper.php b/lib/private/Authentication/Token/DefaultTokenMapper.php
index 9f173571270..970c2242dbe 100644
--- a/lib/private/Authentication/Token/DefaultTokenMapper.php
+++ b/lib/private/Authentication/Token/DefaultTokenMapper.php
@@ -111,4 +111,17 @@ class DefaultTokenMapper extends Mapper {
return $entities;
}
+ /**
+ * @param IUser $user
+ * @param int $id
+ */
+ public function deleteById(IUser $user, $id) {
+ /* @var $qb IQueryBuilder */
+ $qb = $this->db->getQueryBuilder();
+ $qb->delete('authtoken')
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
+ ->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())));
+ $qb->execute();
+ }
+
}
diff --git a/lib/private/Authentication/Token/DefaultTokenProvider.php b/lib/private/Authentication/Token/DefaultTokenProvider.php
index 6c69d852d7b..0f7c54dab57 100644
--- a/lib/private/Authentication/Token/DefaultTokenProvider.php
+++ b/lib/private/Authentication/Token/DefaultTokenProvider.php
@@ -134,6 +134,7 @@ class DefaultTokenProvider implements IProvider {
/**
* @param IToken $savedToken
* @param string $tokenId session token
+ * @throws InvalidTokenException
* @return string
*/
public function getPassword(IToken $savedToken, $tokenId) {
@@ -150,6 +151,16 @@ class DefaultTokenProvider implements IProvider {
}
/**
+ * Invalidate (delete) the given token
+ *
+ * @param IUser $user
+ * @param int $id
+ */
+ public function invalidateTokenById(IUser $user, $id) {
+ $this->mapper->deleteById($user, $id);
+ }
+
+ /**
* Invalidate (delete) old session tokens
*/
public function invalidateOldTokens() {
@@ -203,6 +214,7 @@ class DefaultTokenProvider implements IProvider {
*
* @param string $password
* @param string $token
+ * @throws InvalidTokenException
* @return string the decrypted key
*/
private function decryptPassword($password, $token) {
diff --git a/lib/private/Authentication/Token/IProvider.php b/lib/private/Authentication/Token/IProvider.php
index a5c5faa5639..e4e4581e738 100644
--- a/lib/private/Authentication/Token/IProvider.php
+++ b/lib/private/Authentication/Token/IProvider.php
@@ -35,7 +35,7 @@ interface IProvider {
* @param string $password
* @param string $name
* @param int $type token type
- * @return DefaultToken
+ * @return IToken
*/
public function generateToken($token, $uid, $password, $name, $type = IToken::TEMPORARY_TOKEN);
@@ -47,7 +47,7 @@ interface IProvider {
* @return IToken
*/
public function getToken($tokenId) ;
-
+
/**
* @param string $token
* @throws InvalidTokenException
@@ -63,6 +63,14 @@ interface IProvider {
public function invalidateToken($token);
/**
+ * Invalidate (delete) the given token
+ *
+ * @param IUser $user
+ * @param int $id
+ */
+ public function invalidateTokenById(IUser $user, $id);
+
+ /**
* Update token activity timestamp
*
* @param IToken $token
@@ -85,6 +93,7 @@ interface IProvider {
*
* @param IToken $token
* @param string $tokenId
+ * @throws InvalidTokenException
* @return string
*/
public function getPassword(IToken $token, $tokenId);
diff --git a/lib/private/Authentication/Token/IToken.php b/lib/private/Authentication/Token/IToken.php
index 2a01ea75ea9..b741cd4ac22 100644
--- a/lib/private/Authentication/Token/IToken.php
+++ b/lib/private/Authentication/Token/IToken.php
@@ -22,7 +22,9 @@
namespace OC\Authentication\Token;
-interface IToken {
+use JsonSerializable;
+
+interface IToken extends JsonSerializable {
const TEMPORARY_TOKEN = 0;
const PERMANENT_TOKEN = 1;
@@ -30,7 +32,7 @@ interface IToken {
/**
* Get the token ID
*
- * @return string
+ * @return int
*/
public function getId();
diff --git a/lib/private/Files/Cache/Scanner.php b/lib/private/Files/Cache/Scanner.php
index 03aca1924b0..fd309a4ac45 100644
--- a/lib/private/Files/Cache/Scanner.php
+++ b/lib/private/Files/Cache/Scanner.php
@@ -341,7 +341,7 @@ class Scanner extends BasicEmitter implements IScanner {
if (is_resource($dh)) {
while (($file = readdir($dh)) !== false) {
if (!Filesystem::isIgnoredDir($file)) {
- $children[] = $file;
+ $children[] = trim(\OC\Files\Filesystem::normalizePath($file), '/');
}
}
}
@@ -355,29 +355,45 @@ class Scanner extends BasicEmitter implements IScanner {
* @param string $path
* @param bool $recursive
* @param int $reuse
- * @param array $folderData existing cache data for the folder to be scanned
+ * @param int $folderId id for the folder to be scanned
* @param bool $lock set to false to disable getting an additional read lock during scanning
* @return int the size of the scanned folder or -1 if the size is unknown at this stage
*/
- protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $folderData = null, $lock = true) {
+ protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $folderId = null, $lock = true) {
if ($reuse === -1) {
$reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG;
}
$this->emit('\OC\Files\Cache\Scanner', 'scanFolder', array($path, $this->storageId));
$size = 0;
- $childQueue = array();
- if (is_array($folderData) and isset($folderData['fileid'])) {
- $folderId = $folderData['fileid'];
- } else {
+ if (!is_null($folderId)) {
$folderId = $this->cache->getId($path);
}
+ $childQueue = $this->handleChildren($path, $recursive, $reuse, $folderId, $lock, $size);
+
+ foreach ($childQueue as $child => $childId) {
+ $childSize = $this->scanChildren($child, self::SCAN_RECURSIVE, $reuse, $childId, $lock);
+ if ($childSize === -1) {
+ $size = -1;
+ } else if ($size !== -1) {
+ $size += $childSize;
+ }
+ }
+ $this->updateCache($path, array('size' => $size), $folderId);
+ $this->emit('\OC\Files\Cache\Scanner', 'postScanFolder', array($path, $this->storageId));
+ return $size;
+ }
+
+ private function handleChildren($path, $recursive, $reuse, $folderId, $lock, &$size) {
+ // we put this in it's own function so it cleans up the memory before we start recursing
$existingChildren = $this->getExistingChildren($folderId);
$newChildren = $this->getNewChildren($path);
if ($this->useTransactions) {
\OC::$server->getDatabaseConnection()->beginTransaction();
}
+
$exceptionOccurred = false;
+ $childQueue = [];
foreach ($newChildren as $file) {
$child = ($path) ? $path . '/' . $file : $file;
try {
@@ -385,7 +401,7 @@ class Scanner extends BasicEmitter implements IScanner {
$data = $this->scanFile($child, $reuse, $folderId, $existingData, $lock);
if ($data) {
if ($data['mimetype'] === 'httpd/unix-directory' and $recursive === self::SCAN_RECURSIVE) {
- $childQueue[$child] = $data;
+ $childQueue[$child] = $data['fileid'];
} else if ($data['size'] === -1) {
$size = -1;
} else if ($size !== -1) {
@@ -420,20 +436,7 @@ class Scanner extends BasicEmitter implements IScanner {
// we reload them here
\OC::$server->getMimeTypeLoader()->reset();
}
-
- foreach ($childQueue as $child => $childData) {
- $childSize = $this->scanChildren($child, self::SCAN_RECURSIVE, $reuse, $childData, $lock);
- if ($childSize === -1) {
- $size = -1;
- } else if ($size !== -1) {
- $size += $childSize;
- }
- }
- if (!is_array($folderData) or !isset($folderData['size']) or $folderData['size'] !== $size) {
- $this->updateCache($path, array('size' => $size), $folderId);
- }
- $this->emit('\OC\Files\Cache\Scanner', 'postScanFolder', array($path, $this->storageId));
- return $size;
+ return $childQueue;
}
/**
@@ -466,7 +469,7 @@ class Scanner extends BasicEmitter implements IScanner {
} else {
$lastPath = null;
while (($path = $this->cache->getIncomplete()) !== false && $path !== $lastPath) {
- $this->runBackgroundScanJob(function() use ($path) {
+ $this->runBackgroundScanJob(function () use ($path) {
$this->scan($path, self::SCAN_RECURSIVE, self::REUSE_ETAG);
}, $path);
// FIXME: this won't proceed with the next item, needs revamping of getIncomplete()
diff --git a/lib/private/Files/Storage/Wrapper/Encoding.php b/lib/private/Files/Storage/Wrapper/Encoding.php
new file mode 100644
index 00000000000..0171dfe19b7
--- /dev/null
+++ b/lib/private/Files/Storage/Wrapper/Encoding.php
@@ -0,0 +1,533 @@
+<?php
+/**
+ * @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 OC\Files\Storage\Wrapper;
+
+use OCP\ICache;
+use OC\Cache\CappedMemoryCache;
+
+/**
+ * Encoding wrapper that deals with file names that use unsupported encodings like NFD.
+ *
+ * When applied and a UTF-8 path name was given, the wrapper will first attempt to access
+ * the actual given name and then try its NFD form.
+ */
+class Encoding extends Wrapper {
+
+ /**
+ * @var ICache
+ */
+ private $namesCache;
+
+ /**
+ * @param array $parameters
+ */
+ public function __construct($parameters) {
+ $this->storage = $parameters['storage'];
+ $this->namesCache = new CappedMemoryCache();
+ }
+
+ /**
+ * Returns whether the given string is only made of ASCII characters
+ *
+ * @param string $str string
+ *
+ * @return bool true if the string is all ASCII, false otherwise
+ */
+ private function isAscii($str) {
+ return (bool) !preg_match('/[\\x80-\\xff]+/', $str);
+ }
+
+ /**
+ * Checks whether the given path exists in NFC or NFD form after checking
+ * each form for each path section and returns the correct form.
+ * If no existing path found, returns the path as it was given.
+ *
+ * @param string $fullPath path to check
+ *
+ * @return string original or converted path
+ */
+ private function findPathToUse($fullPath) {
+ $cachedPath = $this->namesCache[$fullPath];
+ if ($cachedPath !== null) {
+ return $cachedPath;
+ }
+
+ $sections = explode('/', $fullPath);
+ $path = '';
+ foreach ($sections as $section) {
+ $convertedPath = $this->findPathToUseLastSection($path, $section);
+ if ($convertedPath === null) {
+ // no point in continuing if the section was not found, use original path
+ return $fullPath;
+ }
+ $path = $convertedPath . '/';
+ }
+ $path = rtrim($path, '/');
+ return $path;
+ }
+
+ /**
+ * Checks whether the last path section of the given path exists in NFC or NFD form
+ * and returns the correct form. If no existing path found, returns null.
+ *
+ * @param string $basePath base path to check
+ * @param string $lastSection last section of the path to check for NFD/NFC variations
+ *
+ * @return string|null original or converted path, or null if none of the forms was found
+ */
+ private function findPathToUseLastSection($basePath, $lastSection) {
+ $fullPath = $basePath . $lastSection;
+ if ($lastSection === '' || $this->isAscii($lastSection) || $this->storage->file_exists($fullPath)) {
+ $this->namesCache[$fullPath] = $fullPath;
+ return $fullPath;
+ }
+
+ // swap encoding
+ if (\Normalizer::isNormalized($lastSection, \Normalizer::FORM_C)) {
+ $otherFormPath = \Normalizer::normalize($lastSection, \Normalizer::FORM_D);
+ } else {
+ $otherFormPath = \Normalizer::normalize($lastSection, \Normalizer::FORM_C);
+ }
+ $otherFullPath = $basePath . $otherFormPath;
+ if ($this->storage->file_exists($otherFullPath)) {
+ $this->namesCache[$fullPath] = $otherFullPath;
+ return $otherFullPath;
+ }
+
+ // return original path, file did not exist at all
+ $this->namesCache[$fullPath] = $fullPath;
+ return null;
+ }
+
+ /**
+ * see http://php.net/manual/en/function.mkdir.php
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function mkdir($path) {
+ // note: no conversion here, method should not be called with non-NFC names!
+ $result = $this->storage->mkdir($path);
+ if ($result) {
+ $this->namesCache[$path] = $path;
+ }
+ return $result;
+ }
+
+ /**
+ * see http://php.net/manual/en/function.rmdir.php
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function rmdir($path) {
+ $result = $this->storage->rmdir($this->findPathToUse($path));
+ if ($result) {
+ unset($this->namesCache[$path]);
+ }
+ return $result;
+ }
+
+ /**
+ * see http://php.net/manual/en/function.opendir.php
+ *
+ * @param string $path
+ * @return resource
+ */
+ public function opendir($path) {
+ return $this->storage->opendir($this->findPathToUse($path));
+ }
+
+ /**
+ * see http://php.net/manual/en/function.is_dir.php
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function is_dir($path) {
+ return $this->storage->is_dir($this->findPathToUse($path));
+ }
+
+ /**
+ * see http://php.net/manual/en/function.is_file.php
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function is_file($path) {
+ return $this->storage->is_file($this->findPathToUse($path));
+ }
+
+ /**
+ * see http://php.net/manual/en/function.stat.php
+ * only the following keys are required in the result: size and mtime
+ *
+ * @param string $path
+ * @return array
+ */
+ public function stat($path) {
+ return $this->storage->stat($this->findPathToUse($path));
+ }
+
+ /**
+ * see http://php.net/manual/en/function.filetype.php
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function filetype($path) {
+ return $this->storage->filetype($this->findPathToUse($path));
+ }
+
+ /**
+ * see http://php.net/manual/en/function.filesize.php
+ * The result for filesize when called on a folder is required to be 0
+ *
+ * @param string $path
+ * @return int
+ */
+ public function filesize($path) {
+ return $this->storage->filesize($this->findPathToUse($path));
+ }
+
+ /**
+ * check if a file can be created in $path
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function isCreatable($path) {
+ return $this->storage->isCreatable($this->findPathToUse($path));
+ }
+
+ /**
+ * check if a file can be read
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function isReadable($path) {
+ return $this->storage->isReadable($this->findPathToUse($path));
+ }
+
+ /**
+ * check if a file can be written to
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function isUpdatable($path) {
+ return $this->storage->isUpdatable($this->findPathToUse($path));
+ }
+
+ /**
+ * check if a file can be deleted
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function isDeletable($path) {
+ return $this->storage->isDeletable($this->findPathToUse($path));
+ }
+
+ /**
+ * check if a file can be shared
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function isSharable($path) {
+ return $this->storage->isSharable($this->findPathToUse($path));
+ }
+
+ /**
+ * get the full permissions of a path.
+ * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php
+ *
+ * @param string $path
+ * @return int
+ */
+ public function getPermissions($path) {
+ return $this->storage->getPermissions($this->findPathToUse($path));
+ }
+
+ /**
+ * see http://php.net/manual/en/function.file_exists.php
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function file_exists($path) {
+ return $this->storage->file_exists($this->findPathToUse($path));
+ }
+
+ /**
+ * see http://php.net/manual/en/function.filemtime.php
+ *
+ * @param string $path
+ * @return int
+ */
+ public function filemtime($path) {
+ return $this->storage->filemtime($this->findPathToUse($path));
+ }
+
+ /**
+ * see http://php.net/manual/en/function.file_get_contents.php
+ *
+ * @param string $path
+ * @return string
+ */
+ public function file_get_contents($path) {
+ return $this->storage->file_get_contents($this->findPathToUse($path));
+ }
+
+ /**
+ * see http://php.net/manual/en/function.file_put_contents.php
+ *
+ * @param string $path
+ * @param string $data
+ * @return bool
+ */
+ public function file_put_contents($path, $data) {
+ return $this->storage->file_put_contents($this->findPathToUse($path), $data);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.unlink.php
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function unlink($path) {
+ $result = $this->storage->unlink($this->findPathToUse($path));
+ if ($result) {
+ unset($this->namesCache[$path]);
+ }
+ return $result;
+ }
+
+ /**
+ * see http://php.net/manual/en/function.rename.php
+ *
+ * @param string $path1
+ * @param string $path2
+ * @return bool
+ */
+ public function rename($path1, $path2) {
+ // second name always NFC
+ return $this->storage->rename($this->findPathToUse($path1), $this->findPathToUse($path2));
+ }
+
+ /**
+ * see http://php.net/manual/en/function.copy.php
+ *
+ * @param string $path1
+ * @param string $path2
+ * @return bool
+ */
+ public function copy($path1, $path2) {
+ return $this->storage->copy($this->findPathToUse($path1), $this->findPathToUse($path2));
+ }
+
+ /**
+ * see http://php.net/manual/en/function.fopen.php
+ *
+ * @param string $path
+ * @param string $mode
+ * @return resource
+ */
+ public function fopen($path, $mode) {
+ $result = $this->storage->fopen($this->findPathToUse($path), $mode);
+ if ($result && $mode !== 'r' && $mode !== 'rb') {
+ unset($this->namesCache[$path]);
+ }
+ return $result;
+ }
+
+ /**
+ * get the mimetype for a file or folder
+ * The mimetype for a folder is required to be "httpd/unix-directory"
+ *
+ * @param string $path
+ * @return string
+ */
+ public function getMimeType($path) {
+ return $this->storage->getMimeType($this->findPathToUse($path));
+ }
+
+ /**
+ * see http://php.net/manual/en/function.hash.php
+ *
+ * @param string $type
+ * @param string $path
+ * @param bool $raw
+ * @return string
+ */
+ public function hash($type, $path, $raw = false) {
+ return $this->storage->hash($type, $this->findPathToUse($path), $raw);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.free_space.php
+ *
+ * @param string $path
+ * @return int
+ */
+ public function free_space($path) {
+ return $this->storage->free_space($this->findPathToUse($path));
+ }
+
+ /**
+ * search for occurrences of $query in file names
+ *
+ * @param string $query
+ * @return array
+ */
+ public function search($query) {
+ return $this->storage->search($query);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.touch.php
+ * If the backend does not support the operation, false should be returned
+ *
+ * @param string $path
+ * @param int $mtime
+ * @return bool
+ */
+ public function touch($path, $mtime = null) {
+ return $this->storage->touch($this->findPathToUse($path), $mtime);
+ }
+
+ /**
+ * get the path to a local version of the file.
+ * The local version of the file can be temporary and doesn't have to be persistent across requests
+ *
+ * @param string $path
+ * @return string
+ */
+ public function getLocalFile($path) {
+ return $this->storage->getLocalFile($this->findPathToUse($path));
+ }
+
+ /**
+ * check if a file or folder has been updated since $time
+ *
+ * @param string $path
+ * @param int $time
+ * @return bool
+ *
+ * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
+ * returning true for other changes in the folder is optional
+ */
+ public function hasUpdated($path, $time) {
+ return $this->storage->hasUpdated($this->findPathToUse($path), $time);
+ }
+
+ /**
+ * get a cache instance for the storage
+ *
+ * @param string $path
+ * @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache
+ * @return \OC\Files\Cache\Cache
+ */
+ public function getCache($path = '', $storage = null) {
+ if (!$storage) {
+ $storage = $this;
+ }
+ return $this->storage->getCache($this->findPathToUse($path), $storage);
+ }
+
+ /**
+ * get a scanner instance for the storage
+ *
+ * @param string $path
+ * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
+ * @return \OC\Files\Cache\Scanner
+ */
+ public function getScanner($path = '', $storage = null) {
+ if (!$storage) {
+ $storage = $this;
+ }
+ return $this->storage->getScanner($this->findPathToUse($path), $storage);
+ }
+
+ /**
+ * get the ETag for a file or folder
+ *
+ * @param string $path
+ * @return string
+ */
+ public function getETag($path) {
+ return $this->storage->getETag($this->findPathToUse($path));
+ }
+
+ /**
+ * @param \OCP\Files\Storage $sourceStorage
+ * @param string $sourceInternalPath
+ * @param string $targetInternalPath
+ * @return bool
+ */
+ public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ if ($sourceStorage === $this) {
+ return $this->copy($sourceInternalPath, $this->findPathToUse($targetInternalPath));
+ }
+
+ $result = $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $this->findPathToUse($targetInternalPath));
+ if ($result) {
+ unset($this->namesCache[$targetInternalPath]);
+ }
+ return $result;
+ }
+
+ /**
+ * @param \OCP\Files\Storage $sourceStorage
+ * @param string $sourceInternalPath
+ * @param string $targetInternalPath
+ * @return bool
+ */
+ public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ if ($sourceStorage === $this) {
+ $result = $this->rename($sourceInternalPath, $this->findPathToUse($targetInternalPath));
+ if ($result) {
+ unset($this->namesCache[$sourceInternalPath]);
+ unset($this->namesCache[$targetInternalPath]);
+ }
+ return $result;
+ }
+
+ $result = $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $this->findPathToUse($targetInternalPath));
+ if ($result) {
+ unset($this->namesCache[$sourceInternalPath]);
+ unset($this->namesCache[$targetInternalPath]);
+ }
+ return $result;
+ }
+
+ /**
+ * @param string $path
+ * @return array
+ */
+ public function getMetaData($path) {
+ return $this->storage->getMetaData($this->findPathToUse($path));
+ }
+}
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 0b7b8f9e403..ea0c436d84b 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -223,6 +223,7 @@ class Server extends ServerContainer implements IServerContainer {
$timeFactory = new TimeFactory();
return new \OC\Authentication\Token\DefaultTokenProvider($mapper, $crypto, $config, $logger, $timeFactory);
});
+ $this->registerAlias('OC\Authentication\Token\IProvider', 'OC\Authentication\Token\DefaultTokenProvider');
$this->registerService('UserSession', function (Server $c) {
$manager = $c->getUserManager();
$session = new \OC\Session\Memory('');
@@ -230,7 +231,7 @@ class Server extends ServerContainer implements IServerContainer {
// Token providers might require a working database. This code
// might however be called when ownCloud is not yet setup.
if (\OC::$server->getSystemConfig()->getValue('installed', false)) {
- $defaultTokenProvider = $c->query('OC\Authentication\Token\DefaultTokenProvider');
+ $defaultTokenProvider = $c->query('OC\Authentication\Token\IProvider');
} else {
$defaultTokenProvider = null;
}
diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php
index f0de39fdad3..8a39c18a495 100644
--- a/lib/private/Share20/DefaultShareProvider.php
+++ b/lib/private/Share20/DefaultShareProvider.php
@@ -733,7 +733,7 @@ class DefaultShareProvider implements IShareProvider {
* @throws InvalidShare
*/
private function createShare($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/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php
index dee9e0cdd21..3568995472a 100644
--- a/lib/private/Share20/Manager.php
+++ b/lib/private/Share20/Manager.php
@@ -201,7 +201,12 @@ class Manager implements IManager {
}
// And you can't share your rootfolder
- if ($this->rootFolder->getUserFolder($share->getSharedBy())->getPath() === $share->getNode()->getPath()) {
+ if ($this->userManager->userExists($share->getSharedBy())) {
+ $sharedPath = $this->rootFolder->getUserFolder($share->getSharedBy())->getPath();
+ } else {
+ $sharedPath = $this->rootFolder->getUserFolder($share->getShareOwner())->getPath();
+ }
+ if ($sharedPath === $share->getNode()->getPath()) {
throw new \InvalidArgumentException('You can\'t share your root folder');
}
@@ -713,7 +718,11 @@ class Manager implements IManager {
}
if ($share->getPermissions() !== $originalShare->getPermissions()) {
- $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
+ if ($this->userManager->userExists($share->getShareOwner())) {
+ $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
+ } else {
+ $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
+ }
\OC_Hook::emit('OCP\Share', 'post_update_permissions', array(
'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
'itemSource' => $share->getNode()->getId(),
@@ -1107,7 +1116,7 @@ class Manager implements IManager {
* @return \OCP\Share\IShare;
*/
public function newShare() {
- return new \OC\Share20\Share($this->rootFolder);
+ return new \OC\Share20\Share($this->rootFolder, $this->userManager);
}
/**
diff --git a/lib/private/Share20/ProviderFactory.php b/lib/private/Share20/ProviderFactory.php
index 0bedfb84fc7..b436a7bc5f3 100644
--- a/lib/private/Share20/ProviderFactory.php
+++ b/lib/private/Share20/ProviderFactory.php
@@ -115,7 +115,8 @@ class ProviderFactory implements IProviderFactory {
$l,
$this->serverContainer->getLogger(),
$this->serverContainer->getLazyRootFolder(),
- $this->serverContainer->getConfig()
+ $this->serverContainer->getConfig(),
+ $this->serverContainer->getUserManager()
);
}
diff --git a/lib/private/Share20/Share.php b/lib/private/Share20/Share.php
index c361f01216f..f56fd94b409 100644
--- a/lib/private/Share20/Share.php
+++ b/lib/private/Share20/Share.php
@@ -24,8 +24,7 @@ use OCP\Files\File;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
-use OCP\IUser;
-use OCP\IGroup;
+use OCP\IUserManager;
use OCP\Share\Exceptions\IllegalIDChangeException;
class Share implements \OCP\Share\IShare {
@@ -68,8 +67,12 @@ class Share implements \OCP\Share\IShare {
/** @var IRootFolder */
private $rootFolder;
- public function __construct(IRootFolder $rootFolder) {
+ /** @var IUserManager */
+ private $userManager;
+
+ public function __construct(IRootFolder $rootFolder, IUserManager $userManager) {
$this->rootFolder = $rootFolder;
+ $this->userManager = $userManager;
}
/**
@@ -145,7 +148,13 @@ class Share implements \OCP\Share\IShare {
throw new NotFoundException();
}
- $userFolder = $this->rootFolder->getUserFolder($this->shareOwner);
+ // for federated shares the owner can be a remote user, in this
+ // case we use the initiator
+ if($this->userManager->userExists($this->shareOwner)) {
+ $userFolder = $this->rootFolder->getUserFolder($this->shareOwner);
+ } else {
+ $userFolder = $this->rootFolder->getUserFolder($this->sharedBy);
+ }
$nodes = $userFolder->getById($this->fileId);
if (empty($nodes)) {
diff --git a/lib/private/URLGenerator.php b/lib/private/URLGenerator.php
index 327c0c32dfe..9c4b0ff0864 100644
--- a/lib/private/URLGenerator.php
+++ b/lib/private/URLGenerator.php
@@ -159,28 +159,31 @@ class URLGenerator implements IURLGenerator {
} elseif (!file_exists(\OC::$SERVERROOT . "/themes/$theme/apps/$app/img/$basename.svg")
&& file_exists(\OC::$SERVERROOT . "/themes/$theme/apps/$app/img/$basename.png")) {
$path = \OC::$WEBROOT . "/themes/$theme/apps/$app/img/$basename.png";
- } elseif ($appPath && file_exists($appPath . "/img/$image")) {
- $path = \OC_App::getAppWebPath($app) . "/img/$image";
- } elseif ($appPath && !file_exists($appPath . "/img/$basename.svg")
- && file_exists($appPath . "/img/$basename.png")) {
- $path = \OC_App::getAppWebPath($app) . "/img/$basename.png";
} elseif (!empty($app) and file_exists(\OC::$SERVERROOT . "/themes/$theme/$app/img/$image")) {
$path = \OC::$WEBROOT . "/themes/$theme/$app/img/$image";
} elseif (!empty($app) and (!file_exists(\OC::$SERVERROOT . "/themes/$theme/$app/img/$basename.svg")
&& file_exists(\OC::$SERVERROOT . "/themes/$theme/$app/img/$basename.png"))) {
$path = \OC::$WEBROOT . "/themes/$theme/$app/img/$basename.png";
- } elseif (!empty($app) and file_exists(\OC::$SERVERROOT . "/$app/img/$image")) {
- $path = \OC::$WEBROOT . "/$app/img/$image";
- } elseif (!empty($app) and (!file_exists(\OC::$SERVERROOT . "/$app/img/$basename.svg")
- && file_exists(\OC::$SERVERROOT . "/$app/img/$basename.png"))) {
- $path = \OC::$WEBROOT . "/$app/img/$basename.png";
} elseif (file_exists(\OC::$SERVERROOT . "/themes/$theme/core/img/$image")) {
$path = \OC::$WEBROOT . "/themes/$theme/core/img/$image";
} elseif (!file_exists(\OC::$SERVERROOT . "/themes/$theme/core/img/$basename.svg")
&& file_exists(\OC::$SERVERROOT . "/themes/$theme/core/img/$basename.png")) {
$path = \OC::$WEBROOT . "/themes/$theme/core/img/$basename.png";
+ } elseif ($appPath && file_exists($appPath . "/img/$image")) {
+ $path = \OC_App::getAppWebPath($app) . "/img/$image";
+ } elseif ($appPath && !file_exists($appPath . "/img/$basename.svg")
+ && file_exists($appPath . "/img/$basename.png")) {
+ $path = \OC_App::getAppWebPath($app) . "/img/$basename.png";
+ } elseif (!empty($app) and file_exists(\OC::$SERVERROOT . "/$app/img/$image")) {
+ $path = \OC::$WEBROOT . "/$app/img/$image";
+ } elseif (!empty($app) and (!file_exists(\OC::$SERVERROOT . "/$app/img/$basename.svg")
+ && file_exists(\OC::$SERVERROOT . "/$app/img/$basename.png"))) {
+ $path = \OC::$WEBROOT . "/$app/img/$basename.png";
} elseif (file_exists(\OC::$SERVERROOT . "/core/img/$image")) {
$path = \OC::$WEBROOT . "/core/img/$image";
+ } elseif (!file_exists(\OC::$SERVERROOT . "/core/img/$basename.svg")
+ && file_exists(\OC::$SERVERROOT . "/core/img/$basename.png")) {
+ $path = \OC::$WEBROOT . "/themes/$theme/core/img/$basename.png";
}
if($path !== '') {
diff --git a/lib/private/legacy/util.php b/lib/private/legacy/util.php
index 4f7a8668dfc..de97a762246 100644
--- a/lib/private/legacy/util.php
+++ b/lib/private/legacy/util.php
@@ -172,6 +172,13 @@ class OC_Util {
return $storage;
});
+ \OC\Files\Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
+ if ($mount->getOption('encoding_compatibility', true) && !$storage->instanceOfStorage('\OC\Files\Storage\Shared') && !$storage->isLocal()) {
+ return new \OC\Files\Storage\Wrapper\Encoding(['storage' => $storage]);
+ }
+ return $storage;
+ });
+
\OC\Files\Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
// set up quota for home storages, even for other users
// which can happen when using sharing
diff --git a/lib/public/Comments/CommentsEntityEvent.php b/lib/public/Comments/CommentsEntityEvent.php
new file mode 100644
index 00000000000..5f012a79885
--- /dev/null
+++ b/lib/public/Comments/CommentsEntityEvent.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@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 OCP\Comments;
+
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Class CommentsEntityEvent
+ *
+ * @package OCP\Comments
+ * @since 9.1.0
+ */
+class CommentsEntityEvent extends Event {
+
+ const EVENT_ENTITY = 'OCP\Comments\ICommentsManager::registerEntity';
+
+ /** @var string */
+ protected $event;
+ /** @var \Closure[] */
+ protected $collections;
+
+ /**
+ * DispatcherEvent constructor.
+ *
+ * @param string $event
+ * @since 9.1.0
+ */
+ public function __construct($event) {
+ $this->event = $event;
+ $this->collections = [];
+ }
+
+ /**
+ * @param string $name
+ * @param \Closure $entityExistsFunction The closure should take one
+ * argument, which is the id of the entity, that comments
+ * should be handled for. The return should then be bool,
+ * depending on whether comments are allowed (true) or not.
+ * @throws \OutOfBoundsException when the entity name is already taken
+ * @since 9.1.0
+ */
+ public function addEntityCollection($name, \Closure $entityExistsFunction) {
+ if (isset($this->collections[$name])) {
+ throw new \OutOfBoundsException('Duplicate entity name "' . $name . '"');
+ }
+
+ $this->collections[$name] = $entityExistsFunction;
+ }
+
+ /**
+ * @return \Closure[]
+ * @since 9.1.0
+ */
+ public function getEntityCollections() {
+ return $this->collections;
+ }
+}
diff --git a/ocs/routes.php b/ocs/routes.php
index af9c3e74137..7f4f78dd35d 100644
--- a/ocs/routes.php
+++ b/ocs/routes.php
@@ -100,7 +100,25 @@ API::register(
// Server-to-Server Sharing
if (\OC::$server->getAppManager()->isEnabledForUser('files_sharing')) {
$federatedSharingApp = new \OCA\FederatedFileSharing\AppInfo\Application('federatedfilesharing');
- $s2s = new \OCA\Files_Sharing\API\Server2Server($federatedSharingApp->getFederatedShareProvider());
+ $addressHandler = new \OCA\FederatedFileSharing\AddressHandler(
+ \OC::$server->getURLGenerator(),
+ \OC::$server->getL10N('federatedfilesharing')
+ );
+ $notification = new \OCA\FederatedFileSharing\Notifications(
+ $addressHandler,
+ \OC::$server->getHTTPClientService(),
+ new \OCA\FederatedFileSharing\DiscoveryManager(\OC::$server->getMemCacheFactory(), \OC::$server->getHTTPClientService()),
+ \OC::$server->getJobList()
+ );
+ $s2s = new OCA\FederatedFileSharing\RequestHandler(
+ $federatedSharingApp->getFederatedShareProvider(),
+ \OC::$server->getDatabaseConnection(),
+ \OC::$server->getShareManager(),
+ \OC::$server->getRequest(),
+ $notification,
+ $addressHandler,
+ \OC::$server->getUserManager()
+ );
API::register('post',
'/cloud/shares',
array($s2s, 'createShare'),
@@ -109,6 +127,21 @@ if (\OC::$server->getAppManager()->isEnabledForUser('files_sharing')) {
);
API::register('post',
+ '/cloud/shares/{id}/reshare',
+ array($s2s, 'reShare'),
+ 'files_sharing',
+ API::GUEST_AUTH
+ );
+
+ API::register('post',
+ '/cloud/shares/{id}/permissions',
+ array($s2s, 'updatePermissions'),
+ 'files_sharing',
+ API::GUEST_AUTH
+ );
+
+
+ API::register('post',
'/cloud/shares/{id}/accept',
array($s2s, 'acceptShare'),
'files_sharing',
@@ -128,4 +161,11 @@ if (\OC::$server->getAppManager()->isEnabledForUser('files_sharing')) {
'files_sharing',
API::GUEST_AUTH
);
+
+ API::register('post',
+ '/cloud/shares/{id}/revoke',
+ array($s2s, 'revoke'),
+ 'files_sharing',
+ API::GUEST_AUTH
+ );
}
diff --git a/settings/Application.php b/settings/Application.php
index 5b84d028abf..728c2bf9de4 100644
--- a/settings/Application.php
+++ b/settings/Application.php
@@ -29,7 +29,9 @@
namespace OC\Settings;
use OC\Files\View;
+use OC\Server;
use OC\Settings\Controller\AppSettingsController;
+use OC\Settings\Controller\AuthSettingsController;
use OC\Settings\Controller\CertificateController;
use OC\Settings\Controller\CheckSetupController;
use OC\Settings\Controller\EncryptionController;
@@ -39,10 +41,9 @@ use OC\Settings\Controller\MailSettingsController;
use OC\Settings\Controller\SecuritySettingsController;
use OC\Settings\Controller\UsersController;
use OC\Settings\Middleware\SubadminMiddleware;
-use \OCP\AppFramework\App;
+use OCP\AppFramework\App;
use OCP\IContainer;
-use \OCP\Util;
-use OC\Server;
+use OCP\Util;
/**
* @package OC\Settings
@@ -97,6 +98,17 @@ class Application extends App {
$c->query('OcsClient')
);
});
+ $container->registerService('AuthSettingsController', function(IContainer $c) {
+ return new AuthSettingsController(
+ $c->query('AppName'),
+ $c->query('Request'),
+ $c->query('ServerContainer')->query('OC\Authentication\Token\IProvider'),
+ $c->query('UserManager'),
+ $c->query('ServerContainer')->getSession(),
+ $c->query('ServerContainer')->getSecureRandom(),
+ $c->query('UserId')
+ );
+ });
$container->registerService('SecuritySettingsController', function(IContainer $c) {
return new SecuritySettingsController(
$c->query('AppName'),
diff --git a/settings/Controller/AuthSettingsController.php b/settings/Controller/AuthSettingsController.php
new file mode 100644
index 00000000000..75311920d2a
--- /dev/null
+++ b/settings/Controller/AuthSettingsController.php
@@ -0,0 +1,151 @@
+<?php
+
+/**
+ * @author Christoph Wurst <christoph@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Settings\Controller;
+
+use OC\AppFramework\Http;
+use OC\Authentication\Exceptions\InvalidTokenException;
+use OC\Authentication\Token\IProvider;
+use OC\Authentication\Token\IToken;
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\JSONResponse;
+use OCP\IRequest;
+use OCP\ISession;
+use OCP\IUserManager;
+use OCP\Security\ISecureRandom;
+use OCP\Session\Exceptions\SessionNotAvailableException;
+
+class AuthSettingsController extends Controller {
+
+ /** @var IProvider */
+ private $tokenProvider;
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /** @var ISession */
+ private $session;
+
+ /** @var string */
+ private $uid;
+
+ /** @var ISecureRandom */
+ private $random;
+
+ /**
+ * @param string $appName
+ * @param IRequest $request
+ * @param IProvider $tokenProvider
+ * @param IUserManager $userManager
+ * @param ISession $session
+ * @param ISecureRandom $random
+ * @param string $uid
+ */
+ public function __construct($appName, IRequest $request, IProvider $tokenProvider, IUserManager $userManager,
+ ISession $session, ISecureRandom $random, $uid) {
+ parent::__construct($appName, $request);
+ $this->tokenProvider = $tokenProvider;
+ $this->userManager = $userManager;
+ $this->uid = $uid;
+ $this->session = $session;
+ $this->random = $random;
+ }
+
+ /**
+ * @NoAdminRequired
+ * @NoSubadminRequired
+ *
+ * @return JSONResponse
+ */
+ public function index() {
+ $user = $this->userManager->get($this->uid);
+ if (is_null($user)) {
+ return [];
+ }
+ return $this->tokenProvider->getTokenByUser($user);
+ }
+
+ /**
+ * @NoAdminRequired
+ * @NoSubadminRequired
+ *
+ * @return JSONResponse
+ */
+ public function create($name) {
+ try {
+ $sessionId = $this->session->getId();
+ } catch (SessionNotAvailableException $ex) {
+ $resp = new JSONResponse();
+ $resp->setStatus(Http::STATUS_SERVICE_UNAVAILABLE);
+ return $resp;
+ }
+
+ try {
+ $sessionToken = $this->tokenProvider->getToken($sessionId);
+ $password = $this->tokenProvider->getPassword($sessionToken, $sessionId);
+ } catch (InvalidTokenException $ex) {
+ $resp = new JSONResponse();
+ $resp->setStatus(Http::STATUS_SERVICE_UNAVAILABLE);
+ return $resp;
+ }
+
+ $token = $this->generateRandomDeviceToken();
+ $deviceToken = $this->tokenProvider->generateToken($token, $this->uid, $password, $name, IToken::PERMANENT_TOKEN);
+
+ return [
+ 'token' => $token,
+ 'deviceToken' => $deviceToken
+ ];
+ }
+
+ /**
+ * Return a 20 digit device password
+ *
+ * Example: ABCDE-FGHIJ-KLMNO-PQRST
+ *
+ * @return string
+ */
+ private function generateRandomDeviceToken() {
+ $groups = [];
+ for ($i = 0; $i < 4; $i++) {
+ $groups[] = $this->random->generate(5, implode('', range('A', 'Z')));
+ }
+ return implode('-', $groups);
+ }
+
+ /**
+ * @NoAdminRequired
+ * @NoSubadminRequired
+ *
+ * @return JSONResponse
+ */
+ public function destroy($id) {
+ $user = $this->userManager->get($this->uid);
+ if (is_null($user)) {
+ return [];
+ }
+
+ $this->tokenProvider->invalidateTokenById($user, $id);
+ return [];
+ }
+
+}
diff --git a/settings/css/settings.css b/settings/css/settings.css
index edc4939d2d8..5fc96343502 100644
--- a/settings/css/settings.css
+++ b/settings/css/settings.css
@@ -100,6 +100,39 @@ input#identity {
table.nostyle label { margin-right: 2em; }
table.nostyle td { padding: 0.2em 0; }
+#sessions table,
+#devices table {
+ width: 100%;
+ min-height: 150px;
+ padding-top: 25px;
+}
+#sessions table th,
+#devices table th {
+ font-weight: 800;
+}
+#sessions table th,
+#sessions table td,
+#devices table th,
+#devices table td {
+ padding: 10px;
+}
+
+#sessions .token-list td,
+#devices .token-list td {
+ border-top: 1px solid #DDD;
+}
+#sessions .token-list td a.icon-delete,
+#devices .token-list td a.icon-delete {
+ display: block;
+ opacity: 0.6;
+}
+
+#device-new-token {
+ width: 186px;
+ font-family: monospace;
+ background-color: lightyellow;
+}
+
/* USERS */
#newgroup-init a span { margin-left: 20px; }
#newgroup-init a span:before {
diff --git a/settings/js/authtoken.js b/settings/js/authtoken.js
new file mode 100644
index 00000000000..215192d7163
--- /dev/null
+++ b/settings/js/authtoken.js
@@ -0,0 +1,33 @@
+/* global Backbone */
+
+/**
+ * @author Christoph Wurst <christoph@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/>
+ *
+ */
+
+(function(OC, Backbone) {
+ 'use strict';
+
+ OC.Settings = OC.Settings || {};
+
+ var AuthToken = Backbone.Model.extend({
+ });
+
+ OC.Settings.AuthToken = AuthToken;
+
+})(OC, Backbone);
diff --git a/settings/js/authtoken_collection.js b/settings/js/authtoken_collection.js
new file mode 100644
index 00000000000..a78e053995f
--- /dev/null
+++ b/settings/js/authtoken_collection.js
@@ -0,0 +1,52 @@
+/* global Backbone */
+
+/**
+ * @author Christoph Wurst <christoph@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/>
+ *
+ */
+
+(function(OC, Backbone) {
+ 'use strict';
+
+ OC.Settings = OC.Settings || {};
+
+ var AuthTokenCollection = Backbone.Collection.extend({
+
+ model: OC.Settings.AuthToken,
+
+ /**
+ * Show recently used sessions/devices first
+ *
+ * @param {OC.Settigns.AuthToken} t1
+ * @param {OC.Settigns.AuthToken} t2
+ * @returns {Boolean}
+ */
+ comparator: function (t1, t2) {
+ var ts1 = parseInt(t1.get('lastActivity'), 10);
+ var ts2 = parseInt(t2.get('lastActivity'), 10);
+ return ts1 < ts2;
+ },
+
+ tokenType: null,
+
+ url: OC.generateUrl('/settings/personal/authtokens')
+ });
+
+ OC.Settings.AuthTokenCollection = AuthTokenCollection;
+
+})(OC, Backbone);
diff --git a/settings/js/authtoken_view.js b/settings/js/authtoken_view.js
new file mode 100644
index 00000000000..a165a465247
--- /dev/null
+++ b/settings/js/authtoken_view.js
@@ -0,0 +1,242 @@
+/* global Backbone, Handlebars, moment */
+
+/**
+ * @author Christoph Wurst <christoph@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/>
+ *
+ */
+
+(function(OC, _, Backbone, $, Handlebars, moment) {
+ 'use strict';
+
+ OC.Settings = OC.Settings || {};
+
+ var TEMPLATE_TOKEN =
+ '<tr data-id="{{id}}">'
+ + '<td>{{name}}</td>'
+ + '<td><span class="last-activity" title="{{lastActivityTime}}">{{lastActivity}}</span></td>'
+ + '<td><a class="icon-delete" title="' + t('core', 'Disconnect') + '"></a></td>'
+ + '<tr>';
+
+ var SubView = Backbone.View.extend({
+ collection: null,
+
+ /**
+ * token type
+ * - 0: browser
+ * - 1: device
+ *
+ * @see OC\Authentication\Token\IToken
+ */
+ type: 0,
+
+ _template: undefined,
+
+ template: function(data) {
+ if (_.isUndefined(this._template)) {
+ this._template = Handlebars.compile(TEMPLATE_TOKEN);
+ }
+
+ return this._template(data);
+ },
+
+ initialize: function(options) {
+ this.type = options.type;
+ this.collection = options.collection;
+
+ this.on(this.collection, 'change', this.render);
+ },
+
+ render: function() {
+ var _this = this;
+
+ var list = this.$('.token-list');
+ var tokens = this.collection.filter(function(token) {
+ return parseInt(token.get('type'), 10) === _this.type;
+ });
+ list.html('');
+
+ // Show header only if there are tokens to show
+ console.log(tokens.length > 0);
+ this._toggleHeader(tokens.length > 0);
+
+ tokens.forEach(function(token) {
+ var viewData = token.toJSON();
+ var ts = viewData.lastActivity * 1000;
+ viewData.lastActivity = OC.Util.relativeModifiedDate(ts);
+ viewData.lastActivityTime = OC.Util.formatDate(ts, 'LLL');
+ var html = _this.template(viewData);
+ var $html = $(html);
+ $html.find('.last-activity').tooltip();
+ $html.find('.icon-delete').tooltip();
+ list.append($html);
+ });
+ },
+
+ toggleLoading: function(state) {
+ this.$('.token-list').toggleClass('icon-loading', state);
+ },
+
+ _toggleHeader: function(show) {
+ this.$('.hidden-when-empty').toggleClass('hidden', !show);
+ }
+ });
+
+ var AuthTokenView = Backbone.View.extend({
+ collection: null,
+
+ _views: [],
+
+ _form: undefined,
+
+ _tokenName: undefined,
+
+ _addTokenBtn: undefined,
+
+ _result: undefined,
+
+ _newToken: undefined,
+
+ _hideTokenBtn: undefined,
+
+ _addingToken: false,
+
+ initialize: function(options) {
+ this.collection = options.collection;
+
+ var tokenTypes = [0, 1];
+ var _this = this;
+ _.each(tokenTypes, function(type) {
+ var el = type === 0 ? '#sessions' : '#devices';
+ _this._views.push(new SubView({
+ el: el,
+ type: type,
+ collection: _this.collection
+ }));
+
+ var $el = $(el);
+ $el.on('click', 'a.icon-delete', _.bind(_this._onDeleteToken, _this));
+ });
+
+ this._form = $('#device-token-form');
+ this._tokenName = $('#device-token-name');
+ this._addTokenBtn = $('#device-add-token');
+ this._addTokenBtn.click(_.bind(this._addDeviceToken, this));
+
+ this._result = $('#device-token-result');
+ this._newToken = $('#device-new-token');
+ this._newToken.on('focus', _.bind(this._onNewTokenFocus, this));
+ this._hideTokenBtn = $('#device-token-hide');
+ this._hideTokenBtn.click(_.bind(this._hideToken, this));
+ },
+
+ render: function() {
+ _.each(this._views, function(view) {
+ view.render();
+ view.toggleLoading(false);
+ });
+ },
+
+ reload: function() {
+ var _this = this;
+
+ _.each(this._views, function(view) {
+ view.toggleLoading(true);
+ });
+
+ var loadingTokens = this.collection.fetch();
+
+ $.when(loadingTokens).done(function() {
+ _this.render();
+ });
+ $.when(loadingTokens).fail(function() {
+ OC.Notification.showTemporary(t('core', 'Error while loading browser sessions and device tokens'));
+ });
+ },
+
+ _addDeviceToken: function() {
+ var _this = this;
+ this._toggleAddingToken(true);
+
+ var deviceName = this._tokenName.val();
+ var creatingToken = $.ajax(OC.generateUrl('/settings/personal/authtokens'), {
+ method: 'POST',
+ data: {
+ name: deviceName
+ }
+ });
+
+ $.when(creatingToken).done(function(resp) {
+ _this.collection.add(resp.deviceToken);
+ _this.render();
+ _this._newToken.val(resp.token);
+ _this._toggleFormResult(false);
+ _this._newToken.select();
+ _this._tokenName.val('');
+ });
+ $.when(creatingToken).fail(function() {
+ OC.Notification.showTemporary(t('core', 'Error while creating device token'));
+ });
+ $.when(creatingToken).always(function() {
+ _this._toggleAddingToken(false);
+ });
+ },
+
+ _onNewTokenFocus: function() {
+ this._newToken.select();
+ },
+
+ _hideToken: function() {
+ this._toggleFormResult(true);
+ },
+
+ _toggleAddingToken: function(state) {
+ this._addingToken = state;
+ this._addTokenBtn.toggleClass('icon-loading-small', state);
+ },
+
+ _onDeleteToken: function(event) {
+ var $target = $(event.target);
+ var $row = $target.closest('tr');
+ var id = $row.data('id');
+
+ var token = this.collection.get(id);
+ if (_.isUndefined(token)) {
+ // Ignore event
+ return;
+ }
+
+ var destroyingToken = token.destroy();
+
+ var _this = this;
+ $.when(destroyingToken).fail(function() {
+ OC.Notification.showTemporary(t('core', 'Error while deleting the token'));
+ });
+ $.when(destroyingToken).always(function() {
+ _this.render();
+ });
+ },
+
+ _toggleFormResult: function(showForm) {
+ this._form.toggleClass('hidden', !showForm);
+ this._result.toggleClass('hidden', showForm);
+ }
+ });
+
+ OC.Settings.AuthTokenView = AuthTokenView;
+
+})(OC, _, Backbone, $, Handlebars, moment);
diff --git a/settings/js/personal.js b/settings/js/personal.js
index 09f63f3f6af..aea2400e999 100644
--- a/settings/js/personal.js
+++ b/settings/js/personal.js
@@ -361,6 +361,13 @@ $(document).ready(function () {
if (oc_config.enable_avatars) {
$('#avatar .avatardiv').avatar(OC.currentUser, 145);
}
+
+ // Show token views
+ var collection = new OC.Settings.AuthTokenCollection();
+ var view = new OC.Settings.AuthTokenView({
+ collection: collection
+ });
+ view.reload();
});
if (!OC.Encryption) {
diff --git a/settings/personal.php b/settings/personal.php
index 6c2fccbec9b..3b283fb2d38 100644
--- a/settings/personal.php
+++ b/settings/personal.php
@@ -42,6 +42,9 @@ $config = \OC::$server->getConfig();
$urlGenerator = \OC::$server->getURLGenerator();
// Highlight navigation entry
+OC_Util::addScript('settings', 'authtoken');
+OC_Util::addScript('settings', 'authtoken_collection');
+OC_Util::addScript('settings', 'authtoken_view');
OC_Util::addScript( 'settings', 'personal' );
OC_Util::addScript('settings', 'certificates');
OC_Util::addStyle( 'settings', 'settings' );
@@ -171,6 +174,8 @@ $tmpl->assign('groups', $groups2);
// add hardcoded forms from the template
$formsAndMore = [];
$formsAndMore[]= ['anchor' => 'avatar', 'section-name' => $l->t('Personal info')];
+$formsAndMore[]= ['anchor' => 'sessions', 'section-name' => $l->t('Sessions')];
+$formsAndMore[]= ['anchor' => 'devices', 'section-name' => $l->t('Devices')];
$formsAndMore[]= ['anchor' => 'clientsbox', 'section-name' => $l->t('Sync clients')];
$forms=OC_App::getForms('personal');
diff --git a/settings/routes.php b/settings/routes.php
index 90e1d1e442b..5c356e01734 100644
--- a/settings/routes.php
+++ b/settings/routes.php
@@ -36,7 +36,8 @@ $application = new Application();
$application->registerRoutes($this, [
'resources' => [
'groups' => ['url' => '/settings/users/groups'],
- 'users' => ['url' => '/settings/users/users']
+ 'users' => ['url' => '/settings/users/users'],
+ 'AuthSettings' => ['url' => '/settings/personal/authtokens'],
],
'routes' => [
['name' => 'MailSettings#setMailSettings', 'url' => '/settings/admin/mailsettings', 'verb' => 'POST'],
diff --git a/settings/templates/personal.php b/settings/templates/personal.php
index 29bf240e7e3..dcc83b3e99e 100644
--- a/settings/templates/personal.php
+++ b/settings/templates/personal.php
@@ -139,6 +139,47 @@ if($_['passwordChangeSupported']) {
}
?>
+<div id="sessions" class="section">
+ <h2><?php p($l->t('Sessions'));?></h2>
+ <span class="hidden-when-empty"><?php p($l->t('These are the web browsers currently logged in to your ownCloud.'));?></span>
+ <table>
+ <thead class="token-list-header">
+ <tr>
+ <th><?php p($l->t('Browser'));?></th>
+ <th><?php p($l->t('Most recent activity'));?></th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody class="token-list icon-loading">
+ </tbody>
+ </table>
+</div>
+
+<div id="devices" class="section">
+ <h2><?php p($l->t('Devices'));?></h2>
+ <span class="hidden-when-empty"><?php p($l->t("You've linked these devices."));?></span>
+ <table>
+ <thead class="hidden-when-empty">
+ <tr>
+ <th><?php p($l->t('Name'));?></th>
+ <th><?php p($l->t('Most recent activity'));?></th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody class="token-list icon-loading">
+ </tbody>
+ </table>
+ <p><?php p($l->t('A device password is a passcode that gives an app or device permissions to access your ownCloud account.'));?></p>
+ <div id="device-token-form">
+ <input id="device-token-name" type="text" placeholder="Device name">
+ <button id="device-add-token" class="button">Create new device password</button>
+ </div>
+ <div id="device-token-result" class="hidden">
+ <input id="device-new-token" type="text" readonly="readonly"/>
+ <button id="device-token-hide" class="button">Done</button>
+ </div>
+</div>
+
<form id="language" class="section">
<h2>
<label for="languageinput"><?php p($l->t('Language'));?></label>
diff --git a/tests/core/command/config/app/deleteconfigtest.php b/tests/Core/Command/Config/App/DeleteConfigTest.php
index 7056e1b1ff9..7056e1b1ff9 100644
--- a/tests/core/command/config/app/deleteconfigtest.php
+++ b/tests/Core/Command/Config/App/DeleteConfigTest.php
diff --git a/tests/core/command/config/app/getconfigtest.php b/tests/Core/Command/Config/App/GetConfigTest.php
index 1ceeb16ccf4..1ceeb16ccf4 100644
--- a/tests/core/command/config/app/getconfigtest.php
+++ b/tests/Core/Command/Config/App/GetConfigTest.php
diff --git a/tests/core/command/config/app/setconfigtest.php b/tests/Core/Command/Config/App/SetConfigTest.php
index 14d7b0cb7b5..14d7b0cb7b5 100644
--- a/tests/core/command/config/app/setconfigtest.php
+++ b/tests/Core/Command/Config/App/SetConfigTest.php
diff --git a/tests/core/command/config/importtest.php b/tests/Core/Command/Config/ImportTest.php
index f14880f8bf4..f14880f8bf4 100644
--- a/tests/core/command/config/importtest.php
+++ b/tests/Core/Command/Config/ImportTest.php
diff --git a/tests/core/command/config/listconfigstest.php b/tests/Core/Command/Config/ListConfigsTest.php
index bde6a1b0db3..bde6a1b0db3 100644
--- a/tests/core/command/config/listconfigstest.php
+++ b/tests/Core/Command/Config/ListConfigsTest.php
diff --git a/tests/core/command/config/system/deleteconfigtest.php b/tests/Core/Command/Config/System/DeleteConfigTest.php
index 11bfb6ae7ad..11bfb6ae7ad 100644
--- a/tests/core/command/config/system/deleteconfigtest.php
+++ b/tests/Core/Command/Config/System/DeleteConfigTest.php
diff --git a/tests/core/command/config/system/getconfigtest.php b/tests/Core/Command/Config/System/GetConfigTest.php
index ebbea634cde..ebbea634cde 100644
--- a/tests/core/command/config/system/getconfigtest.php
+++ b/tests/Core/Command/Config/System/GetConfigTest.php
diff --git a/tests/core/command/config/system/setconfigtest.php b/tests/Core/Command/Config/System/SetConfigTest.php
index c0b664d7522..c0b664d7522 100644
--- a/tests/core/command/config/system/setconfigtest.php
+++ b/tests/Core/Command/Config/System/SetConfigTest.php
diff --git a/tests/core/command/encryption/changekeystorageroottest.php b/tests/Core/Command/Encryption/ChangeKeyStorageRootTest.php
index 2a1f48983f1..2a1f48983f1 100644
--- a/tests/core/command/encryption/changekeystorageroottest.php
+++ b/tests/Core/Command/Encryption/ChangeKeyStorageRootTest.php
diff --git a/tests/core/command/encryption/decryptalltest.php b/tests/Core/Command/Encryption/DecryptAllTest.php
index 972ea03150c..972ea03150c 100644
--- a/tests/core/command/encryption/decryptalltest.php
+++ b/tests/Core/Command/Encryption/DecryptAllTest.php
diff --git a/tests/core/command/encryption/disabletest.php b/tests/Core/Command/Encryption/DisableTest.php
index dfd06e2e26e..dfd06e2e26e 100644
--- a/tests/core/command/encryption/disabletest.php
+++ b/tests/Core/Command/Encryption/DisableTest.php
diff --git a/tests/core/command/encryption/enabletest.php b/tests/Core/Command/Encryption/EnableTest.php
index e2357464aa1..e2357464aa1 100644
--- a/tests/core/command/encryption/enabletest.php
+++ b/tests/Core/Command/Encryption/EnableTest.php
diff --git a/tests/core/command/encryption/encryptalltest.php b/tests/Core/Command/Encryption/EncryptAllTest.php
index 128b4caa148..128b4caa148 100644
--- a/tests/core/command/encryption/encryptalltest.php
+++ b/tests/Core/Command/Encryption/EncryptAllTest.php
diff --git a/tests/core/command/encryption/setdefaultmoduletest.php b/tests/Core/Command/Encryption/SetDefaultModuleTest.php
index 3230a57db07..3230a57db07 100644
--- a/tests/core/command/encryption/setdefaultmoduletest.php
+++ b/tests/Core/Command/Encryption/SetDefaultModuleTest.php
diff --git a/tests/core/command/log/managetest.php b/tests/Core/Command/Log/ManageTest.php
index 6fb83347f23..6fb83347f23 100644
--- a/tests/core/command/log/managetest.php
+++ b/tests/Core/Command/Log/ManageTest.php
diff --git a/tests/core/command/log/owncloudtest.php b/tests/Core/Command/Log/OwnCloudTest.php
index 3cb05221c37..3cb05221c37 100644
--- a/tests/core/command/log/owncloudtest.php
+++ b/tests/Core/Command/Log/OwnCloudTest.php
diff --git a/tests/core/command/maintenance/datafingerprinttest.php b/tests/Core/Command/Maintenance/DataFingerprintTest.php
index 4d661b5c027..4d661b5c027 100644
--- a/tests/core/command/maintenance/datafingerprinttest.php
+++ b/tests/Core/Command/Maintenance/DataFingerprintTest.php
diff --git a/tests/core/command/maintenance/mimetype/updatedbtest.php b/tests/Core/Command/Maintenance/Mimetype/UpdateDBTest.php
index 217301102c5..217301102c5 100644
--- a/tests/core/command/maintenance/mimetype/updatedbtest.php
+++ b/tests/Core/Command/Maintenance/Mimetype/UpdateDBTest.php
diff --git a/tests/core/command/maintenance/singleusertest.php b/tests/Core/Command/Maintenance/SingleUserTest.php
index 6629f39564f..6629f39564f 100644
--- a/tests/core/command/maintenance/singleusertest.php
+++ b/tests/Core/Command/Maintenance/SingleUserTest.php
diff --git a/tests/core/command/user/deletetest.php b/tests/Core/Command/User/DeleteTest.php
index bb813626d7a..bb813626d7a 100644
--- a/tests/core/command/user/deletetest.php
+++ b/tests/Core/Command/User/DeleteTest.php
diff --git a/tests/core/command/user/lastseentest.php b/tests/Core/Command/User/LastSeenTest.php
index 84805f5c072..84805f5c072 100644
--- a/tests/core/command/user/lastseentest.php
+++ b/tests/Core/Command/User/LastSeenTest.php
diff --git a/tests/core/controller/avatarcontrollertest.php b/tests/Core/Controller/AvatarControllerTest.php
index c99b69228b1..937d8aaf17b 100644
--- a/tests/core/controller/avatarcontrollertest.php
+++ b/tests/Core/Controller/AvatarControllerTest.php
@@ -18,13 +18,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
-namespace OC\Core\Controller;
-use OC;
+namespace Tests\Core\Controller;
+
use OC\Core\Application;
use OCP\AppFramework\IAppContainer;
use OCP\AppFramework\Http;
-use OCP\Files\Folder;
use OCP\Files\File;
use OCP\Files\NotFoundException;
use OCP\IUser;
@@ -52,7 +51,7 @@ class AvatarControllerTest extends \Test\TestCase {
/** @var IAppContainer */
private $container;
- /** @var AvatarController */
+ /** @var \OC\Core\Controller\AvatarController */
private $avatarController;
/** @var IAvatar */
private $avatarMock;
@@ -228,7 +227,7 @@ class AvatarControllerTest extends \Test\TestCase {
* Fetch tmp avatar
*/
public function testTmpAvatarValid() {
- $this->container['Cache']->method('get')->willReturn(file_get_contents(OC::$SERVERROOT.'/tests/data/testimage.jpg'));
+ $this->container['Cache']->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg'));
$response = $this->avatarController->getTmpAvatar();
$this->assertEquals(Http::STATUS_OK, $response->getStatus());
@@ -250,14 +249,14 @@ class AvatarControllerTest extends \Test\TestCase {
public function testPostAvatarFile() {
//Create temp file
$fileName = tempnam(null, "avatarTest");
- $copyRes = copy(OC::$SERVERROOT.'/tests/data/testimage.jpg', $fileName);
+ $copyRes = copy(\OC::$SERVERROOT.'/tests/data/testimage.jpg', $fileName);
$this->assertTrue($copyRes);
//Create file in cache
- $this->container['Cache']->method('get')->willReturn(file_get_contents(OC::$SERVERROOT.'/tests/data/testimage.jpg'));
+ $this->container['Cache']->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg'));
//Create request return
- $reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => [filesize(OC::$SERVERROOT.'/tests/data/testimage.jpg')]];
+ $reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => [filesize(\OC::$SERVERROOT.'/tests/data/testimage.jpg')]];
$this->container['Request']->method('getUploadedFile')->willReturn($reqRet);
$response = $this->avatarController->postAvatar(null);
@@ -288,14 +287,14 @@ class AvatarControllerTest extends \Test\TestCase {
public function testPostAvatarFileGif() {
//Create temp file
$fileName = tempnam(null, "avatarTest");
- $copyRes = copy(OC::$SERVERROOT.'/tests/data/testimage.gif', $fileName);
+ $copyRes = copy(\OC::$SERVERROOT.'/tests/data/testimage.gif', $fileName);
$this->assertTrue($copyRes);
//Create file in cache
- $this->container['Cache']->method('get')->willReturn(file_get_contents(OC::$SERVERROOT.'/tests/data/testimage.gif'));
+ $this->container['Cache']->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.gif'));
//Create request return
- $reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => filesize(OC::$SERVERROOT.'/tests/data/testimage.gif')];
+ $reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => filesize(\OC::$SERVERROOT.'/tests/data/testimage.gif')];
$this->container['Request']->method('getUploadedFile')->willReturn($reqRet);
$response = $this->avatarController->postAvatar(null);
@@ -313,7 +312,7 @@ class AvatarControllerTest extends \Test\TestCase {
//Mock node API call
$file = $this->getMockBuilder('OCP\Files\File')
->disableOriginalConstructor()->getMock();
- $file->method('getContent')->willReturn(file_get_contents(OC::$SERVERROOT.'/tests/data/testimage.jpg'));
+ $file->method('getContent')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg'));
$this->container['UserFolder']->method('get')->willReturn($file);
//Create request return
@@ -349,7 +348,7 @@ class AvatarControllerTest extends \Test\TestCase {
->will($this->throwException(new \Exception("foo")));
$file = $this->getMockBuilder('OCP\Files\File')
->disableOriginalConstructor()->getMock();
- $file->method('getContent')->willReturn(file_get_contents(OC::$SERVERROOT.'/tests/data/testimage.jpg'));
+ $file->method('getContent')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg'));
$this->container['UserFolder']->method('get')->willReturn($file);
$this->container['Logger']->expects($this->once())
@@ -382,7 +381,7 @@ class AvatarControllerTest extends \Test\TestCase {
* Test with non square crop
*/
public function testPostCroppedAvatarNoSquareCrop() {
- $this->container['Cache']->method('get')->willReturn(file_get_contents(OC::$SERVERROOT.'/tests/data/testimage.jpg'));
+ $this->container['Cache']->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg'));
$this->avatarMock->method('set')->will($this->throwException(new \OC\NotSquareException));
$this->container['AvatarManager']->method('getAvatar')->willReturn($this->avatarMock);
@@ -395,7 +394,7 @@ class AvatarControllerTest extends \Test\TestCase {
* Check for proper reply on proper crop argument
*/
public function testPostCroppedAvatarValidCrop() {
- $this->container['Cache']->method('get')->willReturn(file_get_contents(OC::$SERVERROOT.'/tests/data/testimage.jpg'));
+ $this->container['Cache']->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg'));
$this->container['AvatarManager']->method('getAvatar')->willReturn($this->avatarMock);
$response = $this->avatarController->postCroppedAvatar(['x' => 0, 'y' => 0, 'w' => 10, 'h' => 10]);
@@ -407,7 +406,7 @@ class AvatarControllerTest extends \Test\TestCase {
* Test what happens if the cropping of the avatar fails
*/
public function testPostCroppedAvatarException() {
- $this->container['Cache']->method('get')->willReturn(file_get_contents(OC::$SERVERROOT.'/tests/data/testimage.jpg'));
+ $this->container['Cache']->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg'));
$this->avatarMock->method('set')->will($this->throwException(new \Exception('foo')));
$this->container['AvatarManager']->method('getAvatar')->willReturn($this->avatarMock);
@@ -424,7 +423,7 @@ class AvatarControllerTest extends \Test\TestCase {
* Check for proper reply on proper crop argument
*/
public function testFileTooBig() {
- $fileName = OC::$SERVERROOT.'/tests/data/testimage.jpg';
+ $fileName = \OC::$SERVERROOT.'/tests/data/testimage.jpg';
//Create request return
$reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => [21*1024*1024]];
$this->container['Request']->method('getUploadedFile')->willReturn($reqRet);
diff --git a/tests/core/controller/LoginControllerTest.php b/tests/Core/Controller/LoginControllerTest.php
index 139d48ad7da..32902a01530 100644
--- a/tests/core/controller/LoginControllerTest.php
+++ b/tests/Core/Controller/LoginControllerTest.php
@@ -19,8 +19,9 @@
*
*/
-namespace OC\Core\Controller;
+namespace Tests\Core\Controller;
+use OC\Core\Controller\LoginController;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IConfig;
diff --git a/tests/core/controller/lostcontrollertest.php b/tests/Core/Controller/LostControllerTest.php
index 44bc539247f..ca63c3404eb 100644
--- a/tests/core/controller/lostcontrollertest.php
+++ b/tests/Core/Controller/LostControllerTest.php
@@ -19,8 +19,9 @@
*
*/
-namespace OC\Core\Controller;
+namespace Tests\Core\Controller;
+use OC\Core\Controller\LostController;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IConfig;
diff --git a/tests/core/controller/TokenControllerTest.php b/tests/Core/Controller/TokenControllerTest.php
index 4635f96f48f..b600bfa5451 100644
--- a/tests/core/controller/TokenControllerTest.php
+++ b/tests/Core/Controller/TokenControllerTest.php
@@ -20,9 +20,10 @@
*
*/
-namespace OC\Core\Controller;
+namespace Tests\Core\Controller;
use OC\AppFramework\Http;
+use OC\Core\Controller\TokenController;
use OCP\AppFramework\Http\Response;
use Test\TestCase;
diff --git a/tests/core/templates/templates.php b/tests/Core/Templates/TemplatesTest.php
index 338d80b276c..03565411a13 100644
--- a/tests/core/templates/templates.php
+++ b/tests/Core/Templates/TemplatesTest.php
@@ -2,7 +2,7 @@
namespace Tests\Core\Templates;
-class Templates extends \Test\TestCase {
+class TemplatesTest extends \Test\TestCase {
public function test403() {
$template = \OC::$SERVERROOT . '/core/templates/403.php';
diff --git a/tests/settings/controller/AppSettingsControllerTest.php b/tests/Settings/Controller/AppSettingsControllerTest.php
index dba5728ca4b..9dcc55e135b 100644
--- a/tests/settings/controller/AppSettingsControllerTest.php
+++ b/tests/Settings/Controller/AppSettingsControllerTest.php
@@ -19,8 +19,9 @@
*
*/
-namespace OC\Settings\Controller;
+namespace Tests\Settings\Controller;
+use OC\Settings\Controller\AppSettingsController;
use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\TemplateResponse;
@@ -36,7 +37,7 @@ use OC\OCSClient;
/**
* Class AppSettingsControllerTest
*
- * @package OC\Settings\Controller
+ * @package Tests\Settings\Controller
*/
class AppSettingsControllerTest extends TestCase {
/** @var AppSettingsController */
diff --git a/tests/settings/controller/CertificateControllerTest.php b/tests/Settings/Controller/CertificateControllerTest.php
index 2fdbbb8b0ac..c9ea2a4024f 100644
--- a/tests/settings/controller/CertificateControllerTest.php
+++ b/tests/Settings/Controller/CertificateControllerTest.php
@@ -19,8 +19,9 @@
*
*/
-namespace OC\Settings\Controller;
+namespace Tests\Settings\Controller;
+use OC\Settings\Controller\CertificateController;
use OCP\App\IAppManager;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
@@ -31,7 +32,7 @@ use OCP\ICertificateManager;
/**
* Class CertificateControllerTest
*
- * @package OC\Settings\Controller
+ * @package Tests\Settings\Controller
*/
class CertificateControllerTest extends \Test\TestCase {
/** @var CertificateController */
diff --git a/tests/settings/controller/CheckSetupControllerTest.php b/tests/Settings/Controller/CheckSetupControllerTest.php
index 3ce7c64b4a3..f48e9c04f3d 100644
--- a/tests/settings/controller/CheckSetupControllerTest.php
+++ b/tests/Settings/Controller/CheckSetupControllerTest.php
@@ -19,8 +19,9 @@
*
*/
-namespace OC\Settings\Controller;
+namespace Tests\Settings\Controller;
+use OC\Settings\Controller\CheckSetupController;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataDisplayResponse;
use OCP\AppFramework\Http\DataResponse;
@@ -47,7 +48,7 @@ function version_compare($version1, $version2) {
/**
* Class CheckSetupControllerTest
*
- * @package OC\Settings\Controller
+ * @package Tests\Settings\Controller
*/
class CheckSetupControllerTest extends TestCase {
/** @var int */
diff --git a/tests/settings/controller/EncryptionControllerTest.php b/tests/Settings/Controller/EncryptionControllerTest.php
index 565aaf29c9a..adbbe2cf6a4 100644
--- a/tests/settings/controller/EncryptionControllerTest.php
+++ b/tests/Settings/Controller/EncryptionControllerTest.php
@@ -19,10 +19,11 @@
*
*/
-namespace OC\Settings\Controller;
+namespace Tests\Settings\Controller;
use OC\DB\Connection;
use OC\Files\View;
+use OC\Settings\Controller\EncryptionController;
use OCP\IConfig;
use OCP\IL10N;
use OCP\ILogger;
@@ -33,7 +34,7 @@ use Test\TestCase;
/**
* Class EncryptionControllerTest
*
- * @package OC\Settings\Controller
+ * @package Tests\Settings\Controller
*/
class EncryptionControllerTest extends TestCase {
/** @var IRequest */
diff --git a/tests/settings/controller/groupscontrollertest.php b/tests/Settings/Controller/GroupsControllerTest.php
index 82b4c7d3c05..70cb8282b26 100644
--- a/tests/settings/controller/groupscontrollertest.php
+++ b/tests/Settings/Controller/GroupsControllerTest.php
@@ -7,16 +7,18 @@
* later.
* See the COPYING-README file.
*/
-namespace OC\Settings\Controller;
+
+namespace Tests\Settings\Controller;
use OC\Group\Group;
use OC\Group\MetaData;
use \OC\Settings\Application;
+use OC\Settings\Controller\GroupsController;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
/**
- * @package OC\Settings\Controller
+ * @package Tests\Settings\Controller
*/
class GroupsControllerTest extends \Test\TestCase {
diff --git a/tests/settings/controller/logsettingscontrollertest.php b/tests/Settings/Controller/LogSettingsControllerTest.php
index 60680ba4647..092c04aecc7 100644
--- a/tests/settings/controller/logsettingscontrollertest.php
+++ b/tests/Settings/Controller/LogSettingsControllerTest.php
@@ -7,13 +7,14 @@
* later.
* See the COPYING-README file.
*/
-namespace Test\Settings\Controller;
+
+namespace Tests\Settings\Controller;
use \OC\Settings\Application;
use OC\Settings\Controller\LogSettingsController;
/**
- * @package OC\Settings\Controller
+ * @package Tests\Settings\Controller
*/
class LogSettingsControllerTest extends \Test\TestCase {
diff --git a/tests/settings/controller/mailsettingscontrollertest.php b/tests/Settings/Controller/MailSettingsControllerTest.php
index cc25fda52f7..1ac6bae69ea 100644
--- a/tests/settings/controller/mailsettingscontrollertest.php
+++ b/tests/Settings/Controller/MailSettingsControllerTest.php
@@ -7,12 +7,13 @@
* later.
* See the COPYING-README file.
*/
-namespace OC\Settings\Controller;
-use \OC\Settings\Application;
+namespace Tests\Settings\Controller;
+
+use OC\Settings\Application;
/**
- * @package OC\Settings\Controller
+ * @package Tests\Settings\Controller
*/
class MailSettingsControllerTest extends \Test\TestCase {
diff --git a/tests/settings/controller/securitysettingscontrollertest.php b/tests/Settings/Controller/SecuritySettingsControllerTest.php
index 56848d8df30..11b0edcae23 100644
--- a/tests/settings/controller/securitysettingscontrollertest.php
+++ b/tests/Settings/Controller/SecuritySettingsControllerTest.php
@@ -7,12 +7,13 @@
* later.
* See the COPYING-README file.
*/
-namespace OC\Settings\Controller;
+namespace Tests\Settings\Controller;
use \OC\Settings\Application;
+use OC\Settings\Controller\SecuritySettingsController;
/**
- * @package OC\Settings\Controller
+ * @package Tests\Settings\Controller
*/
class SecuritySettingsControllerTest extends \PHPUnit_Framework_TestCase {
diff --git a/tests/settings/controller/userscontrollertest.php b/tests/Settings/Controller/UsersControllerTest.php
index 2a2b53d8ff8..244d1f744d3 100644
--- a/tests/settings/controller/userscontrollertest.php
+++ b/tests/Settings/Controller/UsersControllerTest.php
@@ -7,7 +7,8 @@
* later.
* See the COPYING-README file.
*/
-namespace OC\Settings\Controller;
+
+namespace Tests\Settings\Controller;
use \OC\Settings\Application;
use OCP\AppFramework\Http;
@@ -16,7 +17,7 @@ use OCP\AppFramework\Http\DataResponse;
/**
* @group DB
*
- * @package OC\Settings\Controller
+ * @package Tests\Settings\Controller
*/
class UsersControllerTest extends \Test\TestCase {
diff --git a/tests/settings/middleware/subadminmiddlewaretest.php b/tests/Settings/Middleware/SubadminMiddlewareTest.php
index c16c21c9c10..652f8b2d151 100644
--- a/tests/settings/middleware/subadminmiddlewaretest.php
+++ b/tests/Settings/Middleware/SubadminMiddlewareTest.php
@@ -8,10 +8,11 @@
* See the COPYING-README file.
*/
-namespace OC\Settings\Middleware;
+namespace Tests\Settings\Middleware;
use OC\AppFramework\Middleware\Security\Exceptions\NotAdminException;
use OC\AppFramework\Utility\ControllerMethodReflector;
+use OC\Settings\Middleware\SubadminMiddleware;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\TemplateResponse;
@@ -19,7 +20,7 @@ use OCP\AppFramework\Http\TemplateResponse;
* Verifies whether an user has at least subadmin rights.
* To bypass use the `@NoSubadminRequired` annotation
*
- * @package OC\Settings\Middleware
+ * @package Tests\Settings\Middleware
*/
class SubadminMiddlewareTest extends \Test\TestCase {
/** @var SubadminMiddleware */
diff --git a/tests/lib/Authentication/Token/DefaultTokenMapperTest.php b/tests/lib/Authentication/Token/DefaultTokenMapperTest.php
index e17149a5c1b..9179e23bfb2 100644
--- a/tests/lib/Authentication/Token/DefaultTokenMapperTest.php
+++ b/tests/lib/Authentication/Token/DefaultTokenMapperTest.php
@@ -159,4 +159,31 @@ class DefaultTokenMapperTest extends TestCase {
$this->assertCount(0, $this->mapper->getTokenByUser($user));
}
+ public function testDeleteById() {
+ $user = $this->getMock('\OCP\IUser');
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->select('id')
+ ->from('authtoken')
+ ->where($qb->expr()->eq('token', $qb->createNamedParameter('9c5a2e661482b65597408a6bb6c4a3d1af36337381872ac56e445a06cdb7fea2b1039db707545c11027a4966919918b19d875a8b774840b18c6cbb7ae56fe206')));
+ $result = $qb->execute();
+ $id = $result->fetch()['id'];
+ $user->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue('user1'));
+
+ $this->mapper->deleteById($user, $id);
+ $this->assertEquals(2, $this->getNumberOfTokens());
+ }
+
+ public function testDeleteByIdWrongUser() {
+ $user = $this->getMock('\OCP\IUser');
+ $id = 33;
+ $user->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue('user10000'));
+
+ $this->mapper->deleteById($user, $id);
+ $this->assertEquals(3, $this->getNumberOfTokens());
+ }
+
}
diff --git a/tests/lib/Authentication/Token/DefaultTokenProviderTest.php b/tests/lib/Authentication/Token/DefaultTokenProviderTest.php
index eeb249cfa8a..8af5e1e933a 100644
--- a/tests/lib/Authentication/Token/DefaultTokenProviderTest.php
+++ b/tests/lib/Authentication/Token/DefaultTokenProviderTest.php
@@ -170,6 +170,17 @@ class DefaultTokenProviderTest extends TestCase {
$this->tokenProvider->invalidateToken('token7');
}
+ public function testInvaildateTokenById() {
+ $id = 123;
+ $user = $this->getMock('\OCP\IUser');
+
+ $this->mapper->expects($this->once())
+ ->method('deleteById')
+ ->with($user, $id);
+
+ $this->tokenProvider->invalidateTokenById($user, $id);
+ }
+
public function testInvalidateOldTokens() {
$defaultSessionLifetime = 60 * 60 * 24;
$this->config->expects($this->once())
diff --git a/tests/lib/Share20/DefaultShareProviderTest.php b/tests/lib/Share20/DefaultShareProviderTest.php
index 44a48535b9b..6ef00721a70 100644
--- a/tests/lib/Share20/DefaultShareProviderTest.php
+++ b/tests/lib/Share20/DefaultShareProviderTest.php
@@ -57,6 +57,8 @@ class DefaultShareProviderTest extends \Test\TestCase {
$this->groupManager = $this->getMock('OCP\IGroupManager');
$this->rootFolder = $this->getMock('OCP\Files\IRootFolder');
+ $this->userManager->expects($this->any())->method('userExists')->willReturn(true);
+
//Empty share table
$this->dbConn->getQueryBuilder()->delete('share')->execute();
@@ -587,7 +589,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
}
public function testCreateUserShare() {
- $share = new \OC\Share20\Share($this->rootFolder);
+ $share = new \OC\Share20\Share($this->rootFolder, $this->userManager);
$shareOwner = $this->getMock('OCP\IUser');
$shareOwner->method('getUID')->WillReturn('shareOwner');
@@ -635,7 +637,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
}
public function testCreateGroupShare() {
- $share = new \OC\Share20\Share($this->rootFolder);
+ $share = new \OC\Share20\Share($this->rootFolder, $this->userManager);
$shareOwner = $this->getMock('\OCP\IUser');
$shareOwner->method('getUID')->willReturn('shareOwner');
@@ -683,7 +685,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
}
public function testCreateLinkShare() {
- $share = new \OC\Share20\Share($this->rootFolder);
+ $share = new \OC\Share20\Share($this->rootFolder, $this->userManager);
$shareOwner = $this->getMock('\OCP\IUser');
$shareOwner->method('getUID')->willReturn('shareOwner');
diff --git a/tests/lib/Share20/ManagerTest.php b/tests/lib/Share20/ManagerTest.php
index 7d79150449c..a50ea6c892a 100644
--- a/tests/lib/Share20/ManagerTest.php
+++ b/tests/lib/Share20/ManagerTest.php
@@ -2283,6 +2283,9 @@ class ManagerTest extends \Test\TestCase {
}
public function testUpdateShareUser() {
+
+ $this->userManager->expects($this->any())->method('userExists')->willReturn(true);
+
$manager = $this->createManagerMock()
->setMethods([
'canShare',
@@ -2567,4 +2570,4 @@ class DummyFactory implements IProviderFactory {
public function getProviderForType($shareType) {
return $this->provider;
}
-} \ No newline at end of file
+}
diff --git a/tests/lib/Share20/ShareTest.php b/tests/lib/Share20/ShareTest.php
index fdfc69f6577..91bd2fe84b6 100644
--- a/tests/lib/Share20/ShareTest.php
+++ b/tests/lib/Share20/ShareTest.php
@@ -36,7 +36,8 @@ class ShareTest extends \Test\TestCase {
public function setUp() {
$this->rootFolder = $this->getMock('\OCP\Files\IRootFolder');
- $this->share = new \OC\Share20\Share($this->rootFolder);
+ $this->userManager = $this->getMock('OCP\IUserManager');
+ $this->share = new \OC\Share20\Share($this->rootFolder, $this->userManager);
}
/**
diff --git a/tests/lib/files/storage/wrapper/Encoding.php b/tests/lib/files/storage/wrapper/Encoding.php
new file mode 100644
index 00000000000..79b7a3bfb6e
--- /dev/null
+++ b/tests/lib/files/storage/wrapper/Encoding.php
@@ -0,0 +1,203 @@
+<?php
+/**
+ * Copyright (c) 2016 Vincent Petry <pvince81@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\Files\Storage\Wrapper;
+
+class Encoding extends \Test\Files\Storage\Storage {
+
+ const NFD_NAME = 'ümlaut';
+ const NFC_NAME = 'ümlaut';
+
+ /**
+ * @var \OC\Files\Storage\Temporary
+ */
+ private $sourceStorage;
+
+ public function setUp() {
+ parent::setUp();
+ $this->sourceStorage = new \OC\Files\Storage\Temporary([]);
+ $this->instance = new \OC\Files\Storage\Wrapper\Encoding([
+ 'storage' => $this->sourceStorage
+ ]);
+ }
+
+ public function tearDown() {
+ $this->sourceStorage->cleanUp();
+ parent::tearDown();
+ }
+
+ public function directoryProvider() {
+ $a = parent::directoryProvider();
+ $a[] = [self::NFD_NAME];
+ return $a;
+ }
+
+ public function fileNameProvider() {
+ $a = parent::fileNameProvider();
+ $a[] = [self::NFD_NAME . '.txt'];
+ return $a;
+ }
+
+ public function copyAndMoveProvider() {
+ $a = parent::copyAndMoveProvider();
+ $a[] = [self::NFD_NAME . '.txt', self::NFC_NAME . '-renamed.txt'];
+ return $a;
+ }
+
+ public function accessNameProvider() {
+ return [
+ [self::NFD_NAME],
+ [self::NFC_NAME],
+ ];
+ }
+
+ /**
+ * @dataProvider accessNameProvider
+ */
+ public function testFputEncoding($accessName) {
+ $this->sourceStorage->file_put_contents(self::NFD_NAME, 'bar');
+ $this->assertEquals('bar', $this->instance->file_get_contents($accessName));
+ }
+
+ /**
+ * @dataProvider accessNameProvider
+ */
+ public function testFopenReadEncoding($accessName) {
+ $this->sourceStorage->file_put_contents(self::NFD_NAME, 'bar');
+ $fh = $this->instance->fopen($accessName, 'r');
+ $data = fgets($fh);
+ fclose($fh);
+ $this->assertEquals('bar', $data);
+ }
+
+ /**
+ * @dataProvider accessNameProvider
+ */
+ public function testFopenOverwriteEncoding($accessName) {
+ $this->sourceStorage->file_put_contents(self::NFD_NAME, 'bar');
+ $fh = $this->instance->fopen($accessName, 'w');
+ $data = fputs($fh, 'test');
+ fclose($fh);
+ $data = $this->sourceStorage->file_get_contents(self::NFD_NAME);
+ $this->assertEquals('test', $data);
+ $this->assertFalse($this->sourceStorage->file_exists(self::NFC_NAME));
+ }
+
+ /**
+ * @dataProvider accessNameProvider
+ */
+ public function testFileExistsEncoding($accessName) {
+ $this->sourceStorage->file_put_contents(self::NFD_NAME, 'bar');
+ $this->assertTrue($this->instance->file_exists($accessName));
+ }
+
+ /**
+ * @dataProvider accessNameProvider
+ */
+ public function testUnlinkEncoding($accessName) {
+ $this->sourceStorage->file_put_contents(self::NFD_NAME, 'bar');
+ $this->assertTrue($this->instance->unlink($accessName));
+ $this->assertFalse($this->sourceStorage->file_exists(self::NFC_NAME));
+ $this->assertFalse($this->sourceStorage->file_exists(self::NFD_NAME));
+ }
+
+ public function testNfcHigherPriority() {
+ $this->sourceStorage->file_put_contents(self::NFC_NAME, 'nfc');
+ $this->sourceStorage->file_put_contents(self::NFD_NAME, 'nfd');
+ $this->assertEquals('nfc', $this->instance->file_get_contents(self::NFC_NAME));
+ }
+
+ public function encodedDirectoriesProvider() {
+ return [
+ [self::NFD_NAME, self::NFC_NAME],
+ [self::NFD_NAME . '/' . self::NFD_NAME, self::NFC_NAME . '/' . self::NFC_NAME],
+ [self::NFD_NAME . '/' . self::NFC_NAME . '/' .self::NFD_NAME, self::NFC_NAME . '/' . self::NFC_NAME . '/' . self::NFC_NAME],
+ ];
+ }
+
+ /**
+ * @dataProvider encodedDirectoriesProvider
+ */
+ public function testOperationInsideDirectory($sourceDir, $accessDir) {
+ $this->sourceStorage->mkdir($sourceDir);
+ $this->instance->file_put_contents($accessDir . '/test.txt', 'bar');
+ $this->assertTrue($this->instance->file_exists($accessDir . '/test.txt'));
+ $this->assertEquals('bar', $this->instance->file_get_contents($accessDir . '/test.txt'));
+
+ $this->sourceStorage->file_put_contents($sourceDir . '/' . self::NFD_NAME, 'foo');
+ $this->assertTrue($this->instance->file_exists($accessDir . '/' . self::NFC_NAME));
+ $this->assertEquals('foo', $this->instance->file_get_contents($accessDir . '/' . self::NFC_NAME));
+
+ // try again to make it use cached path
+ $this->assertEquals('bar', $this->instance->file_get_contents($accessDir . '/test.txt'));
+ $this->assertTrue($this->instance->file_exists($accessDir . '/test.txt'));
+ $this->assertEquals('foo', $this->instance->file_get_contents($accessDir . '/' . self::NFC_NAME));
+ $this->assertTrue($this->instance->file_exists($accessDir . '/' . self::NFC_NAME));
+ }
+
+ public function testCacheExtraSlash() {
+ $this->sourceStorage->file_put_contents(self::NFD_NAME, 'foo');
+ $this->assertEquals(3, $this->instance->file_put_contents(self::NFC_NAME, 'bar'));
+ $this->assertEquals('bar', $this->instance->file_get_contents(self::NFC_NAME));
+ clearstatcache();
+ $this->assertEquals(5, $this->instance->file_put_contents('/' . self::NFC_NAME, 'baric'));
+ $this->assertEquals('baric', $this->instance->file_get_contents(self::NFC_NAME));
+ clearstatcache();
+ $this->assertEquals(8, $this->instance->file_put_contents('/' . self::NFC_NAME, 'barbaric'));
+ $this->assertEquals('barbaric', $this->instance->file_get_contents('//' . self::NFC_NAME));
+ }
+
+ public function sourceAndTargetDirectoryProvider() {
+ return [
+ [self::NFC_NAME . '1', self::NFC_NAME . '2'],
+ [self::NFD_NAME . '1', self::NFC_NAME . '2'],
+ [self::NFC_NAME . '1', self::NFD_NAME . '2'],
+ [self::NFD_NAME . '1', self::NFD_NAME . '2'],
+ ];
+ }
+
+ /**
+ * @dataProvider sourceAndTargetDirectoryProvider
+ */
+ public function testCopyAndMoveEncodedFolder($sourceDir, $targetDir) {
+ $this->sourceStorage->mkdir($sourceDir);
+ $this->sourceStorage->mkdir($targetDir);
+ $this->sourceStorage->file_put_contents($sourceDir . '/test.txt', 'bar');
+ $this->assertTrue($this->instance->copy(self::NFC_NAME . '1/test.txt', self::NFC_NAME . '2/test.txt'));
+
+ $this->assertTrue($this->instance->file_exists(self::NFC_NAME . '1/test.txt'));
+ $this->assertTrue($this->instance->file_exists(self::NFC_NAME . '2/test.txt'));
+ $this->assertEquals('bar', $this->instance->file_get_contents(self::NFC_NAME . '2/test.txt'));
+
+ $this->assertTrue($this->instance->rename(self::NFC_NAME . '1/test.txt', self::NFC_NAME . '2/test2.txt'));
+ $this->assertFalse($this->instance->file_exists(self::NFC_NAME . '1/test.txt'));
+ $this->assertTrue($this->instance->file_exists(self::NFC_NAME . '2/test2.txt'));
+
+ $this->assertEquals('bar', $this->instance->file_get_contents(self::NFC_NAME . '2/test2.txt'));
+ }
+
+ /**
+ * @dataProvider sourceAndTargetDirectoryProvider
+ */
+ public function testCopyAndMoveFromStorageEncodedFolder($sourceDir, $targetDir) {
+ $this->sourceStorage->mkdir($sourceDir);
+ $this->sourceStorage->mkdir($targetDir);
+ $this->sourceStorage->file_put_contents($sourceDir . '/test.txt', 'bar');
+ $this->assertTrue($this->instance->copyFromStorage($this->instance, self::NFC_NAME . '1/test.txt', self::NFC_NAME . '2/test.txt'));
+
+ $this->assertTrue($this->instance->file_exists(self::NFC_NAME . '1/test.txt'));
+ $this->assertTrue($this->instance->file_exists(self::NFC_NAME . '2/test.txt'));
+ $this->assertEquals('bar', $this->instance->file_get_contents(self::NFC_NAME . '2/test.txt'));
+
+ $this->assertTrue($this->instance->moveFromStorage($this->instance, self::NFC_NAME . '1/test.txt', self::NFC_NAME . '2/test2.txt'));
+ $this->assertFalse($this->instance->file_exists(self::NFC_NAME . '1/test.txt'));
+ $this->assertTrue($this->instance->file_exists(self::NFC_NAME . '2/test2.txt'));
+
+ $this->assertEquals('bar', $this->instance->file_get_contents(self::NFC_NAME . '2/test2.txt'));
+ }
+}
diff --git a/tests/settings/controller/AuthSettingsControllerTest.php b/tests/settings/controller/AuthSettingsControllerTest.php
new file mode 100644
index 00000000000..49491c8ff52
--- /dev/null
+++ b/tests/settings/controller/AuthSettingsControllerTest.php
@@ -0,0 +1,156 @@
+<?php
+
+/**
+ * @author Christoph Wurst <christoph@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 Test\Settings\Controller;
+
+use OC\AppFramework\Http;
+use OC\Authentication\Exceptions\InvalidTokenException;
+use OC\Authentication\Token\IToken;
+use OC\Settings\Controller\AuthSettingsController;
+use OCP\AppFramework\Http\JSONResponse;
+use OCP\Session\Exceptions\SessionNotAvailableException;
+use Test\TestCase;
+
+class AuthSettingsControllerTest extends TestCase {
+
+ /** @var AuthSettingsController */
+ private $controller;
+ private $request;
+ private $tokenProvider;
+ private $userManager;
+ private $session;
+ private $secureRandom;
+ private $uid;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->request = $this->getMock('\OCP\IRequest');
+ $this->tokenProvider = $this->getMock('\OC\Authentication\Token\IProvider');
+ $this->userManager = $this->getMock('\OCP\IUserManager');
+ $this->session = $this->getMock('\OCP\ISession');
+ $this->secureRandom = $this->getMock('\OCP\Security\ISecureRandom');
+ $this->uid = 'jane';
+ $this->user = $this->getMock('\OCP\IUser');
+
+ $this->controller = new AuthSettingsController('core', $this->request, $this->tokenProvider, $this->userManager, $this->session, $this->secureRandom, $this->uid);
+ }
+
+ public function testIndex() {
+ $result = [
+ 'token1',
+ 'token2',
+ ];
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with($this->uid)
+ ->will($this->returnValue($this->user));
+ $this->tokenProvider->expects($this->once())
+ ->method('getTokenByUser')
+ ->with($this->user)
+ ->will($this->returnValue($result));
+
+ $this->assertEquals($result, $this->controller->index());
+ }
+
+ public function testCreate() {
+ $name = 'Nexus 4';
+ $sessionToken = $this->getMock('\OC\Authentication\Token\IToken');
+ $deviceToken = $this->getMock('\OC\Authentication\Token\IToken');
+ $password = '123456';
+
+ $this->session->expects($this->once())
+ ->method('getId')
+ ->will($this->returnValue('sessionid'));
+ $this->tokenProvider->expects($this->once())
+ ->method('getToken')
+ ->with('sessionid')
+ ->will($this->returnValue($sessionToken));
+ $this->tokenProvider->expects($this->once())
+ ->method('getPassword')
+ ->with($sessionToken, 'sessionid')
+ ->will($this->returnValue($password));
+
+ $this->secureRandom->expects($this->exactly(4))
+ ->method('generate')
+ ->with(5, implode('', range('A', 'Z')))
+ ->will($this->returnValue('XXXXX'));
+ $newToken = 'XXXXX-XXXXX-XXXXX-XXXXX';
+
+ $this->tokenProvider->expects($this->once())
+ ->method('generateToken')
+ ->with($newToken, $this->uid, $password, $name, IToken::PERMANENT_TOKEN)
+ ->will($this->returnValue($deviceToken));
+
+ $expected = [
+ 'token' => $newToken,
+ 'deviceToken' => $deviceToken,
+ ];
+ $this->assertEquals($expected, $this->controller->create($name));
+ }
+
+ public function testCreateSessionNotAvailable() {
+ $name = 'personal phone';
+
+ $this->session->expects($this->once())
+ ->method('getId')
+ ->will($this->throwException(new SessionNotAvailableException()));
+
+ $expected = new JSONResponse();
+ $expected->setStatus(Http::STATUS_SERVICE_UNAVAILABLE);
+
+ $this->assertEquals($expected, $this->controller->create($name));
+ }
+
+ public function testCreateInvalidToken() {
+ $name = 'Company IPhone';
+
+ $this->session->expects($this->once())
+ ->method('getId')
+ ->will($this->returnValue('sessionid'));
+ $this->tokenProvider->expects($this->once())
+ ->method('getToken')
+ ->with('sessionid')
+ ->will($this->throwException(new InvalidTokenException()));
+
+ $expected = new JSONResponse();
+ $expected->setStatus(Http::STATUS_SERVICE_UNAVAILABLE);
+
+ $this->assertEquals($expected, $this->controller->create($name));
+ }
+
+ public function testDestroy() {
+ $id = 123;
+ $user = $this->getMock('\OCP\IUser');
+
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with($this->uid)
+ ->will($this->returnValue($user));
+ $this->tokenProvider->expects($this->once())
+ ->method('invalidateTokenById')
+ ->with($user, $id);
+
+ $this->assertEquals([], $this->controller->destroy($id));
+ }
+
+}