From 3d43d4ed6997c51680ab45d3327f556703547694 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 18 Apr 2015 22:40:22 -0700 Subject: [PATCH] GUAC-1053: Move password changing into preferences. --- .../main/webapp/app/index/styles/buttons.css | 18 ++- .../app/navigation/directives/guacUserMenu.js | 138 ------------------ .../app/navigation/styles/user-menu.css | 46 ------ .../navigation/templates/guacUserMenu.html | 27 ---- .../directives/guacSettingsPreferences.js | 117 +++++++++++++++ .../templates/settingsPreferences.html | 31 +++- .../src/main/webapp/translations/en_US.json | 38 ++--- 7 files changed, 178 insertions(+), 237 deletions(-) diff --git a/guacamole/src/main/webapp/app/index/styles/buttons.css b/guacamole/src/main/webapp/app/index/styles/buttons.css index fd49ea256..5990761e3 100644 --- a/guacamole/src/main/webapp/app/index/styles/buttons.css +++ b/guacamole/src/main/webapp/app/index/styles/buttons.css @@ -79,29 +79,35 @@ input[type="submit"]:disabled, button:disabled, button.danger:disabled { opacity: 0.75; } -.button.logout, .button.manage, .button.back, .button.home, .button.change-password { +.button.logout, .button.manage, .button.back, .button.home, .button.change-password, +button.logout, button.manage, button.back, button.home, button.change-password { background-repeat: no-repeat; background-size: 1em; background-position: 0.5em 0.45em; padding-left: 1.8em; } -.button.logout { +.button.logout, +button.logout { background-image: url('images/action-icons/guac-logout.png'); } -.button.manage { +.button.manage, +button.manage { background-image: url('images/action-icons/guac-config.png'); } -.button.back { +.button.back, +button.back { background-image: url('images/action-icons/guac-back.png'); } -.button.home { +.button.home, +button.home { background-image: url('images/action-icons/guac-home.png'); } -.button.change-password { +.button.change-password, +button.change-password { background-image: url('images/action-icons/guac-key.png'); } diff --git a/guacamole/src/main/webapp/app/navigation/directives/guacUserMenu.js b/guacamole/src/main/webapp/app/navigation/directives/guacUserMenu.js index aff6fff4a..4d3b3047e 100644 --- a/guacamole/src/main/webapp/app/navigation/directives/guacUserMenu.js +++ b/guacamole/src/main/webapp/app/navigation/directives/guacUserMenu.js @@ -45,30 +45,12 @@ angular.module('navigation').directive('guacUserMenu', [function guacUserMenu() templateUrl: 'app/navigation/templates/guacUserMenu.html', controller: ['$scope', '$injector', '$element', function guacUserMenuController($scope, $injector, $element) { - // Get required types - var PermissionSet = $injector.get('PermissionSet'); - // Get required services var $document = $injector.get('$document'); var $location = $injector.get('$location'); var authenticationService = $injector.get('authenticationService'); - var guacNotification = $injector.get('guacNotification'); - var permissionService = $injector.get("permissionService"); - var userService = $injector.get('userService'); var userPageService = $injector.get('userPageService'); - /** - * An action to be provided along with the object sent to - * showStatus which closes the currently-shown status dialog. - */ - var ACKNOWLEDGE_ACTION = { - name : 'USER_MENU.ACTION_ACKNOWLEDGE', - // Handle action - callback : function acknowledgeCallback() { - guacNotification.showStatus(false); - } - }; - /** * The outermost element of the user menu directive. * @@ -83,28 +65,6 @@ angular.module('navigation').directive('guacUserMenu', [function guacUserMenu() */ var document = $document[0]; - /** - * Whether the password edit dialog should be shown. - * - * @type Boolean - */ - $scope.showPasswordDialog = false; - - /** - * The new password for the user. - * - * @type String - */ - $scope.newPassword = null; - - /** - * The password match for the user. The update password action will - * fail if $scope.newPassword !== $scope.passwordMatch. - * - * @type String - */ - $scope.newPasswordMatch = null; - /** * Whether the contents of the user menu are currently shown. * @@ -139,81 +99,6 @@ angular.module('navigation').directive('guacUserMenu', [function guacUserMenu() $scope.menuShown = !$scope.menuShown; }; - /** - * Show the password update dialog. - */ - $scope.showPasswordUpdate = function showPasswordUpdate() { - - // Show the dialog - $scope.showPasswordDialog = true; - }; - - /** - * Close the password update dialog. - */ - $scope.closePasswordUpdate = function closePasswordUpdate() { - - // Clear the password fields and close the dialog - $scope.oldPassword = null; - $scope.newPassword = null; - $scope.newPasswordMatch = null; - $scope.showPasswordDialog = false; - }; - - /** - * Update the current user's password to the password currently set within - * the password change dialog. - */ - $scope.updatePassword = function updatePassword() { - - // Verify passwords match - if ($scope.newPasswordMatch !== $scope.newPassword) { - guacNotification.showStatus({ - className : 'error', - title : 'USER_MENU.DIALOG_HEADER_ERROR', - text : 'USER_MENU.ERROR_PASSWORD_MISMATCH', - actions : [ ACKNOWLEDGE_ACTION ] - }); - return; - } - - // Verify that the new password is not blank - if (!$scope.newPassword) { - guacNotification.showStatus({ - className : 'error', - title : 'USER_MENU.DIALOG_HEADER_ERROR', - text : 'USER_MENU.ERROR_PASSWORD_BLANK', - actions : [ ACKNOWLEDGE_ACTION ] - }); - return; - } - - // Save the user with the new password - userService.updateUserPassword($scope.username, $scope.oldPassword, $scope.newPassword) - .success(function passwordUpdated() { - - // Close the password update dialog - $scope.closePasswordUpdate(); - - // Indicate that the password has been changed - guacNotification.showStatus({ - text : 'USER_MENU.PASSWORD_CHANGED', - actions : [ ACKNOWLEDGE_ACTION ] - }); - }) - - // Notify of any errors - .error(function passwordUpdateFailed(error) { - guacNotification.showStatus({ - className : 'error', - title : 'USER_MENU.DIALOG_HEADER_ERROR', - 'text' : error.message, - actions : [ ACKNOWLEDGE_ACTION ] - }); - }); - - }; - /** * Logs out the current user, redirecting them to back to the login * screen after logout completes. @@ -234,34 +119,11 @@ angular.module('navigation').directive('guacUserMenu', [function guacUserMenu() callback : $scope.logout }; - /** - * Action which shows the password update dialog. - */ - var CHANGE_PASSWORD_ACTION = { - name : 'USER_MENU.ACTION_CHANGE_PASSWORD', - className : 'change-password', - callback : $scope.showPasswordUpdate - }; - /** * All available actions for the current user. */ $scope.actions = [ LOGOUT_ACTION ]; - // Retrieve current permissions - permissionService.getPermissions(authenticationService.getCurrentUserID()) - .success(function permissionsRetrieved(permissions) { - - // Add action for changing password if permission is granted - if (PermissionSet.hasUserPermission(permissions, - PermissionSet.ObjectPermissionType.UPDATE, - authenticationService.getCurrentUserID())) - $scope.actions.unshift(CHANGE_PASSWORD_ACTION); - - - }); - - // Close menu when use clicks anywhere else document.body.addEventListener('click', function clickOutsideMenu() { $scope.$apply(function closeMenu() { diff --git a/guacamole/src/main/webapp/app/navigation/styles/user-menu.css b/guacamole/src/main/webapp/app/navigation/styles/user-menu.css index 708c37efc..d5dd37946 100644 --- a/guacamole/src/main/webapp/app/navigation/styles/user-menu.css +++ b/guacamole/src/main/webapp/app/navigation/styles/user-menu.css @@ -201,10 +201,6 @@ background-image: url('images/action-icons/guac-config-dark.png'); } -.user-menu .options li a.change-password { - background-image: url('images/action-icons/guac-key-dark.png'); -} - .user-menu .options li a.logout { background-image: url('images/action-icons/guac-logout-dark.png'); } @@ -218,45 +214,3 @@ .user-menu .options li a.danger:hover { background-color: #C54; } - -.user-menu .password-dialog { - visibility: hidden; - opacity: 0; - -webkit-transition: visibility 0.125s, opacity 0.125s; - -moz-transition: visibility 0.125s, opacity 0.125s; - -ms-transition: visibility 0.125s, opacity 0.125s; - -o-transition: visibility 0.125s, opacity 0.125s; - transition: visibility 0.125s, opacity 0.125s; - position: absolute; - background: white; - padding: 1em; - border: 1px solid rgba(0, 0, 0, 0.25); - box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.25); - margin: 1em; - right: 0; - top: 0; - z-index: 8; -} - -.user-menu .password-dialog .fields { - text-align: right; -} - -.user-menu .password-dialog .action-buttons { - text-align: center; - margin: 0; -} - -.user-menu .password-dialog.shown { - visibility: visible; - opacity: 1; - -webkit-transition: opacity 0.125s; - -moz-transition: opacity 0.125s; - -ms-transition: opacity 0.125s; - -o-transition: opacity 0.125s; - transition: opacity 0.125s; -} - -.user-menu .password-dialog .fields { - width: 100%; -} diff --git a/guacamole/src/main/webapp/app/navigation/templates/guacUserMenu.html b/guacamole/src/main/webapp/app/navigation/templates/guacUserMenu.html index ab5d1d9bf..8df34a53f 100644 --- a/guacamole/src/main/webapp/app/navigation/templates/guacUserMenu.html +++ b/guacamole/src/main/webapp/app/navigation/templates/guacUserMenu.html @@ -52,31 +52,4 @@ - -
- -
- - - - - - - - - - - - - -
{{'USER_MENU.FIELD_HEADER_PASSWORD_OLD' | translate}}
{{'USER_MENU.FIELD_HEADER_PASSWORD_NEW' | translate}}
{{'USER_MENU.FIELD_HEADER_PASSWORD_NEW_AGAIN' | translate}}
-
- - -
- - -
-
- diff --git a/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js b/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js index 002624964..11c9a3d73 100644 --- a/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js +++ b/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js @@ -36,6 +36,123 @@ angular.module('settings').directive('guacSettingsPreferences', [function guacSe templateUrl: 'app/settings/templates/settingsPreferences.html', controller: ['$scope', '$injector', function settingsPreferencesController($scope, $injector) { + // Get required types + var PermissionSet = $injector.get('PermissionSet'); + + // Required services + var authenticationService = $injector.get('authenticationService'); + var guacNotification = $injector.get('guacNotification'); + var userService = $injector.get('userService'); + var permissionService = $injector.get("permissionService"); + + /** + * An action to be provided along with the object sent to + * showStatus which closes the currently-shown status dialog. + */ + var ACKNOWLEDGE_ACTION = { + name : 'SETTINGS_PREFERENCES.ACTION_ACKNOWLEDGE', + // Handle action + callback : function acknowledgeCallback() { + guacNotification.showStatus(false); + } + }; + + /** + * The username of the current user. + * + * @type String + */ + var username = authenticationService.getCurrentUserID(); + + /** + * The new password for the user. + * + * @type String + */ + $scope.newPassword = null; + + /** + * The password match for the user. The update password action will + * fail if $scope.newPassword !== $scope.passwordMatch. + * + * @type String + */ + $scope.newPasswordMatch = null; + + /** + * Whether the current user can change their own password, or null + * if this is not yet known. + * + * @type Boolean + */ + $scope.canChangePassword = null; + + /** + * Update the current user's password to the password currently set within + * the password change dialog. + */ + $scope.updatePassword = function updatePassword() { + + // Verify passwords match + if ($scope.newPasswordMatch !== $scope.newPassword) { + guacNotification.showStatus({ + className : 'error', + title : 'SETTINGS_PREFERENCES.DIALOG_HEADER_ERROR', + text : 'SETTINGS_PREFERENCES.ERROR_PASSWORD_MISMATCH', + actions : [ ACKNOWLEDGE_ACTION ] + }); + return; + } + + // Verify that the new password is not blank + if (!$scope.newPassword) { + guacNotification.showStatus({ + className : 'error', + title : 'SETTINGS_PREFERENCES.DIALOG_HEADER_ERROR', + text : 'SETTINGS_PREFERENCES.ERROR_PASSWORD_BLANK', + actions : [ ACKNOWLEDGE_ACTION ] + }); + return; + } + + // Save the user with the new password + userService.updateUserPassword(username, $scope.oldPassword, $scope.newPassword) + .success(function passwordUpdated() { + + // Clear the password fields + $scope.oldPassword = null; + $scope.newPassword = null; + $scope.newPasswordMatch = null; + + // Indicate that the password has been changed + guacNotification.showStatus({ + text : 'SETTINGS_PREFERENCES.INFO_PASSWORD_CHANGED', + actions : [ ACKNOWLEDGE_ACTION ] + }); + }) + + // Notify of any errors + .error(function passwordUpdateFailed(error) { + guacNotification.showStatus({ + className : 'error', + title : 'SETTINGS_PREFERENCES.DIALOG_HEADER_ERROR', + 'text' : error.message, + actions : [ ACKNOWLEDGE_ACTION ] + }); + }); + + }; + + // Retrieve current permissions + permissionService.getPermissions(username) + .success(function permissionsRetrieved(permissions) { + + // Add action for changing password if permission is granted + $scope.canChangePassword = PermissionSet.hasUserPermission(permissions, + PermissionSet.ObjectPermissionType.UPDATE, username); + + }); + }] }; diff --git a/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html b/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html index c5e072aa5..003b0bb74 100644 --- a/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html +++ b/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html @@ -21,7 +21,32 @@ THE SOFTWARE. --> - -

TODO

+ +
+

{{'SETTINGS_PREFERENCES.SECTION_HEADER_CHANGE_PASSWORD' | translate}}

-
\ No newline at end of file + +
+ + + + + + + + + + + + + +
{{'SETTINGS_PREFERENCES.FIELD_HEADER_PASSWORD_OLD' | translate}}
{{'SETTINGS_PREFERENCES.FIELD_HEADER_PASSWORD_NEW' | translate}}
{{'SETTINGS_PREFERENCES.FIELD_HEADER_PASSWORD_NEW_AGAIN' | translate}}
+
+ + +
+ +
+ + + diff --git a/guacamole/src/main/webapp/translations/en_US.json b/guacamole/src/main/webapp/translations/en_US.json index 1136719d8..152c05bb7 100644 --- a/guacamole/src/main/webapp/translations/en_US.json +++ b/guacamole/src/main/webapp/translations/en_US.json @@ -4,7 +4,6 @@ "ACTION_ACKNOWLEDGE" : "OK", "ACTION_CANCEL" : "Cancel", - "ACTION_CHANGE_PASSWORD" : "Change Password", "ACTION_CLONE" : "Clone", "ACTION_DELETE" : "Delete", "ACTION_DELETE_SESSIONS" : "Kill Sessions", @@ -18,6 +17,7 @@ "ACTION_NAVIGATE_BACK" : "Back", "ACTION_NAVIGATE_HOME" : "Home", "ACTION_SAVE" : "Save", + "ACTION_UPDATE_PASSWORD" : "Update Password", "DIALOG_HEADER_ERROR" : "Error", @@ -402,6 +402,25 @@ "SETTINGS_PREFERENCES" : { + "ACTION_ACKNOWLEDGE" : "@:APP.ACTION_ACKNOWLEDGE", + "ACTION_CANCEL" : "@:APP.ACTION_CANCEL", + "ACTION_UPDATE_PASSWORD" : "@:APP.ACTION_UPDATE_PASSWORD", + + "DIALOG_HEADER_ERROR" : "@:APP.DIALOG_HEADER_ERROR", + + "ERROR_PASSWORD_BLANK" : "Your password cannot be blank.", + "ERROR_PASSWORD_MISMATCH" : "@:APP.ERROR_PASSWORD_MISMATCH", + + "FIELD_HEADER_PASSWORD" : "Password:", + "FIELD_HEADER_PASSWORD_OLD" : "Current Password:", + "FIELD_HEADER_PASSWORD_NEW" : "New Password:", + "FIELD_HEADER_PASSWORD_NEW_AGAIN" : "Confirm New Password:", + "FIELD_HEADER_USERNAME" : "Username:", + + "INFO_PASSWORD_CHANGED" : "Password changed.", + + "SECTION_HEADER_CHANGE_PASSWORD" : "Change Password" + }, "SETTINGS_USERS" : { @@ -447,28 +466,13 @@ "USER_MENU" : { - "ACTION_ACKNOWLEDGE" : "@:APP.ACTION_ACKNOWLEDGE", - "ACTION_CANCEL" : "@:APP.ACTION_CANCEL", - "ACTION_CHANGE_PASSWORD" : "@:APP.ACTION_CHANGE_PASSWORD", "ACTION_LOGOUT" : "@:APP.ACTION_LOGOUT", "ACTION_MANAGE_CONNECTIONS" : "@:APP.ACTION_MANAGE_CONNECTIONS", "ACTION_MANAGE_PREFERENCES" : "@:APP.ACTION_MANAGE_PREFERENCES", "ACTION_MANAGE_SESSIONS" : "@:APP.ACTION_MANAGE_SESSIONS", "ACTION_MANAGE_SETTINGS" : "@:APP.ACTION_MANAGE_SETTINGS", "ACTION_MANAGE_USERS" : "@:APP.ACTION_MANAGE_USERS", - "ACTION_NAVIGATE_HOME" : "@:APP.ACTION_NAVIGATE_HOME", - "ACTION_SAVE" : "@:APP.ACTION_SAVE", - - "DIALOG_HEADER_ERROR" : "@:APP.DIALOG_HEADER_ERROR", - - "ERROR_PASSWORD_BLANK" : "Your password cannot be blank.", - "ERROR_PASSWORD_MISMATCH" : "@:APP.ERROR_PASSWORD_MISMATCH", - - "FIELD_HEADER_PASSWORD_OLD" : "Current Password:", - "FIELD_HEADER_PASSWORD_NEW" : "New Password:", - "FIELD_HEADER_PASSWORD_NEW_AGAIN" : "Confirm New Password:", - - "PASSWORD_CHANGED" : "Password changed." + "ACTION_NAVIGATE_HOME" : "@:APP.ACTION_NAVIGATE_HOME" }