aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/encryption/lib/crypto/encryptall.php6
-rw-r--r--apps/files/css/detailsView.css8
-rw-r--r--apps/files/js/mainfileinfodetailview.js6
-rw-r--r--apps/files_external/controller/globalstoragescontroller.php9
-rw-r--r--apps/files_external/controller/storagescontroller.php13
-rw-r--r--apps/files_external/controller/userstoragescontroller.php9
-rw-r--r--apps/files_external/lib/config.php14
-rw-r--r--apps/files_external/lib/config/configadapter.php2
-rw-r--r--apps/files_external/personal.php2
-rw-r--r--apps/files_external/service/globalstoragesservice.php9
-rw-r--r--apps/files_external/service/storagesservice.php45
-rw-r--r--apps/files_external/service/userglobalstoragesservice.php2
-rw-r--r--apps/files_external/service/userstoragesservice.php9
-rw-r--r--apps/files_external/settings.php2
-rw-r--r--apps/files_external/tests/controller/globalstoragescontrollertest.php4
-rw-r--r--apps/files_external/tests/controller/userstoragescontrollertest.php3
-rw-r--r--apps/files_external/tests/service/storagesservicetest.php46
-rw-r--r--apps/files_external/tests/service/userglobalstoragesservicetest.php14
-rw-r--r--apps/files_sharing/api/sharees.php20
-rw-r--r--apps/files_sharing/js/public.js24
-rw-r--r--apps/files_sharing/lib/mountprovider.php3
-rw-r--r--apps/files_sharing/lib/sharedstorage.php21
-rw-r--r--apps/files_sharing/tests/api/shareestest.php438
-rw-r--r--apps/user_ldap/js/wizard/wizardTabLoginFilter.js13
-rw-r--r--apps/user_ldap/templates/part.wizard-loginfilter.php2
-rw-r--r--core/ajax/share.php10
-rw-r--r--core/img/actions/close.pngbin206 -> 493 bytes
-rw-r--r--core/img/actions/close.svg9
-rw-r--r--core/js/oc-dialogs.js4
-rw-r--r--core/js/shareitemmodel.js19
-rw-r--r--core/js/tests/specs/shareitemmodelSpec.js65
-rw-r--r--core/shipped.json4
-rw-r--r--lib/private/app.php2
-rw-r--r--lib/private/connector/sabre/listenerplugin.php12
-rw-r--r--lib/private/db/querybuilder/quotehelper.php2
-rw-r--r--lib/private/encryption/decryptall.php2
-rw-r--r--lib/private/files/storage/wrapper/permissionsmask.php2
-rw-r--r--lib/private/files/view.php5
-rw-r--r--lib/public/sabrepluginevent.php82
-rw-r--r--lib/public/sabrepluginexception.php41
-rw-r--r--settings/admin.php1
-rw-r--r--settings/templates/admin.php5
-rw-r--r--tests/lib/db/querybuilder/quotehelpertest.php4
-rw-r--r--tests/lib/encryption/decryptalltest.php16
-rw-r--r--tests/lib/files/storage/storage.php25
-rw-r--r--tests/lib/files/view.php135
46 files changed, 1006 insertions, 163 deletions
diff --git a/apps/encryption/lib/crypto/encryptall.php b/apps/encryption/lib/crypto/encryptall.php
index a0c69c13fdd..8e97fe341b4 100644
--- a/apps/encryption/lib/crypto/encryptall.php
+++ b/apps/encryption/lib/crypto/encryptall.php
@@ -280,6 +280,12 @@ class EncryptAll {
$newPasswords[] = [$uid, $password];
}
}
+
+ if (empty($newPasswords)) {
+ $this->output->writeln("\nAll users already had a key-pair, no further action needed.\n");
+ return;
+ }
+
$table->setRows($newPasswords);
$table->render();
diff --git a/apps/files/css/detailsView.css b/apps/files/css/detailsView.css
index 8acf884f219..faa26678562 100644
--- a/apps/files/css/detailsView.css
+++ b/apps/files/css/detailsView.css
@@ -32,12 +32,18 @@
#app-sidebar .image .thumbnail {
width:100%;
display:block;
- height: 250px;
background-repeat: no-repeat;
background-position: center;
background-size: 100%;
float: none;
margin: 0;
+ height: auto;
+}
+
+#app-sidebar .image.landscape .thumbnail::before {
+ content: '';
+ display: block;
+ padding-bottom: 56.25%; /* sets height of .thumbnail to 9/16 of the width */
}
#app-sidebar .image.portrait .thumbnail {
diff --git a/apps/files/js/mainfileinfodetailview.js b/apps/files/js/mainfileinfodetailview.js
index 830f074f3f1..82cca0d0fb3 100644
--- a/apps/files/js/mainfileinfodetailview.js
+++ b/apps/files/js/mainfileinfodetailview.js
@@ -176,9 +176,7 @@
$iconDiv.removeClass('icon-loading icon-32');
var targetHeight = getTargetHeight(img);
if (this.model.isImage() && targetHeight > smallPreviewSize) {
- if (!isLandscape(img)) {
- $container.addClass('portrait');
- }
+ $container.addClass(isLandscape(img)? 'landscape': 'portrait');
$container.addClass('image');
}
@@ -186,7 +184,7 @@
// when we dont have a preview we show the mime icon in the error handler
$iconDiv.css({
'background-image': 'url("' + previewUrl + '")',
- 'height': targetHeight
+ height: (isLandscape(img) && targetHeight > smallPreviewSize)? 'auto': targetHeight
});
}.bind(this),
error: function () {
diff --git a/apps/files_external/controller/globalstoragescontroller.php b/apps/files_external/controller/globalstoragescontroller.php
index 3686a6189b4..3c1f2022505 100644
--- a/apps/files_external/controller/globalstoragescontroller.php
+++ b/apps/files_external/controller/globalstoragescontroller.php
@@ -179,14 +179,5 @@ class GlobalStoragesController extends StoragesController {
}
- /**
- * Get the visibility type for this controller, used in validation
- *
- * @return string BackendService::VISIBILITY_* constants
- */
- protected function getVisibilityType() {
- return BackendService::VISIBILITY_ADMIN;
- }
-
}
diff --git a/apps/files_external/controller/storagescontroller.php b/apps/files_external/controller/storagescontroller.php
index 71055fd1b9c..6a01112f8c5 100644
--- a/apps/files_external/controller/storagescontroller.php
+++ b/apps/files_external/controller/storagescontroller.php
@@ -153,7 +153,7 @@ abstract class StoragesController extends Controller {
$backend = $storage->getBackend();
/** @var AuthMechanism */
$authMechanism = $storage->getAuthMechanism();
- if (!$backend || $backend->checkDependencies()) {
+ if ($backend->checkDependencies()) {
// invalid backend
return new DataResponse(
array(
@@ -165,7 +165,7 @@ abstract class StoragesController extends Controller {
);
}
- if (!$backend->isVisibleFor($this->getVisibilityType())) {
+ if (!$backend->isVisibleFor($this->service->getVisibilityType())) {
// not permitted to use backend
return new DataResponse(
array(
@@ -176,7 +176,7 @@ abstract class StoragesController extends Controller {
Http::STATUS_UNPROCESSABLE_ENTITY
);
}
- if (!$authMechanism->isVisibleFor($this->getVisibilityType())) {
+ if (!$authMechanism->isVisibleFor($this->service->getVisibilityType())) {
// not permitted to use auth mechanism
return new DataResponse(
array(
@@ -211,13 +211,6 @@ abstract class StoragesController extends Controller {
}
/**
- * Get the visibility type for this controller, used in validation
- *
- * @return string BackendService::VISIBILITY_* constants
- */
- abstract protected function getVisibilityType();
-
- /**
* Check whether the given storage is available / valid.
*
* Note that this operation can be time consuming depending
diff --git a/apps/files_external/controller/userstoragescontroller.php b/apps/files_external/controller/userstoragescontroller.php
index fcbe692d79e..f39f8a85d2d 100644
--- a/apps/files_external/controller/userstoragescontroller.php
+++ b/apps/files_external/controller/userstoragescontroller.php
@@ -187,13 +187,4 @@ class UserStoragesController extends StoragesController {
return parent::destroy($id);
}
- /**
- * Get the visibility type for this controller, used in validation
- *
- * @return string BackendService::VISIBILITY_* constants
- */
- protected function getVisibilityType() {
- return BackendService::VISIBILITY_PERSONAL;
- }
-
}
diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php
index 2dc7de30a6c..afea7ead4e6 100644
--- a/apps/files_external/lib/config.php
+++ b/apps/files_external/lib/config.php
@@ -112,7 +112,7 @@ class OC_Mount_Config {
* @param string $uid user
* @return array of mount point string as key, mountpoint config as value
*
- * @deprecated 8.2.0 use UserGlobalStoragesService::getAllStorages() and UserStoragesService::getAllStorages()
+ * @deprecated 8.2.0 use UserGlobalStoragesService::getStorages() and UserStoragesService::getStorages()
*/
public static function getAbsoluteMountPoints($uid) {
$mountPoints = array();
@@ -124,7 +124,7 @@ class OC_Mount_Config {
$userGlobalStoragesService->setUser($user);
$userStoragesService->setUser($user);
- foreach ($userGlobalStoragesService->getAllStorages() as $storage) {
+ foreach ($userGlobalStoragesService->getStorages() as $storage) {
$mountPoint = '/'.$uid.'/files'.$storage->getMountPoint();
$mountEntry = self::prepareMountPointEntry($storage, false);
foreach ($mountEntry['options'] as &$option) {
@@ -133,7 +133,7 @@ class OC_Mount_Config {
$mountPoints[$mountPoint] = $mountEntry;
}
- foreach ($userStoragesService->getAllStorages() as $storage) {
+ foreach ($userStoragesService->getStorages() as $storage) {
$mountPoint = '/'.$uid.'/files'.$storage->getMountPoint();
$mountEntry = self::prepareMountPointEntry($storage, true);
foreach ($mountEntry['options'] as &$option) {
@@ -153,13 +153,13 @@ class OC_Mount_Config {
*
* @return array
*
- * @deprecated 8.2.0 use GlobalStoragesService::getAllStorages()
+ * @deprecated 8.2.0 use GlobalStoragesService::getStorages()
*/
public static function getSystemMountPoints() {
$mountPoints = [];
$service = self::$app->getContainer()->query('OCA\Files_External\Service\GlobalStoragesService');
- foreach ($service->getAllStorages() as $storage) {
+ foreach ($service->getStorages() as $storage) {
$mountPoints[] = self::prepareMountPointEntry($storage, false);
}
@@ -171,13 +171,13 @@ class OC_Mount_Config {
*
* @return array
*
- * @deprecated 8.2.0 use UserStoragesService::getAllStorages()
+ * @deprecated 8.2.0 use UserStoragesService::getStorages()
*/
public static function getPersonalMountPoints() {
$mountPoints = [];
$service = self::$app->getContainer()->query('OCA\Files_External\Service\UserStoragesService');
- foreach ($service->getAllStorages() as $storage) {
+ foreach ($service->getStorages() as $storage) {
$mountPoints[] = self::prepareMountPointEntry($storage, true);
}
diff --git a/apps/files_external/lib/config/configadapter.php b/apps/files_external/lib/config/configadapter.php
index cb8c2f24caa..fb36e011655 100644
--- a/apps/files_external/lib/config/configadapter.php
+++ b/apps/files_external/lib/config/configadapter.php
@@ -133,7 +133,7 @@ class ConfigAdapter implements IMountProvider {
$mounts[$storage->getMountPoint()] = $mount;
}
- foreach ($this->userStoragesService->getAllStorages() as $storage) {
+ foreach ($this->userStoragesService->getStorages() as $storage) {
try {
$this->prepareStorageConfig($storage, $user);
$impl = $this->constructStorage($storage);
diff --git a/apps/files_external/personal.php b/apps/files_external/personal.php
index efd23512ffe..f048d65540b 100644
--- a/apps/files_external/personal.php
+++ b/apps/files_external/personal.php
@@ -54,7 +54,7 @@ foreach ($authMechanisms as $authMechanism) {
$tmpl = new OCP\Template('files_external', 'settings');
$tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled());
$tmpl->assign('isAdminPage', false);
-$tmpl->assign('storages', $userStoragesService->getAllStorages());
+$tmpl->assign('storages', $userStoragesService->getStorages());
$tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends()));
$tmpl->assign('backends', $backends);
$tmpl->assign('authMechanisms', $authMechanisms);
diff --git a/apps/files_external/service/globalstoragesservice.php b/apps/files_external/service/globalstoragesservice.php
index 0e2d3f2b9c1..49ffea43d1b 100644
--- a/apps/files_external/service/globalstoragesservice.php
+++ b/apps/files_external/service/globalstoragesservice.php
@@ -210,4 +210,13 @@ class GlobalStoragesService extends StoragesService {
);
}
}
+
+ /**
+ * Get the visibility type for this controller, used in validation
+ *
+ * @return string BackendService::VISIBILITY_* constants
+ */
+ public function getVisibilityType() {
+ return BackendService::VISIBILITY_ADMIN;
+ }
}
diff --git a/apps/files_external/service/storagesservice.php b/apps/files_external/service/storagesservice.php
index 703f277d84e..83a82de0bed 100644
--- a/apps/files_external/service/storagesservice.php
+++ b/apps/files_external/service/storagesservice.php
@@ -29,6 +29,8 @@ use \OC\Files\Filesystem;
use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_external\NotFoundException;
use \OCA\Files_External\Service\BackendService;
+use \OCA\Files_External\Lib\Backend\Backend;
+use \OCA\Files_External\Lib\Auth\AuthMechanism;
/**
* Service class to manage external storages
@@ -331,7 +333,7 @@ abstract class StoragesService {
}
/**
- * Gets all storages
+ * Gets all storages, valid or not
*
* @return array array of storage configs
*/
@@ -340,6 +342,47 @@ abstract class StoragesService {
}
/**
+ * Gets all valid storages
+ *
+ * @return array
+ */
+ public function getStorages() {
+ return array_filter($this->getAllStorages(), [$this, 'validateStorage']);
+ }
+
+ /**
+ * Validate storage
+ * FIXME: De-duplicate with StoragesController::validate()
+ *
+ * @param StorageConfig $storage
+ * @return bool
+ */
+ protected function validateStorage(StorageConfig $storage) {
+ /** @var Backend */
+ $backend = $storage->getBackend();
+ /** @var AuthMechanism */
+ $authMechanism = $storage->getAuthMechanism();
+
+ if (!$backend->isVisibleFor($this->getVisibilityType())) {
+ // not permitted to use backend
+ return false;
+ }
+ if (!$authMechanism->isVisibleFor($this->getVisibilityType())) {
+ // not permitted to use auth mechanism
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Get the visibility type for this controller, used in validation
+ *
+ * @return string BackendService::VISIBILITY_* constants
+ */
+ abstract public function getVisibilityType();
+
+ /**
* Add new storage to the configuration
*
* @param array $newStorage storage attributes
diff --git a/apps/files_external/service/userglobalstoragesservice.php b/apps/files_external/service/userglobalstoragesservice.php
index b60473f131e..7c60bc6d497 100644
--- a/apps/files_external/service/userglobalstoragesservice.php
+++ b/apps/files_external/service/userglobalstoragesservice.php
@@ -117,7 +117,7 @@ class UserGlobalStoragesService extends GlobalStoragesService {
* @return StorageConfig[]
*/
public function getUniqueStorages() {
- $storages = $this->getAllStorages();
+ $storages = $this->getStorages();
$storagesByMountpoint = [];
foreach ($storages as $storage) {
diff --git a/apps/files_external/service/userstoragesservice.php b/apps/files_external/service/userstoragesservice.php
index c69b8d4f51e..6e3c327c09c 100644
--- a/apps/files_external/service/userstoragesservice.php
+++ b/apps/files_external/service/userstoragesservice.php
@@ -171,4 +171,13 @@ class UserStoragesService extends StoragesService {
$this->triggerHooks($newStorage, Filesystem::signal_create_mount);
}
}
+
+ /**
+ * Get the visibility type for this controller, used in validation
+ *
+ * @return string BackendService::VISIBILITY_* constants
+ */
+ public function getVisibilityType() {
+ return BackendService::VISIBILITY_PERSONAL;
+ }
}
diff --git a/apps/files_external/settings.php b/apps/files_external/settings.php
index 5c920a1495b..f82ab035c1c 100644
--- a/apps/files_external/settings.php
+++ b/apps/files_external/settings.php
@@ -65,7 +65,7 @@ $userBackends = array_filter($backendService->getAvailableBackends(), function($
$tmpl = new OCP\Template('files_external', 'settings');
$tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled());
$tmpl->assign('isAdminPage', true);
-$tmpl->assign('storages', $globalStoragesService->getAllStorages());
+$tmpl->assign('storages', $globalStoragesService->getStorages());
$tmpl->assign('backends', $backends);
$tmpl->assign('authMechanisms', $authMechanisms);
$tmpl->assign('userBackends', $userBackends);
diff --git a/apps/files_external/tests/controller/globalstoragescontrollertest.php b/apps/files_external/tests/controller/globalstoragescontrollertest.php
index e1bfad8caf6..6b020198bd8 100644
--- a/apps/files_external/tests/controller/globalstoragescontrollertest.php
+++ b/apps/files_external/tests/controller/globalstoragescontrollertest.php
@@ -24,6 +24,7 @@ use \OCA\Files_external\Controller\GlobalStoragesController;
use \OCA\Files_external\Service\GlobalStoragesService;
use \OCP\AppFramework\Http;
use \OCA\Files_external\NotFoundException;
+use \OCA\Files_External\Service\BackendService;
class GlobalStoragesControllerTest extends StoragesControllerTest {
public function setUp() {
@@ -32,6 +33,9 @@ class GlobalStoragesControllerTest extends StoragesControllerTest {
->disableOriginalConstructor()
->getMock();
+ $this->service->method('getVisibilityType')
+ ->willReturn(BackendService::VISIBILITY_ADMIN);
+
$this->controller = new GlobalStoragesController(
'files_external',
$this->getMock('\OCP\IRequest'),
diff --git a/apps/files_external/tests/controller/userstoragescontrollertest.php b/apps/files_external/tests/controller/userstoragescontrollertest.php
index 9f1a8df8d2e..33ef274c87c 100644
--- a/apps/files_external/tests/controller/userstoragescontrollertest.php
+++ b/apps/files_external/tests/controller/userstoragescontrollertest.php
@@ -40,6 +40,9 @@ class UserStoragesControllerTest extends StoragesControllerTest {
->disableOriginalConstructor()
->getMock();
+ $this->service->method('getVisibilityType')
+ ->willReturn(BackendService::VISIBILITY_PERSONAL);
+
$this->controller = new UserStoragesController(
'files_external',
$this->getMock('\OCP\IRequest'),
diff --git a/apps/files_external/tests/service/storagesservicetest.php b/apps/files_external/tests/service/storagesservicetest.php
index 28220c9bc2e..ddf52e6272e 100644
--- a/apps/files_external/tests/service/storagesservicetest.php
+++ b/apps/files_external/tests/service/storagesservicetest.php
@@ -305,6 +305,52 @@ abstract class StoragesServiceTest extends \Test\TestCase {
);
}
+ public function testGetStoragesBackendNotVisible() {
+ $backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
+ $backend->expects($this->once())
+ ->method('isVisibleFor')
+ ->with($this->service->getVisibilityType())
+ ->willReturn(false);
+ $authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
+ $authMechanism->method('isVisibleFor')
+ ->with($this->service->getVisibilityType())
+ ->willReturn(true);
+
+ $storage = new StorageConfig(255);
+ $storage->setMountPoint('mountpoint');
+ $storage->setBackend($backend);
+ $storage->setAuthMechanism($authMechanism);
+ $storage->setBackendOptions(['password' => 'testPassword']);
+
+ $newStorage = $this->service->addStorage($storage);
+
+ $this->assertCount(1, $this->service->getAllStorages());
+ $this->assertEmpty($this->service->getStorages());
+ }
+
+ public function testGetStoragesAuthMechanismNotVisible() {
+ $backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
+ $backend->method('isVisibleFor')
+ ->with($this->service->getVisibilityType())
+ ->willReturn(true);
+ $authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
+ $authMechanism->expects($this->once())
+ ->method('isVisibleFor')
+ ->with($this->service->getVisibilityType())
+ ->willReturn(false);
+
+ $storage = new StorageConfig(255);
+ $storage->setMountPoint('mountpoint');
+ $storage->setBackend($backend);
+ $storage->setAuthMechanism($authMechanism);
+ $storage->setBackendOptions(['password' => 'testPassword']);
+
+ $newStorage = $this->service->addStorage($storage);
+
+ $this->assertCount(1, $this->service->getAllStorages());
+ $this->assertEmpty($this->service->getStorages());
+ }
+
public static function createHookCallback($params) {
self::$hookCalls[] = array(
'signal' => Filesystem::signal_create_mount,
diff --git a/apps/files_external/tests/service/userglobalstoragesservicetest.php b/apps/files_external/tests/service/userglobalstoragesservicetest.php
index 867872f3683..b6dc952605d 100644
--- a/apps/files_external/tests/service/userglobalstoragesservicetest.php
+++ b/apps/files_external/tests/service/userglobalstoragesservicetest.php
@@ -209,7 +209,11 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest {
$expectedPrecedence
) {
$backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
+ $backend->method('isVisibleFor')
+ ->willReturn(true);
$authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
+ $authMechanism->method('isVisibleFor')
+ ->willReturn(true);
$storage1 = new StorageConfig();
$storage1->setMountPoint('mountpoint');
@@ -243,6 +247,16 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest {
}
}
+ public function testGetStoragesBackendNotVisible() {
+ // we don't test this here
+ $this->assertTrue(true);
+ }
+
+ public function testGetStoragesAuthMechanismNotVisible() {
+ // we don't test this here
+ $this->assertTrue(true);
+ }
+
public function testHooksAddStorage($a = null, $b = null, $c = null) {
// we don't test this here
$this->assertTrue(true);
diff --git a/apps/files_sharing/api/sharees.php b/apps/files_sharing/api/sharees.php
index 9e324078dad..734c267020f 100644
--- a/apps/files_sharing/api/sharees.php
+++ b/apps/files_sharing/api/sharees.php
@@ -62,6 +62,9 @@ class Sharees {
/** @var bool */
protected $shareWithGroupOnly = false;
+ /** @var bool */
+ protected $shareeEnumeration = true;
+
/** @var int */
protected $offset = 0;
@@ -134,7 +137,7 @@ class Sharees {
}
}
- if (sizeof($users) < $this->limit) {
+ if (!$this->shareeEnumeration || sizeof($users) < $this->limit) {
$this->reachedEndFor[] = 'users';
}
@@ -176,6 +179,10 @@ class Sharees {
]);
}
}
+
+ if (!$this->shareeEnumeration) {
+ $this->result['users'] = [];
+ }
}
/**
@@ -187,7 +194,7 @@ class Sharees {
$groups = $this->groupManager->search($search, $this->limit, $this->offset);
$groups = array_map(function (IGroup $group) { return $group->getGID(); }, $groups);
- if (sizeof($groups) < $this->limit) {
+ if (!$this->shareeEnumeration || sizeof($groups) < $this->limit) {
$this->reachedEndFor[] = 'groups';
}
@@ -233,6 +240,10 @@ class Sharees {
]);
}
}
+
+ if (!$this->shareeEnumeration) {
+ $this->result['groups'] = [];
+ }
}
/**
@@ -273,6 +284,10 @@ class Sharees {
}
}
+ if (!$this->shareeEnumeration) {
+ $this->result['remotes'] = [];
+ }
+
if (!$foundRemoteById && substr_count($search, '@') >= 1 && substr_count($search, ' ') === 0 && $this->offset === 0) {
$this->result['exact']['remotes'][] = [
'label' => $search,
@@ -322,6 +337,7 @@ class Sharees {
}
$this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
+ $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
$this->limit = (int) $perPage;
$this->offset = $perPage * ($page - 1);
diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js
index 1993efe7d73..4908968a937 100644
--- a/apps/files_sharing/js/public.js
+++ b/apps/files_sharing/js/public.js
@@ -159,9 +159,18 @@ OCA.Sharing.PublicApp = {
};
this.fileList.generatePreviewUrl = function (urlSpec) {
+ urlSpec = urlSpec || {};
+ if (!urlSpec.x) {
+ urlSpec.x = 36;
+ }
+ if (!urlSpec.y) {
+ urlSpec.y = 36;
+ }
+ urlSpec.x *= window.devicePixelRatio;
+ urlSpec.y *= window.devicePixelRatio;
+ urlSpec.x = Math.floor(urlSpec.x);
+ urlSpec.y = Math.floor(urlSpec.y);
urlSpec.t = $('#dirToken').val();
- urlSpec.y = Math.floor(36 * window.devicePixelRatio);
- urlSpec.x = Math.floor(36 * window.devicePixelRatio);
return OC.generateUrl('/apps/files_sharing/ajax/publicpreview.php?') + $.param(urlSpec);
};
@@ -293,15 +302,8 @@ $(document).ready(function () {
if (window.Files) {
// HACK: for oc-dialogs previews that depends on Files:
- Files.lazyLoadPreview = function (path, mime, ready, width, height, etag) {
- return App.fileList.lazyLoadPreview({
- path: path,
- mime: mime,
- callback: ready,
- width: width,
- height: height,
- etag: etag
- });
+ Files.generatePreviewUrl = function (urlSpec) {
+ return App.fileList.generatePreviewUrl(urlSpec);
};
}
});
diff --git a/apps/files_sharing/lib/mountprovider.php b/apps/files_sharing/lib/mountprovider.php
index 14a79625993..458e7f2619b 100644
--- a/apps/files_sharing/lib/mountprovider.php
+++ b/apps/files_sharing/lib/mountprovider.php
@@ -69,12 +69,11 @@ class MountProvider implements IMountProvider {
// for updating etags for the share owner when we make changes to this share.
$ownerPropagator = $this->propagationManager->getChangePropagator($share['uid_owner']);
- // for updating our etags when changes are made to the share from the owners side (probably indirectly by us trough another share)
- $this->propagationManager->listenToOwnerChanges($share['uid_owner'], $user->getUID());
return new SharedMount(
'\OC\Files\Storage\Shared',
'/' . $user->getUID() . '/' . $share['file_target'],
array(
+ 'propagationManager' => $this->propagationManager,
'propagator' => $ownerPropagator,
'share' => $share,
'user' => $user->getUID()
diff --git a/apps/files_sharing/lib/sharedstorage.php b/apps/files_sharing/lib/sharedstorage.php
index 1ac401f3cf8..27dd2f1e485 100644
--- a/apps/files_sharing/lib/sharedstorage.php
+++ b/apps/files_sharing/lib/sharedstorage.php
@@ -50,13 +50,34 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
*/
private $ownerView;
+ /**
+ * @var \OCA\Files_Sharing\Propagation\PropagationManager
+ */
+ private $propagationManager;
+
+ /**
+ * @var string
+ */
+ private $user;
+
+ private $initialized = false;
+
public function __construct($arguments) {
$this->share = $arguments['share'];
$this->ownerView = $arguments['ownerView'];
+ $this->propagationManager = $arguments['propagationManager'];
+ $this->user = $arguments['user'];
}
private function init() {
+ if ($this->initialized) {
+ return;
+ }
+ $this->initialized = true;
Filesystem::initMountPoints($this->share['uid_owner']);
+
+ // for updating our etags when changes are made to the share from the owners side (probably indirectly by us trough another share)
+ $this->propagationManager->listenToOwnerChanges($this->share['uid_owner'], $this->user);
}
/**
diff --git a/apps/files_sharing/tests/api/shareestest.php b/apps/files_sharing/tests/api/shareestest.php
index 5c5d5b0d309..91b8b1c7e66 100644
--- a/apps/files_sharing/tests/api/shareestest.php
+++ b/apps/files_sharing/tests/api/shareestest.php
@@ -110,16 +110,30 @@ class ShareesTest extends TestCase {
public function dataGetUsers() {
return [
- ['test', false, [], [], [], [], true, false],
- ['test', true, [], [], [], [], true, false],
+ ['test', false, true, [], [], [], [], true, false],
+ ['test', false, false, [], [], [], [], true, false],
+ ['test', true, true, [], [], [], [], true, false],
+ ['test', true, false, [], [], [], [], true, false],
[
- 'test', false, [], [],
+ 'test', false, true, [], [],
[
['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']],
], [], true, $this->getUserMock('test', 'Test')
],
[
- 'test', true, [], [],
+ 'test', false, false, [], [],
+ [
+ ['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']],
+ ], [], true, $this->getUserMock('test', 'Test')
+ ],
+ [
+ 'test', true, true, [], [],
+ [
+ ['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']],
+ ], [], true, $this->getUserMock('test', 'Test')
+ ],
+ [
+ 'test', true, false, [], [],
[
['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']],
], [], true, $this->getUserMock('test', 'Test')
@@ -127,6 +141,7 @@ class ShareesTest extends TestCase {
[
'test',
false,
+ true,
[],
[
$this->getUserMock('test1', 'Test One'),
@@ -141,6 +156,20 @@ class ShareesTest extends TestCase {
[
'test',
false,
+ false,
+ [],
+ [
+ $this->getUserMock('test1', 'Test One'),
+ ],
+ [],
+ [],
+ true,
+ false,
+ ],
+ [
+ 'test',
+ false,
+ true,
[],
[
$this->getUserMock('test1', 'Test One'),
@@ -157,6 +186,21 @@ class ShareesTest extends TestCase {
[
'test',
false,
+ false,
+ [],
+ [
+ $this->getUserMock('test1', 'Test One'),
+ $this->getUserMock('test2', 'Test Two'),
+ ],
+ [],
+ [],
+ true,
+ false,
+ ],
+ [
+ 'test',
+ false,
+ true,
[],
[
$this->getUserMock('test0', 'Test'),
@@ -175,6 +219,24 @@ class ShareesTest extends TestCase {
],
[
'test',
+ false,
+ false,
+ [],
+ [
+ $this->getUserMock('test0', 'Test'),
+ $this->getUserMock('test1', 'Test One'),
+ $this->getUserMock('test2', 'Test Two'),
+ ],
+ [
+ ['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test0']],
+ ],
+ [],
+ true,
+ false,
+ ],
+ [
+ 'test',
+ true,
true,
['abc', 'xyz'],
[
@@ -191,6 +253,21 @@ class ShareesTest extends TestCase {
[
'test',
true,
+ false,
+ ['abc', 'xyz'],
+ [
+ ['abc', 'test', 2, 0, ['test1' => 'Test One']],
+ ['xyz', 'test', 2, 0, []],
+ ],
+ [],
+ [],
+ true,
+ false,
+ ],
+ [
+ 'test',
+ true,
+ true,
['abc', 'xyz'],
[
['abc', 'test', 2, 0, [
@@ -213,6 +290,27 @@ class ShareesTest extends TestCase {
[
'test',
true,
+ false,
+ ['abc', 'xyz'],
+ [
+ ['abc', 'test', 2, 0, [
+ 'test1' => 'Test One',
+ 'test2' => 'Test Two',
+ ]],
+ ['xyz', 'test', 2, 0, [
+ 'test1' => 'Test One',
+ 'test2' => 'Test Two',
+ ]],
+ ],
+ [],
+ [],
+ true,
+ false,
+ ],
+ [
+ 'test',
+ true,
+ true,
['abc', 'xyz'],
[
['abc', 'test', 2, 0, [
@@ -231,6 +329,26 @@ class ShareesTest extends TestCase {
false,
false,
],
+ [
+ 'test',
+ true,
+ false,
+ ['abc', 'xyz'],
+ [
+ ['abc', 'test', 2, 0, [
+ 'test' => 'Test One',
+ ]],
+ ['xyz', 'test', 2, 0, [
+ 'test2' => 'Test Two',
+ ]],
+ ],
+ [
+ ['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']],
+ ],
+ [],
+ true,
+ false,
+ ],
];
}
@@ -239,6 +357,7 @@ class ShareesTest extends TestCase {
*
* @param string $searchTerm
* @param bool $shareWithGroupOnly
+ * @param bool $shareeEnumeration
* @param array $groupResponse
* @param array $userResponse
* @param array $exactExpected
@@ -246,10 +365,11 @@ class ShareesTest extends TestCase {
* @param bool $reachedEnd
* @param mixed $singleUser
*/
- public function testGetUsers($searchTerm, $shareWithGroupOnly, $groupResponse, $userResponse, $exactExpected, $expected, $reachedEnd, $singleUser) {
+ public function testGetUsers($searchTerm, $shareWithGroupOnly, $shareeEnumeration, $groupResponse, $userResponse, $exactExpected, $expected, $reachedEnd, $singleUser) {
$this->invokePrivate($this->sharees, 'limit', [2]);
$this->invokePrivate($this->sharees, 'offset', [0]);
$this->invokePrivate($this->sharees, 'shareWithGroupOnly', [$shareWithGroupOnly]);
+ $this->invokePrivate($this->sharees, 'shareeEnumeration', [$shareeEnumeration]);
$user = $this->getUserMock('admin', 'Administrator');
$this->session->expects($this->any())
@@ -290,9 +410,10 @@ class ShareesTest extends TestCase {
public function dataGetGroups() {
return [
- ['test', false, [], [], [], [], true, false],
+ ['test', false, true, [], [], [], [], true, false],
+ ['test', false, false, [], [], [], [], true, false],
[
- 'test', false,
+ 'test', false, true,
[$this->getGroupMock('test1')],
[],
[],
@@ -301,7 +422,16 @@ class ShareesTest extends TestCase {
false,
],
[
- 'test', false,
+ 'test', false, false,
+ [$this->getGroupMock('test1')],
+ [],
+ [],
+ [],
+ true,
+ false,
+ ],
+ [
+ 'test', false, true,
[
$this->getGroupMock('test'),
$this->getGroupMock('test1'),
@@ -313,7 +443,19 @@ class ShareesTest extends TestCase {
false,
],
[
- 'test', false,
+ 'test', false, false,
+ [
+ $this->getGroupMock('test'),
+ $this->getGroupMock('test1'),
+ ],
+ [],
+ [['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']]],
+ [],
+ true,
+ false,
+ ],
+ [
+ 'test', false, true,
[
$this->getGroupMock('test0'),
$this->getGroupMock('test1'),
@@ -328,7 +470,19 @@ class ShareesTest extends TestCase {
null,
],
[
- 'test', false,
+ 'test', false, false,
+ [
+ $this->getGroupMock('test0'),
+ $this->getGroupMock('test1'),
+ ],
+ [],
+ [],
+ [],
+ true,
+ null,
+ ],
+ [
+ 'test', false, true,
[
$this->getGroupMock('test0'),
$this->getGroupMock('test1'),
@@ -344,9 +498,24 @@ class ShareesTest extends TestCase {
false,
$this->getGroupMock('test'),
],
- ['test', true, [], [], [], [], true, false],
[
- 'test', true,
+ 'test', false, false,
+ [
+ $this->getGroupMock('test0'),
+ $this->getGroupMock('test1'),
+ ],
+ [],
+ [
+ ['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']],
+ ],
+ [],
+ true,
+ $this->getGroupMock('test'),
+ ],
+ ['test', true, true, [], [], [], [], true, false],
+ ['test', true, false, [], [], [], [], true, false],
+ [
+ 'test', true, true,
[
$this->getGroupMock('test1'),
$this->getGroupMock('test2'),
@@ -358,7 +527,19 @@ class ShareesTest extends TestCase {
false,
],
[
- 'test', true,
+ 'test', true, false,
+ [
+ $this->getGroupMock('test1'),
+ $this->getGroupMock('test2'),
+ ],
+ [$this->getGroupMock('test1')],
+ [],
+ [],
+ true,
+ false,
+ ],
+ [
+ 'test', true, true,
[
$this->getGroupMock('test'),
$this->getGroupMock('test1'),
@@ -370,7 +551,19 @@ class ShareesTest extends TestCase {
false,
],
[
- 'test', true,
+ 'test', true, false,
+ [
+ $this->getGroupMock('test'),
+ $this->getGroupMock('test1'),
+ ],
+ [$this->getGroupMock('test')],
+ [['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']]],
+ [],
+ true,
+ false,
+ ],
+ [
+ 'test', true, true,
[
$this->getGroupMock('test'),
$this->getGroupMock('test1'),
@@ -382,7 +575,19 @@ class ShareesTest extends TestCase {
false,
],
[
- 'test', true,
+ 'test', true, false,
+ [
+ $this->getGroupMock('test'),
+ $this->getGroupMock('test1'),
+ ],
+ [$this->getGroupMock('test1')],
+ [],
+ [],
+ true,
+ false,
+ ],
+ [
+ 'test', true, true,
[
$this->getGroupMock('test'),
$this->getGroupMock('test1'),
@@ -394,7 +599,19 @@ class ShareesTest extends TestCase {
false,
],
[
- 'test', true,
+ 'test', true, false,
+ [
+ $this->getGroupMock('test'),
+ $this->getGroupMock('test1'),
+ ],
+ [$this->getGroupMock('test'), $this->getGroupMock('test0'), $this->getGroupMock('test1')],
+ [['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']]],
+ [],
+ true,
+ false,
+ ],
+ [
+ 'test', true, true,
[
$this->getGroupMock('test0'),
$this->getGroupMock('test1'),
@@ -409,7 +626,19 @@ class ShareesTest extends TestCase {
null,
],
[
- 'test', true,
+ 'test', true, false,
+ [
+ $this->getGroupMock('test0'),
+ $this->getGroupMock('test1'),
+ ],
+ [$this->getGroupMock('test'), $this->getGroupMock('test0'), $this->getGroupMock('test1')],
+ [],
+ [],
+ true,
+ null,
+ ],
+ [
+ 'test', true, true,
[
$this->getGroupMock('test0'),
$this->getGroupMock('test1'),
@@ -425,6 +654,20 @@ class ShareesTest extends TestCase {
false,
$this->getGroupMock('test'),
],
+ [
+ 'test', true, false,
+ [
+ $this->getGroupMock('test0'),
+ $this->getGroupMock('test1'),
+ ],
+ [$this->getGroupMock('test'), $this->getGroupMock('test0'), $this->getGroupMock('test1')],
+ [
+ ['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']],
+ ],
+ [],
+ true,
+ $this->getGroupMock('test'),
+ ],
];
}
@@ -433,6 +676,7 @@ class ShareesTest extends TestCase {
*
* @param string $searchTerm
* @param bool $shareWithGroupOnly
+ * @param bool $shareeEnumeration
* @param array $groupResponse
* @param array $userGroupsResponse
* @param array $exactExpected
@@ -440,10 +684,11 @@ class ShareesTest extends TestCase {
* @param bool $reachedEnd
* @param mixed $singleGroup
*/
- public function testGetGroups($searchTerm, $shareWithGroupOnly, $groupResponse, $userGroupsResponse, $exactExpected, $expected, $reachedEnd, $singleGroup) {
+ public function testGetGroups($searchTerm, $shareWithGroupOnly, $shareeEnumeration, $groupResponse, $userGroupsResponse, $exactExpected, $expected, $reachedEnd, $singleGroup) {
$this->invokePrivate($this->sharees, 'limit', [2]);
$this->invokePrivate($this->sharees, 'offset', [0]);
$this->invokePrivate($this->sharees, 'shareWithGroupOnly', [$shareWithGroupOnly]);
+ $this->invokePrivate($this->sharees, 'shareeEnumeration', [$shareeEnumeration]);
$this->groupManager->expects($this->once())
->method('search')
@@ -480,10 +725,22 @@ class ShareesTest extends TestCase {
public function dataGetRemote() {
return [
- ['test', [], [], [], true],
+ ['test', [], true, [], [], true],
+ ['test', [], false, [], [], true],
+ [
+ 'test@remote',
+ [],
+ true,
+ [
+ ['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']],
+ ],
+ [],
+ true,
+ ],
[
'test@remote',
[],
+ false,
[
['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']],
],
@@ -508,6 +765,7 @@ class ShareesTest extends TestCase {
],
],
],
+ true,
[],
[
['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost']],
@@ -515,6 +773,29 @@ class ShareesTest extends TestCase {
true,
],
[
+ 'test',
+ [
+ [
+ 'FN' => 'User3 @ Localhost',
+ ],
+ [
+ 'FN' => 'User2 @ Localhost',
+ 'CLOUD' => [
+ ],
+ ],
+ [
+ 'FN' => 'User @ Localhost',
+ 'CLOUD' => [
+ 'username@localhost',
+ ],
+ ],
+ ],
+ false,
+ [],
+ [],
+ true,
+ ],
+ [
'test@remote',
[
[
@@ -532,6 +813,7 @@ class ShareesTest extends TestCase {
],
],
],
+ true,
[
['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']],
],
@@ -541,6 +823,31 @@ class ShareesTest extends TestCase {
true,
],
[
+ 'test@remote',
+ [
+ [
+ 'FN' => 'User3 @ Localhost',
+ ],
+ [
+ 'FN' => 'User2 @ Localhost',
+ 'CLOUD' => [
+ ],
+ ],
+ [
+ 'FN' => 'User @ Localhost',
+ 'CLOUD' => [
+ 'username@localhost',
+ ],
+ ],
+ ],
+ false,
+ [
+ ['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']],
+ ],
+ [],
+ true,
+ ],
+ [
'username@localhost',
[
[
@@ -558,11 +865,36 @@ class ShareesTest extends TestCase {
],
],
],
+ true,
[
['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost']],
],
+ [],
+ true,
+ ],
+ [
+ 'username@localhost',
[
+ [
+ 'FN' => 'User3 @ Localhost',
+ ],
+ [
+ 'FN' => 'User2 @ Localhost',
+ 'CLOUD' => [
+ ],
+ ],
+ [
+ 'FN' => 'User @ Localhost',
+ 'CLOUD' => [
+ 'username@localhost',
+ ],
+ ],
],
+ false,
+ [
+ ['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost']],
+ ],
+ [],
true,
],
];
@@ -573,11 +905,13 @@ class ShareesTest extends TestCase {
*
* @param string $searchTerm
* @param array $contacts
+ * @param bool $shareeEnumeration
* @param array $exactExpected
* @param array $expected
* @param bool $reachedEnd
*/
- public function testGetRemote($searchTerm, $contacts, $exactExpected, $expected, $reachedEnd) {
+ public function testGetRemote($searchTerm, $contacts, $shareeEnumeration, $exactExpected, $expected, $reachedEnd) {
+ $this->invokePrivate($this->sharees, 'shareeEnumeration', [$shareeEnumeration]);
$this->contactsManager->expects($this->any())
->method('search')
->with($searchTerm, ['CLOUD', 'FN'])
@@ -595,80 +929,84 @@ class ShareesTest extends TestCase {
$allTypes = [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_GROUP, Share::SHARE_TYPE_REMOTE];
return [
- [[], '', true, '', null, $allTypes, 1, 200, false],
+ [[], '', 'yes', true, '', null, $allTypes, 1, 200, false, true],
// Test itemType
[[
'search' => '',
- ], '', true, '', null, $allTypes, 1, 200, false],
+ ], '', 'yes', true, '', null, $allTypes, 1, 200, false, true],
[[
'search' => 'foobar',
- ], '', true, 'foobar', null, $allTypes, 1, 200, false],
+ ], '', 'yes', true, 'foobar', null, $allTypes, 1, 200, false, true],
[[
'search' => 0,
- ], '', true, '0', null, $allTypes, 1, 200, false],
+ ], '', 'yes', true, '0', null, $allTypes, 1, 200, false, true],
// Test itemType
[[
'itemType' => '',
- ], '', true, '', '', $allTypes, 1, 200, false],
+ ], '', 'yes', true, '', '', $allTypes, 1, 200, false, true],
[[
'itemType' => 'folder',
- ], '', true, '', 'folder', $allTypes, 1, 200, false],
+ ], '', 'yes', true, '', 'folder', $allTypes, 1, 200, false, true],
[[
'itemType' => 0,
- ], '', true, '', '0', $allTypes, 1, 200, false],
+ ], '', 'yes', true, '', '0', $allTypes, 1, 200, false, true],
// Test shareType
[[
- ], '', true, '', null, $allTypes, 1, 200, false],
+ ], '', 'yes', true, '', null, $allTypes, 1, 200, false, true],
[[
'shareType' => 0,
- ], '', true, '', null, [0], 1, 200, false],
+ ], '', 'yes', true, '', null, [0], 1, 200, false, true],
[[
'shareType' => '0',
- ], '', true, '', null, [0], 1, 200, false],
+ ], '', 'yes', true, '', null, [0], 1, 200, false, true],
[[
'shareType' => 1,
- ], '', true, '', null, [1], 1, 200, false],
+ ], '', 'yes', true, '', null, [1], 1, 200, false, true],
[[
'shareType' => 12,
- ], '', true, '', null, [], 1, 200, false],
+ ], '', 'yes', true, '', null, [], 1, 200, false, true],
[[
'shareType' => 'foobar',
- ], '', true, '', null, $allTypes, 1, 200, false],
+ ], '', 'yes', true, '', null, $allTypes, 1, 200, false, true],
[[
'shareType' => [0, 1, 2],
- ], '', true, '', null, [0, 1], 1, 200, false],
+ ], '', 'yes', true, '', null, [0, 1], 1, 200, false, true],
[[
'shareType' => [0, 1],
- ], '', true, '', null, [0, 1], 1, 200, false],
+ ], '', 'yes', true, '', null, [0, 1], 1, 200, false, true],
[[
'shareType' => $allTypes,
- ], '', true, '', null, $allTypes, 1, 200, false],
+ ], '', 'yes', true, '', null, $allTypes, 1, 200, false, true],
[[
'shareType' => $allTypes,
- ], '', false, '', null, [0, 1], 1, 200, false],
+ ], '', 'yes', false, '', null, [0, 1], 1, 200, false, true],
// Test pagination
[[
'page' => 1,
- ], '', true, '', null, $allTypes, 1, 200, false],
+ ], '', 'yes', true, '', null, $allTypes, 1, 200, false, true],
[[
'page' => 10,
- ], '', true, '', null, $allTypes, 10, 200, false],
+ ], '', 'yes', true, '', null, $allTypes, 10, 200, false, true],
// Test perPage
[[
'perPage' => 1,
- ], '', true, '', null, $allTypes, 1, 1, false],
+ ], '', 'yes', true, '', null, $allTypes, 1, 1, false, true],
[[
'perPage' => 10,
- ], '', true, '', null, $allTypes, 1, 10, false],
+ ], '', 'yes', true, '', null, $allTypes, 1, 10, false, true],
// Test $shareWithGroupOnly setting
- [[], 'no', true, '', null, $allTypes, 1, 200, false],
- [[], 'yes', true, '', null, $allTypes, 1, 200, true],
+ [[], 'no', 'yes', true, '', null, $allTypes, 1, 200, false, true],
+ [[], 'yes', 'yes', true, '', null, $allTypes, 1, 200, true, true],
+
+ // Test $shareeEnumeration setting
+ [[], 'no', 'yes', true, '', null, $allTypes, 1, 200, false, true],
+ [[], 'no', 'no', true, '', null, $allTypes, 1, 200, false, false],
];
}
@@ -678,6 +1016,7 @@ class ShareesTest extends TestCase {
*
* @param array $getData
* @param string $apiSetting
+ * @param string $enumSetting
* @param bool $remoteSharingEnabled
* @param string $search
* @param string $itemType
@@ -685,18 +1024,22 @@ class ShareesTest extends TestCase {
* @param int $page
* @param int $perPage
* @param bool $shareWithGroupOnly
+ * @param bool $shareeEnumeration
*/
- public function testSearch($getData, $apiSetting, $remoteSharingEnabled, $search, $itemType, $shareTypes, $page, $perPage, $shareWithGroupOnly) {
+ public function testSearch($getData, $apiSetting, $enumSetting, $remoteSharingEnabled, $search, $itemType, $shareTypes, $page, $perPage, $shareWithGroupOnly, $shareeEnumeration) {
$oldGet = $_GET;
$_GET = $getData;
$config = $this->getMockBuilder('OCP\IConfig')
->disableOriginalConstructor()
->getMock();
- $config->expects($this->once())
+ $config->expects($this->exactly(2))
->method('getAppValue')
- ->with('core', 'shareapi_only_share_with_group_members', 'no')
- ->willReturn($apiSetting);
+ ->with('core', $this->anything(), $this->anything())
+ ->willReturnMap([
+ ['core', 'shareapi_only_share_with_group_members', 'no', $apiSetting],
+ ['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', $enumSetting],
+ ]);
$sharees = $this->getMockBuilder('\OCA\Files_Sharing\API\Sharees')
->setConstructorArgs([
@@ -735,6 +1078,7 @@ class ShareesTest extends TestCase {
$this->assertInstanceOf('\OC_OCS_Result', $sharees->search());
$this->assertSame($shareWithGroupOnly, $this->invokePrivate($sharees, 'shareWithGroupOnly'));
+ $this->assertSame($shareeEnumeration, $this->invokePrivate($sharees, 'shareeEnumeration'));
$_GET = $oldGet;
}
diff --git a/apps/user_ldap/js/wizard/wizardTabLoginFilter.js b/apps/user_ldap/js/wizard/wizardTabLoginFilter.js
index b73d267d168..0316db5b61c 100644
--- a/apps/user_ldap/js/wizard/wizardTabLoginFilter.js
+++ b/apps/user_ldap/js/wizard/wizardTabLoginFilter.js
@@ -71,7 +71,8 @@ OCA = OCA || {};
],
'ldap_login_filter_mode'
);
- _.bindAll(this, 'onVerifyClick');
+ _.bindAll(this, 'onVerifyClick', 'onTestLoginnameChange');
+ this.managedItems.ldap_test_loginname.$element.keyup(this.onTestLoginnameChange);
this.managedItems.ldap_test_loginname.$relatedElements.click(this.onVerifyClick);
},
@@ -231,6 +232,16 @@ OCA = OCA || {};
} else {
this.configModel.requestWizard('ldap_test_loginname', {ldap_test_loginname: testLogin});
}
+ },
+
+ /**
+ * enables/disables the "Verify Settings" button, depending whether
+ * the corresponding text input has a value or not
+ */
+ onTestLoginnameChange: function() {
+ var loginName = this.managedItems.ldap_test_loginname.$element.val();
+ var beDisabled = !_.isString(loginName) || !loginName.trim();
+ this.managedItems.ldap_test_loginname.$relatedElements.prop('disabled', beDisabled);
}
});
diff --git a/apps/user_ldap/templates/part.wizard-loginfilter.php b/apps/user_ldap/templates/part.wizard-loginfilter.php
index 8d9fccf24b8..a13931d9327 100644
--- a/apps/user_ldap/templates/part.wizard-loginfilter.php
+++ b/apps/user_ldap/templates/part.wizard-loginfilter.php
@@ -52,7 +52,7 @@
placeholder="<?php p($l->t('Test Loginname'));?>"
class="ldapVerifyInput"
title="Attempts to receive a DN for the given loginname and the current login filter"/>
- <button class="ldapVerifyLoginName" name="ldapTestLoginSettings" type="button">
+ <button class="ldapVerifyLoginName" name="ldapTestLoginSettings" type="button" disabled="disabled">
<?php p($l->t('Verify settings'));?>
</button>
</p>
diff --git a/core/ajax/share.php b/core/ajax/share.php
index 69b84564ab1..4546217def3 100644
--- a/core/ajax/share.php
+++ b/core/ajax/share.php
@@ -379,6 +379,16 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
}
}
+ $sharingAutocompletion = \OC::$server->getConfig()
+ ->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes');
+
+ if ($sharingAutocompletion !== 'yes') {
+ $searchTerm = strtolower($_GET['search']);
+ $shareWith = array_filter($shareWith, function($user) use ($searchTerm) {
+ return strtolower($user['label']) === $searchTerm
+ || strtolower($user['value']['shareWith']) === $searchTerm;
+ });
+ }
$sorter = new \OC\Share\SearchResultSorter((string)$_GET['search'],
'label',
diff --git a/core/img/actions/close.png b/core/img/actions/close.png
index ece33258e56..66e3c26cc65 100644
--- a/core/img/actions/close.png
+++ b/core/img/actions/close.png
Binary files differ
diff --git a/core/img/actions/close.svg b/core/img/actions/close.svg
index 4471dbc6301..e060da3f8bb 100644
--- a/core/img/actions/close.svg
+++ b/core/img/actions/close.svg
@@ -1,3 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
- <path d="M12.95,11.536,11.536,12.95,8,9.4142,4.4645,12.95,3.0503,11.536,6.5858,8,3.0503,4.4644,4.4645,3.0502,8,6.5858,11.516,3.0311,12.95,4.4644,9.4143,8z" fill="#000"/>
+ <defs>
+ <filter id="a" style="color-interpolation-filters:sRGB" height="1.5994" width="1.6006" y="-.29971" x="-.30029">
+ <feGaussianBlur stdDeviation="1.2386625"/>
+ </filter>
+ </defs>
+ <path d="m12.95 11.536-1.414 1.414-3.536-3.5358-3.5355 3.5358-1.4142-1.414 3.5355-3.536-3.5355-3.5356 1.4142-1.4142 3.5355 3.5356 3.516-3.5547 1.434 1.4333-3.5357 3.5356z" filter="url(#a)" stroke="#fff" stroke-width="2" fill="#fff"/>
+ <path d="m12.95 11.536-1.414 1.414-3.536-3.5358-3.5355 3.5358-1.4142-1.414 3.5355-3.536-3.5355-3.5356 1.4142-1.4142 3.5355 3.5356 3.516-3.5547 1.434 1.4333-3.5357 3.5356z"/>
</svg>
diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js
index 719ac8587a4..38b91be9d2e 100644
--- a/core/js/oc-dialogs.js
+++ b/core/js/oc-dialogs.js
@@ -388,9 +388,9 @@ var OCdialogs = {
c: original.etag,
forceIcon: 0
};
- var previewpath = OC.generateUrl('/core/preview.png?') + $.param(urlSpec);
+ var previewpath = Files.generatePreviewUrl(urlSpec);
// Escaping single quotes
- previewpath = previewpath.replace(/'/g, "%27")
+ previewpath = previewpath.replace(/'/g, "%27");
$originalDiv.find('.icon').css({"background-image": "url('" + previewpath + "')"});
getCroppedPreview(replacement).then(
function(path){
diff --git a/core/js/shareitemmodel.js b/core/js/shareitemmodel.js
index d883497433f..13396670aae 100644
--- a/core/js/shareitemmodel.js
+++ b/core/js/shareitemmodel.js
@@ -69,7 +69,7 @@
*/
var SHARE_RESPONSE_INT_PROPS = [
'id', 'file_parent', 'mail_send', 'file_source', 'item_source', 'permissions',
- 'storage', 'share_type', 'parent', 'stime', 'expiration'
+ 'storage', 'share_type', 'parent', 'stime'
];
/**
@@ -297,8 +297,7 @@
* @returns {boolean}
*/
hasUserShares: function() {
- var shares = this.get('shares');
- return _.isArray(shares) && shares.length > 0;
+ return this.getSharesWithCurrentItem().length > 0;
},
/**
@@ -408,6 +407,20 @@
},
/**
+ * Returns all share entries that only apply to the current item
+ * (file/folder)
+ *
+ * @return {Array.<OC.Share.Types.ShareInfo>}
+ */
+ getSharesWithCurrentItem: function() {
+ var shares = this.get('shares') || [];
+ var fileId = this.fileInfoModel.get('id');
+ return _.filter(shares, function(share) {
+ return share.item_source === fileId;
+ });
+ },
+
+ /**
* @param shareIndex
* @returns {string}
*/
diff --git a/core/js/tests/specs/shareitemmodelSpec.js b/core/js/tests/specs/shareitemmodelSpec.js
index 07a6fbdc23f..b4403e28475 100644
--- a/core/js/tests/specs/shareitemmodelSpec.js
+++ b/core/js/tests/specs/shareitemmodelSpec.js
@@ -169,7 +169,7 @@ describe('OC.Share.ShareItemModel', function() {
/* jshint camelcase: false */
shares: [{
displayname_owner: 'root',
- expiration: 1111,
+ expiration: '2015-10-12 00:00:00',
file_source: 123,
file_target: '/folder',
id: 20,
@@ -187,7 +187,7 @@ describe('OC.Share.ShareItemModel', function() {
uid_owner: 'root'
}, {
displayname_owner: 'root',
- expiration: 2222,
+ expiration: '2015-10-15 00:00:00',
file_source: 456,
file_target: '/file_in_folder.txt',
id: 21,
@@ -263,7 +263,7 @@ describe('OC.Share.ShareItemModel', function() {
reshare: {},
shares: [{
displayname_owner: 'root',
- expiration: '1403900000',
+ expiration: '2015-10-12 00:00:00',
file_source: '123',
file_target: '/folder',
id: '20',
@@ -301,7 +301,64 @@ describe('OC.Share.ShareItemModel', function() {
expect(share.share_type).toEqual(OC.Share.SHARE_TYPE_USER);
expect(share.share_with).toEqual('user1');
expect(share.stime).toEqual(1403884258);
- expect(share.expiration).toEqual(1403900000);
+ expect(share.expiration).toEqual('2015-10-12 00:00:00');
+ });
+ });
+ describe('hasUserShares', function() {
+ it('returns false when no user shares exist', function() {
+ loadItemStub.yields({
+ reshare: {},
+ shares: []
+ });
+
+ model.fetch();
+
+ expect(model.hasUserShares()).toEqual(false);
+ });
+ it('returns true when user shares exist on the current item', function() {
+ loadItemStub.yields({
+ reshare: {},
+ shares: [{
+ id: 1,
+ share_type: OC.Share.SHARE_TYPE_USER,
+ share_with: 'user1',
+ item_source: '123'
+ }]
+ });
+
+ model.fetch();
+
+ expect(model.hasUserShares()).toEqual(true);
+ });
+ it('returns true when group shares exist on the current item', function() {
+ loadItemStub.yields({
+ reshare: {},
+ shares: [{
+ id: 1,
+ share_type: OC.Share.SHARE_TYPE_GROUP,
+ share_with: 'group1',
+ item_source: '123'
+ }]
+ });
+
+ model.fetch();
+
+ expect(model.hasUserShares()).toEqual(true);
+ });
+ it('returns false when share exist on parent item', function() {
+ loadItemStub.yields({
+ reshare: {},
+ shares: [{
+ id: 1,
+ share_type: OC.Share.SHARE_TYPE_GROUP,
+ share_with: 'group1',
+ item_source: '111'
+ }]
+ });
+
+ model.fetch();
+
+ expect(model.hasUserShares()).toEqual(false);
});
});
diff --git a/core/shipped.json b/core/shipped.json
index 7993b61569c..ffa4ee9c738 100644
--- a/core/shipped.json
+++ b/core/shipped.json
@@ -3,11 +3,11 @@
"shippedApps": [
"activity",
"admin_audit",
+ "encryption",
"enterprise_key",
"external",
"files",
"files_antivirus",
- "encryption",
"files_external",
"files_ldap_home",
"files_locking",
@@ -21,6 +21,7 @@
"firewall",
"firstrunwizard",
"gallery",
+ "notifications",
"objectstore",
"provisioning_api",
"sharepoint",
@@ -29,7 +30,6 @@
"user_external",
"user_ldap",
"user_shibboleth",
- "user_webdavauth",
"windows_network_drive"
]
}
diff --git a/lib/private/app.php b/lib/private/app.php
index 26d51947642..5122a4964d4 100644
--- a/lib/private/app.php
+++ b/lib/private/app.php
@@ -837,7 +837,7 @@ class OC_App {
$info['active'] = $active;
- if (isset($info['shipped']) and ($info['shipped'] == 'true')) {
+ if (self::isShipped($app)) {
$info['internal'] = true;
$info['level'] = self::officialApp;
$info['removable'] = false;
diff --git a/lib/private/connector/sabre/listenerplugin.php b/lib/private/connector/sabre/listenerplugin.php
index d0d40f4dc86..ec628add28b 100644
--- a/lib/private/connector/sabre/listenerplugin.php
+++ b/lib/private/connector/sabre/listenerplugin.php
@@ -21,6 +21,9 @@
namespace OC\Connector\Sabre;
+use OCP\AppFramework\Http;
+use OCP\SabrePluginEvent;
+use OCP\SabrePluginException;
use Sabre\DAV\ServerPlugin;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -49,9 +52,16 @@ class ListenerPlugin extends ServerPlugin {
* in case the system is in maintenance mode.
*
* @return bool
+ * @throws \Exception
*/
public function emitListener() {
- $this->dispatcher->dispatch('OC\Connector\Sabre::beforeMethod');
+ $event = new SabrePluginEvent();
+
+ $this->dispatcher->dispatch('OC\Connector\Sabre::beforeMethod', $event);
+
+ if ($event->getStatusCode() !== Http::STATUS_OK) {
+ throw new SabrePluginException($event->getMessage(), $event->getStatusCode());
+ }
return true;
}
diff --git a/lib/private/db/querybuilder/quotehelper.php b/lib/private/db/querybuilder/quotehelper.php
index 0735f313abc..4b62fee6a6c 100644
--- a/lib/private/db/querybuilder/quotehelper.php
+++ b/lib/private/db/querybuilder/quotehelper.php
@@ -52,7 +52,7 @@ class QuoteHelper {
return (string) $string;
}
- if ($string === null || $string === '*') {
+ if ($string === null || $string === 'null' || $string === '*') {
return $string;
}
diff --git a/lib/private/encryption/decryptall.php b/lib/private/encryption/decryptall.php
index 1ff9c74ef84..c1875f16abd 100644
--- a/lib/private/encryption/decryptall.php
+++ b/lib/private/encryption/decryptall.php
@@ -80,7 +80,7 @@ class DecryptAll {
$this->input = $input;
$this->output = $output;
- if ($user !== '' && $this->userManager->userExists($user) === false) {
+ if (!empty($user) && $this->userManager->userExists($user) === false) {
$this->output->writeln('User "' . $user . '" does not exist. Please check the username and try again');
return false;
}
diff --git a/lib/private/files/storage/wrapper/permissionsmask.php b/lib/private/files/storage/wrapper/permissionsmask.php
index 50c3f2a6268..8d40d023630 100644
--- a/lib/private/files/storage/wrapper/permissionsmask.php
+++ b/lib/private/files/storage/wrapper/permissionsmask.php
@@ -66,7 +66,7 @@ class PermissionsMask extends Wrapper {
}
public function isSharable($path) {
- return $this->checkMask(Constants::PERMISSION_SHARE) and parent::isSharable($parm);
+ return $this->checkMask(Constants::PERMISSION_SHARE) and parent::isSharable($path);
}
public function getPermissions($path) {
diff --git a/lib/private/files/view.php b/lib/private/files/view.php
index f92441492f7..95b688fef5c 100644
--- a/lib/private/files/view.php
+++ b/lib/private/files/view.php
@@ -153,7 +153,10 @@ class View {
return '/';
}
- if (strpos($path, $this->fakeRoot) !== 0) {
+ // missing slashes can cause wrong matches!
+ $root = rtrim($this->fakeRoot, '/') . '/';
+
+ if (strpos($path, $root) !== 0) {
return null;
} else {
$path = substr($path, strlen($this->fakeRoot));
diff --git a/lib/public/sabrepluginevent.php b/lib/public/sabrepluginevent.php
new file mode 100644
index 00000000000..fed3237166d
--- /dev/null
+++ b/lib/public/sabrepluginevent.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP;
+
+
+use OCP\AppFramework\Http;
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * @since 8.2.0
+ */
+class SabrePluginEvent extends Event {
+
+ /** @var int */
+ protected $statusCode;
+
+ /** @var string */
+ protected $message;
+
+ /**
+ * @since 8.2.0
+ */
+ public function __construct() {
+ $this->message = '';
+ $this->statusCode = Http::STATUS_OK;
+ }
+
+ /**
+ * @param int $statusCode
+ * @return self
+ * @since 8.2.0
+ */
+ public function setStatusCode($statusCode) {
+ $this->statusCode = (int) $statusCode;
+ return $this;
+ }
+
+ /**
+ * @param string $message
+ * @return self
+ * @since 8.2.0
+ */
+ public function setMessage($message) {
+ $this->message = (string) $message;
+ return $this;
+ }
+
+ /**
+ * @return int
+ * @since 8.2.0
+ */
+ public function getStatusCode() {
+ return $this->statusCode;
+ }
+
+ /**
+ * @return string
+ * @since 8.2.0
+ */
+ public function getMessage() {
+ return $this->message;
+ }
+}
diff --git a/lib/public/sabrepluginexception.php b/lib/public/sabrepluginexception.php
new file mode 100644
index 00000000000..5dba3b90a02
--- /dev/null
+++ b/lib/public/sabrepluginexception.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP;
+
+
+use Sabre\DAV\Exception;
+
+/**
+ * @since 8.2.0
+ */
+class SabrePluginException extends Exception {
+
+ /**
+ * Returns the HTTP statuscode for this exception
+ *
+ * @return int
+ * @since 8.2.0
+ */
+ public function getHTTPCode() {
+ return $this->code;
+ }
+}
diff --git a/settings/admin.php b/settings/admin.php
index 38683438f3a..c8bf1d32749 100644
--- a/settings/admin.php
+++ b/settings/admin.php
@@ -122,6 +122,7 @@ $template->assign('allowPublicUpload', $appConfig->getValue('core', 'shareapi_al
$template->assign('allowResharing', $appConfig->getValue('core', 'shareapi_allow_resharing', 'yes'));
$template->assign('allowPublicMailNotification', $appConfig->getValue('core', 'shareapi_allow_public_notification', 'no'));
$template->assign('allowMailNotification', $appConfig->getValue('core', 'shareapi_allow_mail_notification', 'no'));
+$template->assign('allowShareDialogUserEnumeration', $appConfig->getValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes'));
$template->assign('onlyShareWithGroupMembers', \OC\Share\Share::shareWithGroupMembersOnly());
$databaseOverload = (strpos(\OCP\Config::getSystemValue('dbtype'), 'sqlite') !== false);
$template->assign('databaseOverload', $databaseOverload);
diff --git a/settings/templates/admin.php b/settings/templates/admin.php
index 36088d9f8c2..bfb0d5d364d 100644
--- a/settings/templates/admin.php
+++ b/settings/templates/admin.php
@@ -265,6 +265,11 @@ if ($_['cronErrors']) {
<br />
<em><?php p($l->t('These groups will still be able to receive shares, but not to initiate them.')); ?></em>
</p>
+ <p class="<?php if ($_['shareAPIEnabled'] === 'no') p('hidden');?>">
+ <input type="checkbox" name="shareapi_allow_share_dialog_user_enumeration" value="1" id="shareapi_allow_share_dialog_user_enumeration"
+ <?php if ($_['allowShareDialogUserEnumeration'] === 'yes') print_unescaped('checked="checked"'); ?> />
+ <label for="shareapi_allow_share_dialog_user_enumeration"><?php p($l->t('Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered.'));?></label><br />
+ </p>
<?php print_unescaped($_['fileSharingSettings']); ?>
</div>
diff --git a/tests/lib/db/querybuilder/quotehelpertest.php b/tests/lib/db/querybuilder/quotehelpertest.php
index 904b4c500db..b83d9eed2df 100644
--- a/tests/lib/db/querybuilder/quotehelpertest.php
+++ b/tests/lib/db/querybuilder/quotehelpertest.php
@@ -43,6 +43,10 @@ class QuoteHelperTest extends \Test\TestCase {
[new Literal('literal'), 'literal'],
[new Literal(1), '1'],
[new Parameter(':param'), ':param'],
+
+ // (string) 'null' is Doctrines way to set columns to null
+ // See https://github.com/owncloud/core/issues/19314
+ ['null', 'null'],
];
}
diff --git a/tests/lib/encryption/decryptalltest.php b/tests/lib/encryption/decryptalltest.php
index c2a0711c0a0..ce5bcf1e5ae 100644
--- a/tests/lib/encryption/decryptalltest.php
+++ b/tests/lib/encryption/decryptalltest.php
@@ -82,11 +82,13 @@ class DecryptAllTest extends TestCase {
* @dataProvider dataTrueFalse
* @param bool $prepareResult
*/
- public function testDecryptAll($prepareResult) {
+ public function testDecryptAll($prepareResult, $user) {
- $user = 'user1';
-
- $this->userManager->expects($this->once())->method('userExists')->willReturn(true);
+ if (!empty($user)) {
+ $this->userManager->expects($this->once())->method('userExists')->willReturn(true);
+ } else {
+ $this->userManager->expects($this->never())->method('userExists');
+ }
/** @var DecryptAll | \PHPUnit_Framework_MockObject_MockObject | $instance */
$instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
->setConstructorArgs(
@@ -117,8 +119,10 @@ class DecryptAllTest extends TestCase {
public function dataTrueFalse() {
return [
- [true],
- [false]
+ [true, 'user1'],
+ [false, 'user1'],
+ [true, ''],
+ [true, null]
];
}
diff --git a/tests/lib/files/storage/storage.php b/tests/lib/files/storage/storage.php
index fcd7f73dcde..d381b4cdf40 100644
--- a/tests/lib/files/storage/storage.php
+++ b/tests/lib/files/storage/storage.php
@@ -573,4 +573,29 @@ abstract class Storage extends \Test\TestCase {
$this->assertSameAsLorem($target);
$this->assertTrue($this->instance->file_exists($source), $source . ' was deleted');
}
+
+ public function testIsCreatable() {
+ $this->instance->mkdir('source');
+ $this->assertTrue($this->instance->isCreatable('source'));
+ }
+
+ public function testIsReadable() {
+ $this->instance->mkdir('source');
+ $this->assertTrue($this->instance->isReadable('source'));
+ }
+
+ public function testIsUpdatable() {
+ $this->instance->mkdir('source');
+ $this->assertTrue($this->instance->isUpdatable('source'));
+ }
+
+ public function testIsDeletable() {
+ $this->instance->mkdir('source');
+ $this->assertTrue($this->instance->isDeletable('source'));
+ }
+
+ public function testIsShareable() {
+ $this->instance->mkdir('source');
+ $this->assertTrue($this->instance->isSharable('source'));
+ }
}
diff --git a/tests/lib/files/view.php b/tests/lib/files/view.php
index 83f53833855..ceeb9ba7a94 100644
--- a/tests/lib/files/view.php
+++ b/tests/lib/files/view.php
@@ -193,7 +193,7 @@ class View extends \Test\TestCase {
/**
* @medium
*/
- function testGetPath() {
+ public function testGetPath() {
$storage1 = $this->getTestStorage();
$storage2 = $this->getTestStorage();
$storage3 = $this->getTestStorage();
@@ -219,7 +219,7 @@ class View extends \Test\TestCase {
/**
* @medium
*/
- function testMountPointOverwrite() {
+ public function testMountPointOverwrite() {
$storage1 = $this->getTestStorage(false);
$storage2 = $this->getTestStorage();
$storage1->mkdir('substorage');
@@ -265,7 +265,7 @@ class View extends \Test\TestCase {
$appConfig->setValue('core', 'shareapi_exclude_groups_list', $oldExcludeGroupsList);
}
- function testCacheIncompleteFolder() {
+ public function testCacheIncompleteFolder() {
$storage1 = $this->getTestStorage(false);
\OC\Files\Filesystem::clearMounts();
\OC\Files\Filesystem::mount($storage1, array(), '/incomplete');
@@ -300,7 +300,7 @@ class View extends \Test\TestCase {
/**
* @medium
*/
- function testSearch() {
+ public function testSearch() {
$storage1 = $this->getTestStorage();
$storage2 = $this->getTestStorage();
$storage3 = $this->getTestStorage();
@@ -350,7 +350,7 @@ class View extends \Test\TestCase {
/**
* @medium
*/
- function testWatcher() {
+ public function testWatcher() {
$storage1 = $this->getTestStorage();
\OC\Files\Filesystem::mount($storage1, array(), '/');
$storage1->getWatcher()->setPolicy(Watcher::CHECK_ALWAYS);
@@ -371,7 +371,7 @@ class View extends \Test\TestCase {
/**
* @medium
*/
- function testCopyBetweenStorageNoCross() {
+ public function testCopyBetweenStorageNoCross() {
$storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross');
$storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross');
$this->copyBetweenStorages($storage1, $storage2);
@@ -380,7 +380,7 @@ class View extends \Test\TestCase {
/**
* @medium
*/
- function testCopyBetweenStorageCross() {
+ public function testCopyBetweenStorageCross() {
$storage1 = $this->getTestStorage();
$storage2 = $this->getTestStorage();
$this->copyBetweenStorages($storage1, $storage2);
@@ -389,7 +389,7 @@ class View extends \Test\TestCase {
/**
* @medium
*/
- function testCopyBetweenStorageCrossNonLocal() {
+ public function testCopyBetweenStorageCrossNonLocal() {
$storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal');
$storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal');
$this->copyBetweenStorages($storage1, $storage2);
@@ -417,7 +417,7 @@ class View extends \Test\TestCase {
/**
* @medium
*/
- function testMoveBetweenStorageNoCross() {
+ public function testMoveBetweenStorageNoCross() {
$storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross');
$storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross');
$this->moveBetweenStorages($storage1, $storage2);
@@ -426,7 +426,7 @@ class View extends \Test\TestCase {
/**
* @medium
*/
- function testMoveBetweenStorageCross() {
+ public function testMoveBetweenStorageCross() {
$storage1 = $this->getTestStorage();
$storage2 = $this->getTestStorage();
$this->moveBetweenStorages($storage1, $storage2);
@@ -435,7 +435,7 @@ class View extends \Test\TestCase {
/**
* @medium
*/
- function testMoveBetweenStorageCrossNonLocal() {
+ public function testMoveBetweenStorageCrossNonLocal() {
$storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal');
$storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal');
$this->moveBetweenStorages($storage1, $storage2);
@@ -458,7 +458,7 @@ class View extends \Test\TestCase {
/**
* @medium
*/
- function testUnlink() {
+ public function testUnlink() {
$storage1 = $this->getTestStorage();
$storage2 = $this->getTestStorage();
\OC\Files\Filesystem::mount($storage1, array(), '/');
@@ -481,7 +481,7 @@ class View extends \Test\TestCase {
/**
* @medium
*/
- function testUnlinkRootMustFail() {
+ public function testUnlinkRootMustFail() {
$storage1 = $this->getTestStorage();
$storage2 = $this->getTestStorage();
\OC\Files\Filesystem::mount($storage1, array(), '/');
@@ -500,7 +500,7 @@ class View extends \Test\TestCase {
/**
* @medium
*/
- function testTouch() {
+ public function testTouch() {
$storage = $this->getTestStorage(true, '\Test\Files\TemporaryNoTouch');
\OC\Files\Filesystem::mount($storage, array(), '/');
@@ -524,7 +524,7 @@ class View extends \Test\TestCase {
/**
* @medium
*/
- function testViewHooks() {
+ public function testViewHooks() {
$storage1 = $this->getTestStorage();
$storage2 = $this->getTestStorage();
$defaultRoot = \OC\Files\Filesystem::getRoot();
@@ -590,7 +590,7 @@ class View extends \Test\TestCase {
/**
* @medium
*/
- function testViewHooksIfRootStartsTheSame() {
+ public function testViewHooksIfRootStartsTheSame() {
$storage1 = $this->getTestStorage();
$storage2 = $this->getTestStorage();
$defaultRoot = \OC\Files\Filesystem::getRoot();
@@ -851,24 +851,98 @@ class View extends \Test\TestCase {
}
/**
- * @dataProvider relativePathProvider
+ * @dataProvider chrootRelativePathProvider
*/
- function testGetRelativePath($absolutePath, $expectedPath) {
+ function testChrootGetRelativePath($root, $absolutePath, $expectedPath) {
$view = new \OC\Files\View('/files');
- // simulate a external storage mount point which has a trailing slash
- $view->chroot('/files/');
+ $view->chroot($root);
$this->assertEquals($expectedPath, $view->getRelativePath($absolutePath));
}
- function relativePathProvider() {
+ public function chrootRelativePathProvider() {
+ return $this->relativePathProvider('/');
+ }
+
+ /**
+ * @dataProvider initRelativePathProvider
+ */
+ public function testInitGetRelativePath($root, $absolutePath, $expectedPath) {
+ $view = new \OC\Files\View($root);
+ $this->assertEquals($expectedPath, $view->getRelativePath($absolutePath));
+ }
+
+ public function initRelativePathProvider() {
+ return $this->relativePathProvider(null);
+ }
+
+ public function relativePathProvider($missingRootExpectedPath) {
return array(
- array('/files/', '/'),
- array('/files', '/'),
- array('/files/0', '0'),
- array('/files/false', 'false'),
- array('/files/true', 'true'),
- array('/files/test', 'test'),
- array('/files/test/foo', 'test/foo'),
+ // No root - returns the path
+ array('', '/files', '/files'),
+ array('', '/files/', '/files/'),
+
+ // Root equals path - /
+ array('/files/', '/files/', '/'),
+ array('/files/', '/files', '/'),
+ array('/files', '/files/', '/'),
+ array('/files', '/files', '/'),
+
+ // False negatives: chroot fixes those by adding the leading slash.
+ // But setting them up with this root (instead of chroot($root))
+ // will fail them, although they should be the same.
+ // TODO init should be fixed, so it also adds the leading slash
+ array('files/', '/files/', $missingRootExpectedPath),
+ array('files', '/files/', $missingRootExpectedPath),
+ array('files/', '/files', $missingRootExpectedPath),
+ array('files', '/files', $missingRootExpectedPath),
+
+ // False negatives: Paths provided to the method should have a leading slash
+ // TODO input should be checked to have a leading slash
+ array('/files/', 'files/', null),
+ array('/files', 'files/', null),
+ array('/files/', 'files', null),
+ array('/files', 'files', null),
+
+ // with trailing slashes
+ array('/files/', '/files/0', '0'),
+ array('/files/', '/files/false', 'false'),
+ array('/files/', '/files/true', 'true'),
+ array('/files/', '/files/test', 'test'),
+ array('/files/', '/files/test/foo', 'test/foo'),
+
+ // without trailing slashes
+ // TODO false expectation: Should match "with trailing slashes"
+ array('/files', '/files/0', '/0'),
+ array('/files', '/files/false', '/false'),
+ array('/files', '/files/true', '/true'),
+ array('/files', '/files/test', '/test'),
+ array('/files', '/files/test/foo', '/test/foo'),
+
+ // leading slashes
+ array('/files/', '/files_trashbin/', null),
+ array('/files', '/files_trashbin/', null),
+ array('/files/', '/files_trashbin', null),
+ array('/files', '/files_trashbin', null),
+
+ // no leading slashes
+ array('files/', 'files_trashbin/', null),
+ array('files', 'files_trashbin/', null),
+ array('files/', 'files_trashbin', null),
+ array('files', 'files_trashbin', null),
+
+ // mixed leading slashes
+ array('files/', '/files_trashbin/', null),
+ array('/files/', 'files_trashbin/', null),
+ array('files', '/files_trashbin/', null),
+ array('/files', 'files_trashbin/', null),
+ array('files/', '/files_trashbin', null),
+ array('/files/', 'files_trashbin', null),
+ array('files', '/files_trashbin', null),
+ array('/files', 'files_trashbin', null),
+
+ array('files', 'files_trashbin/test', null),
+ array('/files', '/files_trashbin/test', null),
+ array('/files', 'files_trashbin/test', null),
);
}
@@ -1012,6 +1086,7 @@ class View extends \Test\TestCase {
$storage2->expects($this->any())
->method('fopen')
->will($this->returnCallback(function ($path, $mode) use ($storage2) {
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \OC\Files\Storage\Temporary $storage2 */
$source = fopen($storage2->getSourcePath($path), $mode);
return \OC\Files\Stream\Quota::wrap($source, 9);
}));
@@ -1020,7 +1095,7 @@ class View extends \Test\TestCase {
$storage1->file_put_contents('foo.txt', '0123456789ABCDEFGH');
$storage1->mkdir('dirtomove');
$storage1->file_put_contents('dirtomove/indir1.txt', '0123456'); // fits
- $storage1->file_put_contents('dirtomove/indir2.txt', '0123456789ABCDEFGH'); // doesn't fit
+ $storage1->file_put_contents('dirtomove/indir2.txt', '0123456789ABCDEFGH'); // doesn't fit
$storage2->file_put_contents('existing.txt', '0123');
$storage1->getScanner()->scan('');
$storage2->getScanner()->scan('');
@@ -1296,7 +1371,7 @@ class View extends \Test\TestCase {
$thrown = false;
try {
- // this actually acquires two locks, one on the mount point and one no the storage root,
+ // this actually acquires two locks, one on the mount point and one on the storage root,
// but the one on the storage root will fail
$view->lockFile('/mountpoint.txt', ILockingProvider::LOCK_SHARED);
} catch (\OCP\Lock\LockedException $e) {