From c5a6a4cbaee05147e0482eb55b26237b397c621b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Helge=20=C3=98verland?= Date: Tue, 7 Jan 2025 12:55:03 +0100 Subject: [PATCH 01/11] fix: Make analytics driver class config optional [DHIS2-18417] (#19610) --- .../dhis/external/conf/ConfigurationKey.java | 3 +- .../dhis-support-hibernate/pom.xml | 4 ++ .../config/AnalyticsDataSourceConfig.java | 42 +++++++++++++++++-- .../dhis/db/init/AnalyticsDatabaseInit.java | 7 +++- .../dhis/db/sql/ClickHouseSqlBuilder.java | 10 ----- .../org/hisp/dhis/db/sql/DorisSqlBuilder.java | 11 ++++- .../hisp/dhis/db/sql/PostgreSqlBuilder.java | 10 ----- .../java/org/hisp/dhis/db/sql/SqlBuilder.java | 13 ------ 8 files changed, 58 insertions(+), 42 deletions(-) diff --git a/dhis-2/dhis-support/dhis-support-external/src/main/java/org/hisp/dhis/external/conf/ConfigurationKey.java b/dhis-2/dhis-support/dhis-support-external/src/main/java/org/hisp/dhis/external/conf/ConfigurationKey.java index 1fcfe101b848..44dbad2efb45 100644 --- a/dhis-2/dhis-support/dhis-support-external/src/main/java/org/hisp/dhis/external/conf/ConfigurationKey.java +++ b/dhis-2/dhis-support/dhis-support-external/src/main/java/org/hisp/dhis/external/conf/ConfigurationKey.java @@ -100,8 +100,7 @@ public enum ConfigurationKey { CONNECTION_DRIVER_CLASS("connection.driver_class", "org.postgresql.Driver", false), /** Analytics JDBC driver class. */ - ANALYTICS_CONNECTION_DRIVER_CLASS( - "analytics.connection.driver_class", "org.postgresql.Driver", false), + ANALYTICS_CONNECTION_DRIVER_CLASS("analytics.connection.driver_class", "", false), /** Database connection URL. */ CONNECTION_URL("connection.url", "", false), diff --git a/dhis-2/dhis-support/dhis-support-hibernate/pom.xml b/dhis-2/dhis-support/dhis-support-hibernate/pom.xml index 2a818f633722..b7c274dbca11 100644 --- a/dhis-2/dhis-support/dhis-support-hibernate/pom.xml +++ b/dhis-2/dhis-support/dhis-support-hibernate/pom.xml @@ -31,6 +31,10 @@ org.hisp.dhis dhis-support-commons + + org.hisp.dhis + dhis-support-sql + diff --git a/dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/config/AnalyticsDataSourceConfig.java b/dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/config/AnalyticsDataSourceConfig.java index dee98ba58e5a..468a6ff711bd 100644 --- a/dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/config/AnalyticsDataSourceConfig.java +++ b/dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/config/AnalyticsDataSourceConfig.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.config; +import static org.apache.commons.lang3.StringUtils.isBlank; import static org.hisp.dhis.config.DataSourceConfig.createLoggingDataSource; import static org.hisp.dhis.datasource.DatabasePoolUtils.ConfigKeyMapper.ANALYTICS; import static org.hisp.dhis.external.conf.ConfigurationKey.ANALYTICS_CONNECTION_URL; @@ -43,6 +44,8 @@ import org.hisp.dhis.datasource.DatabasePoolUtils; import org.hisp.dhis.datasource.ReadOnlyDataSourceManager; import org.hisp.dhis.datasource.model.DbPoolConfig; +import org.hisp.dhis.db.model.Database; +import org.hisp.dhis.db.setting.SqlBuilderSettings; import org.hisp.dhis.external.conf.ConfigurationKey; import org.hisp.dhis.external.conf.DhisConfigurationProvider; import org.springframework.beans.factory.annotation.Qualifier; @@ -61,6 +64,8 @@ public class AnalyticsDataSourceConfig { private final DhisConfigurationProvider config; + private final SqlBuilderSettings sqlBuilderSettings; + @Bean("analyticsDataSource") @DependsOn("analyticsActualDataSource") public DataSource jdbcDataSource( @@ -126,11 +131,17 @@ public JdbcTemplate jdbcTemplate(@Qualifier("analyticsDataSource") DataSource da * @return a {@link DataSource}. */ private DataSource getAnalyticsDataSource() { - String jdbcUrl = config.getProperty(ANALYTICS_CONNECTION_URL); - String dbPoolType = config.getProperty(ConfigurationKey.DB_POOL_TYPE); + final String jdbcUrl = config.getProperty(ANALYTICS_CONNECTION_URL); + final String driverClassName = inferDriverClassName(); + final String dbPoolType = config.getProperty(ConfigurationKey.DB_POOL_TYPE); DbPoolConfig poolConfig = - DbPoolConfig.builder().dhisConfig(config).mapper(ANALYTICS).dbPoolType(dbPoolType).build(); + DbPoolConfig.builder() + .driverClassName(driverClassName) + .dhisConfig(config) + .mapper(ANALYTICS) + .dbPoolType(dbPoolType) + .build(); try { return DatabasePoolUtils.createDbPool(poolConfig); @@ -157,4 +168,29 @@ private JdbcTemplate getJdbcTemplate(DataSource dataSource) { jdbcTemplate.setFetchSize(FETCH_SIZE); return jdbcTemplate; } + + /** + * If the driver class name is not explicitly specified, returns the driver class name based on + * the the specified analytics database. + * + * @return a driver class name. + */ + private String inferDriverClassName() { + String driverClass = config.getProperty(ConfigurationKey.ANALYTICS_CONNECTION_DRIVER_CLASS); + return isBlank(driverClass) ? getDriverClassName() : driverClass; + } + + /** + * Returns a driver class name based on the specified analytics database. + * + * @return a driver class name. + */ + private String getDriverClassName() { + final Database database = sqlBuilderSettings.getAnalyticsDatabase(); + return switch (database) { + case POSTGRESQL -> org.postgresql.Driver.class.getName(); + case DORIS -> com.mysql.cj.jdbc.Driver.class.getName(); + case CLICKHOUSE -> com.clickhouse.jdbc.ClickHouseDriver.class.getName(); + }; + } } diff --git a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/init/AnalyticsDatabaseInit.java b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/init/AnalyticsDatabaseInit.java index 1bce670ce479..51de3c92b81e 100644 --- a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/init/AnalyticsDatabaseInit.java +++ b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/init/AnalyticsDatabaseInit.java @@ -37,6 +37,7 @@ import org.hisp.dhis.db.model.Database; import org.hisp.dhis.db.setting.SqlBuilderSettings; import org.hisp.dhis.db.sql.ClickHouseSqlBuilder; +import org.hisp.dhis.db.sql.DorisSqlBuilder; import org.hisp.dhis.db.sql.SqlBuilder; import org.hisp.dhis.external.conf.ConfigurationKey; import org.hisp.dhis.external.conf.DhisConfigurationProvider; @@ -112,8 +113,10 @@ private void createDorisJdbcCatalog() { String username = config.getProperty(ConfigurationKey.CONNECTION_USERNAME); String password = config.getProperty(ConfigurationKey.CONNECTION_PASSWORD); - jdbcTemplate.execute(sqlBuilder.dropCatalogIfExists()); - jdbcTemplate.execute(sqlBuilder.createCatalog(connectionUrl, username, password)); + DorisSqlBuilder dorisSqlBuilder = (DorisSqlBuilder) sqlBuilder; + + jdbcTemplate.execute(dorisSqlBuilder.dropCatalogIfExists()); + jdbcTemplate.execute(dorisSqlBuilder.createCatalog(connectionUrl, username, password)); } /** diff --git a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/ClickHouseSqlBuilder.java b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/ClickHouseSqlBuilder.java index 4cb4e0bec09e..ad833fc9cdeb 100644 --- a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/ClickHouseSqlBuilder.java +++ b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/ClickHouseSqlBuilder.java @@ -374,16 +374,6 @@ public String createIndex(Index index) { return notSupported(); } - @Override - public String createCatalog(String connectionUrl, String username, String password) { - return notSupported(); - } - - @Override - public String dropCatalogIfExists() { - return notSupported(); - } - /** * @param name the collection name. * @param keyValues the map of key value pairs. diff --git a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/DorisSqlBuilder.java b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/DorisSqlBuilder.java index fac63f30672e..82148772e259 100644 --- a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/DorisSqlBuilder.java +++ b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/DorisSqlBuilder.java @@ -444,7 +444,12 @@ public String createIndex(Index index) { return notSupported(); } - @Override + /** + * @param connectionUrl the JDBC connection URL. + * @param username the JDBC connection username. + * @param password the JDBC connection password. + * @return a create catalog statement. + */ public String createCatalog(String connectionUrl, String username, String password) { return replace( """ @@ -465,7 +470,9 @@ public String createCatalog(String connectionUrl, String username, String passwo "driver_filename", driverFilename)); } - @Override + /** + * @return a drop catalog if exists statement. + */ public String dropCatalogIfExists() { return String.format("drop catalog if exists %s;", quote(catalog)); } diff --git a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/PostgreSqlBuilder.java b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/PostgreSqlBuilder.java index 9c18e3c45fe9..56c6b54548a3 100644 --- a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/PostgreSqlBuilder.java +++ b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/PostgreSqlBuilder.java @@ -432,14 +432,4 @@ unique, quote(index.getName()), quote(tableName), typeName, columns) "create %sindex %s on %s using %s(%s %s);", unique, quote(index.getName()), quote(tableName), typeName, columns, sortOrder); } - - @Override - public String createCatalog(String connectionUrl, String username, String password) { - return notSupported(); - } - - @Override - public String dropCatalogIfExists() { - return notSupported(); - } } diff --git a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/SqlBuilder.java b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/SqlBuilder.java index b0e22acac09b..cc9c5d89480f 100644 --- a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/SqlBuilder.java +++ b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/SqlBuilder.java @@ -484,19 +484,6 @@ String ifThenElse( */ String insertIntoSelectFrom(Table intoTable, String fromTable); - /** - * @param connectionUrl the JDBC connection URL. - * @param username the JDBC connection username. - * @param password the JDBC connection password. - * @return a create catalog statement. - */ - String createCatalog(String connectionUrl, String username, String password); - - /** - * @return a drop catalog if exists statement. - */ - String dropCatalogIfExists(); - /** Enumeration of time units. */ enum DateUnit { DAYS, From 68dac3a3ccfc3b02f3fd990ef0a8f70cca653dfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Helge=20=C3=98verland?= Date: Wed, 8 Jan 2025 16:17:37 +0100 Subject: [PATCH 02/11] chore: Remove unused code (#19623) --- .../hisp/dhis/category/CategoryService.java | 25 ----- .../dhis/dataelement/DataElementService.java | 55 --------- .../dhis/dataelement/DataElementStore.java | 25 ----- .../org/hisp/dhis/dataset/DataSetService.java | 9 -- .../org/hisp/dhis/dataset/DataSetStore.java | 14 --- .../organisationunit/OrganisationUnit.java | 2 +- .../OrganisationUnitService.java | 15 --- .../OrganisationUnitStore.java | 35 +----- .../dhis/category/DefaultCategoryService.java | 39 ------- .../DefaultDataElementService.java | 68 ------------ .../hibernate/HibernateDataElementStore.java | 32 ------ .../dhis/dataset/DefaultDataSetService.java | 7 -- .../hibernate/HibernateDataSetStore.java | 15 --- .../DefaultOrganisationUnitService.java | 43 -------- .../HibernateOrganisationUnitStore.java | 104 ------------------ .../DefaultDataSetMetadataExportService.java | 3 - .../dhis/category/CategoryServiceTest.java | 28 ----- .../dataelement/DataElementServiceTest.java | 25 ----- .../dataelement/DataElementStoreTest.java | 38 ------- .../hisp/dhis/dataset/DataSetStoreTest.java | 11 -- 20 files changed, 5 insertions(+), 588 deletions(-) diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/category/CategoryService.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/category/CategoryService.java index 01286d776196..1e1609a6b141 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/category/CategoryService.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/category/CategoryService.java @@ -110,13 +110,6 @@ public interface CategoryService { */ Category getCategoryByName(String name, UserDetails userDetails); - /** - * Returns all DataElementCategories. - * - * @return a list of all DataElementCategories. - */ - List getAllDataElementCategories(); - /** * Retrieves all DataElementCategories of dimension type disaggregation. * @@ -330,24 +323,6 @@ SetValuedMap getCategoryOptionOrganisationUnitsAssociations( */ List getAttributeCategoryCombos(); - /** - * Validates the category combo. Possible return values are: - * - *

- * - *

    - *
  • category_combo_is_null - *
  • category_combo_must_have_at_least_one_category - *
  • category_combo_cannot_have_duplicate_categories - *
  • categories_must_have_at_least_one_category_option - *
  • categories_cannot_share_category_options - *
- * - * @param categoryCombo the category combo to validate. - * @return null if valid, non-empty string if invalid. - */ - String validateCategoryCombo(CategoryCombo categoryCombo); - // ------------------------------------------------------------------------- // CategoryOptionCombo // ------------------------------------------------------------------------- diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementService.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementService.java index 9d05b329c1a5..7dd807f2bc38 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementService.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementService.java @@ -30,12 +30,8 @@ import java.util.Collection; import java.util.List; import javax.annotation.Nonnull; -import org.hisp.dhis.category.CategoryCombo; import org.hisp.dhis.common.IllegalQueryException; -import org.hisp.dhis.common.UID; -import org.hisp.dhis.common.ValueType; import org.hisp.dhis.hierarchy.HierarchyViolationException; -import org.hisp.dhis.period.PeriodType; /** * Defines service functionality for DataElements and DataElementGroups. @@ -110,39 +106,6 @@ public interface DataElementService { */ List getAllDataElements(); - /** - * Returns all DataElements of a given type. - * - * @param valueType the value type restriction - * @return a list of all DataElements with the given value type, or an empty list if there are no - * DataElements. - */ - List getAllDataElementsByValueType(ValueType valueType); - - /** - * Returns all DataElements with the given domain type. - * - * @param domainType the DataElementDomainType. - * @return all DataElements with the given domainType. - */ - List getDataElementsByDomainType(DataElementDomain domainType); - - /** - * Returns the DataElements with the given PeriodType. - * - * @param periodType the PeriodType. - * @return a list of DataElements. - */ - List getDataElementsByPeriodType(PeriodType periodType); - - /** - * Returns all DataElements with the given category combo. - * - * @param categoryCombo the CategoryCombo. - * @return all DataElements with the given category combo. - */ - List getDataElementByCategoryCombo(CategoryCombo categoryCombo); - /** * Returns all DataElements which are not member of any DataElementGroups. * @@ -246,14 +209,6 @@ public interface DataElementService { */ List getAllDataElementGroups(); - /** - * Returns all DataElements which zeroIsSignificant property is true or false. - * - * @param zeroIsSignificant whether zero is significant is true for this query. - * @return a collection of DataElements. - */ - List getDataElementsByZeroIsSignificant(boolean zeroIsSignificant); - // ------------------------------------------------------------------------- // DataElementGroupSet // ------------------------------------------------------------------------- @@ -267,14 +222,4 @@ public interface DataElementService { DataElementGroupSet getDataElementGroupSet(long id); DataElementGroupSet getDataElementGroupSet(String uid); - - DataElementGroupSet getDataElementGroupSetByName(String name); - - List getAllDataElementGroupSets(); - - List getByAttributeAndValue(UID attribute, String value); - - List getByAttribute(UID attribute); - - DataElement getByUniqueAttributeValue(UID attribute, String value); } diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementStore.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementStore.java index d82afe928b27..8065ad0a3f81 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementStore.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementStore.java @@ -30,7 +30,6 @@ import java.util.List; import org.hisp.dhis.category.CategoryCombo; import org.hisp.dhis.common.GenericDimensionalObjectStore; -import org.hisp.dhis.common.ValueType; import org.hisp.dhis.user.User; /** @@ -53,30 +52,6 @@ public interface DataElementStore extends GenericDimensionalObjectStore getDataElementByCategoryCombo(CategoryCombo categoryCombo); - /** - * Returns all DataElement which zeroIsSignificant property is true or false - * - * @param zeroIsSignificant is zeroIsSignificant property - * @return a collection of all DataElement - */ - List getDataElementsByZeroIsSignificant(boolean zeroIsSignificant); - - /** - * Returns all DataElements of the given domain type. - * - * @param domainType the domain type. - * @return all DataElements of the given domain type. - */ - List getDataElementsByDomainType(DataElementDomain domainType); - - /** - * Returns all DataElements of the given value type. - * - * @param valueType the value type. - * @return all DataElements of the given value type. - */ - List getDataElementsByValueType(ValueType valueType); - /** * Returns all DataElements which are not member of any DataElementGroups. * diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSetService.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSetService.java index b79d9218cd38..9cc80d7be245 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSetService.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSetService.java @@ -35,7 +35,6 @@ import org.hisp.dhis.dataentryform.DataEntryForm; import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.period.Period; -import org.hisp.dhis.period.PeriodType; import org.hisp.dhis.user.User; import org.hisp.dhis.user.UserDetails; @@ -108,14 +107,6 @@ public interface DataSetService extends DataSetDataIntegrityProvider { */ List getAllDataSets(); - /** - * Gets all DataSets associated with the given PeriodType. - * - * @param periodType the PeriodType. - * @return a list of DataSets. - */ - List getDataSetsByPeriodType(PeriodType periodType); - /** * Returns the data sets which given user have READ access. If the current user has the ALL * authority then all data sets are returned. diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSetStore.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSetStore.java index b2f4de66224d..c777c3d592c0 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSetStore.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSetStore.java @@ -32,26 +32,12 @@ import org.hisp.dhis.common.IdentifiableObjectStore; import org.hisp.dhis.dataelement.DataElement; import org.hisp.dhis.dataentryform.DataEntryForm; -import org.hisp.dhis.period.PeriodType; /** * @author Kristian Nordal */ public interface DataSetStore extends IdentifiableObjectStore, DataSetDataIntegrityProvider { - String ID = DataSetStore.class.getName(); - - // ------------------------------------------------------------------------- - // DataSet - // ------------------------------------------------------------------------- - - /** - * Gets all DataSets associated with the given PeriodType. - * - * @param periodType the PeriodType. - * @return a list of DataSets. - */ - List getDataSetsByPeriodType(PeriodType periodType); /** * Gets all DataSets associated with the given DataEntryForm. 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 b64446845041..a15fa029b590 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 @@ -136,7 +136,7 @@ public class OrganisationUnit extends BaseDimensionalItemObject private Geometry geometry; - /** A reference to the Image file associated with this OrganisationUnit. */ + /** A reference to the image file resource associated with this {@link OrganisationUnit}. */ private FileResource image; // ------------------------------------------------------------------------- diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitService.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitService.java index 5b3dde26e685..07a740575b23 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitService.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitService.java @@ -307,8 +307,6 @@ List getOrganisationUnitsAtLevels( Long getOrganisationUnitHierarchyMemberCount( OrganisationUnit parent, Object member, String collectionName) throws BadRequestException; - OrganisationUnitDataSetAssociationSet getOrganisationUnitDataSetAssociationSet(User user); - /** * Returns the level of the given org unit level. The level parameter string can either represent * a numerical level, or a UID referring to an {@link OrganisationUnitLevel} object. @@ -385,19 +383,6 @@ List getOrganisationUnitByCoordinate( @Deprecated(forRemoval = true) boolean isInUserDataViewHierarchy(User user, OrganisationUnit organisationUnit); - /** - * Equal to {@link OrganisationUnitService#isInUserSearchHierarchy(User, OrganisationUnit)} except - * adds a caching layer on top. Use this method when performance is imperative and the risk of a - * stale result is tolerable. - * - * @param user the user to check for. - * @param organisationUnit the organisation unit. - * @return true if the given organisation unit is part of the hierarchy. - * @deprecated Use {@link org.hisp.dhis.user.UserDetails#isInUserSearchHierarchy(String)} instead - */ - @Deprecated(forRemoval = true) - boolean isInUserSearchHierarchyCached(User user, OrganisationUnit organisationUnit); - /** * @deprecated Use {@link org.hisp.dhis.user.UserDetails#isInUserSearchHierarchy(String)} instead */ diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitStore.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitStore.java index f35af4770f09..fa0df1fcecd5 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitStore.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitStore.java @@ -30,8 +30,6 @@ import java.util.Collection; import java.util.Date; import java.util.List; -import java.util.Map; -import java.util.Set; import org.hisp.dhis.common.IdentifiableObjectStore; import org.hisp.dhis.dataset.DataSet; import org.hisp.dhis.program.Program; @@ -130,18 +128,6 @@ Long getOrganisationUnitHierarchyMemberCount( */ List getOrganisationUnits(OrganisationUnitQueryParams params); - /** - * Creates a mapping between organisation unit UID and set of data set UIDs being assigned to the - * organisation unit. - * - * @param organisationUnits the parent organisation units of the hierarchy to include, ignored if - * null. - * @param dataSets the data set to include, ignored if null. - * @return a map of sets. - */ - Map> getOrganisationUnitDataSetAssocationMap( - Collection organisationUnits, Collection dataSets); - /** * Retrieves the objects where its coordinate is within the 4 area points. 4 area points are Index * 0: Maximum latitude (north edge of box shape) Index 1: Maxium longitude (east edge of box @@ -153,8 +139,10 @@ Map> getOrganisationUnitDataSetAssocationMap( */ List getWithinCoordinateArea(double[] box); + /** Updates the path property of all org units. */ void updatePaths(); + /** Explicitly updates the path property of all org units. */ void forceUpdatePaths(); /** @@ -166,25 +154,10 @@ Map> getOrganisationUnitDataSetAssocationMap( int getMaxLevel(); /** - * Check if the number of orgunits that satisfies the conditions in the queryParams is greater - * than the threshold provided. Note: groups, maxLevels and levels are not supported yet. + * Sets the geometry field for org units to null. * - * @param params The Org unit query params - * @param threshold the threshold count to check against - * @return true if the org units satisfying the params criteria is above the threshold, false - * otherwise. + * @return then number of affected org units. */ - boolean isOrgUnitCountAboveThreshold(OrganisationUnitQueryParams params, int threshold); - - /** - * Get list of organisation unit uids satisfying the query params. Note: groups, maxLevels and - * levels are not supported yet. - * - * @param params The Org unit query params - * @return the list of org unit uids satisfying the params criteria - */ - List getOrganisationUnitUids(OrganisationUnitQueryParams params); - int updateAllOrganisationUnitsGeometryToNull(); /** diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/category/DefaultCategoryService.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/category/DefaultCategoryService.java index 14a2873596f1..5de0e136c343 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/category/DefaultCategoryService.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/category/DefaultCategoryService.java @@ -28,7 +28,6 @@ package org.hisp.dhis.category; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -132,12 +131,6 @@ public void deleteCategory(Category dataElementCategory) { categoryStore.delete(dataElementCategory); } - @Override - @Transactional(readOnly = true) - public List getAllDataElementCategories() { - return categoryStore.getAll(); - } - @Override @Transactional(readOnly = true) public Category getCategory(long id) { @@ -421,38 +414,6 @@ public List getAttributeCategoryCombos() { return categoryComboStore.getCategoryCombosByDimensionType(DataDimensionType.ATTRIBUTE); } - @Override - @Transactional(readOnly = true) - public String validateCategoryCombo(CategoryCombo categoryCombo) { - if (categoryCombo == null) { - return "category_combo_is_null"; - } - - if (categoryCombo.getCategories() == null || categoryCombo.getCategories().isEmpty()) { - return "category_combo_must_have_at_least_one_category"; - } - - if (Sets.newHashSet(categoryCombo.getCategories()).size() - < categoryCombo.getCategories().size()) { - return "category_combo_cannot_have_duplicate_categories"; - } - - Set categoryOptions = new HashSet<>(); - - for (Category category : categoryCombo.getCategories()) { - if (category == null || category.getCategoryOptions().isEmpty()) { - return "categories_must_have_at_least_one_category_option"; - } - - if (!Sets.intersection(categoryOptions, Sets.newHashSet(category.getCategoryOptions())) - .isEmpty()) { - return "categories_cannot_share_category_options"; - } - } - - return null; - } - // ------------------------------------------------------------------------- // CategoryOptionCombo // ------------------------------------------------------------------------- diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementService.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementService.java index c37fa43fee1a..2894c1d670a9 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementService.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementService.java @@ -29,20 +29,16 @@ import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; import javax.annotation.Nonnull; import lombok.RequiredArgsConstructor; -import org.hisp.dhis.category.CategoryCombo; import org.hisp.dhis.common.GenericDimensionalObjectStore; import org.hisp.dhis.common.IdentifiableObjectStore; import org.hisp.dhis.common.IllegalQueryException; -import org.hisp.dhis.common.UID; import org.hisp.dhis.common.ValueType; import org.hisp.dhis.feedback.ErrorCode; import org.hisp.dhis.feedback.ErrorMessage; import org.hisp.dhis.option.Option; import org.hisp.dhis.option.OptionSet; -import org.hisp.dhis.period.PeriodType; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -142,38 +138,6 @@ public List getAllDataElements() { return dataElementStore.getAll(); } - @Override - @Transactional(readOnly = true) - public List getAllDataElementsByValueType(ValueType valueType) { - return dataElementStore.getDataElementsByValueType(valueType); - } - - @Override - @Transactional(readOnly = true) - public List getDataElementsByZeroIsSignificant(boolean zeroIsSignificant) { - return dataElementStore.getDataElementsByZeroIsSignificant(zeroIsSignificant); - } - - @Override - @Transactional(readOnly = true) - public List getDataElementsByPeriodType(final PeriodType periodType) { - return getAllDataElements().stream() - .filter(p -> p.getPeriodType() != null && p.getPeriodType().equals(periodType)) - .collect(Collectors.toList()); - } - - @Override - @Transactional(readOnly = true) - public List getDataElementsByDomainType(DataElementDomain domainType) { - return dataElementStore.getDataElementsByDomainType(domainType); - } - - @Override - @Transactional(readOnly = true) - public List getDataElementByCategoryCombo(CategoryCombo categoryCombo) { - return dataElementStore.getDataElementByCategoryCombo(categoryCombo); - } - @Override @Transactional(readOnly = true) public List getDataElementsWithoutGroups() { @@ -295,36 +259,4 @@ public DataElementGroupSet getDataElementGroupSet(long id) { public DataElementGroupSet getDataElementGroupSet(String uid) { return dataElementGroupSetStore.getByUid(uid); } - - @Override - @Transactional(readOnly = true) - public DataElementGroupSet getDataElementGroupSetByName(String name) { - List dataElementGroupSets = dataElementGroupSetStore.getAllEqName(name); - - return !dataElementGroupSets.isEmpty() ? dataElementGroupSets.get(0) : null; - } - - @Override - @Transactional(readOnly = true) - public List getAllDataElementGroupSets() { - return dataElementGroupSetStore.getAll(); - } - - @Override - @Transactional(readOnly = true) - public List getByAttributeAndValue(UID attribute, String value) { - return dataElementStore.getByAttributeAndValue(attribute, value); - } - - @Override - @Transactional(readOnly = true) - public List getByAttribute(UID attribute) { - return dataElementStore.getByAttribute(attribute); - } - - @Override - @Transactional(readOnly = true) - public DataElement getByUniqueAttributeValue(UID attribute, String value) { - return dataElementStore.getByUniqueAttributeValue(attribute, value); - } } diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/hibernate/HibernateDataElementStore.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/hibernate/HibernateDataElementStore.java index d271ac4f22ee..0c29da27e7b2 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/hibernate/HibernateDataElementStore.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/hibernate/HibernateDataElementStore.java @@ -33,9 +33,7 @@ import jakarta.persistence.criteria.Root; import java.util.List; import java.util.function.Function; -import lombok.extern.slf4j.Slf4j; import org.hisp.dhis.category.CategoryCombo; -import org.hisp.dhis.common.ValueType; import org.hisp.dhis.common.hibernate.HibernateIdentifiableObjectStore; import org.hisp.dhis.dataelement.DataElement; import org.hisp.dhis.dataelement.DataElementDomain; @@ -51,7 +49,6 @@ /** * @author Torgeir Lorange Ostby */ -@Slf4j @Repository("org.hisp.dhis.dataelement.DataElementStore") public class HibernateDataElementStore extends HibernateIdentifiableObjectStore implements DataElementStore { @@ -67,24 +64,6 @@ public HibernateDataElementStore( // DataElement // ------------------------------------------------------------------------- - @Override - public List getDataElementsByDomainType(DataElementDomain domainType) { - CriteriaBuilder builder = getCriteriaBuilder(); - - return getList( - builder, - newJpaParameters().addPredicate(root -> builder.equal(root.get("domainType"), domainType))); - } - - @Override - public List getDataElementsByValueType(ValueType valueType) { - CriteriaBuilder builder = getCriteriaBuilder(); - - return getList( - builder, - newJpaParameters().addPredicate(root -> builder.equal(root.get("valueType"), valueType))); - } - @Override public List getDataElementByCategoryCombo(CategoryCombo categoryCombo) { CriteriaBuilder builder = getCriteriaBuilder(); @@ -95,17 +74,6 @@ public List getDataElementByCategoryCombo(CategoryCombo categoryCom .addPredicate(root -> builder.equal(root.get("categoryCombo"), categoryCombo))); } - @Override - public List getDataElementsByZeroIsSignificant(boolean zeroIsSignificant) { - CriteriaBuilder builder = getCriteriaBuilder(); - - return getList( - builder, - newJpaParameters() - .addPredicate(root -> builder.equal(root.get("zeroIsSignificant"), zeroIsSignificant)) - .addPredicate(root -> root.get("valueType").in(ValueType.NUMERIC_TYPES))); - } - @Override public List getDataElementsWithoutGroups() { String hql = "from DataElement d where size(d.groups) = 0"; diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataset/DefaultDataSetService.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataset/DefaultDataSetService.java index 20254f48a893..63a1a22f9492 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataset/DefaultDataSetService.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataset/DefaultDataSetService.java @@ -45,7 +45,6 @@ import org.hisp.dhis.dataentryform.DataEntryForm; import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.period.Period; -import org.hisp.dhis.period.PeriodType; import org.hisp.dhis.query.QueryParserException; import org.hisp.dhis.security.Authorities; import org.hisp.dhis.user.CurrentUserUtil; @@ -123,12 +122,6 @@ public List getAllDataSets() { return dataSetStore.getAll(); } - @Override - @Transactional(readOnly = true) - public List getDataSetsByPeriodType(PeriodType periodType) { - return dataSetStore.getDataSetsByPeriodType(periodType); - } - @Override @Transactional(readOnly = true) public List getUserDataRead(@Nonnull UserDetails user) { diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataset/hibernate/HibernateDataSetStore.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataset/hibernate/HibernateDataSetStore.java index 74a1673a7303..09f1850576f4 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataset/hibernate/HibernateDataSetStore.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataset/hibernate/HibernateDataSetStore.java @@ -31,7 +31,6 @@ import com.google.common.collect.Lists; import jakarta.persistence.EntityManager; -import jakarta.persistence.criteria.CriteriaBuilder; import java.util.Collection; import java.util.List; import javax.annotation.Nonnull; @@ -42,7 +41,6 @@ import org.hisp.dhis.dataset.DataSet; import org.hisp.dhis.dataset.DataSetElement; import org.hisp.dhis.dataset.DataSetStore; -import org.hisp.dhis.hibernate.JpaQueryParameters; import org.hisp.dhis.period.PeriodService; import org.hisp.dhis.period.PeriodType; import org.hisp.dhis.security.acl.AclService; @@ -97,19 +95,6 @@ public void update(@Nonnull DataSet dataSet) { super.update(dataSet); } - @Override - public List getDataSetsByPeriodType(PeriodType periodType) { - PeriodType refreshedPeriodType = periodService.reloadPeriodType(periodType); - - CriteriaBuilder builder = getCriteriaBuilder(); - - JpaQueryParameters parameters = - newJpaParameters() - .addPredicate(root -> builder.equal(root.get("periodType"), refreshedPeriodType)); - - return getList(builder, parameters); - } - @Override public List getDataSetsByDataEntryForm(DataEntryForm dataEntryForm) { if (dataEntryForm == null) { diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/DefaultOrganisationUnitService.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/DefaultOrganisationUnitService.java index 7a3bf1cc9eeb..4342ec0960ec 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/DefaultOrganisationUnitService.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/DefaultOrganisationUnitService.java @@ -53,7 +53,6 @@ import org.hisp.dhis.commons.collection.ListUtils; import org.hisp.dhis.commons.filter.FilterUtils; import org.hisp.dhis.configuration.ConfigurationService; -import org.hisp.dhis.dataset.DataSet; import org.hisp.dhis.expression.ExpressionService; import org.hisp.dhis.feedback.BadRequestException; import org.hisp.dhis.hierarchy.HierarchyViolationException; @@ -73,12 +72,10 @@ public class DefaultOrganisationUnitService implements OrganisationUnitService { private static final String LEVEL_PREFIX = "Level "; private final OrganisationUnitStore organisationUnitStore; - private final IdentifiableObjectManager idObjectManager; private final OrganisationUnitLevelStore organisationUnitLevelStore; private final ConfigurationService configurationService; private final Cache inUserOrgUnitHierarchyCache; - private final Cache inUserOrgUnitSearchHierarchyCache; public DefaultOrganisationUnitService( OrganisationUnitStore organisationUnitStore, @@ -94,13 +91,10 @@ public DefaultOrganisationUnitService( checkNotNull(cacheProvider); this.organisationUnitStore = organisationUnitStore; - this.idObjectManager = idObjectManager; this.organisationUnitLevelStore = organisationUnitLevelStore; this.configurationService = configurationService; this.inUserOrgUnitHierarchyCache = cacheProvider.createInUserOrgUnitHierarchyCache(); - this.inUserOrgUnitSearchHierarchyCache = - cacheProvider.createInUserSearchOrgUnitHierarchyCache(); } // ------------------------------------------------------------------------- @@ -362,34 +356,6 @@ public Long getOrganisationUnitHierarchyMemberCount( parent, member, collectionName); } - @Override - @Transactional(readOnly = true) - public OrganisationUnitDataSetAssociationSet getOrganisationUnitDataSetAssociationSet(User user) { - - Set organisationUnits = user != null ? user.getOrganisationUnits() : null; - List dataSets = idObjectManager.getDataWriteAll(DataSet.class); - - Map> associationSet = - organisationUnitStore.getOrganisationUnitDataSetAssocationMap(organisationUnits, dataSets); - - OrganisationUnitDataSetAssociationSet set = new OrganisationUnitDataSetAssociationSet(); - - for (Map.Entry> entry : associationSet.entrySet()) { - int index = set.getDataSetAssociationSets().indexOf(entry.getValue()); - - if (index == -1) // Association set does not exist, add new - { - index = set.getDataSetAssociationSets().size(); - set.getDataSetAssociationSets().add(entry.getValue()); - } - - set.getOrganisationUnitAssociationSetMap().put(entry.getKey(), index); - set.getDistinctDataSets().addAll(entry.getValue()); - } - - return set; - } - @Override @Transactional(readOnly = true) public boolean isInUserHierarchyCached(User user, OrganisationUnit organisationUnit) { @@ -424,15 +390,6 @@ public boolean isInUserDataViewHierarchy(User user, OrganisationUnit organisatio return organisationUnit.isDescendant(user.getDataViewOrganisationUnitsWithFallback()); } - @Override - @Transactional(readOnly = true) - public boolean isInUserSearchHierarchyCached(User user, OrganisationUnit organisationUnit) { - String cacheKey = joinHyphen(user.getUsername(), organisationUnit.getUid()); - - return inUserOrgUnitSearchHierarchyCache.get( - cacheKey, ou -> isInUserSearchHierarchy(user, organisationUnit)); - } - @Override @Transactional(readOnly = true) public boolean isInUserSearchHierarchy(User user, OrganisationUnit organisationUnit) { 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 d45785e0a15d..a7a39218a51c 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 @@ -29,42 +29,33 @@ import static com.google.common.base.Preconditions.checkNotNull; import static java.util.stream.Collectors.toSet; -import static org.hisp.dhis.system.util.SqlUtils.escape; import jakarta.persistence.EntityManager; import java.util.ArrayList; import java.util.Collection; import java.util.Date; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Set; import javax.annotation.Nonnull; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.hibernate.Session; import org.hibernate.query.Query; import org.hisp.dhis.common.IdentifiableObjectUtils; import org.hisp.dhis.common.hibernate.HibernateIdentifiableObjectStore; import org.hisp.dhis.commons.util.SqlHelper; import org.hisp.dhis.commons.util.TextUtils; -import org.hisp.dhis.dataset.DataSet; import org.hisp.dhis.dbms.DbmsManager; import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.organisationunit.OrganisationUnitQueryParams; import org.hisp.dhis.organisationunit.OrganisationUnitStore; import org.hisp.dhis.program.Program; import org.hisp.dhis.security.acl.AclService; -import org.hisp.dhis.system.util.SqlUtils; import org.springframework.context.ApplicationEventPublisher; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; -import org.springframework.util.Assert; /** * @author Kristian Nordal */ -@Slf4j @Repository("org.hisp.dhis.organisationunit.OrganisationUnitStore") public class HibernateOrganisationUnitStore extends HibernateIdentifiableObjectStore implements OrganisationUnitStore { @@ -281,57 +272,6 @@ public List getOrganisationUnits(OrganisationUnitQueryParams p return query.list(); } - @Override - public Map> getOrganisationUnitDataSetAssocationMap( - Collection organisationUnits, Collection dataSets) { - SqlHelper hlp = new SqlHelper(); - - String sql = - "select ou.uid as ou_uid, array_agg(ds.uid) as ds_uid " - + "from datasetsource d " - + "inner join organisationunit ou on ou.organisationunitid=d.sourceid " - + "inner join dataset ds on ds.datasetid=d.datasetid "; - - if (organisationUnits != null) { - Assert.notEmpty(organisationUnits, "Organisation units cannot be empty"); - - sql += hlp.whereAnd() + " ("; - - for (OrganisationUnit unit : organisationUnits) { - sql += "ou.path like '" + unit.getPath() + "%' or "; - } - - sql = TextUtils.removeLastOr(sql) + ") "; - } - - if (dataSets != null) { - Assert.notEmpty(dataSets, "Data sets cannot be empty"); - - sql += - hlp.whereAnd() - + " ds.datasetid in (" - + StringUtils.join(IdentifiableObjectUtils.getIdentifiers(dataSets), ",") - + ") "; - } - - sql += "group by ou_uid"; - - log.debug("Org unit data set association map SQL: " + sql); - - Map> map = new HashMap<>(); - - jdbcTemplate.query( - sql, - rs -> { - String organisationUnitId = rs.getString("ou_uid"); - Set dataSetIds = SqlUtils.getArrayAsSet(rs, "ds_uid"); - - map.put(organisationUnitId, dataSetIds); - }); - - return map; - } - @Override public List getWithinCoordinateArea(double[] box) { // can't use hibernate-spatial 'makeenvelope' function, because not @@ -384,26 +324,6 @@ public int getMaxLevel() { return maxLength != null ? maxLength : 0; } - @Override - public boolean isOrgUnitCountAboveThreshold(OrganisationUnitQueryParams params, int threshold) { - String sql = buildOrganisationUnitDistinctUidsSql(params); - - StringBuilder sb = new StringBuilder(); - sb.append("select count(*) from ("); - sb.append(sql); - sb.append(" limit "); - sb.append(threshold + 1); - sb.append(") as douid"); - - return (jdbcTemplate.queryForObject(sb.toString(), Integer.class) > threshold); - } - - @Override - public List getOrganisationUnitUids(OrganisationUnitQueryParams params) { - String sql = buildOrganisationUnitDistinctUidsSql(params); - return jdbcTemplate.queryForList(sql, String.class); - } - @Override public int updateAllOrganisationUnitsGeometryToNull() { return getQuery("update OrganisationUnit o set o.geometry = null").executeUpdate(); @@ -423,30 +343,6 @@ public List getByCategoryOption(@Nonnull Collection ca .getResultList(); } - private String buildOrganisationUnitDistinctUidsSql(OrganisationUnitQueryParams params) { - SqlHelper hlp = new SqlHelper(); - - String sql = "select distinct o.uid from organisationunit o "; - - if (params.isFetchChildren()) { - sql += " left outer join organisationunit c ON o.organisationunitid = c.parentid "; - } - - if (params.hasParents()) { - sql += hlp.whereAnd() + " ("; - - for (OrganisationUnit parent : params.getParents()) { - sql += "o.path like '" + escape(parent.getPath()) + "%'" + " or "; - } - - sql = TextUtils.removeLastOr(sql) + ") "; - } - - // TODO: Support Groups + Query + Hierarchy + MaxLevels in this sql - - return sql; - } - private void updatePaths(List organisationUnits) { Session session = getSession(); int counter = 0; diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultDataSetMetadataExportService.java b/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultDataSetMetadataExportService.java index 35c5c26c27c9..8e60e6ff0b40 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultDataSetMetadataExportService.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultDataSetMetadataExportService.java @@ -72,7 +72,6 @@ import org.hisp.dhis.schema.descriptors.OptionSetSchemaDescriptor; import org.hisp.dhis.user.CurrentUserUtil; import org.hisp.dhis.user.UserDetails; -import org.hisp.dhis.user.UserService; import org.hisp.dhis.util.DateUtils; import org.springframework.stereotype.Service; @@ -136,8 +135,6 @@ public class DefaultDataSetMetadataExportService implements DataSetMetadataExpor private final ExpressionService expressionService; - private final UserService userService; - @Override public ObjectNode getDataSetMetadata() { UserDetails currentUserDetails = CurrentUserUtil.getCurrentUserDetails(); diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/category/CategoryServiceTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/category/CategoryServiceTest.java index f62af477abc7..fc2aba9673d3 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/category/CategoryServiceTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/category/CategoryServiceTest.java @@ -160,22 +160,6 @@ void testDeleteCategoryOption() { assertTrue(categoryService.getCategoryOption(optionIdA).getCategories().contains(categoryB)); } - @Test - void testGetAll() { - categoryA = createCategory('A'); - categoryB = createCategory('B'); - categoryC = createCategory('C'); - categoryService.addCategory(categoryA); - categoryService.addCategory(categoryB); - categoryService.addCategory(categoryC); - List categories = categoryService.getAllDataElementCategories(); - // Including default - assertEquals(4, categories.size()); - assertTrue(categories.contains(categoryA)); - assertTrue(categories.contains(categoryB)); - assertTrue(categories.contains(categoryC)); - } - @Test void testAddGetCategoryGroup() { CategoryOptionGroup groupA = createCategoryOptionGroup('A'); @@ -304,18 +288,6 @@ void testGetDisaggregationCategoryOptionGroupSetsNoAcl() { assertEquals(1, categoryService.getDisaggregationCategoryOptionGroupSetsNoAcl().size()); } - @Test - void testGetDisaggregationCategories() { - categoryA = createCategory('A', categoryOptionA, categoryOptionB, categoryOptionC); - categoryA.setDataDimensionType(DataDimensionType.DISAGGREGATION); - categoryService.addCategory(categoryA); - // Default Category is created so count should be equal 2 - assertEquals(2, categoryService.getDisaggregationCategories().size()); - assertEquals(1, categoryStore.getCategories(DataDimensionType.DISAGGREGATION, true).size()); - assertEquals( - 1, categoryStore.getCategoriesNoAcl(DataDimensionType.DISAGGREGATION, true).size()); - } - @Test void testAddAndPruneAllCategoryCombos() { categoryA = createCategory('A', categoryOptionA, categoryOptionB); diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataelement/DataElementServiceTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataelement/DataElementServiceTest.java index 6b1e40c9f922..eb5283bc8b2e 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataelement/DataElementServiceTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataelement/DataElementServiceTest.java @@ -251,31 +251,6 @@ void testGetAllDataElements() { assertTrue(dataElements.containsAll(dataElementsRef)); } - @Test - void testGetAllDataElementsByType() { - assertEquals(0, dataElementService.getAllDataElements().size()); - DataElement dataElementA = createDataElement('A'); - DataElement dataElementB = createDataElement('B'); - DataElement dataElementC = createDataElement('C'); - DataElement dataElementD = createDataElement('D'); - dataElementA.setValueType(ValueType.FILE_RESOURCE); - dataElementB.setValueType(ValueType.EMAIL); - dataElementC.setValueType(ValueType.BOOLEAN); - dataElementD.setValueType(ValueType.FILE_RESOURCE); - dataElementService.addDataElement(dataElementA); - dataElementService.addDataElement(dataElementB); - dataElementService.addDataElement(dataElementC); - dataElementService.addDataElement(dataElementD); - List dataElementsRef = new ArrayList<>(); - dataElementsRef.add(dataElementA); - dataElementsRef.add(dataElementD); - List dataElements = - dataElementService.getAllDataElementsByValueType(ValueType.FILE_RESOURCE); - assertNotNull(dataElements); - assertEquals(dataElementsRef.size(), dataElements.size()); - assertTrue(dataElements.containsAll(dataElementsRef)); - } - // ------------------------------------------------------------------------- // DataElementGroup // ------------------------------------------------------------------------- diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataelement/DataElementStoreTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataelement/DataElementStoreTest.java index 42313bcd8286..03013401fef8 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataelement/DataElementStoreTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataelement/DataElementStoreTest.java @@ -154,28 +154,6 @@ void testGetAllDataElements() { assertTrue(dataElements.containsAll(dataElementsRef)); } - @Test - void testGetDataElementsByDomainType() { - assertEquals( - 0, dataElementStore.getDataElementsByDomainType(DataElementDomain.AGGREGATE).size()); - assertEquals(0, dataElementStore.getDataElementsByDomainType(DataElementDomain.TRACKER).size()); - DataElement dataElementA = createDataElement('A'); - dataElementA.setDomainType(DataElementDomain.AGGREGATE); - DataElement dataElementB = createDataElement('B'); - dataElementB.setDomainType(DataElementDomain.TRACKER); - DataElement dataElementC = createDataElement('C'); - dataElementC.setDomainType(DataElementDomain.TRACKER); - DataElement dataElementD = createDataElement('D'); - dataElementD.setDomainType(DataElementDomain.TRACKER); - dataElementStore.save(dataElementA); - dataElementStore.save(dataElementB); - dataElementStore.save(dataElementC); - dataElementStore.save(dataElementD); - assertEquals( - 1, dataElementStore.getDataElementsByDomainType(DataElementDomain.AGGREGATE).size()); - assertEquals(3, dataElementStore.getDataElementsByDomainType(DataElementDomain.TRACKER).size()); - } - @Test void testGetDataElementAggregationLevels() { List aggregationLevels = Arrays.asList(3, 5); @@ -233,22 +211,6 @@ void testGetDataElementsByAggregationLevel() { assertTrue(dataElements.contains(dataElementB)); } - @Test - void testGetDataElementsZeroIsSignificant() { - DataElement dataElementA = createDataElement('A'); - DataElement dataElementB = createDataElement('B'); - DataElement dataElementC = createDataElement('C'); - DataElement dataElementD = createDataElement('D'); - dataElementA.setZeroIsSignificant(true); - dataElementB.setZeroIsSignificant(true); - dataElementStore.save(dataElementA); - dataElementStore.save(dataElementB); - dataElementStore.save(dataElementC); - dataElementStore.save(dataElementD); - List dataElements = dataElementStore.getDataElementsByZeroIsSignificant(true); - assertTrue(equals(dataElements, dataElementA, dataElementB)); - } - @Test void testDataElementByNonUniqueAttributeValue() throws NonUniqueAttributeValueException { Attribute attribute = new Attribute("cid", ValueType.TEXT); diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataset/DataSetStoreTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataset/DataSetStoreTest.java index 5d5f97b31d6e..69785683fbdc 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataset/DataSetStoreTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataset/DataSetStoreTest.java @@ -127,17 +127,6 @@ void testGetAllDataSets() { assertContainsOnly(List.of(dataSetA, dataSetB), dataSetStore.getAll()); } - @Test - void testGetDataSetByPeriodType() { - List types = PeriodType.getAvailablePeriodTypes(); - PeriodType periodType1 = types.get(0); - PeriodType periodType2 = types.get(1); - DataSet dataSetA = addDataSet('A', periodType1); - DataSet dataSetB = addDataSet('B', periodType2); - assertContainsOnly(List.of(dataSetA), dataSetStore.getDataSetsByPeriodType(periodType1)); - assertContainsOnly(List.of(dataSetB), dataSetStore.getDataSetsByPeriodType(periodType2)); - } - @Test void testGetByDataEntryForm() { DataSet dataSetA = addDataSet('A'); From 31e829fca94ab2a29f85f44e2ade351b588d1d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Helge=20=C3=98verland?= Date: Thu, 9 Jan 2025 14:40:36 +0100 Subject: [PATCH 03/11] test: Centralize creation of org units in test (#19630) --- .../organisationunit/OrganisationUnit.java | 8 +++ ...aQueryServiceDimensionItemKeywordTest.java | 22 ++++---- .../data/DimensionalObjectProviderTest.java | 12 ++--- .../handler/SchemeIdResponseMapperTest.java | 54 ++++++++----------- ...AbstractJdbcEventAnalyticsManagerTest.java | 2 +- ...isationUnitStructureResourceTableTest.java | 20 +++---- .../org/hisp/dhis/copy/CopyServiceTest.java | 4 +- .../dhis/query/DefaultQueryServiceTest.java | 3 +- ...ataSetRegistrationExchangeServiceTest.java | 5 +- .../DataValueSetImportValidatorTest.java | 3 +- .../attribute/GeoJsonAttributesCheckTest.java | 4 +- .../attribute/MetadataAttributeCheckTest.java | 6 +-- .../objectbundle/ObjectBundleHooksTest.java | 9 ++-- .../hooks/ProgramObjectBundleHookTest.java | 4 +- ...mStageWorkingListObjectBundleHookTest.java | 4 +- .../PredictionAnalyticsDataFetcherTest.java | 4 +- .../PredictionDataConsolidatorTest.java | 14 ++--- .../PredictionDataValueFetcherTest.java | 14 ++--- .../dhis/predictor/PredictionWriterTest.java | 4 +- .../VisualizationGridServiceTest.java | 5 +- .../acl/DefaultTrackerAccessManagerTest.java | 43 ++++++--------- .../export/OperationsParamsValidatorTest.java | 23 +------- .../EnrollmentOperationParamsMapperTest.java | 5 +- .../event/EventOperationParamsMapperTest.java | 29 ++++------ .../mappers/OrganisationUnitMapperTest.java | 9 ++-- .../mappers/TrackedEntityMapperTest.java | 3 +- .../validation/MessageFormatterTest.java | 3 +- .../enrollment/MetaValidatorTest.java | 10 ++-- .../event/DataValuesValidatorTest.java | 3 +- .../trackedentity/MetaValidatorTest.java | 6 +-- .../ValidationResultServiceTest.java | 3 +- .../java/org/hisp/dhis/test/TestBase.java | 26 ++++----- 32 files changed, 165 insertions(+), 199 deletions(-) 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 a15fa029b590..2cce28d7cc7d 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 @@ -807,6 +807,14 @@ 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/test/java/org/hisp/dhis/analytics/data/DataQueryServiceDimensionItemKeywordTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/DataQueryServiceDimensionItemKeywordTest.java index 622f2b45975f..51ebc5aa1ccd 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/DataQueryServiceDimensionItemKeywordTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/DataQueryServiceDimensionItemKeywordTest.java @@ -32,6 +32,7 @@ import static org.hamcrest.Matchers.is; import static org.hisp.dhis.common.DimensionalObject.PERIOD_DIM_ID; import static org.hisp.dhis.common.IdScheme.UID; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -142,7 +143,7 @@ public void setUp() { lenient().when(i18nManager.getI18n()).thenReturn(i18n); lenient().when(i18n.getString("LAST_12_MONTHS")).thenReturn("Last 12 months"); - rootOu = new OrganisationUnit("Sierra Leone"); + rootOu = createOrganisationUnit('A'); rootOu.setUid(CodeGenerator.generateUid()); rootOu.setCode("OU_525"); } @@ -164,7 +165,7 @@ void convertAnalyticsRequestWithOuLevelToDataQueryParam() { .thenReturn(getOrgUnitLevel(2, "level2UID", "District", null)); when(organisationUnitService.getOrganisationUnitLevelByLevelOrUid("2")).thenReturn(2); when(organisationUnitService.getOrganisationUnitsAtLevels(Mockito.anyList(), Mockito.anyList())) - .thenReturn(Lists.newArrayList(new OrganisationUnit(), new OrganisationUnit())); + .thenReturn(Lists.newArrayList(createOrganisationUnit('A'), createOrganisationUnit('B'))); rb.addOuFilter("LEVEL-2;ImspTQPwCqd"); rb.addDimension(concatenateUuid(DATA_ELEMENT_1, DATA_ELEMENT_2, DATA_ELEMENT_3)); @@ -199,7 +200,7 @@ void convertAnalyticsRequestWithMultipleOuLevelToDataQueryParam() { when(organisationUnitService.getOrganisationUnitLevelByLevelOrUid("3")).thenReturn(3); when(organisationUnitService.getOrganisationUnitLevelByLevelOrUid("2")).thenReturn(2); when(organisationUnitService.getOrganisationUnitsAtLevels(Mockito.anyList(), Mockito.anyList())) - .thenReturn(Lists.newArrayList(new OrganisationUnit(), new OrganisationUnit())); + .thenReturn(Lists.newArrayList(createOrganisationUnit('A'), createOrganisationUnit('B'))); rb.addOuFilter("LEVEL-2;LEVEL-3;ImspTQPwCqd"); rb.addDimension(concatenateUuid(DATA_ELEMENT_1, DATA_ELEMENT_2, DATA_ELEMENT_3)); @@ -240,9 +241,9 @@ void convertAnalyticsRequestWithIndicatorGroup() { when(idObjectManager.getObject(IndicatorGroup.class, UID, INDICATOR_GROUP_UID)) .thenReturn(indicatorGroup); when(idObjectManager.getObject(OrganisationUnit.class, UID, "goRUwCHPg1M")) - .thenReturn(new OrganisationUnit("aaa")); + .thenReturn(createOrganisationUnit('A')); when(idObjectManager.getObject(OrganisationUnit.class, UID, "fdc6uOvgoji")) - .thenReturn(new OrganisationUnit("bbb")); + .thenReturn(createOrganisationUnit('B')); rb.addOuFilter("goRUwCHPg1M;fdc6uOvgoji"); rb.addDimension("IN_GROUP-" + INDICATOR_GROUP_UID + ";cYeuwXTCPkU;Jtf34kNZhz"); @@ -343,7 +344,8 @@ void convertAnalyticsRequestWithOrgUnitLevelAsFilter() { assertNull(keywords.getKeyword("level2UID").getMetadataItem().getCode()); assertNotNull(keywords.getKeyword(rootOu.getUid())); - assertEquals("Sierra Leone", keywords.getKeyword(rootOu.getUid()).getMetadataItem().getName()); + assertEquals( + "OrganisationUnitA", keywords.getKeyword(rootOu.getUid()).getMetadataItem().getName()); assertEquals( rootOu.getCode(), keywords.getKeyword(rootOu.getUid()).getMetadataItem().getCode()); } @@ -403,7 +405,8 @@ void convertAnalyticsRequestWithOrgUnitLevelAndOrgUnitGroupAsFilter() { groupOu.getCode(), keywords.getKeyword(groupOu.getUid()).getMetadataItem().getCode()); assertNotNull(keywords.getKeyword(rootOu.getUid())); - assertEquals("Sierra Leone", keywords.getKeyword(rootOu.getUid()).getMetadataItem().getName()); + assertEquals( + "OrganisationUnitA", keywords.getKeyword(rootOu.getUid()).getMetadataItem().getName()); assertEquals( rootOu.getCode(), keywords.getKeyword(rootOu.getUid()).getMetadataItem().getCode()); } @@ -632,7 +635,7 @@ private void initOrgUnitGroup(String ouGroupUID) { when(idObjectManager.getObject(OrganisationUnit.class, UID, this.rootOu.getUid())) .thenReturn(rootOu); when(organisationUnitService.getOrganisationUnits(Mockito.anyList(), Mockito.anyList())) - .thenReturn(Lists.newArrayList(new OrganisationUnit(), new OrganisationUnit())); + .thenReturn(Lists.newArrayList(createOrganisationUnit('A'), createOrganisationUnit('B'))); } private void assertOrgUnitGroup(String ouGroupUID, DimensionalObject dimension) { @@ -644,7 +647,8 @@ private void assertOrgUnitGroup(String ouGroupUID, DimensionalObject dimension) assertEquals("CODE_001", keywords.getKeyword(ouGroupUID).getMetadataItem().getCode()); assertNotNull(keywords.getKeyword(rootOu.getUid())); - assertEquals("Sierra Leone", keywords.getKeyword(rootOu.getUid()).getMetadataItem().getName()); + assertEquals( + "OrganisationUnitA", keywords.getKeyword(rootOu.getUid()).getMetadataItem().getName()); assertEquals( rootOu.getCode(), keywords.getKeyword(rootOu.getUid()).getMetadataItem().getCode()); } diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/DimensionalObjectProviderTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/DimensionalObjectProviderTest.java index d0277d6514a5..24358bd39c2c 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/DimensionalObjectProviderTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/DimensionalObjectProviderTest.java @@ -216,8 +216,8 @@ void testGetDimensionWhenDataDimensionsAreNotFound() { @Test void testGetOrgUnitDimensionWithNoLevelsNoGroup() { - OrganisationUnit level2Ou1 = createOrganisationUnit("Bo"); - OrganisationUnit level2Ou2 = createOrganisationUnit("Bombali"); + OrganisationUnit level2Ou1 = createOrganisationUnit('A'); + OrganisationUnit level2Ou2 = createOrganisationUnit('B'); OrganisationUnit ou1 = createOrganisationUnit('A'); OrganisationUnit ou2 = createOrganisationUnit('B'); List organisationUnits = @@ -253,10 +253,10 @@ void testGetOrgUnitDimensionWithNoLevelsNoGroup() { @Test void testGetOrgUnitDimensionWithWithLevelAndGroup() { OrganisationUnitGroup organisationUnitGroup = createOrganisationUnitGroup('A'); - OrganisationUnit level2Ou1 = createOrganisationUnit("Bo"); - OrganisationUnit level2Ou2 = createOrganisationUnit("Bombali"); - OrganisationUnit ou1 = createOrganisationUnit('A'); - OrganisationUnit ou2 = createOrganisationUnit('B'); + OrganisationUnit level2Ou1 = createOrganisationUnit('A'); + OrganisationUnit level2Ou2 = createOrganisationUnit('B'); + OrganisationUnit ou1 = createOrganisationUnit('C'); + OrganisationUnit ou2 = createOrganisationUnit('D'); List organisationUnits = new ArrayList<>(asList(level2Ou1, level2Ou2, ou1, ou2)); diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/handler/SchemeIdResponseMapperTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/handler/SchemeIdResponseMapperTest.java index edd44fbee2e6..d4c3abcdab71 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/handler/SchemeIdResponseMapperTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/handler/SchemeIdResponseMapperTest.java @@ -28,7 +28,6 @@ package org.hisp.dhis.analytics.data.handler; import static com.google.common.collect.Lists.newArrayList; -import static java.lang.String.valueOf; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.emptyOrNullString; import static org.hamcrest.Matchers.equalTo; @@ -42,6 +41,7 @@ import static org.hisp.dhis.common.IdScheme.UUID; import static org.hisp.dhis.common.ValueType.TEXT; import static org.hisp.dhis.period.PeriodType.getPeriodFromIsoString; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.TestBase.createProgram; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -83,12 +83,12 @@ class SchemeIdResponseMapperTest { @Test void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToName() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = Data.builder() - .organizationUnits(List.of(stubOrgUnit())) + .organizationUnits(List.of(organisationUnit)) .dataElementOperands(List.of(dataElementOperands.get(0), dataElementOperands.get(1))) .dimensionalItemObjects(Set.of(period, organisationUnit)) .build(); @@ -121,7 +121,7 @@ void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToName() { @Test void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToCode() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -158,12 +158,12 @@ void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToCode() { @Test void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToUuid() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = Data.builder() - .organizationUnits(List.of(stubOrgUnit())) + .organizationUnits(List.of(createOrganisationUnit('A'))) .dataElementOperands(List.of(dataElementOperands.get(0), dataElementOperands.get(1))) .dimensionalItemObjects(Set.of(period, organisationUnit)) .build(); @@ -192,7 +192,7 @@ void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToUuid() { @Test void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToUid() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -226,7 +226,7 @@ void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToUid() { @Test void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToName() { List dataElements = stubDataElements(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -257,7 +257,7 @@ void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToName() { @Test void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToCode() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -295,7 +295,7 @@ void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToCode() { @Test void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToUuid() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -330,7 +330,7 @@ void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToUuid() { void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToUid() { List dataElementOperands = stubDataElementOperands(); DataElement dataElement = stubDataElement(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -365,7 +365,7 @@ void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToUid() { @Test void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToName() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -399,7 +399,7 @@ void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToName() { @Test void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToCode() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -433,7 +433,7 @@ void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToCode() { @Test void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToUuid() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -467,7 +467,7 @@ void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToUuid() { @Test void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToUid() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -501,7 +501,7 @@ void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToUid() { @Test void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeOverridesOutputIdScheme() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -543,7 +543,7 @@ void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeOverridesOutputIdScheme( @Test void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeOverridesOutputOrgUnitIdScheme() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -587,7 +587,7 @@ void testGetSchemeIdResponseMapWhenOutputDataElementOrgUnitIdSchemeOverrideOutpu DataElement dataElement = stubDataElement(); Indicator indicator = stubIndicator(); ProgramIndicator programIndicator = stubProgramIndicator(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); List dataElementOperands = stubDataElementOperands(); @@ -613,13 +613,11 @@ void testGetSchemeIdResponseMapWhenOutputDataElementOrgUnitIdSchemeOverrideOutpu Map responseMap = schemeIdResponseMapper.getSchemeIdResponseMap(schemeInfo); - String orgUnitUid = organisationUnit.getUid(); String periodIsoDate = period.getIsoDate(); DataElement dataElementA = dataElementOperands.get(0).getDataElement(); DataElement dataElementB = dataElementOperands.get(1).getDataElement(); CategoryOptionCombo categoryOptionComboC = dataElementOperands.get(0).getCategoryOptionCombo(); - assertThat(responseMap.get(orgUnitUid), is(equalTo(valueOf(organisationUnit.getId())))); assertThat(responseMap.get(periodIsoDate), is(equalTo(period.getName()))); assertThat(responseMap.get(dataElementA.getUid()), is(equalTo(dataElementA.getCode()))); assertThat(responseMap.get(dataElementB.getUid()), is(equalTo(dataElementB.getCode()))); @@ -636,7 +634,7 @@ void testGetSchemeIdResponseMapWhenOutputDataItemIdSchemeOverridesOutputIdScheme DataElement dataElement = stubDataElement(); Indicator indicator = stubIndicator(); ProgramIndicator programIndicator = stubProgramIndicator(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -870,7 +868,8 @@ private Settings stubSchemeSettings(IdScheme idScheme) { private Data stubSchemeData(Program program) { return Data.builder() .programs(List.of(program)) - .dimensionalItemObjects(Set.of(stubPeriod(), stubOrgUnit(), stubDataElement())) + .dimensionalItemObjects( + Set.of(stubPeriod(), createOrganisationUnit('A'), stubDataElement())) .build(); } @@ -944,15 +943,4 @@ private ProgramIndicator stubProgramIndicator() { return programIndicatorA; } - - private OrganisationUnit stubOrgUnit() { - OrganisationUnit organisationUnit = new OrganisationUnit(); - organisationUnit.setName("OrgUnitA"); - organisationUnit.setShortName("ShortOrgUnitA"); - organisationUnit.setUid("org1234567A"); - organisationUnit.setCode("CodeA"); - organisationUnit.setId(1); - - return organisationUnit; - } } diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManagerTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManagerTest.java index b37709db626e..c78346771352 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManagerTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManagerTest.java @@ -528,7 +528,7 @@ void testGetWhereClauseWithMultipleOrgUnitDescendantsAtSameLevel() { assertThat( whereClause, - containsString("and ax.\"uidlevel0\" in ('ouabcdefghA','ouabcdefghB','ouabcdefghC')")); + containsString("and ax.\"uidlevel1\" in ('ouabcdefghA','ouabcdefghB','ouabcdefghC')")); } @Test diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/resourcetable/table/OrganisationUnitStructureResourceTableTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/resourcetable/table/OrganisationUnitStructureResourceTableTest.java index 2080837b84e6..31d5fb05b764 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/resourcetable/table/OrganisationUnitStructureResourceTableTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/resourcetable/table/OrganisationUnitStructureResourceTableTest.java @@ -43,17 +43,17 @@ void testCreateBatchObjectsWhenLevelsAreSame() { int maxOrgUnitLevels = 3; int currentLevel = 3; - OrganisationUnit root = createOrganisationUnit("ouR"); + OrganisationUnit root = createOrganisationUnit('A'); root.setPath("/p1"); - OrganisationUnit ou1 = createOrganisationUnit("ou1", root); + OrganisationUnit ou1 = createOrganisationUnit('B', root); ou1.setPath("/p1/p2"); - OrganisationUnit ou2 = createOrganisationUnit("ou2", ou1); + OrganisationUnit ou2 = createOrganisationUnit('C', ou1); ou2.setHierarchyLevel(currentLevel); ou2.setPath("/p1/p2/ou2"); - OrganisationUnit ou3 = createOrganisationUnit("ou3", ou1); + OrganisationUnit ou3 = createOrganisationUnit('D', ou1); ou3.setHierarchyLevel(currentLevel); ou3.setPath("/p1/p2/ou3"); @@ -72,10 +72,10 @@ void testCreateBatchObjectsWhenHierarchyLevelIsLowerThanMaxLevel() { int maxOrgUnitLevels = 3; int currentLevel = 2; - OrganisationUnit root = createOrganisationUnit("ouR"); + OrganisationUnit root = createOrganisationUnit('A'); root.setPath("/p1"); - OrganisationUnit ou1 = createOrganisationUnit("ou1", root); + OrganisationUnit ou1 = createOrganisationUnit('B', root); ou1.setPath("/p1/p2"); List organisationUnits = new ArrayList<>(); @@ -92,10 +92,10 @@ void testCreateBatchObjectsWhenCurrentLevelIsLargerThanMaxLevel() { int maxOrgUnitLevels = 2; int currentLevel = 3; - OrganisationUnit root = createOrganisationUnit("ouR"); + OrganisationUnit root = createOrganisationUnit('A'); root.setPath("/p1"); - OrganisationUnit ou1 = createOrganisationUnit("ou1", root); + OrganisationUnit ou1 = createOrganisationUnit('B', root); ou1.setPath("/p1/p2"); ou1.setUid("uid-123"); @@ -120,10 +120,10 @@ void testCreateBatchObjectsWhenCurrentLevelHasNoParent() { int maxOrgUnitLevels = 2; int currentLevel = 3; - OrganisationUnit root = createOrganisationUnit("ouR"); + OrganisationUnit root = createOrganisationUnit('A'); root.setPath("/p1"); - OrganisationUnit ou1 = createOrganisationUnit("ou1"); + OrganisationUnit ou1 = createOrganisationUnit('B'); ou1.setPath("/p1/p2"); ou1.setUid("uid-123"); diff --git a/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/copy/CopyServiceTest.java b/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/copy/CopyServiceTest.java index 177e20ecadc5..aded62162396 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/copy/CopyServiceTest.java +++ b/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/copy/CopyServiceTest.java @@ -131,7 +131,7 @@ void setup() { @Test void testCopyProgramFromUidWithValidProgram() throws NotFoundException, ForbiddenException { - OrganisationUnit orgUnit = createOrganisationUnit("New Org 1"); + OrganisationUnit orgUnit = createOrganisationUnit('A'); List originalEnrollments = List.of(createEnrollment(original, createTrackedEntity(orgUnit), orgUnit)); when(programService.getProgram(VALID_PROGRAM_UID)).thenReturn(original); @@ -382,7 +382,7 @@ Program createProgram() { Set.of(createProgramNotificationTemplate("not1", 20, ENROLLMENT, WEB_HOOK))); p.setOnlyEnrollOnce(true); p.setOpenDaysAfterCoEndDate(20); - p.setOrganisationUnits(Set.of(createOrganisationUnit("Org 1"))); + p.setOrganisationUnits(Set.of(createOrganisationUnit('A'))); p.setProgramAttributes(createProgramAttributes(p)); p.setProgramIndicators(createIndicators(p)); p.setProgramRuleVariables(Set.of(createProgramRuleVariable('v', p))); diff --git a/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/query/DefaultQueryServiceTest.java b/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/query/DefaultQueryServiceTest.java index bb84e91d776f..6087b19e25d5 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/query/DefaultQueryServiceTest.java +++ b/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/query/DefaultQueryServiceTest.java @@ -35,7 +35,6 @@ import java.util.ArrayList; import java.util.List; -import org.apache.commons.lang3.RandomStringUtils; import org.hisp.dhis.common.IdentifiableObject; import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.query.planner.DefaultQueryPlanner; @@ -96,7 +95,7 @@ private List createOrgUnits(int size) { List result = new ArrayList<>(); for (int i = 0; i < size; i++) { - result.add(createOrganisationUnit(RandomStringUtils.randomAlphabetic(1))); + result.add(createOrganisationUnit((char) (i + 'A'))); } return result; } diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/dataset/DefaultCompleteDataSetRegistrationExchangeServiceTest.java b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/dataset/DefaultCompleteDataSetRegistrationExchangeServiceTest.java index 4f9664d8b3b8..1411f486443c 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/dataset/DefaultCompleteDataSetRegistrationExchangeServiceTest.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/dataset/DefaultCompleteDataSetRegistrationExchangeServiceTest.java @@ -121,6 +121,7 @@ class DefaultCompleteDataSetRegistrationExchangeServiceTest { @Mock private BatchHandlerFactory batchHandlerFactory; @Mock private SystemSettingsProvider settingsProvider; + @Mock private SystemSettings settings; @Mock private CategoryService categoryService; @@ -158,7 +159,9 @@ class DefaultCompleteDataSetRegistrationExchangeServiceTest { @Mock private Environment environment; @Mock private AclService aclService; + @Mock private UserService userService; + private User user; private DefaultCompleteDataSetRegistrationExchangeService subject; @@ -299,7 +302,7 @@ void verifyUserHasNoWritePermissionOnCategoryOption() { void testValidateAssertMissingDataSet() { ExportParams params = new ExportParams() - .setOrganisationUnits(Sets.newHashSet(new OrganisationUnit())) + .setOrganisationUnits(Sets.newHashSet(createOrganisationUnit('A'))) .setPeriods(Sets.newHashSet(new Period())); assertIllegalQueryEx( 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 3cda0b79904a..6211873f78ba 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 @@ -29,6 +29,7 @@ import static java.util.Collections.emptySet; import static java.util.Collections.singleton; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -878,7 +879,7 @@ private DataValueContextBuilder createDataValueContext(DataValue dataValue) { builder.period(p); } if (ouId != null) { - OrganisationUnit ou = new OrganisationUnit(); + OrganisationUnit ou = createOrganisationUnit('A'); 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. diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/GeoJsonAttributesCheckTest.java b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/GeoJsonAttributesCheckTest.java index a7a57ed76697..54a62128fb6f 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/GeoJsonAttributesCheckTest.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/GeoJsonAttributesCheckTest.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.dxf2.metadata.attribute; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -71,8 +72,7 @@ class GeoJsonAttributesCheckTest { @BeforeEach public void setUpTest() { - organisationUnit = new OrganisationUnit(); - organisationUnit.setName("A"); + organisationUnit = createOrganisationUnit('A'); attribute = new Attribute(); attribute.setUid("geoJson"); attribute.setName("geoJson"); diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/MetadataAttributeCheckTest.java b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/MetadataAttributeCheckTest.java index b07d0158b6ed..ea1140c4fb7e 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/MetadataAttributeCheckTest.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/MetadataAttributeCheckTest.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.dxf2.metadata.attribute; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -84,8 +85,7 @@ class MetadataAttributeCheckTest { @BeforeEach void setUpTest() { - organisationUnit = new OrganisationUnit(); - organisationUnit.setName("A"); + organisationUnit = createOrganisationUnit('A'); attribute = new Attribute(); attribute.setUid("attributeID"); attribute.setName("attributeA"); @@ -456,7 +456,7 @@ void testAttributeOrganisationUnit() { organisationUnit.addAttributeValue(attribute.getUid(), "OU-ID"); // OrganisationUnit exists - when(manager.get(OrganisationUnit.class, "OU-ID")).thenReturn(new OrganisationUnit()); + when(manager.get(OrganisationUnit.class, "OU-ID")).thenReturn(createOrganisationUnit('A')); List objectReportList = new ArrayList<>(); diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/ObjectBundleHooksTest.java b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/ObjectBundleHooksTest.java index ecf8d84e51b7..608e403d83c3 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/ObjectBundleHooksTest.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/ObjectBundleHooksTest.java @@ -30,6 +30,7 @@ import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -67,20 +68,20 @@ class ObjectBundleHooksTest { @Test void testMatchingClassBoundIsIncluded() { - assertHasHooksOfType(new OrganisationUnit(), OrganisationUnitObjectBundleHook.class); + assertHasHooksOfType(createOrganisationUnit('A'), OrganisationUnitObjectBundleHook.class); assertHasHooksOfType(new User(), UserObjectBundleHook.class); } @Test void testNonMatchingClassBoundIsNotIncluded() { - assertHasNotHooksOfType(new OrganisationUnit(), UserObjectBundleHook.class); + assertHasNotHooksOfType(createOrganisationUnit('A'), UserObjectBundleHook.class); assertHasNotHooksOfType(new User(), OrganisationUnitObjectBundleHook.class); } @Test void testMatchingInterfaceBoundIsIncluded() { assertHasHooksOfType( - new OrganisationUnit(), + createOrganisationUnit('A'), IdentifiableObjectBundleHook.class, VersionedObjectObjectBundleHook.class); assertHasHooksOfType( @@ -94,7 +95,7 @@ void testMatchingInterfaceBoundIsIncluded() { @Test void testNonMatchingInterfaceBoundIsNotIncluded() { - assertHasNotHooksOfType(new OrganisationUnit(), AnalyticalObjectObjectBundleHook.class); + assertHasNotHooksOfType(createOrganisationUnit('A'), AnalyticalObjectObjectBundleHook.class); assertHasNotHooksOfType(new User(), AnalyticalObjectObjectBundleHook.class); } diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramObjectBundleHookTest.java b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramObjectBundleHookTest.java index 5d4e36618955..edf7d86c6467 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramObjectBundleHookTest.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramObjectBundleHookTest.java @@ -30,6 +30,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.TestBase.createProgram; import static org.hisp.dhis.test.TestBase.createProgramStage; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -45,7 +46,6 @@ import org.hisp.dhis.common.IdentifiableObjectManager; import org.hisp.dhis.feedback.ErrorCode; import org.hisp.dhis.feedback.ErrorReport; -import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.organisationunit.OrganisationUnitService; import org.hisp.dhis.program.Enrollment; import org.hisp.dhis.program.EnrollmentStatus; @@ -112,7 +112,7 @@ void verifyMissingBundleIsIgnored() { @Test void verifyProgramInstanceIsSavedForEventProgram() { when(organisationUnitService.getRootOrganisationUnits()) - .thenReturn(List.of(new OrganisationUnit())); + .thenReturn(List.of(createOrganisationUnit('A'))); ArgumentCaptor argument = ArgumentCaptor.forClass(Enrollment.class); programA.setProgramType(ProgramType.WITHOUT_REGISTRATION); diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramStageWorkingListObjectBundleHookTest.java b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramStageWorkingListObjectBundleHookTest.java index 774b8a513ef3..26f098305938 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramStageWorkingListObjectBundleHookTest.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramStageWorkingListObjectBundleHookTest.java @@ -35,6 +35,7 @@ import static org.hisp.dhis.feedback.ErrorCode.E4067; import static org.hisp.dhis.feedback.ErrorCode.E4068; import static org.hisp.dhis.feedback.ErrorCode.E7500; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.utils.Assertions.assertErrorReport; import static org.hisp.dhis.test.utils.Assertions.assertIsEmpty; import static org.mockito.ArgumentMatchers.anyString; @@ -50,7 +51,6 @@ import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundle; import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundleParams; import org.hisp.dhis.feedback.ErrorReport; -import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.organisationunit.OrganisationUnitService; import org.hisp.dhis.preheat.Preheat; import org.hisp.dhis.programstagefilter.DateFilterPeriod; @@ -136,7 +136,7 @@ void shouldReturnNoErrorsWhenQueryCriteriaSuppliedIsValid() { .build(); when(organisationUnitService.getOrganisationUnit(anyString())) - .thenReturn(new OrganisationUnit()); + .thenReturn(createOrganisationUnit('A')); when(dataElementService.getDataElement(anyString())).thenReturn(new DataElement()); when(attributeService.getTrackedEntityAttribute(anyString())) .thenReturn(new TrackedEntityAttribute()); diff --git a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionAnalyticsDataFetcherTest.java b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionAnalyticsDataFetcherTest.java index 5404db0b3a52..eb26204fb471 100644 --- a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionAnalyticsDataFetcherTest.java +++ b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionAnalyticsDataFetcherTest.java @@ -106,8 +106,8 @@ void initTest() { periods = Sets.newHashSet(periodA, periodB); - orgUnitA = createOrganisationUnit("A"); - orgUnitB = createOrganisationUnit("B"); + orgUnitA = createOrganisationUnit('A'); + orgUnitB = createOrganisationUnit('B'); orgUnitA.setUid("orgUnitAuid"); orgUnitB.setUid("orgUnitBuid"); diff --git a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataConsolidatorTest.java b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataConsolidatorTest.java index bb3db588a2e6..010c677236cb 100644 --- a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataConsolidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataConsolidatorTest.java @@ -231,13 +231,13 @@ void initTest() { // -- C ------ F // -- D ------ G - orgUnitA = createOrganisationUnit("A"); - orgUnitB = createOrganisationUnit("B"); - orgUnitC = createOrganisationUnit("C"); - orgUnitD = createOrganisationUnit("D"); - orgUnitE = createOrganisationUnit("E", orgUnitB); - orgUnitF = createOrganisationUnit("F", orgUnitC); - orgUnitG = createOrganisationUnit("G", orgUnitD); + orgUnitA = createOrganisationUnit('A'); + orgUnitB = createOrganisationUnit('B'); + orgUnitC = createOrganisationUnit('C'); + orgUnitD = createOrganisationUnit('D'); + orgUnitE = createOrganisationUnit('E', orgUnitB); + orgUnitF = createOrganisationUnit('F', orgUnitC); + orgUnitG = createOrganisationUnit('G', orgUnitD); orgUnitA.setId(20); orgUnitB.setId(21); diff --git a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataValueFetcherTest.java b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataValueFetcherTest.java index 4b847c628d33..1fe83aff83c4 100644 --- a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataValueFetcherTest.java +++ b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataValueFetcherTest.java @@ -248,13 +248,13 @@ void initTest() { // -- C ------ F // -- D ------ G - orgUnitA = createOrganisationUnit("A"); - orgUnitB = createOrganisationUnit("B"); - orgUnitC = createOrganisationUnit("C"); - orgUnitD = createOrganisationUnit("D"); - orgUnitE = createOrganisationUnit("E", orgUnitB); - orgUnitF = createOrganisationUnit("F", orgUnitC); - orgUnitG = createOrganisationUnit("G", orgUnitD); + orgUnitA = createOrganisationUnit('A'); + orgUnitB = createOrganisationUnit('B'); + orgUnitC = createOrganisationUnit('C'); + orgUnitD = createOrganisationUnit('D'); + orgUnitE = createOrganisationUnit('E', orgUnitB); + orgUnitF = createOrganisationUnit('F', orgUnitC); + orgUnitG = createOrganisationUnit('G', orgUnitD); orgUnitA.setId(20); orgUnitB.setId(21); diff --git a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionWriterTest.java b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionWriterTest.java index 4c62cee80b16..2a546a204d76 100644 --- a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionWriterTest.java +++ b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionWriterTest.java @@ -28,7 +28,7 @@ package org.hisp.dhis.predictor; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -123,7 +123,7 @@ public void initTest() { cocA.setId(++id); cocB.setId(++id); - orgUnitA = createOrganisationUnit("A"); + orgUnitA = createOrganisationUnit('A'); orgUnitA.setId(++id); diff --git a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/visualization/VisualizationGridServiceTest.java b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/visualization/VisualizationGridServiceTest.java index 4aab0ba6ec60..e7e3b0959938 100644 --- a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/visualization/VisualizationGridServiceTest.java +++ b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/visualization/VisualizationGridServiceTest.java @@ -31,6 +31,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasSize; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -90,7 +91,7 @@ void getVisualizationGridByUserWhenItHasOrganisationUnitLevels() { final String anyOrganisationUnitUid = "ouiRzW5e"; final User userStub = userStub(); final List orgUnitLevels = asList(1, 2); - final List orgUnits = asList(new OrganisationUnit()); + final List orgUnits = asList(createOrganisationUnit('A')); final Map valueMap = valueMapStub(); final Visualization visualizationStub = visualizationStub("abc123xy"); @@ -124,7 +125,7 @@ void getVisualizationGridByUserWhenItHasItemOrganisationUnitGroups() { final Date anyRelativePeriodDate = new Date(); final String anyOrganisationUnitUid = "ouiRzW5e"; final User userStub = userStub(); - final List orgUnits = asList(new OrganisationUnit()); + final List orgUnits = asList(createOrganisationUnit('A')); final List orgUnitGroups = asList(new OrganisationUnitGroup()); final Map valueMap = valueMapStub(); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/acl/DefaultTrackerAccessManagerTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/acl/DefaultTrackerAccessManagerTest.java index 1f63f94d30fb..042b9fadc477 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/acl/DefaultTrackerAccessManagerTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/acl/DefaultTrackerAccessManagerTest.java @@ -30,6 +30,8 @@ import static org.hisp.dhis.common.AccessLevel.CLOSED; import static org.hisp.dhis.common.AccessLevel.OPEN; import static org.hisp.dhis.common.AccessLevel.PROTECTED; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; +import static org.hisp.dhis.test.TestBase.createProgram; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -38,6 +40,7 @@ import org.hisp.dhis.program.Program; import org.hisp.dhis.user.User; import org.hisp.dhis.user.UserDetails; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -48,13 +51,22 @@ class DefaultTrackerAccessManagerTest { @InjectMocks private DefaultTrackerAccessManager trackerAccessManager; + private Program program; + + private OrganisationUnit orgUnit; + + private User user; + + @BeforeEach + public void before() { + program = createProgram('A'); + orgUnit = createOrganisationUnit('A'); + user = new User(); + } + @Test void shouldHaveAccessWhenProgramOpenAndSearchAccessAvailable() { - User user = new User(); - Program program = new Program(); program.setAccessLevel(OPEN); - OrganisationUnit orgUnit = new OrganisationUnit(); - user.setTeiSearchOrganisationUnits(Set.of(orgUnit)); assertTrue( @@ -64,10 +76,7 @@ void shouldHaveAccessWhenProgramOpenAndSearchAccessAvailable() { @Test void shouldNotHaveAccessWhenProgramOpenAndSearchAccessNotAvailable() { - User user = new User(); - Program program = new Program(); program.setAccessLevel(OPEN); - OrganisationUnit orgUnit = new OrganisationUnit(); assertFalse( trackerAccessManager.canAccess(UserDetails.fromUser(user), program, orgUnit), @@ -76,9 +85,6 @@ void shouldNotHaveAccessWhenProgramOpenAndSearchAccessNotAvailable() { @Test void shouldHaveAccessWhenProgramNullAndSearchAccessAvailable() { - User user = new User(); - OrganisationUnit orgUnit = new OrganisationUnit(); - user.setTeiSearchOrganisationUnits(Set.of(orgUnit)); assertTrue( @@ -88,9 +94,6 @@ void shouldHaveAccessWhenProgramNullAndSearchAccessAvailable() { @Test void shouldNotHaveAccessWhenProgramNullAndSearchAccessNotAvailable() { - User user = new User(); - OrganisationUnit orgUnit = new OrganisationUnit(); - assertFalse( trackerAccessManager.canAccess(UserDetails.fromUser(user), null, orgUnit), "User should not have access to unspecified program"); @@ -98,11 +101,7 @@ void shouldNotHaveAccessWhenProgramNullAndSearchAccessNotAvailable() { @Test void shouldHaveAccessWhenProgramClosedAndCaptureAccessAvailable() { - User user = new User(); - Program program = new Program(); program.setAccessLevel(CLOSED); - OrganisationUnit orgUnit = new OrganisationUnit(); - user.setOrganisationUnits(Set.of(orgUnit)); assertTrue( @@ -112,10 +111,7 @@ void shouldHaveAccessWhenProgramClosedAndCaptureAccessAvailable() { @Test void shouldNotHaveAccessWhenProgramClosedAndCaptureAccessNotAvailable() { - User user = new User(); - Program program = new Program(); program.setAccessLevel(CLOSED); - OrganisationUnit orgUnit = new OrganisationUnit(); assertFalse( trackerAccessManager.canAccess(UserDetails.fromUser(user), program, orgUnit), @@ -124,11 +120,7 @@ void shouldNotHaveAccessWhenProgramClosedAndCaptureAccessNotAvailable() { @Test void shouldHaveAccessWhenProgramProtectedAndCaptureAccessAvailable() { - User user = new User(); - Program program = new Program(); program.setAccessLevel(PROTECTED); - OrganisationUnit orgUnit = new OrganisationUnit(); - user.setOrganisationUnits(Set.of(orgUnit)); assertTrue( @@ -138,10 +130,7 @@ void shouldHaveAccessWhenProgramProtectedAndCaptureAccessAvailable() { @Test void shouldNotHaveAccessWhenProgramProtectedAndCaptureAccessNotAvailable() { - User user = new User(); - Program program = new Program(); program.setAccessLevel(PROTECTED); - OrganisationUnit orgUnit = new OrganisationUnit(); assertFalse( trackerAccessManager.canAccess(UserDetails.fromUser(user), program, orgUnit), diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/OperationsParamsValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/OperationsParamsValidatorTest.java index 5ab7b641dbcb..b7fa4e296971 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/OperationsParamsValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/OperationsParamsValidatorTest.java @@ -30,6 +30,7 @@ import static org.hisp.dhis.common.OrganisationUnitSelectionMode.ALL; import static org.hisp.dhis.common.OrganisationUnitSelectionMode.CAPTURE; import static org.hisp.dhis.program.ProgramType.WITHOUT_REGISTRATION; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.tracker.export.OperationsParamsValidator.validateOrgUnitMode; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -54,7 +55,6 @@ import org.hisp.dhis.user.User; import org.hisp.dhis.user.UserDetails; import org.hisp.dhis.user.UserRole; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -65,20 +65,13 @@ @ExtendWith(MockitoExtension.class) class OperationsParamsValidatorTest { - - private static final String PARENT_ORG_UNIT_UID = "parent-org-unit"; - - private final OrganisationUnit captureScopeOrgUnit = createOrgUnit("captureScopeOrgUnit", "uid3"); - - private final OrganisationUnit searchScopeOrgUnit = createOrgUnit("searchScopeOrgUnit", "uid4"); - private final Program program = new Program("program"); private final TrackedEntity trackedEntity = new TrackedEntity(); private final TrackedEntityType trackedEntityType = new TrackedEntityType(); - private final OrganisationUnit orgUnit = new OrganisationUnit(); + private final OrganisationUnit orgUnit = createOrganisationUnit('A'); private static final UID PROGRAM_UID = UID.generate(); @@ -104,12 +97,6 @@ class OperationsParamsValidatorTest { private final UserDetails user = UserDetails.fromUser(new User()); - @BeforeEach - public void setUp() { - OrganisationUnit organisationUnit = createOrgUnit("orgUnit", PARENT_ORG_UNIT_UID); - organisationUnit.setChildren(Set.of(captureScopeOrgUnit, searchScopeOrgUnit)); - } - @Test void shouldFailWhenOuModeCaptureAndUserHasNoOrgUnitsAssigned() { Exception exception = @@ -385,10 +372,4 @@ void shouldReturnOrgUnitsWhenUserIsSuperButHasNoAccessToOrgUnit() assertEquals(Set.of(orgUnit), orgUnits); } - - private OrganisationUnit createOrgUnit(String name, String uid) { - OrganisationUnit orgUnit = new OrganisationUnit(name); - orgUnit.setUid(uid); - return orgUnit; - } } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/enrollment/EnrollmentOperationParamsMapperTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/enrollment/EnrollmentOperationParamsMapperTest.java index 853d171634ba..537ce85115ac 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/enrollment/EnrollmentOperationParamsMapperTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/enrollment/EnrollmentOperationParamsMapperTest.java @@ -31,6 +31,7 @@ import static org.hisp.dhis.common.OrganisationUnitSelectionMode.CAPTURE; import static org.hisp.dhis.common.OrganisationUnitSelectionMode.CHILDREN; import static org.hisp.dhis.common.OrganisationUnitSelectionMode.DESCENDANTS; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.utils.Assertions.assertIsEmpty; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.verifyNoInteractions; @@ -105,10 +106,10 @@ void setUp() throws ForbiddenException, BadRequestException { User testUser = new User(); testUser.setUsername("admin"); - orgUnit1 = new OrganisationUnit("orgUnit1"); + orgUnit1 = createOrganisationUnit('A'); orgUnit1.setUid(ORG_UNIT_1_UID.getValue()); when(organisationUnitService.getOrganisationUnit(orgUnit1.getUid())).thenReturn(orgUnit1); - orgUnit2 = new OrganisationUnit("orgUnit2"); + orgUnit2 = createOrganisationUnit('B'); orgUnit2.setUid(ORG_UNIT_2_UID.getValue()); orgUnit2.setParent(orgUnit1); orgUnit1.setChildren(Set.of(orgUnit2)); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java index 824853977ba6..c6e979d6edfc 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java @@ -36,6 +36,7 @@ import static org.hisp.dhis.common.OrganisationUnitSelectionMode.DESCENDANTS; import static org.hisp.dhis.common.OrganisationUnitSelectionMode.SELECTED; import static org.hisp.dhis.security.Authorities.F_TRACKED_ENTITY_INSTANCE_SEARCH_IN_ALL_ORGUNITS; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.utils.Assertions.assertContains; import static org.hisp.dhis.test.utils.Assertions.assertContainsOnly; import static org.hisp.dhis.test.utils.Assertions.assertStartsWith; @@ -131,9 +132,8 @@ class EventOperationParamsMapperTest { @BeforeEach public void setUp() { - OrganisationUnit orgUnit = createOrgUnit("orgUnit"); - orgUnit.setChildren( - Set.of(createOrgUnit("captureScopeChild"), createOrgUnit("searchScopeChild"))); + OrganisationUnit orgUnit = createOrganisationUnit('A'); + orgUnit.setChildren(Set.of(createOrganisationUnit('B'), createOrganisationUnit('C'))); User testUser = new User(); testUser.setUid(CodeGenerator.generateUid()); @@ -142,8 +142,7 @@ public void setUp() { user = UserDetails.fromUser(testUser); // By default, set to ACCESSIBLE for tests that don't set an orgUnit. The orgUnitMode needs to - // be - // set because its validation is in the EventRequestParamsMapper. + // be set because its validation is in the EventRequestParamsMapper. eventBuilder = eventBuilder.orgUnitMode(ACCESSIBLE).eventParams(EventParams.FALSE); userMap.put("admin", createUserWithAuthority(F_TRACKED_ENTITY_INSTANCE_SEARCH_IN_ALL_ORGUNITS)); @@ -421,15 +420,15 @@ void shouldMapOrgUnitWhenProgramProvidedAndRequestedOrgUnitInSearchScope( program.setUid(CodeGenerator.generateUid()); program.setAccessLevel(accessLevel); - OrganisationUnit searchScopeOrgUnit = createOrgUnit("searchScopeOrgUnit"); - OrganisationUnit searchScopeChildOrgUnit = createOrgUnit("searchScopeChildOrgUnit"); + OrganisationUnit searchScopeOrgUnit = createOrganisationUnit('A'); + OrganisationUnit searchScopeChildOrgUnit = createOrganisationUnit('B'); searchScopeOrgUnit.setChildren(Set.of(searchScopeChildOrgUnit)); searchScopeChildOrgUnit.setParent(searchScopeOrgUnit); User user = new User(); user.setUid(CodeGenerator.generateUid()); user.setUsername("testB"); - user.setOrganisationUnits(Set.of(createOrgUnit("captureScopeOrgUnit"))); + user.setOrganisationUnits(Set.of(createOrganisationUnit('C'))); user.setTeiSearchOrganisationUnits(Set.of(searchScopeOrgUnit)); when(organisationUnitService.getOrganisationUnit(searchScopeChildOrgUnit.getUid())) @@ -453,15 +452,15 @@ void shouldMapOrgUnitWhenModeAllProgramProvidedAndRequestedOrgUnitInSearchScope( program.setUid(CodeGenerator.generateUid()); program.setAccessLevel(OPEN); - OrganisationUnit searchScopeOrgUnit = createOrgUnit("searchScopeOrgUnit"); - OrganisationUnit searchScopeChildOrgUnit = createOrgUnit("searchScopeChildOrgUnit"); + OrganisationUnit searchScopeOrgUnit = createOrganisationUnit('A'); + OrganisationUnit searchScopeChildOrgUnit = createOrganisationUnit('B'); searchScopeOrgUnit.setChildren(Set.of(searchScopeChildOrgUnit)); searchScopeChildOrgUnit.setParent(searchScopeOrgUnit); User user = new User(); user.setUid(CodeGenerator.generateUid()); user.setUsername("testB"); - user.setOrganisationUnits(Set.of(createOrgUnit("captureScopeOrgUnit"))); + user.setOrganisationUnits(Set.of(createOrganisationUnit('C'))); user.setTeiSearchOrganisationUnits(Set.of(searchScopeOrgUnit)); UserRole userRole = new UserRole(); userRole.setAuthorities(Set.of(F_TRACKED_ENTITY_INSTANCE_SEARCH_IN_ALL_ORGUNITS.name())); @@ -481,7 +480,7 @@ void shouldMapOrgUnitWhenModeAllProgramProvidedAndRequestedOrgUnitInSearchScope( @EnumSource(value = OrganisationUnitSelectionMode.class) void shouldFailWhenRequestedOrgUnitOutsideOfSearchScope( OrganisationUnitSelectionMode orgUnitMode) { - OrganisationUnit orgUnit = createOrgUnit("name"); + OrganisationUnit orgUnit = createOrganisationUnit('A'); when(organisationUnitService.getOrganisationUnit(orgUnit.getUid())).thenReturn(orgUnit); EventOperationParams operationParams = EventOperationParams.builder().orgUnit(orgUnit).orgUnitMode(orgUnitMode).build(); @@ -544,10 +543,4 @@ private User createUserWithAuthority(Authorities authority) { return user; } - - private OrganisationUnit createOrgUnit(String name) { - OrganisationUnit orgUnit = new OrganisationUnit(name); - orgUnit.setUid(CodeGenerator.generateUid()); - return orgUnit; - } } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/OrganisationUnitMapperTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/OrganisationUnitMapperTest.java index 1f46665e7b91..2816f9e68991 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/OrganisationUnitMapperTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/OrganisationUnitMapperTest.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.tracker.imports.preheat.mappers; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.tracker.imports.preheat.mappers.AttributeCreator.attributeValues; import static org.hisp.dhis.tracker.imports.preheat.mappers.AttributeCreator.setIdSchemeFields; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -44,7 +45,7 @@ void testIdSchemeRelatedFieldsAreMapped() { OrganisationUnit orgUnit = setIdSchemeFields( - new OrganisationUnit(), + createOrganisationUnit('A'), "HpSAvRWtdDR", "meet", "green", @@ -60,11 +61,11 @@ void testIdSchemeRelatedFieldsAreMapped() { @Test void testParentFieldsAreMapped() { - OrganisationUnit rootOrgUnit = new OrganisationUnit(); + OrganisationUnit rootOrgUnit = createOrganisationUnit('A'); rootOrgUnit.setUid("root"); - OrganisationUnit level1OrgUnit = new OrganisationUnit(); + OrganisationUnit level1OrgUnit = createOrganisationUnit('B'); level1OrgUnit.setUid("level1"); - OrganisationUnit level2OrgUnit = new OrganisationUnit(); + OrganisationUnit level2OrgUnit = createOrganisationUnit('C'); level2OrgUnit.setUid("level2"); level2OrgUnit.setParent(level1OrgUnit); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/TrackedEntityMapperTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/TrackedEntityMapperTest.java index eb1e4127ff3e..1972dcc9f201 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/TrackedEntityMapperTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/TrackedEntityMapperTest.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.tracker.imports.preheat.mappers; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.tracker.imports.preheat.mappers.AttributeCreator.attributeValues; import static org.hisp.dhis.tracker.imports.preheat.mappers.AttributeCreator.setIdSchemeFields; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -57,7 +58,7 @@ void testIdSchemeRelatedFieldsAreMapped() { OrganisationUnit orgUnit = setIdSchemeFields( - new OrganisationUnit(), + createOrganisationUnit('A'), "HpSAvRWtdDR", "meet", "green", diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/MessageFormatterTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/MessageFormatterTest.java index dbb09804f82d..5d969ae716e9 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/MessageFormatterTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/MessageFormatterTest.java @@ -29,6 +29,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.utils.Assertions.assertContainsOnly; import static org.hisp.dhis.test.utils.Assertions.assertIsEmpty; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -104,7 +105,7 @@ void formatArgumentsShouldTurnIdentifiableObjectIntoArgument() { relationshipType.setUid("WTTYiPQDqh1"); Program program = new Program("friendship"); ProgramStage programStage = new ProgramStage("meet", program); - OrganisationUnit orgUnit = new OrganisationUnit(); + OrganisationUnit orgUnit = createOrganisationUnit('A'); orgUnit.setAttributeValues(attributeValues("HpSAvRWtdDR", "sunshine")); DataElement dataElement = new DataElement(); dataElement.setAttributeValues(attributeValues("m0GpPuMUfFW", "ice")); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/MetaValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/MetaValidatorTest.java index 5af6e72e5d0e..a13524d98edc 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/MetaValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/MetaValidatorTest.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.tracker.imports.validation.validator.enrollment; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.utils.Assertions.assertIsEmpty; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1068; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1069; @@ -36,7 +37,6 @@ import java.util.Optional; import org.hisp.dhis.common.UID; -import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.program.Program; import org.hisp.dhis.trackedentity.TrackedEntity; import org.hisp.dhis.tracker.TrackerIdSchemeParams; @@ -84,7 +84,7 @@ public void setUp() { void verifyEnrollmentValidationSuccess() { Enrollment enrollment = validEnrollment(); when(preheat.getOrganisationUnit(MetadataIdentifier.ofUid(ORG_UNIT_UID))) - .thenReturn(new OrganisationUnit()); + .thenReturn(createOrganisationUnit('A')); when(preheat.getTrackedEntity(TRACKED_ENTITY_UID)).thenReturn(new TrackedEntity()); when(preheat.getProgram(MetadataIdentifier.ofUid(PROGRAM_UID))).thenReturn(new Program()); @@ -99,7 +99,7 @@ void verifyEnrollmentValidationSuccessWhenTeiIsInPayload() { when(bundle.findTrackedEntityByUid(TRACKED_ENTITY_UID)) .thenReturn(Optional.of(new org.hisp.dhis.tracker.imports.domain.TrackedEntity())); when(preheat.getOrganisationUnit(MetadataIdentifier.ofUid(ORG_UNIT_UID))) - .thenReturn(new OrganisationUnit()); + .thenReturn(createOrganisationUnit('A')); when(preheat.getProgram(MetadataIdentifier.ofUid(PROGRAM_UID))).thenReturn(new Program()); validator.validate(reporter, bundle, enrollment); @@ -122,7 +122,7 @@ void verifyEnrollmentValidationFailsWhenOrgUnitIsNotPresentInDb() { void verifyEnrollmentValidationFailsWhenTrackedEntityIsNotPresentInDbOrPayload() { Enrollment enrollment = validEnrollment(); when(preheat.getOrganisationUnit(MetadataIdentifier.ofUid(ORG_UNIT_UID))) - .thenReturn(new OrganisationUnit()); + .thenReturn(createOrganisationUnit('A')); when(preheat.getProgram(MetadataIdentifier.ofUid(PROGRAM_UID))).thenReturn(new Program()); validator.validate(reporter, bundle, enrollment); @@ -134,7 +134,7 @@ void verifyEnrollmentValidationFailsWhenTrackedEntityIsNotPresentInDbOrPayload() void verifyEnrollmentValidationFailsWhenProgramIsNotPresentInDb() { Enrollment enrollment = validEnrollment(); when(preheat.getOrganisationUnit(MetadataIdentifier.ofUid(ORG_UNIT_UID))) - .thenReturn(new OrganisationUnit()); + .thenReturn(createOrganisationUnit('A')); when(preheat.getTrackedEntity(TRACKED_ENTITY_UID)).thenReturn(new TrackedEntity()); validator.validate(reporter, bundle, enrollment); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/DataValuesValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/DataValuesValidatorTest.java index 9c46f774365b..5e9d99599208 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/DataValuesValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/DataValuesValidatorTest.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.tracker.imports.validation.validator.event; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.utils.Assertions.assertIsEmpty; import static org.hisp.dhis.tracker.imports.validation.validator.AssertValidations.assertHasError; import static org.hisp.dhis.tracker.imports.validation.validator.AssertValidations.assertNoErrors; @@ -1128,7 +1129,7 @@ private Set getProgramStageDataElements( } private OrganisationUnit organisationUnit() { - OrganisationUnit organisationUnit = new OrganisationUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); organisationUnit.setUid(ORGANISATION_UNIT_UID); return organisationUnit; } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/MetaValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/MetaValidatorTest.java index c9dbcde74fe0..d9aac02c46cf 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/MetaValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/MetaValidatorTest.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.tracker.imports.validation.validator.trackedentity; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.utils.Assertions.assertIsEmpty; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1005; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1049; @@ -34,7 +35,6 @@ import static org.mockito.Mockito.when; import org.hisp.dhis.common.UID; -import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.trackedentity.TrackedEntityType; import org.hisp.dhis.tracker.TrackerIdSchemeParams; import org.hisp.dhis.tracker.imports.bundle.TrackerBundle; @@ -81,7 +81,7 @@ public void setUp() { void verifyTrackedEntityValidationSuccess() { TrackedEntity te = validTe(); when(preheat.getOrganisationUnit(MetadataIdentifier.ofUid(ORG_UNIT_UID))) - .thenReturn(new OrganisationUnit()); + .thenReturn(createOrganisationUnit('A')); when(preheat.getTrackedEntityType(MetadataIdentifier.ofUid(TRACKED_ENTITY_TYPE_UID))) .thenReturn(new TrackedEntityType()); @@ -105,7 +105,7 @@ void verifyTrackedEntityValidationFailsWhenOrgUnitIsNotPresentInDb() { void verifyTrackedEntityValidationFailsWhenTrackedEntityTypeIsNotPresentInDb() { TrackedEntity te = validTe(); when(preheat.getOrganisationUnit(MetadataIdentifier.ofUid(ORG_UNIT_UID))) - .thenReturn(new OrganisationUnit()); + .thenReturn(createOrganisationUnit('A')); validator.validate(reporter, bundle, te); diff --git a/dhis-2/dhis-services/dhis-service-validation/src/test/java/org/hisp/dhis/validation/ValidationResultServiceTest.java b/dhis-2/dhis-services/dhis-service-validation/src/test/java/org/hisp/dhis/validation/ValidationResultServiceTest.java index 8639a8e0ba3f..d05f735efc2a 100644 --- a/dhis-2/dhis-services/dhis-service-validation/src/test/java/org/hisp/dhis/validation/ValidationResultServiceTest.java +++ b/dhis-2/dhis-services/dhis-service-validation/src/test/java/org/hisp/dhis/validation/ValidationResultServiceTest.java @@ -30,6 +30,7 @@ import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; @@ -82,7 +83,7 @@ void setUp() { List units = new ArrayList<>(); for (String uid : uids) { if (CodeGenerator.isValidUid(uid)) { - OrganisationUnit unit = new OrganisationUnit(); + OrganisationUnit unit = createOrganisationUnit('A'); unit.setUid(uid); units.add(unit); } diff --git a/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/TestBase.java b/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/TestBase.java index dc740f453a01..353ee96c8e46 100644 --- a/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/TestBase.java +++ b/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/TestBase.java @@ -303,6 +303,7 @@ protected void initServices() { // ------------------------------------------------------------------------- // Convenience methods // ------------------------------------------------------------------------- + public User getCurrentUser() { return userService.getUserByUsername(CurrentUserUtil.getCurrentUsername()); } @@ -996,23 +997,19 @@ public static DataEntryForm createDataEntryForm(char uniqueCharacter, String htm public static OrganisationUnit createOrganisationUnit(char uniqueCharacter) { OrganisationUnit unit = new OrganisationUnit(); unit.setAutoFields(); - unit.setUid(BASE_OU_UID + uniqueCharacter); unit.setName("OrganisationUnit" + uniqueCharacter); unit.setShortName("OrganisationUnitShort" + uniqueCharacter); unit.setCode("OrganisationUnitCode" + uniqueCharacter); unit.setOpeningDate(date); unit.setComment("Comment" + uniqueCharacter); - // unit.getSharing().setPublicAccess("--------"); - + unit.updatePath(); return unit; } public static OrganisationUnit createOrganisationUnit(char uniqueCharacter, Geometry geometry) { OrganisationUnit unit = createOrganisationUnit(uniqueCharacter); - unit.setGeometry(geometry); - return unit; } @@ -1025,37 +1022,36 @@ public static OrganisationUnit createOrganisationUnit( OrganisationUnit unit = createOrganisationUnit(uniqueCharacter); unit.setParent(parent); parent.getChildren().add(unit); - + unit.updatePath(); return unit; } /** + * Deprecated, use {@code createOrganisationUnit(char,OrganisationUnit)}. + * * @param name The name, short name and code of the organisation unit. */ public static OrganisationUnit createOrganisationUnit(String name) { - OrganisationUnit unit = new OrganisationUnit(); - unit.setAutoFields(); - + OrganisationUnit unit = createOrganisationUnit('Y'); unit.setUid(CodeGenerator.generateUid()); unit.setName(name); unit.setShortName(name); unit.setCode(name); - unit.setOpeningDate(date); unit.setComment("Comment " + name); - return unit; } /** + * Deprecated, use {@code createOrganisationUnit(char,OrganisationUnit)}. + * * @param name The name, short name and code of the organisation unit. * @param parent The parent. */ public static OrganisationUnit createOrganisationUnit(String name, OrganisationUnit parent) { OrganisationUnit unit = createOrganisationUnit(name); - unit.setParent(parent); parent.getChildren().add(unit); - + unit.updatePath(); return unit; } @@ -1065,12 +1061,10 @@ public static OrganisationUnit createOrganisationUnit(String name, OrganisationU public static OrganisationUnitGroup createOrganisationUnitGroup(char uniqueCharacter) { OrganisationUnitGroup group = new OrganisationUnitGroup(); group.setAutoFields(); - group.setUid(BASE_UID + uniqueCharacter); group.setName("OrganisationUnitGroup" + uniqueCharacter); group.setShortName("OrganisationUnitGroupShort" + uniqueCharacter); group.setCode("OrganisationUnitGroupCode" + uniqueCharacter); - return group; } @@ -1080,13 +1074,11 @@ public static OrganisationUnitGroup createOrganisationUnitGroup(char uniqueChara public static OrganisationUnitGroupSet createOrganisationUnitGroupSet(char uniqueCharacter) { OrganisationUnitGroupSet groupSet = new OrganisationUnitGroupSet(); groupSet.setAutoFields(); - groupSet.setName("OrganisationUnitGroupSet" + uniqueCharacter); groupSet.setShortName("OrganisationUnitGroupSet" + uniqueCharacter); groupSet.setCode("OrganisationUnitGroupSetCode" + uniqueCharacter); groupSet.setDescription("Description" + uniqueCharacter); groupSet.setCompulsory(true); - return groupSet; } From 0cb4005e83cd214ca222bfc6e4976f4bf7bfd4ad Mon Sep 17 00:00:00 2001 From: Jan Bernitt Date: Thu, 9 Jan 2025 14:53:20 +0100 Subject: [PATCH 04/11] feat: include most recent job progress in post condition error message [DHIS2-18751] (#19621) * fix: executeNow back to standard @Transactional [DHIS2-18751] * chore: removed unused fields and throws exceptions, add validation * fix: execute now API * fix: getSingleResult with null * fix: tx scopes so that execute now is visble directly * fix: mock test compile issue * fix: test setup --- .../scheduling/JobConfigurationService.java | 8 --- .../scheduling/JobConfigurationStore.java | 2 - .../dhis/scheduling/JobExecutionService.java} | 51 ++++++------- .../dhis/scheduling/JobSchedulerService.java | 23 +----- .../parameters/TestJobParameters.java | 2 + .../HibernateDataIntegrityStore.java | 3 +- .../HibernateDashboardItemStore.java | 2 +- .../HibernateOrganisationUnitStore.java | 2 +- .../DefaultJobConfigurationService.java | 58 +++++---------- ...n.java => DefaultJobExecutionService.java} | 58 +++++++++------ .../DefaultJobSchedulerService.java | 55 +++----------- .../HibernateJobConfigurationStore.java | 28 ++------ .../dhis/scheduling/JobCreationHelper.java | 72 ------------------- .../hisp/dhis/scheduling/JobScheduler.java | 4 +- .../dhis/scheduling/RecordingJobProgress.java | 18 ++++- .../org/hisp/dhis/scheduling/TestJob.java | 2 + .../HibernateMetadataProposalStore.java | 4 +- .../JobSchedulingControllerTest.java | 6 +- ...CompleteDataSetRegistrationController.java | 18 ++--- .../controller/DataIntegrityController.java | 17 ++--- .../controller/DataValueSetController.java | 21 +++--- .../controller/GeoJsonImportController.java | 17 ++--- .../controller/PredictionController.java | 9 ++- .../controller/PushAnalysisController.java | 8 +-- .../controller/ResourceTableController.java | 19 ++--- .../MetadataImportExportController.java | 19 ++--- .../JobConfigurationController.java | 11 ++- .../controller/sms/SmsInboundController.java | 15 ++-- .../imports/TrackerImportController.java | 15 ++-- .../validation/ValidationController.java | 12 ++-- .../imports/TrackerImportControllerTest.java | 10 +-- 31 files changed, 204 insertions(+), 385 deletions(-) rename dhis-2/{dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelperForTests.java => dhis-api/src/main/java/org/hisp/dhis/scheduling/JobExecutionService.java} (60%) rename dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/{JobCreationHelperForProduction.java => DefaultJobExecutionService.java} (54%) delete mode 100644 dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelper.java diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationService.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationService.java index dec50e0c1a39..80a0834f65a3 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationService.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationService.java @@ -32,7 +32,6 @@ import java.util.Map; import javax.annotation.Nonnull; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.schema.Property; import org.hisp.dhis.user.UserDetails; import org.springframework.util.MimeType; @@ -62,13 +61,6 @@ String create(JobConfiguration config, MimeType contentType, InputStream content void createDefaultJob(JobType type, UserDetails actingUser); - String createInTransaction( - JobConfiguration jobConfiguration, MimeType contentType, InputStream content) - throws ConflictException, NotFoundException; - - String createInTransaction(JobConfiguration jobConfiguration) - throws ConflictException, NotFoundException; - /** * Updates all {@link JobConfiguration}s that are not {@link JobConfiguration#isEnabled()} to * state {@link JobStatus#DISABLED} in case they are in state {@link JobStatus#SCHEDULED}. diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationStore.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationStore.java index 0d6de0b6e91e..5094901949d9 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationStore.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationStore.java @@ -175,8 +175,6 @@ public interface JobConfigurationStore extends GenericDimensionalObjectStore - */ -@Slf4j -@RequiredArgsConstructor -@Service -@Profile("test") -public class JobCreationHelperForTests implements JobCreationHelper { - - private final JobConfigurationStore jobConfigurationStore; - private final FileResourceService fileResourceService; +public interface JobExecutionService { - @Transactional - public String create(JobConfiguration config) throws ConflictException { - return createFromConfig(config, jobConfigurationStore); - } + /** + * Creates and runs a new job for one-off operations executed via the scheduler. + * + * @param config a new job that does not exist yet + * @param contentType of the provided content data + * @param content the data that should be processed by the job which is stored as file + * @throws ConflictException in case the config belongs to an existing job or when the job isn't + * configured correctly + */ + void executeOnceNow( + @Nonnull JobConfiguration config, @Nonnull MimeType contentType, @Nonnull InputStream content) + throws ConflictException; - @Transactional - public String create(JobConfiguration config, MimeType contentType, InputStream content) - throws ConflictException { - return createFromConfigAndInputStream( - config, contentType, content, jobConfigurationStore, fileResourceService); - } + /** + * Creates and runs a new job for one-off operations executed via the scheduler. + * + * @param config a new job that does not exist yet + * @throws ConflictException in case the config belongs to an existing job or when the job isn't + * configured correctly + */ + void executeOnceNow(@Nonnull JobConfiguration config) throws ConflictException; } diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobSchedulerService.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobSchedulerService.java index 8324a21fff0f..708989cad5a1 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobSchedulerService.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobSchedulerService.java @@ -27,18 +27,15 @@ */ package org.hisp.dhis.scheduling; -import java.io.InputStream; import java.util.List; import java.util.Set; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; -import org.hisp.dhis.common.NonTransactional; import org.hisp.dhis.common.UID; import org.hisp.dhis.feedback.ConflictException; import org.hisp.dhis.feedback.ForbiddenException; import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.scheduling.JobProgress.Progress; -import org.springframework.util.MimeType; /** * This is the external API (called by users via controller API) for the scheduling. @@ -49,7 +46,9 @@ public interface JobSchedulerService { /** - * Attempts to switch the {@link JobConfiguration#getSchedulingType()} to {@link + * Ad-hoc execution of existing jobs. + * + *

Attempts to switch the {@link JobConfiguration#getSchedulingType()} to {@link * SchedulingType#ONCE_ASAP} for the given job. * *

A job with a {@link JobConfiguration#getCronExpression()} switches back to {@link @@ -63,22 +62,6 @@ public interface JobSchedulerService { */ void executeNow(@Nonnull String jobId) throws ConflictException, NotFoundException; - /** - * Executes a job configuration in a separate transaction. - * - * @param jobId the job id to execute - * @throws NotFoundException - * @throws ConflictException - */ - void runInTransaction(String jobId) throws NotFoundException, ConflictException; - - @NonTransactional - void createThenExecute(JobConfiguration config, MimeType contentType, InputStream content) - throws ConflictException, NotFoundException; - - @NonTransactional - void createThenExecute(JobConfiguration config) throws ConflictException, NotFoundException; - /** * Reverts the {@link JobStatus} of the job from {@link JobStatus#RUNNING} to the appropriate * status after a failed execution. For an ad-hoc job this is {@link JobStatus#DISABLED}, for a diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/parameters/TestJobParameters.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/parameters/TestJobParameters.java index 4cb9d19d29b1..47df72b298eb 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/parameters/TestJobParameters.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/parameters/TestJobParameters.java @@ -66,6 +66,8 @@ public class TestJobParameters implements JobParameters { /** When true, an exception is used to fail, otherwise the progress tracking api is used */ @JsonProperty private boolean failWithException; + @JsonProperty private boolean failWithPostCondition; + /** Stage failure policy to use, when {@code null} it is the default policy */ @JsonProperty private FailurePolicy failWithPolicy; diff --git a/dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/hibernate/HibernateDataIntegrityStore.java b/dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/hibernate/HibernateDataIntegrityStore.java index f59b413fd85b..4e008cab873b 100644 --- a/dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/hibernate/HibernateDataIntegrityStore.java +++ b/dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/hibernate/HibernateDataIntegrityStore.java @@ -58,7 +58,8 @@ public class HibernateDataIntegrityStore implements DataIntegrityStore { public DataIntegritySummary querySummary(DataIntegrityCheck check, String sql) { Date startTime = new Date(); // Note! that the SQL here can be touching any table so we cannot sync it - Object summary = entityManager.createNativeQuery(sql).getSingleResult(); + Object summary = + entityManager.createNativeQuery(sql).getResultStream().findFirst().orElse(null); return new DataIntegritySummary( check, startTime, new Date(), null, parseCount(summary), parsePercentage(summary)); } diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dashboard/hibernate/HibernateDashboardItemStore.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dashboard/hibernate/HibernateDashboardItemStore.java index 087858dcf807..c7707902f8d0 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dashboard/hibernate/HibernateDashboardItemStore.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dashboard/hibernate/HibernateDashboardItemStore.java @@ -67,7 +67,7 @@ public Dashboard getDashboardFromDashboardItem(DashboardItem dashboardItem) { Query query = getTypedQuery("from Dashboard d where :item in elements(d.items)"); query.setParameter("item", dashboardItem); - return query.getSingleResult(); + return getSingleResult(query); } @Override 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 a7a39218a51c..ce85602ee002 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 @@ -319,7 +319,7 @@ public int getMaxLevel() { String hql = "select max(ou.hierarchyLevel) from OrganisationUnit ou"; Query query = getTypedQuery(hql); - Integer maxLength = query.getSingleResult(); + Integer maxLength = getSingleResult(query); return maxLength != null ? maxLength : 0; } diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobConfigurationService.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobConfigurationService.java index b3af654bb06b..e1749f453806 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobConfigurationService.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobConfigurationService.java @@ -63,8 +63,8 @@ import org.hisp.dhis.commons.util.TextUtils; import org.hisp.dhis.feedback.ConflictException; import org.hisp.dhis.feedback.ErrorCode; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.fileresource.FileResource; +import org.hisp.dhis.fileresource.FileResourceDomain; import org.hisp.dhis.fileresource.FileResourceService; import org.hisp.dhis.fileresource.FileResourceStorageStatus; import org.hisp.dhis.jsontree.JsonMixed; @@ -92,17 +92,30 @@ public class DefaultJobConfigurationService implements JobConfigurationService { private final JobConfigurationStore jobConfigurationStore; private final FileResourceService fileResourceService; private final SystemSettingsProvider settingsProvider; - private final JobCreationHelper jobCreationHelper; @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) public String create(JobConfiguration config) throws ConflictException { - return jobCreationHelper.create(config); + config.setAutoFields(); + jobConfigurationStore.save(config); + return config.getUid(); } @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) public String create(JobConfiguration config, MimeType contentType, InputStream content) throws ConflictException { - return jobCreationHelper.create(config, contentType, content); + if (config.getSchedulingType() != SchedulingType.ONCE_ASAP) + throw new ConflictException( + "Job must be of type %s to allow content data".formatted(SchedulingType.ONCE_ASAP)); + config.setAutoFields(); // ensure UID is set + FileResource fr = + FileResource.ofKey(FileResourceDomain.JOB_DATA, config.getUid(), contentType.toString()); + fr.setUid(config.getUid()); + fr.setAssigned(true); + fileResourceService.syncSaveFileResource(fr, content); + jobConfigurationStore.save(config); + return config.getUid(); } @Override @@ -140,43 +153,6 @@ public void createDefaultJob(JobType type) { createDefaultJob(type, CurrentUserUtil.getCurrentUserDetails()); } - @Override - @Transactional(propagation = Propagation.REQUIRES_NEW) - public String createInTransaction( - JobConfiguration jobConfiguration, MimeType contentType, InputStream content) - throws ConflictException, NotFoundException { - String jobId = jobCreationHelper.create(jobConfiguration, contentType, content); - - if (!jobConfigurationStore.executeNow(jobId)) { - JobConfiguration job = jobConfigurationStore.getByUid(jobId); - if (job == null) throw new NotFoundException(JobConfiguration.class, jobId); - if (job.getJobStatus() == JobStatus.RUNNING) - throw new ConflictException("Job is already running."); - if (job.getSchedulingType() == SchedulingType.ONCE_ASAP && job.getLastFinished() != null) - throw new ConflictException("Job did already run once."); - throw new ConflictException("Failed to transition job into ONCE_ASAP state."); - } - return jobId; - } - - @Override - @Transactional(propagation = Propagation.REQUIRES_NEW) - public String createInTransaction(JobConfiguration jobConfiguration) - throws ConflictException, NotFoundException { - String jobId = jobCreationHelper.create(jobConfiguration); - - if (!jobConfigurationStore.executeNow(jobId)) { - JobConfiguration job = jobConfigurationStore.getByUid(jobId); - if (job == null) throw new NotFoundException(JobConfiguration.class, jobId); - if (job.getJobStatus() == JobStatus.RUNNING) - throw new ConflictException("Job is already running."); - if (job.getSchedulingType() == SchedulingType.ONCE_ASAP && job.getLastFinished() != null) - throw new ConflictException("Job did already run once."); - throw new ConflictException("Failed to transition job into ONCE_ASAP state."); - } - return jobId; - } - @Override @Transactional public int updateDisabledJobs() { diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelperForProduction.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobExecutionService.java similarity index 54% rename from dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelperForProduction.java rename to dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobExecutionService.java index 7eb431b13b48..b2b68b0038c9 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelperForProduction.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobExecutionService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2024, University of Oslo + * Copyright (c) 2004-2025, University of Oslo * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,36 +28,54 @@ package org.hisp.dhis.scheduling; import java.io.InputStream; +import javax.annotation.Nonnull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.hisp.dhis.common.NonTransactional; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.fileresource.FileResourceService; -import org.springframework.context.annotation.Profile; +import org.hisp.dhis.feedback.NotFoundException; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import org.springframework.util.MimeType; -/** - * @author Morten Svanæs - */ @Slf4j -@RequiredArgsConstructor @Service -@Profile("!test") -public class JobCreationHelperForProduction implements JobCreationHelper { +@RequiredArgsConstructor +public class DefaultJobExecutionService implements JobExecutionService { - private final JobConfigurationStore jobConfigurationStore; - private final FileResourceService fileResourceService; + private final JobConfigurationService jobConfigurationService; + private final JobSchedulerService jobSchedulerService; - @Transactional - public String create(JobConfiguration config) throws ConflictException { - return createFromConfig(config, jobConfigurationStore); + @Override + @NonTransactional + public void executeOnceNow( + @Nonnull JobConfiguration config, @Nonnull MimeType contentType, @Nonnull InputStream content) + throws ConflictException { + validateIsNewRunOnce(config); + executeOnceNow(jobConfigurationService.create(config, contentType, content)); } - @Transactional - public String create(JobConfiguration config, MimeType contentType, InputStream content) - throws ConflictException { - return createFromConfigAndInputStream( - config, contentType, content, jobConfigurationStore, fileResourceService); + @Override + @NonTransactional + public void executeOnceNow(@Nonnull JobConfiguration config) throws ConflictException { + validateIsNewRunOnce(config); + executeOnceNow(jobConfigurationService.create(config)); + } + + private void executeOnceNow(String jobId) throws ConflictException { + try { + jobSchedulerService.executeNow(jobId); + } catch (NotFoundException ex) { + log.error("Ad-hoc job creation failed", ex); + ConflictException error = new ConflictException("Ad-hoc job creation failed"); + error.initCause(ex); + throw error; + } + } + + private void validateIsNewRunOnce(JobConfiguration config) throws ConflictException { + if (config.getId() != 0 || config.getSchedulingType() != SchedulingType.ONCE_ASAP) + throw new ConflictException( + "Job %s must be a run once type but was: %s" + .formatted(config.getName(), config.getSchedulingType())); } } diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerService.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerService.java index dedad7f48690..a36cc0e5426d 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerService.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerService.java @@ -33,7 +33,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.InputStream; import java.util.Collection; import java.util.List; import java.util.Map; @@ -50,9 +49,7 @@ import org.hisp.dhis.scheduling.JobProgress.Progress; import org.hisp.dhis.user.UserDetails; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.MimeType; /** * @author Jan Bernitt @@ -63,11 +60,9 @@ @RequiredArgsConstructor public class DefaultJobSchedulerService implements JobSchedulerService { - private final JobConfigurationStore jobConfigurationStore; private final JobRunner jobRunner; + private final JobConfigurationStore jobConfigurationStore; private final ObjectMapper jsonMapper; - private final JobCreationHelper jobCreationHelper; - private final JobConfigurationService jobConfigurationService; @Override @Transactional @@ -82,11 +77,16 @@ public boolean requestCancel(@Nonnull JobType type) { return jobId != null && requestCancel(jobId); } + /** + * Note that the TX is opened on the store level for {@code tryExecuteNow} so that state changes + * to the job are already visible to other threads even when called from within this method as + * done in case of continuous execution. + */ @Override - @Transactional + @NonTransactional public void executeNow(@Nonnull String jobId) throws NotFoundException, ConflictException { if (!jobConfigurationStore.tryExecuteNow(jobId)) { - JobConfiguration job = jobConfigurationStore.getByUid(jobId); + JobConfiguration job = jobConfigurationStore.getByUidNoAcl(jobId); if (job == null) throw new NotFoundException(JobConfiguration.class, jobId); if (job.getJobStatus() == JobStatus.RUNNING) throw new ConflictException("Job is already running."); @@ -95,45 +95,12 @@ public void executeNow(@Nonnull String jobId) throws NotFoundException, Conflict throw new ConflictException("Failed to transition job into ONCE_ASAP state."); } if (!jobRunner.isScheduling()) { - JobConfiguration job = jobConfigurationStore.getByUid(jobId); - if (job == null) throw new NotFoundException(JobConfiguration.class, jobId); - // run "execute now" request directly when scheduling is not active (tests) - jobRunner.runDueJob(job); - } else { - JobConfiguration job = jobConfigurationStore.getByUid(jobId); - if (job == null) throw new NotFoundException(JobConfiguration.class, jobId); - if (job.getJobType().isUsingContinuousExecution()) { - jobRunner.runIfDue(job); - } - } - } - - @Override - @NonTransactional - public void createThenExecute(JobConfiguration config, MimeType contentType, InputStream content) - throws ConflictException, NotFoundException { - String jobId = jobConfigurationService.createInTransaction(config, contentType, content); - runInTransaction(jobId); - } - - @Override - @NonTransactional - public void createThenExecute(JobConfiguration config) - throws ConflictException, NotFoundException { - String jobId = jobConfigurationService.createInTransaction(config); - runInTransaction(jobId); - } - - @Override - @Transactional(propagation = Propagation.REQUIRES_NEW) - public void runInTransaction(String jobId) throws NotFoundException, ConflictException { - if (!jobRunner.isScheduling()) { - JobConfiguration job = jobConfigurationStore.getByUid(jobId); + JobConfiguration job = jobConfigurationStore.getByUidNoAcl(jobId); if (job == null) throw new NotFoundException(JobConfiguration.class, jobId); // run "execute now" request directly when scheduling is not active (tests) jobRunner.runDueJob(job); } else { - JobConfiguration job = jobConfigurationStore.getByUid(jobId); + JobConfiguration job = jobConfigurationStore.getByUidNoAcl(jobId); if (job == null) throw new NotFoundException(JobConfiguration.class, jobId); if (job.getJobType().isUsingContinuousExecution()) { jobRunner.runIfDue(job); @@ -149,7 +116,7 @@ public void revertNow(@Nonnull UID jobId) if (!currentUser.isAuthorized(F_PERFORM_MAINTENANCE)) throw new ForbiddenException(JobConfiguration.class, jobId.getValue()); if (!jobConfigurationStore.tryRevertNow(jobId.getValue())) { - JobConfiguration job = jobConfigurationStore.getByUid(jobId.getValue()); + JobConfiguration job = jobConfigurationStore.getByUidNoAcl(jobId.getValue()); if (job == null) throw new NotFoundException(JobConfiguration.class, jobId.getValue()); if (job.getJobStatus() != JobStatus.RUNNING) throw new ConflictException("Job is not running"); diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/HibernateJobConfigurationStore.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/HibernateJobConfigurationStore.java index 0cc216f956a8..d7db1f60b562 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/HibernateJobConfigurationStore.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/HibernateJobConfigurationStore.java @@ -48,7 +48,6 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; -import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; /** @@ -269,8 +268,13 @@ select jsonb_build_object( Object::toString); } + /** + * Note that the transaction boundary has been set here instead of the service to avoid over + * complicating the "executeNow" service method which needs this change to be completed and + * visible at the end of this method. + */ @Override - @Transactional(propagation = Propagation.REQUIRES_NEW) + @Transactional public boolean tryExecuteNow(@Nonnull String jobId) { String sql = """ @@ -287,23 +291,6 @@ public boolean tryExecuteNow(@Nonnull String jobId) { return nativeSynchronizedQuery(sql).setParameter("id", jobId).executeUpdate() > 0; } - @Override - public boolean executeNow(@Nonnull String jobId) { - String sql = - """ - update jobconfiguration - set - schedulingtype = 'ONCE_ASAP', - cancel = false, - jobstatus = 'SCHEDULED' - where uid = :id - and enabled = true - and jobstatus != 'RUNNING' - and (schedulingtype != 'ONCE_ASAP' or lastfinished is null) - """; - return nativeSynchronizedQuery(sql).setParameter("id", jobId).executeUpdate() > 0; - } - @Override public boolean tryStart(@Nonnull String jobId) { // only flip from SCHEDULED to RUNNING if no other job of same type is RUNNING @@ -532,8 +519,7 @@ public boolean tryRevertNow(@Nonnull String jobId) { } private static String getSingleResultOrNull(NativeQuery query) { - List res = query.list(); - return res == null || res.isEmpty() ? null : (String) res.get(0); + return (String) query.getResultStream().findFirst().orElse(null); } @SuppressWarnings("unchecked") diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelper.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelper.java deleted file mode 100644 index 5c15c2aff28f..000000000000 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelper.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2004-2024, University of Oslo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.hisp.dhis.scheduling; - -import java.io.InputStream; -import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.fileresource.FileResource; -import org.hisp.dhis.fileresource.FileResourceDomain; -import org.hisp.dhis.fileresource.FileResourceService; -import org.springframework.util.MimeType; - -/** - * @author Morten Svanæs - */ -public interface JobCreationHelper { - - String create(JobConfiguration config) throws ConflictException; - - String create(JobConfiguration config, MimeType contentType, InputStream content) - throws ConflictException; - - default String createFromConfig(JobConfiguration config, JobConfigurationStore store) { - config.setAutoFields(); - store.save(config); - return config.getUid(); - } - - default String createFromConfigAndInputStream( - JobConfiguration config, - MimeType contentType, - InputStream content, - JobConfigurationStore store, - FileResourceService fileResourceService) - throws ConflictException { - if (config.getSchedulingType() != SchedulingType.ONCE_ASAP) - throw new ConflictException( - "Job must be of type %s to allow content data".formatted(SchedulingType.ONCE_ASAP)); - config.setAutoFields(); // ensure UID is set - FileResource fr = - FileResource.ofKey(FileResourceDomain.JOB_DATA, config.getUid(), contentType.toString()); - fr.setUid(config.getUid()); - fr.setAssigned(true); - fileResourceService.syncSaveFileResource(fr, content); - store.save(config); - return config.getUid(); - } -} diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobScheduler.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobScheduler.java index 0b74023e93b5..484e15f20d29 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobScheduler.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobScheduler.java @@ -179,7 +179,7 @@ private void runContinuous(JobType type) { String jobId = jobIds.poll(); while (jobId != null) { JobConfiguration config = service.getJobConfiguration(jobId); - if (config != null && config.getJobStatus() == JobStatus.SCHEDULED) { + if (config != null && (config.getJobStatus() == JobStatus.SCHEDULED)) { Instant now = Instant.now().truncatedTo(ChronoUnit.SECONDS); Instant dueTime = dueTime(now, config); runDueJob(config, dueTime); @@ -225,7 +225,7 @@ private void runDueJob(JobConfiguration config, Instant start) { JobProgress progress = null; try { settingsProvider.clearCurrentSettings(); // ensure working with recent settings - AtomicLong lastAlive = new AtomicLong(currentTimeMillis()); + AtomicLong lastAlive = new AtomicLong(0L); progress = service.startRun(jobId, config.getExecutedBy(), () -> alive(jobId, lastAlive)); jobService.getJob(config.getJobType()).execute(config, progress); diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/RecordingJobProgress.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/RecordingJobProgress.java index c1f5eb712d25..d416b6133154 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/RecordingJobProgress.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/RecordingJobProgress.java @@ -214,12 +214,27 @@ private RuntimeException cancellationException(boolean failedPostCondition) { if (skipRecording && cause instanceof RuntimeException rex) throw rex; CancellationException ex = failedPostCondition - ? new CancellationException("Non-null post-condition failed") + ? new CancellationException(postConditionFailureMessage()) : new CancellationException(); ex.initCause(cause); return ex; } + private String postConditionFailureMessage() { + String msg = "Non-null post-condition failed after: "; + Process p = incompleteProcess.get(); + if (p != null) { + msg += p.getDescription(); + Stage s = incompleteStage.get(); + if (s != null) { + msg += "\n => " + s.getDescription(); + Item i = incompleteItem.get(); + if (i != null) msg += "\n => " + i.getDescription(); + } + } + return msg; + } + @Override public void completedProcess(String summary, Object... args) { observer.run(); @@ -279,6 +294,7 @@ public void startingStage( if (isCancelled()) throw cancellationException(false); skipCurrentStage.set(false); tracker.startingStage(description, workItems); + incompleteItem.remove(); Stage stage = addStageRecord(getOrAddLastIncompleteProcess(), description, workItems, onFailure); logInfo(stage, "", description); diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/TestJob.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/TestJob.java index 5dc879166cc2..9a6f4089af55 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/TestJob.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/TestJob.java @@ -87,6 +87,7 @@ public void execute(JobConfiguration conf, JobProgress progress) { simulateWorkForDuration(params.getItemDuration()); if (failAtThisStage && item == failAtItem) { progress.failedWorkItem(msg); + if (params.isFailWithPostCondition()) progress.nonNullStagePostCondition(null); } else { progress.completedWorkItem(null); } @@ -95,6 +96,7 @@ public void execute(JobConfiguration conf, JobProgress progress) { } else if (failAtThisStage) { if (params.isFailWithException()) throw new RuntimeException(msg); progress.failedStage(msg); + if (params.isFailWithPostCondition()) progress.nonNullStagePostCondition(null); } else { progress.completedStage(format("Stage %d complete", stage + 1)); } diff --git a/dhis-2/dhis-services/dhis-service-metadata-workflow/src/main/java/org/hisp/dhis/metadata/HibernateMetadataProposalStore.java b/dhis-2/dhis-services/dhis-service-metadata-workflow/src/main/java/org/hisp/dhis/metadata/HibernateMetadataProposalStore.java index 90381eaaddeb..bdaee738bbc4 100644 --- a/dhis-2/dhis-services/dhis-service-metadata-workflow/src/main/java/org/hisp/dhis/metadata/HibernateMetadataProposalStore.java +++ b/dhis-2/dhis-services/dhis-service-metadata-workflow/src/main/java/org/hisp/dhis/metadata/HibernateMetadataProposalStore.java @@ -49,7 +49,9 @@ public MetadataProposal getByUid(String uid) { return getSession() .createQuery("from MetadataProposal p where p.uid = :uid", MetadataProposal.class) .setParameter("uid", uid) - .getSingleResult(); + .getResultStream() + .findFirst() + .orElse(null); } @Override diff --git a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/JobSchedulingControllerTest.java b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/JobSchedulingControllerTest.java index 6ac3f48adf20..d6a2d2537f7a 100644 --- a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/JobSchedulingControllerTest.java +++ b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/JobSchedulingControllerTest.java @@ -35,14 +35,12 @@ import org.hisp.dhis.jsontree.JsonObject; import org.hisp.dhis.test.webapi.PostgresControllerIntegrationTestBase; import org.junit.jupiter.api.Test; -import org.springframework.transaction.annotation.Transactional; /** * Tests the {@link org.hisp.dhis.webapi.controller.scheduling.SchedulingController}. * * @author Jan Bernitt */ -@Transactional class JobSchedulingControllerTest extends PostgresControllerIntegrationTestBase { @Test @@ -65,14 +63,14 @@ void testGetCompletedProgressTypes() { @Test void testGetRunningProgress() { - JsonObject progress = GET("/scheduling/running/DATA_INTEGRITY").content(); + JsonObject progress = GET("/scheduling/running/PUSH_ANALYSIS").content(); assertTrue(progress.isObject()); assertTrue(progress.isEmpty()); } @Test void testGetCompletedProgress() { - JsonObject progress = GET("/scheduling/completed/DATA_INTEGRITY").content(); + JsonObject progress = GET("/scheduling/completed/PUSH_ANALYSIS").content(); assertTrue(progress.isObject()); assertTrue(progress.isEmpty()); } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CompleteDataSetRegistrationController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CompleteDataSetRegistrationController.java index 7f4e13de57d0..a099aa28926f 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CompleteDataSetRegistrationController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CompleteDataSetRegistrationController.java @@ -63,17 +63,14 @@ import org.hisp.dhis.dxf2.webmessage.WebMessage; import org.hisp.dhis.dxf2.webmessage.WebMessageException; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.organisationunit.OrganisationUnitService; import org.hisp.dhis.period.Period; import org.hisp.dhis.period.PeriodType; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; -import org.hisp.dhis.scheduling.JobSchedulerService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.user.CurrentUserUtil; import org.hisp.dhis.user.UserDetails; -import org.hisp.dhis.user.UserService; import org.hisp.dhis.webapi.mvc.annotation.ApiVersion; import org.hisp.dhis.webapi.webdomain.CompleteDataSetRegQueryParams; import org.springframework.http.HttpStatus; @@ -112,10 +109,7 @@ public class CompleteDataSetRegistrationController { private final CompleteDataSetRegistrationExchangeService registrationExchangeService; - private final JobConfigurationService jobConfigurationService; - private final JobSchedulerService jobSchedulerService; - - private final UserService userService; + private final JobExecutionService jobExecutionService; // ------------------------------------------------------------------------- // GET @@ -149,7 +143,7 @@ public void getCompleteRegistrationsXml( @ResponseBody public WebMessage postCompleteRegistrationsXml( ImportOptions importOptions, HttpServletRequest request) - throws IOException, ConflictException, NotFoundException { + throws IOException, ConflictException { if (importOptions.isAsync()) { return asyncImport(importOptions, APPLICATION_XML, request); } @@ -164,7 +158,7 @@ public WebMessage postCompleteRegistrationsXml( @ResponseBody public WebMessage postCompleteRegistrationsJson( ImportOptions importOptions, HttpServletRequest request) - throws IOException, ConflictException, NotFoundException { + throws IOException, ConflictException { if (importOptions.isAsync()) { return asyncImport(importOptions, APPLICATION_JSON, request); } @@ -260,13 +254,13 @@ public void deleteCompleteDataSetRegistration( private WebMessage asyncImport( ImportOptions importOptions, MimeType mimeType, HttpServletRequest request) - throws IOException, ConflictException, NotFoundException { + throws IOException, ConflictException { JobConfiguration jobConfig = new JobConfiguration(COMPLETE_DATA_SET_REGISTRATION_IMPORT); jobConfig.setJobParameters(importOptions); jobConfig.setExecutedBy(CurrentUserUtil.getCurrentUserDetails().getUid()); - jobSchedulerService.createThenExecute(jobConfig, mimeType, request.getInputStream()); + jobExecutionService.executeOnceNow(jobConfig, mimeType, request.getInputStream()); return jobConfigurationReport(jobConfig); } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataIntegrityController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataIntegrityController.java index 606da5e7e712..e6fe860c71a0 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataIntegrityController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataIntegrityController.java @@ -47,11 +47,9 @@ import org.hisp.dhis.dataintegrity.DataIntegritySummary; import org.hisp.dhis.dxf2.webmessage.WebMessage; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.scheduling.JobParameters; -import org.hisp.dhis.scheduling.JobSchedulerService; import org.hisp.dhis.scheduling.JobType; import org.hisp.dhis.scheduling.parameters.DataIntegrityDetailsJobParameters; import org.hisp.dhis.scheduling.parameters.DataIntegrityJobParameters; @@ -82,8 +80,7 @@ public class DataIntegrityController { private final DataIntegrityService dataIntegrityService; - private final JobConfigurationService jobConfigurationService; - private final JobSchedulerService jobSchedulerService; + private final JobExecutionService jobExecutionService; @RequiresAuthority(anyOf = F_PERFORM_MAINTENANCE) @PostMapping @@ -92,7 +89,7 @@ public WebMessage runDataIntegrity( @CheckForNull @RequestParam(required = false) Set checks, @CheckForNull @RequestBody(required = false) Set checksBody, @CurrentUser UserDetails currentUser) - throws ConflictException, @OpenApi.Ignore NotFoundException { + throws ConflictException { Set names = getCheckNames(checksBody, checks); return runDataIntegrityAsync(names, currentUser, DataIntegrityReportType.SUMMARY) .setLocation("/dataIntegrity/details?checks=" + toChecksList(names)); @@ -100,7 +97,7 @@ public WebMessage runDataIntegrity( private WebMessage runDataIntegrityAsync( @Nonnull Set checks, UserDetails currentUser, DataIntegrityReportType type) - throws ConflictException, NotFoundException { + throws ConflictException { JobType jobType = type == DataIntegrityReportType.DETAILS ? JobType.DATA_INTEGRITY_DETAILS @@ -113,7 +110,7 @@ private WebMessage runDataIntegrityAsync( : new DataIntegrityJobParameters(type, checks); config.setJobParameters(parameters); - jobSchedulerService.createThenExecute(config); + jobExecutionService.executeOnceNow(config); return jobConfigurationReport(config); } @@ -162,7 +159,7 @@ public WebMessage runSummariesCheck( @CheckForNull @RequestParam(required = false) Set checks, @CheckForNull @RequestBody(required = false) Set checksBody, @CurrentUser UserDetails currentUser) - throws ConflictException, @OpenApi.Ignore NotFoundException { + throws ConflictException { Set names = getCheckNames(checksBody, checks); return runDataIntegrityAsync(names, currentUser, DataIntegrityReportType.SUMMARY) .setLocation("/dataIntegrity/summary?checks=" + toChecksList(names)); @@ -196,7 +193,7 @@ public WebMessage runDetailsCheck( @CheckForNull @RequestParam(required = false) Set checks, @RequestBody(required = false) Set checksBody, @CurrentUser UserDetails currentUser) - throws ConflictException, @OpenApi.Ignore NotFoundException { + throws ConflictException { Set names = getCheckNames(checksBody, checks); return runDataIntegrityAsync(names, currentUser, DataIntegrityReportType.DETAILS) .setLocation("/dataIntegrity/details?checks=" + toChecksList(names)); diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataValueSetController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataValueSetController.java index b4a58a2d7181..4c2281fd5acb 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataValueSetController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataValueSetController.java @@ -67,11 +67,9 @@ import org.hisp.dhis.dxf2.importsummary.ImportSummary; import org.hisp.dhis.dxf2.webmessage.WebMessage; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.node.Provider; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; -import org.hisp.dhis.scheduling.JobSchedulerService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.security.RequiresAuthority; import org.hisp.dhis.user.CurrentUserUtil; import org.hisp.dhis.user.User; @@ -104,8 +102,7 @@ public class DataValueSetController { private final DataValueSetService dataValueSetService; private final AdxDataService adxDataService; private final UserService userService; - private final JobConfigurationService jobConfigurationService; - private final JobSchedulerService jobSchedulerService; + private final JobExecutionService jobExecutionService; // ------------------------------------------------------------------------- // Get @@ -234,7 +231,7 @@ private void getDataValueSet( @RequiresAuthority(anyOf = F_DATAVALUE_ADD) @ResponseBody public WebMessage postDxf2DataValueSet(ImportOptions importOptions, HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { if (importOptions.isAsync()) { return startAsyncImport(importOptions, MediaType.APPLICATION_XML, request); } @@ -249,7 +246,7 @@ public WebMessage postDxf2DataValueSet(ImportOptions importOptions, HttpServletR @RequiresAuthority(anyOf = F_DATAVALUE_ADD) @ResponseBody public WebMessage postAdxDataValueSet(ImportOptions importOptions, HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { if (importOptions.isAsync()) { return startAsyncImport(importOptions, MimeType.valueOf("application/adx+xml"), request); } @@ -264,7 +261,7 @@ public WebMessage postAdxDataValueSet(ImportOptions importOptions, HttpServletRe @RequiresAuthority(anyOf = F_DATAVALUE_ADD) @ResponseBody public WebMessage postJsonDataValueSet(ImportOptions importOptions, HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { if (importOptions.isAsync()) { return startAsyncImport(importOptions, MediaType.APPLICATION_JSON, request); } @@ -279,7 +276,7 @@ public WebMessage postJsonDataValueSet(ImportOptions importOptions, HttpServletR @RequiresAuthority(anyOf = F_DATAVALUE_ADD) @ResponseBody public WebMessage postCsvDataValueSet(ImportOptions importOptions, HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { if (importOptions.isAsync()) { return startAsyncImport(importOptions, MimeType.valueOf("application/csv"), request); } @@ -294,7 +291,7 @@ public WebMessage postCsvDataValueSet(ImportOptions importOptions, HttpServletRe @RequiresAuthority(anyOf = F_DATAVALUE_ADD) @ResponseBody public WebMessage postPdfDataValueSet(ImportOptions importOptions, HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { if (importOptions.isAsync()) { return startAsyncImport(importOptions, MediaType.APPLICATION_PDF, request); } @@ -312,13 +309,13 @@ public WebMessage postPdfDataValueSet(ImportOptions importOptions, HttpServletRe /** Starts an asynchronous import task. */ private WebMessage startAsyncImport( ImportOptions importOptions, MimeType mimeType, HttpServletRequest request) - throws ConflictException, IOException, NotFoundException { + throws ConflictException, IOException { JobConfiguration config = new JobConfiguration(DATAVALUE_IMPORT); User currentUser = userService.getUserByUsername(CurrentUserUtil.getCurrentUsername()); config.setExecutedBy(currentUser.getUid()); config.setJobParameters(importOptions); - jobSchedulerService.createThenExecute(config, mimeType, request.getInputStream()); + jobExecutionService.executeOnceNow(config, mimeType, request.getInputStream()); return jobConfigurationReport(config); } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/GeoJsonImportController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/GeoJsonImportController.java index 22537a7cacda..14895ef6a78d 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/GeoJsonImportController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/GeoJsonImportController.java @@ -46,12 +46,10 @@ import org.hisp.dhis.dxf2.importsummary.ImportStatus; import org.hisp.dhis.dxf2.webmessage.WebMessage; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.feedback.Status; import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; -import org.hisp.dhis.scheduling.JobSchedulerService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.scheduling.JobType; import org.hisp.dhis.scheduling.parameters.GeoJsonImportJobParams; import org.hisp.dhis.security.RequiresAuthority; @@ -77,12 +75,9 @@ @RestController @RequiredArgsConstructor public class GeoJsonImportController { - private final GeoJsonService geoJsonService; - - private final JobSchedulerService jobSchedulerService; - - private final JobConfigurationService jobConfigurationService; + private final GeoJsonService geoJsonService; + private final JobExecutionService jobExecutionService; private final UserService userService; @PostMapping( @@ -96,7 +91,7 @@ public WebMessage postImport( @RequestParam(required = false) boolean dryRun, @RequestParam(required = false, defaultValue = "false") boolean async, HttpServletRequest request) - throws IOException, ConflictException, NotFoundException { + throws IOException, ConflictException { GeoJsonImportJobParams params = GeoJsonImportJobParams.builder() .attributeId(attributeId) @@ -113,14 +108,14 @@ public WebMessage postImport( private WebMessage runImport( boolean async, GeoJsonImportJobParams params, HttpServletRequest request) - throws ConflictException, NotFoundException, IOException { + throws ConflictException, IOException { User currentUser = userService.getUserByUsername(CurrentUserUtil.getCurrentUsername()); if (async) { JobConfiguration jobConfig = new JobConfiguration(JobType.GEOJSON_IMPORT); jobConfig.setJobParameters(params); jobConfig.setExecutedBy(currentUser.getUid()); - jobSchedulerService.createThenExecute(jobConfig, APPLICATION_JSON, request.getInputStream()); + jobExecutionService.executeOnceNow(jobConfig, APPLICATION_JSON, request.getInputStream()); return jobConfigurationReport(jobConfig); } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PredictionController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PredictionController.java index 31a2cd084a31..f2e2594ad628 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PredictionController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PredictionController.java @@ -38,14 +38,13 @@ import org.hisp.dhis.common.OpenApi; import org.hisp.dhis.dxf2.webmessage.WebMessage; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.feedback.Status; import org.hisp.dhis.predictor.PredictionService; import org.hisp.dhis.predictor.PredictionSummary; import org.hisp.dhis.predictor.Predictor; import org.hisp.dhis.scheduling.JobConfiguration; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.scheduling.JobProgress; -import org.hisp.dhis.scheduling.JobSchedulerService; import org.hisp.dhis.scheduling.parameters.PredictorJobParameters; import org.hisp.dhis.security.RequiresAuthority; import org.hisp.dhis.user.CurrentUser; @@ -71,7 +70,7 @@ public class PredictionController { private final PredictionService predictionService; - private final JobSchedulerService jobSchedulerService; + private final JobExecutionService jobExecutionService; @RequestMapping(method = {RequestMethod.POST, RequestMethod.PUT}) @RequiresAuthority(anyOf = F_PREDICTOR_RUN) @@ -83,7 +82,7 @@ public WebMessage runPredictors( @RequestParam(value = "predictorGroup", required = false) List predictorGroups, @RequestParam(defaultValue = "false", required = false) boolean async, @CurrentUser UserDetails currentUser) - throws ConflictException, @OpenApi.Ignore NotFoundException { + throws ConflictException { if (async) { JobConfiguration config = new JobConfiguration(PREDICTOR); @@ -97,7 +96,7 @@ public WebMessage runPredictors( config.setJobParameters(params); config.setExecutedBy(currentUser.getUid()); - jobSchedulerService.createThenExecute(config); + jobExecutionService.executeOnceNow(config); return jobConfigurationReport(config); } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PushAnalysisController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PushAnalysisController.java index 725f4a462f4b..b285f2991d31 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PushAnalysisController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PushAnalysisController.java @@ -43,8 +43,7 @@ import org.hisp.dhis.pushanalysis.PushAnalysisService; import org.hisp.dhis.query.GetObjectListParams; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; -import org.hisp.dhis.scheduling.JobSchedulerService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.scheduling.JobType; import org.hisp.dhis.scheduling.parameters.PushAnalysisJobParameters; import org.hisp.dhis.user.CurrentUserUtil; @@ -73,8 +72,7 @@ public class PushAnalysisController private final PushAnalysisService pushAnalysisService; private final ContextUtils contextUtils; - private final JobConfigurationService jobConfigurationService; - private final JobSchedulerService jobSchedulerService; + private final JobExecutionService jobExecutionService; @GetMapping("/{uid}/render") public void renderPushAnalytics(@PathVariable() String uid, HttpServletResponse response) @@ -112,6 +110,6 @@ public void sendPushAnalysis(@PathVariable() String uid) config.setJobParameters(new PushAnalysisJobParameters(uid)); config.setExecutedBy(CurrentUserUtil.getCurrentUserDetails().getUid()); - jobSchedulerService.createThenExecute(config); + jobExecutionService.executeOnceNow(config); } } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/ResourceTableController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/ResourceTableController.java index 8b1f4e9088e9..084696f7dfaa 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/ResourceTableController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/ResourceTableController.java @@ -56,10 +56,8 @@ import org.hisp.dhis.common.OpenApi; import org.hisp.dhis.dxf2.webmessage.WebMessage; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; -import org.hisp.dhis.scheduling.JobSchedulerService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.scheduling.parameters.AnalyticsJobParameters; import org.hisp.dhis.scheduling.parameters.MonitoringJobParameters; import org.hisp.dhis.security.RequiresAuthority; @@ -85,8 +83,7 @@ @RequiredArgsConstructor public class ResourceTableController { - private final JobConfigurationService jobConfigurationService; - private final JobSchedulerService jobSchedulerService; + private final JobExecutionService jobExecutionService; @RequestMapping( value = "/analytics", @@ -103,7 +100,7 @@ public WebMessage analytics( @RequestParam(defaultValue = "false") Boolean skipOrgUnitOwnership, @RequestParam(required = false) Integer lastYears, @RequestParam(defaultValue = "false") Boolean skipOutliers) - throws ConflictException, @OpenApi.Ignore NotFoundException { + throws ConflictException { Set skipTableTypes = new HashSet<>(); Set skipPrograms = new HashSet<>(); @@ -147,8 +144,7 @@ public WebMessage analytics( @RequestMapping(method = {PUT, POST}) @RequiresAuthority(anyOf = F_PERFORM_MAINTENANCE) @ResponseBody - public WebMessage resourceTables(@CurrentUser UserDetails currentUser) - throws ConflictException, @OpenApi.Ignore NotFoundException { + public WebMessage resourceTables(@CurrentUser UserDetails currentUser) throws ConflictException { JobConfiguration config = new JobConfiguration(RESOURCE_TABLE); config.setExecutedBy(currentUser.getUid()); return execute(config); @@ -159,17 +155,16 @@ public WebMessage resourceTables(@CurrentUser UserDetails currentUser) method = {PUT, POST}) @RequiresAuthority(anyOf = F_PERFORM_MAINTENANCE) @ResponseBody - public WebMessage monitoring() throws ConflictException, @OpenApi.Ignore NotFoundException { + public WebMessage monitoring() throws ConflictException { JobConfiguration config = new JobConfiguration(MONITORING); config.setJobParameters(new MonitoringJobParameters()); return execute(config); } - private WebMessage execute(JobConfiguration configuration) - throws ConflictException, NotFoundException { + private WebMessage execute(JobConfiguration configuration) throws ConflictException { log.debug("Executing requested job of type: '{}'", configuration.getJobType()); - jobSchedulerService.createThenExecute(configuration); + jobExecutionService.executeOnceNow(configuration); return jobConfigurationReport(configuration); } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/metadata/MetadataImportExportController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/metadata/MetadataImportExportController.java index b2428f6fb5fe..b5f34ff2442d 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/metadata/MetadataImportExportController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/metadata/MetadataImportExportController.java @@ -60,7 +60,6 @@ import org.hisp.dhis.dxf2.metadata.feedback.ImportReport; import org.hisp.dhis.dxf2.webmessage.WebMessage; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.feedback.Status; import org.hisp.dhis.importexport.ImportStrategy; import org.hisp.dhis.jsonpatch.BulkJsonPatches; @@ -70,15 +69,13 @@ import org.hisp.dhis.render.RenderFormat; import org.hisp.dhis.render.RenderService; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.scheduling.JobProgress; -import org.hisp.dhis.scheduling.JobSchedulerService; import org.hisp.dhis.scheduling.JobType; import org.hisp.dhis.schema.SchemaService; import org.hisp.dhis.user.CurrentUserUtil; import org.hisp.dhis.user.User; import org.hisp.dhis.user.UserService; -import org.hisp.dhis.user.UserSettingsService; import org.hisp.dhis.webapi.mvc.annotation.ApiVersion; import org.hisp.dhis.webapi.service.ContextService; import org.springframework.http.ResponseEntity; @@ -111,16 +108,14 @@ public class MetadataImportExportController { private final GmlImportService gmlImportService; private final MetadataExportService metadataExportService; private final UserService userService; - private final UserSettingsService userSettingsService; - private final JobConfigurationService jobConfigurationService; - private final JobSchedulerService jobSchedulerService; + private final JobExecutionService jobExecutionService; private final ObjectMapper jsonMapper; private final BulkPatchManager bulkPatchManager; @PostMapping(value = "", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) @ResponseBody public WebMessage postJsonMetadata(HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { MetadataImportParams params = getMetadataImportParams(); if (params.isAsync()) { @@ -140,7 +135,7 @@ public WebMessage postJsonMetadata(HttpServletRequest request) @PostMapping(value = "", consumes = "application/csv") @ResponseBody public WebMessage postCsvMetadata(HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { MetadataImportParams params = getMetadataImportParams(); String classKey = request.getParameter("classKey"); @@ -173,7 +168,7 @@ public WebMessage postCsvMetadata(HttpServletRequest request) @PostMapping(value = "/gml", consumes = APPLICATION_XML_VALUE) @ResponseBody public WebMessage postGmlMetadata(HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { MetadataImportParams params = getMetadataImportParams(); if (params.isAsync()) { @@ -255,12 +250,12 @@ private MetadataImportParams getMetadataImportParams() { private WebMessage startAsyncMetadata( MetadataImportParams params, MimeType contentType, HttpServletRequest request) - throws IOException, ConflictException, NotFoundException { + throws IOException, ConflictException { JobConfiguration config = new JobConfiguration(JobType.METADATA_IMPORT); config.setExecutedBy(CurrentUserUtil.getCurrentUserDetails().getUid()); config.setJobParameters(params); - jobSchedulerService.createThenExecute(config, contentType, request.getInputStream()); + jobExecutionService.executeOnceNow(config, contentType, request.getInputStream()); return jobConfigurationReport(config); } } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/scheduling/JobConfigurationController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/scheduling/JobConfigurationController.java index c2fe9c4b5cc1..c80fc39538c0 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/scheduling/JobConfigurationController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/scheduling/JobConfigurationController.java @@ -127,7 +127,7 @@ public JobTypes getJobTypeInfo() { public ObjectReport executeNow(@PathVariable("uid") String uid) throws NotFoundException, ConflictException { - jobSchedulerService.runInTransaction(uid); + jobSchedulerService.executeNow(uid); // OBS! This response is kept for better backwards compatibility return new ObjectReport(JobConfiguration.class, 0); @@ -236,11 +236,10 @@ private void checkExecutingUserOrAdmin(UID uid, boolean read) JobConfiguration obj = jobConfigurationService.getJobConfigurationByUid(uid.getValue()); if (obj == null) throw new NotFoundException(JobConfiguration.class, uid.getValue()); boolean isAuthorized = - currentUser != null - && (currentUser.isSuper() - || (!read && currentUser.isAuthorized("F_PERFORM_MAINTENANCE")) - || (read && currentUser.isAuthorized(F_JOB_LOG_READ.toString())) - || currentUser.getUid().equals(obj.getExecutedBy())); + currentUser.isSuper() + || !read && currentUser.isAuthorized("F_PERFORM_MAINTENANCE") + || read && currentUser.isAuthorized(F_JOB_LOG_READ.toString()) + || currentUser.getUid().equals(obj.getExecutedBy()); if (!isAuthorized) throw new ForbiddenException(JobConfiguration.class, obj.getUid()); } } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/sms/SmsInboundController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/sms/SmsInboundController.java index fcc2c2e12b96..fdf0872dc4de 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/sms/SmsInboundController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/sms/SmsInboundController.java @@ -50,12 +50,10 @@ import org.hisp.dhis.feedback.BadRequestException; import org.hisp.dhis.feedback.ConflictException; import org.hisp.dhis.feedback.ForbiddenException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.query.GetObjectListParams; import org.hisp.dhis.render.RenderService; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; -import org.hisp.dhis.scheduling.JobSchedulerService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.scheduling.parameters.SmsInboundProcessingJobParameters; import org.hisp.dhis.security.RequiresAuthority; import org.hisp.dhis.sms.command.SMSCommand; @@ -96,8 +94,7 @@ public class SmsInboundController extends AbstractCrudController Date: Thu, 9 Jan 2025 16:09:15 +0100 Subject: [PATCH 05/11] fix: user query parameter must include username [DHIS2-18748] (#19611) * fix: user query parameter must include username [DHIS2-18748] * test: adds a controller test querying matching username --- .../AbstractFullReadOnlyControllerTest.java | 22 +++++++++++++++++++ .../AbstractFullReadOnlyController.java | 3 ++- .../controller/user/UserController.java | 3 ++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyControllerTest.java b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyControllerTest.java index 0621b0724844..9d0087dc59bf 100644 --- a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyControllerTest.java +++ b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyControllerTest.java @@ -38,7 +38,10 @@ import org.hisp.dhis.common.CodeGenerator; import org.hisp.dhis.dataelement.DataElement; import org.hisp.dhis.dataelement.DataElementService; +import org.hisp.dhis.jsontree.JsonList; import org.hisp.dhis.test.webapi.H2ControllerIntegrationTestBase; +import org.hisp.dhis.test.webapi.json.domain.JsonUser; +import org.hisp.dhis.user.User; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -54,6 +57,25 @@ class AbstractFullReadOnlyControllerTest extends H2ControllerIntegrationTestBase @Autowired private DataElementService dataElementService; + @Test + void testGetObjectList_QueryUsers() { + // this just simulates the normal setup with a system super-user + User user = switchToNewUser("system", "ALL"); + // make sure "system" does not occur in any other property that might be searched by query= + user.setName("x"); + user.setFirstName("y"); + user.setSurname("z"); + user.setCode("xyz"); + userService.updateUser(user); + + JsonList users = + GET("/users?fields=id,name,username&query=system") + .content() + .getList("users", JsonUser.class); + assertEquals(1, users.size()); + assertEquals("system", users.get(0).getUsername()); + } + @Test void testGetObjectListCsv() { createDataElements(36); diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyController.java index 9d88e596e414..02edb0947e54 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyController.java @@ -81,6 +81,7 @@ import org.hisp.dhis.security.acl.AclService; import org.hisp.dhis.system.util.ReflectionUtils; import org.hisp.dhis.user.CurrentUser; +import org.hisp.dhis.user.User; import org.hisp.dhis.user.UserDetails; import org.hisp.dhis.user.UserSettingsService; import org.hisp.dhis.webapi.mvc.annotation.ApiVersion; @@ -242,7 +243,7 @@ protected List getPreQueryMatches(P params) throws ConflictException { @Nonnull protected List getAdditionalFilters(P params) throws ConflictException { List filters = new ArrayList<>(); - if (params.getQuery() != null && !params.getQuery().isEmpty()) + if (params.getQuery() != null && !params.getQuery().isEmpty() && getEntityClass() != User.class) filters.add(Restrictions.query(getSchema(), params.getQuery())); List matches = getPreQueryMatches(params); // Note: null = no special filters, empty = no matches for special filters diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java index 0c90bd0acc08..7b038d49aeb0 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java @@ -217,7 +217,8 @@ public static final class GetUserObjectListParams extends GetObjectListParams { @JsonIgnore boolean isUsingAnySpecialFilters() { - return phoneNumber != null + return getQuery() != null + || phoneNumber != null || canManage || authSubset || lastLogin != null From 8654bf223bd309b278c0e32234be1199dbcba708 Mon Sep 17 00:00:00 2001 From: Jan Bernitt Date: Thu, 9 Jan 2025 17:11:05 +0100 Subject: [PATCH 06/11] feat: adds sortable schema property [DHIS2-18749] (#19612) * feat: adds sortable schema property [DHIS2-18749] * fix: take persistent into account, also adds a test --- .../dhis/common/BaseIdentifiableObject.java | 66 ++-- .../hisp/dhis/common/BaseLinkableObject.java | 3 +- .../hisp/dhis/common/BaseNameableObject.java | 6 + .../java/org/hisp/dhis/common/Sortable.java | 42 +++ .../java/org/hisp/dhis/schema/Property.java | 287 ++++-------------- .../test/webapi/json/domain/JsonProperty.java | 4 + .../controller/SchemaControllerTest.java | 35 +++ 7 files changed, 161 insertions(+), 282 deletions(-) create mode 100644 dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/Sortable.java diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseIdentifiableObject.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseIdentifiableObject.java index 6eb4166a55c0..49dc780989af 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseIdentifiableObject.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseIdentifiableObject.java @@ -49,6 +49,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; import java.util.stream.Stream; +import javax.annotation.Nonnull; +import lombok.Setter; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.hibernate.annotations.Immutable; @@ -83,22 +85,22 @@ @JacksonXmlRootElement(localName = "identifiableObject", namespace = DxfNamespaces.DXF_2_0) public class BaseIdentifiableObject extends BaseLinkableObject implements IdentifiableObject { /** The database internal identifier for this Object. */ - protected long id; + @Setter protected long id; /** The unique identifier for this object. */ - @AuditAttribute protected String uid; + @Setter @AuditAttribute protected String uid; /** The unique code for this object. */ - @AuditAttribute protected String code; + @Setter @AuditAttribute protected String code; /** The name of this object. Required and unique. */ - protected String name; + @Setter protected String name; /** The date this object was created. */ - protected Date created; + @Setter protected Date created; /** The date this object was last updated. */ - protected Date lastUpdated; + @Setter protected Date lastUpdated; /** Set of the dynamic attributes values that belong to this data element. */ @AuditAttribute private AttributeValues attributeValues = AttributeValues.empty(); @@ -110,7 +112,7 @@ public class BaseIdentifiableObject extends BaseLinkableObject implements Identi * Cache for object translations, where the cache key is a combination of locale and translation * property, and value is the translated value. */ - private Map translationCache = new ConcurrentHashMap<>(); + private final Map translationCache = new ConcurrentHashMap<>(); /** User who created this object. This field is immutable and must not be updated. */ @Immutable protected User createdBy; @@ -119,13 +121,13 @@ public class BaseIdentifiableObject extends BaseLinkableObject implements Identi protected transient Access access; /** Users who have marked this object as a favorite. */ - protected Set favorites = new HashSet<>(); + @Setter protected Set favorites = new HashSet<>(); /** Last user updated this object. */ - protected User lastUpdatedBy; + @Setter protected User lastUpdatedBy; /** Object sharing (JSONB). */ - protected Sharing sharing = new Sharing(); + @Setter protected Sharing sharing = new Sharing(); // ------------------------------------------------------------------------- // Constructors @@ -162,7 +164,7 @@ public BaseIdentifiableObject(IdentifiableObject identifiableObject) { * name. */ @Override - public int compareTo(IdentifiableObject object) { + public int compareTo(@Nonnull IdentifiableObject object) { if (this.getDisplayName() == null) { return object.getDisplayName() == null ? 0 : 1; } @@ -182,10 +184,6 @@ public long getId() { return id; } - public void setId(long id) { - this.id = id; - } - @Override @JsonProperty(value = "id") @JacksonXmlProperty(localName = "id", isAttribute = true) @@ -196,10 +194,6 @@ public String getUid() { return uid; } - public void setUid(String uid) { - this.uid = uid; - } - @Override @JsonProperty @JacksonXmlProperty(isAttribute = true) @@ -209,10 +203,6 @@ public String getCode() { return code; } - public void setCode(String code) { - this.code = code; - } - @Override @JsonProperty @JacksonXmlProperty(isAttribute = true) @@ -222,11 +212,8 @@ public String getName() { return name; } - public void setName(String name) { - this.name = name; - } - @Override + @Sortable(whenPersisted = false) @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) @Translatable(propertyName = "name", key = "NAME") @@ -243,10 +230,6 @@ public Date getCreated() { return created; } - public void setCreated(Date created) { - this.created = created; - } - @Override @OpenApi.Property(UserPropertyTransformer.UserDto.class) @JsonProperty @@ -258,10 +241,6 @@ public User getLastUpdatedBy() { return lastUpdatedBy; } - public void setLastUpdatedBy(User lastUpdatedBy) { - this.lastUpdatedBy = lastUpdatedBy; - } - @Override @JsonProperty @JacksonXmlProperty(isAttribute = true) @@ -271,10 +250,6 @@ public Date getLastUpdated() { return lastUpdated; } - public void setLastUpdated(Date lastUpdated) { - this.lastUpdated = lastUpdated; - } - public record AttributeValue(@JsonProperty Attribute attribute, @JsonProperty String value) {} @Override @@ -308,6 +283,7 @@ public String getAttributeValue(String attributeUid) { @Gist(included = Include.FALSE) @Override + @Sortable(value = false) @JsonProperty @JacksonXmlElementWrapper(localName = "translations", namespace = DxfNamespaces.DXF_2_0) @JacksonXmlProperty(localName = "translation", namespace = DxfNamespaces.DXF_2_0) @@ -387,8 +363,9 @@ public void setOwner(String userId) { } @Override + @Sortable(value = false) @Gist(included = Include.FALSE) - @JsonProperty + @JsonProperty(access = JsonProperty.Access.READ_ONLY) @JacksonXmlProperty(localName = "access", namespace = DxfNamespaces.DXF_2_0) public Access getAccess() { return access; @@ -407,10 +384,6 @@ public Set getFavorites() { return favorites; } - public void setFavorites(Set favorites) { - this.favorites = favorites; - } - @Override @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) @@ -422,6 +395,7 @@ public boolean isFavorite() { } @Override + @Sortable(value = false) @Gist(included = Include.FALSE) @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) @@ -433,10 +407,6 @@ public Sharing getSharing() { return sharing; } - public void setSharing(Sharing sharing) { - this.sharing = sharing; - } - @Override public boolean setAsFavorite(UserDetails user) { if (this.favorites == null) { diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseLinkableObject.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseLinkableObject.java index 382a88fc72e3..df59ee82f663 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseLinkableObject.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseLinkableObject.java @@ -45,7 +45,8 @@ public class BaseLinkableObject implements LinkableObject { private transient String href; @Override - @JsonProperty + @Sortable(value = false) + @JsonProperty(access = JsonProperty.Access.READ_ONLY) @JacksonXmlProperty(isAttribute = true) @Property(PropertyType.URL) public String getHref() { diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseNameableObject.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseNameableObject.java index fbc0c690596a..33af9314ccb5 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseNameableObject.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseNameableObject.java @@ -166,6 +166,7 @@ public String toString() { // ------------------------------------------------------------------------- @Override + @Sortable @JsonProperty @JacksonXmlProperty(isAttribute = true) @PropertyRange(min = 1) @@ -178,6 +179,7 @@ public void setShortName(String shortName) { } @Override + @Sortable(whenPersisted = false) @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) @Translatable(propertyName = "shortName", key = "SHORT_NAME") @@ -186,6 +188,7 @@ public String getDisplayShortName() { } @Override + @Sortable @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) @PropertyRange(min = 1) @@ -198,6 +201,7 @@ public void setDescription(String description) { } @Override + @Sortable(value = false) @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) @Translatable(propertyName = "description", key = "DESCRIPTION") @@ -206,6 +210,7 @@ public String getDisplayDescription() { } @JsonProperty + @Sortable(whenPersisted = false) @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) @Translatable(propertyName = "formName", key = "FORM_NAME") public String getDisplayFormName() { @@ -217,6 +222,7 @@ public String getFormNameFallback() { return formName != null && !formName.isEmpty() ? getFormName() : getDisplayName(); } + @Sortable @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getFormName() { diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/Sortable.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/Sortable.java new file mode 100644 index 000000000000..4ed4854e0479 --- /dev/null +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/Sortable.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2004-2025, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.common; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Sortable { + + boolean value() default true; + + boolean whenPersisted() default true; +} diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/schema/Property.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/schema/Property.java index 4dabd7abd1e7..56ae50fce9b7 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/schema/Property.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/schema/Property.java @@ -38,10 +38,13 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import lombok.Getter; +import lombok.Setter; import org.hisp.dhis.common.DxfNamespaces; import org.hisp.dhis.common.EmbeddedObject; import org.hisp.dhis.common.IdentifiableObject; import org.hisp.dhis.common.NameableObject; +import org.hisp.dhis.common.Sortable; import org.hisp.dhis.hibernate.HibernateProxyUtils; import org.springframework.core.Ordered; @@ -54,56 +57,56 @@ public class Property implements Ordered, Klass { private Class klass; /** Normalized type of this property */ - private PropertyType propertyType; + @Setter private PropertyType propertyType; /** If this property is a collection, this is the class of the items inside the collection. */ - private Class itemKlass; + @Setter private Class itemKlass; /** * If this property is a collection, this is the normalized type of the items inside the * collection. */ - private PropertyType itemPropertyType; + @Setter private PropertyType itemPropertyType; /** Direct link to getter for this property. */ - private Method getterMethod; + @Getter @Setter private Method getterMethod; /** Direct link to setter for this property. */ - private Method setterMethod; + @Getter @Setter private Method setterMethod; /** * Name for this property, if this class is a collection, it is the name of the items -inside- the * collection and not the collection wrapper itself. */ - private String name; + @Setter private String name; /** Name for actual field, used to persistence operations and getting setter/getter. */ - private String fieldName; + @Setter private String fieldName; /** * Is this property persisted somewhere. This property will be used to create criteria queries on * demand (default: false) */ - private boolean persisted; + @Setter private boolean persisted; /** Name of collection wrapper. */ - private String collectionName; + @Setter private String collectionName; /** If this Property is a collection, should it be wrapped with collectionName? */ - private Boolean collectionWrapping; + @Setter private Boolean collectionWrapping; /** * Description if provided, will be fetched from @Description annotation. * * @see org.hisp.dhis.common.annotation.Description */ - private String description; + @Setter private String description; /** Namespace used for this property. */ - private String namespace; + @Setter private String namespace; /** Usually only used for XML. Is this property considered an attribute. */ - private boolean attribute; + @Setter private boolean attribute; /** * This property is true if the type pointed to does not export any properties itself, it is then @@ -111,120 +114,121 @@ public class Property implements Ordered, Klass { * type of the collection, e.g. List would set simple to be true, but List * would set it to false. */ - private boolean simple; + @Setter private boolean simple; /** * This property is true if the type of this property is a sub-class of Collection. * * @see java.util.Collection */ - private boolean collection; + @Setter private boolean collection; /** * This property is true if collection=true and klass points to a implementation with a stable * order (i.e. List). */ - private boolean ordered; + @Setter private boolean ordered; /** * If this property is a complex object or a collection, is this property considered the owner of * that relationship (important for imports etc). */ - private boolean owner; + @Setter private boolean owner; /** * Is this class a sub-class of IdentifiableObject * * @see org.hisp.dhis.common.IdentifiableObject */ - private boolean identifiableObject; + @Setter private boolean identifiableObject; /** * Is this class a sub-class of NameableObject * * @see org.hisp.dhis.common.NameableObject */ - private boolean nameableObject; + @Setter private boolean nameableObject; /** Does this class implement {@link EmbeddedObject} ? */ - private boolean embeddedObject; + @Setter private boolean embeddedObject; /** Does this class implement {@link EmbeddedObject} ? */ - private boolean analyticalObject; + @Setter private boolean analyticalObject; /** Can this property be read. */ - private boolean readable; + @Setter private boolean readable; /** Can this property be written to. */ - private boolean writable; + @Setter private boolean writable; /** Are the values for this property required to be unique? */ - private boolean unique; + @Setter private boolean unique; /** Nullability of this property. */ - private boolean required; + @Setter private boolean required; /** Maximum length/size/value of this property. */ - private Integer length; + @Setter private Integer length; /** Minimum size/length of this property. */ - private Double max; + @Setter private Double max; /** Minimum size/length of this property. */ - private Double min; + @Setter private Double min; /** Cascading used when doing CRUD operations. */ - private String cascade; + @Setter private String cascade; /** Is property many-to-many. */ - private boolean manyToMany; + @Setter private boolean manyToMany; /** Is property one-to-one. */ - private boolean oneToOne; + @Setter private boolean oneToOne; /** Is property many-to-one. */ - private boolean manyToOne; + @Setter private boolean manyToOne; /** Is property one-to-many. */ - private boolean oneToMany; + @Setter private boolean oneToMany; /** The hibernate role of the owning side. */ - private String owningRole; + @Setter private String owningRole; /** The hibernate role of the inverse side (if many-to-many). */ - private String inverseRole; + @Setter private String inverseRole; /** If property type is enum, this is the list of valid options. */ - private List constants; + @Setter private List constants; /** Used by LinkService to link to the Schema describing this type (if reference). */ - private String href; + @Setter private String href; /** Points to relative Web-API endpoint (if exposed). */ - private String relativeApiEndpoint; + @Setter private String relativeApiEndpoint; /** Used by LinkService to link to the API endpoint containing this type. */ - private String apiEndpoint; + @Setter private String apiEndpoint; /** PropertyTransformer to apply to this property before and field filtering is applied. */ - private Class propertyTransformer; + @Getter @Setter private Class propertyTransformer; /** Default value of the Property */ private Object defaultValue; - private boolean translatable; + @Setter private boolean translatable; - private String translationKey; + @Setter private String translationKey; /** * The translation key use for retrieving I18n translation of this property's name. The key * follows snake_case naming convention. */ - private String i18nTranslationKey; + @Setter private String i18nTranslationKey; private GistPreferences gistPreferences = GistPreferences.DEFAULT; /** All annotations present on this property (either through field or method) */ + @Getter @Setter private Map, Annotation> annotations = new HashMap<>(); public Property() {} @@ -259,144 +263,85 @@ public PropertyType getPropertyType() { return propertyType; } - public void setPropertyType(PropertyType propertyType) { - this.propertyType = propertyType; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public Class getItemKlass() { return itemKlass; } - public void setItemKlass(Class itemKlass) { - this.itemKlass = itemKlass; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public PropertyType getItemPropertyType() { return itemPropertyType; } - public void setItemPropertyType(PropertyType itemPropertyType) { - this.itemPropertyType = itemPropertyType; - } - - public Method getGetterMethod() { - return getterMethod; - } - - public void setGetterMethod(Method getterMethod) { - this.getterMethod = getterMethod; - } - - public Method getSetterMethod() { - return setterMethod; - } - - public void setSetterMethod(Method setterMethod) { - this.setterMethod = setterMethod; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getName() { return name; } - public void setName(String name) { - this.name = name; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getFieldName() { return fieldName; } - public void setFieldName(String fieldName) { - this.fieldName = fieldName; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isPersisted() { return persisted; } - public void setPersisted(boolean persisted) { - this.persisted = persisted; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getCollectionName() { return collectionName != null ? collectionName : (isCollection() ? name : null); } - public void setCollectionName(String collectionName) { - this.collectionName = collectionName; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public Boolean isCollectionWrapping() { return collectionWrapping; } - public void setCollectionWrapping(Boolean collectionWrapping) { - this.collectionWrapping = collectionWrapping; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getDescription() { return description; } - public void setDescription(String description) { - this.description = description; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getNamespace() { return namespace; } - public void setNamespace(String namespace) { - this.namespace = namespace; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isAttribute() { return attribute; } - public void setAttribute(boolean attribute) { - this.attribute = attribute; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isSimple() { return simple; } - public void setSimple(boolean simple) { - this.simple = simple; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isCollection() { return collection; } - public void setCollection(boolean collection) { - this.collection = collection; + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) + public boolean isSortable() { + Sortable sortable = getterMethod == null ? null : getterMethod.getAnnotation(Sortable.class); + return sortable != null + ? sortable.value() && (!sortable.whenPersisted() || isPersisted()) + : !isCollection() && isSimple() && isPersisted(); } @JsonProperty @@ -405,220 +350,132 @@ public boolean isOrdered() { return ordered; } - public void setOrdered(boolean ordered) { - this.ordered = ordered; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isOwner() { return owner; } - public void setOwner(boolean owner) { - this.owner = owner; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isIdentifiableObject() { return identifiableObject; } - public void setIdentifiableObject(boolean identifiableObject) { - this.identifiableObject = identifiableObject; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isNameableObject() { return nameableObject; } - public void setNameableObject(boolean nameableObject) { - this.nameableObject = nameableObject; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isEmbeddedObject() { return embeddedObject; } - public void setEmbeddedObject(boolean embeddedObject) { - this.embeddedObject = embeddedObject; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isAnalyticalObject() { return analyticalObject; } - public void setAnalyticalObject(boolean analyticalObject) { - this.analyticalObject = analyticalObject; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isReadable() { return readable; } - public void setReadable(boolean readable) { - this.readable = readable; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isWritable() { return writable; } - public void setWritable(boolean writable) { - this.writable = writable; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isUnique() { return unique; } - public void setUnique(boolean unique) { - this.unique = unique; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isRequired() { return required; } - public void setRequired(boolean required) { - this.required = required; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public Integer getLength() { return length; } - public void setLength(Integer length) { - this.length = length; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public Double getMax() { return max; } - public void setMax(Double max) { - this.max = max; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public Double getMin() { return min; } - public void setMin(Double min) { - this.min = min; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getCascade() { return cascade; } - public void setCascade(String cascade) { - this.cascade = cascade; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isManyToMany() { return manyToMany; } - public void setManyToMany(boolean manyToMany) { - this.manyToMany = manyToMany; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isOneToOne() { return oneToOne; } - public void setOneToOne(boolean oneToOne) { - this.oneToOne = oneToOne; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isManyToOne() { return manyToOne; } - public void setManyToOne(boolean manyToOne) { - this.manyToOne = manyToOne; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isOneToMany() { return oneToMany; } - public void setOneToMany(boolean oneToMany) { - this.oneToMany = oneToMany; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getOwningRole() { return owningRole; } - public void setOwningRole(String owningRole) { - this.owningRole = owningRole; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getInverseRole() { return inverseRole; } - public void setInverseRole(String inverseRole) { - this.inverseRole = inverseRole; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getTranslationKey() { return this.translationKey; } - public void setTranslationKey(String translationKey) { - this.translationKey = translationKey; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getI18nTranslationKey() { return i18nTranslationKey; } - public void setI18nTranslationKey(String i18nTranslationKey) { - this.i18nTranslationKey = i18nTranslationKey; - } - @JsonProperty @JacksonXmlElementWrapper(localName = "constants", namespace = DxfNamespaces.DXF_2_0) @JacksonXmlProperty(localName = "constant", namespace = DxfNamespaces.DXF_2_0) @@ -626,54 +483,30 @@ public List getConstants() { return constants; } - public void setConstants(List constants) { - this.constants = constants; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getHref() { return href; } - public void setHref(String href) { - this.href = href; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getRelativeApiEndpoint() { return relativeApiEndpoint; } - public void setRelativeApiEndpoint(String relativeApiEndpoint) { - this.relativeApiEndpoint = relativeApiEndpoint; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getApiEndpoint() { return apiEndpoint; } - public void setApiEndpoint(String apiEndpoint) { - this.apiEndpoint = apiEndpoint; - } - @JsonProperty("propertyTransformer") @JacksonXmlProperty(localName = "propertyTransformer", namespace = DxfNamespaces.DXF_2_0) public boolean hasPropertyTransformer() { return propertyTransformer != null; } - public Class getPropertyTransformer() { - return propertyTransformer; - } - - public void setPropertyTransformer(Class propertyTransformer) { - this.propertyTransformer = propertyTransformer; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public Object getDefaultValue() { @@ -695,10 +528,6 @@ public boolean isTranslatable() { return this.translatable; } - public void setTranslatable(boolean translatable) { - this.translatable = translatable; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public GistPreferences getGistPreferences() { @@ -709,14 +538,6 @@ public void setGistPreferences(GistPreferences gistPreferences) { this.gistPreferences = gistPreferences == null ? GistPreferences.DEFAULT : gistPreferences; } - public Map, Annotation> getAnnotations() { - return annotations; - } - - public void setAnnotations(Map, Annotation> annotations) { - this.annotations = annotations; - } - @SuppressWarnings("unchecked") public A getAnnotation(Class annotationType) { return (A) annotations.get(annotationType); diff --git a/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/webapi/json/domain/JsonProperty.java b/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/webapi/json/domain/JsonProperty.java index e3bb6c08751d..27275dff55cf 100644 --- a/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/webapi/json/domain/JsonProperty.java +++ b/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/webapi/json/domain/JsonProperty.java @@ -90,6 +90,10 @@ default boolean isSimple() { return getBoolean("simple").booleanValue(); } + default boolean isSortable() { + return getBoolean("sortable").booleanValue(); + } + default boolean isRequired() { return getBoolean("required").booleanValue(); } diff --git a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/SchemaControllerTest.java b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/SchemaControllerTest.java index 0bf231cd1258..1b13c7777b05 100644 --- a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/SchemaControllerTest.java +++ b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/SchemaControllerTest.java @@ -27,14 +27,18 @@ */ package org.hisp.dhis.webapi.controller; +import static java.util.stream.Collectors.toSet; import static org.hisp.dhis.test.webapi.Assertions.assertWebMessage; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Optional; +import java.util.Set; import org.hisp.dhis.http.HttpStatus; +import org.hisp.dhis.jsontree.JsonList; import org.hisp.dhis.jsontree.JsonObject; import org.hisp.dhis.schema.PropertyType; import org.hisp.dhis.test.webapi.H2ControllerIntegrationTestBase; @@ -145,4 +149,35 @@ void testUserNameIsPersistedButReadOnly() { assertFalse(name.isWritable()); assertFalse(name.isRequired()); } + + @Test + void testSortableProperties() { + JsonSchema de = GET("/schemas/dataElement").content().as(JsonSchema.class); + JsonList properties = de.getProperties(); + Set expected = + Set.of( + "fieldMask", + "aggregationType", + "code", + "domainType", + "displayName", + "created", + "description", + "zeroIsSignificant", + "displayFormName", + "displayShortName", + "url", + "lastUpdated", + "valueType", + "formName", + "name", + "id", + "shortName"); + Set actual = + properties.stream() + .filter(JsonProperty::isSortable) + .map(JsonProperty::getName) + .collect(toSet()); + assertEquals(expected, actual); + } } From 1a5a15b5c291b503236c13f0a253286f5bbd46ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Jan 2025 17:41:43 +0100 Subject: [PATCH 07/11] chore(deps): bump org.apache.tomcat.embed:tomcat-embed-core (#19624) Bumps org.apache.tomcat.embed:tomcat-embed-core from 10.1.31 to 10.1.34. --- updated-dependencies: - dependency-name: org.apache.tomcat.embed:tomcat-embed-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dhis-2/dhis-web-server/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dhis-2/dhis-web-server/pom.xml b/dhis-2/dhis-web-server/pom.xml index 5577fc51763e..2d7993a319c3 100644 --- a/dhis-2/dhis-web-server/pom.xml +++ b/dhis-2/dhis-web-server/pom.xml @@ -15,7 +15,7 @@ ../ ${maven.build.timestamp} - 10.1.31 + 10.1.34 3.4.4 tomcat:${tomcat.version}-jre17 dhis2/core-dev:local From f11b229f20ce73a1eae65f55b172b7a503af2c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Helge=20=C3=98verland?= Date: Fri, 10 Jan 2025 09:28:05 +0100 Subject: [PATCH 08/11] chore: Remove redundant test code (#19632) --- .../organisationunit/OrganisationUnit.java | 1 - .../event/EventOperationParamsMapperTest.java | 8 +- .../SecurityOwnershipValidatorTest.java | 1 + .../event/SecurityOwnershipValidatorTest.java | 1 + .../SecurityOwnershipValidatorTest.java | 1 + .../dhis/analytics/data/QueryPlannerTest.java | 12 +-- .../OrganisationUnitServiceTest.java | 86 ++++--------------- .../ResourceTableServiceTest.java | 8 +- 8 files changed, 29 insertions(+), 89 deletions(-) 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 2cce28d7cc7d..aabb76e20d90 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 @@ -555,7 +555,6 @@ public void updateParent(OrganisationUnit newParent) { } this.parent = newParent; - newParent.getChildren().add(this); } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java index c6e979d6edfc..c235081c16d5 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java @@ -421,9 +421,7 @@ void shouldMapOrgUnitWhenProgramProvidedAndRequestedOrgUnitInSearchScope( program.setAccessLevel(accessLevel); OrganisationUnit searchScopeOrgUnit = createOrganisationUnit('A'); - OrganisationUnit searchScopeChildOrgUnit = createOrganisationUnit('B'); - searchScopeOrgUnit.setChildren(Set.of(searchScopeChildOrgUnit)); - searchScopeChildOrgUnit.setParent(searchScopeOrgUnit); + OrganisationUnit searchScopeChildOrgUnit = createOrganisationUnit('B', searchScopeOrgUnit); User user = new User(); user.setUid(CodeGenerator.generateUid()); @@ -453,9 +451,7 @@ void shouldMapOrgUnitWhenModeAllProgramProvidedAndRequestedOrgUnitInSearchScope( program.setAccessLevel(OPEN); OrganisationUnit searchScopeOrgUnit = createOrganisationUnit('A'); - OrganisationUnit searchScopeChildOrgUnit = createOrganisationUnit('B'); - searchScopeOrgUnit.setChildren(Set.of(searchScopeChildOrgUnit)); - searchScopeChildOrgUnit.setParent(searchScopeOrgUnit); + OrganisationUnit searchScopeChildOrgUnit = createOrganisationUnit('B', searchScopeOrgUnit); User user = new User(); user.setUid(CodeGenerator.generateUid()); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/SecurityOwnershipValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/SecurityOwnershipValidatorTest.java index f471e3731b0d..a2a34fd7197f 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/SecurityOwnershipValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/SecurityOwnershipValidatorTest.java @@ -111,6 +111,7 @@ class SecurityOwnershipValidatorTest extends TestBase { public void setUp() { organisationUnit = createOrganisationUnit('A'); organisationUnit.setUid(ORG_UNIT_ID); + organisationUnit.updatePath(); User u = makeUser("A"); user = UserDetails.fromUser(u); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/SecurityOwnershipValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/SecurityOwnershipValidatorTest.java index 552ecdc2797d..c09843523208 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/SecurityOwnershipValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/SecurityOwnershipValidatorTest.java @@ -112,6 +112,7 @@ public void setUp() { when(bundle.getUser()).thenReturn(user); organisationUnit = createOrganisationUnit('A'); organisationUnit.setUid(ORG_UNIT_ID); + organisationUnit.updatePath(); trackedEntityType = createTrackedEntityType('A'); trackedEntityType.setUid(TE_TYPE_ID); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/SecurityOwnershipValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/SecurityOwnershipValidatorTest.java index 38186f6b4c65..9228ee53a58a 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/SecurityOwnershipValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/SecurityOwnershipValidatorTest.java @@ -106,6 +106,7 @@ class SecurityOwnershipValidatorTest extends TestBase { public void setUp() { organisationUnit = createOrganisationUnit('A'); organisationUnit.setUid(ORG_UNIT_ID); + organisationUnit.updatePath(); User userA = makeUser("A"); userA.addOrganisationUnit(organisationUnit); diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java index f1b9b9001e31..19c4c85f3f7e 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java @@ -565,14 +565,10 @@ void planQueryB() { */ @Test void planQueryC() { - ouB.setParent(ouA); - ouC.setParent(ouA); - ouD.setParent(ouB); - ouE.setParent(ouC); - ouA.getChildren().add(ouB); - ouA.getChildren().add(ouC); - ouD.getChildren().add(ouB); - ouC.getChildren().add(ouE); + ouB.updateParent(ouA); + ouC.updateParent(ouA); + ouD.updateParent(ouB); + ouE.updateParent(ouC); organisationUnitService.updateOrganisationUnit(ouA); organisationUnitService.updateOrganisationUnit(ouB); organisationUnitService.updateOrganisationUnit(ouC); 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 435a06608f51..ee364855fc4d 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 @@ -241,7 +241,6 @@ void testGetOrganisationUnitWithChildren() throws Exception { OrganisationUnit unit3 = createOrganisationUnit('C', unit2); OrganisationUnit unit4 = createOrganisationUnit('D'); long id1 = organisationUnitService.addOrganisationUnit(unit1); - unit1.getChildren().add(unit2); organisationUnitService.addOrganisationUnit(unit2); organisationUnitService.addOrganisationUnit(unit3); organisationUnitService.addOrganisationUnit(unit4); @@ -308,12 +307,6 @@ void testGetOrganisationUnitWithChildrenMaxLevel() { OrganisationUnit unit5 = createOrganisationUnit('E', unit2); OrganisationUnit unit6 = createOrganisationUnit('F', unit3); OrganisationUnit unit7 = createOrganisationUnit('G', unit3); - unit1.getChildren().add(unit2); - unit1.getChildren().add(unit3); - unit2.getChildren().add(unit4); - unit2.getChildren().add(unit5); - unit3.getChildren().add(unit6); - unit3.getChildren().add(unit7); long id1 = organisationUnitService.addOrganisationUnit(unit1); long id2 = organisationUnitService.addOrganisationUnit(unit2); organisationUnitService.addOrganisationUnit(unit3); @@ -415,23 +408,18 @@ void testGetOrganisationUnitsAtLevel() { organisationUnitService.addOrganisationUnitLevel(levelC); organisationUnitService.addOrganisationUnitLevel(levelD); OrganisationUnit unit1 = createOrganisationUnit('1'); - organisationUnitService.addOrganisationUnit(unit1); OrganisationUnit unit2 = createOrganisationUnit('2', unit1); - unit1.getChildren().add(unit2); - organisationUnitService.addOrganisationUnit(unit2); OrganisationUnit unit3 = createOrganisationUnit('3', unit2); - unit2.getChildren().add(unit3); - organisationUnitService.addOrganisationUnit(unit3); OrganisationUnit unit4 = createOrganisationUnit('4', unit2); - unit2.getChildren().add(unit4); - organisationUnitService.addOrganisationUnit(unit4); OrganisationUnit unit5 = createOrganisationUnit('5', unit2); - unit2.getChildren().add(unit5); - organisationUnitService.addOrganisationUnit(unit5); OrganisationUnit unit6 = createOrganisationUnit('6', unit3); - unit3.getChildren().add(unit6); - organisationUnitService.addOrganisationUnit(unit6); OrganisationUnit unit7 = createOrganisationUnit('7'); + organisationUnitService.addOrganisationUnit(unit1); + organisationUnitService.addOrganisationUnit(unit2); + organisationUnitService.addOrganisationUnit(unit3); + organisationUnitService.addOrganisationUnit(unit4); + organisationUnitService.addOrganisationUnit(unit5); + organisationUnitService.addOrganisationUnit(unit6); organisationUnitService.addOrganisationUnit(unit7); // unit1 // unit1 . unit2 @@ -508,16 +496,13 @@ void testGetOrganisationUnitsAtLevel() { void testGetNumberOfOrganisationalLevels() { assertEquals(0, organisationUnitService.getNumberOfOrganisationalLevels()); OrganisationUnit unit1 = createOrganisationUnit('1'); - organisationUnitService.addOrganisationUnit(unit1); OrganisationUnit unit2 = createOrganisationUnit('2', unit1); - unit1.getChildren().add(unit2); + OrganisationUnit unit3 = createOrganisationUnit('3', unit2); + OrganisationUnit unit4 = createOrganisationUnit('4', unit2); + organisationUnitService.addOrganisationUnit(unit1); organisationUnitService.addOrganisationUnit(unit2); assertEquals(2, organisationUnitService.getNumberOfOrganisationalLevels()); - OrganisationUnit unit3 = createOrganisationUnit('3', unit2); - unit2.getChildren().add(unit3); organisationUnitService.addOrganisationUnit(unit3); - OrganisationUnit unit4 = createOrganisationUnit('4', unit2); - unit2.getChildren().add(unit4); organisationUnitService.addOrganisationUnit(unit4); assertEquals(3, organisationUnitService.getNumberOfOrganisationalLevels()); } @@ -525,14 +510,12 @@ void testGetNumberOfOrganisationalLevels() { @Test void testIsDescendantSet() { OrganisationUnit unit1 = createOrganisationUnit('1'); - organisationUnitService.addOrganisationUnit(unit1); OrganisationUnit unit2 = createOrganisationUnit('2', unit1); - unit1.getChildren().add(unit2); - organisationUnitService.addOrganisationUnit(unit2); OrganisationUnit unit3 = createOrganisationUnit('3', unit2); - unit2.getChildren().add(unit3); - organisationUnitService.addOrganisationUnit(unit3); OrganisationUnit unit4 = createOrganisationUnit('4'); + organisationUnitService.addOrganisationUnit(unit1); + organisationUnitService.addOrganisationUnit(unit2); + organisationUnitService.addOrganisationUnit(unit3); organisationUnitService.addOrganisationUnit(unit4); assertTrue(unit1.isDescendant(Sets.newHashSet(unit1))); assertTrue(unit2.isDescendant(Sets.newHashSet(unit1))); @@ -545,14 +528,12 @@ void testIsDescendantSet() { @Test void testIsDescendantOrgUnit() { OrganisationUnit ouA = createOrganisationUnit('A'); - organisationUnitService.addOrganisationUnit(ouA); OrganisationUnit ouB = createOrganisationUnit('B', ouA); - ouA.getChildren().add(ouB); - organisationUnitService.addOrganisationUnit(ouB); OrganisationUnit ouC = createOrganisationUnit('C', ouB); - ouB.getChildren().add(ouC); - organisationUnitService.addOrganisationUnit(ouC); OrganisationUnit ouD = createOrganisationUnit('D'); + organisationUnitService.addOrganisationUnit(ouA); + organisationUnitService.addOrganisationUnit(ouB); + organisationUnitService.addOrganisationUnit(ouC); organisationUnitService.addOrganisationUnit(ouD); assertTrue(ouA.isDescendant(Set.of(ouA))); assertTrue(ouB.isDescendant(Set.of(ouA))); @@ -565,14 +546,12 @@ void testIsDescendantOrgUnit() { @Test void testIsDescendantObject() { OrganisationUnit unit1 = createOrganisationUnit('1'); - organisationUnitService.addOrganisationUnit(unit1); OrganisationUnit unit2 = createOrganisationUnit('2', unit1); - unit1.getChildren().add(unit2); - organisationUnitService.addOrganisationUnit(unit2); OrganisationUnit unit3 = createOrganisationUnit('3', unit2); - unit2.getChildren().add(unit3); - organisationUnitService.addOrganisationUnit(unit3); OrganisationUnit unit4 = createOrganisationUnit('4'); + organisationUnitService.addOrganisationUnit(unit1); + organisationUnitService.addOrganisationUnit(unit2); + organisationUnitService.addOrganisationUnit(unit3); organisationUnitService.addOrganisationUnit(unit4); assertTrue(unit1.isDescendant(unit1)); assertTrue(unit2.isDescendant(unit1)); @@ -652,20 +631,6 @@ void testGetOrganisationUnitAtLevelAndBranches() { OrganisationUnit unitM = createOrganisationUnit('M', unitF); OrganisationUnit unitN = createOrganisationUnit('N', unitG); OrganisationUnit unitO = createOrganisationUnit('O', unitG); - unitA.getChildren().add(unitB); - unitA.getChildren().add(unitC); - unitB.getChildren().add(unitD); - unitB.getChildren().add(unitE); - unitC.getChildren().add(unitF); - unitC.getChildren().add(unitG); - unitD.getChildren().add(unitH); - unitD.getChildren().add(unitI); - unitE.getChildren().add(unitJ); - unitE.getChildren().add(unitK); - unitF.getChildren().add(unitL); - unitF.getChildren().add(unitM); - unitG.getChildren().add(unitN); - unitG.getChildren().add(unitO); organisationUnitService.addOrganisationUnit(unitA); organisationUnitService.addOrganisationUnit(unitB); organisationUnitService.addOrganisationUnit(unitC); @@ -884,9 +849,6 @@ void testGetOrganisationUnitLevels() { OrganisationUnit unitB = createOrganisationUnit('B', unitA); OrganisationUnit unitC = createOrganisationUnit('C', unitB); OrganisationUnit unitD = createOrganisationUnit('D', unitC); - unitA.getChildren().add(unitB); - unitB.getChildren().add(unitC); - unitC.getChildren().add(unitD); organisationUnitService.addOrganisationUnit(unitA); organisationUnitService.addOrganisationUnit(unitB); organisationUnitService.addOrganisationUnit(unitC); @@ -944,12 +906,6 @@ void testIsInUserHierarchy() { OrganisationUnit ouE = createOrganisationUnit('E', ouB); OrganisationUnit ouF = createOrganisationUnit('F', ouC); OrganisationUnit ouG = createOrganisationUnit('G', ouC); - ouA.getChildren().add(ouB); - ouA.getChildren().add(ouC); - ouB.getChildren().add(ouD); - ouB.getChildren().add(ouE); - ouC.getChildren().add(ouF); - ouC.getChildren().add(ouG); organisationUnitService.addOrganisationUnit(ouA); organisationUnitService.addOrganisationUnit(ouB); organisationUnitService.addOrganisationUnit(ouC); @@ -975,9 +931,6 @@ void testGetAncestorUids() { OrganisationUnit ouB = createOrganisationUnit('B', ouA); OrganisationUnit ouC = createOrganisationUnit('C', ouB); OrganisationUnit ouD = createOrganisationUnit('D', ouC); - ouA.getChildren().add(ouB); - ouA.getChildren().add(ouC); - ouB.getChildren().add(ouD); organisationUnitService.addOrganisationUnit(ouA); organisationUnitService.addOrganisationUnit(ouB); organisationUnitService.addOrganisationUnit(ouC); @@ -995,9 +948,6 @@ void testGetParentGraph() { OrganisationUnit ouB = createOrganisationUnit('B', ouA); OrganisationUnit ouC = createOrganisationUnit('C', ouB); OrganisationUnit ouD = createOrganisationUnit('D', ouC); - ouA.getChildren().add(ouB); - ouA.getChildren().add(ouC); - ouB.getChildren().add(ouD); organisationUnitService.addOrganisationUnit(ouA); organisationUnitService.addOrganisationUnit(ouB); organisationUnitService.addOrganisationUnit(ouC); diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/resourcetable/ResourceTableServiceTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/resourcetable/ResourceTableServiceTest.java index f8becff09629..a45664bb2baf 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/resourcetable/ResourceTableServiceTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/resourcetable/ResourceTableServiceTest.java @@ -86,12 +86,8 @@ void setUp() { idObjectManager.save(degsA); idObjectManager.save(degsB); OrganisationUnit ouA = createOrganisationUnit('A'); - OrganisationUnit ouB = createOrganisationUnit('B'); - OrganisationUnit ouC = createOrganisationUnit('C'); - ouB.setParent(ouA); - ouC.setParent(ouA); - ouA.getChildren().add(ouB); - ouA.getChildren().add(ouC); + OrganisationUnit ouB = createOrganisationUnit('B', ouA); + OrganisationUnit ouC = createOrganisationUnit('C', ouA); idObjectManager.save(ouA); idObjectManager.save(ouB); idObjectManager.save(ouC); From 5b5d6027b38797bc3877d47a7b2a59535ac2f210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Helge=20=C3=98verland?= Date: Fri, 10 Jan 2025 11:21:50 +0100 Subject: [PATCH 09/11] fix: Use org unit stored path [DHIS2-18234] (#19626) --- .../dhis/datavalue/DeflatedDataValue.java | 2 +- .../organisationunit/OrganisationUnit.java | 48 ++++++++++++++----- .../data/JdbcRawAnalyticsManager.java | 2 +- .../dhis/analytics/outlier/OutlierHelper.java | 5 +- ...rganisationUnitStructureResourceTable.java | 2 +- .../jdbc/JdbcOrgUnitAssociationsStore.java | 2 +- .../hibernate/HibernateDataValueStore.java | 4 +- .../function/FunctionOrgUnitAncestor.java | 2 +- .../HibernateOrganisationUnitStore.java | 4 +- ...pleteDataSetRegistrationExchangeStore.java | 2 +- .../datavalueset/SpringDataValueSetStore.java | 2 +- .../DataValueSetImportValidatorTest.java | 2 +- .../predictor/PredictionDataValueFetcher.java | 5 +- .../acl/DefaultTrackerAccessManager.java | 18 +++---- .../acl/DefaultTrackerOwnershipManager.java | 6 +-- .../export/OperationsParamsValidator.java | 3 +- .../enrollment/HibernateEnrollmentStore.java | 4 +- .../event/EventOperationParamsMapper.java | 2 +- .../tracker/export/event/JdbcEventStore.java | 6 +-- .../HibernateTrackedEntityStore.java | 4 +- .../SecurityOwnershipValidator.java | 4 +- .../event/SecurityOwnershipValidator.java | 7 ++- .../SecurityOwnershipValidator.java | 2 +- .../HibernateMinMaxDataElementStore.java | 2 +- .../util/OutlierDetectionUtils.java | 5 +- .../HibernateValidationResultStore.java | 3 +- .../OrganisationUnitServiceTest.java | 16 +++++++ .../controller/DataAnalysisController.java | 2 +- .../controller/LockExceptionController.java | 2 +- .../OrganisationUnitController.java | 7 +-- 30 files changed, 112 insertions(+), 63 deletions(-) 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)))); From 946fe6d495e9f1e7392dc8627ffa086c4aa7ba59 Mon Sep 17 00:00:00 2001 From: Enrico Colasante Date: Fri, 10 Jan 2025 07:36:35 -0300 Subject: [PATCH 10/11] fix: Bump rule-engine version [DHIS2-15891] (#19583) --- .../tracker/programs_with_program_rules.json | 12 +++++++----- dhis-2/pom.xml | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/dhis-2/dhis-test-e2e/src/test/resources/tracker/programs_with_program_rules.json b/dhis-2/dhis-test-e2e/src/test/resources/tracker/programs_with_program_rules.json index 9e1757d55eed..2713213dfc93 100644 --- a/dhis-2/dhis-test-e2e/src/test/resources/tracker/programs_with_program_rules.json +++ b/dhis-2/dhis-test-e2e/src/test/resources/tracker/programs_with_program_rules.json @@ -711,7 +711,7 @@ }, "favorites": [], "translations": [], - + "attributeValues": [] }], "translations": [], @@ -960,7 +960,8 @@ "created": "2020-12-08T09:10:20.341", "name": "TA tracker program rule - showerror on stage", "displayName": "TA tracker program rule - showerror", - "condition": "V{enrollment_date} > V{current_date}", + "externalAccess": false, + "condition": "d2:daysBetween(V{enrollment_date},V{current_date}) < 0", "favorite": false, "program": { "id": "U5HE4IRrZ7S" @@ -1002,7 +1003,7 @@ "users": {}, "userGroups": {} }, - "condition": "V{event_date} < V{current_date}", + "condition": "d2:daysBetween(V{event_date},V{current_date}) > 0", "program": { "id": "U5HE4IRrZ7S" }, @@ -1031,7 +1032,7 @@ "users": {}, "userGroups": {} }, - "condition": "V{event_date} < V{current_date}", + "condition": "d2:daysBetween(V{event_date},V{current_date}) > 0", "program": { "id": "U5HE4IRrZ7S" }, @@ -1082,7 +1083,8 @@ "created": "2020-12-08T09:10:20.341", "name": "TA tracker program rule - warnings", "displayName": "TA tracker program rule - warnings", - "condition": "V{enrollment_date} < V{current_date}", + "externalAccess": false, + "condition": "d2:daysBetween(V{enrollment_date},V{current_date}) > 0", "favorite": false, "program": { "id": "U5HE4IRrZ7S" diff --git a/dhis-2/pom.xml b/dhis-2/pom.xml index ae002685a972..060500875d83 100644 --- a/dhis-2/pom.xml +++ b/dhis-2/pom.xml @@ -85,7 +85,7 @@ - 3.2.1 + 3.2.2 0.6.1 From 0caa2110dbab49b1568f49eef2e6c6643d7f2b6e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 11:37:01 +0100 Subject: [PATCH 11/11] chore(deps): bump commons-beanutils:commons-beanutils in /dhis-2 (#19617) Bumps commons-beanutils:commons-beanutils from 1.9.4 to 1.10.0. --- updated-dependencies: - dependency-name: commons-beanutils:commons-beanutils dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dhis-2/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dhis-2/pom.xml b/dhis-2/pom.xml index 060500875d83..a5bb24f0198b 100644 --- a/dhis-2/pom.xml +++ b/dhis-2/pom.xml @@ -190,7 +190,7 @@ 2.13.0 9.2.1 4.4 - 1.9.4 + 1.10.0 3.17.0 1.13.0 1.5