Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
9 changes: 9 additions & 0 deletions ramls/providers.raml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions ramls/types/packages/packageCollectionItem.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -21,22 +26,27 @@
public class PackageCollectionResultConverter implements Converter<PackageCollectionResult, PackageCollection> {

private final Converter<PackageData, PackageCollectionItem> packageCollectionItemConverter;
private final Converter<DbAccessType, AccessType> accessTypeConverter;

public PackageCollectionResultConverter(
Converter<PackageData, PackageCollectionItem> packageCollectionItemConverter) {
Converter<PackageData, PackageCollectionItem> packageCollectionItemConverter,
Converter<DbAccessType, AccessType> accessTypeConverter) {
this.packageCollectionItemConverter = packageCollectionItemConverter;
this.accessTypeConverter = accessTypeConverter;
}

@Override
public PackageCollection convert(PackageCollectionResult packagesResult) {
Packages packages = packagesResult.packages();
List<DbPackage> dbPackages = packagesResult.dbPackages();
List<PackageCollectionItem> 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;
});

Expand All @@ -46,6 +56,23 @@ public PackageCollection convert(PackageCollectionResult packagesResult) {
.withData(packageList);
}

private void addAccessType(PackageCollectionItem item, String packageFullId,
Map<String, DbAccessType> 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<String> getTagsById(List<DbPackage> packages, PackageId packageId) {
return packages.stream()
.filter(dbPackage -> dbPackage.getId().equals(packageId))
Expand Down
44 changes: 32 additions & 12 deletions src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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<ProviderPutRequest, VendorPut> putRequestConverter;
Expand All @@ -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;
Expand Down Expand Up @@ -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<String> filterTags,
List<String> filterAccessType, String filterSelected,
String filterType, String filterVisibility, String filterAccess,
Expand All @@ -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));
Expand All @@ -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 ->
Expand All @@ -241,13 +249,32 @@ public void getEholdingsProvidersPackagesByProviderId(String providerId, String
}

private Function<RmApiTemplateContext, CompletableFuture<?>> retrieveFilteredPackages(int providerId,
PackageRecordFilter filter) {
PackageRecordFilter filter,
List<String> 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<PackageCollectionResult> loadTagsAndAccessTypes(Packages packages,
List<String> 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<VendorResult> loadTags(VendorResult result, RmApiTemplateContext context) {
Expand All @@ -258,13 +285,6 @@ private CompletableFuture<VendorResult> loadTags(VendorResult result, RmApiTempl
return relatedEntitiesLoader.loadTags(result, recordKey, context).thenApply(v -> result);
}

private CompletableFuture<PackageCollectionResult> 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<Void> updateTags(DbProvider provider, Tags tags, String tenant) {
if (Objects.isNull(tags)) {
return completedFuture(null);
Expand Down
Original file line number Diff line number Diff line change
@@ -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<DbPackage> dbPackages) { }
public record PackageCollectionResult(Packages packages, List<DbPackage> dbPackages,
Map<String, DbAccessType> accessTypes) {

public PackageCollectionResult(Packages packages, List<DbPackage> dbPackages) {
this(packages, dbPackages, Collections.emptyMap());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@
"id": "19"
}
}
}
},
"included": []
},
"included": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
"included": false
}
}
}
},
"included": []
}
],
"meta": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,8 @@
"included": false
}
}
}
},
"included": []
}
],
"jsonapi": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@
"included": false
}
}
}
},
"included": []
}
],
"jsonapi": {
Expand Down
Loading