Compare commits

...

2 Commits

Author SHA1 Message Date
Tim Donohue
8fc191e9cb Merge pull request #11403 from tdonohue/port_11321_to_7x
[Port dspace-7_x] DS-8943: adds limit to number of typed links to bitstreams in header
2025-10-02 08:48:10 -05:00
nwoodward
b5501981ab added limit to number of typed links to bitstreams to display, falls back to Link Sets if limit is exceeded 2025-10-01 17:15:14 -05:00
3 changed files with 97 additions and 3 deletions

View File

@@ -18,6 +18,7 @@ import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.security.BitstreamMetadataReadPermissionEvaluatorPlugin;
import org.dspace.app.rest.signposting.model.LinksetNode;
import org.dspace.app.rest.signposting.processor.bitstream.BitstreamSignpostingProcessor;
import org.dspace.app.rest.signposting.processor.item.ItemLinksetProcessor;
import org.dspace.app.rest.signposting.processor.item.ItemSignpostingProcessor;
import org.dspace.app.rest.signposting.processor.metadata.MetadataSignpostingProcessor;
import org.dspace.app.rest.signposting.service.LinksetService;
@@ -28,6 +29,7 @@ import org.dspace.content.Item;
import org.dspace.content.service.ItemService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.services.ConfigurationService;
import org.dspace.utils.DSpace;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -40,12 +42,18 @@ public class LinksetServiceImpl implements LinksetService {
private static final Logger log = LogManager.getLogger(LinksetServiceImpl.class);
@Autowired
private ConfigurationService configurationService;
@Autowired
protected ItemService itemService;
@Autowired
private BitstreamMetadataReadPermissionEvaluatorPlugin bitstreamMetadataReadPermissionEvaluatorPlugin;
@Autowired
ItemLinksetProcessor itemLinksetProcessor;
private final List<BitstreamSignpostingProcessor> bitstreamProcessors = new DSpace().getServiceManager()
.getServicesByType(BitstreamSignpostingProcessor.class);
@@ -74,10 +82,20 @@ public class LinksetServiceImpl implements LinksetService {
Context context,
DSpaceObject object
) {
int itemBitstreamsLimit = configurationService.getIntProperty("signposting.item.bitstreams.limit", 10);
List<LinksetNode> linksetNodes = new ArrayList<>();
if (object.getType() == Constants.ITEM) {
for (ItemSignpostingProcessor processor : itemProcessors) {
processor.addLinkSetNodes(context, request, (Item) object, linksetNodes);
int itemBitstreamsCount = countItemBitstreams((Item) object);
// Do not include individual bitstream typed links if their number exceeds
// the limit in the configuration.
if (itemBitstreamsCount < itemBitstreamsLimit) {
for (ItemSignpostingProcessor processor : itemProcessors) {
processor.addLinkSetNodes(context, request, (Item) object, linksetNodes);
}
} else {
itemLinksetProcessor.addLinkSetNodes(context, request, (Item) object, linksetNodes);
}
} else if (object.getType() == Constants.BITSTREAM) {
for (BitstreamSignpostingProcessor processor : bitstreamProcessors) {
@@ -151,4 +169,17 @@ public class LinksetServiceImpl implements LinksetService {
throw new RuntimeException(e);
}
}
private int countItemBitstreams(Item item) {
try {
int countBitstreams = 0;
List<Bundle> bundles = itemService.getBundles(item, Constants.DEFAULT_BUNDLE_NAME);
for (Bundle bundle: bundles) {
countBitstreams += bundle.getBitstreams().size();
}
return countBitstreams;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -8,6 +8,7 @@
package org.dspace.app.rest.signposting.controller;
import static org.dspace.content.MetadataSchemaEnum.PERSON;
import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
@@ -18,7 +19,9 @@ import java.io.InputStream;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.UUID;
import org.apache.commons.codec.CharEncoding;
import org.apache.commons.io.IOUtils;
@@ -691,6 +694,61 @@ public class LinksetRestControllerIT extends AbstractControllerIntegrationTest {
"&& @.type == 'application/linkset+json')]").exists());
}
@Test
public void showTypedLinksMissingForItemWithMoreBitstreamsThanLimit() throws Exception {
String bitstreamContent = "ThisIsSomeDummyText";
String bitstreamMimeType = "text/plain";
int itemBitstreamsLimit = configurationService.getIntProperty("signposting.item.bitstreams.limit", 10);
context.turnOffAuthorisationSystem();
Item item = ItemBuilder.createItem(context, collection)
.withTitle("Item Test")
.withMetadata("dc", "identifier", "doi", doi)
.build();
// Add more bitstreams than the configured limit
ArrayList<UUID> bitstreamIDs = new ArrayList<>();
for (int i = 0; i <= itemBitstreamsLimit; i++) {
Bitstream bitstream = null;
try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) {
bitstream = BitstreamBuilder.createBitstream(context, item, is)
.withName("Bitstream " + i)
.withDescription("description")
.withMimeType(bitstreamMimeType)
.build();
if (bitstream != null) {
bitstreamIDs.add(bitstream.getID());
}
}
}
context.restoreAuthSystemState();
// Make sure the bitstreams were successfully added.
assertTrue("There was a problem ingesting bitstreams.", bitstreamIDs.size() > itemBitstreamsLimit);
String url = configurationService.getProperty("dspace.ui.url");
String signpostingUrl = configurationService.getProperty("signposting.path");
// There should be typed links to the Link Sets but no typed links to the Bitstreams in the response.
// We only need to check for one of the Bitstream UUIDs, since all of them should be absent.
UUID firstBitstreamId = bitstreamIDs.get(0);
getClient().perform(get("/signposting/links/" + item.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$[?(@.href == '" + url + "/" + signpostingUrl + "/linksets/" +
item.getID().toString() + "' " +
"&& @.rel == 'linkset' " +
"&& @.type == 'application/linkset')]").exists())
.andExpect(jsonPath("$[?(@.href == '" + url + "/" + signpostingUrl + "/linksets/" +
item.getID().toString() + "/json' " +
"&& @.rel == 'linkset' " +
"&& @.type == 'application/linkset+json')]").exists())
.andExpect(jsonPath("$[?(@.href == '" + url + "/bitstreams/" + firstBitstreamId + "/download' " +
"&& @.rel == 'item' " +
"&& @.type == 'text/plain')]").doesNotExist());;
}
@Test
public void findTypedLinkForBitstream() throws Exception {
String bitstreamContent = "ThisIsSomeDummyText";

View File

@@ -32,4 +32,9 @@ signposting.enabled = true
signposting.describedby.crosswalk-name = DataCite
# Mime-type of response of handling of 'describedby' links.
signposting.describedby.mime-type = application/vnd.datacite.datacite+xml
signposting.describedby.mime-type = application/vnd.datacite.datacite+xml
# Limit to the number of an item's bitstreams to return as typed links.
# If there are more bitstreams than this limit then only the typed links to the Link Sets are added to the header.
# Defaults to 10 if the value is unspecified
# signposting.item.bitstreams.limit = 10