diff --git a/NEWS.md b/NEWS.md
index d8deb4f6e..cbc4eee0e 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -8,6 +8,7 @@
### Features
* 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))
### Bug fixes
* Fix offset handling when retrieving holdings from HoldingsIQ. ([MODKBEKBJ-825](https://folio-org.atlassian.net/browse/MODKBEKBJ-825))
diff --git a/pom.xml b/pom.xml
index 627418850..1e3d2391c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -616,6 +616,7 @@
true
+
${project.build.directory}/${project.artifactId}-fat.jar
@@ -627,6 +628,7 @@
**/log4j.properties
**/Log4j2Plugins.dat
+ module-info.class
diff --git a/ramls/types/packages/packagePostDataAttributes.json b/ramls/types/packages/packagePostDataAttributes.json
index 3e372c3c6..6a5d9145d 100644
--- a/ramls/types/packages/packagePostDataAttributes.json
+++ b/ramls/types/packages/packagePostDataAttributes.json
@@ -6,26 +6,57 @@
"javaType": "org.folio.rest.jaxrs.model.PackagePostDataAttributes",
"additionalProperties": false,
"properties": {
- "name": {
+ "accessTypeId": {
"type": "string",
- "description": "Package name",
- "example": "Advanced Placement Psychology Collection"
+ "description": "Access type id",
+ "$ref": "../../raml-util/schemas/uuid.schema",
+ "example": "f973c3b6-85fc-4d35-bda8-f31b568957bf"
},
"contentType": {
"type": "string",
"description": "Package content type",
"$ref": "contentTypeEnum.json"
- },
- "accessTypeId": {
- "type": "string",
- "description": "Access type id",
- "$ref": "../../raml-util/schemas/uuid.schema",
- "example": "f973c3b6-85fc-4d35-bda8-f31b568957bf"
+ },
+ "customAltNames": {
+ "description": "The list of custom alternate names for the package",
+ "items": {
+ "$ref": "packageAltName.json",
+ "type": "object"
+ },
+ "type": "array"
},
"customCoverage": {
"type": "object",
"description": "Custom Coverage",
"$ref": "../coverage.json"
+ },
+ "customDescription": {
+ "description": "The custom description of the package",
+ "example": "Package of medicinal journals (custom)",
+ "type": "string"
+ },
+ "customDisplayName": {
+ "description": "The custom description of the package",
+ "type": "string"
+ },
+ "isFreeAccess": {
+ "description": "Whether this package has free access designation or not",
+ "example": false,
+ "type": "boolean"
+ },
+ "name": {
+ "type": "string",
+ "description": "Package name",
+ "example": "Advanced Placement Psychology Collection"
+ },
+ "proxy": {
+ "$ref": "../proxy.json",
+ "description": "Proxy",
+ "type": "object"
+ },
+ "url": {
+ "description": "Package URL",
+ "type": "string"
}
},
"required": [
diff --git a/ramls/types/proxies/proxyUrl.json b/ramls/types/proxies/proxyUrl.json
index 87a11ea4d..3265dd1ae 100644
--- a/ramls/types/proxies/proxyUrl.json
+++ b/ramls/types/proxies/proxyUrl.json
@@ -2,7 +2,7 @@
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Proxy Url Schema",
"description": "Proxy Url Schema",
- "javaType": "org.folio.rest.jaxrs.model.ProxyUrl",
+ "javaType": "org.folio.rest.jaxrs.model.ProxyUrlDto",
"type": "object",
"additionalProperties": false,
"extends": {
diff --git a/ramls/types/proxy.json b/ramls/types/proxy.json
index 49c62b12e..60dd01ec0 100644
--- a/ramls/types/proxy.json
+++ b/ramls/types/proxy.json
@@ -2,7 +2,7 @@
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Proxy Schema",
"description": "Proxy Schema",
- "javaType": "org.folio.rest.jaxrs.model.Proxy",
+ "javaType": "org.folio.rest.jaxrs.model.ProxyDto",
"type": "object",
"additionalProperties": true,
"properties": {
diff --git a/ramls/types/proxyPut.json b/ramls/types/proxyPut.json
deleted file mode 100644
index 8b9331988..000000000
--- a/ramls/types/proxyPut.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-04/schema#",
- "title": "Proxy Schema",
- "description": "Proxy Schema",
- "javaType": "org.folio.rest.jaxrs.model.Proxy",
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "id": {
- "type": "string",
- "description": "Proxy Id",
- "example": "EZProxy"
- }
- }
-}
diff --git a/ramls/types/tokenPut.json b/ramls/types/tokenPut.json
deleted file mode 100644
index b67658b3a..000000000
--- a/ramls/types/tokenPut.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-04/schema#",
- "title": "Token Put Schema",
- "description": "Token Put Schema",
- "javaType": "org.folio.rest.jaxrs.model.TokenPut",
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "value": {
- "type": "string",
- "description": "Value",
- "example": "hellotoken"
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/folio/common/ListUtils.java b/src/main/java/org/folio/common/ListUtils.java
index 462e9776f..278b80b5d 100644
--- a/src/main/java/org/folio/common/ListUtils.java
+++ b/src/main/java/org/folio/common/ListUtils.java
@@ -6,26 +6,25 @@
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
-import java.util.regex.Pattern;
import java.util.stream.Collectors;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.StringUtils;
+import org.jspecify.annotations.Nullable;
@UtilityClass
public class ListUtils {
- private static final Pattern SPLIT_BY_COMMA_PATTERN = Pattern.compile("\\s*,\\s*");
-
public static List mapItems(Collection source, Function super T, ? extends R> mapper) {
Objects.requireNonNull(source, "Collection is null");
return source.stream().map(mapper).collect(Collectors.toList());
}
- public static List mapItemsNullable(Collection source, Function super T, ? extends R> mapper) {
+ public static @Nullable List mapItemsNullable(Collection source,
+ Function super T, ? extends R> mapper) {
if (source == null) {
return null;
}
- return source.stream().map(mapper).collect(Collectors.toList());
+ return source.stream().map(mapper).filter(Objects::nonNull).collect(Collectors.toList());
}
public static String createPlaceholders(int size) {
@@ -40,6 +39,6 @@ public static String createPlaceholders(int placeholderSize, int copiesSize) {
public static List parseByComma(String string) {
return StringUtils.isBlank(string)
? Collections.emptyList()
- : Arrays.asList(SPLIT_BY_COMMA_PATTERN.split(string));
+ : Arrays.stream(StringUtils.split(string, ',')).map(String::trim).toList();
}
}
diff --git a/src/main/java/org/folio/rest/converter/common/attr/ProxyConverter.java b/src/main/java/org/folio/rest/converter/common/attr/ProxyConverter.java
deleted file mode 100644
index dbf15bad3..000000000
--- a/src/main/java/org/folio/rest/converter/common/attr/ProxyConverter.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.folio.rest.converter.common.attr;
-
-import java.util.Objects;
-import org.folio.holdingsiq.model.ProxyUrl;
-import org.jspecify.annotations.Nullable;
-import org.springframework.core.convert.converter.Converter;
-import org.springframework.stereotype.Component;
-
-@Component
-public class ProxyConverter implements Converter {
- @Override
- public org.folio.rest.jaxrs.model.ProxyUrl convert(@Nullable ProxyUrl proxy) {
- if (Objects.isNull(proxy)) {
- return null;
- }
- org.folio.rest.jaxrs.model.ProxyUrl p = new org.folio.rest.jaxrs.model.ProxyUrl();
- p.setId(proxy.getId());
- p.setInherited(proxy.getInherited());
- p.setProxiedUrl(proxy.getProxiedUrl());
- return p;
- }
-}
diff --git a/src/main/java/org/folio/rest/converter/packages/CommonPackagePutRequestConverter.java b/src/main/java/org/folio/rest/converter/packages/CommonPackagePutRequestConverter.java
new file mode 100644
index 000000000..1e90ef91b
--- /dev/null
+++ b/src/main/java/org/folio/rest/converter/packages/CommonPackagePutRequestConverter.java
@@ -0,0 +1,81 @@
+package org.folio.rest.converter.packages;
+
+import static org.folio.common.ListUtils.mapItems;
+
+import java.util.Arrays;
+import java.util.List;
+import org.folio.holdingsiq.model.AlternateName;
+import org.folio.holdingsiq.model.CoverageDates;
+import org.folio.holdingsiq.model.PackagePut;
+import org.folio.holdingsiq.model.Proxy;
+import org.folio.holdingsiq.model.Visibility;
+import org.folio.rest.jaxrs.model.PackagePutDataAttributes;
+import org.folio.rest.jaxrs.model.PackageVisibility;
+import org.folio.rest.jaxrs.model.VisibilityData;
+
+public abstract class CommonPackagePutRequestConverter {
+
+ protected PackagePut.PackagePutBuilder convertCommonAttributes(PackagePutDataAttributes attributes) {
+ var builder = PackagePut.builder();
+
+ convertSimpleFields(attributes, builder);
+
+ if (attributes.getProxy() != null) {
+ builder.proxy(convertProxy(attributes));
+ }
+
+ if (attributes.getCustomCoverage() != null) {
+ builder.customCoverage(convertCoverageDates(attributes));
+ }
+
+ if (attributes.getCustomAltNames() != null) {
+ builder.customAltNames(convertCustomAltNames(attributes));
+ }
+
+ var visibilityData = attributes.getVisibilityData();
+ if (visibilityData == null || visibilityData.getIsHidden() == null) {
+ builder.visibilityDetails(mapItems(attributes.getVisibility(),
+ pv -> new Visibility(pv.getCategory().value(), pv.getHidden(), pv.getReason())));
+ } else {
+ builder.visibilityDetails(convertVisibilities(visibilityData));
+ }
+
+ return builder;
+ }
+
+ private void convertSimpleFields(PackagePutDataAttributes attributes, PackagePut.PackagePutBuilder builder) {
+ builder.isSelected(attributes.getIsSelected());
+ builder.isFullPackage(attributes.getIsFullPackage());
+ builder.customDescription(attributes.getCustomDescription());
+ builder.customDisplayName(attributes.getCustomDisplayName());
+ builder.packageFreeAccess(attributes.getIsFreeAccess());
+ builder.packageUrl(attributes.getUrl());
+ }
+
+ private List convertVisibilities(VisibilityData visibilityData) {
+ return Arrays.stream(PackageVisibility.Category.values())
+ .map(category -> new Visibility(category.value(), visibilityData.getIsHidden(), visibilityData.getReason()))
+ .toList();
+ }
+
+ private List convertCustomAltNames(PackagePutDataAttributes attributes) {
+ return mapItems(attributes.getCustomAltNames(),
+ packageAltName -> new AlternateName(packageAltName.getId(), packageAltName.getAltName()));
+ }
+
+ private CoverageDates convertCoverageDates(PackagePutDataAttributes attributes) {
+ return CoverageDates.builder()
+ .beginCoverage(attributes.getCustomCoverage().getBeginCoverage())
+ .endCoverage(attributes.getCustomCoverage().getEndCoverage())
+ .build();
+ }
+
+ private Proxy convertProxy(PackagePutDataAttributes attributes) {
+ return Proxy.builder()
+ .id(attributes.getProxy().getId())
+ // RM API gives an error when we pass inherited as true along with updated proxy value
+ // Hard code it to false; it should not affect the state of inherited that RM API maintains
+ .inherited(false)
+ .build();
+ }
+}
diff --git a/src/main/java/org/folio/rest/converter/packages/CustomPackagePostRequestConverter.java b/src/main/java/org/folio/rest/converter/packages/CustomPackagePostRequestConverter.java
new file mode 100644
index 000000000..64b52a7b6
--- /dev/null
+++ b/src/main/java/org/folio/rest/converter/packages/CustomPackagePostRequestConverter.java
@@ -0,0 +1,63 @@
+package org.folio.rest.converter.packages;
+
+import static org.folio.common.ListUtils.mapItemsNullable;
+import static org.folio.rest.converter.packages.PackageConverterUtils.CONTENT_TYPE_TO_RMAPI_CODE;
+
+import javax.annotation.Nullable;
+import org.folio.holdingsiq.model.AlternateName;
+import org.folio.holdingsiq.model.CoverageDates;
+import org.folio.holdingsiq.model.PackagePost;
+import org.folio.holdingsiq.model.Proxy;
+import org.folio.rest.jaxrs.model.Coverage;
+import org.folio.rest.jaxrs.model.PackageAltName;
+import org.folio.rest.jaxrs.model.PackagePostRequest;
+import org.folio.rest.jaxrs.model.ProxyDto;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CustomPackagePostRequestConverter implements Converter {
+
+ @Override
+ public PackagePost convert(PackagePostRequest postPackageBody) {
+ var data = postPackageBody.getData();
+ var attributes = data.getAttributes();
+ return PackagePost.builder()
+ .customAltNames(mapItemsNullable(attributes.getCustomAltNames(), this::convertAlternateName))
+ .coverage(convertCoverageDates(attributes.getCustomCoverage()))
+ .customDescription(attributes.getCustomDescription())
+ .customDisplayName(attributes.getCustomDisplayName())
+ .contentType(CONTENT_TYPE_TO_RMAPI_CODE.getOrDefault(attributes.getContentType(), 6))
+ .packageName(attributes.getName())
+ .packageFreeAccess(attributes.getIsFreeAccess())
+ .proxy(convertProxy(attributes.getProxy()))
+ .build();
+ }
+
+ private @Nullable CoverageDates convertCoverageDates(@Nullable Coverage customCoverage) {
+ if (customCoverage == null) {
+ return null;
+ }
+ return CoverageDates.builder()
+ .beginCoverage(customCoverage.getBeginCoverage())
+ .endCoverage(customCoverage.getEndCoverage())
+ .build();
+ }
+
+ private @Nullable Proxy convertProxy(@Nullable ProxyDto proxy) {
+ if (proxy == null) {
+ return null;
+ }
+ return Proxy.builder()
+ .id(proxy.getId())
+ .inherited(false)
+ .build();
+ }
+
+ private @Nullable AlternateName convertAlternateName(@Nullable PackageAltName packageAltName) {
+ if (packageAltName == null) {
+ return null;
+ }
+ return new AlternateName(packageAltName.getId(), packageAltName.getAltName());
+ }
+}
diff --git a/src/main/java/org/folio/rest/converter/packages/CustomPackagePutRequestConverter.java b/src/main/java/org/folio/rest/converter/packages/CustomPackagePutRequestConverter.java
new file mode 100644
index 000000000..afac2ee25
--- /dev/null
+++ b/src/main/java/org/folio/rest/converter/packages/CustomPackagePutRequestConverter.java
@@ -0,0 +1,24 @@
+package org.folio.rest.converter.packages;
+
+import static org.folio.rest.converter.packages.PackageConverterUtils.CONTENT_TYPE_TO_RMAPI_CODE;
+
+import org.folio.holdingsiq.model.PackagePut;
+import org.folio.rest.jaxrs.model.PackagePutRequest;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CustomPackagePutRequestConverter
+ extends CommonPackagePutRequestConverter
+ implements Converter {
+
+ @Override
+ public PackagePut convert(PackagePutRequest request) {
+ var attributes = request.getData().getAttributes();
+ var builder = convertCommonAttributes(attributes);
+ builder.packageName(attributes.getName());
+ var contentType = CONTENT_TYPE_TO_RMAPI_CODE.get(attributes.getContentType());
+ builder.contentType(contentType != null ? contentType : 6);
+ return builder.build();
+ }
+}
diff --git a/src/main/java/org/folio/rest/converter/packages/ManagedPackagePutRequestConverter.java b/src/main/java/org/folio/rest/converter/packages/ManagedPackagePutRequestConverter.java
new file mode 100644
index 000000000..81faf7182
--- /dev/null
+++ b/src/main/java/org/folio/rest/converter/packages/ManagedPackagePutRequestConverter.java
@@ -0,0 +1,27 @@
+package org.folio.rest.converter.packages;
+
+import org.folio.holdingsiq.model.PackagePut;
+import org.folio.holdingsiq.model.TokenInfo;
+import org.folio.rest.jaxrs.model.PackagePutRequest;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ManagedPackagePutRequestConverter
+ extends CommonPackagePutRequestConverter
+ implements Converter {
+
+ @Override
+ public PackagePut convert(PackagePutRequest request) {
+ var attributes = request.getData().getAttributes();
+ var builder = convertCommonAttributes(attributes);
+ builder.allowEbscoToAddTitles(attributes.getAllowKbToAddTitles());
+ if (attributes.getPackageToken() != null) {
+ var tokenInfo = TokenInfo.builder()
+ .value(attributes.getPackageToken().getValue())
+ .build();
+ builder.packageToken(tokenInfo);
+ }
+ return builder.build();
+ }
+}
diff --git a/src/main/java/org/folio/rest/converter/packages/PackageConverter.java b/src/main/java/org/folio/rest/converter/packages/PackageConverter.java
index 251f9ff1c..fffdb06e2 100644
--- a/src/main/java/org/folio/rest/converter/packages/PackageConverter.java
+++ b/src/main/java/org/folio/rest/converter/packages/PackageConverter.java
@@ -9,6 +9,7 @@
import java.util.List;
import java.util.Objects;
import org.folio.holdingsiq.model.PackageData;
+import org.folio.holdingsiq.model.Proxy;
import org.folio.holdingsiq.model.Titles;
import org.folio.holdingsiq.model.TokenInfo;
import org.folio.holdingsiq.model.VendorById;
@@ -20,7 +21,7 @@
import org.folio.rest.jaxrs.model.PackageCollectionItem;
import org.folio.rest.jaxrs.model.PackageRelationship;
import org.folio.rest.jaxrs.model.Provider;
-import org.folio.rest.jaxrs.model.Proxy;
+import org.folio.rest.jaxrs.model.ProxyDto;
import org.folio.rest.jaxrs.model.RelationshipData;
import org.folio.rest.jaxrs.model.ResourceCollection;
import org.folio.rest.jaxrs.model.Token;
@@ -114,8 +115,8 @@ private void addAccessTypeRelationship(PackageResult result, Package packageData
}
}
- private @Nullable Proxy convertToProxy(org.folio.holdingsiq.model.Proxy proxy) {
- return proxy != null ? new Proxy().withId(proxy.getId()).withInherited(proxy.getInherited()) : null;
+ private @Nullable ProxyDto convertToProxy(@Nullable Proxy proxy) {
+ return proxy != null ? new ProxyDto().withId(proxy.getId()).withInherited(proxy.getInherited()) : null;
}
private List convertResourcesRelationship(PackageData packageData, Titles titles) {
diff --git a/src/main/java/org/folio/rest/converter/packages/PackagePostRequestConverter.java b/src/main/java/org/folio/rest/converter/packages/PackagePostRequestConverter.java
deleted file mode 100644
index 5622ba89e..000000000
--- a/src/main/java/org/folio/rest/converter/packages/PackagePostRequestConverter.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.folio.rest.converter.packages;
-
-import static org.folio.rest.converter.packages.PackageConverterUtils.CONTENT_TYPE_TO_RMAPI_CODE;
-
-import org.folio.holdingsiq.model.PackagePost;
-import org.folio.rest.jaxrs.model.Coverage;
-import org.folio.rest.jaxrs.model.PackagePostRequest;
-import org.springframework.core.convert.converter.Converter;
-import org.springframework.stereotype.Component;
-
-@Component
-public class PackagePostRequestConverter implements Converter {
-
- @Override
- public PackagePost convert(PackagePostRequest postPackageBody) {
- var data = postPackageBody.getData();
- var attributes = data.getAttributes();
- PackagePost.PackagePostBuilder postRequest = PackagePost.builder()
- .contentType(CONTENT_TYPE_TO_RMAPI_CODE.getOrDefault(attributes.getContentType(), 6))
- .packageName(attributes.getName());
-
- Coverage customCoverage = attributes.getCustomCoverage();
- if (customCoverage != null) {
- postRequest.coverage(
- org.folio.holdingsiq.model.CoverageDates.builder()
- .beginCoverage(customCoverage.getBeginCoverage())
- .endCoverage(customCoverage.getEndCoverage())
- .build());
- }
-
- return postRequest.build();
- }
-}
diff --git a/src/main/java/org/folio/rest/converter/packages/PackageRequestConverter.java b/src/main/java/org/folio/rest/converter/packages/PackageRequestConverter.java
deleted file mode 100644
index 9b01a2f86..000000000
--- a/src/main/java/org/folio/rest/converter/packages/PackageRequestConverter.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.folio.rest.converter.packages;
-
-import static org.folio.common.ListUtils.mapItems;
-import static org.folio.rest.converter.packages.PackageConverterUtils.CONTENT_TYPE_TO_RMAPI_CODE;
-
-import java.util.Arrays;
-import org.folio.holdingsiq.model.AlternateName;
-import org.folio.holdingsiq.model.CoverageDates;
-import org.folio.holdingsiq.model.PackagePut;
-import org.folio.holdingsiq.model.Proxy;
-import org.folio.holdingsiq.model.TokenInfo;
-import org.folio.holdingsiq.model.Visibility;
-import org.folio.rest.jaxrs.model.PackagePutDataAttributes;
-import org.folio.rest.jaxrs.model.PackagePutRequest;
-import org.folio.rest.jaxrs.model.PackageVisibility;
-import org.springframework.stereotype.Component;
-
-@Component
-public class PackageRequestConverter {
-
- public PackagePut convertToRmApiCustomPackagePutRequest(PackagePutRequest request) {
- var attributes = request.getData().getAttributes();
- var builder = convertCommonAttributesToPackagePutRequest(attributes);
- builder.packageName(attributes.getName());
- var contentType = CONTENT_TYPE_TO_RMAPI_CODE.get(attributes.getContentType());
- builder.contentType(contentType != null ? contentType : 6);
- return builder.build();
- }
-
- public PackagePut convertToRmApiPackagePutRequest(PackagePutRequest request) {
- var attributes = request.getData().getAttributes();
- var builder = convertCommonAttributesToPackagePutRequest(attributes);
- builder.allowEbscoToAddTitles(attributes.getAllowKbToAddTitles());
- if (attributes.getPackageToken() != null) {
- var tokenInfo = TokenInfo.builder()
- .value(attributes.getPackageToken().getValue())
- .build();
- builder.packageToken(tokenInfo);
- }
- return builder.build();
- }
-
- @SuppressWarnings("checkstyle:MethodLength")
- private PackagePut.PackagePutBuilder convertCommonAttributesToPackagePutRequest(PackagePutDataAttributes attributes) {
- var builder = PackagePut.builder();
-
- builder.isSelected(attributes.getIsSelected());
- builder.isFullPackage(attributes.getIsFullPackage());
-
- if (attributes.getProxy() != null) {
- var proxy = Proxy.builder()
- .id(attributes.getProxy().getId())
- // RM API gives an error when we pass inherited as true along with updated proxy value
- // Hard code it to false; it should not affect the state of inherited that RM API maintains
- .inherited(false)
- .build();
- builder.proxy(proxy);
- }
-
- if (attributes.getCustomCoverage() != null) {
- var coverageDates = CoverageDates.builder()
- .beginCoverage(attributes.getCustomCoverage().getBeginCoverage())
- .endCoverage(attributes.getCustomCoverage().getEndCoverage())
- .build();
- builder.customCoverage(coverageDates);
- }
-
- if (attributes.getCustomAltNames() != null) {
- builder.customAltNames(mapItems(attributes.getCustomAltNames(),
- packageAltName -> new AlternateName(packageAltName.getId(), packageAltName.getAltName())));
- }
-
- builder.customDescription(attributes.getCustomDescription());
- builder.customDisplayName(attributes.getCustomDisplayName());
- builder.packageFreeAccess(attributes.getIsFreeAccess());
- builder.packageUrl(attributes.getUrl());
-
- var visibilityData = attributes.getVisibilityData();
- if (visibilityData == null || visibilityData.getIsHidden() == null) {
- builder.visibilityDetails(mapItems(attributes.getVisibility(),
- pv -> new Visibility(pv.getCategory().value(), pv.getHidden(), pv.getReason())));
- } else {
- var visibilities = Arrays.stream(PackageVisibility.Category.values())
- .map(category -> new Visibility(category.value(), visibilityData.getIsHidden(), visibilityData.getReason()))
- .toList();
- builder.visibilityDetails(visibilities);
- }
-
- return builder;
- }
-}
diff --git a/src/main/java/org/folio/rest/converter/packages/PackageRequestConvertionService.java b/src/main/java/org/folio/rest/converter/packages/PackageRequestConvertionService.java
new file mode 100644
index 000000000..cd6d4ac9e
--- /dev/null
+++ b/src/main/java/org/folio/rest/converter/packages/PackageRequestConvertionService.java
@@ -0,0 +1,29 @@
+package org.folio.rest.converter.packages;
+
+import lombok.RequiredArgsConstructor;
+import org.folio.holdingsiq.model.PackagePost;
+import org.folio.holdingsiq.model.PackagePut;
+import org.folio.rest.jaxrs.model.PackagePostRequest;
+import org.folio.rest.jaxrs.model.PackagePutRequest;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class PackageRequestConvertionService {
+
+ private final ManagedPackagePutRequestConverter managedPackagePutRequestConverter;
+ private final CustomPackagePutRequestConverter customPackagePutRequestConverter;
+ private final CustomPackagePostRequestConverter customPackagePostRequestConverter;
+
+ public PackagePut convertCustomPackagePutRequest(PackagePutRequest request) {
+ return customPackagePutRequestConverter.convert(request);
+ }
+
+ public PackagePut convertManagedPackagePutRequest(PackagePutRequest request) {
+ return managedPackagePutRequestConverter.convert(request);
+ }
+
+ public PackagePost convertCustomPackagePostRequest(PackagePostRequest request) {
+ return customPackagePostRequestConverter.convert(request);
+ }
+}
diff --git a/src/main/java/org/folio/rest/converter/providers/ProviderConverter.java b/src/main/java/org/folio/rest/converter/providers/ProviderConverter.java
index f27c29e4a..075247b0f 100644
--- a/src/main/java/org/folio/rest/converter/providers/ProviderConverter.java
+++ b/src/main/java/org/folio/rest/converter/providers/ProviderConverter.java
@@ -7,6 +7,7 @@
import java.util.List;
import java.util.Objects;
+import org.folio.holdingsiq.model.Proxy;
import org.folio.holdingsiq.model.TokenInfo;
import org.folio.holdingsiq.model.VendorById;
import org.folio.rest.jaxrs.model.MetaDataIncluded;
@@ -15,7 +16,7 @@
import org.folio.rest.jaxrs.model.Provider;
import org.folio.rest.jaxrs.model.ProviderData;
import org.folio.rest.jaxrs.model.ProviderGetDataAttributes;
-import org.folio.rest.jaxrs.model.Proxy;
+import org.folio.rest.jaxrs.model.ProxyDto;
import org.folio.rest.jaxrs.model.RelationshipData;
import org.folio.rest.jaxrs.model.Relationships;
import org.folio.rest.jaxrs.model.Token;
@@ -67,14 +68,18 @@ private ProviderData convertProviderData(VendorResult result, VendorById vendor,
.withPackagesSelected(vendor.getPackagesSelected())
.withSupportsCustomPackages(vendor.isCustomer())
.withProviderToken(tokenInfoConverter.convert(vendorToken))
- .withProxy(new Proxy()
- .withId(vendor.getProxy().getId())
- .withInherited(vendor.getProxy().getInherited()))
+ .withProxy(convertProxy(vendor.getProxy()))
.withTags(result.getTags())
)
.withRelationships(createEmptyProviderRelationships());
}
+ private ProxyDto convertProxy(Proxy proxy) {
+ return new ProxyDto()
+ .withId(proxy.getId())
+ .withInherited(proxy.getInherited());
+ }
+
private List convertPackagesRelationship(org.folio.holdingsiq.model.Packages packages) {
return mapItems(packages.getPackagesList(),
packageData -> new RelationshipData()
diff --git a/src/main/java/org/folio/rest/converter/providers/ProviderPutRequestConverter.java b/src/main/java/org/folio/rest/converter/providers/ProviderPutRequestConverter.java
index 29dd65ccc..3953a8c5f 100644
--- a/src/main/java/org/folio/rest/converter/providers/ProviderPutRequestConverter.java
+++ b/src/main/java/org/folio/rest/converter/providers/ProviderPutRequestConverter.java
@@ -1,5 +1,6 @@
package org.folio.rest.converter.providers;
+import org.folio.holdingsiq.model.Proxy;
import org.folio.holdingsiq.model.VendorPut;
import org.folio.holdingsiq.model.VendorPutToken;
import org.folio.rest.jaxrs.model.ProviderPutRequest;
@@ -19,7 +20,7 @@ public VendorPut convert(ProviderPutRequest provider) {
// API maintains
if (provider.getData().getAttributes().getProxy() != null
&& provider.getData().getAttributes().getProxy().getId() != null) {
- vpb.proxy(org.folio.holdingsiq.model.Proxy.builder()
+ vpb.proxy(Proxy.builder()
.inherited(false)
.id(provider.getData().getAttributes().getProxy().getId())
.build());
diff --git a/src/main/java/org/folio/rest/converter/resources/CommonResourceConverter.java b/src/main/java/org/folio/rest/converter/resources/CommonResourceConverter.java
index 5d331a24a..eb8465a50 100644
--- a/src/main/java/org/folio/rest/converter/resources/CommonResourceConverter.java
+++ b/src/main/java/org/folio/rest/converter/resources/CommonResourceConverter.java
@@ -17,9 +17,11 @@
import org.folio.rest.jaxrs.model.AlternateTitle;
import org.folio.rest.jaxrs.model.Contributors;
import org.folio.rest.jaxrs.model.Coverage;
+import org.folio.rest.jaxrs.model.ProxyUrlDto;
import org.folio.rest.jaxrs.model.ResourceDataAttributes;
import org.folio.rest.jaxrs.model.TitleSubject;
import org.folio.rest.jaxrs.model.VisibilityData;
+import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
@@ -32,7 +34,6 @@ public class CommonResourceConverter {
private final Converter embargoPeriodConverter;
private final Converter visibilityInfoConverter;
private final Converter, List> coverageDatesConverter;
- private final Converter proxyConverter;
private final Converter, List>
alternateTitleConverter;
@@ -43,7 +44,6 @@ public CommonResourceConverter(
Converter embargoPeriodConverter,
Converter visibilityInfoConverter,
Converter, List> coverageDatesConverter,
- Converter proxyConverter,
Converter, List> alternateTitleConverter) {
this.contributorsConverter = contributorsConverter;
this.identifiersConverter = identifiersConverter;
@@ -51,7 +51,6 @@ public CommonResourceConverter(
this.embargoPeriodConverter = embargoPeriodConverter;
this.visibilityInfoConverter = visibilityInfoConverter;
this.coverageDatesConverter = coverageDatesConverter;
- this.proxyConverter = proxyConverter;
this.alternateTitleConverter = alternateTitleConverter;
}
@@ -89,11 +88,21 @@ public ResourceDataAttributes createResourceDataAttributes(Title title, Customer
resource.getCustomCoverageList().stream()
.sorted(Comparator.comparing(CoverageDates::getBeginCoverage).reversed())
.toList()))
- .withProxy(proxyConverter.convert(resource.getProxy()))
+ .withProxy(convertProxy(resource.getProxy()))
.withUserDefinedField1(resource.getUserDefinedFields().getUserDefinedField1())
.withUserDefinedField2(resource.getUserDefinedFields().getUserDefinedField2())
.withUserDefinedField3(resource.getUserDefinedFields().getUserDefinedField3())
.withUserDefinedField4(resource.getUserDefinedFields().getUserDefinedField4())
.withUserDefinedField5(resource.getUserDefinedFields().getUserDefinedField5());
}
+
+ public @Nullable ProxyUrlDto convertProxy(@Nullable ProxyUrl proxy) {
+ if (Objects.isNull(proxy)) {
+ return null;
+ }
+ return new ProxyUrlDto()
+ .withId(proxy.getId())
+ .withInherited(proxy.getInherited())
+ .withProxiedUrl(proxy.getProxiedUrl());
+ }
}
diff --git a/src/main/java/org/folio/rest/converter/resources/ResourceRequestConverter.java b/src/main/java/org/folio/rest/converter/resources/ResourceRequestConverter.java
index 935efe5fa..63da0fab2 100644
--- a/src/main/java/org/folio/rest/converter/resources/ResourceRequestConverter.java
+++ b/src/main/java/org/folio/rest/converter/resources/ResourceRequestConverter.java
@@ -6,10 +6,13 @@
import org.folio.holdingsiq.model.CoverageDates;
import org.folio.holdingsiq.model.CustomerResources;
import org.folio.holdingsiq.model.EmbargoPeriod;
+import org.folio.holdingsiq.model.Proxy;
+import org.folio.holdingsiq.model.ProxyUrl;
import org.folio.holdingsiq.model.ResourcePut;
import org.folio.holdingsiq.model.Title;
import org.folio.holdingsiq.model.UserDefinedFields;
import org.folio.rest.jaxrs.model.Coverage;
+import org.folio.rest.jaxrs.model.ProxyDto;
import org.folio.rest.jaxrs.model.ResourcePutDataAttributes;
import org.folio.rest.jaxrs.model.ResourcePutRequest;
import org.jspecify.annotations.Nullable;
@@ -46,7 +49,7 @@ private ResourcePut.ResourcePutBuilder convertCommonAttributesToResourcePutReque
var oldResource = oldTitle.getCustomerResourcesList().getFirst();
builder.isSelected(valueOrDefault(attributes.getIsSelected(), oldResource.getIsSelected()));
- convertProxy(attributes, oldResource, builder);
+ convertProxy(builder, attributes.getProxy(), oldResource.getProxy());
convertHidden(attributes, oldResource, builder);
if (Boolean.TRUE == oldResource.getIsPackageCustom()) {
builder.url(valueOrDefault(attributes.getUrl(), oldResource.getUrl()));
@@ -71,7 +74,7 @@ private ResourcePut.ResourcePutBuilder convertCommonAttributesToResourcePutReque
}
private void convertHidden(ResourcePutDataAttributes attributes, CustomerResources oldResource,
- ResourcePut.ResourcePutBuilder builder) {
+ ResourcePut.ResourcePutBuilder builder) {
var oldHidden = oldResource.getVisibilityData() != null ? oldResource.getVisibilityData().getIsHidden() : null;
var isHidden = attributes.getVisibilityData() != null && attributes.getVisibilityData().getIsHidden() != null
? attributes.getVisibilityData().getIsHidden() : oldHidden;
@@ -79,13 +82,11 @@ private void convertHidden(ResourcePutDataAttributes attributes, CustomerResourc
builder.isHidden(isHidden);
}
- private void convertProxy(ResourcePutDataAttributes attributes, CustomerResources oldResource,
- ResourcePut.ResourcePutBuilder builder) {
- var proxy = attributes.getProxy();
- var proxyId = proxy != null && proxy.getId() != null ? proxy.getId() : oldResource.getProxy().getId();
+ private void convertProxy(ResourcePut.ResourcePutBuilder builder, @Nullable ProxyDto newProxy, ProxyUrl oldProxy) {
+ var proxyId = newProxy != null && newProxy.getId() != null ? newProxy.getId() : oldProxy.getId();
//RM API gives an error when we pass inherited as true along with updated proxy value
//Hard code it to false; it should not affect the state of inherited that RM API maintains
- var rmApiProxy = org.folio.holdingsiq.model.Proxy.builder()
+ var rmApiProxy = Proxy.builder()
.id(proxyId)
.inherited(false)
.build();
@@ -93,7 +94,7 @@ private void convertProxy(ResourcePutDataAttributes attributes, CustomerResource
}
private void convertCoverageDates(ResourcePutDataAttributes attributes, CustomerResources oldResource,
- ResourcePut.ResourcePutBuilder builder) {
+ ResourcePut.ResourcePutBuilder builder) {
var coverageDates = attributes.getCustomCoverages() != null
? convertToRmApiCustomCoverageList(attributes.getCustomCoverages())
: oldResource.getCustomCoverageList();
@@ -103,7 +104,7 @@ private void convertCoverageDates(ResourcePutDataAttributes attributes, Customer
private void convertEmbargoPeriod(ResourcePutDataAttributes attributes, ResourcePut.ResourcePutBuilder builder) {
var embargoPeriod = attributes.getCustomEmbargoPeriod();
if (embargoPeriod != null && embargoPeriod.getEmbargoUnit() != null
- && embargoPeriod.getEmbargoValue() != null && embargoPeriod.getEmbargoValue() > 0) {
+ && embargoPeriod.getEmbargoValue() != null && embargoPeriod.getEmbargoValue() > 0) {
var customEmbargo = EmbargoPeriod.builder()
.embargoUnit(embargoPeriod.getEmbargoUnit().value())
.embargoValue(embargoPeriod.getEmbargoValue())
@@ -113,7 +114,7 @@ private void convertEmbargoPeriod(ResourcePutDataAttributes attributes, Resource
}
private void convertUserDefinedFields(ResourcePutDataAttributes attributes, ResourcePut.ResourcePutBuilder builder,
- CustomerResources oldResource) {
+ CustomerResources oldResource) {
builder.userDefinedFields(UserDefinedFields.builder()
.userDefinedField1(
valueOrDefault(attributes.getUserDefinedField1(), oldResource.getUserDefinedFields().getUserDefinedField1()))
diff --git a/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java
index 9a6dd172e..8ddd8a104 100644
--- a/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java
+++ b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java
@@ -48,7 +48,7 @@
import org.folio.rest.annotations.Validate;
import org.folio.rest.aspect.HandleValidationErrors;
import org.folio.rest.converter.common.ConverterConsts;
-import org.folio.rest.converter.packages.PackageRequestConverter;
+import org.folio.rest.converter.packages.PackageRequestConvertionService;
import org.folio.rest.exception.InputValidationException;
import org.folio.rest.jaxrs.model.AccessType;
import org.folio.rest.jaxrs.model.Package;
@@ -73,10 +73,7 @@
import org.folio.rest.util.template.RmApiTemplate;
import org.folio.rest.util.template.RmApiTemplateContext;
import org.folio.rest.util.template.RmApiTemplateFactory;
-import org.folio.rest.validator.CustomPackagePutBodyValidator;
-import org.folio.rest.validator.PackagePutBodyValidator;
-import org.folio.rest.validator.PackageTagsPutBodyValidator;
-import org.folio.rest.validator.PackagesPostBodyValidator;
+import org.folio.rest.validator.packages.PackageValidationService;
import org.folio.rmapi.result.PackageResult;
import org.folio.rmapi.result.TitleCollectionResult;
import org.folio.rmapi.result.TitleResult;
@@ -101,17 +98,9 @@ public class EholdingsPackagesImpl implements EholdingsPackages {
private static final String PACKAGE_IS_CUSTOM_NOT_MATCHED_DETAILS = "Package isCustom: %s";
@Autowired
- private PackageRequestConverter converter;
+ private PackageRequestConvertionService requestConvertionService;
@Autowired
- private Converter packagePostRequestConverter;
- @Autowired
- private PackagePutBodyValidator packagePutBodyValidator;
- @Autowired
- private CustomPackagePutBodyValidator customPackagePutBodyValidator;
- @Autowired
- private PackageTagsPutBodyValidator packageTagsPutBodyValidator;
- @Autowired
- private PackagesPostBodyValidator packagesPostBodyValidator;
+ private PackageValidationService validationService;
@Autowired
private RmApiTemplateFactory templateFactory;
@Autowired
@@ -193,10 +182,10 @@ public void getEholdingsPackages(String filterCustom, String q, String queryFiel
@HandleValidationErrors
public void postEholdingsPackages(String contentType, PackagePostRequest entity, Map okapiHeaders,
Handler> asyncResultHandler, Context vertxContext) {
- packagesPostBodyValidator.validate(entity);
+ validationService.validateCustomPackagePostRequest(entity);
RmApiTemplate template = templateFactory.createTemplate(okapiHeaders, asyncResultHandler);
- PackagePost packagePost = packagePostRequestConverter.convert(entity);
+ PackagePost packagePost = requestConvertionService.convertCustomPackagePostRequest(entity);
String accessTypeId = entity.getData().getAttributes().getAccessTypeId();
if (accessTypeId == null) {
@@ -335,7 +324,7 @@ public void putEholdingsPackagesTagsByPackageId(String packageId, String content
Context vertxContext) {
userKbCredentialsService.findByUser(headers)
.thenCompose(creds -> {
- packageTagsPutBodyValidator.validate(entity);
+ validationService.validatePackageTagsPutRequest(entity);
PackageTagsDataAttributes attributes = entity.getData().getAttributes();
@@ -546,11 +535,11 @@ private CompletableFuture processUpdateRequest(PackagePutRequest entity, P
PackagePut packagePutBody;
if (BooleanUtils.isTrue(isEntityCustom)) {
- customPackagePutBodyValidator.validate(entity);
- packagePutBody = converter.convertToRmApiCustomPackagePutRequest(entity);
+ validationService.validateCustomPackagePutRequest(entity);
+ packagePutBody = requestConvertionService.convertCustomPackagePutRequest(entity);
} else {
- packagePutBodyValidator.validate(entity);
- packagePutBody = converter.convertToRmApiPackagePutRequest(entity);
+ validationService.validateManagedPackagePutRequest(entity);
+ packagePutBody = requestConvertionService.convertManagedPackagePutRequest(entity);
}
return context.getPackagesService()
.updatePackage(originalPackage.getPackageId(), packagePutBody);
diff --git a/src/main/java/org/folio/rest/validator/CustomLabelsPutBodyValidator.java b/src/main/java/org/folio/rest/validator/CustomLabelsPutBodyValidator.java
index 0dfe1c465..16d5fac7c 100644
--- a/src/main/java/org/folio/rest/validator/CustomLabelsPutBodyValidator.java
+++ b/src/main/java/org/folio/rest/validator/CustomLabelsPutBodyValidator.java
@@ -39,7 +39,7 @@ private void checkEachLabelIsValid(@NonNull CustomLabelsPutRequest request) {
private void validateCollectionItem(@NonNull CustomLabel customLabel) {
CustomLabelDataAttributes attributes = customLabel.getAttributes();
- checkInRange(1, 5, attributes.getId(), CUSTOM_LABEL_ID_PARAM);
+ checkInRange(CUSTOM_LABEL_ID_PARAM, attributes.getId(), 1, 5);
checkMaxLength(CUSTOM_LABEL_NAME_PARAM, attributes.getDisplayLabel(), properties.labelMaxLength());
checkIsNotNull(FULL_TEXT_FINDER_PARAM, attributes.getDisplayOnFullTextFinder());
checkIsNotNull(PUBLICATION_FINDER_PARAM, attributes.getDisplayOnPublicationFinder());
diff --git a/src/main/java/org/folio/rest/validator/PackagesPostBodyValidator.java b/src/main/java/org/folio/rest/validator/PackagesPostBodyValidator.java
deleted file mode 100644
index 77d81792f..000000000
--- a/src/main/java/org/folio/rest/validator/PackagesPostBodyValidator.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.folio.rest.validator;
-
-import jakarta.validation.ValidationException;
-import java.util.Objects;
-import org.apache.commons.lang3.StringUtils;
-import org.folio.rest.exception.InputValidationException;
-import org.folio.rest.jaxrs.model.Coverage;
-import org.folio.rest.jaxrs.model.PackagePostRequest;
-import org.springframework.stereotype.Component;
-
-/**
- * Verifies that post data for packages are valid.
- */
-@Component
-public class PackagesPostBodyValidator {
-
- private static final String INVALID_BEGIN_COVERAGE = "Begin Coverage has an invalid date.";
- private static final String INVALID_POST_BODY = "Invalid request body";
-
- /**
- * Provides validation for the post data attributes.
- *
- * @throws ValidationException if validation fails
- */
- public void validate(PackagePostRequest entity) {
-
- if (Objects.isNull(entity) || Objects.isNull(entity.getData())
- || Objects.isNull(entity.getData().getAttributes())) {
- throw new InputValidationException(INVALID_POST_BODY, "");
- }
-
- ValidatorUtil.checkIsNotBlank("name", entity.getData().getAttributes().getName());
- ValidatorUtil.checkMaxLength("name", entity.getData().getAttributes().getName(), 200);
- ValidatorUtil.checkIsNotNull("Content type", entity.getData().getAttributes().getContentType());
-
- Coverage customCoverage = entity.getData().getAttributes().getCustomCoverage();
- if (Objects.nonNull(customCoverage)) {
-
- String beginCoverage = customCoverage.getBeginCoverage();
- String endCoverage = customCoverage.getEndCoverage();
-
- ValidatorUtil.checkIsNotNull("beginCoverage", beginCoverage);
- ValidatorUtil.checkDateValid("beginCoverage", beginCoverage);
-
- if (beginCoverage.isEmpty() && !StringUtils.isEmpty(endCoverage)) {
- throw new InputValidationException(INVALID_BEGIN_COVERAGE, "");
- }
-
- if (StringUtils.isNotBlank(endCoverage)) {
- ValidatorUtil.checkDateValid("endCoverage", endCoverage);
- ValidatorUtil.checkDatesOrder(beginCoverage, endCoverage);
- }
- }
- }
-}
diff --git a/src/main/java/org/folio/rest/validator/ValidatorUtil.java b/src/main/java/org/folio/rest/validator/ValidatorUtil.java
index 1948876bd..e0536943c 100644
--- a/src/main/java/org/folio/rest/validator/ValidatorUtil.java
+++ b/src/main/java/org/folio/rest/validator/ValidatorUtil.java
@@ -6,6 +6,7 @@
import java.time.format.DateTimeParseException;
import java.util.Collection;
import java.util.Objects;
+import java.util.regex.Pattern;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.folio.rest.exception.InputValidationException;
@@ -26,6 +27,7 @@ public final class ValidatorUtil {
private static final String INVALID_DATES_ORDER = "Begin Coverage should be smaller than End Coverage";
private static final String MUST_BE_IN_RANGE = "%s should be in range %d - %d";
private static final String MUST_BE_EQUALS = "%s should be equals to '%s' but actual is '%s'";
+ private static final Pattern HTML_TAG_PATTERN = Pattern.compile("<[^>]+>");
private ValidatorUtil() {
}
@@ -137,7 +139,7 @@ public static void checkUrlFormat(String paramName, String value) {
}
}
- public static void checkInRange(int minInclusive, int maxInclusive, Integer value, String paramName) {
+ public static void checkInRange(String paramName, Integer value, int minInclusive, int maxInclusive) {
if (value == null || value < minInclusive || value > maxInclusive) {
throw new InputValidationException(
String.format(INVALID_FIELD_FORMAT, paramName),
@@ -145,6 +147,14 @@ public static void checkInRange(int minInclusive, int maxInclusive, Integer valu
}
}
+ public static void checkNoHtml(String paramName, String value, String errorDetails) {
+ if (value != null && HTML_TAG_PATTERN.matcher(value).find()) {
+ throw new InputValidationException(
+ String.format(INVALID_FIELD_FORMAT, paramName),
+ errorDetails);
+ }
+ }
+
public static void checkIsEqual(String paramName, String expected, String actual) {
if (!expected.equals(actual)) {
throw new InputValidationException(
diff --git a/src/main/java/org/folio/rest/validator/CustomPackagePutBodyValidator.java b/src/main/java/org/folio/rest/validator/packages/CustomPackagePutBodyValidator.java
similarity index 54%
rename from src/main/java/org/folio/rest/validator/CustomPackagePutBodyValidator.java
rename to src/main/java/org/folio/rest/validator/packages/CustomPackagePutBodyValidator.java
index 376c47c9e..a15d4ec7a 100644
--- a/src/main/java/org/folio/rest/validator/CustomPackagePutBodyValidator.java
+++ b/src/main/java/org/folio/rest/validator/packages/CustomPackagePutBodyValidator.java
@@ -1,15 +1,23 @@
-package org.folio.rest.validator;
+package org.folio.rest.validator.packages;
import org.folio.rest.exception.InputValidationException;
import org.folio.rest.jaxrs.model.PackagePutDataAttributes;
import org.folio.rest.jaxrs.model.PackagePutRequest;
+import org.folio.rest.validator.ValidatorUtil;
import org.springframework.stereotype.Component;
@Component
public class CustomPackagePutBodyValidator {
+
private static final String INVALID_REQUEST_BODY_TITLE = "Invalid request body";
private static final String INVALID_REQUEST_BODY_DETAILS = "Json body must contain data.attributes";
+ private final PackageCustomAttributesValidator customAttributesValidator;
+
+ public CustomPackagePutBodyValidator(PackageCustomAttributesValidator customAttributesValidator) {
+ this.customAttributesValidator = customAttributesValidator;
+ }
+
public void validate(PackagePutRequest request) {
if (request == null
|| request.getData() == null
@@ -17,19 +25,14 @@ public void validate(PackagePutRequest request) {
throw new InputValidationException(INVALID_REQUEST_BODY_TITLE, INVALID_REQUEST_BODY_DETAILS);
}
PackagePutDataAttributes attributes = request.getData().getAttributes();
- String name = attributes.getName();
-
- String beginCoverage = null;
- String endCoverage = null;
- if (attributes.getCustomCoverage() != null) {
- beginCoverage = attributes.getCustomCoverage().getBeginCoverage();
- endCoverage = attributes.getCustomCoverage().getEndCoverage();
- }
-
- ValidatorUtil.checkIsNotBlank("name", name);
- ValidatorUtil.checkMaxLength("name", name, 200);
+ ValidatorUtil.checkIsNotBlank("name", attributes.getName());
+ ValidatorUtil.checkMaxLength("name", attributes.getName(), 200);
ValidatorUtil.checkIsNotNull("contentType", attributes.getContentType());
- ValidatorUtil.checkDateValid("beginCoverage", beginCoverage);
- ValidatorUtil.checkDateValid("endCoverage", endCoverage);
+ customAttributesValidator.validate(new PackageCustomAttributesValidator.PackageCustomAttributes(
+ attributes.getCustomDescription(),
+ attributes.getCustomDisplayName(),
+ attributes.getUrl(),
+ attributes.getCustomAltNames(),
+ attributes.getCustomCoverage()));
}
}
diff --git a/src/main/java/org/folio/rest/validator/PackagePutBodyValidator.java b/src/main/java/org/folio/rest/validator/packages/ManagedPackagePutBodyValidator.java
similarity index 56%
rename from src/main/java/org/folio/rest/validator/PackagePutBodyValidator.java
rename to src/main/java/org/folio/rest/validator/packages/ManagedPackagePutBodyValidator.java
index 3f06a4121..5b8297f26 100644
--- a/src/main/java/org/folio/rest/validator/PackagePutBodyValidator.java
+++ b/src/main/java/org/folio/rest/validator/packages/ManagedPackagePutBodyValidator.java
@@ -1,39 +1,48 @@
-package org.folio.rest.validator;
+package org.folio.rest.validator.packages;
import java.util.List;
import org.folio.rest.exception.InputValidationException;
import org.folio.rest.jaxrs.model.PackagePutDataAttributes;
import org.folio.rest.jaxrs.model.PackagePutRequest;
import org.folio.rest.jaxrs.model.PackageVisibility;
+import org.folio.rest.validator.ValidatorUtil;
import org.springframework.stereotype.Component;
@Component
-public class PackagePutBodyValidator {
+public class ManagedPackagePutBodyValidator {
private static final String INVALID_REQUEST_BODY_TITLE = "Invalid request body";
private static final String INVALID_REQUEST_BODY_DETAILS = "Json body must contain data.attributes";
private static final int MAX_TOKEN_LENGTH = 500;
+ private final PackageCustomAttributesValidator customAttributesValidator;
+
+ public ManagedPackagePutBodyValidator(PackageCustomAttributesValidator customAttributesValidator) {
+ this.customAttributesValidator = customAttributesValidator;
+ }
+
public void validate(PackagePutRequest request) {
if (request == null || request.getData() == null || request.getData().getAttributes() == null) {
throw new InputValidationException(INVALID_REQUEST_BODY_TITLE, INVALID_REQUEST_BODY_DETAILS);
}
PackagePutDataAttributes attributes = request.getData().getAttributes();
- Boolean allowKbToAddTitles = attributes.getAllowKbToAddTitles();
-
- String beginCoverage = null;
- String endCoverage = null;
- if (attributes.getCustomCoverage() != null) {
- beginCoverage = attributes.getCustomCoverage().getBeginCoverage();
- endCoverage = attributes.getCustomCoverage().getEndCoverage();
- }
-
- String value = attributes.getPackageToken() != null ? attributes.getPackageToken().getValue() : null;
- validateNotSelected(attributes, allowKbToAddTitles, attributes.getVisibility(), beginCoverage, endCoverage, value);
- ValidatorUtil.checkMaxLength("value", value, MAX_TOKEN_LENGTH);
- ValidatorUtil.checkDateValid("beginCoverage", beginCoverage);
- ValidatorUtil.checkDateValid("endCoverage", endCoverage);
+ String beginCoverage = attributes.getCustomCoverage() != null
+ ? attributes.getCustomCoverage().getBeginCoverage() : null;
+ String endCoverage = attributes.getCustomCoverage() != null
+ ? attributes.getCustomCoverage().getEndCoverage() : null;
+ String tokenValue = attributes.getPackageToken() != null
+ ? attributes.getPackageToken().getValue() : null;
+
+ validateNotSelected(attributes, attributes.getAllowKbToAddTitles(),
+ attributes.getVisibility(), beginCoverage, endCoverage, tokenValue);
+ ValidatorUtil.checkMaxLength("value", tokenValue, MAX_TOKEN_LENGTH);
+ customAttributesValidator.validate(new PackageCustomAttributesValidator.PackageCustomAttributes(
+ attributes.getCustomDescription(),
+ attributes.getCustomDisplayName(),
+ attributes.getUrl(),
+ attributes.getCustomAltNames(),
+ attributes.getCustomCoverage()));
}
private void validateNotSelected(PackagePutDataAttributes attributes, Boolean allowKbToAddTitles,
diff --git a/src/main/java/org/folio/rest/validator/packages/PackageCustomAttributesValidator.java b/src/main/java/org/folio/rest/validator/packages/PackageCustomAttributesValidator.java
new file mode 100644
index 000000000..b4ce7bc4b
--- /dev/null
+++ b/src/main/java/org/folio/rest/validator/packages/PackageCustomAttributesValidator.java
@@ -0,0 +1,102 @@
+package org.folio.rest.validator.packages;
+
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.folio.rest.exception.InputValidationException;
+import org.folio.rest.jaxrs.model.Coverage;
+import org.folio.rest.jaxrs.model.PackageAltName;
+import org.folio.rest.validator.ValidatorUtil;
+import org.springframework.stereotype.Component;
+
+@Component
+public class PackageCustomAttributesValidator {
+
+ private static final int MAX_DESCRIPTION_LENGTH = 2000;
+ private static final int MAX_DISPLAY_NAME_LENGTH = 300;
+ private static final int MAX_ALT_NAME_LENGTH = 300;
+ private static final int MAX_ALT_NAMES_COUNT = 10;
+ private static final int MAX_URL_LENGTH = 500;
+
+ private static final String DESCRIPTION_TOO_LONG = "2000 character limit has been exceeded.";
+ private static final String DISPLAY_NAME_TOO_LONG = "300 character limit has been exceeded.";
+ private static final String DISPLAY_NAME_CONTAINS_HTML =
+ "Invalid characters. Custom alternate name field does not accept HTML.";
+ private static final String ALT_NAMES_LIMIT_EXCEEDED =
+ "Custom alternate names maximum limit of 10 has been exceeded.";
+ private static final String ALT_NAME_TOO_LONG = "300 character limit has been exceeded.";
+ private static final String ALT_NAME_CONTAINS_HTML =
+ "Invalid characters. Custom alternate name field does not accept HTML.";
+ private static final String URL_TOO_LONG = "500 character limit has been exceeded.";
+ private static final String INVALID_BEGIN_COVERAGE = "Begin Coverage has an invalid date.";
+
+ public void validate(PackageCustomAttributes customAttributes) {
+ validateCustomDescription(customAttributes.customDescription);
+ validateCustomDisplayName(customAttributes.customDisplayName);
+ validateCustomAltNames(customAttributes.customAltNames);
+ validateUrl(customAttributes.url);
+ validateCustomCoverage(customAttributes.customCoverage);
+ }
+
+ private void validateCustomDescription(String description) {
+ if (description != null && description.length() > MAX_DESCRIPTION_LENGTH) {
+ throw new InputValidationException(DESCRIPTION_TOO_LONG, "");
+ }
+ }
+
+ private void validateCustomDisplayName(String displayName) {
+ if (displayName != null && displayName.length() > MAX_DISPLAY_NAME_LENGTH) {
+ throw new InputValidationException(DISPLAY_NAME_TOO_LONG, "");
+ }
+ ValidatorUtil.checkNoHtml("customDisplayName", displayName, DISPLAY_NAME_CONTAINS_HTML);
+ }
+
+ private void validateCustomAltNames(List altNames) {
+ if (altNames == null) {
+ return;
+ }
+ if (altNames.size() > MAX_ALT_NAMES_COUNT) {
+ throw new InputValidationException(ALT_NAMES_LIMIT_EXCEEDED, "");
+ }
+ for (PackageAltName altName : altNames) {
+ String name = altName.getAltName();
+ if (name != null && name.length() > MAX_ALT_NAME_LENGTH) {
+ throw new InputValidationException(ALT_NAME_TOO_LONG, "");
+ }
+ ValidatorUtil.checkNoHtml("customAltNames", name, ALT_NAME_CONTAINS_HTML);
+ }
+ }
+
+ private void validateUrl(String url) {
+ if (url == null) {
+ return;
+ }
+ if (url.length() > MAX_URL_LENGTH) {
+ throw new InputValidationException(URL_TOO_LONG, "");
+ }
+ ValidatorUtil.checkUrlFormat("url", url);
+ }
+
+ private void validateCustomCoverage(Coverage coverage) {
+ if (coverage == null) {
+ return;
+ }
+ String beginCoverage = coverage.getBeginCoverage();
+ String endCoverage = coverage.getEndCoverage();
+ ValidatorUtil.checkDateValid("beginCoverage", beginCoverage);
+ if (StringUtils.isEmpty(beginCoverage) && !StringUtils.isEmpty(endCoverage)) {
+ throw new InputValidationException(INVALID_BEGIN_COVERAGE, "");
+ }
+ if (StringUtils.isNotBlank(endCoverage)) {
+ ValidatorUtil.checkDateValid("endCoverage", endCoverage);
+ ValidatorUtil.checkDatesOrder(beginCoverage, endCoverage);
+ }
+ }
+
+ public record PackageCustomAttributes(
+ String customDescription,
+ String customDisplayName,
+ String url,
+ List customAltNames,
+ Coverage customCoverage
+ ) { }
+}
diff --git a/src/main/java/org/folio/rest/validator/PackageTagsPutBodyValidator.java b/src/main/java/org/folio/rest/validator/packages/PackageTagsPutBodyValidator.java
similarity index 92%
rename from src/main/java/org/folio/rest/validator/PackageTagsPutBodyValidator.java
rename to src/main/java/org/folio/rest/validator/packages/PackageTagsPutBodyValidator.java
index 54f3cfe57..9cf6aaf82 100644
--- a/src/main/java/org/folio/rest/validator/PackageTagsPutBodyValidator.java
+++ b/src/main/java/org/folio/rest/validator/packages/PackageTagsPutBodyValidator.java
@@ -1,8 +1,9 @@
-package org.folio.rest.validator;
+package org.folio.rest.validator.packages;
import org.folio.rest.exception.InputValidationException;
import org.folio.rest.jaxrs.model.PackageTagsDataAttributes;
import org.folio.rest.jaxrs.model.PackageTagsPutRequest;
+import org.folio.rest.validator.ValidatorUtil;
import org.springframework.stereotype.Component;
@Component
diff --git a/src/main/java/org/folio/rest/validator/packages/PackageValidationService.java b/src/main/java/org/folio/rest/validator/packages/PackageValidationService.java
new file mode 100644
index 000000000..daa7c9f19
--- /dev/null
+++ b/src/main/java/org/folio/rest/validator/packages/PackageValidationService.java
@@ -0,0 +1,33 @@
+package org.folio.rest.validator.packages;
+
+import lombok.RequiredArgsConstructor;
+import org.folio.rest.jaxrs.model.PackagePostRequest;
+import org.folio.rest.jaxrs.model.PackagePutRequest;
+import org.folio.rest.jaxrs.model.PackageTagsPutRequest;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class PackageValidationService {
+
+ private final ManagedPackagePutBodyValidator managedPackagePutBodyValidator;
+ private final CustomPackagePutBodyValidator customPackagePutBodyValidator;
+ private final PackageTagsPutBodyValidator packageTagsPutBodyValidator;
+ private final PackagesPostBodyValidator packagesPostBodyValidator;
+
+ public void validateManagedPackagePutRequest(PackagePutRequest request) {
+ managedPackagePutBodyValidator.validate(request);
+ }
+
+ public void validateCustomPackagePutRequest(PackagePutRequest request) {
+ customPackagePutBodyValidator.validate(request);
+ }
+
+ public void validateCustomPackagePostRequest(PackagePostRequest request) {
+ packagesPostBodyValidator.validate(request);
+ }
+
+ public void validatePackageTagsPutRequest(PackageTagsPutRequest request) {
+ packageTagsPutBodyValidator.validate(request);
+ }
+}
diff --git a/src/main/java/org/folio/rest/validator/packages/PackagesPostBodyValidator.java b/src/main/java/org/folio/rest/validator/packages/PackagesPostBodyValidator.java
new file mode 100644
index 000000000..689da745e
--- /dev/null
+++ b/src/main/java/org/folio/rest/validator/packages/PackagesPostBodyValidator.java
@@ -0,0 +1,53 @@
+package org.folio.rest.validator.packages;
+
+import jakarta.validation.ValidationException;
+import java.util.Objects;
+import org.folio.rest.exception.InputValidationException;
+import org.folio.rest.jaxrs.model.Coverage;
+import org.folio.rest.jaxrs.model.PackagePostRequest;
+import org.folio.rest.validator.ValidatorUtil;
+import org.springframework.stereotype.Component;
+
+/**
+ * Verifies that post data for packages are valid.
+ */
+@Component
+public class PackagesPostBodyValidator {
+
+ private static final String INVALID_POST_BODY = "Invalid request body";
+
+ private final PackageCustomAttributesValidator customAttributesValidator;
+
+ public PackagesPostBodyValidator(PackageCustomAttributesValidator customAttributesValidator) {
+ this.customAttributesValidator = customAttributesValidator;
+ }
+
+ /**
+ * Provides validation for the post data attributes.
+ *
+ * @throws ValidationException if validation fails
+ */
+ public void validate(PackagePostRequest entity) {
+ if (Objects.isNull(entity) || Objects.isNull(entity.getData())
+ || Objects.isNull(entity.getData().getAttributes())) {
+ throw new InputValidationException(INVALID_POST_BODY, "");
+ }
+ var attributes = entity.getData().getAttributes();
+ ValidatorUtil.checkIsNotBlank("name", attributes.getName());
+ ValidatorUtil.checkMaxLength("name", attributes.getName(), 200);
+ ValidatorUtil.checkIsNotNull("Content type", attributes.getContentType());
+ checkBeginCoverageNotNull(attributes.getCustomCoverage());
+ customAttributesValidator.validate(new PackageCustomAttributesValidator.PackageCustomAttributes(
+ attributes.getCustomDescription(),
+ attributes.getCustomDisplayName(),
+ attributes.getUrl(),
+ attributes.getCustomAltNames(),
+ attributes.getCustomCoverage()));
+ }
+
+ private void checkBeginCoverageNotNull(Coverage coverage) {
+ if (coverage != null) {
+ ValidatorUtil.checkIsNotNull("beginCoverage", coverage.getBeginCoverage());
+ }
+ }
+}
diff --git a/src/test/java/org/folio/rest/converter/packages/CustomPackagePostRequestConverterTest.java b/src/test/java/org/folio/rest/converter/packages/CustomPackagePostRequestConverterTest.java
new file mode 100644
index 000000000..06b0602ac
--- /dev/null
+++ b/src/test/java/org/folio/rest/converter/packages/CustomPackagePostRequestConverterTest.java
@@ -0,0 +1,149 @@
+package org.folio.rest.converter.packages;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+import org.folio.rest.jaxrs.model.ContentType;
+import org.folio.rest.jaxrs.model.Coverage;
+import org.folio.rest.jaxrs.model.PackageAltName;
+import org.folio.rest.jaxrs.model.PackagePostData;
+import org.folio.rest.jaxrs.model.PackagePostDataAttributes;
+import org.folio.rest.jaxrs.model.PackagePostRequest;
+import org.folio.rest.jaxrs.model.ProxyDto;
+import org.junit.jupiter.api.Test;
+
+class CustomPackagePostRequestConverterTest {
+
+ private final CustomPackagePostRequestConverter converter = new CustomPackagePostRequestConverter();
+
+ @Test
+ void shouldMapPackageName() {
+ var result = converter.convert(buildRequest(new PackagePostDataAttributes()
+ .withName("My Package")
+ .withContentType(ContentType.UNKNOWN)));
+ assertEquals("My Package", result.getPackageName());
+ }
+
+ @Test
+ void shouldMapCustomDescription() {
+ var result = converter.convert(buildRequest(new PackagePostDataAttributes()
+ .withContentType(ContentType.UNKNOWN)
+ .withCustomDescription("Some description")));
+ assertEquals("Some description", result.getCustomDescription());
+ }
+
+ @Test
+ void shouldMapCustomDisplayName() {
+ var result = converter.convert(buildRequest(new PackagePostDataAttributes()
+ .withContentType(ContentType.UNKNOWN)
+ .withCustomDisplayName("Display Name")));
+ assertEquals("Display Name", result.getCustomDisplayName());
+ }
+
+ @Test
+ void shouldMapFreeAccess() {
+ var result = converter.convert(buildRequest(new PackagePostDataAttributes()
+ .withContentType(ContentType.UNKNOWN)
+ .withIsFreeAccess(true)));
+ assertTrue(result.getPackageFreeAccess());
+ }
+
+ @Test
+ void shouldMapContentTypeToRmapiCode() {
+ var result = converter.convert(buildRequest(new PackagePostDataAttributes()
+ .withContentType(ContentType.AGGREGATED_FULL_TEXT)));
+ assertEquals(1, result.getContentType());
+ }
+
+ @Test
+ void shouldMapStreamingMediaContentType() {
+ var result = converter.convert(buildRequest(new PackagePostDataAttributes()
+ .withContentType(ContentType.STREAMING_MEDIA)));
+ assertEquals(8, result.getContentType());
+ }
+
+ @Test
+ void shouldUseDefaultContentTypeCodeForUnknown() {
+ var result = converter.convert(buildRequest(new PackagePostDataAttributes()
+ .withContentType(ContentType.UNKNOWN)));
+ assertEquals(6, result.getContentType());
+ }
+
+ @Test
+ void shouldMapCustomCoverage() {
+ var result = converter.convert(buildRequest(new PackagePostDataAttributes()
+ .withContentType(ContentType.UNKNOWN)
+ .withCustomCoverage(new Coverage()
+ .withBeginCoverage("2020-01-01")
+ .withEndCoverage("2021-12-31"))));
+ assertEquals("2020-01-01", result.getCoverage().getBeginCoverage());
+ assertEquals("2021-12-31", result.getCoverage().getEndCoverage());
+ }
+
+ @Test
+ void shouldReturnNullCoverageWhenNotProvided() {
+ var result = converter.convert(buildRequest(new PackagePostDataAttributes()
+ .withContentType(ContentType.UNKNOWN)));
+ assertNull(result.getCoverage());
+ }
+
+ @Test
+ void shouldMapProxy() {
+ var result = converter.convert(buildRequest(new PackagePostDataAttributes()
+ .withContentType(ContentType.UNKNOWN)
+ .withProxy(new ProxyDto().withId("proxy-id"))));
+ assertEquals("proxy-id", result.getProxy().getId());
+ assertFalse(result.getProxy().getInherited());
+ }
+
+ @Test
+ void shouldReturnNullProxyWhenNotProvided() {
+ var result = converter.convert(buildRequest(new PackagePostDataAttributes()
+ .withContentType(ContentType.UNKNOWN)));
+ assertNull(result.getProxy());
+ }
+
+ @Test
+ void shouldMapCustomAltNames() {
+ var result = converter.convert(buildRequest(new PackagePostDataAttributes()
+ .withContentType(ContentType.UNKNOWN)
+ .withCustomAltNames(List.of(
+ new PackageAltName().withId(1).withAltName("Alt One"),
+ new PackageAltName().withId(2).withAltName("Alt Two")))));
+ assertEquals(2, result.getCustomAltNames().size());
+ assertEquals(1, result.getCustomAltNames().get(0).id());
+ assertEquals("Alt One", result.getCustomAltNames().get(0).altName());
+ assertEquals(2, result.getCustomAltNames().get(1).id());
+ assertEquals("Alt Two", result.getCustomAltNames().get(1).altName());
+ }
+
+ @Test
+ void shouldMapEmptyAltNamesToEmptyList() {
+ var result = converter.convert(buildRequest(new PackagePostDataAttributes()
+ .withContentType(ContentType.UNKNOWN)
+ .withCustomAltNames(emptyList())));
+ assertTrue(result.getCustomAltNames().isEmpty());
+ }
+
+ @Test
+ void shouldMapSingleAltName() {
+ var result = converter.convert(buildRequest(new PackagePostDataAttributes()
+ .withContentType(ContentType.UNKNOWN)
+ .withCustomAltNames(singletonList(
+ new PackageAltName().withId(5).withAltName("Single Alt")))));
+ assertEquals(1, result.getCustomAltNames().size());
+ assertEquals("Single Alt", result.getCustomAltNames().getFirst().altName());
+ }
+
+ private PackagePostRequest buildRequest(PackagePostDataAttributes attributes) {
+ return new PackagePostRequest()
+ .withData(new PackagePostData()
+ .withType(PackagePostData.Type.PACKAGES)
+ .withAttributes(attributes));
+ }
+}
diff --git a/src/test/java/org/folio/rest/converter/packages/CustomPackagePutRequestConverterTest.java b/src/test/java/org/folio/rest/converter/packages/CustomPackagePutRequestConverterTest.java
new file mode 100644
index 000000000..8b4ffeb7f
--- /dev/null
+++ b/src/test/java/org/folio/rest/converter/packages/CustomPackagePutRequestConverterTest.java
@@ -0,0 +1,68 @@
+package org.folio.rest.converter.packages;
+
+import static org.folio.util.PackagesTestUtil.getPackagePutRequest;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+import org.folio.rest.jaxrs.model.ContentType;
+import org.folio.rest.jaxrs.model.Coverage;
+import org.folio.rest.jaxrs.model.PackagePutDataAttributes;
+import org.folio.rest.jaxrs.model.PackageVisibility;
+import org.junit.jupiter.api.Test;
+
+class CustomPackagePutRequestConverterTest {
+
+ private final CustomPackagePutRequestConverter converter = new CustomPackagePutRequestConverter();
+
+ @Test
+ void shouldCreateRequestToChangeCustomPackageName() {
+ var packagePut = converter.convert(getPackagePutRequest(
+ new PackagePutDataAttributes()
+ .withName("new package name")));
+ assertEquals("new package name", packagePut.getPackageName());
+ }
+
+ @Test
+ void shouldCreateRequestToChangeCustomPackageCoverageDates() {
+ var packagePut = converter.convert(getPackagePutRequest(
+ new PackagePutDataAttributes()
+ .withCustomCoverage(new Coverage()
+ .withBeginCoverage("2003-01-01")
+ .withEndCoverage("2004-01-01"))));
+ assertEquals("2003-01-01", packagePut.getCustomCoverage().getBeginCoverage());
+ assertEquals("2004-01-01", packagePut.getCustomCoverage().getEndCoverage());
+ }
+
+ @Test
+ void shouldCreateRequestToChangeCustomPackageCoverageDatesToEmpty() {
+ var packagePut = converter.convert(getPackagePutRequest(
+ new PackagePutDataAttributes()
+ .withCustomCoverage(new Coverage()
+ .withBeginCoverage("")
+ .withEndCoverage(""))));
+ assertEquals("", packagePut.getCustomCoverage().getBeginCoverage());
+ assertEquals("", packagePut.getCustomCoverage().getEndCoverage());
+ }
+
+ @Test
+ void shouldCreateRequestToChangeCustomPackageContentType() {
+ var packagePut = converter.convert(getPackagePutRequest(
+ new PackagePutDataAttributes()
+ .withContentType(ContentType.STREAMING_MEDIA)));
+ var aggregatedFullTextContentTypeCode = 8;
+ assertEquals(aggregatedFullTextContentTypeCode, packagePut.getContentType());
+ }
+
+ @Test
+ void shouldCreateRequestToChangeCustomPackageVisibility() {
+ var packagePut =
+ converter.convert(getPackagePutRequest(
+ new PackagePutDataAttributes()
+ .withVisibility(List.of(new PackageVisibility()
+ .withHidden(true)
+ .withCategory(PackageVisibility.Category.PF)))
+ ));
+ assertTrue(packagePut.getVisibilityDetails().getFirst().hidden());
+ }
+}
diff --git a/src/test/java/org/folio/rest/converter/packages/ManagedPackagePutRequestConverterTest.java b/src/test/java/org/folio/rest/converter/packages/ManagedPackagePutRequestConverterTest.java
new file mode 100644
index 000000000..add2bc4f4
--- /dev/null
+++ b/src/test/java/org/folio/rest/converter/packages/ManagedPackagePutRequestConverterTest.java
@@ -0,0 +1,57 @@
+package org.folio.rest.converter.packages;
+
+import static org.folio.util.PackagesTestUtil.getPackagePutRequest;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+import org.folio.rest.jaxrs.model.Coverage;
+import org.folio.rest.jaxrs.model.PackagePutDataAttributes;
+import org.folio.rest.jaxrs.model.PackageVisibility;
+import org.junit.jupiter.api.Test;
+
+class ManagedPackagePutRequestConverterTest {
+
+ private final ManagedPackagePutRequestConverter converter = new ManagedPackagePutRequestConverter();
+
+ @Test
+ void shouldCreateRequestToSelectPackage() {
+ var packagePut = converter.convert(getPackagePutRequest(
+ new PackagePutDataAttributes()
+ .withIsSelected(true)));
+ assertTrue(packagePut.getIsSelected());
+ }
+
+ @Test
+ void shouldCreateRequestToHidePackage() {
+ var packagePut = converter.convert(getPackagePutRequest(
+ new PackagePutDataAttributes()
+ .withIsSelected(true)
+ .withVisibility(List.of(new PackageVisibility()
+ .withHidden(true)
+ .withCategory(PackageVisibility.Category.PF)))
+ ));
+ assertTrue(packagePut.getVisibilityDetails().getFirst().hidden());
+ }
+
+ @Test
+ void shouldCreateRequestToAllowKbAddTitlesToPackage() {
+ var packagePut = converter.convert(getPackagePutRequest(
+ new PackagePutDataAttributes()
+ .withIsSelected(true)
+ .withAllowKbToAddTitles(true)));
+ assertTrue(packagePut.getAllowEbscoToAddTitles());
+ }
+
+ @Test
+ void shouldCreateRequestToAddCustomCoverage() {
+ var packagePut = converter.convert(getPackagePutRequest(
+ new PackagePutDataAttributes()
+ .withIsSelected(true)
+ .withCustomCoverage(new Coverage()
+ .withBeginCoverage("2000-10-10")
+ .withEndCoverage("2000-11-10"))));
+ assertEquals("2000-10-10", packagePut.getCustomCoverage().getBeginCoverage());
+ assertEquals("2000-11-10", packagePut.getCustomCoverage().getEndCoverage());
+ }
+}
diff --git a/src/test/java/org/folio/rest/converter/packages/PackageRequestConverterTest.java b/src/test/java/org/folio/rest/converter/packages/PackageRequestConverterTest.java
deleted file mode 100644
index aeedc16f8..000000000
--- a/src/test/java/org/folio/rest/converter/packages/PackageRequestConverterTest.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package org.folio.rest.converter.packages;
-
-import static org.folio.util.PackagesTestUtil.getPackagePutRequest;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import java.util.List;
-import org.folio.rest.jaxrs.model.ContentType;
-import org.folio.rest.jaxrs.model.Coverage;
-import org.folio.rest.jaxrs.model.PackagePutDataAttributes;
-import org.folio.rest.jaxrs.model.PackageVisibility;
-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.test.context.ContextConfiguration;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-
-@ExtendWith(SpringExtension.class)
-@ContextConfiguration(classes = TestConfig.class)
-class PackageRequestConverterTest {
- @Autowired
- private PackageRequestConverter packagesConverter;
-
- @Test
- void shouldCreateRequestToSelectPackage() {
- var packagePut = packagesConverter.convertToRmApiPackagePutRequest(getPackagePutRequest(
- new PackagePutDataAttributes()
- .withIsSelected(true)));
- assertTrue(packagePut.getIsSelected());
- }
-
- @Test
- void shouldCreateRequestToHidePackage() {
- var packagePut = packagesConverter.convertToRmApiPackagePutRequest(getPackagePutRequest(
- new PackagePutDataAttributes()
- .withIsSelected(true)
- .withVisibility(List.of(new PackageVisibility()
- .withHidden(true)
- .withCategory(PackageVisibility.Category.PF)))
- ));
- assertTrue(packagePut.getVisibilityDetails().getFirst().hidden());
- }
-
- @Test
- void shouldCreateRequestToAllowKbAddTitlesToPackage() {
- var packagePut = packagesConverter.convertToRmApiPackagePutRequest(getPackagePutRequest(
- new PackagePutDataAttributes()
- .withIsSelected(true)
- .withAllowKbToAddTitles(true)));
- assertTrue(packagePut.getAllowEbscoToAddTitles());
- }
-
- @Test
- void shouldCreateRequestToAddCustomCoverage() {
- var packagePut = packagesConverter.convertToRmApiPackagePutRequest(getPackagePutRequest(
- new PackagePutDataAttributes()
- .withIsSelected(true)
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("2000-10-10")
- .withEndCoverage("2000-11-10"))));
- assertEquals("2000-10-10", packagePut.getCustomCoverage().getBeginCoverage());
- assertEquals("2000-11-10", packagePut.getCustomCoverage().getEndCoverage());
- }
-
- @Test
- void shouldCreateRequestToChangeCustomPackageName() {
- var packagePut = packagesConverter.convertToRmApiCustomPackagePutRequest(getPackagePutRequest(
- new PackagePutDataAttributes()
- .withName("new package name")));
- assertEquals("new package name", packagePut.getPackageName());
- }
-
- @Test
- void shouldCreateRequestToChangeCustomPackageCoverageDates() {
- var packagePut = packagesConverter.convertToRmApiCustomPackagePutRequest(getPackagePutRequest(
- new PackagePutDataAttributes()
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("2003-01-01")
- .withEndCoverage("2004-01-01"))));
- assertEquals("2003-01-01", packagePut.getCustomCoverage().getBeginCoverage());
- assertEquals("2004-01-01", packagePut.getCustomCoverage().getEndCoverage());
- }
-
- @Test
- void shouldCreateRequestToChangeCustomPackageCoverageDatesToEmpty() {
- var packagePut = packagesConverter.convertToRmApiCustomPackagePutRequest(getPackagePutRequest(
- new PackagePutDataAttributes()
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("")
- .withEndCoverage(""))));
- assertEquals("", packagePut.getCustomCoverage().getBeginCoverage());
- assertEquals("", packagePut.getCustomCoverage().getEndCoverage());
- }
-
- @Test
- void shouldCreateRequestToChangeCustomPackageContentType() {
- var packagePut = packagesConverter.convertToRmApiCustomPackagePutRequest(getPackagePutRequest(
- new PackagePutDataAttributes()
- .withContentType(ContentType.STREAMING_MEDIA)));
- var aggregatedFullTextContentTypeCode = 8;
- assertEquals(aggregatedFullTextContentTypeCode, packagePut.getContentType());
- }
-
- @Test
- void shouldCreateRequestToChangeCustomPackageVisibility() {
- var packagePut =
- packagesConverter.convertToRmApiCustomPackagePutRequest(getPackagePutRequest(
- new PackagePutDataAttributes()
- .withVisibility(List.of(new PackageVisibility()
- .withHidden(true)
- .withCategory(PackageVisibility.Category.PF)))
- ));
- assertTrue(packagePut.getVisibilityDetails().getFirst().hidden());
- }
-}
diff --git a/src/test/java/org/folio/rest/converter/resources/ResourceRequestConverterTest.java b/src/test/java/org/folio/rest/converter/resources/ResourceRequestConverterTest.java
index 2f9f8d946..afa9b713f 100644
--- a/src/test/java/org/folio/rest/converter/resources/ResourceRequestConverterTest.java
+++ b/src/test/java/org/folio/rest/converter/resources/ResourceRequestConverterTest.java
@@ -10,12 +10,13 @@
import org.folio.holdingsiq.model.CoverageDates;
import org.folio.holdingsiq.model.CustomerResources;
+import org.folio.holdingsiq.model.ProxyUrl;
import org.folio.holdingsiq.model.Title;
import org.folio.holdingsiq.model.UserDefinedFields;
import org.folio.holdingsiq.model.VisibilityInfo;
import org.folio.rest.jaxrs.model.EmbargoPeriod;
import org.folio.rest.jaxrs.model.EmbargoPeriod.EmbargoUnit;
-import org.folio.rest.jaxrs.model.Proxy;
+import org.folio.rest.jaxrs.model.ProxyDto;
import org.folio.rest.jaxrs.model.ResourcePutDataAttributes;
import org.folio.rest.jaxrs.model.VisibilityData;
import org.junit.jupiter.api.BeforeEach;
@@ -49,7 +50,7 @@ void setUp() {
.beginCoverage(OLD_BEGIN_COVERAGE).endCoverage(OLD_END_COVERAGE).build()))
.customEmbargoPeriod(org.folio.holdingsiq.model.EmbargoPeriod.builder()
.embargoUnit(OLD_EMBARGO_UNIT).embargoValue(OLD_EMBARGO_VALUE).build())
- .proxy(org.folio.holdingsiq.model.ProxyUrl.builder().proxiedUrl(OLD_URL)
+ .proxy(ProxyUrl.builder().proxiedUrl(OLD_URL)
.id(OLD_PROXY_ID).inherited(true).build())
.url(OLD_URL)
.userDefinedFields(UserDefinedFields.builder().build())
@@ -82,7 +83,7 @@ void shouldCreateRequestToUpdateProxyForManagedResource() {
var resourcePut = resourcesConverter.convertToRmApiResourcePutRequest(getResourcePutRequest(
new ResourcePutDataAttributes()
.withIsSelected(true)
- .withProxy(new Proxy()
+ .withProxy(new ProxyDto()
.withId("test-proxy-id"))), resourceData);
assertEquals("test-proxy-id", resourcePut.getProxy().getId());
}
@@ -92,7 +93,7 @@ void shouldCreateRequestToUpdateProxyForCustomResource() {
var resourcePut = resourcesConverter.convertToRmApiCustomResourcePutRequest(getResourcePutRequest(
new ResourcePutDataAttributes()
.withIsSelected(true)
- .withProxy(new Proxy()
+ .withProxy(new ProxyDto()
.withId("test-proxy-id"))), resourceData);
assertEquals("test-proxy-id", resourcePut.getProxy().getId());
}
diff --git a/src/test/java/org/folio/rest/validator/PackagePostValidatorTest.java b/src/test/java/org/folio/rest/validator/PackagePostValidatorTest.java
deleted file mode 100644
index e12068983..000000000
--- a/src/test/java/org/folio/rest/validator/PackagePostValidatorTest.java
+++ /dev/null
@@ -1,228 +0,0 @@
-package org.folio.rest.validator;
-
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-import org.folio.rest.exception.InputValidationException;
-import org.folio.rest.jaxrs.model.ContentType;
-import org.folio.rest.jaxrs.model.Coverage;
-import org.folio.rest.jaxrs.model.PackagePostData;
-import org.folio.rest.jaxrs.model.PackagePostDataAttributes;
-import org.folio.rest.jaxrs.model.PackagePostRequest;
-import org.junit.jupiter.api.Test;
-
-class PackagePostValidatorTest {
-
- private final PackagesPostBodyValidator validator = new PackagesPostBodyValidator();
-
- @Test
- void shouldThrowExceptionWhenNoPostBody() {
- PackagePostRequest postRequest = null;
- assertThrows(InputValidationException.class, () ->
- validator.validate(postRequest));
- }
-
- @Test
- void shouldThrowExceptionWhenEmptyBody() {
- PackagePostRequest postRequest = new PackagePostRequest();
- assertThrows(InputValidationException.class, () ->
- validator.validate(postRequest));
- }
-
- @Test
- void shouldThrowExceptionWhenNoPostData() {
- PackagePostRequest postRequest = new PackagePostRequest()
- .withData(null);
- assertThrows(InputValidationException.class, () ->
- validator.validate(postRequest));
- }
-
- @Test
- void shouldThrowExceptionWhenEmptyPostData() {
- PackagePostRequest postRequest = new PackagePostRequest()
- .withData(new PackagePostData());
- assertThrows(InputValidationException.class, () ->
- validator.validate(postRequest));
- }
-
- @Test
- void shouldThrowExceptionWhenEmptyPostDataAttributes() {
- PackagePostRequest postRequest = new PackagePostRequest()
- .withData(new PackagePostData()
- .withAttributes(new PackagePostDataAttributes()));
- assertThrows(InputValidationException.class, () ->
- validator.validate(postRequest));
- }
-
- @Test
- void shouldThrowExceptionWhenPostDataAttributesNameIsEmpty() {
- PackagePostRequest postRequest = new PackagePostRequest()
- .withData(new PackagePostData()
- .withAttributes(new PackagePostDataAttributes()
- .withName("")));
- assertThrows(InputValidationException.class, () ->
- validator.validate(postRequest));
- }
-
- @Test
- void shouldThrowExceptionWhenPostDataAttributesTypeIsNull() {
- PackagePostRequest postRequest = new PackagePostRequest()
- .withData(new PackagePostData()
- .withAttributes(new PackagePostDataAttributes()
- .withName("name")));
- assertThrows(InputValidationException.class, () ->
- validator.validate(postRequest));
- }
-
- @Test
- void shouldThrowExceptionWhenPostDataAttributeCustomCoverageBeginDateIsNull() {
- PackagePostRequest postRequest = new PackagePostRequest()
- .withData(new PackagePostData()
- .withAttributes(new PackagePostDataAttributes()
- .withName("name").withContentType(ContentType.STREAMING_MEDIA)
- .withCustomCoverage(new Coverage())));
- assertThrows(InputValidationException.class, () ->
- validator.validate(postRequest));
- }
-
- @Test
- void shouldThrowExceptionWhenPostDataAttributeCustomCoverageWithEmptyBeginDate() {
- PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData()
- .withAttributes(new PackagePostDataAttributes()
- .withName("name")
- .withContentType(ContentType.STREAMING_MEDIA)
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("")
- .withEndCoverage("2003-11-01"))
- ));
- assertThrows(InputValidationException.class, () ->
- validator.validate(postRequest));
- }
-
- @Test
- void shouldThrowExceptionWhenPostDataAttributeCustomCoverageBeginDateIsInvalidFormat() {
- PackagePostRequest postRequest = new PackagePostRequest()
- .withData(new PackagePostData()
- .withAttributes(new PackagePostDataAttributes()
- .withName("name")
- .withContentType(ContentType.STREAMING_MEDIA)
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("-01"))));
- assertThrows(InputValidationException.class, () ->
- validator.validate(postRequest));
- }
-
- @Test
- void shouldThrowExceptionWhenPostDataAttributeCustomCoverageEndDateIsInvalidFormat() {
- PackagePostRequest postRequest = new PackagePostRequest()
- .withData(new PackagePostData()
- .withAttributes(new PackagePostDataAttributes()
- .withName("name")
- .withContentType(ContentType.STREAMING_MEDIA)
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("2003-11-01")
- .withEndCoverage("-01"))));
- assertThrows(InputValidationException.class, () ->
- validator.validate(postRequest));
- }
-
- @Test
- void shouldThrowExceptionWhenPostDataAttributeCustomCoverageBeginDateIsBeforeEndDate() {
- PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData()
- .withAttributes(new PackagePostDataAttributes()
- .withName("name")
- .withContentType(ContentType.STREAMING_MEDIA)
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("2003-12-01")
- .withEndCoverage("2003-11-01"))
- ));
- assertThrows(InputValidationException.class, () ->
- validator.validate(postRequest));
- }
-
- @Test
- void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageIsNull() {
- PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData()
- .withAttributes(new PackagePostDataAttributes()
- .withName("name")
- .withContentType(ContentType.STREAMING_MEDIA)
- ));
- validator.validate(postRequest);
- }
-
- @Test
- void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithValidDates() {
- PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData()
- .withAttributes(new PackagePostDataAttributes()
- .withName("name")
- .withContentType(ContentType.STREAMING_MEDIA)
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("2003-11-01")
- .withEndCoverage("2003-12-01"))
- ));
- validator.validate(postRequest);
- }
-
- @Test
- void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithEmptyDates() {
- PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData()
- .withAttributes(new PackagePostDataAttributes()
- .withName("name")
- .withContentType(ContentType.STREAMING_MEDIA)
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("")
- .withEndCoverage(""))
- ));
- validator.validate(postRequest);
- }
-
- @Test
- void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageBeginDateIsEmpty() {
- PackagePostRequest postRequest = new PackagePostRequest()
- .withData(new PackagePostData()
- .withAttributes(new PackagePostDataAttributes()
- .withName("name")
- .withContentType(ContentType.STREAMING_MEDIA)
- .withCustomCoverage(new Coverage()
- .withBeginCoverage(""))));
- validator.validate(postRequest);
- }
-
- @Test
- void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithValidBeginDateAndEndDateIsEmpty() {
- PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData()
- .withAttributes(new PackagePostDataAttributes()
- .withName("name")
- .withContentType(ContentType.STREAMING_MEDIA)
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("2003-11-01")
- .withEndCoverage(""))
- ));
- validator.validate(postRequest);
- }
-
- @Test
- void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithValidBeginDateAndEndDateIsNull() {
- PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData()
- .withAttributes(new PackagePostDataAttributes()
- .withName("name")
- .withContentType(ContentType.STREAMING_MEDIA)
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("2003-11-01")
- .withEndCoverage(null))
- ));
- validator.validate(postRequest);
- }
-
- @Test
- void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithValidBeginDateAndEndDateIsNullw() {
- PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData()
- .withAttributes(new PackagePostDataAttributes()
- .withName("name")
- .withContentType(ContentType.STREAMING_MEDIA)
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("")
- .withEndCoverage(null))
- ));
- validator.validate(postRequest);
- }
-}
diff --git a/src/test/java/org/folio/rest/validator/ValidatorUtilTest.java b/src/test/java/org/folio/rest/validator/ValidatorUtilTest.java
new file mode 100644
index 000000000..431342a72
--- /dev/null
+++ b/src/test/java/org/folio/rest/validator/ValidatorUtilTest.java
@@ -0,0 +1,403 @@
+package org.folio.rest.validator;
+
+import static org.folio.rest.validator.ValidatorUtil.checkDateValid;
+import static org.folio.rest.validator.ValidatorUtil.checkDatesOrder;
+import static org.folio.rest.validator.ValidatorUtil.checkFalseOrNull;
+import static org.folio.rest.validator.ValidatorUtil.checkInRange;
+import static org.folio.rest.validator.ValidatorUtil.checkIsBlank;
+import static org.folio.rest.validator.ValidatorUtil.checkIsEmpty;
+import static org.folio.rest.validator.ValidatorUtil.checkIsEmptyCollection;
+import static org.folio.rest.validator.ValidatorUtil.checkIsEqual;
+import static org.folio.rest.validator.ValidatorUtil.checkIsNotAllBlank;
+import static org.folio.rest.validator.ValidatorUtil.checkIsNotBlank;
+import static org.folio.rest.validator.ValidatorUtil.checkIsNotEmpty;
+import static org.folio.rest.validator.ValidatorUtil.checkIsNotNull;
+import static org.folio.rest.validator.ValidatorUtil.checkIsNull;
+import static org.folio.rest.validator.ValidatorUtil.checkMaxLength;
+import static org.folio.rest.validator.ValidatorUtil.checkNoHtml;
+import static org.folio.rest.validator.ValidatorUtil.checkUrlFormat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.Collections;
+import java.util.List;
+import org.folio.rest.exception.InputValidationException;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+class ValidatorUtilTest {
+
+ @Nested
+ class CheckIsNotEmpty {
+
+ @Test
+ void shouldThrow_whenValueIsEmpty() {
+ var ex = assertThrows(InputValidationException.class, () -> checkIsNotEmpty("field", ""));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("field must not be empty", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldThrow_whenValueIsNull() {
+ var ex = assertThrows(InputValidationException.class, () -> checkIsNotEmpty("field", null));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("field must not be empty", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenValueIsPresent() {
+ assertDoesNotThrow(() -> checkIsNotEmpty("field", "value"));
+ }
+ }
+
+ @Nested
+ class CheckIsEmpty {
+
+ @Test
+ void shouldThrow_whenValueIsNotEmpty() {
+ var ex = assertThrows(InputValidationException.class, () -> checkIsEmpty("field", "value"));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("field must be empty", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenValueIsEmpty() {
+ assertDoesNotThrow(() -> checkIsEmpty("field", ""));
+ }
+
+ @Test
+ void shouldNotThrow_whenValueIsNull() {
+ assertDoesNotThrow(() -> checkIsEmpty("field", null));
+ }
+ }
+
+ @Nested
+ class CheckIsBlank {
+
+ @Test
+ void shouldThrow_whenValueIsNotBlank() {
+ var ex = assertThrows(InputValidationException.class, () -> checkIsBlank("field", "text"));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("field must be empty", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenValueIsBlank() {
+ assertDoesNotThrow(() -> checkIsBlank("field", " "));
+ }
+
+ @Test
+ void shouldNotThrow_whenValueIsNull() {
+ assertDoesNotThrow(() -> checkIsBlank("field", null));
+ }
+ }
+
+ @Nested
+ class CheckIsNotBlank {
+
+ @Test
+ void shouldThrow_whenValueIsBlank() {
+ var ex = assertThrows(InputValidationException.class, () -> checkIsNotBlank("field", " "));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("field must not be empty", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldThrow_whenValueIsNull() {
+ var ex = assertThrows(InputValidationException.class, () -> checkIsNotBlank("field", null));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("field must not be empty", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenValueHasContent() {
+ assertDoesNotThrow(() -> checkIsNotBlank("field", "text"));
+ }
+ }
+
+ @Nested
+ class CheckIsNotAllBlank {
+
+ @Test
+ void shouldThrow_whenAllValuesAreBlank() {
+ var ex = assertThrows(InputValidationException.class,
+ () -> checkIsNotAllBlank("field", "", " ", null));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("At least one of field must not be empty", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenAtLeastOneValueIsNotBlank() {
+ assertDoesNotThrow(() -> checkIsNotAllBlank("field", "", "value"));
+ }
+ }
+
+ @Nested
+ class CheckFalseOrNull {
+
+ @Test
+ void shouldThrow_whenValueIsTrue() {
+ var ex = assertThrows(InputValidationException.class, () -> checkFalseOrNull("field", true));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("field must be false", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenValueIsFalse() {
+ assertDoesNotThrow(() -> checkFalseOrNull("field", false));
+ }
+
+ @Test
+ void shouldNotThrow_whenValueIsNull() {
+ assertDoesNotThrow(() -> checkFalseOrNull("field", null));
+ }
+ }
+
+ @Nested
+ class CheckIsNotNull {
+
+ @Test
+ void shouldThrow_whenValueIsNull() {
+ var ex = assertThrows(InputValidationException.class, () -> checkIsNotNull("field", null));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("field must not be null", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenValueIsPresent() {
+ assertDoesNotThrow(() -> checkIsNotNull("field", "value"));
+ }
+ }
+
+ @Nested
+ class CheckIsNull {
+
+ @Test
+ void shouldThrow_whenValueIsNotNull() {
+ var ex = assertThrows(InputValidationException.class, () -> checkIsNull("field", "value"));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("field must be null or not specified", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenValueIsNull() {
+ assertDoesNotThrow(() -> checkIsNull("field", null));
+ }
+ }
+
+ @Nested
+ class CheckIsEmptyCollection {
+
+ @Test
+ void shouldThrow_whenCollectionIsNotEmpty() {
+ var collection = List.of("item");
+ var ex = assertThrows(InputValidationException.class, () -> checkIsEmptyCollection("field", collection));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("field must be null or not specified", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenCollectionIsEmpty() {
+ var collection = Collections.emptyList();
+ assertDoesNotThrow(() -> checkIsEmptyCollection("field", collection));
+ }
+
+ @Test
+ void shouldNotThrow_whenCollectionIsNull() {
+ assertDoesNotThrow(() -> checkIsEmptyCollection("field", null));
+ }
+ }
+
+ @Nested
+ class CheckDateValid {
+
+ @Test
+ void shouldThrow_whenDateFormatIsInvalid() {
+ var ex = assertThrows(InputValidationException.class, () -> checkDateValid("date", "2024/01/01"));
+ assertEquals("Invalid date", ex.getMessage());
+ assertEquals("date has invalid format. Should be YYYY-MM-DD", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldThrow_whenDateHasInvalidValue() {
+ var ex = assertThrows(InputValidationException.class, () -> checkDateValid("date", "not-a-date"));
+ assertEquals("Invalid date", ex.getMessage());
+ assertEquals("date has invalid format. Should be YYYY-MM-DD", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenDateIsValid() {
+ assertDoesNotThrow(() -> checkDateValid("date", "2024-01-15"));
+ }
+
+ @Test
+ void shouldNotThrow_whenDateIsEmpty() {
+ assertDoesNotThrow(() -> checkDateValid("date", ""));
+ }
+
+ @Test
+ void shouldNotThrow_whenDateIsNull() {
+ assertDoesNotThrow(() -> checkDateValid("date", null));
+ }
+ }
+
+ @Nested
+ class CheckMaxLength {
+
+ @Test
+ void shouldThrow_whenValueExceedsMaxLength() {
+ var ex = assertThrows(InputValidationException.class,
+ () -> checkMaxLength("field", "toolongvalue", 5));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("field is too long (maximum is 5 characters)", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenValueEqualsMaxLength() {
+ assertDoesNotThrow(() -> checkMaxLength("field", "exact", 5));
+ }
+
+ @Test
+ void shouldNotThrow_whenValueIsShorterThanMaxLength() {
+ assertDoesNotThrow(() -> checkMaxLength("field", "ok", 5));
+ }
+
+ @Test
+ void shouldNotThrow_whenValueIsNull() {
+ assertDoesNotThrow(() -> checkMaxLength("field", null, 5));
+ }
+ }
+
+ @Nested
+ class CheckDatesOrder {
+
+ @Test
+ void shouldThrow_whenStartIsAfterEnd() {
+ var ex = assertThrows(InputValidationException.class,
+ () -> checkDatesOrder("2024-06-01", "2024-01-01"));
+ assertEquals("Begin Coverage should be smaller than End Coverage", ex.getMessage());
+ assertEquals("", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenStartIsBeforeEnd() {
+ assertDoesNotThrow(() -> checkDatesOrder("2024-01-01", "2024-06-01"));
+ }
+
+ @Test
+ void shouldNotThrow_whenStartEqualsEnd() {
+ assertDoesNotThrow(() -> checkDatesOrder("2024-01-01", "2024-01-01"));
+ }
+ }
+
+ @Nested
+ class CheckUrlFormat {
+
+ @Test
+ void shouldThrow_whenUrlIsInvalid() {
+ var ex = assertThrows(InputValidationException.class,
+ () -> checkUrlFormat("url", "not a url"));
+ assertEquals("Invalid url", ex.getMessage());
+ assertEquals("url has invalid format. Should start with https:// or http://", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenUrlIsHttps() {
+ assertDoesNotThrow(() -> checkUrlFormat("url", "https://example.com"));
+ }
+
+ @Test
+ void shouldNotThrow_whenUrlIsHttp() {
+ assertDoesNotThrow(() -> checkUrlFormat("url", "http://example.com"));
+ }
+ }
+
+ @Nested
+ class CheckInRange {
+
+ @Test
+ void shouldThrow_whenValueIsNull() {
+ var ex = assertThrows(InputValidationException.class,
+ () -> checkInRange("field", null, 1, 10));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("field should be in range 1 - 10", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldThrow_whenValueIsBelowMin() {
+ var ex = assertThrows(InputValidationException.class, () -> checkInRange("field", 0, 1, 10));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("field should be in range 1 - 10", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldThrow_whenValueIsAboveMax() {
+ var ex = assertThrows(InputValidationException.class, () -> checkInRange("field", 11, 1, 10));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("field should be in range 1 - 10", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenValueIsAtMin() {
+ assertDoesNotThrow(() -> checkInRange("field", 1, 1, 10));
+ }
+
+ @Test
+ void shouldNotThrow_whenValueIsAtMax() {
+ assertDoesNotThrow(() -> checkInRange("field", 10, 1, 10));
+ }
+
+ @Test
+ void shouldNotThrow_whenValueIsInRange() {
+ assertDoesNotThrow(() -> checkInRange("field", 5, 1, 10));
+ }
+ }
+
+ @Nested
+ class CheckNoHtml {
+
+ @Test
+ void shouldThrow_whenValueContainsHtmlTag() {
+ var ex = assertThrows(InputValidationException.class,
+ () -> checkNoHtml("field", "bold", "HTML not allowed"));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("HTML not allowed", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldThrow_whenValueContainsSelfClosingTag() {
+ var ex = assertThrows(InputValidationException.class,
+ () -> checkNoHtml("field", "text
more", "HTML not allowed"));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("HTML not allowed", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenValueHasNoHtml() {
+ assertDoesNotThrow(() -> checkNoHtml("field", "plain text", "HTML not allowed"));
+ }
+
+ @Test
+ void shouldNotThrow_whenValueIsNull() {
+ assertDoesNotThrow(() -> checkNoHtml("field", null, "HTML not allowed"));
+ }
+ }
+
+ @Nested
+ class CheckIsEqual {
+
+ @Test
+ void shouldThrow_whenValuesAreNotEqual() {
+ var ex = assertThrows(InputValidationException.class,
+ () -> checkIsEqual("field", "expected", "actual"));
+ assertEquals("Invalid field", ex.getMessage());
+ assertEquals("field should be equals to 'expected' but actual is 'actual'", ex.getMessageDetail());
+ }
+
+ @Test
+ void shouldNotThrow_whenValuesAreEqual() {
+ assertDoesNotThrow(() -> checkIsEqual("field", "value", "value"));
+ }
+ }
+}
diff --git a/src/test/java/org/folio/rest/validator/CustomPackagePutBodyValidatorTest.java b/src/test/java/org/folio/rest/validator/packages/CustomPackagePutBodyValidatorTest.java
similarity index 60%
rename from src/test/java/org/folio/rest/validator/CustomPackagePutBodyValidatorTest.java
rename to src/test/java/org/folio/rest/validator/packages/CustomPackagePutBodyValidatorTest.java
index 6508e4ba0..22ee62c2b 100644
--- a/src/test/java/org/folio/rest/validator/CustomPackagePutBodyValidatorTest.java
+++ b/src/test/java/org/folio/rest/validator/packages/CustomPackagePutBodyValidatorTest.java
@@ -1,30 +1,34 @@
-package org.folio.rest.validator;
+package org.folio.rest.validator.packages;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.lenient;
import org.folio.rest.exception.InputValidationException;
import org.folio.rest.jaxrs.model.ContentType;
-import org.folio.rest.jaxrs.model.Coverage;
import org.folio.rest.jaxrs.model.PackagePutDataAttributes;
import org.folio.util.PackagesTestUtil;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+@ExtendWith(MockitoExtension.class)
class CustomPackagePutBodyValidatorTest {
- private final CustomPackagePutBodyValidator validator = new CustomPackagePutBodyValidator();
+ @Mock
+ private PackageCustomAttributesValidator customAttributesValidator;
- @Test
- void shouldThrowExceptionOnInvalidCoverageDate() {
- var request = PackagesTestUtil.getPackagePutRequest(
- new PackagePutDataAttributes()
- .withIsSelected(true)
- .withContentType(ContentType.MIXED_CONTENT)
- .withName("package name")
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("abcd-10-ab")));
- var exception = assertThrows(InputValidationException.class, () -> validator.validate(request));
- assertTrue(exception.getMessage().contains("beginCoverage"));
+ @InjectMocks
+ private CustomPackagePutBodyValidator validator;
+
+ @BeforeEach
+ void setUp() {
+ lenient().doNothing().when(customAttributesValidator).validate(any());
}
@Test
@@ -45,4 +49,13 @@ void shouldThrowExceptionOnNullContentType() {
var exception = assertThrows(InputValidationException.class, () -> validator.validate(request));
assertTrue(exception.getMessage().contains("contentType"));
}
+
+ @Test
+ void shouldNotThrowExceptionForValidRequest() {
+ var request = PackagesTestUtil.getPackagePutRequest(
+ new PackagePutDataAttributes()
+ .withName("package name")
+ .withContentType(ContentType.MIXED_CONTENT));
+ assertDoesNotThrow(() -> validator.validate(request));
+ }
}
diff --git a/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java b/src/test/java/org/folio/rest/validator/packages/ManagedPackagePutBodyValidatorTest.java
similarity index 68%
rename from src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java
rename to src/test/java/org/folio/rest/validator/packages/ManagedPackagePutBodyValidatorTest.java
index 9ca1eae0c..7318551a1 100644
--- a/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java
+++ b/src/test/java/org/folio/rest/validator/packages/ManagedPackagePutBodyValidatorTest.java
@@ -1,8 +1,10 @@
-package org.folio.rest.validator;
+package org.folio.rest.validator.packages;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.lenient;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
@@ -12,21 +14,35 @@
import org.folio.rest.jaxrs.model.PackageVisibility;
import org.folio.rest.jaxrs.model.Token;
import org.folio.util.PackagesTestUtil;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
-class PackagePutBodyValidatorTest {
+@ExtendWith(MockitoExtension.class)
+class ManagedPackagePutBodyValidatorTest {
- private final PackagePutBodyValidator validator = new PackagePutBodyValidator();
+ @Mock
+ private PackageCustomAttributesValidator customAttributesValidator;
+
+ @InjectMocks
+ private ManagedPackagePutBodyValidator validator;
+
+ @BeforeEach
+ void setUp() {
+ lenient().doNothing().when(customAttributesValidator).validate(any());
+ }
@Test
void shouldValidateWhenPackageIsSelected() {
- var packagePutRequest = PackagesTestUtil.getPackagePutRequest(
+ var request = PackagesTestUtil.getPackagePutRequest(
new PackagePutDataAttributes()
.withIsSelected(true)
.withCustomCoverage(new Coverage())
- .withAllowKbToAddTitles(true)
- );
- assertDoesNotThrow(() -> validator.validate(packagePutRequest));
+ .withAllowKbToAddTitles(true));
+ assertDoesNotThrow(() -> validator.validate(request));
}
@Test
@@ -34,9 +50,10 @@ void shouldThrowExceptionWhenPackageIsNotSelectedAndIsHiddenIsTrue() {
var request = PackagesTestUtil.getPackagePutRequest(
new PackagePutDataAttributes()
.withIsSelected(false)
- .withVisibility(List.of(new PackageVisibility().withCategory(PackageVisibility.Category.PF).withHidden(true)))
- );
-
+ .withVisibility(List.of(
+ new PackageVisibility()
+ .withCategory(PackageVisibility.Category.PF)
+ .withHidden(true))));
var exception = assertThrows(InputValidationException.class, () -> validator.validate(request));
assertTrue(exception.getMessage().contains("visibility"));
}
@@ -46,9 +63,7 @@ void shouldThrowExceptionWhenPackageIsNotSelectedAndCoverageIsNotEmpty() {
var request = PackagesTestUtil.getPackagePutRequest(
new PackagePutDataAttributes()
.withIsSelected(false)
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("2000-01-01")));
-
+ .withCustomCoverage(new Coverage().withBeginCoverage("2000-01-01")));
var exception = assertThrows(InputValidationException.class, () -> validator.validate(request));
assertTrue(exception.getMessage().contains("beginCoverage"));
}
@@ -59,7 +74,6 @@ void shouldThrowExceptionWhenPackageIsNotSelectedAndAllowToAddTitlesTrue() {
new PackagePutDataAttributes()
.withIsSelected(false)
.withAllowKbToAddTitles(true));
-
var exception = assertThrows(InputValidationException.class, () -> validator.validate(request));
assertTrue(exception.getMessage().contains("allowKbToAddTitles"));
}
@@ -70,7 +84,6 @@ void shouldThrowExceptionWhenPackageIsNotSelectedAndTokenIsNotEmpty() {
new PackagePutDataAttributes()
.withIsSelected(false)
.withPackageToken(new Token().withValue("tokenValue")));
-
var exception = assertThrows(InputValidationException.class, () -> validator.validate(request));
assertTrue(exception.getMessage().contains("value"));
}
@@ -81,30 +94,7 @@ void shouldThrowExceptionWhenPackageIsSelectedAndTokenIsTooLong() {
new PackagePutDataAttributes()
.withIsSelected(true)
.withPackageToken(new Token().withValue(StringUtils.repeat("tokenvalue", 200))));
-
var exception = assertThrows(InputValidationException.class, () -> validator.validate(request));
assertTrue(exception.getMessage().contains("value"));
}
-
- @Test
- void shouldThrowExceptionWhenPackageIsSelectedAndCoverageDateIsInvalid() {
- var request = PackagesTestUtil.getPackagePutRequest(
- new PackagePutDataAttributes()
- .withIsSelected(true)
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("abcd-ab-ab")));
-
- var exception = assertThrows(InputValidationException.class, () -> validator.validate(request));
- assertTrue(exception.getMessage().contains("beginCoverage"));
- }
-
- @Test
- void shouldValidateWhenPackageIsSelectedAndCoverageDateIsEmpty() {
- var packagePutRequest = PackagesTestUtil.getPackagePutRequest(
- new PackagePutDataAttributes()
- .withIsSelected(true)
- .withCustomCoverage(new Coverage()
- .withBeginCoverage("")));
- assertDoesNotThrow(() -> validator.validate(packagePutRequest));
- }
}
diff --git a/src/test/java/org/folio/rest/validator/packages/PackageCustomAttributesValidatorTest.java b/src/test/java/org/folio/rest/validator/packages/PackageCustomAttributesValidatorTest.java
new file mode 100644
index 000000000..5fc8a9751
--- /dev/null
+++ b/src/test/java/org/folio/rest/validator/packages/PackageCustomAttributesValidatorTest.java
@@ -0,0 +1,225 @@
+package org.folio.rest.validator.packages;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.IntStream;
+import org.folio.rest.exception.InputValidationException;
+import org.folio.rest.jaxrs.model.Coverage;
+import org.folio.rest.jaxrs.model.PackageAltName;
+import org.folio.rest.validator.packages.PackageCustomAttributesValidator.PackageCustomAttributes;
+import org.junit.jupiter.api.Test;
+
+class PackageCustomAttributesValidatorTest {
+
+ private final PackageCustomAttributesValidator validator = new PackageCustomAttributesValidator();
+
+ @Test
+ void shouldThrowWhenCustomDescriptionExceedsMaxLength() {
+ var customAttributes = withDescription("a".repeat(2001));
+ assertThrows(InputValidationException.class, () -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldNotThrowWhenCustomDescriptionIsExactlyMaxLength() {
+ var customAttributes = withDescription("a".repeat(2000));
+ assertDoesNotThrow(() -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldNotThrowWhenCustomDescriptionContainsHtml() {
+ var customAttributes = withDescription("bold");
+ assertDoesNotThrow(() -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldNotThrowWhenCustomDescriptionIsNull() {
+ var customAttributes = withDescription(null);
+ assertDoesNotThrow(() -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldThrowWhenCustomDisplayNameExceedsMaxLength() {
+ var customAttributes = withDisplayName("a".repeat(301));
+ assertThrows(InputValidationException.class, () -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldNotThrowWhenCustomDisplayNameIsExactlyMaxLength() {
+ var customAttributes = withDisplayName("a".repeat(300));
+ assertDoesNotThrow(() -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldThrowWhenCustomDisplayNameContainsHtml() {
+ var customAttributes = withDisplayName("name");
+ assertThrows(InputValidationException.class, () -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldNotThrowWhenCustomDisplayNameIsNull() {
+ var customAttributes = withDisplayName(null);
+ assertDoesNotThrow(() -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldThrowWhenCustomAltNamesExceedMaxCount() {
+ var altNames = IntStream.rangeClosed(1, 11)
+ .mapToObj(i -> new PackageAltName().withAltName("name" + i))
+ .toList();
+ var customAttributes = withAltNames(altNames);
+ assertThrows(InputValidationException.class, () -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldNotThrowWhenCustomAltNamesCountIsExactlyMax() {
+ var altNames = IntStream.rangeClosed(1, 10)
+ .mapToObj(i -> new PackageAltName().withAltName("name" + i))
+ .toList();
+ var customAttributes = withAltNames(altNames);
+ assertDoesNotThrow(() -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldThrowWhenAltNameExceedsMaxLength() {
+ var customAttributes = withAltNames(Collections.singletonList(
+ new PackageAltName().withAltName("a".repeat(301))));
+ assertThrows(InputValidationException.class, () -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldThrowWhenAltNameContainsHtml() {
+ var customAttributes = withAltNames(Collections.singletonList(
+ new PackageAltName().withAltName("alt")));
+ assertThrows(InputValidationException.class, () -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldNotThrowWhenCustomAltNamesIsNull() {
+ var customAttributes = withAltNames(null);
+ assertDoesNotThrow(() -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldThrowWhenUrlExceedsMaxLength() {
+ var customAttributes = withUrl("a".repeat(501));
+ assertThrows(InputValidationException.class, () -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldNotThrowWhenUrlIsExactlyMaxLength() {
+ var customAttributes = withUrl("https://example.com/" + "a".repeat(480));
+ assertDoesNotThrow(() -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldNotThrowWhenUrlIsValid() {
+ var customAttributes = withUrl("https://example.com/path");
+ assertDoesNotThrow(() -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldThrowWhenUrlHasNoProtocol() {
+ var customAttributes = withUrl("example.com");
+ assertThrows(InputValidationException.class, () -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldThrowWhenUrlIsInvalidFormat() {
+ var customAttributes = withUrl("not a url");
+ assertThrows(InputValidationException.class, () -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldNotThrowWhenUrlIsNull() {
+ var customAttributes = withUrl(null);
+ assertDoesNotThrow(() -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldNotThrowWhenCustomCoverageIsNull() {
+ var customAttributes = withCoverage(null);
+ assertDoesNotThrow(() -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldNotThrowWhenBeginCoverageIsNull() {
+ var customAttributes = withCoverage(new Coverage());
+ assertDoesNotThrow(() -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldThrowWhenBeginCoverageHasInvalidFormat() {
+ var customAttributes = withCoverage(new Coverage().withBeginCoverage("not-a-date"));
+ assertThrows(InputValidationException.class, () -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldThrowWhenEndCoverageHasInvalidFormat() {
+ var customAttributes = withCoverage(new Coverage()
+ .withBeginCoverage("2020-01-01")
+ .withEndCoverage("not-a-date"));
+ assertThrows(InputValidationException.class, () -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldThrowWhenBeginCoverageIsEmptyButEndCoverageIsNot() {
+ var customAttributes = withCoverage(new Coverage()
+ .withBeginCoverage("")
+ .withEndCoverage("2020-12-31"));
+ assertThrows(InputValidationException.class, () -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldThrowWhenBeginCoverageIsAfterEndCoverage() {
+ var customAttributes = withCoverage(new Coverage()
+ .withBeginCoverage("2021-01-01")
+ .withEndCoverage("2020-01-01"));
+ assertThrows(InputValidationException.class, () -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldNotThrowWhenCoverageHasValidDates() {
+ var customAttributes = withCoverage(new Coverage()
+ .withBeginCoverage("2020-01-01")
+ .withEndCoverage("2021-12-31"));
+ assertDoesNotThrow(() -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldNotThrowWhenBeginCoverageIsValidAndEndIsNull() {
+ var customAttributes = withCoverage(new Coverage()
+ .withBeginCoverage("2020-01-01"));
+ assertDoesNotThrow(() -> validator.validate(customAttributes));
+ }
+
+ @Test
+ void shouldNotThrowWhenBothCoverageDatesAreEmpty() {
+ var customAttributes = withCoverage(new Coverage()
+ .withBeginCoverage("")
+ .withEndCoverage(""));
+ assertDoesNotThrow(() -> validator.validate(customAttributes));
+ }
+
+ private PackageCustomAttributes withDescription(String description) {
+ return new PackageCustomAttributes(description, null, null, null, null);
+ }
+
+ private PackageCustomAttributes withDisplayName(String displayName) {
+ return new PackageCustomAttributes(null, displayName, null, null, null);
+ }
+
+ private PackageCustomAttributes withAltNames(List altNames) {
+ return new PackageCustomAttributes(null, null, null, altNames, null);
+ }
+
+ private PackageCustomAttributes withUrl(String url) {
+ return new PackageCustomAttributes(null, null, url, null, null);
+ }
+
+ private PackageCustomAttributes withCoverage(Coverage coverage) {
+ return new PackageCustomAttributes(null, null, null, null, coverage);
+ }
+}
diff --git a/src/test/java/org/folio/rest/validator/packages/PackagePostValidatorTest.java b/src/test/java/org/folio/rest/validator/packages/PackagePostValidatorTest.java
new file mode 100644
index 000000000..3272751db
--- /dev/null
+++ b/src/test/java/org/folio/rest/validator/packages/PackagePostValidatorTest.java
@@ -0,0 +1,104 @@
+package org.folio.rest.validator.packages;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.lenient;
+
+import org.folio.rest.exception.InputValidationException;
+import org.folio.rest.jaxrs.model.ContentType;
+import org.folio.rest.jaxrs.model.Coverage;
+import org.folio.rest.jaxrs.model.PackagePostData;
+import org.folio.rest.jaxrs.model.PackagePostDataAttributes;
+import org.folio.rest.jaxrs.model.PackagePostRequest;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class PackagePostValidatorTest {
+
+ @Mock
+ private PackageCustomAttributesValidator customAttributesValidator;
+
+ @InjectMocks
+ private PackagesPostBodyValidator validator;
+
+ @BeforeEach
+ void setUp() {
+ lenient().doNothing().when(customAttributesValidator).validate(any());
+ }
+
+ @Test
+ void shouldThrowExceptionWhenNoPostBody() {
+ assertThrows(InputValidationException.class, () -> validator.validate(null));
+ }
+
+ @Test
+ void shouldThrowExceptionWhenEmptyBody() {
+ var postRequest = new PackagePostRequest();
+ assertThrows(InputValidationException.class, () -> validator.validate(postRequest));
+ }
+
+ @Test
+ void shouldThrowExceptionWhenNoPostData() {
+ var postRequest = new PackagePostRequest().withData(null);
+ assertThrows(InputValidationException.class, () -> validator.validate(postRequest));
+ }
+
+ @Test
+ void shouldThrowExceptionWhenEmptyPostData() {
+ var postRequest = new PackagePostRequest().withData(new PackagePostData());
+ assertThrows(InputValidationException.class, () -> validator.validate(postRequest));
+ }
+
+ @Test
+ void shouldThrowExceptionWhenEmptyPostDataAttributes() {
+ var postRequest = new PackagePostRequest()
+ .withData(new PackagePostData()
+ .withAttributes(new PackagePostDataAttributes()));
+ assertThrows(InputValidationException.class, () -> validator.validate(postRequest));
+ }
+
+ @Test
+ void shouldThrowExceptionWhenPostDataAttributesNameIsEmpty() {
+ var postRequest = new PackagePostRequest()
+ .withData(new PackagePostData()
+ .withAttributes(new PackagePostDataAttributes()
+ .withName("")));
+ assertThrows(InputValidationException.class, () -> validator.validate(postRequest));
+ }
+
+ @Test
+ void shouldThrowExceptionWhenPostDataAttributesTypeIsNull() {
+ var postRequest = new PackagePostRequest()
+ .withData(new PackagePostData()
+ .withAttributes(new PackagePostDataAttributes()
+ .withName("name")));
+ assertThrows(InputValidationException.class, () -> validator.validate(postRequest));
+ }
+
+ @Test
+ void shouldThrowExceptionWhenBeginCoverageIsNull() {
+ var postRequest = new PackagePostRequest()
+ .withData(new PackagePostData()
+ .withAttributes(new PackagePostDataAttributes()
+ .withName("name")
+ .withContentType(ContentType.STREAMING_MEDIA)
+ .withCustomCoverage(new Coverage())));
+ assertThrows(InputValidationException.class, () -> validator.validate(postRequest));
+ }
+
+ @Test
+ void shouldNotThrowExceptionWhenCoverageIsNull() {
+ var postRequest = new PackagePostRequest()
+ .withData(new PackagePostData()
+ .withAttributes(new PackagePostDataAttributes()
+ .withName("name")
+ .withContentType(ContentType.STREAMING_MEDIA)));
+ assertDoesNotThrow(() -> validator.validate(postRequest));
+ }
+}
diff --git a/src/test/java/org/folio/rest/validator/PackageTagsPutBodyValidatorTest.java b/src/test/java/org/folio/rest/validator/packages/PackageTagsPutBodyValidatorTest.java
similarity index 83%
rename from src/test/java/org/folio/rest/validator/PackageTagsPutBodyValidatorTest.java
rename to src/test/java/org/folio/rest/validator/packages/PackageTagsPutBodyValidatorTest.java
index 693351712..44e617584 100644
--- a/src/test/java/org/folio/rest/validator/PackageTagsPutBodyValidatorTest.java
+++ b/src/test/java/org/folio/rest/validator/packages/PackageTagsPutBodyValidatorTest.java
@@ -1,4 +1,4 @@
-package org.folio.rest.validator;
+package org.folio.rest.validator.packages;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -20,8 +20,7 @@ void shouldThrowExceptionWhenNameIsEmpty() {
.withName("")
.withContentType(ContentType.E_BOOK)
));
- assertThrows(InputValidationException.class, () ->
- validator.validate(request));
+ assertThrows(InputValidationException.class, () -> validator.validate(request));
}
@Test
@@ -31,7 +30,6 @@ void shouldThrowExceptionWhenContentTypeIsNull() {
.withAttributes(new PackageTagsDataAttributes()
.withName("name")
));
- assertThrows(InputValidationException.class, () ->
- validator.validate(request));
+ assertThrows(InputValidationException.class, () -> validator.validate(request));
}
}
diff --git a/src/test/resources/requests/kb-ebsco/package/post-package-request.json b/src/test/resources/requests/kb-ebsco/package/post-package-request.json
index a8d902f1b..4f0231267 100644
--- a/src/test/resources/requests/kb-ebsco/package/post-package-request.json
+++ b/src/test/resources/requests/kb-ebsco/package/post-package-request.json
@@ -2,12 +2,29 @@
"data": {
"type": "packages",
"attributes": {
- "name": "TEST_NAME",
"contentType": "Streaming Media",
+ "customAltNames": [
+ {
+ "altName": "TEST_ALT_NAME"
+ },
+ {
+ "id": 1,
+ "altName": "TEST_ALT_NAME_2"
+ }
+ ],
"customCoverage": {
"beginCoverage": "2017-12-23",
"endCoverage": "2018-03-30"
- }
+ },
+ "customDescription": "TEST_DESCRIPTION",
+ "customDisplayName": "TEST_DISPLAY_NAME",
+ "isFreeAccess": true,
+ "name": "TEST_NAME",
+ "proxy": {
+ "id": "proxy-id",
+ "inherited": true
+ },
+ "url": "https://example.com/test-url"
}
}
}