diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml
index 9b7ed5971f..194d84b446 100644
--- a/dspace-api/pom.xml
+++ b/dspace-api/pom.xml
@@ -548,17 +548,11 @@
com.ibm.icu
icu4j
-
+
org.dspace
oclc-harvester2
-
-
- xalan
- xalan
-
org.dspace
dspace-services
diff --git a/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java b/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java
index 80d69f3b66..81250e9c82 100644
--- a/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java
+++ b/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java
@@ -14,6 +14,7 @@ import java.util.Locale;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.lang3.StringUtils;
import org.dspace.core.Context;
@@ -54,14 +55,14 @@ public final class CreateAdministrator {
protected GroupService groupService;
/**
- * For invoking via the command line. If called with no command line arguments,
+ * For invoking via the command line. If called with no command line arguments,
* it will negotiate with the user for the administrator details
*
* @param argv the command line arguments given
* @throws Exception if error
*/
public static void main(String[] argv)
- throws Exception {
+ throws Exception {
CommandLineParser parser = new DefaultParser();
Options options = new Options();
@@ -69,19 +70,41 @@ public final class CreateAdministrator {
options.addOption("e", "email", true, "administrator email address");
options.addOption("f", "first", true, "administrator first name");
+ options.addOption("h", "help", false, "explain create-administrator options");
options.addOption("l", "last", true, "administrator last name");
options.addOption("c", "language", true, "administrator language");
options.addOption("p", "password", true, "administrator password");
- CommandLine line = parser.parse(options, argv);
+ CommandLine line = null;
+
+ try {
+
+ line = parser.parse(options, argv);
+
+ } catch (Exception e) {
+
+ System.out.println(e.getMessage() + "\nTry \"dspace create-administrator -h\" to print help information.");
+ System.exit(1);
+
+ }
if (line.hasOption("e") && line.hasOption("f") && line.hasOption("l") &&
- line.hasOption("c") && line.hasOption("p")) {
+ line.hasOption("c") && line.hasOption("p")) {
ca.createAdministrator(line.getOptionValue("e"),
- line.getOptionValue("f"), line.getOptionValue("l"),
- line.getOptionValue("c"), line.getOptionValue("p"));
+ line.getOptionValue("f"), line.getOptionValue("l"),
+ line.getOptionValue("c"), line.getOptionValue("p"));
+ } else if (line.hasOption("h")) {
+ String header = "\nA command-line tool for creating an initial administrator for setting up a" +
+ " DSpace site. Unless all the required parameters are passed it will" +
+ " prompt for an e-mail address, last name, first name and password from" +
+ " standard input.. An administrator group is then created and the data passed" +
+ " in used to create an e-person in that group.\n\n";
+ String footer = "\n";
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp("dspace create-administrator", header, options, footer, true);
+ return;
} else {
- ca.negotiateAdministratorDetails();
+ ca.negotiateAdministratorDetails(line);
}
}
@@ -91,7 +114,7 @@ public final class CreateAdministrator {
* @throws Exception if error
*/
protected CreateAdministrator()
- throws Exception {
+ throws Exception {
context = new Context();
groupService = EPersonServiceFactory.getInstance().getGroupService();
ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
@@ -103,20 +126,20 @@ public final class CreateAdministrator {
*
* @throws Exception if error
*/
- protected void negotiateAdministratorDetails()
- throws Exception {
+ protected void negotiateAdministratorDetails(CommandLine line)
+ throws Exception {
Console console = System.console();
System.out.println("Creating an initial administrator account");
- boolean dataOK = false;
-
- String email = null;
- String firstName = null;
- String lastName = null;
- char[] password1 = null;
- char[] password2 = null;
+ String email = line.getOptionValue('e');
+ String firstName = line.getOptionValue('f');
+ String lastName = line.getOptionValue('l');
String language = I18nUtil.getDefaultLocale().getLanguage();
+ ConfigurationService cfg = DSpaceServicesFactory.getInstance().getConfigurationService();
+ boolean flag = line.hasOption('p');
+ char[] password = null;
+ boolean dataOK = line.hasOption('f') && line.hasOption('e') && line.hasOption('l');
while (!dataOK) {
System.out.print("E-mail address: ");
@@ -147,8 +170,6 @@ public final class CreateAdministrator {
if (lastName != null) {
lastName = lastName.trim();
}
-
- ConfigurationService cfg = DSpaceServicesFactory.getInstance().getConfigurationService();
if (cfg.hasProperty("webui.supported.locales")) {
System.out.println("Select one of the following languages: "
+ cfg.getProperty("webui.supported.locales"));
@@ -163,46 +184,59 @@ public final class CreateAdministrator {
}
}
- System.out.println("Password will not display on screen.");
- System.out.print("Password: ");
+ System.out.print("Is the above data correct? (y or n): ");
System.out.flush();
- password1 = console.readPassword();
+ String s = console.readLine();
- System.out.print("Again to confirm: ");
- System.out.flush();
-
- password2 = console.readPassword();
-
- //TODO real password validation
- if (password1.length > 1 && Arrays.equals(password1, password2)) {
- // password OK
- System.out.print("Is the above data correct? (y or n): ");
- System.out.flush();
-
- String s = console.readLine();
-
- if (s != null) {
- s = s.trim();
- if (s.toLowerCase().startsWith("y")) {
- dataOK = true;
- }
+ if (s != null) {
+ s = s.trim();
+ if (s.toLowerCase().startsWith("y")) {
+ dataOK = true;
}
- } else {
- System.out.println("Passwords don't match");
}
+
+ }
+ if (!flag) {
+ password = getPassword(console);
+ if (password == null) {
+ return;
+ }
+ } else {
+ password = line.getOptionValue("p").toCharArray();
}
-
// if we make it to here, we are ready to create an administrator
- createAdministrator(email, firstName, lastName, language, String.valueOf(password1));
+ createAdministrator(email, firstName, lastName, language, String.valueOf(password));
- //Cleaning arrays that held password
- Arrays.fill(password1, ' ');
- Arrays.fill(password2, ' ');
+ }
+
+ private char[] getPassword(Console console) {
+ char[] password1 = null;
+ char[] password2 = null;
+ System.out.println("Password will not display on screen.");
+ System.out.print("Password: ");
+ System.out.flush();
+
+ password1 = console.readPassword();
+
+ System.out.print("Again to confirm: ");
+ System.out.flush();
+
+ password2 = console.readPassword();
+
+ // TODO real password validation
+ if (password1.length > 1 && Arrays.equals(password1, password2)) {
+ // password OK
+ Arrays.fill(password2, ' ');
+ return password1;
+ } else {
+ System.out.println("Passwords don't match");
+ return null;
+ }
}
/**
- * Create the administrator with the given details. If the user
+ * Create the administrator with the given details. If the user
* already exists then they are simply upped to administrator status
*
* @param email the email for the user
@@ -213,8 +247,8 @@ public final class CreateAdministrator {
* @throws Exception if error
*/
protected void createAdministrator(String email, String first, String last,
- String language, String pw)
- throws Exception {
+ String language, String pw)
+ throws Exception {
// Of course we aren't an administrator yet so we need to
// circumvent authorisation
context.turnOffAuthorisationSystem();
diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/CollectionAdministratorsRequestItemStrategy.java b/dspace-api/src/main/java/org/dspace/app/requestitem/CollectionAdministratorsRequestItemStrategy.java
new file mode 100644
index 0000000000..135406069a
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/requestitem/CollectionAdministratorsRequestItemStrategy.java
@@ -0,0 +1,46 @@
+/**
+ * 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.requestitem;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.dspace.content.Collection;
+import org.dspace.content.Item;
+import org.dspace.core.Context;
+import org.dspace.eperson.EPerson;
+import org.springframework.lang.NonNull;
+
+/**
+ * Derive request recipients from groups of the Collection which owns an Item.
+ * The list will include all members of the administrators group. If the
+ * resulting list is empty, delegates to {@link RequestItemHelpdeskStrategy}.
+ *
+ * @author Mark H. Wood
+ */
+public class CollectionAdministratorsRequestItemStrategy
+ extends RequestItemHelpdeskStrategy {
+ @Override
+ @NonNull
+ public List getRequestItemAuthor(Context context,
+ Item item)
+ throws SQLException {
+ List recipients = new ArrayList<>();
+ Collection collection = item.getOwningCollection();
+ for (EPerson admin : collection.getAdministrators().getMembers()) {
+ recipients.add(new RequestItemAuthor(admin));
+ }
+ if (recipients.isEmpty()) {
+ return super.getRequestItemAuthor(context, item);
+ } else {
+ return recipients;
+ }
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/CombiningRequestItemStrategy.java b/dspace-api/src/main/java/org/dspace/app/requestitem/CombiningRequestItemStrategy.java
new file mode 100644
index 0000000000..8292c1a728
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/requestitem/CombiningRequestItemStrategy.java
@@ -0,0 +1,61 @@
+/**
+ * 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.requestitem;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.dspace.content.Item;
+import org.dspace.core.Context;
+import org.springframework.lang.NonNull;
+import org.springframework.util.Assert;
+
+/**
+ * Assemble a list of recipients from the results of other strategies.
+ * The list of strategy classes is injected as the constructor argument
+ * {@code strategies}.
+ * If the strategy list is not configured, returns an empty List.
+ *
+ * @author Mark H. Wood
+ */
+public class CombiningRequestItemStrategy
+ implements RequestItemAuthorExtractor {
+ /** The strategies to combine. */
+ private final List strategies;
+
+ /**
+ * Initialize a combination of strategies.
+ * @param strategies the author extraction strategies to combine.
+ */
+ public CombiningRequestItemStrategy(@NonNull List strategies) {
+ Assert.notNull(strategies, "Strategy list may not be null");
+ this.strategies = strategies;
+ }
+
+ /**
+ * Do not call.
+ * @throws IllegalArgumentException always
+ */
+ private CombiningRequestItemStrategy() {
+ throw new IllegalArgumentException();
+ }
+
+ @Override
+ @NonNull
+ public List getRequestItemAuthor(Context context, Item item)
+ throws SQLException {
+ List recipients = new ArrayList<>();
+
+ for (RequestItemAuthorExtractor strategy : strategies) {
+ recipients.addAll(strategy.getRequestItemAuthor(context, item));
+ }
+
+ return recipients;
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItem.java b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItem.java
index 9e675e97a7..cdefd1298c 100644
--- a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItem.java
+++ b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItem.java
@@ -27,7 +27,7 @@ import org.dspace.core.Context;
import org.dspace.core.ReloadableEntity;
/**
- * Object representing an Item Request
+ * Object representing an Item Request.
*/
@Entity
@Table(name = "requestitem")
@@ -94,6 +94,9 @@ public class RequestItem implements ReloadableEntity {
this.allfiles = allfiles;
}
+ /**
+ * @return {@code true} if all of the Item's files are requested.
+ */
public boolean isAllfiles() {
return allfiles;
}
@@ -102,6 +105,9 @@ public class RequestItem implements ReloadableEntity {
this.reqMessage = reqMessage;
}
+ /**
+ * @return a message from the requester.
+ */
public String getReqMessage() {
return reqMessage;
}
@@ -110,6 +116,9 @@ public class RequestItem implements ReloadableEntity {
this.reqName = reqName;
}
+ /**
+ * @return Human-readable name of the user requesting access.
+ */
public String getReqName() {
return reqName;
}
@@ -118,6 +127,9 @@ public class RequestItem implements ReloadableEntity {
this.reqEmail = reqEmail;
}
+ /**
+ * @return address of the user requesting access.
+ */
public String getReqEmail() {
return reqEmail;
}
@@ -126,6 +138,9 @@ public class RequestItem implements ReloadableEntity {
this.token = token;
}
+ /**
+ * @return a unique request identifier which can be emailed.
+ */
public String getToken() {
return token;
}
diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthor.java b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthor.java
index 49e26fe00b..a189e4a5ef 100644
--- a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthor.java
+++ b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthor.java
@@ -11,20 +11,31 @@ import org.dspace.eperson.EPerson;
/**
* Simple DTO to transfer data about the corresponding author for the Request
- * Copy feature
+ * Copy feature.
*
* @author Andrea Bollini
*/
public class RequestItemAuthor {
- private String fullName;
- private String email;
+ private final String fullName;
+ private final String email;
+ /**
+ * Construct an author record from given data.
+ *
+ * @param fullName the author's full name.
+ * @param email the author's email address.
+ */
public RequestItemAuthor(String fullName, String email) {
super();
this.fullName = fullName;
this.email = email;
}
+ /**
+ * Construct an author from an EPerson's metadata.
+ *
+ * @param ePerson the EPerson.
+ */
public RequestItemAuthor(EPerson ePerson) {
super();
this.fullName = ePerson.getFullName();
diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthorExtractor.java b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthorExtractor.java
index 9b66030e90..bc97bc64bf 100644
--- a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthorExtractor.java
+++ b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthorExtractor.java
@@ -8,26 +8,28 @@
package org.dspace.app.requestitem;
import java.sql.SQLException;
+import java.util.List;
import org.dspace.content.Item;
import org.dspace.core.Context;
+import org.springframework.lang.NonNull;
/**
- * Interface to abstract the strategy for select the author to contact for
- * request copy
+ * Interface to abstract the strategy for selecting the author to contact for
+ * request copy.
*
* @author Andrea Bollini
*/
public interface RequestItemAuthorExtractor {
-
/**
- * Retrieve the auhtor to contact for a request copy of the give item.
+ * Retrieve the author to contact for requesting a copy of the given item.
*
* @param context DSpace context object
* @param item item to request
- * @return An object containing name an email address to send the request to
- * or null if no valid email address was found.
+ * @return Names and email addresses to send the request to.
* @throws SQLException if database error
*/
- public RequestItemAuthor getRequestItemAuthor(Context context, Item item) throws SQLException;
+ @NonNull
+ public List getRequestItemAuthor(Context context, Item item)
+ throws SQLException;
}
diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemEmailNotifier.java b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemEmailNotifier.java
index d72e42eac1..02054ee1a0 100644
--- a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemEmailNotifier.java
+++ b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemEmailNotifier.java
@@ -72,28 +72,48 @@ public class RequestItemEmailNotifier {
static public void sendRequest(Context context, RequestItem ri, String responseLink)
throws IOException, SQLException {
// Who is making this request?
- RequestItemAuthor author = requestItemAuthorExtractor
+ List authors = requestItemAuthorExtractor
.getRequestItemAuthor(context, ri.getItem());
- String authorEmail = author.getEmail();
- String authorName = author.getFullName();
// Build an email to the approver.
Email email = Email.getEmail(I18nUtil.getEmailFilename(context.getCurrentLocale(),
"request_item.author"));
- email.addRecipient(authorEmail);
+ for (RequestItemAuthor author : authors) {
+ email.addRecipient(author.getEmail());
+ }
email.setReplyTo(ri.getReqEmail()); // Requester's address
+
email.addArgument(ri.getReqName()); // {0} Requester's name
+
email.addArgument(ri.getReqEmail()); // {1} Requester's address
+
email.addArgument(ri.isAllfiles() // {2} All bitstreams or just one?
? I18nUtil.getMessage("itemRequest.all") : ri.getBitstream().getName());
- email.addArgument(handleService.getCanonicalForm(ri.getItem().getHandle()));
+
+ email.addArgument(handleService.getCanonicalForm(ri.getItem().getHandle())); // {3}
+
email.addArgument(ri.getItem().getName()); // {4} requested item's title
+
email.addArgument(ri.getReqMessage()); // {5} message from requester
+
email.addArgument(responseLink); // {6} Link back to DSpace for action
- email.addArgument(authorName); // {7} corresponding author name
- email.addArgument(authorEmail); // {8} corresponding author email
- email.addArgument(configurationService.getProperty("dspace.name"));
- email.addArgument(configurationService.getProperty("mail.helpdesk"));
+
+ StringBuilder names = new StringBuilder();
+ StringBuilder addresses = new StringBuilder();
+ for (RequestItemAuthor author : authors) {
+ if (names.length() > 0) {
+ names.append("; ");
+ addresses.append("; ");
+ }
+ names.append(author.getFullName());
+ addresses.append(author.getEmail());
+ }
+ email.addArgument(names.toString()); // {7} corresponding author name
+ email.addArgument(addresses.toString()); // {8} corresponding author email
+
+ email.addArgument(configurationService.getProperty("dspace.name")); // {9}
+
+ email.addArgument(configurationService.getProperty("mail.helpdesk")); // {10}
// Send the email.
try {
diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemHelpdeskStrategy.java b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemHelpdeskStrategy.java
index 7b63d3ea8d..f440ba380a 100644
--- a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemHelpdeskStrategy.java
+++ b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemHelpdeskStrategy.java
@@ -8,6 +8,8 @@
package org.dspace.app.requestitem;
import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.dspace.content.Item;
@@ -16,11 +18,11 @@ import org.dspace.core.I18nUtil;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.service.EPersonService;
import org.dspace.services.ConfigurationService;
-import org.dspace.services.factory.DSpaceServicesFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.lang.NonNull;
/**
- * RequestItem strategy to allow DSpace support team's helpdesk to receive requestItem request
+ * RequestItem strategy to allow DSpace support team's helpdesk to receive requestItem request.
* With this enabled, then the Item author/submitter doesn't receive the request, but the helpdesk instead does.
*
* Failover to the RequestItemSubmitterStrategy, which means the submitter would get the request if there is no
@@ -33,19 +35,24 @@ public class RequestItemHelpdeskStrategy extends RequestItemSubmitterStrategy {
@Autowired(required = true)
protected EPersonService ePersonService;
+ @Autowired(required = true)
+ private ConfigurationService configuration;
+
public RequestItemHelpdeskStrategy() {
}
@Override
- public RequestItemAuthor getRequestItemAuthor(Context context, Item item) throws SQLException {
- ConfigurationService configurationService
- = DSpaceServicesFactory.getInstance().getConfigurationService();
- boolean helpdeskOverridesSubmitter = configurationService
+ @NonNull
+ public List getRequestItemAuthor(Context context, Item item)
+ throws SQLException {
+ boolean helpdeskOverridesSubmitter = configuration
.getBooleanProperty("request.item.helpdesk.override", false);
- String helpDeskEmail = configurationService.getProperty("mail.helpdesk");
+ String helpDeskEmail = configuration.getProperty("mail.helpdesk");
if (helpdeskOverridesSubmitter && StringUtils.isNotBlank(helpDeskEmail)) {
- return getHelpDeskPerson(context, helpDeskEmail);
+ List authors = new ArrayList<>(1);
+ authors.add(getHelpDeskPerson(context, helpDeskEmail));
+ return authors;
} else {
//Fallback to default logic (author of Item) if helpdesk isn't fully enabled or setup
return super.getRequestItemAuthor(context, item);
diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemMetadataStrategy.java b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemMetadataStrategy.java
index 1737490fbb..4372ab9b09 100644
--- a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemMetadataStrategy.java
+++ b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemMetadataStrategy.java
@@ -8,6 +8,8 @@
package org.dspace.app.requestitem;
import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
@@ -16,12 +18,13 @@ import org.dspace.content.MetadataValue;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
import org.dspace.core.I18nUtil;
-import org.dspace.services.factory.DSpaceServicesFactory;
+import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.lang.NonNull;
/**
* Try to look to an item metadata for the corresponding author name and email.
- * Failover to the RequestItemSubmitterStrategy
+ * Failover to the RequestItemSubmitterStrategy.
*
* @author Andrea Bollini
*/
@@ -30,6 +33,9 @@ public class RequestItemMetadataStrategy extends RequestItemSubmitterStrategy {
protected String emailMetadata;
protected String fullNameMetadata;
+ @Autowired(required = true)
+ protected ConfigurationService configurationService;
+
@Autowired(required = true)
protected ItemService itemService;
@@ -37,59 +43,72 @@ public class RequestItemMetadataStrategy extends RequestItemSubmitterStrategy {
}
@Override
- public RequestItemAuthor getRequestItemAuthor(Context context, Item item)
+ @NonNull
+ public List getRequestItemAuthor(Context context, Item item)
throws SQLException {
- RequestItemAuthor author = null;
+ List authors;
if (emailMetadata != null) {
List vals = itemService.getMetadataByMetadataString(item, emailMetadata);
- if (vals.size() > 0) {
- String email = vals.iterator().next().getValue();
- String fullname = null;
- if (fullNameMetadata != null) {
- List nameVals = itemService.getMetadataByMetadataString(item, fullNameMetadata);
- if (nameVals.size() > 0) {
- fullname = nameVals.iterator().next().getValue();
+ List nameVals;
+ if (null != fullNameMetadata) {
+ nameVals = itemService.getMetadataByMetadataString(item, fullNameMetadata);
+ } else {
+ nameVals = Collections.EMPTY_LIST;
+ }
+ boolean useNames = vals.size() == nameVals.size();
+ if (!vals.isEmpty()) {
+ authors = new ArrayList<>(vals.size());
+ for (int authorIndex = 0; authorIndex < vals.size(); authorIndex++) {
+ String email = vals.get(authorIndex).getValue();
+ String fullname = null;
+ if (useNames) {
+ fullname = nameVals.get(authorIndex).getValue();
}
+
+ if (StringUtils.isBlank(fullname)) {
+ fullname = I18nUtil.getMessage(
+ "org.dspace.app.requestitem.RequestItemMetadataStrategy.unnamed",
+ context);
+ }
+ RequestItemAuthor author = new RequestItemAuthor(
+ fullname, email);
+ authors.add(author);
}
- if (StringUtils.isBlank(fullname)) {
- fullname = I18nUtil
- .getMessage(
- "org.dspace.app.requestitem.RequestItemMetadataStrategy.unnamed",
- context);
- }
- author = new RequestItemAuthor(fullname, email);
- return author;
+ return authors;
+ } else {
+ return Collections.EMPTY_LIST;
}
} else {
// Uses the basic strategy to look for the original submitter
- author = super.getRequestItemAuthor(context, item);
- // Is the author or their email null. If so get the help desk or admin name and email
- if (null == author || null == author.getEmail()) {
- String email = null;
- String name = null;
+ authors = super.getRequestItemAuthor(context, item);
+
+ // Remove from the list authors that do not have email addresses.
+ for (RequestItemAuthor author : authors) {
+ if (null == author.getEmail()) {
+ authors.remove(author);
+ }
+ }
+
+ if (authors.isEmpty()) { // No author email addresses! Fall back
//First get help desk name and email
- email = DSpaceServicesFactory.getInstance()
- .getConfigurationService().getProperty("mail.helpdesk");
- name = DSpaceServicesFactory.getInstance()
- .getConfigurationService().getProperty("mail.helpdesk.name");
+ String email = configurationService.getProperty("mail.helpdesk");
+ String name = configurationService.getProperty("mail.helpdesk.name");
// If help desk mail is null get the mail and name of admin
if (email == null) {
- email = DSpaceServicesFactory.getInstance()
- .getConfigurationService().getProperty("mail.admin");
- name = DSpaceServicesFactory.getInstance()
- .getConfigurationService().getProperty("mail.admin.name");
+ email = configurationService.getProperty("mail.admin");
+ name = configurationService.getProperty("mail.admin.name");
}
- author = new RequestItemAuthor(name, email);
+ authors.add(new RequestItemAuthor(name, email));
}
+ return authors;
}
- return author;
}
- public void setEmailMetadata(String emailMetadata) {
+ public void setEmailMetadata(@NonNull String emailMetadata) {
this.emailMetadata = emailMetadata;
}
- public void setFullNameMetadata(String fullNameMetadata) {
+ public void setFullNameMetadata(@NonNull String fullNameMetadata) {
this.fullNameMetadata = fullNameMetadata;
}
diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemSubmitterStrategy.java b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemSubmitterStrategy.java
index 2708c24ba9..dcc1a3e80e 100644
--- a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemSubmitterStrategy.java
+++ b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemSubmitterStrategy.java
@@ -8,10 +8,13 @@
package org.dspace.app.requestitem;
import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
import org.dspace.content.Item;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
+import org.springframework.lang.NonNull;
/**
* Basic strategy that looks to the original submitter.
@@ -24,21 +27,23 @@ public class RequestItemSubmitterStrategy implements RequestItemAuthorExtractor
}
/**
- * Returns the submitter of an Item as RequestItemAuthor or null if the
- * Submitter is deleted.
+ * Returns the submitter of an Item as RequestItemAuthor or an empty List if
+ * the Submitter is deleted.
*
- * @return The submitter of the item or null if the submitter is deleted
+ * @return The submitter of the item or empty List if the submitter is deleted
* @throws SQLException if database error
*/
@Override
- public RequestItemAuthor getRequestItemAuthor(Context context, Item item)
+ @NonNull
+ public List getRequestItemAuthor(Context context, Item item)
throws SQLException {
EPerson submitter = item.getSubmitter();
- RequestItemAuthor author = null;
+ List authors = new ArrayList<>(1);
if (null != submitter) {
- author = new RequestItemAuthor(
- submitter.getFullName(), submitter.getEmail());
+ RequestItemAuthor author = new RequestItemAuthor(
+ submitter.getFullName(), submitter.getEmail());
+ authors.add(author);
}
- return author;
+ return authors;
}
}
diff --git a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java
index 0b76186e48..685fd9000d 100644
--- a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java
+++ b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java
@@ -14,9 +14,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
-import java.net.URLEncoder;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
@@ -465,17 +463,17 @@ public abstract class AbstractMETSDisseminator
Utils.copy(input, zip);
input.close();
} else {
- log.warn("Adding zero-length file for Bitstream, SID="
- + String.valueOf(bitstream.getSequenceID())
+ log.warn("Adding zero-length file for Bitstream, uuid="
+ + String.valueOf(bitstream.getID())
+ ", not authorized for READ.");
}
zip.closeEntry();
} else if (unauth != null && unauth.equalsIgnoreCase("skip")) {
- log.warn("Skipping Bitstream, SID=" + String
- .valueOf(bitstream.getSequenceID()) + ", not authorized for READ.");
+ log.warn("Skipping Bitstream, uuid=" + String
+ .valueOf(bitstream.getID()) + ", not authorized for READ.");
} else {
throw new AuthorizeException(
- "Not authorized to read Bitstream, SID=" + String.valueOf(bitstream.getSequenceID()));
+ "Not authorized to read Bitstream, uuid=" + String.valueOf(bitstream.getID()));
}
}
}
@@ -896,12 +894,12 @@ public abstract class AbstractMETSDisseminator
continue;
} else if (!(unauth != null && unauth.equalsIgnoreCase("zero"))) {
throw new AuthorizeException(
- "Not authorized to read Bitstream, SID=" + String.valueOf(bitstream.getSequenceID()));
+ "Not authorized to read Bitstream, uuid=" + String.valueOf(bitstream.getID()));
}
}
- String sid = String.valueOf(bitstream.getSequenceID());
- String fileID = bitstreamIDstart + sid;
+ String uuid = String.valueOf(bitstream.getID());
+ String fileID = bitstreamIDstart + uuid;
edu.harvard.hul.ois.mets.File file = new edu.harvard.hul.ois.mets.File();
file.setID(fileID);
file.setSEQ(bitstream.getSequenceID());
@@ -924,7 +922,7 @@ public abstract class AbstractMETSDisseminator
* extracted text or a thumbnail, so we use the name to work
* out which bitstream to be in the same group as
*/
- String groupID = "GROUP_" + bitstreamIDstart + sid;
+ String groupID = "GROUP_" + bitstreamIDstart + uuid;
if ((bundle.getName() != null)
&& (bundle.getName().equals("THUMBNAIL") ||
bundle.getName().startsWith("TEXT"))) {
@@ -934,7 +932,7 @@ public abstract class AbstractMETSDisseminator
bitstream);
if (original != null) {
groupID = "GROUP_" + bitstreamIDstart
- + original.getSequenceID();
+ + String.valueOf(original.getID());
}
}
file.setGROUPID(groupID);
@@ -1403,7 +1401,7 @@ public abstract class AbstractMETSDisseminator
// if bare manifest, use external "persistent" URI for bitstreams
if (params != null && (params.getBooleanProperty("manifestOnly", false))) {
// Try to build a persistent(-ish) URI for bitstream
- // Format: {site-base-url}/bitstream/{item-handle}/{sequence-id}/{bitstream-name}
+ // Format: {site-ui-url}/bitstreams/{bitstream-uuid}
try {
// get handle of parent Item of this bitstream, if there is one:
String handle = null;
@@ -1414,26 +1412,13 @@ public abstract class AbstractMETSDisseminator
handle = bi.get(0).getHandle();
}
}
- if (handle != null) {
- return configurationService
- .getProperty("dspace.ui.url")
- + "/bitstream/"
- + handle
- + "/"
- + String.valueOf(bitstream.getSequenceID())
- + "/"
- + URLEncoder.encode(bitstream.getName(), "UTF-8");
- } else { //no Handle assigned, so persistent(-ish) URI for bitstream is
- // Format: {site-base-url}/retrieve/{bitstream-internal-id}
- return configurationService
- .getProperty("dspace.ui.url")
- + "/retrieve/"
- + String.valueOf(bitstream.getID());
- }
+ return configurationService
+ .getProperty("dspace.ui.url")
+ + "/bitstreams/"
+ + String.valueOf(bitstream.getID())
+ + "/download";
} catch (SQLException e) {
log.error("Database problem", e);
- } catch (UnsupportedEncodingException e) {
- log.error("Unknown character set", e);
}
// We should only get here if we failed to build a nice URL above
diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/CreateMissingIdentifiers.java b/dspace-api/src/main/java/org/dspace/ctask/general/CreateMissingIdentifiers.java
new file mode 100644
index 0000000000..9639461426
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/ctask/general/CreateMissingIdentifiers.java
@@ -0,0 +1,94 @@
+/**
+ * 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.ctask.general;
+
+import java.io.IOException;
+import java.sql.SQLException;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.dspace.authorize.AuthorizeException;
+import org.dspace.content.DSpaceObject;
+import org.dspace.content.Item;
+import org.dspace.core.Constants;
+import org.dspace.core.Context;
+import org.dspace.curate.AbstractCurationTask;
+import org.dspace.curate.Curator;
+import org.dspace.identifier.IdentifierException;
+import org.dspace.identifier.IdentifierProvider;
+import org.dspace.identifier.VersionedHandleIdentifierProviderWithCanonicalHandles;
+import org.dspace.identifier.factory.IdentifierServiceFactory;
+import org.dspace.identifier.service.IdentifierService;
+import org.dspace.services.factory.DSpaceServicesFactory;
+
+/**
+ * Ensure that an object has all of the identifiers that it should, minting them
+ * as necessary.
+ *
+ * @author Mark H. Wood {@literal }
+ */
+public class CreateMissingIdentifiers
+ extends AbstractCurationTask {
+ private static final Logger LOG = LogManager.getLogger();
+
+ @Override
+ public int perform(DSpaceObject dso)
+ throws IOException {
+ // Only some kinds of model objects get identifiers
+ if (!(dso instanceof Item)) {
+ return Curator.CURATE_SKIP;
+ }
+
+ // XXX Temporary escape when an incompatible provider is configured.
+ // XXX Remove this when the provider is fixed.
+ boolean compatible = DSpaceServicesFactory
+ .getInstance()
+ .getServiceManager()
+ .getServiceByName(
+ VersionedHandleIdentifierProviderWithCanonicalHandles.class.getCanonicalName(),
+ IdentifierProvider.class) == null;
+ if (!compatible) {
+ setResult("This task is not compatible with VersionedHandleIdentifierProviderWithCanonicalHandles");
+ return Curator.CURATE_ERROR;
+ }
+ // XXX End of escape
+
+ String typeText = Constants.typeText[dso.getType()];
+
+ // Get a Context
+ Context context;
+ try {
+ context = Curator.curationContext();
+ } catch (SQLException ex) {
+ report("Could not get the curation Context: " + ex.getMessage());
+ return Curator.CURATE_ERROR;
+ }
+
+ // Find the IdentifierService implementation
+ IdentifierService identifierService = IdentifierServiceFactory
+ .getInstance()
+ .getIdentifierService();
+
+ // Register any missing identifiers.
+ try {
+ identifierService.register(context, dso);
+ } catch (AuthorizeException | IdentifierException | SQLException ex) {
+ String message = ex.getMessage();
+ report(String.format("Identifier(s) not minted for %s %s: %s%n",
+ typeText, dso.getID().toString(), message));
+ LOG.error("Identifier(s) not minted: {}", message);
+ return Curator.CURATE_ERROR;
+ }
+
+ // Success!
+ report(String.format("%s %s registered.%n",
+ typeText, dso.getID().toString()));
+ return Curator.CURATE_SUCCESS;
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrSearchCore.java b/dspace-api/src/main/java/org/dspace/discovery/SolrSearchCore.java
index b430a0c973..f31feab612 100644
--- a/dspace-api/src/main/java/org/dspace/discovery/SolrSearchCore.java
+++ b/dspace-api/src/main/java/org/dspace/discovery/SolrSearchCore.java
@@ -21,7 +21,6 @@ import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.dspace.discovery.indexobject.IndexableItem;
import org.dspace.service.impl.HttpConnectionPoolService;
import org.dspace.services.ConfigurationService;
-import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.storage.rdbms.DatabaseUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -75,14 +74,13 @@ public class SolrSearchCore {
*/
protected void initSolr() {
if (solr == null) {
- String solrService = DSpaceServicesFactory.getInstance().getConfigurationService()
- .getProperty("discovery.search.server");
+ String solrService = configurationService.getProperty("discovery.search.server");
UrlValidator urlValidator = new UrlValidator(UrlValidator.ALLOW_LOCAL_URLS);
if (urlValidator.isValid(solrService) || configurationService
.getBooleanProperty("discovery.solr.url.validation.enabled", true)) {
try {
- log.debug("Solr URL: " + solrService);
+ log.debug("Solr URL: {}", solrService);
HttpSolrClient solrServer = new HttpSolrClient.Builder(solrService)
.withHttpClient(httpConnectionPoolService.getClient())
.build();
@@ -103,10 +101,13 @@ public class SolrSearchCore {
solr = solrServer;
} catch (SolrServerException | IOException e) {
- log.error("Error while initializing solr server", e);
+ log.error("Error while initializing solr server {}",
+ solrService, e);
+ throw new RuntimeException("Failed to contact Solr at " + solrService
+ + " : " + e.getMessage());
}
} else {
- log.error("Error while initializing solr, invalid url: " + solrService);
+ log.error("Error while initializing solr, invalid url: {}", solrService);
}
}
}
diff --git a/dspace-api/src/main/java/org/dspace/external/provider/impl/OpenAIREFundingDataProvider.java b/dspace-api/src/main/java/org/dspace/external/provider/impl/OpenAIREFundingDataProvider.java
index 3dcd7d16a6..8ca5b7c0ea 100644
--- a/dspace-api/src/main/java/org/dspace/external/provider/impl/OpenAIREFundingDataProvider.java
+++ b/dspace-api/src/main/java/org/dspace/external/provider/impl/OpenAIREFundingDataProvider.java
@@ -15,6 +15,7 @@ import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -33,6 +34,7 @@ import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.external.OpenAIRERestConnector;
import org.dspace.external.model.ExternalDataObject;
import org.dspace.external.provider.AbstractExternalDataProvider;
+import org.dspace.importer.external.metadatamapping.MetadataFieldConfig;
import org.springframework.beans.factory.annotation.Autowired;
/**
@@ -40,13 +42,9 @@ import org.springframework.beans.factory.annotation.Autowired;
* will deal with the OpenAIRE External Data lookup
*
* @author paulo-graca
- *
*/
public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
- /**
- * log4j logger
- */
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(OpenAIREFundingDataProvider.class);
/**
@@ -54,6 +52,16 @@ public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
*/
protected static final String PREFIX = "info:eu-repo/grantAgreement";
+ private static final String TITLE = "dcTitle";
+ private static final String SUBJECT = "dcSubject";
+ private static final String AWARD_URI = "awardURI";
+ private static final String FUNDER_NAME = "funderName";
+ private static final String SPATIAL = "coverageSpatial";
+ private static final String AWARD_NUMBER = "awardNumber";
+ private static final String FUNDER_ID = "funderIdentifier";
+ private static final String FUNDING_STREAM = "fundingStream";
+ private static final String TITLE_ALTERNATIVE = "titleAlternative";
+
/**
* rows default limit
*/
@@ -69,11 +77,9 @@ public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
*/
protected OpenAIRERestConnector connector;
- /**
- * required method
- */
- public void init() throws IOException {
- }
+ protected Map metadataFields;
+
+ public void init() throws IOException {}
@Override
public String getSourceIdentifier() {
@@ -266,14 +272,22 @@ public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
}
}
+ public Map getMetadataFields() {
+ return metadataFields;
+ }
+
+ public void setMetadataFields(Map metadataFields) {
+ this.metadataFields = metadataFields;
+ }
+
/**
* OpenAIRE Funding External Data Builder Class
*
* @author pgraca
- *
*/
- public static class ExternalDataObjectBuilder {
- ExternalDataObject externalDataObject;
+ public class ExternalDataObjectBuilder {
+
+ private ExternalDataObject externalDataObject;
public ExternalDataObjectBuilder(Project project) {
String funderIdPrefix = "urn:openaire:";
@@ -283,46 +297,42 @@ public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
for (FundingTreeType fundingTree : projectHelper.getFundingTreeTypes()) {
FunderType funder = fundingTree.getFunder();
// Funder name
- this.addFunderName(funder.getName());
+ this.addMetadata(metadataFields.get(FUNDER_NAME), funder.getName());
// Funder Id - convert it to an urn
- this.addFunderID(funderIdPrefix + funder.getId());
+ this.addMetadata(metadataFields.get(FUNDER_ID), funderIdPrefix + funder.getId());
// Jurisdiction
- this.addFunderJuristiction(funder.getJurisdiction());
+ this.addMetadata(metadataFields.get(SPATIAL), funder.getJurisdiction());
FundingHelper fundingHelper = new FundingHelper(
- fundingTree.getFundingLevel2OrFundingLevel1OrFundingLevel0());
+ fundingTree.getFundingLevel2OrFundingLevel1OrFundingLevel0());
// Funding description
for (FundingType funding : fundingHelper.getFirstAvailableFunding()) {
- this.addFundingStream(funding.getDescription());
+ this.addMetadata(metadataFields.get(FUNDING_STREAM), funding.getDescription());
}
}
// Title
for (String title : projectHelper.getTitles()) {
- this.addAwardTitle(title);
+ this.addMetadata(metadataFields.get(TITLE), title);
this.setDisplayValue(title);
this.setValue(title);
}
-
// Code
for (String code : projectHelper.getCodes()) {
- this.addAwardNumber(code);
+ this.addMetadata(metadataFields.get(AWARD_NUMBER), code);
}
-
// Website url
for (String url : projectHelper.getWebsiteUrls()) {
- this.addAwardURI(url);
+ this.addMetadata(metadataFields.get(AWARD_URI), url);
}
-
// Acronyms
for (String acronym : projectHelper.getAcronyms()) {
- this.addFundingItemAcronym(acronym);
+ this.addMetadata(metadataFields.get(TITLE_ALTERNATIVE), acronym);
}
-
// Keywords
for (String keyword : projectHelper.getKeywords()) {
- this.addSubject(keyword);
+ this.addMetadata(metadataFields.get(SUBJECT), keyword);
}
}
@@ -366,7 +376,6 @@ public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
* @return ExternalDataObjectBuilder
*/
public ExternalDataObjectBuilder setId(String id) {
-
// we use base64 encoding in order to use slashes / and other
// characters that must be escaped for the <:entry-id>
String base64Id = Base64.getEncoder().encodeToString(id.getBytes());
@@ -374,128 +383,10 @@ public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
return this;
}
- /**
- * Add metadata dc.identifier
- *
- * @param metadata identifier
- * @return ExternalDataObjectBuilder
- */
- public ExternalDataObjectBuilder addIdentifier(String identifier) {
- this.externalDataObject.addMetadata(new MetadataValueDTO("dc", "identifier", null, null, identifier));
- return this;
- }
-
- /**
- * Add metadata project.funder.name
- *
- * @param metadata funderName
- * @return ExternalDataObjectBuilder
- */
- public ExternalDataObjectBuilder addFunderName(String funderName) {
- this.externalDataObject.addMetadata(new MetadataValueDTO("project", "funder", "name", null, funderName));
- return this;
- }
-
- /**
- * Add metadata project.funder.identifier
- *
- * @param metadata funderId
- * @return ExternalDataObjectBuilder
- */
- public ExternalDataObjectBuilder addFunderID(String funderID) {
- this.externalDataObject
- .addMetadata(new MetadataValueDTO("project", "funder", "identifier", null, funderID));
- return this;
- }
-
- /**
- * Add metadata dc.title
- *
- * @param metadata awardTitle
- * @return ExternalDataObjectBuilder
- */
- public ExternalDataObjectBuilder addAwardTitle(String awardTitle) {
- this.externalDataObject.addMetadata(new MetadataValueDTO("dc", "title", null, null, awardTitle));
- return this;
- }
-
- /**
- * Add metadata oaire.fundingStream
- *
- * @param metadata fundingStream
- * @return ExternalDataObjectBuilder
- */
- public ExternalDataObjectBuilder addFundingStream(String fundingStream) {
- this.externalDataObject
- .addMetadata(new MetadataValueDTO("oaire", "fundingStream", null, null, fundingStream));
- return this;
- }
-
- /**
- * Add metadata oaire.awardNumber
- *
- * @param metadata awardNumber
- * @return ExternalDataObjectBuilder
- */
- public ExternalDataObjectBuilder addAwardNumber(String awardNumber) {
- this.externalDataObject.addMetadata(new MetadataValueDTO("oaire", "awardNumber", null, null, awardNumber));
- return this;
- }
-
- /**
- * Add metadata oaire.awardURI
- *
- * @param metadata websiteUrl
- * @return ExternalDataObjectBuilder
- */
- public ExternalDataObjectBuilder addAwardURI(String websiteUrl) {
- this.externalDataObject.addMetadata(new MetadataValueDTO("oaire", "awardURI", null, null, websiteUrl));
- return this;
- }
-
- /**
- * Add metadata dc.title.alternative
- *
- * @param metadata fundingItemAcronym
- * @return ExternalDataObjectBuilder
- */
- public ExternalDataObjectBuilder addFundingItemAcronym(String fundingItemAcronym) {
- this.externalDataObject
- .addMetadata(new MetadataValueDTO("dc", "title", "alternative", null, fundingItemAcronym));
- return this;
- }
-
- /**
- * Add metadata dc.coverage.spatial
- *
- * @param metadata funderJuristiction
- * @return ExternalDataObjectBuilder
- */
- public ExternalDataObjectBuilder addFunderJuristiction(String funderJuristiction) {
- this.externalDataObject
- .addMetadata(new MetadataValueDTO("dc", "coverage", "spatial", null, funderJuristiction));
- return this;
- }
-
- /**
- * Add metadata dc.description
- *
- * @param metadata description
- * @return ExternalDataObjectBuilder
- */
- public ExternalDataObjectBuilder addDescription(String description) {
- this.externalDataObject.addMetadata(new MetadataValueDTO("dc", "description", null, null, description));
- return this;
- }
-
- /**
- * Add metadata dc.subject
- *
- * @param metadata subject
- * @return ExternalDataObjectBuilder
- */
- public ExternalDataObjectBuilder addSubject(String subject) {
- this.externalDataObject.addMetadata(new MetadataValueDTO("dc", "subject", null, null, subject));
+ public ExternalDataObjectBuilder addMetadata(MetadataFieldConfig metadataField, String value) {
+ this.externalDataObject.addMetadata(new MetadataValueDTO(metadataField.getSchema(),
+ metadataField.getElement(),
+ metadataField.getQualifier(), null, value));
return this;
}
@@ -508,4 +399,5 @@ public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
return this.externalDataObject;
}
}
-}
+
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollectionServiceImpl.java b/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollectionServiceImpl.java
index d4bb37cf94..0ad83a3292 100644
--- a/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollectionServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollectionServiceImpl.java
@@ -19,10 +19,8 @@ import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerException;
+import javax.xml.xpath.XPathExpressionException;
-import ORG.oclc.oai.harvester2.verb.Identify;
-import ORG.oclc.oai.harvester2.verb.ListIdentifiers;
import org.dspace.content.Collection;
import org.dspace.core.Context;
import org.dspace.harvest.dao.HarvestedCollectionDAO;
@@ -33,6 +31,8 @@ import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.Namespace;
import org.jdom2.input.DOMBuilder;
+import org.oclc.oai.harvester2.verb.Identify;
+import org.oclc.oai.harvester2.verb.ListIdentifiers;
import org.springframework.beans.factory.annotation.Autowired;
import org.w3c.dom.DOMException;
import org.xml.sax.SAXException;
@@ -198,7 +198,7 @@ public class HarvestedCollectionServiceImpl implements HarvestedCollectionServic
// First, see if we can contact the target server at all.
try {
new Identify(oaiSource);
- } catch (IOException | ParserConfigurationException | TransformerException | SAXException ex) {
+ } catch (IOException | ParserConfigurationException | XPathExpressionException | SAXException ex) {
errorSet.add(OAI_ADDRESS_ERROR + ": OAI server could not be reached.");
return errorSet;
}
@@ -216,7 +216,7 @@ public class HarvestedCollectionServiceImpl implements HarvestedCollectionServic
try {
OREOAIPrefix = OAIHarvester.oaiResolveNamespaceToPrefix(oaiSource, OAIHarvester.getORENamespace().getURI());
DMDOAIPrefix = OAIHarvester.oaiResolveNamespaceToPrefix(oaiSource, DMD_NS.getURI());
- } catch (IOException | ParserConfigurationException | TransformerException | SAXException ex) {
+ } catch (IOException | ParserConfigurationException | XPathExpressionException | SAXException ex) {
errorSet.add(OAI_ADDRESS_ERROR
+ ": OAI did not respond to ListMetadataFormats query ("
+ ORE_NS.getPrefix() + ":" + OREOAIPrefix + " ; "
@@ -260,7 +260,8 @@ public class HarvestedCollectionServiceImpl implements HarvestedCollectionServic
}
}
}
- } catch (IOException | ParserConfigurationException | TransformerException | DOMException | SAXException e) {
+ } catch (IOException | ParserConfigurationException | XPathExpressionException | DOMException |
+ SAXException e) {
errorSet.add(OAI_ADDRESS_ERROR + ": OAI server could not be reached");
return errorSet;
} catch (RuntimeException re) {
diff --git a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java
index a0cc9bcc68..5a6b26da93 100644
--- a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java
+++ b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java
@@ -28,12 +28,8 @@ import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerException;
+import javax.xml.xpath.XPathExpressionException;
-import ORG.oclc.oai.harvester2.verb.GetRecord;
-import ORG.oclc.oai.harvester2.verb.Identify;
-import ORG.oclc.oai.harvester2.verb.ListMetadataFormats;
-import ORG.oclc.oai.harvester2.verb.ListRecords;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -76,6 +72,10 @@ import org.jdom2.Element;
import org.jdom2.Namespace;
import org.jdom2.input.DOMBuilder;
import org.jdom2.output.XMLOutputter;
+import org.oclc.oai.harvester2.verb.GetRecord;
+import org.oclc.oai.harvester2.verb.Identify;
+import org.oclc.oai.harvester2.verb.ListMetadataFormats;
+import org.oclc.oai.harvester2.verb.ListRecords;
import org.xml.sax.SAXException;
@@ -493,11 +493,11 @@ public class OAIHarvester {
* @throws HarvestingException if harvesting error
* @throws ParserConfigurationException XML parsing error
* @throws SAXException if XML processing error
- * @throws TransformerException if XML transformer error
+ * @throws XPathExpressionException if XPath error
*/
protected void processRecord(Element record, String OREPrefix, final long currentRecord, long totalListSize)
throws SQLException, AuthorizeException, IOException, CrosswalkException, HarvestingException,
- ParserConfigurationException, SAXException, TransformerException {
+ ParserConfigurationException, SAXException, XPathExpressionException {
WorkspaceItem wi = null;
Date timeStart = new Date();
@@ -769,10 +769,10 @@ public class OAIHarvester {
* @throws IOException if IO error
* @throws SAXException if XML processing error
* @throws ParserConfigurationException XML parsing error
- * @throws TransformerException if XML transformer error
+ * @throws XPathExpressionException if XPath error
*/
private String oaiGetDateGranularity(String oaiSource)
- throws IOException, ParserConfigurationException, SAXException, TransformerException {
+ throws IOException, ParserConfigurationException, SAXException, XPathExpressionException {
Identify iden = new Identify(oaiSource);
return iden.getDocument().getElementsByTagNameNS(OAI_NS.getURI(), "granularity").item(0).getTextContent();
}
@@ -789,11 +789,11 @@ public class OAIHarvester {
* operations.
* @throws ParserConfigurationException XML parsing error
* @throws SAXException if XML processing error
- * @throws TransformerException if XML transformer error
+ * @throws XPathExpressionException if XPath error
* @throws ConnectException if could not connect to OAI server
*/
public static String oaiResolveNamespaceToPrefix(String oaiSource, String MDNamespace)
- throws IOException, ParserConfigurationException, SAXException, TransformerException, ConnectException {
+ throws IOException, ParserConfigurationException, SAXException, XPathExpressionException, ConnectException {
String metaPrefix = null;
// Query the OAI server for the metadata
@@ -866,11 +866,11 @@ public class OAIHarvester {
* operations.
* @throws ParserConfigurationException XML parsing error
* @throws SAXException if XML processing error
- * @throws TransformerException if XML transformer error
+ * @throws XPathExpressionException if XPath error
* @throws HarvestingException if harvesting error
*/
protected List getMDrecord(String oaiSource, String itemOaiId, String metadataPrefix)
- throws IOException, ParserConfigurationException, SAXException, TransformerException, HarvestingException {
+ throws IOException, ParserConfigurationException, SAXException, XPathExpressionException, HarvestingException {
GetRecord getRecord = new GetRecord(oaiSource, itemOaiId, metadataPrefix);
Set errorSet = new HashSet<>();
// If the metadata is not available for this item, can the whole thing
diff --git a/dspace-api/src/main/java/org/dspace/identifier/service/IdentifierService.java b/dspace-api/src/main/java/org/dspace/identifier/service/IdentifierService.java
index 74219fc71c..64eee1dfcf 100644
--- a/dspace-api/src/main/java/org/dspace/identifier/service/IdentifierService.java
+++ b/dspace-api/src/main/java/org/dspace/identifier/service/IdentifierService.java
@@ -92,6 +92,9 @@ public interface IdentifierService {
throws AuthorizeException, SQLException, IdentifierException;
/**
+ * Used to register newly-minted identifiers. Each provider is responsible
+ * for creating the appropriate identifier. All providers are interrogated.
+ *
* @param context The relevant DSpace Context.
* @param dso DSpace object to be registered
* @throws AuthorizeException if authorization error
@@ -101,7 +104,7 @@ public interface IdentifierService {
void register(Context context, DSpaceObject dso) throws AuthorizeException, SQLException, IdentifierException;
/**
- * Used to Register a specific Identifier (for example a Handle, hdl:1234.5/6)
+ * Used to Register a specific Identifier (for example a Handle, hdl:1234.5/6).
* The provider is responsible for detecting and processing the appropriate
* identifier. All Providers are interrogated. Multiple providers
* can process the same identifier.
diff --git a/dspace-api/src/main/java/org/dspace/importer/external/bibtex/service/BibtexImportMetadataSourceServiceImpl.java b/dspace-api/src/main/java/org/dspace/importer/external/bibtex/service/BibtexImportMetadataSourceServiceImpl.java
index 7468d601f5..445dfedebd 100644
--- a/dspace-api/src/main/java/org/dspace/importer/external/bibtex/service/BibtexImportMetadataSourceServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/importer/external/bibtex/service/BibtexImportMetadataSourceServiceImpl.java
@@ -70,11 +70,24 @@ public class BibtexImportMetadataSourceServiceImpl extends AbstractPlainMetadata
keyValueItem.setKey(entry.getValue().getType().getValue());
keyValueItem.setValue(entry.getKey().getValue());
keyValues.add(keyValueItem);
+ PlainMetadataKeyValueItem typeItem = new PlainMetadataKeyValueItem();
+ typeItem.setKey("type");
+ typeItem.setValue(entry.getValue().getType().getValue());
+ keyValues.add(typeItem);
if (entry.getValue().getFields() != null) {
for (Entry subentry : entry.getValue().getFields().entrySet()) {
PlainMetadataKeyValueItem innerItem = new PlainMetadataKeyValueItem();
- innerItem.setKey(subentry.getKey().getValue());
- innerItem.setValue(subentry.getValue().toUserString());
+ innerItem.setKey(subentry.getKey().getValue().toLowerCase());
+ String latexString = subentry.getValue().toUserString();
+ try {
+ org.jbibtex.LaTeXParser laTeXParser = new org.jbibtex.LaTeXParser();
+ List latexObjects = laTeXParser.parse(latexString);
+ org.jbibtex.LaTeXPrinter laTeXPrinter = new org.jbibtex.LaTeXPrinter();
+ String plainTextString = laTeXPrinter.print(latexObjects);
+ innerItem.setValue(plainTextString.replaceAll("\n", " "));
+ } catch (ParseException e) {
+ innerItem.setValue(latexString);
+ }
keyValues.add(innerItem);
}
}
diff --git a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SplitMetadataContributor.java b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SplitMetadataContributor.java
new file mode 100644
index 0000000000..c04081957f
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SplitMetadataContributor.java
@@ -0,0 +1,65 @@
+/**
+ * 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.importer.external.metadatamapping.contributor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.dspace.importer.external.metadatamapping.MetadataFieldMapping;
+import org.dspace.importer.external.metadatamapping.MetadatumDTO;
+
+/**
+ * Wrapper class used to split another MetadataContributor's output into distinct values.
+ * The split is performed by matching a regular expression against the wrapped MetadataContributor's output.
+ *
+ * @author Philipp Rumpf (philipp.rumpf@uni-bamberg.de)
+ */
+
+public class SplitMetadataContributor implements MetadataContributor {
+ private final MetadataContributor innerContributor;
+ private final String regex;
+
+ /**
+ * @param innerContributor The MetadataContributor whose output is split
+ * @param regex A regular expression matching the separator between different values
+ */
+ public SplitMetadataContributor(MetadataContributor innerContributor, String regex) {
+ this.innerContributor = innerContributor;
+ this.regex = regex;
+ }
+
+ @Override
+ public void setMetadataFieldMapping(MetadataFieldMapping> rt) {
+
+ }
+
+ /**
+ * Each metadatum returned by the wrapped MetadataContributor is split into one or more metadata values
+ * based on the provided regular expression.
+ *
+ * @param t The recordType object to retrieve metadata from
+ * @return The collection of processed metadata values
+ */
+ @Override
+ public Collection contributeMetadata(T t) {
+ Collection metadata = innerContributor.contributeMetadata(t);
+ ArrayList splitMetadata = new ArrayList<>();
+ for (MetadatumDTO metadatumDTO : metadata) {
+ String[] split = metadatumDTO.getValue().split(regex);
+ for (String splitItem : split) {
+ MetadatumDTO splitMetadatumDTO = new MetadatumDTO();
+ splitMetadatumDTO.setSchema(metadatumDTO.getSchema());
+ splitMetadatumDTO.setElement(metadatumDTO.getElement());
+ splitMetadatumDTO.setQualifier(metadatumDTO.getQualifier());
+ splitMetadatumDTO.setValue(splitItem);
+ splitMetadata.add(splitMetadatumDTO);
+ }
+ }
+ return splitMetadata;
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataVisits.java b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataVisits.java
index 4ee7a0f3e4..121e66af48 100644
--- a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataVisits.java
+++ b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataVisits.java
@@ -621,6 +621,10 @@ public class StatisticsDataVisits extends StatisticsData {
}
if (dsoId != null && query.dsoType != -1) {
+ // Store the UUID of the DSO as an attribute. Needed in particular for Bitstream download usage reports,
+ // as the Bitstream itself won't be available when converting points to their REST representation
+ attrs.put("id", dsoId);
+
switch (query.dsoType) {
case Constants.BITSTREAM:
Bitstream bit = bitstreamService.findByIdOrLegacyId(context, dsoId);
diff --git a/dspace-api/src/main/java/org/dspace/submit/model/UploadConfiguration.java b/dspace-api/src/main/java/org/dspace/submit/model/UploadConfiguration.java
index bc2f117b3c..a6421b3f7a 100644
--- a/dspace-api/src/main/java/org/dspace/submit/model/UploadConfiguration.java
+++ b/dspace-api/src/main/java/org/dspace/submit/model/UploadConfiguration.java
@@ -8,15 +8,17 @@
package org.dspace.submit.model;
import java.util.List;
+import javax.inject.Inject;
import org.dspace.services.ConfigurationService;
/**
+ * A collection of conditions to be met when uploading Bitstreams.
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
*/
public class UploadConfiguration {
- private ConfigurationService configurationService;
+ private final ConfigurationService configurationService;
private String metadataDefinition;
private List options;
@@ -24,22 +26,52 @@ public class UploadConfiguration {
private Boolean required;
private String name;
+ /**
+ * Construct a bitstream uploading configuration.
+ * @param configurationService DSpace configuration provided by the DI container.
+ */
+ @Inject
+ public UploadConfiguration(ConfigurationService configurationService) {
+ this.configurationService = configurationService;
+ }
+
+ /**
+ * The list of access restriction types from which a submitter may choose.
+ * @return choices for restricting access to Bitstreams.
+ */
public List getOptions() {
return options;
}
+ /**
+ * Set the list of access restriction types from which to choose.
+ * Required. May be empty.
+ * @param options choices for restricting access to Bitstreams.
+ */
public void setOptions(List options) {
this.options = options;
}
+ /**
+ * Name of the submission form to which these conditions are attached.
+ * @return the form's name.
+ */
public String getMetadata() {
return metadataDefinition;
}
+ /**
+ * Name the submission form to which these conditions are attached.
+ * @param metadata the form's name.
+ */
public void setMetadata(String metadata) {
this.metadataDefinition = metadata;
}
+ /**
+ * Limit on the maximum size of an uploaded Bitstream.
+ * @return maximum upload size in bytes.
+ */
public Long getMaxSize() {
if (maxSize == null) {
maxSize = configurationService.getLongProperty("upload.max");
@@ -47,10 +79,18 @@ public class UploadConfiguration {
return maxSize;
}
+ /**
+ * Limit the maximum size of an uploaded Bitstream.
+ * @param maxSize maximum upload size in bytes.
+ */
public void setMaxSize(Long maxSize) {
this.maxSize = maxSize;
}
+ /**
+ * Is at least one Bitstream required when submitting a new Item?
+ * @return true if a Bitstream is required.
+ */
public Boolean isRequired() {
if (required == null) {
//defaults to true
@@ -60,25 +100,27 @@ public class UploadConfiguration {
return required;
}
+ /**
+ * Is at least one Bitstream required when submitting a new Item?
+ * @param required true if a Bitstream is required.
+ */
public void setRequired(Boolean required) {
this.required = required;
}
- public ConfigurationService getConfigurationService() {
- return configurationService;
- }
-
- public void setConfigurationService(ConfigurationService configurationService) {
- this.configurationService = configurationService;
- }
-
+ /**
+ * The unique name of this configuration.
+ * @return configuration's name.
+ */
public String getName() {
return name;
}
+ /**
+ * Give this configuration a unique name. Required.
+ * @param name configuration's name.
+ */
public void setName(String name) {
this.name = name;
}
-
-
}
diff --git a/dspace-api/src/test/data/dspaceFolder/config/spring/api/access-conditions.xml b/dspace-api/src/test/data/dspaceFolder/config/spring/api/access-conditions.xml
index e21a85cca4..450ed3ad0b 100644
--- a/dspace-api/src/test/data/dspaceFolder/config/spring/api/access-conditions.xml
+++ b/dspace-api/src/test/data/dspaceFolder/config/spring/api/access-conditions.xml
@@ -3,10 +3,9 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
-
+
-
-
+
@@ -18,7 +17,7 @@
-
+
@@ -31,7 +30,7 @@
-
+
@@ -43,13 +42,13 @@
-
+
diff --git a/dspace-api/src/test/data/dspaceFolder/config/spring/api/external-openaire.xml b/dspace-api/src/test/data/dspaceFolder/config/spring/api/external-openaire.xml
index e10d04a16f..f1e6c30d13 100644
--- a/dspace-api/src/test/data/dspaceFolder/config/spring/api/external-openaire.xml
+++ b/dspace-api/src/test/data/dspaceFolder/config/spring/api/external-openaire.xml
@@ -1,6 +1,10 @@
-
@@ -15,11 +19,71 @@
init-method="init">
+
Project
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dspace-api/src/test/java/org/dspace/app/requestitem/CollectionAdministratorsRequestItemStrategyTest.java b/dspace-api/src/test/java/org/dspace/app/requestitem/CollectionAdministratorsRequestItemStrategyTest.java
new file mode 100644
index 0000000000..37292e91c8
--- /dev/null
+++ b/dspace-api/src/test/java/org/dspace/app/requestitem/CollectionAdministratorsRequestItemStrategyTest.java
@@ -0,0 +1,62 @@
+/**
+ * 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.requestitem;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.dspace.content.Collection;
+import org.dspace.content.Item;
+import org.dspace.core.Context;
+import org.dspace.eperson.EPerson;
+import org.dspace.eperson.Group;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ *
+ * @author Mark H. Wood
+ */
+public class CollectionAdministratorsRequestItemStrategyTest {
+ private static final String NAME = "John Q. Public";
+ private static final String EMAIL = "jqpublic@example.com";
+
+ /**
+ * Test of getRequestItemAuthor method, of class CollectionAdministratorsRequestItemStrategy.
+ * @throws java.lang.Exception passed through.
+ */
+ @Test
+ public void testGetRequestItemAuthor()
+ throws Exception {
+ System.out.println("getRequestItemAuthor");
+
+ Context context = Mockito.mock(Context.class);
+
+ EPerson eperson1 = Mockito.mock(EPerson.class);
+ Mockito.when(eperson1.getEmail()).thenReturn(EMAIL);
+ Mockito.when(eperson1.getFullName()).thenReturn(NAME);
+
+ Group group1 = Mockito.mock(Group.class);
+ Mockito.when(group1.getMembers()).thenReturn(List.of(eperson1));
+
+ Collection collection1 = Mockito.mock(Collection.class);
+ Mockito.when(collection1.getAdministrators()).thenReturn(group1);
+
+ Item item = Mockito.mock(Item.class);
+ Mockito.when(item.getOwningCollection()).thenReturn(collection1);
+ Mockito.when(item.getSubmitter()).thenReturn(eperson1);
+
+ CollectionAdministratorsRequestItemStrategy instance = new CollectionAdministratorsRequestItemStrategy();
+ List result = instance.getRequestItemAuthor(context,
+ item);
+ assertEquals("Should be one author", 1, result.size());
+ assertEquals("Name should match " + NAME, NAME, result.get(0).getFullName());
+ assertEquals("Email should match " + EMAIL, EMAIL, result.get(0).getEmail());
+ }
+}
diff --git a/dspace-api/src/test/java/org/dspace/app/requestitem/CombiningRequestItemStrategyTest.java b/dspace-api/src/test/java/org/dspace/app/requestitem/CombiningRequestItemStrategyTest.java
new file mode 100644
index 0000000000..c5475612cb
--- /dev/null
+++ b/dspace-api/src/test/java/org/dspace/app/requestitem/CombiningRequestItemStrategyTest.java
@@ -0,0 +1,53 @@
+/**
+ * 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.requestitem;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
+
+import java.util.List;
+
+import org.dspace.content.Item;
+import org.dspace.core.Context;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ *
+ * @author Mark H. Wood
+ */
+public class CombiningRequestItemStrategyTest {
+ /**
+ * Test of getRequestItemAuthor method, of class CombiningRequestItemStrategy.
+ * @throws java.lang.Exception passed through.
+ */
+ @Test
+ public void testGetRequestItemAuthor()
+ throws Exception {
+ System.out.println("getRequestItemAuthor");
+ Context context = null;
+
+ Item item = Mockito.mock(Item.class);
+ RequestItemAuthor author1 = new RequestItemAuthor("Pat Paulsen", "ppaulsen@example.com");
+ RequestItemAuthor author2 = new RequestItemAuthor("Alfred E. Neuman", "aeneuman@example.com");
+ RequestItemAuthor author3 = new RequestItemAuthor("Alias Undercover", "aundercover@example.com");
+
+ RequestItemAuthorExtractor strategy1 = Mockito.mock(RequestItemHelpdeskStrategy.class);
+ Mockito.when(strategy1.getRequestItemAuthor(context, item)).thenReturn(List.of(author1));
+
+ RequestItemAuthorExtractor strategy2 = Mockito.mock(RequestItemMetadataStrategy.class);
+ Mockito.when(strategy2.getRequestItemAuthor(context, item)).thenReturn(List.of(author2, author3));
+
+ List strategies = List.of(strategy1, strategy2);
+
+ CombiningRequestItemStrategy instance = new CombiningRequestItemStrategy(strategies);
+ List result = instance.getRequestItemAuthor(context,
+ item);
+ assertThat(result, containsInAnyOrder(author1, author2, author3));
+ }
+}
diff --git a/dspace-api/src/test/java/org/dspace/ctask/general/CreateMissingIdentifiersIT.java b/dspace-api/src/test/java/org/dspace/ctask/general/CreateMissingIdentifiersIT.java
new file mode 100644
index 0000000000..383f87bbd7
--- /dev/null
+++ b/dspace-api/src/test/java/org/dspace/ctask/general/CreateMissingIdentifiersIT.java
@@ -0,0 +1,79 @@
+/**
+ * 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.ctask.general;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.dspace.AbstractIntegrationTestWithDatabase;
+import org.dspace.builder.CollectionBuilder;
+import org.dspace.builder.CommunityBuilder;
+import org.dspace.builder.ItemBuilder;
+import org.dspace.content.Collection;
+import org.dspace.content.Item;
+import org.dspace.curate.Curator;
+import org.dspace.identifier.VersionedHandleIdentifierProviderWithCanonicalHandles;
+import org.dspace.services.ConfigurationService;
+import org.dspace.services.factory.DSpaceServicesFactory;
+import org.junit.Test;
+
+/**
+ * Rudimentary test of the curation task.
+ *
+ * @author mwood
+ */
+public class CreateMissingIdentifiersIT
+ extends AbstractIntegrationTestWithDatabase {
+ private static final String P_TASK_DEF
+ = "plugin.named.org.dspace.curate.CurationTask";
+ private static final String TASK_NAME = "test";
+
+ @Test
+ public void testPerform()
+ throws IOException {
+ ConfigurationService configurationService
+ = DSpaceServicesFactory.getInstance().getConfigurationService();
+ configurationService.setProperty(P_TASK_DEF, null);
+ configurationService.addPropertyValue(P_TASK_DEF,
+ CreateMissingIdentifiers.class.getCanonicalName() + " = " + TASK_NAME);
+
+ Curator curator = new Curator();
+ curator.addTask(TASK_NAME);
+
+ context.setCurrentUser(admin);
+ parentCommunity = CommunityBuilder.createCommunity(context)
+ .build();
+ Collection collection = CollectionBuilder.createCollection(context, parentCommunity)
+ .build();
+ Item item = ItemBuilder.createItem(context, collection)
+ .build();
+
+ /*
+ * Curate with regular test configuration -- should succeed.
+ */
+ curator.curate(context, item);
+ int status = curator.getStatus(TASK_NAME);
+ assertEquals("Curation should succeed", Curator.CURATE_SUCCESS, status);
+
+ /*
+ * Now install an incompatible provider to make the task fail.
+ */
+ DSpaceServicesFactory.getInstance()
+ .getServiceManager()
+ .registerServiceClass(
+ VersionedHandleIdentifierProviderWithCanonicalHandles.class.getCanonicalName(),
+ VersionedHandleIdentifierProviderWithCanonicalHandles.class);
+
+ curator.curate(context, item);
+ System.out.format("With incompatible provider, result is '%s'.\n",
+ curator.getResult(TASK_NAME));
+ assertEquals("Curation should fail", Curator.CURATE_ERROR,
+ curator.getStatus(TASK_NAME));
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RequestItemRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RequestItemRepository.java
index d013566a2c..82f9ed3318 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RequestItemRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RequestItemRepository.java
@@ -15,7 +15,9 @@ import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.SQLException;
+import java.util.Collections;
import java.util.Date;
+import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
@@ -229,14 +231,20 @@ public class RequestItemRepository
}
// Check for authorized user
- RequestItemAuthor authorizer;
+ List authorizers;
try {
- authorizer = requestItemAuthorExtractor.getRequestItemAuthor(context, ri.getItem());
+ authorizers = requestItemAuthorExtractor.getRequestItemAuthor(context, ri.getItem());
} catch (SQLException ex) {
LOG.warn("Failed to find an authorizer: {}", ex.getMessage());
- authorizer = new RequestItemAuthor("", "");
+ authorizers = Collections.EMPTY_LIST;
}
- if (!authorizer.getEmail().equals(context.getCurrentUser().getEmail())) {
+
+ boolean authorized = false;
+ String requester = context.getCurrentUser().getEmail();
+ for (RequestItemAuthor authorizer : authorizers) {
+ authorized |= authorizer.getEmail().equals(requester);
+ }
+ if (!authorized) {
throw new AuthorizeException("Not authorized to approve this request");
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/UsageReportUtils.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/UsageReportUtils.java
index ca10b9face..4603569da8 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/UsageReportUtils.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/UsageReportUtils.java
@@ -251,7 +251,10 @@ public class UsageReportUtils {
for (int i = 0; i < dataset.getColLabels().size(); i++) {
UsageReportPointDsoTotalVisitsRest totalDownloadsPoint = new UsageReportPointDsoTotalVisitsRest();
totalDownloadsPoint.setType("bitstream");
- totalDownloadsPoint.setId(dataset.getColLabels().get(i));
+
+ totalDownloadsPoint.setId(dataset.getColLabelsAttrs().get(i).get("id"));
+ totalDownloadsPoint.setLabel(dataset.getColLabels().get(i));
+
totalDownloadsPoint.addValue("views", Integer.valueOf(dataset.getMatrix()[0][i]));
usageReportRest.addPoint(totalDownloadsPoint);
}
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/StatisticsRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/StatisticsRestRepositoryIT.java
index 5dd24451c5..5544ecdb03 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/StatisticsRestRepositoryIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/StatisticsRestRepositoryIT.java
@@ -22,13 +22,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.lang3.StringUtils;
import org.dspace.app.rest.matcher.UsageReportMatcher;
import org.dspace.app.rest.model.UsageReportPointCityRest;
import org.dspace.app.rest.model.UsageReportPointCountryRest;
@@ -50,6 +50,7 @@ import org.dspace.builder.SiteBuilder;
import org.dspace.content.Bitstream;
import org.dspace.content.Collection;
import org.dspace.content.Community;
+import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.Site;
import org.dspace.core.Constants;
@@ -281,42 +282,40 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- UsageReportPointDsoTotalVisitsRest expectedPoint = new UsageReportPointDsoTotalVisitsRest();
- expectedPoint.addValue("views", 1);
- expectedPoint.setType("community");
- expectedPoint.setId(communityVisited.getID().toString());
-
// And request that community's TotalVisits stat report
getClient(adminToken).perform(
get("/api/statistics/usagereports/" + communityVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID))
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(communityVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
- TOTAL_VISITS_REPORT_ID, Arrays.asList(expectedPoint))))
- );
+ UsageReportMatcher.matchUsageReport(
+ communityVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ List.of(
+ getExpectedDsoViews(communityVisited, 1)
+ )
+ )
+ )));
}
@Test
public void totalVisitsReport_Community_NotVisited() throws Exception {
// ** WHEN **
// Community is never visited
- UsageReportPointDsoTotalVisitsRest expectedPoint = new UsageReportPointDsoTotalVisitsRest();
- expectedPoint.addValue("views", 0);
- expectedPoint.setType("community");
- expectedPoint.setId(communityNotVisited.getID().toString());
-
// And request that community's TotalVisits stat report
getClient(adminToken).perform(
get("/api/statistics/usagereports/" + communityNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID))
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(communityNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
- TOTAL_VISITS_REPORT_ID, Arrays.asList(expectedPoint))))
- );
+ UsageReportMatcher.matchUsageReport(
+ communityNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ List.of(
+ getExpectedDsoViews(communityNotVisited, 0)
+ )
+ )
+ )));
}
@Test
@@ -339,42 +338,40 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- UsageReportPointDsoTotalVisitsRest expectedPoint = new UsageReportPointDsoTotalVisitsRest();
- expectedPoint.addValue("views", 2);
- expectedPoint.setType("collection");
- expectedPoint.setId(collectionVisited.getID().toString());
-
// And request that collection's TotalVisits stat report
getClient(adminToken).perform(
get("/api/statistics/usagereports/" + collectionVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID))
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(collectionVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
- TOTAL_VISITS_REPORT_ID, Arrays.asList(expectedPoint))))
- );
+ UsageReportMatcher.matchUsageReport(
+ collectionVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ List.of(
+ getExpectedDsoViews(collectionVisited, 2)
+ )
+ )
+ )));
}
@Test
public void totalVisitsReport_Collection_NotVisited() throws Exception {
// ** WHEN **
// Collection is never visited
- UsageReportPointDsoTotalVisitsRest expectedPoint = new UsageReportPointDsoTotalVisitsRest();
- expectedPoint.addValue("views", 0);
- expectedPoint.setType("collection");
- expectedPoint.setId(collectionNotVisited.getID().toString());
-
// And request that collection's TotalVisits stat report
getClient(adminToken).perform(
get("/api/statistics/usagereports/" + collectionNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID))
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(collectionNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
- TOTAL_VISITS_REPORT_ID, Arrays.asList(expectedPoint))))
- );
+ UsageReportMatcher.matchUsageReport(
+ collectionNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ List.of(
+ getExpectedDsoViews(collectionNotVisited, 0)
+ )
+ )
+ )));
}
@Test
@@ -392,42 +389,42 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- UsageReportPointDsoTotalVisitsRest expectedPoint = new UsageReportPointDsoTotalVisitsRest();
- expectedPoint.addValue("views", 1);
- expectedPoint.setType("item");
- expectedPoint.setId(itemVisited.getID().toString());
-
// And request that collection's TotalVisits stat report
getClient(adminToken).perform(
get("/api/statistics/usagereports/" + itemVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID))
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(itemVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
- TOTAL_VISITS_REPORT_ID, Arrays.asList(expectedPoint))))
- );
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ List.of(
+ getExpectedDsoViews(itemVisited, 1)
+ )
+ )
+ )));
}
@Test
public void totalVisitsReport_Item_NotVisited() throws Exception {
// ** WHEN **
//Item is never visited
- UsageReportPointDsoTotalVisitsRest expectedPoint = new UsageReportPointDsoTotalVisitsRest();
- expectedPoint.addValue("views", 0);
- expectedPoint.setType("item");
- expectedPoint.setId(itemNotVisitedWithBitstreams.getID().toString());
+ List expectedPoints = List.of(
+ getExpectedDsoViews(itemNotVisitedWithBitstreams, 0)
+ );
// And request that item's TotalVisits stat report
getClient(adminToken).perform(
get("/api/statistics/usagereports/" + itemNotVisitedWithBitstreams.getID() + "_" + TOTAL_VISITS_REPORT_ID))
// ** THEN **
.andExpect(status().isOk())
- .andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(itemNotVisitedWithBitstreams.getID() + "_" + TOTAL_VISITS_REPORT_ID,
- TOTAL_VISITS_REPORT_ID, Arrays.asList(expectedPoint))))
- );
+ .andExpect(jsonPath("$", Matchers.is(
+ UsageReportMatcher.matchUsageReport(
+ itemNotVisitedWithBitstreams.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ expectedPoints
+ )
+ )));
// only admin access visits report
getClient(loggedInToken).perform(
@@ -445,19 +442,25 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
get("/api/statistics/usagereports/"
+ itemNotVisitedWithBitstreams.getID() + "_" + TOTAL_VISITS_REPORT_ID))
.andExpect(status().isOk())
- .andExpect(jsonPath("$",
- Matchers.is(UsageReportMatcher.matchUsageReport(
- itemNotVisitedWithBitstreams.getID() + "_" + TOTAL_VISITS_REPORT_ID,
- TOTAL_VISITS_REPORT_ID, Arrays.asList(expectedPoint)))));
+ .andExpect(jsonPath("$", Matchers.is(
+ UsageReportMatcher.matchUsageReport(
+ itemNotVisitedWithBitstreams.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ expectedPoints
+ )
+ )));
- getClient().perform(
+ getClient().perform(
get("/api/statistics/usagereports/"
+ itemNotVisitedWithBitstreams.getID() + "_" + TOTAL_VISITS_REPORT_ID))
.andExpect(status().isOk())
- .andExpect(jsonPath("$",
- Matchers.is(UsageReportMatcher.matchUsageReport(
- itemNotVisitedWithBitstreams.getID() + "_" + TOTAL_VISITS_REPORT_ID,
- TOTAL_VISITS_REPORT_ID, Arrays.asList(expectedPoint)))));
+ .andExpect(jsonPath("$", Matchers.is(
+ UsageReportMatcher.matchUsageReport(
+ itemNotVisitedWithBitstreams.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ expectedPoints
+ )
+ )));
}
@Test
@@ -475,10 +478,9 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- UsageReportPointDsoTotalVisitsRest expectedPoint = new UsageReportPointDsoTotalVisitsRest();
- expectedPoint.addValue("views", 1);
- expectedPoint.setType("bitstream");
- expectedPoint.setId(bitstreamVisited.getID().toString());
+ List expectedPoints = List.of(
+ getExpectedDsoViews(bitstreamVisited, 1)
+ );
// And request that bitstream's TotalVisits stat report
getClient(adminToken).perform(
@@ -486,10 +488,12 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(bitstreamVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
- TOTAL_VISITS_REPORT_ID, Arrays.asList(expectedPoint))))
- );
+ UsageReportMatcher.matchUsageReport(
+ bitstreamVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ expectedPoints
+ )
+ )));
// only admin access visits report
getClient(loggedInToken).perform(
@@ -506,28 +510,34 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
getClient(loggedInToken).perform(
get("/api/statistics/usagereports/" + bitstreamVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID))
.andExpect(status().isOk())
- .andExpect(jsonPath("$",
- Matchers.is(UsageReportMatcher.matchUsageReport(
- bitstreamVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID, TOTAL_VISITS_REPORT_ID,
- Arrays.asList(expectedPoint)))));
+ .andExpect(jsonPath("$", Matchers.is(
+ UsageReportMatcher.matchUsageReport(
+ bitstreamVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ expectedPoints
+ )
+ )));
getClient().perform(
get("/api/statistics/usagereports/" + bitstreamVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID))
.andExpect(status().isOk())
- .andExpect(jsonPath("$",
- Matchers.is(UsageReportMatcher.matchUsageReport(
- bitstreamVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID, TOTAL_VISITS_REPORT_ID,
- Arrays.asList(expectedPoint)))));
+ .andExpect(jsonPath("$", Matchers.is(
+ UsageReportMatcher.matchUsageReport(
+ bitstreamVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ expectedPoints
+ )
+ )));
}
@Test
public void totalVisitsReport_Bitstream_NotVisited() throws Exception {
// ** WHEN **
// Bitstream is never visited
- UsageReportPointDsoTotalVisitsRest expectedPoint = new UsageReportPointDsoTotalVisitsRest();
- expectedPoint.addValue("views", 0);
- expectedPoint.setType("bitstream");
- expectedPoint.setId(bitstreamNotVisited.getID().toString());
+
+ List expectedPoints = List.of(
+ getExpectedDsoViews(bitstreamNotVisited, 0)
+ );
String authToken = getAuthToken(admin.getEmail(), password);
// And request that bitstream's TotalVisits stat report
@@ -536,10 +546,12 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(bitstreamNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
- TOTAL_VISITS_REPORT_ID, Arrays.asList(expectedPoint))))
- );
+ UsageReportMatcher.matchUsageReport(
+ bitstreamNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ expectedPoints
+ )
+ )));
String tokenEPerson = getAuthToken(eperson.getEmail(), password);
getClient(tokenEPerson).perform(
@@ -556,18 +568,24 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
getClient(tokenEPerson).perform(
get("/api/statistics/usagereports/" + bitstreamNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID))
.andExpect(status().isOk())
- .andExpect(jsonPath("$",
- Matchers.is(UsageReportMatcher.matchUsageReport(
- bitstreamNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID, TOTAL_VISITS_REPORT_ID,
- Arrays.asList(expectedPoint)))));
+ .andExpect(jsonPath("$", Matchers.is(
+ UsageReportMatcher.matchUsageReport(
+ bitstreamNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ expectedPoints
+ )
+ )));
getClient().perform(
get("/api/statistics/usagereports/" + bitstreamNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID))
.andExpect(status().isOk())
- .andExpect(jsonPath("$",
- Matchers.is(UsageReportMatcher.matchUsageReport(
- bitstreamNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID, TOTAL_VISITS_REPORT_ID,
- Arrays.asList(expectedPoint)))));
+ .andExpect(jsonPath("$", Matchers.is(
+ UsageReportMatcher.matchUsageReport(
+ bitstreamNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ expectedPoints
+ )
+ )));
}
@Test
@@ -593,9 +611,12 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(itemVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
- TOTAL_VISITS_PER_MONTH_REPORT_ID, expectedPoints))));
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
+ TOTAL_VISITS_PER_MONTH_REPORT_ID,
+ expectedPoints
+ )
+ )));
// only admin has access
getClient(loggedInToken).perform(
@@ -612,26 +633,30 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
getClient(loggedInToken).perform(
get("/api/statistics/usagereports/" + itemVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID))
.andExpect(status().isOk())
- .andExpect(jsonPath("$",
- Matchers.is(UsageReportMatcher.matchUsageReport(
- itemVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
- TOTAL_VISITS_PER_MONTH_REPORT_ID, expectedPoints))));
+ .andExpect(jsonPath("$", Matchers.is(
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
+ TOTAL_VISITS_PER_MONTH_REPORT_ID,
+ expectedPoints
+ )
+ )));
getClient().perform(
get("/api/statistics/usagereports/" + itemVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID))
.andExpect(status().isOk())
- .andExpect(jsonPath("$",
- Matchers.is(UsageReportMatcher.matchUsageReport(
- itemVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
- TOTAL_VISITS_PER_MONTH_REPORT_ID, expectedPoints))));
+ .andExpect(jsonPath("$", Matchers.is(
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
+ TOTAL_VISITS_PER_MONTH_REPORT_ID,
+ expectedPoints
+ )
+ )));
}
@Test
public void totalVisitsPerMonthReport_Item_NotVisited() throws Exception {
// ** WHEN **
// Item is not visited
- List expectedPoints = this.getListOfVisitsPerMonthsPoints(0);
-
// And request that item's TotalVisitsPerMonth stat report
getClient(adminToken).perform(
get("/api/statistics/usagereports/" + itemNotVisitedWithBitstreams.getID() + "_" +
@@ -639,10 +664,12 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(
+ UsageReportMatcher.matchUsageReport(
itemNotVisitedWithBitstreams.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
- TOTAL_VISITS_PER_MONTH_REPORT_ID, expectedPoints))));
+ TOTAL_VISITS_PER_MONTH_REPORT_ID,
+ this.getListOfVisitsPerMonthsPoints(0)
+ )
+ )));
}
@Test
@@ -665,17 +692,18 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- List expectedPoints = this.getListOfVisitsPerMonthsPoints(2);
-
// And request that collection's TotalVisitsPerMonth stat report
getClient(adminToken).perform(
get("/api/statistics/usagereports/" + collectionVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID))
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(collectionVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
- TOTAL_VISITS_PER_MONTH_REPORT_ID, expectedPoints))));
+ UsageReportMatcher.matchUsageReport(
+ collectionVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
+ TOTAL_VISITS_PER_MONTH_REPORT_ID,
+ this.getListOfVisitsPerMonthsPoints(2)
+ )
+ )));
}
@Test
@@ -693,10 +721,9 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- UsageReportPointDsoTotalVisitsRest expectedPoint = new UsageReportPointDsoTotalVisitsRest();
- expectedPoint.addValue("views", 1);
- expectedPoint.setType("bitstream");
- expectedPoint.setId(bitstreamVisited.getID().toString());
+ List expectedPoints = List.of(
+ getExpectedDsoViews(bitstreamVisited, 1)
+ );
// And request that bitstreams's TotalDownloads stat report
getClient(adminToken).perform(
@@ -704,9 +731,12 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(bitstreamVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID,
- TOTAL_DOWNLOADS_REPORT_ID, Arrays.asList(expectedPoint)))));
+ UsageReportMatcher.matchUsageReport(
+ bitstreamVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID,
+ TOTAL_DOWNLOADS_REPORT_ID,
+ expectedPoints
+ )
+ )));
// only admin has access to downloads report
getClient(loggedInToken).perform(
@@ -723,18 +753,24 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
getClient(loggedInToken).perform(
get("/api/statistics/usagereports/" + bitstreamVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID))
.andExpect(status().isOk())
- .andExpect(jsonPath("$",
- Matchers.is(UsageReportMatcher.matchUsageReport(
- bitstreamVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID, TOTAL_DOWNLOADS_REPORT_ID,
- Arrays.asList(expectedPoint)))));
+ .andExpect(jsonPath("$", Matchers.is(
+ UsageReportMatcher.matchUsageReport(
+ bitstreamVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID,
+ TOTAL_DOWNLOADS_REPORT_ID,
+ expectedPoints
+ )
+ )));
getClient().perform(
get("/api/statistics/usagereports/" + bitstreamVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID))
.andExpect(status().isOk())
- .andExpect(jsonPath("$",
- Matchers.is(UsageReportMatcher.matchUsageReport(
- bitstreamVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID, TOTAL_DOWNLOADS_REPORT_ID,
- Arrays.asList(expectedPoint)))));
+ .andExpect(jsonPath("$", Matchers.is(
+ UsageReportMatcher.matchUsageReport(
+ bitstreamVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID,
+ TOTAL_DOWNLOADS_REPORT_ID,
+ expectedPoints
+ )
+ )));
}
@Test
@@ -752,11 +788,6 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- UsageReportPointDsoTotalVisitsRest expectedPoint = new UsageReportPointDsoTotalVisitsRest();
- expectedPoint.addValue("views", 1);
- expectedPoint.setId("BitstreamVisitedName");
- expectedPoint.setType("bitstream");
-
// And request that item's TotalDownloads stat report
getClient(adminToken).perform(
get("/api/statistics/usagereports/" + itemNotVisitedWithBitstreams.getID() + "_" +
@@ -764,9 +795,14 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(itemNotVisitedWithBitstreams.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID,
- TOTAL_DOWNLOADS_REPORT_ID, Arrays.asList(expectedPoint)))));
+ UsageReportMatcher.matchUsageReport(
+ itemNotVisitedWithBitstreams.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID,
+ TOTAL_DOWNLOADS_REPORT_ID,
+ List.of(
+ getExpectedDsoViews(bitstreamVisited, 1)
+ )
+ )
+ )));
}
@Test
@@ -780,9 +816,12 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(itemNotVisitedWithBitstreams.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID,
- TOTAL_DOWNLOADS_REPORT_ID, new ArrayList<>()))));
+ UsageReportMatcher.matchUsageReport(
+ itemNotVisitedWithBitstreams.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID,
+ TOTAL_DOWNLOADS_REPORT_ID,
+ List.of()
+ )
+ )));
}
@Test
@@ -810,10 +849,9 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- UsageReportPointCountryRest expectedPoint = new UsageReportPointCountryRest();
- expectedPoint.addValue("views", 1);
- expectedPoint.setId("US");
- expectedPoint.setLabel("United States");
+ List expectedPoints = List.of(
+ getExpectedCountryViews("US", "United States", 1)
+ );
// And request that collection's TopCountries report
getClient(adminToken).perform(
@@ -821,9 +859,12 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(collectionVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
- TOP_COUNTRIES_REPORT_ID, Arrays.asList(expectedPoint)))));
+ UsageReportMatcher.matchUsageReport(
+ collectionVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
+ TOP_COUNTRIES_REPORT_ID,
+ expectedPoints
+ )
+ )));
// only admin has access to countries report
getClient(loggedInToken).perform(
@@ -840,18 +881,24 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
getClient(loggedInToken).perform(
get("/api/statistics/usagereports/" + collectionVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID))
.andExpect(status().isOk())
- .andExpect(jsonPath("$",
- Matchers.is(UsageReportMatcher.matchUsageReport(
- collectionVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID, TOP_COUNTRIES_REPORT_ID,
- Arrays.asList(expectedPoint)))));
+ .andExpect(jsonPath("$", Matchers.is(
+ UsageReportMatcher.matchUsageReport(
+ collectionVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
+ TOP_COUNTRIES_REPORT_ID,
+ expectedPoints
+ )
+ )));
getClient().perform(
get("/api/statistics/usagereports/" + collectionVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID))
.andExpect(status().isOk())
- .andExpect(jsonPath("$",
- Matchers.is(UsageReportMatcher.matchUsageReport(
- collectionVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID, TOP_COUNTRIES_REPORT_ID,
- Arrays.asList(expectedPoint)))));
+ .andExpect(jsonPath("$", Matchers.is(
+ UsageReportMatcher.matchUsageReport(
+ collectionVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
+ TOP_COUNTRIES_REPORT_ID,
+ expectedPoints
+ )
+ )));
}
/**
@@ -877,20 +924,20 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- UsageReportPointCountryRest expectedPoint = new UsageReportPointCountryRest();
- expectedPoint.addValue("views", 2);
- expectedPoint.setId("US");
- expectedPoint.setLabel("United States");
-
// And request that collection's TopCountries report
getClient(adminToken).perform(
get("/api/statistics/usagereports/" + communityVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID))
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(communityVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
- TOP_COUNTRIES_REPORT_ID, Arrays.asList(expectedPoint)))));
+ UsageReportMatcher.matchUsageReport(
+ communityVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
+ TOP_COUNTRIES_REPORT_ID,
+ List.of(
+ getExpectedCountryViews("US", "United States", 2)
+ )
+ )
+ )));
}
/**
@@ -906,9 +953,12 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(itemNotVisitedWithBitstreams.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
- TOP_COUNTRIES_REPORT_ID, new ArrayList<>()))));
+ UsageReportMatcher.matchUsageReport(
+ itemNotVisitedWithBitstreams.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
+ TOP_COUNTRIES_REPORT_ID,
+ List.of()
+ )
+ )));
}
/**
@@ -929,9 +979,9 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- UsageReportPointCityRest expectedPoint = new UsageReportPointCityRest();
- expectedPoint.addValue("views", 1);
- expectedPoint.setId("New York");
+ List expectedPoints = List.of(
+ getExpectedCityViews("New York", 1)
+ );
// And request that item's TopCities report
getClient(adminToken).perform(
@@ -939,9 +989,12 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(itemVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
- TOP_CITIES_REPORT_ID, Arrays.asList(expectedPoint)))));
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
+ TOP_CITIES_REPORT_ID,
+ expectedPoints
+ )
+ )));
// only admin has access to cities report
getClient(loggedInToken).perform(
@@ -958,18 +1011,24 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
getClient(loggedInToken).perform(
get("/api/statistics/usagereports/" + itemVisited.getID() + "_" + TOP_CITIES_REPORT_ID))
.andExpect(status().isOk())
- .andExpect(jsonPath("$",
- Matchers.is(
- UsageReportMatcher.matchUsageReport(itemVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
- TOP_CITIES_REPORT_ID, Arrays.asList(expectedPoint)))));
+ .andExpect(jsonPath("$", Matchers.is(
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
+ TOP_CITIES_REPORT_ID,
+ expectedPoints
+ )
+ )));
getClient().perform(
get("/api/statistics/usagereports/" + itemVisited.getID() + "_" + TOP_CITIES_REPORT_ID))
.andExpect(status().isOk())
- .andExpect(jsonPath("$",
- Matchers.is(
- UsageReportMatcher.matchUsageReport(itemVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
- TOP_CITIES_REPORT_ID, Arrays.asList(expectedPoint)))));
+ .andExpect(jsonPath("$", Matchers.is(
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
+ TOP_CITIES_REPORT_ID,
+ expectedPoints
+ )
+ )));
}
/**
@@ -1000,19 +1059,20 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- UsageReportPointCityRest expectedPoint = new UsageReportPointCityRest();
- expectedPoint.addValue("views", 3);
- expectedPoint.setId("New York");
-
// And request that community's TopCities report
getClient(adminToken).perform(
get("/api/statistics/usagereports/" + communityVisited.getID() + "_" + TOP_CITIES_REPORT_ID))
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(communityVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
- TOP_CITIES_REPORT_ID, Arrays.asList(expectedPoint)))));
+ UsageReportMatcher.matchUsageReport(
+ communityVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
+ TOP_CITIES_REPORT_ID,
+ List.of(
+ getExpectedCityViews("New York", 3)
+ )
+ )
+ )));
}
/**
@@ -1028,9 +1088,12 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
// ** THEN **
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(
- UsageReportMatcher
- .matchUsageReport(collectionNotVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
- TOP_CITIES_REPORT_ID, new ArrayList<>()))));
+ UsageReportMatcher.matchUsageReport(
+ collectionNotVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
+ TOP_CITIES_REPORT_ID,
+ List.of()
+ )
+ )));
}
@Test
@@ -1155,18 +1218,6 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- List points = new ArrayList<>();
- UsageReportPointDsoTotalVisitsRest expectedPoint1 = new UsageReportPointDsoTotalVisitsRest();
- expectedPoint1.addValue("views", 1);
- expectedPoint1.setType("item");
- expectedPoint1.setId(itemVisited.getID().toString());
- UsageReportPointDsoTotalVisitsRest expectedPoint2 = new UsageReportPointDsoTotalVisitsRest();
- expectedPoint2.addValue("views", 2);
- expectedPoint2.setType("item");
- expectedPoint2.setId(itemVisited2.getID().toString());
- points.add(expectedPoint1);
- points.add(expectedPoint2);
-
// And request the sites global usage report (show top most popular items)
getClient(adminToken)
.perform(get("/api/statistics/usagereports/search/object?uri=http://localhost:8080/server/api/core" +
@@ -1175,8 +1226,15 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.usagereports", not(empty())))
.andExpect(jsonPath("$._embedded.usagereports", Matchers.containsInAnyOrder(
- UsageReportMatcher
- .matchUsageReport(site.getID() + "_" + TOTAL_VISITS_REPORT_ID, TOTAL_VISITS_REPORT_ID, points))));
+ UsageReportMatcher.matchUsageReport(
+ site.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ List.of(
+ getExpectedDsoViews(itemVisited, 1),
+ getExpectedDsoViews(itemVisited2, 2)
+ )
+ )
+ )));
}
@Test
@@ -1194,20 +1252,6 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- UsageReportPointDsoTotalVisitsRest expectedPointTotalVisits = new UsageReportPointDsoTotalVisitsRest();
- expectedPointTotalVisits.addValue("views", 1);
- expectedPointTotalVisits.setType("community");
- expectedPointTotalVisits.setId(communityVisited.getID().toString());
-
- UsageReportPointCityRest expectedPointCity = new UsageReportPointCityRest();
- expectedPointCity.addValue("views", 1);
- expectedPointCity.setId("New York");
-
- UsageReportPointCountryRest expectedPointCountry = new UsageReportPointCountryRest();
- expectedPointCountry.addValue("views", 1);
- expectedPointCountry.setId("US");
- expectedPointCountry.setLabel("United States");
-
// And request the community usage reports
getClient(adminToken)
.perform(get("/api/statistics/usagereports/search/object?uri=http://localhost:8080/server/api/core" +
@@ -1216,27 +1260,39 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.usagereports", not(empty())))
.andExpect(jsonPath("$._embedded.usagereports", Matchers.containsInAnyOrder(
- UsageReportMatcher
- .matchUsageReport(communityVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID, TOTAL_VISITS_REPORT_ID,
- Arrays.asList(expectedPointTotalVisits)),
- UsageReportMatcher.matchUsageReport(communityVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
+ UsageReportMatcher.matchUsageReport(
+ communityVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ List.of(
+ getExpectedDsoViews(communityVisited, 1)
+ )
+ ),
+ UsageReportMatcher.matchUsageReport(
+ communityVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
TOTAL_VISITS_PER_MONTH_REPORT_ID,
- this.getListOfVisitsPerMonthsPoints(1)),
- UsageReportMatcher.matchUsageReport(communityVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
- TOP_CITIES_REPORT_ID, Arrays.asList(expectedPointCity)),
- UsageReportMatcher.matchUsageReport(communityVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
- TOP_COUNTRIES_REPORT_ID, Arrays.asList(expectedPointCountry))
- )));
+ this.getListOfVisitsPerMonthsPoints(1)
+ ),
+ UsageReportMatcher.matchUsageReport(
+ communityVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
+ TOP_CITIES_REPORT_ID,
+ List.of(
+ getExpectedCityViews("New York", 1)
+ )
+ ),
+ UsageReportMatcher.matchUsageReport(
+ communityVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
+ TOP_COUNTRIES_REPORT_ID,
+ List.of(
+ getExpectedCountryViews("US", "United States", 1)
+ )
+ )
+ )));
}
@Test
public void usageReportsSearch_Collection_NotVisited() throws Exception {
// ** WHEN **
// Collection is not visited
- UsageReportPointDsoTotalVisitsRest expectedPointTotalVisits = new UsageReportPointDsoTotalVisitsRest();
- expectedPointTotalVisits.addValue("views", 0);
- expectedPointTotalVisits.setType("collection");
- expectedPointTotalVisits.setId(collectionNotVisited.getID().toString());
// And request the collection's usage reports
getClient(adminToken)
.perform(get("/api/statistics/usagereports/search/object?uri=http://localhost:8080/server/api/core" +
@@ -1245,18 +1301,29 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.usagereports", not(empty())))
.andExpect(jsonPath("$._embedded.usagereports", Matchers.containsInAnyOrder(
- UsageReportMatcher
- .matchUsageReport(collectionNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
- TOTAL_VISITS_REPORT_ID,
- Arrays.asList(expectedPointTotalVisits)),
- UsageReportMatcher
- .matchUsageReport(collectionNotVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
- TOTAL_VISITS_PER_MONTH_REPORT_ID,
- this.getListOfVisitsPerMonthsPoints(0)),
- UsageReportMatcher.matchUsageReport(collectionNotVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
- TOP_CITIES_REPORT_ID, new ArrayList<>()),
- UsageReportMatcher.matchUsageReport(collectionNotVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
- TOP_COUNTRIES_REPORT_ID, new ArrayList<>()))));
+ UsageReportMatcher.matchUsageReport(
+ collectionNotVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ List.of(
+ getExpectedDsoViews(collectionNotVisited, 0)
+ )
+ ),
+ UsageReportMatcher.matchUsageReport(
+ collectionNotVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
+ TOTAL_VISITS_PER_MONTH_REPORT_ID,
+ this.getListOfVisitsPerMonthsPoints(0)
+ ),
+ UsageReportMatcher.matchUsageReport(
+ collectionNotVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
+ TOP_CITIES_REPORT_ID,
+ List.of()
+ ),
+ UsageReportMatcher.matchUsageReport(
+ collectionNotVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
+ TOP_COUNTRIES_REPORT_ID,
+ List.of()
+ )
+ )));
}
@Test
@@ -1274,20 +1341,6 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- UsageReportPointDsoTotalVisitsRest expectedPointTotalVisits = new UsageReportPointDsoTotalVisitsRest();
- expectedPointTotalVisits.addValue("views", 1);
- expectedPointTotalVisits.setType("item");
- expectedPointTotalVisits.setId(itemVisited.getID().toString());
-
- UsageReportPointCityRest expectedPointCity = new UsageReportPointCityRest();
- expectedPointCity.addValue("views", 1);
- expectedPointCity.setId("New York");
-
- UsageReportPointCountryRest expectedPointCountry = new UsageReportPointCountryRest();
- expectedPointCountry.addValue("views", 1);
- expectedPointCountry.setId("US");
- expectedPointCountry.setLabel("United States");
-
// And request the community usage reports
getClient(adminToken)
.perform(get("/api/statistics/usagereports/search/object?uri=http://localhost:8080/server/api/core" +
@@ -1296,18 +1349,38 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.usagereports", not(empty())))
.andExpect(jsonPath("$._embedded.usagereports", Matchers.containsInAnyOrder(
- UsageReportMatcher
- .matchUsageReport(itemVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID, TOTAL_VISITS_REPORT_ID,
- Arrays.asList(expectedPointTotalVisits)),
- UsageReportMatcher.matchUsageReport(itemVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ List.of(
+ getExpectedDsoViews(itemVisited, 1)
+ )
+ ),
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
TOTAL_VISITS_PER_MONTH_REPORT_ID,
- this.getListOfVisitsPerMonthsPoints(1)),
- UsageReportMatcher.matchUsageReport(itemVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
- TOP_CITIES_REPORT_ID, Arrays.asList(expectedPointCity)),
- UsageReportMatcher.matchUsageReport(itemVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
- TOP_COUNTRIES_REPORT_ID, Arrays.asList(expectedPointCountry)),
- UsageReportMatcher.matchUsageReport(itemVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID,
- TOTAL_DOWNLOADS_REPORT_ID, new ArrayList<>()))));
+ this.getListOfVisitsPerMonthsPoints(1)
+ ),
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
+ TOP_CITIES_REPORT_ID,
+ List.of(
+ getExpectedCityViews("New York", 1)
+ )
+ ),
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
+ TOP_COUNTRIES_REPORT_ID,
+ List.of(
+ getExpectedCountryViews("US", "United States", 1)
+ )
+ ),
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID,
+ TOTAL_DOWNLOADS_REPORT_ID,
+ List.of()
+ )
+ )));
}
@Test
@@ -1355,32 +1428,6 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- UsageReportPointDsoTotalVisitsRest expectedPointTotalVisits = new UsageReportPointDsoTotalVisitsRest();
- expectedPointTotalVisits.addValue("views", 1);
- expectedPointTotalVisits.setType("item");
- expectedPointTotalVisits.setId(itemVisited.getID().toString());
-
- UsageReportPointCityRest expectedPointCity = new UsageReportPointCityRest();
- expectedPointCity.addValue("views", 1);
- expectedPointCity.setId("New York");
-
- UsageReportPointCountryRest expectedPointCountry = new UsageReportPointCountryRest();
- expectedPointCountry.addValue("views", 1);
- expectedPointCountry.setId("US");
- expectedPointCountry.setLabel("United States");
-
- List totalDownloadsPoints = new ArrayList<>();
- UsageReportPointDsoTotalVisitsRest expectedPointTotalVisitsBit1 = new UsageReportPointDsoTotalVisitsRest();
- expectedPointTotalVisitsBit1.addValue("views", 1);
- expectedPointTotalVisitsBit1.setId("bitstream1");
- expectedPointTotalVisitsBit1.setType("bitstream");
- UsageReportPointDsoTotalVisitsRest expectedPointTotalVisitsBit2 = new UsageReportPointDsoTotalVisitsRest();
- expectedPointTotalVisitsBit2.addValue("views", 2);
- expectedPointTotalVisitsBit2.setId("bitstream2");
- expectedPointTotalVisitsBit2.setType("bitstream");
- totalDownloadsPoints.add(expectedPointTotalVisitsBit1);
- totalDownloadsPoints.add(expectedPointTotalVisitsBit2);
-
// And request the community usage reports
getClient(adminToken)
.perform(get("/api/statistics/usagereports/search/object?uri=http://localhost:8080/server/api/core" +
@@ -1389,18 +1436,41 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.usagereports", not(empty())))
.andExpect(jsonPath("$._embedded.usagereports", Matchers.containsInAnyOrder(
- UsageReportMatcher
- .matchUsageReport(itemVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID, TOTAL_VISITS_REPORT_ID,
- Arrays.asList(expectedPointTotalVisits)),
- UsageReportMatcher.matchUsageReport(itemVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ List.of(
+ getExpectedDsoViews(itemVisited, 1)
+ )
+ ),
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
TOTAL_VISITS_PER_MONTH_REPORT_ID,
- this.getListOfVisitsPerMonthsPoints(1)),
- UsageReportMatcher.matchUsageReport(itemVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
- TOP_CITIES_REPORT_ID, Arrays.asList(expectedPointCity)),
- UsageReportMatcher.matchUsageReport(itemVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
- TOP_COUNTRIES_REPORT_ID, Arrays.asList(expectedPointCountry)),
- UsageReportMatcher.matchUsageReport(itemVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID,
- TOTAL_DOWNLOADS_REPORT_ID, totalDownloadsPoints))));
+ getListOfVisitsPerMonthsPoints(1)
+ ),
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
+ TOP_CITIES_REPORT_ID,
+ List.of(
+ getExpectedCityViews("New York", 1)
+ )
+ ),
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
+ TOP_COUNTRIES_REPORT_ID,
+ List.of(
+ getExpectedCountryViews("US", "United States", 1)
+ )
+ ),
+ UsageReportMatcher.matchUsageReport(
+ itemVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID,
+ TOTAL_DOWNLOADS_REPORT_ID,
+ List.of(
+ getExpectedDsoViews(bitstream1, 1),
+ getExpectedDsoViews(bitstream2, 2)
+ )
+ )
+ )));
}
@Test
@@ -1418,20 +1488,9 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.contentType(contentType))
.andExpect(status().isCreated());
- UsageReportPointDsoTotalVisitsRest expectedPointTotalVisits = new UsageReportPointDsoTotalVisitsRest();
- expectedPointTotalVisits.addValue("views", 1);
- expectedPointTotalVisits.setType("bitstream");
- expectedPointTotalVisits.setLabel("BitstreamVisitedName");
- expectedPointTotalVisits.setId(bitstreamVisited.getID().toString());
-
- UsageReportPointCityRest expectedPointCity = new UsageReportPointCityRest();
- expectedPointCity.addValue("views", 1);
- expectedPointCity.setId("New York");
-
- UsageReportPointCountryRest expectedPointCountry = new UsageReportPointCountryRest();
- expectedPointCountry.addValue("views", 1);
- expectedPointCountry.setId("US");
- expectedPointCountry.setLabel("United States");
+ List expectedTotalVisits = List.of(
+ getExpectedDsoViews(bitstreamVisited, 1)
+ );
// And request the community usage reports
getClient(adminToken)
@@ -1441,18 +1500,36 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.usagereports", not(empty())))
.andExpect(jsonPath("$._embedded.usagereports", Matchers.containsInAnyOrder(
- UsageReportMatcher
- .matchUsageReport(bitstreamVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID, TOTAL_VISITS_REPORT_ID,
- Arrays.asList(expectedPointTotalVisits)),
- UsageReportMatcher.matchUsageReport(bitstreamVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
+ UsageReportMatcher.matchUsageReport(
+ bitstreamVisited.getID() + "_" + TOTAL_VISITS_REPORT_ID,
+ TOTAL_VISITS_REPORT_ID,
+ expectedTotalVisits
+ ),
+ UsageReportMatcher.matchUsageReport(
+ bitstreamVisited.getID() + "_" + TOTAL_VISITS_PER_MONTH_REPORT_ID,
TOTAL_VISITS_PER_MONTH_REPORT_ID,
- this.getListOfVisitsPerMonthsPoints(1)),
- UsageReportMatcher.matchUsageReport(bitstreamVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
- TOP_CITIES_REPORT_ID, Arrays.asList(expectedPointCity)),
- UsageReportMatcher.matchUsageReport(bitstreamVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
- TOP_COUNTRIES_REPORT_ID, Arrays.asList(expectedPointCountry)),
- UsageReportMatcher.matchUsageReport(bitstreamVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID,
- TOTAL_DOWNLOADS_REPORT_ID, Arrays.asList(expectedPointTotalVisits)))));
+ this.getListOfVisitsPerMonthsPoints(1)
+ ),
+ UsageReportMatcher.matchUsageReport(
+ bitstreamVisited.getID() + "_" + TOP_CITIES_REPORT_ID,
+ TOP_CITIES_REPORT_ID,
+ List.of(
+ getExpectedCityViews("New York", 1)
+ )
+ ),
+ UsageReportMatcher.matchUsageReport(
+ bitstreamVisited.getID() + "_" + TOP_COUNTRIES_REPORT_ID,
+ TOP_COUNTRIES_REPORT_ID,
+ List.of(
+ getExpectedCountryViews("US", "United States", 1)
+ )
+ ),
+ UsageReportMatcher.matchUsageReport(
+ bitstreamVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID,
+ TOTAL_DOWNLOADS_REPORT_ID,
+ expectedTotalVisits
+ )
+ )));
}
// Create expected points from -6 months to now, with given number of views in current month
@@ -1475,4 +1552,34 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes
}
return expectedPoints;
}
+
+ private UsageReportPointDsoTotalVisitsRest getExpectedDsoViews(DSpaceObject dso, int views) {
+ UsageReportPointDsoTotalVisitsRest point = new UsageReportPointDsoTotalVisitsRest();
+
+ point.addValue("views", views);
+ point.setType(StringUtils.lowerCase(Constants.typeText[dso.getType()]));
+ point.setId(dso.getID().toString());
+ point.setLabel(dso.getName());
+
+ return point;
+ }
+
+ private UsageReportPointCountryRest getExpectedCountryViews(String id, String label, int views) {
+ UsageReportPointCountryRest point = new UsageReportPointCountryRest();
+
+ point.addValue("views", views);
+ point.setId(id);
+ point.setLabel(label);
+
+ return point;
+ }
+
+ private UsageReportPointCityRest getExpectedCityViews(String id, int views) {
+ UsageReportPointCityRest point = new UsageReportPointCityRest();
+
+ point.addValue("views", views);
+ point.setId(id);
+
+ return point;
+ }
}
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java
index 0f9d8f2bb9..4a9f03ffff 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java
@@ -995,6 +995,305 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
bibtex.close();
}
+ @Test
+ /**
+ * Test the creation of workspaceitems POSTing to the resource collection endpoint a bibtex file
+ *
+ * @throws Exception
+ */
+ public void createSingleWorkspaceItemFromBibtexArticleFileWithOneEntryTest() throws Exception {
+ context.turnOffAuthorisationSystem();
+
+ //** GIVEN **
+ //1. A community-collection structure with one parent community with sub-community and two collections.
+ 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")
+ .withSubmitterGroup(eperson)
+ .build();
+ Collection col2 = CollectionBuilder.createCollection(context, child1)
+ .withName("Collection 2")
+ .withSubmitterGroup(eperson)
+ .build();
+
+ InputStream bibtex = getClass().getResourceAsStream("bibtex-test-article.bib");
+ final MockMultipartFile bibtexFile = new MockMultipartFile("file", "/local/path/bibtex-test-article.bib",
+ "application/x-bibtex", bibtex);
+
+ context.restoreAuthSystemState();
+
+ AtomicReference> idRef = new AtomicReference<>();
+ String authToken = getAuthToken(eperson.getEmail(), password);
+ try {
+ // create a workspaceitem from a single bibliographic entry file explicitly in the default collection (col1)
+ getClient(authToken).perform(multipart("/api/submission/workspaceitems")
+ .file(bibtexFile))
+ // create should return 200, 201 (created) is better for single resource
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$._embedded.workspaceitems[0]" +
+ ".sections.traditionalpageone['dc.title'][0].value",
+ is("My Article")))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0]" +
+ ".sections.traditionalpageone['dc.type'][0].value",
+ is("article")))
+ .andExpect(
+ jsonPath("$._embedded.workspaceitems[0]._embedded.collection.id",
+ is(col1.getID().toString())))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload.files[0]"
+ + ".metadata['dc.source'][0].value",
+ is("/local/path/bibtex-test-article.bib")))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload.files[0]"
+ + ".metadata['dc.title'][0].value",
+ is("bibtex-test-article.bib")))
+ .andExpect(
+ jsonPath("$._embedded.workspaceitems[*]._embedded.upload").doesNotExist())
+ .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(),
+ "$._embedded.workspaceitems[*].id")));
+ } finally {
+ if (idRef != null && idRef.get() != null) {
+ for (int i : idRef.get()) {
+ WorkspaceItemBuilder.deleteWorkspaceItem(i);
+ }
+ }
+ }
+
+ // create a workspaceitem from a single bibliographic entry file explicitly in the col2
+ try {
+ getClient(authToken).perform(multipart("/api/submission/workspaceitems")
+ .file(bibtexFile)
+ .param("owningCollection", col2.getID().toString()))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$._embedded.workspaceitems[0]" +
+ ".sections.traditionalpageone['dc.title'][0].value",
+ is("My Article")))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0]" +
+ ".sections.traditionalpageone['dc.type'][0].value",
+ is("article")))
+ .andExpect(
+ jsonPath("$._embedded.workspaceitems[0]._embedded.collection.id",
+ is(col2.getID().toString())))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload.files[0]"
+ + ".metadata['dc.source'][0].value",
+ is("/local/path/bibtex-test-article.bib")))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload"
+ + ".files[0].metadata['dc.title'][0].value",
+ is("bibtex-test-article.bib")))
+ .andExpect(
+ jsonPath("$._embedded.workspaceitems[*]._embedded.upload").doesNotExist())
+ .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(),
+ "$._embedded.workspaceitems[*].id")));
+ } finally {
+ if (idRef != null && idRef.get() != null) {
+ for (int i : idRef.get()) {
+ WorkspaceItemBuilder.deleteWorkspaceItem(i);
+ }
+ }
+ }
+ bibtex.close();
+ }
+
+ @Test
+ public void createSingleWorkspaceItemFromBibtexFileWithDiacriticsTest() throws Exception {
+ context.turnOffAuthorisationSystem();
+
+ //** GIVEN **
+ //1. A community-collection structure with one parent community with sub-community and two collections.
+ 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")
+ .withSubmitterGroup(eperson)
+ .build();
+ Collection col2 = CollectionBuilder.createCollection(context, child1)
+ .withName("Collection 2")
+ .withSubmitterGroup(eperson)
+ .build();
+
+ InputStream bibtex = getClass().getResourceAsStream("bibtex-test-diacritics.bib");
+ final MockMultipartFile bibtexFile = new MockMultipartFile("file", "/local/path/bibtex-test-diacritics.bib",
+ "application/x-bibtex", bibtex);
+
+ context.restoreAuthSystemState();
+
+ AtomicReference> idRef = new AtomicReference<>();
+ String authToken = getAuthToken(eperson.getEmail(), password);
+ try {
+ // create a workspaceitem from a single bibliographic entry file explicitly in the default collection (col1)
+ getClient(authToken).perform(multipart("/api/submission/workspaceitems")
+ .file(bibtexFile))
+ // create should return 200, 201 (created) is better for single resource
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$._embedded.workspaceitems[0].sections." +
+ "traditionalpageone['dc.title'][0].value",
+ is("The German umlauts: ÄÖüß")))
+ .andExpect(
+ jsonPath("$._embedded.workspaceitems[0]._embedded.collection.id",
+ is(col1.getID().toString())))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload.files[0]"
+ + ".metadata['dc.source'][0].value",
+ is("/local/path/bibtex-test-diacritics.bib")))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload.files[0]"
+ + ".metadata['dc.title'][0].value",
+ is("bibtex-test-diacritics.bib")))
+ .andExpect(
+ jsonPath("$._embedded.workspaceitems[*]._embedded.upload").doesNotExist())
+ .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(),
+ "$._embedded.workspaceitems[*].id")));
+ } finally {
+ if (idRef != null && idRef.get() != null) {
+ for (int i : idRef.get()) {
+ WorkspaceItemBuilder.deleteWorkspaceItem(i);
+ }
+ }
+ }
+
+ // create a workspaceitem from a single bibliographic entry file explicitly in the col2
+ try {
+ getClient(authToken).perform(multipart("/api/submission/workspaceitems")
+ .file(bibtexFile)
+ .param("owningCollection", col2.getID().toString()))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$._embedded.workspaceitems[0].sections." +
+ "traditionalpageone['dc.title'][0].value",
+ is("The German umlauts: ÄÖüß")))
+ .andExpect(
+ jsonPath("$._embedded.workspaceitems[0]._embedded.collection.id",
+ is(col2.getID().toString())))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload.files[0]"
+ + ".metadata['dc.source'][0].value",
+ is("/local/path/bibtex-test-diacritics.bib")))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload"
+ + ".files[0].metadata['dc.title'][0].value",
+ is("bibtex-test-diacritics.bib")))
+ .andExpect(
+ jsonPath("$._embedded.workspaceitems[*]._embedded.upload").doesNotExist())
+ .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(),
+ "$._embedded.workspaceitems[*].id")));
+ } finally {
+ if (idRef != null && idRef.get() != null) {
+ for (int i : idRef.get()) {
+ WorkspaceItemBuilder.deleteWorkspaceItem(i);
+ }
+ }
+ }
+ bibtex.close();
+ }
+
+ @Test
+ /**
+ * Test the creation of workspaceitems POSTing to the resource collection endpoint a bibtex file
+ *
+ * @throws Exception
+ */
+ public void createSingleWorkspaceItemFromBibtexFileWithMultipleAuthorsTest() throws Exception {
+ context.turnOffAuthorisationSystem();
+
+ //** GIVEN **
+ //1. A community-collection structure with one parent community with sub-community and two collections.
+ 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")
+ .withSubmitterGroup(eperson)
+ .build();
+ Collection col2 = CollectionBuilder.createCollection(context, child1)
+ .withName("Collection 2")
+ .withSubmitterGroup(eperson)
+ .build();
+
+ InputStream bibtex = getClass().getResourceAsStream("bibtex-test-multiple-authors.bib");
+ final MockMultipartFile bibtexFile = new MockMultipartFile("file",
+ "/local/path/bibtex-test-multiple-authors.bib",
+ "application/x-bibtex", bibtex);
+
+ context.restoreAuthSystemState();
+
+ AtomicReference> idRef = new AtomicReference<>();
+ String authToken = getAuthToken(eperson.getEmail(), password);
+ try {
+ // create a workspaceitem from a single bibliographic entry file explicitly in the default collection (col1)
+ getClient(authToken).perform(multipart("/api/submission/workspaceitems")
+ .file(bibtexFile))
+ // create should return 200, 201 (created) is better for single resource
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$._embedded.workspaceitems[0]" +
+ ".sections.traditionalpageone['dc.title'][0].value",
+ is("My Article")))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0]" +
+ ".sections.traditionalpageone['dc.contributor.author'][0].value",
+ is("A. Nauthor")))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0]" +
+ ".sections.traditionalpageone['dc.contributor.author'][1].value",
+ is("A. Nother")))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0]" +
+ ".sections.traditionalpageone['dc.contributor.author'][2].value",
+ is("A. Third")))
+ .andExpect(
+ jsonPath("$._embedded.workspaceitems[0]._embedded.collection.id",
+ is(col1.getID().toString())))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload.files[0]"
+ + ".metadata['dc.source'][0].value",
+ is("/local/path/bibtex-test-multiple-authors.bib")))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload.files[0]"
+ + ".metadata['dc.title'][0].value",
+ is("bibtex-test-multiple-authors.bib")))
+ .andExpect(
+ jsonPath("$._embedded.workspaceitems[*]._embedded.upload").doesNotExist())
+ .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(),
+ "$._embedded.workspaceitems[*].id")));
+ } finally {
+ if (idRef != null && idRef.get() != null) {
+ for (int i : idRef.get()) {
+ WorkspaceItemBuilder.deleteWorkspaceItem(i);
+ }
+ }
+ }
+
+ // create a workspaceitem from a single bibliographic entry file explicitly in the col2
+ try {
+ getClient(authToken).perform(multipart("/api/submission/workspaceitems")
+ .file(bibtexFile)
+ .param("owningCollection", col2.getID().toString()))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$._embedded.workspaceitems[0]" +
+ ".sections.traditionalpageone['dc.title'][0].value",
+ is("My Article")))
+ .andExpect(
+ jsonPath("$._embedded.workspaceitems[0]._embedded.collection.id",
+ is(col2.getID().toString())))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload.files[0]"
+ + ".metadata['dc.source'][0].value",
+ is("/local/path/bibtex-test-multiple-authors.bib")))
+ .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload"
+ + ".files[0].metadata['dc.title'][0].value",
+ is("bibtex-test-multiple-authors.bib")))
+ .andExpect(
+ jsonPath("$._embedded.workspaceitems[*]._embedded.upload").doesNotExist())
+ .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(),
+ "$._embedded.workspaceitems[*].id")));
+ } finally {
+ if (idRef != null && idRef.get() != null) {
+ for (int i : idRef.get()) {
+ WorkspaceItemBuilder.deleteWorkspaceItem(i);
+ }
+ }
+ }
+ bibtex.close();
+ }
+
@Test
/**
* Test the creation of workspaceitems POSTing to the resource collection endpoint a csv file
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/eperson/DeleteEPersonSubmitterIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/eperson/DeleteEPersonSubmitterIT.java
index fb8b44fa17..e020c04b1a 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/eperson/DeleteEPersonSubmitterIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/eperson/DeleteEPersonSubmitterIT.java
@@ -142,10 +142,10 @@ public class DeleteEPersonSubmitterIT extends AbstractControllerIntegrationTest
Item item = itemService.find(context, installItem.getID());
- RequestItemAuthor requestItemAuthor = requestItemAuthorExtractor.getRequestItemAuthor(context, item);
+ List requestItemAuthor = requestItemAuthorExtractor.getRequestItemAuthor(context, item);
- assertEquals("Help Desk", requestItemAuthor.getFullName());
- assertEquals("dspace-help@myu.edu", requestItemAuthor.getEmail());
+ assertEquals("Help Desk", requestItemAuthor.get(0).getFullName());
+ assertEquals("dspace-help@myu.edu", requestItemAuthor.get(0).getEmail());
}
/**
@@ -171,7 +171,7 @@ public class DeleteEPersonSubmitterIT extends AbstractControllerIntegrationTest
Item item = installItemService.installItem(context, wsi);
- List opsToWithDraw = new ArrayList();
+ List opsToWithDraw = new ArrayList<>();
ReplaceOperation replaceOperationToWithDraw = new ReplaceOperation("/withdrawn", true);
opsToWithDraw.add(replaceOperationToWithDraw);
String patchBodyToWithdraw = getPatchContent(opsToWithDraw);
@@ -191,7 +191,7 @@ public class DeleteEPersonSubmitterIT extends AbstractControllerIntegrationTest
assertNull(retrieveItemSubmitter(item.getID()));
- List opsToReinstate = new ArrayList();
+ List opsToReinstate = new ArrayList<>();
ReplaceOperation replaceOperationToReinstate = new ReplaceOperation("/withdrawn", false);
opsToReinstate.add(replaceOperationToReinstate);
String patchBodyToReinstate = getPatchContent(opsToReinstate);
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/UsageReportMatcher.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/UsageReportMatcher.java
index ba82d69b40..9ad1dce28a 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/UsageReportMatcher.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/UsageReportMatcher.java
@@ -49,13 +49,18 @@ public class UsageReportMatcher {
* @param points List of points to match to the json of UsageReport's list of points
* @return The matcher
*/
- public static Matcher super Object> matchUsageReport(String id, String reportType,
- List points) {
+ public static Matcher super Object> matchUsageReport(
+ String id, String reportType, List points
+ ) {
return allOf(
matchUsageReport(id, reportType),
hasJsonPath("$.points", Matchers.containsInAnyOrder(
- points.stream().map(point -> UsageReportPointMatcher
- .matchUsageReportPoint(point.getId(), point.getType(), point.getValues().get("views")))
- .collect(Collectors.toList()))));
+ points.stream()
+ .map(point -> UsageReportPointMatcher.matchUsageReportPoint(
+ point.getId(), point.getLabel(), point.getType(), point.getValues().get("views")
+ ))
+ .collect(Collectors.toList()))
+ )
+ );
}
}
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/UsageReportPointMatcher.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/UsageReportPointMatcher.java
index e7f22066e5..f1c641b18a 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/UsageReportPointMatcher.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/UsageReportPointMatcher.java
@@ -28,15 +28,17 @@ public class UsageReportPointMatcher {
* Matcher for the usage report points (see {@link UsageReportPointRest})
*
* @param id Id to match if of json of UsageReportPoint
+ * @param label Label to match if of json of UsageReportPoint
* @param type Type to match if of json of UsageReportPoint
* @param views Nr of views, is in the values key-value pair of values of UsageReportPoint with key "views"
* @return The matcher
*/
- public static Matcher super Object> matchUsageReportPoint(String id, String type, int views) {
+ public static Matcher super Object> matchUsageReportPoint(String id, String label, String type, int views) {
return allOf(
hasJsonPath("$.id", is(id)),
+ hasJsonPath("$.label", is(label)),
hasJsonPath("$.type", is(type)),
hasJsonPath("$.values.views", is(views))
- );
+ );
}
}
diff --git a/dspace-server-webapp/src/test/resources/org/dspace/app/rest/bibtex-test-article.bib b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/bibtex-test-article.bib
new file mode 100644
index 0000000000..e3f1ca1d4e
--- /dev/null
+++ b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/bibtex-test-article.bib
@@ -0,0 +1,4 @@
+@article{ Nobody01,
+ author = "Nobody Jr",
+ title = "My Article",
+ year = "2006" }
diff --git a/dspace-server-webapp/src/test/resources/org/dspace/app/rest/bibtex-test-diacritics.bib b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/bibtex-test-diacritics.bib
new file mode 100644
index 0000000000..d1cb431bef
--- /dev/null
+++ b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/bibtex-test-diacritics.bib
@@ -0,0 +1,4 @@
+@misc{ Nobody01,
+ author = "Mo\ss",
+ title = { The German umlauts: \"A{\"O}{\"{u}}\ss },
+ year = "2006" }
diff --git a/dspace-server-webapp/src/test/resources/org/dspace/app/rest/bibtex-test-multiple-authors.bib b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/bibtex-test-multiple-authors.bib
new file mode 100644
index 0000000000..1db78de377
--- /dev/null
+++ b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/bibtex-test-multiple-authors.bib
@@ -0,0 +1,4 @@
+@misc{ Nobody01,
+ author = "A. Nauthor and A. Nother and A. Third",
+ title = "My Article",
+ year = "2006" }
diff --git a/dspace/config/spring/api/access-conditions.xml b/dspace/config/spring/api/access-conditions.xml
index cd1550f389..828b31d425 100644
--- a/dspace/config/spring/api/access-conditions.xml
+++ b/dspace/config/spring/api/access-conditions.xml
@@ -3,10 +3,9 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
-
+
-
-
+
@@ -18,7 +17,7 @@
-
+
@@ -31,26 +30,25 @@
-
+
-
-
+
-
+
diff --git a/dspace/config/spring/api/bibtex-integration.xml b/dspace/config/spring/api/bibtex-integration.xml
index eeabace1c7..bc5adf5886 100644
--- a/dspace/config/spring/api/bibtex-integration.xml
+++ b/dspace/config/spring/api/bibtex-integration.xml
@@ -17,6 +17,7 @@
only matters here for postprocessing of the value. The mapped MetadatumContributor has full control over
what metadatafield is generated.
+
@@ -39,14 +40,24 @@
-
-
-
+
+
+
+
+
+
+
+
-
-
\ No newline at end of file
+
+
+
+
+
+
+
diff --git a/dspace/config/spring/api/dublicore-metadata-mapper.xml b/dspace/config/spring/api/dublicore-metadata-mapper.xml
index bb52e99b82..82c0dd47dd 100644
--- a/dspace/config/spring/api/dublicore-metadata-mapper.xml
+++ b/dspace/config/spring/api/dublicore-metadata-mapper.xml
@@ -25,6 +25,9 @@
+
+
+
diff --git a/dspace/config/spring/api/external-openaire.xml b/dspace/config/spring/api/external-openaire.xml
index f483ce7210..25a23a1739 100644
--- a/dspace/config/spring/api/external-openaire.xml
+++ b/dspace/config/spring/api/external-openaire.xml
@@ -1,6 +1,10 @@
-
@@ -10,17 +14,65 @@
-
+
+
+
Project
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dspace/config/spring/api/requestitem.xml b/dspace/config/spring/api/requestitem.xml
index cc18c7916f..90c49156d5 100644
--- a/dspace/config/spring/api/requestitem.xml
+++ b/dspace/config/spring/api/requestitem.xml
@@ -8,25 +8,65 @@
http://www.springframework.org/schema/context/spring-context-2.5.xsd"
default-autowire-candidates="*Service,*DAO,javax.sql.DataSource">
+
+ Strategies for determining who receives Request Copy emails.
+ A copy request "strategy" class produces a list of addresses to which a
+ request email should be sent. Each strategy gets its addresses from a
+ different source. Select the one that meets your need, or use the
+ CombiningRequestItemStrategy to meld the lists from two or more other
+ strategies.
+
+
-
-
+
org.dspace
oclc-harvester2
- 0.1.12
-
-
-
- xalan
- xalan
- 2.7.2
+ 1.0.0
org.apache.httpcomponents