From 55148a6b9507782de3bacb655a3ac22f5174571f Mon Sep 17 00:00:00 2001 From: eskander Date: Thu, 25 Aug 2022 17:32:38 +0200 Subject: [PATCH 1/3] [DSC-712] Create a find method to return bitstrems belonging to a bundle filtered by dc.type --- .../repository/BitstreamRestRepository.java | 103 ++++++++ .../app/rest/BitstreamRestRepositoryIT.java | 243 ++++++++++++++++++ 2 files changed, 346 insertions(+) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java index ae3cf91d4c4..eacaf8c7885 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java @@ -10,6 +10,7 @@ import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.UUID; @@ -32,10 +33,12 @@ import org.dspace.content.Community; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; +import org.dspace.content.MetadataValue; import org.dspace.content.service.BitstreamService; import org.dspace.content.service.BundleService; import org.dspace.content.service.CollectionService; import org.dspace.content.service.CommunityService; +import org.dspace.content.service.ItemService; import org.dspace.core.Context; import org.dspace.handle.service.HandleService; import org.springframework.beans.factory.annotation.Autowired; @@ -72,6 +75,9 @@ public class BitstreamRestRepository extends DSpaceObjectRestRepository findByItemId(@Parameter(value = "uuid", required = true) UUID uuid, + @Parameter(value = "name", required = true) String name, + @Parameter(value = "filterMetadata") String metadata, + @Parameter(value = "filterMetadataValue") String value, + Pageable pageable) { + + validateParameters(metadata, value); + + try { + + List bitstreams = new ArrayList<>(); + List matchedBitstreams; + Context context = obtainContext(); + + Item item = itemService.find(context, uuid); + + if (item == null) { + throw new UnprocessableEntityException("The provided uuid:" + uuid + " does not correspond to an " + + "existing item"); + } + + bs.getItemBitstreams(context, item).forEachRemaining(bitstreams::add); + + matchedBitstreams = filterByBundleName(bitstreams, name); + + if (metadata != null && value != null) { + matchedBitstreams = filterByMetadataAndValue(matchedBitstreams, metadata, value); + } + + if (matchedBitstreams.isEmpty()) { + throw new ResourceNotFoundException("no matched bitstreams found"); + } + + return converter.toRestPage(matchedBitstreams, pageable, matchedBitstreams.size(), + utils.obtainProjection()); + } catch (SQLException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + private void validateParameters(String metadata, String value) { + if ((metadata != null && value == null) || (value != null && metadata == null)) { + throw new IllegalArgumentException("The request must include a filterMetadata " + + "and a filterMetadataValue together"); + } + } + private Bitstream getFirstMatchedBitstream(Item item, Integer sequence, String filename) { List bundles = item.getBundles(); List bitstreams = new LinkedList<>(); @@ -248,4 +313,42 @@ public BundleRest performBitstreamMove(Context context, Bitstream bitstream, Bun return converter.toRest(targetBundle, utils.obtainProjection()); } + + private List filterByBundleName(List bitstreams, String name) throws SQLException { + List matchedBitstreams = new ArrayList<>(); + for (Bitstream bitstream : bitstreams) { + for (Bundle bundle : bitstream.getBundles()) { + if (bundle.getName().equals(name)) { + matchedBitstreams.add(bitstream); + } + } + } + return matchedBitstreams; + } + + private List filterByMetadataAndValue(List bitstreams, String metadata, String value) { + List matchedBitstreams = new ArrayList<>(); + for (Bitstream bitstream : bitstreams) { + for (MetadataValue metadataValue : bitstream.getMetadata()) { + if (isMatched(metadataValue, metadata, value)) { + matchedBitstreams.add(bitstream); + } + } + } + + return matchedBitstreams; + } + + private boolean isMatched(MetadataValue metadataValue, String metadata, String value) { + + boolean metadataMatched = metadataValue.getMetadataField().toString('.').equals(metadata); + + if (value.startsWith("(") && value.endsWith(")")) { + value = value.substring(1, value.length() - 1); + return metadataMatched && metadataValue.getValue().matches(value); + } else { + return metadataMatched && metadataValue.getValue().equals(value); + } + } + } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java index f9c1e469fcf..b901c7e81bd 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java @@ -11,6 +11,7 @@ import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadataDoesNotExist; import static org.dspace.core.Constants.WRITE; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; @@ -2279,6 +2280,248 @@ public void findByHandleAndFileNameForPublicItemWithEmbargoOnFile() throws Excep )); } + @Test + public void findByItemIdWithoutRequiredParameters() throws Exception { + + context.turnOffAuthorisationSystem(); + + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1") + .build(); + + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .build(); + + context.restoreAuthSystemState(); + + getClient().perform(get("/api/core/bitstreams/search/byItemId") + .param("uuid", publicItem1.getID().toString())) + .andExpect(status().isBadRequest()); + + } + + @Test + public void findByItemIdWithMetadataAndWithoutMetadataValue() throws Exception { + + context.turnOffAuthorisationSystem(); + + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1") + .build(); + + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .build(); + + context.restoreAuthSystemState(); + + getClient().perform(get("/api/core/bitstreams/search/byItemId") + .param("uuid", publicItem1.getID().toString()) + .param("name", "bundle name") + .param("filterMetadata", "dc.title")) + .andExpect(status().isBadRequest()); + + } + + @Test + public void findByFakeItemId() throws Exception { + + String fakeId = "9cc8104e-5337-4305-b4ce-b578eb1b24ba"; + + getClient().perform(get("/api/core/bitstreams/search/byItemId") + .param("uuid", fakeId) + .param("name", "bundle name") + .param("filterMetadata", "dc.title") + .param("filterMetadataValue", "test")) + .andExpect(status().isUnprocessableEntity()); + + } + + @Test + public void findByItemIdWithNoMatchedBitstreams() throws Exception { + + context.turnOffAuthorisationSystem(); + + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1").build(); + + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .build(); + + Bundle license = BundleBuilder.createBundle(context, publicItem1) + .withName("LICENSE") + .build(); + + String bitstreamContent1 = "This is an archived bitstream"; + Bitstream bitstream1 = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent1, CharEncoding.UTF_8)) { + bitstream1 = BitstreamBuilder. + createBitstream(context, license, is) + .withName("license bitstream name") + .withMimeType("text/plain") + .build(); + } + + getClient().perform(get("/api/core/bitstreams/search/byItemId") + .param("uuid", publicItem1.getID().toString()) + .param("name", license.getName()) + .param("filterMetadata", "dc.title") + .param("filterMetadataValue", "wrong value")) + .andExpect(status().isNotFound()); + + } + @Test + public void findByItemIdAndBundleNameAndMetadataValue() throws Exception { + + context.turnOffAuthorisationSystem(); + + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1") + .build(); + + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .build(); + + Bundle license = BundleBuilder.createBundle(context, publicItem1) + .withName("LICENSE") + .build(); + + String bitstreamContent1 = "This is an archived bitstream"; + Bitstream bitstream1 = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent1, CharEncoding.UTF_8)) { + bitstream1 = BitstreamBuilder. + createBitstream(context, license, is) + .withName("this is a test") + .withMimeType("text/plain") + .build(); + } + + String bitstreamContent2 = "This is an license bitstream"; + Bitstream bitstream2 = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent2, CharEncoding.UTF_8)) { + bitstream2 = BitstreamBuilder. + createBitstream(context, license, is) + .withName("this is a test 2") + .withMimeType("text/plain") + .build(); + } + + getClient().perform(get("/api/core/bitstreams/search/byItemId") + .param("uuid", publicItem1.getID().toString()) + .param("name", license.getName()) + .param("filterMetadata", "dc.title") + .param("filterMetadataValue", "this is a test") + .param("projection", "full")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andExpect(jsonPath("$._embedded.bitstreams", hasSize(1))) + .andExpect(jsonPath("$._embedded.bitstreams", contains( + BitstreamMatcher.matchBitstreamEntry(bitstream1) + ))); + + getClient().perform(get("/api/core/bitstreams/search/byItemId") + .param("uuid", publicItem1.getID().toString()) + .param("name", license.getName()) + .param("filterMetadata", "dc.title") + .param("filterMetadataValue", "([a-z]+ [a-z]+ [a-z]+ [a-z]+)") + .param("projection", "full")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andExpect(jsonPath("$._embedded.bitstreams", hasSize(1))) + .andExpect(jsonPath("$._embedded.bitstreams", contains( + BitstreamMatcher.matchBitstreamEntry(bitstream1) + ))); + + } + + @Test + public void findByItemIdAndBundleName() throws Exception { + + context.turnOffAuthorisationSystem(); + + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .build(); + + Bundle license = BundleBuilder.createBundle(context, publicItem1) + .withName("LICENSE") + .build(); + + Bundle original = BundleBuilder.createBundle(context, publicItem1) + .withName("ORIGINAL") + .build(); + + String bitstreamContent1 = "This is an archived bitstream"; + Bitstream bitstream1 = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent1, CharEncoding.UTF_8)) { + bitstream1 = BitstreamBuilder. + createBitstream(context, license, is) + .withName("this is a test") + .withMimeType("text/plain") + .build(); + } + + String bitstreamContent2 = "This is an original bitstream"; + Bitstream bitstream2 = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent2, CharEncoding.UTF_8)) { + bitstream2 = BitstreamBuilder. + createBitstream(context, original, is) + .withName("original bitstream name") + .withMimeType("text/plain") + .build(); + } + + getClient().perform(get("/api/core/bitstreams/search/byItemId") + .param("uuid", publicItem1.getID().toString()) + .param("name", license.getName()) + .param("projection", "full")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andExpect(jsonPath("$._embedded.bitstreams", hasSize(1))) + .andExpect(jsonPath("$._embedded.bitstreams", contains( + BitstreamMatcher.matchBitstreamEntry(bitstream1) + ))); + + } } From a28610a0a2f954131f21f2a64b9d6fa9085e203b Mon Sep 17 00:00:00 2001 From: Luca Giamminonni Date: Thu, 22 Sep 2022 13:10:22 +0200 Subject: [PATCH 2/3] [DSC-712] Added support for many filterMetadata --- .../repository/BitstreamRestRepository.java | 138 ++++++++++-------- .../app/rest/BitstreamRestRepositoryIT.java | 113 +++++++++++++- 2 files changed, 187 insertions(+), 64 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java index eacaf8c7885..e5747e924f8 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java @@ -7,13 +7,22 @@ */ package org.dspace.app.rest.repository; +import static org.apache.commons.lang3.ArrayUtils.nullToEmpty; + import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; -import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Spliterators; import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; @@ -40,6 +49,7 @@ import org.dspace.content.service.CommunityService; import org.dspace.content.service.ItemService; import org.dspace.core.Context; +import org.dspace.core.exception.SQLRuntimeException; import org.dspace.handle.service.HandleService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; @@ -205,50 +215,22 @@ public BitstreamRest findByItemHandle(@Parameter(value = "handle", required = tr */ @SearchRestMethod(name = "byItemId") public Page findByItemId(@Parameter(value = "uuid", required = true) UUID uuid, - @Parameter(value = "name", required = true) String name, - @Parameter(value = "filterMetadata") String metadata, - @Parameter(value = "filterMetadataValue") String value, + @Parameter(value = "name", required = true) String bundleName, + @Parameter(value = "filterMetadata") String[] filterMetadataFields, + @Parameter(value = "filterMetadataValue") String[] filterMetadataValues, Pageable pageable) { - validateParameters(metadata, value); - - try { - - List bitstreams = new ArrayList<>(); - List matchedBitstreams; - Context context = obtainContext(); - - Item item = itemService.find(context, uuid); - - if (item == null) { - throw new UnprocessableEntityException("The provided uuid:" + uuid + " does not correspond to an " + - "existing item"); - } - - bs.getItemBitstreams(context, item).forEachRemaining(bitstreams::add); - - matchedBitstreams = filterByBundleName(bitstreams, name); - - if (metadata != null && value != null) { - matchedBitstreams = filterByMetadataAndValue(matchedBitstreams, metadata, value); - } + Map filterMetadata = composeFilterMetadata(filterMetadataFields, filterMetadataValues); - if (matchedBitstreams.isEmpty()) { - throw new ResourceNotFoundException("no matched bitstreams found"); - } + Item item = findItemById(uuid) + .orElseThrow(() -> new UnprocessableEntityException("No item found with the given UUID")); - return converter.toRestPage(matchedBitstreams, pageable, matchedBitstreams.size(), - utils.obtainProjection()); - } catch (SQLException e) { - throw new RuntimeException(e.getMessage(), e); - } - } + List bitstreams = getItemBitstreams(item) + .filter(bitstream -> isContainedInBundleNamed(bitstream, bundleName)) + .filter(bitstream -> hasAllMetadataValues(bitstream, filterMetadata)) + .collect(Collectors.toList()); - private void validateParameters(String metadata, String value) { - if ((metadata != null && value == null) || (value != null && metadata == null)) { - throw new IllegalArgumentException("The request must include a filterMetadata " + - "and a filterMetadataValue together"); - } + return converter.toRestPage(bitstreams, pageable, bitstreams.size(), utils.obtainProjection()); } private Bitstream getFirstMatchedBitstream(Item item, Integer sequence, String filename) { @@ -314,41 +296,73 @@ public BundleRest performBitstreamMove(Context context, Bitstream bitstream, Bun return converter.toRest(targetBundle, utils.obtainProjection()); } - private List filterByBundleName(List bitstreams, String name) throws SQLException { - List matchedBitstreams = new ArrayList<>(); - for (Bitstream bitstream : bitstreams) { - for (Bundle bundle : bitstream.getBundles()) { - if (bundle.getName().equals(name)) { - matchedBitstreams.add(bitstream); - } - } + private Optional findItemById(UUID uuid) { + try { + return Optional.ofNullable(itemService.find(obtainContext(), uuid)); + } catch (SQLException e) { + throw new SQLRuntimeException(e); } - return matchedBitstreams; } - private List filterByMetadataAndValue(List bitstreams, String metadata, String value) { - List matchedBitstreams = new ArrayList<>(); - for (Bitstream bitstream : bitstreams) { - for (MetadataValue metadataValue : bitstream.getMetadata()) { - if (isMatched(metadataValue, metadata, value)) { - matchedBitstreams.add(bitstream); - } - } + private Map composeFilterMetadata(String[] fields, String[] values) { + + if (filterMetadataDoNotHaveSameCardinality(fields, values)) { + throw new IllegalArgumentException("The request must include a filterMetadata " + + "and a filterMetadataValue parameters with the same cardinality"); + } + + Map filterMetadata = new HashMap(); + + for (int i = 0; i < nullToEmpty(fields).length; i++) { + filterMetadata.put(fields[i], values[i]); } - return matchedBitstreams; + return filterMetadata; + } - private boolean isMatched(MetadataValue metadataValue, String metadata, String value) { + private boolean filterMetadataDoNotHaveSameCardinality(String[] fields, String[] values) { + return nullToEmpty(fields).length != nullToEmpty(values).length; + } - boolean metadataMatched = metadataValue.getMetadataField().toString('.').equals(metadata); + private Stream getItemBitstreams(Item item) { + try { + Iterator bitstreamIterator = bs.getItemBitstreams(obtainContext(), item); + return StreamSupport.stream(Spliterators.spliteratorUnknownSize(bitstreamIterator, 0), false); + } catch (SQLException e) { + throw new SQLRuntimeException(e); + } + } + + private boolean isContainedInBundleNamed(Bitstream bitstream, String name) { + try { + return bitstream.getBundles().stream() + .anyMatch(bundle -> bundle.getName().equals(name)); + } catch (SQLException e) { + throw new SQLRuntimeException(e); + } + } + + private boolean hasAllMetadataValues(Bitstream bitstream, Map filterMetadata) { + return filterMetadata.keySet().stream() + .allMatch(metadataField -> hasMetadataValue(bitstream, metadataField, filterMetadata.get(metadataField))); + } + + private boolean hasMetadataValue(Bitstream bitstream, String metadataField, String value) { + return bitstream.getMetadata().stream() + .filter(metadataValue -> metadataValue.getMetadataField().toString('.').equals(metadataField)) + .anyMatch(metadataValue -> matchesMetadataValue(metadataValue, value)); + } + + private boolean matchesMetadataValue(MetadataValue metadataValue, String value) { if (value.startsWith("(") && value.endsWith(")")) { value = value.substring(1, value.length() - 1); - return metadataMatched && metadataValue.getValue().matches(value); + return metadataValue.getValue().matches(value); } else { - return metadataMatched && metadataValue.getValue().equals(value); + return metadataValue.getValue().equals(value); } + } } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java index b901c7e81bd..8f0d74ddde4 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java @@ -11,6 +11,7 @@ import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadataDoesNotExist; import static org.dspace.core.Constants.WRITE; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; @@ -2308,7 +2309,7 @@ public void findByItemIdWithoutRequiredParameters() throws Exception { } @Test - public void findByItemIdWithMetadataAndWithoutMetadataValue() throws Exception { + public void findByItemIdWithMetadataFieldsAndValuesWithDifferentCardinality() throws Exception { context.turnOffAuthorisationSystem(); @@ -2334,6 +2335,20 @@ public void findByItemIdWithMetadataAndWithoutMetadataValue() throws Exception { .param("filterMetadata", "dc.title")) .andExpect(status().isBadRequest()); + getClient().perform(get("/api/core/bitstreams/search/byItemId") + .param("uuid", publicItem1.getID().toString()) + .param("name", "bundle name") + .param("filterMetadata", "dc.title") + .param("filterMetadataValue", "Test", "Test 2")) + .andExpect(status().isBadRequest()); + + getClient().perform(get("/api/core/bitstreams/search/byItemId") + .param("uuid", publicItem1.getID().toString()) + .param("name", "bundle name") + .param("filterMetadata", "dc.title", "dc.date.issued", "dc.description") + .param("filterMetadataValue", "Test", "Test 2")) + .andExpect(status().isBadRequest()); + } @Test @@ -2387,7 +2402,8 @@ public void findByItemIdWithNoMatchedBitstreams() throws Exception { .param("name", license.getName()) .param("filterMetadata", "dc.title") .param("filterMetadataValue", "wrong value")) - .andExpect(status().isNotFound()); + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))); } @@ -2460,6 +2476,20 @@ public void findByItemIdAndBundleNameAndMetadataValue() throws Exception { BitstreamMatcher.matchBitstreamEntry(bitstream1) ))); + getClient().perform(get("/api/core/bitstreams/search/byItemId") + .param("uuid", publicItem1.getID().toString()) + .param("name", license.getName()) + .param("filterMetadata", "dc.title") + .param("filterMetadataValue", "(this is a test.*)") + .param("projection", "full")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(2))) + .andExpect(jsonPath("$._embedded.bitstreams", hasSize(2))) + .andExpect(jsonPath("$._embedded.bitstreams", containsInAnyOrder( + BitstreamMatcher.matchBitstreamEntry(bitstream1), + BitstreamMatcher.matchBitstreamEntry(bitstream2) + ))); + } @Test @@ -2524,4 +2554,83 @@ public void findByItemIdAndBundleName() throws Exception { } + @Test + public void searchByItemWithManyFilterMetadata() throws Exception { + + context.turnOffAuthorisationSystem(); + + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1") + .build(); + + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .build(); + + Bundle license = BundleBuilder.createBundle(context, publicItem1) + .withName("LICENSE") + .build(); + + Bitstream bitstream1 = BitstreamBuilder.createBitstream(context, license, InputStream.nullInputStream()) + .withName("this is a test") + .withType("Image") + .withMimeType("text/plain") + .build(); + + Bitstream bitstream2 = BitstreamBuilder.createBitstream(context, license, InputStream.nullInputStream()) + .withName("this is a test") + .withType("Personal Picture") + .withMimeType("text/plain") + .build(); + + Bitstream bitstream3 = BitstreamBuilder.createBitstream(context, license, InputStream.nullInputStream()) + .withName("this is a test 2") + .withType("Personal Picture") + .withMimeType("text/plain") + .build(); + + getClient().perform(get("/api/core/bitstreams/search/byItemId") + .param("uuid", publicItem1.getID().toString()) + .param("name", license.getName()) + .param("filterMetadata", "dc.title") + .param("filterMetadataValue", "this is a test") + .param("projection", "full")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(2))) + .andExpect(jsonPath("$._embedded.bitstreams", containsInAnyOrder( + BitstreamMatcher.matchBitstreamEntry(bitstream1), + BitstreamMatcher.matchBitstreamEntry(bitstream2)))); + + getClient().perform(get("/api/core/bitstreams/search/byItemId") + .param("uuid", publicItem1.getID().toString()) + .param("name", license.getName()) + .param("filterMetadata", "dc.type") + .param("filterMetadataValue", "Personal Picture") + .param("projection", "full")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(2))) + .andExpect(jsonPath("$._embedded.bitstreams", containsInAnyOrder( + BitstreamMatcher.matchBitstreamEntry(bitstream2), + BitstreamMatcher.matchBitstreamEntry(bitstream3)))); + + getClient().perform(get("/api/core/bitstreams/search/byItemId") + .param("uuid", publicItem1.getID().toString()) + .param("name", license.getName()) + .param("filterMetadata", "dc.title", "dc.type") + .param("filterMetadataValue", "this is a test", "Personal Picture") + .param("projection", "full")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andExpect(jsonPath("$._embedded.bitstreams", hasSize(1))) + .andExpect(jsonPath("$._embedded.bitstreams", contains( + BitstreamMatcher.matchBitstreamEntry(bitstream2)))); + + } + } From 7e8842d2c37e5ca22d94e1e1b3776b0af6bc7444 Mon Sep 17 00:00:00 2001 From: Luca Giamminonni Date: Fri, 30 Sep 2022 15:04:55 +0200 Subject: [PATCH 3/3] [DSC-712] Fixed pagination --- .../org/dspace/app/rest/repository/BitstreamRestRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java index e5747e924f8..beb390ca644 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java @@ -230,7 +230,7 @@ public Page findByItemId(@Parameter(value = "uuid", required = tr .filter(bitstream -> hasAllMetadataValues(bitstream, filterMetadata)) .collect(Collectors.toList()); - return converter.toRestPage(bitstreams, pageable, bitstreams.size(), utils.obtainProjection()); + return converter.toRestPage(bitstreams, pageable, utils.obtainProjection()); } private Bitstream getFirstMatchedBitstream(Item item, Integer sequence, String filename) {