diff --git a/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/AbstractProgramStageFhirRestAppTest.java b/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/AbstractProgramStageFhirRestAppTest.java
index a3a9ca94..00d87771 100644
--- a/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/AbstractProgramStageFhirRestAppTest.java
+++ b/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/AbstractProgramStageFhirRestAppTest.java
@@ -78,5 +78,10 @@ protected void expectProgramStageMetadataRequests() throws Exception
"program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType," +
"optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D%5D&filter=name:eq:Child%20Programme" ) )
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-program.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
+ systemDhis2Server.expect( ExpectedCount.between( 0, 1 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", testConfiguration.getDhis2SystemAuthorization() ) )
+ .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programStages/MsWxkiY6tMS.json?fields=id,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart," +
+ "programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D" ) )
+ .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-program-stage.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
+
}
}
diff --git a/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4QuestionnaireResponseEventFhirRestAppTest.java b/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4QuestionnaireResponseEventFhirRestAppTest.java
new file mode 100644
index 00000000..a3b07489
--- /dev/null
+++ b/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4QuestionnaireResponseEventFhirRestAppTest.java
@@ -0,0 +1,372 @@
+package org.dhis2.fhir.adapter.fhir.server.r4;
+
+/*
+ * Copyright (c) 2004-2019, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import ca.uhn.fhir.rest.api.MethodOutcome;
+import ca.uhn.fhir.rest.client.api.IGenericClient;
+import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor;
+import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
+import org.apache.commons.io.IOUtils;
+import org.dhis2.fhir.adapter.dhis.tracker.program.EventStatus;
+import org.dhis2.fhir.adapter.fhir.extension.DueDateExtensionUtils;
+import org.dhis2.fhir.adapter.fhir.extension.EventStatusExtensionUtils;
+import org.dhis2.fhir.adapter.fhir.extension.LocationExtensionUtils;
+import org.dhis2.fhir.adapter.fhir.model.FhirVersion;
+import org.dhis2.fhir.adapter.fhir.server.AbstractProgramStageFhirRestAppTest;
+import org.hl7.fhir.r4.model.Bundle;
+import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.QuestionnaireResponse;
+import org.hl7.fhir.r4.model.Reference;
+import org.hl7.fhir.r4.model.ResourceFactory;
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.client.ExpectedCount;
+
+import javax.annotation.Nonnull;
+import java.nio.charset.StandardCharsets;
+import java.sql.Date;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.Objects;
+
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.*;
+import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
+import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
+
+/**
+ * R4 tests for rest interfaces that access DHIS2 events by using FHIR Questionnaire Responses.
+ * Some methods are executed twice in order to verify that no cached data is used without authentication.
+ *
+ * @author volsch
+ */
+public class R4QuestionnaireResponseEventFhirRestAppTest extends AbstractProgramStageFhirRestAppTest
+{
+ @Nonnull
+ @Override
+ protected FhirVersion getFhirVersion()
+ {
+ return FhirVersion.R4;
+ }
+
+ @Test( expected = AuthenticationException.class )
+ public void getQuestionnaireResponseWithoutAuthorization()
+ {
+ final IGenericClient client = createGenericClient();
+ client.read().resource( QuestionnaireResponse.class ).withId( "deR4kl4mnf7" ).execute();
+ }
+
+ @Test( expected = AuthenticationException.class )
+ public void getQuestionnaireResponseWithInvalidAuthorization() throws Exception
+ {
+ expectProgramStageMetadataRequests();
+ userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) )
+ .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7.json?fields=deleted,event,orgUnit,program,enrollment,trackedEntityInstance,programStage,status,eventDate,dueDate,coordinate,lastUpdated," +
+ "dataValues%5BdataElement,value,providedElsewhere,lastUpdated,storedBy%5D" ) )
+ .andRespond( withStatus( HttpStatus.UNAUTHORIZED ) );
+
+ final IGenericClient client = createGenericClient();
+ client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "invalid_1" ) );
+ client.read().resource( QuestionnaireResponse.class ).withId( "deR4kl4mnf7" ).execute();
+ }
+
+ @Test
+ public void getQuestionnaireResponseRepeated() throws Exception
+ {
+ getQuestionnaireResponse();
+ getQuestionnaireResponse();
+ }
+
+ private void getQuestionnaireResponse() throws Exception
+ {
+ systemDhis2Server.reset();
+ userDhis2Server.reset();
+
+ expectProgramStageMetadataRequests();
+ userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) )
+ .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7.json?fields=deleted,event,orgUnit,program,enrollment,trackedEntityInstance,programStage,status,eventDate,dueDate,coordinate,lastUpdated," +
+ "dataValues%5BdataElement,value,providedElsewhere,lastUpdated,storedBy%5D" ) )
+ .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-event-91-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
+
+ final IGenericClient client = createGenericClient();
+ client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) );
+ QuestionnaireResponse questionnaireResponse = client.read().resource( QuestionnaireResponse.class ).withId( "deR4kl4mnf7" ).execute();
+ Assert.assertEquals( "Patient/JeR2Ul4mZfx", questionnaireResponse.getSubject().getReference() );
+ Assert.assertEquals( "Location/ldXIdLNUNEn",
+ Objects.requireNonNull( LocationExtensionUtils.getValue( questionnaireResponse ) ).getReferenceElement().getValue() );
+
+ systemDhis2Server.verify();
+ userDhis2Server.verify();
+ }
+
+ @Test( expected = AuthenticationException.class )
+ public void searchQuestionnaireResponseWithoutAuthorization() throws Exception
+ {
+ expectProgramStageMetadataRequests();
+ final IGenericClient client = createGenericClient();
+ client.search().forResource( QuestionnaireResponse.class ).returnBundle( Bundle.class ).execute();
+ }
+
+ @Test( expected = AuthenticationException.class )
+ public void searchQuestionnaireResponseInvalidAuthorization() throws Exception
+ {
+ expectProgramStageMetadataRequests();
+ userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) )
+ .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events.json?skipPaging=false&page=1&pageSize=10&ouMode=ACCESSIBLE&fields=deleted,event,orgUnit,program,enrollment,trackedEntityInstance,programStage,status,eventDate,dueDate," +
+ "coordinate,lastUpdated,dataValues%5BdataElement,value,providedElsewhere,lastUpdated,storedBy%5D" ) )
+ .andRespond( withStatus( HttpStatus.UNAUTHORIZED ) );
+
+ final IGenericClient client = createGenericClient();
+ client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "invalid_1" ) );
+ client.search().forResource( QuestionnaireResponse.class ).returnBundle( Bundle.class ).execute();
+ }
+
+ @Test
+ public void searchQuestionnaireResponseRepeated() throws Exception
+ {
+ searchQuestionnaireResponse();
+ searchQuestionnaireResponse();
+ }
+
+ private void searchQuestionnaireResponse() throws Exception
+ {
+ systemDhis2Server.reset();
+ userDhis2Server.reset();
+
+ expectProgramStageMetadataRequests();
+ userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) )
+ .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events.json?skipPaging=false&page=1&pageSize=10&ouMode=ACCESSIBLE&fields=deleted,event,orgUnit,program,enrollment,trackedEntityInstance,programStage,status,eventDate," +
+ "dueDate,coordinate,lastUpdated,dataValues%5BdataElement,value,providedElsewhere,lastUpdated,storedBy%5D" ) )
+ .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-91-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
+
+ final IGenericClient client = createGenericClient();
+ client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) );
+ Bundle bundle = client.search().forResource( QuestionnaireResponse.class ).returnBundle( Bundle.class ).execute();
+ Assert.assertEquals( 1, bundle.getEntry().size() );
+ QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) bundle.getEntry().get( 0 ).getResource();
+ Assert.assertEquals( "Patient/JeR2Ul4mZfx", questionnaireResponse.getSubject().getReference() );
+ Assert.assertEquals( "Location/ldXIdLNUNEn",
+ Objects.requireNonNull( LocationExtensionUtils.getValue( questionnaireResponse ) ).getReferenceElement().getValue() );
+
+ systemDhis2Server.verify();
+ userDhis2Server.verify();
+ }
+
+ @Test
+ public void searchQuestionnaireResponsePatient() throws Exception
+ {
+ expectProgramStageMetadataRequests();
+ userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) )
+ .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events.json?trackedEntityInstance=JeR2Ul4mZfx&skipPaging=false&page=1&pageSize=10&ouMode=ACCESSIBLE&fields=deleted,event,orgUnit,program,enrollment," +
+ "trackedEntityInstance,programStage,status,eventDate,dueDate,coordinate,lastUpdated,dataValues%5BdataElement,value,providedElsewhere,lastUpdated,storedBy%5D" ) )
+ .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-91-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
+
+ final IGenericClient client = createGenericClient();
+ client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) );
+ Bundle bundle = client.search().forResource( QuestionnaireResponse.class ).where( QuestionnaireResponse.PATIENT.hasId( new IdType( "Patient", "JeR2Ul4mZfx" ) ) ).returnBundle( Bundle.class ).execute();
+ Assert.assertEquals( 1, bundle.getEntry().size() );
+ QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) bundle.getEntry().get( 0 ).getResource();
+ Assert.assertEquals( "Patient/JeR2Ul4mZfx", questionnaireResponse.getSubject().getReference() );
+ Assert.assertEquals( "Location/ldXIdLNUNEn",
+ Objects.requireNonNull( LocationExtensionUtils.getValue( questionnaireResponse ) ).getReferenceElement().getValue() );
+
+ systemDhis2Server.verify();
+ userDhis2Server.verify();
+ }
+
+ @Test( expected = AuthenticationException.class )
+ public void createQuestionnaireResponseWithoutAuthorization() throws Exception
+ {
+ expectProgramStageMetadataRequests();
+
+ QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) getFhirContext().newJsonParser().parseResource(
+ IOUtils.resourceToString( "/org/dhis2/fhir/adapter/fhir/test/" + getResourceDir() + "/get-questionnaire-response-91.json", StandardCharsets.UTF_8 ) );
+ questionnaireResponse.setId( (IdType) null );
+ questionnaireResponse.setSubject( new Reference( "Patient/JeR2Ul4mZfx" ) );
+
+ final IGenericClient client = createGenericClient();
+ client.create().resource( questionnaireResponse ).execute();
+ }
+
+ @Test( expected = AuthenticationException.class )
+ public void createQuestionnaireResponseInvalidAuthorization() throws Exception
+ {
+ expectProgramStageMetadataRequests();
+ userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events.json?strategy=CREATE" ) ).andExpect( method( HttpMethod.POST ) )
+ .andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) )
+ .andExpect( content().contentTypeCompatibleWith( MediaType.APPLICATION_JSON ) )
+ .andExpect( content().json( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-91-create.json", StandardCharsets.UTF_8 ) ) )
+ .andRespond( withStatus( HttpStatus.UNAUTHORIZED ) );
+
+ QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) getFhirContext().newJsonParser().parseResource(
+ IOUtils.resourceToString( "/org/dhis2/fhir/adapter/fhir/test/" + getResourceDir() + "/get-questionnaire-response-91.json", StandardCharsets.UTF_8 ) );
+ questionnaireResponse.setId( (IdType) null );
+ questionnaireResponse.setSubject( new Reference( "Patient/JeR2Ul4mZfx" ) );
+ LocationExtensionUtils.setValue( questionnaireResponse, new Reference( "Location/ldXIdLNUNEn" ) );
+
+ final IGenericClient client = createGenericClient();
+ client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "invalid_1" ) );
+ client.create().resource( questionnaireResponse ).execute();
+ }
+
+ @Test
+ public void createQuestionnaireResponse() throws Exception
+ {
+ expectProgramStageMetadataRequests();
+ userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events.json?strategy=CREATE" ) ).andExpect( method( HttpMethod.POST ) )
+ .andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) )
+ .andExpect( content().contentTypeCompatibleWith( MediaType.APPLICATION_JSON ) )
+ .andExpect( content().json( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-91-create.json", StandardCharsets.UTF_8 ) ) )
+ .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-91-create-response.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON )
+ .headers( createDefaultHeaders() ) );
+
+ QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) getFhirContext().newJsonParser().parseResource(
+ IOUtils.resourceToString( "/org/dhis2/fhir/adapter/fhir/test/" + getResourceDir() + "/get-questionnaire-response-91.json", StandardCharsets.UTF_8 ) );
+ questionnaireResponse.setId( (IdType) null );
+ questionnaireResponse.setSubject( new Reference( "Patient/JeR2Ul4mZfx" ) );
+ LocationExtensionUtils.setValue( questionnaireResponse, new Reference( "Location/ldXIdLNUNEn" ) );
+
+ final IGenericClient client = createGenericClient();
+ client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) );
+ MethodOutcome methodOutcome = client.create().resource( questionnaireResponse ).execute();
+ Assert.assertEquals( Boolean.TRUE, methodOutcome.getCreated() );
+ Assert.assertEquals( "http://localhost:" + localPort + "/fhir/r4/default/QuestionnaireResponse/deR4kl4mnf7", methodOutcome.getId().toString() );
+ }
+
+ @Test( expected = AuthenticationException.class )
+ public void updateQuestionnaireResponseWithoutAuthorization() throws Exception
+ {
+ expectProgramStageMetadataRequests();
+ userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) )
+ .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/trackedEntityInstances/JeR2Ul4mZfx.json?" +
+ "fields=deleted,trackedEntityInstance,trackedEntityType,orgUnit,coordinates,lastUpdated,attributes%5Battribute,value,lastUpdated,storedBy%5D" ) )
+ .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-tei-15-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
+
+ QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) getFhirContext().newJsonParser().parseResource(
+ IOUtils.resourceToString( "/org/dhis2/fhir/adapter/fhir/test/" + getResourceDir() + "/get-questionnaire-response-91.json", StandardCharsets.UTF_8 ) );
+ questionnaireResponse.setId( "deR4kl4mnf7" );
+ questionnaireResponse.setSubject( new Reference( "Patient/JeR2Ul4mZfx" ) );
+
+ final IGenericClient client = createGenericClient();
+ client.update().resource( questionnaireResponse ).execute();
+ }
+
+ @Test( expected = AuthenticationException.class )
+ public void updateQuestionnaireResponseInvalidAuthorization() throws Exception
+ {
+ expectProgramStageMetadataRequests();
+ userDhis2Server.expect( ExpectedCount.between( 1, 2 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) )
+ .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7.json?fields=deleted,event,orgUnit,program,enrollment,trackedEntityInstance,programStage,status,eventDate,dueDate,coordinate,lastUpdated," +
+ "dataValues%5BdataElement,value,providedElsewhere,lastUpdated,storedBy%5D" ) )
+ .andRespond( withStatus( HttpStatus.UNAUTHORIZED ) );
+
+ QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) getFhirContext().newJsonParser().parseResource(
+ IOUtils.resourceToString( "/org/dhis2/fhir/adapter/fhir/test/" + getResourceDir() + "/get-questionnaire-response-91.json", StandardCharsets.UTF_8 ) );
+ questionnaireResponse.setId( "deR4kl4mnf7" );
+ questionnaireResponse.setSubject( new Reference( "Patient/JeR2Ul4mZfx" ) );
+
+ final IGenericClient client = createGenericClient();
+ client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "invalid_1" ) );
+ client.update().resource( questionnaireResponse ).execute();
+ }
+
+ @Test
+ public void updateQuestionnaireResponse() throws Exception
+ {
+ expectProgramStageMetadataRequests();
+
+ userDhis2Server.expect( ExpectedCount.between( 1, 3 ), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7.json?fields=deleted,event,orgUnit,program,enrollment,trackedEntityInstance,programStage,status,eventDate," +
+ "dueDate,coordinate,lastUpdated,dataValues%5BdataElement,value,providedElsewhere,lastUpdated,storedBy%5D" ) )
+ .andExpect( method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) )
+ .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-event-91-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
+ userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7.json?mergeMode=MERGE" ) ).andExpect( method( HttpMethod.PUT ) )
+ .andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) )
+ .andExpect( content().contentTypeCompatibleWith( MediaType.APPLICATION_JSON ) )
+ .andExpect( content().json( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-91-update.json", StandardCharsets.UTF_8 ) ) )
+ .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-91-update-response.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON )
+ .headers( createDefaultHeaders() ) );
+
+ QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) getFhirContext().newJsonParser().parseResource(
+ IOUtils.resourceToString( "/org/dhis2/fhir/adapter/fhir/test/" + getResourceDir() + "/get-questionnaire-response-91.json", StandardCharsets.UTF_8 ) );
+ questionnaireResponse.setId( "deR4kl4mnf7" );
+ questionnaireResponse.setSubject( new Reference( "Patient/JeR2Ul4mZfx" ) );
+ questionnaireResponse.setStatus( QuestionnaireResponse.QuestionnaireResponseStatus.INPROGRESS );
+ LocationExtensionUtils.setValue( questionnaireResponse, new Reference( "Location/ldXIdLNUNEn" ) );
+ EventStatusExtensionUtils.setValue( questionnaireResponse, EventStatus.OVERDUE, ResourceFactory::createType );
+ DueDateExtensionUtils.setValue( questionnaireResponse,
+ Date.from( LocalDate.of( 2018, 11, 14 ).atStartOfDay( ZoneId.systemDefault() ).toInstant() ), ResourceFactory::createType );
+
+ final IGenericClient client = createGenericClient();
+ client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) );
+ MethodOutcome methodOutcome = client.update().resource( questionnaireResponse ).execute();
+ Assert.assertNotEquals( Boolean.TRUE, methodOutcome.getCreated() );
+ Assert.assertEquals( "http://localhost:" + localPort + "/fhir/r4/default/QuestionnaireResponse/deR4kl4mnf7", methodOutcome.getId().toString() );
+ }
+
+ @Test( expected = AuthenticationException.class )
+ public void deleteQuestionnaireResponseWithoutAuthorization() throws Exception
+ {
+ expectProgramStageMetadataRequests();
+
+ final IGenericClient client = createGenericClient();
+ client.delete().resourceById( "QuestionnaireResponse", "deR4kl4mnf7" ).execute();
+ }
+
+ @Test( expected = AuthenticationException.class )
+ public void deleteQuestionnaireResponseInvalidAuthorization() throws Exception
+ {
+ expectProgramStageMetadataRequests();
+ userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7" ) )
+ .andExpect( method( HttpMethod.DELETE ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) )
+ .andRespond( withStatus( HttpStatus.UNAUTHORIZED ) );
+
+ final IGenericClient client = createGenericClient();
+ client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "invalid_1" ) );
+ client.delete().resourceById( "QuestionnaireResponse", "deR4kl4mnf7" ).execute();
+
+ userDhis2Server.verify();
+ }
+
+ @Test
+ public void deleteQuestionnaireResponse() throws Exception
+ {
+ expectProgramStageMetadataRequests();
+ userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7" ) )
+ .andExpect( method( HttpMethod.DELETE ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) )
+ .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-event-91-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
+
+ final IGenericClient client = createGenericClient();
+ client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) );
+ client.delete().resourceById( "QuestionnaireResponse", "deR4kl4mnf7" ).execute();
+
+ userDhis2Server.verify();
+ }
+}
diff --git a/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-get.json b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-get.json
new file mode 100644
index 00000000..104fb831
--- /dev/null
+++ b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-get.json
@@ -0,0 +1,27 @@
+{
+ "events": [
+ {
+ "event": "deR4kl4mnf7",
+ "status": "ACTIVE",
+ "eventDate": "2018-11-10T00:00:00+01:00",
+ "dueDate": "2018-11-12T00:00:00+01:00",
+ "coordinate": null,
+ "dataValues": [
+ {
+ "value": "3666",
+ "providedElsewhere": false,
+ "dataElement": "BnplxU2jGvX"
+ },
+ {
+ "value": "1",
+ "providedElsewhere": false,
+ "dataElement": "ft7iD5ZzPxJ"
+ }
+ ],
+ "orgUnit": "ldXIdLNUNEn",
+ "program": "EPDyQuoRnXk",
+ "trackedEntityInstance": "JeR2Ul4mZfx",
+ "programStage": "MsWxkiY6tMS"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-update-response.json b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-update-response.json
new file mode 100644
index 00000000..fb4ea45f
--- /dev/null
+++ b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-update-response.json
@@ -0,0 +1,11 @@
+{
+ "status": "OK",
+ "response": {
+ "importSummaries": [
+ {
+ "status": "SUCCESS",
+ "reference": "deR4kl4mnf7"
+ }
+ ]
+ }
+}
diff --git a/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-update.json b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-update.json
new file mode 100644
index 00000000..121dc860
--- /dev/null
+++ b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-update.json
@@ -0,0 +1,22 @@
+{
+ "status": "OVERDUE",
+ "eventDate": "2018-11-10T00:00:00+01:00",
+ "dueDate": "2018-11-14T00:00:00+01:00",
+ "coordinate": null,
+ "dataValues": [
+ {
+ "value": "3666",
+ "providedElsewhere": false,
+ "dataElement": "BnplxU2jGvX"
+ },
+ {
+ "value": "1",
+ "providedElsewhere": false,
+ "dataElement": "ft7iD5ZzPxJ"
+ }
+ ],
+ "orgUnit": "ldXIdLNUNEn",
+ "program": "EPDyQuoRnXk",
+ "trackedEntityInstance": "JeR2Ul4mZfx",
+ "programStage": "MsWxkiY6tMS"
+}
\ No newline at end of file
diff --git a/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/single-event-91-get.json b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/single-event-91-get.json
new file mode 100644
index 00000000..2529d67a
--- /dev/null
+++ b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/single-event-91-get.json
@@ -0,0 +1,23 @@
+{
+ "event": "deR4kl4mnf7",
+ "status": "ACTIVE",
+ "eventDate": "2018-11-10T00:00:00+01:00",
+ "dueDate": "2018-11-12T00:00:00+01:00",
+ "coordinate": null,
+ "dataValues": [
+ {
+ "value": "3666",
+ "providedElsewhere": false,
+ "dataElement": "BnplxU2jGvX"
+ },
+ {
+ "value": "1",
+ "providedElsewhere": false,
+ "dataElement": "ft7iD5ZzPxJ"
+ }
+ ],
+ "orgUnit": "ldXIdLNUNEn",
+ "program": "EPDyQuoRnXk",
+ "trackedEntityInstance": "JeR2Ul4mZfx",
+ "programStage": "MsWxkiY6tMS"
+}
\ No newline at end of file
diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/ProgramStageRule.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/ProgramStageRule.java
index f7045bbb..80823bb9 100644
--- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/ProgramStageRule.java
+++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/ProgramStageRule.java
@@ -64,12 +64,12 @@
query = "SELECT psr FROM ProgramStageRule psr " +
"LEFT JOIN psr.programStage ps ON (ps.enabled=true AND ps.expEnabled=true AND (ps.fhirCreateEnabled=true OR ps.fhirUpdateEnabled=true) AND ps.programStageReference IN (:programStageReferences)) " +
"LEFT JOIN ps.program p ON (p.enabled=true AND p.expEnabled=true AND (p.fhirCreateEnabled=true OR p.fhirUpdateEnabled=true) AND p.programReference IN (:programReferences)) WHERE " +
- "psr.enabled=true AND psr.expEnabled=true AND (psr.fhirCreateEnabled=true OR psr.fhirUpdateEnabled=true) AND psr.transformExpScript IS NOT NULL" ),
+ "psr.enabled=true AND psr.expEnabled=true AND (psr.fhirCreateEnabled=true OR psr.fhirUpdateEnabled=true)" ),
@NamedQuery( name = ProgramStageRule.FIND_ALL_EXP_BY_DATA_REF_NAMED_QUERY,
query = "SELECT psr FROM ProgramStageRule psr " +
"LEFT JOIN psr.programStage ps ON (ps.enabled=true AND ps.expEnabled=true AND (ps.fhirCreateEnabled=true OR ps.fhirUpdateEnabled=true) AND ps.programStageReference IN (:programStageReferences)) " +
"LEFT JOIN ps.program p ON (p.enabled=true AND p.expEnabled=true AND (p.fhirCreateEnabled=true OR p.fhirUpdateEnabled=true) AND p.programReference IN (:programReferences)) WHERE " +
- "psr.enabled=true AND psr.expEnabled=true AND (psr.fhirCreateEnabled=true OR psr.fhirUpdateEnabled=true) AND psr.transformExpScript IS NOT NULL AND " +
+ "psr.enabled=true AND psr.expEnabled=true AND (psr.fhirCreateEnabled=true OR psr.fhirUpdateEnabled=true) AND " +
"EXISTS (SELECT 1 FROM RuleDhisDataReference edr WHERE edr.rule=psr AND edr.dataReference IN (:dataReferences))" )
} )
@Relation( value = "rule", collectionRelation = "rules" )
diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/CustomRuleRepository.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/CustomRuleRepository.java
index f1b83c57..a3ddefad 100644
--- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/CustomRuleRepository.java
+++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/CustomRuleRepository.java
@@ -68,5 +68,4 @@ public interface CustomRuleRepository
@RestResource( exported = false )
@Nonnull
Collection> findAllExp( @Nonnull DhisResourceType dhisResourceType );
-
}
diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/impl/CustomRuleRepositoryImpl.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/impl/CustomRuleRepositoryImpl.java
index 5f070628..baae592e 100644
--- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/impl/CustomRuleRepositoryImpl.java
+++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/impl/CustomRuleRepositoryImpl.java
@@ -120,6 +120,25 @@ public Collection> findAllExp( @Nonnull DhisRes
return rules.stream().map( r -> {
Hibernate.initialize( r.getDhisDataReferences() );
+
+ return new RuleInfo<>( r, r.getDhisDataReferences() );
+ } ).collect( Collectors.toList() );
+ }
+
+ @RestResource( exported = false )
+ @Nonnull
+ @Cacheable( key = "{#root.methodName, #a0, #a1}", cacheManager = "metadataCacheManager", cacheNames = "rule" )
+ @Transactional( readOnly = true )
+ public Collection> findAllExp( @Nonnull DhisResourceType dhisResourceType, @Nonnull FhirResourceType fhirResourceType )
+ {
+ final List rules = entityManager.createQuery( "SELECT r FROM " + dhisResourceType.getRuleType() +
+ " r WHERE r.enabled=true AND r.expEnabled=true AND r.fhirResourceType=:fhirResourceType AND " +
+ "(r.fhirCreateEnabled=true OR r.fhirUpdateEnabled=true)", AbstractRule.class )
+ .setParameter( "fhirResourceType", fhirResourceType ).getResultList();
+
+ return rules.stream().map( r -> {
+ Hibernate.initialize( r.getDhisDataReferences() );
+
return new RuleInfo<>( r, r.getDhisDataReferences() );
} ).collect( Collectors.toList() );
}
diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirRequestResolver.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirRequestResolver.java
index ee7d7494..bad1109e 100644
--- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirRequestResolver.java
+++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirRequestResolver.java
@@ -58,7 +58,7 @@ public interface DhisToFhirRequestResolver
List> resolveRules( @Nonnull ScriptedDhisResource dhisResource );
@Nonnull
- List> resolveRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules );
+ List> filterRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules );
@Nonnull
Optional resolveFhirClient( @Nonnull ScriptedDhisResource scriptedDhisResource );
diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirTransformerServiceImpl.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirTransformerServiceImpl.java
index 45da1791..4edb03a3 100644
--- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirTransformerServiceImpl.java
+++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirTransformerServiceImpl.java
@@ -318,8 +318,8 @@ public DhisToFhirTransformerRequest createTransformerRequest( @Nonnull FhirClien
{
final DhisToFhirRequestResolver requestResolver = getRequestResolver( dhisRequest.getResourceType() );
- return createTransformerRequest( dhisRequest, rr -> rr.convert( resource, dhisRequest ), requestResolver, ( rr, scriptedResource ) -> rr.resolveRules( scriptedResource, rules ),
- ri -> true, ( si, rr ) -> fhirClient );
+ return createTransformerRequest( dhisRequest, rr -> rr.convert( resource, dhisRequest ), requestResolver,
+ ( rr, scriptedResource ) -> rr.filterRules( scriptedResource, rules ), ri -> true, ( si, rr ) -> fhirClient );
}
@Nullable
diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/enrollment/EnrollmentToFhirRequestResolver.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/enrollment/EnrollmentToFhirRequestResolver.java
index a65af7a7..b540bbe7 100644
--- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/enrollment/EnrollmentToFhirRequestResolver.java
+++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/enrollment/EnrollmentToFhirRequestResolver.java
@@ -118,7 +118,7 @@ public List> resolveRules( @Nonnull ScriptedDhi
@Nonnull
@Override
- public List> resolveRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules )
+ public List> filterRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules )
{
return rules.stream().map( ri -> new RuleInfo<>( (EnrollmentRule) ri.getRule(), ri.getDhisDataReferences() ) )
.sorted().collect( Collectors.toList() );
diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/AbstractDhisMetadataToFhirRequestResolver.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/AbstractDhisMetadataToFhirRequestResolver.java
index 574e8695..c1ad7e0c 100644
--- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/AbstractDhisMetadataToFhirRequestResolver.java
+++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/AbstractDhisMetadataToFhirRequestResolver.java
@@ -61,12 +61,13 @@ protected AbstractDhisMetadataToFhirRequestResolver( @Nonnull FhirClientReposito
@Override
public List> resolveRules( @Nonnull ScriptedDhisResource dhisResource )
{
- return ruleRepository.findAllExp( dhisResource.getResourceType() ).stream().sorted().collect( Collectors.toList() );
+ return ruleRepository.findAllExp( dhisResource.getResourceType() ).stream()
+ .sorted().collect( Collectors.toList() );
}
@Nonnull
@Override
- public List> resolveRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules )
+ public List> filterRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules )
{
return rules.stream().sorted().collect( Collectors.toList() );
}
diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/program/ProgramStageToFhirRequestResolver.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/program/ProgramStageToFhirRequestResolver.java
index 87f9d1ac..76ef7e10 100644
--- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/program/ProgramStageToFhirRequestResolver.java
+++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/program/ProgramStageToFhirRequestResolver.java
@@ -74,7 +74,7 @@ public class ProgramStageToFhirRequestResolver extends AbstractDhisToFhirRequest
{
private final ProgramMetadataService programMetadataService;
- private final ProgramStageRuleRepository ruleRepository;
+ private final ProgramStageRuleRepository programStageRuleRepository;
private final TrackedEntityService trackedEntityService;
@@ -87,7 +87,7 @@ public class ProgramStageToFhirRequestResolver extends AbstractDhisToFhirRequest
public ProgramStageToFhirRequestResolver(
@Nonnull FhirClientRepository fhirClientRepository,
@Nonnull ProgramMetadataService programMetadataService,
- @Nonnull ProgramStageRuleRepository ruleRepository,
+ @Nonnull ProgramStageRuleRepository programStageRuleRepository,
@Nonnull TrackedEntityService trackedEntityService,
@Nonnull TrackedEntityMetadataService trackedEntityMetadataService,
@Nonnull ScriptExecutionContext scriptExecutionContext,
@@ -96,7 +96,7 @@ public ProgramStageToFhirRequestResolver(
super( fhirClientRepository );
this.programMetadataService = programMetadataService;
- this.ruleRepository = ruleRepository;
+ this.programStageRuleRepository = programStageRuleRepository;
this.trackedEntityService = trackedEntityService;
this.trackedEntityMetadataService = trackedEntityMetadataService;
this.scriptExecutionContext = scriptExecutionContext;
@@ -116,13 +116,13 @@ public List> resolveRules( @Nonnull ScriptedDhi
{
final ScriptedEvent event = (ScriptedEvent) dhisResource;
- return ruleRepository.findAllExp( event.getProgram().getAllReferences(), event.getProgramStage().getAllReferences(), null )
+ return programStageRuleRepository.findAllExp( event.getProgram().getAllReferences(), event.getProgramStage().getAllReferences(), null )
.stream().sorted().collect( Collectors.toList() );
}
@Nonnull
@Override
- public List> resolveRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules )
+ public List> filterRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules )
{
final ScriptedEvent event = (ScriptedEvent) dhisResource;
final Program program = event.getProgram();
diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/trackedentity/TrackedEntityToFhirRequestResolver.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/trackedentity/TrackedEntityToFhirRequestResolver.java
index d4a5142c..06be8698 100644
--- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/trackedentity/TrackedEntityToFhirRequestResolver.java
+++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/trackedentity/TrackedEntityToFhirRequestResolver.java
@@ -108,7 +108,7 @@ public List> resolveRules( @Nonnull ScriptedDhi
@Nonnull
@Override
- public List> resolveRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules )
+ public List> filterRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules )
{
final ScriptedTrackedEntityInstance tei = (ScriptedTrackedEntityInstance) dhisResource;
final TrackedEntityType type = tei.getType();