From 505c465f420cdaf1e03b70114e1af2e724ba8625 Mon Sep 17 00:00:00 2001 From: viacheslav_kolesnyk Date: Fri, 28 Aug 2026 13:29:59 +0200 Subject: [PATCH 1/2] feat(providers): Add access types to eholdings/providers/{id}/packages response - Add field to response - Add optional includes API parameter to include new field in response Implements: MODKBEKBJ-839 --- NEWS.md | 1 + ramls/providers.raml | 9 ++++ .../types/packages/packageCollectionItem.json | 8 ++++ .../PackageCollectionResultConverter.java | 39 +++++++++++++--- .../rest/impl/EholdingsProvidersImpl.java | 44 ++++++++++++++----- .../rmapi/result/PackageCollectionResult.java | 11 ++++- ...EholdingsProvidersImplIntegrationTest.java | 32 ++++++++++++++ .../expected-package-by-id-with-provider.json | 3 +- ...d-package-collection-with-one-element.json | 3 +- ...ected-resource-by-id-with-all-objects.json | 3 +- .../expected-resource-by-id-with-package.json | 3 +- 11 files changed, 133 insertions(+), 23 deletions(-) diff --git a/NEWS.md b/NEWS.md index afe03b047..0aae3eeb7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,6 +10,7 @@ * Migrate Package Endpoints to HoldingsIQ v2 API ([MODKBEKBJ-804](https://folio-org.atlassian.net/browse/MODKBEKBJ-804)) * Add additional fields to POST /eholdings/packages endpoint ([MODKBEKBJ-823](https://folio-org.atlassian.net/browse/MODKBEKBJ-823)) * Update visibility hidden reason handling ([MODKBEKBJ-823](https://folio-org.atlassian.net/browse/MODKBEKBJ-823)) +* Add access types to eholdings/providers/{id}/packages response ([MODKBEKBJ-839](https://folio-org.atlassian.net/browse/MODKBEKBJ-839)) ### Bug fixes * Fix offset handling when retrieving holdings from HoldingsIQ. ([MODKBEKBJ-825](https://folio-org.atlassian.net/browse/MODKBEKBJ-825)) diff --git a/ramls/providers.raml b/ramls/providers.raml index a81ae4c3b..4f7b4d012 100644 --- a/ramls/providers.raml +++ b/ramls/providers.raml @@ -132,6 +132,15 @@ traits: is: [packageQueriable, taggable, accessible, packageFilterable, sortable: {defaultValue: 'relevance', possibleValues: 'name, relevance'}, pageable: {maxCountValue: 100, defaultCountValue: 25}] + queryParameters: + include: + displayName: Include access type + type: string + description: | + Include related objects in response + Possible values are + - accessType + required: false responses: 200: description: OK diff --git a/ramls/types/packages/packageCollectionItem.json b/ramls/types/packages/packageCollectionItem.json index 1213ec818..9d8c5cf14 100644 --- a/ramls/types/packages/packageCollectionItem.json +++ b/ramls/types/packages/packageCollectionItem.json @@ -25,6 +25,14 @@ "type": "object", "description": "Displays if any resources are included in relationships", "$ref": "packageRelationships.json" + }, + "included": { + "type": "array", + "description": "List of included objects", + "items": { + "type": "object", + "javaType": "java.lang.Object" + } } } } diff --git a/src/main/java/org/folio/rest/converter/packages/PackageCollectionResultConverter.java b/src/main/java/org/folio/rest/converter/packages/PackageCollectionResultConverter.java index 628ede9b3..9b6c89133 100644 --- a/src/main/java/org/folio/rest/converter/packages/PackageCollectionResultConverter.java +++ b/src/main/java/org/folio/rest/converter/packages/PackageCollectionResultConverter.java @@ -4,13 +4,18 @@ import java.util.Collections; import java.util.List; +import java.util.Map; import org.folio.holdingsiq.model.PackageData; import org.folio.holdingsiq.model.PackageId; -import org.folio.holdingsiq.model.Packages; +import org.folio.repository.accesstypes.DbAccessType; import org.folio.repository.packages.DbPackage; +import org.folio.rest.jaxrs.model.AccessType; +import org.folio.rest.jaxrs.model.HasOneRelationship; +import org.folio.rest.jaxrs.model.MetaDataIncluded; import org.folio.rest.jaxrs.model.MetaTotalResults; import org.folio.rest.jaxrs.model.PackageCollection; import org.folio.rest.jaxrs.model.PackageCollectionItem; +import org.folio.rest.jaxrs.model.RelationshipData; import org.folio.rest.jaxrs.model.Tags; import org.folio.rest.util.RestConstants; import org.folio.rmapi.result.PackageCollectionResult; @@ -21,22 +26,27 @@ public class PackageCollectionResultConverter implements Converter { private final Converter packageCollectionItemConverter; + private final Converter accessTypeConverter; public PackageCollectionResultConverter( - Converter packageCollectionItemConverter) { + Converter packageCollectionItemConverter, + Converter accessTypeConverter) { this.packageCollectionItemConverter = packageCollectionItemConverter; + this.accessTypeConverter = accessTypeConverter; } @Override public PackageCollection convert(PackageCollectionResult packagesResult) { - Packages packages = packagesResult.packages(); - List dbPackages = packagesResult.dbPackages(); - List packageList = mapItems(packages.getPackagesList(), + var packages = packagesResult.packages(); + var dbPackages = packagesResult.dbPackages(); + var accessTypes = packagesResult.accessTypes(); + var packageList = mapItems(packages.getPackagesList(), packageData -> { - PackageCollectionItem item = packageCollectionItemConverter.convert(packageData); + var item = packageCollectionItemConverter.convert(packageData); item.getAttributes() .withTags(new Tags() .withTagList(getTagsById(dbPackages, createPackageId(packageData)))); + addAccessType(item, packageData.getFullPackageId(), accessTypes); return item; }); @@ -46,6 +56,23 @@ public PackageCollection convert(PackageCollectionResult packagesResult) { .withData(packageList); } + private void addAccessType(PackageCollectionItem item, String packageFullId, + Map accessTypes) { + var dbAccessType = accessTypes.get(packageFullId); + if (dbAccessType == null) { + return; + } + var accessType = accessTypeConverter.convert(dbAccessType); + item.getIncluded().add(accessType); + item.getRelationships() + .withAccessType(new HasOneRelationship() + .withData(new RelationshipData() + .withId(accessType.getId()) + .withType(AccessType.Type.ACCESS_TYPES.value())) + .withMeta(new MetaDataIncluded() + .withIncluded(true))); + } + private List getTagsById(List packages, PackageId packageId) { return packages.stream() .filter(dbPackage -> dbPackage.getId().equals(packageId)) diff --git a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java index b6538ee62..0ef80cb8c 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java @@ -2,6 +2,7 @@ import static java.util.Collections.emptyList; import static java.util.concurrent.CompletableFuture.completedFuture; +import static org.folio.common.ListUtils.parseByComma; import static org.folio.db.RowSetUtils.toUUID; import static org.folio.rest.util.ExceptionMappers.error422InputValidationMapper; import static org.folio.rest.util.IdParser.getPackageIds; @@ -14,6 +15,7 @@ import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.Vertx; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -60,6 +62,7 @@ import org.folio.rest.validator.ProviderTagsPutBodyValidator; import org.folio.rmapi.result.PackageCollectionResult; import org.folio.rmapi.result.VendorResult; +import org.folio.service.accesstypes.AccessTypesService; import org.folio.service.kbcredentials.UserKbCredentialsService; import org.folio.service.loader.FilteredEntitiesLoader; import org.folio.service.loader.RelatedEntitiesLoader; @@ -72,6 +75,7 @@ public class EholdingsProvidersImpl implements EholdingsProviders { private static final String GET_PROVIDER_NOT_FOUND_MESSAGE = "Provider not found"; + private static final String ACCESS_TYPE_INCLUDE_PARAM = "accessType"; @Autowired private Converter putRequestConverter; @@ -88,6 +92,8 @@ public class EholdingsProvidersImpl implements EholdingsProviders { @Autowired private PackageRepository packageRepository; @Autowired + private AccessTypesService accessTypesService; + @Autowired private RelatedEntitiesLoader relatedEntitiesLoader; @Autowired private FilteredEntitiesLoader filteredEntitiesLoader; @@ -197,7 +203,7 @@ tags, new RequestContext(headers).getTenant()) @Override @Validate @HandleValidationErrors - public void getEholdingsProvidersPackagesByProviderId(String providerId, String q, String queryField, + public void getEholdingsProvidersPackagesByProviderId(String providerId, String include, String q, String queryField, String queryType, boolean highlight, List filterTags, List filterAccessType, String filterSelected, String filterType, String filterVisibility, String filterAccess, @@ -222,7 +228,9 @@ public void getEholdingsProvidersPackagesByProviderId(String providerId, String .count(count) .build(); - RmApiTemplate template = templateFactory.createTemplate(okapiHeaders, asyncResultHandler); + var includedObjects = parseByComma(include); + + var template = templateFactory.createTemplate(okapiHeaders, asyncResultHandler); if (filter.isTagsFilter()) { template.requestAction( context -> filteredEntitiesLoader.fetchPackagesByTagFilter(TagFilter.from(filter), context)); @@ -231,7 +239,7 @@ public void getEholdingsProvidersPackagesByProviderId(String providerId, String .fetchPackagesByAccessTypeFilter(AccessTypeFilter.from(filter), context) .thenApply(packages -> new PackageCollectionResult(packages, emptyList()))); } else { - template.requestAction(retrieveFilteredPackages(parsedProviderId, filter)); + template.requestAction(retrieveFilteredPackages(parsedProviderId, filter, includedObjects)); } template .addErrorMapper(ResourceNotFoundException.class, exception -> @@ -241,13 +249,32 @@ public void getEholdingsProvidersPackagesByProviderId(String providerId, String } private Function> retrieveFilteredPackages(int providerId, - PackageRecordFilter filter) { + PackageRecordFilter filter, + List includedObjects) { var packageFilter = filter.toClientFilter(searchProperties); var pageable = filter.toPageable(); return context -> context.getPackagesService() .retrievePackages(providerId, packageFilter, pageable) - .thenCompose(packages -> loadTags(packages, context)); + .thenCompose(packages -> loadTagsAndAccessTypes(packages, includedObjects, context)); + } + + private CompletableFuture loadTagsAndAccessTypes(Packages packages, + List includedObjects, + RmApiTemplateContext context) { + var credentialsId = toUUID(context.getCredentialsId()); + var tenant = context.getRequestContext().getTenant(); + var tagsFuture = packageRepository.findByIds(getPackageIds(packages), credentialsId, tenant); + if (includedObjects.contains(ACCESS_TYPE_INCLUDE_PARAM)) { + var packageIds = packages.getPackagesList().stream() + .map(packageData -> packageData.getVendorId() + "-" + packageData.getPackageId()) + .toList(); + var accessTypesFuture = accessTypesService.findPerRecord(context.getCredentialsId(), new ArrayList<>(packageIds), + RecordType.PACKAGE, tenant); + return tagsFuture.thenCombine(accessTypesFuture, + (dbPackages, accessTypes) -> new PackageCollectionResult(packages, dbPackages, accessTypes)); + } + return tagsFuture.thenApply(dbPackages -> new PackageCollectionResult(packages, dbPackages)); } private CompletableFuture loadTags(VendorResult result, RmApiTemplateContext context) { @@ -258,13 +285,6 @@ private CompletableFuture loadTags(VendorResult result, RmApiTempl return relatedEntitiesLoader.loadTags(result, recordKey, context).thenApply(v -> result); } - private CompletableFuture loadTags(Packages packages, RmApiTemplateContext context) { - UUID credentialsId = toUUID(context.getCredentialsId()); - String tenant = context.getRequestContext().getTenant(); - return packageRepository.findByIds(getPackageIds(packages), credentialsId, tenant) - .thenApply(dbPackages -> new PackageCollectionResult(packages, dbPackages)); - } - private CompletableFuture updateTags(DbProvider provider, Tags tags, String tenant) { if (Objects.isNull(tags)) { return completedFuture(null); diff --git a/src/main/java/org/folio/rmapi/result/PackageCollectionResult.java b/src/main/java/org/folio/rmapi/result/PackageCollectionResult.java index d092cc123..da0ac81f7 100644 --- a/src/main/java/org/folio/rmapi/result/PackageCollectionResult.java +++ b/src/main/java/org/folio/rmapi/result/PackageCollectionResult.java @@ -1,7 +1,16 @@ package org.folio.rmapi.result; +import java.util.Collections; import java.util.List; +import java.util.Map; import org.folio.holdingsiq.model.Packages; +import org.folio.repository.accesstypes.DbAccessType; import org.folio.repository.packages.DbPackage; -public record PackageCollectionResult(Packages packages, List dbPackages) { } +public record PackageCollectionResult(Packages packages, List dbPackages, + Map accessTypes) { + + public PackageCollectionResult(Packages packages, List dbPackages) { + this(packages, dbPackages, Collections.emptyMap()); + } +} diff --git a/src/test/java/org/folio/rest/impl/EholdingsProvidersImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsProvidersImplIntegrationTest.java index af3f22767..20de3152e 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsProvidersImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsProvidersImplIntegrationTest.java @@ -38,7 +38,9 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import com.github.tomakehurst.wiremock.matching.RegexPattern; @@ -467,6 +469,36 @@ void shouldReturn404WhenNonProviderIdNotFound() { assertErrorContainsTitle(error, "Provider not found"); } + @Test + void shouldReturnProviderPackagesWithAccessTypeWhenIncludeParamPassed() { + var accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); + var expectedAccessTypeId = accessTypes.getFirst().getId(); + insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, expectedAccessTypeId, vertx); + + mockGet(new RegexPattern(providerPackagesRmApi(STUB_VENDOR_ID) + ".*"), readFile(STUB_PACKAGE_RESPONSE)); + + var collection = getWithOk(PROVIDER_PACKAGES + "?include=accessType").as(PackageCollection.class); + var packageItem = collection.getData().getFirst(); + + assertFalse(packageItem.getIncluded().isEmpty()); + assertEquals(expectedAccessTypeId, + packageItem.getRelationships().getAccessType().getData().getId()); + } + + @Test + void shouldReturnProviderPackagesWithoutAccessTypeWhenIncludeParamNotPassed() { + var accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); + insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, accessTypes.getFirst().getId(), vertx); + + mockGet(new RegexPattern(providerPackagesRmApi(STUB_VENDOR_ID) + ".*"), readFile(STUB_PACKAGE_RESPONSE)); + + var collection = getWithOk(PROVIDER_PACKAGES).as(PackageCollection.class); + var packageItem = collection.getData().getFirst(); + + assertTrue(packageItem.getIncluded().isEmpty()); + assertNull(packageItem.getRelationships().getAccessType()); + } + private String getPackageResponse(String packageName, int packageId, int providerId) { PackageData packageData = readJsonFile(STUB_PACKAGE_JSON_PATH, PackageData.class); return Json.encode(packageData.toBuilder() diff --git a/src/test/resources/responses/kb-ebsco/packages/expected-package-by-id-with-provider.json b/src/test/resources/responses/kb-ebsco/packages/expected-package-by-id-with-provider.json index de2576c89..371fe06af 100644 --- a/src/test/resources/responses/kb-ebsco/packages/expected-package-by-id-with-provider.json +++ b/src/test/resources/responses/kb-ebsco/packages/expected-package-by-id-with-provider.json @@ -52,7 +52,8 @@ "id": "19" } } - } + }, + "included": [] }, "included": [ { diff --git a/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-one-element.json b/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-one-element.json index 9a17870c7..0c9c6fd6d 100644 --- a/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-one-element.json +++ b/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-one-element.json @@ -38,7 +38,8 @@ "included": false } } - } + }, + "included": [] } ], "meta": { diff --git a/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-all-objects.json b/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-all-objects.json index 87633804e..ae19510ca 100644 --- a/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-all-objects.json +++ b/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-all-objects.json @@ -225,7 +225,8 @@ "included": false } } - } + }, + "included": [] } ], "jsonapi": { diff --git a/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-package.json b/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-package.json index c7a05bbaa..1bb254e70 100644 --- a/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-package.json +++ b/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-package.json @@ -148,7 +148,8 @@ "included": false } } - } + }, + "included": [] } ], "jsonapi": { From 9cb228f1fb77f37cdd309bc8f8859be3e5866f15 Mon Sep 17 00:00:00 2001 From: viacheslav_kolesnyk Date: Tue, 1 Sep 2026 13:22:32 +0200 Subject: [PATCH 2/2] Refactor --- .../rest/impl/EholdingsPackagesImpl.java | 6 +- .../rest/impl/EholdingsProvidersImpl.java | 12 +-- .../service/loader/RelatedEntitiesLoader.java | 7 ++ .../loader/RelatedEntitiesLoaderImpl.java | 13 +++ .../PackageCollectionResultConverterTest.java | 81 +++++++++++++++++++ 5 files changed, 106 insertions(+), 13 deletions(-) create mode 100644 src/test/java/org/folio/rest/converter/packages/PackageCollectionResultConverterTest.java diff --git a/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java index 8ddd8a104..449789c81 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java @@ -453,10 +453,8 @@ private Function> RmApiTemplateContext context) { return titleCollection -> { Map resourceIdToAccessType = mapResourceIdToTitleResult(titleCollection); - String credentialsId = context.getCredentialsId(); - String tenant = context.getRequestContext().getTenant(); - return accessTypesService.findPerRecord(credentialsId, new ArrayList<>(resourceIdToAccessType.keySet()), - RecordType.RESOURCE, tenant) + return relatedEntitiesLoader.loadAccessTypes(new ArrayList<>(resourceIdToAccessType.keySet()), + RecordType.RESOURCE, context) .thenApply(accessTypeMap -> { populateResourceAccessTypes(resourceIdToAccessType, accessTypeMap); return titleCollection; diff --git a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java index 0ef80cb8c..2ece7131e 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java @@ -15,7 +15,6 @@ import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.Vertx; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -62,7 +61,6 @@ import org.folio.rest.validator.ProviderTagsPutBodyValidator; import org.folio.rmapi.result.PackageCollectionResult; import org.folio.rmapi.result.VendorResult; -import org.folio.service.accesstypes.AccessTypesService; import org.folio.service.kbcredentials.UserKbCredentialsService; import org.folio.service.loader.FilteredEntitiesLoader; import org.folio.service.loader.RelatedEntitiesLoader; @@ -92,8 +90,6 @@ public class EholdingsProvidersImpl implements EholdingsProviders { @Autowired private PackageRepository packageRepository; @Autowired - private AccessTypesService accessTypesService; - @Autowired private RelatedEntitiesLoader relatedEntitiesLoader; @Autowired private FilteredEntitiesLoader filteredEntitiesLoader; @@ -263,15 +259,13 @@ private CompletableFuture loadTagsAndAccessTypes(Packag List includedObjects, RmApiTemplateContext context) { var credentialsId = toUUID(context.getCredentialsId()); - var tenant = context.getRequestContext().getTenant(); - var tagsFuture = packageRepository.findByIds(getPackageIds(packages), credentialsId, tenant); + var tagsFuture = packageRepository.findByIds(getPackageIds(packages), credentialsId, + context.getRequestContext().getTenant()); if (includedObjects.contains(ACCESS_TYPE_INCLUDE_PARAM)) { var packageIds = packages.getPackagesList().stream() .map(packageData -> packageData.getVendorId() + "-" + packageData.getPackageId()) .toList(); - var accessTypesFuture = accessTypesService.findPerRecord(context.getCredentialsId(), new ArrayList<>(packageIds), - RecordType.PACKAGE, tenant); - return tagsFuture.thenCombine(accessTypesFuture, + return tagsFuture.thenCombine(relatedEntitiesLoader.loadAccessTypes(packageIds, RecordType.PACKAGE, context), (dbPackages, accessTypes) -> new PackageCollectionResult(packages, dbPackages, accessTypes)); } return tagsFuture.thenApply(dbPackages -> new PackageCollectionResult(packages, dbPackages)); diff --git a/src/main/java/org/folio/service/loader/RelatedEntitiesLoader.java b/src/main/java/org/folio/service/loader/RelatedEntitiesLoader.java index 9794fbc4d..240276e50 100644 --- a/src/main/java/org/folio/service/loader/RelatedEntitiesLoader.java +++ b/src/main/java/org/folio/service/loader/RelatedEntitiesLoader.java @@ -1,7 +1,11 @@ package org.folio.service.loader; +import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import org.folio.repository.RecordKey; +import org.folio.repository.RecordType; +import org.folio.repository.accesstypes.DbAccessType; import org.folio.rest.util.template.RmApiTemplateContext; import org.folio.rmapi.result.Accessible; import org.folio.rmapi.result.Tagable; @@ -11,4 +15,7 @@ public interface RelatedEntitiesLoader { CompletableFuture loadAccessType(Accessible accessible, RecordKey recordKey, RmApiTemplateContext context); CompletableFuture loadTags(Tagable tagable, RecordKey recordKey, RmApiTemplateContext context); + + CompletableFuture> loadAccessTypes(List recordIds, RecordType recordType, + RmApiTemplateContext context); } diff --git a/src/main/java/org/folio/service/loader/RelatedEntitiesLoaderImpl.java b/src/main/java/org/folio/service/loader/RelatedEntitiesLoaderImpl.java index b4b1ccff5..f99ae33fd 100644 --- a/src/main/java/org/folio/service/loader/RelatedEntitiesLoaderImpl.java +++ b/src/main/java/org/folio/service/loader/RelatedEntitiesLoaderImpl.java @@ -1,10 +1,14 @@ package org.folio.service.loader; +import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import javax.ws.rs.NotFoundException; import lombok.extern.log4j.Log4j2; import org.folio.repository.RecordKey; +import org.folio.repository.RecordType; +import org.folio.repository.accesstypes.DbAccessType; import org.folio.repository.tag.DbTag; import org.folio.repository.tag.TagRepository; import org.folio.rest.jaxrs.model.Tags; @@ -48,6 +52,15 @@ public CompletableFuture loadAccessType(Accessible accessible, RecordKey r return future; } + @Override + public CompletableFuture> loadAccessTypes(List recordIds, RecordType recordType, + RmApiTemplateContext context) { + log.debug("loadAccessTypes:: by [recordIds count: {}, recordType: {}]", recordIds.size(), recordType); + String tenant = context.getRequestContext().getTenant(); + return accessTypesService.findPerRecord(context.getCredentialsId(), new ArrayList<>(recordIds), recordType, tenant) + .toCompletableFuture(); + } + @Override public CompletableFuture loadTags(Tagable tagable, RecordKey recordKey, RmApiTemplateContext context) { String tenant = context.getRequestContext().getTenant(); diff --git a/src/test/java/org/folio/rest/converter/packages/PackageCollectionResultConverterTest.java b/src/test/java/org/folio/rest/converter/packages/PackageCollectionResultConverterTest.java new file mode 100644 index 000000000..cef6db1bf --- /dev/null +++ b/src/test/java/org/folio/rest/converter/packages/PackageCollectionResultConverterTest.java @@ -0,0 +1,81 @@ +package org.folio.rest.converter.packages; + +import static org.folio.util.TestUtil.readJsonFile; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Collections; +import java.util.Map; +import java.util.UUID; +import org.folio.holdingsiq.model.Packages; +import org.folio.repository.accesstypes.DbAccessType; +import org.folio.rest.jaxrs.model.AccessType; +import org.folio.rest.jaxrs.model.PackageCollection; +import org.folio.rmapi.result.PackageCollectionResult; +import org.folio.spring.config.TestConfig; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.convert.ConversionService; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = TestConfig.class) +class PackageCollectionResultConverterTest { + + private static final String PACKAGES_FIXTURE = "responses/rmapi/packages/get-packages-by-provider-id.json"; + private static final String PACKAGE_FULL_ID = "19-3964"; + private static final String ACCESS_TYPE_NAME = "Subscribed"; + private static final String ACCESS_TYPE_DESCRIPTION = "Access Type description"; + + @Autowired + private ConversionService conversionService; + + @Test + void shouldIncludeAccessTypeInPackageItemWhenAccessTypeIsMapped() { + var packages = readJsonFile(PACKAGES_FIXTURE, Packages.class); + var accessTypeId = UUID.randomUUID(); + var credentialsId = UUID.randomUUID(); + var dbAccessType = DbAccessType.builder() + .id(accessTypeId) + .credentialsId(credentialsId) + .name(ACCESS_TYPE_NAME) + .description(ACCESS_TYPE_DESCRIPTION) + .build(); + Map accessTypes = Map.of(PACKAGE_FULL_ID, dbAccessType); + var result = new PackageCollectionResult(packages, Collections.emptyList(), accessTypes); + + var packageCollection = conversionService.convert(result, PackageCollection.class); + + assertNotNull(packageCollection); + var item = packageCollection.getData().getFirst(); + + assertEquals(1, item.getIncluded().size()); + var includedAccessType = (AccessType) item.getIncluded().getFirst(); + assertEquals(accessTypeId.toString(), includedAccessType.getId()); + assertEquals(AccessType.Type.ACCESS_TYPES, includedAccessType.getType()); + + var accessTypeRel = item.getRelationships().getAccessType(); + assertNotNull(accessTypeRel); + assertEquals(accessTypeId.toString(), accessTypeRel.getData().getId()); + assertEquals("accessTypes", accessTypeRel.getData().getType()); + assertTrue(accessTypeRel.getMeta().getIncluded()); + } + + @Test + void shouldNotIncludeAccessTypeWhenAccessTypesMapIsEmpty() { + var packages = readJsonFile(PACKAGES_FIXTURE, Packages.class); + var result = new PackageCollectionResult(packages, Collections.emptyList()); + + var packageCollection = conversionService.convert(result, PackageCollection.class); + + assertNotNull(packageCollection); + var item = packageCollection.getData().getFirst(); + + assertTrue(item.getIncluded().isEmpty()); + assertNull(item.getRelationships().getAccessType()); + } +}