From 5a4c6db6d198e7959e931a42d0490269c0f5b366 Mon Sep 17 00:00:00 2001 From: James Muehlner Date: Mon, 28 Dec 2015 21:33:40 -0800 Subject: [PATCH] GUAC-1407: Add support for user cloning. --- .../controllers/manageUserController.js | 77 +++++++++++++++++++ .../app/manage/templates/manageUser.html | 1 + .../src/main/webapp/translations/de.json | 1 + .../src/main/webapp/translations/en.json | 1 + .../src/main/webapp/translations/fr.json | 1 + .../src/main/webapp/translations/it.json | 1 + .../src/main/webapp/translations/nl.json | 1 + .../src/main/webapp/translations/ru.json | 1 + 8 files changed, 84 insertions(+) diff --git a/guacamole/src/main/webapp/app/manage/controllers/manageUserController.js b/guacamole/src/main/webapp/app/manage/controllers/manageUserController.js index 1641091fa..f6684a7d2 100644 --- a/guacamole/src/main/webapp/app/manage/controllers/manageUserController.js +++ b/guacamole/src/main/webapp/app/manage/controllers/manageUserController.js @@ -80,6 +80,14 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto */ var selectedDataSource = $routeParams.dataSource; + /** + * The username of the original user from which this user is + * being cloned. Only valid if this is a new user. + * + * @type String + */ + var cloneSourceUsername = $location.search().clone; + /** * The username of the user being edited. If a new user is * being created, this will not be defined. @@ -362,6 +370,43 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto }; + /** + * Returns whether the current user can save the user being edited within + * the given data source. Saving will create or update that user depending + * on whether the user already exists. + * + * @param {String} [dataSource] + * The identifier of the data source to check. If omitted, this will + * default to the currently-selected data source. + * + * @returns {Boolean} + * true if the current user can save changes to the user being edited, + * false otherwise. + */ + $scope.canCloneUser = function canCloneUser(dataSource) { + + // Do not check if permissions are not yet loaded + if (!$scope.permissions) + return false; + + // Use currently-selected data source if unspecified + dataSource = dataSource || selectedDataSource; + + // If we are not editing an existing user, we cannot clone + if (!username) + return false; + + // The administrator can always clone users + if (PermissionSet.hasSystemPermission($scope.permissions[dataSource], + PermissionSet.SystemPermissionType.ADMINISTER)) + return true; + + // Otherwise we need explicit CREATE_USER permission + return PermissionSet.hasSystemPermission($scope.permissions[dataSource], + PermissionSet.SystemPermissionType.CREATE_USER); + + }; + /** * Returns whether the current user can delete the user being edited from * the given data source. @@ -488,6 +533,30 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto }); } + // If we are cloning an existing user, pull his/her data instead + else if (cloneSourceUsername) { + + dataSourceService.apply(userService.getUser, dataSources, cloneSourceUsername) + .then(function usersReceived(users) { + + // Get user for currently-selected data source + $scope.users = {}; + $scope.user = users[selectedDataSource]; + + }); + + // Pull user permissions + permissionService.getPermissions(selectedDataSource, cloneSourceUsername).success(function gotPermissions(permissions) { + $scope.permissionFlags = PermissionFlagSet.fromPermissionSet(permissions); + permissionsAdded = permissions; + }) + + // If permissions cannot be retrieved, use empty permissions + .error(function permissionRetrievalFailed() { + $scope.permissionFlags = new PermissionFlagSet(); + }); + } + // Use skeleton data if we are creating a new user else { @@ -838,6 +907,14 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto $scope.cancel = function cancel() { $location.path('/settings/users'); }; + + /** + * Cancels all pending edits, opening an edit page for a new user + * which is prepopulated with the data from the user currently being edited. + */ + $scope.cloneUser = function cloneUser() { + $location.path('/manage/' + encodeURIComponent(selectedDataSource) + '/users').search('clone', username); + }; /** * Saves the user, updating the existing user only. diff --git a/guacamole/src/main/webapp/app/manage/templates/manageUser.html b/guacamole/src/main/webapp/app/manage/templates/manageUser.html index 6d275e5c1..18e0915ac 100644 --- a/guacamole/src/main/webapp/app/manage/templates/manageUser.html +++ b/guacamole/src/main/webapp/app/manage/templates/manageUser.html @@ -108,6 +108,7 @@ THE SOFTWARE.
+
diff --git a/guacamole/src/main/webapp/translations/de.json b/guacamole/src/main/webapp/translations/de.json index 996f6adbb..058193835 100644 --- a/guacamole/src/main/webapp/translations/de.json +++ b/guacamole/src/main/webapp/translations/de.json @@ -237,6 +237,7 @@ "ACTION_ACKNOWLEDGE" : "@:APP.ACTION_ACKNOWLEDGE", "ACTION_CANCEL" : "@:APP.ACTION_CANCEL", + "ACTION_CLONE" : "@:APP.ACTION_CLONE", "ACTION_DELETE" : "@:APP.ACTION_DELETE", "ACTION_SAVE" : "@:APP.ACTION_SAVE", diff --git a/guacamole/src/main/webapp/translations/en.json b/guacamole/src/main/webapp/translations/en.json index 951b38b03..c311f7eb2 100644 --- a/guacamole/src/main/webapp/translations/en.json +++ b/guacamole/src/main/webapp/translations/en.json @@ -237,6 +237,7 @@ "ACTION_ACKNOWLEDGE" : "@:APP.ACTION_ACKNOWLEDGE", "ACTION_CANCEL" : "@:APP.ACTION_CANCEL", + "ACTION_CLONE" : "@:APP.ACTION_CLONE", "ACTION_DELETE" : "@:APP.ACTION_DELETE", "ACTION_SAVE" : "@:APP.ACTION_SAVE", diff --git a/guacamole/src/main/webapp/translations/fr.json b/guacamole/src/main/webapp/translations/fr.json index c8fa6be22..f391bfe5e 100644 --- a/guacamole/src/main/webapp/translations/fr.json +++ b/guacamole/src/main/webapp/translations/fr.json @@ -228,6 +228,7 @@ "ACTION_ACKNOWLEDGE" : "@:APP.ACTION_ACKNOWLEDGE", "ACTION_CANCEL" : "@:APP.ACTION_CANCEL", + "ACTION_CLONE" : "@:APP.ACTION_CLONE", "ACTION_DELETE" : "@:APP.ACTION_DELETE", "ACTION_SAVE" : "@:APP.ACTION_SAVE", diff --git a/guacamole/src/main/webapp/translations/it.json b/guacamole/src/main/webapp/translations/it.json index 0dea25c3f..bed8c4c8c 100644 --- a/guacamole/src/main/webapp/translations/it.json +++ b/guacamole/src/main/webapp/translations/it.json @@ -225,6 +225,7 @@ "ACTION_ACKNOWLEDGE" : "@:APP.ACTION_ACKNOWLEDGE", "ACTION_CANCEL" : "@:APP.ACTION_CANCEL", + "ACTION_CLONE" : "@:APP.ACTION_CLONE", "ACTION_DELETE" : "@:APP.ACTION_DELETE", "ACTION_SAVE" : "@:APP.ACTION_SAVE", diff --git a/guacamole/src/main/webapp/translations/nl.json b/guacamole/src/main/webapp/translations/nl.json index 4dbdd8c47..e4c9a8111 100644 --- a/guacamole/src/main/webapp/translations/nl.json +++ b/guacamole/src/main/webapp/translations/nl.json @@ -237,6 +237,7 @@ "ACTION_ACKNOWLEDGE" : "@:APP.ACTION_ACKNOWLEDGE", "ACTION_CANCEL" : "@:APP.ACTION_CANCEL", + "ACTION_CLONE" : "@:APP.ACTION_CLONE", "ACTION_DELETE" : "@:APP.ACTION_DELETE", "ACTION_SAVE" : "@:APP.ACTION_SAVE", diff --git a/guacamole/src/main/webapp/translations/ru.json b/guacamole/src/main/webapp/translations/ru.json index 6ac7fbe0c..9fdd48fb9 100644 --- a/guacamole/src/main/webapp/translations/ru.json +++ b/guacamole/src/main/webapp/translations/ru.json @@ -225,6 +225,7 @@ "ACTION_ACKNOWLEDGE" : "@:APP.ACTION_ACKNOWLEDGE", "ACTION_CANCEL" : "@:APP.ACTION_CANCEL", + "ACTION_CLONE" : "@:APP.ACTION_CLONE", "ACTION_DELETE" : "@:APP.ACTION_DELETE", "ACTION_SAVE" : "@:APP.ACTION_SAVE",