diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java index 5b24f5788..6a92bad2e 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java @@ -1,9 +1,11 @@ package edu.internet2.tier.shibboleth.admin.ui.controller; import com.fasterxml.jackson.databind.exc.InvalidTypeIdException; +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolverValidationService; import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository; +import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -22,8 +24,10 @@ import java.io.IOException; import java.net.URI; +import java.util.List; import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolverValidator.ValidationResult; +import static java.util.stream.Collectors.toList; @RestController @RequestMapping("/api") @@ -36,6 +40,9 @@ public class MetadataResolversController { @Autowired MetadataResolverValidationService metadataResolverValidationService; + @Autowired + private MetadataResolverService metadataResolverService; + @ExceptionHandler({InvalidTypeIdException.class, IOException.class, HttpMessageNotReadableException.class}) public ResponseEntity unableToParseJson(Exception ex) { return ResponseEntity.badRequest().body(new ErrorResponse(HttpStatus.BAD_REQUEST.toString(), ex.getMessage())); @@ -67,18 +74,19 @@ public ResponseEntity create(@RequestBody MetadataResolver newResolver) { return ResponseEntity.status(HttpStatus.CONFLICT).build(); } - //TODO: we are disregarding attached filters if any sent from UI. - //Only deal with filters via filters endpoints? - newResolver.clearAllFilters(); - ResponseEntity validationErrorResponse = validate(newResolver); if(validationErrorResponse != null) { return validationErrorResponse; } + newResolver.convertFiltersFromTransientRepresentationIfNecessary(); MetadataResolver persistedResolver = resolverRepository.save(newResolver); persistedResolver.updateVersion(); + //TODO: should we call this here? Doing so currently throws ClassCastException + //this.metadataResolverService.reloadFilters(persistedResolver.getName()); + + persistedResolver.convertFiltersIntoTransientRepresentationIfNecessary(); return ResponseEntity.created(getResourceUriFor(persistedResolver)).body(persistedResolver); } @@ -102,8 +110,7 @@ public ResponseEntity update(@PathVariable String resourceId, @RequestBody Me updatedResolver.setAudId(existingResolver.getAudId()); - //TODO: we are disregarding attached filters if any sent from UI. - //Only deal with filters via filters endpoints? + //If one needs to update filters, it should be dealt with via filters endpoints updatedResolver.setMetadataFilters(existingResolver.getMetadataFilters()); MetadataResolver persistedResolver = resolverRepository.save(updatedResolver); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolver.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolver.java index e5b1221c1..d1f0e97f6 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolver.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolver.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractAuditable; +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter; import edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -23,6 +24,8 @@ import java.util.List; import java.util.UUID; +import static java.util.stream.Collectors.toList; + @Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) @EqualsAndHashCode(callSuper = true, exclude = {"version"}) @@ -71,7 +74,18 @@ public void updateVersion() { this.version = hashCode(); } - public void clearAllFilters() { - this.metadataFilters.clear(); + public void convertFiltersIntoTransientRepresentationIfNecessary() { + getAvailableEntityAttributesFilters().forEach(EntityAttributesFilter::intoTransientRepresentation); + } + + public void convertFiltersFromTransientRepresentationIfNecessary() { + getAvailableEntityAttributesFilters().forEach(EntityAttributesFilter::fromTransientRepresentation); + } + + private List getAvailableEntityAttributesFilters() { + return this.metadataFilters.stream() + .filter(EntityAttributesFilter.class::isInstance) + .map(EntityAttributesFilter.class::cast) + .collect(toList()); } } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversControllerIntegrationTests.groovy index cb6592990..25071cb98 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversControllerIntegrationTests.groovy @@ -2,6 +2,8 @@ package edu.internet2.tier.shibboleth.admin.ui.controller import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicHttpMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository @@ -53,6 +55,7 @@ class MetadataResolversControllerIntegrationTests extends Specification { generator = new TestObjectGenerator(attributeUtility) mapper = new ObjectMapper() mapper.enable(SerializationFeature.INDENT_OUTPUT) + mapper.registerModule(new JavaTimeModule()) } def cleanup() { @@ -148,7 +151,7 @@ class MetadataResolversControllerIntegrationTests extends Specification { } @Unroll - def "POST new DynamicHttpMetadataResolver of type #resolverType -> /api/MetadataResolvers"(String resolverType) { + def "POST new concrete MetadataResolver of type #resolverType -> /api/MetadataResolvers"(String resolverType) { given: 'New MetadataResolver JSON representation' def resolver = generator.buildRandomMetadataResolverOfType(resolverType) @@ -231,6 +234,27 @@ class MetadataResolversControllerIntegrationTests extends Specification { updatedResult.statusCodeValue == 409 } + def "POST new MetadataResolver with one EntityAttributesFilters attached -> /api/MetadataResolvers"() { + given: 'New MetadataResolver with attached entity attributes filter JSON representation' + def resolver = generator.buildRandomMetadataResolverOfType('FileBacked') + resolver.metadataFilters << generator.entityAttributesFilter() + + when: 'POST request is made with new FileBackedMetadataResolver with EntityAttributesFilter JSON representation' + def result = this.restTemplate.postForEntity(BASE_URI, createRequestHttpEntityFor { mapper.writeValueAsString(resolver) }, String) + + then: + result.statusCodeValue == 201 + result.headers.Location[0].contains(BASE_URI) + + when: 'Query REST API for newly created resolver' + def createdResolverResult = this.restTemplate.getForEntity(result.headers.Location[0], String) + def createdResolver = mapper.readValue(createdResolverResult.body, edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver) + + then: + createdResolver.metadataFilters.size() == 1 + createdResolver.metadataFilters[0] instanceof EntityAttributesFilter + } + private HttpEntity createRequestHttpEntityFor(Closure jsonBodySupplier) { new HttpEntity(jsonBodySupplier(), ['Content-Type': 'application/json'] as HttpHeaders) }