← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 18621: Implemented feature for resending user account invitation emails.

 

------------------------------------------------------------
revno: 18621
committer: Lars Helge Overland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Wed 2015-03-18 19:51:30 +0100
message:
  Implemented feature for resending user account invitation emails.
modified:
  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/test/java/org/hisp/dhis/security/SecurityServiceTest.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java
  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/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/javascript/user.js


--
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-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-<email>-<uid>.
+     * 
+     * @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@xxxxxxxxx-OsTci1JyHRU" ) );
+        assertTrue( securityService.isInviteUsername( "invite-fr37@xxxxxxx-OsTci1JyHRU" ) );
+        assertTrue( securityService.isInviteUsername( null ) );
+        assertFalse( securityService.isInviteUsername( "inv1te-mark@xxxxxxxxx-OsTci1JyHRU" ) );
+        assertFalse( securityService.isInviteUsername( "invite-tomjohnson@xxxxxxxxx-OsTci1JyHRUC" ) );
+        assertFalse( securityService.isInviteUsername( "invite-johnthomson@xxxxxxxxx-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';
 </script>
 
@@ -23,6 +24,7 @@
     <li data-enabled="canUpdate"><a data-target-fn="showUpdateUserForm"><i class="fa fa-edit"></i>&nbsp;&nbsp;$i18n.getString( "edit" )</a></li>
     <li data-enabled="canDelete"><a data-target-fn="removeUser"><i class="fa fa-trash-o"></i>&nbsp;&nbsp;$i18n.getString( "remove" )</a></li>
     <li data-enabled="canReplicate"><a data-target-fn="showReplicateUserDialog"><i class="fa fa-copy"></i>&nbsp;&nbsp;$i18n.getString( "replicate" )</a></li>
+    <li data-enabled="canReinvite"><a data-target-fn="resendInvitation"><i class="fa fa-repeat"></i>&nbsp;&nbsp;$i18n.getString( "resend_invitation" )</a></li>
     <li><a data-target-fn="showUserDetails"><i class="fa fa-info-circle"></i>&nbsp;&nbsp;$i18n.getString( "show_details" )</a></li>
     <li data-enabled="userEnabled"><a data-target-fn="disableUser"><i class="fa fa-ban"></i>&nbsp;&nbsp;$i18n.getString( "disable")</a></li>
     <li data-enabled="userDisabled"><a data-target-fn="enableUser"><i class="fa fa-ban"></i>&nbsp;&nbsp;$i18n.getString( "enable" )</a></li>
@@ -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 );
+		}
+	} );
+}