diff --git a/dspace-api/src/main/java/org/dspace/app/customurl/service/CustomUrlServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/customurl/service/CustomUrlServiceImpl.java index cceaa005f86..b6939aa11dd 100644 --- a/dspace-api/src/main/java/org/dspace/app/customurl/service/CustomUrlServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/customurl/service/CustomUrlServiceImpl.java @@ -17,6 +17,7 @@ import java.util.stream.Stream; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.dspace.app.customurl.CustomUrlService; import org.dspace.content.Item; import org.dspace.content.MetadataValue; @@ -129,7 +130,9 @@ public void deleteOldCustomUrlByIndex(Context context, Item item, int index) { @Override @SuppressWarnings("rawtypes") public Optional findItemByCustomUrl(Context context, String customUrl) { - + if (StringUtils.isBlank(customUrl)) { + return Optional.empty(); + } DiscoverQuery discoverQuery = new DiscoverQuery(); discoverQuery.addDSpaceObjectFilter(IndexableItem.TYPE); discoverQuery.addFilterQueries("customurl:" + searchService.escapeQueryChars(customUrl)); diff --git a/dspace-api/src/main/java/org/dspace/content/enhancer/impl/RelatedEntityItemEnhancer.java b/dspace-api/src/main/java/org/dspace/content/enhancer/impl/RelatedEntityItemEnhancer.java index 870dfbddfa8..4d3bd44fb92 100644 --- a/dspace-api/src/main/java/org/dspace/content/enhancer/impl/RelatedEntityItemEnhancer.java +++ b/dspace-api/src/main/java/org/dspace/content/enhancer/impl/RelatedEntityItemEnhancer.java @@ -15,6 +15,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -134,9 +135,11 @@ private boolean equivalent(Map> currMetadataValues, } private boolean equivalent(List metadataValue, List metadataValueDTO) { - if (metadataValue.size() != metadataValueDTO.size()) { + if ((Objects.isNull(metadataValue) && !Objects.isNull(metadataValueDTO)) || + (!Objects.isNull(metadataValue) && Objects.isNull(metadataValueDTO)) || + metadataValue.size() != metadataValueDTO.size()) { return false; - } else { + } else if (!Objects.isNull(metadataValue) && !Objects.isNull(metadataValueDTO)) { for (int i = 0; i < metadataValue.size(); i++) { if (!equivalent(metadataValue.get(i), metadataValueDTO.get(i))) { return false; diff --git a/dspace-api/src/main/java/org/dspace/content/enhancer/script/ItemEnhancerScript.java b/dspace-api/src/main/java/org/dspace/content/enhancer/script/ItemEnhancerScript.java index c965edd6766..968acb3b477 100644 --- a/dspace-api/src/main/java/org/dspace/content/enhancer/script/ItemEnhancerScript.java +++ b/dspace-api/src/main/java/org/dspace/content/enhancer/script/ItemEnhancerScript.java @@ -73,9 +73,9 @@ private void enhanceItems(Context context) { try { int total = itemService.countArchivedItems(context); for (int offset = 0; offset < total; offset += PAGE_SIZE) { + // commit and session clear within the enhance method + // do one by one to reduce the risk of conflict with the enhance thread findItemsToEnhance(offset).forEachRemaining(this::enhanceItem); - context.commit(); - context.clear(); } } catch (SQLException e) { throw new SQLRuntimeException(e); @@ -91,13 +91,10 @@ private Iterator findItemsToEnhance(int offset) { } private void enhanceItem(Item item) { - itemEnhancerService.enhance(context, item, force); - uncacheItem(item); - } - - private void uncacheItem(Item item) { try { - context.uncacheEntity(item); + itemEnhancerService.enhance(context, item, force); + context.commit(); + context.clear(); } catch (SQLException e) { throw new SQLRuntimeException(e); } diff --git a/dspace-api/src/main/java/org/dspace/content/security/MetadataSecurityServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/security/MetadataSecurityServiceImpl.java index 603ddb228f2..02af6dd20d8 100644 --- a/dspace-api/src/main/java/org/dspace/content/security/MetadataSecurityServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/security/MetadataSecurityServiceImpl.java @@ -20,7 +20,7 @@ import javax.annotation.PostConstruct; import javax.annotation.Resource; -import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.dspace.app.util.DCInputSet; import org.dspace.app.util.DCInputsReader; import org.dspace.app.util.DCInputsReaderException; @@ -123,11 +123,10 @@ public boolean checkMetadataFieldVisibility(Context context, Item item, Metadata return isMetadataFieldVisible(context, boxes, item, metadataField, false); } - private List getPermissionFilteredMetadata(Context context, Item item, List metadataValues, boolean preventBoxSecurityCheck) { - if (item.isWithdrawn() && isNotAdmin(context)) { + if (item.isWithdrawn() && isNotAdmin(context, item)) { return new ArrayList(); } @@ -177,42 +176,17 @@ private boolean isMetadataValueVisible(Context context, List boxe private boolean isMetadataFieldVisible(Context context, List boxes, Item item, MetadataField metadataField, boolean preventBoxSecurityCheck) { - if (CollectionUtils.isNotEmpty(boxes)) { - return isMetadataFieldVisibleByBoxes(context, boxes, item, metadataField, preventBoxSecurityCheck); - } - return isNotAdmin(context) ? isMetadataFieldVisibleFor(context, item, metadataField) : true; - } - - private boolean isMetadataFieldVisibleFor(Context context, Item item, MetadataField metadataField) { - return canEditItem(context, item) || isNotHidden(context, metadataField); - } - - private boolean isMetadataValueReturnAllowed(Context context, Item item, MetadataValue metadataValue) { - Integer securityLevel = metadataValue.getSecurityLevel(); - if (securityLevel == null) { - return true; - } - - MetadataSecurityEvaluation metadataSecurityEvaluation = getMetadataSecurityEvaluator(securityLevel); - try { - return metadataSecurityEvaluation.allowMetadataFieldReturn(context, item, metadataValue.getMetadataField()); - } catch (SQLException e) { - throw new SQLRuntimeException(e); - } - } - - private boolean isMetadataFieldVisibleByBoxes(Context context, List boxes, Item item, - MetadataField metadataField, boolean preventBoxSecurityCheck) { if (isPublicMetadataField(metadataField, boxes, preventBoxSecurityCheck)) { return true; } + // stop any further costly check if the converter request the fastest strategy if (preventBoxSecurityCheck) { return false; } - EPerson currentUser = context.getCurrentUser(); + EPerson currentUser = context != null ? context.getCurrentUser() : null; List notPublicBoxes = getNotPublicBoxes(metadataField, boxes); if (Objects.nonNull(currentUser)) { @@ -232,13 +206,46 @@ private boolean isMetadataFieldVisibleByBoxes(Context context, List boxes, boolean preventBoxSecurityCheck) { - List publicFields = preventBoxSecurityCheck ? getPublicMetadataFromConfig() : getPublicMetadata(boxes); + List publicFields = preventBoxSecurityCheck || boxes.isEmpty() ? + getPublicMetadataFromConfig() : getPublicMetadata(boxes); return publicFields.stream() - .anyMatch(publicField -> publicField.equals(metadataField.toString('.'))); + .anyMatch(publicField -> metadataMatch(metadataField, publicField)); + } + + private boolean metadataMatch(MetadataField metadataField, String publicField) { + if (metadataField == null || publicField == null) { + return false; + } + if (publicField.contains(".*")) { + final String exactMatch = publicField.replace(".*", ""); + StringBuffer qualifiedMatch = new StringBuffer(exactMatch).append("."); + return exactMatch.equals(metadataField.toString('.')) || + StringUtils.startsWith(metadataField.toString('.'), qualifiedMatch.toString()); + } else { + return publicField.equals(metadataField.toString('.')); + } } private List getPublicMetadataFromConfig() { @@ -291,13 +298,9 @@ private List dcInputsSet(final String sd) { } } - private boolean isAdmin(Context context) { - return !isNotAdmin(context); - } - - private boolean isNotAdmin(Context context) { + private boolean isNotAdmin(Context context, Item item) { try { - return context == null || !authorizeService.isAdmin(context); + return context == null || !authorizeService.isAdmin(context, item); } catch (SQLException e) { throw new SQLRuntimeException(e); } @@ -311,7 +314,7 @@ private List getFromSubmission(Context context, List dcInputSets, MetadataFiel private boolean isNotHidden(Context context, MetadataField metadataField) { try { - return !metadataExposureService.isHidden(context, metadataField.getMetadataSchema().getName(), - metadataField.getElement(), metadataField.getQualifier()); + return metadataField != null && + !metadataExposureService.isHidden(context, metadataField.getMetadataSchema().getName(), + metadataField.getElement(), metadataField.getQualifier()); } catch (SQLException e) { throw new SQLRuntimeException(e); } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/enhancer/RelatedItemEnhancerUpdatePoller.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/enhancer/RelatedItemEnhancerUpdatePoller.java index 1d341b61cce..16de405de62 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/enhancer/RelatedItemEnhancerUpdatePoller.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/enhancer/RelatedItemEnhancerUpdatePoller.java @@ -33,9 +33,8 @@ public class RelatedItemEnhancerUpdatePoller { @Scheduled(fixedDelayString = "${related-item-enhancer-poller.delay}") public void pollItemToUpdateAndProcess() { - try { + try (Context context = new Context();) { log.debug("item enhancer poller executed"); - Context context = new Context(); context.setDispatcher(RelatedItemEnhancerUpdatePoller.class.getSimpleName()); context.turnOffAuthorisationSystem(); UUID extractedUuid; diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/exception/DSpaceApiExceptionControllerAdvice.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/exception/DSpaceApiExceptionControllerAdvice.java index 54c7815d83e..ded7684b00a 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/exception/DSpaceApiExceptionControllerAdvice.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/exception/DSpaceApiExceptionControllerAdvice.java @@ -19,6 +19,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.catalina.connector.ClientAbortException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.dspace.app.exception.ResourceAlreadyExistsException; @@ -268,6 +269,14 @@ protected ResponseEntity handleTypeMismatch(TypeMismatchException ex, Ht return super.handleTypeMismatch(ex, headers, HttpStatus.BAD_REQUEST, request); } + @ExceptionHandler(ClientAbortException.class) + public void clientAbortExceptionHandler(HttpServletRequest request, ClientAbortException e) { + // This usually means the browser closed or disconnected or + // something. We can't do anything. To avoid excessive stack traces + // in log, just print a simple message + log.warn("ClientAbortException"); + } + @ExceptionHandler(Exception.class) protected void handleGenericException(HttpServletRequest request, HttpServletResponse response, Exception ex) throws IOException { diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java index b5584f29512..edbb58332f4 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java @@ -5287,6 +5287,10 @@ public void testSearchItemByCustomUrlWithoutResult() throws Exception { .param("q", "http://example.com/sample")) .andExpect(status().isNoContent()); + getClient(token).perform(get("/api/core/items/search/findByCustomURL") + .param("q", "")) + .andExpect(status().isNoContent()); + } @Test diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index fbdeb2bc863..6ea5bad8978 100644 --- a/dspace/config/dspace.cfg +++ b/dspace/config/dspace.cfg @@ -1801,6 +1801,8 @@ context-menu-entry.requestcorrection.enabled = true context-menu-entry.statistics.enabled = true context-menu-entry.subscriptions.enabled = true context-menu-entry.itemversion.enabled = true +context-menu-entry.orcidview.enabled = true +context-menu-entry.fullitem.enabled = true ################################################ ################ CrossWalk configurations ########### diff --git a/dspace/config/log4j2.xml b/dspace/config/log4j2.xml index b2d1c33d20a..b867d0313d8 100644 --- a/dspace/config/log4j2.xml +++ b/dspace/config/log4j2.xml @@ -188,6 +188,18 @@ + + + + diff --git a/dspace/config/modules/public-metadata.cfg b/dspace/config/modules/public-metadata.cfg index c09a6bc5396..e5dc8ab7b13 100644 --- a/dspace/config/modules/public-metadata.cfg +++ b/dspace/config/modules/public-metadata.cfg @@ -1,4 +1,16 @@ metadata.publicField = dc.title -metadata.publicField = dc.date.issued +metadata.publicField = dc.creator +metadata.publicField = dc.contributor.* +metadata.publicField = dc.publisher metadata.publicField = dc.description.abstract - +metadata.publicField = dc.date.issued +metadata.publicField = dc.date.accessioned +metadata.publicField = dc.type +metadata.publicField = dspace.entity.type +metadata.publicField = datacite.rights +metadata.publicField = datacite.available +metadata.publicField = person.familyName +metadata.publicField = person.givenName +metadata.publicField = person.affiliation.name +metadata.publicField = person.jobTitle +metadata.publicField = oairecerif.person.affiliation \ No newline at end of file