Skip to content

Commit

Permalink
Added support for REST delete on FHIR resources.
Browse files Browse the repository at this point in the history
  • Loading branch information
volsch committed Apr 1, 2019
1 parent 0fae8d9 commit 7a3d488
Show file tree
Hide file tree
Showing 19 changed files with 394 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -380,4 +380,54 @@ public void updateObservation() throws Exception
Assert.assertNotEquals( Boolean.TRUE, methodOutcome.getCreated() );
Assert.assertEquals( "http://localhost:" + localPort + "/fhir/dstu3/default/Observation/ps-deR4kl4mnf7-097d9ee0bdb344aeb9613b4584bad1db", methodOutcome.getId().toString() );
}

@Test( expected = AuthenticationException.class )
public void deleteObservationWithoutAuthorization() throws Exception
{
expectProgramStageMetadataRequests();

final IGenericClient client = createGenericClient();
client.delete().resourceById( "Observation", "ps-deR4kl4mnf7-097d9ee0bdb344aeb9613b4584bad1db" ).execute();
}

@Test( expected = AuthenticationException.class )
public void deleteObservationInvalidAuthorization() throws Exception
{
expectProgramStageMetadataRequests();
userDhis2Server.expect( ExpectedCount.once(), 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 Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) )
.andRespond( withStatus( HttpStatus.UNAUTHORIZED ) );

final IGenericClient client = createGenericClient();
client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "invalid_1" ) );
client.delete().resourceById( "Observation", "ps-deR4kl4mnf7-097d9ee0bdb344aeb9613b4584bad1db" ).execute();

userDhis2Server.verify();
}

@Test
public void deleteObservation() throws Exception
{
expectProgramStageMetadataRequests();
userDhis2Server.expect( ExpectedCount.once(), 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-70-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/enrollments/ieR4nl4mufa.json" ) )
.andExpect( method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) )
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-enrollment-70-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7/BnplxU2jGvX.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-70-update-delete.json", StandardCharsets.UTF_8 ) ) )
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-70-update-response.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON )
.headers( createDefaultHeaders() ) );

final IGenericClient client = createGenericClient();
client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) );
client.delete().resourceById( "Observation", "ps-deR4kl4mnf7-097d9ee0bdb344aeb9613b4584bad1db" ).execute();

userDhis2Server.verify();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -421,4 +421,43 @@ public void updatePatient() throws Exception
Assert.assertNotEquals( Boolean.TRUE, methodOutcome.getCreated() );
Assert.assertEquals( "http://localhost:" + localPort + "/fhir/dstu3/default/Patient/te-JeR2Ul4mZfx-5f9ebdc9852e4c8387ca795946aabc35", methodOutcome.getId().toString() );
}

@Test( expected = AuthenticationException.class )
public void deletePatientWithoutAuthorization() throws Exception
{
expectTrackedEntityMetadataRequests();

final IGenericClient client = createGenericClient();
client.delete().resourceById( "Patient", "te-JeR2Ul4mZfx-5f9ebdc9852e4c8387ca795946aabc35" ).execute();
}

@Test( expected = AuthenticationException.class )
public void deletePatientInvalidAuthorization() throws Exception
{
expectTrackedEntityMetadataRequests();
userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/trackedEntityInstances/JeR2Ul4mZfx" ) )
.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( "Patient", "te-JeR2Ul4mZfx-5f9ebdc9852e4c8387ca795946aabc35" ).execute();

userDhis2Server.verify();
}

@Test
public void deletePatient() throws Exception
{
expectTrackedEntityMetadataRequests();
userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/trackedEntityInstances/JeR2Ul4mZfx" ) )
.andExpect( method( HttpMethod.DELETE ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) )
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-tei-15-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );

final IGenericClient client = createGenericClient();
client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) );
client.delete().resourceById( "Patient", "te-JeR2Ul4mZfx-5f9ebdc9852e4c8387ca795946aabc35" ).execute();

userDhis2Server.verify();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -413,4 +413,93 @@ public void updateObservation() throws Exception
Assert.assertNotEquals( Boolean.TRUE, methodOutcome.getCreated() );
Assert.assertEquals( "http://localhost:" + localPort + "/fhir/r4/default/Observation/ps-deR4kl4mnf7-097d9ee0bdb344aeb9613b4584bad1db", methodOutcome.getId().toString() );
}

@Test( expected = AuthenticationException.class )
public void deleteObservationWithoutAuthorization() throws Exception
{
expectProgramStageMetadataRequests();

final IGenericClient client = createGenericClient();
client.delete().resourceById( "Observation", "ps-deR4kl4mnf7-097d9ee0bdb344aeb9613b4584bad1db" ).execute();
}

@Test( expected = AuthenticationException.class )
public void deleteObservationInvalidAuthorization() throws Exception
{
expectProgramStageMetadataRequests();
userDhis2Server.expect( ExpectedCount.once(), 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 Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) )
.andRespond( withStatus( HttpStatus.UNAUTHORIZED ) );

final IGenericClient client = createGenericClient();
client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "invalid_1" ) );
client.delete().resourceById( "Observation", "ps-deR4kl4mnf7-097d9ee0bdb344aeb9613b4584bad1db" ).execute();

userDhis2Server.verify();
}

@Test
public void deleteObservation() throws Exception
{
expectProgramStageMetadataRequests();
userDhis2Server.expect( ExpectedCount.once(), 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-70-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/enrollments/ieR4nl4mufa.json" ) )
.andExpect( method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) )
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-enrollment-70-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7/BnplxU2jGvX.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-70-update-delete.json", StandardCharsets.UTF_8 ) ) )
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-70-update-response.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON )
.headers( createDefaultHeaders() ) );

final IGenericClient client = createGenericClient();
client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) );
client.delete().resourceById( "Observation", "ps-deR4kl4mnf7-097d9ee0bdb344aeb9613b4584bad1db" ).execute();

userDhis2Server.verify();
}

@Test( expected = AuthenticationException.class )
public void deleteEncounterWithoutAuthorization() throws Exception
{
expectProgramStageMetadataRequests();

final IGenericClient client = createGenericClient();
client.delete().resourceById( "Encounter", "ps-deR4kl4mnf7-9d342f13aec146299d654f03fd0e848c" ).execute();
}

@Test( expected = AuthenticationException.class )
public void deleteEncounterInvalidAuthorization() 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( "Encounter", "ps-deR4kl4mnf7-9d342f13aec146299d654f03fd0e848c" ).execute();

userDhis2Server.verify();
}

@Test
public void deleteEncounter() 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-tei-15-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );

final IGenericClient client = createGenericClient();
client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) );
client.delete().resourceById( "Encounter", "ps-deR4kl4mnf7-9d342f13aec146299d654f03fd0e848c" ).execute();

userDhis2Server.verify();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -421,4 +421,43 @@ public void updatePatient() throws Exception
Assert.assertNotEquals( Boolean.TRUE, methodOutcome.getCreated() );
Assert.assertEquals( "http://localhost:" + localPort + "/fhir/r4/default/Patient/te-JeR2Ul4mZfx-5f9ebdc9852e4c8387ca795946aabc35", methodOutcome.getId().toString() );
}

@Test( expected = AuthenticationException.class )
public void deletePatientWithoutAuthorization() throws Exception
{
expectTrackedEntityMetadataRequests();

final IGenericClient client = createGenericClient();
client.delete().resourceById( "Patient", "te-JeR2Ul4mZfx-5f9ebdc9852e4c8387ca795946aabc35" ).execute();
}

@Test( expected = AuthenticationException.class )
public void deletePatientInvalidAuthorization() throws Exception
{
expectTrackedEntityMetadataRequests();
userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/trackedEntityInstances/JeR2Ul4mZfx" ) )
.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( "Patient", "te-JeR2Ul4mZfx-5f9ebdc9852e4c8387ca795946aabc35" ).execute();

userDhis2Server.verify();
}

@Test
public void deletePatient() throws Exception
{
expectTrackedEntityMetadataRequests();
userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/trackedEntityInstances/JeR2Ul4mZfx" ) )
.andExpect( method( HttpMethod.DELETE ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) )
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-tei-15-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );

final IGenericClient client = createGenericClient();
client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) );
client.delete().resourceById( "Patient", "te-JeR2Ul4mZfx-5f9ebdc9852e4c8387ca795946aabc35" ).execute();

userDhis2Server.verify();
}
}
2 changes: 1 addition & 1 deletion app/src/test/resources/data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1806,7 +1806,7 @@ UPDATE fhir_code_set_value SET preferred_export=true WHERE code_id='d308a6acad84

-- Encounter Child Programme, Birth
INSERT INTO fhir_rule (id, version, name, description, enabled, evaluation_order, fhir_resource_type, dhis_resource_type, imp_enabled, transform_exp_script_id, fhir_create_enabled, fhir_update_enabled, exp_enabled, grouping)
VALUES ('9d342f13aec146299d654f03fd0e848c', 0, 'Child Programme Birth Encounter', NULL, TRUE, 1000, 'ENCOUNTER', 'PROGRAM_STAGE_EVENT', FALSE, '5eab76a90ff443b0a7d05a6e726ca80e', TRUE, TRUE, TRUE, TRUE);
VALUES ('9d342f13aec146299d654f03fd0e848c', 0, 'Child Programme Birth Encounter', NULL, TRUE, 1000, 'ENCOUNTER', 'PROGRAM_STAGE_EVENT', TRUE, '5eab76a90ff443b0a7d05a6e726ca80e', TRUE, TRUE, TRUE, TRUE);
INSERT INTO fhir_program_stage_rule (id, program_stage_id)
VALUES ('9d342f13aec146299d654f03fd0e848c', '4c074c85be494b9d89739e16b9615dad');

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"status": "ACTIVE",
"dataValues": [
{
"value": null,
"providedElsewhere": false,
"dataElement": "BnplxU2jGvX"
}
],
"orgUnit": "ldXIdLNUNEp",
"program": "EPDyQuoRnXk",
"trackedEntityInstance": "JeR2Ul4mZfx",
"programStage": "MsWxkiY6tMS"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"status": "OK",
"response": {
"importSummaries": [
{
"status": "SUCCESS",
"reference": "deR4kl4mnf7"
}
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,6 @@ public interface DhisResourceRepository

@Nonnull
DhisResource save( @Nonnull DhisResource resource );

boolean delete( @Nonnull DhisResource resource );
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,22 @@ public DhisResource save( @Nonnull DhisResource resource )
return resource;
}

@Override
public boolean delete( @Nonnull DhisResource resource )
{
switch ( resource.getResourceType() )
{
case TRACKED_ENTITY:
return trackedEntityService.delete( resource.getId() );
case ENROLLMENT:
throw new UnsupportedOperationException( "Deleting DHIS enrollment resources is nut supported currently." );
case PROGRAM_STAGE_EVENT:
return eventService.delete( resource.getId() );
default:
throw new AssertionError( "Unhandled DHIS resource type: " + resource.getResourceType() );
}
}

private boolean saveTrackedEntityInstance( @Nonnull TrackedEntityInstance trackedEntityInstance )
{
if ( trackedEntityInstance.isNewResource() || trackedEntityInstance.isModified() )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ public Event()
super();
}

public Event( @Nonnull String id )
{
this.id = id;
}

public Event( boolean newResource )
{
this.newResource = newResource;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ List<Event> find( @Nonnull String programId, @Nonnull String programStageId,
@Nonnull
Event createOrMinimalUpdate( @Nonnull Event event );

boolean delete( @Nonnull String eventId );

@Nonnull
DhisResourceResult<Event> find( @Nonnull String programId, @Nonnull String programStageId, @Nonnull UriFilterApplier uriFilterApplier, int from, int max );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,26 @@ public EventServiceImpl( @Nonnull @Qualifier( "userDhis2RestTemplate" ) RestTemp
this.polledProgramRetriever = polledProgramRetriever;
}

@HystrixCommand( ignoreExceptions = { DhisConflictException.class, UnauthorizedException.class } )
@Override
public boolean delete( @Nonnull String eventId )
{
Event instance;
try
{
restTemplate.delete( "/events/{id}", eventId );
}
catch ( HttpClientErrorException e )
{
if ( RestTemplateUtils.isNotFound( e ) )
{
return false;
}
throw e;
}
return true;
}

@HystrixCommand( ignoreExceptions = { DhisConflictException.class, UnauthorizedException.class } )
@Nonnull
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ public TrackedEntityInstance()
super();
}

public TrackedEntityInstance( @Nonnull String id )
{
this.id = id;
}

public TrackedEntityInstance( @Nonnull TrackedEntityType type, @Nullable String id, boolean newResource )
{
this.typeId = type.getId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ Collection<TrackedEntityInstance> findByAttrValue( @Nonnull String typeId,
@Nonnull
TrackedEntityInstance createOrUpdate( @Nonnull TrackedEntityInstance trackedEntityInstance );

boolean delete( @Nonnull String teiId );

@Nonnull
DhisResourceResult<TrackedEntityInstance> find( @Nonnull String trackedEntityTypeId, @Nonnull UriFilterApplier uriFilterApplier, int from, int max );

Expand Down
Loading

0 comments on commit 7a3d488

Please sign in to comment.