From 3ef56da8511b4a52c59958819e167f411f63d5ee Mon Sep 17 00:00:00 2001
From: Nils Christian Ehmke <nie@informatik.uni-kiel.de>
Date: Sun, 25 Nov 2012 15:57:35 +0100
Subject: [PATCH] Corrected and advanced the user management

---
 .../persistence/impl/DerbyUserDAOImpl.java    |   2 +
 .../beans/view/CurrentUserManagementBean.java | 120 +++++++++++++++---
 .../lang/UserManagementPage_de.properties     |   1 +
 .../lang/UserManagementPage_en.properties     |   1 +
 .../dialogs/UserManagementDialogs.xhtml       |  75 ++++++++++-
 .../pages/admin/UserManagementPage.xhtml      |   7 +-
 6 files changed, 180 insertions(+), 26 deletions(-)

diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/DerbyUserDAOImpl.java b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/DerbyUserDAOImpl.java
index b7756eda..b64ce0df 100644
--- a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/DerbyUserDAOImpl.java
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/DerbyUserDAOImpl.java
@@ -163,11 +163,13 @@ public class DerbyUserDAOImpl implements IUserDAO {
 			// Choose the right update command, depending on whether the password has to be changed or not
 			if (user.getPassword() == null) {
 				updateCmd = this.connection.prepareStatement("UPDATE Users SET name=?, isGuest=?, isUser=?, isAdministrator=?, isEnabled=? WHERE name=?");
+				updateCmd.setString(6, user.getName());
 			} else {
 				// In this case we have to set the password as well
 				updateCmd = this.connection
 						.prepareStatement("UPDATE Users SET name=?, isGuest=?, isUser=?, isAdministrator=?, isEnabled=?, password=? WHERE name=?");
 				updateCmd.setString(6, user.getPassword());
+				updateCmd.setString(7, user.getName());
 			}
 
 			// Set the other values
diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentUserManagementBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentUserManagementBean.java
index a87f46a0..1af38a82 100644
--- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentUserManagementBean.java
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentUserManagementBean.java
@@ -26,6 +26,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Scope;
 import org.springframework.stereotype.Component;
 
+import kieker.common.logging.Log;
+import kieker.common.logging.LogFactory;
 import kieker.webgui.common.exception.DataAccessException;
 import kieker.webgui.domain.User;
 import kieker.webgui.domain.User.Role;
@@ -33,16 +35,24 @@ import kieker.webgui.service.IUserService;
 import kieker.webgui.web.beans.application.GlobalPropertiesBean;
 
 /**
+ * The {@link CurrentUserManagementBean} contains the necessary data behind an instance of the user management page.
+ * The class is a Spring managed bean with view scope to make sure that one user (even in one session) can open multiple instances of the page at a time without
+ * causing any problems.
+ * 
  * @author Nils Christian Ehmke
  */
 @Component
 @Scope("view")
 public final class CurrentUserManagementBean {
 
+	private static final Log LOG = LogFactory.getLog(CurrentUserManagementBean.class);
+
 	@Autowired
 	private IUserService userService;
 
-	private List<User> availableUses = new ArrayList<User>();
+	private List<User> availableUsers = new ArrayList<User>();
+	private User selectedUserCopy;
+	private User selectedUser;
 
 	/**
 	 * Default constructor. <b>Do not call this constructor manually. It will only be accessed by Spring.</b>
@@ -55,7 +65,7 @@ public final class CurrentUserManagementBean {
 	 * This method initializes the bean. <b>Do not call this method manually. It will only be accessed by Spring.</b>
 	 */
 	@PostConstruct
-	protected void initialialize() {
+	protected synchronized void initialialize() {
 		this.updateList();
 	}
 
@@ -71,44 +81,84 @@ public final class CurrentUserManagementBean {
 	 * @param isEnabled
 	 *            Determines whether the user is enabled already or not.
 	 */
-	public void addUser(final String username, final String password, final Role role, final boolean isEnabled) {
+	public synchronized void addUser(final String username, final String password, final Role role, final boolean isEnabled) {
 		final User user = new User(username, password, role, isEnabled);
 		try {
+			// Add the user to the database and - if that didn't fail - to our list.
 			this.userService.addUser(user);
-			this.availableUses.add(user);
+			this.availableUsers.add(user);
 			GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_INFO, "Added user to the database.");
 		} catch (final DataAccessException ex) {
+			CurrentUserManagementBean.LOG.error("Could not add the user to the database.", ex);
 			GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_ERROR, "Could not add the user to the database.");
 		}
 	}
 
 	/**
-	 * This method removed the given user from the database and informs about success via the growl component.
-	 * 
-	 * @param user
-	 *            The user to be deleted.
+	 * This method removes the currently selected user from the database and informs about success via the growl component.
 	 */
-	public void deleteUser(final User user) {
+	public synchronized void deleteUser() {
 		try {
-			this.userService.deleteUser(user);
-			this.availableUses.remove(user);
+			this.userService.deleteUser(this.selectedUser);
+			this.availableUsers.remove(this.selectedUser);
 			GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_INFO, "Deleted user from the database.");
 		} catch (final DataAccessException ex) {
+			CurrentUserManagementBean.LOG.error("Could not delete the user from the database.", ex);
 			GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_ERROR, "Could not delete the user from the database.");
 		}
 	}
 
 	/**
-	 * This method edits the given user within the database and informs about success via the growl component.
+	 * This method edits the currently selected user within the database and informs about success via the growl component. The password will not be changed.
+	 */
+	public synchronized void editUser() {
+		try {
+			// This is the "normal" edit - make sure that the password won't be changed
+			this.selectedUserCopy.setPassword(null);
+			// Edit the user and replace the entry within our list
+			this.userService.editUser(this.selectedUserCopy);
+			this.availableUsers.set(this.availableUsers.indexOf(this.selectedUser), this.selectedUserCopy);
+
+			GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_INFO, "Modified user within the database.");
+		} catch (final DataAccessException ex) {
+			CurrentUserManagementBean.LOG.error("Could not modify the user within the database.", ex);
+			GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_ERROR, "Could not modify the user within the database.");
+		}
+	}
+
+	/**
+	 * This method edits the currently selected user within the database and informs about success via the growl component. The password will be changed.
+	 */
+	public synchronized void editUserWithPassword() {
+		try {
+			// Edit the user completely and replace the entry within our list
+			this.userService.editUser(this.selectedUserCopy);
+			this.availableUsers.set(this.availableUsers.indexOf(this.selectedUser), this.selectedUserCopy);
+
+			GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_INFO, "Modified user within the database.");
+		} catch (final DataAccessException ex) {
+			CurrentUserManagementBean.LOG.error("Could not modify the user within the database.", ex);
+			GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_ERROR, "Could not modify the user within the database.");
+		}
+	}
+
+	/**
+	 * This method changes the enabled state of the given user and informs about success via the growl component.
 	 * 
 	 * @param user
-	 *            The user to be modified.
+	 *            The user whose state should be changed.
 	 */
-	public void editUser(final User user) {
+	public synchronized void changeUserEnableState(final User user) {
 		try {
-			this.userService.editUser(user);
+			this.setSelectedUser(user);
+			this.selectedUserCopy.setEnabled(!this.selectedUserCopy.isEnabled());
+			this.selectedUserCopy.setPassword(null);
+			this.userService.editUser(this.selectedUserCopy);
+
+			this.availableUsers.set(this.availableUsers.indexOf(this.selectedUser), this.selectedUserCopy);
 			GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_INFO, "Modified user within the database.");
 		} catch (final DataAccessException ex) {
+			CurrentUserManagementBean.LOG.error("Could not modify the user within the database.", ex);
 			GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_ERROR, "Could not modify the user within the database.");
 		}
 	}
@@ -116,10 +166,11 @@ public final class CurrentUserManagementBean {
 	/**
 	 * Updates the list containing the available users.
 	 */
-	public void updateList() {
+	public synchronized void updateList() {
 		try {
-			this.availableUses = this.userService.getUsers();
+			this.availableUsers = this.userService.getUsers();
 		} catch (final DataAccessException ex) {
+			CurrentUserManagementBean.LOG.error("An error occured while accessing the database.", ex);
 			GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while accessing the database.");
 		}
 	}
@@ -129,7 +180,38 @@ public final class CurrentUserManagementBean {
 	 * 
 	 * @return All currently available users.
 	 */
-	public List<User> getUsers() {
-		return this.availableUses;
+	public synchronized List<User> getUsers() {
+		return this.availableUsers;
+	}
+
+	/**
+	 * Getter for the property {@link CurrentUserManagementBean#selectedUser}.
+	 * 
+	 * @return The current value of the property.
+	 */
+	public User getSelectedUser() {
+		return this.selectedUser;
+	}
+
+	/**
+	 * Getter for the property {@link CurrentUserManagementBean#selectedUserCopy}.
+	 * 
+	 * @return The current value of the property.
+	 */
+	public User getSelectedUserCopy() {
+		return this.selectedUserCopy;
+	}
+
+	/**
+	 * Setter for the property {@link CurrentUserManagementBean#selectedUser}.
+	 * 
+	 * @param selectedUser
+	 *            The new value of the property.
+	 */
+	public void setSelectedUser(final User selectedUser) {
+		// We remember the selected user, but we make also a copy. This is necessary, because otherwise we would have to do something like a rollback, if for example
+		// an edit within the DB fails.
+		this.selectedUser = selectedUser;
+		this.selectedUserCopy = new User(selectedUser.getName(), null, selectedUser.getRole(), selectedUser.isEnabled());
 	}
 }
diff --git a/Kieker.WebGUI/src/main/resources/lang/UserManagementPage_de.properties b/Kieker.WebGUI/src/main/resources/lang/UserManagementPage_de.properties
index 878f37ba..2669b5ff 100644
--- a/Kieker.WebGUI/src/main/resources/lang/UserManagementPage_de.properties
+++ b/Kieker.WebGUI/src/main/resources/lang/UserManagementPage_de.properties
@@ -13,6 +13,7 @@ editUser = Benutzer Bearbeiten
 disableUser = Benutzer Deaktivieren
 enableUser = Benutzer Aktivieren
 deleteUser = Benutzer L\u00f6schen
+editPassword = Password Ändern
 
 username = Benutzername
 userrole = Benutzerrolle
diff --git a/Kieker.WebGUI/src/main/resources/lang/UserManagementPage_en.properties b/Kieker.WebGUI/src/main/resources/lang/UserManagementPage_en.properties
index f705fdec..a76b097a 100644
--- a/Kieker.WebGUI/src/main/resources/lang/UserManagementPage_en.properties
+++ b/Kieker.WebGUI/src/main/resources/lang/UserManagementPage_en.properties
@@ -13,6 +13,7 @@ editUser = Edit User
 disableUser = Disable User
 enableUser = Enable User
 deleteUser = Delete User
+editPassword = Edit Password
 
 username = Username
 userrole = Userrole
diff --git a/Kieker.WebGUI/src/main/webapp/dialogs/UserManagementDialogs.xhtml b/Kieker.WebGUI/src/main/webapp/dialogs/UserManagementDialogs.xhtml
index fb9e94bc..ce56e1e7 100644
--- a/Kieker.WebGUI/src/main/webapp/dialogs/UserManagementDialogs.xhtml
+++ b/Kieker.WebGUI/src/main/webapp/dialogs/UserManagementDialogs.xhtml
@@ -3,17 +3,18 @@
     xmlns:h="http://java.sun.com/jsf/html"
     xmlns:ui="http://java.sun.com/jsf/facelets"
     xmlns:f="http://java.sun.com/jsf/core"
-    xmlns:p="http://primefaces.org/ui">     
+    xmlns:p="http://primefaces.org/ui"
+    xmlns:c="http://java.sun.com/jsp/jstl/core">     
 
     <p:dialog id="newUserDialog" header="Neuer Benutzer" resizable="false" modal="true" widgetVar="newUserDlg">
-        <!-- Make sure that closing of the dialog also clears the input field. -->
+        <!-- Make sure that closing of the dialog also clears the input fields. -->
         <p:ajax event="close" update=":newUserDialogForm" />
         <h:form id="newUserDialogForm">
             <h:panelGrid columnClasses="col1 , col2" columns="2" cellpadding="5">
-                <h:outputText value="Benutzername: " /> 
+                <h:outputText value="#{localizedUserManagementMessages.username}: " /> 
                 <p:inputText value="#{newUserBean.username}" style="width: 100%" />
 
-                <h:outputText value="Passwort: " /> 
+                <h:outputText value="#{localizedUserManagementMessages.password}: " /> 
                 <p:password feedback="true" value="#{newUserBean.password}" style="width: 100%" />
 
                 <h:outputText value="Benutzerrolle: " /> 
@@ -36,4 +37,70 @@
             </div>
         </h:form>
     </p:dialog>
+
+    <p:dialog id="editUserDialog" header="Benutzer Bearbeiten" resizable="false" modal="true" widgetVar="editUserDlg">
+        <!-- Make sure that closing of the dialog also clears the input field. -->
+        <p:ajax event="close" update=":editUserDialogForm" />
+        <h:form id="editUserDialogForm">
+            <ui:fragment rendered="#{not empty currentUserManagementBean.selectedUser}">
+                <h:panelGrid columnClasses="col1 , col2" columns="2" cellpadding="5">
+                    <h:outputText value="#{localizedUserManagementMessages.username}: " /> 
+                    <p:inputText value="#{currentUserManagementBean.selectedUserCopy.name}" style="width: 100%" disabled="true" />
+
+                    <h:outputText value="Benutzerrolle: " /> 
+                    <p:selectOneRadio value="#{currentUserManagementBean.selectedUserCopy.role}" converter="roleStringConverter">  
+                        <f:selectItem itemLabel="Gast" itemValue="#{ROLE_GUEST}" />  
+                        <f:selectItem itemLabel="Benutzer" itemValue="#{ROLE_USER}" />  
+                        <f:selectItem itemLabel="Administrator" itemValue="#{ROLE_ADMIN}" />  
+                    </p:selectOneRadio>
+
+                    <h:outputText value="Status: " /> 
+                    <p:selectOneRadio value="#{currentUserManagementBean.selectedUserCopy.enabled}">
+                        <f:selectItem itemLabel="Aktiviert" itemValue="#{true}" />  
+                        <f:selectItem itemLabel="Deaktiviert" itemValue="#{false}" />  
+                    </p:selectOneRadio> 
+                </h:panelGrid>
+            </ui:fragment>
+
+            <hr/>
+            <div style="text-align: right">
+                <p:commandButton value="#{localizedMessages.ok}" action="#{currentUserManagementBean.editUser()}" oncomplete="editUserDlg.hide()" ajax="true" update=":messages :usersListForm"/>
+            </div>
+        </h:form>
+    </p:dialog>
+
+    <p:dialog id="editPasswordDialog" header="Passwort Bearbeiten" resizable="false" modal="true" widgetVar="editPasswordDlg">
+        <!-- Make sure that closing of the dialog also clears the input field. -->
+        <p:ajax event="close" update=":editPasswordDialogForm" />
+        <h:form id="editPasswordDialogForm">
+            <ui:fragment rendered="#{not empty currentUserManagementBean.selectedUser}">
+                <h:panelGrid columnClasses="col1 , col2" columns="2" cellpadding="5">
+                    <h:outputText value="Benutzername: " /> 
+                    <p:inputText value="#{currentUserManagementBean.selectedUserCopy.name}" style="width: 100%" disabled="true" />
+
+                    <h:outputText value="Passwort: " /> 
+                    <p:password feedback="true" value="#{currentUserManagementBean.selectedUserCopy.password}" style="width: 100%" />
+                </h:panelGrid>
+            </ui:fragment>
+
+            <hr/>
+            <div style="text-align: right">
+                <p:commandButton value="#{localizedMessages.ok}" action="#{currentUserManagementBean.editUserWithPassword()}" oncomplete="editPasswordDlg.hide()" ajax="true" update=":messages :usersListForm"/>
+            </div>
+        </h:form>
+    </p:dialog>
+
+    <p:dialog id="deleteUserDialog" header="#{localizedProjectOverviewMessages.deleteProject}" resizable="false" modal="true" widgetVar="deleteUserDlg">
+        <h:form>  
+            <div style="text-align: center">
+                <h:outputText value="Wollen Sie den Benutzer wirklich löschen?" /> 
+            </div>
+
+            <hr/>
+            <div style="text-align: right">
+                <p:commandButton value="#{localizedMessages.ok}" action="#{currentUserManagementBean.deleteUser()}" update=":usersListForm :messages" oncomplete="deleteUserDlg.hide()" />
+            </div>
+        </h:form>  
+    </p:dialog>
+
 </ui:composition>
\ No newline at end of file
diff --git a/Kieker.WebGUI/src/main/webapp/pages/admin/UserManagementPage.xhtml b/Kieker.WebGUI/src/main/webapp/pages/admin/UserManagementPage.xhtml
index 0a341ca0..8fe6135f 100644
--- a/Kieker.WebGUI/src/main/webapp/pages/admin/UserManagementPage.xhtml
+++ b/Kieker.WebGUI/src/main/webapp/pages/admin/UserManagementPage.xhtml
@@ -41,10 +41,11 @@
                             <p:commandLink id="dynaButton" value="#{user.name}"/>
 
                             <p:menu overlay="true" trigger="dynaButton" my="left top" at="left bottom" style="width:210px">
-                                <p:menuitem icon="ui-icon-edit" styleClass="element-with-whitespace" value="  #{localizedUserManagementMessages.editUser}"/>
-                                <p:menuitem icon="ui-icon-userEnableDisable" styleClass="element-with-whitespace" value="  #{user.enabled ? localizedUserManagementMessages.disableUser : localizedUserManagementMessages.enableUser}"/>
+                                <p:menuitem icon="ui-icon-edit" styleClass="element-with-whitespace" value="  #{localizedUserManagementMessages.editUser}" action="#{currentUserManagementBean.setSelectedUser(user)}" update=":editUserDialogForm" onclick="editUserDlg.show();"/>
+                                <p:menuitem icon="ui-icon-edit" styleClass="element-with-whitespace" value="  #{localizedUserManagementMessages.editPassword}" action="#{currentUserManagementBean.setSelectedUser(user)}" update=":editPasswordDialogForm" onclick="editPasswordDlg.show();"/>
+                                <p:menuitem icon="ui-icon-userEnableDisable" styleClass="element-with-whitespace" value="  #{user.enabled ? localizedUserManagementMessages.disableUser : localizedUserManagementMessages.enableUser}" action="#{currentUserManagementBean.changeUserEnableState(user)}" update=":messages :usersListForm"/>
                                 <p:separator/>
-                                <p:menuitem icon="ui-icon-delete" styleClass="element-with-whitespace" value="  #{localizedUserManagementMessages.deleteUser}"/>
+                                <p:menuitem icon="ui-icon-delete" styleClass="element-with-whitespace" value="  #{localizedUserManagementMessages.deleteUser}" action="#{currentUserManagementBean.setSelectedUser(user)}" onclick="deleteUserDlg.show();" update=":messages"/>
                             </p:menu>
                         </p:column>
 
-- 
GitLab