diff --git a/guacamole/src/main/webapp/app/manage/controllers/manageConnectionController.js b/guacamole/src/main/webapp/app/manage/controllers/manageConnectionController.js index 3a97bd3a2..13f59dd54 100644 --- a/guacamole/src/main/webapp/app/manage/controllers/manageConnectionController.js +++ b/guacamole/src/main/webapp/app/manage/controllers/manageConnectionController.js @@ -53,6 +53,14 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i $scope.showStatus(false); } }; + + /** + * The identifier of the original connection from which this connection is + * being cloned. Only valid if this is a new connection. + * + * @type String + */ + var cloneSourceIdentifier = $location.search().clone; /** * The identifier of the connection being edited. If a new connection is @@ -99,18 +107,26 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i $scope.historyEntryWrappers = null; /** - * Whether the user has UPDATE permission for the current connection. + * Whether the user can save the connection being edited. This could be + * updating an existing connection, or creating a new connection. * * @type Boolean */ - $scope.hasUpdatePermission = null; + $scope.canSaveConnection = null; /** - * Whether the user has DELETE permission for the current connection. + * Whether the user can delete the connection being edited. * * @type Boolean */ - $scope.hasDeletePermission = null; + $scope.canDeleteConnection = null; + + /** + * Whether the user can clone the connection being edited. + * + * @type Boolean + */ + $scope.canCloneConnection = null; /** * Returns whether critical data has completed being loaded. @@ -126,8 +142,9 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i && $scope.connection !== null && $scope.parameters !== null && $scope.historyEntryWrappers !== null - && $scope.hasUpdatePermission !== null - && $scope.hasDeletePermission !== null; + && $scope.canSaveConnection !== null + && $scope.canDeleteConnection !== null + && $scope.canCloneConnection !== null; }; @@ -142,15 +159,27 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i permissionService.getPermissions(authenticationService.getCurrentUserID()) .success(function permissionsReceived(permissions) { - // Check if the user has UPDATE permission - $scope.hasUpdatePermission = - PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) + // Check if the connection is new or if the user has UPDATE permission + $scope.canSaveConnection = + !identifier + || PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) || PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, identifier); - // Check if the user has DELETE permission - $scope.hasDeletePermission = - PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) - || PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.DELETE, identifier); + // Check if connection is not new and the user has DELETE permission + $scope.canDeleteConnection = + !!identifier && ( + PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) + || PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.DELETE, identifier) + ); + + // Check if the connection is not new and the user has UPDATE and CREATE_CONNECTION permissions + $scope.canCloneConnection = + !!identifier && ( + PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) || ( + PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, identifier) + && PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_CONNECTION) + ) + ); }); @@ -182,7 +211,26 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i connectionService.getConnectionParameters(identifier).success(function parametersReceived(parameters) { $scope.parameters = parameters; }); + } + + // If we are cloning an existing connection, pull its data instead + else if (cloneSourceIdentifier) { + // Pull data from cloned connection + connectionService.getConnection(cloneSourceIdentifier).success(function connectionRetrieved(connection) { + $scope.connection = connection; + + // Clear the identifier field because this connection is new + delete $scope.connection.identifier; + }); + + // Do not pull connection history + $scope.historyEntryWrappers = []; + + // Pull connection parameters from cloned connection + connectionService.getConnectionParameters(cloneSourceIdentifier).success(function parametersReceived(parameters) { + $scope.parameters = parameters; + }); } // If we are creating a new connection, populate skeleton connection data @@ -231,7 +279,15 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i * Cancels all pending edits, returning to the management page. */ $scope.cancel = function cancel() { - $location.path('/manage/'); + $location.url('/manage/'); + }; + + /** + * Cancels all pending edits, opening an edit page for a new connection + * which is prepopulated with the data from the connection currently being edited. + */ + $scope.cloneConnection = function cloneConnection() { + $location.path('/manage/connections').search('clone', identifier); }; /** diff --git a/guacamole/src/main/webapp/app/manage/controllers/manageConnectionGroupController.js b/guacamole/src/main/webapp/app/manage/controllers/manageConnectionGroupController.js index 0b88c27d7..94813b8d5 100644 --- a/guacamole/src/main/webapp/app/manage/controllers/manageConnectionGroupController.js +++ b/guacamole/src/main/webapp/app/manage/controllers/manageConnectionGroupController.js @@ -94,10 +94,10 @@ angular.module('manage').controller('manageConnectionGroupController', ['$scope' */ $scope.isLoaded = function isLoaded() { - return $scope.rootGroup !== null - && $scope.connectionGroup !== null - && $scope.hasUpdatePermission !== null - && $scope.hasDeletePermission !== null; + return $scope.rootGroup !== null + && $scope.connectionGroup !== null + && $scope.canSaveConnectionGroup !== null + && $scope.canDeleteConnectionGroup !== null; }; @@ -105,15 +105,18 @@ angular.module('manage').controller('manageConnectionGroupController', ['$scope' permissionService.getPermissions(authenticationService.getCurrentUserID()) .success(function permissionsReceived(permissions) { - // Check if the user has UPDATE permission - $scope.hasUpdatePermission = - PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) - || PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, identifier); - - // Check if the user has DELETE permission - $scope.hasDeletePermission = - PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) - || PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.DELETE, identifier); + // Check if the connection group is new or if the user has UPDATE permission + $scope.canSaveConnectionGroup = + !identifier + || PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) + || PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, identifier); + + // Check if connection group is not new and the user has DELETE permission + $scope.canDeleteConnectionGroup = + !!identifier && ( + PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) + || PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.DELETE, identifier) + ); }); diff --git a/guacamole/src/main/webapp/app/manage/controllers/manageUserController.js b/guacamole/src/main/webapp/app/manage/controllers/manageUserController.js index 29d254017..9aa16627a 100644 --- a/guacamole/src/main/webapp/app/manage/controllers/manageUserController.js +++ b/guacamole/src/main/webapp/app/manage/controllers/manageUserController.js @@ -105,8 +105,8 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto return $scope.user !== null && $scope.permissionFlags !== null && $scope.rootGroup !== null - && $scope.hasUpdatePermission !== null - && $scope.hasDeletePermission !== null; + && $scope.canSaveUser !== null + && $scope.canDeleteUser !== null; }; @@ -130,16 +130,19 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto permissionService.getPermissions(authenticationService.getCurrentUserID()) .success(function permissionsReceived(permissions) { - // Check if the user has UPDATE permission - $scope.hasUpdatePermission = - PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) - || PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, username); - - // Check if the user has DELETE permission - $scope.hasDeletePermission = - PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) - || PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.DELETE, username); - + // Check if the user is new or if the user has UPDATE permission + $scope.canSaveUser = + !username + || PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) + || PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, username); + + // Check if user is not new and the user has DELETE permission + $scope.canDeleteUser = + !!username && ( + PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) + || PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.DELETE, username) + ); + }); /** diff --git a/guacamole/src/main/webapp/app/manage/directives/locationChooser.js b/guacamole/src/main/webapp/app/manage/directives/locationChooser.js index 9f4b912d3..0789444bb 100644 --- a/guacamole/src/main/webapp/app/manage/directives/locationChooser.js +++ b/guacamole/src/main/webapp/app/manage/directives/locationChooser.js @@ -62,13 +62,22 @@ angular.module('manage').directive('locationChooser', [function locationChooser( */ var connectionGroups = {}; + /** + * Recursively traverses the given connection group and all + * children, storing each encountered connection group within the + * connectionGroups map by its identifier. + * + * @param {GroupListItem} group + * The connection group to traverse. + */ var mapConnectionGroups = function mapConnectionGroups(group) { // Map given group connectionGroups[group.identifier] = group; // Map all child groups - group.childConnectionGroups.forEach(mapConnectionGroups); + if (group.childConnectionGroups) + group.childConnectionGroups.forEach(mapConnectionGroups); }; diff --git a/guacamole/src/main/webapp/app/manage/templates/manageConnection.html b/guacamole/src/main/webapp/app/manage/templates/manageConnection.html index 85dca606a..0a340425c 100644 --- a/guacamole/src/main/webapp/app/manage/templates/manageConnection.html +++ b/guacamole/src/main/webapp/app/manage/templates/manageConnection.html @@ -76,9 +76,10 @@ THE SOFTWARE.
- + + - +
diff --git a/guacamole/src/main/webapp/app/manage/templates/manageConnectionGroup.html b/guacamole/src/main/webapp/app/manage/templates/manageConnectionGroup.html index 0fca9ea5d..81b4b78ee 100644 --- a/guacamole/src/main/webapp/app/manage/templates/manageConnectionGroup.html +++ b/guacamole/src/main/webapp/app/manage/templates/manageConnectionGroup.html @@ -61,9 +61,9 @@ THE SOFTWARE.
- + - +
diff --git a/guacamole/src/main/webapp/app/manage/templates/manageUser.html b/guacamole/src/main/webapp/app/manage/templates/manageUser.html index 3ed5f798b..4028e74ff 100644 --- a/guacamole/src/main/webapp/app/manage/templates/manageUser.html +++ b/guacamole/src/main/webapp/app/manage/templates/manageUser.html @@ -73,9 +73,9 @@ THE SOFTWARE.
- + - +
diff --git a/guacamole/src/main/webapp/translations/en_US.json b/guacamole/src/main/webapp/translations/en_US.json index 1010cabe9..64859ed5d 100644 --- a/guacamole/src/main/webapp/translations/en_US.json +++ b/guacamole/src/main/webapp/translations/en_US.json @@ -4,6 +4,7 @@ "ACTION_ACKNOWLEDGE" : "OK", "ACTION_CANCEL" : "Cancel", + "ACTION_CLONE" : "Clone", "ACTION_DELETE" : "Delete", "ACTION_LOGIN" : "Login", "ACTION_LOGOUT" : "Logout", @@ -156,6 +157,7 @@ "ACTION_ACKNOWLEDGE" : "@:APP.ACTION_ACKNOWLEDGE", "ACTION_CANCEL" : "@:APP.ACTION_CANCEL", + "ACTION_CLONE" : "@:APP.ACTION_CLONE", "ACTION_DELETE" : "@:APP.ACTION_DELETE", "ACTION_LOGOUT" : "@:APP.ACTION_LOGOUT", "ACTION_NAVIGATE_BACK" : "@:APP.ACTION_NAVIGATE_BACK",