From 2f45cb54959e40387d63c46c00785bb266e100cd Mon Sep 17 00:00:00 2001 From: Mukhiddin Yusupov <133661057+mukhiddin-yusuf@users.noreply.github.com> Date: Fri, 14 Jun 2024 14:52:35 +0500 Subject: [PATCH] feat(search-locations): Extend Inventory Locations in Consortia endpoint with additional response fields * feat(search-locations): Extend Inventory Locations in Consortia endpoint with additional response fields Closes: MSEARCH-775 --- NEWS.md | 1 + .../folio/search/model/dto/LocationDto.java | 3 ++ src/main/resources/model/location.json | 51 ++++++++++++++++--- .../schemas/entity/consortiumLocation.yaml | 33 ++++++++++++ .../ConsortiumSearchLocationsIT.java | 23 +++++++-- .../LocationsIndexingConsortiumIT.java | 39 ++++++++------ .../ConsortiumLocationServiceTest.java | 23 +++++---- 7 files changed, 137 insertions(+), 36 deletions(-) diff --git a/NEWS.md b/NEWS.md index ed2ff1124..cdf304fa6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -20,6 +20,7 @@ * Search consolidated items/holdings data in consortium ([MSEARCH-759](https://folio-org.atlassian.net/browse/MSEARCH-759)) * Create bibframe index and process bibframe events ([MSEARCH-781](https://folio-org.atlassian.net/browse/MSEARCH-781)) * Allow Unified List of Inventory Locations in a Consortium to be fetched by member tenants ([MSEARCH-660](https://folio-org.atlassian.net/browse/MSEARCH-660)) +* Extend response with additional Location fields for Inventory Locations in a Consortium endpoint ([MSEARCH-775](https://folio-org.atlassian.net/browse/MSEARCH-775)) ### Bug fixes * Do not delete kafka topics if collection topic is enabled ([MSEARCH-725](https://folio-org.atlassian.net/browse/MSEARCH-725)) diff --git a/src/main/java/org/folio/search/model/dto/LocationDto.java b/src/main/java/org/folio/search/model/dto/LocationDto.java index da0a970ce..8d5464996 100644 --- a/src/main/java/org/folio/search/model/dto/LocationDto.java +++ b/src/main/java/org/folio/search/model/dto/LocationDto.java @@ -7,6 +7,7 @@ import lombok.Builder; import lombok.Data; import lombok.extern.jackson.Jacksonized; +import org.folio.search.domain.dto.Metadata; /** * Describes Location object that comes from external channels. @@ -39,5 +40,7 @@ public class LocationDto { private UUID primaryServicePoint; @JsonProperty("servicePointIds") private List servicePointIds; + @JsonProperty("metadata") + private Metadata metadata; } diff --git a/src/main/resources/model/location.json b/src/main/resources/model/location.json index 37a2674f5..595d0b332 100644 --- a/src/main/resources/model/location.json +++ b/src/main/resources/model/location.json @@ -20,23 +20,62 @@ "index": "keyword_lowercase", "showInResponse": [ "search" ] }, + "description": { + "index": "keyword_lowercase", + "showInResponse": [ "search" ] + }, + "discoveryDisplayName": { + "index": "keyword_lowercase", + "showInResponse": [ "search" ] + }, "isActive": { - "index": "bool" + "index": "bool", + "showInResponse": [ "search" ] }, "institutionId": { - "index": "keyword_lowercase" + "index": "keyword_lowercase", + "showInResponse": [ "search" ] }, "campusId": { - "index": "keyword_lowercase" + "index": "keyword_lowercase", + "showInResponse": [ "search" ] }, "libraryId": { - "index": "keyword_lowercase" + "index": "keyword_lowercase", + "showInResponse": [ "search" ] }, "primaryServicePoint": { - "index": "keyword_lowercase" + "index": "keyword_lowercase", + "showInResponse": [ "search" ] }, "servicePointIds": { - "index": "keyword_lowercase" + "index": "keyword_lowercase", + "showInResponse": [ "search" ] + }, + "metadata": { + "type": "object", + "properties": { + "createdDate": { + "searchTypes": "filter", + "index": "date" + }, + "createdByUserId": { + "index": "keyword_lowercase" + }, + "createdByUsername": { + "index": "keyword_lowercase" + }, + "updatedDate": { + "searchTypes": "filter", + "index": "date" + }, + "updatedByUserId": { + "index": "keyword_lowercase" + }, + "updatedByUsername": { + "index": "keyword_lowercase" + } + } } } } diff --git a/src/main/resources/swagger.api/schemas/entity/consortiumLocation.yaml b/src/main/resources/swagger.api/schemas/entity/consortiumLocation.yaml index d3938d42f..02ae2ef5c 100644 --- a/src/main/resources/swagger.api/schemas/entity/consortiumLocation.yaml +++ b/src/main/resources/swagger.api/schemas/entity/consortiumLocation.yaml @@ -9,3 +9,36 @@ properties: tenantId: description: Tenant ID of the Location type: string + code: + description: Code of the (shelf) location, usually an abbreviation of the name. + type: string + description: + description: Description of the (shelf) location. + type: string + discoveryDisplayName: + description: Name of the (shelf) location to be shown in the discovery. + type: string + isActive: + description: Whether this (shelf) location is active. Inactive (shelf) locations can no longer been used. + type: string + institutionId: + description: The UUID of the institution, the first-level location unit, this (shelf) location belongs to. + type: string + campusId: + description: The UUID of the campus, the second-level location unit, this (shelf) location belongs to. + type: string + libraryId: + description: The UUID of the library, the third-level location unit, this (shelf) location belongs to. + type: string + primaryServicePoint: + description: The UUID of the primary service point of this (shelf) location. + type: string + format: uuid + servicePointIds: + description: All service points that this (shelf) location has. + type: array + items: + type: string + format: uuid + metadata: + $ref: "../dto/common/metadata.yaml" diff --git a/src/test/java/org/folio/search/controller/ConsortiumSearchLocationsIT.java b/src/test/java/org/folio/search/controller/ConsortiumSearchLocationsIT.java index 4f0df7094..33d2e1b99 100644 --- a/src/test/java/org/folio/search/controller/ConsortiumSearchLocationsIT.java +++ b/src/test/java/org/folio/search/controller/ConsortiumSearchLocationsIT.java @@ -1,5 +1,6 @@ package org.folio.search.controller; +import static org.apache.commons.lang3.ObjectUtils.isNotEmpty; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; import static org.awaitility.Durations.ONE_MINUTE; @@ -17,6 +18,8 @@ import java.util.List; import java.util.stream.Stream; +import org.assertj.core.groups.Tuple; +import org.folio.search.domain.dto.ConsortiumLocation; import org.folio.search.domain.dto.ConsortiumLocationCollection; import org.folio.search.model.Pair; import org.folio.search.support.base.BaseConsortiumIntegrationTest; @@ -24,6 +27,7 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.platform.commons.util.StringUtils; @IntegrationTest class ConsortiumSearchLocationsIT extends BaseConsortiumIntegrationTest { @@ -57,11 +61,20 @@ void doGetConsortiumLocations_returns200AndRecords() { .filteredOn(location -> location.getTenantId().equals(CENTRAL_TENANT_ID)) .hasSize(7); assertThat(actual.getLocations()) - .allSatisfy(location -> { - assertThat(location.getId()).isNotBlank(); - assertThat(location.getName()).isNotBlank(); - assertThat(location.getTenantId()).isNotBlank(); - }); + .extracting(ConsortiumLocation::getId, ConsortiumLocation::getName, ConsortiumLocation::getTenantId, + ConsortiumLocation::getInstitutionId, ConsortiumLocation::getCampusId, ConsortiumLocation::getLibraryId, + ConsortiumLocation::getPrimaryServicePoint) + .map(Tuple::toList) + .matches(locations -> locations.stream().allMatch(obj -> StringUtils.isNotBlank(obj.toString()))); + assertThat(actual.getLocations()) + .map(ConsortiumLocation::getMetadata) + .filteredOn(metadata -> metadata.getCreatedDate() != null && metadata.getUpdatedDate() != null) + .hasSize(14); + + assertThat(actual.getLocations()) + .filteredOn(location -> "true".equals(location.getIsActive()) && isNotEmpty(location.getServicePointIds())) + .filteredOn(location -> List.of(MEMBER_TENANT_ID, CENTRAL_TENANT_ID).contains(location.getTenantId())) + .hasSize(12); } @Test diff --git a/src/test/java/org/folio/search/controller/LocationsIndexingConsortiumIT.java b/src/test/java/org/folio/search/controller/LocationsIndexingConsortiumIT.java index a7761acab..3930584af 100644 --- a/src/test/java/org/folio/search/controller/LocationsIndexingConsortiumIT.java +++ b/src/test/java/org/folio/search/controller/LocationsIndexingConsortiumIT.java @@ -16,6 +16,9 @@ import static org.folio.search.utils.TestUtils.toMap; import java.io.IOException; +import java.util.List; +import java.util.UUID; +import org.folio.search.domain.dto.Metadata; import org.folio.search.domain.dto.ResourceEvent; import org.folio.search.model.dto.LocationDto; import org.folio.search.support.base.BaseConsortiumIntegrationTest; @@ -47,11 +50,7 @@ void tearDown() throws IOException { @Test void shouldIndexAndRemoveLocation() { - var locationId = randomId(); - var location = LocationDto.builder().id(locationId) - .name("location name") - .code("CODE") - .build(); + var location = location(); var createEvent = kafkaResourceEvent(CENTRAL_TENANT_ID, CREATE, toMap(location), null); kafkaTemplate.send(inventoryLocationTopic(CENTRAL_TENANT_ID), createEvent); awaitAssertLocationCount(1); @@ -63,11 +62,7 @@ void shouldIndexAndRemoveLocation() { @Test void shouldIndexSameLocationFromDifferentTenantsAsSeparateDocs() { - var locationId = randomId(); - var location = LocationDto.builder().id(locationId) - .name("location name") - .code("CODE") - .build(); + var location = location(); var createCentralEvent = kafkaResourceEvent(CENTRAL_TENANT_ID, CREATE, toMap(location), null); var createMemberEvent = kafkaResourceEvent(MEMBER_TENANT_ID, CREATE, toMap(location), null); kafkaTemplate.send(inventoryLocationTopic(CENTRAL_TENANT_ID), createCentralEvent); @@ -77,11 +72,7 @@ void shouldIndexSameLocationFromDifferentTenantsAsSeparateDocs() { @Test void shouldRemoveAllDocumentsByTenantIdOnDeleteAllEvent() { - var locationId = randomId(); - var location = LocationDto.builder().id(locationId) - .name("location name") - .code("CODE") - .build(); + var location = location(); var createCentralEvent = kafkaResourceEvent(CENTRAL_TENANT_ID, CREATE, toMap(location), null); var createMemberEvent = kafkaResourceEvent(MEMBER_TENANT_ID, CREATE, toMap(location), null); kafkaTemplate.send(inventoryLocationTopic(CENTRAL_TENANT_ID), createCentralEvent); @@ -100,4 +91,22 @@ public static void awaitAssertLocationCount(int expected) { }); } + private LocationDto location() { + var id = randomId(); + return LocationDto.builder().id(id) + .name("location name") + .code("CODE") + .campusId(id) + .institutionId(id) + .description("desc") + .discoveryDisplayName("display name") + .primaryServicePoint(UUID.fromString(id)) + .isActive(true) + .servicePointIds(List.of(UUID.fromString(id))) + .metadata(new Metadata() + .createdDate("2021-03-01T00:00:00.000+00:00") + .updatedDate("2021-03-01T00:00:00.000+00:00")) + .build(); + } + } diff --git a/src/test/java/org/folio/search/service/consortium/ConsortiumLocationServiceTest.java b/src/test/java/org/folio/search/service/consortium/ConsortiumLocationServiceTest.java index 988d8f932..4b41f223d 100644 --- a/src/test/java/org/folio/search/service/consortium/ConsortiumLocationServiceTest.java +++ b/src/test/java/org/folio/search/service/consortium/ConsortiumLocationServiceTest.java @@ -7,6 +7,7 @@ import static org.mockito.Mockito.when; import java.util.List; +import java.util.UUID; import java.util.function.Supplier; import org.folio.search.domain.dto.ConsortiumLocation; import org.folio.search.domain.dto.SortOrder; @@ -24,7 +25,7 @@ @ExtendWith(MockitoExtension.class) public class ConsortiumLocationServiceTest { - public static final String ID = "id"; + public static final String ID = UUID.randomUUID().toString(); public static final String LOCATION_NAME = "location name"; public static final String CONSORTIUM_TENANT = "consortium"; public static final String NAME = "name"; @@ -53,21 +54,23 @@ void fetchLocations_ValidSortBy() { var actual = service.fetchLocations(tenantHeader, tenantId, limit, offset, sortBy, sortOrder); - assertThat(actual).isNotNull(); - assertThat(actual.getRecords()).hasSize(1); - assertThat(actual.getRecords().get(0).getTenantId()).isEqualTo(CONSORTIUM_TENANT); - assertThat(actual.getRecords().get(0).getName()).isEqualTo(LOCATION_NAME); - assertThat(actual.getRecords().get(0).getId()).isEqualTo(ID); + assertThat(actual).isEqualTo(searchResult); verify(repository).fetchLocations(tenantHeader, tenantId, limit, offset, sortBy, sortOrder); verify(executor).execute(eq(tenantId), any(Supplier.class)); } @NotNull private static SearchResult prepareSearchResult() { - var location = new ConsortiumLocation(); - location.setId(ID); - location.setName(LOCATION_NAME); - location.setTenantId(CONSORTIUM_TENANT); + var location = new ConsortiumLocation() + .id(ID) + .name(LOCATION_NAME) + .tenantId(CONSORTIUM_TENANT) + .description("desc") + .discoveryDisplayName("display-name") + .campusId(ID) + .libraryId(ID) + .institutionId(ID) + .servicePointIds(List.of(UUID.fromString(ID))); var searchResult = new SearchResult(); searchResult.records(List.of(location));