From fabdc6706afdd6b9d3e9512dd3e10bb343155f7d Mon Sep 17 00:00:00 2001 From: saba_zedginidze Date: Thu, 12 Sep 2024 20:57:50 +0400 Subject: [PATCH] [MODORDERS-1174] Filter pieces based on user affiliations --- ramls/acq-models | 2 +- .../org/folio/config/ApplicationConfig.java | 12 ++++- .../orders/utils/RequestContextUtil.java | 4 ++ .../orders/utils/ResourcePathResolver.java | 3 ++ .../ConsortiumUserTenantsRetriever.java | 48 +++++++++++++++++++ .../service/pieces/PieceStorageService.java | 35 ++++++++++++-- .../service/pieces/util/UserTenantFields.java | 19 ++++++++ .../CirculationRequestsRetrieverTest.java | 18 ++++++- .../OrderLineUpdateInstanceHandlerTest.java | 18 +++++-- .../pieces/PieceStorageServiceTest.java | 19 +++++++- 10 files changed, 163 insertions(+), 15 deletions(-) create mode 100644 src/main/java/org/folio/service/consortium/ConsortiumUserTenantsRetriever.java create mode 100644 src/main/java/org/folio/service/pieces/util/UserTenantFields.java diff --git a/ramls/acq-models b/ramls/acq-models index f28215d2e..c1f931704 160000 --- a/ramls/acq-models +++ b/ramls/acq-models @@ -1 +1 @@ -Subproject commit f28215d2ee2b2582f96f65b91c388f4ac7395f46 +Subproject commit c1f931704fc6d2dedfc671e308b27f56499750a7 diff --git a/src/main/java/org/folio/config/ApplicationConfig.java b/src/main/java/org/folio/config/ApplicationConfig.java index face26fd4..563e2e3c9 100644 --- a/src/main/java/org/folio/config/ApplicationConfig.java +++ b/src/main/java/org/folio/config/ApplicationConfig.java @@ -31,6 +31,7 @@ import org.folio.service.caches.InventoryCache; import org.folio.service.configuration.ConfigurationEntriesService; import org.folio.service.consortium.ConsortiumConfigurationService; +import org.folio.service.consortium.ConsortiumUserTenantsRetriever; import org.folio.service.consortium.SharingInstanceService; import org.folio.service.exchange.ExchangeRateProviderResolver; import org.folio.service.exchange.FinanceExchangeRateService; @@ -521,8 +522,10 @@ PieceChangeReceiptStatusPublisher receiptStatusPublisher() { } @Bean - PieceStorageService pieceStorageService(RestClient restClient) { - return new PieceStorageService(restClient); + PieceStorageService pieceStorageService(ConsortiumConfigurationService consortiumConfigurationService, + ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever, + RestClient restClient) { + return new PieceStorageService(consortiumConfigurationService, consortiumUserTenantsRetriever, restClient); } @Bean @@ -848,6 +851,11 @@ ConsortiumConfigurationService consortiumConfigurationService(RestClient restCli return new ConsortiumConfigurationService(restClient); } + @Bean + ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever(RestClient restClient) { + return new ConsortiumUserTenantsRetriever(restClient); + } + @Bean SharingInstanceService sharingInstanceService(RestClient restClient) { return new SharingInstanceService(restClient); diff --git a/src/main/java/org/folio/orders/utils/RequestContextUtil.java b/src/main/java/org/folio/orders/utils/RequestContextUtil.java index dbd6ac27c..8097f677d 100644 --- a/src/main/java/org/folio/orders/utils/RequestContextUtil.java +++ b/src/main/java/org/folio/orders/utils/RequestContextUtil.java @@ -22,4 +22,8 @@ public static RequestContext createContextWithNewTenantId(RequestContext request return new RequestContext(requestContext.getContext(), modifiedHeaders); } + public static String getUserIdFromContext(RequestContext requestContext) { + return requestContext.getHeaders().get(XOkapiHeaders.USER_ID); + } + } diff --git a/src/main/java/org/folio/orders/utils/ResourcePathResolver.java b/src/main/java/org/folio/orders/utils/ResourcePathResolver.java index f481313a6..520b8d846 100644 --- a/src/main/java/org/folio/orders/utils/ResourcePathResolver.java +++ b/src/main/java/org/folio/orders/utils/ResourcePathResolver.java @@ -53,6 +53,8 @@ private ResourcePathResolver() { public static final String ROUTING_LISTS = "routingLists"; public static final String ORDER_SETTINGS = "orderSettings"; public static final String USERS = "users"; + public static final String CONSORTIA_USER_TENANTS = "consortia.user-tenants"; + private static final Map SUB_OBJECT_ITEM_APIS; private static final Map SUB_OBJECT_COLLECTION_APIS; @@ -96,6 +98,7 @@ private ResourcePathResolver() { apis.put(EXPORT_HISTORY, "/orders-storage/export-history"); apis.put(TAGS, "/tags"); apis.put(USERS, "/users"); + apis.put(CONSORTIA_USER_TENANTS, "/consortia/:id/user-tenants"); apis.put(ORDER_SETTINGS, "/orders-storage/settings"); apis.put(ROUTING_LISTS, "/orders-storage/routing-lists"); diff --git a/src/main/java/org/folio/service/consortium/ConsortiumUserTenantsRetriever.java b/src/main/java/org/folio/service/consortium/ConsortiumUserTenantsRetriever.java new file mode 100644 index 000000000..b69b98fda --- /dev/null +++ b/src/main/java/org/folio/service/consortium/ConsortiumUserTenantsRetriever.java @@ -0,0 +1,48 @@ +package org.folio.service.consortium; + +import io.vertx.core.Future; +import io.vertx.core.json.JsonObject; +import org.folio.rest.core.RestClient; +import org.folio.rest.core.models.RequestContext; +import org.folio.rest.core.models.RequestEntry; + +import java.util.List; +import java.util.stream.IntStream; + +import static org.folio.orders.utils.RequestContextUtil.getUserIdFromContext; +import static org.folio.orders.utils.ResourcePathResolver.CONSORTIA_USER_TENANTS; +import static org.folio.orders.utils.ResourcePathResolver.resourcesPath; +import static org.folio.service.pieces.util.UserTenantFields.COLLECTION_USER_TENANTS; +import static org.folio.service.pieces.util.UserTenantFields.TENANT_ID; +import static org.folio.service.pieces.util.UserTenantFields.USER_ID; + +public class ConsortiumUserTenantsRetriever { + + private static final String CONSORTIA_USER_TENANTS_ENDPOINT = resourcesPath(CONSORTIA_USER_TENANTS); + + private final RestClient restClient; + + public ConsortiumUserTenantsRetriever(RestClient restClient) { + this.restClient = restClient; + } + + public Future> getUserTenants(String consortiumId, RequestContext requestContext) { + var userId = getUserIdFromContext(requestContext); + var requestEntry = new RequestEntry(CONSORTIA_USER_TENANTS_ENDPOINT) + .withOffset(0) + .withLimit(Integer.MAX_VALUE) + .withId(consortiumId) + .withQueryParameter(USER_ID.getValue(), userId); + return restClient.getAsJsonObject(requestEntry, requestContext) + .map(this::extractTenantIds); + } + + private List extractTenantIds(JsonObject userTenantCollection) { + var userTenants = userTenantCollection.getJsonArray(COLLECTION_USER_TENANTS.getValue()); + return IntStream.range(0, userTenants.size()) + .mapToObj(userTenants::getJsonObject) + .map(userTenant -> userTenant.getString(TENANT_ID.getValue())) + .toList(); + } + +} diff --git a/src/main/java/org/folio/service/pieces/PieceStorageService.java b/src/main/java/org/folio/service/pieces/PieceStorageService.java index ba270d6b9..c67194e0f 100644 --- a/src/main/java/org/folio/service/pieces/PieceStorageService.java +++ b/src/main/java/org/folio/service/pieces/PieceStorageService.java @@ -11,6 +11,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import org.apache.logging.log4j.LogManager; @@ -24,6 +25,8 @@ import org.folio.rest.jaxrs.model.PieceCollection; import io.vertx.core.Future; +import org.folio.service.consortium.ConsortiumUserTenantsRetriever; +import org.folio.service.consortium.ConsortiumConfigurationService; public class PieceStorageService { private static final Logger logger = LogManager.getLogger(PieceStorageService.class); @@ -33,9 +36,15 @@ public class PieceStorageService { private static final String PIECE_STORAGE_ENDPOINT = resourcesPath(PIECES_STORAGE); private static final String PIECE_STORAGE_BY_ID_ENDPOINT = PIECE_STORAGE_ENDPOINT + "/{id}"; + private final ConsortiumConfigurationService consortiumConfigurationService; + private final ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever; private final RestClient restClient; - public PieceStorageService(RestClient restClient) { + public PieceStorageService(ConsortiumConfigurationService consortiumConfigurationService, + ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever, + RestClient restClient) { + this.consortiumConfigurationService = consortiumConfigurationService; + this.consortiumUserTenantsRetriever = consortiumUserTenantsRetriever; this.restClient = restClient; } @@ -110,10 +119,26 @@ public Future> getPiecesByHoldingId(String holdingId, RequestContext } public Future getPieces(int limit, int offset, String query, RequestContext requestContext) { - RequestEntry requestEntry = new RequestEntry(PIECE_STORAGE_ENDPOINT).withQuery(query) - .withOffset(offset) - .withLimit(limit); - return restClient.get(requestEntry, PieceCollection.class, requestContext); + var requestEntry = new RequestEntry(PIECE_STORAGE_ENDPOINT).withQuery(query).withOffset(offset).withLimit(limit); + return restClient.get(requestEntry, PieceCollection.class, requestContext) + .compose(piecesCollection -> filterPiecesByUserTenantsIfNecessary(piecesCollection.getPieces(), requestContext)) + .map(pieces -> new PieceCollection().withPieces(pieces).withTotalRecords(pieces.size())); + } + + private Future> filterPiecesByUserTenantsIfNecessary(List pieces, RequestContext requestContext) { + return consortiumConfigurationService.getConsortiumConfiguration(requestContext) + .compose(consortiumConfiguration -> consortiumConfiguration + .map(configuration -> consortiumUserTenantsRetriever.getUserTenants(configuration.consortiumId(), requestContext) + .map(userTenants -> filterPiecesByUserTenants(pieces, userTenants))) + .orElse(Future.succeededFuture(pieces))); + } + + private List filterPiecesByUserTenants(List pieces, List userTenants) { + return pieces.stream() + .filter(piece -> Optional.ofNullable(piece.getReceivingTenantId()) + .map(userTenants::contains) + .orElse(true)) + .toList(); } public Future> getPiecesByIds(List pieceIds, RequestContext requestContext) { diff --git a/src/main/java/org/folio/service/pieces/util/UserTenantFields.java b/src/main/java/org/folio/service/pieces/util/UserTenantFields.java new file mode 100644 index 000000000..217c1a999 --- /dev/null +++ b/src/main/java/org/folio/service/pieces/util/UserTenantFields.java @@ -0,0 +1,19 @@ +package org.folio.service.pieces.util; + +public enum UserTenantFields { + + USER_ID("userId"), + TENANT_ID("tenantId"), + COLLECTION_USER_TENANTS("userTenants"); + + private final String value; + + UserTenantFields(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + +} diff --git a/src/test/java/org/folio/service/CirculationRequestsRetrieverTest.java b/src/test/java/org/folio/service/CirculationRequestsRetrieverTest.java index 93ccb3034..bb2f71a1d 100644 --- a/src/test/java/org/folio/service/CirculationRequestsRetrieverTest.java +++ b/src/test/java/org/folio/service/CirculationRequestsRetrieverTest.java @@ -11,6 +11,8 @@ import org.folio.rest.core.models.RequestContext; import org.folio.rest.core.models.RequestEntry; import org.folio.rest.jaxrs.model.PieceCollection; +import org.folio.service.consortium.ConsortiumConfigurationService; +import org.folio.service.consortium.ConsortiumUserTenantsRetriever; import org.folio.service.pieces.PieceStorageService; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; @@ -235,8 +237,10 @@ public RestClient restClient() { } @Bean - public PieceStorageService pieceStorageService(RestClient restClient) { - return spy(new PieceStorageService(restClient)); + public PieceStorageService pieceStorageService(ConsortiumConfigurationService consortiumConfigurationService, + ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever, + RestClient restClient) { + return spy(new PieceStorageService(consortiumConfigurationService, consortiumUserTenantsRetriever, restClient)); } @Bean @@ -244,6 +248,16 @@ public CirculationRequestsRetriever circulationRequestsRetriever(PieceStorageSer return new CirculationRequestsRetriever(pieceStorageService, restClient); } + @Bean + ConsortiumConfigurationService consortiumConfigurationService(RestClient restClient) { + return new ConsortiumConfigurationService(restClient); + } + + @Bean + ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever(RestClient restClient) { + return new ConsortiumUserTenantsRetriever(restClient); + } + } } diff --git a/src/test/java/org/folio/service/orders/lines/update/OrderLineUpdateInstanceHandlerTest.java b/src/test/java/org/folio/service/orders/lines/update/OrderLineUpdateInstanceHandlerTest.java index 41f7d91cc..8fb9947b0 100644 --- a/src/test/java/org/folio/service/orders/lines/update/OrderLineUpdateInstanceHandlerTest.java +++ b/src/test/java/org/folio/service/orders/lines/update/OrderLineUpdateInstanceHandlerTest.java @@ -39,6 +39,7 @@ import org.folio.service.caches.InventoryCache; import org.folio.service.configuration.ConfigurationEntriesService; import org.folio.service.consortium.ConsortiumConfigurationService; +import org.folio.service.consortium.ConsortiumUserTenantsRetriever; import org.folio.service.consortium.SharingInstanceService; import org.folio.service.inventory.InventoryHoldingManager; import org.folio.service.inventory.InventoryItemManager; @@ -221,19 +222,30 @@ static class ContextConfiguration { return new ProtectionService(acquisitionsUnitsService); } - @Bean PieceStorageService pieceStorageService(RestClient restClient) { - return new PieceStorageService(restClient); + @Bean PieceStorageService pieceStorageService(ConsortiumConfigurationService consortiumConfigurationService, + ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever, + RestClient restClient) { + return new PieceStorageService(consortiumConfigurationService, consortiumUserTenantsRetriever, restClient); } + @Bean InventoryService inventoryService (RestClient restClient) { return new InventoryService(restClient); } + @Bean SharingInstanceService sharingInstanceService (RestClient restClient) { return new SharingInstanceService(restClient); } - @Bean ConsortiumConfigurationService consortiumConfigurationService (RestClient restClient) { + + @Bean + ConsortiumConfigurationService consortiumConfigurationService(RestClient restClient) { return new ConsortiumConfigurationService(restClient); } + @Bean + ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever(RestClient restClient) { + return new ConsortiumUserTenantsRetriever(restClient); + } + @Bean PurchaseOrderStorageService purchaseOrderStorageService () { return mock(PurchaseOrderStorageService.class); } diff --git a/src/test/java/org/folio/service/pieces/PieceStorageServiceTest.java b/src/test/java/org/folio/service/pieces/PieceStorageServiceTest.java index dc4c3bfb0..dbcddbc92 100644 --- a/src/test/java/org/folio/service/pieces/PieceStorageServiceTest.java +++ b/src/test/java/org/folio/service/pieces/PieceStorageServiceTest.java @@ -32,6 +32,8 @@ import org.folio.rest.jaxrs.model.Piece; import org.folio.rest.jaxrs.model.PieceCollection; import org.folio.service.ProtectionService; +import org.folio.service.consortium.ConsortiumConfigurationService; +import org.folio.service.consortium.ConsortiumUserTenantsRetriever; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; @@ -136,8 +138,21 @@ private static class ContextConfiguration { return mock(ProtectionService.class); } - @Bean PieceStorageService pieceStorageService(RestClient restClient, ProtectionService protectionService) { - return spy(new PieceStorageService(restClient)); + @Bean PieceStorageService pieceStorageService(ConsortiumConfigurationService consortiumConfigurationService, + ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever, + RestClient restClient) { + return spy(new PieceStorageService(consortiumConfigurationService, consortiumUserTenantsRetriever, restClient)); } + + @Bean + ConsortiumConfigurationService consortiumConfigurationService(RestClient restClient) { + return new ConsortiumConfigurationService(restClient); + } + + @Bean + ConsortiumUserTenantsRetriever consortiumUserTenantsRetriever(RestClient restClient) { + return new ConsortiumUserTenantsRetriever(restClient); + } + } }