dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #27806
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 13850: Merged in user account invite branch
Merge authors:
Jim Grace (jimgrace)
------------------------------------------------------------
revno: 13850 [merge]
committer: Jim Grace <jimgrace@xxxxxxxxx>
branch nick: dhis2
timestamp: Sat 2014-01-25 14:03:56 -0500
message:
Merged in user account invite branch
added:
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/RestoreType.java
dhis-2/dhis-services/dhis-service-core/src/main/resources/invite_message1.vm
dhis-2/dhis-services/dhis-service-core/src/main/resources/invite_message2.vm
dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/useraccount/action/IsInviteTokenValidAction.java
modified:
dhis-2/dhis-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/DefaultSecurityService.java
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/SecurityService.java
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/setting/DefaultSystemSettingManager.java
dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/security/SecurityServiceTest.java
dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AccountController.java
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/useraccount/account.js
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/useraccount/updateUserAccountForm.js
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/validationRules.js
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/useraccount/account.vm
dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/interceptor/SystemSettingInterceptor.java
dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/useraccount/action/IsRestoreTokenValidAction.java
dhis-2/dhis-web/dhis-web-commons/src/main/resources/META-INF/dhis/beans.xml
dhis-2/dhis-web/dhis-web-commons/src/main/resources/dhis-web-commons.xml
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/SetAccessSettingsAction.java
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/org/hisp/dhis/settings/i18n_module.properties
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemAccessSettings.vm
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/pom.xml
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/AddUserAction.java
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/META-INF/dhis/beans.xml
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/org/hisp/dhis/user/i18n_module.properties
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/struts.xml
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/addUserForm.vm
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/javascript/user.js
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/updateUserForm.vm
--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk
Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java 2013-12-25 15:01:48 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java 2014-01-23 15:04:07 +0000
@@ -79,6 +79,7 @@
final String KEY_SCHEDULE_AGGREGATE_QUERY_BUILDER_TASK_STRATEGY = "scheduleAggregateQueryBuilderTackStrategy";
final String KEY_CONFIGURATION = "keyConfig";
final String KEY_ACCOUNT_RECOVERY = "keyAccountRecovery";
+ final String KEY_ACCOUNT_INVITE = "keyAccountInvite";
final String KEY_LAST_MONITORING_RUN = "keyLastMonitoringRun";
final String KEY_GOOGLE_ANALYTICS_UA = "googleAnalyticsUA";
final String KEY_CREDENTIALS_EXPIRES = "credentialsExpires";
@@ -135,6 +136,8 @@
boolean accountRecoveryEnabled();
+ boolean accountInviteEnabled();
+
boolean selfRegistrationNoRecaptcha();
boolean emailEnabled();
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/DefaultSecurityService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/DefaultSecurityService.java 2014-01-13 15:16:22 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/DefaultSecurityService.java 2014-01-25 18:46:36 +0000
@@ -46,7 +46,6 @@
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Arrays;
-import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -61,10 +60,13 @@
{
private static final Log log = LogFactory.getLog( DefaultSecurityService.class );
- private static final String RESTORE_PATH = "/dhis-web-commons/security/restore.action";
-
- private static final int TOKEN_LENGTH = 50;
- private static final int CODE_LENGTH = 15;
+ private static final String RESTORE_PATH = "/dhis-web-commons/security/";
+
+ private static final int INVITED_USERNAME_UNIQUE_LENGTH = 15;
+ private static final int INVITED_USER_PASSWORD_LENGTH = 40;
+
+ private static final int RESTORE_TOKEN_LENGTH = 50;
+ private static final int RESTORE_CODE_LENGTH = 15;
// -------------------------------------------------------------------------
// Dependencies
@@ -105,7 +107,25 @@
// SecurityService implementation
// -------------------------------------------------------------------------
- public boolean sendRestoreMessage( UserCredentials credentials, String rootPath )
+ public boolean prepareUserForInvite( UserCredentials credentials )
+ {
+ if ( credentials == null || credentials.getUser() == null )
+ {
+ return false;
+ }
+
+ String username = "invitedUser_" + CodeGenerator.generateCode( INVITED_USERNAME_UNIQUE_LENGTH );
+ String rawPassword = CodeGenerator.generateCode( INVITED_USER_PASSWORD_LENGTH );
+
+ credentials.getUser().setSurname( "(TBD)" );
+ credentials.getUser().setFirstName( "(TBD)" );
+ credentials.setUsername( username );
+ credentials.setPassword( passwordManager.encodePassword( username, rawPassword ) );
+
+ return true;
+ }
+
+ public boolean sendRestoreMessage( UserCredentials credentials, String rootPath, RestoreType restoreType )
{
if ( credentials == null || rootPath == null )
{
@@ -114,58 +134,58 @@
if ( credentials.getUser() == null || credentials.getUser().getEmail() == null )
{
- log.info( "Could not send message as user does not exist or has no email: " + credentials );
+ log.info( "Could not send " + restoreType.name() + " message as user does not exist or has no email: " + credentials );
return false;
}
if ( !ValidationUtils.emailIsValid( credentials.getUser().getEmail() ) )
{
- log.info( "Could not send message as email is invalid" );
+ log.info( "Could not send " + restoreType.name() + " message as email is invalid" );
return false;
}
if ( !systemSettingManager.emailEnabled() )
{
- log.info( "Could not send message as email is not configured" );
+ log.info( "Could not send " + restoreType.name() + " message as email is not configured" );
return false;
}
if ( credentials.hasAnyAuthority( Arrays.asList( UserAuthorityGroup.CRITICAL_AUTHS ) ) )
{
- log.info( "Not allowed to recover credentials with critical authorities" );
+ log.info( "Not allowed to " + restoreType.name() + " users with critical authorities" );
return false;
}
- String[] result = initRestore( credentials );
+ String[] result = initRestore( credentials, restoreType );
Set<User> users = new HashSet<User>();
users.add( credentials.getUser() );
Map<String, String> vars = new HashMap<String, String>();
vars.put( "rootPath", rootPath );
- vars.put( "restorePath", rootPath + RESTORE_PATH );
+ vars.put( "restorePath", rootPath + RESTORE_PATH + restoreType.getAction() );
vars.put( "token", result[0] );
vars.put( "code", result[1] );
vars.put( "username", credentials.getUsername() );
- String text1 = new VelocityManager().render( vars, "restore_message1" );
- String text2 = new VelocityManager().render( vars, "restore_message2" );
+ String text1 = new VelocityManager().render( vars, restoreType.getEmailTemplate() + "1" );
+ String text2 = new VelocityManager().render( vars, restoreType.getEmailTemplate() + "2" );
- emailMessageSender.sendMessage( "User account restore confirmation (message 1 of 2)", text1, null, users, true );
- emailMessageSender.sendMessage( "User account restore confirmation (message 2 of 2)", text2, null, users, true );
+ emailMessageSender.sendMessage( restoreType.getEmailSubject() + " (message 1 of 2)", text1, null, users, true );
+ emailMessageSender.sendMessage( restoreType.getEmailSubject() + " (message 2 of 2)", text2, null, users, true );
return true;
}
- public String[] initRestore( UserCredentials credentials )
+ public String[] initRestore( UserCredentials credentials, RestoreType restoreType )
{
- String token = CodeGenerator.generateCode( TOKEN_LENGTH );
- String code = CodeGenerator.generateCode( CODE_LENGTH );
+ String token = restoreType.getTokenPrefix() + CodeGenerator.generateCode( RESTORE_TOKEN_LENGTH );
+ String code = CodeGenerator.generateCode( RESTORE_CODE_LENGTH );
String hashedToken = passwordManager.encodePassword( credentials.getUsername(), token );
String hashedCode = passwordManager.encodePassword( credentials.getUsername(), code );
- Date expiry = new Cal().now().add( Calendar.HOUR_OF_DAY, 1 ).time();
+ Date expiry = new Cal().now().add( restoreType.getExpiryIntervalType(), restoreType.getExpiryIntervalCount() ).time();
credentials.setRestoreToken( hashedToken );
credentials.setRestoreCode( hashedCode );
@@ -177,24 +197,15 @@
return result;
}
- public boolean restore( UserCredentials credentials, String token, String code, String newPassword )
+ public boolean restore( UserCredentials credentials, String token, String code, String newPassword, RestoreType restoreType )
{
- if ( credentials == null || token == null || code == null || newPassword == null )
+ if ( credentials == null || token == null || code == null || newPassword == null
+ || !canRestoreNow( credentials, token, code, restoreType ) )
{
return false;
}
String username = credentials.getUsername();
-
- token = passwordManager.encodePassword( username, token );
- code = passwordManager.encodePassword( username, code );
-
- Date date = new Cal().now().time();
-
- if ( !credentials.canRestore( token, code, date ) )
- {
- return false;
- }
newPassword = passwordManager.encodePassword( username, newPassword );
@@ -209,13 +220,36 @@
return true;
}
- public boolean verifyToken( UserCredentials credentials, String token )
+ public boolean canRestoreNow( UserCredentials credentials, String token, String code, RestoreType restoreType )
+ {
+ if ( !verifyToken ( credentials, token, restoreType ) )
+ {
+ return false;
+ }
+
+ String username = credentials.getUsername();
+
+ String encodedToken = passwordManager.encodePassword( username, token );
+ String encodedCode = passwordManager.encodePassword( username, code );
+
+ Date date = new Cal().now().time();
+
+ return credentials.canRestore( encodedToken, encodedCode, date );
+ }
+
+ public boolean verifyToken( UserCredentials credentials, String token, RestoreType restoreType )
{
if ( credentials == null || token == null )
{
return false;
}
+ if ( !token.startsWith( restoreType.getTokenPrefix() ) )
+ {
+ log.info( "Wrong prefix for restore type " + restoreType.name() + " on token: " + token );
+ return false;
+ }
+
if ( credentials.getRestoreToken() == null )
{
log.info( "Could not verify token as user has no token: " + credentials );
=== added file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/RestoreType.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/RestoreType.java 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/RestoreType.java 2014-01-17 03:48:57 +0000
@@ -0,0 +1,122 @@
+package org.hisp.dhis.security;
+/*
+ * Copyright (c) 2004-2013, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.util.Calendar;
+
+/**
+ * Type of user account restore operation.
+ *
+ * @author Jim Grace
+ */
+
+public enum RestoreType
+{
+ RECOVER_PASSWORD ("R", Calendar.HOUR_OF_DAY, 1, "restore_message", "User account restore confirmation", "restore.action" ),
+ INVITE ("I", Calendar.MONTH, 3, "invite_message", "Create DHIS 2 user account invitation", "invite.action" );
+
+ /**
+ * Prefix to be used on restore token. This prevents one type of restore
+ * URL from being hacked and used for a different type of restore.
+ */
+ private final String tokenPrefix;
+
+ /**
+ * Type of Calendar interval before the restore expires.
+ */
+ private final int expiryIntervalType;
+
+ /**
+ * Count of Calendar intervals before the restore expires.
+ */
+ private final int expiryIntervalCount;
+
+ /**
+ * Name of the email template for this restore action type.
+ */
+ private final String emailTemplate;
+
+ /**
+ * Subject line of the email for this restore action type.
+ */
+ private final String emailSubject;
+
+ /**
+ * Return web action to put in the email message.
+ */
+ private final String action;
+
+ // -------------------------------------------------------------------------
+ // Constructor
+ // -------------------------------------------------------------------------
+
+ RestoreType( String tokenPrefix, int expiryIntervalType, int expiryIntervalCount,
+ String emailTemplate, String emailSubject, String action )
+ {
+ this.tokenPrefix = tokenPrefix;
+ this.expiryIntervalType = expiryIntervalType;
+ this.expiryIntervalCount = expiryIntervalCount;
+ this.emailTemplate = emailTemplate;
+ this.emailSubject = emailSubject;
+ this.action = action;
+ }
+
+ // -------------------------------------------------------------------------
+ // Getters
+ // -------------------------------------------------------------------------
+
+ public String getTokenPrefix()
+ {
+ return tokenPrefix;
+ }
+
+ public int getExpiryIntervalType()
+ {
+ return expiryIntervalType;
+ }
+
+ public int getExpiryIntervalCount()
+ {
+ return expiryIntervalCount;
+ }
+
+ public String getEmailTemplate()
+ {
+ return emailTemplate;
+ }
+
+ public String getEmailSubject()
+ {
+ return emailSubject;
+ }
+
+ public String getAction()
+ {
+ return action;
+ }
+}
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/SecurityService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/SecurityService.java 2014-01-13 15:16:22 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/SecurityService.java 2014-01-25 18:46:36 +0000
@@ -37,27 +37,42 @@
public interface SecurityService
{
/**
- * Will invoke the initiateRestore method and dispatch email messages with
+ * Sets information for a user who will be invited by email to finish
+ * setting up their user account.
+ *
+ * @param credentials the credentials of the user to invite.
+ * @return true if the invitation was sent, otherwise false.
+ */
+ boolean prepareUserForInvite( UserCredentials credentials );
+
+ /**
+ * Invokes the initRestore method and dispatches email messages with
* restore information to the user.
+ * <p>
+ * In the case of inviting a user to finish setting up an account,
+ * the user account must already be configured with the profile desired
+ * for the user (e.g., locale, organisation unit(s), role(s), etc.)
*
* @param credentials the credentials for the user to send restore message.
* @param rootPath the root path of the request.
+ * @param restoreType type of restore operation (e.g. pw recovery, invite).
* @return false if any of the arguments are null or if the user credentials
* identified by the user name does not exist, true otherwise.
*/
- boolean sendRestoreMessage( UserCredentials credentials, String rootPath );
+ boolean sendRestoreMessage( UserCredentials credentials, String rootPath, RestoreType restoreType );
/**
- * Will populate the restoreToken and restoreCode property of the given
- * credentials with a hashed version of auto-generated values. Will set the
- * restoreExpiry property with a date time one hour from now. Changes will be
- * persisted.
+ * Populates the restoreToken and restoreCode property of the given
+ * credentials with a hashed version of auto-generated values. Sets the
+ * restoreExpiry property with a date time some interval from now depending
+ * on the restore type. Changes are persisted.
*
* @param credentials the user credentials.
+ * @param restoreType type of restore operation (e.g. pw recovery, invite).
* @return an array where index 0 is the clear-text token and index 1 the
* clear-text code.
*/
- String[] initRestore( UserCredentials credentials );
+ String[] initRestore( UserCredentials credentials, RestoreType restoreType );
/**
* Tests whether the given token and code are valid for the given user name.
@@ -70,9 +85,24 @@
* @param token the token.
* @param code the code.
* @param newPassword the proposed new password.
- * @return true or false.
- */
- boolean restore( UserCredentials credentials, String token, String code, String newPassword );
+ * @param restoreType type of restore operation (e.g. pw recovery, invite).
+ * @return true or false.
+ */
+ boolean restore( UserCredentials credentials, String token, String code, String newPassword, RestoreType restoreType );
+
+ /**
+ * Tests whether the given token and code are valid for the given user name.
+ * In order to succeed, the given token and code must match the ones on the
+ * credentials, and the current date must be before the expiry date time of
+ * the credentials.
+ *
+ * @param credentials the user credentials.
+ * @param token the token.
+ * @param code the code.
+ * @param restoreType type of restore operation (e.g. pw recovery, invite).
+ * @return true or false.
+ */
+ boolean canRestoreNow( UserCredentials credentials, String token, String code, RestoreType restoreType );
/**
* Tests whether the given token in combination with the given user name is
@@ -85,7 +115,7 @@
* identified by the user name does not exist, true if the arguments
* are valid.
*/
- boolean verifyToken( UserCredentials credentials, String token );
+ boolean verifyToken( UserCredentials credentials, String token, RestoreType restoreType );
/**
* Checks whether current user has read access to object.
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/setting/DefaultSystemSettingManager.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/setting/DefaultSystemSettingManager.java 2013-12-19 13:25:04 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/setting/DefaultSystemSettingManager.java 2014-01-23 15:04:07 +0000
@@ -163,6 +163,11 @@
return (Boolean) getSystemSetting( KEY_ACCOUNT_RECOVERY, false );
}
+ public boolean accountInviteEnabled()
+ {
+ return (Boolean) getSystemSetting( KEY_ACCOUNT_INVITE, false );
+ }
+
@Override
public boolean selfRegistrationNoRecaptcha()
{
=== added file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/invite_message1.vm'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/invite_message1.vm 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/invite_message1.vm 2014-01-17 03:48:57 +0000
@@ -0,0 +1,11 @@
+This is an invitation to create a user account on the DHIS 2 system at ${object.rootPath}.
+You have been sent two emails, where this is the first one. Please follow the
+link below. In the next step you will be asked to enter a code which has been
+sent to you in the other email.
+
+
+${object.restorePath}?username=${object.username}&token=${object.token}
+
+
+You must respond to this invitation within 3 months. If you take no action,
+the invitation will expire at that time.
=== added file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/invite_message2.vm'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/invite_message2.vm 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/invite_message2.vm 2014-01-23 15:04:07 +0000
@@ -0,0 +1,11 @@
+This is an invitation to create a user account on the DHIS 2 system at ${object.rootPath}.
+You have been sent two emails, where this is the second one. Please read the
+first email and follow the instructions. Please use the code below to complete
+the new account form.
+
+
+${object.code}
+
+
+You must respond to this invitation within 3 months. If you take no action,
+the invitation will expire at that time.
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/security/SecurityServiceTest.java'
--- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/security/SecurityServiceTest.java 2014-01-13 15:16:22 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/security/SecurityServiceTest.java 2014-01-25 18:46:36 +0000
@@ -44,7 +44,9 @@
extends DhisSpringTest
{
private UserCredentials credentials;
-
+
+ private UserCredentials otherCredentials;
+
@Autowired
private UserService userService;
@@ -60,37 +62,142 @@
credentials = new UserCredentials();
credentials.setUsername( "johndoe" );
credentials.setPassword( "" );
-
- User user = createUser( 'A' );
- user.setEmail( "valid@xxxxxxxxx" );
- user.setUserCredentials( credentials );
- credentials.setUser( user );
+
+ User userA = createUser( 'A' );
+ userA.setEmail( "validA@xxxxxxxxx" );
+ userA.setUserCredentials( credentials );
+ credentials.setUser( userA );
userService.addUserCredentials( credentials );
- }
-
- @Test
- public void testRestore()
- {
- String[] result = securityService.initRestore( credentials );
-
- assertNotNull( result[0] );
- assertNotNull( result[1] );
- assertNotNull( credentials.getRestoreToken() );
- assertNotNull( credentials.getRestoreCode() );
- assertNotNull( credentials.getRestoreExpiry() );
-
- boolean verified = securityService.verifyToken( credentials, result[0] );
-
- assertTrue( verified );
-
- String password = "NewPassword1";
-
- boolean restored = securityService.restore( credentials, result[0], result[1], password );
-
- assertTrue( restored );
-
- String hashedPassword = passwordManager.encodePassword( credentials.getUsername(), password );
-
+
+ otherCredentials = new UserCredentials();
+ otherCredentials.setUsername( "janesmith" );
+ otherCredentials.setPassword( "" );
+
+ User userB = createUser( 'B' );
+ userB.setEmail( "validB@xxxxxxxxx" );
+ userB.setUserCredentials( otherCredentials );
+ otherCredentials.setUser( userB );
+ userService.addUserCredentials( otherCredentials );
+ }
+
+ @Test
+ public void testRestoreRecoverPassword()
+ {
+ String[] result = securityService.initRestore( credentials, RestoreType.RECOVER_PASSWORD );
+
+ String token = result[0];
+ String code = result[1];
+
+ assertNotNull( token );
+ assertNotNull( code );
+ assertNotNull( credentials.getRestoreToken() );
+ assertNotNull( credentials.getRestoreCode() );
+ assertNotNull( credentials.getRestoreExpiry() );
+
+ //
+ // verifyToken()
+ //
+ assertFalse( securityService.verifyToken( otherCredentials, token, RestoreType.RECOVER_PASSWORD ) );
+
+ assertFalse( securityService.verifyToken( credentials, "wrongToken", RestoreType.RECOVER_PASSWORD ) );
+
+ assertFalse( securityService.verifyToken( credentials, token, RestoreType.INVITE ) );
+
+ assertTrue( securityService.verifyToken( credentials, token, RestoreType.RECOVER_PASSWORD ) );
+
+ //
+ // canRestoreNow()
+ //
+ assertFalse( securityService.canRestoreNow( otherCredentials, token, code, RestoreType.RECOVER_PASSWORD ) );
+
+ assertFalse( securityService.canRestoreNow( credentials, "wrongToken", code, RestoreType.RECOVER_PASSWORD ) );
+
+ assertFalse( securityService.canRestoreNow( credentials, token, "wrongCode", RestoreType.RECOVER_PASSWORD ) );
+
+ assertFalse( securityService.canRestoreNow( credentials, token, code, RestoreType.INVITE ) );
+
+ assertTrue( securityService.canRestoreNow( credentials, token, code, RestoreType.RECOVER_PASSWORD ) );
+
+ //
+ // restore()
+ //
+ String password = "NewPassword1";
+
+ assertFalse( securityService.restore( otherCredentials, token, code, password, RestoreType.RECOVER_PASSWORD ) );
+
+ assertFalse( securityService.restore( credentials, "wrongToken", code, password, RestoreType.RECOVER_PASSWORD ) );
+
+ assertFalse( securityService.restore( credentials, token, "wrongCode", password, RestoreType.RECOVER_PASSWORD ) );
+
+ assertFalse( securityService.restore( credentials, token, code, password, RestoreType.INVITE ) );
+
+ assertTrue( securityService.restore( credentials, token, code, password, RestoreType.RECOVER_PASSWORD ) );
+
+ //
+ // check password
+ //
+ String hashedPassword = passwordManager.encodePassword( credentials.getUsername(), password );
+
+ assertEquals( hashedPassword, credentials.getPassword() );
+ }
+
+ @Test
+ public void testRestoreInvite()
+ {
+ String[] result = securityService.initRestore( credentials, RestoreType.INVITE );
+ String token = result[0];
+ String code = result[1];
+
+ assertNotNull( token );
+ assertNotNull( code );
+ assertNotNull( credentials.getRestoreToken() );
+ assertNotNull( credentials.getRestoreCode() );
+ assertNotNull( credentials.getRestoreExpiry() );
+
+ //
+ // verifyToken()
+ //
+ assertFalse( securityService.verifyToken( otherCredentials, token, RestoreType.INVITE ) );
+
+ assertFalse( securityService.verifyToken( credentials, "wrongToken", RestoreType.INVITE ) );
+
+ assertFalse( securityService.verifyToken( credentials, token, RestoreType.RECOVER_PASSWORD ) );
+
+ assertTrue( securityService.verifyToken( credentials, token, RestoreType.INVITE ) );
+
+ //
+ // canRestoreNow()
+ //
+ assertFalse( securityService.canRestoreNow( otherCredentials, token, code, RestoreType.INVITE ) );
+
+ assertFalse( securityService.canRestoreNow( credentials, "wrongToken", code, RestoreType.INVITE ) );
+
+ assertFalse( securityService.canRestoreNow( credentials, token, "wrongCode", RestoreType.INVITE ) );
+
+ assertFalse( securityService.canRestoreNow( credentials, token, code, RestoreType.RECOVER_PASSWORD ) );
+
+ assertTrue( securityService.canRestoreNow( credentials, token, code, RestoreType.INVITE ) );
+
+ //
+ // restore()
+ //
+ String password = "NewPassword1";
+
+ assertFalse( securityService.restore( otherCredentials, token, code, password, RestoreType.INVITE ) );
+
+ assertFalse( securityService.restore( credentials, "wrongToken", code, password, RestoreType.INVITE ) );
+
+ assertFalse( securityService.restore( credentials, token, "wrongCode", password, RestoreType.INVITE ) );
+
+ assertFalse( securityService.restore( credentials, token, code, password, RestoreType.RECOVER_PASSWORD ) );
+
+ assertTrue( securityService.restore( credentials, token, code, password, RestoreType.INVITE ) );
+
+ //
+ // check password
+ //
+ String hashedPassword = passwordManager.encodePassword( credentials.getUsername(), password );
+
assertEquals( hashedPassword, credentials.getPassword() );
}
}
=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AccountController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AccountController.java 2014-01-13 15:16:22 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AccountController.java 2014-01-23 15:04:07 +0000
@@ -35,7 +35,9 @@
import org.hisp.dhis.api.utils.ContextUtils;
import org.hisp.dhis.configuration.ConfigurationService;
import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.period.Cal;
import org.hisp.dhis.security.PasswordManager;
+import org.hisp.dhis.security.RestoreType;
import org.hisp.dhis.security.SecurityService;
import org.hisp.dhis.setting.SystemSettingManager;
import org.hisp.dhis.system.util.ValidationUtils;
@@ -131,7 +133,7 @@
return "User does not exist: " + username;
}
- boolean recover = securityService.sendRestoreMessage( credentials, rootPath );
+ boolean recover = securityService.sendRestoreMessage( credentials, rootPath, RestoreType.RECOVER_PASSWORD );
if ( !recover )
{
@@ -180,7 +182,7 @@
return "User does not exist: " + username;
}
- boolean restore = securityService.restore( credentials, token, code, password );
+ boolean restore = securityService.restore( credentials, token, code, password, RestoreType.RECOVER_PASSWORD );
if ( !restore )
{
@@ -203,17 +205,51 @@
@RequestParam String email,
@RequestParam String phoneNumber,
@RequestParam String employer,
+ @RequestParam String inviteUsername,
+ @RequestParam String inviteToken,
+ @RequestParam String inviteCode,
@RequestParam( value = "recaptcha_challenge_field", required = false ) String recapChallenge,
@RequestParam( value = "recaptcha_response_field", required = false ) String recapResponse,
HttpServletRequest request,
HttpServletResponse response )
{
- boolean allowed = configurationService.getConfiguration().selfRegistrationAllowed();
-
- if ( !allowed )
- {
- response.setStatus( HttpServletResponse.SC_BAD_REQUEST );
- return "User self registration is not allowed";
+ UserCredentials credentials = null;
+
+ boolean invitedByEmail = !inviteUsername.isEmpty();
+
+ if ( invitedByEmail )
+ {
+ if ( !systemSettingManager.accountInviteEnabled() )
+ {
+ response.setStatus( HttpServletResponse.SC_CONFLICT );
+ return "Account invite is not enabled";
+ }
+
+ credentials = userService.getUserCredentialsByUsername( inviteUsername );
+
+ if ( credentials == null )
+ {
+ response.setStatus( HttpServletResponse.SC_BAD_REQUEST );
+ return "Invitation link not valid";
+ }
+
+ boolean canRestore = securityService.canRestoreNow( credentials, inviteToken, inviteCode, RestoreType.INVITE );
+
+ if ( !canRestore )
+ {
+ response.setStatus( HttpServletResponse.SC_BAD_REQUEST );
+ return "Invitation code not valid";
+ }
+ }
+ else
+ {
+ boolean allowed = configurationService.getConfiguration().selfRegistrationAllowed();
+
+ if ( !allowed )
+ {
+ response.setStatus( HttpServletResponse.SC_BAD_REQUEST );
+ return "User self registration is not allowed";
+ }
}
// ---------------------------------------------------------------------
@@ -240,9 +276,9 @@
return "User name is not specified or invalid";
}
- UserCredentials credentials = userService.getUserCredentialsByUsername( username );
+ UserCredentials usernameAlreadyTakenCredentials = userService.getUserCredentialsByUsername( username );
- if ( credentials != null )
+ if ( usernameAlreadyTakenCredentials != null )
{
response.setStatus( HttpServletResponse.SC_BAD_REQUEST );
return "User name is already taken";
@@ -333,32 +369,64 @@
// Create and save user, return 201
// ---------------------------------------------------------------------
- UserAuthorityGroup userRole = configurationService.getConfiguration().getSelfRegistrationRole();
- OrganisationUnit orgUnit = configurationService.getConfiguration().getSelfRegistrationOrgUnit();
-
- User user = new User();
- user.setFirstName( firstName );
- user.setSurname( surname );
- user.setEmail( email );
- user.setPhoneNumber( phoneNumber );
- user.setEmployer( employer );
- user.getOrganisationUnits().add( orgUnit );
-
- credentials = new UserCredentials();
- credentials.setUsername( username );
- credentials.setPassword( passwordManager.encodePassword( username, password ) );
- credentials.setSelfRegistered( true );
- credentials.setUser( user );
- credentials.getUserAuthorityGroups().add( userRole );
-
- user.setUserCredentials( credentials );
-
- userService.addUser( user );
- userService.addUserCredentials( credentials );
-
- authenticate( username, password, userRole, request );
-
- log.info( "Created user with username: " + username );
+ if ( invitedByEmail )
+ {
+ boolean restored = securityService.restore( credentials, inviteToken, inviteCode, password, RestoreType.INVITE );
+
+ if ( !restored )
+ {
+ log.info( "Invite restore failed for: " + inviteUsername );
+
+ response.setStatus( HttpServletResponse.SC_BAD_REQUEST );
+ return "Unable to create invited user account";
+ }
+
+ User user = credentials.getUser();
+ user.setFirstName( firstName );
+ user.setSurname( surname );
+ user.setEmail( email );
+ user.setPhoneNumber( phoneNumber );
+ user.setEmployer( employer );
+
+ credentials.setUsername( username );
+ credentials.setPassword( passwordManager.encodePassword( username, password ) );
+
+ userService.updateUser( user );
+ userService.updateUserCredentials( credentials );
+
+ log.info( "User " + username + " accepted invitation for " + inviteUsername );
+ }
+ else
+ {
+ UserAuthorityGroup userRole = configurationService.getConfiguration().getSelfRegistrationRole();
+ OrganisationUnit orgUnit = configurationService.getConfiguration().getSelfRegistrationOrgUnit();
+
+ User user = new User();
+ user.setFirstName( firstName );
+ user.setSurname( surname );
+ user.setEmail( email );
+ user.setPhoneNumber( phoneNumber );
+ user.setEmployer( employer );
+ user.getOrganisationUnits().add( orgUnit );
+
+ credentials = new UserCredentials();
+ credentials.setUsername( username );
+ credentials.setPassword( passwordManager.encodePassword( username, password ) );
+ credentials.setSelfRegistered( true );
+ credentials.setUser( user );
+ credentials.getUserAuthorityGroups().add( userRole );
+
+ user.setUserCredentials( credentials );
+
+ userService.addUser( user );
+ userService.addUserCredentials( credentials );
+
+ log.info( "Created user with username: " + username );
+ }
+
+ Set<GrantedAuthority> authorities = getAuthorities( credentials.getUserAuthorityGroups() );
+
+ authenticate( username, password, authorities, request );
response.setStatus( HttpServletResponse.SC_CREATED );
return "Account created";
@@ -473,23 +541,9 @@
session.setAttribute( "SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext() );
}
- private void authenticate( String username, String rawPassword, UserAuthorityGroup userRole, HttpServletRequest request )
- {
- UsernamePasswordAuthenticationToken token =
- new UsernamePasswordAuthenticationToken( username, rawPassword, getAuthorities( userRole ) );
-
- Authentication auth = authenticationManager.authenticate( token );
-
- SecurityContextHolder.getContext().setAuthentication( auth );
-
- HttpSession session = request.getSession();
-
- session.setAttribute( "SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext() );
- }
-
- private Collection<GrantedAuthority> getAuthorities( Set<UserAuthorityGroup> userRoles )
- {
- Collection<GrantedAuthority> auths = new HashSet<GrantedAuthority>();
+ private Set<GrantedAuthority> getAuthorities( Set<UserAuthorityGroup> userRoles )
+ {
+ Set<GrantedAuthority> auths = new HashSet<GrantedAuthority>();
for ( UserAuthorityGroup userRole : userRoles )
{
@@ -499,9 +553,9 @@
return auths;
}
- private Collection<GrantedAuthority> getAuthorities( UserAuthorityGroup userRole )
+ private Set<GrantedAuthority> getAuthorities( UserAuthorityGroup userRole )
{
- Collection<GrantedAuthority> auths = new HashSet<GrantedAuthority>();
+ Set<GrantedAuthority> auths = new HashSet<GrantedAuthority>();
for ( String auth : userRole.getAuthorities() )
{
=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/useraccount/account.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/useraccount/account.js 2013-12-19 13:25:04 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/useraccount/account.js 2014-01-17 03:48:57 +0000
@@ -28,6 +28,11 @@
email: true,
rangelength: [ 4, 80 ]
},
+ inviteEmail : {
+ required : true,
+ email : true,
+ rangelength : [ 4, 80 ]
+ },
phoneNumber: {
required: true,
rangelength: [ 6, 30 ]
=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/useraccount/updateUserAccountForm.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/useraccount/updateUserAccountForm.js 2012-10-11 17:21:32 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/useraccount/updateUserAccountForm.js 2014-01-17 03:48:57 +0000
@@ -5,6 +5,7 @@
/* some customization is needed for the updateUserAccount validation rules */
rules["rawPassword"].required = false;
rules["retypePassword"].required = false;
+ rules["inviteEmail"].required = false;
rules["oldPassword"] = {
required: true
=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/validationRules.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/validationRules.js 2014-01-14 13:07:02 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/validationRules.js 2014-01-17 03:48:57 +0000
@@ -31,6 +31,11 @@
"email" : true,
"rangelength" : [ 0, 160 ]
},
+ "inviteEmail" : {
+ "required" : true,
+ "email" : true,
+ "rangelength" : [ 4, 160 ]
+ },
"phoneNumber" : {
"rangelength" : [ 0, 80 ]
},
=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/useraccount/account.vm'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/useraccount/account.vm 2013-12-19 13:25:04 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/useraccount/account.vm 2014-01-23 15:04:07 +0000
@@ -27,6 +27,16 @@
<form id="accountForm">
<table>
+
+ <tr #if( $accountAction != "invited" ) style="display:none" #end>
+ <td style="width:140px"><label for="code">$i18n.getString( "code_from_email" )</label></td>
+ <td>
+ <input type="text" id="inviteCode" name="inviteCode" autocomplete="off">
+ <input type="hidden" id="inviteUsername" name="inviteUsername" #if( $accountAction == "invited" ) value="$username" #end>
+ <input type="hidden" id="inviteToken" name="inviteToken" #if( $accountAction == "invited" ) value="$token" #end>
+ </td>
+ </tr>
+
<tr>
<td style="width:140px"><label id="label_firstName" for="firstName">$i18n.getString( "name" )</label></td>
<td><input type="text" id="firstName" name="firstName" autocomplete="off" style="width:11.7em; margin-right:7px;" placeholder="First">
@@ -46,7 +56,7 @@
</tr>
<tr>
<td><label id="label_email" for="email">$i18n.getString( "email" )</label></td>
- <td><input type="text" id="email" name="email"></td>
+ <td><input type="text" id="email" name="email" #if( $accountAction == "invited" )value="$email" #end></td>
</tr>
<tr>
<td><label id="label_phoneNumber" for="phoneNumber">$i18n.getString( "mobile_phone" )</label></td>
=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/interceptor/SystemSettingInterceptor.java'
--- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/interceptor/SystemSettingInterceptor.java 2013-12-25 15:01:48 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/interceptor/SystemSettingInterceptor.java 2014-01-23 15:04:07 +0000
@@ -94,6 +94,7 @@
map.put( KEY_PHONE_NUMBER_AREA_CODE, systemSettingManager.getSystemSetting( KEY_PHONE_NUMBER_AREA_CODE, "" ) );
map.put( KEY_MULTI_ORGANISATION_UNIT_FORMS, systemSettingManager.getSystemSetting( KEY_MULTI_ORGANISATION_UNIT_FORMS, false ) );
map.put( KEY_ACCOUNT_RECOVERY, systemSettingManager.getSystemSetting( KEY_ACCOUNT_RECOVERY, false ) );
+ map.put( KEY_ACCOUNT_INVITE, systemSettingManager.getSystemSetting( KEY_ACCOUNT_INVITE, false ) );
map.put( KEY_CONFIGURATION, configurationService.getConfiguration() );
map.put( KEY_APP_BASE_URL, systemSettingManager.getSystemSetting( KEY_APP_BASE_URL ) );
map.put( KEY_GOOGLE_ANALYTICS_UA, systemSettingManager.getSystemSetting( KEY_GOOGLE_ANALYTICS_UA, "" ) );
=== added file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/useraccount/action/IsInviteTokenValidAction.java'
--- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/useraccount/action/IsInviteTokenValidAction.java 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/useraccount/action/IsInviteTokenValidAction.java 2014-01-23 15:04:07 +0000
@@ -0,0 +1,132 @@
+package org.hisp.dhis.useraccount.action;
+
+/*
+ * Copyright (c) 2004-2013, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import org.hisp.dhis.security.RestoreType;
+import org.hisp.dhis.security.SecurityService;
+import org.hisp.dhis.setting.SystemSettingManager;
+import org.hisp.dhis.user.UserCredentials;
+import org.hisp.dhis.user.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.opensymphony.xwork2.Action;
+
+/**
+ * @author Jim Grace
+ */
+public class IsInviteTokenValidAction
+ implements Action
+{
+ @Autowired
+ private SystemSettingManager systemSettingManager;
+
+ @Autowired
+ private SecurityService securityService;
+
+ @Autowired
+ private UserService userService;
+
+ // -------------------------------------------------------------------------
+ // Input
+ // -------------------------------------------------------------------------
+
+ private String username;
+
+ public String getUsername()
+ {
+ return username;
+ }
+
+ public void setUsername( String username )
+ {
+ this.username = username;
+ }
+
+ private String token;
+
+ public String getToken()
+ {
+ return token;
+ }
+
+ public void setToken( String token )
+ {
+ this.token = token;
+ }
+
+ // -------------------------------------------------------------------------
+ // Output
+ // -------------------------------------------------------------------------
+
+ private UserCredentials userCredentials;
+
+ public UserCredentials getUserCredentials()
+ {
+ return userCredentials;
+ }
+
+ private final String accountAction = "invited";
+
+ public String getAccountAction()
+ {
+ return accountAction;
+ }
+
+ private String email;
+
+ public String getEmail()
+ {
+ return email;
+ }
+
+ // -------------------------------------------------------------------------
+ // Action implementation
+ // -------------------------------------------------------------------------
+
+ public String execute()
+ {
+ if ( !systemSettingManager.accountInviteEnabled() )
+ {
+ return ERROR;
+ }
+
+ userCredentials = userService.getUserCredentialsByUsername( username );
+
+ if ( userCredentials == null )
+ {
+ return ERROR;
+ }
+
+ email = userCredentials.getUser().getEmail();
+
+ boolean verified = securityService.verifyToken( userCredentials, token, RestoreType.INVITE );
+
+ return verified ? SUCCESS : ERROR;
+ }
+}
=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/useraccount/action/IsRestoreTokenValidAction.java'
--- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/useraccount/action/IsRestoreTokenValidAction.java 2014-01-13 15:44:28 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/useraccount/action/IsRestoreTokenValidAction.java 2014-01-17 03:48:57 +0000
@@ -28,6 +28,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+import org.hisp.dhis.security.RestoreType;
import org.hisp.dhis.security.SecurityService;
import org.hisp.dhis.user.UserCredentials;
import org.hisp.dhis.user.UserService;
@@ -88,7 +89,7 @@
return ERROR;
}
- boolean verified = securityService.verifyToken( credentials, token );
+ boolean verified = securityService.verifyToken( credentials, token, RestoreType.RECOVER_PASSWORD );
return verified ? SUCCESS : ERROR;
}
=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-web/dhis-web-commons/src/main/resources/META-INF/dhis/beans.xml 2014-01-08 17:41:22 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/resources/META-INF/dhis/beans.xml 2014-01-23 15:04:07 +0000
@@ -577,6 +577,9 @@
<bean id="org.hisp.dhis.useraccount.action.IsRestoreTokenValidAction" class="org.hisp.dhis.useraccount.action.IsRestoreTokenValidAction"
scope="prototype" />
+ <bean id="org.hisp.dhis.useraccount.action.IsInviteTokenValidAction" class="org.hisp.dhis.useraccount.action.IsInviteTokenValidAction"
+ scope="prototype" />
+
<bean id="org.hisp.dhis.useraccount.action.IsAccountRecoveryAllowedAction"
class="org.hisp.dhis.useraccount.action.IsAccountRecoveryAllowedAction"
scope="prototype" />
=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/resources/dhis-web-commons.xml'
--- dhis-2/dhis-web/dhis-web-commons/src/main/resources/dhis-web-commons.xml 2014-01-08 17:41:22 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/resources/dhis-web-commons.xml 2014-01-23 15:04:07 +0000
@@ -146,10 +146,15 @@
</action>
<action name="restore" class="org.hisp.dhis.useraccount.action.IsRestoreTokenValidAction">
- <result name="success" type="velocity">/dhis-web-commons/useraccount/restore.vm</result>
- <result name="error" type="redirect">login.action</result>
- </action>
-
+ <result name="success" type="velocity">/dhis-web-commons/useraccount/restore.vm</result>
+ <result name="error" type="redirect">login.action</result>
+ </action>
+
+ <action name="invite" class="org.hisp.dhis.useraccount.action.IsInviteTokenValidAction">
+ <result name="success" type="velocity">/dhis-web-commons/useraccount/account.vm</result>
+ <result name="error" type="redirect">login.action</result>
+ </action>
+
</package>
<!-- Organisation Unit Selection Tree -->
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/SetAccessSettingsAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/SetAccessSettingsAction.java 2013-12-19 13:25:04 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/SetAccessSettingsAction.java 2014-01-23 15:04:07 +0000
@@ -91,6 +91,13 @@
this.accountRecovery = accountRecovery;
}
+ private Boolean accountInvite;
+
+ public void setAccountInvite( Boolean accountInvite )
+ {
+ this.accountInvite = accountInvite;
+ }
+
private Integer credentialsExpires;
public void setCredentialsExpires( Integer credentialsExpires )
@@ -141,6 +148,7 @@
configurationService.setConfiguration( config );
systemSettingManager.saveSystemSetting( KEY_ACCOUNT_RECOVERY, accountRecovery );
+ systemSettingManager.saveSystemSetting( KEY_ACCOUNT_INVITE, accountInvite );
systemSettingManager.saveSystemSetting( KEY_SELF_REGISTRATION_NO_RECAPTCHA, selfRegistrationNoRecaptcha );
if ( credentialsExpires != null )
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/org/hisp/dhis/settings/i18n_module.properties'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/org/hisp/dhis/settings/i18n_module.properties 2013-12-30 13:02:41 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/org/hisp/dhis/settings/i18n_module.properties 2014-01-23 15:04:07 +0000
@@ -56,6 +56,7 @@
self_registration_account_organisation_unit=Self registration account organisation unit
access=Access
enable_user_account_recovery=Enable user account recovery
+enable_user_account_invite=Enable user account invite
select_organisation_unit=Select organisation unit
application_notification=Application notification
multi_organisation_unit_forms=Enable multi-organisation unit forms
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemAccessSettings.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemAccessSettings.vm 2013-12-30 13:02:41 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemAccessSettings.vm 2014-01-23 15:04:07 +0000
@@ -6,6 +6,7 @@
selfRegistrationOrgUnit: jQuery( "#selfRegistrationOrgUnit" ).val(),
selfRegistrationNoRecaptcha: jQuery( '#selfRegistrationNoRecaptcha' ).is( ':checked' ),
accountRecovery: jQuery( '#accountRecovery' ).is( ':checked' ),
+ accountInvite: jQuery( '#accountInvite' ).is( ':checked' ),
credentialsExpires: jQuery( '#credentialsExpires' ).val()
}, function( json ) {
if ( json.response == "success" ) {
@@ -50,8 +51,13 @@
</div>
<div class="setting">
- <input type="checkbox" id="accountRecovery" name="accountRecovery"#if( $keyAccountRecovery ) checked="checked"#end>
- <label for="accountRecovery">$i18n.getString( "enable_user_account_recovery" )</label>
+ <input type="checkbox" id="accountRecovery" name="accountRecovery"#if( $keyAccountRecovery ) checked="checked"#end>
+ <label for="accountRecovery">$i18n.getString( "enable_user_account_recovery" )</label>
+</div>
+
+<div class="setting">
+ <input type="checkbox" id="accountInvite" name="accountInvite"#if( $keyAccountInvite ) checked="checked"#end>
+ <label for="accountInvite">$i18n.getString( "enable_user_account_invite" )</label>
</div>
<div class="settingLabel">$i18n.getString( "user_credentials_expires" )</div>
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/pom.xml'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/pom.xml 2014-01-09 21:56:49 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/pom.xml 2014-01-17 03:48:57 +0000
@@ -18,6 +18,11 @@
<dependencies>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ </dependency>
+
<!-- DHIS -->
<dependency>
@@ -51,7 +56,7 @@
</dependencies>
- <properties>
- <rootDir>../../../</rootDir>
- </properties>
+ <properties>
+ <rootDir>../../../</rootDir>
+ </properties>
</project>
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/AddUserAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/AddUserAction.java 2013-09-16 17:07:25 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/AddUserAction.java 2014-01-25 18:46:36 +0000
@@ -33,11 +33,17 @@
import java.util.HashSet;
import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.struts2.ServletActionContext;
+import org.hisp.dhis.api.utils.ContextUtils;
import org.hisp.dhis.attribute.AttributeService;
import org.hisp.dhis.organisationunit.OrganisationUnit;
import org.hisp.dhis.oust.manager.SelectionTreeManager;
import org.hisp.dhis.ouwt.manager.OrganisationUnitSelectionManager;
import org.hisp.dhis.security.PasswordManager;
+import org.hisp.dhis.security.RestoreType;
+import org.hisp.dhis.security.SecurityService;
import org.hisp.dhis.system.util.AttributeUtils;
import org.hisp.dhis.system.util.LocaleUtils;
import org.hisp.dhis.user.CurrentUserService;
@@ -54,8 +60,10 @@
* @author Torgeir Lorange Ostby
*/
public class AddUserAction
- implements Action
+ implements Action
{
+ private String ACCOUNT_ACTION_INVITE = "invite";
+
// -------------------------------------------------------------------------
// Dependencies
// -------------------------------------------------------------------------
@@ -81,6 +89,13 @@
this.userService = userService;
}
+ private SecurityService securityService;
+
+ public void setSecurityService( SecurityService securityService )
+ {
+ this.securityService = securityService;
+ }
+
private PasswordManager passwordManager;
public void setPasswordManager( PasswordManager passwordManager )
@@ -106,6 +121,13 @@
// Input & Output
// -------------------------------------------------------------------------
+ private String accountAction;
+
+ public void setAccountAction( String accountAction )
+ {
+ this.accountAction = accountAction;
+ }
+
private String username;
public void setUsername( String username )
@@ -141,6 +163,13 @@
this.email = email;
}
+ private String inviteEmail;
+
+ public void setInviteEmail( String inviteEmail )
+ {
+ this.inviteEmail = inviteEmail;
+ }
+
private String phoneNumber;
public void setPhoneNumber( String phoneNumber )
@@ -161,7 +190,7 @@
}
private String localeUi;
-
+
public void setLocaleUi( String localeUi )
{
this.localeUi = localeUi;
@@ -187,16 +216,16 @@
{
this.jsonAttributeValues = jsonAttributeValues;
}
-
+
// -------------------------------------------------------------------------
// Action implementation
// -------------------------------------------------------------------------
public String execute()
- throws Exception
+ throws Exception
{
UserCredentials currentUserCredentials = currentUserService.getCurrentUser() != null ? currentUserService
- .getCurrentUser().getUserCredentials() : null;
+ .getCurrentUser().getUserCredentials() : null;
// ---------------------------------------------------------------------
// Prepare values
@@ -208,6 +237,7 @@
}
username = username.trim();
+ inviteEmail = inviteEmail.trim();
// ---------------------------------------------------------------------
// Create userCredentials and user
@@ -215,18 +245,31 @@
Collection<OrganisationUnit> orgUnits = selectionTreeManager.getReloadedSelectedOrganisationUnits();
+ UserCredentials userCredentials = new UserCredentials();
User user = new User();
- user.setSurname( surname );
- user.setFirstName( firstName );
- user.setEmail( email );
- user.setPhoneNumber( phoneNumber );
+
+ userCredentials.setUser( user );
+ user.setUserCredentials( userCredentials );
+
+ if ( ACCOUNT_ACTION_INVITE.equals( accountAction ) )
+ {
+ user.setEmail( inviteEmail );
+
+ securityService.prepareUserForInvite ( userCredentials );
+ }
+ else
+ {
+ user.setSurname( surname );
+ user.setFirstName( firstName );
+ user.setEmail( email );
+ user.setPhoneNumber( phoneNumber );
+
+ userCredentials.setUsername( username );
+ userCredentials.setPassword( passwordManager.encodePassword( username, rawPassword ) );
+ }
+
user.updateOrganisationUnits( new HashSet<OrganisationUnit>( orgUnits ) );
- UserCredentials userCredentials = new UserCredentials();
- userCredentials.setUser( user );
- userCredentials.setUsername( username );
- userCredentials.setPassword( passwordManager.encodePassword( username, rawPassword ) );
-
for ( String id : selectedList )
{
UserAuthorityGroup group = userService.getUserAuthorityGroup( Integer.parseInt( id ) );
@@ -237,12 +280,10 @@
}
}
- user.setUserCredentials( userCredentials );
-
if ( jsonAttributeValues != null )
{
AttributeUtils.updateAttributeValuesFromJson( user.getAttributeValues(), jsonAttributeValues,
- attributeService );
+ attributeService );
}
userService.addUser( user );
@@ -252,10 +293,22 @@
{
selectionManager.setSelectedOrganisationUnits( orgUnits );
}
-
+
userService.addUserSetting( new UserSetting( user, UserSettingService.KEY_UI_LOCALE, LocaleUtils.getLocale( localeUi ) ) );
userService.addUserSetting( new UserSetting( user, UserSettingService.KEY_DB_LOCALE, LocaleUtils.getLocale( localeDb ) ) );
-
+
+ if ( ACCOUNT_ACTION_INVITE.equals( accountAction ) )
+ {
+ securityService.sendRestoreMessage( userCredentials, getRootPath(), RestoreType.INVITE );
+ }
+
return SUCCESS;
}
+
+ private String getRootPath()
+ {
+ HttpServletRequest request = ServletActionContext.getRequest();
+
+ return ContextUtils.getContextPath( request );
+ }
}
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/META-INF/dhis/beans.xml 2013-10-13 16:19:17 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/META-INF/dhis/beans.xml 2014-01-17 03:48:57 +0000
@@ -8,6 +8,7 @@
<bean id="org.hisp.dhis.user.action.AddUserAction" class="org.hisp.dhis.user.action.AddUserAction" scope="prototype">
<property name="userService" ref="org.hisp.dhis.user.UserService" />
+ <property name="securityService" ref="org.hisp.dhis.security.SecurityService" />
<property name="passwordManager" ref="org.hisp.dhis.security.PasswordManager" />
<property name="selectionTreeManager" ref="org.hisp.dhis.oust.manager.SelectionTreeManager" />
<property name="selectionManager" ref="org.hisp.dhis.ouwt.manager.OrganisationUnitSelectionManager" />
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/org/hisp/dhis/user/i18n_module.properties'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/org/hisp/dhis/user/i18n_module.properties 2014-01-22 09:14:39 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/org/hisp/dhis/user/i18n_module.properties 2014-01-23 15:03:16 +0000
@@ -252,6 +252,9 @@
#-- User module ---------------------------------------------------------------#
user_management=User management
+action=Action
+create_account_with_user_details=Create account with user details
+email_invitation_to_create_account=Email invitation to create account
username=Username
fullname=Fullname
role=Role
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/struts.xml'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/struts.xml 2014-01-22 09:14:39 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/struts.xml 2014-01-23 15:04:07 +0000
@@ -55,6 +55,7 @@
<action name="addUser" class="org.hisp.dhis.user.action.AddUserAction">
<result name="success" type="redirect">user.action?currentPage=${keyCurrentPage}&key=${keyCurrentKey}</result>
<result name="error" type="redirect">showAddUserForm.action</result>
+ <param name="javascripts">javascript/user.js</param>
<param name="requiredAuthorities">F_USER_ADD</param>
</action>
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/addUserForm.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/addUserForm.vm 2014-01-13 16:34:27 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/addUserForm.vm 2014-01-23 15:04:07 +0000
@@ -1,5 +1,6 @@
<script type="text/javascript">
- jQuery(function() {
+ jQuery(function()
+ {
validation2( 'addUserForm', function( form )
{
jQuery( "#selectedList" ).children().attr( "selected", true );
@@ -46,41 +47,58 @@
<table>
<col style="width: 120px"/>
+ #if ( $keyAccountInvite )
+ <tr>
+ <td><label>$i18n.getString( "action" )</label></td>
+ <td>
+ <select id="accountAction" name="accountAction" onchange="changeAccountAction()">
+ <option value="create" selected="selected">$i18n.getString( "create_account_with_user_details" )</option>
+ <option value="invite">$i18n.getString( "email_invitation_to_create_account" )</option>
+ </select>
+ </td>
+ </tr>
+ #end
+
<tr>
<th colspan="4">$i18n.getString( "details" )</th>
</tr>
- <tr>
+ <tr id="usernameTR">
<td><label for="username">$i18n.getString( "username" ) <em title="$i18n.getString( 'required' )" class="required">*</em></label></td>
<td colspan="3"><input type="text" id="username" name="username" autocomplete="off"></td>
</tr>
- <tr>
+ <tr id="rawPasswordTR">
<td><label for="rawPassword">$i18n.getString( "password" ) <em title="$i18n.getString( 'required' )" class="required">*</em></label></td>
<td colspan="3"><input type="password" id="rawPassword" name="rawPassword" autocomplete="off"></td>
</tr>
- <tr>
+ <tr id="retypePasswordTR">
<td><label for="retypePassword">$i18n.getString( "retype_password" ) <em title="$i18n.getString( 'required' )" class="required">*</em></label></td>
<td colspan="3"><input type="password" id="retypePassword" name="retypePassword" autocomplete="off"></td>
</tr>
- <tr>
+ <tr id="surnameTR">
<td><label for="surname">$i18n.getString( "surname" ) <em title="$i18n.getString( 'required' )" class="required">*</em></label></td>
<td colspan="3"><input type="text" id="surname" name="surname"></td>
</tr>
- <tr>
+ <tr id="firstNameTR">
<td><label for="firstName">$i18n.getString( "firstName" ) <em title="$i18n.getString( 'required' )" class="required">*</em></label></td>
<td colspan="3"><input type="text" id="firstName" name="firstName"></td>
</tr>
- <tr>
+ <tr id="emailTR">
<td><label for="email">$i18n.getString( "email" )</label></td>
- <td colspan="3"><input type="text" id="email" name="email" ></td>
- </tr>
-
- <tr>
+ <td colspan="3"><input type="text" id="email" name="email" ></td>
+ </tr>
+
+ <tr id="inviteEmailTR" style="display:none">
+ <td><label for="inviteEmail">$i18n.getString( "email" ) <em title="$i18n.getString( 'required' )" class="required">*</em></label></td>
+ <td colspan="3"><input type="text" id="inviteEmail" name="inviteEmail" value="validEmail@xxxxxxxxxx" ></td>
+ </tr>
+
+ <tr id="phoneNumberTR">
<td><label for="phoneNumber">$i18n.getString( "phone_number" )</label></td>
<td colspan="3"><input type="text" id="phoneNumber" name="phoneNumber"></td>
</tr>
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/javascript/user.js'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/javascript/user.js 2013-12-04 14:39:36 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/javascript/user.js 2014-01-23 15:04:07 +0000
@@ -76,6 +76,65 @@
}
// -----------------------------------------------------------------------------
+// Add user
+// -----------------------------------------------------------------------------
+
+var saved = {};
+
+function changeAccountAction()
+{
+ if( $('#accountAction').val() == 'create' )
+ {
+ $('#username').val( saved["username"] );
+ $('#rawPassword').val( saved["rawPassword"] );
+ $('#retypePassword').val( saved["retypePassword"] );
+ $('#surname').val( saved["surname"] );
+ $('#firstName').val( saved["firstName"] );
+ $('#phoneNumber').val( saved["phoneNumber"] );
+ $('#email').val( $('#inviteEmail').val() );
+ $('#inviteEmail').val( 'validEmail@xxxxxxxxxx' );
+
+ showById('usernameTR');
+ showById('rawPasswordTR');
+ showById('retypePasswordTR');
+ showById('surnameTR');
+ showById('firstNameTR');
+ showById('phoneNumberTR');
+ showById('emailTR');
+
+ hideById('inviteEmailTR');
+ }
+ else
+ {
+ hideById('usernameTR');
+ hideById('rawPasswordTR');
+ hideById('retypePasswordTR');
+ hideById('surnameTR');
+ hideById('firstNameTR');
+ hideById('phoneNumberTR');
+ hideById('emailTR');
+
+ showById('inviteEmailTR');
+
+ saved["username"] = $('#username').val();
+ saved["rawPassword"] = $('#rawPassword').val();
+ saved["retypePassword"] = $('#retypePassword').val();
+ saved["surname"] = $('#surname').val();
+ saved["firstName"] = $('#firstName').val();
+ saved["phoneNumber"] = $('#phoneNumber').val();
+
+ $('#username').val( 'nonExistingUserName_RpuECtIlVoRKTpYmEkYrAHmPtX4m1U' );
+ $('#rawPassword').val( 'validPassword_123' );
+ $('#retypePassword').val( 'validPassword_123' );
+ $('#surname').val( 'validSurname' );
+ $('#firstName').val( 'validFirstName' );
+ $('#phoneNumber').val( '5555555555' );
+ $('#inviteEmail').val( $('#email').val() );
+ $('#email').val( '' );
+ }
+}
+
+// -----------------------------------------------------------------------------
// Remove user
// -----------------------------------------------------------------------------
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/updateUserForm.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/updateUserForm.vm 2013-10-08 17:16:47 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/updateUserForm.vm 2014-01-17 03:48:57 +0000
@@ -2,8 +2,9 @@
jQuery(function() {
var rules = getValidationRules( "user" );
rules["rawPassword"].required = false;
- rules["retypePassword"].required = false;
-
+ rules["retypePassword"].required = false;
+ rules["inviteEmail"].required = false;
+
validation2( 'updateUserForm', function( form )
{
jQuery( "#selectedList" ).children().attr( "selected", true );