Introduce BackendService for managing external storage backends

Backends are registered to the BackendService through new data
structures:

Backends are concrete classes, deriving from
\OCA\Files_External\Lib\Backend\Backend. During construction, the
various configuration parameters of the Backend can be set, in a design
similar to Symfony Console.

DefinitionParameter stores a parameter configuration for an external
storage: name of parameter, human-readable name, type of parameter
(text, password, hidden, checkbox), flags (optional or not).

Storages in the StoragesController now get their parameters validated
server-side (fixes a TODO).
This commit is contained in:
Robin McCorkell 2015-08-11 18:45:07 +01:00
parent 74237a9c44
commit 37beb58c6f
31 changed files with 1639 additions and 559 deletions

View File

@ -30,9 +30,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* *
*/ */
$app = new \OCA\Files_external\Appinfo\Application();
$l = \OC::$server->getL10N('files_external');
OC::$CLASSPATH['OC\Files\Storage\StreamWrapper'] = 'files_external/lib/streamwrapper.php'; OC::$CLASSPATH['OC\Files\Storage\StreamWrapper'] = 'files_external/lib/streamwrapper.php';
OC::$CLASSPATH['OC\Files\Storage\FTP'] = 'files_external/lib/ftp.php'; OC::$CLASSPATH['OC\Files\Storage\FTP'] = 'files_external/lib/ftp.php';
@ -50,6 +47,11 @@ OC::$CLASSPATH['OCA\Files\External\Api'] = 'files_external/lib/api.php';
require_once __DIR__ . '/../3rdparty/autoload.php'; require_once __DIR__ . '/../3rdparty/autoload.php';
$app = new \OCA\Files_external\Appinfo\Application();
$appContainer = $app->getContainer();
$l = \OC::$server->getL10N('files_external');
OCP\App::registerAdmin('files_external', 'settings'); OCP\App::registerAdmin('files_external', 'settings');
if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == 'yes') { if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == 'yes') {
OCP\App::registerPersonal('files_external', 'personal'); OCP\App::registerPersonal('files_external', 'personal');
@ -63,6 +65,9 @@ if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == '
"name" => $l->t('External storage') "name" => $l->t('External storage')
]); ]);
// Teach OC_Mount_Config about the AppFramework
\OC_Mount_Config::initApp($appContainer);
// connecting hooks // connecting hooks
OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\OC_Mount_Config', 'initMountPointsHook'); OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\OC_Mount_Config', 'initMountPointsHook');
OCP\Util::connectHook('OC_User', 'post_login', 'OC\Files\Storage\SMB_OC', 'login'); OCP\Util::connectHook('OC_User', 'post_login', 'OC\Files\Storage\SMB_OC', 'login');
@ -237,5 +242,5 @@ OC_Mount_Config::registerBackend('\OC\Files\Storage\SFTP_Key', [
'custom' => 'sftp_key', 'custom' => 'sftp_key',
] ]
); );
$mountProvider = new \OCA\Files_External\Config\ConfigAdapter(); $mountProvider = $appContainer->query('OCA\Files_External\Config\ConfigAdapter');
\OC::$server->getMountProviderCollection()->registerProvider($mountProvider); \OC::$server->getMountProviderCollection()->registerProvider($mountProvider);

View File

@ -3,6 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de> * @author Morris Jobke <hey@morrisjobke.de>
* @author Ross Nicoll <jrn@jrn.me.uk> * @author Ross Nicoll <jrn@jrn.me.uk>
* @author Vincent Petry <pvince81@owncloud.com> * @author Vincent Petry <pvince81@owncloud.com>
* @author Robin McCorkell <rmccorkell@owncloud.com>
* *
* @copyright Copyright (c) 2015, ownCloud, Inc. * @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0 * @license AGPL-3.0
@ -26,6 +27,9 @@ namespace OCA\Files_External\AppInfo;
use \OCA\Files_External\Controller\AjaxController; use \OCA\Files_External\Controller\AjaxController;
use \OCP\AppFramework\App; use \OCP\AppFramework\App;
use \OCP\IContainer; use \OCP\IContainer;
use \OCA\Files_External\Service\BackendService;
use \OCA\Files_External\Lib\BackendConfig;
use \OCA\Files_External\Lib\BackendParameter;
/** /**
* @package OCA\Files_External\Appinfo * @package OCA\Files_External\Appinfo
@ -45,5 +49,16 @@ class Application extends App {
$c->query('Request') $c->query('Request')
); );
}); });
$this->loadBackends();
} }
/**
* Load storage backends provided by this app
*/
protected function loadBackends() {
$container = $this->getContainer();
$service = $container->query('OCA\\Files_External\\Service\\BackendService');
}
} }

View File

@ -81,14 +81,18 @@ class GlobalStoragesController extends StoragesController {
$applicableGroups, $applicableGroups,
$priority $priority
) { ) {
$newStorage = new StorageConfig(); $newStorage = $this->createStorage(
$newStorage->setMountPoint($mountPoint); $mountPoint,
$newStorage->setBackendClass($backendClass); $backendClass,
$newStorage->setBackendOptions($backendOptions); $backendOptions,
$newStorage->setMountOptions($mountOptions); $mountOptions,
$newStorage->setApplicableUsers($applicableUsers); $applicableUsers,
$newStorage->setApplicableGroups($applicableGroups); $applicableGroups,
$newStorage->setPriority($priority); $priority
);
if ($newStorage instanceof DataResponse) {
return $newStorage;
}
$response = $this->validate($newStorage); $response = $this->validate($newStorage);
if (!empty($response)) { if (!empty($response)) {
@ -129,14 +133,19 @@ class GlobalStoragesController extends StoragesController {
$applicableGroups, $applicableGroups,
$priority $priority
) { ) {
$storage = new StorageConfig($id); $storage = $this->createStorage(
$storage->setMountPoint($mountPoint); $mountPoint,
$storage->setBackendClass($backendClass); $backendClass,
$storage->setBackendOptions($backendOptions); $backendOptions,
$storage->setMountOptions($mountOptions); $mountOptions,
$storage->setApplicableUsers($applicableUsers); $applicableUsers,
$storage->setApplicableGroups($applicableGroups); $applicableGroups,
$storage->setPriority($priority); $priority
);
if ($storage instanceof DataResponse) {
return $storage;
}
$storage->setId($id);
$response = $this->validate($storage); $response = $this->validate($storage);
if (!empty($response)) { if (!empty($response)) {

View File

@ -32,6 +32,7 @@ use \OCP\AppFramework\Http;
use \OCA\Files_external\Service\StoragesService; use \OCA\Files_external\Service\StoragesService;
use \OCA\Files_external\NotFoundException; use \OCA\Files_external\NotFoundException;
use \OCA\Files_external\Lib\StorageConfig; use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_External\Lib\Backend\Backend;
/** /**
* Base class for storages controllers * Base class for storages controllers
@ -71,6 +72,48 @@ abstract class StoragesController extends Controller {
$this->service = $storagesService; $this->service = $storagesService;
} }
/**
* Create a storage from its parameters
*
* @param string $mountPoint storage mount point
* @param string $backendClass backend class name
* @param array $backendOptions backend-specific options
* @param array|null $mountOptions mount-specific options
* @param array|null $applicableUsers users for which to mount the storage
* @param array|null $applicableGroups groups for which to mount the storage
* @param int|null $priority priority
*
* @return StorageConfig|DataResponse
*/
protected function createStorage(
$mountPoint,
$backendClass,
$backendOptions,
$mountOptions = null,
$applicableUsers = null,
$applicableGroups = null,
$priority = null
) {
try {
return $this->service->createStorage(
$mountPoint,
$backendClass,
$backendOptions,
$mountOptions,
$applicableUsers,
$applicableGroups,
$priority
);
} catch (\InvalidArgumentException $e) {
return new DataResponse(
[
'message' => (string)$this->l10n->t('Invalid backend class "%s"', [$backendClass])
],
Http::STATUS_UNPROCESSABLE_ENTITY
);
}
}
/** /**
* Validate storage config * Validate storage config
* *
@ -89,14 +132,24 @@ abstract class StoragesController extends Controller {
); );
} }
// TODO: validate that other attrs are set /** @var Backend */
$backend = $storage->getBackend();
$backends = \OC_Mount_Config::getBackends(); if (!$backend || $backend->checkDependencies()) {
if (!isset($backends[$storage->getBackendClass()])) {
// invalid backend // invalid backend
return new DataResponse( return new DataResponse(
array( array(
'message' => (string)$this->l10n->t('Invalid storage backend "%s"', array($storage->getBackendClass())) 'message' => (string)$this->l10n->t('Invalid storage backend "%s"', [
$storage->getBackend()->getClass()
])
),
Http::STATUS_UNPROCESSABLE_ENTITY
);
}
if (!$backend->validateStorage($storage)) {
// unsatisfied parameters
return new DataResponse(
array(
'message' => (string)$this->l10n->t('Unsatisfied backend parameters')
), ),
Http::STATUS_UNPROCESSABLE_ENTITY Http::STATUS_UNPROCESSABLE_ENTITY
); );
@ -114,10 +167,14 @@ abstract class StoragesController extends Controller {
* @param StorageConfig $storage storage configuration * @param StorageConfig $storage storage configuration
*/ */
protected function updateStorageStatus(StorageConfig &$storage) { protected function updateStorageStatus(StorageConfig &$storage) {
/** @var Backend */
$backend = $storage->getBackend();
$backend->manipulateStorageConfig($storage);
// update status (can be time-consuming) // update status (can be time-consuming)
$storage->setStatus( $storage->setStatus(
\OC_Mount_Config::getBackendStatus( \OC_Mount_Config::getBackendStatus(
$storage->getBackendClass(), $storage->getBackend()->getStorageClass(),
$storage->getBackendOptions(), $storage->getBackendOptions(),
false false
) )

View File

@ -30,8 +30,10 @@ use \OCP\AppFramework\Http\DataResponse;
use \OCP\AppFramework\Controller; use \OCP\AppFramework\Controller;
use \OCP\AppFramework\Http; use \OCP\AppFramework\Http;
use \OCA\Files_external\Service\UserStoragesService; use \OCA\Files_external\Service\UserStoragesService;
use \OCA\Files_External\Service\BackendService;
use \OCA\Files_external\NotFoundException; use \OCA\Files_external\NotFoundException;
use \OCA\Files_external\Lib\StorageConfig; use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_External\Lib\Backend\Backend;
/** /**
* User storages controller * User storages controller
@ -69,17 +71,20 @@ class UserStoragesController extends StoragesController {
protected function validate(StorageConfig $storage) { protected function validate(StorageConfig $storage) {
$result = parent::validate($storage); $result = parent::validate($storage);
if ($result != null) { if ($result !== null) {
return $result; return $result;
} }
// Verify that the mount point applies for the current user // Verify that the mount point applies for the current user
// Prevent non-admin users from mounting local storage and other disabled backends // Prevent non-admin users from mounting local storage and other disabled backends
$allowedBackends = \OC_Mount_Config::getPersonalBackends(); /** @var Backend */
if (!isset($allowedBackends[$storage->getBackendClass()])) { $backend = $storage->getBackend();
if (!$backend->isVisibleFor(BackendService::VISIBILITY_PERSONAL)) {
return new DataResponse( return new DataResponse(
array( array(
'message' => (string)$this->l10n->t('Invalid storage backend "%s"', array($storage->getBackendClass())) 'message' => (string)$this->l10n->t('Admin-only storage backend "%s"', [
$storage->getBackend()->getClass()
])
), ),
Http::STATUS_UNPROCESSABLE_ENTITY Http::STATUS_UNPROCESSABLE_ENTITY
); );
@ -117,11 +122,15 @@ class UserStoragesController extends StoragesController {
$backendOptions, $backendOptions,
$mountOptions $mountOptions
) { ) {
$newStorage = new StorageConfig(); $newStorage = $this->createStorage(
$newStorage->setMountPoint($mountPoint); $mountPoint,
$newStorage->setBackendClass($backendClass); $backendClass,
$newStorage->setBackendOptions($backendOptions); $backendOptions,
$newStorage->setMountOptions($mountOptions); $mountOptions
);
if ($newStorage instanceOf DataResponse) {
return $newStorage;
}
$response = $this->validate($newStorage); $response = $this->validate($newStorage);
if (!empty($response)) { if (!empty($response)) {
@ -157,11 +166,16 @@ class UserStoragesController extends StoragesController {
$backendOptions, $backendOptions,
$mountOptions $mountOptions
) { ) {
$storage = new StorageConfig($id); $storage = $this->createStorage(
$storage->setMountPoint($mountPoint); $mountPoint,
$storage->setBackendClass($backendClass); $backendClass,
$storage->setBackendOptions($backendOptions); $backendOptions,
$storage->setMountOptions($mountOptions); $mountOptions
);
if ($storage instanceOf DataResponse) {
return $storage;
}
$storage->setId($id);
$response = $this->validate($storage); $response = $this->validate($storage);
if (!empty($response)) { if (!empty($response)) {

View File

@ -0,0 +1,94 @@
<?php
/**
* @author Robin McCorkell <rmccorkell@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_External\Lib\Backend;
use \OCA\Files_External\Lib\StorageConfig;
use \OCA\Files_External\Lib\VisibilityTrait;
use \OCA\Files_External\Lib\FrontendDefinitionTrait;
use \OCA\Files_External\Lib\PriorityTrait;
use \OCA\Files_External\Lib\DependencyTrait;
use \OCA\Files_External\Lib\StorageModifierTrait;
/**
* Storage backend
*/
class Backend implements \JsonSerializable {
use VisibilityTrait;
use FrontendDefinitionTrait;
use PriorityTrait;
use DependencyTrait;
use StorageModifierTrait;
/** @var string storage class */
private $storageClass;
/**
* @return string
*/
public function getClass() {
// return storage class for legacy compat
return $this->getStorageClass();
}
/**
* @return string
*/
public function getStorageClass() {
return $this->storageClass;
}
/**
* @param string $class
* @return self
*/
public function setStorageClass($class) {
$this->storageClass = $class;
return $this;
}
/**
* Serialize into JSON for client-side JS
*
* @return array
*/
public function jsonSerialize() {
$data = $this->jsonSerializeDefinition();
$data['backend'] = $data['name']; // legacy compat
$data['priority'] = $this->getPriority();
return $data;
}
/**
* Check if parameters are satisfied in a StorageConfig
*
* @param StorageConfig $storage
* @return bool
*/
public function validateStorage(StorageConfig $storage) {
return $this->validateStorageDefinition($storage);
}
}

View File

@ -32,6 +32,9 @@
*/ */
use phpseclib\Crypt\AES; use phpseclib\Crypt\AES;
use \OCP\AppFramework\IAppContainer;
use \OCA\Files_External\Lib\BackendConfig;
use \OCA\Files_External\Service\BackendService;
/** /**
* Class to configure mount.json globally and for users * Class to configure mount.json globally and for users
@ -51,71 +54,19 @@ class OC_Mount_Config {
// whether to skip backend test (for unit tests, as this static class is not mockable) // whether to skip backend test (for unit tests, as this static class is not mockable)
public static $skipTest = false; public static $skipTest = false;
private static $backends = array(); /** @var IAppContainer */
private static $appContainer;
/** /**
* @param string $class * Teach OC_Mount_Config about the AppFramework
* @param array $definition
* @return bool
*/
public static function registerBackend($class, $definition) {
if (!isset($definition['backend'])) {
return false;
}
OC_Mount_Config::$backends[$class] = $definition;
return true;
}
/**
* Setup backends
* *
* @return array of previously registered backends * @param IAppContainer $appContainer
*/ */
public static function setUp($backends = array()) { public static function initApp(IAppContainer $appContainer) {
$backup = self::$backends; self::$appContainer = $appContainer;
self::$backends = $backends;
return $backup;
} }
/** /*
* Get details on each of the external storage backends, used for the mount config UI
* If a custom UI is needed, add the key 'custom' and a javascript file with that name will be loaded
* If the configuration parameter should be secret, add a '*' to the beginning of the value
* If the configuration parameter is a boolean, add a '!' to the beginning of the value
* If the configuration parameter is optional, add a '&' to the beginning of the value
* If the configuration parameter is hidden, add a '#' to the beginning of the value
*
* @return array
*/
public static function getBackends() {
$sortFunc = function ($a, $b) {
return strcasecmp($a['backend'], $b['backend']);
};
$backEnds = array();
foreach (OC_Mount_Config::$backends as $class => $backend) {
if (isset($backend['has_dependencies']) and $backend['has_dependencies'] === true) {
if (!method_exists($class, 'checkDependencies')) {
\OCP\Util::writeLog('files_external',
"Backend class $class has dependencies but doesn't provide method checkDependencies()",
\OCP\Util::DEBUG);
continue;
} elseif ($class::checkDependencies() !== true) {
continue;
}
}
$backEnds[$class] = $backend;
}
uasort($backEnds, $sortFunc);
return $backEnds;
}
/**
* Hook that mounts the given user's visible mount points * Hook that mounts the given user's visible mount points
* *
* @param array $data * @param array $data
@ -151,14 +102,14 @@ class OC_Mount_Config {
/** /**
* Returns the mount points for the given user. * Returns the mount points for the given user.
* The mount point is relative to the data directory. * The mount point is relative to the data directory.
* TODO: Move me into StoragesService
* *
* @param string $user user * @param string $user user
* @return array of mount point string as key, mountpoint config as value * @return array of mount point string as key, mountpoint config as value
*/ */
public static function getAbsoluteMountPoints($user) { public static function getAbsoluteMountPoints($user) {
$mountPoints = array(); $mountPoints = array();
$backendService = self::$appContainer->query('OCA\Files_External\Service\BackendService');
$backends = self::getBackends();
// Load system mount points // Load system mount points
$mountConfig = self::readData(); $mountConfig = self::readData();
@ -166,18 +117,20 @@ class OC_Mount_Config {
// Global mount points (is this redundant?) // Global mount points (is this redundant?)
if (isset($mountConfig[self::MOUNT_TYPE_GLOBAL])) { if (isset($mountConfig[self::MOUNT_TYPE_GLOBAL])) {
foreach ($mountConfig[self::MOUNT_TYPE_GLOBAL] as $mountPoint => $options) { foreach ($mountConfig[self::MOUNT_TYPE_GLOBAL] as $mountPoint => $options) {
$backend = $backendService->getBackend($options['class']);
$options['personal'] = false; $options['personal'] = false;
$options['options'] = self::decryptPasswords($options['options']); $options['options'] = self::decryptPasswords($options['options']);
if (!isset($options['priority'])) { if (!isset($options['priority'])) {
$options['priority'] = $backends[$options['class']]['priority']; $options['priority'] = $backend->getPriority();
} }
// Override if priority greater // Override if priority greater
if ((!isset($mountPoints[$mountPoint])) if ((!isset($mountPoints[$mountPoint]))
|| ($options['priority'] >= $mountPoints[$mountPoint]['priority']) || ($options['priority'] >= $mountPoints[$mountPoint]['priority'])
) { ) {
$options['priority_type'] = self::MOUNT_TYPE_GLOBAL; $options['priority_type'] = self::MOUNT_TYPE_GLOBAL;
$options['backend'] = $backends[$options['class']]['backend']; $options['backend'] = $backend->getText();
$mountPoints[$mountPoint] = $options; $mountPoints[$mountPoint] = $options;
} }
} }
@ -190,10 +143,11 @@ class OC_Mount_Config {
foreach ($options as &$option) { foreach ($options as &$option) {
$option = self::setUserVars($user, $option); $option = self::setUserVars($user, $option);
} }
$backend = $backendService->getBackend($options['class']);
$options['personal'] = false; $options['personal'] = false;
$options['options'] = self::decryptPasswords($options['options']); $options['options'] = self::decryptPasswords($options['options']);
if (!isset($options['priority'])) { if (!isset($options['priority'])) {
$options['priority'] = $backends[$options['class']]['priority']; $options['priority'] = $backend->getPriority();
} }
// Override if priority greater // Override if priority greater
@ -201,7 +155,7 @@ class OC_Mount_Config {
|| ($options['priority'] >= $mountPoints[$mountPoint]['priority']) || ($options['priority'] >= $mountPoints[$mountPoint]['priority'])
) { ) {
$options['priority_type'] = self::MOUNT_TYPE_GLOBAL; $options['priority_type'] = self::MOUNT_TYPE_GLOBAL;
$options['backend'] = $backends[$options['class']]['backend']; $options['backend'] = $backend->getText();
$mountPoints[$mountPoint] = $options; $mountPoints[$mountPoint] = $options;
} }
} }
@ -215,10 +169,11 @@ class OC_Mount_Config {
foreach ($options as &$option) { foreach ($options as &$option) {
$option = self::setUserVars($user, $option); $option = self::setUserVars($user, $option);
} }
$backend = $backendService->getBackend($options['class']);
$options['personal'] = false; $options['personal'] = false;
$options['options'] = self::decryptPasswords($options['options']); $options['options'] = self::decryptPasswords($options['options']);
if (!isset($options['priority'])) { if (!isset($options['priority'])) {
$options['priority'] = $backends[$options['class']]['priority']; $options['priority'] = $backend->getPriority();
} }
// Override if priority greater or if priority type different // Override if priority greater or if priority type different
@ -227,7 +182,7 @@ class OC_Mount_Config {
|| ($mountPoints[$mountPoint]['priority_type'] !== self::MOUNT_TYPE_GROUP) || ($mountPoints[$mountPoint]['priority_type'] !== self::MOUNT_TYPE_GROUP)
) { ) {
$options['priority_type'] = self::MOUNT_TYPE_GROUP; $options['priority_type'] = self::MOUNT_TYPE_GROUP;
$options['backend'] = $backends[$options['class']]['backend']; $options['backend'] = $backend->getText();
$mountPoints[$mountPoint] = $options; $mountPoints[$mountPoint] = $options;
} }
} }
@ -243,10 +198,11 @@ class OC_Mount_Config {
foreach ($options as &$option) { foreach ($options as &$option) {
$option = self::setUserVars($user, $option); $option = self::setUserVars($user, $option);
} }
$backend = $backendService->getBackend($options['class']);
$options['personal'] = false; $options['personal'] = false;
$options['options'] = self::decryptPasswords($options['options']); $options['options'] = self::decryptPasswords($options['options']);
if (!isset($options['priority'])) { if (!isset($options['priority'])) {
$options['priority'] = $backends[$options['class']]['priority']; $options['priority'] = $backend->getPriority();
} }
// Override if priority greater or if priority type different // Override if priority greater or if priority type different
@ -255,7 +211,7 @@ class OC_Mount_Config {
|| ($mountPoints[$mountPoint]['priority_type'] !== self::MOUNT_TYPE_USER) || ($mountPoints[$mountPoint]['priority_type'] !== self::MOUNT_TYPE_USER)
) { ) {
$options['priority_type'] = self::MOUNT_TYPE_USER; $options['priority_type'] = self::MOUNT_TYPE_USER;
$options['backend'] = $backends[$options['class']]['backend']; $options['backend'] = $backend->getText();
$mountPoints[$mountPoint] = $options; $mountPoints[$mountPoint] = $options;
} }
} }
@ -263,19 +219,18 @@ class OC_Mount_Config {
} }
} }
$personalBackends = self::getPersonalBackends();
// Load personal mount points // Load personal mount points
$mountConfig = self::readData($user); $mountConfig = self::readData($user);
if (isset($mountConfig[self::MOUNT_TYPE_USER][$user])) { if (isset($mountConfig[self::MOUNT_TYPE_USER][$user])) {
foreach ($mountConfig[self::MOUNT_TYPE_USER][$user] as $mountPoint => $options) { foreach ($mountConfig[self::MOUNT_TYPE_USER][$user] as $mountPoint => $options) {
if (isset($personalBackends[$options['class']])) { $backend = $backendService->getBackend($options['class']);
if ($backend->isVisibleFor(BackendService::VISIBILITY_PERSONAL)) {
$options['personal'] = true; $options['personal'] = true;
$options['options'] = self::decryptPasswords($options['options']); $options['options'] = self::decryptPasswords($options['options']);
// Always override previous config // Always override previous config
$options['priority_type'] = self::MOUNT_TYPE_PERSONAL; $options['priority_type'] = self::MOUNT_TYPE_PERSONAL;
$options['backend'] = $backends[$options['class']]['backend']; $options['backend'] = $backend->getText();
$mountPoints[$mountPoint] = $options; $mountPoints[$mountPoint] = $options;
} }
} }
@ -304,43 +259,6 @@ class OC_Mount_Config {
return $input; return $input;
} }
/**
* Get details on each of the external storage backends, used for the mount config UI
* Some backends are not available as a personal backend, f.e. Local and such that have
* been disabled by the admin.
*
* If a custom UI is needed, add the key 'custom' and a javascript file with that name will be loaded
* If the configuration parameter should be secret, add a '*' to the beginning of the value
* If the configuration parameter is a boolean, add a '!' to the beginning of the value
* If the configuration parameter is optional, add a '&' to the beginning of the value
* If the configuration parameter is hidden, add a '#' to the beginning of the value
*
* @return array
*/
public static function getPersonalBackends() {
// Check whether the user has permissions to add personal storage backends
// return an empty array if this is not the case
if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') !== 'yes') {
return array();
}
$backEnds = self::getBackends();
// Remove local storage and other disabled storages
unset($backEnds['\OC\Files\Storage\Local']);
$allowedBackEnds = explode(',', OCP\Config::getAppValue('files_external', 'user_mounting_backends', ''));
foreach ($backEnds as $backend => $null) {
if (!in_array($backend, $allowedBackEnds)) {
unset($backEnds[$backend]);
}
}
return $backEnds;
}
/** /**
* Get the system mount points * Get the system mount points
* The returned array is not in the same format as getUserMountPoints() * The returned array is not in the same format as getUserMountPoints()
@ -349,7 +267,7 @@ class OC_Mount_Config {
*/ */
public static function getSystemMountPoints() { public static function getSystemMountPoints() {
$mountPoints = self::readData(); $mountPoints = self::readData();
$backends = self::getBackends(); $backendService = self::$appContainer->query('\OCA\Files_External\Service\BackendService');
$system = array(); $system = array();
if (isset($mountPoints[self::MOUNT_TYPE_GROUP])) { if (isset($mountPoints[self::MOUNT_TYPE_GROUP])) {
foreach ($mountPoints[self::MOUNT_TYPE_GROUP] as $group => $mounts) { foreach ($mountPoints[self::MOUNT_TYPE_GROUP] as $group => $mounts) {
@ -358,9 +276,10 @@ class OC_Mount_Config {
if (strpos($mount['class'], 'OC_Filestorage_') !== false) { if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
$mount['class'] = '\OC\Files\Storage\\' . substr($mount['class'], 15); $mount['class'] = '\OC\Files\Storage\\' . substr($mount['class'], 15);
} }
$backend = $backendService->getBackend($mount['class']);
$mount['options'] = self::decryptPasswords($mount['options']); $mount['options'] = self::decryptPasswords($mount['options']);
if (!isset($mount['priority'])) { if (!isset($mount['priority'])) {
$mount['priority'] = $backends[$mount['class']]['priority']; $mount['priority'] = $backend->getPriority();
} }
// Remove '/$user/files/' from mount point // Remove '/$user/files/' from mount point
$mountPoint = substr($mountPoint, 13); $mountPoint = substr($mountPoint, 13);
@ -368,7 +287,7 @@ class OC_Mount_Config {
$config = array( $config = array(
'class' => $mount['class'], 'class' => $mount['class'],
'mountpoint' => $mountPoint, 'mountpoint' => $mountPoint,
'backend' => $backends[$mount['class']]['backend'], 'backend' => $backend->getText(),
'priority' => $mount['priority'], 'priority' => $mount['priority'],
'options' => $mount['options'], 'options' => $mount['options'],
'applicable' => array('groups' => array($group), 'users' => array()) 'applicable' => array('groups' => array($group), 'users' => array())
@ -401,16 +320,17 @@ class OC_Mount_Config {
if (strpos($mount['class'], 'OC_Filestorage_') !== false) { if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
$mount['class'] = '\OC\Files\Storage\\' . substr($mount['class'], 15); $mount['class'] = '\OC\Files\Storage\\' . substr($mount['class'], 15);
} }
$backend = $backendService->getBackend($mount['class']);
$mount['options'] = self::decryptPasswords($mount['options']); $mount['options'] = self::decryptPasswords($mount['options']);
if (!isset($mount['priority'])) { if (!isset($mount['priority'])) {
$mount['priority'] = $backends[$mount['class']]['priority']; $mount['priority'] = $backend->getPriority();
} }
// Remove '/$user/files/' from mount point // Remove '/$user/files/' from mount point
$mountPoint = substr($mountPoint, 13); $mountPoint = substr($mountPoint, 13);
$config = array( $config = array(
'class' => $mount['class'], 'class' => $mount['class'],
'mountpoint' => $mountPoint, 'mountpoint' => $mountPoint,
'backend' => $backends[$mount['class']]['backend'], 'backend' => $backend->getText(),
'priority' => $mount['priority'], 'priority' => $mount['priority'],
'options' => $mount['options'], 'options' => $mount['options'],
'applicable' => array('groups' => array(), 'users' => array($user)) 'applicable' => array('groups' => array(), 'users' => array($user))
@ -447,7 +367,7 @@ class OC_Mount_Config {
*/ */
public static function getPersonalMountPoints() { public static function getPersonalMountPoints() {
$mountPoints = self::readData(OCP\User::getUser()); $mountPoints = self::readData(OCP\User::getUser());
$backEnds = self::getBackends(); $backendService = self::$appContainer->query('\OCA\Files_External\Service\BackendService');
$uid = OCP\User::getUser(); $uid = OCP\User::getUser();
$personal = array(); $personal = array();
if (isset($mountPoints[self::MOUNT_TYPE_USER][$uid])) { if (isset($mountPoints[self::MOUNT_TYPE_USER][$uid])) {
@ -456,12 +376,13 @@ class OC_Mount_Config {
if (strpos($mount['class'], 'OC_Filestorage_') !== false) { if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
$mount['class'] = '\OC\Files\Storage\\' . substr($mount['class'], 15); $mount['class'] = '\OC\Files\Storage\\' . substr($mount['class'], 15);
} }
$backend = $backendService->getBackend($mount['class']);
$mount['options'] = self::decryptPasswords($mount['options']); $mount['options'] = self::decryptPasswords($mount['options']);
$config = array( $config = array(
'class' => $mount['class'], 'class' => $mount['class'],
// Remove '/uid/files/' from mount point // Remove '/uid/files/' from mount point
'mountpoint' => substr($mountPoint, strlen($uid) + 8), 'mountpoint' => substr($mountPoint, strlen($uid) + 8),
'backend' => $backEnds[$mount['class']]['backend'], 'backend' => $backend->getText(),
'options' => $mount['options'] 'options' => $mount['options']
); );
if (isset($mount['id'])) { if (isset($mount['id'])) {
@ -535,7 +456,7 @@ class OC_Mount_Config {
$applicable, $applicable,
$isPersonal = false, $isPersonal = false,
$priority = null) { $priority = null) {
$backends = self::getBackends(); $backendService = self::$appContainer->query('\OCA\Files_External\Service\BackendService');
$mountPoint = OC\Files\Filesystem::normalizePath($mountPoint); $mountPoint = OC\Files\Filesystem::normalizePath($mountPoint);
$relMountPoint = $mountPoint; $relMountPoint = $mountPoint;
if ($mountPoint === '' || $mountPoint === '/') { if ($mountPoint === '' || $mountPoint === '/') {
@ -543,15 +464,15 @@ class OC_Mount_Config {
return false; return false;
} }
if (!isset($backends[$class])) { $backend = $backendService->getBackend($class);
if (!isset($backend)) {
// invalid backend // invalid backend
return false; return false;
} }
if ($isPersonal) { if ($isPersonal) {
// Verify that the mount point applies for the current user // Verify that the mount point applies for the current user
// Prevent non-admin users from mounting local storage and other disabled backends // Prevent non-admin users from mounting local storage and other disabled backends
$allowed_backends = self::getPersonalBackends(); if ($applicable != OCP\User::getUser() || !$backend->isVisibleFor(BackendConfig::VISIBILITY_PERSONAL)) {
if ($applicable != OCP\User::getUser() || !isset($allowed_backends[$class])) {
return false; return false;
} }
$mountPoint = '/' . $applicable . '/files/' . ltrim($mountPoint, '/'); $mountPoint = '/' . $applicable . '/files/' . ltrim($mountPoint, '/');
@ -578,13 +499,8 @@ class OC_Mount_Config {
// Set default priority if none set // Set default priority if none set
if (!isset($mountPoints[$mountType][$applicable][$mountPoint]['priority'])) { if (!isset($mountPoints[$mountType][$applicable][$mountPoint]['priority'])) {
if (isset($backends[$class]['priority'])) {
$mountPoints[$mountType][$applicable][$mountPoint]['priority'] $mountPoints[$mountType][$applicable][$mountPoint]['priority']
= $backends[$class]['priority']; = $backend->getPriority();
} else {
$mountPoints[$mountType][$applicable][$mountPoint]['priority']
= 100;
}
} }
self::writeData($isPersonal ? OCP\User::getUser() : null, $mountPoints); self::writeData($isPersonal ? OCP\User::getUser() : null, $mountPoints);
@ -721,74 +637,35 @@ class OC_Mount_Config {
} }
/** /**
* check dependencies * Get backend dependency message
* TODO: move into AppFramework along with templates
*
* @param BackendConfig[] $backends
* @return string
*/ */
public static function checkDependencies() { public static function dependencyMessage($backends) {
$dependencies = array();
foreach (OC_Mount_Config::$backends as $class => $backend) {
if (isset($backend['has_dependencies']) and $backend['has_dependencies'] === true) {
$result = $class::checkDependencies();
if ($result !== true) {
if (!is_array($result)) {
$result = array($result);
}
foreach ($result as $key => $value) {
if (is_numeric($key)) {
OC_Mount_Config::addDependency($dependencies, $value, $backend['backend']);
} else {
OC_Mount_Config::addDependency($dependencies, $key, $backend['backend'], $value);
}
}
}
}
}
if (count($dependencies) > 0) {
return OC_Mount_Config::generateDependencyMessage($dependencies);
}
return '';
}
private static function addDependency(&$dependencies, $module, $backend, $message = null) {
if (!isset($dependencies[$module])) {
$dependencies[$module] = array();
}
if ($message === null) {
$dependencies[$module][] = $backend;
} else {
$dependencies[$module][] = array('backend' => $backend, 'message' => $message);
}
}
private static function generateDependencyMessage($dependencies) {
$l = new \OC_L10N('files_external'); $l = new \OC_L10N('files_external');
$dependencyMessage = ''; $message = '';
foreach ($dependencies as $module => $backends) { $dependencyGroups = [];
$dependencyGroup = array();
foreach ($backends as $backend) { foreach ($backends as $backend) {
if (is_array($backend)) { foreach ($backend->checkDependencies() as $dependency) {
$dependencyMessage .= '<br />' . $l->t('<b>Note:</b> ') . $backend['message']; if ($message = $dependency->getMessage()) {
$message .= '<br />' . $l->t('<b>Note:</b> ') . $message;
} else { } else {
$dependencyGroup[] = $backend; $dependencyGroups[$dependency->getDependency()][] = $backend;
}
} }
} }
$dependencyGroupCount = count($dependencyGroup); foreach ($dependencyGroups as $module => $dependants) {
if ($dependencyGroupCount > 0) { $backends = implode(', ', array_map(function($backend) {
$backends = ''; return '<i>' . $backend->getText() . '</i>';
for ($i = 0; $i < $dependencyGroupCount; $i++) { }, $dependants));
if ($i > 0 && $i === $dependencyGroupCount - 1) { $message .= '<br />' . OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends);
$backends .= ' ' . $l->t('and') . ' ';
} elseif ($i > 0) {
$backends .= ', ';
} }
$backends .= '<i>' . $dependencyGroup[$i] . '</i>';
} return $message;
$dependencyMessage .= '<br />' . OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends);
}
}
return $dependencyMessage;
} }
/** /**

View File

@ -24,14 +24,23 @@ namespace OCA\Files_External\Config;
use OC\Files\Mount\MountPoint; use OC\Files\Mount\MountPoint;
use OCP\Files\Storage\IStorageFactory; use OCP\Files\Storage\IStorageFactory;
use OCA\Files_External\PersonalMount; use OCA\Files_External\Lib\PersonalMount;
use OCP\Files\Config\IMountProvider; use OCP\Files\Config\IMountProvider;
use OCP\IUser; use OCP\IUser;
use OCA\Files_external\Service\UserStoragesService;
/** /**
* Make the old files_external config work with the new public mount config api * Make the old files_external config work with the new public mount config api
*/ */
class ConfigAdapter implements IMountProvider { class ConfigAdapter implements IMountProvider {
/**
* @param UserStoragesService $userStoragesService
*/
public function __construct(UserStoragesService $userStoragesService) {
$this->userStoragesService = $userStoragesService;
}
/** /**
* Get all mountpoints applicable for the user * Get all mountpoints applicable for the user
* *
@ -49,7 +58,8 @@ class ConfigAdapter implements IMountProvider {
} }
$mountOptions = isset($options['mountOptions']) ? $options['mountOptions'] : []; $mountOptions = isset($options['mountOptions']) ? $options['mountOptions'] : [];
if (isset($options['personal']) && $options['personal']) { if (isset($options['personal']) && $options['personal']) {
$mounts[] = new PersonalMount($options['class'], $mountPoint, $options['options'], $loader, $mountOptions); $mount = new PersonalMount($this->userStoragesService, $options['id'], $options['class'], $mountPoint, $options['options'], $loader, $mountOptions);
$mounts[] = $mount;
} else { } else {
$mounts[] = new MountPoint($options['class'], $mountPoint, $options['options'], $loader, $mountOptions); $mounts[] = new MountPoint($options['class'], $mountPoint, $options['options'], $loader, $mountOptions);
} }

View File

@ -0,0 +1,179 @@
<?php
/**
* @author Robin McCorkell <rmccorkell@karoshi.org.uk>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_External\Lib;
/**
* Parameter for an external storage definition
*/
class DefinitionParameter implements \JsonSerializable {
/** Value constants */
const VALUE_TEXT = 0;
const VALUE_BOOLEAN = 1;
const VALUE_PASSWORD = 2;
const VALUE_HIDDEN = 3;
/** Flag constants */
const FLAG_NONE = 0;
const FLAG_OPTIONAL = 1;
/** @var string name of parameter */
private $name;
/** @var string human-readable parameter text */
private $text;
/** @var int value type, see self::VALUE_* constants */
private $type = self::VALUE_TEXT;
/** @var int flags, see self::FLAG_* constants */
private $flags = self::FLAG_NONE;
/**
* @param string $name
* @param string $text
*/
public function __construct($name, $text) {
$this->name = $name;
$this->text = $text;
}
/**
* @return string
*/
public function getName() {
return $this->name;
}
/**
* @return string
*/
public function getText() {
return $this->text;
}
/**
* Get value type
*
* @return int
*/
public function getType() {
return $this->type;
}
/**
* Set value type
*
* @param int $type
* @return self
*/
public function setType($type) {
$this->type = $type;
return $this;
}
/**
* @return int
*/
public function getFlags() {
return $this->flags;
}
/**
* @param int $flags
* @return self
*/
public function setFlags($flags) {
$this->flags = $flags;
return $this;
}
/**
* @param int $flag
* @return self
*/
public function setFlag($flag) {
$this->flags |= $flag;
return $this;
}
/**
* @param int $flag
* @return bool
*/
public function isFlagSet($flag) {
return (bool) $this->flags & $flag;
}
/**
* Serialize into JSON for client-side JS
*
* @return string
*/
public function jsonSerialize() {
$prefix = '';
switch ($this->getType()) {
case self::VALUE_BOOLEAN:
$prefix = '!';
break;
case self::VALUE_PASSWORD:
$prefix = '*';
break;
case self::VALUE_HIDDEN:
$prefix = '#';
break;
}
switch ($this->getFlags()) {
case self::FLAG_OPTIONAL:
$prefix = '&' . $prefix;
break;
}
return $prefix . $this->getText();
}
/**
* Validate a parameter value against this
*
* @param mixed $value Value to check
* @return bool success
*/
public function validateValue($value) {
if ($this->getFlags() & self::FLAG_OPTIONAL) {
return true;
}
switch ($this->getType()) {
case self::VALUE_BOOLEAN:
if (!is_bool($value)) {
return false;
}
break;
default:
if (empty($value)) {
return false;
}
break;
}
return true;
}
}

View File

@ -0,0 +1,86 @@
<?php
/**
* @author Robin McCorkell <rmccorkell@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_External\Lib;
use \OCA\Files_External\Lib\MissingDependency;
/**
* Trait for objects that have dependencies for use
*/
trait DependencyTrait {
/** @var callable|null dependency check */
private $dependencyCheck = null;
/**
* @return bool
*/
public function hasDependencies() {
return !is_null($this->dependencyCheck);
}
/**
* @param callable $dependencyCheck
* @return self
*/
public function setDependencyCheck(callable $dependencyCheck) {
$this->dependencyCheck = $dependencyCheck;
return $this;
}
/**
* Check if object is valid for use
*
* @return MissingDependency[] Unsatisfied dependencies
*/
public function checkDependencies() {
$ret = [];
if ($this->hasDependencies()) {
$result = call_user_func($this->dependencyCheck);
if ($result !== true) {
if (!is_array($result)) {
$result = [$result];
}
foreach ($result as $key => $value) {
if (!($value instanceof MissingDependency)) {
$module = null;
$message = null;
if (is_numeric($key)) {
$module = $value;
} else {
$module = $key;
$message = $value;
}
$value = new MissingDependency($module, $this);
$value->setMessage($message);
}
$ret[] = $value;
}
}
}
return $ret;
}
}

View File

@ -0,0 +1,147 @@
<?php
/**
* @author Robin McCorkell <rmccorkell@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_External\Lib;
use \OCA\Files_External\Lib\DefinitionParameter;
use \OCA\Files_External\Lib\StorageConfig;
/**
* Trait for objects that have a frontend representation
*/
trait FrontendDefinitionTrait {
/** @var string human-readable mechanism name */
private $text;
/** @var DefinitionParameter[] parameters for mechanism */
private $parameters = [];
/** @var string|null custom JS */
private $customJs = null;
/**
* @return string
*/
public function getText() {
return $this->text;
}
/**
* @param string $text
* @return self
*/
public function setText($text) {
$this->text = $text;
return $this;
}
/**
* @param FrontendDefinitionTrait $a
* @param FrontendDefinitionTrait $b
* @return int
*/
public static function lexicalCompare(FrontendDefinitionTrait $a, FrontendDefinitionTrait $b) {
return strcmp($a->getText(), $b->getText());
}
/**
* @return DefinitionParameter[]
*/
public function getParameters() {
return $this->parameters;
}
/**
* @param DefinitionParameter[] $parameters
* @return self
*/
public function addParameters(array $parameters) {
foreach ($parameters as $parameter) {
$this->addParameter($parameter);
}
return $this;
}
/**
* @param DefinitionParameter $parameter
* @return self
*/
public function addParameter(DefinitionParameter $parameter) {
$this->parameters[$parameter->getName()] = $parameter;
return $this;
}
/**
* @return string|null
*/
public function getCustomJs() {
return $this->customJs;
}
/**
* @param string $custom
* @return self
*/
public function setCustomJs($custom) {
$this->customJs = $custom;
return $this;
}
/**
* Serialize into JSON for client-side JS
*
* @return array
*/
public function jsonSerializeDefinition() {
$configuration = [];
foreach ($this->getParameters() as $parameter) {
$configuration[$parameter->getName()] = $parameter;
}
$data = [
'name' => $this->getText(),
'configuration' => $configuration,
];
if (isset($this->customJs)) {
$data['custom'] = $this->getCustomJs();
}
return $data;
}
/**
* Check if parameters are satisfied in a StorageConfig
*
* @param StorageConfig $storage
* @return bool
*/
public function validateStorageDefinition(StorageConfig $storage) {
$options = $storage->getBackendOptions();
foreach ($this->getParameters() as $name => $parameter) {
$value = isset($options[$name]) ? $options[$name] : null;
if (!$parameter->validateValue($value)) {
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,64 @@
<?php
/**
* @author Robin McCorkell <rmccorkell@karoshi.org.uk>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_External\Lib;
/**
* External storage backend dependency
*/
class MissingDependency {
/** @var string */
private $dependency;
/** @var string|null Custom message */
private $message = null;
/**
* @param string $dependency
*/
public function __construct($dependency) {
$this->dependency = $dependency;
}
/**
* @return string
*/
public function getDependency() {
return $this->dependency;
}
/**
* @return string|null
*/
public function getMessage() {
return $this->message;
}
/**
* @param string $message
* @return self
*/
public function setMessage($message) {
$this->message = $message;
return $this;
}
}

View File

@ -20,15 +20,45 @@
* *
*/ */
namespace OCA\Files_External; namespace OCA\Files_External\Lib;
use OC\Files\Mount\MountPoint; use OC\Files\Mount\MountPoint;
use OC\Files\Mount\MoveableMount; use OC\Files\Mount\MoveableMount;
use OCA\Files_External\Service\UserStoragesService;
/** /**
* Person mount points can be moved by the user * Person mount points can be moved by the user
*/ */
class PersonalMount extends MountPoint implements MoveableMount { class PersonalMount extends MountPoint implements MoveableMount {
/** @var UserStoragesService */
protected $storagesService;
/** @var int */
protected $storageId;
/**
* @param UserStoragesService $storagesService
* @param int $storageId
* @param string|\OC\Files\Storage\Storage $storage
* @param string $mountpoint
* @param array $arguments (optional) configuration for the storage backend
* @param \OCP\Files\Storage\IStorageFactory $loader
* @param array $mountOptions mount specific options
*/
public function __construct(
UserStoragesService $storagesService,
$storageId,
$storage,
$mountpoint,
$arguments = null,
$loader = null,
$mountOptions = null
) {
parent::__construct($storage, $mountpoint, $arguments, $loader, $mountOptions);
$this->storagesService = $storagesService;
$this->storageId = $storageId;
}
/** /**
* Move the mount point to $target * Move the mount point to $target
* *
@ -36,9 +66,13 @@ class PersonalMount extends MountPoint implements MoveableMount {
* @return bool * @return bool
*/ */
public function moveMount($target) { public function moveMount($target) {
$result = \OC_Mount_Config::movePersonalMountPoint($this->getMountPoint(), $target, \OC_Mount_Config::MOUNT_TYPE_USER); $storage = $this->storagesService->getStorage($this->storageId);
// remove "/$user/files" prefix
$targetParts = explode('/', trim($target, '/'), 3);
$storage->setMountPoint($targetParts[2]);
$this->storagesService->updateStorage($storage);
$this->setMountPoint($target); $this->setMountPoint($target);
return $result; return true;
} }
/** /**
@ -47,8 +81,7 @@ class PersonalMount extends MountPoint implements MoveableMount {
* @return bool * @return bool
*/ */
public function removeMount() { public function removeMount() {
$user = \OCP\User::getUser(); $this->storagesService->removeStorage($this->storageId);
$relativeMountPoint = substr($this->getMountPoint(), strlen('/' . $user . '/files/')); return true;
return \OC_Mount_Config::removeMountPoint($relativeMountPoint, \OC_Mount_Config::MOUNT_TYPE_USER, $user , true);
} }
} }

View File

@ -0,0 +1,60 @@
<?php
/**
* @author Robin McCorkell <rmccorkell@karoshi.org.uk>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_External\Lib;
use \OCA\Files_External\Service\BackendService;
/**
* Trait to implement priority mechanics for a configuration class
*/
trait PriorityTrait {
/** @var int initial priority */
protected $priority = BackendService::PRIORITY_DEFAULT;
/**
* @return int
*/
public function getPriority() {
return $this->priority;
}
/**
* @param int $priority
* @return self
*/
public function setPriority($priority) {
$this->priority = $priority;
return $this;
}
/**
* @param PriorityTrait $a
* @param PriorityTrait $b
* @return int
*/
public static function priorityCompare(PriorityTrait $a, PriorityTrait $b) {
return ($a->getPriority() - $b->getPriority());
}
}

View File

@ -21,6 +21,8 @@
namespace OCA\Files_external\Lib; namespace OCA\Files_external\Lib;
use \OCA\Files_External\Lib\Backend\Backend;
/** /**
* External storage configuration * External storage configuration
*/ */
@ -34,11 +36,11 @@ class StorageConfig implements \JsonSerializable {
private $id; private $id;
/** /**
* Backend class name * Backend
* *
* @var string * @var Backend
*/ */
private $backendClass; private $backend;
/** /**
* Backend options * Backend options
@ -138,21 +140,17 @@ class StorageConfig implements \JsonSerializable {
} }
/** /**
* Returns the external storage backend class name * @return Backend
*
* @return string external storage backend class name
*/ */
public function getBackendClass() { public function getBackend() {
return $this->backendClass; return $this->backend;
} }
/** /**
* Sets the external storage backend class name * @param Backend
*
* @param string external storage backend class name
*/ */
public function setBackendClass($backendClass) { public function setBackend(Backend $backend) {
$this->backendClass = $backendClass; $this->backend= $backend;
} }
/** /**
@ -173,6 +171,25 @@ class StorageConfig implements \JsonSerializable {
$this->backendOptions = $backendOptions; $this->backendOptions = $backendOptions;
} }
/**
* @param string $key
* @return mixed
*/
public function getBackendOption($key) {
if (isset($this->backendOptions[$key])) {
return $this->backendOptions[$key];
}
return null;
}
/**
* @param string $key
* @param mixed $value
*/
public function setBackendOption($key, $value) {
$this->backendOptions[$key] = $value;
}
/** /**
* Returns the mount priority * Returns the mount priority
* *
@ -283,7 +300,7 @@ class StorageConfig implements \JsonSerializable {
$result['id'] = $this->id; $result['id'] = $this->id;
} }
$result['mountPoint'] = $this->mountPoint; $result['mountPoint'] = $this->mountPoint;
$result['backendClass'] = $this->backendClass; $result['backendClass'] = $this->backend->getClass();
$result['backendOptions'] = $this->backendOptions; $result['backendOptions'] = $this->backendOptions;
if (!is_null($this->priority)) { if (!is_null($this->priority)) {
$result['priority'] = $this->priority; $result['priority'] = $this->priority;

View File

@ -0,0 +1,51 @@
<?php
/**
* @author Robin McCorkell <rmccorkell@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_External\Lib;
use \OCP\Files\Storage;
use \OCA\Files_External\Lib\StorageConfig;
/**
* Trait for objects that can modify StorageConfigs and wrap Storages
*/
trait StorageModifierTrait {
/**
* Modify a StorageConfig parameters
*
* @param StorageConfig $storage
*/
public function manipulateStorageConfig(StorageConfig &$storage) {
}
/**
* Wrap a Storage if necessary
*
* @param Storage $storage
* @return Storage
*/
public function wrapStorage(Storage $storage) {
return $storage;
}
}

View File

@ -0,0 +1,129 @@
<?php
/**
* @author Robin McCorkell <rmccorkell@karoshi.org.uk>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_External\Lib;
use \OCA\Files_External\Service\BackendService;
/**
* Trait to implement visibility mechanics for a configuration class
*/
trait VisibilityTrait {
/** @var int visibility */
protected $visibility = BackendService::VISIBILITY_DEFAULT;
/** @var int allowed visibilities */
protected $allowedVisibility = BackendService::VISIBILITY_DEFAULT;
/**
* @return int
*/
public function getVisibility() {
return $this->visibility;
}
/**
* Check if the backend is visible for a user type
*
* @param int $visibility
* @return bool
*/
public function isVisibleFor($visibility) {
if ($this->visibility & $visibility) {
return true;
}
return false;
}
/**
* @param int $visibility
* @return self
*/
public function setVisibility($visibility) {
$this->visibility = $visibility;
$this->allowedVisibility |= $visibility;
return $this;
}
/**
* @param int $visibility
* @return self
*/
public function addVisibility($visibility) {
return $this->setVisibility($this->visibility | $visibility);
}
/**
* @param int $visibility
* @return self
*/
public function removeVisibility($visibility) {
return $this->setVisibility($this->visibility & ~$visibility);
}
/**
* @return int
*/
public function getAllowedVisibility() {
return $this->allowedVisibility;
}
/**
* Check if the backend is allowed to be visible for a user type
*
* @param int $allowedVisibility
* @return bool
*/
public function isAllowedVisibleFor($allowedVisibility) {
if ($this->allowedVisibility & $allowedVisibility) {
return true;
}
return false;
}
/**
* @param int $allowedVisibility
* @return self
*/
public function setAllowedVisibility($allowedVisibility) {
$this->allowedVisibility = $allowedVisibility;
$this->visibility &= $allowedVisibility;
return $this;
}
/**
* @param int $allowedVisibility
* @return self
*/
public function addAllowedVisibility($allowedVisibility) {
return $this->setAllowedVisibility($this->allowedVisibility | $allowedVisibility);
}
/**
* @param int $allowedVisibility
* @return self
*/
public function removeAllowedVisibility($allowedVisibility) {
return $this->setAllowedVisibility($this->allowedVisibility & ~$allowedVisibility);
}
}

View File

@ -24,34 +24,20 @@
* *
*/ */
use \OCA\Files_External\Service\BackendService;
$app = new \OCA\Files_external\Appinfo\Application();
$appContainer = $app->getContainer();
$backendService = $appContainer->query('OCA\Files_External\Service\BackendService');
$userStoragesService = $appContainer->query('OCA\Files_external\Service\UserStoragesService');
OCP\Util::addScript('files_external', 'settings'); OCP\Util::addScript('files_external', 'settings');
OCP\Util::addStyle('files_external', 'settings'); OCP\Util::addStyle('files_external', 'settings');
$backends = OC_Mount_Config::getPersonalBackends();
$mounts = OC_Mount_Config::getPersonalMountPoints();
$hasId = true;
foreach ($mounts as $mount) {
if (!isset($mount['id'])) {
// some mount points are missing ids
$hasId = false;
break;
}
}
if (!$hasId) {
$service = new \OCA\Files_external\Service\UserStoragesService(\OC::$server->getUserSession());
// this will trigger the new storage code which will automatically
// generate storage config ids
$service->getAllStorages();
// re-read updated config
$mounts = OC_Mount_Config::getPersonalMountPoints();
// TODO: use the new storage config format in the template
}
$tmpl = new OCP\Template('files_external', 'settings'); $tmpl = new OCP\Template('files_external', 'settings');
$tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled()); $tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled());
$tmpl->assign('isAdminPage', false); $tmpl->assign('isAdminPage', false);
$tmpl->assign('mounts', $mounts); $tmpl->assign('storages', $userStoragesService->getAllStorages());
$tmpl->assign('dependencies', OC_Mount_Config::checkDependencies()); $tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends()));
$tmpl->assign('backends', $backends); $tmpl->assign('backends', $backendService->getBackendsVisibleFor(BackendService::VISIBILITY_PERSONAL));
return $tmpl->fetchPage(); return $tmpl->fetchPage();

View File

@ -0,0 +1,170 @@
<?php
/**
* @author Robin McCorkell <rmccorkell@karoshi.org.uk>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_External\Service;
use \OCP\IConfig;
use \OCA\Files_External\Lib\Backend\Backend;
/**
* Service class to manage backend definitions
*/
class BackendService {
/** Visibility constants for VisibilityTrait */
const VISIBILITY_NONE = 0;
const VISIBILITY_PERSONAL = 1;
const VISIBILITY_ADMIN = 2;
//const VISIBILITY_ALIENS = 4;
const VISIBILITY_DEFAULT = 3; // PERSONAL | ADMIN
/** Priority constants for PriorityTrait */
const PRIORITY_DEFAULT = 100;
/** @var IConfig */
protected $config;
/** @var bool */
private $userMountingAllowed = true;
/** @var string[] */
private $userMountingBackends = [];
/** @var Backend[] */
private $backends = [];
/**
* @param IConfig $config
*/
public function __construct(
IConfig $config
) {
$this->config = $config;
// Load config values
if ($this->config->getAppValue('files_external', 'allow_user_mounting', 'yes') !== 'yes') {
$this->userMountingAllowed = false;
}
$this->userMountingBackends = explode(',',
$this->config->getAppValue('files_external', 'user_mounting_backends', '')
);
}
/**
* Register a backend
*
* @param Backend $backend
*/
public function registerBackend(Backend $backend) {
if (!$this->isAllowedUserBackend($backend)) {
$backend->removeVisibility(BackendService::VISIBILITY_PERSONAL);
}
$this->backends[$backend->getClass()] = $backend;
}
/**
* @param Backend[] $backends
*/
public function registerBackends(array $backends) {
foreach ($backends as $backend) {
$this->registerBackend($backend);
}
}
/**
* Get all backends
*
* @return Backend[]
*/
public function getBackends() {
return $this->backends;
}
/**
* Get all available backends
*
* @return Backend[]
*/
public function getAvailableBackends() {
return array_filter($this->getBackends(), function($backend) {
return empty($backend->checkDependencies());
});
}
/**
* Get backends visible for $visibleFor
*
* @param int $visibleFor
* @return Backend[]
*/
public function getBackendsVisibleFor($visibleFor) {
return array_filter($this->getAvailableBackends(), function($backend) use ($visibleFor) {
return $backend->isVisibleFor($visibleFor);
});
}
/**
* Get backends allowed to be visible for $visibleFor
*
* @param int $visibleFor
* @return Backend[]
*/
public function getBackendsAllowedVisibleFor($visibleFor) {
return array_filter($this->getAvailableBackends(), function($backend) use ($visibleFor) {
return $backend->isAllowedVisibleFor($visibleFor);
});
}
/**
* @param string $class Backend class name
* @return Backend|null
*/
public function getBackend($class) {
if (isset($this->backends[$class])) {
return $this->backends[$class];
}
return null;
}
/**
* @return bool
*/
public function isUserMountingAllowed() {
return $this->userMountingAllowed;
}
/**
* Check a backend if a user is allowed to mount it
*
* @param Backend $backend
* @return bool
*/
protected function isAllowedUserBackend(Backend $backend) {
if ($this->userMountingAllowed &&
in_array($backend->getClass(), $this->userMountingBackends)
) {
return true;
}
return false;
}
}

View File

@ -28,12 +28,23 @@ use \OC\Files\Filesystem;
use \OCA\Files_external\Lib\StorageConfig; use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_external\NotFoundException; use \OCA\Files_external\NotFoundException;
use \OCA\Files_External\Service\BackendService;
/** /**
* Service class to manage external storages * Service class to manage external storages
*/ */
abstract class StoragesService { abstract class StoragesService {
/** @var BackendService */
protected $backendService;
/**
* @param BackendService $backendService
*/
public function __construct(BackendService $backendService) {
$this->backendService = $backendService;
}
/** /**
* Read legacy config data * Read legacy config data
* *
@ -60,14 +71,17 @@ abstract class StoragesService {
$applicable, $applicable,
$storageOptions $storageOptions
) { ) {
$storageConfig->setBackendClass($storageOptions['class']); $backend = $this->backendService->getBackend($storageOptions['class']);
$storageConfig->setBackend($backend);
$storageConfig->setBackendOptions($storageOptions['options']); $storageConfig->setBackendOptions($storageOptions['options']);
if (isset($storageOptions['mountOptions'])) { if (isset($storageOptions['mountOptions'])) {
$storageConfig->setMountOptions($storageOptions['mountOptions']); $storageConfig->setMountOptions($storageOptions['mountOptions']);
} }
if (isset($storageOptions['priority'])) { if (!isset($storageOptions['priority'])) {
$storageConfig->setPriority($storageOptions['priority']); $storageOptions['priority'] = $backend->getPriority();
} }
$storageConfig->setPriority($storageOptions['priority']);
if ($mountType === \OC_Mount_Config::MOUNT_TYPE_USER) { if ($mountType === \OC_Mount_Config::MOUNT_TYPE_USER) {
$applicableUsers = $storageConfig->getApplicableUsers(); $applicableUsers = $storageConfig->getApplicableUsers();
@ -222,7 +236,7 @@ abstract class StoragesService {
$options = [ $options = [
'id' => $storageConfig->getId(), 'id' => $storageConfig->getId(),
'class' => $storageConfig->getBackendClass(), 'class' => $storageConfig->getBackend()->getClass(),
'options' => $storageConfig->getBackendOptions(), 'options' => $storageConfig->getBackendOptions(),
]; ];
@ -296,6 +310,52 @@ abstract class StoragesService {
return $newStorage; return $newStorage;
} }
/**
* Create a storage from its parameters
*
* @param string $mountPoint storage mount point
* @param string $backendClass backend class name
* @param array $backendOptions backend-specific options
* @param array|null $mountOptions mount-specific options
* @param array|null $applicableUsers users for which to mount the storage
* @param array|null $applicableGroups groups for which to mount the storage
* @param int|null $priority priority
*
* @return StorageConfig
*/
public function createStorage(
$mountPoint,
$backendClass,
$backendOptions,
$mountOptions = null,
$applicableUsers = null,
$applicableGroups = null,
$priority = null
) {
$backend = $this->backendService->getBackend($backendClass);
if (!$backend) {
throw new \InvalidArgumentException('Unable to get backend for backend class '.$backendClass);
}
$newStorage = new StorageConfig();
$newStorage->setMountPoint($mountPoint);
$newStorage->setBackend($backend);
$newStorage->setBackendOptions($backendOptions);
if (isset($mountOptions)) {
$newStorage->setMountOptions($mountOptions);
}
if (isset($applicableUsers)) {
$newStorage->setApplicableUsers($applicableUsers);
}
if (isset($applicableGroups)) {
$newStorage->setApplicableGroups($applicableGroups);
}
if (isset($priority)) {
$newStorage->setPriority($priority);
}
return $newStorage;
}
/** /**
* Triggers the given hook signal for all the applicables given * Triggers the given hook signal for all the applicables given
* *

View File

@ -26,6 +26,7 @@ use \OC\Files\Filesystem;
use \OCA\Files_external\Lib\StorageConfig; use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_external\NotFoundException; use \OCA\Files_external\NotFoundException;
use \OCA\Files_External\Service\BackendService;
/** /**
* Service class to manage user external storages * Service class to manage user external storages
@ -43,12 +44,15 @@ class UserStoragesService extends StoragesService {
/** /**
* Create a user storages service * Create a user storages service
* *
* @param BackendService $backendService
* @param IUserSession $userSession user session * @param IUserSession $userSession user session
*/ */
public function __construct( public function __construct(
BackendService $backendService,
IUserSession $userSession IUserSession $userSession
) { ) {
$this->userSession = $userSession; $this->userSession = $userSession;
parent::__construct($backendService);
} }
/** /**

View File

@ -26,54 +26,27 @@
* *
*/ */
use \OCA\Files_External\Service\BackendService;
OC_Util::checkAdminUser(); OC_Util::checkAdminUser();
$app = new \OCA\Files_external\Appinfo\Application();
$appContainer = $app->getContainer();
$backendService = $appContainer->query('OCA\Files_External\Service\BackendService');
$globalStoragesService = $appContainer->query('OCA\Files_external\Service\GlobalStoragesService');
OCP\Util::addScript('files_external', 'settings'); OCP\Util::addScript('files_external', 'settings');
OCP\Util::addStyle('files_external', 'settings'); OCP\Util::addStyle('files_external', 'settings');
\OC_Util::addVendorScript('select2/select2'); \OC_Util::addVendorScript('select2/select2');
\OC_Util::addVendorStyle('select2/select2'); \OC_Util::addVendorStyle('select2/select2');
$backends = OC_Mount_Config::getBackends();
$personal_backends = array();
$enabled_backends = explode(',', OCP\Config::getAppValue('files_external', 'user_mounting_backends', ''));
foreach ($backends as $class => $backend)
{
if ($class != '\OC\Files\Storage\Local')
{
$personal_backends[$class] = array(
'backend' => $backend['backend'],
'enabled' => in_array($class, $enabled_backends),
);
}
}
$mounts = OC_Mount_Config::getSystemMountPoints();
$hasId = true;
foreach ($mounts as $mount) {
if (!isset($mount['id'])) {
// some mount points are missing ids
$hasId = false;
break;
}
}
if (!$hasId) {
$service = new \OCA\Files_external\Service\GlobalStoragesService();
// this will trigger the new storage code which will automatically
// generate storage config ids
$service->getAllStorages();
// re-read updated config
$mounts = OC_Mount_Config::getSystemMountPoints();
// TODO: use the new storage config format in the template
}
$tmpl = new OCP\Template('files_external', 'settings'); $tmpl = new OCP\Template('files_external', 'settings');
$tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled()); $tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled());
$tmpl->assign('isAdminPage', true); $tmpl->assign('isAdminPage', true);
$tmpl->assign('mounts', $mounts); $tmpl->assign('storages', $globalStoragesService->getAllStorages());
$tmpl->assign('backends', $backends); $tmpl->assign('backends', $backendService->getBackendsVisibleFor(BackendService::VISIBILITY_ADMIN));
$tmpl->assign('personal_backends', $personal_backends); $tmpl->assign('userBackends', $backendService->getBackendsAllowedVisibleFor(BackendService::VISIBILITY_PERSONAL));
$tmpl->assign('dependencies', OC_Mount_Config::checkDependencies()); $tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends()));
$tmpl->assign('allowUserMounting', OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes')); $tmpl->assign('allowUserMounting', $backendService->isUserMountingAllowed());
return $tmpl->fetchPage(); return $tmpl->fetchPage();

View File

@ -1,3 +1,8 @@
<?php
use \OCA\Files_External\Lib\Backend\Backend;
use \OCA\Files_External\Lib\DefinitionParameter;
use \OCA\Files_External\Service\BackendService;
?>
<form id="files_external" class="section" data-encryption-enabled="<?php echo $_['encryptionEnabled']?'true': 'false'; ?>"> <form id="files_external" class="section" data-encryption-enabled="<?php echo $_['encryptionEnabled']?'true': 'false'; ?>">
<h2><?php p($l->t('External Storage')); ?></h2> <h2><?php p($l->t('External Storage')); ?></h2>
<?php if (isset($_['dependencies']) and ($_['dependencies']<>'')) print_unescaped(''.$_['dependencies'].''); ?> <?php if (isset($_['dependencies']) and ($_['dependencies']<>'')) print_unescaped(''.$_['dependencies'].''); ?>
@ -14,103 +19,149 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<?php $_['mounts'] = array_merge($_['mounts'], array('' => array('id' => ''))); ?> <?php foreach ($_['storages'] as $storage): ?>
<?php foreach ($_['mounts'] as $mount): ?> <tr class="<?php p($storage->getBackend()->getClass()); ?>" data-id="<?php p($storage->getId()); ?>">
<tr <?php print_unescaped(isset($mount['mountpoint']) ? 'class="'.OC_Util::sanitizeHTML($mount['class']).'"' : 'id="addMountPoint"'); ?> data-id="<?php p($mount['id']) ?>">
<td class="status"> <td class="status">
<span></span> <span></span>
</td> </td>
<td class="mountPoint"><input type="text" name="mountPoint" <td class="mountPoint"><input type="text" name="mountPoint"
value="<?php p(isset($mount['mountpoint']) ? $mount['mountpoint'] : ''); ?>" value="<?php p(ltrim($storage->getMountPoint(), '/')); ?>"
data-mountpoint="<?php p(isset($mount['mountpoint']) ? $mount['mountpoint'] : ''); ?>" data-mountpoint="<?php p(ltrim($storage->getMountPoint(), '/')); ?>"
placeholder="<?php p($l->t('Folder name')); ?>" /> placeholder="<?php p($l->t('Folder name')); ?>" />
</td> </td>
<?php if (!isset($mount['mountpoint'])): ?> <td class="backend" data-class="<?php p($storage->getBackend()->getClass()); ?>"><?php p($storage->getBackend()->getText()); ?>
<td class="backend">
<select id="selectBackend" class="selectBackend" data-configurations='<?php p(json_encode($_['backends'])); ?>'>
<option value="" disabled selected
style="display:none;"><?php p($l->t('Add storage')); ?></option>
<?php foreach ($_['backends'] as $class => $backend): ?>
<option value="<?php p($class); ?>"><?php p($backend['backend']); ?></option>
<?php endforeach; ?>
</select>
</td> </td>
<?php else: ?> <td class="configuration">
<td class="backend" data-class="<?php p($mount['class']); ?>"><?php p($mount['backend']); ?> <?php $options = $storage->getBackendOptions(); ?>
</td> <?php foreach ($storage->getBackend()->getParameters() as $parameter): ?>
<?php endif; ?>
<td class ="configuration">
<?php if (isset($mount['options'])): ?>
<?php foreach ($mount['options'] as $parameter => $value): ?>
<?php if (isset($_['backends'][$mount['class']]['configuration'][$parameter])): ?>
<?php <?php
$placeholder = $_['backends'][$mount['class']]['configuration'][$parameter]; $value = '';
$is_optional = FALSE; if (isset($options[$parameter->getName()])) {
if (strpos($placeholder, '&') === 0) { $value = $options[$parameter->getName()];
$is_optional = TRUE;
$placeholder = substr($placeholder, 1);
} }
?> $placeholder = $parameter->getText();
<?php if (strpos($placeholder, '*') === 0): ?> $is_optional = $parameter->isFlagSet(DefinitionParameter::FLAG_OPTIONAL);
switch ($parameter->getType()) {
case DefinitionParameter::VALUE_PASSWORD: ?>
<input type="password" <input type="password"
<?php if ($is_optional): ?> class="optional"<?php endif; ?> <?php if ($is_optional): ?> class="optional"<?php endif; ?>
data-parameter="<?php p($parameter); ?>" data-parameter="<?php p($parameter->getName()); ?>"
value="<?php p($value); ?>" value="<?php p($value); ?>"
placeholder="<?php p(substr($placeholder, 1)); ?>" /> placeholder="<?php p($placeholder); ?>"
<?php elseif (strpos($placeholder, '!') === 0): ?> />
<label><input type="checkbox" <?php
data-parameter="<?php p($parameter); ?>" break;
case DefinitionParameter::VALUE_BOOLEAN: ?>
<label>
<input type="checkbox"
data-parameter="<?php p($parameter->getName()); ?>"
<?php if ($value == 'true'): ?> checked="checked"<?php endif; ?> <?php if ($value == 'true'): ?> checked="checked"<?php endif; ?>
/><?php p(substr($placeholder, 1)); ?></label> />
<?php elseif (strpos($placeholder, '#') === 0): ?> <?php p($placeholder); ?>
</label>
<?php
break;
case DefinitionParameter::VALUE_HIDDEN: ?>
<input type="hidden" <input type="hidden"
data-parameter="<?php p($parameter); ?>" data-parameter="<?php p($parameter->getName()); ?>"
value="<?php p($value); ?>" /> value="<?php p($value); ?>"
<?php else: ?> />
<?php
break;
default: ?>
<input type="text" <input type="text"
<?php if ($is_optional): ?> class="optional"<?php endif; ?> <?php if ($is_optional): ?> class="optional"<?php endif; ?>
data-parameter="<?php p($parameter); ?>" data-parameter="<?php p($parameter->getName()); ?>"
value="<?php p($value); ?>" value="<?php p($value); ?>"
placeholder="<?php p($placeholder); ?>" /> placeholder="<?php p($placeholder); ?>"
<?php endif; ?> />
<?php endif; ?> <?php
}
?>
<?php endforeach; ?> <?php endforeach; ?>
<?php if (isset($_['backends'][$mount['class']]['custom'])): ?> <?php
<?php OCP\Util::addScript('files_external', $_['backends'][$mount['class']]['custom']); ?> $customJs = $storage->getBackend()->getCustomJs();
<?php endif; ?> if (isset($customJs)) {
<?php endif; ?> \OCP\Util::addScript('files_external', $customJs);
}
?>
</td> </td>
<?php if ($_['isAdminPage']): ?> <?php if ($_['isAdminPage']): ?>
<td class="applicable" <td class="applicable"
align="right" align="right"
data-applicable-groups='<?php if (isset($mount['applicable']['groups'])) data-applicable-groups='<?php print_unescaped(json_encode($storage->getApplicableGroups())); ?>'
print_unescaped(json_encode($mount['applicable']['groups'])); ?>' data-applicable-users='<?php print_unescaped(json_encode($storage->getApplicableUsers())); ?>'>
data-applicable-users='<?php if (isset($mount['applicable']['users']))
print_unescaped(json_encode($mount['applicable']['users'])); ?>'>
<input type="hidden" class="applicableUsers" style="width:20em;" value=""/> <input type="hidden" class="applicableUsers" style="width:20em;" value=""/>
</td> </td>
<?php endif; ?> <?php endif; ?>
<td class="mountOptionsToggle <?php if (!isset($mount['mountpoint'])) { p('hidden'); } ?>" <td class="mountOptionsToggle">
><img <img
class="svg action" class="svg action"
title="<?php p($l->t('Advanced settings')); ?>" title="<?php p($l->t('Advanced settings')); ?>"
alt="<?php p($l->t('Advanced settings')); ?>" alt="<?php p($l->t('Advanced settings')); ?>"
src="<?php print_unescaped(image_path('core', 'actions/settings.svg')); ?>" /> src="<?php print_unescaped(image_path('core', 'actions/settings.svg')); ?>"
<input type="hidden" class="mountOptions" value="<?php isset($mount['mountOptions']) ? p(json_encode($mount['mountOptions'])) : '' ?>" /> />
<input type="hidden" class="mountOptions" value="<?php p(json_encode($storage->getMountOptions())); ?>" />
<?php if ($_['isAdminPage']): ?> <?php if ($_['isAdminPage']): ?>
<?php if (isset($mount['priority'])): ?> <input type="hidden" class="priority" value="<?php p($storage->getPriority()); ?>" />
<input type="hidden" class="priority" value="<?php p($mount['priority']) ?>" />
<?php endif; ?>
<?php endif; ?> <?php endif; ?>
</td> </td>
<td <?php if (isset($mount['mountpoint'])): ?>class="remove" <td class="remove">
<?php else: ?>class="hidden" <img alt="<?php p($l->t('Delete')); ?>"
<?php endif ?>><img alt="<?php p($l->t('Delete')); ?>"
title="<?php p($l->t('Delete')); ?>" title="<?php p($l->t('Delete')); ?>"
class="svg action" class="svg action"
src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>" /></td> src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>"
/>
</td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
<tr id="addMountPoint">
<td class="status">
<span></span>
</td>
<td class="mountPoint"><input type="text" name="mountPoint" value=""
placeholder="<?php p($l->t('Folder name')); ?>">
</td>
<td class="backend">
<select id="selectBackend" class="selectBackend" data-configurations='<?php p(json_encode($_['backends'])); ?>'>
<option value="" disabled selected
style="display:none;">
<?php p($l->t('Add storage')); ?>
</option>
<?php
$sortedBackends = $_['backends'];
uasort($sortedBackends, function($a, $b) {
return strcasecmp($a->getText(), $b->getText());
});
?>
<?php foreach ($sortedBackends as $backend): ?>
<option value="<?php p($backend->getClass()); ?>"><?php p($backend->getText()); ?></option>
<?php endforeach; ?>
</select>
</td>
<td class="configuration"</td>
<?php if ($_['isAdminPage']): ?>
<td class="applicable" align="right">
<input type="hidden" class="applicableUsers" style="width:20em;" value="" />
</td>
<?php endif; ?>
<td class="mountOptionsToggle hidden">
<img class="svg action"
title="<?php p($l->t('Advanced settings')); ?>"
alt="<?php p($l->t('Advanced settings')); ?>"
src="<?php print_unescaped(image_path('core', 'actions/settings.svg')); ?>"
/>
<input type="hidden" class="mountOptions" value="" />
</td>
<td class="hidden">
<img class="svg action"
alt="<?php p($l->t('Delete')); ?>"
title="<?php p($l->t('Delete')); ?>"
src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>"
/>
</td>
</tr>
</tbody> </tbody>
</table> </table>
<br /> <br />
@ -123,9 +174,9 @@
<p id="userMountingBackends"<?php if ($_['allowUserMounting'] != 'yes'): ?> class="hidden"<?php endif; ?>> <p id="userMountingBackends"<?php if ($_['allowUserMounting'] != 'yes'): ?> class="hidden"<?php endif; ?>>
<?php p($l->t('Allow users to mount the following external storage')); ?><br /> <?php p($l->t('Allow users to mount the following external storage')); ?><br />
<?php $i = 0; foreach ($_['personal_backends'] as $class => $backend): ?> <?php $i = 0; foreach ($_['userBackends'] as $backend): ?>
<input type="checkbox" id="allowUserMountingBackends<?php p($i); ?>" name="allowUserMountingBackends[]" value="<?php p($class); ?>" <?php if ($backend['enabled']) print_unescaped(' checked="checked"'); ?> /> <input type="checkbox" id="allowUserMountingBackends<?php p($i); ?>" name="allowUserMountingBackends[]" value="<?php p($backend->getClass()); ?>" <?php if ($backend->isVisibleFor(BackendService::VISIBILITY_PERSONAL)) print_unescaped(' checked="checked"'); ?> />
<label for="allowUserMountingBackends<?php p($i); ?>"><?php p($backend['backend']); ?></label> <br /> <label for="allowUserMountingBackends<?php p($i); ?>"><?php p($backend->getText()); ?></label> <br />
<?php $i++; ?> <?php $i++; ?>
<?php endforeach; ?> <?php endforeach; ?>
</p> </p>

View File

@ -28,7 +28,9 @@ use \OCA\Files_external\NotFoundException;
class GlobalStoragesControllerTest extends StoragesControllerTest { class GlobalStoragesControllerTest extends StoragesControllerTest {
public function setUp() { public function setUp() {
parent::setUp(); parent::setUp();
$this->service = $this->getMock('\OCA\Files_external\Service\GlobalStoragesService'); $this->service = $this->getMockBuilder('\OCA\Files_external\Service\GlobalStoragesService')
->disableOriginalConstructor()
->getMock();
$this->controller = new GlobalStoragesController( $this->controller = new GlobalStoragesController(
'files_external', 'files_external',

View File

@ -47,10 +47,32 @@ abstract class StoragesControllerTest extends \Test\TestCase {
\OC_Mount_Config::$skipTest = false; \OC_Mount_Config::$skipTest = false;
} }
protected function getBackendMock($class = '\OCA\Files_External\Lib\Backend\SMB', $storageClass = '\OC\Files\Storage\SMB') {
$backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
->disableOriginalConstructor()
->getMock();
$backend->method('getStorageClass')
->willReturn($storageClass);
$backend->method('getClass')
->willReturn($storageClass);
return $backend;
}
public function testAddStorage() { public function testAddStorage() {
$backend = $this->getBackendMock();
$backend->method('validateStorage')
->willReturn(true);
$backend->method('isVisibleFor')
->willReturn(true);
$storageConfig = new StorageConfig(1); $storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('mount'); $storageConfig->setMountPoint('mount');
$storageConfig->setBackend($backend);
$storageConfig->setBackendOptions([]);
$this->service->expects($this->once())
->method('createStorage')
->will($this->returnValue($storageConfig));
$this->service->expects($this->once()) $this->service->expects($this->once())
->method('addStorage') ->method('addStorage')
->will($this->returnValue($storageConfig)); ->will($this->returnValue($storageConfig));
@ -71,9 +93,20 @@ abstract class StoragesControllerTest extends \Test\TestCase {
} }
public function testUpdateStorage() { public function testUpdateStorage() {
$backend = $this->getBackendMock();
$backend->method('validateStorage')
->willReturn(true);
$backend->method('isVisibleFor')
->willReturn(true);
$storageConfig = new StorageConfig(1); $storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('mount'); $storageConfig->setMountPoint('mount');
$storageConfig->setBackend($backend);
$storageConfig->setBackendOptions([]);
$this->service->expects($this->once())
->method('createStorage')
->will($this->returnValue($storageConfig));
$this->service->expects($this->once()) $this->service->expects($this->once())
->method('updateStorage') ->method('updateStorage')
->will($this->returnValue($storageConfig)); ->will($this->returnValue($storageConfig));
@ -106,6 +139,14 @@ abstract class StoragesControllerTest extends \Test\TestCase {
* @dataProvider mountPointNamesProvider * @dataProvider mountPointNamesProvider
*/ */
public function testAddOrUpdateStorageInvalidMountPoint($mountPoint) { public function testAddOrUpdateStorageInvalidMountPoint($mountPoint) {
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint($mountPoint);
$storageConfig->setBackend($this->getBackendMock());
$storageConfig->setBackendOptions([]);
$this->service->expects($this->exactly(2))
->method('createStorage')
->will($this->returnValue($storageConfig));
$this->service->expects($this->never()) $this->service->expects($this->never())
->method('addStorage'); ->method('addStorage');
$this->service->expects($this->never()) $this->service->expects($this->never())
@ -138,6 +179,9 @@ abstract class StoragesControllerTest extends \Test\TestCase {
} }
public function testAddOrUpdateStorageInvalidBackend() { public function testAddOrUpdateStorageInvalidBackend() {
$this->service->expects($this->exactly(2))
->method('createStorage')
->will($this->throwException(new \InvalidArgumentException()));
$this->service->expects($this->never()) $this->service->expects($this->never())
->method('addStorage'); ->method('addStorage');
$this->service->expects($this->never()) $this->service->expects($this->never())
@ -170,6 +214,20 @@ abstract class StoragesControllerTest extends \Test\TestCase {
} }
public function testUpdateStorageNonExisting() { public function testUpdateStorageNonExisting() {
$backend = $this->getBackendMock();
$backend->method('validateStorage')
->willReturn(true);
$backend->method('isVisibleFor')
->willReturn(true);
$storageConfig = new StorageConfig(255);
$storageConfig->setMountPoint('mount');
$storageConfig->setBackend($backend);
$storageConfig->setBackendOptions([]);
$this->service->expects($this->once())
->method('createStorage')
->will($this->returnValue($storageConfig));
$this->service->expects($this->once()) $this->service->expects($this->once())
->method('updateStorage') ->method('updateStorage')
->will($this->throwException(new NotFoundException())); ->will($this->throwException(new NotFoundException()));
@ -206,9 +264,10 @@ abstract class StoragesControllerTest extends \Test\TestCase {
} }
public function testGetStorage() { public function testGetStorage() {
$backend = $this->getBackendMock();
$storageConfig = new StorageConfig(1); $storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('test'); $storageConfig->setMountPoint('test');
$storageConfig->setBackendClass('\OC\Files\Storage\SMB'); $storageConfig->setBackend($backend);
$storageConfig->setBackendOptions(['user' => 'test', 'password', 'password123']); $storageConfig->setBackendOptions(['user' => 'test', 'password', 'password123']);
$storageConfig->setMountOptions(['priority' => false]); $storageConfig->setMountOptions(['priority' => false]);

View File

@ -24,6 +24,8 @@ use \OCA\Files_external\Controller\UserStoragesController;
use \OCA\Files_external\Service\UserStoragesService; use \OCA\Files_external\Service\UserStoragesService;
use \OCP\AppFramework\Http; use \OCP\AppFramework\Http;
use \OCA\Files_external\NotFoundException; use \OCA\Files_external\NotFoundException;
use \OCA\Files_External\Lib\StorageConfig;
use \OCA\Files_External\Service\BackendService;
class UserStoragesControllerTest extends StoragesControllerTest { class UserStoragesControllerTest extends StoragesControllerTest {
@ -44,41 +46,22 @@ class UserStoragesControllerTest extends StoragesControllerTest {
$this->getMock('\OCP\IL10N'), $this->getMock('\OCP\IL10N'),
$this->service $this->service
); );
$config = \OC::$server->getConfig();
$this->oldAllowedBackends = $config->getAppValue(
'files_external',
'user_mounting_backends',
''
);
$config->setAppValue(
'files_external',
'user_mounting_backends',
'\OC\Files\Storage\SMB'
);
} }
public function tearDown() { public function testAddOrUpdateStorageDisallowedBackend() {
$config = \OC::$server->getConfig(); $backend = $this->getBackendMock();
$config->setAppValue( $backend->method('isVisibleFor')
'files_external', ->with(BackendService::VISIBILITY_PERSONAL)
'user_mounting_backends', ->willReturn(false);
$this->oldAllowedBackends
);
parent::tearDown();
}
function disallowedBackendClassProvider() { $storageConfig = new StorageConfig(1);
return array( $storageConfig->setMountPoint('mount');
array('\OC\Files\Storage\Local'), $storageConfig->setBackend($backend);
array('\OC\Files\Storage\FTP'), $storageConfig->setBackendOptions([]);
);
} $this->service->expects($this->exactly(2))
/** ->method('createStorage')
* @dataProvider disallowedBackendClassProvider ->will($this->returnValue($storageConfig));
*/
public function testAddOrUpdateStorageDisallowedBackend($backendClass) {
$this->service->expects($this->never()) $this->service->expects($this->never())
->method('addStorage'); ->method('addStorage');
$this->service->expects($this->never()) $this->service->expects($this->never())
@ -86,7 +69,7 @@ class UserStoragesControllerTest extends StoragesControllerTest {
$response = $this->controller->create( $response = $this->controller->create(
'mount', 'mount',
$backendClass, '\OC\Files\Storage\SMB',
array(), array(),
[], [],
[], [],
@ -99,7 +82,7 @@ class UserStoragesControllerTest extends StoragesControllerTest {
$response = $this->controller->update( $response = $this->controller->update(
1, 1,
'mount', 'mount',
$backendClass, '\OC\Files\Storage\SMB',
array(), array(),
[], [],
[], [],

View File

@ -1,104 +0,0 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @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/>
*
*/
require_once __DIR__ . '/../../../lib/base.php';
/**
* Class Test_Mount_Config_Dummy_Backend
*/
class Test_Mount_Config_Dummy_Backend {
public static $checkDependencies = true;
public static function checkDependencies() {
return self::$checkDependencies;
}
}
/**
* Class Test_Dynamic_Mount_Config
*/
class Test_Dynamic_Mount_Config extends \Test\TestCase {
private $backup;
public function testRegistration() {
// second registration shall return false
$result = OC_Mount_Config::registerBackend('Test_Mount_Config_Dummy_Backend', array(
'backend' => 'Test Dummy',
'configuration' => array(),
'has_dependencies' => true));
$this->assertTrue($result);
}
public function testDependencyGetBackend() {
// is the backend listed?
Test_Mount_Config_Dummy_Backend::$checkDependencies = true;
$backEnds = OC_Mount_Config::getBackends();
$this->assertArrayHasKey('Test_Mount_Config_Dummy_Backend', $backEnds);
// backend shall not be listed
Test_Mount_Config_Dummy_Backend::$checkDependencies = false;
$backEnds = OC_Mount_Config::getBackends();
$this->assertArrayNotHasKey('Test_Mount_Config_Dummy_Backend', $backEnds);
}
public function testCheckDependencies() {
Test_Mount_Config_Dummy_Backend::$checkDependencies = true;
$message = OC_Mount_Config::checkDependencies();
$this->assertEmpty($message);
// backend shall not be listed
Test_Mount_Config_Dummy_Backend::$checkDependencies = array('dummy');
$message = OC_Mount_Config::checkDependencies();
$this->assertEquals('<br /><b>Note:</b> "dummy" is not installed. Mounting of <i>Test Dummy</i> is not possible. Please ask your system administrator to install it.',
$message);
}
protected function setUp() {
parent::setUp();
$this->backup = OC_Mount_Config::setUp();
// register dummy backend
$result = OC_Mount_Config::registerBackend('Test_Mount_Config_Dummy_Backend', array(
'backend' => 'Test Dummy',
'configuration' => array(),
'has_dependencies' => true));
$this->assertTrue($result);
}
protected function tearDown()
{
OC_Mount_Config::setUp($this->backup);
parent::tearDown();
}
}

View File

@ -29,7 +29,7 @@ use \OCA\Files_external\Lib\StorageConfig;
class GlobalStoragesServiceTest extends StoragesServiceTest { class GlobalStoragesServiceTest extends StoragesServiceTest {
public function setUp() { public function setUp() {
parent::setUp(); parent::setUp();
$this->service = new GlobalStoragesService(); $this->service = new GlobalStoragesService($this->backendService);
} }
public function tearDown() { public function tearDown() {
@ -59,7 +59,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
return [ return [
// all users // all users
[ [
$this->makeStorageConfig([ [
'mountPoint' => 'mountpoint', 'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB', 'backendClass' => '\OC\Files\Storage\SMB',
'backendOptions' => [ 'backendOptions' => [
@ -70,11 +70,11 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
'applicableUsers' => [], 'applicableUsers' => [],
'applicableGroups' => [], 'applicableGroups' => [],
'priority' => 15, 'priority' => 15,
]), ],
], ],
// some users // some users
[ [
$this->makeStorageConfig([ [
'mountPoint' => 'mountpoint', 'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB', 'backendClass' => '\OC\Files\Storage\SMB',
'backendOptions' => [ 'backendOptions' => [
@ -85,11 +85,11 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
'applicableUsers' => ['user1', 'user2'], 'applicableUsers' => ['user1', 'user2'],
'applicableGroups' => [], 'applicableGroups' => [],
'priority' => 15, 'priority' => 15,
]), ],
], ],
// some groups // some groups
[ [
$this->makeStorageConfig([ [
'mountPoint' => 'mountpoint', 'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB', 'backendClass' => '\OC\Files\Storage\SMB',
'backendOptions' => [ 'backendOptions' => [
@ -100,11 +100,11 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
'applicableUsers' => [], 'applicableUsers' => [],
'applicableGroups' => ['group1', 'group2'], 'applicableGroups' => ['group1', 'group2'],
'priority' => 15, 'priority' => 15,
]), ],
], ],
// both users and groups // both users and groups
[ [
$this->makeStorageConfig([ [
'mountPoint' => 'mountpoint', 'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB', 'backendClass' => '\OC\Files\Storage\SMB',
'backendOptions' => [ 'backendOptions' => [
@ -115,7 +115,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
'applicableUsers' => ['user1', 'user2'], 'applicableUsers' => ['user1', 'user2'],
'applicableGroups' => ['group1', 'group2'], 'applicableGroups' => ['group1', 'group2'],
'priority' => 15, 'priority' => 15,
]), ],
], ],
]; ];
} }
@ -123,7 +123,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
/** /**
* @dataProvider storageDataProvider * @dataProvider storageDataProvider
*/ */
public function testAddStorage($storage) { public function testAddStorage($storageParams) {
$storage = $this->makeStorageConfig($storageParams);
$newStorage = $this->service->addStorage($storage); $newStorage = $this->service->addStorage($storage);
$this->assertEquals(1, $newStorage->getId()); $this->assertEquals(1, $newStorage->getId());
@ -132,7 +133,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$newStorage = $this->service->getStorage(1); $newStorage = $this->service->getStorage(1);
$this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint()); $this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint());
$this->assertEquals($storage->getBackendClass(), $newStorage->getBackendClass()); $this->assertEquals($storage->getBackend(), $newStorage->getBackend());
$this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions()); $this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions());
$this->assertEquals($storage->getApplicableUsers(), $newStorage->getApplicableUsers()); $this->assertEquals($storage->getApplicableUsers(), $newStorage->getApplicableUsers());
$this->assertEquals($storage->getApplicableGroups(), $newStorage->getApplicableGroups()); $this->assertEquals($storage->getApplicableGroups(), $newStorage->getApplicableGroups());
@ -148,7 +149,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
/** /**
* @dataProvider storageDataProvider * @dataProvider storageDataProvider
*/ */
public function testUpdateStorage($updatedStorage) { public function testUpdateStorage($updatedStorageParams) {
$updatedStorage = $this->makeStorageConfig($updatedStorageParams);
$storage = $this->makeStorageConfig([ $storage = $this->makeStorageConfig([
'mountPoint' => 'mountpoint', 'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB', 'backendClass' => '\OC\Files\Storage\SMB',

View File

@ -24,6 +24,7 @@ use \OC\Files\Filesystem;
use \OCA\Files_external\NotFoundException; use \OCA\Files_external\NotFoundException;
use \OCA\Files_external\Lib\StorageConfig; use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_External\Lib\BackendService;
abstract class StoragesServiceTest extends \Test\TestCase { abstract class StoragesServiceTest extends \Test\TestCase {
@ -32,6 +33,9 @@ abstract class StoragesServiceTest extends \Test\TestCase {
*/ */
protected $service; protected $service;
/** @var BackendService */
protected $backendService;
/** /**
* Data directory * Data directory
* *
@ -55,6 +59,25 @@ abstract class StoragesServiceTest extends \Test\TestCase {
); );
\OC_Mount_Config::$skipTest = true; \OC_Mount_Config::$skipTest = true;
$this->backendService =
$this->getMockBuilder('\OCA\Files_External\Service\BackendService')
->disableOriginalConstructor()
->getMock();
$backends = [
'\OC\Files\Storage\SMB' => $this->getBackendMock('\OCA\Files_External\Lib\Backend\SMB', '\OC\Files\Storage\SMB'),
'\OC\Files\Storage\SFTP' => $this->getBackendMock('\OCA\Files_External\Lib\Backend\SFTP', '\OC\Files\Storage\SFTP'),
];
$this->backendService->method('getBackend')
->will($this->returnCallback(function($backendClass) use ($backends) {
if (isset($backends[$backendClass])) {
return $backends[$backendClass];
}
return null;
}));
$this->backendService->method('getBackends')
->will($this->returnValue($backends));
\OCP\Util::connectHook( \OCP\Util::connectHook(
Filesystem::CLASSNAME, Filesystem::CLASSNAME,
Filesystem::signal_create_mount, Filesystem::signal_create_mount,
@ -71,6 +94,17 @@ abstract class StoragesServiceTest extends \Test\TestCase {
self::$hookCalls = array(); self::$hookCalls = array();
} }
protected function getBackendMock($class = '\OCA\Files_External\Lib\Backend\SMB', $storageClass = '\OC\Files\Storage\SMB') {
$backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
->disableOriginalConstructor()
->getMock();
$backend->method('getStorageClass')
->willReturn($storageClass);
$backend->method('getClass')
->willReturn($storageClass);
return $backend;
}
/** /**
* Creates a StorageConfig instance based on array data * Creates a StorageConfig instance based on array data
* *
@ -84,7 +118,12 @@ abstract class StoragesServiceTest extends \Test\TestCase {
$storage->setId($data['id']); $storage->setId($data['id']);
} }
$storage->setMountPoint($data['mountPoint']); $storage->setMountPoint($data['mountPoint']);
$storage->setBackendClass($data['backendClass']); if (!isset($data['backend'])) {
// data providers are run before $this->backendService is initialised
// so $data['backend'] can be specified directly
$data['backend'] = $this->backendService->getBackend($data['backendClass']);
}
$storage->setBackend($data['backend']);
$storage->setBackendOptions($data['backendOptions']); $storage->setBackendOptions($data['backendOptions']);
if (isset($data['applicableUsers'])) { if (isset($data['applicableUsers'])) {
$storage->setApplicableUsers($data['applicableUsers']); $storage->setApplicableUsers($data['applicableUsers']);
@ -106,16 +145,18 @@ abstract class StoragesServiceTest extends \Test\TestCase {
* @expectedException \OCA\Files_external\NotFoundException * @expectedException \OCA\Files_external\NotFoundException
*/ */
public function testNonExistingStorage() { public function testNonExistingStorage() {
$backend = $this->backendService->getBackend('\OC\Files\Storage\SMB');
$storage = new StorageConfig(255); $storage = new StorageConfig(255);
$storage->setMountPoint('mountpoint'); $storage->setMountPoint('mountpoint');
$storage->setBackendClass('\OC\Files\Storage\SMB'); $storage->setBackend($backend);
$this->service->updateStorage($storage); $this->service->updateStorage($storage);
} }
public function testDeleteStorage() { public function testDeleteStorage() {
$backend = $this->backendService->getBackend('\OC\Files\Storage\SMB');
$storage = new StorageConfig(255); $storage = new StorageConfig(255);
$storage->setMountPoint('mountpoint'); $storage->setMountPoint('mountpoint');
$storage->setBackendClass('\OC\Files\Storage\SMB'); $storage->setBackend($backend);
$storage->setBackendOptions(['password' => 'testPassword']); $storage->setBackendOptions(['password' => 'testPassword']);
$newStorage = $this->service->addStorage($storage); $newStorage = $this->service->addStorage($storage);

View File

@ -40,7 +40,7 @@ class UserStoragesServiceTest extends StoragesServiceTest {
->method('getUser') ->method('getUser')
->will($this->returnValue($this->user)); ->will($this->returnValue($this->user));
$this->service = new UserStoragesService($userSession); $this->service = new UserStoragesService($this->backendService, $userSession);
// create home folder // create home folder
mkdir($this->dataDir . '/' . $this->userId . '/'); mkdir($this->dataDir . '/' . $this->userId . '/');
@ -76,7 +76,7 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$newStorage = $this->service->getStorage(1); $newStorage = $this->service->getStorage(1);
$this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint()); $this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint());
$this->assertEquals($storage->getBackendClass(), $newStorage->getBackendClass()); $this->assertEquals($storage->getBackend(), $newStorage->getBackend());
$this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions()); $this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions());
$this->assertEquals(1, $newStorage->getId()); $this->assertEquals(1, $newStorage->getId());
$this->assertEquals(0, $newStorage->getStatus()); $this->assertEquals(0, $newStorage->getStatus());

View File

@ -26,9 +26,15 @@ use \OCA\Files_external\Lib\StorageConfig;
class StorageConfigTest extends \Test\TestCase { class StorageConfigTest extends \Test\TestCase {
public function testJsonSerialization() { public function testJsonSerialization() {
$backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
->disableOriginalConstructor()
->getMock();
$backend->method('getClass')
->willReturn('\OC\Files\Storage\SMB');
$storageConfig = new StorageConfig(1); $storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('test'); $storageConfig->setMountPoint('test');
$storageConfig->setBackendClass('\OC\Files\Storage\SMB'); $storageConfig->setBackend($backend);
$storageConfig->setBackendOptions(['user' => 'test', 'password' => 'password123']); $storageConfig->setBackendOptions(['user' => 'test', 'password' => 'password123']);
$storageConfig->setPriority(128); $storageConfig->setPriority(128);
$storageConfig->setApplicableUsers(['user1', 'user2']); $storageConfig->setApplicableUsers(['user1', 'user2']);