From a1704c86233312c4574bc368b78b73fb6b605c2b Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Sun, 13 Sep 2015 23:23:42 +0100 Subject: [PATCH 1/9] Render external storages list in JS --- .../controller/storagescontroller.php | 14 ++ apps/files_external/js/settings.js | 208 +++++++++++------- apps/files_external/templates/settings.php | 67 ------ 3 files changed, 140 insertions(+), 149 deletions(-) diff --git a/apps/files_external/controller/storagescontroller.php b/apps/files_external/controller/storagescontroller.php index 048f3588ed..c66bd902d8 100644 --- a/apps/files_external/controller/storagescontroller.php +++ b/apps/files_external/controller/storagescontroller.php @@ -255,6 +255,20 @@ abstract class StoragesController extends Controller { } } + /** + * Get all storage entries + * + * @return DataResponse + */ + public function index() { + $storages = $this->service->getAllStorages(); + + return new DataResponse( + $storages, + Http::STATUS_OK + ); + } + /** * Get an external storage entry. * diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index a839f396b9..9b048ba193 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -623,36 +623,9 @@ MountConfigListView.prototype = _.extend({ 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) { - var $tr = $(tr); - var $applicable = $tr.find('.applicable'); - if ($applicable.length > 0) { - var groups = $applicable.data('applicable-groups'); - var groupsId = []; - $.each(groups, function () { - groupsId.push(this + '(group)'); - }); - var users = $applicable.data('applicable-users'); - if (users.indexOf('all') > -1 || users === '') { - $tr.find('.applicableUsers').val(''); - } else { - $tr.find('.applicableUsers').val(groupsId.concat(users).join(',')); - } - } - }); - - addSelect2(this.$el.find('tr:not(#addMountPoint) .applicableUsers'), this._userListLimit); - this.$el.tooltip({ - selector: '.status span', - container: 'body' - }); - this._initEvents(); - this.$el.find('tbody tr:not(#addMountPoint)').each(function(i, tr) { - self.recheckStorageConfig($(tr)); - }); + this.loadStorages(); }, /** @@ -661,7 +634,7 @@ MountConfigListView.prototype = _.extend({ */ whenSelectBackend: function(callback) { this.$el.find('tbody tr:not(#addMountPoint)').each(function(i, tr) { - var backend = $(tr).find('.backend').data('class'); + var backend = $(tr).find('.backend').data('identifier'); callback($(tr), backend); }); this.on('selectBackend', callback); @@ -725,57 +698,15 @@ MountConfigListView.prototype = _.extend({ _onSelectBackend: function(event) { var $target = $(event.target); - var $el = this.$el; var $tr = $target.closest('tr'); - $el.find('tbody').append($tr.clone()); - $el.find('tbody tr').last().find('.mountPoint input').val(''); - $tr.data('constructing', true); - var selected = $target.find('option:selected').text(); - 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(backend); - $tr.find('.backend').data('class', backend); - var backendConfiguration = this._allBackends[backend]; - var selectAuthMechanism = $(''); - $.each(this._allAuthMechanisms, function(authClass, authMechanism) { - if (backendConfiguration['authSchemes'][authMechanism['scheme']]) { - selectAuthMechanism.append( - $('') - ); - } - }); - $tr.find('td.authentication').append(selectAuthMechanism); + var storageConfig = new this._storageConfigClass(); + storageConfig.mountPoint = $tr.find('.mountPoint input').val(); + storageConfig.backend = $target.val(); - var $td = $tr.find('td.configuration'); - $.each(backendConfiguration['configuration'], _.partial(this.writeParameterInput, $td)); + $tr = this.newStorage(storageConfig); - this.trigger('selectBackend', $tr, backend); - - selectAuthMechanism.trigger('change'); // generate configuration parameters for auth mechanism - - var priorityEl = $(''); - $tr.append(priorityEl); - $td.children().not('[type=hidden]').first().focus(); - - // FIXME default backend mount options - $tr.find('input.mountOptions').val(JSON.stringify({ - 'encrypt': true, - 'previews': true, - 'filesystem_check_changes': 1 - })); - - $tr.find('td').last().attr('class', 'remove'); - $tr.find('td.mountOptionsToggle').removeClass('hidden'); - $tr.find('td').last().removeAttr('style'); - $tr.removeAttr('id'); - $target.remove(); - addSelect2($tr.find('.applicableUsers'), this._userListLimit); - - $tr.removeData('constructing'); + $tr.find('td.configuration').children().not('[type=hidden]').first().focus(); this.saveStorageConfig($tr); }, @@ -802,6 +733,118 @@ MountConfigListView.prototype = _.extend({ } }, + /** + * Create a config row for a new storage + * + * @param {StorageConfig} storageConfig storage config to pull values from + * @return {jQuery} created row + */ + newStorage: function(storageConfig) { + var mountPoint = storageConfig.mountPoint; + var backend = this._allBackends[storageConfig.backend]; + + // FIXME: Replace with a proper Handlebar template + var $tr = this.$el.find('tr#addMountPoint'); + this.$el.find('tbody').append($tr.clone()); + + $tr.find('td').last().attr('class', 'remove'); + $tr.find('td.mountOptionsToggle').removeClass('hidden'); + $tr.find('td').last().removeAttr('style'); + $tr.removeAttr('id'); + $tr.find('select#selectBackend'); + addSelect2($tr.find('.applicableUsers'), this._userListLimit); + + $tr.data('constructing', true); + + if (storageConfig.id) { + $tr.data('id', storageConfig.id); + } + + $tr.find('.backend').text(backend.name); + if (mountPoint === '') { + mountPoint = this._suggestMountPoint(backend.name); + } + $tr.find('.mountPoint input').val(mountPoint); + $tr.addClass(backend.identifier); + $tr.find('.backend').data('identifier', backend.identifier); + + var selectAuthMechanism = $(''); + $.each(this._allAuthMechanisms, function(authIdentifier, authMechanism) { + if (backend.authSchemes[authMechanism.scheme]) { + selectAuthMechanism.append( + $('') + ); + } + }); + if (storageConfig.authMechanism) { + selectAuthMechanism.val(storageConfig.authMechanism); + } + $tr.find('td.authentication').append(selectAuthMechanism); + + var $td = $tr.find('td.configuration'); + $.each(backend.configuration, _.partial(this.writeParameterInput, $td)); + + this.trigger('selectBackend', $tr, backend.identifier); + + selectAuthMechanism.trigger('change'); // generate configuration parameters for auth mechanism + + if (storageConfig.backendOptions) { + $td.children().each(function() { + var input = $(this); + input.val(storageConfig.backendOptions[input.data('parameter')]); + highlightInput(input); + }); + } + + var priorityEl = $(''); + $tr.append(priorityEl); + + if (storageConfig.mountOptions) { + $tr.find('input.mountOptions').val(JSON.stringify(storageConfig.mountOptions)); + } else { + // FIXME default backend mount options + $tr.find('input.mountOptions').val(JSON.stringify({ + 'encrypt': true, + 'previews': true, + 'filesystem_check_changes': 1 + })); + } + + $tr.removeData('constructing'); + return $tr; + }, + + /** + * Load storages into config rows + */ + loadStorages: function() { + var self = this; + + var url = this._storageConfigClass.prototype._url; + + $.ajax({ + type: 'GET', + url: OC.generateUrl(url), + contentType: 'application/json', + success: function(result) { + $.each(result, function(i, storageParams) { + storageParams.mountPoint = storageParams.mountPoint.substr(1); // trim leading slash + var storageConfig = new self._storageConfigClass(); + _.extend(storageConfig, storageParams); + var $tr = self.newStorage(storageConfig); + self.recheckStorageConfig($tr); + }); + } + }); + }, + + /** + * @param {jQuery} $td + * @param {string} parameter + * @param {string} placeholder + * @param {Array} classes + * @return {jQuery} newly created input + */ writeParameterInput: function($td, parameter, placeholder, classes) { classes = $.isArray(classes) ? classes : []; classes.push('added'); @@ -822,6 +865,7 @@ MountConfigListView.prototype = _.extend({ } highlightInput(newElement); $td.append(newElement); + return newElement; }, /** @@ -831,14 +875,14 @@ MountConfigListView.prototype = _.extend({ * @return {OCA.External.StorageConfig} storage model instance */ getStorageConfig: function($tr) { - var storageId = parseInt($tr.attr('data-id'), 10); + var storageId = $tr.data('id'); if (!storageId) { // new entry storageId = null; } var storage = new this._storageConfigClass(storageId); storage.mountPoint = $tr.find('.mountPoint input').val(); - storage.backend = $tr.find('.backend').data('class'); + storage.backend = $tr.find('.backend').data('identifier'); storage.authMechanism = $tr.find('.selectAuthMechanism').val(); var classOptions = {}; @@ -951,8 +995,8 @@ MountConfigListView.prototype = _.extend({ if (concurrentTimer === undefined || $tr.data('save-timer') === concurrentTimer ) { - self.updateStatus($tr, result.status, result.statusMessage); - $tr.attr('data-id', result.id); + self.updateStatus($tr, result.status); + $tr.data('id', result.id); if (_.isFunction(callback)) { callback(storage); @@ -1054,12 +1098,12 @@ MountConfigListView.prototype = _.extend({ } return defaultMountPoint + append; }, - + /** * Toggles the mount options dropdown * * @param {Object} $tr configuration row - */ + */ _showMountOptionsDropdown: function($tr) { if (this._preventNextDropdown) { // prevented because the click was on the toggle diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php index cebf6cc4de..14136a9bad 100644 --- a/apps/files_external/templates/settings.php +++ b/apps/files_external/templates/settings.php @@ -70,73 +70,6 @@ - - - - - - - - getBackend()->getText()); ?> - - - - - - getBackendOptions(); - foreach ($storage->getBackend()->getParameters() as $parameter) { - writeParameterInput($parameter, $options); - } - foreach ($storage->getAuthMechanism()->getParameters() as $parameter) { - writeParameterInput($parameter, $options, ['auth-param']); - } - ?> - - - - - - - - <?php p($l->t('Advanced settings')); ?> - - - - - - - <?php p($l->t('Delete')); ?> - - - From 28876bf46363116218c48021ddf556c53d5256f5 Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Mon, 14 Sep 2015 13:57:49 +0100 Subject: [PATCH 2/9] Display applicable global storages in personal mount list --- apps/files_external/appinfo/routes.php | 1 + .../userglobalstoragescontroller.php | 121 ++++++++++++++++++ apps/files_external/js/settings.js | 31 +++++ apps/files_external/personal.php | 26 +--- apps/files_external/settings.php | 31 +---- apps/files_external/templates/settings.php | 34 ++++- 6 files changed, 187 insertions(+), 57 deletions(-) create mode 100644 apps/files_external/controller/userglobalstoragescontroller.php diff --git a/apps/files_external/appinfo/routes.php b/apps/files_external/appinfo/routes.php index 39ded1dc2e..e66c010a8c 100644 --- a/apps/files_external/appinfo/routes.php +++ b/apps/files_external/appinfo/routes.php @@ -36,6 +36,7 @@ namespace OCA\Files_External\AppInfo; 'resources' => array( 'global_storages' => array('url' => '/globalstorages'), 'user_storages' => array('url' => '/userstorages'), + 'user_global_storages' => array('url' => '/userglobalstorages'), ), 'routes' => array( array( diff --git a/apps/files_external/controller/userglobalstoragescontroller.php b/apps/files_external/controller/userglobalstoragescontroller.php new file mode 100644 index 0000000000..b77e23104e --- /dev/null +++ b/apps/files_external/controller/userglobalstoragescontroller.php @@ -0,0 +1,121 @@ + + * + * @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 + * + */ + +namespace OCA\Files_External\Controller; + +use \OCP\IRequest; +use \OCP\IL10N; +use \OCP\AppFramework\Http\DataResponse; +use \OCP\AppFramework\Controller; +use \OCP\AppFramework\Http; +use \OCA\Files_external\Service\UserGlobalStoragesService; +use \OCA\Files_external\NotFoundException; +use \OCA\Files_external\Lib\StorageConfig; +use \OCA\Files_External\Lib\Backend\Backend; + +/** + * User global storages controller + */ +class UserGlobalStoragesController extends StoragesController { + /** + * Creates a new user global storages controller. + * + * @param string $AppName application name + * @param IRequest $request request object + * @param IL10N $l10n l10n service + * @param UserGlobalStoragesService $userGlobalStoragesService storage service + */ + public function __construct( + $AppName, + IRequest $request, + IL10N $l10n, + UserGlobalStoragesService $userGlobalStoragesService + ) { + parent::__construct( + $AppName, + $request, + $l10n, + $userGlobalStoragesService + ); + } + + /** + * Get all storage entries + * + * @return DataResponse + * + * @NoAdminRequired + */ + public function index() { + $storages = $this->service->getAllStorages(); + + // remove configuration data, this must be kept private + foreach ($storages as $storage) { + $this->sanitizeStorage($storage); + } + + return new DataResponse( + $storages, + Http::STATUS_OK + ); + } + + /** + * Get an external storage entry. + * + * @param int $id storage id + * @return DataResponse + * + * @NoAdminRequired + */ + public function show($id) { + try { + $storage = $this->service->getStorage($id); + + $this->updateStorageStatus($storage); + } catch (NotFoundException $e) { + return new DataResponse( + [ + 'message' => (string)$this->l10n->t('Storage with id "%i" not found', array($id)) + ], + Http::STATUS_NOT_FOUND + ); + } + + $this->sanitizeStorage($storage); + + return new DataResponse( + $storage, + Http::STATUS_OK + ); + } + + /** + * Remove sensitive data from a StorageConfig before returning it to the user + * + * @param StorageConfig $storage + */ + protected function sanitizeStorage(StorageConfig $storage) { + $storage->setBackendOptions([]); + $storage->setMountOptions([]); + } + +} diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index 9b048ba193..c9badb2f72 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -820,6 +820,37 @@ MountConfigListView.prototype = _.extend({ loadStorages: function() { var self = this; + if (this._isPersonal) { + // load userglobal storages + $.ajax({ + type: 'GET', + url: OC.generateUrl('apps/files_external/userglobalstorages'), + contentType: 'application/json', + success: function(result) { + $.each(result, function(i, storageParams) { + storageParams.mountPoint = storageParams.mountPoint.substr(1); // trim leading slash + var storageConfig = new self._storageConfigClass(); + _.extend(storageConfig, storageParams); + var $tr = self.newStorage(storageConfig); + + // userglobal storages must be at the top of the list + $tr.detach(); + self.$el.prepend($tr); + + var $authentication = $tr.find('.authentication'); + $authentication.text($authentication.find('select option:selected').text()); + + // userglobal storages do not expose configuration data + $tr.find('.configuration').text(t('files_external', 'Admin defined')); + + // disable any other inputs + $tr.find('.mountOptionsToggle, .remove').empty(); + $tr.find('input, select, button').attr('disabled', 'disabled'); + }); + } + }); + } + var url = this._storageConfigClass.prototype._url; $.ajax({ diff --git a/apps/files_external/personal.php b/apps/files_external/personal.php index df15c3bd25..05196a5890 100644 --- a/apps/files_external/personal.php +++ b/apps/files_external/personal.php @@ -32,31 +32,11 @@ $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 = array_filter($backendService->getAvailableBackends(), function($backend) { - return $backend->isVisibleFor(BackendService::VISIBILITY_PERSONAL); -}); -$authMechanisms = array_filter($backendService->getAuthMechanisms(), function($authMechanism) { - return $authMechanism->isVisibleFor(BackendService::VISIBILITY_PERSONAL); -}); -foreach ($backends as $backend) { - if ($backend->getCustomJs()) { - \OCP\Util::addScript('files_external', $backend->getCustomJs()); - } -} -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('visibilityType', BackendService::VISIBILITY_PERSONAL); $tmpl->assign('storages', $userStoragesService->getStorages()); $tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends())); -$tmpl->assign('backends', $backends); -$tmpl->assign('authMechanisms', $authMechanisms); +$tmpl->assign('backends', $backendService->getAvailableBackends()); +$tmpl->assign('authMechanisms', $backendService->getAuthMechanisms()); return $tmpl->fetchPage(); diff --git a/apps/files_external/settings.php b/apps/files_external/settings.php index 03ed363bdb..50d47d667f 100644 --- a/apps/files_external/settings.php +++ b/apps/files_external/settings.php @@ -35,40 +35,15 @@ $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 = array_filter($backendService->getAvailableBackends(), function($backend) { - return $backend->isVisibleFor(BackendService::VISIBILITY_ADMIN); -}); -$authMechanisms = array_filter($backendService->getAuthMechanisms(), function($authMechanism) { - return $authMechanism->isVisibleFor(BackendService::VISIBILITY_ADMIN); -}); -foreach ($backends as $backend) { - if ($backend->getCustomJs()) { - \OCP\Util::addScript('files_external', $backend->getCustomJs()); - } -} -foreach ($authMechanisms as $authMechanism) { - if ($authMechanism->getCustomJs()) { - \OCP\Util::addScript('files_external', $authMechanism->getCustomJs()); - } -} - -$userBackends = array_filter($backendService->getAvailableBackends(), function($backend) { - return $backend->isAllowedVisibleFor(BackendService::VISIBILITY_PERSONAL); -}); - $tmpl = new OCP\Template('files_external', 'settings'); $tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled()); -$tmpl->assign('isAdminPage', true); +$tmpl->assign('visibilityType', BackendService::VISIBILITY_ADMIN); $tmpl->assign('storages', $globalStoragesService->getStorages()); -$tmpl->assign('backends', $backends); -$tmpl->assign('authMechanisms', $authMechanisms); -$tmpl->assign('userBackends', $userBackends); +$tmpl->assign('backends', $backendService->getAvailableBackends()); +$tmpl->assign('authMechanisms', $backendService->getAuthMechanisms()); $tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends())); $tmpl->assign('allowUserMounting', $backendService->isUserMountingAllowed()); return $tmpl->fetchPage(); diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php index 14136a9bad..f7caf3d2ca 100644 --- a/apps/files_external/templates/settings.php +++ b/apps/files_external/templates/settings.php @@ -3,6 +3,21 @@ use \OCA\Files_External\Lib\DefinitionParameter; use \OCA\Files_External\Service\BackendService; + script('files_external', 'settings'); + style('files_external', 'settings'); + + // load custom JS + foreach ($_['backends'] as $backend) { + if ($backend->getCustomJs()) { + script('files_external', $backend->getCustomJs()); + } + } + foreach ($_['authMechanisms'] as $authMechanism) { + if ($authMechanism->getCustomJs()) { + script('files_external', $authMechanism->getCustomJs()); + } + } + function writeParameterInput($parameter, $options, $classes = []) { $value = ''; if (isset($options[$parameter->getName()])) { @@ -56,7 +71,7 @@

t('External Storage')); ?>

'')) print_unescaped(''.$_['dependencies'].''); ?> - '> +
'> @@ -64,7 +79,7 @@ - '.$l->t('Available for').''); ?> + '.$l->t('Available for').''); ?> @@ -84,7 +99,9 @@ t('Add storage')); ?> isVisibleFor($_['visibilityType']); + }); uasort($sortedBackends, function($a, $b) { return strcasecmp($a->getText(), $b->getText()); }); @@ -97,7 +114,7 @@ - + @@ -122,7 +139,7 @@
t('External storage')); ?> t('Authentication')); ?> t('Configuration')); ?>   
'>

- +
/> @@ -130,7 +147,12 @@

class="hidden"> t('Allow users to mount the following external storage')); ?>
- + isAllowedVisibleFor(BackendService::VISIBILITY_PERSONAL); + }); + ?> + getDeprecateTo()): ?> From 2efffb810d89f56cf2e128b536b79925bd5f9638 Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Mon, 14 Sep 2015 20:21:16 +0100 Subject: [PATCH 3/9] Load applicable users/groups correctly --- apps/files_external/js/settings.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index c9badb2f72..d2ff23e89b 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -796,6 +796,19 @@ MountConfigListView.prototype = _.extend({ }); } + var applicable = []; + if (storageConfig.applicableUsers) { + applicable = applicable.concat(storageConfig.applicableUsers); + } + if (storageConfig.applicableGroups) { + applicable = applicable.concat( + _.map(storageConfig.applicableGroups, function(group) { + return group+'(group)'; + }) + ); + } + $tr.find('.applicableUsers').val(applicable).trigger('change'); + var priorityEl = $(''); $tr.append(priorityEl); From 8f4b780a9055e9ce26a7c147fd4ee70dde8f02dc Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Mon, 14 Sep 2015 20:31:24 +0100 Subject: [PATCH 4/9] Fix external storage priority logic --- apps/files_external/controller/userglobalstoragescontroller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files_external/controller/userglobalstoragescontroller.php b/apps/files_external/controller/userglobalstoragescontroller.php index b77e23104e..c6f777763e 100644 --- a/apps/files_external/controller/userglobalstoragescontroller.php +++ b/apps/files_external/controller/userglobalstoragescontroller.php @@ -65,7 +65,7 @@ class UserGlobalStoragesController extends StoragesController { * @NoAdminRequired */ public function index() { - $storages = $this->service->getAllStorages(); + $storages = $this->service->getUniqueStorages(); // remove configuration data, this must be kept private foreach ($storages as $storage) { From 6a2e7632d17eb2b239aad068ba1dcd1252d6ae0f Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Mon, 14 Sep 2015 22:21:42 +0100 Subject: [PATCH 5/9] Fix JS unit tests --- apps/files_external/js/settings.js | 3 +-- apps/files_external/tests/js/settingsSpec.js | 7 +++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index d2ff23e89b..586b9af7a8 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -624,8 +624,6 @@ MountConfigListView.prototype = _.extend({ this._allAuthMechanisms = this.$el.find('#addMountPoint .authentication').data('mechanisms'); this._initEvents(); - - this.loadStorages(); }, /** @@ -1194,6 +1192,7 @@ $(document).ready(function() { var mountConfigListView = new MountConfigListView($('#externalStorage'), { encryptionEnabled: encryptionEnabled }); + mountConfigListView.loadStorages(); $('#sslCertificate').on('click', 'td.remove>img', function() { var $tr = $(this).closest('tr'); diff --git a/apps/files_external/tests/js/settingsSpec.js b/apps/files_external/tests/js/settingsSpec.js index 67a8127712..3d0168898c 100644 --- a/apps/files_external/tests/js/settingsSpec.js +++ b/apps/files_external/tests/js/settingsSpec.js @@ -54,7 +54,8 @@ describe('OCA.External.Settings tests', function() { // within the DOM by the server template $('#externalStorage .selectBackend:first').data('configurations', { '\\OC\\TestBackend': { - 'backend': 'Test Backend Name', + 'identifier': '\\OC\\TestBackend', + 'name': 'Test Backend', 'configuration': { 'field1': 'Display Name 1', 'field2': '&Display Name 2' @@ -65,7 +66,8 @@ describe('OCA.External.Settings tests', function() { 'priority': 11 }, '\\OC\\AnotherTestBackend': { - 'backend': 'Another Test Backend Name', + 'identifier': '\\OC\\AnotherTestBackend', + 'name': 'Another Test Backend', 'configuration': { 'field1': 'Display Name 1', 'field2': '&Display Name 2' @@ -80,6 +82,7 @@ describe('OCA.External.Settings tests', function() { $('#externalStorage #addMountPoint .authentication:first').data('mechanisms', { 'mechanism1': { + 'identifier': 'mechanism1', 'name': 'Mechanism 1', 'configuration': { }, From be8afc2c12efcc6734ce813e12fefeb792d04867 Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Tue, 15 Sep 2015 14:38:28 +0100 Subject: [PATCH 6/9] Reset mountpoint input field when creating new mount --- apps/files_external/js/settings.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index 586b9af7a8..3152c644b3 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -701,6 +701,7 @@ MountConfigListView.prototype = _.extend({ var storageConfig = new this._storageConfigClass(); storageConfig.mountPoint = $tr.find('.mountPoint input').val(); storageConfig.backend = $target.val(); + $tr.find('.mountPoint input').val(''); $tr = this.newStorage(storageConfig); From c5966ed21b56f083e090a0b1b48e567383e7ee39 Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Tue, 20 Oct 2015 13:26:46 +0100 Subject: [PATCH 7/9] Only set value if it exists in the StorageConfig --- apps/files_external/js/settings.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index 3152c644b3..e16944eaa1 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -790,8 +790,11 @@ MountConfigListView.prototype = _.extend({ if (storageConfig.backendOptions) { $td.children().each(function() { var input = $(this); - input.val(storageConfig.backendOptions[input.data('parameter')]); - highlightInput(input); + var val = storageConfig.backendOptions[input.data('parameter')]; + if (val !== undefined) { + input.val(storageConfig.backendOptions[input.data('parameter')]); + highlightInput(input); + } }); } From ee7128b43549ed2ce1e8a96c132503809ac87ba9 Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Tue, 20 Oct 2015 13:35:45 +0100 Subject: [PATCH 8/9] Clear highlight on RSA public key generation --- apps/files_external/js/public_key.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files_external/js/public_key.js b/apps/files_external/js/public_key.js index a854606745..e35d7ad378 100644 --- a/apps/files_external/js/public_key.js +++ b/apps/files_external/js/public_key.js @@ -33,7 +33,7 @@ $(document).ready(function() { $.post(OC.filePath('files_external', 'ajax', 'public_key.php'), {}, function(result) { if (result && result.status === 'success') { - $(config).find('[data-parameter="public_key"]').val(result.data.public_key); + $(config).find('[data-parameter="public_key"]').val(result.data.public_key).keyup(); $(config).find('[data-parameter="private_key"]').val(result.data.private_key); OCA.External.Settings.mountConfig.saveStorageConfig(tr, function() { // Nothing to do From 08839ce77dcf23ae12725bd47e58c1bab5ea4aaf Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Sun, 22 Nov 2015 17:25:32 +0000 Subject: [PATCH 9/9] Defer initialisation of data until after complete construction --- apps/files_external/js/public_key.js | 12 ++++--- apps/files_external/js/settings.js | 49 ++++++++++++++++++---------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/apps/files_external/js/public_key.js b/apps/files_external/js/public_key.js index e35d7ad378..5f9658381f 100644 --- a/apps/files_external/js/public_key.js +++ b/apps/files_external/js/public_key.js @@ -1,10 +1,16 @@ $(document).ready(function() { - OCA.External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme) { + OCA.External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme, onCompletion) { if (scheme === 'publickey') { var config = $tr.find('.configuration'); if ($(config).find('[name="public_key_generate"]').length === 0) { setupTableRow($tr, config); + onCompletion.then(function() { + // If there's no private key, build one + if (0 === $(config).find('[data-parameter="private_key"]').val().length) { + generateKeys($tr); + } + }); } } }); @@ -22,10 +28,6 @@ $(document).ready(function() { .attr('value', t('files_external', 'Generate keys')) .attr('name', 'public_key_generate') ); - // If there's no private key, build one - if (0 === $(config).find('[data-parameter="private_key"]').val().length) { - generateKeys(tr); - } } function generateKeys(tr) { diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index e16944eaa1..f712ecf432 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -703,7 +703,9 @@ MountConfigListView.prototype = _.extend({ storageConfig.backend = $target.val(); $tr.find('.mountPoint input').val(''); - $tr = this.newStorage(storageConfig); + var onCompletion = jQuery.Deferred(); + $tr = this.newStorage(storageConfig, onCompletion); + onCompletion.resolve(); $tr.find('td.configuration').children().not('[type=hidden]').first().focus(); this.saveStorageConfig($tr); @@ -712,8 +714,23 @@ MountConfigListView.prototype = _.extend({ _onSelectAuthMechanism: function(event) { var $target = $(event.target); var $tr = $target.closest('tr'); - var authMechanism = $target.val(); + + var onCompletion = jQuery.Deferred(); + this.configureAuthMechanism($tr, authMechanism, onCompletion); + onCompletion.resolve(); + + this.saveStorageConfig($tr); + }, + + /** + * Configure the storage config with a new authentication mechanism + * + * @param {jQuery} $tr config row + * @param {string} authMechanism + * @param {jQuery.Deferred} onCompletion + */ + configureAuthMechanism: function($tr, authMechanism, onCompletion) { var authMechanismConfiguration = this._allAuthMechanisms[authMechanism]; var $td = $tr.find('td.configuration'); $td.find('.auth-param').remove(); @@ -723,22 +740,18 @@ MountConfigListView.prototype = _.extend({ )); this.trigger('selectAuthMechanism', - $tr, authMechanism, authMechanismConfiguration['scheme'] + $tr, authMechanism, authMechanismConfiguration['scheme'], onCompletion ); - - if ($tr.data('constructing') !== true) { - // row is ready, trigger recheck - this.saveStorageConfig($tr); - } }, /** * Create a config row for a new storage * * @param {StorageConfig} storageConfig storage config to pull values from + * @param {jQuery.Deferred} onCompletion * @return {jQuery} created row */ - newStorage: function(storageConfig) { + newStorage: function(storageConfig, onCompletion) { var mountPoint = storageConfig.mountPoint; var backend = this._allBackends[storageConfig.backend]; @@ -753,8 +766,6 @@ MountConfigListView.prototype = _.extend({ $tr.find('select#selectBackend'); addSelect2($tr.find('.applicableUsers'), this._userListLimit); - $tr.data('constructing', true); - if (storageConfig.id) { $tr.data('id', storageConfig.id); } @@ -777,15 +788,16 @@ MountConfigListView.prototype = _.extend({ }); if (storageConfig.authMechanism) { selectAuthMechanism.val(storageConfig.authMechanism); + } else { + storageConfig.authMechanism = selectAuthMechanism.val(); } $tr.find('td.authentication').append(selectAuthMechanism); var $td = $tr.find('td.configuration'); $.each(backend.configuration, _.partial(this.writeParameterInput, $td)); - this.trigger('selectBackend', $tr, backend.identifier); - - selectAuthMechanism.trigger('change'); // generate configuration parameters for auth mechanism + this.trigger('selectBackend', $tr, backend.identifier, onCompletion); + this.configureAuthMechanism($tr, storageConfig.authMechanism, onCompletion); if (storageConfig.backendOptions) { $td.children().each(function() { @@ -825,7 +837,6 @@ MountConfigListView.prototype = _.extend({ })); } - $tr.removeData('constructing'); return $tr; }, @@ -842,11 +853,12 @@ MountConfigListView.prototype = _.extend({ url: OC.generateUrl('apps/files_external/userglobalstorages'), contentType: 'application/json', success: function(result) { + var onCompletion = jQuery.Deferred(); $.each(result, function(i, storageParams) { storageParams.mountPoint = storageParams.mountPoint.substr(1); // trim leading slash var storageConfig = new self._storageConfigClass(); _.extend(storageConfig, storageParams); - var $tr = self.newStorage(storageConfig); + var $tr = self.newStorage(storageConfig, onCompletion); // userglobal storages must be at the top of the list $tr.detach(); @@ -862,6 +874,7 @@ MountConfigListView.prototype = _.extend({ $tr.find('.mountOptionsToggle, .remove').empty(); $tr.find('input, select, button').attr('disabled', 'disabled'); }); + onCompletion.resolve(); } }); } @@ -873,13 +886,15 @@ MountConfigListView.prototype = _.extend({ url: OC.generateUrl(url), contentType: 'application/json', success: function(result) { + var onCompletion = jQuery.Deferred(); $.each(result, function(i, storageParams) { storageParams.mountPoint = storageParams.mountPoint.substr(1); // trim leading slash var storageConfig = new self._storageConfigClass(); _.extend(storageConfig, storageParams); - var $tr = self.newStorage(storageConfig); + var $tr = self.newStorage(storageConfig, onCompletion); self.recheckStorageConfig($tr); }); + onCompletion.resolve(); } }); },