diff --git a/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerVersionEndpointsIntegrationTests.groovy b/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerVersionEndpointsIntegrationTests.groovy index 705f50021..99b5810ce 100644 --- a/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerVersionEndpointsIntegrationTests.groovy +++ b/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerVersionEndpointsIntegrationTests.groovy @@ -36,7 +36,7 @@ class EntityDescriptorControllerVersionEndpointsIntegrationTests extends Specifi result.statusCodeValue == 404 } - def "GET /api/EntityDescriptor{resourceId}/Versions with 1 entity descriptor version"() { + def "GET /api/EntityDescriptor/{resourceId}/Versions with 1 entity descriptor version"() { given: EntityDescriptor ed = new EntityDescriptor(entityID: 'http://test/controller', createdBy: 'anonymousUser') entityDescriptorRepository.save(ed) @@ -50,7 +50,7 @@ class EntityDescriptorControllerVersionEndpointsIntegrationTests extends Specifi result.body[0].id && result.body[0].creator && result.body[0].date } - def "GET /api/EntityDescriptor{resourceId}/Versions with 2 entity descriptor versions"() { + def "GET /api/EntityDescriptor/{resourceId}/Versions with 2 entity descriptor versions"() { given: EntityDescriptor ed = new EntityDescriptor(entityID: 'http://test/controller', createdBy: 'anonymousUser') ed = entityDescriptorRepository.save(ed) @@ -68,7 +68,7 @@ class EntityDescriptorControllerVersionEndpointsIntegrationTests extends Specifi result.body[0].date < result.body[1].date } - def "GET /api/EntityDescriptor{resourceId}/Versions/{version} for non existent version"() { + def "GET /api/EntityDescriptor/{resourceId}/Versions/{version} for non existent version"() { given: EntityDescriptor ed = new EntityDescriptor(entityID: 'http://test/controller', createdBy: 'anonymousUser') ed = entityDescriptorRepository.save(ed) diff --git a/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/service/envers/EnversVersioningMetadataTests.groovy b/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/service/envers/EnversVersioningMetadataTests.groovy index c4e677c57..9eed8e2bc 100644 --- a/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/service/envers/EnversVersioningMetadataTests.groovy +++ b/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/service/envers/EnversVersioningMetadataTests.groovy @@ -6,6 +6,7 @@ import edu.internet2.tier.shibboleth.admin.ui.configuration.Internationalization import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.TestConfiguration import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicHttpMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.LocalDynamicMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver import edu.internet2.tier.shibboleth.admin.ui.repository.EntityDescriptorRepository @@ -81,4 +82,46 @@ class EnversVersioningMetadataTests extends Specification { edVersions[1].creator == ed.modifiedBy edVersions[1].date == ed.modifiedDateAsZonedDateTime() } + + def "test current version correct logic"() { + when: 'Initial versions' + MetadataResolver mr = new DynamicHttpMetadataResolver(name: 'resolver') + EntityDescriptor ed = new EntityDescriptor(serviceProviderName: 'descriptor') + mr = EnversTestsSupport.doInExplicitTransaction(txMgr) { + metadataResolverRepository.save(mr) + } + ed = EnversTestsSupport.doInExplicitTransaction(txMgr) { + entityDescriptorRepository.save(ed) + } + def mrVersions = metadataResolverVersionService.findVersionsForMetadataResolver(mr.resourceId) + def edVersions = entityDescriptorVersionService.findVersionsForEntityDescriptor(ed.resourceId) + def mrV1 = metadataResolverVersionService.findSpecificVersionOfMetadataResolver(mr.resourceId, mrVersions[0].id) + def edV1 = entityDescriptorVersionService.findSpecificVersionOfEntityDescriptor(ed.resourceId, edVersions[0].id) + + then: + mrV1.isCurrent() + edV1.isCurrent() + + when: 'new version due to update' + mr.name = 'UPDATED' + ed.serviceProviderName = 'UPDATED' + mr = EnversTestsSupport.doInExplicitTransaction(txMgr) { + metadataResolverRepository.save(mr) + } + ed = EnversTestsSupport.doInExplicitTransaction(txMgr) { + entityDescriptorRepository.save(ed) + } + mrVersions = metadataResolverVersionService.findVersionsForMetadataResolver(mr.resourceId) + edVersions = entityDescriptorVersionService.findVersionsForEntityDescriptor(ed.resourceId) + mrV1 = metadataResolverVersionService.findSpecificVersionOfMetadataResolver(mr.resourceId, mrVersions[0].id) + edV1 = entityDescriptorVersionService.findSpecificVersionOfEntityDescriptor(ed.resourceId, edVersions[0].id) + def mrV2 = metadataResolverVersionService.findSpecificVersionOfMetadataResolver(mr.resourceId, mrVersions[1].id) + def edV2 = entityDescriptorVersionService.findSpecificVersionOfEntityDescriptor(ed.resourceId, edVersions[1].id) + + then: + !mrV1.isCurrent() + !edV1.isCurrent() + mrV2.isCurrent() + edV2.isCurrent() + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AbstractAuditable.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AbstractAuditable.java index 24731b6f3..3d2ed1391 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AbstractAuditable.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AbstractAuditable.java @@ -1,5 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.domain; +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.EqualsAndHashCode; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; @@ -16,6 +18,7 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.MappedSuperclass; +import javax.persistence.Transient; import javax.validation.constraints.NotNull; import java.time.Instant; import java.time.LocalDateTime; @@ -27,7 +30,7 @@ @MappedSuperclass @EntityListeners(AuditingEntityListener.class) -@EqualsAndHashCode +@EqualsAndHashCode(exclude = {"current"}) @Audited public abstract class AbstractAuditable implements Auditable { @@ -53,6 +56,9 @@ public abstract class AbstractAuditable implements Auditable { @LastModifiedBy private String modifiedBy; + @Transient + @JsonProperty + private boolean current; @Override public Long getAudId() { @@ -108,6 +114,14 @@ public ZonedDateTime modifiedDateAsZonedDateTime() { return toZonedDateTime(this.modifiedDate); } + public boolean isCurrent() { + return this.current; + } + + public void markAsCurrent() { + this.current = true; + } + private static ZonedDateTime toZonedDateTime(LocalDateTime localDateTime) { return localDateTime .atZone(ZoneId.systemDefault()) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/frontend/EntityDescriptorRepresentation.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/frontend/EntityDescriptorRepresentation.java index e378f5fbb..44f1463c5 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/frontend/EntityDescriptorRepresentation.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/frontend/EntityDescriptorRepresentation.java @@ -1,5 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.frontend; +import com.fasterxml.jackson.annotation.JsonProperty; + import javax.validation.constraints.NotNull; import java.io.Serializable; import java.time.LocalDateTime; @@ -64,6 +66,9 @@ public EntityDescriptorRepresentation(String id, private String createdBy; + @JsonProperty + private boolean current; + public String getId() { return id; } @@ -112,6 +117,7 @@ public void setMdui(MduiRepresentation mdui) { this.mdui = mdui; } + public ServiceProviderSsoDescriptorRepresentation getServiceProviderSsoDescriptor() { return this.getServiceProviderSsoDescriptor(false); } @@ -213,4 +219,12 @@ public String getCreatedBy() { public void setCreatedBy(String createdBy) { this.createdBy = createdBy; } + + public boolean isCurrent() { + return current; + } + + public void setCurrent(boolean current) { + this.current = current; + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/envers/EnversVersionServiceSupport.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/envers/EnversVersionServiceSupport.java index b12d943fc..b5e713143 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/envers/EnversVersionServiceSupport.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/envers/EnversVersionServiceSupport.java @@ -46,14 +46,30 @@ public List findVersionsForPersistentEntity(String resourceId, Class public Object findSpecificVersionOfPersistentEntity(String resourceId, String versionId, Class entityClass) { try { - return AuditReaderFactory.get(entityManager).createQuery() + AbstractAuditable abstractAuditable = + (AbstractAuditable) AuditReaderFactory.get(entityManager).createQuery() .forEntitiesAtRevision(entityClass, Integer.valueOf(versionId)) .add(AuditEntity.property("resourceId").eq(resourceId)) .add(AuditEntity.revisionNumber().eq(Integer.valueOf(versionId))) .getSingleResult(); - } - catch (NoResultException e) { + if(isCurrentRevision(resourceId, versionId, entityClass)) { + abstractAuditable.markAsCurrent(); + } + return abstractAuditable; + } catch (NoResultException e) { return null; } } + + private boolean isCurrentRevision(String resourceId, String versionId, Class entityClass) { + Number revision = (Number) AuditReaderFactory + .get(entityManager) + .createQuery() + .forRevisionsOfEntity(entityClass, false, false) + .addProjection(AuditEntity.revisionNumber().max()) + .add(AuditEntity.property("resourceId").eq(resourceId)) + .getSingleResult(); + + return Integer.valueOf(versionId) == revision.intValue(); + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java index ca7a8659e..7be97f308 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java @@ -497,6 +497,7 @@ public EntityDescriptorRepresentation createRepresentationFromDescriptor(org.ope representation.setModifiedDate(ed.getModifiedDate()); representation.setVersion(ed.hashCode()); representation.setCreatedBy(ed.getCreatedBy()); + representation.setCurrent(ed.isCurrent()); if (ed.getSPSSODescriptor("") != null && ed.getSPSSODescriptor("").getSupportedProtocols().size() > 0) { ServiceProviderSsoDescriptorRepresentation serviceProviderSsoDescriptorRepresentation = representation.getServiceProviderSsoDescriptor(true); diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/versioning/VersionJsonSerializationBasicTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/versioning/VersionJsonSerializationBasicTests.groovy index 011fe7033..c05d9e52b 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/versioning/VersionJsonSerializationBasicTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/versioning/VersionJsonSerializationBasicTests.groovy @@ -22,12 +22,12 @@ class VersionJsonSerializationBasicTests extends Specification { def "Verify basic Version JSON serialization"() { given: def staticDate = ZonedDateTime.parse("2019-05-20T15:00:00.574Z") - def version = new Version('2', 'kramer', staticDate) + def version = new Version('2', 'kramer', staticDate, false) def expectedJson = """ { "id": "2", "creator": "kramer", - "date": "2019-05-20T15:00:00.574Z" + "date": "2019-05-20T15:00:00.574Z" } """ def expectedJsonMap = jsonSlurper.parseText(expectedJson) @@ -37,5 +37,7 @@ class VersionJsonSerializationBasicTests extends Specification { then: deSerializedJsonMap.date == expectedJsonMap.date + deSerializedJsonMap.id == expectedJsonMap.id + deSerializedJsonMap.creator == expectedJsonMap.creator } }