Skip to content
This repository was archived by the owner on Jul 31, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions resources/src/main/java/org/cdshooks/Card.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ public String getDetail() {
public void setDetail(String detail) {
this.detail = detail;
}

// Add details to what already exists
public void addDetail(String detail) {
if (this.detail == null) {
setDetail(detail);
} else {
this.detail = detail + "\n" + this.detail;
}
}

public IndicatorEnum getIndicator() {
return indicator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import org.cdshooks.*;
import org.hl7.davinci.FhirComponentsT;
import org.hl7.davinci.PrefetchTemplateElement;
import org.hl7.davinci.endpoint.cdshooks.services.crd.r4.FhirRequestProcessor;
import org.hl7.davinci.endpoint.config.YamlConfig;
import org.hl7.davinci.endpoint.rules.CoverageRequirementRuleCriteria;
import org.hl7.davinci.r4.crdhook.DiscoveryExtension;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -95,7 +97,7 @@ public List<PrefetchTemplateElement> getPrefetchElements() {
}

protected Link smartLinkBuilder(String patientId, String fhirBase, URL applicationBaseUrl, String questionnaireUri,
String reqResourceId, CoverageRequirementRuleCriteria criteria, boolean priorAuthRequired, String label) {
String reqResourceId, IBaseResource request, String label) {
URI configLaunchUri = myConfig.getLaunchUrl();
questionnaireUri = applicationBaseUrl + "/fhir/r4/" + questionnaireUri;

Expand Down Expand Up @@ -125,13 +127,9 @@ protected Link smartLinkBuilder(String patientId, String fhirBase, URL applicati
// request is the ID of the device request or medrec (not the full URI like the
// IG says, since it should be taken from fhirBase

String filepath = "../../getfile/" + criteria.getQueryString();

String appContext = "template=" + questionnaireUri + "&request=" + reqResourceId;
appContext = appContext + "&fhirpath=" + applicationBaseUrl + "/fhir/";
String appContext = "questionnaire=" + questionnaireUri + "&order=" + reqResourceId + "&coverage=" + FhirRequestProcessor.getCoverageFromRequest(request).getReference();

appContext = appContext + "&priorauth=" + (priorAuthRequired ? "true" : "false");
appContext = appContext + "&filepath=" + applicationBaseUrl + "/";
if (myConfig.getUrlEncodeAppContext()) {
logger.info("CdsService::smartLinkBuilder: URL encoding appcontext");
appContext = URLEncoder.encode(appContext, StandardCharsets.UTF_8).toString();
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,10 @@ public CdsServiceRems(String id, Hook hook, String title, String description,
*/
public CdsResponse handleRequest(@Valid @RequestBody requestTypeT request, URL applicationBaseUrl) {
CdsResponse response = new CdsResponse();
CardBuilder cardBuilder = new CardBuilder();
List<Coding> medications = getMedications(request);
for (Coding medication : medications) {
Card card = CardBuilder.summaryCard(CardTypes.COVERAGE, "");
Card card = cardBuilder.summaryCard(CardTypes.COVERAGE, "");
if (isRemsDrug(medication)) {
card.setSummary(String.format("%s has REMS", medication.getDisplay()));
} else {
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
public class CardBuilder {
static final Logger logger = LoggerFactory.getLogger(CardBuilder.class);

public boolean deidentifiedResourcesContainPhi = false;

public static class CqlResultsForCard {
private Boolean ruleApplies;

Expand Down Expand Up @@ -77,14 +79,18 @@ public CqlResultsForCard setRequest(IBaseResource request) {
}
}

public void setDeidentifiedResourcesContainsPhi(boolean deidentifiedResourcesContainPhi) {
this.deidentifiedResourcesContainPhi = deidentifiedResourcesContainPhi;
}

/**
* Transforms a result from the database into a card.
*
* @param cardType
* @param cqlResults
* @return card with appropriate information
*/
public static Card transform(CardTypes cardType, CqlResultsForCard cqlResults, Boolean addLink) {
public Card transform(CardTypes cardType, CqlResultsForCard cqlResults, Boolean addLink) {
String requestId = Utilities.getIdFromIBaseResource(cqlResults.getRequest());
Card card = baseCard(cardType, requestId);

Expand All @@ -97,7 +103,7 @@ public static Card transform(CardTypes cardType, CqlResultsForCard cqlResults, B
}

card.setSummary(cqlResults.getCoverageRequirements().getSummary());
card.setDetail(cqlResults.getCoverageRequirements().getDetails());
card.addDetail(cqlResults.getCoverageRequirements().getDetails());

return card;
}
Expand All @@ -109,7 +115,7 @@ public static Card transform(CardTypes cardType, CqlResultsForCard cqlResults, B
* @param cqlResults
* @return card with appropriate information
*/
public static Card transform(CardTypes cardType, CqlResultsForCard cqlResults) {
public Card transform(CardTypes cardType, CqlResultsForCard cqlResults) {
return transform(cardType, cqlResults, true);
}

Expand All @@ -121,7 +127,7 @@ public static Card transform(CardTypes cardType, CqlResultsForCard cqlResults) {
* @param smartAppLaunchLink smart app launch Link
* @return card with appropriate information
*/
public static Card transform(CardTypes cardType, CqlResultsForCard cqlResults, Link smartAppLaunchLink) {
public Card transform(CardTypes cardType, CqlResultsForCard cqlResults, Link smartAppLaunchLink) {
Card card = transform(cardType, cqlResults);
List<Link> links = new ArrayList<Link>(card.getLinks());
links.add(smartAppLaunchLink);
Expand All @@ -137,7 +143,7 @@ public static Card transform(CardTypes cardType, CqlResultsForCard cqlResults, L
* @param smartAppLaunchLinks a list of links
* @return card to be returned
*/
public static Card transform(CardTypes cardType, CqlResultsForCard cqlResults, List<Link> smartAppLaunchLinks) {
public Card transform(CardTypes cardType, CqlResultsForCard cqlResults, List<Link> smartAppLaunchLinks) {
Card card = transform(cardType, cqlResults);
List<Link> links = new ArrayList<Link>(card.getLinks());
links.addAll(smartAppLaunchLinks);
Expand All @@ -152,20 +158,20 @@ public static Card transform(CardTypes cardType, CqlResultsForCard cqlResults, L
* @param summary The desired summary for the card
* @return valid card
*/
public static Card summaryCard(CardTypes cardType, String summary) {
public Card summaryCard(CardTypes cardType, String summary) {
Card card = baseCard(cardType, "");
card.setSummary(summary);
return card;
}

public static Card alternativeTherapyCard(AlternativeTherapy alternativeTherapy, IBaseResource resource,
public Card alternativeTherapyCard(AlternativeTherapy alternativeTherapy, IBaseResource resource,
FhirComponentsT fhirComponents) {
logger.info("Build Alternative Therapy Card: " + alternativeTherapy.toString());
String requestId = Utilities.getIdFromIBaseResource(resource);
Card card = baseCard(CardTypes.THERAPY_ALTERNATIVES_OPT, requestId);

card.setSummary("Alternative Therapy Suggested");
card.setDetail(alternativeTherapy.getDisplay() + " (" + alternativeTherapy.getCode() + ") should be used instead.");
card.addDetail(alternativeTherapy.getDisplay() + " (" + alternativeTherapy.getCode() + ") should be used instead.");

List<Suggestion> suggestionList = new ArrayList<>();
Suggestion alternativeTherapySuggestion = new Suggestion();
Expand Down Expand Up @@ -205,17 +211,17 @@ public static Card alternativeTherapyCard(AlternativeTherapy alternativeTherapy,
return card;
}

public static Card drugInteractionCard(DrugInteraction drugInteraction, IBaseResource resource) {
public Card drugInteractionCard(DrugInteraction drugInteraction, IBaseResource resource) {
logger.info("Build Drug Interaction Card: " + drugInteraction.getSummary());
String requestId = Utilities.getIdFromIBaseResource(resource);
Card card = baseCard(CardTypes.CONTRAINDICATION, requestId);
card.setSummary(drugInteraction.getSummary());
card.setDetail(drugInteraction.getDetail());
card.addDetail(drugInteraction.getDetail());
card.setIndicator(Card.IndicatorEnum.WARNING);
return card;
}

public static Card priorAuthCard(CqlResultsForCard cqlResults,
public Card priorAuthCard(CqlResultsForCard cqlResults,
IBaseResource request,
FhirComponentsT fhirComponents,
String priorAuthId,
Expand Down Expand Up @@ -264,7 +270,7 @@ public static Card priorAuthCard(CqlResultsForCard cqlResults,
return card;
}

public static Suggestion createSuggestionWithResource(IBaseResource request,
public Suggestion createSuggestionWithResource(IBaseResource request,
IBaseResource resource,
FhirComponentsT fhirComponents,
String label,
Expand All @@ -291,7 +297,7 @@ public static Suggestion createSuggestionWithResource(IBaseResource request,
return suggestion;
}

public static Suggestion createSuggestionWithNote(Card card,
public Suggestion createSuggestionWithNote(Card card,
IBaseResource request,
FhirComponentsT fhirComponents,
String label,
Expand Down Expand Up @@ -394,7 +400,7 @@ public static Suggestion createSuggestionWithNote(Card card,
return requestWithNoteSuggestion;
}

private static Source createSource(CardTypes cardType) {
private Source createSource(CardTypes cardType) {
Source source = new Source();
source.setLabel("Da Vinci CRD Reference Implementation");
source.setTopic(cardType.getCoding());
Expand All @@ -408,19 +414,18 @@ private static Source createSource(CardTypes cardType) {
* @param cardType
* @param response The response to check and add cards to
*/
public static void errorCardIfNonePresent(CardTypes cardType, CdsResponse response) {
public void errorCardIfNonePresent(CardTypes cardType, CdsResponse response) {
if (response.getCards() == null || response.getCards().size() == 0) {
Card card = new Card();
Card card = baseCard(cardType, "");
card.setIndicator(Card.IndicatorEnum.WARNING);
card.setSource(createSource(cardType));
String msg = "Unable to process hook request from provided information.";
card.setSummary(msg);
response.addCard(card);
logger.warn(msg + "; summary card sent to client");
}
}

private static Card baseCard(CardTypes cardType, String requestId) {
private Card baseCard(CardTypes cardType, String requestId) {
Card card = new Card();
card.setIndicator(Card.IndicatorEnum.INFO);
card.setSource(createSource(cardType));
Expand All @@ -430,6 +435,10 @@ private static Card baseCard(CardTypes cardType, String requestId) {
cardExtension.addAssociatedResource(requestId);
card.setExtension(cardExtension);
}

if (deidentifiedResourcesContainPhi) {
card.setDetail("Note: de-identified resources provided in request contain Protected Health Information (PHI). Please notify administrator.");
}

return card;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.hl7.davinci.endpoint.controllers;

import org.aspectj.weaver.patterns.TypePatternQuestions;
import org.hl7.davinci.FhirResourceInfo;
import org.hl7.davinci.endpoint.Application;
import org.hl7.davinci.endpoint.Utils;
Expand All @@ -19,6 +20,7 @@
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.Optional;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;

Expand All @@ -28,7 +30,7 @@
*/
@RestController
public class FhirController {
private static Logger logger = Logger.getLogger(Application.class.getName());
private static Logger logger = Logger.getLogger(FhirController.class.getName());

@Autowired
private FileStore fileStore;
Expand Down Expand Up @@ -229,7 +231,23 @@ public ResponseEntity<String> submitFhirResource(HttpServletRequest request, Htt
@PostMapping(path = "/fhir/{fhirVersion}/Questionnaire/$questionnaire-package", consumes = { MediaType.APPLICATION_JSON_VALUE, "application/fhir+json" })
public ResponseEntity<String> questionnaireForOrderOperation(HttpServletRequest request, HttpEntity<String> entity,
@PathVariable String fhirVersion) {
return handleQuestionnaireOperation(request, entity, fhirVersion, null);
}

/**
* FHIR Operation to retrieve a Questionnaire and CQL files associated with a given request.
* @param fhirVersion (converted to uppercase)
* @return FHIR Bundle
* @throws IOException
*/
@PostMapping(path = "/fhir/{fhirVersion}/Questionnaire/{questionnaireId}/$questionnaire-package", consumes = { MediaType.APPLICATION_JSON_VALUE, "application/fhir+json" })
public ResponseEntity<String> questionnaireForOrderOperationScoped(HttpServletRequest request, HttpEntity<String> entity,
@PathVariable String fhirVersion, @PathVariable String questionnaireId) {
return handleQuestionnaireOperation(request, entity, fhirVersion, questionnaireId);
}

private ResponseEntity<String> handleQuestionnaireOperation(HttpServletRequest request, HttpEntity<String> entity,
String fhirVersion, String questionnaireId) {
fhirVersion = fhirVersion.toUpperCase();
String baseUrl = Utils.getApplicationBaseUrl(request).toString() + "/";

Expand All @@ -238,15 +256,15 @@ public ResponseEntity<String> questionnaireForOrderOperation(HttpServletRequest
String resource = null;
if (fhirVersion.equalsIgnoreCase("R4")) {
QuestionnairePackageOperation operation = new QuestionnairePackageOperation(fileStore, baseUrl);
resource = operation.execute(entity.getBody());
resource = operation.execute(entity.getBody(), questionnaireId);

if (resource == null) {
logger.warning("bad parameters");
HttpStatus status = HttpStatus.BAD_REQUEST;
MediaType contentType = MediaType.TEXT_PLAIN;

return ResponseEntity.status(status).contentType(contentType)
.body("Bad Parameters");
.body("Bad Parameters");
}

} else {
Expand All @@ -255,11 +273,11 @@ public ResponseEntity<String> questionnaireForOrderOperation(HttpServletRequest
MediaType contentType = MediaType.TEXT_PLAIN;

return ResponseEntity.status(status).contentType(contentType)
.body("Bad Request");
.body("Bad Request");
}

return ResponseEntity.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
.body(resource);
.body(resource);
}


Expand Down
Loading