← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 16382: DataApproval fix: if user can approve higher levels, don't allow lower levels without the approve...

 

------------------------------------------------------------
revno: 16382
committer: jimgrace@xxxxxxxxx
branch nick: dhis2
timestamp: Mon 2014-08-11 17:36:11 -0400
message:
  DataApproval fix: if user can approve higher levels, don't allow lower levels without the approveLowerLevels authority.
modified:
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalService.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/dataapproval/DefaultDataApprovalService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalService.java	2014-08-04 13:20:47 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalService.java	2014-08-11 21:36:11 +0000
@@ -118,7 +118,7 @@
     public void addDataApproval( DataApproval dataApproval )
     {
         if ( ( dataApproval.getCategoryOptionGroup() == null || securityService.canRead( dataApproval.getCategoryOptionGroup() ) )
-            && mayApprove( dataApproval.getOrganisationUnit() ) )
+            && mayApprove( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit() ) )
         {
             PeriodType selectionPeriodType = dataApproval.getPeriod().getPeriodType();
             PeriodType dataSetPeriodType = dataApproval.getDataSet().getPeriodType();
@@ -139,14 +139,18 @@
         }
         else
         {
-            warnNotPermitted( dataApproval, "approve", mayApprove( dataApproval.getOrganisationUnit() ) );
+            warnNotPermitted( dataApproval, "approve",
+                    mayApprove( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit() ) );
         }
     }
 
     public void deleteDataApproval( DataApproval dataApproval )
     {
+        boolean mayUnapprove = mayUnapprove( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit(), dataApproval.isAccepted() )
+                || mayAcceptOrUnaccept( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit() );
+
         if ( ( dataApproval.getCategoryOptionGroup() == null || securityService.canRead( dataApproval.getCategoryOptionGroup() ) )
-            && mayUnapprove( dataApproval ) )
+            && mayUnapprove )
         {
             PeriodType selectionPeriodType = dataApproval.getPeriod().getPeriodType();
             PeriodType dataSetPeriodType = dataApproval.getDataSet().getPeriodType();
@@ -178,7 +182,7 @@
         }
         else
         {
-            warnNotPermitted( dataApproval, "unapprove", mayUnapprove( dataApproval ) );
+            warnNotPermitted( dataApproval, "unapprove", mayUnapprove );
         }
     }
 
@@ -236,15 +240,17 @@
                 case ACCEPTED_HERE:
                 case PARTIALLY_APPROVED_HERE:
                 case APPROVED_HERE:
-                    permissions.setMayApprove( mayApprove( organisationUnit ) );
-                    permissions.setMayUnapprove( mayUnapprove( status.getDataApproval() ) );
-                    permissions.setMayAccept( mayAcceptOrUnaccept( status.getDataApproval() ) );
+                case UNAPPROVED_READY:
+                    permissions.setMayApprove( mayApprove( status.getDataApprovalLevel(), organisationUnit ) );
+                    permissions.setMayUnapprove( mayUnapprove( status.getDataApprovalLevel(), organisationUnit, status.getDataApprovalState().isAccepted() ) );
+                    permissions.setMayAccept( mayAcceptOrUnaccept( status.getDataApprovalLevel(), organisationUnit ) );
                     permissions.setMayUnaccept( permissions.isMayAccept() );
-                    break;
-
-                case UNAPPROVED_READY:
-                    permissions.setMayApprove( mayApprove( organisationUnit ) );
-                    permissions.setMayUnapprove( isAuthorizedToUnapprove( organisationUnit ) );
+
+                    if ( permissions.isMayUnaccept() )
+                    {
+                        permissions.setMayUnapprove( true );
+                    }
+
                     break;
             }
         }
@@ -282,7 +288,7 @@
     public void acceptOrUnaccept ( DataApproval dataApproval, boolean accepted )
     {
         if ( ( dataApproval.getCategoryOptionGroup() == null || securityService.canRead( dataApproval.getCategoryOptionGroup() ) )
-                && mayAcceptOrUnaccept( dataApproval ) )
+                && mayAcceptOrUnaccept( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit() ) )
         {
             PeriodType selectionPeriodType = dataApproval.getPeriod().getPeriodType();
             PeriodType dataSetPeriodType = dataApproval.getDataSet().getPeriodType();
@@ -301,7 +307,8 @@
             }
         } else
         {
-            warnNotPermitted( dataApproval, accepted ? "accept" : "unaccept", mayAcceptOrUnaccept( dataApproval ) );
+            warnNotPermitted( dataApproval, accepted ? "accept" : "unaccept",
+                    mayAcceptOrUnaccept( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit() ) );
         }
     }
 
@@ -443,27 +450,35 @@
      * Checks to see whether a user may approve data for a given
      * organisation unit.
      *
+     * @param dataApprovalLevel This data approval level.
      * @param organisationUnit The organisation unit to check for permission.
      * @return true if the user may approve, otherwise false
      */
-    private boolean mayApprove( OrganisationUnit organisationUnit )
+    private boolean mayApprove( DataApprovalLevel dataApprovalLevel, OrganisationUnit organisationUnit )
     {
         User user = currentUserService.getCurrentUser();
 
         if ( user != null )
         {
             boolean mayApprove = user.getUserCredentials().isAuthorized( DataApproval.AUTH_APPROVE );
+            boolean mayApproveAtLowerLevels = user.getUserCredentials().isAuthorized( DataApproval.AUTH_APPROVE_LOWER_LEVELS );
 
             if ( mayApprove && user.getOrganisationUnits().contains( organisationUnit ) )
             {
+                if ( !mayApproveAtLowerLevels && mayApproveAtNextHigherLevelOnly( dataApprovalLevel, organisationUnit ) )
+                {
+                    log.debug( "mayApprove = false because user may approve at the next higher level from approval level "
+                        + dataApprovalLevel.getLevel() + " with " + organisationUnit.getName() );
+
+                    return false;
+                }
+
                 log.debug( "mayApprove = true because organisation unit " + organisationUnit.getName()
                         + " is assigned to user and user may approve at same level." );
 
                 return true;
             }
 
-            boolean mayApproveAtLowerLevels = user.getUserCredentials().isAuthorized( DataApproval.AUTH_APPROVE_LOWER_LEVELS );
-
             if ( mayApproveAtLowerLevels && CollectionUtils.containsAny( user.getOrganisationUnits(),
                 organisationUnit.getAncestors() ) )
             {
@@ -480,6 +495,45 @@
     }
 
     /**
+     * Checks to see whether a user may approve data at the next higher
+     * approval level for this orgnaisation unit -- because they can
+     * approve only at that next higher level (and not at lower levels.)
+     * <p>
+     * It is assumed that the user has the authority to approve at their
+     * level -- and not the authority to approve at lower levels.
+     *
+     * @param dataApprovalLevel This data approval level.
+     * @param organisationUnit The organisation unit to check for permission.
+     * @return true if the user may approve at the next higher level.
+     */
+    private boolean mayApproveAtNextHigherLevelOnly( DataApprovalLevel dataApprovalLevel, OrganisationUnit organisationUnit )
+    {
+        if ( dataApprovalLevel.getLevel() > 1 )
+        {
+            DataApprovalLevel nextLevel = dataApprovalLevelService.getDataApprovalLevelByLevelNumber( dataApprovalLevel.getLevel() - 1 );
+
+            if ( securityService.canRead( nextLevel )
+                    && ( nextLevel.getCategoryOptionGroupSet() == null ||
+                    ( securityService.canRead( nextLevel.getCategoryOptionGroupSet() )
+                            && canReadSomeCategoryOptionGroup( nextLevel.getCategoryOptionGroupSet().getMembers() ) ) ) )
+            {
+                OrganisationUnit acceptOrgUnit = organisationUnit;
+                for ( int i = nextLevel.getOrgUnitLevel(); i < dataApprovalLevel.getOrgUnitLevel(); i++ )
+                {
+                    acceptOrgUnit = acceptOrgUnit.getParent();
+                }
+
+                if ( currentUserService.getCurrentUser().getOrganisationUnits().contains( acceptOrgUnit ) )
+                {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
      * Checks to see whether a user may unapprove a data approval.
      * <p>
      * A user may unapprove data for organisation unit A if they have the
@@ -497,11 +551,11 @@
      * @param dataApproval the data approval object for the attempted operation.
      * @return true if the user may unapprove, otherwise false
      */
-    private boolean mayUnapprove( DataApproval dataApproval )
+    private boolean mayUnapprove( DataApprovalLevel dataApprovalLevel, OrganisationUnit organisationUnit, boolean isAccepted )
     {
-        if ( isAuthorizedToUnapprove( dataApproval.getOrganisationUnit() ) )
+        if ( isAuthorizedToUnapprove( dataApprovalLevel, organisationUnit ) )
         {
-            if ( !dataApproval.isAccepted() || mayAcceptOrUnaccept( dataApproval ) )
+            if ( !isAccepted || mayAcceptOrUnaccept( dataApprovalLevel, organisationUnit ) )
             {
                 return true;
             }
@@ -512,47 +566,25 @@
 
     /**
      * Checks to see whether a user may accept or unaccept an approval.
+     * (For this, they will need access to the next higher approval level.)
      *
      * @param dataApproval The approval to check for permission.
      * @return true if the user may accept or unaccept, otherwise false.
      */
-    private boolean mayAcceptOrUnaccept ( DataApproval dataApproval )
+    private boolean mayAcceptOrUnaccept ( DataApprovalLevel dataApprovalLevel, OrganisationUnit organisationUnit )
     {
-        OrganisationUnit organisationUnit = null;
-
         User user = currentUserService.getCurrentUser();
 
-        if ( dataApproval != null && user != null )
+        if ( dataApprovalLevel != null && user != null )
         {
             boolean mayAcceptAtLowerLevels = user.getUserCredentials().isAuthorized( DataApproval.AUTH_ACCEPT_LOWER_LEVELS );
 
-            organisationUnit = dataApproval.getOrganisationUnit();
-
-            DataApprovalLevel dataApprovalLevel = dataApproval.getDataApprovalLevel();
-
-            if ( mayAcceptAtLowerLevels && organisationUnit != null && dataApprovalLevel != null && dataApprovalLevel.getLevel() > 1 )
+            if ( mayAcceptAtLowerLevels && mayAccessNextHigherLevel( dataApprovalLevel, organisationUnit ) )
             {
-                DataApprovalLevel acceptLevel = dataApprovalLevelService.getDataApprovalLevelByLevelNumber( dataApprovalLevel.getLevel() - 1 );
-
-                if ( securityService.canRead( acceptLevel )
-                        && ( acceptLevel.getCategoryOptionGroupSet() == null ||
-                        ( securityService.canRead( acceptLevel.getCategoryOptionGroupSet() )
-                                && canReadSomeCategoryOptionGroup( acceptLevel.getCategoryOptionGroupSet().getMembers() ) ) ) )
-                {
-                    OrganisationUnit acceptOrgUnit = dataApproval.getOrganisationUnit();
-                    for ( int i = acceptLevel.getOrgUnitLevel(); i < dataApprovalLevel.getOrgUnitLevel(); i++ )
-                    {
-                        acceptOrgUnit = acceptOrgUnit.getParent();
-                    }
-
-                    if ( user.getOrganisationUnits().contains( acceptOrgUnit ) ||
-                            CollectionUtils.containsAny( user.getOrganisationUnits(), acceptOrgUnit.getAncestors() ) )
-                    {
-                        log.debug( "User may accept or unaccept for organisation unit " + organisationUnit.getName() );
-
-                        return true;
-                    }
-                }
+                log.debug( "User may accept or unaccept for organisation unit " + organisationUnit.getName()
+                    + " and approval level " + dataApprovalLevel.getLevel() );
+
+                return true;
             }
         }
 
@@ -565,6 +597,46 @@
     }
 
     /**
+     * Checks to see whether a user may access the next higher approval
+     * level to see if they can accept at this approval level.
+     * <p>
+     * It is assumed that the user has the authority to accept at lower levels.
+     *
+     * @param dataApprovalLevel This data approval level.
+     * @param organisationUnit The organisation unit to check for permission.
+     * @return true if the user may approve at the next higher level.
+     */
+    private boolean mayAccessNextHigherLevel( DataApprovalLevel dataApprovalLevel, OrganisationUnit organisationUnit )
+    {
+        if ( dataApprovalLevel.getLevel() > 1 )
+        {
+            DataApprovalLevel nextLevel = dataApprovalLevelService.getDataApprovalLevelByLevelNumber( dataApprovalLevel.getLevel() - 1 );
+
+            if ( securityService.canRead( nextLevel )
+                    && ( nextLevel.getCategoryOptionGroupSet() == null ||
+                    ( securityService.canRead( nextLevel.getCategoryOptionGroupSet() )
+                            && canReadSomeCategoryOptionGroup( nextLevel.getCategoryOptionGroupSet().getMembers() ) ) ) )
+            {
+                OrganisationUnit acceptOrgUnit = organisationUnit;
+                for ( int i = nextLevel.getOrgUnitLevel(); i < dataApprovalLevel.getOrgUnitLevel(); i++ )
+                {
+                    acceptOrgUnit = acceptOrgUnit.getParent();
+                }
+
+                User user = currentUserService.getCurrentUser();
+
+                if ( user.getOrganisationUnits().contains( acceptOrgUnit ) ||
+                        CollectionUtils.containsAny( user.getOrganisationUnits(), acceptOrgUnit.getAncestors() ) )
+                {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
      * Tests whether the user is authorized to unapprove for this organisation
      * unit.
      * <p>
@@ -575,11 +647,11 @@
      * @param organisationUnit OrganisationUnit to check for approval.
      * @return true if the user may approve, otherwise false
      */
-    private boolean isAuthorizedToUnapprove( OrganisationUnit organisationUnit )
+    private boolean isAuthorizedToUnapprove( DataApprovalLevel dataApprovalLevel, OrganisationUnit organisationUnit )
     {
         log.debug( "isAuthorizedToUnapprove( " + organisationUnit.getName() + ")" );
 
-        if ( mayApprove( organisationUnit ) )
+        if ( mayApprove( dataApprovalLevel, organisationUnit ) )
         {
             log.debug( "User may unapprove at " + organisationUnit.getName() );
 
@@ -588,7 +660,7 @@
 
         for ( OrganisationUnit ancestor : organisationUnit.getAncestors() )
         {
-            if ( mayApprove( ancestor ) )
+            if ( mayApprove( dataApprovalLevel, ancestor ) )
             {
                 log.debug( "User may unapprove at " + ancestor.getName() );