dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #29259
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 14753: WIP, function for constraining analytics queries on certain dimensions
------------------------------------------------------------
revno: 14753
committer: Lars Helge Øverland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Tue 2014-04-08 20:25:25 +0200
message:
WIP, function for constraining analytics queries on certain dimensions
modified:
dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserCredentials.java
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/dimension/DefaultDimensionService.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-api/src/main/java/org/hisp/dhis/user/UserCredentials.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserCredentials.java 2014-04-02 05:00:27 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserCredentials.java 2014-04-08 18:25:25 +0000
@@ -36,11 +36,14 @@
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import org.hisp.dhis.common.BaseIdentifiableObject;
+import org.hisp.dhis.common.DimensionType;
+import org.hisp.dhis.common.DimensionalObject;
import org.hisp.dhis.common.DxfNamespaces;
import org.hisp.dhis.common.IdentifiableObjectUtils;
import org.hisp.dhis.common.annotation.Scanned;
import org.hisp.dhis.common.view.DetailedView;
import org.hisp.dhis.common.view.ExportView;
+import org.hisp.dhis.dataelement.CategoryOptionGroupSet;
import org.hisp.dhis.dataset.DataSet;
import java.util.Collection;
@@ -91,6 +94,11 @@
*/
@Scanned
private Set<UserAuthorityGroup> userAuthorityGroups = new HashSet<UserAuthorityGroup>();
+
+ /**
+ * Category option group set dimensions to constrain data analytics aggregation.
+ */
+ private Set<CategoryOptionGroupSet> cogsDimensionConstraints = new HashSet<CategoryOptionGroupSet>();
/**
* Date of the user's last login.
@@ -354,6 +362,32 @@
return token.equals( this.restoreToken ) && code.equals( this.restoreCode );
}
+
+ /**
+ * Returns the dimensions to use as constrains (filters) in data analytics
+ * aggregation.
+ */
+ public Set<DimensionalObject> getDimensionConstraints()
+ {
+ Set<DimensionalObject> constraints = new HashSet<DimensionalObject>();
+
+ for ( CategoryOptionGroupSet cogs : cogsDimensionConstraints )
+ {
+ cogs.setDimensionType( DimensionType.CATEGORYOPTION_GROUPSET );
+ constraints.add( cogs );
+ }
+
+ return constraints;
+ }
+
+ /**
+ * Indicates whether this user has dimension constraints.
+ */
+ public boolean hasDimensionConstraints()
+ {
+ Set<DimensionalObject> constraints = getDimensionConstraints();
+ return constraints != null && !constraints.isEmpty();
+ }
// -------------------------------------------------------------------------
// hashCode and equals
@@ -440,6 +474,21 @@
}
@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()
+ {
+ return cogsDimensionConstraints;
+ }
+
+ public void setCogsDimensionConstraints( Set<CategoryOptionGroupSet> cogsDimensionConstraints )
+ {
+ this.cogsDimensionConstraints = cogsDimensionConstraints;
+ }
+
+ @JsonProperty
@JsonView({ DetailedView.class, ExportView.class })
@JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0)
public String getUsername()
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java 2014-04-01 12:44:59 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java 2014-04-08 18:25:25 +0000
@@ -1136,7 +1136,7 @@
/**
* Retrieves the options for the the dimension or filter with the given
- * identifier. Returns null of the dimension of filter is not present.
+ * identifier. Returns null if the dimension or filter is not present.
*/
public List<NameableObject> getDimensionOrFilter( String key )
{
@@ -1196,6 +1196,16 @@
{
return dimensions.indexOf( new BaseDimensionalObject( key ) ) != -1 || filters.indexOf( new BaseDimensionalObject( key ) ) != -1;
}
+
+ /**
+ * Indicates whether a dimension or filter which specifies dimension items
+ * with the given identifier exists.
+ */
+ public boolean hasDimensionOrFilterWithItems( String key )
+ {
+ List<NameableObject> items = getDimensionOrFilter( key );
+ return items != null && !items.isEmpty();
+ }
/**
* Indicates whether a dimension with the given identifier exists. Returns
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java 2014-04-08 18:25:25 +0000
@@ -103,4 +103,14 @@
* names respectively.
*/
List<DataQueryParams> groupByPeriodType( DataQueryParams params );
+
+ /**
+ * Applies dimension constraints to the given params. Dimension constraints
+ * with all accessible dimension items will be added as filters to this query.
+ * If current user has no dimension constraints, no action is taken. If the
+ * constraint dimensions are already specified with accessible items in the
+ * query, no action is taken. If the current user does not have accessible
+ * items in any dimension constraint, an IllegalQueryException is thrown.
+ */
+ void applyDimensionConstraints( DataQueryParams params );
}
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java 2014-04-08 17:05:58 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java 2014-04-08 18:25:25 +0000
@@ -203,6 +203,8 @@
@Override
public Grid getAggregatedDataValues( DataQueryParams params )
{
+ queryPlanner.applyDimensionConstraints( params );
+
queryPlanner.validate( params );
params.conform();
@@ -758,6 +760,8 @@
return params;
}
+ // TODO verify that current user can read each dimension and dimension item
+
public List<DimensionalObject> getDimension( String dimension, List<String> items, Date relativePeriodDate, I18nFormat format )
{
if ( DATA_X_DIM_ID.equals( dimension ) )
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java 2014-04-08 17:28:02 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java 2014-04-08 18:25:25 +0000
@@ -47,6 +47,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -57,6 +58,7 @@
import org.hisp.dhis.analytics.QueryPlanner;
import org.hisp.dhis.analytics.table.PartitionUtils;
import org.hisp.dhis.common.BaseDimensionalObject;
+import org.hisp.dhis.common.DimensionService;
import org.hisp.dhis.common.DimensionType;
import org.hisp.dhis.common.DimensionalObject;
import org.hisp.dhis.common.IllegalQueryException;
@@ -69,6 +71,8 @@
import org.hisp.dhis.period.PeriodType;
import org.hisp.dhis.system.util.MathUtils;
import org.hisp.dhis.system.util.PaginatedList;
+import org.hisp.dhis.user.CurrentUserService;
+import org.hisp.dhis.user.User;
import org.springframework.beans.factory.annotation.Autowired;
/**
@@ -84,6 +88,12 @@
@Autowired
private OrganisationUnitService organisationUnitService;
+ @Autowired
+ private DimensionService dimensionService;
+
+ @Autowired
+ private CurrentUserService currentUserService;
+
// -------------------------------------------------------------------------
// DefaultQueryPlanner implementation
// -------------------------------------------------------------------------
@@ -281,6 +291,57 @@
return queryGroups;
}
+ public void applyDimensionConstraints( DataQueryParams params )
+ {
+ User user = currentUserService.getCurrentUser();
+
+ if ( params == null || user == null || user.getUserCredentials() == null )
+ {
+ return;
+ }
+
+ if ( !user.getUserCredentials().hasDimensionConstraints() )
+ {
+ return;
+ }
+
+ Set<DimensionalObject> dimensionConstraints = user.getUserCredentials().getDimensionConstraints();
+
+ for ( DimensionalObject dimension : dimensionConstraints )
+ {
+ // -----------------------------------------------------------------
+ // Check if constraint is already specified with items
+ // -----------------------------------------------------------------
+
+ if ( params.hasDimensionOrFilterWithItems( dimension.getUid() ) )
+ {
+ continue;
+ }
+
+ List<NameableObject> canReadItems = dimensionService.getCanReadDimensionItems( dimension.getDimension() );
+
+ // -----------------------------------------------------------------
+ // Check if current user has access to any items from constraint
+ // -----------------------------------------------------------------
+
+ if ( canReadItems == null || canReadItems.isEmpty() )
+ {
+ throw new IllegalQueryException( "Current user is constrained by a dimension but has access to no associated dimension items: " + dimension.getDimension() );
+ }
+
+ // -----------------------------------------------------------------
+ // Apply constraint as filter, and remove potential all-dimension
+ // -----------------------------------------------------------------
+
+ params.removeDimensionOrFilter( dimension.getDimension() );
+
+ DimensionalObject constraint = new BaseDimensionalObject( dimension.getDimension(),
+ dimension.getDimensionType(), null, dimension.getDisplayName(), canReadItems );
+
+ params.getFilters().add( constraint );
+ }
+ }
+
// -------------------------------------------------------------------------
// Supportive methods
// -------------------------------------------------------------------------
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/dimension/DefaultDimensionService.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/dimension/DefaultDimensionService.java 2014-03-27 06:07:15 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/dimension/DefaultDimensionService.java 2014-04-08 18:25:25 +0000
@@ -164,9 +164,11 @@
List<NameableObject> items = new ArrayList<NameableObject>();
if ( dimension != null && dimension.getItems() != null )
- {
+ {
User user = currentUserService.getCurrentUser();
+ //TODO do this with query to improve performance
+
for ( NameableObject item : dimension.getItems() )
{
boolean canRead = aclService.canRead( user, item );
@@ -180,7 +182,7 @@
return items;
}
-
+
public DimensionType getDimensionType( String uid )
{
DataElementCategory cat = identifiableObjectManager.get( DataElementCategory.class, uid );