Merge pull request #15914 from owncloud/ext-backend-register

Introduce BackendService for managing external storage backends
This commit is contained in:
Morris Jobke 2015-08-19 14:15:27 +02:00
commit a9bb6be019
55 changed files with 4257 additions and 2205 deletions

View file

@ -30,9 +30,6 @@
* 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\FTP'] = 'files_external/lib/ftp.php';
@ -50,6 +47,12 @@ OC::$CLASSPATH['OCA\Files\External\Api'] = 'files_external/lib/api.php';
require_once __DIR__ . '/../3rdparty/autoload.php';
// register Application object singleton
\OC_Mount_Config::$app = new \OCA\Files_external\Appinfo\Application();
$appContainer = \OC_Mount_Config::$app->getContainer();
$l = \OC::$server->getL10N('files_external');
OCP\App::registerAdmin('files_external', 'settings');
if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == 'yes') {
OCP\App::registerPersonal('files_external', 'personal');
@ -74,6 +77,10 @@ OC_Mount_Config::registerBackend('\OC\Files\Storage\Local', [
'datadir' => (string)$l->t('Location')
],
]);
// Local must only be visible to the admin
$appContainer->query('OCA\Files_External\Service\BackendService')
->getBackend('\OC\Files\Storage\Local')
->setAllowedVisibility(\OCA\Files_External\Service\BackendService::VISIBILITY_ADMIN);
OC_Mount_Config::registerBackend('\OC\Files\Storage\AmazonS3', [
'backend' => (string)$l->t('Amazon S3'),
@ -237,5 +244,5 @@ OC_Mount_Config::registerBackend('\OC\Files\Storage\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);

View file

@ -3,6 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Ross Nicoll <jrn@jrn.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
* @author Robin McCorkell <rmccorkell@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
@ -26,6 +27,9 @@ namespace OCA\Files_External\AppInfo;
use \OCA\Files_External\Controller\AjaxController;
use \OCP\AppFramework\App;
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
@ -45,5 +49,33 @@ class Application extends App {
$c->query('Request')
);
});
$this->loadBackends();
$this->loadAuthMechanisms();
}
/**
* Load storage backends provided by this app
*/
protected function loadBackends() {
$container = $this->getContainer();
$service = $container->query('OCA\\Files_External\\Service\\BackendService');
}
/**
* Load authentication mechanisms provided by this app
*/
protected function loadAuthMechanisms() {
$container = $this->getContainer();
$service = $container->query('OCA\\Files_External\\Service\\BackendService');
$service->registerAuthMechanisms([
// AuthMechanism::SCHEME_NULL mechanism
$container->query('OCA\Files_External\Lib\Auth\NullMechanism'),
// AuthMechanism::SCHEME_BUILTIN mechanism
$container->query('OCA\Files_External\Lib\Auth\Builtin'),
]);
}
}

View file

@ -28,8 +28,7 @@ namespace OCA\Files_External\AppInfo;
/**
* @var $this \OC\Route\Router
**/
$application = new Application();
$application->registerRoutes(
\OC_Mount_Config::$app->registerRoutes(
$this,
array(
'resources' => array(

View file

@ -63,7 +63,8 @@ class GlobalStoragesController extends StoragesController {
* Create an external storage entry.
*
* @param string $mountPoint storage mount point
* @param string $backendClass backend class name
* @param string $backend backend identifier
* @param string $authMechanism authentication mechanism identifier
* @param array $backendOptions backend-specific options
* @param array $mountOptions mount-specific options
* @param array $applicableUsers users for which to mount the storage
@ -74,21 +75,27 @@ class GlobalStoragesController extends StoragesController {
*/
public function create(
$mountPoint,
$backendClass,
$backend,
$authMechanism,
$backendOptions,
$mountOptions,
$applicableUsers,
$applicableGroups,
$priority
) {
$newStorage = new StorageConfig();
$newStorage->setMountPoint($mountPoint);
$newStorage->setBackendClass($backendClass);
$newStorage->setBackendOptions($backendOptions);
$newStorage->setMountOptions($mountOptions);
$newStorage->setApplicableUsers($applicableUsers);
$newStorage->setApplicableGroups($applicableGroups);
$newStorage->setPriority($priority);
$newStorage = $this->createStorage(
$mountPoint,
$backend,
$authMechanism,
$backendOptions,
$mountOptions,
$applicableUsers,
$applicableGroups,
$priority
);
if ($newStorage instanceof DataResponse) {
return $newStorage;
}
$response = $this->validate($newStorage);
if (!empty($response)) {
@ -110,7 +117,8 @@ class GlobalStoragesController extends StoragesController {
*
* @param int $id storage id
* @param string $mountPoint storage mount point
* @param string $backendClass backend class name
* @param string $backend backend identifier
* @param string $authMechanism authentication mechansim identifier
* @param array $backendOptions backend-specific options
* @param array $mountOptions mount-specific options
* @param array $applicableUsers users for which to mount the storage
@ -122,21 +130,28 @@ class GlobalStoragesController extends StoragesController {
public function update(
$id,
$mountPoint,
$backendClass,
$backend,
$authMechanism,
$backendOptions,
$mountOptions,
$applicableUsers,
$applicableGroups,
$priority
) {
$storage = new StorageConfig($id);
$storage->setMountPoint($mountPoint);
$storage->setBackendClass($backendClass);
$storage->setBackendOptions($backendOptions);
$storage->setMountOptions($mountOptions);
$storage->setApplicableUsers($applicableUsers);
$storage->setApplicableGroups($applicableGroups);
$storage->setPriority($priority);
$storage = $this->createStorage(
$mountPoint,
$backend,
$authMechanism,
$backendOptions,
$mountOptions,
$applicableUsers,
$applicableGroups,
$priority
);
if ($storage instanceof DataResponse) {
return $storage;
}
$storage->setId($id);
$response = $this->validate($storage);
if (!empty($response)) {

View file

@ -32,6 +32,10 @@ use \OCP\AppFramework\Http;
use \OCA\Files_external\Service\StoragesService;
use \OCA\Files_external\NotFoundException;
use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_External\Lib\Backend\Backend;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
use \OCP\Files\StorageNotAvailableException;
use \OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
/**
* Base class for storages controllers
@ -71,6 +75,51 @@ abstract class StoragesController extends Controller {
$this->service = $storagesService;
}
/**
* Create a storage from its parameters
*
* @param string $mountPoint storage mount point
* @param string $backend backend identifier
* @param string $authMechanism authentication mechanism identifier
* @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,
$backend,
$authMechanism,
$backendOptions,
$mountOptions = null,
$applicableUsers = null,
$applicableGroups = null,
$priority = null
) {
try {
return $this->service->createStorage(
$mountPoint,
$backend,
$authMechanism,
$backendOptions,
$mountOptions,
$applicableUsers,
$applicableGroups,
$priority
);
} catch (\InvalidArgumentException $e) {
return new DataResponse(
[
'message' => (string)$this->l10n->t('Invalid backend or authentication mechanism class')
],
Http::STATUS_UNPROCESSABLE_ENTITY
);
}
}
/**
* Validate storage config
*
@ -89,18 +138,39 @@ abstract class StoragesController extends Controller {
);
}
// TODO: validate that other attrs are set
$backends = \OC_Mount_Config::getBackends();
if (!isset($backends[$storage->getBackendClass()])) {
/** @var Backend */
$backend = $storage->getBackend();
/** @var AuthMechanism */
$authMechanism = $storage->getAuthMechanism();
if (!$backend || $backend->checkDependencies()) {
// invalid backend
return new DataResponse(
array(
'message' => (string)$this->l10n->t('Invalid storage backend "%s"', array($storage->getBackendClass()))
'message' => (string)$this->l10n->t('Invalid storage backend "%s"', [
$storage->getBackend()->getIdentifier()
])
),
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
);
}
if (!$authMechanism->validateStorage($storage)) {
// unsatisfied parameters
return new DataResponse(
[
'message' => (string)$this->l10n->t('Unsatisfied authentication mechanism parameters')
],
Http::STATUS_UNPROCESSABLE_ENTITY
);
}
return null;
}
@ -114,14 +184,27 @@ abstract class StoragesController extends Controller {
* @param StorageConfig $storage storage configuration
*/
protected function updateStorageStatus(StorageConfig &$storage) {
// update status (can be time-consuming)
$storage->setStatus(
\OC_Mount_Config::getBackendStatus(
$storage->getBackendClass(),
$storage->getBackendOptions(),
false
)
);
try {
/** @var AuthMechanism */
$authMechanism = $storage->getAuthMechanism();
$authMechanism->manipulateStorageConfig($storage);
/** @var Backend */
$backend = $storage->getBackend();
$backend->manipulateStorageConfig($storage);
// update status (can be time-consuming)
$storage->setStatus(
\OC_Mount_Config::getBackendStatus(
$backend->getStorageClass(),
$storage->getBackendOptions(),
false
)
);
} catch (InsufficientDataForMeaningfulAnswerException $e) {
$storage->setStatus(\OC_Mount_Config::STATUS_INDETERMINATE);
} catch (StorageNotAvailableException $e) {
$storage->setStatus(\OC_Mount_Config::STATUS_ERROR);
}
}
/**

View file

@ -30,8 +30,10 @@ use \OCP\AppFramework\Http\DataResponse;
use \OCP\AppFramework\Controller;
use \OCP\AppFramework\Http;
use \OCA\Files_external\Service\UserStoragesService;
use \OCA\Files_External\Service\BackendService;
use \OCA\Files_external\NotFoundException;
use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_External\Lib\Backend\Backend;
/**
* User storages controller
@ -69,17 +71,20 @@ class UserStoragesController extends StoragesController {
protected function validate(StorageConfig $storage) {
$result = parent::validate($storage);
if ($result != null) {
if ($result !== null) {
return $result;
}
// Verify that the mount point applies for the current user
// Prevent non-admin users from mounting local storage and other disabled backends
$allowedBackends = \OC_Mount_Config::getPersonalBackends();
if (!isset($allowedBackends[$storage->getBackendClass()])) {
/** @var Backend */
$backend = $storage->getBackend();
if (!$backend->isVisibleFor(BackendService::VISIBILITY_PERSONAL)) {
return new DataResponse(
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()->getIdentifier()
])
),
Http::STATUS_UNPROCESSABLE_ENTITY
);
@ -103,7 +108,8 @@ class UserStoragesController extends StoragesController {
* Create an external storage entry.
*
* @param string $mountPoint storage mount point
* @param string $backendClass backend class name
* @param string $backend backend identifier
* @param string $authMechanism authentication mechanism identifier
* @param array $backendOptions backend-specific options
* @param array $mountOptions backend-specific mount options
*
@ -113,15 +119,21 @@ class UserStoragesController extends StoragesController {
*/
public function create(
$mountPoint,
$backendClass,
$backend,
$authMechanism,
$backendOptions,
$mountOptions
) {
$newStorage = new StorageConfig();
$newStorage->setMountPoint($mountPoint);
$newStorage->setBackendClass($backendClass);
$newStorage->setBackendOptions($backendOptions);
$newStorage->setMountOptions($mountOptions);
$newStorage = $this->createStorage(
$mountPoint,
$backend,
$authMechanism,
$backendOptions,
$mountOptions
);
if ($newStorage instanceOf DataResponse) {
return $newStorage;
}
$response = $this->validate($newStorage);
if (!empty($response)) {
@ -142,7 +154,8 @@ class UserStoragesController extends StoragesController {
*
* @param int $id storage id
* @param string $mountPoint storage mount point
* @param string $backendClass backend class name
* @param string $backend backend identifier
* @param string $authMechanism authentication mechanism identifier
* @param array $backendOptions backend-specific options
* @param array $mountOptions backend-specific mount options
*
@ -153,15 +166,22 @@ class UserStoragesController extends StoragesController {
public function update(
$id,
$mountPoint,
$backendClass,
$backend,
$authMechanism,
$backendOptions,
$mountOptions
) {
$storage = new StorageConfig($id);
$storage->setMountPoint($mountPoint);
$storage->setBackendClass($backendClass);
$storage->setBackendOptions($backendOptions);
$storage->setMountOptions($mountOptions);
$storage = $this->createStorage(
$mountPoint,
$backend,
$authMechanism,
$backendOptions,
$mountOptions
);
if ($storage instanceOf DataResponse) {
return $storage;
}
$storage->setId($id);
$response = $this->validate($storage);
if (!empty($response)) {

View file

@ -191,7 +191,8 @@ var StorageConfig = function(id) {
StorageConfig.Status = {
IN_PROGRESS: -1,
SUCCESS: 0,
ERROR: 1
ERROR: 1,
INDETERMINATE: 2
};
/**
* @memberof OCA.External.Settings
@ -214,11 +215,18 @@ StorageConfig.prototype = {
mountPoint: '',
/**
* Backend class name
* Backend
*
* @type string
*/
backendClass: null,
backend: null,
/**
* Authentication mechanism
*
* @type string
*/
authMechanism: null,
/**
* Backend-specific configuration
@ -272,7 +280,8 @@ StorageConfig.prototype = {
getData: function() {
var data = {
mountPoint: this.mountPoint,
backendClass: this.backendClass,
backend: this.backend,
authMechanism: this.authMechanism,
backendOptions: this.backendOptions
};
if (this.id) {
@ -579,6 +588,13 @@ MountConfigListView.prototype = {
*/
_allBackends: null,
/**
* List of all supported authentication mechanisms
*
* @type Object.<string,Object>
*/
_allAuthMechanisms: null,
_encryptionEnabled: false,
/**
@ -605,6 +621,7 @@ MountConfigListView.prototype = {
// read the backend config that was carefully crammed
// into the data-configurations attribute of the select
this._allBackends = this.$el.find('.selectBackend').data('configurations');
this._allAuthMechanisms = this.$el.find('#addMountPoint .authentication').data('mechanisms');
//initialize hidden input field with list of users and groups
this.$el.find('tr:not(#addMountPoint)').each(function(i,tr) {
@ -660,6 +677,7 @@ MountConfigListView.prototype = {
});
this.$el.on('change', '.selectBackend', _.bind(this._onSelectBackend, this));
this.$el.on('change', '.selectAuthMechanism', _.bind(this._onSelectAuthMechanism, this));
},
_onChange: function(event) {
@ -687,47 +705,34 @@ MountConfigListView.prototype = {
$el.find('tbody').append($tr.clone());
$el.find('tbody tr').last().find('.mountPoint input').val('');
var selected = $target.find('option:selected').text();
var backendClass = $target.val();
var backend = $target.val();
$tr.find('.backend').text(selected);
if ($tr.find('.mountPoint input').val() === '') {
$tr.find('.mountPoint input').val(this._suggestMountPoint(selected));
}
$tr.addClass(backendClass);
$tr.find('.backend').data('class', backendClass);
var configurations = this._allBackends;
var $td = $tr.find('td.configuration');
$.each(configurations, function(backend, parameters) {
if (backend === backendClass) {
$.each(parameters['configuration'], function(parameter, placeholder) {
var is_optional = false;
if (placeholder.indexOf('&') === 0) {
is_optional = true;
placeholder = placeholder.substring(1);
}
var newElement;
if (placeholder.indexOf('*') === 0) {
var class_string = is_optional ? ' optional' : '';
newElement = $('<input type="password" class="added' + class_string + '" data-parameter="'+parameter+'" placeholder="'+placeholder.substring(1)+'" />');
} else if (placeholder.indexOf('!') === 0) {
newElement = $('<label><input type="checkbox" class="added" data-parameter="'+parameter+'" />'+placeholder.substring(1)+'</label>');
} else if (placeholder.indexOf('#') === 0) {
newElement = $('<input type="hidden" class="added" data-parameter="'+parameter+'" />');
} else {
var class_string = is_optional ? ' optional' : '';
newElement = $('<input type="text" class="added' + class_string + '" data-parameter="'+parameter+'" placeholder="'+placeholder+'" />');
}
highlightInput(newElement);
$td.append(newElement);
});
var priorityEl = $('<input type="hidden" class="priority" value="' + parameters['priority'] + '" />');
$tr.append(priorityEl);
if (parameters['custom'] && $el.find('tbody tr.'+backendClass.replace(/\\/g, '\\\\')).length === 1) {
OC.addScript('files_external', parameters['custom']);
}
$td.children().not('[type=hidden]').first().focus();
return false;
$tr.addClass(backend);
$tr.find('.backend').data('class', backend);
var backendConfiguration = this._allBackends[backend];
var selectAuthMechanism = $('<select class="selectAuthMechanism"></select>');
$.each(this._allAuthMechanisms, function(authClass, authMechanism) {
if (backendConfiguration['authSchemes'][authMechanism['scheme']]) {
selectAuthMechanism.append(
$('<option value="'+authClass+'" data-scheme="'+authMechanism['scheme']+'">'+authMechanism['name']+'</option>')
);
}
});
$tr.find('td.authentication').append(selectAuthMechanism);
var $td = $tr.find('td.configuration');
$.each(backendConfiguration['configuration'], _.partial(this.writeParameterInput, $td));
selectAuthMechanism.trigger('change'); // generate configuration parameters for auth mechanism
var priorityEl = $('<input type="hidden" class="priority" value="' + backendConfiguration['priority'] + '" />');
$tr.append(priorityEl);
$td.children().not('[type=hidden]').first().focus();
$tr.find('td').last().attr('class', 'remove');
$tr.find('td.mountOptionsToggle').removeClass('hidden');
$tr.find('td').last().removeAttr('style');
@ -736,6 +741,41 @@ MountConfigListView.prototype = {
addSelect2($tr.find('.applicableUsers'), this._userListLimit);
},
_onSelectAuthMechanism: function(event) {
var $target = $(event.target);
var $tr = $target.closest('tr');
var authMechanism = $target.val();
var authMechanismConfiguration = this._allAuthMechanisms[authMechanism];
var $td = $tr.find('td.configuration');
$td.find('.auth-param').remove();
$.each(authMechanismConfiguration['configuration'], _.partial(
this.writeParameterInput, $td, _, _, ['auth-param']
));
},
writeParameterInput: function($td, parameter, placeholder, classes) {
classes = $.isArray(classes) ? classes : [];
classes.push('added');
if (placeholder.indexOf('&') === 0) {
classes.push('optional');
placeholder = placeholder.substring(1);
}
var newElement;
if (placeholder.indexOf('*') === 0) {
newElement = $('<input type="password" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" placeholder="'+placeholder.substring(1)+'" />');
} else if (placeholder.indexOf('!') === 0) {
newElement = $('<label><input type="checkbox" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" />'+placeholder.substring(1)+'</label>');
} else if (placeholder.indexOf('#') === 0) {
newElement = $('<input type="hidden" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" />');
} else {
newElement = $('<input type="text" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" placeholder="'+placeholder+'" />');
}
highlightInput(newElement);
$td.append(newElement);
},
/**
* Gets the storage model from the given row
*
@ -750,7 +790,8 @@ MountConfigListView.prototype = {
}
var storage = new this._storageConfigClass(storageId);
storage.mountPoint = $tr.find('.mountPoint input').val();
storage.backendClass = $tr.find('.backend').data('class');
storage.backend = $tr.find('.backend').data('class');
storage.authMechanism = $tr.find('.selectAuthMechanism').val();
var classOptions = {};
var configuration = $tr.find('.configuration input');
@ -903,7 +944,7 @@ MountConfigListView.prototype = {
*/
updateStatus: function($tr, status) {
var $statusSpan = $tr.find('.status span');
$statusSpan.removeClass('success error loading-small');
$statusSpan.removeClass('loading-small success indeterminate error');
switch (status) {
case StorageConfig.Status.IN_PROGRESS:
$statusSpan.addClass('loading-small');
@ -911,6 +952,9 @@ MountConfigListView.prototype = {
case StorageConfig.Status.SUCCESS:
$statusSpan.addClass('success');
break;
case StorageConfig.Status.INDETERMINATE:
$statusSpan.addClass('indeterminate');
break;
default:
$statusSpan.addClass('error');
}

View file

@ -0,0 +1,116 @@
<?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\Auth;
use \OCA\Files_External\Lib\StorageConfig;
use \OCA\Files_External\Lib\VisibilityTrait;
use \OCA\Files_External\Lib\IdentifierTrait;
use \OCA\Files_External\Lib\FrontendDefinitionTrait;
use \OCA\Files_External\Lib\StorageModifierTrait;
/**
* Authentication mechanism
*
* An authentication mechanism can have services injected during construction,
* such as \OCP\IDB for database operations. This allows an authentication
* mechanism to perform advanced operations based on provided information.
*
* An authenication scheme defines the parameter interface, common to the
* storage implementation, the backend and the authentication mechanism.
* A storage implementation expects parameters according to the authentication
* scheme, which are provided from the authentication mechanism.
*
* This class uses the following traits:
* - VisibilityTrait
* Restrict usage to admin-only/none
* - FrontendDefinitionTrait
* Specify configuration parameters and other definitions
* - StorageModifierTrait
* Object can affect storage mounting
*/
class AuthMechanism implements \JsonSerializable {
/** Standard authentication schemes */
const SCHEME_NULL = 'null';
const SCHEME_BUILTIN = 'builtin';
const SCHEME_PASSWORD = 'password';
const SCHEME_OAUTH1 = 'oauth1';
const SCHEME_OAUTH2 = 'oauth2';
const SCHEME_PUBLICKEY = 'publickey';
const SCHEME_OPENSTACK = 'openstack';
use VisibilityTrait;
use FrontendDefinitionTrait;
use StorageModifierTrait;
use IdentifierTrait;
/** @var string */
protected $scheme;
/**
* Get the authentication scheme implemented
* See self::SCHEME_* constants
*
* @return string
*/
public function getScheme() {
return $this->scheme;
}
/**
* @param string $scheme
* @return self
*/
public function setScheme($scheme) {
$this->scheme = $scheme;
return $this;
}
/**
* Serialize into JSON for client-side JS
*
* @return array
*/
public function jsonSerialize() {
$data = $this->jsonSerializeDefinition();
$data['scheme'] = $this->getScheme();
return $data;
}
/**
* Check if parameters are satisfied in a StorageConfig
*
* @param StorageConfig $storage
* @return bool
*/
public function validateStorage(StorageConfig $storage) {
// does the backend actually support this scheme
$supportedSchemes = $storage->getBackend()->getAuthSchemes();
if (!isset($supportedSchemes[$this->getScheme()])) {
return false;
}
return $this->validateStorageDefinition($storage);
}
}

View file

@ -0,0 +1,41 @@
<?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\Auth;
use \OCP\IL10N;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
use \OCA\Files_external\Lib\StorageConfig;
/**
* Builtin authentication mechanism, for legacy backends
*/
class Builtin extends AuthMechanism {
public function __construct(IL10N $l) {
$this
->setIdentifier('builtin::builtin')
->setScheme(self::SCHEME_BUILTIN)
->setText($l->t('Builtin'))
;
}
}

View file

@ -0,0 +1,41 @@
<?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\Auth;
use \OCP\IL10N;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
use \OCA\Files_external\Lib\StorageConfig;
/**
* Null authentication mechanism
*/
class NullMechanism extends AuthMechanism {
public function __construct(IL10N $l) {
$this
->setIdentifier('null::null')
->setScheme(self::SCHEME_NULL)
->setText($l->t('None'))
;
}
}

View file

@ -0,0 +1,164 @@
<?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;
use \OCA\Files_External\Lib\IdentifierTrait;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
/**
* Storage backend
*
* A backend can have services injected during construction,
* such as \OCP\IDB for database operations. This allows a backend
* to perform advanced operations based on provided information.
*
* An authenication scheme defines the parameter interface, common to the
* storage implementation, the backend and the authentication mechanism.
* A storage implementation expects parameters according to the authentication
* scheme, which are provided from the authentication mechanism.
*
* This class uses the following traits:
* - VisibilityTrait
* Restrict usage to admin-only/none
* - FrontendDefinitionTrait
* Specify configuration parameters and other definitions
* - PriorityTrait
* Allow objects to prioritize over others with the same mountpoint
* - DependencyTrait
* The object requires certain dependencies to be met
* - StorageModifierTrait
* Object can affect storage mounting
*/
class Backend implements \JsonSerializable {
use VisibilityTrait;
use FrontendDefinitionTrait;
use PriorityTrait;
use DependencyTrait;
use StorageModifierTrait;
use IdentifierTrait;
/** @var string storage class */
private $storageClass;
/** @var array 'scheme' => true, supported authentication schemes */
private $authSchemes = [];
/** @var AuthMechanism|callable authentication mechanism fallback */
private $legacyAuthMechanism;
/**
* @return string
*/
public function getStorageClass() {
return $this->storageClass;
}
/**
* @param string $class
* @return self
*/
public function setStorageClass($class) {
$this->storageClass = $class;
return $this;
}
/**
* @return array
*/
public function getAuthSchemes() {
if (empty($this->authSchemes)) {
return [AuthMechanism::SCHEME_NULL => true];
}
return $this->authSchemes;
}
/**
* @param string $scheme
* @return self
*/
public function addAuthScheme($scheme) {
$this->authSchemes[$scheme] = true;
return $this;
}
/**
* @param array $parameters storage parameters, for dynamic mechanism selection
* @return AuthMechanism
*/
public function getLegacyAuthMechanism(array $parameters = []) {
if (is_callable($this->legacyAuthMechanism)) {
return call_user_func($this->legacyAuthMechanism, $parameters);
}
return $this->legacyAuthMechanism;
}
/**
* @param AuthMechanism $authMechanism
* @return self
*/
public function setLegacyAuthMechanism(AuthMechanism $authMechanism) {
$this->legacyAuthMechanism = $authMechanism;
return $this;
}
/**
* @param callable $callback dynamic auth mechanism selection
* @return self
*/
public function setLegacyAuthMechanismCallback(callable $callback) {
$this->legacyAuthMechanism = $callback;
}
/**
* 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();
$data['authSchemes'] = $this->getAuthSchemes();
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

@ -0,0 +1,85 @@
<?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\DefinitionParameter;
use \OCA\Files_External\Lib\Backend\Backend;
use \OCA\Files_External\Lib\Auth\Builtin;
/**
* Legacy compatibility for OC_Mount_Config::registerBackend()
*/
class LegacyBackend extends Backend {
/**
* @param string $class
* @param array $definition
* @param Builtin $authMechanism
*/
public function __construct($class, array $definition, Builtin $authMechanism) {
$this
->setIdentifier($class)
->setStorageClass($class)
->setText($definition['backend'])
->addAuthScheme(Builtin::SCHEME_BUILTIN)
->setLegacyAuthMechanism($authMechanism)
;
foreach ($definition['configuration'] as $name => $placeholder) {
$flags = DefinitionParameter::FLAG_NONE;
$type = DefinitionParameter::VALUE_TEXT;
if ($placeholder[0] === '&') {
$flags = DefinitionParameter::FLAG_OPTIONAL;
$placeholder = substr($placeholder, 1);
}
switch ($placeholder[0]) {
case '!':
$type = DefinitionParameter::VALUE_BOOLEAN;
$placeholder = substr($placeholder, 1);
break;
case '*':
$type = DefinitionParameter::VALUE_PASSWORD;
$placeholder = substr($placeholder, 1);
break;
case '#':
$type = DefinitionParameter::VALUE_HIDDEN;
$placeholder = substr($placeholder, 1);
break;
}
$this->addParameter((new DefinitionParameter($name, $placeholder))
->setType($type)
->setFlags($flags)
);
}
if (isset($definition['priority'])) {
$this->setPriority($definition['priority']);
}
if (isset($definition['custom'])) {
$this->setCustomJs($definition['custom']);
}
if (isset($definition['has_dependencies']) && $definition['has_dependencies']) {
$this->setDependencyCheck($class . '::checkDependencies');
}
}
}

View file

@ -32,6 +32,11 @@
*/
use phpseclib\Crypt\AES;
use \OCA\Files_External\Appinfo\Application;
use \OCA\Files_External\Lib\BackendConfig;
use \OCA\Files_External\Service\BackendService;
use \OCA\Files_External\Lib\Backend\LegacyBackend;
use \OCA\Files_External\Lib\StorageConfig;
/**
* Class to configure mount.json globally and for users
@ -47,75 +52,30 @@ class OC_Mount_Config {
// getBackendStatus return types
const STATUS_SUCCESS = 0;
const STATUS_ERROR = 1;
const STATUS_INDETERMINATE = 2;
// whether to skip backend test (for unit tests, as this static class is not mockable)
public static $skipTest = false;
private static $backends = array();
/** @var Application */
public static $app;
/**
* @param string $class
* @param array $definition
* @return bool
* @deprecated 8.2.0 use \OCA\Files_External\Service\BackendService::registerBackend()
*/
public static function registerBackend($class, $definition) {
if (!isset($definition['backend'])) {
return false;
}
$backendService = self::$app->getContainer()->query('OCA\Files_External\Service\BackendService');
$auth = self::$app->getContainer()->query('OCA\Files_External\Lib\Auth\Builtin');
$backendService->registerBackend(new LegacyBackend($class, $definition, $auth));
OC_Mount_Config::$backends[$class] = $definition;
return true;
}
/**
* Setup backends
*
* @return array of previously registered backends
*/
public static function setUp($backends = array()) {
$backup = self::$backends;
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
*
* @param array $data
@ -152,138 +112,106 @@ class OC_Mount_Config {
* Returns the mount points for the given user.
* The mount point is relative to the data directory.
*
* @param string $user user
* @param string $uid user
* @return array of mount point string as key, mountpoint config as value
*
* @deprecated 8.2.0 use UserGlobalStoragesService::getAllStorages() and UserStoragesService::getAllStorages()
*/
public static function getAbsoluteMountPoints($user) {
public static function getAbsoluteMountPoints($uid) {
$mountPoints = array();
$backends = self::getBackends();
$userGlobalStoragesService = self::$app->getContainer()->query('OCA\Files_External\Service\UserGlobalStoragesService');
$userStoragesService = self::$app->getContainer()->query('OCA\Files_External\Service\UserStoragesService');
$user = self::$app->getContainer()->query('OCP\IUserManager')->get($uid);
// Load system mount points
$mountConfig = self::readData();
$userGlobalStoragesService->setUser($user);
$userStoragesService->setUser($user);
// Global mount points (is this redundant?)
if (isset($mountConfig[self::MOUNT_TYPE_GLOBAL])) {
foreach ($mountConfig[self::MOUNT_TYPE_GLOBAL] as $mountPoint => $options) {
$options['personal'] = false;
$options['options'] = self::decryptPasswords($options['options']);
if (!isset($options['priority'])) {
$options['priority'] = $backends[$options['class']]['priority'];
}
// Override if priority greater
if ((!isset($mountPoints[$mountPoint]))
|| ($options['priority'] >= $mountPoints[$mountPoint]['priority'])
) {
$options['priority_type'] = self::MOUNT_TYPE_GLOBAL;
$options['backend'] = $backends[$options['class']]['backend'];
$mountPoints[$mountPoint] = $options;
}
}
}
// All user mount points
if (isset($mountConfig[self::MOUNT_TYPE_USER]) && isset($mountConfig[self::MOUNT_TYPE_USER]['all'])) {
$mounts = $mountConfig[self::MOUNT_TYPE_USER]['all'];
foreach ($mounts as $mountPoint => $options) {
$mountPoint = self::setUserVars($user, $mountPoint);
foreach ($options as &$option) {
$option = self::setUserVars($user, $option);
}
$options['personal'] = false;
$options['options'] = self::decryptPasswords($options['options']);
if (!isset($options['priority'])) {
$options['priority'] = $backends[$options['class']]['priority'];
}
// Override if priority greater
if ((!isset($mountPoints[$mountPoint]))
|| ($options['priority'] >= $mountPoints[$mountPoint]['priority'])
) {
$options['priority_type'] = self::MOUNT_TYPE_GLOBAL;
$options['backend'] = $backends[$options['class']]['backend'];
$mountPoints[$mountPoint] = $options;
}
}
}
// Group mount points
if (isset($mountConfig[self::MOUNT_TYPE_GROUP])) {
foreach ($mountConfig[self::MOUNT_TYPE_GROUP] as $group => $mounts) {
if (\OC_Group::inGroup($user, $group)) {
foreach ($mounts as $mountPoint => $options) {
$mountPoint = self::setUserVars($user, $mountPoint);
foreach ($options as &$option) {
$option = self::setUserVars($user, $option);
}
$options['personal'] = false;
$options['options'] = self::decryptPasswords($options['options']);
if (!isset($options['priority'])) {
$options['priority'] = $backends[$options['class']]['priority'];
}
// Override if priority greater or if priority type different
if ((!isset($mountPoints[$mountPoint]))
|| ($options['priority'] >= $mountPoints[$mountPoint]['priority'])
|| ($mountPoints[$mountPoint]['priority_type'] !== self::MOUNT_TYPE_GROUP)
) {
$options['priority_type'] = self::MOUNT_TYPE_GROUP;
$options['backend'] = $backends[$options['class']]['backend'];
$mountPoints[$mountPoint] = $options;
}
}
}
}
}
// User mount points
if (isset($mountConfig[self::MOUNT_TYPE_USER])) {
foreach ($mountConfig[self::MOUNT_TYPE_USER] as $mountUser => $mounts) {
if (strtolower($mountUser) === strtolower($user)) {
foreach ($mounts as $mountPoint => $options) {
$mountPoint = self::setUserVars($user, $mountPoint);
foreach ($options as &$option) {
$option = self::setUserVars($user, $option);
}
$options['personal'] = false;
$options['options'] = self::decryptPasswords($options['options']);
if (!isset($options['priority'])) {
$options['priority'] = $backends[$options['class']]['priority'];
}
// Override if priority greater or if priority type different
if ((!isset($mountPoints[$mountPoint]))
|| ($options['priority'] >= $mountPoints[$mountPoint]['priority'])
|| ($mountPoints[$mountPoint]['priority_type'] !== self::MOUNT_TYPE_USER)
) {
$options['priority_type'] = self::MOUNT_TYPE_USER;
$options['backend'] = $backends[$options['class']]['backend'];
$mountPoints[$mountPoint] = $options;
}
}
}
foreach ($userGlobalStoragesService->getAllStorages() as $storage) {
$mountPoint = '/'.$uid.'/files'.$storage->getMountPoint();
$mountEntry = self::prepareMountPointEntry($storage, false);
foreach ($mountEntry['options'] as &$option) {
$option = self::setUserVars($uid, $option);
}
$mountPoints[$mountPoint] = $mountEntry;
}
$personalBackends = self::getPersonalBackends();
// Load personal mount points
$mountConfig = self::readData($user);
if (isset($mountConfig[self::MOUNT_TYPE_USER][$user])) {
foreach ($mountConfig[self::MOUNT_TYPE_USER][$user] as $mountPoint => $options) {
if (isset($personalBackends[$options['class']])) {
$options['personal'] = true;
$options['options'] = self::decryptPasswords($options['options']);
// Always override previous config
$options['priority_type'] = self::MOUNT_TYPE_PERSONAL;
$options['backend'] = $backends[$options['class']]['backend'];
$mountPoints[$mountPoint] = $options;
}
foreach ($userStoragesService->getAllStorages() as $storage) {
$mountPoint = '/'.$uid.'/files'.$storage->getMountPoint();
$mountEntry = self::prepareMountPointEntry($storage, true);
foreach ($mountEntry['options'] as &$option) {
$option = self::setUserVars($uid, $option);
}
$mountPoints[$mountPoint] = $mountEntry;
}
$userGlobalStoragesService->resetUser();
$userStoragesService->resetUser();
return $mountPoints;
}
/**
* Get the system mount points
*
* @return array
*
* @deprecated 8.2.0 use GlobalStoragesService::getAllStorages()
*/
public static function getSystemMountPoints() {
$mountPoints = [];
$service = self::$app->getContainer()->query('OCA\Files_External\Service\GlobalStoragesService');
foreach ($service->getAllStorages() as $storage) {
$mountPoints[] = self::prepareMountPointEntry($storage, false);
}
}
/**
* Get the personal mount points of the current user
*
* @return array
*
* @deprecated 8.2.0 use UserStoragesService::getAllStorages()
*/
public static function getPersonalMountPoints() {
$mountPoints = [];
$service = self::$app->getContainer()->query('OCA\Files_External\Service\UserStoragesService');
foreach ($service->getAllStorages() as $storage) {
$mountPoints[] = self::prepareMountPointEntry($storage, true);
}
}
/**
* Convert a StorageConfig to the legacy mountPoints array format
* There's a lot of extra information in here, to satisfy all of the legacy functions
*
* @param StorageConfig $storage
* @param bool $isPersonal
* @return array
*/
private static function prepareMountPointEntry(StorageConfig $storage, $isPersonal) {
$mountEntry = [];
$mountEntry['mountpoint'] = substr($storage->getMountPoint(), 1); // remove leading slash
$mountEntry['class'] = $storage->getBackend()->getIdentifier();
$mountEntry['backend'] = $storage->getBackend()->getText();
$mountEntry['authMechanism'] = $storage->getAuthMechanism()->getIdentifier();
$mountEntry['personal'] = $isPersonal;
$mountEntry['options'] = self::decryptPasswords($storage->getBackendOptions());
$mountEntry['mountOptions'] = $storage->getMountOptions();
$mountEntry['priority'] = $storage->getPriority();
$mountEntry['applicable'] = [
'groups' => $storage->getApplicableGroups(),
'users' => $storage->getApplicableUsers(),
];
$mountEntry['id'] = $storage->getId();
// $mountEntry['storage_id'] = null; // we don't store this!
return $mountEntry;
}
/**
* fill in the correct values for $user
*
@ -291,7 +219,7 @@ class OC_Mount_Config {
* @param string|array $input
* @return string
*/
private static function setUserVars($user, $input) {
public static function setUserVars($user, $input) {
if (is_array($input)) {
foreach ($input as &$value) {
if (is_string($value)) {
@ -304,181 +232,6 @@ class OC_Mount_Config {
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
* The returned array is not in the same format as getUserMountPoints()
*
* @return array
*/
public static function getSystemMountPoints() {
$mountPoints = self::readData();
$backends = self::getBackends();
$system = array();
if (isset($mountPoints[self::MOUNT_TYPE_GROUP])) {
foreach ($mountPoints[self::MOUNT_TYPE_GROUP] as $group => $mounts) {
foreach ($mounts as $mountPoint => $mount) {
// Update old classes to new namespace
if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
$mount['class'] = '\OC\Files\Storage\\' . substr($mount['class'], 15);
}
$mount['options'] = self::decryptPasswords($mount['options']);
if (!isset($mount['priority'])) {
$mount['priority'] = $backends[$mount['class']]['priority'];
}
// Remove '/$user/files/' from mount point
$mountPoint = substr($mountPoint, 13);
$config = array(
'class' => $mount['class'],
'mountpoint' => $mountPoint,
'backend' => $backends[$mount['class']]['backend'],
'priority' => $mount['priority'],
'options' => $mount['options'],
'applicable' => array('groups' => array($group), 'users' => array())
);
if (isset($mount['id'])) {
$config['id'] = (int)$mount['id'];
}
if (isset($mount['storage_id'])) {
$config['storage_id'] = (int)$mount['storage_id'];
}
if (isset($mount['mountOptions'])) {
$config['mountOptions'] = $mount['mountOptions'];
}
$hash = self::makeConfigHash($config);
// If an existing config exists (with same class, mountpoint and options)
if (isset($system[$hash])) {
// add the groups into that config
$system[$hash]['applicable']['groups']
= array_merge($system[$hash]['applicable']['groups'], array($group));
} else {
$system[$hash] = $config;
}
}
}
}
if (isset($mountPoints[self::MOUNT_TYPE_USER])) {
foreach ($mountPoints[self::MOUNT_TYPE_USER] as $user => $mounts) {
foreach ($mounts as $mountPoint => $mount) {
// Update old classes to new namespace
if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
$mount['class'] = '\OC\Files\Storage\\' . substr($mount['class'], 15);
}
$mount['options'] = self::decryptPasswords($mount['options']);
if (!isset($mount['priority'])) {
$mount['priority'] = $backends[$mount['class']]['priority'];
}
// Remove '/$user/files/' from mount point
$mountPoint = substr($mountPoint, 13);
$config = array(
'class' => $mount['class'],
'mountpoint' => $mountPoint,
'backend' => $backends[$mount['class']]['backend'],
'priority' => $mount['priority'],
'options' => $mount['options'],
'applicable' => array('groups' => array(), 'users' => array($user))
);
if (isset($mount['id'])) {
$config['id'] = (int)$mount['id'];
}
if (isset($mount['storage_id'])) {
$config['storage_id'] = (int)$mount['storage_id'];
}
if (isset($mount['mountOptions'])) {
$config['mountOptions'] = $mount['mountOptions'];
}
$hash = self::makeConfigHash($config);
// If an existing config exists (with same class, mountpoint and options)
if (isset($system[$hash])) {
// add the users into that config
$system[$hash]['applicable']['users']
= array_merge($system[$hash]['applicable']['users'], array($user));
} else {
$system[$hash] = $config;
}
}
}
}
return array_values($system);
}
/**
* Get the personal mount points of the current user
* The returned array is not in the same format as getUserMountPoints()
*
* @return array
*/
public static function getPersonalMountPoints() {
$mountPoints = self::readData(OCP\User::getUser());
$backEnds = self::getBackends();
$uid = OCP\User::getUser();
$personal = array();
if (isset($mountPoints[self::MOUNT_TYPE_USER][$uid])) {
foreach ($mountPoints[self::MOUNT_TYPE_USER][$uid] as $mountPoint => $mount) {
// Update old classes to new namespace
if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
$mount['class'] = '\OC\Files\Storage\\' . substr($mount['class'], 15);
}
$mount['options'] = self::decryptPasswords($mount['options']);
$config = array(
'class' => $mount['class'],
// Remove '/uid/files/' from mount point
'mountpoint' => substr($mountPoint, strlen($uid) + 8),
'backend' => $backEnds[$mount['class']]['backend'],
'options' => $mount['options']
);
if (isset($mount['id'])) {
$config['id'] = (int)$mount['id'];
}
if (isset($mount['storage_id'])) {
$config['storage_id'] = (int)$mount['storage_id'];
}
if (isset($mount['mountOptions'])) {
$config['mountOptions'] = $mount['mountOptions'];
}
$personal[] = $config;
}
}
return $personal;
}
/**
* Test connecting using the given backend configuration
*
@ -514,163 +267,6 @@ class OC_Mount_Config {
return self::STATUS_ERROR;
}
/**
* Add a mount point to the filesystem
*
* @param string $mountPoint Mount point
* @param string $class Backend class
* @param array $classOptions Backend parameters for the class
* @param string $mountType MOUNT_TYPE_GROUP | MOUNT_TYPE_USER
* @param string $applicable User or group to apply mount to
* @param bool $isPersonal Personal or system mount point i.e. is this being called from the personal or admin page
* @param int|null $priority Mount point priority, null for default
* @return boolean
*
* @deprecated use StoragesService#addStorage() instead
*/
public static function addMountPoint($mountPoint,
$class,
$classOptions,
$mountType,
$applicable,
$isPersonal = false,
$priority = null) {
$backends = self::getBackends();
$mountPoint = OC\Files\Filesystem::normalizePath($mountPoint);
$relMountPoint = $mountPoint;
if ($mountPoint === '' || $mountPoint === '/') {
// can't mount at root folder
return false;
}
if (!isset($backends[$class])) {
// invalid backend
return false;
}
if ($isPersonal) {
// Verify that the mount point applies for the current user
// Prevent non-admin users from mounting local storage and other disabled backends
$allowed_backends = self::getPersonalBackends();
if ($applicable != OCP\User::getUser() || !isset($allowed_backends[$class])) {
return false;
}
$mountPoint = '/' . $applicable . '/files/' . ltrim($mountPoint, '/');
} else {
$mountPoint = '/$user/files/' . ltrim($mountPoint, '/');
}
$mount = array($applicable => array(
$mountPoint => array(
'class' => $class,
'options' => self::encryptPasswords($classOptions))
)
);
if (!$isPersonal && !is_null($priority)) {
$mount[$applicable][$mountPoint]['priority'] = $priority;
}
$mountPoints = self::readData($isPersonal ? OCP\User::getUser() : null);
// who else loves multi-dimensional array ?
$isNew = !isset($mountPoints[$mountType]) ||
!isset($mountPoints[$mountType][$applicable]) ||
!isset($mountPoints[$mountType][$applicable][$mountPoint]);
$mountPoints = self::mergeMountPoints($mountPoints, $mount, $mountType);
// Set default priority if none set
if (!isset($mountPoints[$mountType][$applicable][$mountPoint]['priority'])) {
if (isset($backends[$class]['priority'])) {
$mountPoints[$mountType][$applicable][$mountPoint]['priority']
= $backends[$class]['priority'];
} else {
$mountPoints[$mountType][$applicable][$mountPoint]['priority']
= 100;
}
}
self::writeData($isPersonal ? OCP\User::getUser() : null, $mountPoints);
$result = self::getBackendStatus($class, $classOptions, $isPersonal);
if ($result === self::STATUS_SUCCESS && $isNew) {
\OC_Hook::emit(
\OC\Files\Filesystem::CLASSNAME,
\OC\Files\Filesystem::signal_create_mount,
array(
\OC\Files\Filesystem::signal_param_path => $relMountPoint,
\OC\Files\Filesystem::signal_param_mount_type => $mountType,
\OC\Files\Filesystem::signal_param_users => $applicable,
)
);
}
return $result;
}
/**
*
* @param string $mountPoint Mount point
* @param string $mountType MOUNT_TYPE_GROUP | MOUNT_TYPE_USER
* @param string $applicable User or group to remove mount from
* @param bool $isPersonal Personal or system mount point
* @return bool
*
* @deprecated use StoragesService#removeStorage() instead
*/
public static function removeMountPoint($mountPoint, $mountType, $applicable, $isPersonal = false) {
// Verify that the mount point applies for the current user
$relMountPoints = $mountPoint;
if ($isPersonal) {
if ($applicable != OCP\User::getUser()) {
return false;
}
$mountPoint = '/' . $applicable . '/files/' . ltrim($mountPoint, '/');
} else {
$mountPoint = '/$user/files/' . ltrim($mountPoint, '/');
}
$mountPoint = \OC\Files\Filesystem::normalizePath($mountPoint);
$mountPoints = self::readData($isPersonal ? OCP\User::getUser() : null);
// Remove mount point
unset($mountPoints[$mountType][$applicable][$mountPoint]);
// Unset parent arrays if empty
if (empty($mountPoints[$mountType][$applicable])) {
unset($mountPoints[$mountType][$applicable]);
if (empty($mountPoints[$mountType])) {
unset($mountPoints[$mountType]);
}
}
self::writeData($isPersonal ? OCP\User::getUser() : null, $mountPoints);
\OC_Hook::emit(
\OC\Files\Filesystem::CLASSNAME,
\OC\Files\Filesystem::signal_delete_mount,
array(
\OC\Files\Filesystem::signal_param_path => $relMountPoints,
\OC\Files\Filesystem::signal_param_mount_type => $mountType,
\OC\Files\Filesystem::signal_param_users => $applicable,
)
);
return true;
}
/**
*
* @param string $mountPoint Mount point
* @param string $target The new mount point
* @param string $mountType MOUNT_TYPE_GROUP | MOUNT_TYPE_USER
* @return bool
*/
public static function movePersonalMountPoint($mountPoint, $target, $mountType) {
$mountPoint = rtrim($mountPoint, '/');
$user = OCP\User::getUser();
$mountPoints = self::readData($user);
if (!isset($mountPoints[$mountType][$user][$mountPoint])) {
return false;
}
$mountPoints[$mountType][$user][$target] = $mountPoints[$mountType][$user][$mountPoint];
// Remove old mount point
unset($mountPoints[$mountType][$user][$mountPoint]);
self::writeData($user, $mountPoints);
return true;
}
/**
* Read the mount points in the config file into an array
*
@ -721,74 +317,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() {
$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) {
public static function dependencyMessage($backends) {
$l = new \OC_L10N('files_external');
$dependencyMessage = '';
foreach ($dependencies as $module => $backends) {
$dependencyGroup = array();
foreach ($backends as $backend) {
if (is_array($backend)) {
$dependencyMessage .= '<br />' . $l->t('<b>Note:</b> ') . $backend['message'];
} else {
$dependencyGroup[] = $backend;
}
}
$message = '';
$dependencyGroups = [];
$dependencyGroupCount = count($dependencyGroup);
if ($dependencyGroupCount > 0) {
$backends = '';
for ($i = 0; $i < $dependencyGroupCount; $i++) {
if ($i > 0 && $i === $dependencyGroupCount - 1) {
$backends .= ' ' . $l->t('and') . ' ';
} elseif ($i > 0) {
$backends .= ', ';
}
$backends .= '<i>' . $dependencyGroup[$i] . '</i>';
foreach ($backends as $backend) {
foreach ($backend->checkDependencies() as $dependency) {
if ($message = $dependency->getMessage()) {
$message .= '<br />' . $l->t('<b>Note:</b> ') . $message;
} else {
$dependencyGroups[$dependency->getDependency()][] = $backend;
}
$dependencyMessage .= '<br />' . OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends);
}
}
return $dependencyMessage;
foreach ($dependencyGroups as $module => $dependants) {
$backends = implode(', ', array_map(function($backend) {
return '<i>' . $backend->getText() . '</i>';
}, $dependants));
$message .= '<br />' . OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends);
}
return $message;
}
/**
@ -918,7 +475,8 @@ class OC_Mount_Config {
public static function makeConfigHash($config) {
$data = json_encode(
array(
'c' => $config['class'],
'c' => $config['backend'],
'a' => $config['authMechanism'],
'm' => $config['mountpoint'],
'o' => $config['options'],
'p' => isset($config['priority']) ? $config['priority'] : -1,
@ -967,7 +525,8 @@ class OC_Mount_Config {
return false;
}
$class = $options['class'];
$service = self::$app->getContainer()->query('OCA\Files_External\Service\BackendService');
$class = $service->getBackend($options['backend'])->getStorageClass();
try {
/** @var \OC\Files\Storage\Storage $storage */
$storage = new $class($options['options']);

View file

@ -2,6 +2,7 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Robin McCorkell <rmccorkell@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
@ -22,16 +23,81 @@
namespace OCA\Files_External\Config;
use OCP\Files\Storage;
use OC\Files\Mount\MountPoint;
use OCP\Files\Storage\IStorageFactory;
use OCA\Files_External\PersonalMount;
use OCA\Files_External\Lib\PersonalMount;
use OCP\Files\Config\IMountProvider;
use OCP\IUser;
use OCA\Files_external\Service\UserStoragesService;
use OCA\Files_External\Service\UserGlobalStoragesService;
use OCA\Files_External\Lib\StorageConfig;
use OCP\Files\StorageNotAvailableException;
use OCA\Files_External\Lib\FailedStorage;
/**
* Make the old files_external config work with the new public mount config api
*/
class ConfigAdapter implements IMountProvider {
/** @var UserStoragesService */
private $userStoragesService;
/** @var UserGlobalStoragesService */
private $userGlobalStoragesService;
/**
* @param UserStoragesService $userStoragesService
* @param UserGlobalStoragesService $userGlobalStoragesService
*/
public function __construct(
UserStoragesService $userStoragesService,
UserGlobalStoragesService $userGlobalStoragesService
) {
$this->userStoragesService = $userStoragesService;
$this->userGlobalStoragesService = $userGlobalStoragesService;
}
/**
* Process storage ready for mounting
*
* @param StorageConfig $storage
* @param IUser $user
*/
private function prepareStorageConfig(StorageConfig &$storage, IUser $user) {
foreach ($storage->getBackendOptions() as $option => $value) {
$storage->setBackendOption($option, \OC_Mount_Config::setUserVars(
$user->getUID(), $value
));
}
$objectStore = $storage->getBackendOption('objectstore');
if ($objectStore) {
$objectClass = $objectStore['class'];
$storage->setBackendOption('objectstore', new $objectClass($objectStore));
}
$storage->getAuthMechanism()->manipulateStorageConfig($storage);
$storage->getBackend()->manipulateStorageConfig($storage);
}
/**
* Construct the storage implementation
*
* @param StorageConfig $storageConfig
* @return Storage
*/
private function constructStorage(StorageConfig $storageConfig) {
$class = $storageConfig->getBackend()->getStorageClass();
$storage = new $class($storageConfig->getBackendOptions());
// auth mechanism should fire first
$storage = $storageConfig->getBackend()->wrapStorage($storage);
$storage = $storageConfig->getAuthMechanism()->wrapStorage($storage);
return $storage;
}
/**
* Get all mountpoints applicable for the user
*
@ -40,20 +106,54 @@ class ConfigAdapter implements IMountProvider {
* @return \OCP\Files\Mount\IMountPoint[]
*/
public function getMountsForUser(IUser $user, IStorageFactory $loader) {
$mountPoints = \OC_Mount_Config::getAbsoluteMountPoints($user->getUID());
$mounts = array();
foreach ($mountPoints as $mountPoint => $options) {
if (isset($options['options']['objectstore'])) {
$objectClass = $options['options']['objectstore']['class'];
$options['options']['objectstore'] = new $objectClass($options['options']['objectstore']);
}
$mountOptions = isset($options['mountOptions']) ? $options['mountOptions'] : [];
if (isset($options['personal']) && $options['personal']) {
$mounts[] = new PersonalMount($options['class'], $mountPoint, $options['options'], $loader, $mountOptions);
} else {
$mounts[] = new MountPoint($options['class'], $mountPoint, $options['options'], $loader, $mountOptions);
$mounts = [];
$this->userStoragesService->setUser($user);
$this->userGlobalStoragesService->setUser($user);
foreach ($this->userGlobalStoragesService->getAllStorages() as $storage) {
try {
$this->prepareStorageConfig($storage, $user);
$impl = $this->constructStorage($storage);
} catch (\Exception $e) {
// propagate exception into filesystem
$impl = new FailedStorage(['exception' => $e]);
}
$mount = new MountPoint(
$impl,
'/'.$user->getUID().'/files' . $storage->getMountPoint(),
null,
$loader,
$storage->getMountOptions()
);
$mounts[$storage->getMountPoint()] = $mount;
}
foreach ($this->userStoragesService->getAllStorages() as $storage) {
try {
$this->prepareStorageConfig($storage, $user);
$impl = $this->constructStorage($storage);
} catch (\Exception $e) {
// propagate exception into filesystem
$impl = new FailedStorage(['exception' => $e]);
}
$mount = new PersonalMount(
$this->userStoragesService,
$storage->getId(),
$impl,
'/'.$user->getUID().'/files' . $storage->getMountPoint(),
null,
$loader,
$storage->getMountOptions()
);
$mounts[$storage->getMountPoint()] = $mount;
}
$this->userStoragesService->resetUser();
$this->userGlobalStoragesService->resetUser();
return $mounts;
}
}

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,200 @@
<?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\Lock\ILockingProvider;
use \OC\Files\Storage\Common;
use \OCP\Files\StorageNotAvailableException;
/**
* Storage placeholder to represent a missing precondition, storage unavailable
*/
class FailedStorage extends Common {
/** @var \Exception */
protected $e;
/**
* @param array $params ['exception' => \Exception]
*/
public function __construct($params) {
$this->e = $params['exception'];
}
public function getId() {
// we can't return anything sane here
return 'failedstorage';
}
public function mkdir($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function rmdir($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function opendir($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function is_dir($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function is_file($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function stat($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function filetype($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function filesize($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function isCreatable($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function isReadable($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function isUpdatable($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function isDeletable($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function isSharable($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function getPermissions($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function file_exists($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function filemtime($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function file_get_contents($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function file_put_contents($path, $data) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function unlink($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function rename($path1, $path2) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function copy($path1, $path2) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function fopen($path, $mode) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function getMimeType($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function hash($type, $path, $raw = false) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function free_space($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function search($query) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function touch($path, $mtime = null) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function getLocalFile($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function getLocalFolder($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function hasUpdated($path, $time) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function getETag($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function getDirectDownload($path) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function verifyPath($path, $fileName) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function acquireLock($path, $type, ILockingProvider $provider) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function releaseLock($path, $type, ILockingProvider $provider) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function changeLock($path, $type, ILockingProvider $provider) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
}

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,68 @@
<?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;
/**
* Trait for objects requiring an identifier (and/or identifier aliases)
*/
trait IdentifierTrait {
/** @var string */
protected $identifier;
/** @var string[] */
protected $identifierAliases = [];
/**
* @return string
*/
public function getIdentifier() {
return $this->identifier;
}
/**
* @param string $identifier
* @return self
*/
public function setIdentifier($identifier) {
$this->identifier = $identifier;
$this->identifierAliases[] = $identifier;
return $this;
}
/**
* @return string[]
*/
public function getIdentifierAliases() {
return $this->identifierAliases;
}
/**
* @param string $alias
* @return self
*/
public function addIdentifierAlias($alias) {
$this->identifierAliases[] = $alias;
return $this;
}
}

View file

@ -0,0 +1,30 @@
<?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\StorageNotAvailableException;
/**
* Authentication mechanism or backend has insufficient data
*/
class InsufficientDataForMeaningfulAnswerException extends StorageNotAvailableException {
}

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\MoveableMount;
use OCA\Files_External\Service\UserStoragesService;
/**
* Person mount points can be moved by the user
*/
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
*
@ -36,9 +66,13 @@ class PersonalMount extends MountPoint implements MoveableMount {
* @return bool
*/
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);
return $result;
return true;
}
/**
@ -47,8 +81,7 @@ class PersonalMount extends MountPoint implements MoveableMount {
* @return bool
*/
public function removeMount() {
$user = \OCP\User::getUser();
$relativeMountPoint = substr($this->getMountPoint(), strlen('/' . $user . '/files/'));
return \OC_Mount_Config::removeMountPoint($relativeMountPoint, \OC_Mount_Config::MOUNT_TYPE_USER, $user , true);
$this->storagesService->removeStorage($this->storageId);
return 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,9 @@
namespace OCA\Files_external\Lib;
use \OCA\Files_External\Lib\Backend\Backend;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
/**
* External storage configuration
*/
@ -34,11 +37,18 @@ class StorageConfig implements \JsonSerializable {
private $id;
/**
* Backend class name
* Backend
*
* @var string
* @var Backend
*/
private $backendClass;
private $backend;
/**
* Authentication mechanism
*
* @var AuthMechanism
*/
private $authMechanism;
/**
* Backend options
@ -138,21 +148,31 @@ class StorageConfig implements \JsonSerializable {
}
/**
* Returns the external storage backend class name
*
* @return string external storage backend class name
* @return Backend
*/
public function getBackendClass() {
return $this->backendClass;
public function getBackend() {
return $this->backend;
}
/**
* Sets the external storage backend class name
*
* @param string external storage backend class name
* @param Backend
*/
public function setBackendClass($backendClass) {
$this->backendClass = $backendClass;
public function setBackend(Backend $backend) {
$this->backend= $backend;
}
/**
* @return AuthMechanism
*/
public function getAuthMechanism() {
return $this->authMechanism;
}
/**
* @param AuthMechanism
*/
public function setAuthMechanism(AuthMechanism $authMechanism) {
$this->authMechanism = $authMechanism;
}
/**
@ -173,6 +193,25 @@ class StorageConfig implements \JsonSerializable {
$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
*
@ -283,7 +322,8 @@ class StorageConfig implements \JsonSerializable {
$result['id'] = $this->id;
}
$result['mountPoint'] = $this->mountPoint;
$result['backendClass'] = $this->backendClass;
$result['backend'] = $this->backend->getIdentifier();
$result['authMechanism'] = $this->authMechanism->getIdentifier();
$result['backendOptions'] = $this->backendOptions;
if (!is_null($this->priority)) {
$result['priority'] = $this->priority;

View file

@ -0,0 +1,67 @@
<?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;
use \OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
use \OCP\Files\StorageNotAvailableException;
/**
* Trait for objects that can modify StorageConfigs and wrap Storages
*
* When a storage implementation is being prepared for use, the StorageConfig
* is passed through manipulateStorageConfig() to update any parameters as
* necessary. After the storage implementation has been constructed, it is
* passed through wrapStorage(), potentially replacing the implementation with
* a wrapped storage that changes its behaviour.
*
* Certain configuration options need to be set before the implementation is
* constructed, while others are retrieved directly from the storage
* implementation and so need a wrapper to be modified.
*/
trait StorageModifierTrait {
/**
* Modify a StorageConfig parameters
*
* @param StorageConfig $storage
* @throws InsufficientDataForMeaningfulAnswerException
* @throws StorageNotAvailableException
*/
public function manipulateStorageConfig(StorageConfig &$storage) {
}
/**
* Wrap a Storage if necessary
*
* @param Storage $storage
* @return Storage
* @throws InsufficientDataForMeaningfulAnswerException
* @throws StorageNotAvailableException
*/
public function wrapStorage(Storage $storage) {
return $storage;
}
}

View file

@ -0,0 +1,136 @@
<?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
*
* The standard visibility defines which users/groups can use or see the
* object. The allowed visibility defines the maximum visibility allowed to be
* set on the object. The standard visibility is often set dynamically by
* stored configuration parameters that can be modified by the administrator,
* while the allowed visibility is set directly by the object and cannot be
* modified by the administrator.
*/
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,34 @@
*
*/
use \OCA\Files_External\Service\BackendService;
// we must use the same container
$appContainer = \OC_Mount_Config::$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::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;
$backends = $backendService->getBackendsVisibleFor(BackendService::VISIBILITY_PERSONAL);
$authMechanisms = $backendService->getAuthMechanismsVisibleFor(BackendService::VISIBILITY_PERSONAL);
foreach ($backends as $backend) {
if ($backend->getCustomJs()) {
\OCP\Util::addScript('files_external', $backend->getCustomJs());
}
}
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
foreach ($authMechanisms as $authMechanism) {
if ($authMechanism->getCustomJs()) {
\OCP\Util::addScript('files_external', $authMechanism->getCustomJs());
}
}
$tmpl = new OCP\Template('files_external', 'settings');
$tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled());
$tmpl->assign('isAdminPage', false);
$tmpl->assign('mounts', $mounts);
$tmpl->assign('dependencies', OC_Mount_Config::checkDependencies());
$tmpl->assign('storages', $userStoragesService->getAllStorages());
$tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends()));
$tmpl->assign('backends', $backends);
$tmpl->assign('authMechanisms', $authMechanisms);
return $tmpl->fetchPage();

View file

@ -0,0 +1,275 @@
<?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;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
/**
* 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 = [];
/** @var AuthMechanism[] */
private $authMechanisms = [];
/**
* @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);
}
foreach ($backend->getIdentifierAliases() as $alias) {
$this->backends[$alias] = $backend;
}
}
/**
* @param Backend[] $backends
*/
public function registerBackends(array $backends) {
foreach ($backends as $backend) {
$this->registerBackend($backend);
}
}
/**
* Register an authentication mechanism
*
* @param AuthMechanism $authMech
*/
public function registerAuthMechanism(AuthMechanism $authMech) {
if (!$this->isAllowedAuthMechanism($authMech)) {
$authMech->removeVisibility(BackendService::VISIBILITY_PERSONAL);
}
foreach ($authMech->getIdentifierAliases() as $alias) {
$this->authMechanisms[$alias] = $authMech;
}
}
/**
* @param AuthMechanism[] $mechanisms
*/
public function registerAuthMechanisms(array $mechanisms) {
foreach ($mechanisms as $mechanism) {
$this->registerAuthMechanism($mechanism);
}
}
/**
* Get all backends
*
* @return Backend[]
*/
public function getBackends() {
// only return real identifiers, no aliases
$backends = [];
foreach ($this->backends as $backend) {
$backends[$backend->getIdentifier()] = $backend;
}
return $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 $identifier
* @return Backend|null
*/
public function getBackend($identifier) {
if (isset($this->backends[$identifier])) {
return $this->backends[$identifier];
}
return null;
}
/**
* Get all authentication mechanisms
*
* @return AuthMechanism[]
*/
public function getAuthMechanisms() {
// only return real identifiers, no aliases
$mechanisms = [];
foreach ($this->authMechanisms as $mechanism) {
$mechanisms[$mechanism->getIdentifier()] = $mechanism;
}
return $mechanisms;
}
/**
* Get all authentication mechanisms for schemes
*
* @param string[] $schemes
* @return AuthMechanism[]
*/
public function getAuthMechanismsByScheme(array $schemes) {
return array_filter($this->getAuthMechanisms(), function($authMech) use ($schemes) {
return in_array($authMech->getScheme(), $schemes, true);
});
}
/**
* Get authentication mechanisms visible for $visibleFor
*
* @param int $visibleFor
* @return AuthMechanism[]
*/
public function getAuthMechanismsVisibleFor($visibleFor) {
return array_filter($this->getAuthMechanisms(), function($authMechanism) use ($visibleFor) {
return $authMechanism->isVisibleFor($visibleFor);
});
}
/**
* Get authentication mechanisms allowed to be visible for $visibleFor
*
* @param int $visibleFor
* @return AuthMechanism[]
*/
public function getAuthMechanismsAllowedVisibleFor($visibleFor) {
return array_filter($this->getAuthMechanisms(), function($authMechanism) use ($visibleFor) {
return $authMechanism->isAllowedVisibleFor($visibleFor);
});
}
/**
* @param string $identifier
* @return AuthMechanism|null
*/
public function getAuthMechanism($identifier) {
if (isset($this->authMechanisms[$identifier])) {
return $this->authMechanisms[$identifier];
}
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 &&
!empty(array_intersect($backend->getIdentifierAliases(), $this->userMountingBackends))
) {
return true;
}
return false;
}
/**
* Check an authentication mechanism if a user is allowed to use it
*
* @param AuthMechanism $authMechanism
* @return bool
*/
protected function isAllowedAuthMechanism(AuthMechanism $authMechanism) {
return true; // not implemented
}
}

View file

@ -92,7 +92,7 @@ class GlobalStoragesService extends StoragesService {
$storageConfig->setBackendOptions($oldBackendOptions);
}
\OC_Mount_Config::writeData(null, $mountPoints);
$this->writeLegacyConfig($mountPoints);
}
/**

View file

@ -28,12 +28,23 @@ use \OC\Files\Filesystem;
use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_external\NotFoundException;
use \OCA\Files_External\Service\BackendService;
/**
* Service class to manage external storages
*/
abstract class StoragesService {
/** @var BackendService */
protected $backendService;
/**
* @param BackendService $backendService
*/
public function __construct(BackendService $backendService) {
$this->backendService = $backendService;
}
/**
* Read legacy config data
*
@ -44,6 +55,16 @@ abstract class StoragesService {
return \OC_Mount_Config::readData();
}
/**
* Write legacy config data
*
* @param array $mountPoints
*/
protected function writeLegacyConfig(array $mountPoints) {
// write global config
\OC_Mount_Config::writeData(null, $mountPoints);
}
/**
* Copy legacy storage options into the given storage config object.
*
@ -60,14 +81,31 @@ abstract class StoragesService {
$applicable,
$storageOptions
) {
$storageConfig->setBackendClass($storageOptions['class']);
$backend = $this->backendService->getBackend($storageOptions['backend']);
if (!$backend) {
throw new \UnexpectedValueException('Invalid backend '.$storageOptions['backend']);
}
$storageConfig->setBackend($backend);
if (isset($storageOptions['authMechanism'])) {
$authMechanism = $this->backendService->getAuthMechanism($storageOptions['authMechanism']);
} else {
$authMechanism = $backend->getLegacyAuthMechanism($storageOptions);
$storageOptions['authMechanism'] = 'null'; // to make error handling easier
}
if (!$authMechanism) {
throw new \UnexpectedValueException('Invalid authentication mechanism '.$storageOptions['authMechanism']);
}
$storageConfig->setAuthMechanism($authMechanism);
$storageConfig->setBackendOptions($storageOptions['options']);
if (isset($storageOptions['mountOptions'])) {
$storageConfig->setMountOptions($storageOptions['mountOptions']);
}
if (isset($storageOptions['priority'])) {
$storageConfig->setPriority($storageOptions['priority']);
if (!isset($storageOptions['priority'])) {
$storageOptions['priority'] = $backend->getPriority();
}
$storageConfig->setPriority($storageOptions['priority']);
if ($mountType === \OC_Mount_Config::MOUNT_TYPE_USER) {
$applicableUsers = $storageConfig->getApplicableUsers();
@ -102,8 +140,10 @@ abstract class StoragesService {
* - $mountPath is the mount point path (where the storage must be mounted)
* - $storageOptions is a map of storage options:
* - "priority": storage priority
* - "backend": backend class name
* - "backend": backend identifier
* - "class": LEGACY backend class name
* - "options": backend-specific options
* - "authMechanism": authentication mechanism identifier
* - "mountOptions": mount-specific options (ex: disable previews, scanner, etc)
*/
@ -147,6 +187,13 @@ abstract class StoragesService {
// options might be needed for the config hash
$storageOptions['options'] = \OC_Mount_Config::decryptPasswords($storageOptions['options']);
if (!isset($storageOptions['backend'])) {
$storageOptions['backend'] = $storageOptions['class']; // legacy compat
}
if (!isset($storageOptions['authMechanism'])) {
$storageOptions['authMechanism'] = null; // ensure config hash works
}
if (isset($storageOptions['id'])) {
$configId = (int)$storageOptions['id'];
if (isset($storages[$configId])) {
@ -188,20 +235,30 @@ abstract class StoragesService {
// process storages with config hash, they must get a real id
if (!empty($storagesWithConfigHash)) {
$nextId = $this->generateNextId($storages);
foreach ($storagesWithConfigHash as $storage) {
$storage->setId($nextId);
$storages[$nextId] = $storage;
$nextId++;
}
// re-save the config with the generated ids
$this->writeConfig($storages);
$this->setRealStorageIds($storages, $storagesWithConfigHash);
}
return $storages;
}
/**
* Replace config hash ID with real IDs, for migrating legacy storages
*
* @param StorageConfig[] $storages Storages with real IDs
* @param StorageConfig[] $storagesWithConfigHash Storages with config hash IDs
*/
protected function setRealStorageIds(array &$storages, array $storagesWithConfigHash) {
$nextId = $this->generateNextId($storages);
foreach ($storagesWithConfigHash as $storage) {
$storage->setId($nextId);
$storages[$nextId] = $storage;
$nextId++;
}
// re-save the config with the generated ids
$this->writeConfig($storages);
}
/**
* Add mount point into the messy mount point structure
*
@ -222,7 +279,9 @@ abstract class StoragesService {
$options = [
'id' => $storageConfig->getId(),
'class' => $storageConfig->getBackendClass(),
'backend' => $storageConfig->getBackend()->getIdentifier(),
//'class' => $storageConfig->getBackend()->getClass(),
'authMechanism' => $storageConfig->getAuthMechanism()->getIdentifier(),
'options' => $storageConfig->getBackendOptions(),
];
@ -296,6 +355,59 @@ abstract class StoragesService {
return $newStorage;
}
/**
* Create a storage from its parameters
*
* @param string $mountPoint storage mount point
* @param string $backendIdentifier backend identifier
* @param string $authMechanismIdentifier authentication mechanism identifier
* @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,
$backendIdentifier,
$authMechanismIdentifier,
$backendOptions,
$mountOptions = null,
$applicableUsers = null,
$applicableGroups = null,
$priority = null
) {
$backend = $this->backendService->getBackend($backendIdentifier);
if (!$backend) {
throw new \InvalidArgumentException('Unable to get backend for '.$backendIdentifier);
}
$authMechanism = $this->backendService->getAuthMechanism($authMechanismIdentifier);
if (!$authMechanism) {
throw new \InvalidArgumentException('Unable to get authentication mechanism for '.$authMechanismIdentifier);
}
$newStorage = new StorageConfig();
$newStorage->setMountPoint($mountPoint);
$newStorage->setBackend($backend);
$newStorage->setAuthMechanism($authMechanism);
$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
*

View file

@ -0,0 +1,107 @@
<?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\Service;
use \OCA\Files_external\Service\GlobalStoragesService;
use \OCA\Files_External\Service\BackendService;
use \OCP\IUserSession;
use \OCP\IGroupManager;
use \OCA\Files_External\Service\UserTrait;
/**
* Service class to read global storages applicable to the user
* Read-only access available, attempting to write will throw DomainException
*/
class UserGlobalStoragesService extends GlobalStoragesService {
use UserTrait;
/** @var IGroupManager */
protected $groupManager;
/**
* @param BackendService $backendService
* @param IUserSession $userSession
* @param IGroupManager $groupManager
*/
public function __construct(
BackendService $backendService,
IUserSession $userSession,
IGroupManager $groupManager
) {
parent::__construct($backendService);
$this->userSession = $userSession;
$this->groupManager = $groupManager;
}
/**
* Replace config hash ID with real IDs, for migrating legacy storages
*
* @param StorageConfig[] $storages Storages with real IDs
* @param StorageConfig[] $storagesWithConfigHash Storages with config hash IDs
*/
protected function setRealStorageIds(array &$storages, array $storagesWithConfigHash) {
// as a read-only view, storage IDs don't need to be real
foreach ($storagesWithConfigHash as $storage) {
$storages[$storage->getId()] = $storage;
}
}
/**
* Read legacy config data
*
* @return array list of mount configs
*/
protected function readLegacyConfig() {
// read global config
$data = parent::readLegacyConfig();
$userId = $this->getUser()->getUID();
if (isset($data[\OC_Mount_Config::MOUNT_TYPE_USER])) {
$data[\OC_Mount_Config::MOUNT_TYPE_USER] = array_filter(
$data[\OC_Mount_Config::MOUNT_TYPE_USER], function($key) use ($userId) {
return (strtolower($key) === strtolower($userId) || $key === 'all');
}, ARRAY_FILTER_USE_KEY
);
}
if (isset($data[\OC_Mount_Config::MOUNT_TYPE_GROUP])) {
$data[\OC_Mount_Config::MOUNT_TYPE_GROUP] = array_filter(
$data[\OC_Mount_Config::MOUNT_TYPE_GROUP], function($key) use ($userId) {
return ($this->groupManager->isInGroup($userId, $key));
}, ARRAY_FILTER_USE_KEY
);
}
return $data;
}
/**
* Write legacy config data
*
* @param array $mountPoints
*/
protected function writeLegacyConfig(array $mountPoints) {
throw new \DomainException('UserGlobalStoragesService writing disallowed');
}
}

View file

@ -26,6 +26,8 @@ use \OC\Files\Filesystem;
use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_external\NotFoundException;
use \OCA\Files_External\Service\BackendService;
use \OCA\Files_External\Service\UserTrait;
/**
* Service class to manage user external storages
@ -33,22 +35,20 @@ use \OCA\Files_external\NotFoundException;
*/
class UserStoragesService extends StoragesService {
/**
* User session
*
* @var IUserSession
*/
private $userSession;
use UserTrait;
/**
* Create a user storages service
*
* @param BackendService $backendService
* @param IUserSession $userSession user session
*/
public function __construct(
BackendService $backendService,
IUserSession $userSession
) {
$this->userSession = $userSession;
parent::__construct($backendService);
}
/**
@ -58,17 +58,28 @@ class UserStoragesService extends StoragesService {
*/
protected function readLegacyConfig() {
// read user config
$user = $this->userSession->getUser()->getUID();
$user = $this->getUser()->getUID();
return \OC_Mount_Config::readData($user);
}
/**
* Write legacy config data
*
* @param array $mountPoints
*/
protected function writeLegacyConfig(array $mountPoints) {
// write user config
$user = $this->getUser()->getUID();
\OC_Mount_Config::writeData($user, $mountPoints);
}
/**
* Read the external storages config
*
* @return array map of storage id to storage config
*/
protected function readConfig() {
$user = $this->userSession->getUser()->getUID();
$user = $this->getUser()->getUID();
// TODO: in the future don't rely on the global config reading code
$storages = parent::readConfig();
@ -95,7 +106,7 @@ class UserStoragesService extends StoragesService {
* @param array $storages map of storage id to storage config
*/
public function writeConfig($storages) {
$user = $this->userSession->getUser()->getUID();
$user = $this->getUser()->getUID();
// let the horror begin
$mountPoints = [];
@ -123,7 +134,7 @@ class UserStoragesService extends StoragesService {
$storageConfig->setBackendOptions($oldBackendOptions);
}
\OC_Mount_Config::writeData($user, $mountPoints);
$this->writeLegacyConfig($mountPoints);
}
/**
@ -134,7 +145,7 @@ class UserStoragesService extends StoragesService {
* @param string $signal signal to trigger
*/
protected function triggerHooks(StorageConfig $storage, $signal) {
$user = $this->userSession->getUser()->getUID();
$user = $this->getUser()->getUID();
// trigger hook for the current user
$this->triggerApplicableHooks(

View file

@ -0,0 +1,74 @@
<?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\Service;
use \OCP\IUserSession;
use \OCP\IUser;
/**
* Trait for getting user information in a service
*/
trait UserTrait {
/** @var IUserSession */
protected $userSession;
/**
* User override
*
* @var IUser|null
*/
private $user = null;
/**
* @return IUser|null
*/
protected function getUser() {
if ($this->user) {
return $this->user;
}
return $this->userSession->getUser();
}
/**
* Override the user from the session
* Unset with ->resetUser() when finished!
*
* @param IUser
* @return self
*/
public function setUser(IUser $user) {
$this->user = $user;
return $this;
}
/**
* Reset the user override
*
* @return self
*/
public function resetUser() {
$this->user = null;
return $this;
}
}

View file

@ -26,54 +26,41 @@
*
*/
use \OCA\Files_External\Service\BackendService;
OC_Util::checkAdminUser();
// we must use the same container
$appContainer = \OC_Mount_Config::$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::addStyle('files_external', 'settings');
\OC_Util::addVendorScript('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),
);
$backends = $backendService->getBackendsVisibleFor(BackendService::VISIBILITY_ADMIN);
$authMechanisms = $backendService->getAuthMechanismsVisibleFor(BackendService::VISIBILITY_ADMIN);
foreach ($backends as $backend) {
if ($backend->getCustomJs()) {
\OCP\Util::addScript('files_external', $backend->getCustomJs());
}
}
$mounts = OC_Mount_Config::getSystemMountPoints();
$hasId = true;
foreach ($mounts as $mount) {
if (!isset($mount['id'])) {
// some mount points are missing ids
$hasId = false;
break;
foreach ($authMechanisms as $authMechanism) {
if ($authMechanism->getCustomJs()) {
\OCP\Util::addScript('files_external', $authMechanism->getCustomJs());
}
}
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->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled());
$tmpl->assign('isAdminPage', true);
$tmpl->assign('mounts', $mounts);
$tmpl->assign('storages', $globalStoragesService->getAllStorages());
$tmpl->assign('backends', $backends);
$tmpl->assign('personal_backends', $personal_backends);
$tmpl->assign('dependencies', OC_Mount_Config::checkDependencies());
$tmpl->assign('allowUserMounting', OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes'));
$tmpl->assign('authMechanisms', $authMechanisms);
$tmpl->assign('userBackends', $backendService->getBackendsAllowedVisibleFor(BackendService::VISIBILITY_PERSONAL));
$tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends()));
$tmpl->assign('allowUserMounting', $backendService->isUserMountingAllowed());
return $tmpl->fetchPage();

View file

@ -1,3 +1,58 @@
<?php
use \OCA\Files_External\Lib\Backend\Backend;
use \OCA\Files_External\Lib\DefinitionParameter;
use \OCA\Files_External\Service\BackendService;
function writeParameterInput($parameter, $options, $classes = []) {
$value = '';
if (isset($options[$parameter->getName()])) {
$value = $options[$parameter->getName()];
}
$placeholder = $parameter->getText();
$is_optional = $parameter->isFlagSet(DefinitionParameter::FLAG_OPTIONAL);
switch ($parameter->getType()) {
case DefinitionParameter::VALUE_PASSWORD: ?>
<?php if ($is_optional) { $classes[] = 'optional'; } ?>
<input type="password"
<?php if (!empty($classes)): ?> class="<?php p(implode(' ', $classes)); ?>"<?php endif; ?>
data-parameter="<?php p($parameter->getName()); ?>"
value="<?php p($value); ?>"
placeholder="<?php p($placeholder); ?>"
/>
<?php
break;
case DefinitionParameter::VALUE_BOOLEAN: ?>
<label>
<input type="checkbox"
<?php if (!empty($classes)): ?> class="<?php p(implode(' ', $classes)); ?>"<?php endif; ?>
data-parameter="<?php p($parameter->getName()); ?>"
<?php if ($value == 'true'): ?> checked="checked"<?php endif; ?>
/>
<?php p($placeholder); ?>
</label>
<?php
break;
case DefinitionParameter::VALUE_HIDDEN: ?>
<input type="hidden"
<?php if (!empty($classes)): ?> class="<?php p(implode(' ', $classes)); ?>"<?php endif; ?>
data-parameter="<?php p($parameter->getName()); ?>"
value="<?php p($value); ?>"
/>
<?php
break;
default: ?>
<?php if ($is_optional) { $classes[] = 'optional'; } ?>
<input type="text"
<?php if (!empty($classes)): ?> class="<?php p(implode(' ', $classes)); ?>"<?php endif; ?>
data-parameter="<?php p($parameter->getName()); ?>"
value="<?php p($value); ?>"
placeholder="<?php p($placeholder); ?>"
/>
<?php
}
}
?>
<form id="files_external" class="section" data-encryption-enabled="<?php echo $_['encryptionEnabled']?'true': 'false'; ?>">
<h2><?php p($l->t('External Storage')); ?></h2>
<?php if (isset($_['dependencies']) and ($_['dependencies']<>'')) print_unescaped(''.$_['dependencies'].''); ?>
@ -7,6 +62,7 @@
<th></th>
<th><?php p($l->t('Folder name')); ?></th>
<th><?php p($l->t('External storage')); ?></th>
<th><?php p($l->t('Authentication')); ?></th>
<th><?php p($l->t('Configuration')); ?></th>
<?php if ($_['isAdminPage']) print_unescaped('<th>'.$l->t('Available for').'</th>'); ?>
<th>&nbsp;</th>
@ -14,103 +70,120 @@
</tr>
</thead>
<tbody>
<?php $_['mounts'] = array_merge($_['mounts'], array('' => array('id' => ''))); ?>
<?php foreach ($_['mounts'] as $mount): ?>
<tr <?php print_unescaped(isset($mount['mountpoint']) ? 'class="'.OC_Util::sanitizeHTML($mount['class']).'"' : 'id="addMountPoint"'); ?> data-id="<?php p($mount['id']) ?>">
<?php foreach ($_['storages'] as $storage): ?>
<tr class="<?php p($storage->getBackend()->getIdentifier()); ?>" data-id="<?php p($storage->getId()); ?>">
<td class="status">
<span></span>
</td>
<td class="mountPoint"><input type="text" name="mountPoint"
value="<?php p(isset($mount['mountpoint']) ? $mount['mountpoint'] : ''); ?>"
data-mountpoint="<?php p(isset($mount['mountpoint']) ? $mount['mountpoint'] : ''); ?>"
value="<?php p(ltrim($storage->getMountPoint(), '/')); ?>"
data-mountpoint="<?php p(ltrim($storage->getMountPoint(), '/')); ?>"
placeholder="<?php p($l->t('Folder name')); ?>" />
</td>
<?php if (!isset($mount['mountpoint'])): ?>
<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>
<?php else: ?>
<td class="backend" data-class="<?php p($mount['class']); ?>"><?php p($mount['backend']); ?>
</td>
<?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
$placeholder = $_['backends'][$mount['class']]['configuration'][$parameter];
$is_optional = FALSE;
if (strpos($placeholder, '&') === 0) {
$is_optional = TRUE;
$placeholder = substr($placeholder, 1);
}
?>
<?php if (strpos($placeholder, '*') === 0): ?>
<input type="password"
<?php if ($is_optional): ?> class="optional"<?php endif; ?>
data-parameter="<?php p($parameter); ?>"
value="<?php p($value); ?>"
placeholder="<?php p(substr($placeholder, 1)); ?>" />
<?php elseif (strpos($placeholder, '!') === 0): ?>
<label><input type="checkbox"
data-parameter="<?php p($parameter); ?>"
<?php if ($value == 'true'): ?> checked="checked"<?php endif; ?>
/><?php p(substr($placeholder, 1)); ?></label>
<?php elseif (strpos($placeholder, '#') === 0): ?>
<input type="hidden"
data-parameter="<?php p($parameter); ?>"
value="<?php p($value); ?>" />
<?php else: ?>
<input type="text"
<?php if ($is_optional): ?> class="optional"<?php endif; ?>
data-parameter="<?php p($parameter); ?>"
value="<?php p($value); ?>"
placeholder="<?php p($placeholder); ?>" />
<?php endif; ?>
<?php endif; ?>
<td class="backend" data-class="<?php p($storage->getBackend()->getIdentifier()); ?>"><?php p($storage->getBackend()->getText()); ?>
</td>
<td class="authentication">
<select class="selectAuthMechanism">
<?php
$authSchemes = $storage->getBackend()->getAuthSchemes();
$authMechanisms = array_filter($_['authMechanisms'], function($mech) use ($authSchemes) {
return isset($authSchemes[$mech->getScheme()]);
});
?>
<?php foreach ($authMechanisms as $mech): ?>
<option value="<?php p($mech->getIdentifier()); ?>" data-scheme="<?php p($mech->getScheme());?>"
<?php if ($mech->getIdentifier() === $storage->getAuthMechanism()->getIdentifier()): ?>selected<?php endif; ?>
><?php p($mech->getText()); ?></option>
<?php endforeach; ?>
<?php if (isset($_['backends'][$mount['class']]['custom'])): ?>
<?php OCP\Util::addScript('files_external', $_['backends'][$mount['class']]['custom']); ?>
<?php endif; ?>
<?php endif; ?>
</select>
</td>
<td class="configuration">
<?php
$options = $storage->getBackendOptions();
foreach ($storage->getBackend()->getParameters() as $parameter) {
writeParameterInput($parameter, $options);
}
foreach ($storage->getAuthMechanism()->getParameters() as $parameter) {
writeParameterInput($parameter, $options, ['auth-param']);
}
?>
</td>
<?php if ($_['isAdminPage']): ?>
<td class="applicable"
align="right"
data-applicable-groups='<?php if (isset($mount['applicable']['groups']))
print_unescaped(json_encode($mount['applicable']['groups'])); ?>'
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=""/>
</td>
<td class="applicable"
align="right"
data-applicable-groups='<?php print_unescaped(json_encode($storage->getApplicableGroups())); ?>'
data-applicable-users='<?php print_unescaped(json_encode($storage->getApplicableUsers())); ?>'>
<input type="hidden" class="applicableUsers" style="width:20em;" value=""/>
</td>
<?php endif; ?>
<td class="mountOptionsToggle <?php if (!isset($mount['mountpoint'])) { p('hidden'); } ?>"
><img
<td class="mountOptionsToggle">
<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="<?php isset($mount['mountOptions']) ? p(json_encode($mount['mountOptions'])) : '' ?>" />
src="<?php print_unescaped(image_path('core', 'actions/settings.svg')); ?>"
/>
<input type="hidden" class="mountOptions" value="<?php p(json_encode($storage->getMountOptions())); ?>" />
<?php if ($_['isAdminPage']): ?>
<?php if (isset($mount['priority'])): ?>
<input type="hidden" class="priority" value="<?php p($mount['priority']) ?>" />
<?php endif; ?>
<input type="hidden" class="priority" value="<?php p($storage->getPriority()); ?>" />
<?php endif; ?>
</td>
<td <?php if (isset($mount['mountpoint'])): ?>class="remove"
<?php else: ?>class="hidden"
<?php endif ?>><img alt="<?php p($l->t('Delete')); ?>"
title="<?php p($l->t('Delete')); ?>"
class="svg action"
src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>" /></td>
<td class="remove">
<img alt="<?php p($l->t('Delete')); ?>"
title="<?php p($l->t('Delete')); ?>"
class="svg action"
src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>"
/>
</td>
</tr>
<?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->getIdentifier()); ?>"><?php p($backend->getText()); ?></option>
<?php endforeach; ?>
</select>
</td>
<td class="authentication" data-mechanisms='<?php p(json_encode($_['authMechanisms'])); ?>'></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>
</table>
<br />
@ -123,9 +196,9 @@
<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 $i = 0; foreach ($_['personal_backends'] as $class => $backend): ?>
<input type="checkbox" id="allowUserMountingBackends<?php p($i); ?>" name="allowUserMountingBackends[]" value="<?php p($class); ?>" <?php if ($backend['enabled']) print_unescaped(' checked="checked"'); ?> />
<label for="allowUserMountingBackends<?php p($i); ?>"><?php p($backend['backend']); ?></label> <br />
<?php $i = 0; foreach ($_['userBackends'] as $backend): ?>
<input type="checkbox" id="allowUserMountingBackends<?php p($i); ?>" name="allowUserMountingBackends[]" value="<?php p($backend->getIdentifier()); ?>" <?php if ($backend->isVisibleFor(BackendService::VISIBILITY_PERSONAL)) print_unescaped(' checked="checked"'); ?> />
<label for="allowUserMountingBackends<?php p($i); ?>"><?php p($backend->getText()); ?></label> <br />
<?php $i++; ?>
<?php endforeach; ?>
</p>

View file

@ -0,0 +1,80 @@
<?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\Tests\Auth;
class AuthMechanismTest extends \Test\TestCase {
public function testJsonSerialization() {
$mechanism = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism')
->setMethods(['jsonSerializeDefinition'])
->getMock();
$mechanism->expects($this->once())
->method('jsonSerializeDefinition')
->willReturn(['foo' => 'bar']);
$mechanism->setScheme('scheme');
$json = $mechanism->jsonSerialize();
$this->assertEquals('bar', $json['foo']);
$this->assertEquals('scheme', $json['scheme']);
}
public function validateStorageProvider() {
return [
[true, 'scheme', true],
[false, 'scheme', false],
[true, 'foobar', true],
[false, 'barfoo', true],
];
}
/**
* @dataProvider validateStorageProvider
*/
public function testValidateStorage($expectedSuccess, $scheme, $definitionSuccess) {
$mechanism = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism')
->setMethods(['validateStorageDefinition'])
->getMock();
$mechanism->expects($this->atMost(1))
->method('validateStorageDefinition')
->willReturn($definitionSuccess);
$mechanism->setScheme($scheme);
$backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
->disableOriginalConstructor()
->getMock();
$backend->expects($this->once())
->method('getAuthSchemes')
->willReturn(['scheme' => true, 'foobar' => true]);
$storageConfig = $this->getMockBuilder('\OCA\Files_External\Lib\StorageConfig')
->disableOriginalConstructor()
->getMock();
$storageConfig->expects($this->once())
->method('getBackend')
->willReturn($backend);
$this->assertEquals($expectedSuccess, $mechanism->validateStorage($storageConfig));
}
}

View file

@ -0,0 +1,89 @@
<?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\Tests\Backend;
use \OCA\Files_External\Lib\Backend\Backend;
class BackendTest extends \Test\TestCase {
public function testJsonSerialization() {
$backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
->setMethods(['jsonSerializeDefinition'])
->getMock();
$backend->expects($this->once())
->method('jsonSerializeDefinition')
->willReturn(['foo' => 'bar', 'name' => 'abc']);
$backend->setPriority(57);
$backend->addAuthScheme('foopass');
$backend->addAuthScheme('barauth');
$json = $backend->jsonSerialize();
$this->assertEquals('bar', $json['foo']);
$this->assertEquals('abc', $json['name']);
$this->assertEquals($json['name'], $json['backend']);
$this->assertEquals(57, $json['priority']);
$this->assertContains('foopass', $json['authSchemes']);
$this->assertContains('barauth', $json['authSchemes']);
}
public function validateStorageProvider() {
return [
[true, true],
[false, false],
];
}
/**
* @dataProvider validateStorageProvider
*/
public function testValidateStorage($expectedSuccess, $definitionSuccess) {
$backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
->setMethods(['validateStorageDefinition'])
->getMock();
$backend->expects($this->atMost(1))
->method('validateStorageDefinition')
->willReturn($definitionSuccess);
$storageConfig = $this->getMockBuilder('\OCA\Files_External\Lib\StorageConfig')
->disableOriginalConstructor()
->getMock();
$this->assertEquals($expectedSuccess, $backend->validateStorage($storageConfig));
}
public function testLegacyAuthMechanismCallback() {
$backend = new Backend();
$backend->setLegacyAuthMechanismCallback(function(array $params) {
if (isset($params['ping'])) {
return 'pong';
}
return 'foobar';
});
$this->assertEquals('pong', $backend->getLegacyAuthMechanism(['ping' => true]));
$this->assertEquals('foobar', $backend->getLegacyAuthMechanism(['other' => true]));
$this->assertEquals('foobar', $backend->getLegacyAuthMechanism());
}
}

View file

@ -0,0 +1,81 @@
<?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\Tests\Backend;
use \OCA\Files_External\Lib\Backend\LegacyBackend;
use \OCA\Files_External\Lib\DefinitionParameter;
class LegacyBackendTest extends \Test\TestCase {
public function testConstructor() {
$auth = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\Builtin')
->disableOriginalConstructor()
->getMock();
$class = '\OC\Files\Storage\SMB';
$definition = [
'configuration' => [
'textfield' => 'Text field',
'passwordfield' => '*Password field',
'checkbox' => '!Checkbox',
'hiddenfield' => '#Hidden field',
'optionaltext' => '&Optional text field',
'optionalpassword' => '&*Optional password field',
],
'backend' => 'Backend text',
'priority' => 123,
'custom' => 'foo/bar.js',
'has_dependencies' => true,
];
$backend = new LegacyBackend($class, $definition, $auth);
$this->assertEquals('\OC\Files\Storage\SMB', $backend->getStorageClass());
$this->assertEquals('Backend text', $backend->getText());
$this->assertEquals(123, $backend->getPriority());
$this->assertEquals('foo/bar.js', $backend->getCustomJs());
$this->assertEquals(true, $backend->hasDependencies());
$this->assertArrayHasKey('builtin', $backend->getAuthSchemes());
$this->assertEquals($auth, $backend->getLegacyAuthMechanism());
$parameters = $backend->getParameters();
$this->assertEquals('Text field', $parameters['textfield']->getText());
$this->assertEquals(DefinitionParameter::VALUE_TEXT, $parameters['textfield']->getType());
$this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['textfield']->getFlags());
$this->assertEquals('Password field', $parameters['passwordfield']->getText());
$this->assertEquals(DefinitionParameter::VALUE_PASSWORD, $parameters['passwordfield']->getType());
$this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['passwordfield']->getFlags());
$this->assertEquals('Checkbox', $parameters['checkbox']->getText());
$this->assertEquals(DefinitionParameter::VALUE_BOOLEAN, $parameters['checkbox']->getType());
$this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['checkbox']->getFlags());
$this->assertEquals('Hidden field', $parameters['hiddenfield']->getText());
$this->assertEquals(DefinitionParameter::VALUE_HIDDEN, $parameters['hiddenfield']->getType());
$this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['hiddenfield']->getFlags());
$this->assertEquals('Optional text field', $parameters['optionaltext']->getText());
$this->assertEquals(DefinitionParameter::VALUE_TEXT, $parameters['optionaltext']->getType());
$this->assertEquals(DefinitionParameter::FLAG_OPTIONAL, $parameters['optionaltext']->getFlags());
$this->assertEquals('Optional password field', $parameters['optionalpassword']->getText());
$this->assertEquals(DefinitionParameter::VALUE_PASSWORD, $parameters['optionalpassword']->getType());
$this->assertEquals(DefinitionParameter::FLAG_OPTIONAL, $parameters['optionalpassword']->getFlags());
}
}

View file

@ -28,7 +28,9 @@ use \OCA\Files_external\NotFoundException;
class GlobalStoragesControllerTest extends StoragesControllerTest {
public function 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(
'files_external',

View file

@ -1,6 +1,7 @@
<?php
/**
* @author Vincent Petry <pvince81@owncloud.com>
* @author Robin McCorkell <rmccorkell@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
@ -47,10 +48,48 @@ abstract class StoragesControllerTest extends \Test\TestCase {
\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('getIdentifier')
->willReturn('identifier:'.$class);
return $backend;
}
protected function getAuthMechMock($scheme = 'null', $class = '\OCA\Files_External\Lib\Auth\NullMechanism') {
$authMech = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism')
->disableOriginalConstructor()
->getMock();
$authMech->method('getScheme')
->willReturn($scheme);
$authMech->method('getIdentifier')
->willReturn('identifier:'.$class);
return $authMech;
}
public function testAddStorage() {
$authMech = $this->getAuthMechMock();
$authMech->method('validateStorage')
->willReturn(true);
$backend = $this->getBackendMock();
$backend->method('validateStorage')
->willReturn(true);
$backend->method('isVisibleFor')
->willReturn(true);
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('mount');
$storageConfig->setBackend($backend);
$storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions([]);
$this->service->expects($this->once())
->method('createStorage')
->will($this->returnValue($storageConfig));
$this->service->expects($this->once())
->method('addStorage')
->will($this->returnValue($storageConfig));
@ -58,6 +97,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$response = $this->controller->create(
'mount',
'\OC\Files\Storage\SMB',
'\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@ -66,14 +106,29 @@ abstract class StoragesControllerTest extends \Test\TestCase {
);
$data = $response->getData();
$this->assertEquals($storageConfig, $data);
$this->assertEquals(Http::STATUS_CREATED, $response->getStatus());
$this->assertEquals($storageConfig, $data);
}
public function testUpdateStorage() {
$authMech = $this->getAuthMechMock();
$authMech->method('validateStorage')
->willReturn(true);
$backend = $this->getBackendMock();
$backend->method('validateStorage')
->willReturn(true);
$backend->method('isVisibleFor')
->willReturn(true);
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('mount');
$storageConfig->setBackend($backend);
$storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions([]);
$this->service->expects($this->once())
->method('createStorage')
->will($this->returnValue($storageConfig));
$this->service->expects($this->once())
->method('updateStorage')
->will($this->returnValue($storageConfig));
@ -82,6 +137,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
1,
'mount',
'\OC\Files\Storage\SMB',
'\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@ -90,8 +146,8 @@ abstract class StoragesControllerTest extends \Test\TestCase {
);
$data = $response->getData();
$this->assertEquals($storageConfig, $data);
$this->assertEquals(Http::STATUS_OK, $response->getStatus());
$this->assertEquals($storageConfig, $data);
}
function mountPointNamesProvider() {
@ -106,6 +162,15 @@ abstract class StoragesControllerTest extends \Test\TestCase {
* @dataProvider mountPointNamesProvider
*/
public function testAddOrUpdateStorageInvalidMountPoint($mountPoint) {
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint($mountPoint);
$storageConfig->setBackend($this->getBackendMock());
$storageConfig->setAuthMechanism($this->getAuthMechMock());
$storageConfig->setBackendOptions([]);
$this->service->expects($this->exactly(2))
->method('createStorage')
->will($this->returnValue($storageConfig));
$this->service->expects($this->never())
->method('addStorage');
$this->service->expects($this->never())
@ -114,6 +179,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$response = $this->controller->create(
$mountPoint,
'\OC\Files\Storage\SMB',
'\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@ -127,6 +193,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
1,
$mountPoint,
'\OC\Files\Storage\SMB',
'\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@ -138,6 +205,9 @@ abstract class StoragesControllerTest extends \Test\TestCase {
}
public function testAddOrUpdateStorageInvalidBackend() {
$this->service->expects($this->exactly(2))
->method('createStorage')
->will($this->throwException(new \InvalidArgumentException()));
$this->service->expects($this->never())
->method('addStorage');
$this->service->expects($this->never())
@ -146,6 +216,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$response = $this->controller->create(
'mount',
'\OC\Files\Storage\InvalidStorage',
'\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@ -159,6 +230,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
1,
'mount',
'\OC\Files\Storage\InvalidStorage',
'\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@ -170,6 +242,24 @@ abstract class StoragesControllerTest extends \Test\TestCase {
}
public function testUpdateStorageNonExisting() {
$authMech = $this->getAuthMechMock();
$authMech->method('validateStorage')
->willReturn(true);
$backend = $this->getBackendMock();
$backend->method('validateStorage')
->willReturn(true);
$backend->method('isVisibleFor')
->willReturn(true);
$storageConfig = new StorageConfig(255);
$storageConfig->setMountPoint('mount');
$storageConfig->setBackend($backend);
$storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions([]);
$this->service->expects($this->once())
->method('createStorage')
->will($this->returnValue($storageConfig));
$this->service->expects($this->once())
->method('updateStorage')
->will($this->throwException(new NotFoundException()));
@ -178,6 +268,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
255,
'mount',
'\OC\Files\Storage\SMB',
'\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@ -206,9 +297,12 @@ abstract class StoragesControllerTest extends \Test\TestCase {
}
public function testGetStorage() {
$backend = $this->getBackendMock();
$authMech = $this->getAuthMechMock();
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('test');
$storageConfig->setBackendClass('\OC\Files\Storage\SMB');
$storageConfig->setBackend($backend);
$storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions(['user' => 'test', 'password', 'password123']);
$storageConfig->setMountOptions(['priority' => false]);
@ -221,4 +315,66 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$this->assertEquals(Http::STATUS_OK, $response->getStatus());
$this->assertEquals($storageConfig, $response->getData());
}
public function validateStorageProvider() {
return [
[true, true, true],
[false, true, false],
[true, false, false],
[false, false, false]
];
}
/**
* @dataProvider validateStorageProvider
*/
public function testValidateStorage($backendValidate, $authMechValidate, $expectSuccess) {
$backend = $this->getBackendMock();
$backend->method('validateStorage')
->willReturn($backendValidate);
$backend->method('isVisibleFor')
->willReturn(true);
$authMech = $this->getAuthMechMock();
$authMech->method('validateStorage')
->will($this->returnValue($authMechValidate));
$storageConfig = new StorageConfig();
$storageConfig->setMountPoint('mount');
$storageConfig->setBackend($backend);
$storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions([]);
$this->service->expects($this->once())
->method('createStorage')
->will($this->returnValue($storageConfig));
if ($expectSuccess) {
$this->service->expects($this->once())
->method('addStorage')
->with($storageConfig)
->will($this->returnValue($storageConfig));
} else {
$this->service->expects($this->never())
->method('addStorage');
}
$response = $this->controller->create(
'mount',
'\OC\Files\Storage\SMB',
'\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
[],
null
);
if ($expectSuccess) {
$this->assertEquals(Http::STATUS_CREATED, $response->getStatus());
} else {
$this->assertEquals(Http::STATUS_UNPROCESSABLE_ENTITY, $response->getStatus());
}
}
}

View file

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

View file

@ -0,0 +1,70 @@
<?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\Tests;
use \OCA\Files_External\Lib\DefinitionParameter as Param;
class DefinitionParameterTest extends \Test\TestCase {
public function testJsonSerialization() {
$param = new Param('foo', 'bar');
$this->assertEquals('bar', $param->jsonSerialize());
$param->setType(Param::VALUE_BOOLEAN);
$this->assertEquals('!bar', $param->jsonSerialize());
$param->setType(Param::VALUE_PASSWORD);
$param->setFlag(Param::FLAG_OPTIONAL);
$this->assertEquals('&*bar', $param->jsonSerialize());
$param->setType(Param::VALUE_HIDDEN);
$param->setFlags(Param::FLAG_NONE);
$this->assertEquals('#bar', $param->jsonSerialize());
}
public function validateValueProvider() {
return [
[Param::VALUE_TEXT, Param::FLAG_NONE, 'abc', true],
[Param::VALUE_TEXT, Param::FLAG_NONE, '', false],
[Param::VALUE_TEXT, Param::FLAG_OPTIONAL, '', true],
[Param::VALUE_BOOLEAN, Param::FLAG_NONE, false, true],
[Param::VALUE_BOOLEAN, Param::FLAG_NONE, 123, false],
[Param::VALUE_PASSWORD, Param::FLAG_NONE, 'foobar', true],
[Param::VALUE_PASSWORD, Param::FLAG_NONE, '', false],
[Param::VALUE_HIDDEN, Param::FLAG_NONE, '', false]
];
}
/**
* @dataProvider validateValueProvider
*/
public function testValidateValue($type, $flags, $value, $success) {
$param = new Param('foo', 'bar');
$param->setType($type);
$param->setFlags($flags);
$this->assertEquals($success, $param->validateValue($value));
}
}

View file

@ -0,0 +1,45 @@
<?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\Tests;
use \OCA\Files_External\Lib\MissingDependency;
class DependencyTraitTest extends \Test\TestCase {
public function testCheckDependencies() {
$trait = $this->getMockForTrait('\OCA\Files_External\Lib\DependencyTrait');
$trait->setDependencyCheck(function() {
return [
(new MissingDependency('dependency'))->setMessage('missing dependency'),
(new MissingDependency('program'))->setMessage('cannot find program'),
];
});
$dependencies = $trait->checkDependencies();
$this->assertCount(2, $dependencies);
$this->assertEquals('dependency', $dependencies[0]->getDependency());
$this->assertEquals('missing dependency', $dependencies[0]->getMessage());
$this->assertEquals('program', $dependencies[1]->getDependency());
$this->assertEquals('cannot find program', $dependencies[1]->getMessage());
}
}

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

@ -0,0 +1,83 @@
<?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\Tests;
class FrontendDefinitionTraitTest extends \Test\TestCase {
public function testJsonSerialization() {
$param = $this->getMockBuilder('\OCA\Files_External\Lib\DefinitionParameter')
->disableOriginalConstructor()
->getMock();
$param->method('getName')->willReturn('foo');
$trait = $this->getMockForTrait('\OCA\Files_External\Lib\FrontendDefinitionTrait');
$trait->setText('test');
$trait->addParameters([$param]);
$trait->setCustomJs('foo/bar.js');
$json = $trait->jsonSerializeDefinition();
$this->assertEquals('test', $json['name']);
$this->assertEquals('foo/bar.js', $json['custom']);
$configuration = $json['configuration'];
$this->assertArrayHasKey('foo', $configuration);
}
public function validateStorageProvider() {
return [
[true, ['foo' => true, 'bar' => true, 'baz' => true]],
[false, ['foo' => true, 'bar' => false]]
];
}
/**
* @dataProvider validateStorageProvider
*/
public function testValidateStorage($expectedSuccess, $params) {
$backendParams = [];
foreach ($params as $name => $valid) {
$param = $this->getMockBuilder('\OCA\Files_External\Lib\DefinitionParameter')
->disableOriginalConstructor()
->getMock();
$param->method('getName')
->willReturn($name);
$param->expects($this->once())
->method('validateValue')
->willReturn($valid);
$backendParams[] = $param;
}
$storageConfig = $this->getMockBuilder('\OCA\Files_External\Lib\StorageConfig')
->disableOriginalConstructor()
->getMock();
$storageConfig->expects($this->once())
->method('getBackendOptions')
->willReturn([]);
$trait = $this->getMockForTrait('\OCA\Files_External\Lib\FrontendDefinitionTrait');
$trait->setText('test');
$trait->addParameters($backendParams);
$this->assertEquals($expectedSuccess, $trait->validateStorageDefinition($storageConfig));
}
}

View file

@ -39,6 +39,7 @@ describe('OCA.External.Settings tests', function() {
'<option value="\\OC\\AnotherTestBackend">Another Test Backend</option>' +
'</select>' +
'</td>' +
'<td class="authentication"></td>' +
'<td class="configuration"></td>' +
'<td class="applicable">' +
'<input type="hidden" class="applicableUsers">' +
@ -58,6 +59,9 @@ describe('OCA.External.Settings tests', function() {
'field1': 'Display Name 1',
'field2': '&Display Name 2'
},
'authSchemes': {
'builtin': true,
},
'priority': 11
},
'\\OC\\AnotherTestBackend': {
@ -66,10 +70,23 @@ describe('OCA.External.Settings tests', function() {
'field1': 'Display Name 1',
'field2': '&Display Name 2'
},
'authSchemes': {
'builtin': true,
},
'priority': 12
}
}
);
$('#externalStorage #addMountPoint .authentication:first').data('mechanisms', {
'mechanism1': {
'name': 'Mechanism 1',
'configuration': {
},
'scheme': 'builtin',
},
});
});
afterEach(function() {
select2Stub.restore();
@ -80,7 +97,7 @@ describe('OCA.External.Settings tests', function() {
var view;
function selectBackend(backendName) {
view.$el.find('.selectBackend:first').val('\\OC\\TestBackend').trigger('change');
view.$el.find('.selectBackend:first').val(backendName).trigger('change');
}
beforeEach(function() {
@ -139,7 +156,8 @@ describe('OCA.External.Settings tests', function() {
var request = fakeServer.requests[0];
expect(request.url).toEqual(OC.webroot + '/index.php/apps/files_external/globalstorages');
expect(JSON.parse(request.requestBody)).toEqual({
backendClass: '\\OC\\TestBackend',
backend: '\\OC\\TestBackend',
authMechanism: 'mechanism1',
backendOptions: {
'field1': 'test',
'field2': ''

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,152 @@
<?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\Tests\Service;
use \OCA\Files_External\Service\BackendService;
class BackendServiceTest extends \Test\TestCase {
/** @var \OCP\IConfig */
protected $config;
/** @var \OCP\IL10N */
protected $l10n;
protected function setUp() {
$this->config = $this->getMock('\OCP\IConfig');
$this->l10n = $this->getMock('\OCP\IL10N');
}
protected function getBackendMock($class) {
$backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
->disableOriginalConstructor()
->getMock();
$backend->method('getIdentifier')->will($this->returnValue('identifier:'.$class));
$backend->method('getIdentifierAliases')->will($this->returnValue(['identifier:'.$class]));
return $backend;
}
public function testRegisterBackend() {
$service = new BackendService($this->config, $this->l10n);
$backend = $this->getBackendMock('\Foo\Bar');
$backendAlias = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
->disableOriginalConstructor()
->getMock();
$backendAlias->method('getIdentifierAliases')
->willReturn(['identifier_real', 'identifier_alias']);
$backendAlias->method('getIdentifier')
->willReturn('identifier_real');
$service->registerBackend($backend);
$service->registerBackend($backendAlias);
$this->assertEquals($backend, $service->getBackend('identifier:\Foo\Bar'));
$this->assertEquals($backendAlias, $service->getBackend('identifier_real'));
$this->assertEquals($backendAlias, $service->getBackend('identifier_alias'));
$backends = $service->getBackends();
$this->assertCount(2, $backends);
$this->assertArrayHasKey('identifier:\Foo\Bar', $backends);
$this->assertArrayHasKey('identifier_real', $backends);
$this->assertArrayNotHasKey('identifier_alias', $backends);
}
public function testUserMountingBackends() {
$this->config->expects($this->exactly(2))
->method('getAppValue')
->will($this->returnValueMap([
['files_external', 'allow_user_mounting', 'yes', 'yes'],
['files_external', 'user_mounting_backends', '', 'identifier:\User\Mount\Allowed,identifier_alias']
]));
$service = new BackendService($this->config, $this->l10n);
$backendAllowed = $this->getBackendMock('\User\Mount\Allowed');
$backendAllowed->expects($this->never())
->method('removeVisibility');
$backendNotAllowed = $this->getBackendMock('\User\Mount\NotAllowed');
$backendNotAllowed->expects($this->once())
->method('removeVisibility')
->with(BackendService::VISIBILITY_PERSONAL);
$backendAlias = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
->disableOriginalConstructor()
->getMock();
$backendAlias->method('getIdentifierAliases')
->willReturn(['identifier_real', 'identifier_alias']);
$backendAlias->expects($this->never())
->method('removeVisibility');
$service->registerBackend($backendAllowed);
$service->registerBackend($backendNotAllowed);
$service->registerBackend($backendAlias);
}
public function testGetAvailableBackends() {
$service = new BackendService($this->config, $this->l10n);
$backendAvailable = $this->getBackendMock('\Backend\Available');
$backendAvailable->expects($this->once())
->method('checkDependencies')
->will($this->returnValue([]));
$backendNotAvailable = $this->getBackendMock('\Backend\NotAvailable');
$backendNotAvailable->expects($this->once())
->method('checkDependencies')
->will($this->returnValue([
$this->getMockBuilder('\OCA\Files_External\Lib\MissingDependency')
->disableOriginalConstructor()
->getMock()
]));
$service->registerBackend($backendAvailable);
$service->registerBackend($backendNotAvailable);
$availableBackends = $service->getAvailableBackends();
$this->assertArrayHasKey('identifier:\Backend\Available', $availableBackends);
$this->assertArrayNotHasKey('identifier:\Backend\NotAvailable', $availableBackends);
}
public function testGetUserBackends() {
$service = new BackendService($this->config, $this->l10n);
$backendAllowed = $this->getBackendMock('\User\Mount\Allowed');
$backendAllowed->expects($this->once())
->method('isVisibleFor')
->with(BackendService::VISIBILITY_PERSONAL)
->will($this->returnValue(true));
$backendNotAllowed = $this->getBackendMock('\User\Mount\NotAllowed');
$backendNotAllowed->expects($this->once())
->method('isVisibleFor')
->with(BackendService::VISIBILITY_PERSONAL)
->will($this->returnValue(false));
$service->registerBackend($backendAllowed);
$service->registerBackend($backendNotAllowed);
$userBackends = $service->getBackendsVisibleFor(BackendService::VISIBILITY_PERSONAL);
$this->assertArrayHasKey('identifier:\User\Mount\Allowed', $userBackends);
$this->assertArrayNotHasKey('identifier:\User\Mount\NotAllowed', $userBackends);
}
}

View file

@ -29,7 +29,7 @@ use \OCA\Files_external\Lib\StorageConfig;
class GlobalStoragesServiceTest extends StoragesServiceTest {
public function setUp() {
parent::setUp();
$this->service = new GlobalStoragesService();
$this->service = new GlobalStoragesService($this->backendService);
}
public function tearDown() {
@ -40,7 +40,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
protected function makeTestStorageData() {
return $this->makeStorageConfig([
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@ -59,9 +60,10 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
return [
// all users
[
$this->makeStorageConfig([
[
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@ -70,13 +72,14 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
'applicableUsers' => [],
'applicableGroups' => [],
'priority' => 15,
]),
],
],
// some users
[
$this->makeStorageConfig([
[
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@ -85,13 +88,14 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
'applicableUsers' => ['user1', 'user2'],
'applicableGroups' => [],
'priority' => 15,
]),
],
],
// some groups
[
$this->makeStorageConfig([
[
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@ -100,13 +104,14 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
'applicableUsers' => [],
'applicableGroups' => ['group1', 'group2'],
'priority' => 15,
]),
],
],
// both users and groups
[
$this->makeStorageConfig([
[
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@ -115,7 +120,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
'applicableUsers' => ['user1', 'user2'],
'applicableGroups' => ['group1', 'group2'],
'priority' => 15,
]),
],
],
];
}
@ -123,7 +128,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
/**
* @dataProvider storageDataProvider
*/
public function testAddStorage($storage) {
public function testAddStorage($storageParams) {
$storage = $this->makeStorageConfig($storageParams);
$newStorage = $this->service->addStorage($storage);
$this->assertEquals(1, $newStorage->getId());
@ -132,7 +138,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$newStorage = $this->service->getStorage(1);
$this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint());
$this->assertEquals($storage->getBackendClass(), $newStorage->getBackendClass());
$this->assertEquals($storage->getBackend(), $newStorage->getBackend());
$this->assertEquals($storage->getAuthMechanism(), $newStorage->getAuthMechanism());
$this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions());
$this->assertEquals($storage->getApplicableUsers(), $newStorage->getApplicableUsers());
$this->assertEquals($storage->getApplicableGroups(), $newStorage->getApplicableGroups());
@ -148,10 +155,12 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
/**
* @dataProvider storageDataProvider
*/
public function testUpdateStorage($updatedStorage) {
public function testUpdateStorage($updatedStorageParams) {
$updatedStorage = $this->makeStorageConfig($updatedStorageParams);
$storage = $this->makeStorageConfig([
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@ -638,7 +647,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$mountPointOptions = current($mountPointData);
$this->assertEquals(1, $mountPointOptions['id']);
$this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
$this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']);
$this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(15, $mountPointOptions['priority']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
@ -678,7 +688,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$mountPointOptions = current($mountPointData);
$this->assertEquals(1, $mountPointOptions['id']);
$this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
$this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']);
$this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(15, $mountPointOptions['priority']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
@ -695,7 +706,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$mountPointOptions = current($mountPointData);
$this->assertEquals(1, $mountPointOptions['id']);
$this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
$this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']);
$this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(15, $mountPointOptions['priority']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
@ -720,13 +732,15 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$legacyBackendOptions = \OC_Mount_Config::encryptPasswords($legacyBackendOptions);
$legacyConfig = [
'class' => '\OC\Files\Storage\SMB',
'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
'authMechanism' => 'identifier:\Auth\Mechanism',
'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => false],
];
// different mount options
$legacyConfig2 = [
'class' => '\OC\Files\Storage\SMB',
'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
'authMechanism' => 'identifier:\Auth\Mechanism',
'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => true],
];
@ -737,7 +751,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
// different config
$legacyConfig3 = [
'class' => '\OC\Files\Storage\SMB',
'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
'authMechanism' => 'identifier:\Auth\Mechanism',
'options' => $legacyBackendOptions2,
'mountOptions' => ['preview' => true],
];
@ -811,4 +826,85 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$this->assertEquals([], $storage4->getApplicableGroups());
$this->assertEquals(['preview' => true], $storage4->getMountOptions());
}
public function testReadLegacyConfigNoAuthMechanism() {
$configFile = $this->dataDir . '/mount.json';
$json = [
'user' => [
'user1' => [
'/$user/files/somemount' => [
'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SFTP',
'authMechanism' => 'identifier:\Auth\Mechanism',
'options' => [],
'mountOptions' => [],
],
'/$user/files/othermount' => [
'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SFTP',
// no authMechanism
'options' => [],
'mountOptions' => [],
],
]
]
];
file_put_contents($configFile, json_encode($json));
$allStorages = $this->service->getAllStorages();
$this->assertCount(2, $allStorages);
$storage1 = $allStorages[1];
$storage2 = $allStorages[2];
$this->assertEquals('/somemount', $storage1->getMountPoint());
$this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage1->getBackend()->getIdentifier());
$this->assertEquals('identifier:\Auth\Mechanism', $storage1->getAuthMechanism()->getIdentifier());
$this->assertEquals('/othermount', $storage2->getMountPoint());
$this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage2->getBackend()->getIdentifier());
$this->assertEquals('identifier:\Other\Auth\Mechanism', $storage2->getAuthMechanism()->getIdentifier());
}
public function testReadLegacyConfigClass() {
$configFile = $this->dataDir . '/mount.json';
$json = [
'user' => [
'user1' => [
'/$user/files/somemount' => [
'class' => 'identifier:\OCA\Files_External\Lib\Backend\SFTP',
'authMechanism' => 'identifier:\Auth\Mechanism',
'options' => [],
'mountOptions' => [],
],
'/$user/files/othermount' => [
'class' => 'identifier:sftp_alias',
'authMechanism' => 'identifier:\Auth\Mechanism',
'options' => [],
'mountOptions' => [],
],
]
]
];
file_put_contents($configFile, json_encode($json));
$allStorages = $this->service->getAllStorages();
$this->assertCount(2, $allStorages);
$storage1 = $allStorages[1];
$storage2 = $allStorages[2];
$this->assertEquals('/somemount', $storage1->getMountPoint());
$this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage1->getBackend()->getIdentifier());
$this->assertEquals('identifier:\Auth\Mechanism', $storage1->getAuthMechanism()->getIdentifier());
$this->assertEquals('/othermount', $storage2->getMountPoint());
$this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage2->getBackend()->getIdentifier());
$this->assertEquals('identifier:\Auth\Mechanism', $storage2->getAuthMechanism()->getIdentifier());
}
}

View file

@ -1,6 +1,7 @@
<?php
/**
* @author Vincent Petry <pvince81@owncloud.com>
* @author Robin McCorkell <rmccorkell@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
@ -24,6 +25,7 @@ use \OC\Files\Filesystem;
use \OCA\Files_external\NotFoundException;
use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_External\Lib\BackendService;
abstract class StoragesServiceTest extends \Test\TestCase {
@ -32,6 +34,9 @@ abstract class StoragesServiceTest extends \Test\TestCase {
*/
protected $service;
/** @var BackendService */
protected $backendService;
/**
* Data directory
*
@ -55,6 +60,51 @@ abstract class StoragesServiceTest extends \Test\TestCase {
);
\OC_Mount_Config::$skipTest = true;
// prepare BackendService mock
$this->backendService =
$this->getMockBuilder('\OCA\Files_External\Service\BackendService')
->disableOriginalConstructor()
->getMock();
$authMechanisms = [
'identifier:\Auth\Mechanism' => $this->getAuthMechMock('null', '\Auth\Mechanism'),
'identifier:\Other\Auth\Mechanism' => $this->getAuthMechMock('null', '\Other\Auth\Mechanism'),
'identifier:\OCA\Files_External\Lib\Auth\NullMechanism' => $this->getAuthMechMock(),
];
$this->backendService->method('getAuthMechanism')
->will($this->returnCallback(function($class) use ($authMechanisms) {
if (isset($authMechanisms[$class])) {
return $authMechanisms[$class];
}
return null;
}));
$this->backendService->method('getAuthMechanismsByScheme')
->will($this->returnCallback(function($schemes) use ($authMechanisms) {
return array_filter($authMechanisms, function ($authMech) use ($schemes) {
return in_array($authMech->getScheme(), $schemes, true);
});
}));
$this->backendService->method('getAuthMechanisms')
->will($this->returnValue($authMechanisms));
$sftpBackend = $this->getBackendMock('\OCA\Files_External\Lib\Backend\SFTP', '\OC\Files\Storage\SFTP');
$backends = [
'identifier:\OCA\Files_External\Lib\Backend\SMB' => $this->getBackendMock('\OCA\Files_External\Lib\Backend\SMB', '\OC\Files\Storage\SMB'),
'identifier:\OCA\Files_External\Lib\Backend\SFTP' => $sftpBackend,
'identifier:sftp_alias' => $sftpBackend,
];
$backends['identifier:\OCA\Files_External\Lib\Backend\SFTP']->method('getLegacyAuthMechanism')
->willReturn($authMechanisms['identifier:\Other\Auth\Mechanism']);
$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(
Filesystem::CLASSNAME,
Filesystem::signal_create_mount,
@ -64,6 +114,19 @@ abstract class StoragesServiceTest extends \Test\TestCase {
Filesystem::signal_delete_mount,
get_class($this), 'deleteHookCallback');
$containerMock = $this->getMock('\OCP\AppFramework\IAppContainer');
$containerMock->method('query')
->will($this->returnCallback(function($name) {
if ($name === 'OCA\Files_External\Service\BackendService') {
return $this->backendService;
}
}));
\OC_Mount_Config::$app = $this->getMockBuilder('\OCA\Files_External\Appinfo\Application')
->disableOriginalConstructor()
->getMock();
\OC_Mount_Config::$app->method('getContainer')
->willReturn($containerMock);
}
public function tearDown() {
@ -71,6 +134,29 @@ abstract class StoragesServiceTest extends \Test\TestCase {
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('getIdentifier')
->willReturn('identifier:'.$class);
return $backend;
}
protected function getAuthMechMock($scheme = 'null', $class = '\OCA\Files_External\Lib\Auth\NullMechanism') {
$authMech = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism')
->disableOriginalConstructor()
->getMock();
$authMech->method('getScheme')
->willReturn($scheme);
$authMech->method('getIdentifier')
->willReturn('identifier:'.$class);
return $authMech;
}
/**
* Creates a StorageConfig instance based on array data
*
@ -84,7 +170,22 @@ abstract class StoragesServiceTest extends \Test\TestCase {
$storage->setId($data['id']);
}
$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['backendIdentifier']);
}
if (!isset($data['backend'])) {
throw new \Exception('oops, no backend');
}
if (!isset($data['authMechanism'])) {
$data['authMechanism'] = $this->backendService->getAuthMechanism($data['authMechanismIdentifier']);
}
if (!isset($data['authMechanism'])) {
throw new \Exception('oops, no auth mechanism');
}
$storage->setBackend($data['backend']);
$storage->setAuthMechanism($data['authMechanism']);
$storage->setBackendOptions($data['backendOptions']);
if (isset($data['applicableUsers'])) {
$storage->setApplicableUsers($data['applicableUsers']);
@ -106,16 +207,22 @@ abstract class StoragesServiceTest extends \Test\TestCase {
* @expectedException \OCA\Files_external\NotFoundException
*/
public function testNonExistingStorage() {
$backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
$authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
$storage = new StorageConfig(255);
$storage->setMountPoint('mountpoint');
$storage->setBackendClass('\OC\Files\Storage\SMB');
$storage->setBackend($backend);
$storage->setAuthMechanism($authMechanism);
$this->service->updateStorage($storage);
}
public function testDeleteStorage() {
$backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
$authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
$storage = new StorageConfig(255);
$storage->setMountPoint('mountpoint');
$storage->setBackendClass('\OC\Files\Storage\SMB');
$storage->setBackend($backend);
$storage->setAuthMechanism($authMechanism);
$storage->setBackendOptions(['password' => 'testPassword']);
$newStorage = $this->service->addStorage($storage);
@ -140,6 +247,64 @@ abstract class StoragesServiceTest extends \Test\TestCase {
$this->service->removeStorage(255);
}
public function testCreateStorage() {
$mountPoint = 'mount';
$backendIdentifier = 'identifier:\OCA\Files_External\Lib\Backend\SMB';
$authMechanismIdentifier = 'identifier:\Auth\Mechanism';
$backendOptions = ['param' => 'foo', 'param2' => 'bar'];
$mountOptions = ['option' => 'foobar'];
$applicableUsers = ['user1', 'user2'];
$applicableGroups = ['group'];
$priority = 123;
$backend = $this->backendService->getBackend($backendIdentifier);
$authMechanism = $this->backendService->getAuthMechanism($authMechanismIdentifier);
$storage = $this->service->createStorage(
$mountPoint,
$backendIdentifier,
$authMechanismIdentifier,
$backendOptions,
$mountOptions,
$applicableUsers,
$applicableGroups,
$priority
);
$this->assertEquals('/'.$mountPoint, $storage->getMountPoint());
$this->assertEquals($backend, $storage->getBackend());
$this->assertEquals($authMechanism, $storage->getAuthMechanism());
$this->assertEquals($backendOptions, $storage->getBackendOptions());
$this->assertEquals($mountOptions, $storage->getMountOptions());
$this->assertEquals($applicableUsers, $storage->getApplicableUsers());
$this->assertEquals($applicableGroups, $storage->getApplicableGroups());
$this->assertEquals($priority, $storage->getPriority());
}
/**
* @expectedException \InvalidArgumentException
*/
public function testCreateStorageInvalidClass() {
$this->service->createStorage(
'mount',
'identifier:\OC\Not\A\Backend',
'identifier:\Auth\Mechanism',
[]
);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testCreateStorageInvalidAuthMechanismClass() {
$this->service->createStorage(
'mount',
'identifier:\OCA\Files_External\Lib\Backend\SMB',
'identifier:\Not\An\Auth\Mechanism',
[]
);
}
public static function createHookCallback($params) {
self::$hookCalls[] = array(
'signal' => Filesystem::signal_create_mount,

View file

@ -0,0 +1,215 @@
<?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\Tests\Service;
use \OCA\Files_External\Service\UserGlobalStoragesService;
use \OCP\IGroupManager;
use \OCA\Files_External\Lib\StorageConfig;
class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest {
protected $groupManager;
protected $globalStoragesService;
protected $user;
const USER_ID = 'test_user';
const GROUP_ID = 'test_group';
public function setUp() {
parent::setUp();
$this->globalStoragesService = $this->service;
$this->user = new \OC\User\User(self::USER_ID, null);
$userSession = $this->getMock('\OCP\IUserSession');
$userSession
->expects($this->any())
->method('getUser')
->will($this->returnValue($this->user));
$this->groupManager = $this->getMock('\OCP\IGroupManager');
$this->groupManager->method('isInGroup')
->will($this->returnCallback(function($userId, $groupId) {
if ($userId === self::USER_ID && $groupId === self::GROUP_ID) {
return true;
}
return false;
}));
$this->service = new UserGlobalStoragesService(
$this->backendService,
$userSession,
$this->groupManager
);
}
public function applicableStorageProvider() {
return [
[[], [], true],
// not applicable cases
[['user1'], [], false],
[[], ['group1'], false],
[['user1'], ['group1'], false],
// applicable cases
[[self::USER_ID], [], true],
[[], [self::GROUP_ID], true],
[[self::USER_ID], ['group1'], true],
[['user1'], [self::GROUP_ID], true],
// sanity checks
[['user1', 'user2', self::USER_ID, 'user3'], [], true],
];
}
/**
* @dataProvider applicableStorageProvider
*/
public function testGetStorageWithApplicable($applicableUsers, $applicableGroups, $isVisible) {
$backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
$authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
$storage = new StorageConfig();
$storage->setMountPoint('mountpoint');
$storage->setBackend($backend);
$storage->setAuthMechanism($authMechanism);
$storage->setBackendOptions(['password' => 'testPassword']);
$storage->setApplicableUsers($applicableUsers);
$storage->setApplicableGroups($applicableGroups);
$newStorage = $this->globalStoragesService->addStorage($storage);
$storages = $this->service->getAllStorages();
if ($isVisible) {
$this->assertEquals(1, count($storages));
$retrievedStorage = $this->service->getStorage($newStorage->getId());
$this->assertEquals('/mountpoint', $retrievedStorage->getMountPoint());
} else {
$this->assertEquals(0, count($storages));
}
}
/**
* @expectedException \DomainException
*/
public function testAddStorage($storageParams = null) {
$backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
$authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
$storage = new StorageConfig(255);
$storage->setMountPoint('mountpoint');
$storage->setBackend($backend);
$storage->setAuthMechanism($authMechanism);
$storage->setBackendOptions(['password' => 'testPassword']);
$this->service->addStorage($storage);
}
/**
* @expectedException \DomainException
*/
public function testUpdateStorage($storageParams = null) {
$backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
$authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
$storage = new StorageConfig(255);
$storage->setMountPoint('mountpoint');
$storage->setBackend($backend);
$storage->setAuthMechanism($authMechanism);
$storage->setBackendOptions(['password' => 'testPassword']);
$newStorage = $this->globalStoragesService->addStorage($storage);
$retrievedStorage = $this->service->getStorage($newStorage->getId());
$retrievedStorage->setMountPoint('abc');
$this->service->updateStorage($retrievedStorage);
}
/**
* @expectedException \DomainException
*/
public function testDeleteStorage() {
$backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
$authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
$storage = new StorageConfig(255);
$storage->setMountPoint('mountpoint');
$storage->setBackend($backend);
$storage->setAuthMechanism($authMechanism);
$storage->setBackendOptions(['password' => 'testPassword']);
$newStorage = $this->globalStoragesService->addStorage($storage);
$this->assertEquals(1, $newStorage->getId());
$this->service->removeStorage(1);
}
public function testHooksAddStorage($a = null, $b = null, $c = null) {
// we don't test this here
$this->assertTrue(true);
}
public function testHooksUpdateStorage($a = null, $b = null, $c = null, $d = null, $e = null) {
// we don't test this here
$this->assertTrue(true);
}
public function testHooksRenameMountPoint() {
// we don't test this here
$this->assertTrue(true);
}
public function testHooksDeleteStorage($a = null, $b = null, $c = null) {
// we don't test this here
$this->assertTrue(true);
}
public function testLegacyConfigConversionApplicableAll() {
// we don't test this here
$this->assertTrue(true);
}
public function testLegacyConfigConversionApplicableUserAndGroup() {
// we don't test this here
$this->assertTrue(true);
}
public function testReadLegacyConfigAndGenerateConfigId() {
// we don't test this here
$this->assertTrue(true);
}
public function testReadLegacyConfigNoAuthMechanism() {
// we don't test this here
$this->assertTrue(true);
}
public function testReadLegacyConfigClass() {
// we don't test this here
$this->assertTrue(true);
}
}

View file

@ -40,7 +40,7 @@ class UserStoragesServiceTest extends StoragesServiceTest {
->method('getUser')
->will($this->returnValue($this->user));
$this->service = new UserStoragesService($userSession);
$this->service = new UserStoragesService($this->backendService, $userSession);
// create home folder
mkdir($this->dataDir . '/' . $this->userId . '/');
@ -54,7 +54,8 @@ class UserStoragesServiceTest extends StoragesServiceTest {
private function makeTestStorageData() {
return $this->makeStorageConfig([
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@ -76,7 +77,8 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$newStorage = $this->service->getStorage(1);
$this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint());
$this->assertEquals($storage->getBackendClass(), $newStorage->getBackendClass());
$this->assertEquals($storage->getBackend(), $newStorage->getBackend());
$this->assertEquals($storage->getAuthMechanism(), $newStorage->getAuthMechanism());
$this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions());
$this->assertEquals(1, $newStorage->getId());
$this->assertEquals(0, $newStorage->getStatus());
@ -98,7 +100,8 @@ class UserStoragesServiceTest extends StoragesServiceTest {
public function testUpdateStorage() {
$storage = $this->makeStorageConfig([
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@ -191,7 +194,8 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$mountPointOptions = current($mountPointData);
$this->assertEquals(1, $mountPointOptions['id']);
$this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
$this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']);
$this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
$backendOptions = $mountPointOptions['options'];
@ -214,13 +218,15 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$legacyBackendOptions = \OC_Mount_Config::encryptPasswords($legacyBackendOptions);
$legacyConfig = [
'class' => '\OC\Files\Storage\SMB',
'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
'authMechanism' => 'identifier:\Auth\Mechanism',
'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => false],
];
// different mount options
$legacyConfig2 = [
'class' => '\OC\Files\Storage\SMB',
'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
'authMechanism' => 'identifier:\Auth\Mechanism',
'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => true],
];

View file

@ -26,9 +26,22 @@ use \OCA\Files_external\Lib\StorageConfig;
class StorageConfigTest extends \Test\TestCase {
public function testJsonSerialization() {
$backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
->disableOriginalConstructor()
->getMock();
$backend->method('getIdentifier')
->willReturn('storage::identifier');
$authMech = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism')
->disableOriginalConstructor()
->getMock();
$authMech->method('getIdentifier')
->willReturn('auth::identifier');
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('test');
$storageConfig->setBackendClass('\OC\Files\Storage\SMB');
$storageConfig->setBackend($backend);
$storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions(['user' => 'test', 'password' => 'password123']);
$storageConfig->setPriority(128);
$storageConfig->setApplicableUsers(['user1', 'user2']);
@ -39,7 +52,8 @@ class StorageConfigTest extends \Test\TestCase {
$this->assertEquals(1, $json['id']);
$this->assertEquals('/test', $json['mountPoint']);
$this->assertEquals('\OC\Files\Storage\SMB', $json['backendClass']);
$this->assertEquals('storage::identifier', $json['backend']);
$this->assertEquals('auth::identifier', $json['authMechanism']);
$this->assertEquals('test', $json['backendOptions']['user']);
$this->assertEquals('password123', $json['backendOptions']['password']);
$this->assertEquals(128, $json['priority']);

View file

@ -431,14 +431,16 @@ table.grid td.date{
}
span.success {
background: #37ce02;
border-radius: 3px;
background: #37ce02;
border-radius: 3px;
}
span.error {
background: #ce3702;
background: #ce3702;
}
span.indeterminate {
background: #e6db00;
border-radius: 40% 0;
}
/* PASSWORD */
.strengthify-wrapper {

View file

@ -108,10 +108,7 @@ $clients = array(
$enableCertImport = false;
$externalStorageEnabled = \OC::$server->getAppManager()->isEnabledForUser('files_external');
if ($externalStorageEnabled) {
$backends = OC_Mount_Config::getPersonalBackends();
if (!empty($backends)) {
$enableCertImport = true;
}
$enableCertImport = true;
}