From 3a4d1c01337d57897f603ab9f7b587ee968adc4c Mon Sep 17 00:00:00 2001 From: Marcos Lopez Gonzalez Date: Tue, 11 May 2021 21:08:59 +0200 Subject: [PATCH] audit log WIP --- registry-events/pom.xml | 9 +- .../registry/events/VarnishPurgeListener.java | 117 +++++++++++----- .../events/collections/AuditLogger.java | 115 +++++++++++++++ ...ChangedCollectionEntityComponentEvent.java | 55 -------- .../collections/CollectionsBaseEvent.java | 39 ++++++ .../CreateCollectionEntityEvent.java | 16 +-- .../DeleteCollectionEntityEvent.java | 20 +-- .../events/collections/EventType.java | 13 ++ .../collections/ReplaceEntityEvent.java | 38 +++++ .../collections/SubEntityCollectionEvent.java | 96 +++++++++++++ .../UpdateCollectionEntityEvent.java | 16 +-- .../resource/CollectionResourceIT.java | 2 - .../CollectionsSearchResourceTest.java | 63 +++++++++ .../resource/LookupResourceTest.java | 109 +++++++++++++++ .../it/collections/service/BaseServiceIT.java | 14 +- .../service/CollectionsSearchIT.java | 2 +- .../service/merge/BaseMergeServiceIT.java | 9 +- .../merge/InstitutionMergeServiceIT.java | 4 +- .../collections/CollectionsEmailManager.java | 17 +-- .../persistence/mapper/CommentMapper.java | 3 + .../persistence/mapper/IdentifierMapper.java | 2 + .../persistence/mapper/TagMapper.java | 3 + .../collections/ChangeSuggestionMapper.java | 6 +- .../mapper/collections/CollectionMapper.java | 7 +- .../mapper/collections/InstitutionMapper.java | 7 +- .../collections/OccurrenceMappingMapper.java | 3 + .../collections/PrimaryEntityMapper.java | 11 ++ ...ableMapper.java => ReplaceableMapper.java} | 2 +- .../mapper/collections/dto/AuditLogDto.java | 67 ++++++--- .../collections/dto/ChangeSuggestionDto.java | 12 +- .../persistence/mapper/CommentMapper.xml | 8 +- .../persistence/mapper/IdentifierMapper.xml | 9 +- .../registry/persistence/mapper/TagMapper.xml | 9 +- .../mapper/collections/AuditLogMapper.xml | 16 ++- .../collections/ChangeSuggestionMapper.xml | 10 +- .../collections/OccurrenceMappingMapper.xml | 16 ++- .../CollectionsSearchResponse.java | 131 ------------------ .../collections/CollectionsSearchService.java | 1 + registry-security/pom.xml | 1 + registry-service/pom.xml | 4 - .../BaseCollectionEntityService.java | 74 ++++++---- .../BasePrimaryCollectionEntityService.java | 72 ++++++---- .../collections/DefaultCollectionService.java | 2 - .../DefaultInstitutionService.java | 56 ++++---- .../collections/DefaultPersonService.java | 4 +- .../collections/audit/AuditLogger.java | 75 ---------- .../service/collections/audit/BaseEvent.java | 34 ----- .../collections/audit/CreatedEntityEvent.java | 18 --- .../collections/audit/DeletedEntityEvent.java | 18 --- .../collections/audit/UpdatedEntityEvent.java | 24 ---- .../collections/merge/BaseMergeService.java | 84 ++++------- .../merge/CollectionMergeService.java | 43 +++--- .../merge/InstitutionMergeService.java | 104 ++++++-------- .../BaseChangeSuggestionService.java | 46 ++++-- .../CollectionChangeSuggestionService.java | 7 +- .../InstitutionChangeSuggestionService.java | 7 +- .../collections/CollectionsSearchClient.java | 20 +++ .../ws/client/collections/LookupClient.java | 28 ++++ .../CollectionsSearchResource.java | 2 +- .../resources/collections/LookupResource.java | 5 +- 60 files changed, 1060 insertions(+), 745 deletions(-) create mode 100644 registry-events/src/main/java/org/gbif/registry/events/collections/AuditLogger.java delete mode 100644 registry-events/src/main/java/org/gbif/registry/events/collections/ChangedCollectionEntityComponentEvent.java create mode 100644 registry-events/src/main/java/org/gbif/registry/events/collections/CollectionsBaseEvent.java create mode 100644 registry-events/src/main/java/org/gbif/registry/events/collections/EventType.java create mode 100644 registry-events/src/main/java/org/gbif/registry/events/collections/ReplaceEntityEvent.java create mode 100644 registry-events/src/main/java/org/gbif/registry/events/collections/SubEntityCollectionEvent.java create mode 100644 registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/resource/CollectionsSearchResourceTest.java create mode 100644 registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/resource/LookupResourceTest.java create mode 100644 registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/PrimaryEntityMapper.java rename registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/{MergeableMapper.java => ReplaceableMapper.java} (95%) delete mode 100644 registry-search/src/main/java/org/gbif/registry/search/dataset/service/collections/CollectionsSearchResponse.java delete mode 100644 registry-service/src/main/java/org/gbif/registry/service/collections/audit/AuditLogger.java delete mode 100644 registry-service/src/main/java/org/gbif/registry/service/collections/audit/BaseEvent.java delete mode 100644 registry-service/src/main/java/org/gbif/registry/service/collections/audit/CreatedEntityEvent.java delete mode 100644 registry-service/src/main/java/org/gbif/registry/service/collections/audit/DeletedEntityEvent.java delete mode 100644 registry-service/src/main/java/org/gbif/registry/service/collections/audit/UpdatedEntityEvent.java create mode 100644 registry-ws-client/src/main/java/org/gbif/registry/ws/client/collections/CollectionsSearchClient.java create mode 100644 registry-ws-client/src/main/java/org/gbif/registry/ws/client/collections/LookupClient.java diff --git a/registry-events/pom.xml b/registry-events/pom.xml index b292e8a1f9..07769b22c3 100644 --- a/registry-events/pom.xml +++ b/registry-events/pom.xml @@ -46,13 +46,20 @@ org.gbif gbif-httputils - + + org.gbif.registry + registry-persistence + com.google.guava guava + + org.springframework.cloud + spring-cloud-starter-sleuth + diff --git a/registry-events/src/main/java/org/gbif/registry/events/VarnishPurgeListener.java b/registry-events/src/main/java/org/gbif/registry/events/VarnishPurgeListener.java index 611f3b0ee9..f4c5e0bd98 100644 --- a/registry-events/src/main/java/org/gbif/registry/events/VarnishPurgeListener.java +++ b/registry-events/src/main/java/org/gbif/registry/events/VarnishPurgeListener.java @@ -16,11 +16,10 @@ package org.gbif.registry.events; import org.gbif.api.model.collections.CollectionEntity; -import org.gbif.api.model.collections.Institution; +import org.gbif.api.model.collections.CollectionEntityType; import org.gbif.api.model.collections.Person; import org.gbif.api.model.collections.request.CollectionSearchRequest; import org.gbif.api.model.collections.request.InstitutionSearchRequest; -import org.gbif.api.model.collections.view.CollectionView; import org.gbif.api.model.registry.Dataset; import org.gbif.api.model.registry.Installation; import org.gbif.api.model.registry.NetworkEntity; @@ -32,15 +31,15 @@ import org.gbif.api.service.registry.InstallationService; import org.gbif.api.service.registry.OrganizationService; import org.gbif.registry.domain.ws.DerivedDataset; -import org.gbif.registry.events.collections.ChangedCollectionEntityComponentEvent; import org.gbif.registry.events.collections.CreateCollectionEntityEvent; import org.gbif.registry.events.collections.DeleteCollectionEntityEvent; +import org.gbif.registry.events.collections.SubEntityCollectionEvent; import org.gbif.registry.events.collections.UpdateCollectionEntityEvent; +import org.gbif.registry.persistence.mapper.collections.dto.ChangeSuggestionDto; import org.gbif.varnish.VarnishPurger; import java.net.URI; import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.UUID; @@ -111,8 +110,38 @@ *
  • derivedDataset/dataset/{doiPrefix}/{doiSuffix} BAN *
  • derivedDataset/user/{user} BAN * + *

    Institution

    + * + *

    Collection

    + * + *

    Person

    + * + *

    ChangeSuggestion

    + * */ -// TODO: documentation grscicoll +// TODO: clear grscicoll cache public class VarnishPurgeListener { private static final Logger LOG = LoggerFactory.getLogger(VarnishPurgeListener.class); @@ -206,47 +235,65 @@ public final void deleted(DeleteEvent event) { public final void createdCollection( CreateCollectionEntityEvent event) { purgeEntityAndBanLists( - path("grscicoll", event.getObjectClass().getSimpleName().toLowerCase()), + path("grscicoll", event.getCollectionEntityType().name().toLowerCase()), event.getNewObject().getKey()); - if (event.getObjectClass().equals(Person.class)) { + if (event.getCollectionEntityType() == CollectionEntityType.PERSON) { cascadePersonChange((Person) event.getNewObject()); } + + purger.ban("grscicoll/search"); } @Subscribe public final void updatedCollection( UpdateCollectionEntityEvent event) { purgeEntityAndBanLists( - path("grscicoll", event.getObjectClass().getSimpleName().toLowerCase()), + path("grscicoll", event.getCollectionEntityType().name().toLowerCase()), event.getOldObject().getKey()); - if (event.getObjectClass().equals(Person.class)) { - cascadePersonChange((Person) event.getOldObject(), (Person) event.getNewObject()); + if (event.getCollectionEntityType() == CollectionEntityType.PERSON) { + cascadePersonChange((Person) event.getOldObject()); } + + purger.ban("grscicoll/search"); } @Subscribe public final void deletedCollection( DeleteCollectionEntityEvent event) { purgeEntityAndBanLists( - path("grscicoll", event.getObjectClass().getSimpleName().toLowerCase()), + path("grscicoll", event.getCollectionEntityType().name().toLowerCase()), event.getOldObject().getKey()); - if (event.getObjectClass().equals(Person.class)) { + if (event.getCollectionEntityType() == CollectionEntityType.PERSON) { cascadePersonChange((Person) event.getOldObject()); } + + purger.ban("grscicoll/search"); } @Subscribe - public final void collectionEntityComponentChange(ChangedCollectionEntityComponentEvent event) { - purgeEntityAndBanLists( - path("grscicoll", event.getTargetClass().getSimpleName().toLowerCase()), - event.getTargetEntityKey()); + public final void collectionSubEntityChange( + SubEntityCollectionEvent event) { + if (event.getSubEntityClass().equals(ChangeSuggestionDto.class)) { + purgeEntityAndBanLists( + path( + "grscicoll", + event.getCollectionEntityType().name().toLowerCase(), + "changeSuggestion"), + event.getSubEntityKey()); + } else { + purgeEntityAndBanLists( + path("grscicoll", event.getCollectionEntityType().name().toLowerCase()), + event.getCollectionEntityKey()); + } - if (event.getTargetClass().equals(Person.class)) { - cascadePersonChange(personService.get(event.getTargetEntityKey())); + if (event.getCollectionEntityType() == CollectionEntityType.PERSON) { + cascadePersonChange(personService.get(event.getCollectionEntityKey())); } + + purger.ban("grscicoll/search"); } @Subscribe @@ -325,21 +372,17 @@ private void cascadeInstallationChange(Installation... installations) { private void cascadePersonChange(Person... persons) { Set collectionKeys = new UUIDHashSet(); - for (Person p : persons) { - List collections = - collectionService - .list(CollectionSearchRequest.builder().contact(p.getKey()).build()) - .getResults(); - collections.forEach(c -> collectionKeys.add(c.getCollection().getKey())); - } - Set institutionKeys = new UUIDHashSet(); for (Person p : persons) { - List institutions = - institutionService - .list(InstitutionSearchRequest.builder().contact(p.getKey()).build()) - .getResults(); - institutions.forEach(i -> institutionKeys.add(i.getKey())); + collectionService + .list(CollectionSearchRequest.builder().contact(p.getKey()).build()) + .getResults() + .forEach(c -> collectionKeys.add(c.getCollection().getKey())); + + institutionService + .list(InstitutionSearchRequest.builder().contact(p.getKey()).build()) + .getResults() + .forEach(i -> institutionKeys.add(i.getKey())); } // /collection/{collectionKey}/contact BAN @@ -362,15 +405,23 @@ private void cascadeDerivedDatasetChange(DerivedDataset derivedDataset) { * check which entity class was supplied, but as it is some type of NetworkEntity we deal with the * right urls. */ - private void purgeEntityAndBanLists(String rootPath, UUID key) { + private void purgeEntityAndBanLists(String rootPath, String entityPath) { // purge entity detail - purger.purge(path(rootPath, key)); + purger.purge(entityPath); // banRegex lists and searches purger.ban(String.format("%s(/search|/suggest)?[^/]*$", rootPath)); } + private void purgeEntityAndBanLists(String rootPath, UUID key) { + purgeEntityAndBanLists(rootPath, path(rootPath, key)); + } + + private void purgeEntityAndBanLists(String rootPath, int key) { + purgeEntityAndBanLists(rootPath, path(rootPath, key)); + } + private void purgeEntityAndBanLists(Class cl, UUID key) { purgeEntityAndBanLists(path(cl.getSimpleName().toLowerCase()), key); } diff --git a/registry-events/src/main/java/org/gbif/registry/events/collections/AuditLogger.java b/registry-events/src/main/java/org/gbif/registry/events/collections/AuditLogger.java new file mode 100644 index 0000000000..428cd63ec4 --- /dev/null +++ b/registry-events/src/main/java/org/gbif/registry/events/collections/AuditLogger.java @@ -0,0 +1,115 @@ +package org.gbif.registry.events.collections; + +import org.gbif.api.model.collections.CollectionEntity; +import org.gbif.registry.persistence.mapper.collections.AuditLogMapper; +import org.gbif.registry.persistence.mapper.collections.dto.AuditLogDto; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.event.EventListener; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import brave.Tracer; + +// TODO: listeners que sean @Async?? luego poner @EnableAsync en Application + +@Component +public class AuditLogger { + + private final Tracer tracer; + private final AuditLogMapper auditLogMapper; + private final ObjectMapper objectMapper; + + @Autowired + public AuditLogger(Tracer tracer, AuditLogMapper auditLogMapper, ObjectMapper objectMapper) { + this.tracer = tracer; + this.auditLogMapper = auditLogMapper; + this.objectMapper = objectMapper; + } + + @EventListener + public void logCreatedEvents(CreateCollectionEntityEvent event) { + AuditLogDto dto = collectionBaseEventToDto(event); + dto.setCollectionEntityKey(event.getNewObject().getKey()); + dto.setPostState(toJson(event.getNewObject())); + auditLogMapper.create(dto); + } + + @EventListener + public void logUpdatedEvents(UpdateCollectionEntityEvent event) { + AuditLogDto dto = collectionBaseEventToDto(event); + dto.setCollectionEntityKey(event.getNewObject().getKey()); + dto.setPreState(toJson(event.getOldObject())); + dto.setPostState(toJson(event.getNewObject())); + auditLogMapper.create(dto); + } + + @EventListener + public void logDeletedEvents(DeleteCollectionEntityEvent event) { + AuditLogDto dto = collectionBaseEventToDto(event); + dto.setCollectionEntityKey(event.getOldObject().getKey()); + dto.setPreState(toJson(event.getOldObject())); + dto.setPostState(toJson(event.getDeletedObject())); + auditLogMapper.create(dto); + } + + @EventListener + public void logReplacedEvents(ReplaceEntityEvent event) { + AuditLogDto dto = collectionBaseEventToDto(event); + dto.setCollectionEntityKey(event.getTargetEntityKey()); + dto.setReplacementKey(event.getReplacementKey()); + auditLogMapper.create(dto); + } + + @EventListener + public void logSubEntityEvents( + SubEntityCollectionEvent event) { + AuditLogDto dto = subEntityToDto(event); + auditLogMapper.create(dto); + } + + private AuditLogDto subEntityToDto( + SubEntityCollectionEvent event) { + AuditLogDto dto = collectionBaseEventToDto(event); + dto.setSubEntityType(event.getSubEntity().getClass().getSimpleName()); + dto.setCollectionEntityKey(event.getCollectionEntityKey()); + dto.setSubEntityKey(event.getSubEntityKey()); + + if (event.getEventType() == EventType.CREATE) { + dto.setPostState(toJson(event.getSubEntity())); + } else if (event.getEventType() == EventType.DELETE) { + dto.setPreState(toJson(event.getSubEntity())); + } + + return dto; + } + + private AuditLogDto collectionBaseEventToDto( + CollectionsBaseEvent event) { + AuditLogDto dto = new AuditLogDto(); + dto.setTraceId(tracer.currentSpan().context().traceId()); + dto.setCollectionEntityType(event.getCollectionEntityType()); + dto.setOperation(event.getEventType().name()); + dto.setCreatedBy(getUsername()); + return dto; + } + + // TODO: getusername y toJson deberian ir a una clase de utils ya q lo uso en changeSuggestion tb + + protected String getUsername() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + return authentication.getName(); + } + + protected String toJson(Object entity) { + try { + return objectMapper.writeValueAsString(entity); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException("Cannot serialize entity", e); + } + } +} diff --git a/registry-events/src/main/java/org/gbif/registry/events/collections/ChangedCollectionEntityComponentEvent.java b/registry-events/src/main/java/org/gbif/registry/events/collections/ChangedCollectionEntityComponentEvent.java deleted file mode 100644 index fb9d506076..0000000000 --- a/registry-events/src/main/java/org/gbif/registry/events/collections/ChangedCollectionEntityComponentEvent.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2020 Global Biodiversity Information Facility (GBIF) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gbif.registry.events.collections; - -import java.util.UUID; - -import com.google.common.base.Preconditions; - -/** - * This event is fired after collection entity components such as contacts, identifiers or tags have - * been successfully updated, added or removed. - */ -public class ChangedCollectionEntityComponentEvent { - - private final UUID targetEntityKey; - private final Class targetClass; - private final Class componentClass; - - public static ChangedCollectionEntityComponentEvent newInstance( - UUID targetEntityKey, Class targetClass, Class componentClass) { - return new ChangedCollectionEntityComponentEvent(targetEntityKey, targetClass, componentClass); - } - - private ChangedCollectionEntityComponentEvent( - UUID targetEntityKey, Class targetClass, Class componentClass) { - this.targetEntityKey = Preconditions.checkNotNull(targetEntityKey); - this.targetClass = Preconditions.checkNotNull(targetClass); - this.componentClass = Preconditions.checkNotNull(componentClass); - } - - public UUID getTargetEntityKey() { - return targetEntityKey; - } - - public Class getTargetClass() { - return targetClass; - } - - public Class getComponentClass() { - return componentClass; - } -} diff --git a/registry-events/src/main/java/org/gbif/registry/events/collections/CollectionsBaseEvent.java b/registry-events/src/main/java/org/gbif/registry/events/collections/CollectionsBaseEvent.java new file mode 100644 index 0000000000..c168ce1473 --- /dev/null +++ b/registry-events/src/main/java/org/gbif/registry/events/collections/CollectionsBaseEvent.java @@ -0,0 +1,39 @@ +package org.gbif.registry.events.collections; + +import org.gbif.api.model.collections.Collection; +import org.gbif.api.model.collections.CollectionEntity; +import org.gbif.api.model.collections.CollectionEntityType; +import org.gbif.api.model.collections.Institution; +import org.gbif.api.model.collections.Person; + +abstract class CollectionsBaseEvent { + + protected final Class collectionEntityClass; + protected final EventType eventType; + + protected CollectionsBaseEvent(EventType eventType, Class collectionEntityClass) { + this.eventType = eventType; + this.collectionEntityClass = collectionEntityClass; + } + + public Class getCollectionEntityClass() { + return collectionEntityClass; + } + + public EventType getEventType() { + return eventType; + } + + public CollectionEntityType getCollectionEntityType() { + if (collectionEntityClass.equals(Institution.class)) { + return CollectionEntityType.INSTITUTION; + } else if (collectionEntityClass.equals(Collection.class)) { + return CollectionEntityType.COLLECTION; + } else if (collectionEntityClass.equals(Person.class)) { + return CollectionEntityType.PERSON; + } + + throw new IllegalArgumentException( + "Entity type not supported: " + collectionEntityClass.getSimpleName()); + } +} diff --git a/registry-events/src/main/java/org/gbif/registry/events/collections/CreateCollectionEntityEvent.java b/registry-events/src/main/java/org/gbif/registry/events/collections/CreateCollectionEntityEvent.java index f3f13124e5..85f5b68076 100644 --- a/registry-events/src/main/java/org/gbif/registry/events/collections/CreateCollectionEntityEvent.java +++ b/registry-events/src/main/java/org/gbif/registry/events/collections/CreateCollectionEntityEvent.java @@ -20,26 +20,22 @@ import static com.google.common.base.Preconditions.checkNotNull; /** This event is fired after a new collection entity has been successfully created. */ -public class CreateCollectionEntityEvent { +public class CreateCollectionEntityEvent + extends CollectionsBaseEvent { private final T newObject; - private final Class objectClass; public static CreateCollectionEntityEvent newInstance( - T newObject, Class objectClass) { - return new CreateCollectionEntityEvent<>(newObject, objectClass); + T newObject) { + return new CreateCollectionEntityEvent<>(newObject, (Class) newObject.getClass()); } - private CreateCollectionEntityEvent(T newObject, Class objectClass) { + private CreateCollectionEntityEvent(T newObject, Class collectionEntityClass) { + super(EventType.CREATE, collectionEntityClass); this.newObject = checkNotNull(newObject, "newObject can't be null"); - this.objectClass = checkNotNull(objectClass, "objectClass can't be null"); } public T getNewObject() { return newObject; } - - public Class getObjectClass() { - return objectClass; - } } diff --git a/registry-events/src/main/java/org/gbif/registry/events/collections/DeleteCollectionEntityEvent.java b/registry-events/src/main/java/org/gbif/registry/events/collections/DeleteCollectionEntityEvent.java index 0fcb7c7b08..276b2669a3 100644 --- a/registry-events/src/main/java/org/gbif/registry/events/collections/DeleteCollectionEntityEvent.java +++ b/registry-events/src/main/java/org/gbif/registry/events/collections/DeleteCollectionEntityEvent.java @@ -18,26 +18,30 @@ import org.gbif.api.model.collections.CollectionEntity; /** This event is fired after a new collection entity has been successfully deleted. */ -public class DeleteCollectionEntityEvent { +public class DeleteCollectionEntityEvent + extends CollectionsBaseEvent { private final T oldObject; - private final Class objectClass; + private final T deletedObject; public static DeleteCollectionEntityEvent newInstance( - T oldObject, Class objectClass) { - return new DeleteCollectionEntityEvent<>(oldObject, objectClass); + T oldObject, T deletedObject) { + return new DeleteCollectionEntityEvent<>( + oldObject, deletedObject, (Class) oldObject.getClass()); } - private DeleteCollectionEntityEvent(T oldObject, Class objectClass) { + private DeleteCollectionEntityEvent( + T oldObject, T deletedObject, Class collectionEntityClass) { + super(EventType.DELETE, collectionEntityClass); this.oldObject = oldObject; - this.objectClass = objectClass; + this.deletedObject = deletedObject; } public T getOldObject() { return oldObject; } - public Class getObjectClass() { - return objectClass; + public T getDeletedObject() { + return deletedObject; } } diff --git a/registry-events/src/main/java/org/gbif/registry/events/collections/EventType.java b/registry-events/src/main/java/org/gbif/registry/events/collections/EventType.java new file mode 100644 index 0000000000..8ee779a143 --- /dev/null +++ b/registry-events/src/main/java/org/gbif/registry/events/collections/EventType.java @@ -0,0 +1,13 @@ +package org.gbif.registry.events.collections; + +public enum EventType { + CREATE, + UPDATE, + DELETE, + LINK, + UNLINK, + REPLACE, + CONVERSION_TO_COLLECTION, + APPLY_SUGGESTION, + DISCARD_SUGGESTION; +} diff --git a/registry-events/src/main/java/org/gbif/registry/events/collections/ReplaceEntityEvent.java b/registry-events/src/main/java/org/gbif/registry/events/collections/ReplaceEntityEvent.java new file mode 100644 index 0000000000..54e52ec1e0 --- /dev/null +++ b/registry-events/src/main/java/org/gbif/registry/events/collections/ReplaceEntityEvent.java @@ -0,0 +1,38 @@ +package org.gbif.registry.events.collections; + +import org.gbif.api.model.collections.CollectionEntity; + +import java.util.UUID; + +public class ReplaceEntityEvent extends CollectionsBaseEvent { + + private final UUID targetEntityKey; + private final UUID replacementKey; + + public static ReplaceEntityEvent newInstance( + Class collectionEntityClass, + UUID targetEntityKey, + UUID replacementKey, + EventType eventType) { + return new ReplaceEntityEvent<>( + collectionEntityClass, targetEntityKey, replacementKey, eventType); + } + + private ReplaceEntityEvent( + Class collectionEntityClass, + UUID targetEntityKey, + UUID replacementKey, + EventType eventType) { + super(eventType, collectionEntityClass); + this.targetEntityKey = targetEntityKey; + this.replacementKey = replacementKey; + } + + public UUID getTargetEntityKey() { + return targetEntityKey; + } + + public UUID getReplacementKey() { + return replacementKey; + } +} diff --git a/registry-events/src/main/java/org/gbif/registry/events/collections/SubEntityCollectionEvent.java b/registry-events/src/main/java/org/gbif/registry/events/collections/SubEntityCollectionEvent.java new file mode 100644 index 0000000000..823aebd132 --- /dev/null +++ b/registry-events/src/main/java/org/gbif/registry/events/collections/SubEntityCollectionEvent.java @@ -0,0 +1,96 @@ +/* + * Copyright 2020 Global Biodiversity Information Facility (GBIF) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gbif.registry.events.collections; + +import org.gbif.api.model.collections.CollectionEntity; + +import java.util.UUID; + +import com.google.common.base.Preconditions; + +/** + * This event is fired after collection entity components such as contacts, identifiers or tags have + * been successfully updated, added or removed. + */ +public class SubEntityCollectionEvent + extends CollectionsBaseEvent { + + private final UUID collectionEntityKey; + private final Class subEntityClass; + // it's a string so we can use uuids and integer keys + private final String subEntityKey; + private final R subEntity; + + public static SubEntityCollectionEvent newInstance( + UUID collectionEntityKey, + Class collectionEntityClass, + Class subEntityClass, + UUID subEntityKey, + EventType eventType) { + return new SubEntityCollectionEvent<>( + collectionEntityKey, + collectionEntityClass, + subEntityClass, + null, + subEntityKey.toString(), + eventType); + } + + public static SubEntityCollectionEvent newInstance( + UUID collectionEntityKey, + Class collectionEntityClass, + R subEntity, + int subEntityKey, + EventType eventType) { + return new SubEntityCollectionEvent<>( + collectionEntityKey, + collectionEntityClass, + (Class) subEntity.getClass(), + subEntity, + String.valueOf(subEntityKey), + eventType); + } + + private SubEntityCollectionEvent( + UUID collectionEntityKey, + Class collectionEntityClass, + Class subEntityClass, + R subEntity, + String subEntityKey, + EventType eventType) { + super(eventType, collectionEntityClass); + this.collectionEntityKey = Preconditions.checkNotNull(collectionEntityKey); + this.subEntityClass = Preconditions.checkNotNull(subEntityClass); + this.subEntity = subEntity; + this.subEntityKey = Preconditions.checkNotNull(subEntityKey); + } + + public UUID getCollectionEntityKey() { + return collectionEntityKey; + } + + public Class getSubEntityClass() { + return subEntityClass; + } + + public R getSubEntity() { + return subEntity; + } + + public String getSubEntityKey() { + return subEntityKey; + } +} diff --git a/registry-events/src/main/java/org/gbif/registry/events/collections/UpdateCollectionEntityEvent.java b/registry-events/src/main/java/org/gbif/registry/events/collections/UpdateCollectionEntityEvent.java index 5b16d867c9..1d475f75c8 100644 --- a/registry-events/src/main/java/org/gbif/registry/events/collections/UpdateCollectionEntityEvent.java +++ b/registry-events/src/main/java/org/gbif/registry/events/collections/UpdateCollectionEntityEvent.java @@ -18,21 +18,21 @@ import org.gbif.api.model.collections.CollectionEntity; /** This event is fired after a new collection entity has been successfully updated. */ -public class UpdateCollectionEntityEvent { +public class UpdateCollectionEntityEvent + extends CollectionsBaseEvent { private final T newObject; private final T oldObject; - private final Class objectClass; public static UpdateCollectionEntityEvent newInstance( - T newObject, T oldObject, Class objectClass) { - return new UpdateCollectionEntityEvent<>(newObject, oldObject, objectClass); + T newObject, T oldObject) { + return new UpdateCollectionEntityEvent<>(newObject, oldObject, (Class) newObject.getClass()); } - private UpdateCollectionEntityEvent(T newObject, T oldObject, Class objectClass) { + private UpdateCollectionEntityEvent(T newObject, T oldObject, Class collectionEntityClass) { + super(EventType.UPDATE, collectionEntityClass); this.newObject = newObject; this.oldObject = oldObject; - this.objectClass = objectClass; } public T getNewObject() { @@ -42,8 +42,4 @@ public T getNewObject() { public T getOldObject() { return oldObject; } - - public Class getObjectClass() { - return objectClass; - } } diff --git a/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/resource/CollectionResourceIT.java b/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/resource/CollectionResourceIT.java index 17dbd6f377..ad58b86faf 100644 --- a/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/resource/CollectionResourceIT.java +++ b/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/resource/CollectionResourceIT.java @@ -116,8 +116,6 @@ public void listDeletedTest() { assertEquals(views.size(), result.getResults().size()); } - // TODO: suggestions - @Override protected PrimaryCollectionEntityService getMockPrimaryEntityService() { return collectionService; diff --git a/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/resource/CollectionsSearchResourceTest.java b/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/resource/CollectionsSearchResourceTest.java new file mode 100644 index 0000000000..009b8ea0b5 --- /dev/null +++ b/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/resource/CollectionsSearchResourceTest.java @@ -0,0 +1,63 @@ +package org.gbif.registry.ws.it.collections.resource; + +import org.gbif.api.model.collections.search.CollectionsSearchResponse; +import org.gbif.registry.search.dataset.service.collections.CollectionsSearchService; +import org.gbif.registry.search.test.EsManageServer; +import org.gbif.registry.ws.client.collections.CollectionsSearchClient; +import org.gbif.registry.ws.it.fixtures.RequestTestFixture; +import org.gbif.registry.ws.it.fixtures.TestConstants; +import org.gbif.ws.client.filter.SimplePrincipalProvider; + +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.web.server.LocalServerPort; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +public class CollectionsSearchResourceTest extends BaseResourceIT { + + @MockBean private CollectionsSearchService collectionsSearchService; + + private final CollectionsSearchClient collectionsSearchClient; + + @Autowired + public CollectionsSearchResourceTest( + SimplePrincipalProvider simplePrincipalProvider, + EsManageServer esServer, + RequestTestFixture requestTestFixture, + @LocalServerPort int localServerPort) { + super(simplePrincipalProvider, esServer, requestTestFixture); + this.collectionsSearchClient = + prepareClient( + TestConstants.TEST_GRSCICOLL_ADMIN, localServerPort, CollectionsSearchClient.class); + } + + @Test + public void searchTest() { + String q = "foo"; + boolean highlight = true; + int limit = 10; + + CollectionsSearchResponse response = new CollectionsSearchResponse(); + response.setCode("c1"); + response.setInstitutionKey(UUID.randomUUID()); + CollectionsSearchResponse.Match match = new CollectionsSearchResponse.Match(); + match.setField("field1"); + match.setSnippet("snippet"); + response.setMatches(Collections.singleton(match)); + + when(collectionsSearchService.search(q, highlight, limit)) + .thenReturn(Collections.singletonList(response)); + + List responseReturned = + collectionsSearchClient.searchCollections(q, highlight, limit); + assertEquals(1, responseReturned.size()); + assertEquals(response, responseReturned.get(0)); + } +} diff --git a/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/resource/LookupResourceTest.java b/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/resource/LookupResourceTest.java new file mode 100644 index 0000000000..c233f46f72 --- /dev/null +++ b/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/resource/LookupResourceTest.java @@ -0,0 +1,109 @@ +package org.gbif.registry.ws.it.collections.resource; + +import org.gbif.api.model.collections.lookup.AlternativeMatches; +import org.gbif.api.model.collections.lookup.CollectionMatched; +import org.gbif.api.model.collections.lookup.InstitutionMatched; +import org.gbif.api.model.collections.lookup.LookupParams; +import org.gbif.api.model.collections.lookup.LookupResult; +import org.gbif.api.model.collections.lookup.Match; +import org.gbif.api.vocabulary.Country; +import org.gbif.registry.search.test.EsManageServer; +import org.gbif.registry.service.collections.lookup.LookupService; +import org.gbif.registry.ws.client.collections.LookupClient; +import org.gbif.registry.ws.it.fixtures.RequestTestFixture; +import org.gbif.registry.ws.it.fixtures.TestConstants; +import org.gbif.ws.client.filter.SimplePrincipalProvider; + +import java.net.URI; +import java.util.Collections; +import java.util.UUID; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.web.server.LocalServerPort; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +public class LookupResourceTest extends BaseResourceIT { + + @MockBean private LookupService lookupService; + + private final LookupClient lookupClient; + + @Autowired + public LookupResourceTest( + SimplePrincipalProvider simplePrincipalProvider, + EsManageServer esServer, + RequestTestFixture requestTestFixture, + @LocalServerPort int localServerPort) { + super(simplePrincipalProvider, esServer, requestTestFixture); + this.lookupClient = + prepareClient(TestConstants.TEST_GRSCICOLL_ADMIN, localServerPort, LookupClient.class); + } + + @Test + public void lookupTest() { + UUID datasetKey = UUID.randomUUID(); + String institutionCode = "i1"; + String institutionId = "iid1"; + String ownerInstitutionCode = "owner"; + String collectionCode = "c1"; + String collectionId = "cid1"; + Country country = Country.DENMARK; + boolean verbose = true; + + LookupParams params = new LookupParams(); + params.setDatasetKey(datasetKey); + params.setInstitutionCode(institutionCode); + params.setInstitutionId(institutionId); + params.setOwnerInstitutionCode(ownerInstitutionCode); + params.setCollectionCode(collectionCode); + params.setCollectionId(collectionId); + params.setCountry(country); + params.setVerbose(verbose); + + LookupResult result = new LookupResult(); + InstitutionMatched institutionMatched = new InstitutionMatched(); + institutionMatched.setCode("c1"); + institutionMatched.setName("n1"); + institutionMatched.setActive(true); + institutionMatched.setSelfLink(URI.create("http://test.com")); + result.setInstitutionMatch(Match.exact(institutionMatched, Match.Reason.CODE_MATCH)); + + CollectionMatched collectionMatched = new CollectionMatched(); + collectionMatched.setCode("c2"); + collectionMatched.setName("n2"); + collectionMatched.setActive(true); + collectionMatched.setSelfLink(URI.create("http://test2.com")); + result.setCollectionMatch(Match.exact(collectionMatched, Match.Reason.CODE_MATCH)); + + AlternativeMatches alternativeMatches = new AlternativeMatches(); + alternativeMatches.setInstitutionMatches( + Collections.singletonList(result.getInstitutionMatch())); + alternativeMatches.setCollectionMatches(Collections.singletonList(result.getCollectionMatch())); + result.setAlternativeMatches(alternativeMatches); + + when(lookupService.lookup(params)).thenReturn(result); + + LookupResult resultReturned = + lookupClient.lookup( + datasetKey, + institutionCode, + institutionId, + ownerInstitutionCode, + collectionCode, + collectionId, + country, + verbose); + assertEquals(result.getInstitutionMatch(), resultReturned.getInstitutionMatch()); + assertEquals(result.getCollectionMatch(), resultReturned.getCollectionMatch()); + assertEquals( + result.getAlternativeMatches().getInstitutionMatches(), + resultReturned.getAlternativeMatches().getInstitutionMatches()); + assertEquals( + result.getAlternativeMatches().getCollectionMatches(), + resultReturned.getAlternativeMatches().getCollectionMatches()); + } +} diff --git a/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/BaseServiceIT.java b/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/BaseServiceIT.java index 529972d9e1..bd9cd53028 100644 --- a/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/BaseServiceIT.java +++ b/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/BaseServiceIT.java @@ -25,10 +25,10 @@ import java.sql.SQLException; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; +import java.util.stream.Collectors; import java.util.stream.Stream; import javax.sql.DataSource; @@ -164,15 +164,19 @@ public void setup() { } } - protected void resetSecurityContext(String principal, UserRole role) { + protected void resetSecurityContext(String principal, UserRole... role) { simplePrincipalProvider.setPrincipal(principal); SecurityContext ctx = SecurityContextHolder.createEmptyContext(); SecurityContextHolder.setContext(ctx); + List authorities = + Arrays.stream(role) + .map(r -> new SimpleGrantedAuthority(r.name())) + .collect(Collectors.toList()); + ; + ctx.setAuthentication( new UsernamePasswordAuthenticationToken( - simplePrincipalProvider.get().getName(), - "", - Collections.singleton(new SimpleGrantedAuthority(role.name())))); + simplePrincipalProvider.get().getName(), "", authorities)); } public SimplePrincipalProvider getSimplePrincipalProvider() { diff --git a/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/CollectionsSearchIT.java b/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/CollectionsSearchIT.java index fac08c31fa..3b4e0aa564 100644 --- a/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/CollectionsSearchIT.java +++ b/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/CollectionsSearchIT.java @@ -19,13 +19,13 @@ import org.gbif.api.model.collections.AlternativeCode; import org.gbif.api.model.collections.Collection; import org.gbif.api.model.collections.Institution; +import org.gbif.api.model.collections.search.CollectionsSearchResponse; import org.gbif.api.model.registry.Identifier; import org.gbif.api.service.collections.CollectionService; import org.gbif.api.service.collections.InstitutionService; import org.gbif.api.vocabulary.Country; import org.gbif.api.vocabulary.IdentifierType; import org.gbif.registry.database.TestCaseDatabaseInitializer; -import org.gbif.registry.search.dataset.service.collections.CollectionsSearchResponse; import org.gbif.registry.search.dataset.service.collections.CollectionsSearchService; import org.gbif.registry.search.test.EsManageServer; import org.gbif.ws.client.filter.SimplePrincipalProvider; diff --git a/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/merge/BaseMergeServiceIT.java b/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/merge/BaseMergeServiceIT.java index e6414788fb..fe726ec3eb 100644 --- a/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/merge/BaseMergeServiceIT.java +++ b/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/merge/BaseMergeServiceIT.java @@ -51,7 +51,6 @@ import org.gbif.api.vocabulary.UserRole; import org.gbif.registry.search.test.EsManageServer; import org.gbif.registry.service.collections.merge.MergeService; -import org.gbif.registry.ws.it.BaseItTest; import org.gbif.registry.ws.it.collections.service.BaseServiceIT; import org.gbif.ws.client.filter.SimplePrincipalProvider; @@ -61,7 +60,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.test.context.support.WithMockUser; -import static org.gbif.registry.domain.collections.Constants.*; +import static org.gbif.registry.domain.collections.Constants.IDIGBIO_NAMESPACE; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -74,7 +73,7 @@ public abstract class BaseMergeServiceIT< & Taggable & Commentable> extends BaseServiceIT { - protected final MergeService mergeService; + protected final MergeService mergeService; protected final CrudService crudService; protected final IdentifierService identifierService; protected final ContactService contactService; @@ -90,7 +89,7 @@ public abstract class BaseMergeServiceIT< public BaseMergeServiceIT( SimplePrincipalProvider simplePrincipalProvider, EsManageServer esServer, - MergeService mergeService, + MergeService mergeService, CrudService crudService, IdentifierService identifierService, ContactService contactService, @@ -215,7 +214,7 @@ public void preconditionsTest() { IllegalArgumentException.class, () -> mergeService.merge(e1.getKey(), e2.getKey())); // if the user has the idigbio role we can merge them - resetSecurityContext("idigibo", UserRole.IDIGBIO_GRSCICOLL_EDITOR); + resetSecurityContext("idigibo", UserRole.IDIGBIO_GRSCICOLL_EDITOR, UserRole.GRSCICOLL_ADMIN); assertDoesNotThrow(() -> mergeService.merge(e1.getKey(), e2.getKey())); } diff --git a/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/merge/InstitutionMergeServiceIT.java b/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/merge/InstitutionMergeServiceIT.java index 8b8be47652..871c1406d2 100644 --- a/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/merge/InstitutionMergeServiceIT.java +++ b/registry-integration-tests/src/test/java/org/gbif/registry/ws/it/collections/service/merge/InstitutionMergeServiceIT.java @@ -36,7 +36,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import static org.gbif.registry.domain.collections.Constants.*; +import static org.gbif.registry.domain.collections.Constants.IDIGBIO_NAMESPACE; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -208,7 +208,7 @@ public void convertIDigBioInstitution() { IllegalArgumentException.class, () -> institutionMergeService.convertToCollection(toConvert.getKey(), null, "test")); - resetSecurityContext("idigibo", UserRole.IDIGBIO_GRSCICOLL_EDITOR); + resetSecurityContext("idigibo", UserRole.IDIGBIO_GRSCICOLL_EDITOR, UserRole.GRSCICOLL_ADMIN); assertDoesNotThrow( () -> institutionMergeService.convertToCollection(toConvert.getKey(), null, "test")); } diff --git a/registry-mail/src/main/java/org/gbif/registry/mail/collections/CollectionsEmailManager.java b/registry-mail/src/main/java/org/gbif/registry/mail/collections/CollectionsEmailManager.java index 51968f72f3..976728c791 100644 --- a/registry-mail/src/main/java/org/gbif/registry/mail/collections/CollectionsEmailManager.java +++ b/registry-mail/src/main/java/org/gbif/registry/mail/collections/CollectionsEmailManager.java @@ -1,6 +1,6 @@ package org.gbif.registry.mail.collections; -import org.gbif.api.model.collections.EntityType; +import org.gbif.api.model.collections.CollectionEntityType; import org.gbif.registry.domain.mail.GrscicollChangeSuggestionDataModel; import org.gbif.registry.mail.BaseEmailModel; import org.gbif.registry.mail.EmailTemplateProcessor; @@ -37,25 +37,26 @@ public CollectionsEmailManager( } public BaseEmailModel generateNewChangeSuggestionEmailModel( - int suggestionKey, EntityType entityType) throws IOException { + int suggestionKey, CollectionEntityType collectionEntityType) throws IOException { return buildBaseEmailModel( - suggestionKey, entityType, CollectionsEmailType.NEW_CHANGE_SUGGESTION); + suggestionKey, collectionEntityType, CollectionsEmailType.NEW_CHANGE_SUGGESTION); } public BaseEmailModel generateAppliedChangeSuggestionEmailModel( - int suggestionKey, EntityType entityType) throws IOException { + int suggestionKey, CollectionEntityType collectionEntityType) throws IOException { return buildBaseEmailModel( - suggestionKey, entityType, CollectionsEmailType.APPLIED_CHANGE_SUGGESTION); + suggestionKey, collectionEntityType, CollectionsEmailType.APPLIED_CHANGE_SUGGESTION); } public BaseEmailModel generateDiscardedChangeSuggestionEmailModel( - int suggestionKey, EntityType entityType) throws IOException { + int suggestionKey, CollectionEntityType collectionEntityType) throws IOException { return buildBaseEmailModel( - suggestionKey, entityType, CollectionsEmailType.DISCARDED_CHANGE_SUGGESTION); + suggestionKey, collectionEntityType, CollectionsEmailType.DISCARDED_CHANGE_SUGGESTION); } private BaseEmailModel buildBaseEmailModel( - int suggestionKey, EntityType entityType, CollectionsEmailType emailType) throws IOException { + int suggestionKey, CollectionEntityType entityType, CollectionsEmailType emailType) + throws IOException { BaseEmailModel baseEmailModel; try { URL suggestionUrl = diff --git a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/CommentMapper.java b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/CommentMapper.java index d4796bc8c7..470b8fe88f 100644 --- a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/CommentMapper.java +++ b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/CommentMapper.java @@ -17,10 +17,13 @@ import org.gbif.api.model.registry.Comment; +import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; @Repository public interface CommentMapper { int createComment(Comment comment); + + Comment get(@Param("key") int key); } diff --git a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/IdentifierMapper.java b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/IdentifierMapper.java index e11b3ac6c6..6a5336dec2 100644 --- a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/IdentifierMapper.java +++ b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/IdentifierMapper.java @@ -35,4 +35,6 @@ List list( @Nullable @Param("type") IdentifierType type, @Nullable @Param("identifier") String identifier, @Nullable @Param("page") Pageable page); + + Identifier get(@Param("key") int key); } diff --git a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/TagMapper.java b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/TagMapper.java index 58ac1560d7..478732e976 100644 --- a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/TagMapper.java +++ b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/TagMapper.java @@ -17,10 +17,13 @@ import org.gbif.api.model.registry.Tag; +import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; @Repository public interface TagMapper { int createTag(Tag tag); + + Tag get(@Param("key") int key); } diff --git a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/ChangeSuggestionMapper.java b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/ChangeSuggestionMapper.java index e1f5b43f72..4e23bef4b4 100644 --- a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/ChangeSuggestionMapper.java +++ b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/ChangeSuggestionMapper.java @@ -1,6 +1,6 @@ package org.gbif.registry.persistence.mapper.collections; -import org.gbif.api.model.collections.EntityType; +import org.gbif.api.model.collections.CollectionEntityType; import org.gbif.api.model.collections.suggestions.Status; import org.gbif.api.model.collections.suggestions.Type; import org.gbif.api.model.common.paging.Pageable; @@ -25,7 +25,7 @@ public interface ChangeSuggestionMapper { List list( @Param("status") Status status, @Param("type") Type type, - @Param("entityType") EntityType entityType, + @Param("entityType") CollectionEntityType collectionEntityType, @Param("country") Country country, @Param("proposer") String proposer, @Param("entityKey") UUID entityKey, @@ -34,7 +34,7 @@ List list( long count( @Param("status") Status status, @Param("type") Type type, - @Param("entityType") EntityType entityType, + @Param("entityType") CollectionEntityType collectionEntityType, @Param("country") Country country, @Param("proposer") String proposer, @Param("entityKey") UUID entityKey); diff --git a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/CollectionMapper.java b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/CollectionMapper.java index 2df81c93d7..bcaa564873 100644 --- a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/CollectionMapper.java +++ b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/CollectionMapper.java @@ -18,7 +18,6 @@ import org.gbif.api.model.collections.Collection; import org.gbif.api.model.common.paging.Pageable; import org.gbif.api.model.registry.search.collections.KeyCodeNameResult; -import org.gbif.registry.persistence.ContactableMapper; import org.gbif.registry.persistence.mapper.collections.dto.CollectionDto; import org.gbif.registry.persistence.mapper.collections.dto.CollectionMatchedDto; import org.gbif.registry.persistence.mapper.collections.params.CollectionSearchParams; @@ -34,11 +33,7 @@ /** Mapper for {@link Collection} entities. */ @Repository public interface CollectionMapper - extends BaseMapper, - ContactableMapper, - LookupMapper, - OccurrenceMappeableMapper, - MergeableMapper { + extends PrimaryEntityMapper, LookupMapper { List list( @Param("params") CollectionSearchParams searchParams, @Nullable @Param("page") Pageable page); diff --git a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/InstitutionMapper.java b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/InstitutionMapper.java index ce540c032d..6f1cd28915 100644 --- a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/InstitutionMapper.java +++ b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/InstitutionMapper.java @@ -18,7 +18,6 @@ import org.gbif.api.model.collections.Institution; import org.gbif.api.model.common.paging.Pageable; import org.gbif.api.model.registry.search.collections.KeyCodeNameResult; -import org.gbif.registry.persistence.ContactableMapper; import org.gbif.registry.persistence.mapper.collections.dto.InstitutionMatchedDto; import org.gbif.registry.persistence.mapper.collections.params.InstitutionSearchParams; @@ -33,11 +32,7 @@ /** Mapper for {@link Institution} entities. */ @Repository public interface InstitutionMapper - extends BaseMapper, - ContactableMapper, - LookupMapper, - OccurrenceMappeableMapper, - MergeableMapper { + extends PrimaryEntityMapper, LookupMapper { List list( @Param("params") InstitutionSearchParams searchParams, diff --git a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/OccurrenceMappingMapper.java b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/OccurrenceMappingMapper.java index 17c327ff97..36a3c8b66c 100644 --- a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/OccurrenceMappingMapper.java +++ b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/OccurrenceMappingMapper.java @@ -17,10 +17,13 @@ import org.gbif.api.model.collections.OccurrenceMapping; +import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; @Repository public interface OccurrenceMappingMapper { int createOccurrenceMapping(OccurrenceMapping occurrenceMapping); + + OccurrenceMapping get(@Param("key") int key); } diff --git a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/PrimaryEntityMapper.java b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/PrimaryEntityMapper.java new file mode 100644 index 0000000000..8d3f300ff5 --- /dev/null +++ b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/PrimaryEntityMapper.java @@ -0,0 +1,11 @@ +package org.gbif.registry.persistence.mapper.collections; + +import org.gbif.api.model.registry.Commentable; +import org.gbif.api.model.registry.Identifiable; +import org.gbif.api.model.registry.MachineTaggable; +import org.gbif.api.model.registry.Taggable; +import org.gbif.registry.persistence.ContactableMapper; + +public interface PrimaryEntityMapper< + T extends Taggable & Identifiable & MachineTaggable & Commentable> + extends BaseMapper, ContactableMapper, OccurrenceMappeableMapper, ReplaceableMapper {} diff --git a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/MergeableMapper.java b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/ReplaceableMapper.java similarity index 95% rename from registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/MergeableMapper.java rename to registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/ReplaceableMapper.java index 2185993fa4..ade1599515 100644 --- a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/MergeableMapper.java +++ b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/ReplaceableMapper.java @@ -19,7 +19,7 @@ import org.apache.ibatis.annotations.Param; -public interface MergeableMapper { +public interface ReplaceableMapper { void replace( @Param("targetEntityKey") UUID targetEntityKey, @Param("replacementKey") UUID replacementKey); diff --git a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/dto/AuditLogDto.java b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/dto/AuditLogDto.java index 9908aba5d4..a7b2e8f7e3 100644 --- a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/dto/AuditLogDto.java +++ b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/dto/AuditLogDto.java @@ -1,6 +1,6 @@ package org.gbif.registry.persistence.mapper.collections.dto; -import org.gbif.api.model.collections.EntityType; +import org.gbif.api.model.collections.CollectionEntityType; import java.util.Date; import java.util.UUID; @@ -9,13 +9,16 @@ public class AuditLogDto { private long key; private long traceId; - private EntityType entityType; - private UUID entityKey; + private CollectionEntityType collectionEntityType; + private String subEntityType; + private String operation; + private UUID collectionEntityKey; + private String subEntityKey; + private UUID replacementKey; private Date created; private String createdBy; private String preState; private String postState; - private String note; public long getKey() { return key; @@ -33,20 +36,52 @@ public void setTraceId(long traceId) { this.traceId = traceId; } - public EntityType getEntityType() { - return entityType; + public CollectionEntityType getCollectionEntityType() { + return collectionEntityType; } - public void setEntityType(EntityType entityType) { - this.entityType = entityType; + public void setCollectionEntityType(CollectionEntityType collectionEntityType) { + this.collectionEntityType = collectionEntityType; } - public UUID getEntityKey() { - return entityKey; + public String getSubEntityType() { + return subEntityType; } - public void setEntityKey(UUID entityKey) { - this.entityKey = entityKey; + public void setSubEntityType(String subEntityType) { + this.subEntityType = subEntityType; + } + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + public UUID getCollectionEntityKey() { + return collectionEntityKey; + } + + public void setCollectionEntityKey(UUID collectionEntityKey) { + this.collectionEntityKey = collectionEntityKey; + } + + public String getSubEntityKey() { + return subEntityKey; + } + + public void setSubEntityKey(String subEntityKey) { + this.subEntityKey = subEntityKey; + } + + public UUID getReplacementKey() { + return replacementKey; + } + + public void setReplacementKey(UUID replacementKey) { + this.replacementKey = replacementKey; } public Date getCreated() { @@ -80,12 +115,4 @@ public String getPostState() { public void setPostState(String postState) { this.postState = postState; } - - public String getNote() { - return note; - } - - public void setNote(String note) { - this.note = note; - } } diff --git a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/dto/ChangeSuggestionDto.java b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/dto/ChangeSuggestionDto.java index 5c39fa3bb6..7e5c82b21b 100644 --- a/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/dto/ChangeSuggestionDto.java +++ b/registry-persistence/src/main/java/org/gbif/registry/persistence/mapper/collections/dto/ChangeSuggestionDto.java @@ -1,6 +1,6 @@ package org.gbif.registry.persistence.mapper.collections.dto; -import org.gbif.api.model.collections.EntityType; +import org.gbif.api.model.collections.CollectionEntityType; import org.gbif.api.model.collections.suggestions.Status; import org.gbif.api.model.collections.suggestions.Type; import org.gbif.api.vocabulary.Country; @@ -15,7 +15,7 @@ public class ChangeSuggestionDto { private Integer key; - private EntityType entityType; + private CollectionEntityType collectionEntityType; private UUID entityKey; private Type type; private Status status; @@ -43,12 +43,12 @@ public void setKey(Integer key) { this.key = key; } - public EntityType getEntityType() { - return entityType; + public CollectionEntityType getCollectionEntityType() { + return collectionEntityType; } - public void setEntityType(EntityType entityType) { - this.entityType = entityType; + public void setCollectionEntityType(CollectionEntityType collectionEntityType) { + this.collectionEntityType = collectionEntityType; } public UUID getEntityKey() { diff --git a/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/CommentMapper.xml b/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/CommentMapper.xml index 84e6fb4e00..549055a36e 100644 --- a/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/CommentMapper.xml +++ b/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/CommentMapper.xml @@ -31,4 +31,10 @@ INSERT INTO comment() VALUES() - \ No newline at end of file + + + diff --git a/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/IdentifierMapper.xml b/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/IdentifierMapper.xml index 7af4260cc7..b3390a5f47 100644 --- a/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/IdentifierMapper.xml +++ b/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/IdentifierMapper.xml @@ -37,4 +37,11 @@ LIMIT #{page.limit} OFFSET #{page.offset} - \ No newline at end of file + + + + diff --git a/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/TagMapper.xml b/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/TagMapper.xml index 3a06d4aa3c..65e8db065c 100644 --- a/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/TagMapper.xml +++ b/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/TagMapper.xml @@ -20,4 +20,11 @@ INSERT INTO tag() VALUES() - \ No newline at end of file + + + + diff --git a/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/collections/AuditLogMapper.xml b/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/collections/AuditLogMapper.xml index 39b4342ad7..00ced7f36f 100644 --- a/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/collections/AuditLogMapper.xml +++ b/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/collections/AuditLogMapper.xml @@ -8,18 +8,22 @@ - trace_id, entity_type, entity_key, created, created_by, pre_state, post_state, note + trace_id, collection_entity_type, subEntityType, operation, collection_entity_key, sub_entity_key, + sub_entity_key, replacement_key, created, created_by, pre_state, post_state - #{traceId,jdbcType=OTHER}, - #{entityType,jdbcType=OTHER}, - #{entityKey,jdbcType=OTHER}, + #{traceId,jdbcType=BIGINT}, + #{collectionEntityType,jdbcType=OTHER}, + #{subEntityType,jdbcType=VARCHAR}, + #{operation,jdbcType=VARCHAR}, + #{collectionEntityKey,jdbcType=OTHER}, + #{subEntityKey,jdbcType=VARCHAR}, + #{replacementKey,jdbcType=OTHER}, now(), #{createdBy,jdbcType=VARCHAR}, #{preState,jdbcType=OTHER}::jsonb, - #{postState,jdbcType=OTHER}::jsonb, - #{note,jdbcType=VARCHAR} + #{postState,jdbcType=OTHER}::jsonb diff --git a/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/collections/ChangeSuggestionMapper.xml b/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/collections/ChangeSuggestionMapper.xml index 32b2fab4ca..633b8b9ca2 100644 --- a/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/collections/ChangeSuggestionMapper.xml +++ b/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/collections/ChangeSuggestionMapper.xml @@ -22,7 +22,7 @@ - #{entityType,jdbcType=OTHER}, + #{collectionEntityType,jdbcType=OTHER}, #{entityKey,jdbcType=OTHER}, #{type,jdbcType=OTHER}, #{status,jdbcType=OTHER}, @@ -77,8 +77,8 @@ AND cs.type = #{type,jdbcType=OTHER} - - AND cs.entity_type = #{entityType,jdbcType=OTHER} + + AND cs.entity_type = #{collectionEntityType,jdbcType=OTHER} AND cs.country = #{country,jdbcType=VARCHAR} @@ -106,8 +106,8 @@ AND cs.type = #{type,jdbcType=OTHER} - - AND cs.entity_type = #{entityType,jdbcType=OTHER} + + AND cs.entity_type = #{collectionEntityType,jdbcType=OTHER} AND cs.country = #{country,jdbcType=VARCHAR} diff --git a/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/collections/OccurrenceMappingMapper.xml b/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/collections/OccurrenceMappingMapper.xml index d7a978ca46..52b693a7d6 100644 --- a/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/collections/OccurrenceMappingMapper.xml +++ b/registry-persistence/src/main/resources/org/gbif/registry/persistence/mapper/collections/OccurrenceMappingMapper.xml @@ -9,12 +9,18 @@ INSERT INTO occurrence_mapping(code, identifier, dataset_key, created_by, created) VALUES( - #{code,jdbcType=VARCHAR}, - #{identifier,jdbcType=VARCHAR}, - #{datasetKey,jdbcType=OTHER}, - #{createdBy,jdbcType=VARCHAR}, - now() + #{code,jdbcType=VARCHAR}, + #{identifier,jdbcType=VARCHAR}, + #{datasetKey,jdbcType=OTHER}, + #{createdBy,jdbcType=VARCHAR}, + now() ) + + diff --git a/registry-search/src/main/java/org/gbif/registry/search/dataset/service/collections/CollectionsSearchResponse.java b/registry-search/src/main/java/org/gbif/registry/search/dataset/service/collections/CollectionsSearchResponse.java deleted file mode 100644 index de89273648..0000000000 --- a/registry-search/src/main/java/org/gbif/registry/search/dataset/service/collections/CollectionsSearchResponse.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2020 Global Biodiversity Information Facility (GBIF) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gbif.registry.search.dataset.service.collections; - -import java.util.Objects; -import java.util.Set; -import java.util.UUID; - -/** Models the response for the {@link CollectionsSearchService}. */ -public class CollectionsSearchResponse { - - private String type; - private UUID key; - private String code; - private String name; - private UUID institutionKey; - private String institutionCode; - private String institutionName; - private Set matches; - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public UUID getKey() { - return key; - } - - public void setKey(UUID key) { - this.key = key; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public UUID getInstitutionKey() { - return institutionKey; - } - - public void setInstitutionKey(UUID institutionKey) { - this.institutionKey = institutionKey; - } - - public String getInstitutionCode() { - return institutionCode; - } - - public void setInstitutionCode(String institutionCode) { - this.institutionCode = institutionCode; - } - - public String getInstitutionName() { - return institutionName; - } - - public void setInstitutionName(String institutionName) { - this.institutionName = institutionName; - } - - public Set getMatches() { - return matches; - } - - public void setMatches(Set matches) { - this.matches = matches; - } - - public static class Match { - private String field; - private String snippet; - - public String getField() { - return field; - } - - public void setField(String field) { - this.field = field; - } - - public String getSnippet() { - return snippet; - } - - public void setSnippet(String snippet) { - this.snippet = snippet; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Match match = (Match) o; - return Objects.equals(field, match.field); - } - - @Override - public int hashCode() { - return Objects.hash(field); - } - } -} diff --git a/registry-search/src/main/java/org/gbif/registry/search/dataset/service/collections/CollectionsSearchService.java b/registry-search/src/main/java/org/gbif/registry/search/dataset/service/collections/CollectionsSearchService.java index c77efc264c..e3c4ede3cf 100644 --- a/registry-search/src/main/java/org/gbif/registry/search/dataset/service/collections/CollectionsSearchService.java +++ b/registry-search/src/main/java/org/gbif/registry/search/dataset/service/collections/CollectionsSearchService.java @@ -15,6 +15,7 @@ */ package org.gbif.registry.search.dataset.service.collections; +import org.gbif.api.model.collections.search.CollectionsSearchResponse; import org.gbif.registry.persistence.mapper.collections.CollectionsSearchMapper; import org.gbif.registry.persistence.mapper.collections.dto.SearchDto; diff --git a/registry-security/pom.xml b/registry-security/pom.xml index 4121b00397..53a5561933 100644 --- a/registry-security/pom.xml +++ b/registry-security/pom.xml @@ -28,6 +28,7 @@ org.springframework.boot spring-boot-starter-security + org.springframework.cloud spring-cloud-starter-sleuth diff --git a/registry-service/pom.xml b/registry-service/pom.xml index cb4dbea047..9a89fcf7e9 100644 --- a/registry-service/pom.xml +++ b/registry-service/pom.xml @@ -24,10 +24,6 @@ org.springframework.boot spring-boot-starter - - org.springframework.cloud - spring-cloud-starter-sleuth - diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/BaseCollectionEntityService.java b/registry-service/src/main/java/org/gbif/registry/service/collections/BaseCollectionEntityService.java index b895684a04..52c75f7c40 100644 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/BaseCollectionEntityService.java +++ b/registry-service/src/main/java/org/gbif/registry/service/collections/BaseCollectionEntityService.java @@ -14,8 +14,9 @@ import org.gbif.api.vocabulary.TagName; import org.gbif.api.vocabulary.TagNamespace; import org.gbif.registry.events.EventManager; -import org.gbif.registry.events.collections.ChangedCollectionEntityComponentEvent; import org.gbif.registry.events.collections.DeleteCollectionEntityEvent; +import org.gbif.registry.events.collections.EventType; +import org.gbif.registry.events.collections.SubEntityCollectionEvent; import org.gbif.registry.persistence.mapper.CommentMapper; import org.gbif.registry.persistence.mapper.IdentifierMapper; import org.gbif.registry.persistence.mapper.MachineTagMapper; @@ -25,6 +26,7 @@ import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; import javax.validation.groups.Default; @@ -86,17 +88,15 @@ public T get(UUID key) { @Transactional @Override public void delete(UUID key) { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - T entityToDelete = get(key); checkArgument(entityToDelete != null, "Entity to delete doesn't exist"); - entityToDelete.setModifiedBy(authentication.getName()); + // udpates audit fields like the modifiedBy update(entityToDelete); baseMapper.delete(key); - eventManager.post(DeleteCollectionEntityEvent.newInstance(get(key), objectClass)); + eventManager.post(DeleteCollectionEntityEvent.newInstance(entityToDelete, get(key))); } @Secured({GRSCICOLL_ADMIN_ROLE, GRSCICOLL_EDITOR_ROLE}) @@ -109,8 +109,8 @@ public int addIdentifier(UUID entityKey, Identifier identifier) { int identifierKey = withMyBatis.addIdentifier(identifierMapper, baseMapper, entityKey, identifier); eventManager.post( - ChangedCollectionEntityComponentEvent.newInstance( - entityKey, objectClass, Identifier.class)); + SubEntityCollectionEvent.newInstance( + entityKey, objectClass, identifier, identifierKey, EventType.CREATE)); return identifierKey; } @@ -118,10 +118,12 @@ public int addIdentifier(UUID entityKey, Identifier identifier) { @Transactional @Override public void deleteIdentifier(UUID entityKey, int identifierKey) { + Identifier identifierToDelete = identifierMapper.get(identifierKey); baseMapper.deleteIdentifier(entityKey, identifierKey); + eventManager.post( - ChangedCollectionEntityComponentEvent.newInstance( - entityKey, objectClass, Identifier.class)); + SubEntityCollectionEvent.newInstance( + entityKey, objectClass, identifierToDelete, identifierKey, EventType.DELETE)); } @Override @@ -137,7 +139,8 @@ public int addTag(UUID entityKey, Tag tag) { tag.setCreatedBy(authentication.getName()); int tagKey = withMyBatis.addTag(tagMapper, baseMapper, entityKey, tag); eventManager.post( - ChangedCollectionEntityComponentEvent.newInstance(entityKey, objectClass, Tag.class)); + SubEntityCollectionEvent.newInstance( + entityKey, objectClass, tag, tagKey, EventType.CREATE)); return tagKey; } @@ -152,9 +155,11 @@ public int addTag(UUID key, String value) { @Secured({GRSCICOLL_ADMIN_ROLE, GRSCICOLL_EDITOR_ROLE}) @Override public void deleteTag(UUID entityKey, int tagKey) { + Tag tagToDelete = tagMapper.get(tagKey); baseMapper.deleteTag(entityKey, tagKey); eventManager.post( - ChangedCollectionEntityComponentEvent.newInstance(entityKey, objectClass, Tag.class)); + SubEntityCollectionEvent.newInstance( + entityKey, objectClass, tagToDelete, tagKey, EventType.DELETE)); } @Override @@ -182,8 +187,8 @@ public int addMachineTag(UUID targetEntityKey, MachineTag machineTag) { machineTag.setCreatedBy(nameFromContext); int key = withMyBatis.addMachineTag(machineTagMapper, baseMapper, targetEntityKey, machineTag); eventManager.post( - ChangedCollectionEntityComponentEvent.newInstance( - targetEntityKey, objectClass, MachineTag.class)); + SubEntityCollectionEvent.newInstance( + targetEntityKey, objectClass, machineTag, key, EventType.CREATE)); return key; } @@ -216,7 +221,11 @@ public int addMachineTag(UUID targetEntityKey, TagName tagName, String value) { @Secured(GRSCICOLL_ADMIN_ROLE) @Override public void deleteMachineTag(UUID targetEntityKey, int machineTagKey) { + MachineTag machineTagToDelete = machineTagMapper.get(machineTagKey); baseMapper.deleteMachineTag(targetEntityKey, machineTagKey); + eventManager.post( + SubEntityCollectionEvent.newInstance( + targetEntityKey, objectClass, machineTagToDelete, machineTagKey, EventType.DELETE)); } @Secured(GRSCICOLL_ADMIN_ROLE) @@ -228,19 +237,24 @@ public void deleteMachineTags(UUID targetEntityKey, TagNamespace tagNamespace) { @Secured(GRSCICOLL_ADMIN_ROLE) @Override public void deleteMachineTags(UUID targetEntityKey, String namespace) { + List machineTagsToDelete = + baseMapper.listMachineTags(targetEntityKey).stream() + .filter(mt -> mt.getNamespace().equals(namespace)) + .collect(Collectors.toList()); + baseMapper.deleteMachineTags(targetEntityKey, namespace, null); - eventManager.post( - ChangedCollectionEntityComponentEvent.newInstance( - targetEntityKey, objectClass, MachineTag.class)); + + machineTagsToDelete.forEach( + mt -> + eventManager.post( + SubEntityCollectionEvent.newInstance( + targetEntityKey, objectClass, mt, mt.getKey(), EventType.DELETE))); } @Secured(GRSCICOLL_ADMIN_ROLE) @Override public void deleteMachineTags(UUID targetEntityKey, TagName tagName) { deleteMachineTags(targetEntityKey, tagName.getNamespace().getNamespace(), tagName.getName()); - eventManager.post( - ChangedCollectionEntityComponentEvent.newInstance( - targetEntityKey, objectClass, MachineTag.class)); } /** @@ -250,10 +264,17 @@ public void deleteMachineTags(UUID targetEntityKey, TagName tagName) { @Secured(GRSCICOLL_ADMIN_ROLE) @Override public void deleteMachineTags(UUID targetEntityKey, String namespace, String name) { + List machineTagsToDelete = + baseMapper.listMachineTags(targetEntityKey).stream() + .filter(mt -> mt.getNamespace().equals(namespace) && mt.getName().equals(name)) + .collect(Collectors.toList()); + baseMapper.deleteMachineTags(targetEntityKey, namespace, name); - eventManager.post( - ChangedCollectionEntityComponentEvent.newInstance( - targetEntityKey, objectClass, MachineTag.class)); + machineTagsToDelete.forEach( + mt -> + eventManager.post( + SubEntityCollectionEvent.newInstance( + targetEntityKey, objectClass, mt, mt.getKey(), EventType.DELETE))); } @Override @@ -279,8 +300,8 @@ public int addComment(UUID targetEntityKey, Comment comment) { comment.setModifiedBy(authentication.getName()); int key = withMyBatis.addComment(commentMapper, baseMapper, targetEntityKey, comment); eventManager.post( - ChangedCollectionEntityComponentEvent.newInstance( - targetEntityKey, objectClass, Comment.class)); + SubEntityCollectionEvent.newInstance( + targetEntityKey, objectClass, comment, key, EventType.CREATE)); return key; } @@ -294,10 +315,11 @@ public int addComment(UUID targetEntityKey, Comment comment) { @Secured({GRSCICOLL_ADMIN_ROLE, GRSCICOLL_EDITOR_ROLE}) @Override public void deleteComment(UUID targetEntityKey, int commentKey) { + Comment commentToDelete = commentMapper.get(commentKey); baseMapper.deleteComment(targetEntityKey, commentKey); eventManager.post( - ChangedCollectionEntityComponentEvent.newInstance( - targetEntityKey, objectClass, Comment.class)); + SubEntityCollectionEvent.newInstance( + targetEntityKey, objectClass, commentToDelete, commentKey, EventType.DELETE)); } @GetMapping(value = "{key}/comment") diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/BasePrimaryCollectionEntityService.java b/registry-service/src/main/java/org/gbif/registry/service/collections/BasePrimaryCollectionEntityService.java index 97cfffa6b6..4a66fbd158 100644 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/BasePrimaryCollectionEntityService.java +++ b/registry-service/src/main/java/org/gbif/registry/service/collections/BasePrimaryCollectionEntityService.java @@ -18,18 +18,18 @@ import org.gbif.api.model.registry.Taggable; import org.gbif.api.service.collections.PrimaryCollectionEntityService; import org.gbif.registry.events.EventManager; -import org.gbif.registry.events.collections.ChangedCollectionEntityComponentEvent; import org.gbif.registry.events.collections.CreateCollectionEntityEvent; +import org.gbif.registry.events.collections.EventType; +import org.gbif.registry.events.collections.ReplaceEntityEvent; +import org.gbif.registry.events.collections.SubEntityCollectionEvent; import org.gbif.registry.events.collections.UpdateCollectionEntityEvent; -import org.gbif.registry.persistence.ContactableMapper; import org.gbif.registry.persistence.mapper.CommentMapper; import org.gbif.registry.persistence.mapper.IdentifierMapper; import org.gbif.registry.persistence.mapper.MachineTagMapper; import org.gbif.registry.persistence.mapper.TagMapper; import org.gbif.registry.persistence.mapper.collections.AddressMapper; -import org.gbif.registry.persistence.mapper.collections.BaseMapper; -import org.gbif.registry.persistence.mapper.collections.OccurrenceMappeableMapper; import org.gbif.registry.persistence.mapper.collections.OccurrenceMappingMapper; +import org.gbif.registry.persistence.mapper.collections.PrimaryEntityMapper; import org.gbif.registry.service.WithMyBatis; import org.gbif.ws.WebApplicationException; @@ -50,6 +50,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static org.gbif.registry.security.UserRoles.GRSCICOLL_ADMIN_ROLE; import static org.gbif.registry.security.UserRoles.GRSCICOLL_EDITOR_ROLE; +import static org.gbif.registry.security.UserRoles.IDIGBIO_GRSCICOLL_EDITOR_ROLE; @Validated public abstract class BasePrimaryCollectionEntityService< @@ -58,26 +59,23 @@ public abstract class BasePrimaryCollectionEntityService< & Commentable & OccurrenceMappeable> extends BaseCollectionEntityService implements PrimaryCollectionEntityService { - private final ContactableMapper contactableMapper; private final OccurrenceMappingMapper occurrenceMappingMapper; - private final OccurrenceMappeableMapper occurrenceMappeableMapper; private final AddressMapper addressMapper; + private final PrimaryEntityMapper primaryEntityMapper; protected BasePrimaryCollectionEntityService( Class objectClass, - BaseMapper baseMapper, + PrimaryEntityMapper primaryEntityMapper, AddressMapper addressMapper, MachineTagMapper machineTagMapper, TagMapper tagMapper, IdentifierMapper identifierMapper, - ContactableMapper contactableMapper, CommentMapper commentMapper, OccurrenceMappingMapper occurrenceMappingMapper, - OccurrenceMappeableMapper occurrenceMappeableMapper, EventManager eventManager, WithMyBatis withMyBatis) { super( - baseMapper, + primaryEntityMapper, tagMapper, machineTagMapper, identifierMapper, @@ -86,9 +84,8 @@ protected BasePrimaryCollectionEntityService( eventManager, withMyBatis); this.addressMapper = addressMapper; - this.contactableMapper = contactableMapper; this.occurrenceMappingMapper = occurrenceMappingMapper; - this.occurrenceMappeableMapper = occurrenceMappeableMapper; + this.primaryEntityMapper = primaryEntityMapper; } @Secured({GRSCICOLL_ADMIN_ROLE, GRSCICOLL_EDITOR_ROLE}) @@ -134,7 +131,7 @@ public UUID create(T entity) { } } - eventManager.post(CreateCollectionEntityEvent.newInstance(entity, objectClass)); + eventManager.post(CreateCollectionEntityEvent.newInstance(entity)); return entity.getKey(); } @@ -181,7 +178,7 @@ public void update(T entity) { T newEntity = get(entity.getKey()); - eventManager.post(UpdateCollectionEntityEvent.newInstance(newEntity, entityOld, objectClass)); + eventManager.post(UpdateCollectionEntityEvent.newInstance(newEntity, entityOld)); } private void updateAddress(Address newAddress, Address oldAddress) { @@ -201,29 +198,31 @@ private void updateAddress(Address newAddress, Address oldAddress) { @Override public void addContact(@NotNull UUID entityKey, @NotNull UUID personKey) { // check if the contact exists - List contacts = contactableMapper.listContacts(entityKey); + List contacts = primaryEntityMapper.listContacts(entityKey); if (contacts != null && contacts.stream().anyMatch(p -> p.getKey().equals(personKey))) { throw new WebApplicationException("Duplicate contact", HttpStatus.CONFLICT); } - contactableMapper.addContact(entityKey, personKey); + primaryEntityMapper.addContact(entityKey, personKey); eventManager.post( - ChangedCollectionEntityComponentEvent.newInstance(entityKey, objectClass, Person.class)); + SubEntityCollectionEvent.newInstance( + entityKey, objectClass, Person.class, personKey, EventType.LINK)); } @Secured({GRSCICOLL_ADMIN_ROLE, GRSCICOLL_EDITOR_ROLE}) @Transactional @Override public void removeContact(@NotNull UUID entityKey, @NotNull UUID personKey) { - contactableMapper.removeContact(entityKey, personKey); + primaryEntityMapper.removeContact(entityKey, personKey); eventManager.post( - ChangedCollectionEntityComponentEvent.newInstance(entityKey, objectClass, Person.class)); + SubEntityCollectionEvent.newInstance( + entityKey, objectClass, Person.class, personKey, EventType.UNLINK)); } @Override public List listContacts(@PathVariable UUID key) { - return contactableMapper.listContacts(key); + return primaryEntityMapper.listContacts(key); } @Secured({GRSCICOLL_ADMIN_ROLE, GRSCICOLL_EDITOR_ROLE}) @@ -235,28 +234,47 @@ public int addOccurrenceMapping(UUID entityKey, OccurrenceMapping occurrenceMapp checkArgument( occurrenceMapping.getKey() == null, "Unable to create an entity which already has a key"); occurrenceMappingMapper.createOccurrenceMapping(occurrenceMapping); - occurrenceMappeableMapper.addOccurrenceMapping(entityKey, occurrenceMapping.getKey()); + primaryEntityMapper.addOccurrenceMapping(entityKey, occurrenceMapping.getKey()); eventManager.post( - ChangedCollectionEntityComponentEvent.newInstance( - entityKey, objectClass, OccurrenceMapping.class)); + SubEntityCollectionEvent.newInstance( + entityKey, + objectClass, + occurrenceMapping, + occurrenceMapping.getKey(), + EventType.CREATE)); return occurrenceMapping.getKey(); } @Override public List listOccurrenceMappings(@NotNull UUID uuid) { - return occurrenceMappeableMapper.listOccurrenceMappings(uuid); + return primaryEntityMapper.listOccurrenceMappings(uuid); } @Secured({GRSCICOLL_ADMIN_ROLE, GRSCICOLL_EDITOR_ROLE}) @Transactional @Override public void deleteOccurrenceMapping(UUID entityKey, int occurrenceMappingKey) { - occurrenceMappeableMapper.deleteOccurrenceMapping(entityKey, occurrenceMappingKey); + OccurrenceMapping occurrenceMappingToDelete = occurrenceMappingMapper.get(occurrenceMappingKey); + primaryEntityMapper.deleteOccurrenceMapping(entityKey, occurrenceMappingKey); eventManager.post( - ChangedCollectionEntityComponentEvent.newInstance( - entityKey, objectClass, OccurrenceMapping.class)); + SubEntityCollectionEvent.newInstance( + entityKey, + objectClass, + occurrenceMappingToDelete, + occurrenceMappingKey, + EventType.DELETE)); + } + + @Secured({GRSCICOLL_ADMIN_ROLE, IDIGBIO_GRSCICOLL_EDITOR_ROLE}) + @Transactional + @Override + public void replace(UUID targetEntityKey, UUID replacementKey) { + primaryEntityMapper.replace(targetEntityKey, replacementKey); + eventManager.post( + ReplaceEntityEvent.newInstance( + objectClass, targetEntityKey, replacementKey, EventType.REPLACE)); } /** diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/DefaultCollectionService.java b/registry-service/src/main/java/org/gbif/registry/service/collections/DefaultCollectionService.java index c713d844e6..c1cc4b04c0 100644 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/DefaultCollectionService.java +++ b/registry-service/src/main/java/org/gbif/registry/service/collections/DefaultCollectionService.java @@ -57,10 +57,8 @@ protected DefaultCollectionService( machineTagMapper, tagMapper, identifierMapper, - collectionMapper, commentMapper, occurrenceMappingMapper, - collectionMapper, eventManager, withMyBatis); this.collectionMapper = collectionMapper; diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/DefaultInstitutionService.java b/registry-service/src/main/java/org/gbif/registry/service/collections/DefaultInstitutionService.java index 2232d98f09..f96d0ab679 100644 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/DefaultInstitutionService.java +++ b/registry-service/src/main/java/org/gbif/registry/service/collections/DefaultInstitutionService.java @@ -8,6 +8,8 @@ import org.gbif.api.model.registry.search.collections.KeyCodeNameResult; import org.gbif.api.service.collections.InstitutionService; import org.gbif.registry.events.EventManager; +import org.gbif.registry.events.collections.EventType; +import org.gbif.registry.events.collections.ReplaceEntityEvent; import org.gbif.registry.persistence.mapper.CommentMapper; import org.gbif.registry.persistence.mapper.IdentifierMapper; import org.gbif.registry.persistence.mapper.MachineTagMapper; @@ -19,15 +21,16 @@ import org.gbif.registry.service.WithMyBatis; import java.util.List; - -import com.google.common.base.CharMatcher; -import com.google.common.base.Strings; +import java.util.UUID; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RequestParam; +import com.google.common.base.CharMatcher; +import com.google.common.base.Strings; + @Validated @Service public class DefaultInstitutionService extends BasePrimaryCollectionEntityService @@ -53,10 +56,8 @@ protected DefaultInstitutionService( machineTagMapper, tagMapper, identifierMapper, - institutionMapper, commentMapper, occurrenceMappingMapper, - institutionMapper, eventManager, withMyBatis); this.institutionMapper = institutionMapper; @@ -67,26 +68,26 @@ public PagingResponse list(InstitutionSearchRequest searchRequest) Pageable page = searchRequest.getPage() == null ? new PagingRequest() : searchRequest.getPage(); String query = - searchRequest.getQ() != null - ? Strings.emptyToNull(CharMatcher.WHITESPACE.trimFrom(searchRequest.getQ())) - : searchRequest.getQ(); + searchRequest.getQ() != null + ? Strings.emptyToNull(CharMatcher.WHITESPACE.trimFrom(searchRequest.getQ())) + : searchRequest.getQ(); InstitutionSearchParams params = - InstitutionSearchParams.builder() - .query(query) - .contactKey(searchRequest.getContact()) - .code(searchRequest.getCode()) - .name(searchRequest.getName()) - .alternativeCode(searchRequest.getAlternativeCode()) - .machineTagNamespace(searchRequest.getMachineTagNamespace()) - .machineTagName(searchRequest.getMachineTagName()) - .machineTagValue(searchRequest.getMachineTagValue()) - .identifierType(searchRequest.getIdentifierType()) - .identifier(searchRequest.getIdentifier()) - .country(searchRequest.getCountry()) - .city(searchRequest.getCity()) - .fuzzyName(searchRequest.getFuzzyName()) - .build(); + InstitutionSearchParams.builder() + .query(query) + .contactKey(searchRequest.getContact()) + .code(searchRequest.getCode()) + .name(searchRequest.getName()) + .alternativeCode(searchRequest.getAlternativeCode()) + .machineTagNamespace(searchRequest.getMachineTagNamespace()) + .machineTagName(searchRequest.getMachineTagName()) + .machineTagValue(searchRequest.getMachineTagValue()) + .identifierType(searchRequest.getIdentifierType()) + .identifier(searchRequest.getIdentifier()) + .country(searchRequest.getCountry()) + .city(searchRequest.getCity()) + .fuzzyName(searchRequest.getFuzzyName()) + .build(); long total = institutionMapper.count(params); return new PagingResponse<>(page, total, institutionMapper.list(params, page)); @@ -96,7 +97,7 @@ public PagingResponse list(InstitutionSearchRequest searchRequest) public PagingResponse listDeleted(Pageable page) { page = page == null ? new PagingRequest() : page; return new PagingResponse<>( - page, institutionMapper.countDeleted(), institutionMapper.deleted(page)); + page, institutionMapper.countDeleted(), institutionMapper.deleted(page)); } @Override @@ -104,4 +105,11 @@ public List suggest(@RequestParam(value = "q", required = fal return institutionMapper.suggest(q); } + @Override + public void convertToCollection(UUID targetEntityKey, UUID collectionKey) { + institutionMapper.convertToCollection(targetEntityKey, collectionKey); + eventManager.post( + ReplaceEntityEvent.newInstance( + Institution.class, targetEntityKey, collectionKey, EventType.CONVERSION_TO_COLLECTION)); + } } diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/DefaultPersonService.java b/registry-service/src/main/java/org/gbif/registry/service/collections/DefaultPersonService.java index 918758343e..0c6db17eba 100644 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/DefaultPersonService.java +++ b/registry-service/src/main/java/org/gbif/registry/service/collections/DefaultPersonService.java @@ -110,7 +110,7 @@ public UUID create(Person person) { } } - eventManager.post(CreateCollectionEntityEvent.newInstance(person, Person.class)); + eventManager.post(CreateCollectionEntityEvent.newInstance(person)); return person.getKey(); } @@ -154,7 +154,7 @@ public void update(Person person) { // check if we have to delete the address Person newPerson = get(person.getKey()); - eventManager.post(UpdateCollectionEntityEvent.newInstance(newPerson, oldPerson, Person.class)); + eventManager.post(UpdateCollectionEntityEvent.newInstance(newPerson, oldPerson)); } @Override diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/audit/AuditLogger.java b/registry-service/src/main/java/org/gbif/registry/service/collections/audit/AuditLogger.java deleted file mode 100644 index 350b55aadc..0000000000 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/audit/AuditLogger.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.gbif.registry.service.collections.audit; - -import org.gbif.api.model.collections.CollectionEntity; -import org.gbif.registry.persistence.mapper.collections.AuditLogMapper; -import org.gbif.registry.persistence.mapper.collections.dto.AuditLogDto; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.event.EventListener; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Component; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -import brave.Tracer; - -// TODO: listerners que sean @Async?? luego poner @EnableAsync en Application -// TODO: usar mismos events que en registry-events - -@Component -public class AuditLogger { - - private final Tracer tracer; - private final AuditLogMapper auditLogMapper; - private final ObjectMapper objectMapper; - - @Autowired - public AuditLogger(Tracer tracer, AuditLogMapper auditLogMapper, ObjectMapper objectMapper) { - this.tracer = tracer; - this.auditLogMapper = auditLogMapper; - this.objectMapper = objectMapper; - } - - @EventListener - public void logCreatedEvents(CreatedEntityEvent event) { - AuditLogDto dto = createBaseDto(event); - dto.setEntityKey(event.getCreatedEntity().getKey()); - dto.setPostState(toJson(event.getCreatedEntity())); - auditLogMapper.create(dto); - } - - @EventListener - public void logUpdatedEvents(UpdatedEntityEvent event) { - AuditLogDto dto = createBaseDto(event); - dto.setEntityKey(event.getNewEntity().getKey()); - dto.setPreState(toJson(event.getOldEntity())); - dto.setPostState(toJson(event.getNewEntity())); - auditLogMapper.create(dto); - } - - private AuditLogDto createBaseDto(BaseEvent event) { - AuditLogDto dto = new AuditLogDto(); - dto.setTraceId(tracer.currentSpan().context().traceId()); - dto.setEntityType(event.getEntityType()); - dto.setCreatedBy(getUsername()); - dto.setNote(event.getNote()); - return dto; - } - - // TODO: getusername y toJson deberian ir a una clase de utils ya q lo uso en changeSuggestion tb - - protected String getUsername() { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - return authentication.getName(); - } - - protected String toJson(T entity) { - try { - return objectMapper.writeValueAsString(entity); - } catch (JsonProcessingException e) { - throw new IllegalArgumentException("Cannot serialize entity", e); - } - } -} diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/audit/BaseEvent.java b/registry-service/src/main/java/org/gbif/registry/service/collections/audit/BaseEvent.java deleted file mode 100644 index 0a7d58db07..0000000000 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/audit/BaseEvent.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.gbif.registry.service.collections.audit; - -import org.gbif.api.model.collections.Collection; -import org.gbif.api.model.collections.CollectionEntity; -import org.gbif.api.model.collections.EntityType; -import org.gbif.api.model.collections.Institution; -import org.gbif.api.model.collections.Person; - -abstract class BaseEvent { - - protected String note; - protected EntityType entityType; - - public String getNote() { - return note; - } - - public EntityType getEntityType() { - return entityType; - } - - protected EntityType getEntityType(T entity) { - if (entity instanceof Institution) { - return EntityType.INSTITUTION; - } else if (entity instanceof Collection) { - return EntityType.COLLECTION; - } else if (entity instanceof Person) { - return EntityType.PERSON; - } - - throw new IllegalArgumentException( - "Entity type not supported: " + entity.getClass().getSimpleName()); - } -} diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/audit/CreatedEntityEvent.java b/registry-service/src/main/java/org/gbif/registry/service/collections/audit/CreatedEntityEvent.java deleted file mode 100644 index 3f565b95bd..0000000000 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/audit/CreatedEntityEvent.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.gbif.registry.service.collections.audit; - -import org.gbif.api.model.collections.CollectionEntity; - -public class CreatedEntityEvent extends BaseEvent { - - private final T createdEntity; - - public CreatedEntityEvent(T createdEntity) { - this.createdEntity = createdEntity; - this.entityType = getEntityType(createdEntity); - this.note = "Create " + createdEntity.getClass().getSimpleName(); - } - - public T getCreatedEntity() { - return createdEntity; - } -} diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/audit/DeletedEntityEvent.java b/registry-service/src/main/java/org/gbif/registry/service/collections/audit/DeletedEntityEvent.java deleted file mode 100644 index 5f50f4acde..0000000000 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/audit/DeletedEntityEvent.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.gbif.registry.service.collections.audit; - -import org.gbif.api.model.collections.CollectionEntity; - -public class DeletedEntityEvent extends BaseEvent { - - private final T deletedEntity; - - public DeletedEntityEvent(T deletedEntity) { - this.deletedEntity = deletedEntity; - this.entityType = getEntityType(deletedEntity); - this.note = "Delete " + deletedEntity.getClass().getSimpleName(); - } - - public T getDeletedEntity() { - return deletedEntity; - } -} diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/audit/UpdatedEntityEvent.java b/registry-service/src/main/java/org/gbif/registry/service/collections/audit/UpdatedEntityEvent.java deleted file mode 100644 index 15a36d3b49..0000000000 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/audit/UpdatedEntityEvent.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.gbif.registry.service.collections.audit; - -import org.gbif.api.model.collections.CollectionEntity; - -public class UpdatedEntityEvent extends BaseEvent { - - private final T oldEntity; - private final T newEntity; - - public UpdatedEntityEvent(T oldEntity, T newEntity) { - this.oldEntity = oldEntity; - this.newEntity = newEntity; - this.entityType = getEntityType(oldEntity); - this.note = "Update " + newEntity.getClass().getSimpleName(); - } - - public T getOldEntity() { - return oldEntity; - } - - public T getNewEntity() { - return newEntity; - } -} diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/merge/BaseMergeService.java b/registry-service/src/main/java/org/gbif/registry/service/collections/merge/BaseMergeService.java index 883ae52677..8d7b6b4b91 100644 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/merge/BaseMergeService.java +++ b/registry-service/src/main/java/org/gbif/registry/service/collections/merge/BaseMergeService.java @@ -15,24 +15,18 @@ */ package org.gbif.registry.service.collections.merge; -import org.gbif.api.model.collections.CollectionEntity; +import org.gbif.api.model.collections.Address; import org.gbif.api.model.collections.Contactable; import org.gbif.api.model.collections.OccurrenceMappeable; import org.gbif.api.model.collections.OccurrenceMapping; +import org.gbif.api.model.collections.PrimaryCollectionEntity; import org.gbif.api.model.registry.Commentable; import org.gbif.api.model.registry.Identifiable; import org.gbif.api.model.registry.Identifier; import org.gbif.api.model.registry.MachineTaggable; import org.gbif.api.model.registry.Taggable; +import org.gbif.api.service.collections.PrimaryCollectionEntityService; import org.gbif.api.vocabulary.IdentifierType; -import org.gbif.registry.persistence.ContactableMapper; -import org.gbif.registry.persistence.mapper.IdentifierMapper; -import org.gbif.registry.persistence.mapper.MachineTagMapper; -import org.gbif.registry.persistence.mapper.collections.BaseMapper; -import org.gbif.registry.persistence.mapper.collections.MergeableMapper; -import org.gbif.registry.persistence.mapper.collections.OccurrenceMappeableMapper; -import org.gbif.registry.persistence.mapper.collections.OccurrenceMappingMapper; -import org.gbif.registry.persistence.mapper.collections.PersonMapper; import org.gbif.registry.security.SecurityContextCheck; import org.gbif.registry.security.UserRoles; @@ -60,43 +54,17 @@ public abstract class BaseMergeService< T extends - CollectionEntity & Identifiable & MachineTaggable & OccurrenceMappeable & Contactable - & Taggable & Commentable> + PrimaryCollectionEntity & Identifiable & MachineTaggable & OccurrenceMappeable + & Contactable & Taggable & Commentable> implements MergeService { - // TODO: usar los servicios en lugar de los mappers. Necesito nuevos servicios para el audit log - // tb (como por ejemplo uno para mover un identifer) - - protected final BaseMapper baseMapper; - protected final MergeableMapper mergeableMapper; - protected final ContactableMapper contactableMapper; - protected final IdentifierMapper identifierMapper; - protected final OccurrenceMappeableMapper occurrenceMappeableMapper; - protected final PersonMapper personMapper; - private final MachineTagMapper machineTagMapper; - private final OccurrenceMappingMapper occurrenceMappingMapper; - - protected BaseMergeService( - BaseMapper baseMapper, - MergeableMapper mergeableMapper, - ContactableMapper contactableMapper, - IdentifierMapper identifierMapper, - OccurrenceMappeableMapper occurrenceMappeableMapper, - PersonMapper personMapper, - MachineTagMapper machineTagMapper, - OccurrenceMappingMapper occurrenceMappingMapper) { - this.baseMapper = baseMapper; - this.mergeableMapper = mergeableMapper; - this.contactableMapper = contactableMapper; - this.identifierMapper = identifierMapper; - this.occurrenceMappeableMapper = occurrenceMappeableMapper; - this.personMapper = personMapper; - this.machineTagMapper = machineTagMapper; - this.occurrenceMappingMapper = occurrenceMappingMapper; + protected final PrimaryCollectionEntityService primaryEntityService; + + protected BaseMergeService(PrimaryCollectionEntityService primaryEntityService) { + this.primaryEntityService = primaryEntityService; } @Secured({GRSCICOLL_ADMIN_ROLE, IDIGBIO_GRSCICOLL_EDITOR_ROLE}) - @Override @Transactional public void merge(UUID entityToReplaceKey, UUID replacementKey) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); @@ -106,12 +74,12 @@ public void merge(UUID entityToReplaceKey, UUID replacementKey) { !entityToReplaceKey.equals(replacementKey), "The replacement has to be different than the entity to replace"); - T entityToReplace = baseMapper.get(entityToReplaceKey); + T entityToReplace = primaryEntityService.get(entityToReplaceKey); checkArgument( entityToReplace != null, "Not found entity to replace with key " + entityToReplaceKey); checkArgument(entityToReplace.getDeleted() == null, "Cannot merge a deleted entity"); - T replacement = baseMapper.get(replacementKey); + T replacement = primaryEntityService.get(replacementKey); checkArgument(replacement != null, "Not found replacement entity with key " + replacementKey); checkArgument( replacement.getDeleted() == null, "Cannot merge an entity with a deleted replacement"); @@ -137,20 +105,21 @@ && isIDigBioRecord(replacement)) { checkMergeExtraPreconditions(entityToReplace, replacement); // delete and set the replacement - mergeableMapper.replace(entityToReplaceKey, replacementKey); + primaryEntityService.replace(entityToReplaceKey, replacementKey); // merge entity fields T updatedEntityToReplace = mergeEntityFields(entityToReplace, replacement); updatedEntityToReplace.setModifiedBy(authentication.getName()); - baseMapper.update(updatedEntityToReplace); + primaryEntityService.update(updatedEntityToReplace); // copy the identifiers entityToReplace .getIdentifiers() .forEach( i -> { - identifierMapper.createIdentifier(i); - baseMapper.addIdentifier(replacementKey, i.getKey()); + i.setKey(null); + // TODO: created must be null, create utility method to reuse + primaryEntityService.addIdentifier(replacementKey, i); }); // copy iDigBio machine tags @@ -158,29 +127,27 @@ && isIDigBioRecord(replacement)) { .filter(mt -> mt.getNamespace().equals(IDIGBIO_NAMESPACE)) .forEach( mt -> { - machineTagMapper.createMachineTag(mt); - baseMapper.addMachineTag(replacementKey, mt.getKey()); + mt.setKey(null); + primaryEntityService.addMachineTag(replacementKey, mt); }); // merge contacts Objects.requireNonNull(entityToReplace.getContacts()).stream() .filter(c -> !replacement.getContacts().contains(c)) - .forEach(c -> contactableMapper.addContact(replacementKey, c.getKey())); + .forEach(c -> primaryEntityService.addContact(replacementKey, c.getKey())); // add the UUID key of the replaced entity as an identifier of the replacement Identifier keyIdentifier = new Identifier(IdentifierType.UUID, entityToReplace.getKey().toString()); - keyIdentifier.setCreatedBy(authentication.getName()); - identifierMapper.createIdentifier(keyIdentifier); - baseMapper.addIdentifier(replacementKey, keyIdentifier.getKey()); + primaryEntityService.addIdentifier(replacementKey, keyIdentifier); // update occurrence mappings List occMappings = - occurrenceMappeableMapper.listOccurrenceMappings(entityToReplaceKey); + primaryEntityService.listOccurrenceMappings(entityToReplaceKey); occMappings.forEach( om -> { - occurrenceMappingMapper.createOccurrenceMapping(om); - occurrenceMappeableMapper.addOccurrenceMapping(replacementKey, om.getKey()); + om.setKey(null); + primaryEntityService.addOccurrenceMapping(replacementKey, om); }); additionalOperations(entityToReplace, replacement); @@ -225,6 +192,11 @@ protected void setNullFields(T target, T source) { // set value in target if (sourceValue != null) { + if (sourceValue instanceof Address) { + // set the key to null to create the address + ((Address) sourceValue).setKey(null); + } + clazz .getMethod("set" + capitalize.apply(f.getName()), f.getType()) .invoke(target, sourceValue); diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/merge/CollectionMergeService.java b/registry-service/src/main/java/org/gbif/registry/service/collections/merge/CollectionMergeService.java index b44cc8cd73..e6acbe8fab 100644 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/merge/CollectionMergeService.java +++ b/registry-service/src/main/java/org/gbif/registry/service/collections/merge/CollectionMergeService.java @@ -18,13 +18,9 @@ import org.gbif.api.model.collections.AlternativeCode; import org.gbif.api.model.collections.Collection; import org.gbif.api.model.collections.Person; -import org.gbif.registry.persistence.mapper.IdentifierMapper; -import org.gbif.registry.persistence.mapper.MachineTagMapper; -import org.gbif.registry.persistence.mapper.collections.CollectionMapper; -import org.gbif.registry.persistence.mapper.collections.OccurrenceMappingMapper; -import org.gbif.registry.persistence.mapper.collections.PersonMapper; - -import java.util.List; +import org.gbif.api.model.common.paging.PagingResponse; +import org.gbif.api.service.collections.CollectionService; +import org.gbif.api.service.collections.PersonService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -35,22 +31,13 @@ @Service public class CollectionMergeService extends BaseMergeService { + private final PersonService personService; + @Autowired protected CollectionMergeService( - CollectionMapper collectionMapper, - IdentifierMapper identifierMapper, - PersonMapper personMapper, - MachineTagMapper machineTagMapper, - OccurrenceMappingMapper occurrenceMappingMapper) { - super( - collectionMapper, - collectionMapper, - collectionMapper, - identifierMapper, - collectionMapper, - personMapper, - machineTagMapper, - occurrenceMappingMapper); + CollectionService collectionService, PersonService personService) { + super(collectionService); + this.personService = personService; } @Override @@ -98,11 +85,13 @@ Collection mergeEntityFields(Collection entityToReplace, Collection replacement) @Override void additionalOperations(Collection entityToReplace, Collection replacement) { // fix primary collection of contacts - List persons = personMapper.list(null, entityToReplace.getKey(), null, null); - persons.forEach( - p -> { - p.setPrimaryCollectionKey(replacement.getKey()); - personMapper.update(p); - }); + PagingResponse persons = personService.list(null, entityToReplace.getKey(), null, null); + persons + .getResults() + .forEach( + p -> { + p.setPrimaryCollectionKey(replacement.getKey()); + personService.update(p); + }); } } diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/merge/InstitutionMergeService.java b/registry-service/src/main/java/org/gbif/registry/service/collections/merge/InstitutionMergeService.java index ae8eabc5de..dbfd3f3f17 100644 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/merge/InstitutionMergeService.java +++ b/registry-service/src/main/java/org/gbif/registry/service/collections/merge/InstitutionMergeService.java @@ -19,18 +19,15 @@ import org.gbif.api.model.collections.Collection; import org.gbif.api.model.collections.Institution; import org.gbif.api.model.collections.Person; -import org.gbif.registry.persistence.mapper.IdentifierMapper; -import org.gbif.registry.persistence.mapper.MachineTagMapper; -import org.gbif.registry.persistence.mapper.collections.CollectionMapper; -import org.gbif.registry.persistence.mapper.collections.InstitutionMapper; -import org.gbif.registry.persistence.mapper.collections.OccurrenceMappingMapper; -import org.gbif.registry.persistence.mapper.collections.PersonMapper; -import org.gbif.registry.persistence.mapper.collections.dto.CollectionDto; -import org.gbif.registry.persistence.mapper.collections.params.CollectionSearchParams; +import org.gbif.api.model.collections.request.CollectionSearchRequest; +import org.gbif.api.model.collections.view.CollectionView; +import org.gbif.api.model.common.paging.PagingResponse; +import org.gbif.api.service.collections.CollectionService; +import org.gbif.api.service.collections.InstitutionService; +import org.gbif.api.service.collections.PersonService; import org.gbif.registry.security.SecurityContextCheck; import org.gbif.registry.security.UserRoles; -import java.util.List; import java.util.UUID; import javax.annotation.Nullable; @@ -52,32 +49,19 @@ @Service public class InstitutionMergeService extends BaseMergeService { - private final InstitutionMapper institutionMapper; - private final CollectionMapper collectionMapper; - private final MachineTagMapper machineTagMapper; - private final OccurrenceMappingMapper occurrenceMappingMapper; + private final InstitutionService institutionService; + private final CollectionService collectionService; + private final PersonService personService; @Autowired public InstitutionMergeService( - InstitutionMapper institutionMapper, - CollectionMapper collectionMapper, - IdentifierMapper identifierMapper, - MachineTagMapper machineTagMapper, - OccurrenceMappingMapper occurrenceMappingMapper, - PersonMapper personMapper) { - super( - institutionMapper, - institutionMapper, - institutionMapper, - identifierMapper, - institutionMapper, - personMapper, - machineTagMapper, - occurrenceMappingMapper); - this.institutionMapper = institutionMapper; - this.collectionMapper = collectionMapper; - this.machineTagMapper = machineTagMapper; - this.occurrenceMappingMapper = occurrenceMappingMapper; + InstitutionService institutionService, + CollectionService collectionService, + PersonService personService) { + super(institutionService); + this.institutionService = institutionService; + this.collectionService = collectionService; + this.personService = personService; } @Secured({GRSCICOLL_ADMIN_ROLE, IDIGBIO_GRSCICOLL_EDITOR_ROLE}) @@ -93,7 +77,7 @@ public UUID convertToCollection( institutionKeyForNewCollection != null || !Strings.isNullOrEmpty(newInstitutionName), "Either the institution key for the new collection or a name to create a new institution are required"); - Institution institutionToConvert = institutionMapper.get(institutionKey); + Institution institutionToConvert = institutionService.get(institutionKey); checkArgument( institutionToConvert.getDeleted() == null, "Cannot convert a deleted institution"); checkArgument( @@ -132,12 +116,12 @@ && isIDigBioRecord(institutionToConvert)) { newInstitution.setName(newInstitutionName); newInstitution.setCreatedBy(authentication.getName()); newInstitution.setModifiedBy(authentication.getName()); - institutionMapper.create(newInstitution); + institutionService.create(newInstitution); newCollection.setInstitutionKey(newInstitution.getKey()); } else { Institution institutionForNewCollection = - institutionMapper.get(institutionKeyForNewCollection); + institutionService.get(institutionKeyForNewCollection); checkArgument( institutionForNewCollection.getDeleted() == null, "Cannot assign the new collection to a deleted institution"); @@ -145,8 +129,8 @@ && isIDigBioRecord(institutionToConvert)) { newCollection.setInstitutionKey(institutionKeyForNewCollection); } - collectionMapper.create(newCollection); - institutionMapper.convertToCollection(institutionKey, newCollection.getKey()); + collectionService.create(newCollection); + institutionService.convertToCollection(institutionKey, newCollection.getKey()); // move the collections moveCollectionsToAnotherInstitution( @@ -157,8 +141,8 @@ && isIDigBioRecord(institutionToConvert)) { .getIdentifiers() .forEach( i -> { - identifierMapper.createIdentifier(i); - collectionMapper.addIdentifier(newCollection.getKey(), i.getKey()); + i.setKey(null); + collectionService.addIdentifier(newCollection.getKey(), i); }); // move the machine tags @@ -166,8 +150,8 @@ && isIDigBioRecord(institutionToConvert)) { .getMachineTags() .forEach( mt -> { - machineTagMapper.createMachineTag(mt); - collectionMapper.addMachineTag(newCollection.getKey(), mt.getKey()); + mt.setKey(null); + collectionService.addMachineTag(newCollection.getKey(), mt); }); // move the occurrence mappings @@ -175,14 +159,14 @@ && isIDigBioRecord(institutionToConvert)) { .getOccurrenceMappings() .forEach( om -> { - occurrenceMappingMapper.createOccurrenceMapping(om); - collectionMapper.addOccurrenceMapping(newCollection.getKey(), om.getKey()); + om.setKey(null); + collectionService.addOccurrenceMapping(newCollection.getKey(), om); }); // copy the contacts institutionToConvert .getContacts() - .forEach(c -> collectionMapper.addContact(newCollection.getKey(), c.getKey())); + .forEach(c -> collectionService.addContact(newCollection.getKey(), c.getKey())); return newCollection.getKey(); } @@ -221,12 +205,14 @@ Institution mergeEntityFields(Institution entityToReplace, Institution replaceme @Override void additionalOperations(Institution entityToReplace, Institution replacement) { // fix primary institution of contacts - List persons = personMapper.list(entityToReplace.getKey(), null, null, null); - persons.forEach( - p -> { - p.setPrimaryInstitutionKey(replacement.getKey()); - personMapper.update(p); - }); + PagingResponse persons = personService.list(null, entityToReplace.getKey(), null, null); + persons + .getResults() + .forEach( + p -> { + p.setPrimaryInstitutionKey(replacement.getKey()); + personService.update(p); + }); moveCollectionsToAnotherInstitution(entityToReplace.getKey(), replacement.getKey()); } @@ -234,13 +220,15 @@ void additionalOperations(Institution entityToReplace, Institution replacement) private void moveCollectionsToAnotherInstitution( UUID sourceInstitutionKey, UUID targetInstitutionKey) { // move the collections to the entity to keep - List collections = - collectionMapper.list( - CollectionSearchParams.builder().institutionKey(sourceInstitutionKey).build(), null); - collections.forEach( - c -> { - c.getCollection().setInstitutionKey(targetInstitutionKey); - collectionMapper.update(c.getCollection()); - }); + PagingResponse collections = + collectionService.list( + CollectionSearchRequest.builder().institution(sourceInstitutionKey).build()); + collections + .getResults() + .forEach( + c -> { + c.getCollection().setInstitutionKey(targetInstitutionKey); + collectionService.update(c.getCollection()); + }); } } diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/suggestions/BaseChangeSuggestionService.java b/registry-service/src/main/java/org/gbif/registry/service/collections/suggestions/BaseChangeSuggestionService.java index 1a55d7d0fd..f30d49f317 100644 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/suggestions/BaseChangeSuggestionService.java +++ b/registry-service/src/main/java/org/gbif/registry/service/collections/suggestions/BaseChangeSuggestionService.java @@ -3,8 +3,8 @@ import org.gbif.api.model.collections.Address; import org.gbif.api.model.collections.Collection; import org.gbif.api.model.collections.CollectionEntity; +import org.gbif.api.model.collections.CollectionEntityType; import org.gbif.api.model.collections.Contactable; -import org.gbif.api.model.collections.EntityType; import org.gbif.api.model.collections.Institution; import org.gbif.api.model.collections.OccurrenceMappeable; import org.gbif.api.model.collections.suggestions.Change; @@ -21,6 +21,9 @@ import org.gbif.api.model.registry.Taggable; import org.gbif.api.service.collections.CrudService; import org.gbif.api.vocabulary.Country; +import org.gbif.registry.events.EventManager; +import org.gbif.registry.events.collections.EventType; +import org.gbif.registry.events.collections.SubEntityCollectionEvent; import org.gbif.registry.mail.BaseEmailModel; import org.gbif.registry.mail.EmailSender; import org.gbif.registry.mail.collections.CollectionsEmailManager; @@ -88,7 +91,8 @@ public abstract class BaseChangeSuggestionService< private final ObjectMapper objectMapper; private final EmailSender emailSender; private final CollectionsEmailManager emailManager; - private EntityType entityType; + private final EventManager eventManager; + private CollectionEntityType collectionEntityType; protected BaseChangeSuggestionService( ChangeSuggestionMapper changeSuggestionMapper, @@ -97,7 +101,8 @@ protected BaseChangeSuggestionService( Class clazz, ObjectMapper objectMapper, EmailSender emailSender, - CollectionsEmailManager emailManager) { + CollectionsEmailManager emailManager, + EventManager eventManager) { this.changeSuggestionMapper = changeSuggestionMapper; this.mergeService = mergeService; this.crudService = crudService; @@ -105,11 +110,12 @@ protected BaseChangeSuggestionService( this.objectMapper = objectMapper; this.emailSender = emailSender; this.emailManager = emailManager; + this.eventManager = eventManager; if (clazz == Institution.class) { - entityType = EntityType.INSTITUTION; + collectionEntityType = CollectionEntityType.INSTITUTION; } else if (clazz == Collection.class) { - entityType = EntityType.COLLECTION; + collectionEntityType = CollectionEntityType.COLLECTION; } } @@ -134,10 +140,15 @@ public int createChangeSuggestion(R changeSuggestion) { changeSuggestionMapper.create(dto); + eventManager.post( + SubEntityCollectionEvent.newInstance( + dto.getEntityKey(), clazz, dto, dto.getKey(), EventType.CREATE)); + // send email try { BaseEmailModel emailModel = - emailManager.generateNewChangeSuggestionEmailModel(dto.getKey(), dto.getEntityType()); + emailManager.generateNewChangeSuggestionEmailModel( + dto.getKey(), dto.getCollectionEntityType()); emailSender.send(emailModel); } catch (Exception e) { LOG.error("Couldn't send email for new change suggestion"); @@ -218,6 +229,10 @@ public void updateChangeSuggestion(R updatedChangeSuggestion) { dto.setComments(updatedChangeSuggestion.getComments()); dto.setModifiedBy(getUsername()); changeSuggestionMapper.update(dto); + + eventManager.post( + SubEntityCollectionEvent.newInstance( + dto.getEntityKey(), clazz, dto, dto.getKey(), EventType.UPDATE)); } @Secured({GRSCICOLL_ADMIN_ROLE, GRSCICOLL_EDITOR_ROLE}) @@ -230,11 +245,15 @@ public void discardChangeSuggestion(int key) { dto.setModifiedBy(getUsername()); changeSuggestionMapper.update(dto); + eventManager.post( + SubEntityCollectionEvent.newInstance( + dto.getEntityKey(), clazz, dto, dto.getKey(), EventType.DISCARD_SUGGESTION)); + // send email try { BaseEmailModel emailModel = emailManager.generateDiscardedChangeSuggestionEmailModel( - dto.getKey(), dto.getEntityType()); + dto.getKey(), dto.getCollectionEntityType()); emailSender.send(emailModel); } catch (Exception e) { LOG.error("Couldn't send email for discarded change suggestion"); @@ -264,12 +283,17 @@ public UUID applyChangeSuggestion(int suggestionKey) { dto.setModifiedBy(getUsername()); dto.setApplied(new Date()); dto.setAppliedBy(getUsername()); + changeSuggestionMapper.update(dto); + eventManager.post( + SubEntityCollectionEvent.newInstance( + dto.getEntityKey(), clazz, dto, dto.getKey(), EventType.APPLY_SUGGESTION)); // send email try { BaseEmailModel emailModel = - emailManager.generateAppliedChangeSuggestionEmailModel(dto.getKey(), dto.getEntityType()); + emailManager.generateAppliedChangeSuggestionEmailModel( + dto.getKey(), dto.getCollectionEntityType()); emailSender.send(emailModel); } catch (Exception e) { LOG.error("Couldn't send email for applied change suggestion"); @@ -292,7 +316,7 @@ public PagingResponse list( changeSuggestionMapper.list( status, type, - entityType, + collectionEntityType, country, newEmptyChangeSuggestion().getProposerEmail(), entityKey, @@ -302,7 +326,7 @@ public PagingResponse list( changeSuggestionMapper.count( status, type, - entityType, + collectionEntityType, country, newEmptyChangeSuggestion().getProposerEmail(), entityKey); @@ -367,7 +391,7 @@ protected ChangeSuggestionDto createBaseChangeSuggestionDto(R changeSuggestion) dto.setStatus(Status.PENDING); dto.setType(changeSuggestion.getType()); dto.setComments(changeSuggestion.getComments()); - dto.setEntityType(entityType); + dto.setCollectionEntityType(collectionEntityType); dto.setProposedBy(changeSuggestion.getProposerEmail()); dto.setModifiedBy(getUsername()); return dto; diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/suggestions/CollectionChangeSuggestionService.java b/registry-service/src/main/java/org/gbif/registry/service/collections/suggestions/CollectionChangeSuggestionService.java index 7c32c3af29..49a92dd09d 100644 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/suggestions/CollectionChangeSuggestionService.java +++ b/registry-service/src/main/java/org/gbif/registry/service/collections/suggestions/CollectionChangeSuggestionService.java @@ -3,6 +3,7 @@ import org.gbif.api.model.collections.Collection; import org.gbif.api.model.collections.suggestions.CollectionChangeSuggestion; import org.gbif.api.service.collections.CollectionService; +import org.gbif.registry.events.EventManager; import org.gbif.registry.mail.EmailSender; import org.gbif.registry.mail.collections.CollectionsEmailManager; import org.gbif.registry.persistence.mapper.collections.ChangeSuggestionMapper; @@ -31,7 +32,8 @@ public CollectionChangeSuggestionService( CollectionMergeService collectionMergeService, ObjectMapper objectMapper, EmailSender emailSender, - CollectionsEmailManager emailManager) { + CollectionsEmailManager emailManager, + EventManager eventManager) { super( changeSuggestionMapper, collectionMergeService, @@ -39,7 +41,8 @@ public CollectionChangeSuggestionService( Collection.class, objectMapper, emailSender, - emailManager); + emailManager, + eventManager); this.changeSuggestionMapper = changeSuggestionMapper; } diff --git a/registry-service/src/main/java/org/gbif/registry/service/collections/suggestions/InstitutionChangeSuggestionService.java b/registry-service/src/main/java/org/gbif/registry/service/collections/suggestions/InstitutionChangeSuggestionService.java index 7440bdd676..463bed235a 100644 --- a/registry-service/src/main/java/org/gbif/registry/service/collections/suggestions/InstitutionChangeSuggestionService.java +++ b/registry-service/src/main/java/org/gbif/registry/service/collections/suggestions/InstitutionChangeSuggestionService.java @@ -4,6 +4,7 @@ import org.gbif.api.model.collections.suggestions.InstitutionChangeSuggestion; import org.gbif.api.model.collections.suggestions.Type; import org.gbif.api.service.collections.InstitutionService; +import org.gbif.registry.events.EventManager; import org.gbif.registry.mail.EmailSender; import org.gbif.registry.mail.collections.CollectionsEmailManager; import org.gbif.registry.persistence.mapper.collections.ChangeSuggestionMapper; @@ -41,7 +42,8 @@ public InstitutionChangeSuggestionService( InstitutionMergeService institutionMergeService, ObjectMapper objectMapper, EmailSender emailSender, - CollectionsEmailManager emailManager) { + CollectionsEmailManager emailManager, + EventManager eventManager) { super( changeSuggestionMapper, institutionMergeService, @@ -49,7 +51,8 @@ public InstitutionChangeSuggestionService( Institution.class, objectMapper, emailSender, - emailManager); + emailManager, + eventManager); this.changeSuggestionMapper = changeSuggestionMapper; this.institutionService = institutionService; this.institutionMergeService = institutionMergeService; diff --git a/registry-ws-client/src/main/java/org/gbif/registry/ws/client/collections/CollectionsSearchClient.java b/registry-ws-client/src/main/java/org/gbif/registry/ws/client/collections/CollectionsSearchClient.java new file mode 100644 index 0000000000..5b509feb7c --- /dev/null +++ b/registry-ws-client/src/main/java/org/gbif/registry/ws/client/collections/CollectionsSearchClient.java @@ -0,0 +1,20 @@ +package org.gbif.registry.ws.client.collections; + +import org.gbif.api.model.collections.search.CollectionsSearchResponse; + +import java.util.List; + +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +@RequestMapping("grscicoll/search") +public interface CollectionsSearchClient { + + @RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + List searchCollections( + @RequestParam(value = "q", required = false) String query, + @RequestParam(value = "highlight", defaultValue = "false") boolean highlight, + @RequestParam(value = "limit", defaultValue = "20") int limit); +} diff --git a/registry-ws-client/src/main/java/org/gbif/registry/ws/client/collections/LookupClient.java b/registry-ws-client/src/main/java/org/gbif/registry/ws/client/collections/LookupClient.java new file mode 100644 index 0000000000..186d283917 --- /dev/null +++ b/registry-ws-client/src/main/java/org/gbif/registry/ws/client/collections/LookupClient.java @@ -0,0 +1,28 @@ +package org.gbif.registry.ws.client.collections; + +import org.gbif.api.annotation.Trim; +import org.gbif.api.model.collections.lookup.LookupResult; +import org.gbif.api.vocabulary.Country; + +import java.util.UUID; + +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +@RequestMapping("grscicoll/lookup") +public interface LookupClient { + + @RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + LookupResult lookup( + @RequestParam(value = "datasetKey", required = false) UUID datasetKey, + @RequestParam(value = "institutionCode", required = false) @Trim String institutionCode, + @RequestParam(value = "institutionId", required = false) @Trim String institutionId, + @RequestParam(value = "ownerInstitutionCode", required = false) @Trim + String ownerInstitutionCode, + @RequestParam(value = "collectionCode", required = false) @Trim String collectionCode, + @RequestParam(value = "collectionId", required = false) @Trim String collectionId, + @RequestParam(value = "country") Country country, + @RequestParam(value = "verbose", required = false) boolean verbose); +} diff --git a/registry-ws/src/main/java/org/gbif/registry/ws/resources/collections/CollectionsSearchResource.java b/registry-ws/src/main/java/org/gbif/registry/ws/resources/collections/CollectionsSearchResource.java index 1067e1ebb9..02b854e091 100644 --- a/registry-ws/src/main/java/org/gbif/registry/ws/resources/collections/CollectionsSearchResource.java +++ b/registry-ws/src/main/java/org/gbif/registry/ws/resources/collections/CollectionsSearchResource.java @@ -15,7 +15,7 @@ */ package org.gbif.registry.ws.resources.collections; -import org.gbif.registry.search.dataset.service.collections.CollectionsSearchResponse; +import org.gbif.api.model.collections.search.CollectionsSearchResponse; import org.gbif.registry.search.dataset.service.collections.CollectionsSearchService; import java.util.List; diff --git a/registry-ws/src/main/java/org/gbif/registry/ws/resources/collections/LookupResource.java b/registry-ws/src/main/java/org/gbif/registry/ws/resources/collections/LookupResource.java index e426704eb9..6189fcdf5f 100644 --- a/registry-ws/src/main/java/org/gbif/registry/ws/resources/collections/LookupResource.java +++ b/registry-ws/src/main/java/org/gbif/registry/ws/resources/collections/LookupResource.java @@ -20,6 +20,7 @@ import org.gbif.api.model.collections.lookup.LookupResult; import org.gbif.api.vocabulary.Country; import org.gbif.registry.service.collections.lookup.DefaultLookupService; +import org.gbif.registry.service.collections.lookup.LookupService; import java.util.UUID; @@ -35,9 +36,9 @@ @RequestMapping(value = "grscicoll/lookup", produces = MediaType.APPLICATION_JSON_VALUE) public class LookupResource { - private final DefaultLookupService lookupService; + private final LookupService lookupService; - public LookupResource(DefaultLookupService lookupService) { + public LookupResource(LookupService lookupService) { this.lookupService = lookupService; }