diff --git a/src/main/java/org/avniproject/etl/controller/ReportController.java b/src/main/java/org/avniproject/etl/controller/ReportController.java index 4e9f84b0..05c68d22 100644 --- a/src/main/java/org/avniproject/etl/controller/ReportController.java +++ b/src/main/java/org/avniproject/etl/controller/ReportController.java @@ -1,6 +1,5 @@ package org.avniproject.etl.controller; -import org.avniproject.etl.domain.OrgIdentityContextHolder; import org.avniproject.etl.dto.AggregateReportResult; import org.avniproject.etl.dto.UserActivityDTO; import org.avniproject.etl.repository.ReportRepository; @@ -25,124 +24,92 @@ public ReportController(ReportRepository reportRepository, ReportUtil reportUtil @PreAuthorize("hasAnyAuthority('analytics_user')") @RequestMapping(value = "/report/aggregate/summaryTable", method = RequestMethod.GET) - public List getSummaryTable(@RequestParam(value = "startDate", required = false) String startDate, - @RequestParam(value = "endDate", required = false) String endDate, - @RequestParam(value = "userIds", required = false, defaultValue = "") List userIds){ - return reportRepository.generateSummaryTable( - OrgIdentityContextHolder.getDbSchema() - ); + public List getSummaryTable(){ + return reportRepository.generateSummaryTable(); } @PreAuthorize("hasAnyAuthority('analytics_user')") @RequestMapping(value = "report/hr/userActivity", method = RequestMethod.GET) public List getUserActivity(@RequestParam(value = "startDate", required = false) String startDate, - @RequestParam(value = "endDate", required = false) String endDate, - @RequestParam(value = "userIds", required = false, defaultValue = "") List userIds){ + @RequestParam(value = "endDate", required = false) String endDate){ return reportRepository.generateUserActivity( - OrgIdentityContextHolder.getDbSchema(), reportUtil.getDateDynamicWhere(startDate, endDate, "registration_date"), reportUtil.getDateDynamicWhere(startDate, endDate, "encounter_date_time"), - reportUtil.getDateDynamicWhere(startDate, endDate, "enrolment_date_time"), - reportUtil.getDynamicUserWhere(userIds, "u.id") - ); + reportUtil.getDateDynamicWhere(startDate, endDate, "enrolment_date_time")); } @PreAuthorize("hasAnyAuthority('analytics_user')") @RequestMapping(value = "/report/hr/syncFailures",method = RequestMethod.GET) public List getUserWiseSyncFailures(@RequestParam(value = "startDate", required = false) String startDate, - @RequestParam(value = "endDate", required = false) String endDate, - @RequestParam(value = "userIds", required = false, defaultValue = "") List userIds){ + @RequestParam(value = "endDate", required = false) String endDate){ return reportRepository.generateUserSyncFailures( - OrgIdentityContextHolder.getDbSchema(), - reportUtil.getDateDynamicWhere(startDate, endDate, "st.sync_start_time"), - reportUtil.getDynamicUserWhere(userIds, "u.id") + reportUtil.getDateDynamicWhere(startDate, endDate, "st.sync_start_time") ); } @PreAuthorize("hasAnyAuthority('analytics_user')") @RequestMapping(value = "/report/hr/deviceModels", method = RequestMethod.GET) - public List getUserWiseDeviceModels(@RequestParam(value = "userIds", required = false, defaultValue = "") List userIds) { + public List getUserWiseDeviceModels() { - return reportRepository.generateUserDeviceModels( - OrgIdentityContextHolder.getDbSchema(), - reportUtil.getDynamicUserWhere(userIds, "u.id")); + return reportRepository.generateUserDeviceModels(); } @PreAuthorize("hasAnyAuthority('analytics_user')") @RequestMapping(value = "/report/hr/appVersions", method = RequestMethod.GET) - public List getUserWiseAppVersions(@RequestParam(value = "userIds", required = false, defaultValue = "") List userIds) { + public List getUserWiseAppVersions() { - return reportRepository.generateUserAppVersions( - OrgIdentityContextHolder.getDbSchema(), - reportUtil.getDynamicUserWhere(userIds, "u.id")); + return reportRepository.generateUserAppVersions(); } @PreAuthorize("hasAnyAuthority('analytics_user')") @RequestMapping(value = "/report/hr/userDetails", method = RequestMethod.GET) - public List getUserDetails(@RequestParam(value = "userIds", required = false, defaultValue = "") List userIds) { + public List getUserDetails() { - return reportRepository.generateUserDetails( - OrgIdentityContextHolder.getDbSchema(), - reportUtil.getDynamicUserWhere(userIds, "u.id")); + return reportRepository.generateUserDetails(); } @PreAuthorize("hasAnyAuthority('analytics_user')") @RequestMapping(value = "/report/hr/latestSyncs", method = RequestMethod.GET) public List getLatestSyncs(@RequestParam(value = "startDate", required = false) String startDate, - @RequestParam(value = "endDate", required = false) String endDate, - @RequestParam(value = "userIds", required = false, defaultValue = "") List userIds) { + @RequestParam(value = "endDate", required = false) String endDate) { return reportRepository.generateLatestSyncs( - OrgIdentityContextHolder.getDbSchema(), - reportUtil.getDateDynamicWhere(startDate, endDate, "st.sync_end_time"), - reportUtil.getDynamicUserWhere(userIds, "u.id")); + reportUtil.getDateDynamicWhere(startDate, endDate, "st.sync_end_time")); } @PreAuthorize("hasAnyAuthority('analytics_user')") @RequestMapping(value = "/report/hr/medianSync", method = RequestMethod.GET) public List getMedianSync(@RequestParam(value = "startDate", required = false) String startDate, - @RequestParam(value = "endDate", required = false) String endDate, - @RequestParam(value = "userIds", required = false, defaultValue = "") List userIds) { + @RequestParam(value = "endDate", required = false) String endDate) { return reportRepository.generateMedianSync( - OrgIdentityContextHolder.getDbSchema(), reportUtil.getDateSeries(startDate, endDate)); } @PreAuthorize("hasAnyAuthority('analytics_user')") @RequestMapping(value = "/report/hr/championUsers", method = RequestMethod.GET) public List getChampionUsers(@RequestParam(value = "startDate", required = false) String startDate, - @RequestParam(value = "endDate", required = false) String endDate, - @RequestParam(value = "userIds", required = false, defaultValue = "") List userIds) { + @RequestParam(value = "endDate", required = false) String endDate) { return reportRepository.generateCompletedVisitsOnTimeByProportion( ">= 0.5", - OrgIdentityContextHolder.getDbSchema(), - reportUtil.getDateDynamicWhere(startDate, endDate, "encounter_date_time"), - reportUtil.getDynamicUserWhere(userIds, "u.id")); + reportUtil.getDateDynamicWhere(startDate, endDate, "encounter_date_time")); } @PreAuthorize("hasAnyAuthority('analytics_user')") @RequestMapping(value = "/report/hr/nonPerformingUsers", method = RequestMethod.GET) public List getNonPerformingUsers(@RequestParam(value = "startDate", required = false) String startDate, - @RequestParam(value = "endDate", required = false) String endDate, - @RequestParam(value = "userIds", required = false, defaultValue = "") List userIds) { + @RequestParam(value = "endDate", required = false) String endDate) { return reportRepository.generateCompletedVisitsOnTimeByProportion( "<= 0.5", - OrgIdentityContextHolder.getDbSchema(), - reportUtil.getDateDynamicWhere(startDate, endDate, "encounter_date_time"), - reportUtil.getDynamicUserWhere(userIds, "u.id") - ); + reportUtil.getDateDynamicWhere(startDate, endDate, "encounter_date_time")); } @PreAuthorize("hasAnyAuthority('analytics_user')") @RequestMapping(value = "/report/hr/mostCancelled", method = RequestMethod.GET) public List getUsersCancellingMostVisits(@RequestParam(value = "startDate", required = false) String startDate, - @RequestParam(value = "endDate", required = false) String endDate, - @RequestParam(value = "userIds", required = false, defaultValue = "") List userIds) { + @RequestParam(value = "endDate", required = false) String endDate) { return reportRepository.generateUserCancellingMostVisits( - OrgIdentityContextHolder.getDbSchema(), - reportUtil.getDateDynamicWhere(startDate, endDate, "encounter_date_time"), - reportUtil.getDynamicUserWhere(userIds, "u.id")); + reportUtil.getDateDynamicWhere(startDate, endDate, "encounter_date_time")); } diff --git a/src/main/java/org/avniproject/etl/repository/ReportRepository.java b/src/main/java/org/avniproject/etl/repository/ReportRepository.java index 0c762b7a..0b98631f 100644 --- a/src/main/java/org/avniproject/etl/repository/ReportRepository.java +++ b/src/main/java/org/avniproject/etl/repository/ReportRepository.java @@ -1,37 +1,50 @@ package org.avniproject.etl.repository; +import org.avniproject.etl.domain.NullObject; +import org.avniproject.etl.domain.OrgIdentityContextHolder; import org.avniproject.etl.domain.metadata.SchemaMetadata; import org.avniproject.etl.dto.AggregateReportResult; import org.avniproject.etl.dto.UserActivityDTO; import org.avniproject.etl.repository.rowMappers.reports.*; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Component; import org.stringtemplate.v4.ST; import java.util.List; +import static org.avniproject.etl.repository.JdbcContextWrapper.runInOrgContext; + @Component public class ReportRepository { - private final NamedParameterJdbcTemplate jdbcTemplate; + private final NamedParameterJdbcTemplate namedJdbcTemplate; private final SchemaMetadataRepository schemaMetadataRepository; + private final JdbcTemplate jdbcTemplate; @Autowired - public ReportRepository(NamedParameterJdbcTemplate jdbcTemplate, SchemaMetadataRepository schemaMetadataRepository) { - this.jdbcTemplate = jdbcTemplate; + public ReportRepository(NamedParameterJdbcTemplate namedJdbcTemplate, SchemaMetadataRepository schemaMetadataRepository, JdbcTemplate jdbcTemplate) { + this.namedJdbcTemplate = namedJdbcTemplate; this.schemaMetadataRepository = schemaMetadataRepository; + this.jdbcTemplate = jdbcTemplate; } - public List generateSummaryTable(String orgSchemaName){ + public List generateSummaryTable(){ String baseQuery = "select name, type \n" + "from public.table_metadata\n" + "where schema_name = '${schemaName}'\n" + "order by type;"; - String query= baseQuery.replace("${schemaName}", orgSchemaName); - return jdbcTemplate.query(query, new SummaryTableMapper()); + String query= baseQuery.replace("${schemaName}", OrgIdentityContextHolder.getDbSchema()); + + runInOrgContext(() -> { + jdbcTemplate.execute(query); + return NullObject.instance(); + }, jdbcTemplate); + + return namedJdbcTemplate.query(query, new SummaryTableMapper()); } - public List generateUserActivity(String orgSchemaName, String subjectWhere, String encounterWhere, String enrolmentWhere, String userWhere) { + public List generateUserActivity(String subjectWhere, String encounterWhere, String enrolmentWhere) { SchemaMetadata schema = schemaMetadataRepository.getExistingSchemaMetadata(); List subjectTableNames = schema.getAllSubjectTableNames().stream().toList(); List encounterTableNames = schema.getAllEncounterTableNames().stream().toList(); @@ -109,7 +122,6 @@ public List generateUserActivity(String orgSchemaName, String s " where (u.is_voided = false or u.is_voided isnull) and u.organisation_id notnull\n" + " and coalesce(coalesce(registration_count, 0) + coalesce(encounter_count, 0) + coalesce(enrolment_count, 0) +\n" + " coalesce(program_encounter_count, 0), 0) > 0\n" + - " $userWhere \n" + "),\n" + "final_table as (\n" + " select id, name,\n"+ @@ -130,15 +142,20 @@ public List generateUserActivity(String orgSchemaName, String s .add("encounterTableNames", encounterTableNames) .add("programEnrolmentTableNames", programEnrolmentTableNames) .add("programEncounterTableNames", programEncounterTableNames); - String query = baseQuery.render().replace("$schemaName", orgSchemaName) + String query = baseQuery.render().replace("$schemaName", OrgIdentityContextHolder.getDbSchema()) .replace("$subjectWhere", subjectWhere) .replace("$encounterWhere", encounterWhere) - .replace("$enrolmentWhere", enrolmentWhere) - .replace("$userWhere", userWhere); - return jdbcTemplate.query(query, new UserActivityMapper()); + .replace("$enrolmentWhere", enrolmentWhere); + + runInOrgContext(() -> { + jdbcTemplate.execute(query); + return NullObject.instance(); + }, jdbcTemplate); + + return namedJdbcTemplate.query(query, new UserActivityMapper()); } - public List generateUserSyncFailures(String orgSchemaName, String syncTelemetryWhere, String userWhere) { + public List generateUserSyncFailures(String syncTelemetryWhere) { String baseQuery = "select coalesce(u.name, u.username) as name, \n" + " count(*) as count\n" + "from ${schemaName}.sync_telemetry st\n" + @@ -147,18 +164,22 @@ public List generateUserSyncFailures(String orgSchemaName, Stri "and (u.is_voided = false or u.is_voided isnull)\n" + "and u.organisation_id notnull\n" + "${syncTelemetryWhere}\n"+ - "${userWhere}\n"+ "group by 1\n" + "order by 2 desc\n" + "limit 10;"; String query = baseQuery - .replace("${schemaName}", orgSchemaName) - .replace("${syncTelemetryWhere}", syncTelemetryWhere) - .replace("${userWhere}", userWhere); - return jdbcTemplate.query(query, new UserCountMapper()); + .replace("${schemaName}", OrgIdentityContextHolder.getDbSchema()) + .replace("${syncTelemetryWhere}", syncTelemetryWhere); + + runInOrgContext(() -> { + jdbcTemplate.execute(query); + return NullObject.instance(); + }, jdbcTemplate); + + return namedJdbcTemplate.query(query, new UserCountMapper()); } - public List generateUserAppVersions(String orgSchemaName, String userWhere) { + public List generateUserAppVersions() { String baseQuery = "select app_version as indicator,\n" + " count(*) as count\n" + "from ${schemaName}.users u\n" + @@ -168,15 +189,19 @@ public List generateUserAppVersions(String orgSchemaName, " row_number() over (partition by user_id order by sync_start_time desc ) as rn\n" + " from ${schemaName}.sync_telemetry) l on l.user_id = u.id and rn = 1\n" + "where (u.is_voided = false or u.is_voided isnull) and u.organisation_id notnull\n" + - "${userWhere}\n"+ "group by app_version;"; String query = baseQuery - .replace("${schemaName}", orgSchemaName) - .replace("${userWhere}", userWhere); - return jdbcTemplate.query(query, new AggregateReportMapper()); + .replace("${schemaName}", OrgIdentityContextHolder.getDbSchema()); + + runInOrgContext(() -> { + jdbcTemplate.execute(query); + return NullObject.instance(); + }, jdbcTemplate); + + return namedJdbcTemplate.query(query, new AggregateReportMapper()); } - public List generateUserDeviceModels(String orgSchemaName, String userWhere) { + public List generateUserDeviceModels() { String baseQuery = "select device_model as indicator,\n" + " count(*) as count\n" + "from ${schemaName}.users u\n" + @@ -186,15 +211,19 @@ public List generateUserDeviceModels(String orgSchemaName " row_number() over (partition by user_id order by sync_start_time desc ) as rn\n" + " from ${schemaName}.sync_telemetry) l on l.user_id = u.id and rn = 1\n" + "where (u.is_voided = false or u.is_voided isnull) and u.organisation_id notnull \n" + - "${userWhere}\n"+ "group by device_model;"; String query = baseQuery - .replace("${schemaName}", orgSchemaName) - .replace("${userWhere}", userWhere); - return jdbcTemplate.query(query, new AggregateReportMapper()); + .replace("${schemaName}", OrgIdentityContextHolder.getDbSchema()); + + runInOrgContext(() -> { + jdbcTemplate.execute(query); + return NullObject.instance(); + }, jdbcTemplate); + + return namedJdbcTemplate.query(query, new AggregateReportMapper()); } - public List generateUserDetails(String orgSchemaName, String userWhere) { + public List generateUserDetails() { String baseQuery = "select coalesce(u.name, u.username) as name,\n" + " app_version,\n" + " device_model,\n" + @@ -210,32 +239,40 @@ public List generateUserDetails(String orgSchemaName, String us " where sync_status = 'complete') l on l.user_id = u.id and rn = 1\n" + "where (u.is_voided = false or u.is_voided isnull)\n" + " and u.organisation_id notnull\n" + - " ${userWhere}\n"+ "order by 1 desc;"; String query = baseQuery - .replace("${schemaName}", orgSchemaName) - .replace("${userWhere}", userWhere); - return jdbcTemplate.query(query, new UserDetailsMapper()); + .replace("${schemaName}", OrgIdentityContextHolder.getDbSchema()); + + runInOrgContext(() -> { + jdbcTemplate.execute(query); + return NullObject.instance(); + }, jdbcTemplate); + + return namedJdbcTemplate.query(query, new UserDetailsMapper()); } - public List generateLatestSyncs(String orgSchemaName, String syncTelemetryWhere, String userWhere) { + public List generateLatestSyncs(String syncTelemetryWhere) { String baseQuery = "SELECT coalesce(u.name,u.username) as name, \n" + " android_version, app_version, device_name, sync_start_time, sync_end_time, sync_status, sync_source\n" + "FROM public.sync_telemetry st\n" + "join ${schemaName}.users u on st.last_modified_by_id = u.id\n" + "where (u.is_voided = false or u.is_voided isnull) and u.organisation_id notnull\n" + "${syncTelemetryWhere}\n"+ - "${userWhere}\n"+ "order by 6 desc\n" + "limit 10;\n"; String query = baseQuery - .replace("${schemaName}", orgSchemaName) - .replace("${syncTelemetryWhere}", syncTelemetryWhere) - .replace("${userWhere}", userWhere); - return jdbcTemplate.query(query, new LatestSyncMapper()); + .replace("${schemaName}", OrgIdentityContextHolder.getDbSchema()) + .replace("${syncTelemetryWhere}", syncTelemetryWhere); + + runInOrgContext(() -> { + jdbcTemplate.execute(query); + return NullObject.instance(); + }, jdbcTemplate); + + return namedJdbcTemplate.query(query, new LatestSyncMapper()); } - public List generateMedianSync(String orgSchemaName, String syncTelemetryWhere) { + public List generateMedianSync(String syncTelemetryWhere) { String baseQuery = "with weeks as (\n" + " select day::date start_date, day::date+6 end_date\n" + " ${syncTelemetryWhere}\n" + @@ -248,12 +285,18 @@ public List generateMedianSync(String orgSchemaName, String syn "and st.sync_source = 'manual'\n" + "group by 1,2;"; String query = baseQuery - .replace("${schemaName}", orgSchemaName) + .replace("${schemaName}", OrgIdentityContextHolder.getDbSchema()) .replace("${syncTelemetryWhere}", syncTelemetryWhere); - return jdbcTemplate.query(query, new MedianSyncMapper()); + + runInOrgContext(() -> { + jdbcTemplate.execute(query); + return NullObject.instance(); + }, jdbcTemplate); + + return namedJdbcTemplate.query(query, new MedianSyncMapper()); } - public List generateCompletedVisitsOnTimeByProportion(String proportionCondition, String orgSchemaName, String encounterWhere, String userWhere) { + public List generateCompletedVisitsOnTimeByProportion(String proportionCondition, String encounterWhere) { SchemaMetadata schema = schemaMetadataRepository.getExistingSchemaMetadata(); List encounterTableNames = schema.getAllEncounterTableNames().stream().toList(); List programEncounterTableNames = schema.getAllProgramEncounterTableNames().stream().toList(); @@ -305,7 +348,6 @@ public List generateCompletedVisitsOnTimeByProportion(Str " left join program_enc_data ped on ped.last_modified_by_id = u.id\n" + " where u.organisation_id notnull\n" + " and (is_voided = false or is_voided isnull)\n" + - " $userWhere\n" + " group by u.name, u.username \n" + ")\n" + "select indicator,\n" + @@ -318,13 +360,18 @@ public List generateCompletedVisitsOnTimeByProportion(Str baseQuery.add("programEncounterTableNames", programEncounterTableNames) .add("encounterTableNames", encounterTableNames); String query = baseQuery.render().replace("$proportion_condition", proportionCondition) - .replace("$schemaName", orgSchemaName) - .replace("$encounterWhere", encounterWhere) - .replace("$userWhere", userWhere); - return jdbcTemplate.query(query, new AggregateReportMapper()); + .replace("$schemaName", OrgIdentityContextHolder.getDbSchema()) + .replace("$encounterWhere", encounterWhere); + + runInOrgContext(() -> { + jdbcTemplate.execute(query); + return NullObject.instance(); + }, jdbcTemplate); + + return namedJdbcTemplate.query(query, new AggregateReportMapper()); } - public List generateUserCancellingMostVisits(String orgSchemaName, String encounterWhere, String userWhere) { + public List generateUserCancellingMostVisits(String encounterWhere) { SchemaMetadata schema = schemaMetadataRepository.getExistingSchemaMetadata(); List encounterTableNames = schema.getAllEncounterTableNames().stream().toList(); List programEncounterTableNames = schema.getAllProgramEncounterTableNames().stream().toList(); @@ -371,7 +418,6 @@ public List generateUserCancellingMostVisits(String orgSc "where u.organisation_id notnull\n" + " and (is_voided = false or is_voided isnull)\n" + " and coalesce(ged.cancelled_visits, 0) + coalesce(ped.cancelled_visits, 0) > 0 \n" + - " $userWhere\n" + " group by u.name,u.username \n" + ")\n" + "select indicator,\n" + @@ -382,9 +428,14 @@ public List generateUserCancellingMostVisits(String orgSc ); baseQuery.add("programEncounterTableNames", programEncounterTableNames) .add("encounterTableNames", encounterTableNames); - String query = baseQuery.render().replace("$schemaName", orgSchemaName) - .replace("$encounterWhere", encounterWhere) - .replace("$userWhere", userWhere); - return jdbcTemplate.query(query, new AggregateReportMapper()); + String query = baseQuery.render().replace("$schemaName", OrgIdentityContextHolder.getDbSchema()) + .replace("$encounterWhere", encounterWhere); + + runInOrgContext(() -> { + jdbcTemplate.execute(query); + return NullObject.instance(); + }, jdbcTemplate); + + return namedJdbcTemplate.query(query, new AggregateReportMapper()); } } diff --git a/src/main/java/org/avniproject/etl/util/ReportUtil.java b/src/main/java/org/avniproject/etl/util/ReportUtil.java index 239282b6..98436b12 100644 --- a/src/main/java/org/avniproject/etl/util/ReportUtil.java +++ b/src/main/java/org/avniproject/etl/util/ReportUtil.java @@ -24,7 +24,7 @@ public String getDateSeries(String startDate, String endDate) { public String getDynamicUserWhere(List userIds, String columnName) { if (!userIds.isEmpty()) { - return format("and %s in (%s)", columnName, StrUtil.joinLongToList(userIds)); + return format("and %s in (%s)", columnName, StringUtil.joinLongToList(userIds)); } return ""; } diff --git a/src/main/java/org/avniproject/etl/util/StrUtil.java b/src/main/java/org/avniproject/etl/util/StringUtil.java similarity index 67% rename from src/main/java/org/avniproject/etl/util/StrUtil.java rename to src/main/java/org/avniproject/etl/util/StringUtil.java index 10e759cc..8f0ccf45 100644 --- a/src/main/java/org/avniproject/etl/util/StrUtil.java +++ b/src/main/java/org/avniproject/etl/util/StringUtil.java @@ -3,11 +3,7 @@ import java.util.List; import java.util.stream.Collectors; -public class StrUtil { - - public static boolean isEmpty(String string) { - return string == null || string.trim().isEmpty(); - } +public class StringUtil { public static String joinLongToList(List lists) { return lists.isEmpty() ? "" : lists.stream().map(String::valueOf)