Skip to content

Commit

Permalink
Merge branch 'development' into LNK-2186
Browse files Browse the repository at this point in the history
# Conflicts:
#	core/src/main/java/com/lantanagroup/link/sender/FileSystemSender.java
  • Loading branch information
seanmcilvenna committed Mar 15, 2024
2 parents f58a740 + 002681a commit 34e5084
Show file tree
Hide file tree
Showing 33 changed files with 442 additions and 324 deletions.
19 changes: 0 additions & 19 deletions .idea/runConfigurations/API_DEV___No_Scheduling.xml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ private MeasureReport generateMeasureReport() {
MeasureReport measureReport;
String patientDataBundleId = ReportIdHelper.getPatientDataBundleId(reportContext.getMasterIdentifierValue(), patientId);
String measureId = this.measureContext.getMeasure().getIdElement().getIdPart();
String start = this.criteria.getPeriodStart().substring(0, this.criteria.getPeriodStart().indexOf("."));
String end = this.criteria.getPeriodEnd().substring(0, this.criteria.getPeriodEnd().indexOf("."));

Bundle patientBundle;
try (Stopwatch stopwatch = this.stopwatchManager.start(Constants.TASK_RETRIEVE_PATIENT_DATA, Constants.CATEGORY_REPORT)) {
Expand All @@ -60,7 +58,7 @@ private MeasureReport generateMeasureReport() {
Helper.dumpToFile(patientBundle, config.getDebugPath(), fileName);
}

logger.info("Executing $evaluate-measure for measure: {}, start: {}, end: {}, patient: {}, resources: {}", measureId, start, end, patientId, patientBundle.getEntry().size());
logger.info("Executing $evaluate-measure for measure: {}, start: {}, end: {}, patient: {}, resources: {}", measureId, criteria.getPeriodStart(), criteria.getPeriodEnd(), patientId, patientBundle.getEntry().size());

//noinspection unused
try (Stopwatch stopwatch = this.stopwatchManager.start(Constants.TASK_MEASURE, Constants.CATEGORY_EVALUATE)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@
import com.lantanagroup.link.config.api.ApiConfig;
import com.lantanagroup.link.db.SharedService;
import com.lantanagroup.link.db.model.User;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
Expand Down Expand Up @@ -52,7 +52,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
logger.debug("Validating the requesting IP address against the token IP address.");
DecodedJWT jwt = JWT.decode(authHeader.substring(7));

if (!jwt.getClaim("ip").isNull() && !"0:0:0:0:0:0:0:1(0:0:0:0:0:0:0:1)".equals(ipAddress) && !jwt.getClaim("ip").asString().equals(ipAddress)) {
if (!jwt.getClaim("ip").isNull() && !"127.0.0.1(127.0.0.1)".equals(ipAddress) && !"0:0:0:0:0:0:0:1(0:0:0:0:0:0:0:1)".equals(ipAddress) && !jwt.getClaim("ip").asString().equals(ipAddress)) {
throw new JWTVerificationException("IP Address does not match.");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,17 @@ public List<GlobalReportResponse> getReports(
if (!startDate.isEmpty()) {
Date date = Helper.parseFhirDate(startDate);

reports = reports.stream().filter(x -> {
try {
return Helper.parseFhirDate(x.getPeriodStart()).after(date) || Helper.parseFhirDate(x.getPeriodStart()).equals(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}).collect(Collectors.toList());
reports = reports.stream().filter(x ->
Helper.parseFhirDate(x.getPeriodStart()).after(date) || Helper.parseFhirDate(x.getPeriodStart()).equals(date)
).collect(Collectors.toList());
}

if (!endDate.isEmpty()) {
Date date = Helper.parseFhirDate(endDate);

reports = reports.stream().filter(x -> {
try {
return Helper.parseFhirDate(x.getPeriodEnd()).before(date) || Helper.parseFhirDate(x.getPeriodStart()).equals(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}).collect(Collectors.toList());
reports = reports.stream().filter(x ->
Helper.parseFhirDate(x.getPeriodEnd()).before(date) || Helper.parseFhirDate(x.getPeriodStart()).equals(date)
).collect(Collectors.toList());
}

if (!tenantId.isEmpty()) {
Expand All @@ -66,8 +58,7 @@ public List<GlobalReportResponse> getReports(
reports = reports.stream().filter(x -> x.getStatus().equals(ReportStatuses.valueOf(status))).collect(Collectors.toList());
}

if(measureIds.length() > 0)
{
if (!measureIds.isEmpty()) {
String[] ids = measureIds.split(",");
reports = reports.stream().filter(x -> {
HashSet<String> measureIdsSet = new HashSet<>(x.getMeasureIds());
Expand All @@ -80,7 +71,11 @@ public List<GlobalReportResponse> getReports(
}).collect(Collectors.toList());
}

reports = reports.stream().skip((long) (page -1) * count).limit(count).collect(Collectors.toList());
reports = reports
.stream()
.skip((long) (page - 1) * count)
.limit(count)
.collect(Collectors.toList());

return reports;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,8 @@ public LogSearchResponse getLogs(@RequestParam(required = false) String startDat
Date startDateObj;
Date endDateObj;

try {
startDateObj = Helper.parseFhirDate(startDate);
endDateObj = Helper.parseFhirDate(endDate);
} catch (ParseException ex) {
throw new IllegalArgumentException("Invalid date format, must be in the format yyyy-MM-dd'T'HH:mm:ss.SSSXXX or yyyy-MM-dd'T'HH:mm:ssXXX");
}
startDateObj = Helper.parseFhirDate(startDate);
endDateObj = Helper.parseFhirDate(endDate);

List<LogMessage> logMessages = this.sharedService.findLogMessages(startDateObj, endDateObj, severity, page, content);
LogSearchResponse res = new LogSearchResponse();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

import ca.uhn.fhir.rest.api.EncodingEnum;
import com.lantanagroup.link.FhirContextProvider;
import com.lantanagroup.link.FhirDataProvider;
import com.lantanagroup.link.FhirHelper;
import com.lantanagroup.link.Helper;
import com.lantanagroup.link.api.MeasureServiceWrapper;
import com.lantanagroup.link.config.api.ApiConfig;
import com.lantanagroup.link.config.api.MeasureDefConfig;
import com.lantanagroup.link.db.SharedService;
import com.lantanagroup.link.db.model.MeasureDefinition;
import com.lantanagroup.link.db.model.MeasurePackage;
Expand Down Expand Up @@ -86,11 +86,12 @@ public void createOrUpdateMeasureDef(@RequestBody(required = false) Bundle bundl
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Either a Bundle must be specified in a JSON body of the request, or a \"measureId\" query parameter must be specified");
}

if (StringUtils.isNotEmpty(measureId) && this.apiConfig.getMeasureDefUrls().get(measureId) == null) {
MeasureDefConfig foundMeasureDef = this.apiConfig.getMeasureDefinition(measureId);
if (StringUtils.isNotEmpty(measureId) && foundMeasureDef == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "The specified measureId is not configured with a measure definition URL");
}

String url = StringUtils.isNotEmpty(measureId) ? this.apiConfig.getMeasureDefUrls().get(measureId) : null;
String url = foundMeasureDef != null ? foundMeasureDef.getDefinitionUrl() : null;
Bundle bundle = bundleBody == null ? this.getBundleFromUrl(url) : bundleBody;

if (bundle == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.lantanagroup.link.*;
import com.lantanagroup.link.api.ReportGenerator;
import com.lantanagroup.link.auth.LinkCredentials;
import com.lantanagroup.link.config.api.ApiConfig;
import com.lantanagroup.link.db.SharedService;
import com.lantanagroup.link.db.TenantService;
import com.lantanagroup.link.db.model.*;
Expand Down Expand Up @@ -82,6 +83,10 @@ public class ReportController extends BaseController {
@Autowired
private ValidationService validationService;

@Autowired
private ApiConfig apiConfig;


@InitBinder
public void initBinder(WebDataBinder binder) {
binder.setDisallowedFields(DISALLOWED_FIELDS);
Expand Down Expand Up @@ -275,15 +280,15 @@ public Report generateReport(
}

private void checkReportingPlan(TenantService tenantService, String periodStart, List<String> measureIds) throws ParseException, URISyntaxException, IOException {
if (tenantService.getConfig().getReportingPlan() == null) {
if (apiConfig.getReportingPlan() == null) {
return;
}

if (!tenantService.getConfig().getReportingPlan().isEnabled()) {
if (!apiConfig.getReportingPlan().isEnabled()) {
return;
}

if (StringUtils.isEmpty(tenantService.getConfig().getReportingPlan().getUrl())) {
if (StringUtils.isEmpty(apiConfig.getReportingPlan().getUrl())) {
logger.error("Reporting plan for tenant {} is not configured with a URL", tenantService.getConfig().getId());
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR);
}
Expand All @@ -293,13 +298,13 @@ private void checkReportingPlan(TenantService tenantService, String periodStart,
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR);
}

ReportingPlanService reportingPlanService = new ReportingPlanService(tenantService.getConfig().getReportingPlan(), tenantService.getConfig().getCdcOrgId());
ReportingPlanService reportingPlanService = new ReportingPlanService(apiConfig.getReportingPlan(), tenantService.getConfig().getCdcOrgId());

Date date = Helper.parseFhirDate(periodStart);
int year = date.getYear() + 1900;
int month = date.getMonth() + 1;
for (String bundleId : measureIds) {
String planName = tenantService.getConfig().getReportingPlan().getPlanNames().get(bundleId);
String planName = apiConfig.getReportingPlan().getPlanNames().get(bundleId);
if (!reportingPlanService.isReporting(planName, year, month)) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Measure not in MRP for specified year and month");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.lantanagroup.link.api.scheduling.Scheduler;
import com.lantanagroup.link.db.SharedService;
import com.lantanagroup.link.db.TenantService;
import com.lantanagroup.link.db.model.Report;
import com.lantanagroup.link.db.model.tenant.Tenant;
import com.lantanagroup.link.db.model.tenant.TenantVendors;
import com.lantanagroup.link.model.SearchTenantResponse;
Expand Down Expand Up @@ -49,7 +50,7 @@ public List<SearchTenantResponse> searchTenants() {
}

@GetMapping("summary")
public TenantSummaryResponse searchTenantSummaries(@RequestParam(required = false) String searchCriteria, @RequestParam(defaultValue = "NAME", required = false) String sort, @RequestParam(defaultValue = "1", required = false) int page, @RequestParam(defaultValue = "true", required = false) boolean sortAscend) {
public TenantSummaryResponse searchTenants(@RequestParam(required = false) String searchCriteria, @RequestParam(defaultValue = "NAME", required = false) String sort, @RequestParam(defaultValue = "1", required = false) int page, @RequestParam(defaultValue = "true", required = false) boolean sortAscend) {
// validation
int itemsPerPage = 5;

Expand All @@ -67,9 +68,22 @@ public TenantSummaryResponse searchTenantSummaries(@RequestParam(required = fals
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid sort criteria. Valid values are NAME, NHSN_ORG_ID, SUBMISSION_DATE");
}
}
List<TenantSummary> tenants = this.sharedService.getTenantSummary(searchCriteria, TenantSummarySort.valueOf(sort.trim()), sortAscend).stream().collect(Collectors.toList());

List<TenantSummary> results = tenants.stream().skip(skip).limit(itemsPerPage).collect(Collectors.toList());
List<TenantSummary> tenants = this.sharedService.searchTenants(searchCriteria, TenantSummarySort.valueOf(sort.trim()), sortAscend);
List<TenantSummary> results = tenants.stream()
.skip(skip)
.limit(itemsPerPage)
.collect(Collectors.toList());

results.forEach(t -> {
TenantService tenantService = TenantService.create(this.sharedService.getTenantConfig(t.getId()));
Report lastReport = tenantService.findLastReport();

if (lastReport != null) {
t.setLastSubmissionId(lastReport.getId());
t.setLastSubmissionDate(String.valueOf(lastReport.getSubmittedTime()));
}
});

TenantSummaryResponse response = new TenantSummaryResponse();
response.setTotal(tenants.size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ public class ValidationController extends BaseController {
/**
* Validates a Bundle provided in the request body
*
* @param tenantId The id of the tenant
* @param severity The minimum severity level to report on
* @return Returns an OperationOutcome resource that provides details about each of the issues found
*/
Expand All @@ -73,7 +72,6 @@ public OperationOutcome validate(@RequestBody Bundle bundle, @RequestParam(defau
/**
* Validates a Bundle provided in the request body
*
* @param tenantId The id of the tenant
* @param severity The minimum severity level to report on
* @return Returns an OperationOutcome resource that provides details about each of the issues found
*/
Expand All @@ -92,7 +90,9 @@ public String validateSummary(@RequestBody Bundle bundle, @RequestParam(defaultV
* @throws IOException
*/
@GetMapping("/{tenantId}/{reportId}")
public OperationOutcome getValidationIssuesForReport(@PathVariable String tenantId, @PathVariable String reportId, @RequestParam(defaultValue = "INFORMATION") OperationOutcome.IssueSeverity severity, @RequestParam(required = false) String code) {
public OperationOutcome getValidationIssuesForReport(@PathVariable String tenantId, @PathVariable String reportId,
@RequestParam(defaultValue = "INFORMATION") OperationOutcome.IssueSeverity severity,
@RequestParam(required = false) String code) {
TenantService tenantService = TenantService.create(this.sharedService, tenantId);

if (tenantService == null) {
Expand Down
11 changes: 2 additions & 9 deletions core/src/main/java/com/lantanagroup/link/ApplyConceptMaps.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

public class ApplyConceptMaps {
private static final Logger logger = LoggerFactory.getLogger(ApplyConceptMaps.class);
private final DefaultProfileValidationSupport validationSupport = new DefaultProfileValidationSupport(FhirContextProvider.getFhirContext());

private List<com.lantanagroup.link.db.model.ConceptMap> conceptMaps;

Expand All @@ -27,14 +26,8 @@ public static boolean isMapped(Coding coding, String system, String code) {
.anyMatch(mappedCoding -> mappedCoding.is(system, code));
}

public ApplyConceptMaps() {
validationSupport.fetchAllStructureDefinitions();
}
public ApplyConceptMaps() {}

private FHIRPathEngine getFhirPathEngine() {
HapiWorkerContext workerContext = new HapiWorkerContext(FhirContextProvider.getFhirContext(), validationSupport);
return new FHIRPathEngine(workerContext);
}

private void translateCoding(ConceptMap map, Coding code) {
map.getGroup().stream().forEach((ConceptMap.ConceptMapGroupComponent group) -> {
Expand Down Expand Up @@ -81,7 +74,7 @@ public List<Base> filterResourcesByPathList(DomainResource resource, List<String
List<Base> results = new ArrayList<>();
// logger.debug(String.format("FindCodings for resource %s based on path %s", resource.getResourceType() + "/" + resource.getIdElement().getIdPart(), List.of(pathList)));
pathList.stream().forEach(path -> {
results.addAll(getFhirPathEngine().evaluate(resource, path));
results.addAll(FhirHelper.getFhirPathEngine().evaluate(resource, path));
});
return results;
}
Expand Down
5 changes: 5 additions & 0 deletions core/src/main/java/com/lantanagroup/link/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,9 @@ public class Constants {
public static final String VALIDATION_ISSUE_TASK = "Validation";
public static final String VALIDATION_ISSUE_CATEGORY = "Validation Issues";
public static final String REPORT_GENERATION_TASK = "Report Generation";

//Submission file names
public static final String ORGANIZATION_FILE_NAME = "organization.json";
public static final String DEVICE_FILE_NAME = "device.json";
public static final String QUERY_PLAN_FILE_NAME = "query-plan.yml";
}

0 comments on commit 34e5084

Please sign in to comment.