From 85e2f4b772d9f9f7b39e2e5c24314b9b6f75dde3 Mon Sep 17 00:00:00 2001 From: soimugeo Date: Thu, 14 Nov 2024 17:54:38 +0200 Subject: [PATCH 1/2] added handler for GetEntityHistorySummaryRequest --- .../uiHistoryConcern/dto/EntityChange.java | 16 ++++++++ .../dto/EntityHistorySummary.java | 9 +++++ ...GetEntityHistorySummaryCommandHandler.java | 38 +++++++++++++++++++ .../GetEntityHistorySummaryRequest.java | 23 +++++++++++ .../GetEntityHistorySummaryResponse.java | 16 ++++++++ .../RevisionsEventRepository.java | 4 ++ .../services/NewRevisionsEventService.java | 4 +- .../NewRevisionsEventServiceImpl.java | 17 +++++++++ 8 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/dto/EntityChange.java create mode 100644 src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/dto/EntityHistorySummary.java create mode 100644 src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/handlers/GetEntityHistorySummaryCommandHandler.java create mode 100644 src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/handlers/GetEntityHistorySummaryRequest.java create mode 100644 src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/handlers/GetEntityHistorySummaryResponse.java diff --git a/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/dto/EntityChange.java b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/dto/EntityChange.java new file mode 100644 index 0000000..c781977 --- /dev/null +++ b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/dto/EntityChange.java @@ -0,0 +1,16 @@ +package edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.dto; + +import edu.stanford.protege.webprotege.common.UserId; + +import java.time.LocalDateTime; + +public record EntityChange(String changeSummary, + UserId userId, + LocalDateTime dateTime) { + + public static EntityChange create(String changeSummary, + UserId userId, + LocalDateTime dateTime){ + return new EntityChange(changeSummary,userId,dateTime); + } +} diff --git a/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/dto/EntityHistorySummary.java b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/dto/EntityHistorySummary.java new file mode 100644 index 0000000..2ef4abf --- /dev/null +++ b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/dto/EntityHistorySummary.java @@ -0,0 +1,9 @@ +package edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.dto; + +import java.util.List; + +public record EntityHistorySummary(List changes) { + public static EntityHistorySummary create(List changes) { + return new EntityHistorySummary(changes); + } +} diff --git a/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/handlers/GetEntityHistorySummaryCommandHandler.java b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/handlers/GetEntityHistorySummaryCommandHandler.java new file mode 100644 index 0000000..3a50cc1 --- /dev/null +++ b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/handlers/GetEntityHistorySummaryCommandHandler.java @@ -0,0 +1,38 @@ +package edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.handlers; + +import edu.stanford.protege.webprotege.common.ProjectId; +import edu.stanford.protege.webprotege.ipc.*; +import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.dto.EntityHistorySummary; +import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.services.NewRevisionsEventService; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Mono; + +import javax.annotation.Nonnull; + +@Component +public class GetEntityHistorySummaryCommandHandler implements CommandHandler { + + private final NewRevisionsEventService service; + + public GetEntityHistorySummaryCommandHandler(NewRevisionsEventService service) { + this.service = service; + } + + + @Nonnull + @Override + public String getChannelName() { + return GetEntityHistorySummaryRequest.CHANNEL; + } + + @Override + public Class getRequestClass() { + return GetEntityHistorySummaryRequest.class; + } + + @Override + public Mono handleRequest(GetEntityHistorySummaryRequest request, ExecutionContext executionContext) { + EntityHistorySummary entityHistorySummary = service.getEntityHistorySummary(ProjectId.valueOf(request.projectId()), request.entityIri()); + return Mono.just(GetEntityHistorySummaryResponse.create(entityHistorySummary)); + } +} diff --git a/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/handlers/GetEntityHistorySummaryRequest.java b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/handlers/GetEntityHistorySummaryRequest.java new file mode 100644 index 0000000..4af8373 --- /dev/null +++ b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/handlers/GetEntityHistorySummaryRequest.java @@ -0,0 +1,23 @@ +package edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.handlers; + +import com.fasterxml.jackson.annotation.*; +import edu.stanford.protege.webprotege.common.Request; + +@JsonTypeName(GetEntityHistorySummaryRequest.CHANNEL) +public record GetEntityHistorySummaryRequest( + @JsonProperty("projectId") String projectId, + @JsonProperty("entityIri") String entityIri +) implements Request { + + public static final String CHANNEL = "webprotege.history.GetEntityHistorySummary"; + + public static GetEntityHistorySummaryRequest create(String projectId, + String entityIri) { + return new GetEntityHistorySummaryRequest(projectId, entityIri); + } + + @Override + public String getChannel() { + return CHANNEL; + } +} diff --git a/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/handlers/GetEntityHistorySummaryResponse.java b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/handlers/GetEntityHistorySummaryResponse.java new file mode 100644 index 0000000..f81c1d7 --- /dev/null +++ b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/handlers/GetEntityHistorySummaryResponse.java @@ -0,0 +1,16 @@ +package edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.handlers; + +import com.fasterxml.jackson.annotation.*; +import edu.stanford.protege.webprotege.common.Response; +import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.dto.EntityHistorySummary; + +import static edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.handlers.GetEntityHistorySummaryRequest.CHANNEL; + +@JsonTypeName(CHANNEL) +public record GetEntityHistorySummaryResponse( + @JsonProperty("entityHistorySummary") EntityHistorySummary entityHistorySummary +) implements Response { + public static GetEntityHistorySummaryResponse create(EntityHistorySummary entityHistorySummary) { + return new GetEntityHistorySummaryResponse(entityHistorySummary); + } +} diff --git a/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/repositories/RevisionsEventRepository.java b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/repositories/RevisionsEventRepository.java index ffdaae2..a2b6203 100644 --- a/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/repositories/RevisionsEventRepository.java +++ b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/repositories/RevisionsEventRepository.java @@ -1,5 +1,6 @@ package edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.repositories; +import edu.stanford.protege.webprotege.common.ProjectId; import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.events.RevisionsEvent; import org.springframework.data.mongodb.repository.*; @@ -8,4 +9,7 @@ public interface RevisionsEventRepository extends MongoRepository { @Query("{ 'projectId.id': ?0, 'timestamp': { $gt: ?1 } }") List findByProjectIdAndTimestampAfter(String projectId, long timestamp); + + List findByProjectIdAndWhoficEntityIriOrderByTimestampDesc(ProjectId projectId, String whoficEntityIri); + } diff --git a/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/services/NewRevisionsEventService.java b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/services/NewRevisionsEventService.java index e68ad28..0a52714 100644 --- a/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/services/NewRevisionsEventService.java +++ b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/services/NewRevisionsEventService.java @@ -2,7 +2,7 @@ import edu.stanford.protege.webprotege.change.ProjectChange; import edu.stanford.protege.webprotege.common.*; -import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.dto.ChangedEntities; +import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.dto.*; import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.events.NewRevisionsEvent; import org.semanticweb.owlapi.model.OWLEntity; @@ -16,4 +16,6 @@ public interface NewRevisionsEventService { Page fetchPaginatedProjectChanges(ProjectId projectId, Optional subject, int pageNumber, int pageSize); ChangedEntities getChangedEntitiesAfterTimestamp(ProjectId projectId, Timestamp timestamp); + + EntityHistorySummary getEntityHistorySummary(ProjectId projectId, String entityIri); } diff --git a/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/services/NewRevisionsEventServiceImpl.java b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/services/NewRevisionsEventServiceImpl.java index aedb8f3..f3413f9 100644 --- a/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/services/NewRevisionsEventServiceImpl.java +++ b/src/main/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/services/NewRevisionsEventServiceImpl.java @@ -14,6 +14,7 @@ import org.springframework.transaction.annotation.Transactional; import java.sql.Timestamp; +import java.time.*; import java.util.*; import java.util.stream.Collectors; @@ -99,4 +100,20 @@ private static List groupByChangeType(List revisionsEven .distinct() .collect(Collectors.toList()); } + + @Override + public EntityHistorySummary getEntityHistorySummary(ProjectId projectId, String entityIri) { + List revisionsForEntity = repository.findByProjectIdAndWhoficEntityIriOrderByTimestampDesc(projectId, entityIri); + List entityChanges = revisionsForEntity.stream() + .map(revisionEvent -> { + ProjectChange projectChange = projectChangeMapper.mapProjectChangeDocumentToProjectChange(revisionEvent.projectChange()); + Instant instant = Instant.ofEpochMilli(projectChange.getTimestamp()); + LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.of("UTC")); + return EntityChange.create(projectChange.getSummary(), projectChange.getAuthor(), localDateTime); + } + ).toList(); + + + return EntityHistorySummary.create(entityChanges); + } } From a6d1435c39e4c28b92526d3ab2c5836998ccdf61 Mon Sep 17 00:00:00 2001 From: soimugeo Date: Mon, 18 Nov 2024 13:06:56 +0200 Subject: [PATCH 2/2] Added test for NewRevisionsEventService.getEntityHistorySummary() --- .../NewRevisionsEventServiceTest.java | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/src/test/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/services/NewRevisionsEventServiceTest.java b/src/test/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/services/NewRevisionsEventServiceTest.java index 8920e4a..9e4a035 100644 --- a/src/test/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/services/NewRevisionsEventServiceTest.java +++ b/src/test/java/edu/stanford/protege/webprotegeeventshistory/uiHistoryConcern/services/NewRevisionsEventServiceTest.java @@ -3,6 +3,7 @@ import edu.stanford.protege.webprotege.change.ProjectChange; import edu.stanford.protege.webprotege.common.Page; import edu.stanford.protege.webprotege.common.*; +import edu.stanford.protege.webprotege.revision.RevisionNumber; import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.dto.*; import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.events.*; import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.mappers.*; @@ -17,6 +18,7 @@ import org.springframework.data.domain.*; import java.sql.Timestamp; +import java.time.*; import java.util.*; import static org.junit.jupiter.api.Assertions.*; @@ -183,4 +185,92 @@ public void GIVEN_multipleEntitiesChangedAfterTimestamp_WHEN_getChangedEntitiesA verify(repository).findByProjectIdAndTimestampAfter(projectId.id(), timestamp.getTime()); } + + @Test + public void GIVEN_noHistoryForEntity_WHEN_getEntityHistorySummaryCalled_THEN_returnEmptyHistorySummary() { + String entityIri = "http://example.com/entity1"; + + when(repository.findByProjectIdAndWhoficEntityIriOrderByTimestampDesc(projectId, entityIri)) + .thenReturn(Collections.emptyList()); + + EntityHistorySummary result = service.getEntityHistorySummary(projectId, entityIri); + + assertNotNull(result); + assertTrue(result.changes().isEmpty()); + + verify(repository).findByProjectIdAndWhoficEntityIriOrderByTimestampDesc(projectId, entityIri); + } + + @Test + public void GIVEN_validHistoryForEntity_WHEN_getEntityHistorySummaryCalled_THEN_returnMappedHistorySummary() { + String entityIri = "http://example.com/entity1"; + long timestamp1 = 1234567890123L; + long timestamp2 = 1234567890124L; + UserId userId1 = UserId.valueOf("user1"); + UserId userId2 = UserId.valueOf("user2"); + + Document document1 = new Document("a", "b"); + Document document2 = new Document("c", "d"); + + RevisionsEvent eventCreate = RevisionsEvent.create(projectId, entityIri, ChangeType.CREATE_ENTITY, timestamp2, document2); + RevisionsEvent eventUpdate = RevisionsEvent.create(projectId, entityIri, ChangeType.UPDATE_ENTITY, timestamp1, document1); + + ProjectChange changeCreate = ProjectChange.get( + RevisionNumber.getRevisionNumber(1), + userId1, + timestamp1, + "Create", + 1, + Page.emptyPage() + ); + ProjectChange changeUpdate = ProjectChange.get( + RevisionNumber.getRevisionNumber(2), + userId2, + timestamp2, + "Update", + 1, + Page.emptyPage() + ); + + when(repository.findByProjectIdAndWhoficEntityIriOrderByTimestampDesc(projectId, entityIri)) + .thenReturn(List.of(eventUpdate, eventCreate)); + when(projectChangeMapper.mapProjectChangeDocumentToProjectChange(eq(eventCreate.projectChange()))) + .thenReturn(changeCreate); + when(projectChangeMapper.mapProjectChangeDocumentToProjectChange(eq(eventUpdate.projectChange()))) + .thenReturn(changeUpdate); + + EntityHistorySummary result = service.getEntityHistorySummary(projectId, entityIri); + + assertNotNull(result); + assertEquals(2, result.changes().size()); + + EntityChange entityUpdate = result.changes().get(0); + assertEquals("Update", entityUpdate.changeSummary()); + assertEquals(userId2, entityUpdate.userId()); + assertEquals(LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp2), ZoneId.of("UTC")), entityUpdate.dateTime()); + + EntityChange entityCreate = result.changes().get(1); + assertEquals("Create", entityCreate.changeSummary()); + assertEquals(userId1, entityCreate.userId()); + assertEquals(LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp1), ZoneId.of("UTC")), entityCreate.dateTime()); + + verify(repository).findByProjectIdAndWhoficEntityIriOrderByTimestampDesc(projectId, entityIri); + verify(projectChangeMapper).mapProjectChangeDocumentToProjectChange(eventCreate.projectChange()); + verify(projectChangeMapper).mapProjectChangeDocumentToProjectChange(eventUpdate.projectChange()); + } + + @Test + public void GIVEN_emptyHistory_WHEN_getEntityHistorySummaryCalled_THEN_returnEmptySummary() { + String entityIri = "http://example.com/entity2"; + + when(repository.findByProjectIdAndWhoficEntityIriOrderByTimestampDesc(projectId, entityIri)) + .thenReturn(Collections.emptyList()); + + EntityHistorySummary result = service.getEntityHistorySummary(projectId, entityIri); + + assertNotNull(result); + assertTrue(result.changes().isEmpty()); + + verify(repository).findByProjectIdAndWhoficEntityIriOrderByTimestampDesc(projectId, entityIri); + } }