← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 15423: Add category dimension constraints, also validation implements dimension constraints.

 

------------------------------------------------------------
revno: 15423
committer: jimgrace@xxxxxxxxx
branch nick: dhis2
timestamp: Mon 2014-05-26 22:41:16 -0400
message:
  Add category dimension constraints, also validation implements dimension constraints.
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueService.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueStore.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserCredentials.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/DefaultDataValueService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/DefaultUserService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/DefaultValidationRuleService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidationRunContext.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/Validator.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidatorThread.java
  dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/user/hibernate/UserCredentials.hbm.xml
  dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/validation/ValidationRuleServiceTest.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
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/UpdateUserAction.java
  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/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/datavalue/DataValueService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueService.java	2014-05-23 17:54:54 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueService.java	2014-05-27 02:41:16 +0000
@@ -30,9 +30,12 @@
 
 import java.util.Collection;
 import java.util.Date;
+import java.util.Set;
 
 import org.hisp.dhis.common.MapMap;
+import org.hisp.dhis.dataelement.CategoryOptionGroup;
 import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementCategoryOption;
 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
 import org.hisp.dhis.dataelement.DataElementOperand;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
@@ -314,6 +317,7 @@
      */
     MapMap<Integer, DataElementOperand, Double> getDataValueMapByAttributeCombo( Collection<DataElement> dataElements, Date date,
             OrganisationUnit source, Collection<PeriodType> periodTypes, DataElementCategoryOptionCombo attributeCombo,
+            Set<CategoryOptionGroup> cogDimensionConstraints, Set<DataElementCategoryOption> coDimensionConstraints,
             MapMap<Integer, DataElementOperand, Date> lastUpdatedMap );
 
     /**

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueStore.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueStore.java	2014-05-18 00:49:40 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueStore.java	2014-05-27 02:41:16 +0000
@@ -30,9 +30,12 @@
 
 import java.util.Collection;
 import java.util.Date;
+import java.util.Set;
 
 import org.hisp.dhis.common.MapMap;
+import org.hisp.dhis.dataelement.CategoryOptionGroup;
 import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementCategoryOption;
 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
 import org.hisp.dhis.dataelement.DataElementOperand;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
@@ -289,9 +292,10 @@
      * @param lastUpdatedMap map in which to return the lastUpdated date for each value
      * @return map of values by attribute option combo id, then DataElementOperand
      */
-    MapMap<Integer, DataElementOperand, Double> getDataValueMapByAttributeCombo( Collection<DataElement> dataElements, Date date,
-            OrganisationUnit source, Collection<PeriodType> periodTypes, DataElementCategoryOptionCombo attributeCombo,
-            MapMap<Integer, DataElementOperand, Date> lastUpdatedMap );
+    public MapMap<Integer, DataElementOperand, Double> getDataValueMapByAttributeCombo( Collection<DataElement> dataElements, Date date,
+        OrganisationUnit source, Collection<PeriodType> periodTypes, DataElementCategoryOptionCombo attributeCombo,
+        Set<CategoryOptionGroup> cogDimensionConstraints, Set<DataElementCategoryOption> coDimensionConstraints,
+        MapMap<Integer, DataElementOperand, Date> lastUpdatedMap );
     
     /**
      * Gets a Collection of DeflatedDataValues.

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserCredentials.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserCredentials.java	2014-05-12 16:37:39 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserCredentials.java	2014-05-27 02:41:16 +0000
@@ -45,6 +45,7 @@
 import org.hisp.dhis.common.view.DetailedView;
 import org.hisp.dhis.common.view.ExportView;
 import org.hisp.dhis.dataelement.CategoryOptionGroupSet;
+import org.hisp.dhis.dataelement.DataElementCategory;
 import org.hisp.dhis.dataset.DataSet;
 import org.springframework.util.StringUtils;
 
@@ -104,6 +105,12 @@
     private Set<CategoryOptionGroupSet> cogsDimensionConstraints = new HashSet<CategoryOptionGroupSet>();
 
     /**
+     * Category dimensions to constrain data analytics aggregation.
+     */
+    @Scanned
+    private Set<DataElementCategory> catDimensionConstraints = new HashSet<DataElementCategory>();
+
+    /**
      * Date of the user's last login.
      */
     private Date lastLogin;
@@ -381,6 +388,12 @@
             constraints.add( cogs );
         }
 
+        for ( DataElementCategory cat : catDimensionConstraints )
+        {
+            cat.setDimensionType( DimensionType.CATEGORY );
+            constraints.add( cat );
+        }
+
         return constraints;
     }
 
@@ -480,6 +493,21 @@
     @JsonProperty
     @JsonSerialize( contentAs = BaseIdentifiableObject.class )
     @JsonView( { DetailedView.class, ExportView.class } )
+    @JacksonXmlElementWrapper( localName = "catDimensionConstraints", namespace = DxfNamespaces.DXF_2_0 )
+    @JacksonXmlProperty( localName = "catDimensionConstraint", namespace = DxfNamespaces.DXF_2_0 )
+    public Set<DataElementCategory> getCatDimensionConstraints()
+    {
+        return catDimensionConstraints;
+    }
+
+    public void setCatDimensionConstraints( Set<DataElementCategory> catDimensionConstraints )
+    {
+        this.catDimensionConstraints = catDimensionConstraints;
+    }
+
+    @JsonProperty
+    @JsonSerialize( contentAs = BaseIdentifiableObject.class )
+    @JsonView( { DetailedView.class, ExportView.class } )
     @JacksonXmlElementWrapper( localName = "cogsDimensionConstraints", namespace = DxfNamespaces.DXF_2_0 )
     @JacksonXmlProperty( localName = "cogsDimensionConstraint", namespace = DxfNamespaces.DXF_2_0 )
     public Set<CategoryOptionGroupSet> getCogsDimensionConstraints()
@@ -601,6 +629,9 @@
             selfRegistered = userCredentials.isSelfRegistered();
             password = StringUtils.isEmpty( userCredentials.getPassword() ) ? password : userCredentials.getPassword();
 
+            catDimensionConstraints.clear();
+            catDimensionConstraints.addAll( userCredentials.getCatDimensionConstraints() );
+
             cogsDimensionConstraints.clear();
             cogsDimensionConstraints.addAll( userCredentials.getCogsDimensionConstraints() );
 

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserService.java	2014-05-15 13:16:11 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserService.java	2014-05-27 02:41:16 +0000
@@ -1,5 +1,7 @@
 package org.hisp.dhis.user;
 
+import org.hisp.dhis.dataelement.CategoryOptionGroup;
+import org.hisp.dhis.dataelement.DataElementCategoryOption;
 import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 
@@ -8,6 +10,7 @@
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /*
  * Copyright (c) 2004-2014, University of Oslo
@@ -150,6 +153,24 @@
 
     List<User> queryForUsers( String query );
 
+    /**
+     * Returns a set of CategoryOptionGroups that may be seen by the current
+     * user, if the current user has any CategoryOptionGroupSet constraint(s).
+     *
+     * @param userCredentials User credentials to check restrictions for.
+     * @return Set of CategoryOptionGroups if constrained, else null.
+     */
+    public Set<CategoryOptionGroup> getCogDimensionConstraints( UserCredentials userCredentials );
+
+    /**
+     * Returns a set of CategoryOptions that may be seen by the current
+     * user, if the current user has any Category constraint(s).
+     *
+     * @param userCredentials User credentials to check restrictions for.
+     * @return Set of CategoryOptions if constrained, else null.
+     */
+    public Set<DataElementCategoryOption> getCoDimensionConstraints( UserCredentials userCredentials );
+
     // -------------------------------------------------------------------------
     // UserCredentials
     // -------------------------------------------------------------------------

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/DefaultDataValueService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/DefaultDataValueService.java	2014-05-23 09:32:08 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/DefaultDataValueService.java	2014-05-27 02:41:16 +0000
@@ -33,11 +33,14 @@
 import java.util.Calendar;
 import java.util.Collection;
 import java.util.Date;
+import java.util.Set;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.hisp.dhis.common.MapMap;
+import org.hisp.dhis.dataelement.CategoryOptionGroup;
 import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementCategoryOption;
 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
 import org.hisp.dhis.dataelement.DataElementCategoryService;
 import org.hisp.dhis.dataelement.DataElementOperand;
@@ -243,9 +246,11 @@
     
     public MapMap<Integer, DataElementOperand, Double> getDataValueMapByAttributeCombo( Collection<DataElement> dataElements, Date date,
             OrganisationUnit source, Collection<PeriodType> periodTypes, DataElementCategoryOptionCombo attributeCombo,
+            Set<CategoryOptionGroup> cogDimensionConstraints, Set<DataElementCategoryOption> coDimensionConstraints,
             MapMap<Integer, DataElementOperand, Date> lastUpdatedMap )
     {
-        return dataValueStore.getDataValueMapByAttributeCombo( dataElements, date, source, periodTypes, attributeCombo, lastUpdatedMap );
+        return dataValueStore.getDataValueMapByAttributeCombo( dataElements, date, source, periodTypes, attributeCombo,
+               cogDimensionConstraints, coDimensionConstraints, lastUpdatedMap );
     }
     
     public Collection<DeflatedDataValue> getDeflatedDataValues( int dataElementId, int periodId, Collection<Integer> sourceIds )

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java	2014-05-23 09:32:08 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java	2014-05-27 02:41:16 +0000
@@ -35,6 +35,7 @@
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.Set;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -44,8 +45,10 @@
 import org.hibernate.SessionFactory;
 import org.hibernate.criterion.Projections;
 import org.hibernate.criterion.Restrictions;
+import org.hisp.dhis.dataelement.CategoryOptionGroup;
 import org.hisp.dhis.common.MapMap;
 import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementCategoryOption;
 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
 import org.hisp.dhis.dataelement.DataElementOperand;
 import org.hisp.dhis.datavalue.DataValue;
@@ -459,32 +462,51 @@
         return rs != null ? rs.intValue() : 0;
     }
 
-    public MapMap<Integer, DataElementOperand, Double> getDataValueMapByAttributeCombo( Collection<DataElement> dataElements, Date date, OrganisationUnit source,
-        Collection<PeriodType> periodTypes, DataElementCategoryOptionCombo attributeCombo, MapMap<Integer, DataElementOperand, Date> lastUpdatedMap )
+    public MapMap<Integer, DataElementOperand, Double> getDataValueMapByAttributeCombo( Collection<DataElement> dataElements, Date date,
+        OrganisationUnit source, Collection<PeriodType> periodTypes, DataElementCategoryOptionCombo attributeCombo,
+        Set<CategoryOptionGroup> cogDimensionConstraints, Set<DataElementCategoryOption> coDimensionConstraints,
+        MapMap<Integer, DataElementOperand, Date> lastUpdatedMap )
     {
         MapMap<Integer, DataElementOperand, Double> map = new MapMap<Integer, DataElementOperand, Double>();
 
-        if ( dataElements.isEmpty() || periodTypes.isEmpty() )
+        if ( dataElements.isEmpty() || periodTypes.isEmpty()
+                || ( cogDimensionConstraints != null && cogDimensionConstraints.isEmpty() )
+                || ( coDimensionConstraints != null && coDimensionConstraints.isEmpty() ) )
         {
             return map;
         }
 
+        String joinCo = coDimensionConstraints == null && cogDimensionConstraints == null ? "" :
+                "join categoryoptioncombos_categoryoptions c_c on dv.attributeoptioncomboid = c_c.categoryoptioncomboid ";
+
+        String joinCog = cogDimensionConstraints == null ? "" :
+                "join categoryoptiongroupmembers cogm on c_c.categoryoptionid = cogm.categoryoptionid ";
+
+        String whereCo = coDimensionConstraints == null ? "" :
+                "and c_c.categoryoptionid in (" + TextUtils.getCommaDelimitedString( ConversionUtils.getIdentifiers( DataElementCategoryOption.class, coDimensionConstraints ) ) + ") ";
+
+        String whereCog = cogDimensionConstraints == null ? "" :
+                "and cogm.categoryoptiongroupid in (" + TextUtils.getCommaDelimitedString( ConversionUtils.getIdentifiers( CategoryOptionGroup.class, cogDimensionConstraints ) ) + ") ";
+
+        String whereCombo = attributeCombo == null ? "" :
+                "and dv.attributeoptioncomboid = " + attributeCombo.getId() + " ";
+
         String sql =
                 "select de.uid, coc.uid, dv.attributeoptioncomboid, dv.value, dv.lastupdated, p.startdate, p.enddate " +
                         "from datavalue dv " +
                         "join dataelement de on dv.dataelementid = de.dataelementid " +
                         "join categoryoptioncombo coc on dv.categoryoptioncomboid = coc.categoryoptioncomboid " +
                         "join period p on p.periodid = dv.periodid " +
+                        joinCo +
+                        joinCog +
                         "where dv.dataelementid in (" + TextUtils.getCommaDelimitedString( ConversionUtils.getIdentifiers( DataElement.class, dataElements ) ) + ") " +
                         "and dv.sourceid = " + source.getId() + " " +
                         "and p.startdate <= '" + DateUtils.getMediumDateString( date ) + "' " +
                         "and p.enddate >= '" + DateUtils.getMediumDateString( date ) + "' " +
-                        "and p.periodtypeid in (" + TextUtils.getCommaDelimitedString( ConversionUtils.getIdentifiers( PeriodType.class, periodTypes ) ) + ") ";
-
-        if ( attributeCombo != null )
-        {
-            sql += " and dv.attributeoptioncomboid = " + attributeCombo.getId();
-        }
+                        "and p.periodtypeid in (" + TextUtils.getCommaDelimitedString( ConversionUtils.getIdentifiers( PeriodType.class, periodTypes ) ) + ") " +
+                        whereCo +
+                        whereCog +
+                        whereCombo;
 
         SqlRowSet rowSet = jdbcTemplate.queryForRowSet( sql );
 

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/DefaultUserService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/DefaultUserService.java	2014-05-19 11:42:06 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/DefaultUserService.java	2014-05-27 02:41:16 +0000
@@ -37,12 +37,18 @@
 import java.util.Collection;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.hisp.dhis.common.AuditLogUtil;
+import org.hisp.dhis.dataelement.CategoryOptionGroup;
+import org.hisp.dhis.dataelement.CategoryOptionGroupSet;
+import org.hisp.dhis.dataelement.DataElementCategory;
+import org.hisp.dhis.dataelement.DataElementCategoryOption;
 import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.period.PeriodType;
@@ -316,6 +322,56 @@
         return users;
     }
 
+    public Set<CategoryOptionGroup> getCogDimensionConstraints( UserCredentials userCredentials )
+    {
+        Set<CategoryOptionGroup> groups = null;
+
+        Set<CategoryOptionGroupSet> cogsConstraints = userCredentials.getCogsDimensionConstraints();
+
+        if ( cogsConstraints != null && !cogsConstraints.isEmpty() )
+        {
+            groups = new HashSet<CategoryOptionGroup>();
+
+            for ( CategoryOptionGroupSet set : cogsConstraints )
+            {
+                for ( CategoryOptionGroup g : set.getMembers() )
+                {
+                    if ( securityService.canRead( g ) )
+                    {
+                        groups.add( g );
+                    }
+                }
+            }
+        }
+
+        return groups;
+    }
+
+    public Set<DataElementCategoryOption> getCoDimensionConstraints( UserCredentials userCredentials )
+    {
+        Set<DataElementCategoryOption> options = null;
+
+        Set<DataElementCategory> catConstraints = userCredentials.getCatDimensionConstraints();
+
+        if ( catConstraints != null && !catConstraints.isEmpty() )
+        {
+            options = new HashSet<DataElementCategoryOption>();
+
+            for ( DataElementCategory cat : catConstraints )
+            {
+                for ( DataElementCategoryOption o : cat.getCategoryOptions() )
+                {
+                    if ( securityService.canRead( o ) )
+                    {
+                        options.add( o );
+                    }
+                }
+            }
+        }
+
+        return options;
+    }
+
     // -------------------------------------------------------------------------
     // UserAuthorityGroup
     // -------------------------------------------------------------------------

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/DefaultValidationRuleService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/DefaultValidationRuleService.java	2014-05-18 00:49:40 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/DefaultValidationRuleService.java	2014-05-27 02:41:16 +0000
@@ -70,8 +70,10 @@
 import org.hisp.dhis.setting.SystemSettingManager;
 import org.hisp.dhis.system.util.Filter;
 import org.hisp.dhis.system.util.FilterUtils;
+import org.hisp.dhis.user.CurrentUserService;
 import org.hisp.dhis.user.User;
 import org.hisp.dhis.user.UserGroup;
+import org.hisp.dhis.user.UserService;
 import org.springframework.transaction.annotation.Transactional;
 
 /**
@@ -165,7 +167,21 @@
     {
         this.organisationUnitService = organisationUnitService;
     }
-    
+
+    private UserService userService;
+
+    public void setUserService( UserService userService )
+    {
+        this.userService = userService;
+    }
+
+    private CurrentUserService currentUserService;
+
+    public void setCurrentUserService( CurrentUserService currentUserService )
+    {
+        this.currentUserService = currentUserService;
+    }
+
     private SystemSettingManager systemSettingManager;
 
     public void setSystemSettingManager( SystemSettingManager systemSettingManager )
@@ -187,8 +203,8 @@
         Collection<ValidationRule> rules = group != null ? group.getMembers() : getAllValidationRules();
         
         Collection<ValidationResult> results = Validator.validate( sources, periods, rules, attributeCombo, null,
-            constantService, expressionService, periodService, dataValueService, dataElementCategoryService );
-        
+            constantService, expressionService, periodService, dataValueService, dataElementCategoryService, userService, currentUserService );
+
         formatPeriods( results, format );
         
         if ( sendAlerts )
@@ -212,7 +228,7 @@
         sources.add( source );
 
         return Validator.validate( sources, periods, rules, null, null,
-            constantService, expressionService, periodService, dataValueService, dataElementCategoryService );
+                constantService, expressionService, periodService, dataValueService, dataElementCategoryService, userService, currentUserService );
     }
 
     @Override
@@ -243,7 +259,7 @@
         sources.add( source );
         
         return Validator.validate( sources, periods, rules, attributeCombo, null,
-            constantService, expressionService, periodService, dataValueService, dataElementCategoryService );
+                constantService, expressionService, periodService, dataValueService, dataElementCategoryService, userService, currentUserService );
     }
 
     @Override
@@ -269,7 +285,7 @@
             + ", last run: " + ( lastScheduledRun == null ? "[none]" : lastScheduledRun ) );
         
         Collection<ValidationResult> results = Validator.validate( sources, periods, rules, null, lastScheduledRun,
-            constantService, expressionService, periodService, dataValueService, dataElementCategoryService );
+                constantService, expressionService, periodService, dataValueService, dataElementCategoryService, userService, currentUserService );
         
         log.info( "Validation run result count: " + results.size() );
         

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidationRunContext.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidationRunContext.java	2014-05-18 00:49:40 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidationRunContext.java	2014-05-27 02:41:16 +0000
@@ -41,7 +41,9 @@
 import org.apache.commons.lang.builder.ToStringStyle;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.hisp.dhis.dataelement.CategoryOptionGroup;
 import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementCategoryOption;
 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
 import org.hisp.dhis.dataelement.DataElementCategoryService;
 import org.hisp.dhis.dataset.DataSet;
@@ -51,6 +53,9 @@
 import org.hisp.dhis.period.Period;
 import org.hisp.dhis.period.PeriodService;
 import org.hisp.dhis.period.PeriodType;
+import org.hisp.dhis.user.CurrentUserService;
+import org.hisp.dhis.user.UserCredentials;
+import org.hisp.dhis.user.UserService;
 
 /**
  * Holds common values that are used during a validation run (either interactive
@@ -88,6 +93,10 @@
     
     private int countOfSourcesToValidate;
 
+    private Set<CategoryOptionGroup> cogDimensionConstraints;
+
+    private Set<DataElementCategoryOption> coDimensionConstraints;
+
     private Collection<ValidationResult> validationResults;
 
     private ExpressionService expressionService;
@@ -123,14 +132,24 @@
      * @param rules validation rules for validation
      * @param runType whether this is an INTERACTIVE or SCHEDULED run
      * @param lastScheduledRun (for SCHEDULED runs) date/time of previous run
+     * @param expressionService expression service
+     * @param periodService period service
+     * @param dataValueService data value service
+     * @param dataElementCategoryService data element category service
+     * @param userService user service
+     * @param currentUserService current user service
+     *
      * @return context object for this run
      */
     public static ValidationRunContext getNewValidationRunContext( Collection<OrganisationUnit> sources,
         Collection<Period> periods, DataElementCategoryOptionCombo attributeCombo, Collection<ValidationRule> rules,
         Map<String, Double> constantMap, ValidationRunType runType, Date lastScheduledRun,
         ExpressionService expressionService, PeriodService periodService,
-        DataValueService dataValueService, DataElementCategoryService dataElementCategoryService )
+        DataValueService dataValueService, DataElementCategoryService dataElementCategoryService,
+        UserService userService, CurrentUserService currentUserService )
     {
+        UserCredentials currentUserCredentials = currentUserService.getCurrentUser().getUserCredentials();
+
         ValidationRunContext context = new ValidationRunContext();
         context.runType = runType;
         context.lastScheduledRun = lastScheduledRun;
@@ -144,6 +163,8 @@
         context.dataValueService = dataValueService;
         context.dataElementCategoryService = dataElementCategoryService;
         context.attributeCombo = attributeCombo;
+        context.cogDimensionConstraints = userService.getCogDimensionConstraints( currentUserCredentials );
+        context.coDimensionConstraints = userService.getCoDimensionConstraints( currentUserCredentials );
         context.initialize( sources, periods, rules );
         return context;
     }
@@ -381,7 +402,7 @@
     }
 
     // -------------------------------------------------------------------------
-    // Set and get methods
+    // Get methods
     // -------------------------------------------------------------------------
 
     public Map<PeriodType, PeriodTypeExtended> getPeriodTypeExtendedMap()
@@ -429,6 +450,16 @@
         return validationResults;
     }
 
+    public Set<CategoryOptionGroup> getCogDimensionConstraints()
+    {
+        return cogDimensionConstraints;
+    }
+
+    public Set<DataElementCategoryOption> getCoDimensionConstraints()
+    {
+        return coDimensionConstraints;
+    }
+
     public ExpressionService getExpressionService()
     {
         return expressionService;

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/Validator.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/Validator.java	2014-05-23 09:32:08 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/Validator.java	2014-05-27 02:41:16 +0000
@@ -43,6 +43,9 @@
 import org.hisp.dhis.period.Period;
 import org.hisp.dhis.period.PeriodService;
 import org.hisp.dhis.system.util.SystemUtils;
+import org.hisp.dhis.user.CurrentUserService;
+import org.hisp.dhis.user.UserCredentials;
+import org.hisp.dhis.user.UserService;
 
 /**
  * Evaluates validation rules.
@@ -68,16 +71,19 @@
      * @param periodService Period Service reference
      * @param dataValueService Data Value Service reference
      * @param dataElementCategoryService Data Element Category Service reference
+     * @param userService user service
+     * @param currentUserService current user service
      * @return a collection of any validations that were found
      */
     public static Collection<ValidationResult> validate( Collection<OrganisationUnit> sources, Collection<Period> periods,
         Collection<ValidationRule> rules, DataElementCategoryOptionCombo attributeCombo, Date lastScheduledRun,
         ConstantService constantService, ExpressionService expressionService, PeriodService periodService,
-        DataValueService dataValueService, DataElementCategoryService dataElementCategoryService )
+        DataValueService dataValueService, DataElementCategoryService dataElementCategoryService,
+        UserService userService, CurrentUserService currentUserService )
     {
         ValidationRunContext context = ValidationRunContext.getNewValidationRunContext( sources, periods,
             attributeCombo, rules, constantService.getConstantMap(), ValidationRunType.SCHEDULED, lastScheduledRun,
-            expressionService, periodService, dataValueService, dataElementCategoryService );
+            expressionService, periodService, dataValueService, dataElementCategoryService, userService, currentUserService );
 
         int threadPoolSize = getThreadPoolSize( context );
         ExecutorService executor = Executors.newFixedThreadPool( threadPoolSize );

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidatorThread.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidatorThread.java	2014-05-18 00:49:40 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidatorThread.java	2014-05-27 02:41:16 +0000
@@ -567,7 +567,8 @@
         else
         {
             dataValueMap2 = context.getDataValueService().getDataValueMapByAttributeCombo( dataElementsToGet,
-                period.getStartDate(), source, allowedPeriodTypes, context.getAttributeCombo(), lastUpdatedMap );
+                period.getStartDate(), source, allowedPeriodTypes, context.getAttributeCombo(),
+                context.getCogDimensionConstraints(), context.getCoDimensionConstraints(), lastUpdatedMap );
         }
 
         // See if there are any data elements we need to get recursively:

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml	2014-05-23 18:02:29 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml	2014-05-27 02:41:16 +0000
@@ -508,6 +508,8 @@
     <property name="i18nService" ref="org.hisp.dhis.i18n.I18nService" />
     <property name="messageService" ref="org.hisp.dhis.message.MessageService" />
     <property name="organisationUnitService" ref="org.hisp.dhis.organisationunit.OrganisationUnitService" />
+    <property name="userService" ref="org.hisp.dhis.user.UserService" />
+    <property name="currentUserService" ref="org.hisp.dhis.user.CurrentUserService" />
     <property name="systemSettingManager" ref="org.hisp.dhis.setting.SystemSettingManager" />
   </bean>
 

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/user/hibernate/UserCredentials.hbm.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/user/hibernate/UserCredentials.hbm.xml	2014-04-08 19:36:25 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/user/hibernate/UserCredentials.hbm.xml	2014-05-27 02:41:16 +0000
@@ -36,7 +36,7 @@
       <many-to-many column="userroleid" class="org.hisp.dhis.user.UserAuthorityGroup" 
         foreign-key="fk_userrolemembers_userroleid" />
     </set>
-    
+
     <set name="cogsDimensionConstraints" table="users_cogsdimensionconstraints">
       <cache usage="read-write" />
       <key column="userid" foreign-key="fk_users_cogsconstraints_userid" />
@@ -44,6 +44,13 @@
         foreign-key="fk_fk_users_cogsconstraints_categoryoptiongroupsetid" />
     </set>
 
+    <set name="catDimensionConstraints" table="users_catdimensionconstraints">
+      <cache usage="read-write" />
+      <key column="userid" foreign-key="fk_users_catconstraints_userid" />
+      <many-to-many column="dataelementcategoryid" class="org.hisp.dhis.dataelement.DataElementCategory"
+                    foreign-key="fk_fk_users_catconstraints_dataelementcategoryid" />
+    </set>
+
     <property name="lastLogin" />
 
     <property name="restoreToken" />

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/validation/ValidationRuleServiceTest.java'
--- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/validation/ValidationRuleServiceTest.java	2014-05-18 00:49:40 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/validation/ValidationRuleServiceTest.java	2014-05-27 02:41:16 +0000
@@ -59,6 +59,7 @@
 import org.hisp.dhis.datavalue.DataValueService;
 import org.hisp.dhis.expression.Expression;
 import org.hisp.dhis.expression.ExpressionService;
+import org.hisp.dhis.mock.MockCurrentUserService;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.organisationunit.OrganisationUnitService;
 import org.hisp.dhis.period.MonthlyPeriodType;
@@ -68,6 +69,7 @@
 import org.hisp.dhis.period.WeeklyPeriodType;
 import org.hisp.dhis.period.YearlyPeriodType;
 import org.hisp.dhis.system.util.MathUtils;
+import org.hisp.dhis.user.CurrentUserService;
 import org.junit.Test;
 
 /**
@@ -174,6 +176,8 @@
 
     private Set<OrganisationUnit> sourcesA = new HashSet<OrganisationUnit>();
 
+    private Set<OrganisationUnit> allSources = new HashSet<OrganisationUnit>();
+
     private ValidationRule validationRuleA;
 
     private ValidationRule validationRuleB;
@@ -242,6 +246,9 @@
 
         categoryService = (DataElementCategoryService) getBean( DataElementCategoryService.ID );
 
+        CurrentUserService currentUserService = new MockCurrentUserService( allSources, null );
+        setDependency( validationRuleService, "currentUserService", currentUserService, CurrentUserService.class );
+
         periodTypeWeekly = new WeeklyPeriodType();
         periodTypeMonthly = new MonthlyPeriodType();
         periodTypeYearly = new YearlyPeriodType();
@@ -332,6 +339,14 @@
         sourcesA.add( sourceA );
         sourcesA.add( sourceB );
 
+        allSources.add( sourceA );
+        allSources.add( sourceB );
+        allSources.add( sourceC );
+        allSources.add( sourceD );
+        allSources.add( sourceE );
+        allSources.add( sourceF );
+        allSources.add( sourceG );
+
         joinDataSetToSource( dataSetMonthly, sourceA );
         joinDataSetToSource( dataSetMonthly, sourceB );
         joinDataSetToSource( dataSetMonthly, sourceC );

=== 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-26 19:10:33 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java	2014-05-27 02:41:16 +0000
@@ -293,6 +293,9 @@
         user.getUserCredentials().getCogsDimensionConstraints().addAll(
             currentUserService.getCurrentUser().getUserCredentials().getCogsDimensionConstraints() );
 
+        user.getUserCredentials().getCatDimensionConstraints().addAll(
+            currentUserService.getCurrentUser().getUserCredentials().getCatDimensionConstraints() );
+
         String encodePassword = passwordManager.encodePassword( user.getUsername(),
             user.getUserCredentials().getPassword() );
         user.getUserCredentials().setPassword( encodePassword );

=== 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-26 19:10:33 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/AddUserAction.java	2014-05-27 02:41:16 +0000
@@ -37,6 +37,7 @@
 import org.hisp.dhis.webapi.utils.ContextUtils;
 import org.hisp.dhis.attribute.AttributeService;
 import org.hisp.dhis.dataelement.CategoryOptionGroupSet;
+import org.hisp.dhis.dataelement.DataElementCategory;
 import org.hisp.dhis.dataelement.DataElementCategoryService;
 import org.hisp.dhis.i18n.I18n;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
@@ -398,13 +399,31 @@
         // ---------------------------------------------------------------------
 
         userCredentials.setCogsDimensionConstraints( new HashSet<CategoryOptionGroupSet>( currentUser.getUserCredentials().getCogsDimensionConstraints() ) );
+        userCredentials.setCatDimensionConstraints( new HashSet<DataElementCategory>( currentUser.getUserCredentials().getCatDimensionConstraints() ) );
 
         for ( String id : dcSelected )
         {
             CategoryOptionGroupSet cogs = categoryService.getCategoryOptionGroupSet( id );
-            userCredentials.getCogsDimensionConstraints().add( cogs );
+
+            if ( cogs != null )
+            {
+                userCredentials.getCogsDimensionConstraints().add( cogs );
+                continue;
+            }
+
+            DataElementCategory cat = categoryService.getDataElementCategory( id );
+
+            if ( cat != null )
+            {
+                userCredentials.getCatDimensionConstraints().add( cat );
+                continue;
+            }
         }
 
+        // ---------------------------------------------------------------------
+        // Add User
+        // ---------------------------------------------------------------------
+
         userService.addUser( user );
         userService.addUserCredentials( userCredentials );
 

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/UpdateUserAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/UpdateUserAction.java	2014-05-16 09:24:56 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/UpdateUserAction.java	2014-05-27 02:41:16 +0000
@@ -37,6 +37,7 @@
 
 import org.hisp.dhis.attribute.AttributeService;
 import org.hisp.dhis.dataelement.CategoryOptionGroupSet;
+import org.hisp.dhis.dataelement.DataElementCategory;
 import org.hisp.dhis.dataelement.DataElementCategoryService;
 import org.hisp.dhis.i18n.I18n;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
@@ -357,12 +358,30 @@
         // ---------------------------------------------------------------------
 
         userCredentials.setCogsDimensionConstraints( new HashSet<CategoryOptionGroupSet>( currentUser.getUserCredentials().getCogsDimensionConstraints() ) );
-        
+        userCredentials.setCatDimensionConstraints( new HashSet<DataElementCategory>( currentUser.getUserCredentials().getCatDimensionConstraints() ) );
+
         for ( String id : dcSelected )
         {
             CategoryOptionGroupSet cogs = categoryService.getCategoryOptionGroupSet( id );
-            userCredentials.getCogsDimensionConstraints().add( cogs );
+
+            if ( cogs != null )
+            {
+                userCredentials.getCogsDimensionConstraints().add( cogs );
+                continue;
+            }
+
+            DataElementCategory cat = categoryService.getDataElementCategory( id );
+
+            if ( cat != null )
+            {
+                userCredentials.getCatDimensionConstraints().add( cat );
+                continue;
+            }
         }
+
+        // ---------------------------------------------------------------------
+        // Update User
+        // ---------------------------------------------------------------------
         
         userService.updateUserCredentials( userCredentials );
         userService.updateUser( user );

=== 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-05-22 11:59:55 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/addUserForm.vm	2014-05-27 02:41:16 +0000
@@ -44,10 +44,10 @@
     });
     
     $('#dcAvailable').selected({
-      url: '../api/categoryOptionGroupSets.json',
+      url: '../api/dimensions/constraints.json',
       target: $('#dcSelected'),
       search: $('#dcAvailableSearch'),
-      iterator: 'categoryOptionGroupSets'
+      iterator: 'dimensions'
     });
   });
 </script>

=== 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	2014-04-14 06:26:46 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/updateUserForm.vm	2014-05-27 02:41:16 +0000
@@ -52,10 +52,10 @@
     });
     
     $('#dcAvailable').selected({
-      url: '../api/categoryOptionGroupSets.json',
+      url: '../api/dimensions/constraints.json',
       target: $('#dcSelected'),
       search: $('#dcAvailableSearch'),
-      iterator: 'categoryOptionGroupSets'
+      iterator: 'dimensions'
     });
   });
 </script>
@@ -193,7 +193,7 @@
     "prefix": "dc",
     "i18n_available": "available_dimension_restrictions_for_data_analytics",
     "i18n_selected": "selected_dimension_restrictions_for_data_analytics",
-    "objects": $userCredentials.cogsDimensionConstraints
+    "objects": $userCredentials.dimensionConstraints
 })
 
 <div id="showLessOptions" style="margin-bottom: 20px;"><a href="javascript:showUserOptions()">$i18n.getString( "show_less_options" )</a></div>