=== 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 2015-02-22 20:02:00 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/DefaultSecurityService.java 2015-03-18 18:51:30 +0000 @@ -28,6 +28,15 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hisp.dhis.acl.AclService; @@ -51,14 +60,6 @@ import org.joda.time.DateTime; import org.springframework.beans.factory.annotation.Autowired; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - /** * @author Lars Helge Overland */ @@ -68,6 +69,7 @@ private static final Log log = LogFactory.getLog( DefaultSecurityService.class ); private static final String RESTORE_PATH = "/dhis-web-commons/security/"; + private static final Pattern INVITE_USERNAME_PATTERN = Pattern.compile( "^invite\\-(.+?)\\-(\\w{11})$" ); private static final String DEFAULT_APPLICATION_TITLE = "DHIS 2"; @@ -152,7 +154,7 @@ return true; } - + @Override public String validateRestore( UserCredentials credentials ) { @@ -462,6 +464,17 @@ } @Override + public boolean isInviteUsername( String username ) + { + if ( username == null || username.isEmpty() ) + { + return true; + } + + return INVITE_USERNAME_PATTERN.matcher( username ).matches(); + } + + @Override public boolean canCreatePublic( IdentifiableObject identifiableObject ) { return !aclService.isShareable( identifiableObject.getClass() ) === 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 2015-02-13 12:51:17 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/SecurityService.java 2015-03-18 18:51:30 +0000 @@ -157,6 +157,16 @@ String verifyToken( UserCredentials credentials, String token, RestoreType restoreType ); /** + * Indicates whether the given username is an invite. The username is + * considered an invite if it is null or matches the invite username pattern + * of invite--. + * + * @param username the username. + * @return true if the username represents an account invitation. + */ + boolean isInviteUsername( String username ); + + /** * Checks whether current user has read access to object. * * @param identifiableObject Object to check for read access. === 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 2015-01-17 07:41:26 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/security/SecurityServiceTest.java 2015-03-18 18:51:30 +0000 @@ -231,4 +231,15 @@ assertEquals( RestoreType.INVITE, restoreOptions.getRestoreType() ); assertEquals( true, restoreOptions.isUsernameChoice() ); } + + @Test + public void testIsInviteUsername() + { + assertTrue( securityService.isInviteUsername( "invite-johndoe@gmail.com-OsTci1JyHRU" ) ); + assertTrue( securityService.isInviteUsername( "invite-fr37@abc.gov-OsTci1JyHRU" ) ); + assertTrue( securityService.isInviteUsername( null ) ); + assertFalse( securityService.isInviteUsername( "inv1te-mark@gmail.com-OsTci1JyHRU" ) ); + assertFalse( securityService.isInviteUsername( "invite-tomjohnson@yahoo.com-OsTci1JyHRUC" ) ); + assertFalse( securityService.isInviteUsername( "invite-johnthomson@gmail.com-OsTci1yHRU" ) ); + } } === modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java' --- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java 2015-02-25 06:51:55 +0000 +++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java 2015-03-18 18:51:30 +0000 @@ -243,6 +243,39 @@ } } + @RequestMapping( value = "/{id}" + INVITE_PATH, method = RequestMethod.POST ) + public void resendInvite( @PathVariable String id, HttpServletRequest request, HttpServletResponse response ) throws Exception + { + User user = userService.getUser( id ); + + if ( user == null ) + { + ContextUtils.conflictResponse( response, "User not found: " + id ); + return; + } + + if ( user.getUserCredentials() == null || !user.getUserCredentials().isInvitation() ) + { + ContextUtils.conflictResponse( response, "User account is not an invitation: " + id ); + return; + } + + String valid = securityService.validateRestore( user.getUserCredentials() ); + + if ( valid != null ) + { + ContextUtils.conflictResponse( response, valid ); + return; + } + + boolean isInviteUsername = securityService.isInviteUsername( user.getUsername() ); + + RestoreOptions restoreOptions = isInviteUsername ? RestoreOptions.INVITE_WITH_USERNAME_CHOICE : RestoreOptions.INVITE_WITH_DEFINED_USERNAME; + + securityService.sendRestoreMessage( user.getUserCredentials(), + ContextUtils.getContextPath( request ), restoreOptions ); + } + @RequestMapping( value = BULK_INVITE_PATH, method = RequestMethod.POST, consumes = "application/json" ) public void postJsonInvites( HttpServletRequest request, HttpServletResponse response ) throws Exception { === 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 2015-02-01 23:02:22 +0000 +++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/org/hisp/dhis/user/i18n_module.properties 2015-03-18 18:51:30 +0000 @@ -376,4 +376,6 @@ expired_invitations = Expired invitations show_self_registrations = Show self-registrations self_registered_users = Self-registered users -replicate=Replicate \ No newline at end of file +replicate=Replicate +resend_invitation=Resend invitation +invitation_sent=Invitation sent \ No newline at end of file === modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/allUser.vm' --- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/allUser.vm 2015-01-12 18:53:15 +0000 +++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/allUser.vm 2015-03-18 18:51:30 +0000 @@ -10,6 +10,7 @@ var i18n_username = '$encoder.jsEscape( $i18n.getString( "username" ) , "'")'; var i18n_name = '$encoder.jsEscape( $i18n.getString( "name" ) , "'")'; var i18n_operations = '$encoder.jsEscape( $i18n.getString( "operations" ) , "'")'; + var i18n_invitation_sent = '$encoder.jsEscape( $i18n.getString( "invitation_sent" ) , "'")'; var currentUserName = '$currentUsername'; @@ -23,6 +24,7 @@
  •   $i18n.getString( "edit" )
  •   $i18n.getString( "remove" )
  •   $i18n.getString( "replicate" )
  • +
  •   $i18n.getString( "resend_invitation" )
  •   $i18n.getString( "show_details" )
  •   $i18n.getString( "disable")
  •   $i18n.getString( "enable" )
  • @@ -77,6 +79,7 @@ data-can-manage="$security.canManage( $user.userCredentials )" data-can-update="$security.canUpdate( $user.userCredentials )" data-can-delete="$security.canDelete( $user.userCredentials )" + data-can-reinvite="#if( $user.userCredentials.isInvitation() && $security.canUpdate( $user.userCredentials ) )true#{else}false#end" data-can-replicate="$hasAllAuth" data-user-enabled="#if( !$user.userCredentials.disabled )true#{else}false#end" data-user-disabled="$user.userCredentials.disabled"> === 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 2015-01-12 18:53:15 +0000 +++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/javascript/user.js 2015-03-18 18:51:30 +0000 @@ -239,3 +239,18 @@ function cancelReplicateUser() { $( "#replicateUserForm" ).dialog( "destroy" ); } + +function resendInvitation( context ) { + var userId = context.uid; + + $.ajax( { + url: "../api/users/" + userId + "/invite", + type: "post", + success: function() { + setHeaderDelayMessage( i18n_invitation_sent ); + }, + error: function( xhr, status, error ) { + setHeaderDelayMessage( xhr.responseText ); + } + } ); +}