diff --git a/app/docker/views/configs/configsController.js b/app/docker/views/configs/configsController.js index 08c16d2bd..fc047501f 100644 --- a/app/docker/views/configs/configsController.js +++ b/app/docker/views/configs/configsController.js @@ -3,12 +3,14 @@ import angular from 'angular'; class ConfigsController { /* @ngInject */ - constructor($state, ConfigService, Notifications) { + constructor($state, ConfigService, Notifications, $async) { this.$state = $state; this.ConfigService = ConfigService; this.Notifications = Notifications; + this.$async = $async; this.removeAction = this.removeAction.bind(this); + this.removeActionAsync = this.removeActionAsync.bind(this); } async $onInit() { @@ -20,7 +22,11 @@ class ConfigsController { } } - async removeAction(selectedItems) { + removeAction(selectedItems) { + return this.$async(this.removeActionAsync, selectedItems); + } + + async removeActionAsync(selectedItems) { let actionCount = selectedItems.length; for (const config of selectedItems) { try { diff --git a/app/docker/views/configs/create/createConfigController.js b/app/docker/views/configs/create/createConfigController.js index f77b8fa17..8baebf698 100644 --- a/app/docker/views/configs/create/createConfigController.js +++ b/app/docker/views/configs/create/createConfigController.js @@ -5,7 +5,7 @@ import angular from "angular"; class CreateConfigController { /* @ngInject */ - constructor($state, $transition$, Notifications, ConfigService, Authentication, FormValidator, ResourceControlService) { + constructor($async, $state, $transition$, Notifications, ConfigService, Authentication, FormValidator, ResourceControlService) { this.$state = $state; this.$transition$ = $transition$; this.Notifications = Notifications; @@ -13,6 +13,7 @@ class CreateConfigController { this.Authentication = Authentication; this.FormValidator = FormValidator; this.ResourceControlService = ResourceControlService; + this.$async = $async; this.formValues = { Name: "", @@ -26,6 +27,30 @@ class CreateConfigController { }; this.editorUpdate = this.editorUpdate.bind(this); + this.createAsync = this.createAsync.bind(this); + } + + async $onInit() { + if (!this.$transition$.params().id) { + this.formValues.displayCodeEditor = true; + return; + } + + try { + let data = await this.ConfigService.config(this.$transition$.params().id); + this.formValues.Name = data.Name + "_copy"; + this.formValues.Data = data.Data; + let labels = _.keys(data.Labels); + for (let i = 0; i < labels.length; i++) { + let labelName = labels[i]; + let labelValue = data.Labels[labelName]; + this.formValues.Labels.push({ name: labelName, value: labelValue }); + } + this.formValues.displayCodeEditor = true; + } catch (err) { + this.formValues.displayCodeEditor = true; + this.Notifications.error("Failure", err, "Unable to clone config"); + } } addLabel() { @@ -74,7 +99,11 @@ class CreateConfigController { return true; } - async create() { + create() { + return this.$async(this.createAsync); + } + + async createAsync() { let accessControlData = this.formValues.AccessControlData; let userDetails = this.Authentication.getUserDetails(); let isAdmin = this.Authentication.isAdmin(); @@ -111,29 +140,6 @@ class CreateConfigController { editorUpdate(cm) { this.formValues.ConfigContent = cm.getValue(); } - - async $onInit() { - if (!this.$transition$.params().id) { - this.formValues.displayCodeEditor = true; - return; - } - - try { - let data = await this.ConfigService.config(this.$transition$.params().id); - this.formValues.Name = data.Name + "_copy"; - this.formValues.Data = data.Data; - let labels = _.keys(data.Labels); - for (let i = 0; i < labels.length; i++) { - let labelName = labels[i]; - let labelValue = data.Labels[labelName]; - this.formValues.Labels.push({ name: labelName, value: labelValue }); - } - this.formValues.displayCodeEditor = true; - } catch (err) { - this.formValues.displayCodeEditor = true; - this.Notifications.error("Failure", err, "Unable to clone config"); - } - } } export default CreateConfigController; diff --git a/app/extensions/rbac/directives/authorization.js b/app/extensions/rbac/directives/authorization.js index 668314800..966266331 100644 --- a/app/extensions/rbac/directives/authorization.js +++ b/app/extensions/rbac/directives/authorization.js @@ -1,33 +1,37 @@ -angular.module('portainer.extensions.rbac').directive('authorization', ['Authentication', 'ExtensionService', - function(Authentication, ExtensionService) { - return { - restrict: 'A', - link: async function(scope, elem, attrs) { - elem.hide(); - try { - const rbacEnabled = await ExtensionService.extensionEnabled(ExtensionService.EXTENSIONS.RBAC); - if (!rbacEnabled) { - elem.show(); - return; - } - } catch (err) { +angular.module('portainer.extensions.rbac').directive('authorization', ['Authentication', 'ExtensionService', '$async', + function(Authentication, ExtensionService, $async) { + + async function linkAsync(scope, elem, attrs) { + elem.hide(); + try { + const rbacEnabled = await ExtensionService.extensionEnabled(ExtensionService.EXTENSIONS.RBAC); + if (!rbacEnabled) { elem.show(); return; } + } catch (err) { + elem.show(); + return; + } + var authorizations = attrs.authorization.split(","); + for (var i = 0; i < authorizations.length; i++) { + authorizations[i] = authorizations[i].trim(); + } - var authorizations = attrs.authorization.split(","); - for (var i = 0; i < authorizations.length; i++) { - authorizations[i] = authorizations[i].trim(); - } + var hasAuthorizations = Authentication.hasAuthorizations(authorizations); - var hasAuthorizations = Authentication.hasAuthorizations(authorizations); + if (hasAuthorizations) { + elem.show(); + } else if (!hasAuthorizations && elem[0].tagName === 'A') { + elem.show(); + elem.addClass('portainer-disabled-link'); + } + } - if (hasAuthorizations) { - elem.show(); - } else if (!hasAuthorizations && elem[0].tagName === 'A') { - elem.show(); - elem.addClass('portainer-disabled-link'); - } + return { + restrict: 'A', + link: function(scope, elem, attrs) { + return $async(linkAsync, scope, elem, attrs); } } }]); diff --git a/app/extensions/rbac/directives/disable-authorization.js b/app/extensions/rbac/directives/disable-authorization.js index 094aeb855..5dad08074 100644 --- a/app/extensions/rbac/directives/disable-authorization.js +++ b/app/extensions/rbac/directives/disable-authorization.js @@ -1,27 +1,32 @@ angular.module('portainer.extensions.rbac') - .directive('disableAuthorization', ['Authentication', 'ExtensionService', function(Authentication, ExtensionService) { - return { - restrict: 'A', - link: async function (scope, elem, attrs) { - try { - const rbacEnabled = await ExtensionService.extensionEnabled(ExtensionService.EXTENSIONS.RBAC); - if (!rbacEnabled) { - elem.show(); - return; - } - } catch (err) { + .directive('disableAuthorization', ['Authentication', 'ExtensionService', '$async', function(Authentication, ExtensionService, $async) { + + async function linkAsync(scope, elem, attrs) { + try { + const rbacEnabled = await ExtensionService.extensionEnabled(ExtensionService.EXTENSIONS.RBAC); + if (!rbacEnabled) { elem.show(); return; } + } catch (err) { + elem.show(); + return; + } - var authorizations = attrs.disableAuthorization.split(","); - for (var i = 0; i < authorizations.length; i++) { - authorizations[i] = authorizations[i].trim(); - } + var authorizations = attrs.disableAuthorization.split(","); + for (var i = 0; i < authorizations.length; i++) { + authorizations[i] = authorizations[i].trim(); + } - if (!Authentication.hasAuthorizations(authorizations)) { - elem.attr('disabled', true); - } + if (!Authentication.hasAuthorizations(authorizations)) { + elem.attr('disabled', true); + } + } + + return { + restrict: 'A', + link: function (scope, elem, attrs) { + return $async(linkAsync, scope, elem, attrs); } } }]); diff --git a/app/portainer/services/api/extensionService.js b/app/portainer/services/api/extensionService.js index b53a1375b..159674745 100644 --- a/app/portainer/services/api/extensionService.js +++ b/app/portainer/services/api/extensionService.js @@ -2,7 +2,7 @@ import _ from 'lodash-es'; import { ExtensionViewModel } from '../../models/extension'; angular.module('portainer.app') -.factory('ExtensionService', ['$q', 'Extension', 'StateManager', function ExtensionServiceFactory($q, Extension, StateManager) { +.factory('ExtensionService', ['$q', 'Extension', 'StateManager', '$async', function ExtensionServiceFactory($q, Extension, StateManager, $async) { 'use strict'; var service = {}; @@ -12,19 +12,27 @@ angular.module('portainer.app') RBAC: 3 }); - service.enable = function(license) { + service.enable = enable; + service.update = update; + service.delete = _delete; + service.extensions = extensions; + service.extension = extension; + service.extensionEnabled = extensionEnabled; + service.retrieveAndSaveEnabledExtensions = retrieveAndSaveEnabledExtensions; + + function enable(license) { return Extension.create({ license: license }).$promise; - }; + } - service.update = function(id, version) { + function update(id, version) { return Extension.update({ id: id, version: version }).$promise; - }; + } - service.delete = function(id) { + function _delete(id) { return Extension.delete({ id: id }).$promise; - }; + } - service.extensions = function(store) { + function extensions(store) { var deferred = $q.defer(); Extension.query({ store: store }).$promise @@ -39,9 +47,9 @@ angular.module('portainer.app') }); return deferred.promise; - }; + } - service.extension = function(id) { + function extension(id) { var deferred = $q.defer(); Extension.get({ id: id }).$promise @@ -54,9 +62,13 @@ angular.module('portainer.app') }); return deferred.promise; - }; + } - service.extensionEnabled = async function(extensionId) { + function extensionEnabled(extensionId) { + return $async(extensionsEnabledAsync, extensionId) + } + + async function extensionsEnabledAsync(extensionId) { if (extensionId === service.EXTENSIONS.RBAC) { return StateManager.getExtension(extensionId) ? true : false; } else { @@ -64,13 +76,17 @@ angular.module('portainer.app') const extension = _.find(extensions, (ext) => ext.Id === extensionId); return extension ? extension.Enabled : false; } - }; + } - service.retrieveAndSaveEnabledExtensions = async function() { + function retrieveAndSaveEnabledExtensions() { + return $async(retrieveAndSaveEnabledExtensionsAsync) + } + + async function retrieveAndSaveEnabledExtensionsAsync() { const extensions = await service.extensions(false); _.forEach(extensions, (ext) => delete ext.License); StateManager.saveExtensions(extensions); - }; + } return service; }]); diff --git a/app/portainer/services/async.js b/app/portainer/services/async.js new file mode 100644 index 000000000..ab4369c60 --- /dev/null +++ b/app/portainer/services/async.js @@ -0,0 +1,23 @@ +/** + * Look a the following PR for how to use the wrapper + * and documentation about it + * https://github.com/portainer/portainer/pull/2945 + */ + +angular.module('portainer').factory('$async', ['$q', + function($q) { + return function(asyncFunc, ...args) { + const def = $q.defer(); + const wrapper = function(params) { + const deferred = $q.defer(); + asyncFunc(...params) + .then(deferred.resolve) + .catch(deferred.reject); + return deferred.promise; + }; + + wrapper(args).then(def.resolve).catch(def.reject) + return def.promise; + }; + } +]); diff --git a/app/portainer/views/auth/authController.js b/app/portainer/views/auth/authController.js index 517cc03fd..840e9a7d8 100644 --- a/app/portainer/views/auth/authController.js +++ b/app/portainer/views/auth/authController.js @@ -1,6 +1,6 @@ angular.module('portainer.app') -.controller('AuthenticationController', ['$q', '$scope', '$state', '$stateParams', '$sanitize', 'Authentication', 'UserService', 'EndpointService', 'ExtensionService', 'StateManager', 'Notifications', 'SettingsService', 'URLHelper', -function($q, $scope, $state, $stateParams, $sanitize, Authentication, UserService, EndpointService, ExtensionService, StateManager, Notifications, SettingsService, URLHelper) { +.controller('AuthenticationController', ['$async', '$q', '$scope', '$state', '$stateParams', '$sanitize', 'Authentication', 'UserService', 'EndpointService', 'ExtensionService', 'StateManager', 'Notifications', 'SettingsService', 'URLHelper', +function($async, $q, $scope, $state, $stateParams, $sanitize, Authentication, UserService, EndpointService, ExtensionService, StateManager, Notifications, SettingsService, URLHelper) { $scope.logo = StateManager.getState().application.logo; $scope.formValues = { @@ -14,7 +14,11 @@ function($q, $scope, $state, $stateParams, $sanitize, Authentication, UserServic OAuthProvider: '' }; - async function retrieveAndSaveEnabledExtensions() { + function retrieveAndSaveEnabledExtensions() { + return $async(retrieveAndSaveEnabledExtensionsAsync); + } + + async function retrieveAndSaveEnabledExtensionsAsync() { try { await ExtensionService.retrieveAndSaveEnabledExtensions(); } catch (err) { diff --git a/app/portainer/views/endpoints/access/endpointAccessController.js b/app/portainer/views/endpoints/access/endpointAccessController.js index 708343a6e..3738cc9cc 100644 --- a/app/portainer/views/endpoints/access/endpointAccessController.js +++ b/app/portainer/views/endpoints/access/endpointAccessController.js @@ -2,13 +2,16 @@ import angular from "angular"; class EndpointAccessController { /* @ngInject */ - constructor($state, $transition$, Notifications, EndpointService, GroupService) { + constructor($state, $transition$, Notifications, EndpointService, GroupService, $async) { this.$state = $state; this.$transition$ = $transition$; this.Notifications = Notifications; this.EndpointService = EndpointService; this.GroupService = GroupService; + this.$async = $async; + this.updateAccess = this.updateAccess.bind(this); + this.updateAccessAsync = this.updateAccessAsync.bind(this); } async $onInit() { @@ -23,7 +26,11 @@ class EndpointAccessController { } } - async updateAccess() { + updateAccess() { + return this.$async(this.updateAccessAsync); + } + + async updateAccessAsync() { try { this.state.actionInProgress = true; await this.EndpointService.updateEndpoint(this.$transition$.params().id, this.endpoint); diff --git a/app/portainer/views/init/admin/initAdminController.js b/app/portainer/views/init/admin/initAdminController.js index 8384b3cd6..bc7f66c0e 100644 --- a/app/portainer/views/init/admin/initAdminController.js +++ b/app/portainer/views/init/admin/initAdminController.js @@ -1,6 +1,6 @@ angular.module('portainer.app') -.controller('InitAdminController', ['$scope', '$state', 'Notifications', 'Authentication', 'StateManager', 'UserService', 'EndpointService', 'ExtensionService', -function ($scope, $state, Notifications, Authentication, StateManager, UserService, EndpointService, ExtensionService) { +.controller('InitAdminController', ['$async', '$scope', '$state', 'Notifications', 'Authentication', 'StateManager', 'UserService', 'EndpointService', 'ExtensionService', +function ($async, $scope, $state, Notifications, Authentication, StateManager, UserService, EndpointService, ExtensionService) { $scope.logo = StateManager.getState().application.logo; @@ -14,7 +14,11 @@ function ($scope, $state, Notifications, Authentication, StateManager, UserServi actionInProgress: false }; - async function retrieveAndSaveEnabledExtensions() { + function retrieveAndSaveEnabledExtensions() { + return $async(retrieveAndSaveEnabledExtensionsAsync) + } + + async function retrieveAndSaveEnabledExtensionsAsync() { try { await ExtensionService.retrieveAndSaveEnabledExtensions(); } catch (err) {