diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DeflatedDataValue.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DeflatedDataValue.java index 80dfadd0b7fe..a24053cdf35a 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DeflatedDataValue.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DeflatedDataValue.java @@ -95,7 +95,7 @@ public DeflatedDataValue(DataValue dataValue) { this.dataElementId = dataValue.getDataElement().getId(); this.periodId = dataValue.getPeriod().getId(); this.sourceId = dataValue.getSource().getId(); - this.sourcePath = dataValue.getSource().getPath(); + this.sourcePath = dataValue.getSource().getStoredPath(); this.categoryOptionComboId = dataValue.getCategoryOptionCombo().getId(); this.attributeOptionComboId = dataValue.getAttributeOptionCombo().getId(); this.value = dataValue.getValue(); diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnit.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnit.java index aabb76e20d90..4ad96db1e958 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnit.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnit.java @@ -28,7 +28,9 @@ package org.hisp.dhis.organisationunit; import static org.apache.commons.collections4.CollectionUtils.isEmpty; +import static org.apache.commons.lang3.StringUtils.isNotEmpty; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; @@ -573,7 +575,7 @@ public boolean isDescendant(Collection ancestors) { return ancestors.stream() .filter(Objects::nonNull) .map(OrganisationUnit::getUid) - .anyMatch(uid -> StringUtils.contains(this.getPath(), uid)); + .anyMatch(uid -> StringUtils.contains(this.getStoredPath(), uid)); } /** @@ -587,7 +589,7 @@ public boolean isDescendant(OrganisationUnit ancestor) { return false; } - return StringUtils.contains(this.getPath(), ancestor.getUid()); + return StringUtils.contains(this.getStoredPath(), ancestor.getUid()); } public Set getChildrenThisIfEmpty() { @@ -753,6 +755,13 @@ public void setChildren(Set children) { this.children = children; } + /** + * Note that the {@code path} property is mapped with the "property access" mode. This method will + * calculate and return the path property value based on the org unit ancestors. To access the + * {@code path} property directly, use {@link OrganisationUnit#getStoredPath}. + * + * @return the path. + */ @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getPath() { @@ -779,11 +788,36 @@ public String getPath() { return this.path; } - /** Do not set directly, managed by persistence layer. */ + /** + * Note that the {@code path} property is mapped with the "property access" mode. This method will + * return the persisted {@code path} property value directly. If the path is not defined, + * typically as part of an integration test where the state is not yet flushed to the database, + * the calculated path based on the org unit ancestors is returned. To get the calculated path + * value explicitly, use {@link OrganisationUnit#getPath}. + * + * @return the path. + */ + @JsonIgnore + public String getStoredPath() { + return isNotEmpty(path) ? path : getPath(); + } + + /** + * Note that the {@code path} property is mapped with the "property access" mode. Do not set + * directly, this property is managed by the persistence layer. + */ public void setPath(String path) { this.path = path; } + /** + * Note that the {@code path} property is mapped with the "property access" mode. This method is + * for unit testing purposes only. + */ + public void updatePath() { + setPath(getPath()); + } + /** * Used by persistence layer. Purpose is to have a column for use in database queries. For * application use see {@link OrganisationUnit#getLevel()} which has better performance. @@ -806,14 +840,6 @@ public Integer getHierarchyLevel() { return hierarchyLevel; } - /** - * Note that the {@code path} is mapped with the "property access" mode. This method is for unit - * testing purposes only. - */ - public void updatePath() { - setPath(getPath()); - } - /** Do not set directly. */ public void setHierarchyLevel(Integer hierarchyLevel) { this.hierarchyLevel = hierarchyLevel; diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/JdbcRawAnalyticsManager.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/JdbcRawAnalyticsManager.java index 5c364d231b50..9f6263bfae80 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/JdbcRawAnalyticsManager.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/JdbcRawAnalyticsManager.java @@ -167,7 +167,7 @@ private String getSelectStatement(DataQueryParams params, List - sql.append(pathAlias).append(".\"path\" like '").append(ou.getPath()).append("%' or ")); + sql.append(pathAlias) + .append(".\"path\" like '") + .append(ou.getStoredPath()) + .append("%' or ")); return StringUtils.trim(TextUtils.removeLastOr(sql.toString())) + ")"; } diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/resourcetable/table/OrganisationUnitStructureResourceTable.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/resourcetable/table/OrganisationUnitStructureResourceTable.java index 8b9e14844c19..1a924b5fe302 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/resourcetable/table/OrganisationUnitStructureResourceTable.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/resourcetable/table/OrganisationUnitStructureResourceTable.java @@ -156,7 +156,7 @@ List createBatchObjects(List units, int level) { values.add(unit.getOpeningDate()); values.add(unit.getClosedDate()); values.add(level); - values.add(unit.getPath()); + values.add(unit.getStoredPath()); Map identifiers = new HashMap<>(); Map uids = new HashMap<>(); diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/association/jdbc/JdbcOrgUnitAssociationsStore.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/association/jdbc/JdbcOrgUnitAssociationsStore.java index 2fcad3f94b00..6aa5c6b3b373 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/association/jdbc/JdbcOrgUnitAssociationsStore.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/association/jdbc/JdbcOrgUnitAssociationsStore.java @@ -108,7 +108,7 @@ private Set getUserOrgUnitPaths() { User currentUser = userService.getUserByUsername(CurrentUserUtil.getCurrentUsername()); Set allUserOrgUnitPaths = currentUser.getOrganisationUnits().stream() - .map(OrganisationUnit::getPath) + .map(OrganisationUnit::getStoredPath) .collect(Collectors.toSet()); return allUserOrgUnitPaths.stream() diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java index 338b825c5453..19a6107ff8d1 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java @@ -334,7 +334,7 @@ private String getDataValuesHql( hql.append( params.getOrganisationUnits().stream() - .map(OrganisationUnit::getPath) + .map(OrganisationUnit::getStoredPath) .map(p -> "ou.path like '" + p + "%'") .collect(joining(" or "))); @@ -565,7 +565,7 @@ private void getDdvOrgUnits( where .append(sqlHelper.or()) .append("ou.path like '") - .append(parent.getPath()) + .append(parent.getStoredPath()) .append("%'"); } diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/function/FunctionOrgUnitAncestor.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/function/FunctionOrgUnitAncestor.java index 891620983f60..915df6787b65 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/function/FunctionOrgUnitAncestor.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/function/FunctionOrgUnitAncestor.java @@ -65,7 +65,7 @@ public Object evaluate(ExpressionParser.ExprContext ctx, CommonExpressionVisitor if (orgUnit != null) { for (TerminalNode uid : ctx.UID()) { - if (orgUnit.getPath().contains(uid.getText() + "/")) { + if (orgUnit.getStoredPath().contains(uid.getText() + "/")) { return true; } } diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/hibernate/HibernateOrganisationUnitStore.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/hibernate/HibernateOrganisationUnitStore.java index ce85602ee002..aff18bb99259 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/hibernate/HibernateOrganisationUnitStore.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/hibernate/HibernateOrganisationUnitStore.java @@ -186,7 +186,7 @@ public Long getOrganisationUnitHierarchyMemberCount( + ")"; Query query = getTypedQuery(hql); - query.setParameter("path", parent.getPath() + "%").setParameter("object", member); + query.setParameter("path", parent.getStoredPath() + "%").setParameter("object", member); return query.getSingleResult(); } @@ -244,7 +244,7 @@ public List getOrganisationUnits(OrganisationUnitQueryParams p if (params.hasParents()) { for (OrganisationUnit parent : params.getParents()) { - query.setParameter(parent.getUid(), parent.getPath() + "%"); + query.setParameter(parent.getUid(), parent.getStoredPath() + "%"); } } diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/dataset/JdbcCompleteDataSetRegistrationExchangeStore.java b/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/dataset/JdbcCompleteDataSetRegistrationExchangeStore.java index ddc97d992bf4..c67d8b3242f2 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/dataset/JdbcCompleteDataSetRegistrationExchangeStore.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/dataset/JdbcCompleteDataSetRegistrationExchangeStore.java @@ -272,7 +272,7 @@ private static String createOrgUnitClause( clause += params.getOrganisationUnits().stream() - .map(o -> " ou.path LIKE '" + o.getPath() + "%' OR ") + .map(o -> " ou.path LIKE '" + o.getStoredPath() + "%' OR ") .collect(Collectors.joining()); return TextUtils.removeLastOr(clause) + " ) "; diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/SpringDataValueSetStore.java b/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/SpringDataValueSetStore.java index 5f2213f268a4..594192de27d9 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/SpringDataValueSetStore.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/SpringDataValueSetStore.java @@ -289,7 +289,7 @@ private String getDataValueSql(DataExportParams params) { sql += "and ("; for (OrganisationUnit parent : params.getOrganisationUnits()) { - sql += "ou.path like '" + parent.getPath() + "%' or "; + sql += "ou.path like '" + parent.getStoredPath() + "%' or "; } sql = TextUtils.removeLastOr(sql) + ") "; diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetImportValidatorTest.java b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetImportValidatorTest.java index 6211873f78ba..90b7ba472ffd 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetImportValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetImportValidatorTest.java @@ -883,7 +883,7 @@ private DataValueContextBuilder createDataValueContext(DataValue dataValue) { ou.setUid(ouId); // we set the path here just for the tests. This is usually done by the persistence layer // but there is no interaction with that in these tests. - ou.setPath(ou.getPath()); + ou.updatePath(); builder.orgUnit(ou); } if (coId != null) { diff --git a/dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/predictor/PredictionDataValueFetcher.java b/dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/predictor/PredictionDataValueFetcher.java index 32411bd17e9c..0d433ae22556 100644 --- a/dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/predictor/PredictionDataValueFetcher.java +++ b/dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/predictor/PredictionDataValueFetcher.java @@ -207,7 +207,8 @@ public void init( this.outputDataElementOperand = outputDataElementOperand; orgUnitLookup = - orgUnits.stream().collect(Collectors.toMap(OrganisationUnit::getPath, Function.identity())); + orgUnits.stream() + .collect(Collectors.toMap(OrganisationUnit::getStoredPath, Function.identity())); dataElementLookup = dataElements.stream() .collect(toMap(DataElement::getId, Function.identity(), (de1, de2) -> de1)); @@ -359,7 +360,7 @@ private PredictionData getPredictionData( addValueToMap(dv, map); } - if (ddv.getSourcePath().equals(dv.getSource().getPath()) + if (ddv.getSourcePath().equals(dv.getSource().getStoredPath()) && ddv.getDataElementId() == outputDataElementOperand.getDataElement().getId() && (outputDataElementOperand.getCategoryOptionCombo() == null || ddv.getCategoryOptionComboId() diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/acl/DefaultTrackerAccessManager.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/acl/DefaultTrackerAccessManager.java index 9a9a18a5a491..d5d19148dd31 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/acl/DefaultTrackerAccessManager.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/acl/DefaultTrackerAccessManager.java @@ -282,7 +282,7 @@ public List canCreate( Program program = enrollment.getProgram(); List errors = new ArrayList<>(); OrganisationUnit ou = enrollment.getOrganisationUnit(); - if (ou != null && !user.isInUserHierarchy(ou.getPath())) { + if (ou != null && !user.isInUserHierarchy(ou.getStoredPath())) { errors.add("User has no create access to organisation unit: " + ou.getUid()); } @@ -336,7 +336,7 @@ public List canUpdate( } else { OrganisationUnit ou = enrollment.getOrganisationUnit(); - if (ou != null && !user.isInUserHierarchy(ou.getPath())) { + if (ou != null && !user.isInUserHierarchy(ou.getStoredPath())) { errors.add("User has no write access to organisation unit: " + ou.getUid()); } } @@ -371,7 +371,7 @@ public List canDelete( } } else { OrganisationUnit ou = enrollment.getOrganisationUnit(); - if (ou != null && !user.isInUserHierarchy(ou.getPath())) { + if (ou != null && !user.isInUserHierarchy(ou.getStoredPath())) { errors.add("User has no delete access to organisation unit: " + ou.getUid()); } } @@ -447,8 +447,8 @@ public List canCreate( if (ou != null) { boolean isInHierarchy = event.isCreatableInSearchScope() - ? user.isInUserEffectiveSearchOrgUnitHierarchy(ou.getPath()) - : user.isInUserHierarchy(ou.getPath()); + ? user.isInUserEffectiveSearchOrgUnitHierarchy(ou.getStoredPath()) + : user.isInUserHierarchy(ou.getStoredPath()); if (!isInHierarchy) { errors.add("User has no create access to organisation unit: " + ou.getUid()); @@ -493,7 +493,7 @@ public List canUpdate( canManageWithRegistration(errors, user, programStage, program); OrganisationUnit ou = event.getOrganisationUnit(); - if (ou != null && !user.isInUserEffectiveSearchOrgUnitHierarchy(ou.getPath())) { + if (ou != null && !user.isInUserEffectiveSearchOrgUnitHierarchy(ou.getStoredPath())) { errors.add("User has no update access to organisation unit: " + ou.getUid()); } @@ -528,7 +528,7 @@ public List canDelete( List errors = new ArrayList<>(); if (program.isWithoutRegistration()) { OrganisationUnit ou = event.getOrganisationUnit(); - if (ou != null && !user.isInUserHierarchy(ou.getPath())) { + if (ou != null && !user.isInUserHierarchy(ou.getStoredPath())) { errors.add("User has no delete access to organisation unit: " + ou.getUid()); } @@ -748,10 +748,10 @@ public boolean canAccess(@Nonnull UserDetails user, Program program, Organisatio } if (program != null && (program.isClosed() || program.isProtected())) { - return user.isInUserHierarchy(orgUnit.getPath()); + return user.isInUserHierarchy(orgUnit.getStoredPath()); } - return user.isInUserEffectiveSearchOrgUnitHierarchy(orgUnit.getPath()); + return user.isInUserEffectiveSearchOrgUnitHierarchy(orgUnit.getStoredPath()); } @Override diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/acl/DefaultTrackerOwnershipManager.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/acl/DefaultTrackerOwnershipManager.java index e7c7ebb2a8d1..068d619ce5d0 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/acl/DefaultTrackerOwnershipManager.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/acl/DefaultTrackerOwnershipManager.java @@ -226,7 +226,7 @@ public boolean hasAccess(UserDetails user, TrackedEntity trackedEntity, Program OrganisationUnit ou = getOwner(trackedEntity, program, trackedEntity::getOrganisationUnit); - final String orgUnitPath = ou.getPath(); + final String orgUnitPath = ou.getStoredPath(); return switch (program.getAccessLevel()) { case OPEN, AUDITED -> user.isInUserEffectiveSearchOrgUnitHierarchy(orgUnitPath); case PROTECTED -> @@ -243,7 +243,7 @@ public boolean hasAccess( return true; } - final String orgUnitPath = owningOrgUnit.getPath(); + final String orgUnitPath = owningOrgUnit.getStoredPath(); return switch (program.getAccessLevel()) { case OPEN, AUDITED -> user.isInUserEffectiveSearchOrgUnitHierarchy(orgUnitPath); case PROTECTED -> @@ -267,7 +267,7 @@ public boolean canSkipOwnershipCheck(UserDetails user, ProgramType programType) public boolean isOwnerInUserSearchScope( UserDetails user, TrackedEntity trackedEntity, Program program) { return user.isInUserSearchHierarchy( - getOwner(trackedEntity, program, trackedEntity::getOrganisationUnit).getPath()); + getOwner(trackedEntity, program, trackedEntity::getOrganisationUnit).getStoredPath()); } // ------------------------------------------------------------------------- diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/OperationsParamsValidator.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/OperationsParamsValidator.java index 26ef82f9ee46..03ebb2305160 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/OperationsParamsValidator.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/OperationsParamsValidator.java @@ -242,7 +242,8 @@ public Set validateOrgUnits(Set orgUnitIds, UserDetails u throw new BadRequestException("Organisation unit does not exist: " + orgUnitUid); } - if (!user.isSuper() && !user.isInUserEffectiveSearchOrgUnitHierarchy(orgUnit.getPath())) { + if (!user.isSuper() + && !user.isInUserEffectiveSearchOrgUnitHierarchy(orgUnit.getStoredPath())) { throw new ForbiddenException( "Organisation unit is not part of the search scope: " + orgUnit.getUid()); } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/enrollment/HibernateEnrollmentStore.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/enrollment/HibernateEnrollmentStore.java index d67e20076ef6..7a7612b0f459 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/enrollment/HibernateEnrollmentStore.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/enrollment/HibernateEnrollmentStore.java @@ -237,7 +237,7 @@ private String getDescendantsQuery(Set organisationUnits) { ouClause .append(orHlp.or()) .append("en.organisationUnit.path LIKE '") - .append(organisationUnit.getPath()) + .append(organisationUnit.getStoredPath()) .append("%'"); } @@ -252,7 +252,7 @@ private String getChildrenQuery(SqlHelper hlp, Set organisatio orgUnits .append(hlp.or()) .append("en.organisationUnit.path LIKE '") - .append(organisationUnit.getPath()) + .append(organisationUnit.getStoredPath()) .append("%'") .append(" AND (en.organisationUnit.hierarchyLevel = ") .append(organisationUnit.getHierarchyLevel()) diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapper.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapper.java index 76da7f7c71b8..de9898b5f70f 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapper.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapper.java @@ -175,7 +175,7 @@ private OrganisationUnit validateRequestedOrgUnit(String orgUnitUid, UserDetails "Organisation unit is specified but does not exist: " + orgUnitUid); } - if (!user.isInUserEffectiveSearchOrgUnitHierarchy(orgUnit.getPath())) { + if (!user.isInUserEffectiveSearchOrgUnitHierarchy(orgUnit.getStoredPath())) { throw new ForbiddenException( "Organisation unit is not part of your search scope: " + orgUnit.getUid()); } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/event/JdbcEventStore.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/event/JdbcEventStore.java index 2b5d9f11e8b6..a5518be292f0 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/event/JdbcEventStore.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/event/JdbcEventStore.java @@ -1195,7 +1195,7 @@ private String createAccessibleSql( private String createDescendantsSql( User user, EventQueryParams params, MapSqlParameterSource mapSqlParameterSource) { - mapSqlParameterSource.addValue(COLUMN_ORG_UNIT_PATH, params.getOrgUnit().getPath()); + mapSqlParameterSource.addValue(COLUMN_ORG_UNIT_PATH, params.getOrgUnit().getStoredPath()); if (isProgramRestricted(params.getProgram())) { return createCaptureScopeQuery( @@ -1208,7 +1208,7 @@ private String createDescendantsSql( private String createChildrenSql( User user, EventQueryParams params, MapSqlParameterSource mapSqlParameterSource) { - mapSqlParameterSource.addValue(COLUMN_ORG_UNIT_PATH, params.getOrgUnit().getPath()); + mapSqlParameterSource.addValue(COLUMN_ORG_UNIT_PATH, params.getOrgUnit().getStoredPath()); String customChildrenQuery = " and (ou.hierarchylevel = " @@ -1231,7 +1231,7 @@ private String createChildrenSql( private String createSelectedSql( User user, EventQueryParams params, MapSqlParameterSource mapSqlParameterSource) { - mapSqlParameterSource.addValue(COLUMN_ORG_UNIT_PATH, params.getOrgUnit().getPath()); + mapSqlParameterSource.addValue(COLUMN_ORG_UNIT_PATH, params.getOrgUnit().getStoredPath()); String orgUnitPathEqualsMatchQuery = " ou.path = :" diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/trackedentity/HibernateTrackedEntityStore.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/trackedentity/HibernateTrackedEntityStore.java index 948d63004212..a98de521046f 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/trackedentity/HibernateTrackedEntityStore.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/trackedentity/HibernateTrackedEntityStore.java @@ -685,7 +685,7 @@ private String getDescendantsQuery(TrackedEntityQueryParams params) { orgUnits .append(orHlp.or()) .append("OU.path LIKE '") - .append(organisationUnit.getPath()) + .append(organisationUnit.getStoredPath()) .append("%'"); } @@ -704,7 +704,7 @@ private String getChildrenQuery(TrackedEntityQueryParams params) { orgUnits .append(orHlp.or()) .append(" OU.path LIKE '") - .append(organisationUnit.getPath()) + .append(organisationUnit.getStoredPath()) .append("%'") .append(" AND (ou.hierarchylevel = ") .append(organisationUnit.getHierarchyLevel()) diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/SecurityOwnershipValidator.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/SecurityOwnershipValidator.java index 29934dfa8eba..bccfd613cf23 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/SecurityOwnershipValidator.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/SecurityOwnershipValidator.java @@ -32,7 +32,6 @@ import java.util.Map; import javax.annotation.Nonnull; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.hisp.dhis.common.UID; import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.program.Program; @@ -59,7 +58,6 @@ @Component( "org.hisp.dhis.tracker.imports.validation.validator.enrollment.SecurityOwnershipValidator") @RequiredArgsConstructor -@Slf4j class SecurityOwnershipValidator implements Validator { @Nonnull private final AclService aclService; @@ -170,7 +168,7 @@ public boolean needsToRun(TrackerImportStrategy strategy) { private void checkOrgUnitInCaptureScope( Reporter reporter, TrackerDto dto, OrganisationUnit orgUnit, UserDetails user) { - if (!user.isInUserHierarchy(orgUnit.getPath())) { + if (!user.isInUserHierarchy(orgUnit.getStoredPath())) { reporter.addError(dto, ValidationCode.E1000, user, orgUnit); } } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/event/SecurityOwnershipValidator.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/event/SecurityOwnershipValidator.java index 69e94d859633..60ee5c6e03d7 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/event/SecurityOwnershipValidator.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/event/SecurityOwnershipValidator.java @@ -33,7 +33,6 @@ import java.util.Map; import javax.annotation.Nonnull; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.hisp.dhis.category.CategoryOption; import org.hisp.dhis.category.CategoryOptionCombo; import org.hisp.dhis.common.UID; @@ -63,7 +62,6 @@ */ @Component("org.hisp.dhis.tracker.imports.validation.validator.event.SecurityOwnershipValidator") @RequiredArgsConstructor -@Slf4j class SecurityOwnershipValidator implements Validator { @Nonnull private final AclService aclService; @@ -295,9 +293,10 @@ private void checkEventOrgUnitWriteAccess( OrganisationUnit eventOrgUnit, boolean isCreatableInSearchScope, UserDetails user) { + String path = eventOrgUnit.getStoredPath(); if (isCreatableInSearchScope - ? !user.isInUserEffectiveSearchOrgUnitHierarchy(eventOrgUnit.getPath()) - : !user.isInUserHierarchy(eventOrgUnit.getPath())) { + ? !user.isInUserEffectiveSearchOrgUnitHierarchy(path) + : !user.isInUserHierarchy(path)) { reporter.addError(event, ValidationCode.E1000, user, eventOrgUnit); } } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/SecurityOwnershipValidator.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/SecurityOwnershipValidator.java index d69bd64581fc..1de1b8055817 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/SecurityOwnershipValidator.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/SecurityOwnershipValidator.java @@ -125,7 +125,7 @@ public boolean needsToRun(TrackerImportStrategy strategy) { private void checkOrgUnitInCaptureScope( Reporter reporter, TrackerDto dto, OrganisationUnit orgUnit, UserDetails user) { - if (!user.isInUserHierarchy(orgUnit.getPath())) { + if (!user.isInUserHierarchy(orgUnit.getStoredPath())) { reporter.addError(dto, ValidationCode.E1000, user, orgUnit); } } diff --git a/dhis-2/dhis-services/dhis-service-validation/src/main/java/org/hisp/dhis/minmax/hibernate/HibernateMinMaxDataElementStore.java b/dhis-2/dhis-services/dhis-service-validation/src/main/java/org/hisp/dhis/minmax/hibernate/HibernateMinMaxDataElementStore.java index 61e453207ba8..f7c977b97f07 100644 --- a/dhis-2/dhis-services/dhis-service-validation/src/main/java/org/hisp/dhis/minmax/hibernate/HibernateMinMaxDataElementStore.java +++ b/dhis-2/dhis-services/dhis-service-validation/src/main/java/org/hisp/dhis/minmax/hibernate/HibernateMinMaxDataElementStore.java @@ -177,7 +177,7 @@ public void delete(Collection dataElements, OrganisationUnit parent getQuery(hql) .setParameterList("dataElements", dataElements) - .setParameter("path", parent.getPath() + "%") + .setParameter("path", parent.getStoredPath() + "%") .executeUpdate(); } diff --git a/dhis-2/dhis-services/dhis-service-validation/src/main/java/org/hisp/dhis/outlierdetection/util/OutlierDetectionUtils.java b/dhis-2/dhis-services/dhis-service-validation/src/main/java/org/hisp/dhis/outlierdetection/util/OutlierDetectionUtils.java index a6e9c6321960..da8852edffe1 100644 --- a/dhis-2/dhis-services/dhis-service-validation/src/main/java/org/hisp/dhis/outlierdetection/util/OutlierDetectionUtils.java +++ b/dhis-2/dhis-services/dhis-service-validation/src/main/java/org/hisp/dhis/outlierdetection/util/OutlierDetectionUtils.java @@ -63,7 +63,10 @@ public static String getOrgUnitPathClause(List orgUnits, Strin StringBuilder sql = new StringBuilder("("); orgUnits.forEach( ou -> - sql.append(pathAlias).append(".\"path\" like '").append(ou.getPath()).append("%' or ")); + sql.append(pathAlias) + .append(".\"path\" like '") + .append(ou.getStoredPath()) + .append("%' or ")); return StringUtils.trim(TextUtils.removeLastOr(sql.toString())) + ")"; } diff --git a/dhis-2/dhis-services/dhis-service-validation/src/main/java/org/hisp/dhis/validation/hibernate/HibernateValidationResultStore.java b/dhis-2/dhis-services/dhis-service-validation/src/main/java/org/hisp/dhis/validation/hibernate/HibernateValidationResultStore.java index 284d5c7076bc..c561f52dfa5c 100644 --- a/dhis-2/dhis-services/dhis-service-validation/src/main/java/org/hisp/dhis/validation/hibernate/HibernateValidationResultStore.java +++ b/dhis-2/dhis-services/dhis-service-validation/src/main/java/org/hisp/dhis/validation/hibernate/HibernateValidationResultStore.java @@ -205,7 +205,8 @@ public List getValidationResults( + "vr.validationRule in :validationRules and vr.period in :periods "); if (orgUnit != null) { - query.setParameter("orgUnitPath", orgUnit.getPath() + (includeOrgUnitDescendants ? "%" : "")); + query.setParameter( + "orgUnitPath", orgUnit.getStoredPath() + (includeOrgUnitDescendants ? "%" : "")); } query.setParameter("validationRules", validationRules); diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/organisationunit/OrganisationUnitServiceTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/organisationunit/OrganisationUnitServiceTest.java index ee364855fc4d..341c32c8a7c9 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/organisationunit/OrganisationUnitServiceTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/organisationunit/OrganisationUnitServiceTest.java @@ -959,6 +959,22 @@ void testGetParentGraph() { assertEquals(expected, ouD.getParentGraph(Sets.newHashSet(ouB))); } + @Test + void testGetStoredPath() { + OrganisationUnit ouA = createOrganisationUnit('A'); + OrganisationUnit ouB = createOrganisationUnit('B', ouA); + OrganisationUnit ouC = createOrganisationUnit('C', ouB); + organisationUnitService.addOrganisationUnit(ouA); + organisationUnitService.addOrganisationUnit(ouB); + organisationUnitService.addOrganisationUnit(ouC); + String expectedA = String.format("/%s", ouA.getUid()); + String expectedB = String.format("/%s/%s", ouA.getUid(), ouB.getUid()); + String expectedC = String.format("/%s/%s/%s", ouA.getUid(), ouB.getUid(), ouC.getUid()); + assertEquals(expectedA, ouA.getStoredPath()); + assertEquals(expectedB, ouB.getStoredPath()); + assertEquals(expectedC, ouC.getStoredPath()); + } + @Test void testSaveImage() { byte[] content = "<>".getBytes(); diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataAnalysisController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataAnalysisController.java index c2a674756fc2..efa85a4d88a6 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataAnalysisController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataAnalysisController.java @@ -672,7 +672,7 @@ private List validationResultsListToResponse( if (organisationUnit != null) { validationResultView.setOrganisationUnitId(organisationUnit.getUid()); validationResultView.setOrganisationUnitDisplayName(organisationUnit.getDisplayName()); - validationResultView.setOrganisationUnitPath(organisationUnit.getPath()); + validationResultView.setOrganisationUnitPath(organisationUnit.getStoredPath()); validationResultView.setOrganisationUnitAncestorNames(organisationUnit.getAncestorNames()); } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/LockExceptionController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/LockExceptionController.java index da710c5fb24a..267c87f86c68 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/LockExceptionController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/LockExceptionController.java @@ -301,6 +301,6 @@ private boolean canCapture(OrganisationUnit captureTarget) { User currentUser = userService.getUserByUsername(CurrentUserUtil.getCurrentUsername()); return currentUser.isSuper() || currentUser.getOrganisationUnits().stream() - .anyMatch(ou -> captureTarget.getPath().startsWith(ou.getPath())); + .anyMatch(ou -> captureTarget.getStoredPath().startsWith(ou.getStoredPath())); } } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/organisationunit/OrganisationUnitController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/organisationunit/OrganisationUnitController.java index 6d6ca6fdffae..2265cbae802b 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/organisationunit/OrganisationUnitController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/organisationunit/OrganisationUnitController.java @@ -252,7 +252,8 @@ Limits results to organisation units on the given level or above (absolute start @CurrentUser UserDetails currentUser) throws ForbiddenException, BadRequestException, NotFoundException, ConflictException { OrganisationUnit parent = getEntity(uid); - List childrenWithLevel = List.of(like("path", parent.getPath(), MatchMode.START)); + List childrenWithLevel = + List.of(like("path", parent.getStoredPath(), MatchMode.START)); params.setParentLevel(parent.getLevel()); return getObjectListWith(params, response, currentUser, childrenWithLevel); } @@ -300,7 +301,7 @@ Limits results to organisation units on the given level or above (absolute start @CurrentUser UserDetails currentUser) throws ForbiddenException, BadRequestException, NotFoundException, ConflictException { OrganisationUnit root = getEntity(uid); - List ancestorsIds = List.of(root.getPath().split("/")); + List ancestorsIds = List.of(root.getStoredPath().split("/")); List ancestorPaths = new ArrayList<>(); for (int i = 0; i < ancestorsIds.size(); i++) ancestorPaths.add(Restrictions.eq("path", String.join("/", ancestorsIds.subList(0, i + 1)))); @@ -321,7 +322,7 @@ Limits results to organisation units on the given level or above (absolute start // when parent is root => no matches by adding an impossible in filter if (parent.getLevel() == 1) return getObjectListWith(params, response, currentUser, List.of(in("id", List.of()))); - List ancestorsIds = List.of(parent.getPath().split("/")); + List ancestorsIds = List.of(parent.getStoredPath().split("/")); List parentPaths = new ArrayList<>(); for (int i = 0; i < ancestorsIds.size() - 1; i++) parentPaths.add(Restrictions.eq("path", String.join("/", ancestorsIds.subList(0, i + 1))));