mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
Merge remote-tracking branch 'origin/main' into w2p-97298_issue-3281_self-register-issue-main
This commit is contained in:
@@ -598,18 +598,19 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
|
||||
changes.add(whatHasChanged);
|
||||
}
|
||||
|
||||
if (change) {
|
||||
//only clear cache if changes have been made.
|
||||
c.uncacheEntity(wsItem);
|
||||
c.uncacheEntity(wfItem);
|
||||
c.uncacheEntity(item);
|
||||
if (change && (rowCount % configurationService.getIntProperty("bulkedit.change.commit.count", 100) == 0)) {
|
||||
c.commit();
|
||||
handler.logInfo(LogHelper.getHeader(c, "metadata_import_commit", "lineNumber=" + rowCount));
|
||||
}
|
||||
populateRefAndRowMap(line, item == null ? null : item.getID());
|
||||
// keep track of current rows processed
|
||||
rowCount++;
|
||||
}
|
||||
if (change) {
|
||||
c.commit();
|
||||
}
|
||||
|
||||
c.setMode(originalMode);
|
||||
c.setMode(Context.Mode.READ_ONLY);
|
||||
|
||||
|
||||
// Return the changes
|
||||
|
@@ -67,6 +67,7 @@ public class ItemImport extends DSpaceRunnable<ItemImportScriptConfiguration> {
|
||||
protected String eperson = null;
|
||||
protected String[] collections = null;
|
||||
protected boolean isTest = false;
|
||||
protected boolean isExcludeContent = false;
|
||||
protected boolean isResume = false;
|
||||
protected boolean useWorkflow = false;
|
||||
protected boolean useWorkflowSendEmail = false;
|
||||
@@ -119,6 +120,8 @@ public class ItemImport extends DSpaceRunnable<ItemImportScriptConfiguration> {
|
||||
handler.logInfo("**Test Run** - not actually importing items.");
|
||||
}
|
||||
|
||||
isExcludeContent = commandLine.hasOption('x');
|
||||
|
||||
if (commandLine.hasOption('p')) {
|
||||
template = true;
|
||||
}
|
||||
@@ -204,6 +207,7 @@ public class ItemImport extends DSpaceRunnable<ItemImportScriptConfiguration> {
|
||||
.getItemImportService();
|
||||
try {
|
||||
itemImportService.setTest(isTest);
|
||||
itemImportService.setExcludeContent(isExcludeContent);
|
||||
itemImportService.setResume(isResume);
|
||||
itemImportService.setUseWorkflow(useWorkflow);
|
||||
itemImportService.setUseWorkflowSendEmail(useWorkflowSendEmail);
|
||||
|
@@ -13,7 +13,7 @@ import org.dspace.scripts.configuration.ScriptConfiguration;
|
||||
|
||||
/**
|
||||
* The {@link ScriptConfiguration} for the {@link ItemImportCLI} script
|
||||
*
|
||||
*
|
||||
* @author Francesco Pio Scognamiglio (francescopio.scognamiglio at 4science.com)
|
||||
*/
|
||||
public class ItemImportCLIScriptConfiguration extends ItemImportScriptConfiguration<ItemImportCLI> {
|
||||
@@ -55,6 +55,9 @@ public class ItemImportCLIScriptConfiguration extends ItemImportScriptConfigurat
|
||||
options.addOption(Option.builder("v").longOpt("validate")
|
||||
.desc("test run - do not actually import items")
|
||||
.hasArg(false).required(false).build());
|
||||
options.addOption(Option.builder("x").longOpt("exclude-bitstreams")
|
||||
.desc("do not load or expect content bitstreams")
|
||||
.hasArg(false).required(false).build());
|
||||
options.addOption(Option.builder("p").longOpt("template")
|
||||
.desc("apply template")
|
||||
.hasArg(false).required(false).build());
|
||||
|
@@ -19,7 +19,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* The {@link ScriptConfiguration} for the {@link ItemImport} script
|
||||
*
|
||||
*
|
||||
* @author Francesco Pio Scognamiglio (francescopio.scognamiglio at 4science.com)
|
||||
*/
|
||||
public class ItemImportScriptConfiguration<T extends ItemImport> extends ScriptConfiguration<T> {
|
||||
@@ -81,6 +81,9 @@ public class ItemImportScriptConfiguration<T extends ItemImport> extends ScriptC
|
||||
options.addOption(Option.builder("v").longOpt("validate")
|
||||
.desc("test run - do not actually import items")
|
||||
.hasArg(false).required(false).build());
|
||||
options.addOption(Option.builder("x").longOpt("exclude-bitstreams")
|
||||
.desc("do not load or expect content bitstreams")
|
||||
.hasArg(false).required(false).build());
|
||||
options.addOption(Option.builder("p").longOpt("template")
|
||||
.desc("apply template")
|
||||
.hasArg(false).required(false).build());
|
||||
|
@@ -62,6 +62,7 @@ import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.itemimport.service.ItemImportService;
|
||||
import org.dspace.app.util.LocalSchemaFilenameFilter;
|
||||
@@ -135,7 +136,7 @@ import org.xml.sax.SAXException;
|
||||
* allow the registration of files (bitstreams) into DSpace.
|
||||
*/
|
||||
public class ItemImportServiceImpl implements ItemImportService, InitializingBean {
|
||||
private final Logger log = org.apache.logging.log4j.LogManager.getLogger(ItemImportServiceImpl.class);
|
||||
private final Logger log = LogManager.getLogger();
|
||||
|
||||
private DSpaceRunnableHandler handler;
|
||||
|
||||
@@ -181,6 +182,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
protected String tempWorkDir;
|
||||
|
||||
protected boolean isTest = false;
|
||||
protected boolean isExcludeContent = false;
|
||||
protected boolean isResume = false;
|
||||
protected boolean useWorkflow = false;
|
||||
protected boolean useWorkflowSendEmail = false;
|
||||
@@ -1403,6 +1405,10 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
protected void processContentFileEntry(Context c, Item i, String path,
|
||||
String fileName, String bundleName, boolean primary) throws SQLException,
|
||||
IOException, AuthorizeException {
|
||||
if (isExcludeContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
String fullpath = path + File.separatorChar + fileName;
|
||||
|
||||
// get an input stream
|
||||
@@ -2342,6 +2348,11 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
this.isTest = isTest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludeContent(boolean isExcludeContent) {
|
||||
this.isExcludeContent = isExcludeContent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResume(boolean isResume) {
|
||||
this.isResume = isResume;
|
||||
|
@@ -211,6 +211,13 @@ public interface ItemImportService {
|
||||
*/
|
||||
public void setTest(boolean isTest);
|
||||
|
||||
/**
|
||||
* Set exclude-content flag.
|
||||
*
|
||||
* @param isExcludeContent true or false
|
||||
*/
|
||||
public void setExcludeContent(boolean isExcludeContent);
|
||||
|
||||
/**
|
||||
* Set resume flag
|
||||
*
|
||||
|
@@ -10,6 +10,7 @@ package org.dspace.app.util;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -131,10 +132,15 @@ public class DCInput {
|
||||
private boolean closedVocabulary = false;
|
||||
|
||||
/**
|
||||
* the regex to comply with, null if nothing
|
||||
* the regex in ECMAScript standard format, usable also by rests.
|
||||
*/
|
||||
private String regex = null;
|
||||
|
||||
/**
|
||||
* the computed pattern, null if nothing
|
||||
*/
|
||||
private Pattern pattern = null;
|
||||
|
||||
/**
|
||||
* allowed document types
|
||||
*/
|
||||
@@ -178,7 +184,7 @@ public class DCInput {
|
||||
|
||||
//check if the input have a language tag
|
||||
language = Boolean.valueOf(fieldMap.get("language"));
|
||||
valueLanguageList = new ArrayList();
|
||||
valueLanguageList = new ArrayList<>();
|
||||
if (language) {
|
||||
String languageNameTmp = fieldMap.get("value-pairs-name");
|
||||
if (StringUtils.isBlank(languageNameTmp)) {
|
||||
@@ -191,7 +197,7 @@ public class DCInput {
|
||||
repeatable = "true".equalsIgnoreCase(repStr)
|
||||
|| "yes".equalsIgnoreCase(repStr);
|
||||
String nameVariantsString = fieldMap.get("name-variants");
|
||||
nameVariants = (StringUtils.isNotBlank(nameVariantsString)) ?
|
||||
nameVariants = StringUtils.isNotBlank(nameVariantsString) ?
|
||||
nameVariantsString.equalsIgnoreCase("true") : false;
|
||||
label = fieldMap.get("label");
|
||||
inputType = fieldMap.get("input-type");
|
||||
@@ -203,17 +209,17 @@ public class DCInput {
|
||||
}
|
||||
hint = fieldMap.get("hint");
|
||||
warning = fieldMap.get("required");
|
||||
required = (warning != null && warning.length() > 0);
|
||||
required = warning != null && warning.length() > 0;
|
||||
visibility = fieldMap.get("visibility");
|
||||
readOnly = fieldMap.get("readonly");
|
||||
vocabulary = fieldMap.get("vocabulary");
|
||||
regex = fieldMap.get("regex");
|
||||
this.initRegex(fieldMap.get("regex"));
|
||||
String closedVocabularyStr = fieldMap.get("closedVocabulary");
|
||||
closedVocabulary = "true".equalsIgnoreCase(closedVocabularyStr)
|
||||
|| "yes".equalsIgnoreCase(closedVocabularyStr);
|
||||
|
||||
// parsing of the <type-bind> element (using the colon as split separator)
|
||||
typeBind = new ArrayList<>();
|
||||
typeBind = new ArrayList<String>();
|
||||
String typeBindDef = fieldMap.get("type-bind");
|
||||
if (typeBindDef != null && typeBindDef.trim().length() > 0) {
|
||||
String[] types = typeBindDef.split(",");
|
||||
@@ -238,6 +244,22 @@ public class DCInput {
|
||||
|
||||
}
|
||||
|
||||
protected void initRegex(String regex) {
|
||||
this.regex = null;
|
||||
this.pattern = null;
|
||||
if (regex != null) {
|
||||
try {
|
||||
Optional.ofNullable(RegexPatternUtils.computePattern(regex))
|
||||
.ifPresent(pattern -> {
|
||||
this.pattern = pattern;
|
||||
this.regex = regex;
|
||||
});
|
||||
} catch (PatternSyntaxException e) {
|
||||
log.warn("The regex field of input {} with value {} is invalid!", this.label, regex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this DCInput for display in the given scope? The scope should be
|
||||
* either "workflow" or "submit", as per the input forms definition. If the
|
||||
@@ -248,7 +270,7 @@ public class DCInput {
|
||||
* @return whether the input should be displayed or not
|
||||
*/
|
||||
public boolean isVisible(String scope) {
|
||||
return (visibility == null || visibility.equals(scope));
|
||||
return visibility == null || visibility.equals(scope);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -381,7 +403,7 @@ public class DCInput {
|
||||
|
||||
/**
|
||||
* Get the style for this form field
|
||||
*
|
||||
*
|
||||
* @return the style
|
||||
*/
|
||||
public String getStyle() {
|
||||
@@ -512,8 +534,12 @@ public class DCInput {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
public Pattern getPattern() {
|
||||
return this.pattern;
|
||||
}
|
||||
|
||||
public String getRegex() {
|
||||
return regex;
|
||||
return this.regex;
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
@@ -546,8 +572,7 @@ public class DCInput {
|
||||
public boolean validate(String value) {
|
||||
if (StringUtils.isNotBlank(value)) {
|
||||
try {
|
||||
if (StringUtils.isNotBlank(regex)) {
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
if (this.pattern != null) {
|
||||
if (!pattern.matcher(value).matches()) {
|
||||
return false;
|
||||
}
|
||||
@@ -557,7 +582,6 @@ public class DCInput {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.util;
|
||||
|
||||
import static java.util.regex.Pattern.CASE_INSENSITIVE;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* Utility class useful for check regex and patterns.
|
||||
*
|
||||
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
|
||||
*
|
||||
*/
|
||||
public class RegexPatternUtils {
|
||||
|
||||
// checks input having the format /{pattern}/{flags}
|
||||
// allowed flags are: g,i,m,s,u,y
|
||||
public static final String REGEX_INPUT_VALIDATOR = "(/?)(.+)\\1([gimsuy]*)";
|
||||
// flags usable inside regex definition using format (?i|m|s|u|y)
|
||||
public static final String REGEX_FLAGS = "(?%s)";
|
||||
public static final Pattern PATTERN_REGEX_INPUT_VALIDATOR =
|
||||
Pattern.compile(REGEX_INPUT_VALIDATOR, CASE_INSENSITIVE);
|
||||
|
||||
/**
|
||||
* Computes a pattern starting from a regex definition with flags that
|
||||
* uses the standard format: <code>/{regex}/{flags}</code> (ECMAScript format).
|
||||
* This method can transform an ECMAScript regex into a java {@code Pattern} object
|
||||
* wich can be used to validate strings.
|
||||
* <br/>
|
||||
* If regex is null, empty or blank a null {@code Pattern} will be retrieved
|
||||
* If it's a valid regex, then a non-null {@code Pattern} will be retrieved,
|
||||
* an exception will be thrown otherwise.
|
||||
*
|
||||
* @param regex with format <code>/{regex}/{flags}</code>
|
||||
* @return {@code Pattern} regex pattern instance
|
||||
* @throws PatternSyntaxException
|
||||
*/
|
||||
public static final Pattern computePattern(String regex) throws PatternSyntaxException {
|
||||
if (StringUtils.isBlank(regex)) {
|
||||
return null;
|
||||
}
|
||||
Matcher inputMatcher = PATTERN_REGEX_INPUT_VALIDATOR.matcher(regex);
|
||||
String regexPattern = regex;
|
||||
String regexFlags = "";
|
||||
if (inputMatcher.matches()) {
|
||||
regexPattern =
|
||||
Optional.of(inputMatcher.group(2))
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.orElse(regex);
|
||||
regexFlags =
|
||||
Optional.ofNullable(inputMatcher.group(3))
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.map(flags -> String.format(REGEX_FLAGS, flags))
|
||||
.orElse("")
|
||||
.replaceAll("g", "");
|
||||
}
|
||||
return Pattern.compile(regexFlags + regexPattern);
|
||||
}
|
||||
|
||||
private RegexPatternUtils() {}
|
||||
|
||||
}
|
@@ -31,10 +31,12 @@ import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.BitstreamService;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.WorkspaceItemService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.discovery.DiscoverQuery;
|
||||
import org.dspace.discovery.DiscoverQuery.SORT_ORDER;
|
||||
import org.dspace.discovery.DiscoverResult;
|
||||
import org.dspace.discovery.IndexableObject;
|
||||
import org.dspace.discovery.SearchService;
|
||||
@@ -830,7 +832,7 @@ public class AuthorizeServiceImpl implements AuthorizeService {
|
||||
query = formatCustomQuery(query);
|
||||
DiscoverResult discoverResult = getDiscoverResult(context, query + "search.resourcetype:" +
|
||||
IndexableCommunity.TYPE,
|
||||
offset, limit);
|
||||
offset, limit, null, null);
|
||||
for (IndexableObject solrCollections : discoverResult.getIndexableObjects()) {
|
||||
Community community = ((IndexableCommunity) solrCollections).getIndexedObject();
|
||||
communities.add(community);
|
||||
@@ -852,7 +854,7 @@ public class AuthorizeServiceImpl implements AuthorizeService {
|
||||
query = formatCustomQuery(query);
|
||||
DiscoverResult discoverResult = getDiscoverResult(context, query + "search.resourcetype:" +
|
||||
IndexableCommunity.TYPE,
|
||||
null, null);
|
||||
null, null, null, null);
|
||||
return discoverResult.getTotalSearchResults();
|
||||
}
|
||||
|
||||
@@ -877,7 +879,7 @@ public class AuthorizeServiceImpl implements AuthorizeService {
|
||||
query = formatCustomQuery(query);
|
||||
DiscoverResult discoverResult = getDiscoverResult(context, query + "search.resourcetype:" +
|
||||
IndexableCollection.TYPE,
|
||||
offset, limit);
|
||||
offset, limit, CollectionService.SOLR_SORT_FIELD, SORT_ORDER.asc);
|
||||
for (IndexableObject solrCollections : discoverResult.getIndexableObjects()) {
|
||||
Collection collection = ((IndexableCollection) solrCollections).getIndexedObject();
|
||||
collections.add(collection);
|
||||
@@ -899,7 +901,7 @@ public class AuthorizeServiceImpl implements AuthorizeService {
|
||||
query = formatCustomQuery(query);
|
||||
DiscoverResult discoverResult = getDiscoverResult(context, query + "search.resourcetype:" +
|
||||
IndexableCollection.TYPE,
|
||||
null, null);
|
||||
null, null, null, null);
|
||||
return discoverResult.getTotalSearchResults();
|
||||
}
|
||||
|
||||
@@ -919,7 +921,7 @@ public class AuthorizeServiceImpl implements AuthorizeService {
|
||||
}
|
||||
|
||||
try {
|
||||
DiscoverResult discoverResult = getDiscoverResult(context, query, null, null);
|
||||
DiscoverResult discoverResult = getDiscoverResult(context, query, null, null, null, null);
|
||||
if (discoverResult.getTotalSearchResults() > 0) {
|
||||
return true;
|
||||
}
|
||||
@@ -931,7 +933,8 @@ public class AuthorizeServiceImpl implements AuthorizeService {
|
||||
return false;
|
||||
}
|
||||
|
||||
private DiscoverResult getDiscoverResult(Context context, String query, Integer offset, Integer limit)
|
||||
private DiscoverResult getDiscoverResult(Context context, String query, Integer offset, Integer limit,
|
||||
String sortField, SORT_ORDER sortOrder)
|
||||
throws SearchServiceException, SQLException {
|
||||
String groupQuery = getGroupToQuery(groupService.allMemberGroups(context, context.getCurrentUser()));
|
||||
|
||||
@@ -947,7 +950,9 @@ public class AuthorizeServiceImpl implements AuthorizeService {
|
||||
if (limit != null) {
|
||||
discoverQuery.setMaxResults(limit);
|
||||
}
|
||||
|
||||
if (sortField != null && sortOrder != null) {
|
||||
discoverQuery.setSortField(sortField, sortOrder);
|
||||
}
|
||||
|
||||
return searchService.search(context, discoverQuery);
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.solr.client.solrj.util.ClientUtils;
|
||||
import org.dspace.authorize.factory.AuthorizeServiceFactory;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Item;
|
||||
@@ -206,7 +207,8 @@ public class SolrBrowseDAO implements BrowseDAO {
|
||||
query.addFilterQueries("{!field f=" + facetField + "_partial}" + value);
|
||||
}
|
||||
if (StringUtils.isNotBlank(startsWith) && orderField != null) {
|
||||
query.addFilterQueries("bi_" + orderField + "_sort:" + startsWith + "*");
|
||||
query.addFilterQueries(
|
||||
"bi_" + orderField + "_sort:" + ClientUtils.escapeQueryChars(startsWith) + "*");
|
||||
}
|
||||
// filter on item to be sure to don't include any other object
|
||||
// indexed in the Discovery Search core
|
||||
|
@@ -43,6 +43,7 @@ import org.dspace.core.I18nUtil;
|
||||
import org.dspace.core.LogHelper;
|
||||
import org.dspace.core.service.LicenseService;
|
||||
import org.dspace.discovery.DiscoverQuery;
|
||||
import org.dspace.discovery.DiscoverQuery.SORT_ORDER;
|
||||
import org.dspace.discovery.DiscoverResult;
|
||||
import org.dspace.discovery.IndexableObject;
|
||||
import org.dspace.discovery.SearchService;
|
||||
@@ -946,6 +947,7 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl<Collection> i
|
||||
discoverQuery.setDSpaceObjectFilter(IndexableCollection.TYPE);
|
||||
discoverQuery.setStart(offset);
|
||||
discoverQuery.setMaxResults(limit);
|
||||
discoverQuery.setSortField(SOLR_SORT_FIELD, SORT_ORDER.asc);
|
||||
DiscoverResult resp = retrieveCollectionsWithSubmit(context, discoverQuery, null, community, q);
|
||||
for (IndexableObject solrCollections : resp.getIndexableObjects()) {
|
||||
Collection c = ((IndexableCollection) solrCollections).getIndexedObject();
|
||||
@@ -1025,6 +1027,7 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl<Collection> i
|
||||
discoverQuery.setDSpaceObjectFilter(IndexableCollection.TYPE);
|
||||
discoverQuery.setStart(offset);
|
||||
discoverQuery.setMaxResults(limit);
|
||||
discoverQuery.setSortField(SOLR_SORT_FIELD, SORT_ORDER.asc);
|
||||
DiscoverResult resp = retrieveCollectionsWithSubmit(context, discoverQuery,
|
||||
entityType, community, q);
|
||||
for (IndexableObject solrCollections : resp.getIndexableObjects()) {
|
||||
|
@@ -33,6 +33,11 @@ import org.dspace.eperson.Group;
|
||||
public interface CollectionService
|
||||
extends DSpaceObjectService<Collection>, DSpaceObjectLegacySupportService<Collection> {
|
||||
|
||||
/*
|
||||
* Field used to sort community and collection lists at solr
|
||||
*/
|
||||
public static final String SOLR_SORT_FIELD = "dc.title_sort";
|
||||
|
||||
/**
|
||||
* Create a new collection with a new ID.
|
||||
* Once created the collection is added to the given community
|
||||
@@ -46,7 +51,6 @@ public interface CollectionService
|
||||
public Collection create(Context context, Community community) throws SQLException,
|
||||
AuthorizeException;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new collection with the supplied handle and with a new ID.
|
||||
* Once created the collection is added to the given community
|
||||
|
@@ -9,6 +9,7 @@ package org.dspace.handle;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -211,17 +212,17 @@ public class HandleServiceImpl implements HandleService {
|
||||
@Override
|
||||
public void unbindHandle(Context context, DSpaceObject dso)
|
||||
throws SQLException {
|
||||
List<Handle> handles = getInternalHandles(context, dso);
|
||||
if (CollectionUtils.isNotEmpty(handles)) {
|
||||
for (Handle handle : handles) {
|
||||
Iterator<Handle> handles = dso.getHandles().iterator();
|
||||
if (handles.hasNext()) {
|
||||
while (handles.hasNext()) {
|
||||
final Handle handle = handles.next();
|
||||
handles.remove();
|
||||
//Only set the "resouce_id" column to null when unbinding a handle.
|
||||
// We want to keep around the "resource_type_id" value, so that we
|
||||
// can verify during a restore whether the same *type* of resource
|
||||
// is reusing this handle!
|
||||
handle.setDSpaceObject(null);
|
||||
|
||||
//Also remove the handle from the DSO list to keep a consistent model
|
||||
dso.getHandles().remove(handle);
|
||||
|
||||
handleDAO.save(context, handle);
|
||||
|
||||
@@ -256,7 +257,7 @@ public class HandleServiceImpl implements HandleService {
|
||||
@Override
|
||||
public String findHandle(Context context, DSpaceObject dso)
|
||||
throws SQLException {
|
||||
List<Handle> handles = getInternalHandles(context, dso);
|
||||
List<Handle> handles = dso.getHandles();
|
||||
if (CollectionUtils.isEmpty(handles)) {
|
||||
return null;
|
||||
} else {
|
||||
@@ -328,20 +329,6 @@ public class HandleServiceImpl implements HandleService {
|
||||
////////////////////////////////////////
|
||||
// Internal methods
|
||||
////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Return the handle for an Object, or null if the Object has no handle.
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param dso DSpaceObject for which we require our handles
|
||||
* @return The handle for object, or null if the object has no handle.
|
||||
* @throws SQLException If a database error occurs
|
||||
*/
|
||||
protected List<Handle> getInternalHandles(Context context, DSpaceObject dso)
|
||||
throws SQLException {
|
||||
return handleDAO.getHandlesByDSpaceObject(context, dso);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the database row corresponding to handle.
|
||||
*
|
||||
|
@@ -0,0 +1,9 @@
|
||||
--
|
||||
-- The contents of this file are subject to the license and copyright
|
||||
-- detailed in the LICENSE and NOTICE files at the root of the source
|
||||
-- tree and available online at
|
||||
--
|
||||
-- http://www.dspace.org/license/
|
||||
--
|
||||
|
||||
CREATE INDEX resourcepolicy_action_idx ON resourcepolicy(action_id);
|
@@ -0,0 +1,9 @@
|
||||
--
|
||||
-- The contents of this file are subject to the license and copyright
|
||||
-- detailed in the LICENSE and NOTICE files at the root of the source
|
||||
-- tree and available online at
|
||||
--
|
||||
-- http://www.dspace.org/license/
|
||||
--
|
||||
|
||||
CREATE INDEX resourcepolicy_action_idx ON resourcepolicy(action_id);
|
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import org.dspace.AbstractUnitTest;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for RegexPatternUtils
|
||||
*
|
||||
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
|
||||
*
|
||||
*/
|
||||
public class RegexPatternUtilsTest extends AbstractUnitTest {
|
||||
|
||||
@Test
|
||||
public void testValidRegexWithFlag() {
|
||||
final String insensitiveWord = "/[a-z]+/i";
|
||||
Pattern computePattern = Pattern.compile(insensitiveWord);
|
||||
assertNotNull(computePattern);
|
||||
|
||||
Matcher matcher = computePattern.matcher("Hello");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("DSpace");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("Community");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("/wrongpattern/i");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("001");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("?/'`}{][<>.,");
|
||||
assertFalse(matcher.matches());
|
||||
computePattern = RegexPatternUtils.computePattern(insensitiveWord);
|
||||
assertNotNull(computePattern);
|
||||
|
||||
matcher = computePattern.matcher("Hello");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("DSpace");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("Community");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("/wrong-pattern/i");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("001");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("?/'`}{][<>.,");
|
||||
assertFalse(matcher.matches());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegexWithoutFlag() {
|
||||
final String sensitiveWord = "[a-z]+";
|
||||
Pattern computePattern = RegexPatternUtils.computePattern(sensitiveWord);
|
||||
assertNotNull(computePattern);
|
||||
|
||||
Matcher matcher = computePattern.matcher("hello");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("dspace");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("community");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("Hello");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("DSpace");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("Community");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("/wrongpattern/i");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("001");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("?/'`}{][<>.,");
|
||||
assertFalse(matcher.matches());
|
||||
|
||||
final String sensitiveWordWithDelimiter = "/[a-z]+/";
|
||||
computePattern = RegexPatternUtils.computePattern(sensitiveWordWithDelimiter);
|
||||
assertNotNull(computePattern);
|
||||
|
||||
matcher = computePattern.matcher("hello");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("dspace");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("community");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("Hello");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("DSpace");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("Community");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("/wrongpattern/i");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("001");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("?/'`}{][<>.,");
|
||||
assertFalse(matcher.matches());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithFuzzyRegex() {
|
||||
String fuzzyRegex = "/[a-z]+";
|
||||
Pattern computePattern = RegexPatternUtils.computePattern(fuzzyRegex);
|
||||
assertNotNull(computePattern);
|
||||
|
||||
Matcher matcher = computePattern.matcher("/hello");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("hello");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("Hello");
|
||||
assertFalse(matcher.matches());
|
||||
|
||||
fuzzyRegex = "[a-z]+/";
|
||||
computePattern = RegexPatternUtils.computePattern(fuzzyRegex);
|
||||
matcher = computePattern.matcher("hello/");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("/hello");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("hello");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("Hello");
|
||||
assertFalse(matcher.matches());
|
||||
|
||||
// equals to pattern \\[a-z]+\\ -> searching for a word delimited by '\'
|
||||
fuzzyRegex = "\\\\[a-z]+\\\\";
|
||||
computePattern = RegexPatternUtils.computePattern(fuzzyRegex);
|
||||
// equals to '\hello\'
|
||||
matcher = computePattern.matcher("\\hello\\");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("/hello");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("hello");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("Hello");
|
||||
assertFalse(matcher.matches());
|
||||
|
||||
// equals to pattern /[a-z]+/ -> searching for a string delimited by '/'
|
||||
fuzzyRegex = "\\/[a-z]+\\/";
|
||||
computePattern = RegexPatternUtils.computePattern(fuzzyRegex);
|
||||
matcher = computePattern.matcher("/hello/");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("/hello");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("hello");
|
||||
assertFalse(matcher.matches());
|
||||
matcher = computePattern.matcher("Hello");
|
||||
assertFalse(matcher.matches());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidRegex() {
|
||||
String invalidSensitive = "[a-z+";
|
||||
assertThrows(PatternSyntaxException.class, () -> RegexPatternUtils.computePattern(invalidSensitive));
|
||||
|
||||
String invalidRange = "a{1-";
|
||||
assertThrows(PatternSyntaxException.class, () -> RegexPatternUtils.computePattern(invalidRange));
|
||||
|
||||
String invalidGroupPattern = "(abc";
|
||||
assertThrows(PatternSyntaxException.class, () -> RegexPatternUtils.computePattern(invalidGroupPattern));
|
||||
|
||||
String emptyPattern = "";
|
||||
Pattern computePattern = RegexPatternUtils.computePattern(emptyPattern);
|
||||
assertNull(computePattern);
|
||||
|
||||
String blankPattern = " ";
|
||||
computePattern = RegexPatternUtils.computePattern(blankPattern);
|
||||
assertNull(computePattern);
|
||||
|
||||
String nullPattern = null;
|
||||
computePattern = RegexPatternUtils.computePattern(nullPattern);
|
||||
assertNull(computePattern);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiFlagRegex() {
|
||||
String multilineSensitive = "/[a-z]+/gi";
|
||||
Pattern computePattern = RegexPatternUtils.computePattern(multilineSensitive);
|
||||
assertNotNull(computePattern);
|
||||
Matcher matcher = computePattern.matcher("hello");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("Hello");
|
||||
assertTrue(matcher.matches());
|
||||
|
||||
multilineSensitive = "/[a-z]+/gim";
|
||||
computePattern = RegexPatternUtils.computePattern(multilineSensitive);
|
||||
assertNotNull(computePattern);
|
||||
matcher = computePattern.matcher("Hello" + System.lineSeparator() + "Everyone");
|
||||
assertTrue(matcher.find());
|
||||
assertEquals("Hello", matcher.group());
|
||||
assertTrue(matcher.find());
|
||||
assertEquals("Everyone", matcher.group());
|
||||
|
||||
matcher = computePattern.matcher("hello");
|
||||
assertTrue(matcher.matches());
|
||||
matcher = computePattern.matcher("HELLO");
|
||||
assertTrue(matcher.matches());
|
||||
}
|
||||
}
|
@@ -111,7 +111,7 @@ public class VersionRestRepository extends DSpaceRestRepository<VersionRest, Int
|
||||
}
|
||||
|
||||
EPerson submitter = item.getSubmitter();
|
||||
boolean isAdmin = authorizeService.isAdmin(context);
|
||||
boolean isAdmin = authorizeService.isAdmin(context, item);
|
||||
boolean canCreateVersion = configurationService.getBooleanProperty("versioning.submitterCanCreateNewVersion");
|
||||
|
||||
if (!isAdmin && !(canCreateVersion && Objects.equals(submitter, context.getCurrentUser()))) {
|
||||
|
@@ -1111,7 +1111,7 @@ public class BrowsesResourceControllerIT extends AbstractControllerIntegrationTe
|
||||
|
||||
//We expect the totalElements to be the 1 item present in the collection
|
||||
.andExpect(jsonPath("$.page.totalElements", is(1)))
|
||||
//As this is is a small collection, we expect to go-to page 0
|
||||
//As this is a small collection, we expect to go-to page 0
|
||||
.andExpect(jsonPath("$.page.number", is(0)))
|
||||
.andExpect(jsonPath("$._links.self.href", containsString("startsWith=Blade")))
|
||||
|
||||
@@ -1121,6 +1121,33 @@ public class BrowsesResourceControllerIT extends AbstractControllerIntegrationTe
|
||||
"Blade Runner",
|
||||
"1982-06-25")
|
||||
)));
|
||||
|
||||
//Test filtering with spaces:
|
||||
//** WHEN **
|
||||
//An anonymous user browses the items in the Browse by Title endpoint
|
||||
//with startsWith set to Blade Runner and scope set to Col 1
|
||||
getClient().perform(get("/api/discover/browses/title/items?startsWith=Blade Runner")
|
||||
.param("scope", col1.getID().toString())
|
||||
.param("size", "2"))
|
||||
|
||||
//** THEN **
|
||||
//The status has to be 200 OK
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
|
||||
//We expect the totalElements to be the 1 item present in the collection
|
||||
.andExpect(jsonPath("$.page.totalElements", is(1)))
|
||||
//As this is a small collection, we expect to go-to page 0
|
||||
.andExpect(jsonPath("$.page.number", is(0)))
|
||||
.andExpect(jsonPath("$._links.self.href", containsString("startsWith=Blade Runner")))
|
||||
|
||||
//Verify that the index jumps to the "Blade Runner" item.
|
||||
.andExpect(jsonPath("$._embedded.items",
|
||||
contains(ItemMatcher.matchItemWithTitleAndDateIssued(item2,
|
||||
"Blade Runner",
|
||||
"1982-06-25")
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@@ -850,6 +850,55 @@ public class VersionRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createNewVersionItemByCollectionAdminTest() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Community rootCommunity = CommunityBuilder.createCommunity(context)
|
||||
.withName("Parent Community")
|
||||
.build();
|
||||
|
||||
EPerson colAdmin = EPersonBuilder.createEPerson(context)
|
||||
.withCanLogin(true)
|
||||
.withEmail("coladmin@email.com")
|
||||
.withPassword(password)
|
||||
.withNameInMetadata("Collection", "Admin")
|
||||
.build();
|
||||
Collection col = CollectionBuilder
|
||||
.createCollection(context, rootCommunity)
|
||||
.withName("Collection 1")
|
||||
.withAdminGroup(colAdmin)
|
||||
.build();
|
||||
|
||||
Item item = ItemBuilder.createItem(context, col)
|
||||
.withTitle("Public test item")
|
||||
.withIssueDate("2022-12-19")
|
||||
.withAuthor("Doe, John")
|
||||
.withSubject("ExtraEntry")
|
||||
.build();
|
||||
|
||||
item.setSubmitter(eperson);
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
AtomicReference<Integer> idRef = new AtomicReference<Integer>();
|
||||
String token = getAuthToken(colAdmin.getEmail(), password);
|
||||
try {
|
||||
getClient(token).perform(post("/api/versioning/versions")
|
||||
.param("summary", "test summary!")
|
||||
.contentType(MediaType.parseMediaType(RestMediaTypes.TEXT_URI_LIST_VALUE))
|
||||
.content("/api/core/items/" + item.getID()))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$", Matchers.allOf(
|
||||
hasJsonPath("$.version", is(2)),
|
||||
hasJsonPath("$.summary", is("test summary!")),
|
||||
hasJsonPath("$.type", is("version"))
|
||||
)))
|
||||
.andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
|
||||
} finally {
|
||||
VersionBuilder.delete(idRef.get());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void patchReplaceSummaryTest() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
@@ -32,3 +32,11 @@
|
||||
# By default, only 'dspace.agreements.end-user' can be deleted in bulk, as doing so allows
|
||||
# an administrator to force all users to re-review the End User Agreement on their next login.
|
||||
bulkedit.allow-bulk-deletion = dspace.agreements.end-user
|
||||
|
||||
### metadata import script ###
|
||||
# Set the number after which the changes should be committed while running the script
|
||||
# After too much consecutive records everything starts to slow down because too many things are being loaded into memory
|
||||
# If we commit these to the database these are cleared out of our memory and we don't lose as much performance
|
||||
# By default this is set to 100
|
||||
bulkedit.change.commit.count = 100
|
||||
|
||||
|
Reference in New Issue
Block a user