Skip to content

Commit

Permalink
Merge branch 'main' into bobby/MOP-backend
Browse files Browse the repository at this point in the history
  • Loading branch information
bobbywells52 authored Oct 28, 2024
2 parents c0f4311 + 12574a3 commit 07a087a
Show file tree
Hide file tree
Showing 32 changed files with 1,529 additions and 863 deletions.
4 changes: 2 additions & 2 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jar {

dependencies {
// core infrastructure
implementation 'org.springframework.boot:spring-boot-starter-web:3.2.0'
implementation 'org.springframework.boot:spring-boot-starter-web:3.3.4'
implementation 'org.springframework.boot:spring-boot-starter-cache'
implementation 'org.springframework.boot:spring-boot-actuator'
implementation 'org.springframework.boot:spring-boot-actuator-autoconfigure'
Expand Down Expand Up @@ -61,7 +61,7 @@ dependencies {
*
* DevSecOps verifies these packages at least once per month. LAST VERIFIED: 10 July 2024.
*/
implementation 'com.squareup.okio:okio:3.9.0'
implementation 'com.squareup.okio:okio:3.9.1'
implementation 'org.springframework:spring-core:6.0.16'
implementation 'org.springframework.security:spring-security-core:6.1.8'
implementation 'org.springframework.security:spring-security-oauth2-client:6.3.1'
Expand Down
6 changes: 3 additions & 3 deletions backend/gradle.lockfile
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ com.sendgrid:java-http-client:4.5.0=compileClasspath,runtimeClasspath
com.sendgrid:sendgrid-java:4.10.3=compileClasspath,runtimeClasspath
com.smartystreets.api:smartystreets-java-sdk:3.18.0=compileClasspath,runtimeClasspath
com.squareup.okhttp3:okhttp:4.10.0=compileClasspath,runtimeClasspath
com.squareup.okio:okio-jvm:3.9.0=compileClasspath,runtimeClasspath
com.squareup.okio:okio:3.9.0=compileClasspath,runtimeClasspath
com.squareup.okio:okio-jvm:3.9.1=compileClasspath,runtimeClasspath
com.squareup.okio:okio:3.9.1=compileClasspath,runtimeClasspath
com.stoyanr:evictor:1.0.0=compileClasspath,runtimeClasspath
com.sun.istack:istack-commons-runtime:4.1.2=runtimeClasspath
com.twilio.sdk:twilio:10.1.0=compileClasspath,runtimeClasspath
Expand Down Expand Up @@ -204,7 +204,7 @@ org.springframework.boot:spring-boot-starter-security:3.1.7=compileClasspath,run
org.springframework.boot:spring-boot-starter-thymeleaf:3.1.7=compileClasspath,runtimeClasspath
org.springframework.boot:spring-boot-starter-tomcat:3.1.7=compileClasspath,runtimeClasspath
org.springframework.boot:spring-boot-starter-validation:3.1.7=compileClasspath,runtimeClasspath
org.springframework.boot:spring-boot-starter-web:3.2.0=compileClasspath,runtimeClasspath
org.springframework.boot:spring-boot-starter-web:3.3.4=compileClasspath,runtimeClasspath
org.springframework.boot:spring-boot-starter:3.1.7=compileClasspath,runtimeClasspath
org.springframework.boot:spring-boot:3.1.7=compileClasspath,runtimeClasspath
org.springframework.cloud:spring-cloud-commons:4.0.4=compileClasspath,runtimeClasspath
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,51 @@ public static String parseState(String s) {
throw IllegalGraphqlArgumentException.invalidInput(s, "state");
}

private static final Map<String, String> RESPIRATORY_SYMPTOMS =
Map.ofEntries(
Map.entry("426000000", "Fever over 100.4F"),
Map.entry("103001002", "Feeling feverish"),
Map.entry("43724002", "Chills"),
Map.entry("49727002", "Cough"),
Map.entry("267036007", "Shortness of breath"),
Map.entry("230145002", "Difficulty breathing"),
Map.entry("84229001", "Fatigue"),
Map.entry("68962001", "Muscle or body aches"),
Map.entry("25064002", "Headache"),
Map.entry("36955009", "New loss of taste"),
Map.entry("44169009", "New loss of smell"),
Map.entry("162397003", "Sore throat"),
Map.entry("68235000", "Nasal congestion"),
Map.entry("64531003", "Runny nose"),
Map.entry("422587007", "Nausea"),
Map.entry("422400008", "Vomiting"),
Map.entry("62315008", "Diarrhea"),
Map.entry("261665006", "Other symptom not listed"));

private static final Map<String, String> SYPHILIS_SYMPTOMS =
Map.ofEntries(
Map.entry("724386005", "Genital sore/lesion"),
Map.entry("195469007", "Anal sore/lesion"),
Map.entry("26284000", "Sore(s) in mouth/lips"),
Map.entry("266128007", "Body Rash"),
Map.entry("56940005", "Palmar (hand)/plantar (foot) rash"),
Map.entry("91554004", "Flat white warts"),
Map.entry("15188001", "Hearing loss"),
Map.entry("246636008", "Blurred vision"),
Map.entry("56317004", "Alopecia"));

private static Map<String, String> getSupportedSymptoms() {
Map<String, String> supportedSymptoms = new HashMap<>();
supportedSymptoms.putAll(RESPIRATORY_SYMPTOMS);
supportedSymptoms.putAll(SYPHILIS_SYMPTOMS);
return supportedSymptoms;
}

public static String getSymptomName(String snomedCode) {
Map<String, String> supportedSymptoms = getSupportedSymptoms();
return supportedSymptoms.get(snomedCode);
}

public static Map<String, Boolean> parseSymptoms(String symptoms) {
if (symptoms == null) {
return Collections.emptyMap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ private FhirConstants() {

public static final String LOINC_AOE_IDENTIFIER = "81959-9";
public static final String LOINC_AOE_SYMPTOMATIC = "95419-8";
public static final String LOINC_SYMPTOM_TIMING_PANEL = "99582-9";
public static final String LOINC_SYMPTOM = "75325-1";
public static final String LOINC_AOE_SYMPTOM_ONSET = "11368-8";
public static final String LOINC_AOE_PREGNANCY_STATUS = "82810-3";
public static final String LOINC_AOE_EMPLOYED_IN_HEALTHCARE = "95418-0";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import static gov.cdc.usds.simplereport.api.Translators.REFUSED;
import static gov.cdc.usds.simplereport.api.Translators.TRANS_MAN;
import static gov.cdc.usds.simplereport.api.Translators.TRANS_WOMAN;
import static gov.cdc.usds.simplereport.api.Translators.getSymptomName;
import static gov.cdc.usds.simplereport.api.converter.FhirConstants.ABNORMAL_FLAGS_CODE_SYSTEM;
import static gov.cdc.usds.simplereport.api.converter.FhirConstants.ABNORMAL_FLAG_ABNORMAL;
import static gov.cdc.usds.simplereport.api.converter.FhirConstants.ABNORMAL_FLAG_NORMAL;
Expand All @@ -34,6 +35,8 @@
import static gov.cdc.usds.simplereport.api.converter.FhirConstants.LOINC_AOE_SYMPTOM_ONSET;
import static gov.cdc.usds.simplereport.api.converter.FhirConstants.LOINC_CODE_SYSTEM;
import static gov.cdc.usds.simplereport.api.converter.FhirConstants.LOINC_GENDER_IDENTITY;
import static gov.cdc.usds.simplereport.api.converter.FhirConstants.LOINC_SYMPTOM;
import static gov.cdc.usds.simplereport.api.converter.FhirConstants.LOINC_SYMPTOM_TIMING_PANEL;
import static gov.cdc.usds.simplereport.api.converter.FhirConstants.NOTE_TYPE_CODING_SYSTEM;
import static gov.cdc.usds.simplereport.api.converter.FhirConstants.NOTE_TYPE_CODING_SYSTEM_CODE;
import static gov.cdc.usds.simplereport.api.converter.FhirConstants.NOTE_TYPE_CODING_SYSTEM_CODE_INDEX_EXTENSION_URL;
Expand Down Expand Up @@ -114,12 +117,15 @@
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -802,7 +808,7 @@ private void addCorrectionNote(
}
}

public Set<Observation> convertToAOESymptomObservation(
public Set<Observation> convertToAOESymptomaticObservation(
String eventId, Boolean symptomatic, LocalDate symptomOnsetDate) {
var observations = new LinkedHashSet<Observation>();
var symptomaticCode =
Expand All @@ -827,6 +833,33 @@ public Set<Observation> convertToAOESymptomObservation(
return observations;
}

public Observation createSymptomObservation(CodeableConcept code, Type value) {
Observation observation =
new Observation().setStatus(ObservationStatus.FINAL).setCode(code).setValue(value);
observation.setId(uuidGenerator.randomUUID().toString());
observation
.addIdentifier()
.setUse(IdentifierUse.OFFICIAL)
.setType(createLoincConcept(LOINC_SYMPTOM_TIMING_PANEL, "Symptom and timing panel", null));
return observation;
}

public Set<Observation> convertToSymptomsObservations(List<String> symptoms) {
HashSet<Observation> observations = new HashSet<>();

CodeableConcept symptomStatusCode = createLoincConcept(LOINC_SYMPTOM, "Symptom", "Symptom");

symptoms.forEach(
symptom -> {
String symptomName = getSymptomName(symptom);
if (symptomName != null && !symptomName.isBlank()) {
CodeableConcept symptomValueCode = createSNOMEDConcept(symptom, symptomName, null);
observations.add(createSymptomObservation(symptomStatusCode, symptomValueCode));
}
});
return observations;
}

public Set<Observation> convertToAOEGenderOfSexualPartnersObservation(
Set<String> sexualPartners) {
HashSet<Observation> observations = new LinkedHashSet<>();
Expand Down Expand Up @@ -972,10 +1005,12 @@ public Set<Observation> convertToAOEObservations(
} else if (surveyData.getSymptoms() != null
&& surveyData.getSymptoms().containsValue(Boolean.TRUE)) {
symptomatic = true;
List<String> symptomsPresent = getFilteredSymptomsPresent(surveyData.getSymptoms());
observations.addAll(convertToSymptomsObservations(symptomsPresent));
} // implied else: AoE form was not completed. Symptomatic set to null

var symptomOnsetDate = surveyData.getSymptomOnsetDate();
observations.addAll(convertToAOESymptomObservation(eventId, symptomatic, symptomOnsetDate));
observations.addAll(convertToAOESymptomaticObservation(eventId, symptomatic, symptomOnsetDate));

String pregnancyStatus = surveyData.getPregnancy();
if (pregnancyStatus != null && pregnancyStatusSnomedMap.values().contains(pregnancyStatus)) {
Expand Down Expand Up @@ -1195,15 +1230,18 @@ public ServiceRequest convertToServiceRequest(
*/
public DiagnosticReport convertToDiagnosticReport(TestEvent testEvent, Date currentDate) {
DiagnosticReportStatus status = null;
String id = Objects.toString(testEvent.getInternalId(), "");
switch (testEvent.getCorrectionStatus()) {
case ORIGINAL:
status = (DiagnosticReportStatus.FINAL);
break;
case CORRECTED:
status = (DiagnosticReportStatus.CORRECTED);
id = testEvent.getPriorCorrectedTestEventId().toString();
break;
case REMOVED:
status = (DiagnosticReportStatus.ENTEREDINERROR);
id = testEvent.getPriorCorrectedTestEventId().toString();
break;
}

Expand Down Expand Up @@ -1241,12 +1279,7 @@ public DiagnosticReport convertToDiagnosticReport(TestEvent testEvent, Date curr
dateIssued = ZonedDateTime.ofInstant(currentDate.toInstant(), ZoneOffset.UTC);

return convertToDiagnosticReport(
status,
testOrderLoinc,
testOrderLoincLongName,
Objects.toString(testEvent.getInternalId(), ""),
dateTested,
dateIssued);
status, testOrderLoinc, testOrderLoincLongName, id, dateTested, dateIssued);
}

/**
Expand Down Expand Up @@ -1616,6 +1649,13 @@ private Patient assignPotentiallyAbsentName(
return patient;
}

private List<String> getFilteredSymptomsPresent(Map<String, Boolean> symptomsMap) {
return symptomsMap.entrySet().stream()
.filter(symptom -> Boolean.TRUE.equals(symptom.getValue()))
.map(Entry::getKey)
.collect(Collectors.toList());
}

public Bundle createFhirBundle(ConditionAgnosticCreateFhirBundleProps props) {

var patientFullUrl = ResourceType.Patient + "/" + props.getPatient().getId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class FeatureFlagsConfig {
private final FeatureFlagRepository _repo;

private boolean oktaMigrationEnabled;
private boolean hepatitisCEnabled;
private boolean syphilisEnabled;
private boolean hivBulkUploadEnabled;
private boolean hivEnabled;
Expand All @@ -40,6 +41,7 @@ private void loadFeatureFlagsFromDB() {
private void flagMapping(String flagName, Boolean flagValue) {
switch (flagName) {
case "oktaMigrationEnabled" -> setOktaMigrationEnabled(flagValue);
case "hepatitisCEnabled" -> setHepatitisCEnabled(flagValue);
case "syphilisEnabled" -> setSyphilisEnabled(flagValue);
case "hivBulkUploadEnabled" -> setHivBulkUploadEnabled(flagValue);
case "hivEnabled" -> setHivEnabled(flagValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,10 @@ private UserInfo consolidateUser(ApiUser apiUser, PartialOktaUser oktaUser) {
OrganizationRoles orgRoles =
getOrganizationRoles(Optional.ofNullable(oktaClaims), apiUser, isSiteAdmin);

_dbOrgRoleClaimsService.checkOrgRoleClaimsEquality(
List.of(oktaClaims),
List.of(_dbOrgRoleClaimsService.getOrganizationRoleClaims(apiUser)),
apiUser.getLoginEmail());
return new UserInfo(apiUser, Optional.of(orgRoles), isSiteAdmin, userStatus);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ public OrganizationRoleClaims getOrganizationRoleClaims(ApiUser user) {
* @return boolean
*/
public boolean checkOrgRoleClaimsEquality(
List<OrganizationRoleClaims> oktaClaims, List<OrganizationRoleClaims> dbClaims) {
List<OrganizationRoleClaims> oktaClaims,
List<OrganizationRoleClaims> dbClaims,
String username) {
boolean hasEqualRoleClaims = false;
if (oktaClaims.size() == dbClaims.size()) {
List<OrganizationRoleClaims> sanitizedOktaClaims = sanitizeOktaOrgRoleClaims(oktaClaims);
Expand All @@ -79,17 +81,18 @@ public boolean checkOrgRoleClaimsEquality(
.anyMatch(dbClaim -> equalOrgRoleClaim(sanitizedOktaClaim, dbClaim)));
}
if (!hasEqualRoleClaims) {
logUnequalClaims();
logUnequalClaims(username);
}

return hasEqualRoleClaims;
}

/** Logs a message saying OrganizationRoleClaims are unequal with the affected User ID */
private void logUnequalClaims() {
// WIP: Currently assumes check is for the current user
// This may change based on where checkOrgRoleClaimsEquality is called
String username = _getCurrentUser.get().getUsername();
/**
* Logs a message saying OrganizationRoleClaims are unequal with the affected User ID *
*
* @param username - String user login email
*/
private void logUnequalClaims(String username) {
ApiUser user = _userRepo.findByLoginEmail(username).orElseThrow(NonexistentUserException::new);
log.error(
"Okta OrganizationRoleClaims do not match database OrganizationRoleClaims for User ID: {}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public List<OrganizationRoleClaims> findAllOrganizationRoles() {
String username = currentAuth.getName();
List<OrganizationRoleClaims> dbOrgRoleClaims =
_dbOrgRoleClaimsService.getOrganizationRoleClaims(username);
_dbOrgRoleClaimsService.checkOrgRoleClaimsEquality(
oktaOrgRoleClaims, dbOrgRoleClaims, username);
if (_featureFlagsConfig.isOktaMigrationEnabled()) {
return dbOrgRoleClaims;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,8 @@ private Bundle convertRowToFhirBundle(TestResultRow row, UUID orgId) {
}

aoeObservations.addAll(
fhirConverter.convertToAOESymptomObservation(testEventId, symptomatic, symptomOnsetDate));
fhirConverter.convertToAOESymptomaticObservation(
testEventId, symptomatic, symptomOnsetDate));

String pregnancyValue = row.getPregnant().getValue();
if (StringUtils.isNotBlank(pregnancyValue)) {
Expand Down
1 change: 1 addition & 0 deletions backend/src/main/resources/application-azure-prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ twilio:
from-number: "+14045312484"
features:
oktaMigrationEnabled: false
hepatitisCEnabled: false
syphilisEnabled: false
hivBulkUploadEnabled: true
hivEnabled: true
Expand Down
1 change: 1 addition & 0 deletions backend/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ datahub:
csv-upload-api-fhir-client: "simple_report.fullelr"
features:
oktaMigrationEnabled: false
hepatitisCEnabled: true
syphilisEnabled: true
hivBulkUploadEnabled: true
hivEnabled: true
Expand Down
21 changes: 20 additions & 1 deletion backend/src/main/resources/db/changelog/db.changelog-master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5634,7 +5634,7 @@ databaseChangeLog:
- addColumn:
tableName: test_order
columns:
- column:
- column:
name: timer_started_at
type: text
constraints:
Expand All @@ -5644,6 +5644,25 @@ databaseChangeLog:
tableName: test_order
columnName: timer_started_at

- changeSet:
id: add-hepatitis-c-to-supported_disease-table
author: [email protected]
comment: Add Hepatitis-C to the supported_disease table.
changes:
- tagDatabase:
tag: add-hepatitis-c-to-supported_disease-table
- sql:
sql: |
INSERT INTO ${database.defaultSchemaName}.supported_disease (
internal_id,
name,
loinc)
VALUES
(gen_random_uuid(), 'Hepatitis-C', 'LP14400-3')
rollback:
- sql:
sql: DELETE FROM ${database.defaultSchemaName}.supported_disease WHERE name = 'Hepatitis-C';

- changeSet:
id: create-facility_providers-table
author: [email protected]
Expand Down
Loading

0 comments on commit 07a087a

Please sign in to comment.