aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
m---------3rdparty0
-rw-r--r--apps/encryption/lib/crypto/encryptall.php6
-rw-r--r--apps/files/css/detailsView.css8
-rw-r--r--apps/files/js/filelist.js2
-rw-r--r--apps/files/js/mainfileinfodetailview.js6
-rw-r--r--apps/files/templates/fileexists.html8
-rw-r--r--apps/files/templates/list.php2
-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/css/sharetabview.css6
-rw-r--r--apps/files_sharing/js/public.js24
-rw-r--r--apps/files_sharing/lib/activity.php8
-rw-r--r--apps/files_sharing/lib/capabilities.php42
-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/files_sharing/tests/capabilities.php37
-rw-r--r--apps/files_trashbin/tests/expiration.php1
-rw-r--r--apps/files_versions/lib/storage.php3
-rw-r--r--apps/files_versions/tests/expirationtest.php1
-rw-r--r--apps/files_versions/tests/versions.php37
-rw-r--r--apps/user_ldap/js/wizard/wizardTabLoginFilter.js13
-rw-r--r--apps/user_ldap/templates/part.wizard-loginfilter.php2
-rw-r--r--config/config.sample.php15
-rw-r--r--core/ajax/share.php41
-rw-r--r--core/command/app/checkcode.php66
-rw-r--r--core/command/config/listconfigs.php43
-rw-r--r--core/css/apps.css1
-rw-r--r--core/css/fixes.css5
-rw-r--r--core/css/styles.css20
-rw-r--r--core/img/actions/close.pngbin206 -> 493 bytes
-rw-r--r--core/img/actions/close.svg9
-rw-r--r--core/img/actions/upload.pngbin144 -> 142 bytes
-rw-r--r--core/img/actions/upload.svg4
-rw-r--r--core/img/actions/view-close.pngbin317 -> 1442 bytes
-rw-r--r--core/img/actions/view-close.svg9
-rw-r--r--core/img/actions/view-next.pngbin232 -> 1215 bytes
-rw-r--r--core/img/actions/view-next.svg10
-rw-r--r--core/img/actions/view-pause.pngbin108 -> 682 bytes
-rw-r--r--core/img/actions/view-pause.svg12
-rw-r--r--core/img/actions/view-play.pngbin154 -> 870 bytes
-rw-r--r--core/img/actions/view-play.svg12
-rw-r--r--core/img/actions/view-previous.pngbin231 -> 1189 bytes
-rw-r--r--core/img/actions/view-previous.svg10
-rw-r--r--core/js/multiselect.js3
-rw-r--r--core/js/oc-dialogs.js4
-rw-r--r--core/js/sharedialogshareelistview.js8
-rw-r--r--core/js/shareitemmodel.js19
-rw-r--r--core/js/tests/specs/shareitemmodelSpec.js65
-rw-r--r--core/register_command.php3
-rw-r--r--core/shipped.json4
-rw-r--r--core/templates/login.php2
-rw-r--r--lib/base.php69
-rw-r--r--lib/private/allconfig.php11
-rw-r--r--lib/private/app.php2
-rw-r--r--lib/private/app/codechecker/infochecker.php146
-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/private/log.php36
-rw-r--r--lib/private/preview.php7
-rw-r--r--lib/private/server.php1
-rw-r--r--lib/private/share/share.php1
-rw-r--r--lib/private/systemconfig.php54
-rw-r--r--lib/private/template.php117
-rw-r--r--lib/private/util.php53
-rw-r--r--lib/public/iconfig.php15
-rw-r--r--lib/public/ilogger.php10
-rw-r--r--lib/public/iservercontainer.php6
-rw-r--r--lib/public/sabrepluginevent.php82
-rw-r--r--lib/public/sabrepluginexception.php41
-rw-r--r--lib/public/util.php11
-rw-r--r--settings/admin.php1
-rw-r--r--settings/js/users/users.js29
-rw-r--r--settings/templates/admin.php5
-rw-r--r--settings/templates/users/main.php15
-rw-r--r--settings/users.php7
-rw-r--r--tests/apps/testapp-infoxml-version-different/appinfo/info.xml9
-rw-r--r--tests/apps/testapp-infoxml-version-different/appinfo/version1
-rw-r--r--tests/apps/testapp-infoxml-version/appinfo/info.xml9
-rw-r--r--tests/apps/testapp-infoxml-version/appinfo/version1
-rw-r--r--tests/apps/testapp-infoxml/appinfo/info.xml9
-rw-r--r--tests/apps/testapp-name-missing/appinfo/info.xml8
-rw-r--r--tests/apps/testapp-version-missing/appinfo/info.xml8
-rw-r--r--tests/apps/testapp-version/appinfo/info.xml8
-rw-r--r--tests/apps/testapp-version/appinfo/version1
-rw-r--r--tests/core/command/config/listconfigstest.php25
-rw-r--r--tests/lib/app/codechecker/infocheckertest.php73
-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
-rw-r--r--tests/lib/logger.php44
-rw-r--r--tests/lib/share/share.php37
110 files changed, 2014 insertions, 377 deletions
diff --git a/3rdparty b/3rdparty
-Subproject 338ab170afcb4770e79cc4427a9803cb29a0a23
+Subproject 3cd7b7048e33e0076c1f94cf2ed721934e0c497
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/filelist.js b/apps/files/js/filelist.js
index 4b1b38d783c..ad3dce19778 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -925,7 +925,7 @@
if (this._allowSelection) {
td.append(
'<input id="select-' + this.id + '-' + fileData.id +
- '" type="checkbox" class="selectCheckBox"/><label for="select-' + this.id + '-' + fileData.id + '">' +
+ '" type="checkbox" class="selectCheckBox checkbox"/><label for="select-' + this.id + '-' + fileData.id + '">' +
'<div class="thumbnail" style="background-image:url(' + icon + '); background-size: 32px;"></div>' +
'<span class="hidden-visually">' + t('files', 'Select') + '</span>' +
'</label>'
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/templates/fileexists.html b/apps/files/templates/fileexists.html
index c783f9a05c7..e3513237d2b 100644
--- a/apps/files/templates/fileexists.html
+++ b/apps/files/templates/fileexists.html
@@ -3,14 +3,14 @@
<span class="what">{what}<!-- If you select both versions, the copied file will have a number added to its name. --></span><br/>
<br/>
<table>
- <th><input id="checkbox-allnewfiles" class="allnewfiles" type="checkbox" /><label for="checkbox-allnewfiles">{allnewfiles}<span class="count"></span></label></th>
- <th><input id="checkbox-allexistingfiles" class="allexistingfiles" type="checkbox" /><label for="checkbox-allexistingfiles">{allexistingfiles}<span class="count"></span></label></th>
+ <th><input id="checkbox-allnewfiles" class="allnewfiles checkbox" type="checkbox" /><label for="checkbox-allnewfiles">{allnewfiles}<span class="count"></span></label></th>
+ <th><input id="checkbox-allexistingfiles" class="allexistingfiles checkbox" type="checkbox" /><label for="checkbox-allexistingfiles">{allexistingfiles}<span class="count"></span></label></th>
</table>
<div class="conflicts">
<div class="template">
<div class="filename"></div>
<div class="replacement">
- <input type="checkbox" class="u-left"/>
+ <input type="checkbox" class="checkbox u-left"/>
<label>
<span class="svg icon"></span>
<div class="mtime"></div>
@@ -18,7 +18,7 @@
</label>
</div>
<div class="original">
- <input type="checkbox" class="u-left" />
+ <input type="checkbox" class="checkbox u-left" />
<label>
<span class="svg icon"></span>
<div class="mtime"></div>
diff --git a/apps/files/templates/list.php b/apps/files/templates/list.php
index 15af1970dc3..bbbce8473de 100644
--- a/apps/files/templates/list.php
+++ b/apps/files/templates/list.php
@@ -56,7 +56,7 @@
<tr>
<th id='headerName' class="hidden column-name">
<div id="headerName-container">
- <input type="checkbox" id="select_all_files" class="select-all"/>
+ <input type="checkbox" id="select_all_files" class="select-all checkbox"/>
<label for="select_all_files">
<span class="hidden-visually"><?php p($l->t('Select all'))?></span>
</label>
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/css/sharetabview.css b/apps/files_sharing/css/sharetabview.css
index fe7a1947502..1745eba5846 100644
--- a/apps/files_sharing/css/sharetabview.css
+++ b/apps/files_sharing/css/sharetabview.css
@@ -73,5 +73,9 @@
}
.shareTabView .icon-loading-small {
- margin-left: -30px;
+ position: absolute;
+ display: inline-block;
+ z-index: 1;
+ background-color: white;
+ padding: 2px;
}
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/activity.php b/apps/files_sharing/lib/activity.php
index 1257e7a445c..63ac2e90b2a 100644
--- a/apps/files_sharing/lib/activity.php
+++ b/apps/files_sharing/lib/activity.php
@@ -58,6 +58,7 @@ class Activity implements IExtension {
const SUBJECT_RESHARED_GROUP_BY = 'reshared_group_by';
const SUBJECT_RESHARED_LINK_BY = 'reshared_link_by';
const SUBJECT_RESHARED_USER_BY = 'reshared_user_by';
+ const SUBJECT_SHARED_EMAIL = 'shared_with_email';
const SUBJECT_SHARED_WITH_BY = 'shared_with_by';
/** @var IFactory */
@@ -182,6 +183,8 @@ class Activity implements IExtension {
return (string) $l->t('%2$s shared %1$s with you', $params);
case self::SUBJECT_SHARED_LINK_SELF:
return (string) $l->t('You shared %1$s via link', $params);
+ case self::SUBJECT_SHARED_EMAIL:
+ return (string) $l->t('You shared %1$s with %2$s', $params);
}
}
@@ -227,6 +230,11 @@ class Activity implements IExtension {
1 => 'username',
2 => '',
];
+ case self::SUBJECT_SHARED_EMAIL:
+ return array(
+ 0 => 'file',
+ 1 => '',// 'email' is neither supported nor planned for now
+ );
case self::SUBJECT_SHARED_USER_SELF:
case self::SUBJECT_SHARED_WITH_BY:
diff --git a/apps/files_sharing/lib/capabilities.php b/apps/files_sharing/lib/capabilities.php
index b24eb8d61f0..c8ba1273281 100644
--- a/apps/files_sharing/lib/capabilities.php
+++ b/apps/files_sharing/lib/capabilities.php
@@ -45,28 +45,36 @@ class Capabilities implements ICapability {
public function getCapabilities() {
$res = [];
- $public = [];
- $public['enabled'] = $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
- if ($public['enabled']) {
- $public['password'] = [];
- $public['password']['enforced'] = ($this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes');
+ if ($this->config->getAppValue('core', 'shareapi_enabled', 'yes') !== 'yes') {
+ $res['api_enabled'] = false;
+ $res['public'] = ['enabled' => false];
+ $res['user'] = ['send_mail' => false];
+ $res['resharing'] = false;
+ } else {
+ $res['api_enabled'] = true;
- $public['expire_date'] = [];
- $public['expire_date']['enabled'] = $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
- if ($public['expire_date']['enabled']) {
- $public['expire_date']['days'] = $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
- $public['expire_date']['enforced'] = $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
- }
+ $public = [];
+ $public['enabled'] = $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
+ if ($public['enabled']) {
+ $public['password'] = [];
+ $public['password']['enforced'] = ($this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes');
- $public['send_mail'] = $this->config->getAppValue('core', 'shareapi_allow_public_notification', 'no') === 'yes';
- $public['upload'] = $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
- }
- $res["public"] = $public;
+ $public['expire_date'] = [];
+ $public['expire_date']['enabled'] = $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
+ if ($public['expire_date']['enabled']) {
+ $public['expire_date']['days'] = $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
+ $public['expire_date']['enforced'] = $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
+ }
- $res['user']['send_mail'] = $this->config->getAppValue('core', 'shareapi_allow_mail_notification', 'no') === 'yes';
+ $public['send_mail'] = $this->config->getAppValue('core', 'shareapi_allow_public_notification', 'no') === 'yes';
+ $public['upload'] = $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
+ }
+ $res["public"] = $public;
- $res['resharing'] = $this->config->getAppValue('core', 'shareapi_allow_resharing', 'yes') === 'yes';
+ $res['user']['send_mail'] = $this->config->getAppValue('core', 'shareapi_allow_mail_notification', 'no') === 'yes';
+ $res['resharing'] = $this->config->getAppValue('core', 'shareapi_allow_resharing', 'yes') === 'yes';
+ }
//Federated sharing
$res['federation'] = [
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/files_sharing/tests/capabilities.php b/apps/files_sharing/tests/capabilities.php
index f1a9626db9b..cff7bdf1fe8 100644
--- a/apps/files_sharing/tests/capabilities.php
+++ b/apps/files_sharing/tests/capabilities.php
@@ -56,8 +56,31 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
return $result;
}
+ public function testEnabledSharingAPI() {
+ $map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
+ ];
+ $result = $this->getResults($map);
+ $this->assertTrue($result['api_enabled']);
+ $this->assertContains('public', $result);
+ $this->assertContains('user', $result);
+ $this->assertContains('resharing', $result);
+ }
+
+ public function testDisabledSharingAPI() {
+ $map = [
+ ['core', 'shareapi_enabled', 'yes', 'no'],
+ ];
+ $result = $this->getResults($map);
+ $this->assertFalse($result['api_enabled']);
+ $this->assertNotContains('public', $result);
+ $this->assertNotContains('user', $result);
+ $this->assertNotContains('resharing', $result);
+ }
+
public function testNoLinkSharing() {
$map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
['core', 'shareapi_allow_links', 'yes', 'no'],
];
$result = $this->getResults($map);
@@ -67,6 +90,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testOnlyLinkSharing() {
$map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
['core', 'shareapi_allow_links', 'yes', 'yes'],
];
$result = $this->getResults($map);
@@ -76,6 +100,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkPassword() {
$map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_enforce_links_password', 'no', 'yes'],
];
@@ -87,6 +112,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkNoPassword() {
$map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_enforce_links_password', 'no', 'no'],
];
@@ -98,6 +124,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkNoExpireDate() {
$map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_default_expire_date', 'no', 'no'],
];
@@ -109,6 +136,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkExpireDate() {
$map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_default_expire_date', 'no', 'yes'],
['core', 'shareapi_expire_after_n_days', '7', '7'],
@@ -124,6 +152,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkExpireDateEnforced() {
$map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_default_expire_date', 'no', 'yes'],
['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
@@ -136,6 +165,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkSendMail() {
$map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_allow_public_notification', 'no', 'yes'],
];
@@ -145,6 +175,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkNoSendMail() {
$map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_allow_public_notification', 'no', 'no'],
];
@@ -154,6 +185,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testUserSendMail() {
$map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
['core', 'shareapi_allow_mail_notification', 'no', 'yes'],
];
$result = $this->getResults($map);
@@ -162,6 +194,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testUserNoSendMail() {
$map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
['core', 'shareapi_allow_mail_notification', 'no', 'no'],
];
$result = $this->getResults($map);
@@ -170,6 +203,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testResharing() {
$map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
['core', 'shareapi_allow_resharing', 'yes', 'yes'],
];
$result = $this->getResults($map);
@@ -178,6 +212,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testNoResharing() {
$map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
['core', 'shareapi_allow_resharing', 'yes', 'no'],
];
$result = $this->getResults($map);
@@ -186,6 +221,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkPublicUpload() {
$map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_allow_public_upload', 'yes', 'yes'],
];
@@ -195,6 +231,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkNoPublicUpload() {
$map = [
+ ['core', 'shareapi_enabled', 'yes', 'yes'],
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_allow_public_upload', 'yes', 'no'],
];
diff --git a/apps/files_trashbin/tests/expiration.php b/apps/files_trashbin/tests/expiration.php
index b3c6fcd95af..76fb24aa4df 100644
--- a/apps/files_trashbin/tests/expiration.php
+++ b/apps/files_trashbin/tests/expiration.php
@@ -207,6 +207,7 @@ class Expiration_Test extends \PHPUnit_Framework_TestCase {
'setSystemValues',
'setSystemValue',
'getSystemValue',
+ 'getFilteredSystemValue',
'deleteSystemValue',
'getAppKeys',
'setAppValue',
diff --git a/apps/files_versions/lib/storage.php b/apps/files_versions/lib/storage.php
index 6aa58c55e9b..bdf1811c5f9 100644
--- a/apps/files_versions/lib/storage.php
+++ b/apps/files_versions/lib/storage.php
@@ -315,6 +315,9 @@ class Storage {
if (self::copyFileContents($users_view, 'files_versions' . $filename . '.v' . $revision, 'files' . $filename)) {
$files_view->touch($file, $revision);
Storage::scheduleExpire($uid, $file);
+ \OC_Hook::emit('\OCP\Versions', 'rollback', array(
+ 'path' => $filename,
+ ));
return true;
} else if ($versionCreated) {
self::deleteVersion($users_view, $version);
diff --git a/apps/files_versions/tests/expirationtest.php b/apps/files_versions/tests/expirationtest.php
index 54024b85b78..11a4746c5e7 100644
--- a/apps/files_versions/tests/expirationtest.php
+++ b/apps/files_versions/tests/expirationtest.php
@@ -177,6 +177,7 @@ class Expiration_Test extends \Test\TestCase {
'setSystemValues',
'setSystemValue',
'getSystemValue',
+ 'getFilteredSystemValue',
'deleteSystemValue',
'getAppKeys',
'setAppValue',
diff --git a/apps/files_versions/tests/versions.php b/apps/files_versions/tests/versions.php
index da214ead60a..d4a85c8bffe 100644
--- a/apps/files_versions/tests/versions.php
+++ b/apps/files_versions/tests/versions.php
@@ -580,6 +580,35 @@ class Test_Files_Versioning extends \Test\TestCase {
$this->doTestRestore();
}
+ /**
+ * @param string $hookName name of hook called
+ * @param string $params variable to recieve parameters provided by hook
+ */
+ private function connectMockHooks($hookName, &$params) {
+ if ($hookName === null) {
+ return;
+ }
+
+ $eventHandler = $this->getMockBuilder('\stdclass')
+ ->setMethods(['callback'])
+ ->getMock();
+
+ $eventHandler->expects($this->any())
+ ->method('callback')
+ ->will($this->returnCallback(
+ function($p) use (&$params) {
+ $params = $p;
+ }
+ ));
+
+ \OCP\Util::connectHook(
+ '\OCP\Versions',
+ $hookName,
+ $eventHandler,
+ 'callback'
+ );
+ }
+
private function doTestRestore() {
$filePath = self::TEST_VERSIONS_USER . '/files/sub/test.txt';
$this->rootView->file_put_contents($filePath, 'test file');
@@ -608,7 +637,15 @@ class Test_Files_Versioning extends \Test\TestCase {
$this->assertEquals('test file', $this->rootView->file_get_contents($filePath));
$info1 = $this->rootView->getFileInfo($filePath);
+ $params = array();
+ $this->connectMockHooks('rollback', $params);
+
\OCA\Files_Versions\Storage::rollback('sub/test.txt', $t2);
+ $expectedParams = array(
+ 'path' => '/sub/test.txt',
+ );
+
+ $this->assertEquals($expectedParams, $params);
$this->assertEquals('version2', $this->rootView->file_get_contents($filePath));
$info2 = $this->rootView->getFileInfo($filePath);
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/config/config.sample.php b/config/config.sample.php
index 51529cdb0cc..e0c486d75c1 100644
--- a/config/config.sample.php
+++ b/config/config.sample.php
@@ -806,6 +806,21 @@ $CONFIG = array(
*/
'ldapUserCleanupInterval' => 51,
+/**
+ * Enforce the existence of the home folder naming rule for all users
+ *
+ * Following scenario:
+ * * a home folder naming rule is set in LDAP advanced settings
+ * * a user doesn't have the home folder naming rule attribute set
+ *
+ * If this is set to **true** (default) it will NOT fallback to the core's
+ * default naming rule of using the internal user ID as home folder name.
+ *
+ * If this is set to **false** it will fallback for the users without the
+ * attribute set to naming the home folder like the internal user ID.
+ *
+ */
+'enforce_home_folder_naming_rule' => true,
/**
* Maintenance
diff --git a/core/ajax/share.php b/core/ajax/share.php
index 69b84564ab1..50c99cb56b4 100644
--- a/core/ajax/share.php
+++ b/core/ajax/share.php
@@ -183,6 +183,37 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
$result = $mailNotification->sendLinkShareMail($to_address, $file, $link, $expiration);
if(empty($result)) {
+ // Get the token from the link
+ $linkParts = explode('/', $link);
+ $token = array_pop($linkParts);
+
+ // Get the share for the token
+ $share = \OCP\Share::getShareByToken($token, false);
+ if ($share !== false) {
+ $currentUser = \OC::$server->getUserSession()->getUser()->getUID();
+ $file = '/' . ltrim($file, '/');
+
+ // Check whether share belongs to the user and whether the file is the same
+ if ($share['file_target'] === $file && $share['uid_owner'] === $currentUser) {
+
+ // Get the path for the user
+ $view = new \OC\Files\View('/' . $currentUser . '/files');
+ $fileId = (int) $share['item_source'];
+ $path = $view->getPath((int) $share['item_source']);
+
+ if ($path !== null) {
+ $event = \OC::$server->getActivityManager()->generateEvent();
+ $event->setApp(\OCA\Files_Sharing\Activity::FILES_SHARING_APP)
+ ->setType(\OCA\Files_Sharing\Activity::TYPE_SHARED)
+ ->setAuthor($currentUser)
+ ->setAffectedUser($currentUser)
+ ->setObject('files', $fileId, $path)
+ ->setSubject(\OCA\Files_Sharing\Activity::SUBJECT_SHARED_EMAIL, [$path, $to_address]);
+ \OC::$server->getActivityManager()->publish($event);
+ }
+ }
+ }
+
\OCP\JSON::success();
} else {
$l = \OC::$server->getL10N('core');
@@ -379,6 +410,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/command/app/checkcode.php b/core/command/app/checkcode.php
index a4e7322460f..9f6e0729ce9 100644
--- a/core/command/app/checkcode.php
+++ b/core/command/app/checkcode.php
@@ -26,6 +26,8 @@ namespace OC\Core\Command\App;
use OC\App\CodeChecker\CodeChecker;
use OC\App\CodeChecker\EmptyCheck;
+use OC\App\CodeChecker\InfoChecker;
+use OC\App\InfoParser;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@@ -33,12 +35,21 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class CheckCode extends Command {
+
+ /** @var InfoParser */
+ private $infoParser;
+
protected $checkers = [
'private' => '\OC\App\CodeChecker\PrivateCheck',
'deprecation' => '\OC\App\CodeChecker\DeprecationCheck',
'strong-comparison' => '\OC\App\CodeChecker\StrongComparisonCheck',
];
+ public function __construct(InfoParser $infoParser) {
+ parent::__construct();
+ $this->infoParser = $infoParser;
+ }
+
protected function configure() {
$this
->setName('app:check-code')
@@ -54,6 +65,12 @@ class CheckCode extends Command {
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'enable the specified checker(s)',
[ 'private', 'deprecation', 'strong-comparison' ]
+ )
+ ->addOption(
+ '--skip-validate-info',
+ null,
+ InputOption::VALUE_NONE,
+ 'skips the info.xml/version check'
);
}
@@ -84,7 +101,7 @@ class CheckCode extends Command {
$output->writeln("<info>Analysing {$filename}</info>");
}
- // show error count if there are errros present or the verbosity is high
+ // show error count if there are errors present or the verbosity is high
if($count > 0 || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
$output->writeln(" {$count} errors");
}
@@ -98,6 +115,53 @@ class CheckCode extends Command {
}
});
$errors = $codeChecker->analyse($appId);
+
+ if(!$input->getOption('skip-validate-info')) {
+ $infoChecker = new InfoChecker($this->infoParser);
+
+ $infoChecker->listen('InfoChecker', 'mandatoryFieldMissing', function($key) use ($output) {
+ $output->writeln("<error>Mandatory field missing: $key</error>");
+ });
+
+ $infoChecker->listen('InfoChecker', 'deprecatedFieldFound', function($key, $value) use ($output) {
+ if($value === [] || is_null($value) || $value === '') {
+ $output->writeln("<info>Deprecated field available: $key</info>");
+ } else {
+ $output->writeln("<info>Deprecated field available: $key => $value</info>");
+ }
+ });
+
+ $infoChecker->listen('InfoChecker', 'differentVersions', function($versionFile, $infoXML) use ($output) {
+ $output->writeln("<error>Different versions provided (appinfo/version: $versionFile - appinfo/info.xml: $infoXML)</error>");
+ });
+
+ $infoChecker->listen('InfoChecker', 'sameVersions', function($path) use ($output) {
+ $output->writeln("<info>Version file isn't needed anymore and can be safely removed ($path)</info>");
+ });
+
+ $infoChecker->listen('InfoChecker', 'migrateVersion', function($version) use ($output) {
+ $output->writeln("<info>Migrate the app version to appinfo/info.xml (add <version>$version</version> to appinfo/info.xml and remove appinfo/version)</info>");
+ });
+
+ if(OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
+ $infoChecker->listen('InfoChecker', 'mandatoryFieldFound', function($key, $value) use ($output) {
+ $output->writeln("<info>Mandatory field available: $key => $value</info>");
+ });
+
+ $infoChecker->listen('InfoChecker', 'optionalFieldFound', function($key, $value) use ($output) {
+ $output->writeln("<info>Optional field available: $key => $value</info>");
+ });
+
+ $infoChecker->listen('InfoChecker', 'unusedFieldFound', function($key, $value) use ($output) {
+ $output->writeln("<info>Unused field available: $key => $value</info>");
+ });
+ }
+
+ $infoErrors = $infoChecker->analyse($appId);
+
+ $errors = array_merge($errors, $infoErrors);
+ }
+
if (empty($errors)) {
$output->writeln('<info>App is compliant - awesome job!</info>');
return 0;
diff --git a/core/command/config/listconfigs.php b/core/command/config/listconfigs.php
index 5796362f2fc..37aeb53c6f5 100644
--- a/core/command/config/listconfigs.php
+++ b/core/command/config/listconfigs.php
@@ -32,20 +32,6 @@ use Symfony\Component\Console\Output\OutputInterface;
class ListConfigs extends Base {
protected $defaultOutputFormat = self::OUTPUT_FORMAT_JSON_PRETTY;
- /** @var array */
- protected $sensitiveValues = [
- 'dbpassword' => true,
- 'dbuser' => true,
- 'mail_smtpname' => true,
- 'mail_smtppassword' => true,
- 'passwordsalt' => true,
- 'secret' => true,
- 'ldap_agent_password' => true,
- 'objectstore' => ['arguments' => ['password' => true]],
- ];
-
- const SENSITIVE_VALUE = '***REMOVED SENSITIVE VALUE***';
-
/** * @var SystemConfig */
protected $systemConfig;
@@ -127,10 +113,10 @@ class ListConfigs extends Base {
$configs = [];
foreach ($keys as $key) {
- $value = $this->systemConfig->getValue($key, serialize(null));
-
- if ($noSensitiveValues && isset($this->sensitiveValues[$key])) {
- $value = $this->removeSensitiveValue($this->sensitiveValues[$key], $value);
+ if ($noSensitiveValues) {
+ $value = $this->systemConfig->getFilteredValue($key, serialize(null));
+ } else {
+ $value = $this->systemConfig->getValue($key, serialize(null));
}
if ($value !== 'N;') {
@@ -140,25 +126,4 @@ class ListConfigs extends Base {
return $configs;
}
-
- /**
- * @param bool|array $keysToRemove
- * @param mixed $value
- * @return mixed
- */
- protected function removeSensitiveValue($keysToRemove, $value) {
- if ($keysToRemove === true) {
- return self::SENSITIVE_VALUE;
- }
-
- if (is_array($value)) {
- foreach ($keysToRemove as $keyToRemove => $valueToRemove) {
- if (isset($value[$keyToRemove])) {
- $value[$keyToRemove] = $this->removeSensitiveValue($valueToRemove, $value[$keyToRemove]);
- }
- }
- }
-
- return $value;
- }
}
diff --git a/core/css/apps.css b/core/css/apps.css
index 6dd7e63bb69..23e0c519d00 100644
--- a/core/css/apps.css
+++ b/core/css/apps.css
@@ -417,7 +417,6 @@
position: relative;
height: 100%;
overflow-y: auto;
- -webkit-overflow-scrolling: touch;
}
#app-content-wrapper {
diff --git a/core/css/fixes.css b/core/css/fixes.css
index e5dbeb137ab..7ef44ba6909 100644
--- a/core/css/fixes.css
+++ b/core/css/fixes.css
@@ -115,8 +115,3 @@ select {
line-height: 38px;
}
-.lte8 input[type="checkbox"] + label:before { background-image: url('../img/actions/checkbox.png'); }
-.lte8 input[type="checkbox"].white + label:before { background-image: url('../img/actions/checkbox-white.png'); }
-.lte8 input[type="checkbox"]:checked + label:before { background-image: url('../img/actions/checkbox-checked.png'); }
-.lte8 input[type="checkbox"].white:checked + label:before { background-image: url('../img/actions/checkbox-checked-white.png'); }
-
diff --git a/core/css/styles.css b/core/css/styles.css
index aefc0ff755a..d952a33c24a 100644
--- a/core/css/styles.css
+++ b/core/css/styles.css
@@ -158,7 +158,9 @@ textarea:hover, textarea:focus, textarea:active {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
opacity: 1;
}
-input[type="checkbox"] {
+
+/* ie8 doesn't support :checked */
+html:not(.ie8) input[type="checkbox"].checkbox {
margin:0;
padding:0;
height:auto;
@@ -166,7 +168,7 @@ input[type="checkbox"] {
display: none;
}
-input[type="checkbox"] + label:before {
+html:not(.ie8) input[type="checkbox"].checkbox + label:before {
content: "";
display: inline-block;
@@ -174,27 +176,27 @@ input[type="checkbox"] + label:before {
width: 20px;
vertical-align: middle;
- background: url('../img/actions/checkbox.svg') left center no-repeat;
+ background: url('../img/actions/checkbox.svg') left top no-repeat;
opacity: 0.7;
}
-input[type="checkbox"]:disabled +label:before { opacity: .6; }
+html:not(.ie8) input[type="checkbox"].checkbox:disabled +label:before { opacity: .6; }
-input[type="checkbox"].u-left +label:before { float: left; }
+html:not(.ie8) input[type="checkbox"].checkbox.u-left +label:before { float: left; }
-input[type="checkbox"].white + label:before {
+html:not(.ie8) input[type="checkbox"].checkbox--white + label:before {
background-image: url('../img/actions/checkbox-white.svg');
}
-input[type="checkbox"]:checked + label:before {
+html:not(.ie8) input[type="checkbox"].checkbox:checked + label:before {
background-image: url('../img/actions/checkbox-checked.svg');
}
-input[type="checkbox"].white:checked + label:before {
+html:not(.ie8) input[type="checkbox"].checkbox--white:checked + label:before {
background-image: url('../img/actions/checkbox-checked-white.svg');
}
-input[type="checkbox"]:hover+label:before, input[type="checkbox"]:focus+label:before {
+html:not(.ie8) input[type="checkbox"].checkbox:hover+label:before, input[type="checkbox"]:focus+label:before {
color:#111 !important;
}
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/img/actions/upload.png b/core/img/actions/upload.png
index a6969c23fa6..8955ed96412 100644
--- a/core/img/actions/upload.png
+++ b/core/img/actions/upload.png
Binary files differ
diff --git a/core/img/actions/upload.svg b/core/img/actions/upload.svg
index 80231797c96..bf1c08cd488 100644
--- a/core/img/actions/upload.svg
+++ b/core/img/actions/upload.svg
@@ -1,4 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
- <path d="M10,12,6,12,6,6,2,6,8,0,14,6,10,6z"/>
- <path fill="#000" d="m0,11,0,5,16,0,0-5-2,0,0,3-12,0,0-3z"/>
+ <path d="m8 1-6 6h4v4h4v-4h4zm-6 12v2h12v-2z"/>
</svg>
diff --git a/core/img/actions/view-close.png b/core/img/actions/view-close.png
index c21f6ee30e7..0874381a576 100644
--- a/core/img/actions/view-close.png
+++ b/core/img/actions/view-close.png
Binary files differ
diff --git a/core/img/actions/view-close.svg b/core/img/actions/view-close.svg
index 89d1fab88dd..2b91e382eb1 100644
--- a/core/img/actions/view-close.svg
+++ b/core/img/actions/view-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="32" width="32" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
- <path fill="#FFF" d="m23.071,6.1013,2.8278,2.8278-7.0713,7.0717,7.071,7.0704-2.8279,2.8283-7.0714-7.0704l-7.0713,7.071-2.8282-2.828,7.0705-7.071-7.1084-7.0316,2.8665-2.8679,7.0709,7.0705z"/>
+ <defs>
+ <filter id="a" style="color-interpolation-filters:sRGB" height="1.5997" width="1.6003" y="-.29984" x="-.30016">
+ <feGaussianBlur stdDeviation="2.2386623"/>
+ </filter>
+ </defs>
+ <path d="m24.955 23.538-1.414 1.414-7.536-7.5358-7.5355 7.5358-1.4142-1.414 7.5355-7.536-7.5355-7.5356 1.4142-1.4142 7.5355 7.5356 7.516-7.5547 1.434 1.4333-7.5357 7.5356z" filter="url(#a)" stroke="#000" stroke-width="2"/>
+ <path d="m24.955 23.538-1.414 1.414-7.536-7.5358-7.5355 7.5358-1.4142-1.414 7.5355-7.536-7.5355-7.5356 1.4142-1.4142 7.5355 7.5356 7.516-7.5547 1.434 1.4333-7.5357 7.5356z" fill="#fff"/>
</svg>
diff --git a/core/img/actions/view-next.png b/core/img/actions/view-next.png
index 8a23452e083..d8c749bec9b 100644
--- a/core/img/actions/view-next.png
+++ b/core/img/actions/view-next.png
Binary files differ
diff --git a/core/img/actions/view-next.svg b/core/img/actions/view-next.svg
index 07c95b73ff0..4b719842efd 100644
--- a/core/img/actions/view-next.svg
+++ b/core/img/actions/view-next.svg
@@ -1,6 +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="32" width="32" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
- <g transform="translate(0 -1020.4)">
- <path d="m9 1024.4 2-2 14 14-14 14-2-2 10-12z" fill="#fff"/>
- </g>
+ <defs>
+ <filter id="a" style="color-interpolation-filters:sRGB" height="1.4477" width="1.8073" y="-.22386" x="-.40365">
+ <feGaussianBlur stdDeviation="2.4158278"/>
+ </filter>
+ </defs>
+ <path d="m10.414 28.952-1.414-1.414 11.535-11.536-11.535-11.536 1.414-1.4138 12.95 12.95z" filter="url(#a)" stroke="#000" stroke-width="2"/>
+ <path d="m10.414 28.952-1.414-1.414 11.535-11.536-11.535-11.536 1.414-1.4138 12.95 12.95z" fill="#fff"/>
</svg>
diff --git a/core/img/actions/view-pause.png b/core/img/actions/view-pause.png
index 1de1fb4654b..87a18128ade 100644
--- a/core/img/actions/view-pause.png
+++ b/core/img/actions/view-pause.png
Binary files differ
diff --git a/core/img/actions/view-pause.svg b/core/img/actions/view-pause.svg
index f5fdc030479..e9ff43be0bf 100644
--- a/core/img/actions/view-pause.svg
+++ b/core/img/actions/view-pause.svg
@@ -1,6 +1,14 @@
<?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="32" width="32" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
- <g transform="translate(0 -1020.4)">
- <path d="m6 1026.4v20h8v-20h-8zm12 0v20h8v-20h-8z" fill="#fff"/>
+ <defs>
+ <filter id="a" style="color-interpolation-filters:sRGB" height="1.6" width="1.6" y="-.3" x="-.3">
+ <feGaussianBlur stdDeviation="2.5"/>
+ </filter>
+ </defs>
+ <g transform="matrix(.9 0 0 .9 1.6 -916.76)" filter="url(#a)" stroke="#000" stroke-width="2.2222">
+ <path d="m6 1026.4v20h8v-20h-8zm12 0v20h8v-20h-8z" stroke="#000" stroke-width="2.2222"/>
+ </g>
+ <g transform="matrix(.9 0 0 .9 1.6 -916.76)">
+ <path fill="#fff" d="m6 1026.4v20h8v-20h-8zm12 0v20h8v-20h-8z"/>
</g>
</svg>
diff --git a/core/img/actions/view-play.png b/core/img/actions/view-play.png
index c506815c0cf..b07c6de3cfd 100644
--- a/core/img/actions/view-play.png
+++ b/core/img/actions/view-play.png
Binary files differ
diff --git a/core/img/actions/view-play.svg b/core/img/actions/view-play.svg
index d9fa355371c..e617e29cb01 100644
--- a/core/img/actions/view-play.svg
+++ b/core/img/actions/view-play.svg
@@ -1,6 +1,14 @@
<?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="32" width="32" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
- <g transform="translate(0 -1020.4)">
- <path d="m4 1024.4 24 12-24 12z" fill="#fff"/>
+ <defs>
+ <filter id="a" style="color-interpolation-filters:sRGB" height="1.6" width="1.6" y="-.3" x="-.3">
+ <feGaussianBlur stdDeviation="3"/>
+ </filter>
+ </defs>
+ <g transform="matrix(.83333 0 0 .83333 2.6667 -847.67)" filter="url(#a)" stroke="#000" stroke-width="2.4">
+ <path d="m4 1024.4 24 12-24 12z" stroke="#000" stroke-width="2.4"/>
+ </g>
+ <g transform="matrix(.83333 0 0 .83333 2.6667 -847.67)">
+ <path fill="#fff" d="m4 1024.4 24 12-24 12z"/>
</g>
</svg>
diff --git a/core/img/actions/view-previous.png b/core/img/actions/view-previous.png
index 79dcb2301df..f601ec2ba44 100644
--- a/core/img/actions/view-previous.png
+++ b/core/img/actions/view-previous.png
Binary files differ
diff --git a/core/img/actions/view-previous.svg b/core/img/actions/view-previous.svg
index 68a31c04433..8a5013aad40 100644
--- a/core/img/actions/view-previous.svg
+++ b/core/img/actions/view-previous.svg
@@ -1,6 +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="32" width="32" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
- <g transform="translate(0 -1020.4)">
- <path d="m23 1024.4-2-2-14 14 14 14 2-2-10-12z" fill="#fff"/>
- </g>
+ <defs>
+ <filter id="a" style="color-interpolation-filters:sRGB" height="1.4477" width="1.8073" y="-.22386" x="-.40365">
+ <feGaussianBlur stdDeviation="2.4158278"/>
+ </filter>
+ </defs>
+ <path d="m10.414 28.952-1.414-1.414 11.535-11.536-11.535-11.536 1.414-1.4138 12.95 12.95z" transform="matrix(-1 0 0 1 32.364 0)" filter="url(#a)" stroke="#000" stroke-width="2"/>
+ <path d="m21.95 28.952 1.414-1.414-11.536-11.536 11.536-11.536-1.414-1.4138-12.95 12.95z" fill="#fff"/>
</svg>
diff --git a/core/js/multiselect.js b/core/js/multiselect.js
index 41dc68ac051..6d5c54ac0f5 100644
--- a/core/js/multiselect.js
+++ b/core/js/multiselect.js
@@ -109,6 +109,9 @@
var id='ms'+multiSelectId+'-option-'+item;
var input=$('<input type="' + inputType + '"/>');
input.attr('id',id);
+ if(inputType === 'checkbox') {
+ input.addClass('checkbox');
+ }
if(settings.singleSelect) {
input.attr('name', 'ms'+multiSelectId+'-option');
}
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/sharedialogshareelistview.js b/core/js/sharedialogshareelistview.js
index d2c45bb08b1..8c1934ff264 100644
--- a/core/js/sharedialogshareelistview.js
+++ b/core/js/sharedialogshareelistview.js
@@ -21,7 +21,7 @@
' {{/if}}' +
' {{#unless isCollection}}' +
' <li data-share-type="{{shareType}}" data-share-with="{{shareWith}}" title="{{shareWith}}">' +
- ' <a href="#" class="unshare"><img class="svg" alt="{{unshareLabel}}" title="{{unshareLabel}}" src="{{unshareImage}}" /></a>' +
+ ' <a href="#" class="unshare"><span class="icon-loading-small hidden"></span><img class="svg" alt="{{unshareLabel}}" title="{{unshareLabel}}" src="{{unshareImage}}" /></a>' +
' {{#if avatarEnabled}}' +
' <div class="avatar {{#if modSeed}}imageplaceholderseed{{/if}}" data-username="{{shareWith}}" {{#if modSeed}}data-seed="{{shareWith}} {{shareType}}"{{/if}}></div>' +
' {{/if}}' +
@@ -244,12 +244,14 @@
onUnshare: function(event) {
var $element = $(event.target);
+ console.log($element);
- if($element.hasClass('icon-loading-small')) {
+ var $loading = $element.siblings('.icon-loading-small').eq(0);
+ if(!$loading.hasClass('hidden')) {
// in process
return;
}
- $element.empty().addClass('icon-loading-small');
+ $loading.removeClass('hidden');
var $li = $element.closest('li');
var shareType = $li.data('share-type');
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/register_command.php b/core/register_command.php
index 114e115c491..878542f72c9 100644
--- a/core/register_command.php
+++ b/core/register_command.php
@@ -28,7 +28,8 @@
/** @var $application Symfony\Component\Console\Application */
$application->add(new OC\Core\Command\Status);
$application->add(new OC\Core\Command\Check(\OC::$server->getConfig()));
-$application->add(new OC\Core\Command\App\CheckCode());
+$infoParser = new \OC\App\InfoParser(\OC::$server->getHTTPHelper(), \OC::$server->getURLGenerator());
+$application->add(new OC\Core\Command\App\CheckCode($infoParser));
$application->add(new OC\Core\Command\L10n\CreateJs());
if (\OC::$server->getConfig()->getSystemValue('installed', 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/core/templates/login.php b/core/templates/login.php
index 2057b1034d0..db77f63bbd0 100644
--- a/core/templates/login.php
+++ b/core/templates/login.php
@@ -65,7 +65,7 @@ script('core', [
<?php endif; ?>
<?php if ($_['rememberLoginAllowed'] === true) : ?>
<div class="remember-login-container">
- <input type="checkbox" name="remember_login" value="1" id="remember_login" class="white">
+ <input type="checkbox" name="remember_login" value="1" id="remember_login" class="checkbox checkbox--white">
<label for="remember_login"><?php p($l->t('remember')); ?></label>
</div>
<?php endif; ?>
diff --git a/lib/base.php b/lib/base.php
index 3624a3fbaf9..32b90cad1fa 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -376,63 +376,6 @@ class OC {
$tmpl->printPage();
}
- public static function initTemplateEngine() {
- // Add the stuff we need always
- // following logic will import all vendor libraries that are
- // specified in core/js/core.json
- $fileContent = file_get_contents(OC::$SERVERROOT . '/core/js/core.json');
- if($fileContent !== false) {
- $coreDependencies = json_decode($fileContent, true);
- foreach($coreDependencies['vendor'] as $vendorLibrary) {
- // remove trailing ".js" as addVendorScript will append it
- OC_Util::addVendorScript(
- substr($vendorLibrary, 0, strlen($vendorLibrary) - 3));
- }
- } else {
- throw new \Exception('Cannot read core/js/core.json');
- }
-
- OC_Util::addScript("placeholders");
- OC_Util::addScript("compatibility");
- OC_Util::addScript("jquery.ocdialog");
- OC_Util::addScript("oc-dialogs");
- OC_Util::addScript("js");
- OC_Util::addScript("l10n");
- OC_Util::addTranslations("core");
- OC_Util::addScript("octemplate");
- OC_Util::addScript("eventsource");
- OC_Util::addScript("config");
- OC_Util::addScript('search', 'search');
- OC_Util::addScript("oc-requesttoken");
- OC_Util::addScript("apps");
- OC_Util::addScript('mimetype');
- OC_Util::addScript('mimetypelist');
- OC_Util::addVendorScript('snapjs/dist/latest/snap');
- OC_Util::addVendorScript('core', 'backbone/backbone');
- OC_Util::addScript('oc-backbone');
-
- // avatars
- if (\OC::$server->getSystemConfig()->getValue('enable_avatars', true) === true) {
- \OC_Util::addScript('placeholder');
- \OC_Util::addVendorScript('blueimp-md5/js/md5');
- \OC_Util::addScript('jquery.avatar');
- \OC_Util::addScript('avatar');
- }
-
- OC_Util::addStyle("styles");
- OC_Util::addStyle("header");
- OC_Util::addStyle("mobile");
- OC_Util::addStyle("icons");
- OC_Util::addStyle("fonts");
- OC_Util::addStyle("apps");
- OC_Util::addStyle("fixes");
- OC_Util::addStyle("multiselect");
- OC_Util::addVendorStyle('jquery-ui/themes/base/jquery-ui');
- OC_Util::addStyle('jquery-ui-fixes');
- OC_Util::addStyle("tooltip");
- OC_Util::addStyle("jquery.ocdialog");
- }
-
public static function initSession() {
// prevents javascript from accessing php session cookies
ini_set('session.cookie_httponly', true);
@@ -611,7 +554,6 @@ class OC {
self::initSession();
}
\OC::$server->getEventLogger()->end('init_session');
- self::initTemplateEngine();
self::checkConfig();
self::checkInstalled();
@@ -673,7 +615,7 @@ class OC {
self::registerFilesystemHooks();
if ($systemConfig->getValue('enable_previews', true)) {
self::registerPreviewHooks();
- }
+ }
self::registerShareHooks();
self::registerLogRotate();
self::registerLocalAddressBook();
@@ -686,12 +628,6 @@ class OC {
$lockProvider = \OC::$server->getLockingProvider();
register_shutdown_function(array($lockProvider, 'releaseAll'));
- if ($systemConfig->getValue('installed', false) && !self::checkUpgrade(false)) {
- if (\OC::$server->getConfig()->getAppValue('core', 'backgroundjobs_mode', 'ajax') == 'ajax') {
- OC_Util::addScript('backgroundjobs');
- }
- }
-
// Check whether the sample configuration has been copied
if($systemConfig->getValue('copied_sample_config', false)) {
$l = \OC::$server->getL10N('lib');
@@ -803,8 +739,9 @@ class OC {
OC_Hook::connect('\OCP\Versions', 'preDelete', 'OC\Preview', 'prepare_delete');
OC_Hook::connect('\OCP\Trashbin', 'preDelete', 'OC\Preview', 'prepare_delete');
OC_Hook::connect('OC_Filesystem', 'post_delete', 'OC\Preview', 'post_delete_files');
- OC_Hook::connect('\OCP\Versions', 'delete', 'OC\Preview', 'post_delete');
+ OC_Hook::connect('\OCP\Versions', 'delete', 'OC\Preview', 'post_delete_versions');
OC_Hook::connect('\OCP\Trashbin', 'delete', 'OC\Preview', 'post_delete');
+ OC_Hook::connect('\OCP\Versions', 'rollback', 'OC\Preview', 'post_delete_versions');
}
/**
diff --git a/lib/private/allconfig.php b/lib/private/allconfig.php
index 63cc92601bb..7c2037e8048 100644
--- a/lib/private/allconfig.php
+++ b/lib/private/allconfig.php
@@ -119,6 +119,17 @@ class AllConfig implements \OCP\IConfig {
}
/**
+ * Looks up a system wide defined value and filters out sensitive data
+ *
+ * @param string $key the key of the value, under which it was saved
+ * @param mixed $default the default value to be returned if the value isn't set
+ * @return mixed the value or $default
+ */
+ public function getFilteredSystemValue($key, $default = '') {
+ return $this->systemConfig->getFilteredValue($key, $default);
+ }
+
+ /**
* Delete a system wide defined value
*
* @param string $key the key of the value, under which it was saved
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/app/codechecker/infochecker.php b/lib/private/app/codechecker/infochecker.php
new file mode 100644
index 00000000000..91580bde07d
--- /dev/null
+++ b/lib/private/app/codechecker/infochecker.php
@@ -0,0 +1,146 @@
+<?php
+/**
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\App\CodeChecker;
+
+use OC\App\InfoParser;
+use OC\Hooks\BasicEmitter;
+
+class InfoChecker extends BasicEmitter {
+
+ /** @var InfoParser */
+ private $infoParser;
+
+ private $mandatoryFields = [
+ 'author',
+ 'description',
+ 'id',
+ 'licence',
+ 'name',
+ ];
+ private $optionalFields = [
+ 'bugs',
+ 'category',
+ 'default_enable',
+ 'dependencies',
+ 'documentation',
+ 'namespace',
+ 'ocsid',
+ 'public',
+ 'remote',
+ 'repository',
+ 'require',
+ 'requiremin',
+ 'types',
+ 'version',
+ 'website',
+ ];
+ private $deprecatedFields = [
+ 'info',
+ 'shipped',
+ 'standalone',
+ ];
+
+ public function __construct(InfoParser $infoParser) {
+ $this->infoParser = $infoParser;
+ }
+
+ /**
+ * @param string $appId
+ * @return array
+ */
+ public function analyse($appId) {
+ $appPath = \OC_App::getAppPath($appId);
+ if ($appPath === false) {
+ throw new \RuntimeException("No app with given id <$appId> known.");
+ }
+
+ $errors = [];
+
+ $info = $this->infoParser->parse($appPath . '/appinfo/info.xml');
+
+ foreach ($info as $key => $value) {
+ if(is_array($value)) {
+ $value = json_encode($value);
+ }
+ if (in_array($key, $this->mandatoryFields)) {
+ $this->emit('InfoChecker', 'mandatoryFieldFound', [$key, $value]);
+ continue;
+ }
+
+ if (in_array($key, $this->optionalFields)) {
+ $this->emit('InfoChecker', 'optionalFieldFound', [$key, $value]);
+ continue;
+ }
+
+ if (in_array($key, $this->deprecatedFields)) {
+ // skip empty arrays - empty arrays for remote and public are always added
+ if($value === '[]' && in_array($key, ['public', 'remote', 'info'])) {
+ continue;
+ }
+ $this->emit('InfoChecker', 'deprecatedFieldFound', [$key, $value]);
+ continue;
+ }
+
+ $this->emit('InfoChecker', 'unusedFieldFound', [$key, $value]);
+ }
+
+ foreach ($this->mandatoryFields as $key) {
+ if(!isset($info[$key])) {
+ $this->emit('InfoChecker', 'mandatoryFieldMissing', [$key]);
+ $errors[] = [
+ 'type' => 'mandatoryFieldMissing',
+ 'field' => $key,
+ ];
+ }
+ }
+
+ $versionFile = $appPath . '/appinfo/version';
+ if (is_file($versionFile)) {
+ $version = trim(file_get_contents($versionFile));
+ if(isset($info['version'])) {
+ if($info['version'] !== $version) {
+ $this->emit('InfoChecker', 'differentVersions',
+ [$version, $info['version']]);
+ $errors[] = [
+ 'type' => 'differentVersions',
+ 'message' => 'appinfo/version: ' . $version .
+ ' - appinfo/info.xml: ' . $info['version'],
+ ];
+ } else {
+ $this->emit('InfoChecker', 'sameVersions', [$versionFile]);
+ }
+ } else {
+ $this->emit('InfoChecker', 'migrateVersion', [$version]);
+ }
+ } else {
+ if(!isset($info['version'])) {
+ $this->emit('InfoChecker', 'mandatoryFieldMissing', ['version']);
+ $errors[] = [
+ 'type' => 'mandatoryFieldMissing',
+ 'field' => 'version',
+ ];
+ }
+ }
+
+ return $errors;
+ }
+}
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/private/log.php b/lib/private/log.php
index 3c0e7b45d1b..4a0a34b7113 100644
--- a/lib/private/log.php
+++ b/lib/private/log.php
@@ -3,6 +3,7 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Olivier Paroz <owncloud@oparoz.com>
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Mรผller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
@@ -26,6 +27,8 @@
namespace OC;
+use InterfaSys\LogNormalizer\Normalizer;
+
use \OCP\ILogger;
use OCP\Security\StringUtils;
@@ -48,12 +51,15 @@ class Log implements ILogger {
/** @var boolean|null cache the result of the log condition check for the request */
private $logConditionSatisfied = null;
+ /** @var Normalizer */
+ private $normalizer;
/**
* @param string $logger The logger that should be used
* @param SystemConfig $config the system config object
+ * @param null $normalizer
*/
- public function __construct($logger=null, SystemConfig $config=null) {
+ public function __construct($logger=null, SystemConfig $config=null, $normalizer = null) {
// FIXME: Add this for backwards compatibility, should be fixed at some point probably
if($config === null) {
$config = \OC::$server->getSystemConfig();
@@ -68,6 +74,11 @@ class Log implements ILogger {
} else {
$this->logger = $logger;
}
+ if ($normalizer === null) {
+ $this->normalizer = new Normalizer();
+ } else {
+ $this->normalizer = $normalizer;
+ }
}
@@ -175,6 +186,8 @@ class Log implements ILogger {
$minLevel = min($this->config->getValue('loglevel', \OCP\Util::WARN), \OCP\Util::ERROR);
$logCondition = $this->config->getValue('log.condition', []);
+ array_walk($context, [$this->normalizer, 'format']);
+
if (isset($context['app'])) {
$app = $context['app'];
@@ -241,4 +254,25 @@ class Log implements ILogger {
call_user_func(array($logger, 'write'), $app, $message, $level);
}
}
+
+ /**
+ * Logs an exception very detailed
+ *
+ * @param \Exception $exception
+ * @param array $context
+ * @return void
+ * @since 8.2.0
+ */
+ public function logException(\Exception $exception, array $context = array()) {
+ $exception = array(
+ 'Exception' => get_class($exception),
+ 'Message' => $exception->getMessage(),
+ 'Code' => $exception->getCode(),
+ 'Trace' => $exception->getTraceAsString(),
+ 'File' => $exception->getFile(),
+ 'Line' => $exception->getLine(),
+ );
+ $exception['Trace'] = preg_replace('!(login|checkPassword)\(.*\)!', '$1(*** username and password replaced ***)', $exception['Trace']);
+ $this->error('Exception: ' . json_encode($exception), $context);
+ }
}
diff --git a/lib/private/preview.php b/lib/private/preview.php
index 978da1161c2..de964b72df2 100644
--- a/lib/private/preview.php
+++ b/lib/private/preview.php
@@ -1296,6 +1296,13 @@ class Preview {
/**
* @param array $args
+ */
+ public static function post_delete_versions($args) {
+ self::post_delete($args, 'files/');
+ }
+
+ /**
+ * @param array $args
* @param string $prefix
*/
public static function post_delete($args, $prefix = '') {
diff --git a/lib/private/server.php b/lib/private/server.php
index 9f99ead849b..26eb99927fc 100644
--- a/lib/private/server.php
+++ b/lib/private/server.php
@@ -1098,4 +1098,5 @@ class Server extends SimpleContainer implements IServerContainer {
public function getUserStoragesService() {
return \OC_Mount_Config::$app->getContainer()->query('OCA\\Files_External\\Service\\UserStoragesService');
}
+
}
diff --git a/lib/private/share/share.php b/lib/private/share/share.php
index 07c7f31a853..32389f34868 100644
--- a/lib/private/share/share.php
+++ b/lib/private/share/share.php
@@ -1998,7 +1998,6 @@ class Share extends Constants {
$suggestedItemTarget = $result['suggestedItemTarget'];
$suggestedFileTarget = $result['suggestedFileTarget'];
$filePath = $result['filePath'];
- $expirationDate = $result['expirationDate'];
}
$isGroupShare = false;
diff --git a/lib/private/systemconfig.php b/lib/private/systemconfig.php
index 13b0959768a..94b815aebd7 100644
--- a/lib/private/systemconfig.php
+++ b/lib/private/systemconfig.php
@@ -22,12 +22,28 @@
namespace OC;
+
+use OCP\IConfig;
+
/**
* Class which provides access to the system config values stored in config.php
* Internal class for bootstrap only.
* fixes cyclic DI: AllConfig needs AppConfig needs Database needs AllConfig
*/
class SystemConfig {
+
+ /** @var array */
+ protected $sensitiveValues = [
+ 'dbpassword' => true,
+ 'dbuser' => true,
+ 'mail_smtpname' => true,
+ 'mail_smtppassword' => true,
+ 'passwordsalt' => true,
+ 'secret' => true,
+ 'ldap_agent_password' => true,
+ 'objectstore' => ['arguments' => ['password' => true]],
+ ];
+
/**
* Lists all available config keys
* @return array an array of key names
@@ -68,6 +84,23 @@ class SystemConfig {
}
/**
+ * Looks up a system wide defined value and filters out sensitive data
+ *
+ * @param string $key the key of the value, under which it was saved
+ * @param mixed $default the default value to be returned if the value isn't set
+ * @return mixed the value or $default
+ */
+ public function getFilteredValue($key, $default = '') {
+ $value = $this->getValue($key, $default);
+
+ if (isset($this->sensitiveValues[$key])) {
+ $value = $this->removeSensitiveValue($this->sensitiveValues[$key], $value);
+ }
+
+ return $value;
+ }
+
+ /**
* Delete a system wide defined value
*
* @param string $key the key of the value, under which it was saved
@@ -75,4 +108,25 @@ class SystemConfig {
public function deleteValue($key) {
\OC_Config::deleteKey($key);
}
+
+ /**
+ * @param bool|array $keysToRemove
+ * @param mixed $value
+ * @return mixed
+ */
+ protected function removeSensitiveValue($keysToRemove, $value) {
+ if ($keysToRemove === true) {
+ return IConfig::SENSITIVE_VALUE;
+ }
+
+ if (is_array($value)) {
+ foreach ($keysToRemove as $keyToRemove => $valueToRemove) {
+ if (isset($value[$keyToRemove])) {
+ $value[$keyToRemove] = $this->removeSensitiveValue($valueToRemove, $value[$keyToRemove]);
+ }
+ }
+ }
+
+ return $value;
+ }
}
diff --git a/lib/private/template.php b/lib/private/template.php
index 920be71abbf..0300e43edea 100644
--- a/lib/private/template.php
+++ b/lib/private/template.php
@@ -37,27 +37,40 @@ require_once __DIR__.'/template/functions.php';
* This class provides the templates for ownCloud.
*/
class OC_Template extends \OC\Template\Base {
- private $renderas; // Create a full page?
+
+ /** @var string */
+ private $renderAs; // Create a full page?
+
+ /** @var string */
private $path; // The path to the template
+
+ /** @var array */
private $headers = array(); //custom headers
+
+ /** @var string */
protected $app; // app id
/**
* Constructor
* @param string $app app providing the template
* @param string $name of the template file (without suffix)
- * @param string $renderas = ""; produce a full page
+ * @param string $renderAs = ""; produce a full page
* @param bool $registerCall = true
* @return OC_Template object
*
* This function creates an OC_Template object.
*
- * If $renderas is set, OC_Template will try to produce a full page in the
- * according layout. For now, renderas can be set to "guest", "user" or
+ * If $renderAs is set, OC_Template will try to produce a full page in the
+ * according layout. For now, $renderAs can be set to "guest", "user" or
* "admin".
*/
- public function __construct( $app, $name, $renderas = "", $registerCall = true ) {
+
+ protected static $initTemplateEngineFirstRun = true;
+
+ public function __construct( $app, $name, $renderAs = "", $registerCall = true ) {
// Read the selected theme from the config file
+ self::initTemplateEngine();
+
$theme = OC_Util::getTheme();
$requesttoken = (OC::$server->getSession() and $registerCall) ? OC_Util::callRegister() : '';
@@ -69,13 +82,85 @@ class OC_Template extends \OC\Template\Base {
list($path, $template) = $this->findTemplate($theme, $app, $name);
// Set the private data
- $this->renderas = $renderas;
+ $this->renderAs = $renderAs;
$this->path = $path;
$this->app = $app;
parent::__construct($template, $requesttoken, $l10n, $themeDefaults);
}
+ public static function initTemplateEngine() {
+ if (self::$initTemplateEngineFirstRun){
+
+ //apps that started before the template initialization can load their own scripts/styles
+ //so to make sure this scripts/styles here are loaded first we use OC_Util::addScript() with $prepend=true
+ //meaning the last script/style in this list will be loaded first
+ if (\OC::$server->getSystemConfig ()->getValue ( 'installed', false ) && ! \OCP\Util::needUpgrade ()) {
+ if (\OC::$server->getConfig ()->getAppValue ( 'core', 'backgroundjobs_mode', 'ajax' ) == 'ajax') {
+ OC_Util::addScript ( 'backgroundjobs', null, true );
+ }
+ }
+
+ OC_Util::addStyle("tooltip",null,true);
+ OC_Util::addStyle('jquery-ui-fixes',null,true);
+ OC_Util::addVendorStyle('jquery-ui/themes/base/jquery-ui',null,true);
+ OC_Util::addStyle("multiselect",null,true);
+ OC_Util::addStyle("fixes",null,true);
+ OC_Util::addStyle("apps",null,true);
+ OC_Util::addStyle("fonts",null,true);
+ OC_Util::addStyle("icons",null,true);
+ OC_Util::addStyle("mobile",null,true);
+ OC_Util::addStyle("header",null,true);
+ OC_Util::addStyle("styles",null,true);
+
+ // avatars
+ if (\OC::$server->getSystemConfig()->getValue('enable_avatars', true) === true) {
+ \OC_Util::addScript('avatar', null, true);
+ \OC_Util::addScript('jquery.avatar', null, true);
+ \OC_Util::addScript('placeholder', null, true);
+ }
+
+ OC_Util::addScript('oc-backbone', null, true);
+ OC_Util::addVendorScript('core', 'backbone/backbone', true);
+ OC_Util::addVendorScript('snapjs/dist/latest/snap', null, true);
+ OC_Util::addScript('mimetypelist', null, true);
+ OC_Util::addScript('mimetype', null, true);
+ OC_Util::addScript("apps", null, true);
+ OC_Util::addScript("oc-requesttoken", null, true);
+ OC_Util::addScript('search', 'search', true);
+ OC_Util::addScript("config", null, true);
+ OC_Util::addScript("eventsource", null, true);
+ OC_Util::addScript("octemplate", null, true);
+ OC_Util::addTranslations("core", null, true);
+ OC_Util::addScript("l10n", null, true);
+ OC_Util::addScript("js", null, true);
+ OC_Util::addScript("oc-dialogs", null, true);
+ OC_Util::addScript("jquery.ocdialog", null, true);
+ OC_Util::addStyle("jquery.ocdialog");
+ OC_Util::addScript("compatibility", null, true);
+ OC_Util::addScript("placeholders", null, true);
+
+ // Add the stuff we need always
+ // following logic will import all vendor libraries that are
+ // specified in core/js/core.json
+ $fileContent = file_get_contents(OC::$SERVERROOT . '/core/js/core.json');
+ if($fileContent !== false) {
+ $coreDependencies = json_decode($fileContent, true);
+ foreach(array_reverse($coreDependencies['vendor']) as $vendorLibrary) {
+ // remove trailing ".js" as addVendorScript will append it
+ OC_Util::addVendorScript(
+ substr($vendorLibrary, 0, strlen($vendorLibrary) - 3),null,true);
+ }
+ } else {
+ throw new \Exception('Cannot read core/js/core.json');
+ }
+
+ self::$initTemplateEngineFirstRun = false;
+ }
+
+ }
+
+
/**
* find the template with the given name
* @param string $name of the template file (without suffix)
@@ -118,14 +203,14 @@ class OC_Template extends \OC\Template\Base {
* Process the template
* @return boolean|string
*
- * This function process the template. If $this->renderas is set, it
+ * This function process the template. If $this->renderAs is set, it
* will produce a full page.
*/
public function fetchPage() {
$data = parent::fetchPage();
- if( $this->renderas ) {
- $page = new OC_TemplateLayout($this->renderas, $this->app);
+ if( $this->renderAs ) {
+ $page = new OC_TemplateLayout($this->renderAs, $this->app);
// Add custom headers
$headers = '';
@@ -141,18 +226,20 @@ class OC_Template extends \OC\Template\Base {
}
}
- $page->assign('headers', $headers, false);
+ $page->assign('headers', $headers);
- $page->assign('content', $data, false );
+ $page->assign('content', $data);
return $page->fetchPage();
}
- else{
- return $data;
- }
+
+ return $data;
}
/**
* Include template
+ *
+ * @param string $file
+ * @param array|null $additionalParams
* @return string returns content of included template
*
* Includes another template. use <?php echo $this->inc('template'); ?> to
@@ -222,7 +309,7 @@ class OC_Template extends \OC\Template\Base {
/**
* print error page using Exception details
- * @param Exception|Error $exception
+ * @param Exception $exception
*/
public static function printExceptionErrorPage($exception) {
$request = \OC::$server->getRequest();
diff --git a/lib/private/util.php b/lib/private/util.php
index 667d358655f..9abaef71a68 100644
--- a/lib/private/util.php
+++ b/lib/private/util.php
@@ -439,16 +439,23 @@ class OC_Util {
*
* @param string $application application id
* @param string|null $file filename
+ * @param bool $prepend prepend the Script to the beginning of the list
* @return void
*/
- public static function addScript($application, $file = null) {
+ public static function addScript($application, $file = null, $prepend = false) {
$path = OC_Util::generatePath($application, 'js', $file);
+ //TODO eliminate double code
if (!in_array($path, self::$scripts)) {
// core js files need separate handling
if ($application !== 'core' && $file !== null) {
self::addTranslations($application);
}
- self::$scripts[] = $path;
+ if ($prepend===true) {
+ array_unshift(self::$scripts, $path);
+ }
+ else {
+ self::$scripts[] = $path;
+ }
}
}
@@ -457,12 +464,18 @@ class OC_Util {
*
* @param string $application application id
* @param string|null $file filename
+ * @param bool $prepend prepend the Script to the beginning of the list
* @return void
*/
- public static function addVendorScript($application, $file = null) {
+ public static function addVendorScript($application, $file = null, $prepend = false) {
$path = OC_Util::generatePath($application, 'vendor', $file);
- if (!in_array($path, self::$scripts)) {
- self::$scripts[] = $path;
+ //TODO eliminate double code
+ if (! in_array ( $path, self::$scripts )) {
+ if ($prepend === true) {
+ array_unshift ( self::$scripts, $path );
+ } else {
+ self::$scripts [] = $path;
+ }
}
}
@@ -471,8 +484,9 @@ class OC_Util {
*
* @param string $application application id
* @param string $languageCode language code, defaults to the current language
+ * @param bool $prepend prepend the Script to the beginning of the list
*/
- public static function addTranslations($application, $languageCode = null) {
+ public static function addTranslations($application, $languageCode = null, $prepend = false) {
if (is_null($languageCode)) {
$languageCode = \OC_L10N::findLanguage($application);
}
@@ -481,8 +495,13 @@ class OC_Util {
} else {
$path = "l10n/$languageCode";
}
+ //TODO eliminate double code
if (!in_array($path, self::$scripts)) {
- self::$scripts[] = $path;
+ if ($prepend === true) {
+ array_unshift ( self::$scripts, $path );
+ } else {
+ self::$scripts [] = $path;
+ }
}
}
@@ -491,12 +510,18 @@ class OC_Util {
*
* @param string $application application id
* @param string|null $file filename
+ * @param bool $prepend prepend the Style to the beginning of the list
* @return void
*/
- public static function addStyle($application, $file = null) {
+ public static function addStyle($application, $file = null, $prepend = false) {
$path = OC_Util::generatePath($application, 'css', $file);
+ //TODO eliminate double code
if (!in_array($path, self::$styles)) {
- self::$styles[] = $path;
+ if ($prepend === true) {
+ array_unshift ( self::$styles, $path );
+ } else {
+ self::$styles[] = $path;
+ }
}
}
@@ -505,12 +530,18 @@ class OC_Util {
*
* @param string $application application id
* @param string|null $file filename
+ * @param bool $prepend prepend the Style to the beginning of the list
* @return void
*/
- public static function addVendorStyle($application, $file = null) {
+ public static function addVendorStyle($application, $file = null, $prepend = false) {
$path = OC_Util::generatePath($application, 'vendor', $file);
+ //TODO eliminate double code
if (!in_array($path, self::$styles)) {
- self::$styles[] = $path;
+ if ($prepend === true) {
+ array_unshift ( self::$styles, $path );
+ } else {
+ self::$styles[] = $path;
+ }
}
}
diff --git a/lib/public/iconfig.php b/lib/public/iconfig.php
index ff0b6c6a5b0..933eef97ae1 100644
--- a/lib/public/iconfig.php
+++ b/lib/public/iconfig.php
@@ -41,6 +41,11 @@ namespace OCP;
*/
interface IConfig {
/**
+ * @since 8.2.0
+ */
+ const SENSITIVE_VALUE = '***REMOVED SENSITIVE VALUE***';
+
+ /**
* Sets and deletes system wide values
*
* @param array $configs Associative array with `key => value` pairs
@@ -69,6 +74,16 @@ interface IConfig {
public function getSystemValue($key, $default = '');
/**
+ * Looks up a system wide defined value and filters out sensitive data
+ *
+ * @param string $key the key of the value, under which it was saved
+ * @param mixed $default the default value to be returned if the value isn't set
+ * @return mixed the value or $default
+ * @since 8.2.0
+ */
+ public function getFilteredSystemValue($key, $default = '');
+
+ /**
* Delete a system wide defined value
*
* @param string $key the key of the value, under which it was saved
diff --git a/lib/public/ilogger.php b/lib/public/ilogger.php
index 43b1ef70e5b..27a5d63dfdb 100644
--- a/lib/public/ilogger.php
+++ b/lib/public/ilogger.php
@@ -122,4 +122,14 @@ interface ILogger {
* @since 7.0.0
*/
public function log($level, $message, array $context = array());
+
+ /**
+ * Logs an exception very detailed
+ *
+ * @param \Exception $exception
+ * @param array $context
+ * @return void
+ * @since 8.2.0
+ */
+ public function logException(\Exception $exception, array $context = array());
}
diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php
index 8be23dff214..e37652c1adc 100644
--- a/lib/public/iservercontainer.php
+++ b/lib/public/iservercontainer.php
@@ -194,6 +194,12 @@ interface IServerContainer {
public function getAppConfig();
/**
+ * @return \OCP\L10N\IFactory
+ * @since 8.2.0
+ */
+ public function getL10NFactory();
+
+ /**
* get an L10N instance
* @param string $app appid
* @param string $lang
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/lib/public/util.php b/lib/public/util.php
index c32668b14a8..652df5192cf 100644
--- a/lib/public/util.php
+++ b/lib/public/util.php
@@ -158,17 +158,10 @@ class Util {
* @param \Exception $ex exception to log
* @param int $level log level, defaults to \OCP\Util::FATAL
* @since ....0.0 - parameter $level was added in 7.0.0
+ * @deprecated 8.2.0 use logException of \OCP\ILogger
*/
public static function logException( $app, \Exception $ex, $level = \OCP\Util::FATAL ) {
- $exception = array(
- 'Exception' => get_class($ex),
- 'Message' => $ex->getMessage(),
- 'Code' => $ex->getCode(),
- 'Trace' => $ex->getTraceAsString(),
- 'File' => $ex->getFile(),
- 'Line' => $ex->getLine(),
- );
- \OCP\Util::writeLog($app, 'Exception: ' . json_encode($exception), $level);
+ \OC::$server->getLogger()->logException($ex, ['app' => $app]);
}
/**
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/js/users/users.js b/settings/js/users/users.js
index 5b12366ad40..47d63c11b95 100644
--- a/settings/js/users/users.js
+++ b/settings/js/users/users.js
@@ -813,44 +813,73 @@ $(document).ready(function () {
});
});
+ if ($('#CheckboxStorageLocation').is(':checked')) {
+ $("#userlist .storageLocation").show();
+ }
// Option to display/hide the "Storage location" column
$('#CheckboxStorageLocation').click(function() {
if ($('#CheckboxStorageLocation').is(':checked')) {
$("#userlist .storageLocation").show();
+ OC.AppConfig.setValue('core', 'umgmt_show_storage_location', 'true');
} else {
$("#userlist .storageLocation").hide();
+ OC.AppConfig.setValue('core', 'umgmt_show_storage_location', 'false');
}
});
+
+ if ($('#CheckboxLastLogin').is(':checked')) {
+ $("#userlist .lastLogin").show();
+ }
// Option to display/hide the "Last Login" column
$('#CheckboxLastLogin').click(function() {
if ($('#CheckboxLastLogin').is(':checked')) {
$("#userlist .lastLogin").show();
+ OC.AppConfig.setValue('core', 'umgmt_show_last_login', 'true');
} else {
$("#userlist .lastLogin").hide();
+ OC.AppConfig.setValue('core', 'umgmt_show_last_login', 'false');
}
});
+
+ if ($('#CheckboxEmailAddress').is(':checked')) {
+ $("#userlist .mailAddress").show();
+ }
// Option to display/hide the "Mail Address" column
$('#CheckboxEmailAddress').click(function() {
if ($('#CheckboxEmailAddress').is(':checked')) {
$("#userlist .mailAddress").show();
+ OC.AppConfig.setValue('core', 'umgmt_show_email', 'true');
} else {
$("#userlist .mailAddress").hide();
+ OC.AppConfig.setValue('core', 'umgmt_show_email', 'false');
}
});
+
+ if ($('#CheckboxUserBackend').is(':checked')) {
+ $("#userlist .userBackend").show();
+ }
// Option to display/hide the "User Backend" column
$('#CheckboxUserBackend').click(function() {
if ($('#CheckboxUserBackend').is(':checked')) {
$("#userlist .userBackend").show();
+ OC.AppConfig.setValue('core', 'umgmt_show_backend', 'true');
} else {
$("#userlist .userBackend").hide();
+ OC.AppConfig.setValue('core', 'umgmt_show_backend', 'false');
}
});
+
+ if ($('#CheckboxMailOnUserCreate').is(':checked')) {
+ $("#newemail").show();
+ }
// Option to display/hide the "E-Mail" input field
$('#CheckboxMailOnUserCreate').click(function() {
if ($('#CheckboxMailOnUserCreate').is(':checked')) {
$("#newemail").show();
+ OC.AppConfig.setValue('core', 'umgmt_send_email', 'true');
} else {
$("#newemail").hide();
+ OC.AppConfig.setValue('core', 'umgmt_send_email', 'false');
}
});
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/settings/templates/users/main.php b/settings/templates/users/main.php
index 73552f8ad2e..0abe31f4a59 100644
--- a/settings/templates/users/main.php
+++ b/settings/templates/users/main.php
@@ -45,31 +45,36 @@ translation('settings');
<div id="userlistoptions">
<p>
- <input type="checkbox" name="StorageLocation" value="StorageLocation" id="CheckboxStorageLocation">
+ <input type="checkbox" name="StorageLocation" value="StorageLocation" id="CheckboxStorageLocation"
+ <?php if ($_['show_storage_location'] === 'true') print_unescaped('checked="checked"'); ?> />
<label for="CheckboxStorageLocation">
<?php p($l->t('Show storage location')) ?>
</label>
</p>
<p>
- <input type="checkbox" name="LastLogin" value="LastLogin" id="CheckboxLastLogin">
+ <input type="checkbox" name="LastLogin" value="LastLogin" id="CheckboxLastLogin"
+ <?php if ($_['show_last_login'] === 'true') print_unescaped('checked="checked"'); ?> />
<label for="CheckboxLastLogin">
<?php p($l->t('Show last log in')) ?>
</label>
</p>
<p>
- <input type="checkbox" name="UserBackend" value="UserBackend" id="CheckboxUserBackend">
+ <input type="checkbox" name="UserBackend" value="UserBackend" id="CheckboxUserBackend"
+ <?php if ($_['show_backend'] === 'true') print_unescaped('checked="checked"'); ?> />
<label for="CheckboxUserBackend">
<?php p($l->t('Show user backend')) ?>
</label>
</p>
<p>
- <input type="checkbox" name="MailOnUserCreate" value="MailOnUserCreate" id="CheckboxMailOnUserCreate">
+ <input type="checkbox" name="MailOnUserCreate" value="MailOnUserCreate" id="CheckboxMailOnUserCreate"
+ <?php if ($_['send_email'] === 'true') print_unescaped('checked="checked"'); ?> />
<label for="CheckboxMailOnUserCreate">
<?php p($l->t('Send email to new user')) ?>
</label>
</p>
<p>
- <input type="checkbox" name="EmailAddress" value="EmailAddress" id="CheckboxEmailAddress">
+ <input type="checkbox" name="EmailAddress" value="EmailAddress" id="CheckboxEmailAddress"
+ <?php if ($_['show_email'] === 'true') print_unescaped('checked="checked"'); ?> />
<label for="CheckboxEmailAddress">
<?php p($l->t('Show email address')) ?>
</label>
diff --git a/settings/users.php b/settings/users.php
index 843995a57f9..e0ef56f15c5 100644
--- a/settings/users.php
+++ b/settings/users.php
@@ -99,4 +99,11 @@ $tmpl->assign('default_quota', $defaultQuota);
$tmpl->assign('defaultQuotaIsUserDefined', $defaultQuotaIsUserDefined);
$tmpl->assign('recoveryAdminEnabled', $recoveryAdminEnabled);
$tmpl->assign('enableAvatars', \OC::$server->getConfig()->getSystemValue('enable_avatars', true));
+
+$tmpl->assign('show_storage_location', $config->getAppValue('core', 'umgmt_show_storage_location', 'false'));
+$tmpl->assign('show_last_login', $config->getAppValue('core', 'umgmt_show_last_login', 'false'));
+$tmpl->assign('show_email', $config->getAppValue('core', 'umgmt_show_email', 'false'));
+$tmpl->assign('show_backend', $config->getAppValue('core', 'umgmt_show_backend', 'false'));
+$tmpl->assign('send_email', $config->getAppValue('core', 'umgmt_send_email', 'false'));
+
$tmpl->printPage();
diff --git a/tests/apps/testapp-infoxml-version-different/appinfo/info.xml b/tests/apps/testapp-infoxml-version-different/appinfo/info.xml
new file mode 100644
index 00000000000..c765400a76f
--- /dev/null
+++ b/tests/apps/testapp-infoxml-version-different/appinfo/info.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<info>
+ <id>testapp-infoxml-version</id>
+ <version>1.2.3</version>
+ <author>Jane</author>
+ <description>A b c</description>
+ <licence>Abc</licence>
+ <name>Test app</name>
+</info>
diff --git a/tests/apps/testapp-infoxml-version-different/appinfo/version b/tests/apps/testapp-infoxml-version-different/appinfo/version
new file mode 100644
index 00000000000..e8ea05db814
--- /dev/null
+++ b/tests/apps/testapp-infoxml-version-different/appinfo/version
@@ -0,0 +1 @@
+1.2.4
diff --git a/tests/apps/testapp-infoxml-version/appinfo/info.xml b/tests/apps/testapp-infoxml-version/appinfo/info.xml
new file mode 100644
index 00000000000..c765400a76f
--- /dev/null
+++ b/tests/apps/testapp-infoxml-version/appinfo/info.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<info>
+ <id>testapp-infoxml-version</id>
+ <version>1.2.3</version>
+ <author>Jane</author>
+ <description>A b c</description>
+ <licence>Abc</licence>
+ <name>Test app</name>
+</info>
diff --git a/tests/apps/testapp-infoxml-version/appinfo/version b/tests/apps/testapp-infoxml-version/appinfo/version
new file mode 100644
index 00000000000..0495c4a88ca
--- /dev/null
+++ b/tests/apps/testapp-infoxml-version/appinfo/version
@@ -0,0 +1 @@
+1.2.3
diff --git a/tests/apps/testapp-infoxml/appinfo/info.xml b/tests/apps/testapp-infoxml/appinfo/info.xml
new file mode 100644
index 00000000000..cb63a0fc76e
--- /dev/null
+++ b/tests/apps/testapp-infoxml/appinfo/info.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<info>
+ <id>testapp-infoxml</id>
+ <version>1.2.3</version>
+ <author>Jane</author>
+ <description>A b c</description>
+ <licence>Abc</licence>
+ <name>Test app</name>
+</info>
diff --git a/tests/apps/testapp-name-missing/appinfo/info.xml b/tests/apps/testapp-name-missing/appinfo/info.xml
new file mode 100644
index 00000000000..f0a62b8d380
--- /dev/null
+++ b/tests/apps/testapp-name-missing/appinfo/info.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<info>
+ <id>testapp-version</id>
+ <version>1.1.1</version>
+ <author>Jane</author>
+ <description>A b c</description>
+ <licence>Abc</licence>
+</info>
diff --git a/tests/apps/testapp-version-missing/appinfo/info.xml b/tests/apps/testapp-version-missing/appinfo/info.xml
new file mode 100644
index 00000000000..d7da3e07e36
--- /dev/null
+++ b/tests/apps/testapp-version-missing/appinfo/info.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<info>
+ <id>testapp-version</id>
+ <author>Jane</author>
+ <description>A b c</description>
+ <licence>Abc</licence>
+ <name>Test app</name>
+</info>
diff --git a/tests/apps/testapp-version/appinfo/info.xml b/tests/apps/testapp-version/appinfo/info.xml
new file mode 100644
index 00000000000..d7da3e07e36
--- /dev/null
+++ b/tests/apps/testapp-version/appinfo/info.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<info>
+ <id>testapp-version</id>
+ <author>Jane</author>
+ <description>A b c</description>
+ <licence>Abc</licence>
+ <name>Test app</name>
+</info>
diff --git a/tests/apps/testapp-version/appinfo/version b/tests/apps/testapp-version/appinfo/version
new file mode 100644
index 00000000000..0495c4a88ca
--- /dev/null
+++ b/tests/apps/testapp-version/appinfo/version
@@ -0,0 +1 @@
+1.2.3
diff --git a/tests/core/command/config/listconfigstest.php b/tests/core/command/config/listconfigstest.php
index 7492701cce3..bde6a1b0db3 100644
--- a/tests/core/command/config/listconfigstest.php
+++ b/tests/core/command/config/listconfigstest.php
@@ -23,6 +23,7 @@ namespace Tests\Core\Command\Config;
use OC\Core\Command\Config\ListConfigs;
+use OCP\IConfig;
use Test\TestCase;
class ListConfigsTest extends TestCase {
@@ -66,7 +67,7 @@ class ListConfigsTest extends TestCase {
'overwrite.cli.url',
],
[
- ['secret', 'N;', 'my secret'],
+ ['secret', 'N;', IConfig::SENSITIVE_VALUE],
['overwrite.cli.url', 'N;', 'http://localhost'],
],
// app config
@@ -81,7 +82,7 @@ class ListConfigsTest extends TestCase {
false,
json_encode([
'system' => [
- 'secret' => ListConfigs::SENSITIVE_VALUE,
+ 'secret' => IConfig::SENSITIVE_VALUE,
'overwrite.cli.url' => 'http://localhost',
],
'apps' => [
@@ -139,12 +140,12 @@ class ListConfigsTest extends TestCase {
'overwrite.cli.url',
],
[
- ['secret', 'N;', 'my secret'],
+ ['secret', 'N;', IConfig::SENSITIVE_VALUE],
['objectstore', 'N;', [
'class' => 'OC\\Files\\ObjectStore\\Swift',
'arguments' => [
'username' => 'facebook100000123456789',
- 'password' => 'Secr3tPaSSWoRdt7',
+ 'password' => IConfig::SENSITIVE_VALUE,
],
]],
['overwrite.cli.url', 'N;', 'http://localhost'],
@@ -161,12 +162,12 @@ class ListConfigsTest extends TestCase {
false,
json_encode([
'system' => [
- 'secret' => ListConfigs::SENSITIVE_VALUE,
+ 'secret' => IConfig::SENSITIVE_VALUE,
'objectstore' => [
'class' => 'OC\\Files\\ObjectStore\\Swift',
'arguments' => [
'username' => 'facebook100000123456789',
- 'password' => ListConfigs::SENSITIVE_VALUE,
+ 'password' => IConfig::SENSITIVE_VALUE,
],
],
'overwrite.cli.url' => 'http://localhost',
@@ -276,9 +277,15 @@ class ListConfigsTest extends TestCase {
$this->systemConfig->expects($this->any())
->method('getKeys')
->willReturn($systemConfigs);
- $this->systemConfig->expects($this->any())
- ->method('getValue')
- ->willReturnMap($systemConfigMap);
+ if ($private) {
+ $this->systemConfig->expects($this->any())
+ ->method('getValue')
+ ->willReturnMap($systemConfigMap);
+ } else {
+ $this->systemConfig->expects($this->any())
+ ->method('getFilteredValue')
+ ->willReturnMap($systemConfigMap);
+ }
$this->appConfig->expects($this->any())
->method('getApps')
diff --git a/tests/lib/app/codechecker/infocheckertest.php b/tests/lib/app/codechecker/infocheckertest.php
new file mode 100644
index 00000000000..59c1316b769
--- /dev/null
+++ b/tests/lib/app/codechecker/infocheckertest.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\App\CodeChecker;
+
+use OC\App\InfoParser;
+use Test\TestCase;
+
+class InfoCheckerTest extends TestCase {
+ /** @var InfoChecker */
+ protected $infoChecker;
+
+ public static function setUpBeforeClass() {
+ \OC::$APPSROOTS[] = [
+ 'path' => \OC::$SERVERROOT . '/tests/apps',
+ 'url' => '/apps-test',
+ 'writable' => false,
+ ];
+ }
+
+ public static function tearDownAfterClass() {
+ // remove last element
+ array_pop(\OC::$APPSROOTS);
+ }
+
+ protected function setUp() {
+ parent::setUp();
+ $infoParser = new InfoParser(\OC::$server->getHTTPHelper(), \OC::$server->getURLGenerator());
+
+ $this->infoChecker = new InfoChecker($infoParser);
+ }
+
+ public function appInfoData() {
+ return [
+ ['testapp-infoxml', []],
+ ['testapp-version', []],
+ ['testapp-infoxml-version', []],
+ ['testapp-infoxml-version-different', [['type' => 'differentVersions', 'message' => 'appinfo/version: 1.2.4 - appinfo/info.xml: 1.2.3']]],
+ ['testapp-version-missing', [['type' => 'mandatoryFieldMissing', 'field' => 'version']]],
+ ['testapp-name-missing', [['type' => 'mandatoryFieldMissing', 'field' => 'name']]],
+ ];
+ }
+
+ /**
+ * @dataProvider appInfoData
+ *
+ * @param $appId
+ * @param $expectedErrors
+ */
+ public function testApps($appId, $expectedErrors) {
+ $errors = $this->infoChecker->analyse($appId);
+
+ $this->assertEquals($expectedErrors, $errors);
+ }
+}
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) {
diff --git a/tests/lib/logger.php b/tests/lib/logger.php
index c8566988cf4..9c9cd9e6728 100644
--- a/tests/lib/logger.php
+++ b/tests/lib/logger.php
@@ -63,4 +63,48 @@ class Logger extends TestCase {
public static function write($app, $message, $level) {
self::$logs[]= "$level $message";
}
+
+ public function userAndPasswordData() {
+ return [
+ ['abc', 'def'],
+ ['mySpecialUsername', 'MySuperSecretPassword'],
+ ['my-user', '324324()#รค234'],
+ ['my-user', ')qwer'],
+ ['my-user', 'qwer)asdf'],
+ ['my-user', 'qwer)'],
+ ['my-user', '(qwer'],
+ ['my-user', 'qwer(asdf'],
+ ['my-user', 'qwer('],
+ ];
+ }
+
+ /**
+ * @dataProvider userAndPasswordData
+ */
+ public function testDetectlogin($user, $password) {
+ $e = new \Exception('test');
+ $this->logger->logException($e);
+
+ $logLines = $this->getLogs();
+ foreach($logLines as $logLine) {
+ $this->assertNotContains($user, $logLine);
+ $this->assertNotContains($password, $logLine);
+ $this->assertContains('login(*** username and password replaced ***)', $logLine);
+ }
+ }
+
+ /**
+ * @dataProvider userAndPasswordData
+ */
+ public function testDetectcheckPassword($user, $password) {
+ $e = new \Exception('test');
+ $this->logger->logException($e);
+ $logLines = $this->getLogs();
+
+ foreach($logLines as $logLine) {
+ $this->assertNotContains($user, $logLine);
+ $this->assertNotContains($password, $logLine);
+ $this->assertContains('checkPassword(*** username and password replaced ***)', $logLine);
+ }
+ }
}
diff --git a/tests/lib/share/share.php b/tests/lib/share/share.php
index ef0d9822085..58a76470afa 100644
--- a/tests/lib/share/share.php
+++ b/tests/lib/share/share.php
@@ -1567,6 +1567,43 @@ class Test_Share extends \Test\TestCase {
$this->setHttpHelper($oldHttpHelper);
}
+ /**
+ * Test case for #19119
+ */
+ public function testReshareWithLinkDefaultExpirationDate() {
+ $config = \OC::$server->getConfig();
+ $config->setAppValue('core', 'shareapi_default_expire_date', 'yes');
+ $config->setAppValue('core', 'shareapi_expire_after_n_days', '2');
+
+ // Expiration date
+ $expireAt = time() + 2 * 24*60*60;
+ $date = new DateTime();
+ $date->setTimestamp($expireAt);
+ $date->setTime(0, 0, 0);
+
+ //Share a file from user 1 to user 2
+ $this->shareUserTestFileWithUser($this->user1, $this->user2);
+
+ //User 2 shares as link
+ OC_User::setUserId($this->user2);
+ $result = OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_LINK, null, \OCP\Constants::PERMISSION_READ);
+ $this->assertTrue(is_string($result));
+
+ //Check if expire date is correct
+ $result = OCP\Share::getItemShared('test', 'test.txt');
+ $this->assertCount(1, $result);
+ $result = reset($result);
+ $this->assertNotEmpty($result['expiration']);
+ $expireDate = new DateTime($result['expiration']);
+ $this->assertEquals($date, $expireDate);
+
+ //Unshare
+ $this->assertTrue(OCP\Share::unshareAll('test', 'test.txt'));
+
+ //Reset config
+ $config->deleteAppValue('core', 'shareapi_default_expire_date');
+ $config->deleteAppValue('core', 'shareapi_expire_after_n_days');
+ }
}
class DummyShareClass extends \OC\Share\Share {