← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 15421: Add to webapi: POST /users/invite

 

Merge authors:
  Jim Grace (jimgrace)
------------------------------------------------------------
revno: 15421 [merge]
committer: jimgrace@xxxxxxxxx
branch nick: dhis2
timestamp: Mon 2014-05-26 15:10:33 -0400
message:
  Add to webapi: POST /users/invite
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-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/java/org/hisp/dhis/user/action/AddUserAction.java


--
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	2014-03-27 08:25:39 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/DefaultSecurityService.java	2014-05-24 18:16:41 +0000
@@ -110,25 +110,25 @@
     // SecurityService implementation
     // -------------------------------------------------------------------------
 
-    public boolean prepareUserForInvite( UserCredentials credentials )
+    public boolean prepareUserForInvite( User user )
     {
-        if ( credentials == null || credentials.getUser() == null )
+        if ( user == null || user.getUserCredentials() == null )
         {
             return false;
         }
 
-        if ( credentials.getUsername().isEmpty() )
+        if ( user.getUsername() == null || user.getUsername().isEmpty() )
         {
             String username = "user_invitation_" + CodeGenerator.generateCode( INVITED_USERNAME_UNIQUE_LENGTH );
 
-            credentials.setUsername( username );
+            user.getUserCredentials().setUsername( username );
         }
 
         String rawPassword = CodeGenerator.generateCode( INVITED_USER_PASSWORD_LENGTH );
 
-        credentials.getUser().setSurname( "(TBD)" );
-        credentials.getUser().setFirstName( "(TBD)" );
-        credentials.setPassword( passwordManager.encodePassword( credentials.getUsername(), rawPassword ) );
+        user.setSurname( "(TBD)" );
+        user.setFirstName( "(TBD)" );
+        user.getUserCredentials().setPassword( passwordManager.encodePassword( user.getUsername(), rawPassword ) );
 
         return true;
     }

=== 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-03-18 08:10:10 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/SecurityService.java	2014-05-24 18:16:41 +0000
@@ -29,6 +29,7 @@
  */
 
 import org.hisp.dhis.common.IdentifiableObject;
+import org.hisp.dhis.user.User;
 import org.hisp.dhis.user.UserCredentials;
 
 /**
@@ -40,10 +41,10 @@
      * 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.
+     * @param user the user to invite.
      * @return true if the invitation was sent, otherwise false.
      */
-    boolean prepareUserForInvite( UserCredentials credentials );
+    boolean prepareUserForInvite( User user );
 
     /**
      * Invokes the initRestore method and dispatches email messages with

=== 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	2014-05-22 12:40:24 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java	2014-05-26 19:10:33 +0000
@@ -29,6 +29,7 @@
  */
 
 import com.google.common.collect.Lists;
+import org.apache.struts2.ServletActionContext;
 import org.hisp.dhis.webapi.controller.AbstractCrudController;
 import org.hisp.dhis.webapi.controller.WebMetaData;
 import org.hisp.dhis.webapi.controller.WebOptions;
@@ -39,7 +40,12 @@
 import org.hisp.dhis.hibernate.exception.UpdateAccessDeniedException;
 import org.hisp.dhis.importexport.ImportStrategy;
 import org.hisp.dhis.security.PasswordManager;
+import org.hisp.dhis.security.RestoreOptions;
+import org.hisp.dhis.security.SecurityService;
+import org.hisp.dhis.setting.SystemSettingManager;
 import org.hisp.dhis.user.User;
+import org.hisp.dhis.user.UserGroup;
+import org.hisp.dhis.user.UserGroupService;
 import org.hisp.dhis.user.UserService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
@@ -59,6 +65,8 @@
 import java.util.List;
 import java.util.Map;
 
+import static org.hisp.dhis.setting.SystemSettingManager.KEY_ONLY_MANAGE_WITHIN_USER_GROUPS;
+
 /**
  * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
  */
@@ -68,13 +76,23 @@
     extends AbstractCrudController<User>
 {
     public static final String RESOURCE_PATH = "/users";
+    public static final String INVITE_PATH = "/invite";
 
     @Autowired
     private UserService userService;
 
     @Autowired
+    private UserGroupService userGroupService;
+
+    @Autowired
     private PasswordManager passwordManager;
 
+    @Autowired
+    private SecurityService securityService;
+
+    @Autowired
+    private SystemSettingManager systemSettingManager;
+
     @Override
     @PreAuthorize( "hasRole('ALL') or hasRole('F_USER_VIEW')" )
     public String getObjectList( @RequestParam Map<String, String> parameters, Model model, HttpServletResponse response, HttpServletRequest request )
@@ -130,38 +148,34 @@
     @RequestMapping( method = RequestMethod.POST, consumes = { "application/xml", "text/xml" } )
     public void postXmlObject( HttpServletResponse response, HttpServletRequest request, InputStream input ) throws Exception
     {
-        if ( !aclService.canCreate( currentUserService.getCurrentUser(), getEntityClass() ) )
-        {
-            throw new CreateAccessDeniedException( "You don't have the proper permissions to create this object." );
-        }
-
         User user = renderService.fromXml( request.getInputStream(), getEntityClass() );
 
-        String encodePassword = passwordManager.encodePassword( user.getUsername(),
-            user.getUserCredentials().getPassword() );
-        user.getUserCredentials().setPassword( encodePassword );
-
-        ImportTypeSummary summary = importService.importObject( currentUserService.getCurrentUser().getUid(), user, ImportStrategy.CREATE );
-        renderService.toJson( response.getOutputStream(), summary );
+        createUser( user, response );
     }
 
     @Override
     @RequestMapping( method = RequestMethod.POST, consumes = "application/json" )
     public void postJsonObject( HttpServletResponse response, HttpServletRequest request, InputStream input ) throws Exception
     {
-        if ( !aclService.canCreate( currentUserService.getCurrentUser(), getEntityClass() ) )
-        {
-            throw new CreateAccessDeniedException( "You don't have the proper permissions to create this object." );
-        }
-
-        User user = renderService.fromJson( request.getInputStream(), getEntityClass() );
-
-        String encodePassword = passwordManager.encodePassword( user.getUsername(),
-            user.getUserCredentials().getPassword() );
-        user.getUserCredentials().setPassword( encodePassword );
-
-        ImportTypeSummary summary = importService.importObject( currentUserService.getCurrentUser().getUid(), user, ImportStrategy.CREATE );
-        renderService.toJson( response.getOutputStream(), summary );
+        User user = renderService.fromJson( request.getInputStream(), getEntityClass() );
+
+        createUser( user, response );
+    }
+
+    @RequestMapping( value = INVITE_PATH, method = RequestMethod.POST, consumes = { "application/xml", "text/xml" } )
+    public void postXmlInvite( HttpServletResponse response, HttpServletRequest request, InputStream input ) throws Exception
+    {
+        User user = renderService.fromXml( request.getInputStream(), getEntityClass() );
+
+        inviteUser( user, response );
+    }
+
+    @RequestMapping( value = INVITE_PATH, method = RequestMethod.POST, consumes = "application/json" )
+    public void postJsonInvite( HttpServletResponse response, HttpServletRequest request, InputStream input ) throws Exception
+    {
+        User user = renderService.fromJson( request.getInputStream(), getEntityClass() );
+
+        inviteUser( user, response );
     }
 
     //--------------------------------------------------------------------------
@@ -230,4 +244,128 @@
         ImportTypeSummary summary = importService.importObject( currentUserService.getCurrentUser().getUid(), parsed, ImportStrategy.UPDATE );
         renderService.toJson( response.getOutputStream(), summary );
     }
+
+    //--------------------------------------------------------------------------
+    // Supportive methods
+    //--------------------------------------------------------------------------
+
+    /**
+     * Creates a user invitation and invites the user
+     *
+     * @param user user object parsed from the POST request
+     * @param response response for created user invitation
+     * @throws Exception
+     */
+    private void inviteUser( User user, HttpServletResponse response ) throws Exception
+    {
+        RestoreOptions restoreOptions = user.getUsername() == null || user.getUsername().isEmpty() ?
+            RestoreOptions.INVITE_WITH_USERNAME_CHOICE : RestoreOptions.INVITE_WITH_DEFINED_USERNAME;
+
+        securityService.prepareUserForInvite( user );
+
+        createUser( user, response );
+
+        securityService.sendRestoreMessage( user.getUserCredentials(),
+            ContextUtils.getContextPath( ServletActionContext.getRequest() ), restoreOptions );
+    }
+
+    /**
+     * Creates a user
+     *
+     * @param user user object parsed from the POST request
+     * @param response response for created user
+     * @throws Exception
+     */
+    private void createUser( User user, HttpServletResponse response ) throws Exception
+    {
+        if ( currentUserService.getCurrentUser() == null )
+        {
+            throw new CreateAccessDeniedException( "Internal error: currentUserService.getCurrentUser() returns null." );
+        }
+
+        if ( !aclService.canCreate( currentUserService.getCurrentUser(), getEntityClass() ) )
+        {
+            throw new CreateAccessDeniedException( "You don't have the proper permissions to create this object." );
+        }
+
+        checkUserGroups( user );
+
+        user.getUserCredentials().getCogsDimensionConstraints().addAll(
+            currentUserService.getCurrentUser().getUserCredentials().getCogsDimensionConstraints() );
+
+        String encodePassword = passwordManager.encodePassword( user.getUsername(),
+            user.getUserCredentials().getPassword() );
+        user.getUserCredentials().setPassword( encodePassword );
+
+        ImportTypeSummary summary = importService.importObject( currentUserService.getCurrentUser().getUid(), user, ImportStrategy.CREATE );
+
+        renderService.toJson( response.getOutputStream(), summary );
+
+        addUserGroups( user );
+    }
+
+    /**
+     * Before adding the user, checks to see that any specified user groups
+     * exist. Also checks to see that user can be created by the current
+     * user, if it is required that the current user have read/write access
+     * to a user group that is assigned to the new user.
+     *
+     * @param user user object parsed from the POST request
+     */
+    private void checkUserGroups( User user )
+    {
+        boolean writeGroupRequired = (Boolean) systemSettingManager.getSystemSetting( KEY_ONLY_MANAGE_WITHIN_USER_GROUPS, false );
+
+        boolean writeGroupFound = false;
+
+        if ( currentUserService.getCurrentUser() != null && user.getGroups() != null )
+        {
+            for ( UserGroup ug : user.getGroups() )
+            {
+                UserGroup group = userGroupService.getUserGroup( ug.getUid() );
+
+                if ( group == null )
+                {
+                    throw new UpdateAccessDeniedException( "Can't add user: Can't find user group with UID = " + ug.getUid() );
+                }
+
+                if ( writeGroupRequired && securityService.canWrite( group ) )
+                {
+                    writeGroupFound = true;
+
+                    break;
+                }
+            }
+        }
+
+        if ( writeGroupRequired && !writeGroupFound )
+        {
+            throw new CreateAccessDeniedException( "The new user must be assigned to a user group to which you have write access." );
+        }
+    }
+
+    /**
+     * Adds user groups (if any) to the newly-created user
+     *
+     * @param user user object (including user groups) parsed from the POST request
+     */
+    private void addUserGroups( User user )
+    {
+        if ( user.getGroups() != null )
+        {
+            boolean writeGroupRequired = (Boolean) systemSettingManager.getSystemSetting( KEY_ONLY_MANAGE_WITHIN_USER_GROUPS, false );
+
+            for ( UserGroup ug : new ArrayList<UserGroup>( user.getGroups() ) )
+            {
+                UserGroup group = userGroupService.getUserGroup( ug.getUid() );
+
+                if ( group != null && ( !writeGroupRequired || securityService.canWrite( group ) ) )
+                {
+                    group.addUser( user );
+
+                    userGroupService.updateUserGroup( group );
+                }
+            }
+        }
+    }
 }

=== 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	2014-05-22 12:40:24 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/AddUserAction.java	2014-05-26 19:10:33 +0000
@@ -342,7 +342,7 @@
             userCredentials.setUsername( inviteUsername );
             user.setEmail( inviteEmail );
 
-            securityService.prepareUserForInvite( userCredentials );
+            securityService.prepareUserForInvite( user );
         }
         else
         {