Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rule apply patient export #4892

Open
wants to merge 41 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
55305ad
Force Verify tests
tadgh May 3, 2023
71edea3
fix ITs (#4809)
fil512 May 3, 2023
5855ea9
Fix migrator error on Oracle (#4814)
jamesagnew May 4, 2023
2821201
Update clinical reasoning version (#4816)
barhodes May 4, 2023
b33263d
Opening the care-gaps endpoint for GET. (#4823)
chalmarm May 5, 2023
9af24ad
added version to mdm golden resource tag (#4820)
longma1 May 5, 2023
f97da3b
Update the changelog for 4697 to be more descriptive (#4827)
JPercival May 5, 2023
609bc53
Fixes a bug with tags. (#4813)
tadgh May 5, 2023
a8e823a
fix migration issue (#4830)
fil512 May 6, 2023
5212009
Create correct version enum
tadgh May 7, 2023
ab070ef
Remove superfluous migration
tadgh May 7, 2023
5fa92dc
fixing test (#4835)
TipzCM May 8, 2023
d63dc07
email subscription, throw NullPointerException (#4790)
samguntersmilecdr May 10, 2023
37bfbf0
Add docs for CR operations (#4855)
barhodes May 11, 2023
9d9df27
Add documentation for $care-gaps operation. (#4862)
chalmarm May 11, 2023
22c9a18
4853 validation does not error when display is not the same as the di…
StevenXLi May 11, 2023
99f58f5
fixing patient everything operator (#4845)
TipzCM May 11, 2023
c3ccfb3
fix link
tadgh May 12, 2023
1891a19
Move image file
tadgh May 12, 2023
f464113
Bundle resources containing over 100 references to the same Organizat…
lukedegruchy May 12, 2023
e8cc02f
added warn message and test (#4848)
longma1 May 12, 2023
681a21c
Issue 4804 full table scan on mpi link during mdm clear (#4805)
jmarchionatto May 12, 2023
30eea1b
Fix erroneous batch 2 $export 75% complete count when the job is COMP…
lukedegruchy May 12, 2023
cf8935e
disable wars (#4877)
fil512 May 14, 2023
2973b65
4868 fix paging hapi (#4870)
TipzCM May 15, 2023
0303120
Test, fix, and changelog
michaelabuckley May 15, 2023
680dcc0
4875-binary-access-write-doest-trigger-STORAGE-BINARY-ASSIGN-BLOB-ID-…
jmarchionatto May 15, 2023
35f7b52
Better partition resolution
michaelabuckley May 15, 2023
dd56b13
Add checks based on rule applier
tadgh May 15, 2023
0a8e516
Fix ordering failure due to hash set
tadgh May 15, 2023
cf19036
Allow empty auth interceptor
tadgh May 15, 2023
75e28ba
Fix batch job (bulk export) processed record count (#4879)
michaelabuckley May 15, 2023
3c788c1
Fix up operation type on invocation
tadgh May 15, 2023
835d6d2
Throw 404 when requesting $export of non-existent Group or Patient (#…
michaelabuckley May 15, 2023
9d9dc9a
Add more tests, make hack implementation for patient instance level o…
tadgh May 15, 2023
7d0813f
Tighten test name
tadgh May 15, 2023
879e5c9
Merge branch 'rel_6_6' into rule-apply-patient-export
tadgh May 16, 2023
792e755
Changelog
tadgh May 16, 2023
f60f6aa
Default method
tadgh May 16, 2023
b989710
remove dead method
tadgh May 16, 2023
c20eab6
Remove dead autowire
tadgh May 16, 2023
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
Prev Previous commit
Next Next commit
Throw 404 when requesting $export of non-existent Group or Patient (#…
  • Loading branch information
michaelabuckley committed May 15, 2023
commit 835d6d2d895b8729ab2c257788e5a70f7b97442d
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
type: fix
issue: 4886
title: "Requests to start an $export of Patient or Group will now fail with 404 ResourceNotFound when the target
resources do not exist. Before, the system would start a bulk export background job which would then fail."
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.api.model.Batch2JobInfo;
import ca.uhn.fhir.jpa.api.model.Batch2JobOperationResult;
import ca.uhn.fhir.jpa.api.model.BulkExportJobResults;
Expand Down Expand Up @@ -98,6 +99,8 @@ public class BulkDataExportProviderTest {
private final HttpClientExtension myClient = new HttpClientExtension();
@Mock
private IBatch2JobRunner myJobRunner;
@Mock
IFhirResourceDao myFhirResourceDao;
@InjectMocks
private BulkDataExportProvider myProvider;
@RegisterExtension
Expand Down Expand Up @@ -140,6 +143,8 @@ public void injectStorageSettings() {
myProvider.setStorageSettings(myStorageSettings);
DaoRegistry daoRegistry = mock(DaoRegistry.class);
lenient().when(daoRegistry.getRegisteredDaoTypes()).thenReturn(Set.of("Patient", "Observation", "Encounter"));

lenient().when(daoRegistry.getResourceDao(anyString())).thenReturn(myFhirResourceDao);
myProvider.setDaoRegistry(daoRegistry);

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package ca.uhn.fhir.jpa.provider.r4;

import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.StringType;
import org.junit.jupiter.api.Test;

import static ca.uhn.fhir.jpa.model.util.JpaConstants.OPERATION_EXPORT;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.jupiter.api.Assertions.assertThrows;

public class BulkExportProviderR4Test extends BaseResourceProviderR4Test {
@Test
void testBulkExport_groupNotExists_throws404() {
// given no data

ResourceNotFoundException e = assertThrows(ResourceNotFoundException.class,
() -> myClient
.operation().onInstance("Group/ABC_not_exist").named(OPERATION_EXPORT)
.withNoParameters(Parameters.class)
.withAdditionalHeader("Prefer", "respond-async")
.returnMethodOutcome()
.execute(),
"$export of missing Group throws 404");

assertThat(e.getStatusCode(), equalTo(404));
}

@Test
void testBulkExport_patientNotExists_throws404() {
// given no data

ResourceNotFoundException e = assertThrows(ResourceNotFoundException.class,
() -> myClient
.operation().onInstance("Patient/ABC_not_exist").named(OPERATION_EXPORT)
.withNoParameters(Parameters.class)
.withAdditionalHeader("Prefer", "respond-async")
.returnMethodOutcome()
.execute(),
"$export of missing Patient throws 404");

assertThat(e.getStatusCode(), equalTo(404));
}


@Test
void testBulkExport_typePatientIdNotExists_throws404() {
// given no data

ResourceNotFoundException e = assertThrows(ResourceNotFoundException.class,
() -> myClient
.operation().onType("Patient").named(OPERATION_EXPORT)
.withParameter(Parameters.class, "patient", new StringType("Patient/abc-no-way"))
.withAdditionalHeader("Prefer", "respond-async")
.returnMethodOutcome()
.execute(),
"Patient/$export with missing patient throws 404");

assertThat(e.getStatusCode(), equalTo(404));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
import ca.uhn.fhir.jpa.util.BulkExportUtils;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
Expand All @@ -47,6 +48,7 @@
import ca.uhn.fhir.rest.api.PreferHeader;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import ca.uhn.fhir.rest.api.server.bulk.BulkDataExportOptions;
import ca.uhn.fhir.rest.server.RestfulServerUtils;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
Expand All @@ -60,6 +62,8 @@
import ca.uhn.fhir.util.SearchParameterUtil;
import ca.uhn.fhir.util.UrlUtil;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IIdType;
Expand Down Expand Up @@ -211,6 +215,9 @@ public void groupExport(

validatePreferAsyncHeader(theRequestDetails, JpaConstants.OPERATION_EXPORT);

// verify the Group exists before starting the job
validateTargetsExists(theRequestDetails, "Group", List.of(theIdParam));

BulkDataExportOptions bulkDataExportOptions = buildGroupBulkExportOptions(theOutputFormat, theType, theSince, theTypeFilter, theIdParam, theMdm, theExportIdentifier, theTypePostFetchFilterUrl);

if (isNotEmpty(bulkDataExportOptions.getResourceTypes())) {
Expand All @@ -223,6 +230,24 @@ public void groupExport(
startJob(theRequestDetails, bulkDataExportOptions);
}

/**
* Throw ResourceNotFound if the target resources don't exist.
* Otherwise, we start a bulk-export job which then fails, reporting a 500.
*
* @param theRequestDetails the caller details
* @param theTargetResourceName the type of the target
* @param theIdParams the id(s) to verify exist
*/
private void validateTargetsExists(RequestDetails theRequestDetails, String theTargetResourceName, Iterable<IIdType> theIdParams) {
RequestPartitionId partitionId = myRequestPartitionHelperService.determineReadPartitionForRequestForRead(theRequestDetails, theTargetResourceName, theIdParams.iterator().next());
SystemRequestDetails requestDetails = new SystemRequestDetails().setRequestPartitionId(partitionId);
for (IIdType nextId: theIdParams) {
myDaoRegistry.getResourceDao(theTargetResourceName)
.read(nextId, requestDetails);
}

}

private void validateResourceTypesAllContainPatientSearchParams(Set<String> theResourceTypes) {
if (theResourceTypes != null) {
List<String> badResourceTypes = theResourceTypes.stream()
Expand Down Expand Up @@ -259,6 +284,11 @@ public void patientExport(
ServletRequestDetails theRequestDetails
) {
validatePreferAsyncHeader(theRequestDetails, JpaConstants.OPERATION_EXPORT);

if (thePatient != null) {
validateTargetsExists(theRequestDetails, "Patient", Lists.transform(thePatient, s -> new IdDt(s.getValue())));
}

BulkDataExportOptions bulkDataExportOptions = buildPatientBulkExportOptions(theOutputFormat, theType, theSince, theTypeFilter, theExportIdentifier, thePatient, theTypePostFetchFilterUrl);
validateResourceTypesAllContainPatientSearchParams(bulkDataExportOptions.getResourceTypes());

Expand All @@ -280,6 +310,9 @@ public void patientInstanceExport(
ServletRequestDetails theRequestDetails
) {
validatePreferAsyncHeader(theRequestDetails, JpaConstants.OPERATION_EXPORT);

validateTargetsExists(theRequestDetails, "Patient", List.of(theIdParam));

BulkDataExportOptions bulkDataExportOptions = buildPatientBulkExportOptions(theOutputFormat, theType, theSince, theTypeFilter, theExportIdentifier, theIdParam, theTypePostFetchFilterUrl);
validateResourceTypesAllContainPatientSearchParams(bulkDataExportOptions.getResourceTypes());

Expand Down Expand Up @@ -529,7 +562,7 @@ private Set<String> splitTypeFilters(List<IPrimitiveType<String>> theTypeFilter)
public static void validatePreferAsyncHeader(ServletRequestDetails theRequestDetails, String theOperationName) {
String preferHeader = theRequestDetails.getHeader(Constants.HEADER_PREFER);
PreferHeader prefer = RestfulServerUtils.parsePreferHeader(null, preferHeader);
if (prefer.getRespondAsync() == false) {
if (!prefer.getRespondAsync()) {
throw new InvalidRequestException(Msg.code(513) + "Must request async processing for " + theOperationName);
}
}
Expand Down
Loading