diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersController.java index 52122b64f..2ec5f01ab 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersController.java @@ -14,6 +14,8 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -21,12 +23,16 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import java.net.URI; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.springframework.http.HttpStatus.NOT_FOUND; + @RestController @RequestMapping("/api/MetadataResolvers/{metadataResolverId}") public class MetadataFiltersController { @@ -40,33 +46,33 @@ public class MetadataFiltersController { @Autowired private FilterRepository filterRepository; + private static final Supplier HTTP_404_CLIENT_ERROR_EXCEPTION = () -> new HttpClientErrorException(NOT_FOUND); + + @ExceptionHandler + public ResponseEntity notFoundHandler(HttpClientErrorException ex) { + if(ex.getStatusCode() == NOT_FOUND) { + return ResponseEntity.notFound().build(); + } + throw ex; + } + @GetMapping("/Filters") @Transactional(readOnly = true) public ResponseEntity getAll(@PathVariable String metadataResolverId) { - MetadataResolver resolver = repository.findByResourceId(metadataResolverId); - if(resolver == null) { - return ResponseEntity.notFound().build(); - } + MetadataResolver resolver = findResolverOrThrowHttp404(metadataResolverId); return ResponseEntity.ok(resolver.getMetadataFilters()); } @GetMapping("/Filters/{resourceId}") + @Transactional(readOnly = true) public ResponseEntity getOne(@PathVariable String metadataResolverId, @PathVariable String resourceId) { - MetadataResolver resolver = repository.findByResourceId(metadataResolverId); - if(resolver == null) { - return ResponseEntity.notFound().build(); - } - return ResponseEntity.ok(resolver.getMetadataFilters().stream() - .filter(f -> f.getResourceId().equals(resourceId)) - .collect(Collectors.toList()).get(0)); + MetadataResolver resolver = findResolverOrThrowHttp404(metadataResolverId); + return ResponseEntity.ok(findFilterOrThrowHttp404(resolver, resourceId)); } @PostMapping("/Filters") public ResponseEntity create(@PathVariable String metadataResolverId, @RequestBody MetadataFilter createdFilter) { - MetadataResolver metadataResolver = repository.findByResourceId(metadataResolverId); - if(metadataResolver == null) { - return ResponseEntity.notFound().build(); - } + MetadataResolver metadataResolver = findResolverOrThrowHttp404(metadataResolverId); metadataResolver.getMetadataFilters().add(createdFilter); MetadataResolver persistedMr = repository.save(metadataResolver); @@ -78,7 +84,6 @@ public ResponseEntity create(@PathVariable String metadataResolverId, @Reques return ResponseEntity .created(getResourceUriFor(persistedMr, createdFilter.getResourceId())) .body(persistedFilter); - } @PutMapping("/Filters/{resourceId}") @@ -90,10 +95,7 @@ public ResponseEntity update(@PathVariable String metadataResolverId, return ResponseEntity.notFound().build(); } - MetadataResolver metadataResolver = repository.findByResourceId(metadataResolverId); - if(metadataResolver == null) { - return ResponseEntity.notFound().build(); - } + MetadataResolver metadataResolver = findResolverOrThrowHttp404(metadataResolverId); // check to make sure that the relationship exists if (!metadataResolver.getMetadataFilters().contains(filterTobeUpdated)) { @@ -122,6 +124,40 @@ public ResponseEntity update(@PathVariable String metadataResolverId, return ResponseEntity.ok().body(persistedFilter); } + @DeleteMapping("/Filters/{resourceId}") + @Transactional + public ResponseEntity delete(@PathVariable String metadataResolverId, + @PathVariable String resourceId) { + + MetadataResolver resolver = findResolverOrThrowHttp404(metadataResolverId); + //TODO: consider implementing delete of filter directly from RDBMS via FilterRepository + boolean removed = resolver.getMetadataFilters().removeIf(f -> f.getResourceId().equals(resourceId)); + if(!removed) { + throw HTTP_404_CLIENT_ERROR_EXCEPTION.get(); + } + repository.save(resolver); + + //TODO: do we need to reload filters here?!? + //metadataResolverService.reloadFilters(persistedMr.getName()); + + return ResponseEntity.noContent().build(); + } + + private MetadataResolver findResolverOrThrowHttp404(String resolverResourceId) { + MetadataResolver resolver = repository.findByResourceId(resolverResourceId); + if(resolver == null) { + throw HTTP_404_CLIENT_ERROR_EXCEPTION.get(); + } + return resolver; + } + + private MetadataFilter findFilterOrThrowHttp404(MetadataResolver resolver, String filterResourceId) { + return resolver.getMetadataFilters().stream() + .filter(f -> f.getResourceId().equals(filterResourceId)) + .findFirst() + .orElseThrow(HTTP_404_CLIENT_ERROR_EXCEPTION); + } + private MetadataFilter newlyPersistedFilter(Stream filters, final String filterResourceId) { MetadataFilter persistedFilter = filters .filter(f -> f.getResourceId().equals(filterResourceId)) @@ -180,4 +216,4 @@ private static URI getResourceUriFor(MetadataResolver mr, String filterResourceI .build() .toUri(); } -} +} \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerIntegrationTests.groovy index 557fdf56e..e65a7e963 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerIntegrationTests.groovy @@ -103,6 +103,29 @@ class MetadataFiltersControllerIntegrationTests extends Specification { updatedResultFromPUT.statusCode.value() == 200 } + def "DELETE Filter"() { + given: 'MetadataResolver with attached filter is available in data store' + def resolver = generator.buildRandomMetadataResolverOfType('FileBacked') + resolver.metadataFilters << generator.entityAttributesFilter() + def filterResourceId = resolver.metadataFilters[0].resourceId + def resolverResourceId = resolver.resourceId + metadataResolverRepository.save(resolver) + + + when: 'GET request is made with resource Id matching the existing filter' + def result = this.restTemplate.getForEntity("$BASE_URI/$resolverResourceId/Filters/$filterResourceId", String) + + then: + result.statusCode.value() == 200 + + and: 'DELETE call is made and then GET call is made for the just deleted resource' + restTemplate.delete("$BASE_URI/$resolverResourceId/Filters/$filterResourceId") + def GETResultAfterDelete = this.restTemplate.getForEntity("$BASE_URI/$resolverResourceId/Filters/$filterResourceId", String) + + then: 'The deleted resource is gone' + GETResultAfterDelete.statusCode.value() == 404 + } + private HttpEntity createRequestHttpEntityFor(Closure jsonBodySupplier) { new HttpEntity(jsonBodySupplier(), ['Content-Type': 'application/json'] as HttpHeaders) }