Merge branch 'master' into DS-4042_ITs_WrongPatchRequest

This commit is contained in:
Mykhaylo
2020-06-25 18:46:59 +02:00
219 changed files with 10363 additions and 2449 deletions

View File

@@ -20,11 +20,8 @@ List of changes in this PR:
_This checklist provides a reminder of what we are going to look for when reviewing your PR. You need not complete this checklist prior to creating your PR (draft PRs are always welcome). If you are unsure about an item in the checklist, don't hesitate to ask. We're here to help!_
- [ ] My PR is small in size (e.g. less than 1,000 lines of code, not including comments & integration tests). Exceptions may be made if previously agreed upon.
- [ ] My PR passes Checkstyle validation based on the [Code Style Guide](https://wiki.lyrasis.org/display/DSPACE/Code+Style+Guide)
- [ ] My PR passes Checkstyle validation based on the [Code Style Guide](https://wiki.lyrasis.org/display/DSPACE/Code+Style+Guide).
- [ ] My PR includes Javadoc for _all new (or modified) public methods and classes_. It also includes Javadoc for large or complex private methods.
- [ ] My PR passes all tests and includes new/updated Unit or Integration Tests for any bug fixes, improvements or new features. A few reminders about what constitutes good tests:
* Include tests for different user types, including: (1) Anonymous user, (2) Logged in user (non-admin), and (3) Administrator.
* Include tests for known error scenarios and error codes (e.g. `400 Bad Request`, `401 Unauthorized`, `403 Forbidden`, `404 Not Found`, etc)
* For bug fixes, include a test that reproduces the bug and proves it is fixed. For clarity, it may be useful to provide the test in a separate commit from the bug fix.
- [ ] My PR passes all tests and includes new/updated Unit or Integration Tests based on the [Code Testing Guide](https://wiki.lyrasis.org/display/DSPACE/Code+Testing+Guide).
- [ ] If my PR includes new, third-party dependencies (in any `pom.xml`), I've made sure their licenses align with the [DSpace BSD License](https://github.com/DSpace/DSpace/blob/master/LICENSE) based on the [Licensing of Contributions](https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines#CodeContributionGuidelines-LicensingofContributions) documentation.
- [ ] If my PR modifies the REST API, I've linked to the REST Contract page (or open PR) related to this change.

View File

@@ -98,20 +98,6 @@
</execution>
</executions>
</plugin>
<!-- Verify OS license headers for all source code files -->
<plugin>
<groupId>com.mycila</groupId>
<artifactId>license-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/src/test/resources/**</exclude>
<exclude>**/src/test/data/**</exclude>
<exclude>**/.gitignore</exclude>
<exclude>**/src/main/resources/rebel.xml</exclude>
<exclude>src/test/data/dspaceFolder/config/spiders/**</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>

View File

@@ -8,14 +8,10 @@
package org.dspace.app.bulkedit;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -27,6 +23,7 @@ import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.dspace.authority.AuthorityValue;
import org.dspace.authority.factory.AuthorityServiceFactory;
@@ -141,18 +138,18 @@ public class DSpaceCSV implements Serializable {
/**
* Create a new instance, reading the lines in from file
*
* @param f The file to read from
* @param inputStream the inputstream to read from
* @param c The DSpace Context
* @throws Exception thrown if there is an error reading or processing the file
*/
public DSpaceCSV(File f, Context c) throws Exception {
public DSpaceCSV(InputStream inputStream, Context c) throws Exception {
// Initialise the class
init();
// Open the CSV file
BufferedReader input = null;
try {
input = new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8"));
input = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
// Read the heading line
String head = input.readLine();
@@ -623,21 +620,15 @@ public class DSpaceCSV implements Serializable {
}
/**
* Save the CSV file to the given filename
*
* @param filename The filename to save the CSV file to
* @throws IOException Thrown if an error occurs when writing the file
* Creates and returns an InputStream from the CSV Lines in this DSpaceCSV
* @return The InputStream created from the CSVLines in this DSpaceCSV
*/
public final void save(String filename) throws IOException {
// Save the file
BufferedWriter out = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(filename), "UTF-8"));
public InputStream getInputStream() {
StringBuilder stringBuilder = new StringBuilder();
for (String csvLine : getCSVLinesAsStringArray()) {
out.write(csvLine + "\n");
stringBuilder.append(csvLine + "\n");
}
out.flush();
out.close();
return IOUtils.toInputStream(stringBuilder.toString(), StandardCharsets.UTF_8);
}
/**

View File

@@ -8,271 +8,84 @@
package org.dspace.app.bulkedit;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.google.common.collect.Iterators;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.core.Constants;
import org.dspace.content.service.MetadataDSpaceCsvExportService;
import org.dspace.core.Context;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.utils.DSpace;
/**
* Metadata exporter to allow the batch export of metadata into a file
*
* @author Stuart Lewis
*/
public class MetadataExport {
/**
* The items to export
*/
protected Iterator<Item> toExport;
public class MetadataExport extends DSpaceRunnable<MetadataExportScriptConfiguration> {
protected ItemService itemService;
private boolean help = false;
private String filename = null;
private String handle = null;
private boolean exportAllMetadata = false;
private boolean exportAllItems = false;
protected Context context;
private static final String EXPORT_CSV = "exportCSV";
/**
* Whether to export all metadata, or just normally edited metadata
*/
protected boolean exportAll;
private MetadataDSpaceCsvExportService metadataDSpaceCsvExportService = new DSpace().getServiceManager()
.getServicesByType(MetadataDSpaceCsvExportService.class).get(0);
protected MetadataExport() {
itemService = ContentServiceFactory.getInstance().getItemService();
private EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
@Override
public void internalRun() throws Exception {
if (help) {
handler.logInfo("\nfull export: metadata-export -f filename");
handler.logInfo("partial export: metadata-export -i handle -f filename");
printHelp();
return;
}
/**
* Set up a new metadata export
*
* @param c The Context
* @param toExport The ItemIterator of items to export
* @param exportAll whether to export all metadata or not (include handle, provenance etc)
*/
public MetadataExport(Context c, Iterator<Item> toExport, boolean exportAll) {
itemService = ContentServiceFactory.getInstance().getItemService();
// Store the export settings
this.toExport = toExport;
this.exportAll = exportAll;
this.context = c;
}
/**
* Method to export a community (and sub-communities and collections)
*
* @param c The Context
* @param toExport The Community to export
* @param exportAll whether to export all metadata or not (include handle, provenance etc)
*/
public MetadataExport(Context c, Community toExport, boolean exportAll) {
itemService = ContentServiceFactory.getInstance().getItemService();
Context context = new Context();
context.turnOffAuthorisationSystem();
try {
// Try to export the community
this.toExport = buildFromCommunity(c, toExport, 0);
this.exportAll = exportAll;
this.context = c;
} catch (SQLException sqle) {
// Something went wrong...
System.err.println("Error running exporter:");
sqle.printStackTrace(System.err);
System.exit(1);
context.setCurrentUser(ePersonService.find(context, this.getEpersonIdentifier()));
} catch (SQLException e) {
handler.handleException(e);
}
DSpaceCSV dSpaceCSV = metadataDSpaceCsvExportService
.handleExport(context, exportAllItems, exportAllMetadata, handle,
handler);
handler.writeFilestream(context, filename, dSpaceCSV.getInputStream(), EXPORT_CSV);
context.restoreAuthSystemState();
context.complete();
}
/**
* Build an array list of item ids that are in a community (include sub-communities and collections)
*
* @param context DSpace context
* @param community The community to build from
* @param indent How many spaces to use when writing out the names of items added
* @return The list of item ids
* @throws SQLException if database error
*/
protected Iterator<Item> buildFromCommunity(Context context, Community community, int indent)
throws SQLException {
// Add all the collections
List<Collection> collections = community.getCollections();
Iterator<Item> result = null;
for (Collection collection : collections) {
for (int i = 0; i < indent; i++) {
System.out.print(" ");
@Override
public MetadataExportScriptConfiguration getScriptConfiguration() {
return new DSpace().getServiceManager().getServiceByName("metadata-export",
MetadataExportScriptConfiguration.class);
}
Iterator<Item> items = itemService.findByCollection(context, collection);
result = addItemsToResult(result, items);
@Override
public void setup() throws ParseException {
}
// Add all the sub-communities
List<Community> communities = community.getSubcommunities();
for (Community subCommunity : communities) {
for (int i = 0; i < indent; i++) {
System.out.print(" ");
}
Iterator<Item> items = buildFromCommunity(context, subCommunity, indent + 1);
result = addItemsToResult(result, items);
}
return result;
}
private Iterator<Item> addItemsToResult(Iterator<Item> result, Iterator<Item> items) {
if (result == null) {
result = items;
} else {
result = Iterators.concat(result, items);
}
return result;
}
/**
* Run the export
*
* @return the exported CSV lines
*/
public DSpaceCSV export() {
try {
Context.Mode originalMode = context.getCurrentMode();
context.setMode(Context.Mode.READ_ONLY);
// Process each item
DSpaceCSV csv = new DSpaceCSV(exportAll);
while (toExport.hasNext()) {
Item item = toExport.next();
csv.addItem(item);
context.uncacheEntity(item);
}
context.setMode(originalMode);
// Return the results
return csv;
} catch (Exception e) {
// Something went wrong...
System.err.println("Error exporting to CSV:");
e.printStackTrace();
return null;
}
}
/**
* Print the help message
*
* @param options The command line options the user gave
* @param exitCode the system exit code to use
*/
private static void printHelp(Options options, int exitCode) {
// print the help message
HelpFormatter myhelp = new HelpFormatter();
myhelp.printHelp("MetadataExport\n", options);
System.out.println("\nfull export: metadataexport -f filename");
System.out.println("partial export: metadataexport -i handle -f filename");
System.exit(exitCode);
}
/**
* main method to run the metadata exporter
*
* @param argv the command line arguments given
* @throws Exception if error occurs
*/
public static void main(String[] argv) throws Exception {
// Create an options object and populate it
CommandLineParser parser = new PosixParser();
Options options = new Options();
options.addOption("i", "id", true, "ID or handle of thing to export (item, collection, or community)");
options.addOption("f", "file", true, "destination where you want file written");
options.addOption("a", "all", false,
"include all metadata fields that are not normally changed (e.g. provenance)");
options.addOption("h", "help", false, "help");
CommandLine line = null;
try {
line = parser.parse(options, argv);
} catch (ParseException pe) {
System.err.println("Error with commands.");
printHelp(options, 1);
System.exit(0);
}
if (line.hasOption('h')) {
printHelp(options, 0);
if (commandLine.hasOption('h')) {
help = true;
return;
}
// Check a filename is given
if (!line.hasOption('f')) {
System.err.println("Required parameter -f missing!");
printHelp(options, 1);
if (!commandLine.hasOption('f')) {
throw new ParseException("Required parameter -f missing!");
}
String filename = line.getOptionValue('f');
filename = commandLine.getOptionValue('f');
// Create a context
Context c = new Context(Context.Mode.READ_ONLY);
c.turnOffAuthorisationSystem();
exportAllMetadata = commandLine.hasOption('a');
// The things we'll export
Iterator<Item> toExport = null;
MetadataExport exporter = null;
// Export everything?
boolean exportAll = line.hasOption('a');
ContentServiceFactory contentServiceFactory = ContentServiceFactory.getInstance();
// Check we have an item OK
ItemService itemService = contentServiceFactory.getItemService();
if (!line.hasOption('i')) {
System.out.println("Exporting whole repository WARNING: May take some time!");
exporter = new MetadataExport(c, itemService.findAll(c), exportAll);
} else {
String handle = line.getOptionValue('i');
DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(c, handle);
if (dso == null) {
System.err.println("Item '" + handle + "' does not resolve to an item in your repository!");
printHelp(options, 1);
if (!commandLine.hasOption('i')) {
exportAllItems = true;
}
if (dso.getType() == Constants.ITEM) {
System.out.println("Exporting item '" + dso.getName() + "' (" + handle + ")");
List<Item> item = new ArrayList<>();
item.add((Item) dso);
exporter = new MetadataExport(c, item.iterator(), exportAll);
} else if (dso.getType() == Constants.COLLECTION) {
System.out.println("Exporting collection '" + dso.getName() + "' (" + handle + ")");
Collection collection = (Collection) dso;
toExport = itemService.findByCollection(c, collection);
exporter = new MetadataExport(c, toExport, exportAll);
} else if (dso.getType() == Constants.COMMUNITY) {
System.out.println("Exporting community '" + dso.getName() + "' (" + handle + ")");
exporter = new MetadataExport(c, (Community) dso, exportAll);
} else {
System.err.println("Error identifying '" + handle + "'");
System.exit(1);
}
}
// Perform the export
DSpaceCSV csv = exporter.export();
// Save the files to the file
csv.save(filename);
// Finish off and tidy up
c.restoreAuthSystemState();
c.complete();
handle = commandLine.getOptionValue('i');
}
}

View File

@@ -0,0 +1,74 @@
/**
* 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.bulkedit;
import java.io.OutputStream;
import java.sql.SQLException;
import org.apache.commons.cli.Options;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.core.Context;
import org.dspace.scripts.configuration.ScriptConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
/**
* The {@link ScriptConfiguration} for the {@link MetadataExport} script
*/
public class MetadataExportScriptConfiguration<T extends MetadataExport> extends ScriptConfiguration<T> {
@Autowired
private AuthorizeService authorizeService;
private Class<T> dspaceRunnableClass;
@Override
public Class<T> getDspaceRunnableClass() {
return dspaceRunnableClass;
}
/**
* Generic setter for the dspaceRunnableClass
* @param dspaceRunnableClass The dspaceRunnableClass to be set on this MetadataExportScriptConfiguration
*/
@Override
public void setDspaceRunnableClass(Class<T> dspaceRunnableClass) {
this.dspaceRunnableClass = dspaceRunnableClass;
}
@Override
public boolean isAllowedToExecute(Context context) {
try {
return authorizeService.isAdmin(context);
} catch (SQLException e) {
throw new RuntimeException("SQLException occurred when checking if the current user is an admin", e);
}
}
@Override
public Options getOptions() {
if (options == null) {
Options options = new Options();
options.addOption("i", "id", true, "ID or handle of thing to export (item, collection, or community)");
options.getOption("i").setType(String.class);
options.addOption("f", "file", true, "destination where you want file written");
options.getOption("f").setType(OutputStream.class);
options.getOption("f").setRequired(true);
options.addOption("a", "all", false,
"include all metadata fields that are not normally changed (e.g. provenance)");
options.getOption("a").setType(boolean.class);
options.addOption("h", "help", false, "help");
options.getOption("h").setType(boolean.class);
super.options = options;
}
return options;
}
}

View File

@@ -7,10 +7,8 @@
*/
package org.dspace.app.bulkedit;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
@@ -19,16 +17,12 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Nullable;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.authority.AuthorityValue;
@@ -65,6 +59,10 @@ import org.dspace.eperson.EPerson;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
import org.dspace.utils.DSpace;
import org.dspace.workflow.WorkflowException;
import org.dspace.workflow.WorkflowItem;
import org.dspace.workflow.WorkflowService;
import org.dspace.workflow.factory.WorkflowServiceFactory;
@@ -74,11 +72,7 @@ import org.dspace.workflow.factory.WorkflowServiceFactory;
*
* @author Stuart Lewis
*/
public class MetadataImport {
/**
* The Context
*/
Context c;
public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfiguration> {
/**
* The DSpaceCSV object we're processing
@@ -95,10 +89,6 @@ public class MetadataImport {
*/
protected static Set<String> authorityControlled;
static {
setAuthorizedMetadataFields();
}
/**
* The prefix of the authority controlled field
*/
@@ -143,45 +133,208 @@ public class MetadataImport {
*/
protected Integer rowCount = 1;
private boolean useTemplate = false;
private String filename = null;
private boolean useWorkflow = false;
private boolean workflowNotify = false;
private boolean change = false;
private boolean help = false;
protected boolean validateOnly;
/**
* Logger
*/
protected static final Logger log = org.apache.logging.log4j.LogManager.getLogger(MetadataImport.class);
protected final AuthorityValueService authorityValueService;
protected final ItemService itemService;
protected final InstallItemService installItemService;
protected final CollectionService collectionService;
protected final HandleService handleService;
protected final WorkspaceItemService workspaceItemService;
protected final RelationshipTypeService relationshipTypeService;
protected final RelationshipService relationshipService;
protected final EntityTypeService entityTypeService;
protected final EntityService entityService;
protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
protected InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService();
protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
protected HandleService handleService = HandleServiceFactory.getInstance().getHandleService();
protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
protected RelationshipTypeService relationshipTypeService = ContentServiceFactory.getInstance()
.getRelationshipTypeService();
protected RelationshipService relationshipService = ContentServiceFactory.getInstance().getRelationshipService();
protected EntityTypeService entityTypeService = ContentServiceFactory.getInstance().getEntityTypeService();
protected EntityService entityService = ContentServiceFactory.getInstance().getEntityService();
protected AuthorityValueService authorityValueService = AuthorityServiceFactory.getInstance()
.getAuthorityValueService();
/**
* Create an instance of the metadata importer. Requires a context and an array of CSV lines
* to examine.
*
* @param c The context
* @param toImport An array of CSV lines to examine
*/
public MetadataImport(Context c, DSpaceCSV toImport) {
public void initMetadataImport(DSpaceCSV toImport) {
// Store the import settings
this.c = c;
csv = toImport;
this.toImport = toImport.getCSVLines();
installItemService = ContentServiceFactory.getInstance().getInstallItemService();
itemService = ContentServiceFactory.getInstance().getItemService();
collectionService = ContentServiceFactory.getInstance().getCollectionService();
handleService = HandleServiceFactory.getInstance().getHandleService();
authorityValueService = AuthorityServiceFactory.getInstance().getAuthorityValueService();
workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
relationshipService = ContentServiceFactory.getInstance().getRelationshipService();
relationshipTypeService = ContentServiceFactory.getInstance().getRelationshipTypeService();
entityTypeService = ContentServiceFactory.getInstance().getEntityTypeService();
entityService = ContentServiceFactory.getInstance().getEntityService();
}
@Override
public void internalRun() throws Exception {
if (help) {
printHelp();
return;
}
// Create a context
Context c = null;
c = new Context();
c.turnOffAuthorisationSystem();
// Find the EPerson, assign to context
try {
if (commandLine.hasOption('e')) {
EPerson eperson;
String e = commandLine.getOptionValue('e');
if (e.indexOf('@') != -1) {
eperson = EPersonServiceFactory.getInstance().getEPersonService().findByEmail(c, e);
} else {
eperson = EPersonServiceFactory.getInstance().getEPersonService().find(c, UUID.fromString(e));
}
if (eperson == null) {
throw new ParseException("Error, eperson cannot be found: " + e);
}
c.setCurrentUser(eperson);
}
} catch (Exception e) {
throw new ParseException("Unable to find DSpace user: " + e.getMessage());
}
if (authorityControlled == null) {
setAuthorizedMetadataFields();
}
// Read commandLines from the CSV file
try {
Optional<InputStream> optionalFileStream = handler.getFileStream(c, filename);
if (optionalFileStream.isPresent()) {
csv = new DSpaceCSV(optionalFileStream.get(), c);
} else {
throw new IllegalArgumentException("Error reading file, the file couldn't be found for filename: " +
filename);
}
} catch (MetadataImportInvalidHeadingException miihe) {
throw miihe;
} catch (Exception e) {
throw new Exception("Error reading file: " + e.getMessage(), e);
}
// Perform the first import - just highlight differences
initMetadataImport(csv);
List<BulkEditChange> changes;
if (!commandLine.hasOption('s') || validateOnly) {
// See what has changed
try {
changes = runImport(c, false, useWorkflow, workflowNotify, useTemplate);
} catch (MetadataImportException mie) {
throw mie;
}
// Display the changes
int changeCounter = displayChanges(changes, false);
// If there were changes, ask if we should execute them
if (!validateOnly && changeCounter > 0) {
try {
// Ask the user if they want to make the changes
handler.logInfo("\n" + changeCounter + " item(s) will be changed\n");
change = determineChange(handler);
} catch (IOException ioe) {
throw new IOException("Error: " + ioe.getMessage() + ", No changes have been made", ioe);
}
} else {
handler.logInfo("There were no changes detected");
}
} else {
change = true;
}
try {
// If required, make the change
if (change && !validateOnly) {
try {
// Make the changes
changes = runImport(c, true, useWorkflow, workflowNotify, useTemplate);
} catch (MetadataImportException mie) {
throw mie;
}
// Display the changes
displayChanges(changes, true);
}
// Finsh off and tidy up
c.restoreAuthSystemState();
c.complete();
} catch (Exception e) {
c.abort();
throw new Exception(
"Error committing changes to database: " + e.getMessage() + ", aborting most recent changes", e);
}
}
/**
* This method determines whether the changes should be applied or not. This is default set to true for the REST
* script as we don't want to interact with the caller. This will be overwritten in the CLI script to ask for
* confirmation
* @param handler Applicable DSpaceRunnableHandler
* @return boolean indicating the value
* @throws IOException If something goes wrong
*/
protected boolean determineChange(DSpaceRunnableHandler handler) throws IOException {
return true;
}
@Override
public MetadataImportScriptConfiguration getScriptConfiguration() {
return new DSpace().getServiceManager().getServiceByName("metadata-import",
MetadataImportScriptConfiguration.class);
}
public void setup() throws ParseException {
useTemplate = false;
filename = null;
useWorkflow = false;
workflowNotify = false;
if (commandLine.hasOption('h')) {
help = true;
return;
}
// Check a filename is given
if (!commandLine.hasOption('f')) {
throw new ParseException("Required parameter -f missing!");
}
filename = commandLine.getOptionValue('f');
if (!commandLine.hasOption('e')) {
throw new ParseException("Required parameter -e missing!");
}
// Option to apply template to new items
if (commandLine.hasOption('t')) {
useTemplate = true;
}
// Options for workflows, and workflow notifications for new items
if (commandLine.hasOption('w')) {
useWorkflow = true;
if (commandLine.hasOption('n')) {
workflowNotify = true;
}
} else if (commandLine.hasOption('n')) {
throw new ParseException(
"Invalid option 'n': (notify) can only be specified with the 'w' (workflow) option.");
}
validateOnly = commandLine.hasOption('v');
// Is this a silent run?
change = false;
}
/**
@@ -195,15 +348,15 @@ public class MetadataImport {
* @return An array of BulkEditChange elements representing the items that have changed
* @throws MetadataImportException if something goes wrong
*/
public List<BulkEditChange> runImport(boolean change,
public List<BulkEditChange> runImport(Context c, boolean change,
boolean useWorkflow,
boolean workflowNotify,
boolean useTemplate) throws MetadataImportException {
boolean useTemplate)
throws MetadataImportException, SQLException, AuthorizeException, WorkflowException, IOException {
// Store the changes
ArrayList<BulkEditChange> changes = new ArrayList<BulkEditChange>();
// Make the changes
try {
Context.Mode originalMode = c.getCurrentMode();
c.setMode(Context.Mode.BATCH_EDIT);
@@ -212,7 +365,7 @@ public class MetadataImport {
for (DSpaceCSVLine line : toImport) {
// Resolve target references to other items
populateRefAndRowMap(line, line.getID());
line = resolveEntityRefs(line);
line = resolveEntityRefs(c, line);
// Get the DSpace item to compare with
UUID id = line.getID();
@@ -244,7 +397,7 @@ public class MetadataImport {
throw new MetadataImportException("Missing collection from item " + item.getHandle());
}
List<Collection> actualCollections = item.getCollections();
compare(item, collections, actualCollections, whatHasChanged, change);
compare(c, item, collections, actualCollections, whatHasChanged, change);
}
// Iterate through each metadata element in the csv line
@@ -263,7 +416,7 @@ public class MetadataImport {
}
}
// Compare
compareAndUpdate(item, fromCSV, change, md, whatHasChanged, line);
compareAndUpdate(c, item, fromCSV, change, md, whatHasChanged, line);
}
}
@@ -339,7 +492,7 @@ public class MetadataImport {
}
// Add all the values from the CSV line
add(fromCSV, md, whatHasChanged);
add(c, fromCSV, md, whatHasChanged);
}
}
@@ -461,15 +614,11 @@ public class MetadataImport {
}
c.setMode(originalMode);
} catch (MetadataImportException mie) {
throw mie;
} catch (Exception e) {
e.printStackTrace();
}
// Return the changes
if (!change) {
validateExpressedRelations();
validateExpressedRelations(c);
}
return changes;
}
@@ -487,7 +636,7 @@ public class MetadataImport {
* @throws AuthorizeException if there is an authorization problem with permissions
* @throws MetadataImportException custom exception for error handling within metadataimport
*/
protected void compareAndUpdate(Item item, String[] fromCSV, boolean change,
protected void compareAndUpdate(Context c, Item item, String[] fromCSV, boolean change,
String md, BulkEditChange changes, DSpaceCSVLine line)
throws SQLException, AuthorizeException, MetadataImportException {
// Log what metadata element we're looking at
@@ -565,7 +714,7 @@ public class MetadataImport {
// Compare from current->csv
for (int v = 0; v < fromCSV.length; v++) {
String value = fromCSV[v];
BulkEditMetadataValue dcv = getBulkEditValueFromCSV(language, schema, element, qualifier, value,
BulkEditMetadataValue dcv = getBulkEditValueFromCSV(c, language, schema, element, qualifier, value,
fromAuthority);
if (fromAuthority != null) {
value = dcv.getValue() + csv.getAuthoritySeparator() + dcv.getAuthority() + csv
@@ -754,7 +903,8 @@ public class MetadataImport {
// Get the correct RelationshipType based on typeName
List<RelationshipType> relType = relationshipTypeService.findByLeftwardOrRightwardTypeName(c, typeName);
RelationshipType foundRelationshipType = matchRelationshipType(relType,
relationEntityRelationshipType, itemRelationshipType, typeName);
relationEntityRelationshipType,
itemRelationshipType, typeName);
if (foundRelationshipType == null) {
throw new MetadataImportException("Error on CSV row " + rowCount + ":" + "\n" +
@@ -801,7 +951,7 @@ public class MetadataImport {
* @throws IOException Can be thrown when moving items in communities
* @throws MetadataImportException If something goes wrong to be reported back to the user
*/
protected void compare(Item item,
protected void compare(Context c, Item item,
List<String> collections,
List<Collection> actualCollections,
BulkEditChange bechange,
@@ -898,8 +1048,8 @@ public class MetadataImport {
// Remove from old owned collection (if still a member)
if (bechange.getOldOwningCollection() != null) {
boolean found = false;
for (Collection c : item.getCollections()) {
if (c.getID().equals(bechange.getOldOwningCollection().getID())) {
for (Collection collection : item.getCollections()) {
if (collection.getID().equals(bechange.getOldOwningCollection().getID())) {
found = true;
}
}
@@ -926,7 +1076,7 @@ public class MetadataImport {
* @throws SQLException when an SQL error has occurred (querying DSpace)
* @throws AuthorizeException If the user can't make the changes
*/
protected void add(String[] fromCSV, String md, BulkEditChange changes)
protected void add(Context c, String[] fromCSV, String md, BulkEditChange changes)
throws SQLException, AuthorizeException {
// Don't add owning collection or action
if (("collection".equals(md)) || ("action".equals(md))) {
@@ -964,7 +1114,7 @@ public class MetadataImport {
// Add all the values
for (String value : fromCSV) {
BulkEditMetadataValue dcv = getBulkEditValueFromCSV(language, schema, element, qualifier, value,
BulkEditMetadataValue dcv = getBulkEditValueFromCSV(c, language, schema, element, qualifier, value,
fromAuthority);
if (fromAuthority != null) {
value = dcv.getValue() + csv.getAuthoritySeparator() + dcv.getAuthority() + csv
@@ -978,7 +1128,7 @@ public class MetadataImport {
}
}
protected BulkEditMetadataValue getBulkEditValueFromCSV(String language, String schema, String element,
protected BulkEditMetadataValue getBulkEditValueFromCSV(Context c, String language, String schema, String element,
String qualifier, String value,
AuthorityValue fromAuthority) {
// Look to see if it should be removed
@@ -1057,20 +1207,6 @@ public class MetadataImport {
return in.replaceAll("\r\n", "").replaceAll("\n", "").trim();
}
/**
* Print the help message
*
* @param options The command line options the user gave
* @param exitCode the system exit code to use
*/
private static void printHelp(Options options, int exitCode) {
// print the help message
HelpFormatter myhelp = new HelpFormatter();
myhelp.printHelp("MetatadataImport\n", options);
System.out.println("\nmetadataimport: MetadataImport -f filename");
System.exit(exitCode);
}
/**
* Display the changes that have been detected, or that have been made
*
@@ -1078,7 +1214,7 @@ public class MetadataImport {
* @param changed Whether or not the changes have been made
* @return The number of items that have changed
*/
private static int displayChanges(List<BulkEditChange> changes, boolean changed) {
private int displayChanges(List<BulkEditChange> changes, boolean changed) {
// Display the changes
int changeCounter = 0;
for (BulkEditChange change : changes) {
@@ -1093,20 +1229,18 @@ public class MetadataImport {
(change.isDeleted()) || (change.isWithdrawn()) || (change.isReinstated())) {
// Show the item
Item i = change.getItem();
System.out.println("-----------------------------------------------------------");
handler.logInfo("-----------------------------------------------------------");
if (!change.isNewItem()) {
System.out.println("Changes for item: " + i.getID() + " (" + i.getHandle() + ")");
handler.logInfo("Changes for item: " + i.getID() + " (" + i.getHandle() + ")");
} else {
System.out.print("New item: ");
handler.logInfo("New item: ");
if (i != null) {
if (i.getHandle() != null) {
System.out.print(i.getID() + " (" + i.getHandle() + ")");
handler.logInfo(i.getID() + " (" + i.getHandle() + ")");
} else {
System.out.print(i.getID() + " (in workflow)");
handler.logInfo(i.getID() + " (in workflow)");
}
}
System.out.println();
}
changeCounter++;
}
@@ -1114,23 +1248,23 @@ public class MetadataImport {
// Show actions
if (change.isDeleted()) {
if (changed) {
System.out.println(" - EXPUNGED!");
handler.logInfo(" - EXPUNGED!");
} else {
System.out.println(" - EXPUNGE!");
handler.logInfo(" - EXPUNGE!");
}
}
if (change.isWithdrawn()) {
if (changed) {
System.out.println(" - WITHDRAWN!");
handler.logInfo(" - WITHDRAWN!");
} else {
System.out.println(" - WITHDRAW!");
handler.logInfo(" - WITHDRAW!");
}
}
if (change.isReinstated()) {
if (changed) {
System.out.println(" - REINSTATED!");
handler.logInfo(" - REINSTATED!");
} else {
System.out.println(" - REINSTATE!");
handler.logInfo(" - REINSTATE!");
}
}
@@ -1140,11 +1274,11 @@ public class MetadataImport {
String cHandle = c.getHandle();
String cName = c.getName();
if (!changed) {
System.out.print(" + New owning collection (" + cHandle + "): ");
handler.logInfo(" + New owning collection (" + cHandle + "): ");
} else {
System.out.print(" + New owning collection (" + cHandle + "): ");
handler.logInfo(" + New owning collection (" + cHandle + "): ");
}
System.out.println(cName);
handler.logInfo(cName);
}
c = change.getOldOwningCollection();
@@ -1152,11 +1286,11 @@ public class MetadataImport {
String cHandle = c.getHandle();
String cName = c.getName();
if (!changed) {
System.out.print(" + Old owning collection (" + cHandle + "): ");
handler.logInfo(" + Old owning collection (" + cHandle + "): ");
} else {
System.out.print(" + Old owning collection (" + cHandle + "): ");
handler.logInfo(" + Old owning collection (" + cHandle + "): ");
}
System.out.println(cName);
handler.logInfo(cName);
}
}
@@ -1165,11 +1299,11 @@ public class MetadataImport {
String cHandle = c.getHandle();
String cName = c.getName();
if (!changed) {
System.out.print(" + Map to collection (" + cHandle + "): ");
handler.logInfo(" + Map to collection (" + cHandle + "): ");
} else {
System.out.print(" + Mapped to collection (" + cHandle + "): ");
handler.logInfo(" + Mapped to collection (" + cHandle + "): ");
}
System.out.println(cName);
handler.logInfo(cName);
}
// Show old mapped collections
@@ -1177,11 +1311,11 @@ public class MetadataImport {
String cHandle = c.getHandle();
String cName = c.getName();
if (!changed) {
System.out.print(" + Un-map from collection (" + cHandle + "): ");
handler.logInfo(" + Un-map from collection (" + cHandle + "): ");
} else {
System.out.print(" + Un-mapped from collection (" + cHandle + "): ");
handler.logInfo(" + Un-mapped from collection (" + cHandle + "): ");
}
System.out.println(cName);
handler.logInfo(cName);
}
// Show additions
@@ -1194,16 +1328,15 @@ public class MetadataImport {
md += "[" + metadataValue.getLanguage() + "]";
}
if (!changed) {
System.out.print(" + Add (" + md + "): ");
handler.logInfo(" + Add (" + md + "): ");
} else {
System.out.print(" + Added (" + md + "): ");
handler.logInfo(" + Added (" + md + "): ");
}
System.out.print(metadataValue.getValue());
handler.logInfo(metadataValue.getValue());
if (isAuthorityControlledField(md)) {
System.out.print(", authority = " + metadataValue.getAuthority());
System.out.print(", confidence = " + metadataValue.getConfidence());
handler.logInfo(", authority = " + metadataValue.getAuthority());
handler.logInfo(", confidence = " + metadataValue.getConfidence());
}
System.out.println("");
}
// Show removals
@@ -1216,16 +1349,15 @@ public class MetadataImport {
md += "[" + metadataValue.getLanguage() + "]";
}
if (!changed) {
System.out.print(" - Remove (" + md + "): ");
handler.logInfo(" - Remove (" + md + "): ");
} else {
System.out.print(" - Removed (" + md + "): ");
handler.logInfo(" - Removed (" + md + "): ");
}
System.out.print(metadataValue.getValue());
handler.logInfo(metadataValue.getValue());
if (isAuthorityControlledField(md)) {
System.out.print(", authority = " + metadataValue.getAuthority());
System.out.print(", confidence = " + metadataValue.getConfidence());
handler.logInfo(", authority = " + metadataValue.getAuthority());
handler.logInfo(", confidence = " + metadataValue.getConfidence());
}
System.out.println("");
}
}
return changeCounter;
@@ -1243,7 +1375,7 @@ public class MetadataImport {
/**
* Set authority controlled fields
*/
private static void setAuthorizedMetadataFields() {
private void setAuthorizedMetadataFields() {
authorityControlled = new HashSet<String>();
Enumeration propertyNames = ConfigurationManager.getProperties().propertyNames();
while (propertyNames.hasMoreElements()) {
@@ -1255,191 +1387,6 @@ public class MetadataImport {
}
}
/**
* main method to run the metadata exporter
*
* @param argv the command line arguments given
*/
public static void main(String[] argv) {
// Create an options object and populate it
CommandLineParser parser = new PosixParser();
Options options = new Options();
options.addOption("f", "file", true, "source file");
options.addOption("e", "email", true, "email address or user id of user (required if adding new items)");
options.addOption("s", "silent", false,
"silent operation - doesn't request confirmation of changes USE WITH CAUTION");
options.addOption("w", "workflow", false, "workflow - when adding new items, use collection workflow");
options.addOption("n", "notify", false,
"notify - when adding new items using a workflow, send notification emails");
options.addOption("t", "template", false,
"template - when adding new items, use the collection template (if it exists)");
options.addOption("v", "validate-only", false,
"validate - just validate the csv, don't run the import");
options.addOption("h", "help", false, "help");
// Parse the command line arguments
CommandLine line;
try {
line = parser.parse(options, argv);
} catch (ParseException pe) {
System.err.println("Error parsing command line arguments: " + pe.getMessage());
System.exit(1);
return;
}
if (line.hasOption('h')) {
printHelp(options, 0);
}
// Check a filename is given
if (!line.hasOption('f')) {
System.err.println("Required parameter -f missing!");
printHelp(options, 1);
}
String filename = line.getOptionValue('f');
// Option to apply template to new items
boolean useTemplate = false;
if (line.hasOption('t')) {
useTemplate = true;
}
// Options for workflows, and workflow notifications for new items
boolean useWorkflow = false;
boolean workflowNotify = false;
if (line.hasOption('w')) {
useWorkflow = true;
if (line.hasOption('n')) {
workflowNotify = true;
}
} else if (line.hasOption('n')) {
System.err.println("Invalid option 'n': (notify) can only be specified with the 'w' (workflow) option.");
System.exit(1);
}
// Create a context
Context c;
try {
c = new Context();
c.turnOffAuthorisationSystem();
} catch (Exception e) {
System.err.println("Unable to create a new DSpace Context: " + e.getMessage());
System.exit(1);
return;
}
// Find the EPerson, assign to context
try {
if (line.hasOption('e')) {
EPerson eperson;
String e = line.getOptionValue('e');
if (e.indexOf('@') != -1) {
eperson = EPersonServiceFactory.getInstance().getEPersonService().findByEmail(c, e);
} else {
eperson = EPersonServiceFactory.getInstance().getEPersonService().find(c, UUID.fromString(e));
}
if (eperson == null) {
System.out.println("Error, eperson cannot be found: " + e);
System.exit(1);
}
c.setCurrentUser(eperson);
}
} catch (Exception e) {
System.err.println("Unable to find DSpace user: " + e.getMessage());
System.exit(1);
return;
}
// Is this a silent run?
boolean change = false;
// Read lines from the CSV file
DSpaceCSV csv;
try {
csv = new DSpaceCSV(new File(filename), c);
} catch (MetadataImportInvalidHeadingException miihe) {
System.err.println(miihe.getMessage());
System.exit(1);
return;
} catch (Exception e) {
System.err.println("Error reading file: " + e.getMessage());
System.exit(1);
return;
}
// Perform the first import - just highlight differences
MetadataImport importer = new MetadataImport(c, csv);
List<BulkEditChange> changes;
boolean validateOnly = line.hasOption('v');
if (!line.hasOption('s') || validateOnly) {
// See what has changed
try {
changes = importer.runImport(false, useWorkflow, workflowNotify, useTemplate);
} catch (MetadataImportException mie) {
System.err.println("Error: " + mie.getMessage());
System.exit(1);
return;
}
// Display the changes
int changeCounter = displayChanges(changes, false);
// If there were changes, ask if we should execute them
if (!validateOnly && changeCounter > 0) {
try {
// Ask the user if they want to make the changes
System.out.println("\n" + changeCounter + " item(s) will be changed\n");
System.out.print("Do you want to make these changes? [y/n] ");
String yn = (new BufferedReader(new InputStreamReader(System.in))).readLine();
if ("y".equalsIgnoreCase(yn)) {
change = true;
} else {
System.out.println("No data has been changed.");
}
} catch (IOException ioe) {
System.err.println("Error: " + ioe.getMessage());
System.err.println("No changes have been made");
System.exit(1);
}
} else {
System.out.println("There were no changes detected");
}
} else {
change = true;
}
try {
// If required, make the change
if (change && !validateOnly) {
try {
// Make the changes
changes = importer.runImport(true, useWorkflow, workflowNotify, useTemplate);
} catch (MetadataImportException mie) {
System.err.println("Error: " + mie.getMessage());
System.exit(1);
return;
}
// Display the changes
displayChanges(changes, true);
}
// Finsh off and tidy up
c.restoreAuthSystemState();
c.complete();
} catch (Exception e) {
c.abort();
System.err.println("Error committing changes to database: " + e.getMessage());
System.err.println("Aborting most recent changes.");
System.exit(1);
}
}
/**
* Gets a copy of the given csv line with all entity target references resolved to UUID strings.
* Keys being iterated over represent metadatafields or special columns to be processed.
@@ -1448,7 +1395,7 @@ public class MetadataImport {
* @return a copy, with all references resolved.
* @throws MetadataImportException if there is an error resolving any entity target reference.
*/
public DSpaceCSVLine resolveEntityRefs(DSpaceCSVLine line) throws MetadataImportException {
public DSpaceCSVLine resolveEntityRefs(Context c, DSpaceCSVLine line) throws MetadataImportException {
DSpaceCSVLine newLine = new DSpaceCSVLine(line.getID());
UUID originId = evaluateOriginId(line.getID());
for (String key : line.keys()) {
@@ -1630,7 +1577,8 @@ public class MetadataImport {
if (uuid == null) {
throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
"No matches found for reference: " + reference
+ "\nKeep in mind you can only reference entries that are listed before " +
+ "\nKeep in mind you can only reference entries that are " +
"listed before " +
"this one within the CSV.");
} else {
return uuid; // one match from db
@@ -1688,14 +1636,16 @@ public class MetadataImport {
* Validate every relation modification expressed in the CSV.
*
*/
private void validateExpressedRelations() throws MetadataImportException {
private void validateExpressedRelations(Context c) throws MetadataImportException {
for (String targetUUID : entityRelationMap.keySet()) {
String targetType = null;
try {
// Get the type of reference. Attempt lookup in processed map first before looking in archive.
if (entityTypeMap.get(UUID.fromString(targetUUID)) != null) {
targetType = entityTypeService.
findByEntityType(c, entityTypeMap.get(UUID.fromString(targetUUID))).getLabel();
findByEntityType(c,
entityTypeMap.get(UUID.fromString(targetUUID)))
.getLabel();
} else {
// Target item may be archived; check there.
// Add to errors if Realtionship.type cannot be derived
@@ -1703,7 +1653,8 @@ public class MetadataImport {
if (itemService.find(c, UUID.fromString(targetUUID)) != null) {
targetItem = itemService.find(c, UUID.fromString(targetUUID));
List<MetadataValue> relTypes = itemService.
getMetadata(targetItem, "relationship", "type", null, Item.ANY);
getMetadata(targetItem, "relationship", "type",
null, Item.ANY);
String relTypeValue = null;
if (relTypes.size() > 0) {
relTypeValue = relTypes.get(0).getValue();
@@ -1739,7 +1690,7 @@ public class MetadataImport {
// Attempt lookup in processed map first before looking in archive.
if (entityTypeMap.get(UUID.fromString(originRefererUUID)) != null) {
originType = entityTypeMap.get(UUID.fromString(originRefererUUID));
validateTypesByTypeByTypeName(targetType, originType, typeName, originRow);
validateTypesByTypeByTypeName(c, targetType, originType, typeName, originRow);
} else {
// Origin item may be archived; check there.
// Add to errors if Realtionship.type cannot be derived.
@@ -1747,12 +1698,13 @@ public class MetadataImport {
if (itemService.find(c, UUID.fromString(targetUUID)) != null) {
originItem = itemService.find(c, UUID.fromString(originRefererUUID));
List<MetadataValue> relTypes = itemService.
getMetadata(originItem, "relationship", "type", null, Item.ANY);
getMetadata(originItem, "relationship",
"type", null, Item.ANY);
String relTypeValue = null;
if (relTypes.size() > 0) {
relTypeValue = relTypes.get(0).getValue();
originType = entityTypeService.findByEntityType(c, relTypeValue).getLabel();
validateTypesByTypeByTypeName(targetType, originType, typeName, originRow);
validateTypesByTypeByTypeName(c, targetType, originType, typeName, originRow);
} else {
relationValidationErrors.add("Error on CSV row " + originRow + ":" + "\n" +
"Cannot resolve Entity type for reference: "
@@ -1791,12 +1743,14 @@ public class MetadataImport {
* @param typeName left or right typeName of the respective Relationship.
* @return the UUID of the item.
*/
private void validateTypesByTypeByTypeName(String targetType, String originType, String typeName, String originRow)
private void validateTypesByTypeByTypeName(Context c,
String targetType, String originType, String typeName, String originRow)
throws MetadataImportException {
try {
RelationshipType foundRelationshipType = null;
List<RelationshipType> relationshipTypeList = relationshipTypeService.
findByLeftwardOrRightwardTypeName(c, typeName.split("\\.")[1]);
findByLeftwardOrRightwardTypeName(
c, typeName.split("\\.")[1]);
// Validate described relationship form the CSV.
foundRelationshipType = matchRelationshipType(relationshipTypeList, targetType, originType, typeName);
if (foundRelationshipType == null) {

View File

@@ -0,0 +1,33 @@
/**
* 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.bulkedit;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
/**
* CLI variant for the {@link MetadataImport} class
* This has been made so that we can specify the behaviour of the determineChanges method to be specific for the CLI
*/
public class MetadataImportCLI extends MetadataImport {
@Override
protected boolean determineChange(DSpaceRunnableHandler handler) throws IOException {
handler.logInfo("Do you want to make these changes? [y/n] ");
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in))) {
String yn = bufferedReader.readLine();
if ("y".equalsIgnoreCase(yn)) {
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,16 @@
/**
* 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.bulkedit;
import org.dspace.scripts.configuration.ScriptConfiguration;
/**
* The {@link ScriptConfiguration} for the {@link org.dspace.app.bulkedit.MetadataImportCLI} CLI script
*/
public class MetadataImportCliScriptConfiguration extends MetadataImportScriptConfiguration<MetadataImportCLI> {
}

View File

@@ -0,0 +1,84 @@
/**
* 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.bulkedit;
import java.io.InputStream;
import java.sql.SQLException;
import org.apache.commons.cli.Options;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.core.Context;
import org.dspace.scripts.configuration.ScriptConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
/**
* The {@link ScriptConfiguration} for the {@link MetadataImport} script
*/
public class MetadataImportScriptConfiguration<T extends MetadataImport> extends ScriptConfiguration<T> {
@Autowired
private AuthorizeService authorizeService;
private Class<T> dspaceRunnableClass;
@Override
public Class<T> getDspaceRunnableClass() {
return dspaceRunnableClass;
}
/**
* Generic setter for the dspaceRunnableClass
* @param dspaceRunnableClass The dspaceRunnableClass to be set on this MetadataImportScriptConfiguration
*/
@Override
public void setDspaceRunnableClass(Class<T> dspaceRunnableClass) {
this.dspaceRunnableClass = dspaceRunnableClass;
}
@Override
public boolean isAllowedToExecute(Context context) {
try {
return authorizeService.isAdmin(context);
} catch (SQLException e) {
throw new RuntimeException("SQLException occurred when checking if the current user is an admin", e);
}
}
@Override
public Options getOptions() {
if (options == null) {
Options options = new Options();
options.addOption("f", "file", true, "source file");
options.getOption("f").setType(InputStream.class);
options.getOption("f").setRequired(true);
options.addOption("e", "email", true, "email address or user id of user (required if adding new items)");
options.getOption("e").setType(String.class);
options.getOption("e").setRequired(true);
options.addOption("s", "silent", false,
"silent operation - doesn't request confirmation of changes USE WITH CAUTION");
options.getOption("s").setType(boolean.class);
options.addOption("w", "workflow", false, "workflow - when adding new items, use collection workflow");
options.getOption("w").setType(boolean.class);
options.addOption("n", "notify", false,
"notify - when adding new items using a workflow, send notification emails");
options.getOption("n").setType(boolean.class);
options.addOption("v", "validate-only", false,
"validate - just validate the csv, don't run the import");
options.getOption("v").setType(boolean.class);
options.addOption("t", "template", false,
"template - when adding new items, use the collection template (if it exists)");
options.getOption("t").setType(boolean.class);
options.addOption("h", "help", false, "help");
options.getOption("h").setType(boolean.class);
super.options = options;
}
return options;
}
}

View File

@@ -16,9 +16,11 @@ import java.util.TreeMap;
import org.apache.commons.cli.ParseException;
import org.apache.log4j.Logger;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.scripts.configuration.ScriptConfiguration;
import org.dspace.scripts.factory.ScriptServiceFactory;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
import org.dspace.scripts.handler.impl.CommandLineDSpaceRunnableHandler;
import org.dspace.scripts.service.ScriptService;
import org.dspace.servicemanager.DSpaceKernelImpl;
import org.dspace.servicemanager.DSpaceKernelInit;
import org.dspace.services.RequestService;
@@ -44,7 +46,8 @@ public class ScriptLauncher {
/**
* Default constructor
*/
private ScriptLauncher() { }
private ScriptLauncher() {
}
/**
* Execute the DSpace script launcher
@@ -54,7 +57,7 @@ public class ScriptLauncher {
* @throws FileNotFoundException if file doesn't exist
*/
public static void main(String[] args)
throws FileNotFoundException, IOException {
throws FileNotFoundException, IOException, IllegalAccessException, InstantiationException {
// Initialise the service manager kernel
try {
kernelImpl = DSpaceKernelInit.getKernel(null);
@@ -111,9 +114,14 @@ public class ScriptLauncher {
*/
public static int handleScript(String[] args, Document commandConfigs,
DSpaceRunnableHandler dSpaceRunnableHandler,
DSpaceKernelImpl kernelImpl) {
DSpaceKernelImpl kernelImpl) throws InstantiationException, IllegalAccessException {
int status;
DSpaceRunnable script = ScriptServiceFactory.getInstance().getScriptService().getScriptForName(args[0]);
ScriptService scriptService = ScriptServiceFactory.getInstance().getScriptService();
ScriptConfiguration scriptConfiguration = scriptService.getScriptConfiguration(args[0]);
DSpaceRunnable script = null;
if (scriptConfiguration != null) {
script = scriptService.createDSpaceRunnableForScriptConfiguration(scriptConfiguration);
}
if (script != null) {
status = executeScript(args, dSpaceRunnableHandler, script);
} else {
@@ -132,7 +140,7 @@ public class ScriptLauncher {
private static int executeScript(String[] args, DSpaceRunnableHandler dSpaceRunnableHandler,
DSpaceRunnable script) {
try {
script.initialize(args, dSpaceRunnableHandler);
script.initialize(args, dSpaceRunnableHandler, null);
script.run();
return 0;
} catch (ParseException e) {

View File

@@ -590,8 +590,11 @@ public class AuthorizeUtil {
authorizeManageAdminGroup(context, collection);
return;
}
// if we reach this point, it means that the group is related
// to a collection but as it is not the submitters, nor the administrators,
// nor a workflow groups it must be a default item/bitstream groups
authorizeManageDefaultReadGroup(context, collection);
return;
}
if (parentObject.getType() == Constants.COMMUNITY) {
Community community = (Community) parentObject;
@@ -601,4 +604,38 @@ public class AuthorizeUtil {
throw new AuthorizeException("not authorized to manage this group");
}
/**
* This method checks if the community Admin can manage accounts
*
* @return true if is able
*/
public static boolean canCommunityAdminManageAccounts() {
boolean isAble = false;
if (AuthorizeConfiguration.canCommunityAdminManagePolicies()
|| AuthorizeConfiguration.canCommunityAdminManageAdminGroup()
|| AuthorizeConfiguration.canCommunityAdminManageCollectionPolicies()
|| AuthorizeConfiguration.canCommunityAdminManageCollectionSubmitters()
|| AuthorizeConfiguration.canCommunityAdminManageCollectionWorkflows()
|| AuthorizeConfiguration.canCommunityAdminManageCollectionAdminGroup()) {
isAble = true;
}
return isAble;
}
/**
* This method checks if the Collection Admin can manage accounts
*
* @return true if is able
*/
public static boolean canCollectionAdminManageAccounts() {
boolean isAble = false;
if (AuthorizeConfiguration.canCollectionAdminManagePolicies()
|| AuthorizeConfiguration.canCollectionAdminManageSubmitters()
|| AuthorizeConfiguration.canCollectionAdminManageWorkflows()
|| AuthorizeConfiguration.canCollectionAdminManageAdminGroup()) {
isAble = true;
}
return isAble;
}
}

View File

@@ -430,7 +430,11 @@ public class AuthorizeServiceImpl implements AuthorizeService {
public boolean isCommunityAdmin(Context c) throws SQLException {
EPerson e = c.getCurrentUser();
return isCommunityAdmin(c, e);
}
@Override
public boolean isCommunityAdmin(Context c, EPerson e) throws SQLException {
if (e != null) {
List<ResourcePolicy> policies = resourcePolicyService.find(c, e,
groupService.allMemberGroups(c, e),
@@ -446,7 +450,11 @@ public class AuthorizeServiceImpl implements AuthorizeService {
public boolean isCollectionAdmin(Context c) throws SQLException {
EPerson e = c.getCurrentUser();
return isCollectionAdmin(c, e);
}
@Override
public boolean isCollectionAdmin(Context c, EPerson e) throws SQLException {
if (e != null) {
List<ResourcePolicy> policies = resourcePolicyService.find(c, e,
groupService.allMemberGroups(c, e),

View File

@@ -213,6 +213,26 @@ public interface AuthorizeService {
public boolean isCollectionAdmin(Context c) throws SQLException;
/**
* Check to see if a specific user is Community admin
*
* @param c current context
* @param e the user to check
* @return true if user is an admin of some community
* @throws SQLException
*/
public boolean isCommunityAdmin(Context c, EPerson e) throws SQLException;
/**
* Check to see if a specific user is Collection admin
*
* @param c current context
* @param e the user to check
* @return true if user is an admin of some collection
* @throws SQLException if database error
*/
public boolean isCollectionAdmin(Context c, EPerson e) throws SQLException;
///////////////////////////////////////////////
// policy manipulation methods
///////////////////////////////////////////////

View File

@@ -17,11 +17,13 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Set;
import java.util.UUID;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.apache.solr.client.solrj.util.ClientUtils;
import org.dspace.app.util.AuthorizeUtil;
import org.dspace.authorize.AuthorizeConfiguration;
import org.dspace.authorize.AuthorizeException;
@@ -40,6 +42,13 @@ import org.dspace.core.Context;
import org.dspace.core.I18nUtil;
import org.dspace.core.LogManager;
import org.dspace.core.service.LicenseService;
import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.DiscoverResult;
import org.dspace.discovery.IndexableObject;
import org.dspace.discovery.SearchService;
import org.dspace.discovery.SearchServiceException;
import org.dspace.discovery.indexobject.IndexableCollection;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.eperson.service.GroupService;
import org.dspace.eperson.service.SubscribeService;
@@ -100,6 +109,9 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl<Collection> i
@Autowired(required = true)
protected CollectionRoleService collectionRoleService;
@Autowired(required = true)
protected SearchService searchService;
protected CollectionServiceImpl() {
super();
}
@@ -907,4 +919,77 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl<Collection> i
return role;
}
@Override
public List<Collection> findCollectionsWithSubmit(String q, Context context, Community community,
int offset, int limit) throws SQLException, SearchServiceException {
List<Collection> collections = new ArrayList<Collection>();
DiscoverQuery discoverQuery = new DiscoverQuery();
discoverQuery.setDSpaceObjectFilter(IndexableCollection.TYPE);
discoverQuery.setStart(offset);
discoverQuery.setMaxResults(limit);
DiscoverResult resp = retrieveCollectionsWithSubmit(context, discoverQuery,community, q);
for (IndexableObject solrCollections : resp.getIndexableObjects()) {
Collection c = ((IndexableCollection) solrCollections).getIndexedObject();
collections.add(c);
}
return collections;
}
@Override
public int countCollectionsWithSubmit(String q, Context context, Community community)
throws SQLException, SearchServiceException {
DiscoverQuery discoverQuery = new DiscoverQuery();
discoverQuery.setMaxResults(0);
discoverQuery.setDSpaceObjectFilter(IndexableCollection.TYPE);
DiscoverResult resp = retrieveCollectionsWithSubmit(context, discoverQuery,community,q);
return (int)resp.getTotalSearchResults();
}
/**
* Finds all Indexed Collections where the current user has submit rights. If the user is an Admin,
* this is all Indexed Collections. Otherwise, it includes those collections where
* an indexed "submit" policy lists either the eperson or one of the eperson's groups
*
* @param context DSpace context
* @param discoverQuery
* @param community parent community, could be null
* @param q limit the returned collection to those with metadata values matching the query
* terms. The terms are used to make also a prefix query on SOLR
* so it can be used to implement an autosuggest feature over the collection name
* @return discovery search result objects
* @throws SQLException if something goes wrong
* @throws SearchServiceException if search error
*/
private DiscoverResult retrieveCollectionsWithSubmit(Context context, DiscoverQuery discoverQuery,
Community community, String q) throws SQLException, SearchServiceException {
StringBuilder query = new StringBuilder();
EPerson currentUser = context.getCurrentUser();
if (!authorizeService.isAdmin(context)) {
String userId = "";
if (currentUser != null) {
userId = currentUser.getID().toString();
}
query.append("submit:(e").append(userId);
Set<Group> groups = groupService.allMemberGroupsSet(context, currentUser);
for (Group group : groups) {
query.append(" OR g").append(group.getID());
}
query.append(")");
discoverQuery.addFilterQueries(query.toString());
}
if (community != null) {
discoverQuery.addFilterQueries("location.comm:" + community.getID().toString());
}
if (StringUtils.isNotBlank(q)) {
StringBuilder buildQuery = new StringBuilder();
String escapedQuery = ClientUtils.escapeQueryChars(q);
buildQuery.append(escapedQuery).append(" OR ").append(escapedQuery).append("*");
discoverQuery.setQuery(buildQuery.toString());
}
DiscoverResult resp = searchService.search(context, discoverQuery);
return resp;
}
}

View File

@@ -0,0 +1,129 @@
/**
* 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.content;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.google.common.collect.Iterators;
import org.dspace.app.bulkedit.DSpaceCSV;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.MetadataDSpaceCsvExportService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Implementation of {@link MetadataDSpaceCsvExportService}
*/
public class MetadataDSpaceCsvExportServiceImpl implements MetadataDSpaceCsvExportService {
@Autowired
private ItemService itemService;
@Override
public DSpaceCSV handleExport(Context context, boolean exportAllItems, boolean exportAllMetadata, String handle,
DSpaceRunnableHandler handler) throws Exception {
Iterator<Item> toExport = null;
if (exportAllItems) {
handler.logInfo("Exporting whole repository WARNING: May take some time!");
toExport = itemService.findAll(context);
} else {
DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(context, handle);
if (dso == null) {
throw new IllegalArgumentException(
"Item '" + handle + "' does not resolve to an item in your repository!");
}
if (dso.getType() == Constants.ITEM) {
handler.logInfo("Exporting item '" + dso.getName() + "' (" + handle + ")");
List<Item> item = new ArrayList<>();
item.add((Item) dso);
toExport = item.iterator();
} else if (dso.getType() == Constants.COLLECTION) {
handler.logInfo("Exporting collection '" + dso.getName() + "' (" + handle + ")");
Collection collection = (Collection) dso;
toExport = itemService.findByCollection(context, collection);
} else if (dso.getType() == Constants.COMMUNITY) {
handler.logInfo("Exporting community '" + dso.getName() + "' (" + handle + ")");
toExport = buildFromCommunity(context, (Community) dso);
} else {
throw new IllegalArgumentException("Error identifying '" + handle + "'");
}
}
DSpaceCSV csv = this.export(context, toExport, exportAllMetadata);
return csv;
}
@Override
public DSpaceCSV export(Context context, Iterator<Item> toExport, boolean exportAll) throws Exception {
Context.Mode originalMode = context.getCurrentMode();
context.setMode(Context.Mode.READ_ONLY);
// Process each item
DSpaceCSV csv = new DSpaceCSV(exportAll);
while (toExport.hasNext()) {
Item item = toExport.next();
csv.addItem(item);
context.uncacheEntity(item);
}
context.setMode(originalMode);
// Return the results
return csv;
}
@Override
public DSpaceCSV export(Context context, Community community, boolean exportAll) throws Exception {
return export(context, buildFromCommunity(context, community), exportAll);
}
/**
* Build an array list of item ids that are in a community (include sub-communities and collections)
*
* @param context DSpace context
* @param community The community to build from
* @return The list of item ids
* @throws SQLException if database error
*/
private Iterator<Item> buildFromCommunity(Context context, Community community)
throws SQLException {
// Add all the collections
List<Collection> collections = community.getCollections();
Iterator<Item> result = null;
for (Collection collection : collections) {
Iterator<Item> items = itemService.findByCollection(context, collection);
result = addItemsToResult(result, items);
}
// Add all the sub-communities
List<Community> communities = community.getSubcommunities();
for (Community subCommunity : communities) {
Iterator<Item> items = buildFromCommunity(context, subCommunity);
result = addItemsToResult(result, items);
}
return result;
}
private Iterator<Item> addItemsToResult(Iterator<Item> result, Iterator<Item> items) {
if (result == null) {
result = items;
} else {
result = Iterators.concat(result, items);
}
return result;
}
}

View File

@@ -20,8 +20,10 @@ import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.core.Context;
import org.dspace.discovery.SearchServiceException;
import org.dspace.eperson.Group;
/**
* Service interface class for the Collection object.
* The implementation of this class is responsible for all business logic calls for the Collection object and is
@@ -354,4 +356,42 @@ public interface CollectionService
*/
Group createDefaultReadGroup(Context context, Collection collection, String typeOfGroupString, int defaultRead)
throws SQLException, AuthorizeException;
/**
* Returns Collections for which the current user has 'submit' privileges.
* NOTE: for better performance, this method retrieves its results from an
* index (cache) and does not query the database directly.
* This means that results may be stale or outdated until DS-4524 is resolved"
*
* @param q limit the returned collection to those with metadata values matching the query terms.
* The terms are used to make also a prefix query on SOLR so it can be used to implement
* an autosuggest feature over the collection name
* @param context DSpace Context
* @param community parent community
* @param offset the position of the first result to return
* @param limit paging limit
* @return discovery search result objects
* @throws SQLException if something goes wrong
* @throws SearchServiceException if search error
*/
public List<Collection> findCollectionsWithSubmit(String q, Context context, Community community,
int offset, int limit) throws SQLException, SearchServiceException;
/**
* Counts the number of Collection for which the current user has 'submit' privileges.
* NOTE: for better performance, this method retrieves its results from an index (cache)
* and does not query the database directly.
* This means that results may be stale or outdated until DS-4524 is resolved."
*
* @param q limit the returned collection to those with metadata values matching the query terms.
* The terms are used to make also a prefix query on SOLR so it can be used to implement
* an autosuggest feature over the collection name
* @param context DSpace Context
* @param community parent community
* @return total collections found
* @throws SQLException if something goes wrong
* @throws SearchServiceException if search error
*/
public int countCollectionsWithSubmit(String q, Context context, Community community)
throws SQLException, SearchServiceException;
}

View File

@@ -0,0 +1,58 @@
/**
* 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.content.service;
import java.util.Iterator;
import org.dspace.app.bulkedit.DSpaceCSV;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.core.Context;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
/**
* This is the interface to be implemented by a Service that deals with the exporting of Metadata
*/
public interface MetadataDSpaceCsvExportService {
/**
* This method will export DSpaceObject objects depending on the parameters it gets. It can export all the items
* in the repository, all the items in a community, all the items in a collection or a specific item. The latter
* three are specified by the handle parameter. The entire repository can be exported by defining the
* exportAllItems parameter as true
* @param context The relevant DSpace context
* @param exportAllItems A boolean indicating whether or not the entire repository should be exported
* @param exportAllMetadata Defines if all metadata should be exported or only the allowed ones
* @param handle The handle for the DSpaceObject to be exported, can be a Community, Collection or Item
* @return A DSpaceCSV object containing the exported information
* @throws Exception If something goes wrong
*/
public DSpaceCSV handleExport(Context context, boolean exportAllItems, boolean exportAllMetadata,
String handle, DSpaceRunnableHandler dSpaceRunnableHandler) throws Exception;
/**
* This method will export all the Items in the given toExport iterator to a DSpaceCSV
* @param context The relevant DSpace context
* @param toExport The iterator containing the items to export
* @param exportAll Defines if all metadata should be exported or only the allowed ones
* @return A DSpaceCSV object containing the exported information
* @throws Exception If something goes wrong
*/
public DSpaceCSV export(Context context, Iterator<Item> toExport, boolean exportAll) throws Exception;
/**
* This method will export all the Items within the given Community to a DSpaceCSV
* @param context The relevant DSpace context
* @param community The Community that contains the Items to be exported
* @param exportAll Defines if all metadata should be exported or only the allowed ones
* @return A DSpaceCSV object containing the exported information
* @throws Exception If something goes wrong
*/
public DSpaceCSV export(Context context, Community community, boolean exportAll) throws Exception;
}

View File

@@ -14,7 +14,6 @@ import java.util.Optional;
import java.util.UUID;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
@@ -30,17 +29,18 @@ import org.dspace.discovery.indexobject.factory.IndexFactory;
import org.dspace.discovery.indexobject.factory.IndexObjectFactoryFactory;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.scripts.DSpaceRunnable;
import org.springframework.beans.factory.annotation.Autowired;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.utils.DSpace;
/**
* Class used to reindex dspace communities/collections/items into discovery
*/
public class IndexClient extends DSpaceRunnable {
public class IndexClient extends DSpaceRunnable<IndexDiscoveryScriptConfiguration> {
private Context context;
@Autowired
private IndexingService indexer;
private IndexingService indexer = DSpaceServicesFactory.getInstance().getServiceManager()
.getServiceByName(IndexingService.class.getName(),
IndexingService.class);
private IndexClientOptions indexClientOptions;
@@ -144,6 +144,12 @@ public class IndexClient extends DSpaceRunnable {
handler.logInfo("Done with indexing");
}
@Override
public IndexDiscoveryScriptConfiguration getScriptConfiguration() {
return new DSpace().getServiceManager().getServiceByName("index-discovery",
IndexDiscoveryScriptConfiguration.class);
}
public void setup() throws ParseException {
try {
context = new Context(Context.Mode.READ_ONLY);
@@ -151,18 +157,8 @@ public class IndexClient extends DSpaceRunnable {
} catch (Exception e) {
throw new ParseException("Unable to create a new DSpace Context: " + e.getMessage());
}
indexClientOptions = IndexClientOptions.getIndexClientOption(commandLine);
}
/**
* Constructor for this class. This will ensure that the Options are created and set appropriately.
*/
private IndexClient() {
Options options = IndexClientOptions.constructOptions();
this.options = options;
}
/**
* Indexes the given object and all children, if applicable.
*

View File

@@ -0,0 +1,58 @@
/**
* 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.discovery;
import java.sql.SQLException;
import org.apache.commons.cli.Options;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.core.Context;
import org.dspace.scripts.configuration.ScriptConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
/**
* The {@link ScriptConfiguration} for the {@link IndexClient} script
*/
public class IndexDiscoveryScriptConfiguration<T extends IndexClient> extends ScriptConfiguration<T> {
@Autowired
private AuthorizeService authorizeService;
private Class<T> dspaceRunnableClass;
@Override
public Class<T> getDspaceRunnableClass() {
return dspaceRunnableClass;
}
@Override
public boolean isAllowedToExecute(Context context) {
try {
return authorizeService.isAdmin(context);
} catch (SQLException e) {
throw new RuntimeException("SQLException occurred when checking if the current user is an admin", e);
}
}
@Override
public Options getOptions() {
if (options == null) {
super.options = IndexClientOptions.constructOptions();
}
return options;
}
/**
* Generic setter for the dspaceRunnableClass
* @param dspaceRunnableClass The dspaceRunnableClass to be set on this IndexDiscoveryScriptConfiguration
*/
@Override
public void setDspaceRunnableClass(Class<T> dspaceRunnableClass) {
this.dspaceRunnableClass = dspaceRunnableClass;
}
}

View File

@@ -0,0 +1,76 @@
/**
* 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.discovery;
import java.sql.SQLException;
import java.util.List;
import org.apache.logging.log4j.Logger;
import org.apache.solr.common.SolrInputDocument;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.discovery.indexobject.IndexableCollection;
import org.springframework.beans.factory.annotation.Autowired;
/**
* The purpose of this plugin is to index all ADD type resource policies related to collections.
*
* @author Mykhaylo Boychuk (at 4science.it)
*/
public class SolrServiceIndexCollectionSubmittersPlugin implements SolrServiceIndexPlugin {
private static final Logger log = org.apache.logging.log4j.LogManager
.getLogger(SolrServiceIndexCollectionSubmittersPlugin.class);
@Autowired(required = true)
protected AuthorizeService authorizeService;
@Override
public void additionalIndex(Context context, IndexableObject idxObj, SolrInputDocument document) {
if (idxObj instanceof IndexableCollection) {
Collection col = ((IndexableCollection) idxObj).getIndexedObject();
if (col != null) {
try {
String fieldValue = null;
Community parent = (Community) ContentServiceFactory.getInstance().getDSpaceObjectService(col)
.getParentObject(context, col);
while (parent != null) {
if (parent.getAdministrators() != null) {
fieldValue = "g" + parent.getAdministrators().getID();
document.addField("submit", fieldValue);
}
parent = (Community) ContentServiceFactory.getInstance().getDSpaceObjectService(parent)
.getParentObject(context, parent);
}
List<ResourcePolicy> policies = authorizeService.getPoliciesActionFilter(context, col,
Constants.ADD);
for (ResourcePolicy resourcePolicy : policies) {
if (resourcePolicy.getGroup() != null) {
fieldValue = "g" + resourcePolicy.getGroup().getID();
} else {
fieldValue = "e" + resourcePolicy.getEPerson().getID();
}
document.addField("submit", fieldValue);
context.uncacheEntity(resourcePolicy);
}
} catch (SQLException e) {
log.error(LogManager.getHeader(context, "Error while indexing resource policies",
"Collection: (id " + col.getID() + " type " + col.getName() + ")" ));
}
}
}
}
}

View File

@@ -23,7 +23,9 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.dspace.authorize.AuthorizeConfiguration;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.authorize.service.ResourcePolicyService;
import org.dspace.content.Collection;
import org.dspace.content.DSpaceObject;
import org.dspace.content.DSpaceObjectServiceImpl;
@@ -76,6 +78,8 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl<Group> implements
@Autowired(required = true)
protected AuthorizeService authorizeService;
@Autowired(required = true)
protected ResourcePolicyService resourcePolicyService;
protected GroupServiceImpl() {
super();
@@ -654,6 +658,23 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl<Group> implements
return collectionService.getParentObject(context, collection);
}
}
} else {
if (AuthorizeConfiguration.canCollectionAdminManagePolicies()
|| AuthorizeConfiguration.canCommunityAdminManagePolicies()
|| AuthorizeConfiguration.canCommunityAdminManageCollectionWorkflows()) {
List<Group> groups = new ArrayList<Group>();
groups.add(group);
List<ResourcePolicy> policies = resourcePolicyService.find(context, null, groups,
Constants.DEFAULT_ITEM_READ, Constants.COLLECTION);
if (policies.size() > 0) {
return policies.get(0).getdSpaceObject();
}
policies = resourcePolicyService.find(context, null, groups,
Constants.DEFAULT_BITSTREAM_READ, Constants.COLLECTION);
if (policies.size() > 0) {
return policies.get(0).getdSpaceObject();
}
}
}
}
if (AuthorizeConfiguration.canCommunityAdminManageAdminGroup()) {

View File

@@ -8,6 +8,8 @@
package org.dspace.license;
import java.util.List;
/**
* @author wbossons
*/
@@ -15,17 +17,17 @@ public class CCLicense {
private String licenseName;
private String licenseId;
private int order = 0;
private List<CCLicenseField> ccLicenseFieldList;
public CCLicense() {
super();
}
public CCLicense(String licenseId, String licenseName, int order) {
public CCLicense(String licenseId, String licenseName, List<CCLicenseField> ccLicenseFieldList) {
super();
this.licenseId = licenseId;
this.licenseName = licenseName;
this.order = order;
this.ccLicenseFieldList = ccLicenseFieldList;
}
public String getLicenseName() {
@@ -44,13 +46,19 @@ public class CCLicense {
this.licenseId = licenseId;
}
public int getOrder() {
return this.order;
/**
* Gets the list of CC License Fields
* @return the list of CC License Fields
*/
public List<CCLicenseField> getCcLicenseFieldList() {
return ccLicenseFieldList;
}
public void setOrder(int order) {
this.order = order;
/**
* Sets the list of CC License Fields
* @param ccLicenseFieldList
*/
public void setCcLicenseFieldList(final List<CCLicenseField> ccLicenseFieldList) {
this.ccLicenseFieldList = ccLicenseFieldList;
}
}

View File

@@ -0,0 +1,60 @@
/**
* 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.license;
import java.io.IOException;
import java.util.Map;
import org.jdom.Document;
/**
* Service interface class for the Creative commons license connector service.
* The implementation of this class is responsible for all the calls to the CC license API and parsing the response
* The service is autowired by spring
*/
public interface CCLicenseConnectorService {
/**
* Retrieves the CC Licenses for the provided language from the CC License API
*
* @param language - the language to retrieve the licenses for
* @return a map of licenses with the id and the license for the provided language
*/
public Map<String, CCLicense> retrieveLicenses(String language);
/**
* Retrieve the CC License URI based on the provided license id, language and answers to the field questions from
* the CC License API
*
* @param licenseId - the ID of the license
* @param language - the language for which to retrieve the full answerMap
* @param answerMap - the answers to the different field questions
* @return the CC License URI
*/
public String retrieveRightsByQuestion(String licenseId,
String language,
Map<String, String> answerMap);
/**
* Retrieve the license RDF document based on the license URI
*
* @param licenseURI - The license URI for which to retrieve the license RDF document
* @return the license RDF document
* @throws IOException
*/
public Document retrieveLicenseRDFDoc(String licenseURI) throws IOException;
/**
* Retrieve the license Name from the license document
*
* @param doc - The license document from which to retrieve the license name
* @return the license name
*/
public String retrieveLicenseName(final Document doc);
}

View File

@@ -0,0 +1,371 @@
/**
* 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.license;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.services.ConfigurationService;
import org.jaxen.JaxenException;
import org.jaxen.jdom.JDOMXPath;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.xml.sax.InputSource;
/**
* Implementation for the Creative commons license connector service.
* This class is responsible for all the calls to the CC license API and parsing the response
*/
public class CCLicenseConnectorServiceImpl implements CCLicenseConnectorService, InitializingBean {
private Logger log = org.apache.logging.log4j.LogManager.getLogger(CCLicenseConnectorServiceImpl.class);
private CloseableHttpClient client;
protected SAXBuilder parser = new SAXBuilder();
private String postArgument = "answers";
private String postAnswerFormat =
"<answers> " +
"<locale>{1}</locale>" +
"<license-{0}>" +
"{2}" +
"</license-{0}>" +
"</answers>";
@Autowired
private ConfigurationService configurationService;
@Override
public void afterPropertiesSet() throws Exception {
HttpClientBuilder builder = HttpClientBuilder.create();
client = builder
.disableAutomaticRetries()
.setMaxConnTotal(5)
.build();
}
/**
* Retrieves the CC Licenses for the provided language from the CC License API
*
* @param language - the language to retrieve the licenses for
* @return a map of licenses with the id and the license for the provided language
*/
public Map<String, CCLicense> retrieveLicenses(String language) {
String ccLicenseUrl = configurationService.getProperty("cc.api.rooturl");
String uri = ccLicenseUrl + "/?locale=" + language;
HttpGet httpGet = new HttpGet(uri);
List<String> licenses;
try (CloseableHttpResponse response = client.execute(httpGet)) {
licenses = retrieveLicenses(response);
} catch (JDOMException | JaxenException | IOException e) {
log.error("Error while retrieving the license details using url: " + uri, e);
licenses = Collections.emptyList();
}
Map<String, CCLicense> ccLicenses = new HashMap<>();
for (String license : licenses) {
String licenseUri = ccLicenseUrl + "/license/" + license;
HttpGet licenseHttpGet = new HttpGet(licenseUri);
try (CloseableHttpResponse response = client.execute(licenseHttpGet)) {
CCLicense ccLicense = retrieveLicenseObject(license, response);
ccLicenses.put(ccLicense.getLicenseId(), ccLicense);
} catch (JaxenException | JDOMException | IOException e) {
log.error("Error while retrieving the license details using url: " + licenseUri, e);
}
}
return ccLicenses;
}
/**
* Retrieve the list of licenses from the response from the CC License API and remove the licenses configured
* to be excluded
*
* @param response The response from the API
* @return a list of license identifiers for which details need to be retrieved
* @throws IOException
* @throws JaxenException
* @throws JDOMException
*/
private List<String> retrieveLicenses(CloseableHttpResponse response)
throws IOException, JaxenException, JDOMException {
List<String> domains = new LinkedList<>();
String[] excludedLicenses = configurationService.getArrayProperty("cc.license.classfilter");
String responseString = EntityUtils.toString(response.getEntity());
JDOMXPath licenseClassXpath = new JDOMXPath("//licenses/license");
try (StringReader stringReader = new StringReader(responseString)) {
InputSource is = new InputSource(stringReader);
org.jdom.Document classDoc = this.parser.build(is);
List<Element> elements = licenseClassXpath.selectNodes(classDoc);
for (Element element : elements) {
String licenseId = getSingleNodeValue(element, "@id");
if (StringUtils.isNotBlank(licenseId) && !ArrayUtils.contains(excludedLicenses, licenseId)) {
domains.add(licenseId);
}
}
}
return domains;
}
/**
* Parse the response for a single CC License and return the corresponding CC License Object
*
* @param licenseId the license id of the CC License to retrieve
* @param response for a specific CC License response
* @return the corresponding CC License Object
* @throws IOException
* @throws JaxenException
* @throws JDOMException
*/
private CCLicense retrieveLicenseObject(final String licenseId, CloseableHttpResponse response)
throws IOException, JaxenException, JDOMException {
String responseString = EntityUtils.toString(response.getEntity());
JDOMXPath licenseClassXpath = new JDOMXPath("//licenseclass");
JDOMXPath licenseFieldXpath = new JDOMXPath("field");
try (StringReader stringReader = new StringReader(responseString)) {
InputSource is = new InputSource(stringReader);
org.jdom.Document classDoc = this.parser.build(is);
Object element = licenseClassXpath.selectSingleNode(classDoc);
String licenseLabel = getSingleNodeValue(element, "label");
List<CCLicenseField> ccLicenseFields = new LinkedList<>();
List<Element> licenseFields = licenseFieldXpath.selectNodes(element);
for (Element licenseField : licenseFields) {
CCLicenseField ccLicenseField = parseLicenseField(licenseField);
ccLicenseFields.add(ccLicenseField);
}
return new CCLicense(licenseId, licenseLabel, ccLicenseFields);
}
}
private CCLicenseField parseLicenseField(final Element licenseField) throws JaxenException {
String id = getSingleNodeValue(licenseField, "@id");
String label = getSingleNodeValue(licenseField, "label");
String description = getSingleNodeValue(licenseField, "description");
JDOMXPath enumXpath = new JDOMXPath("enum");
List<Element> enums = enumXpath.selectNodes(licenseField);
List<CCLicenseFieldEnum> ccLicenseFieldEnumList = new LinkedList<>();
for (Element enumElement : enums) {
CCLicenseFieldEnum ccLicenseFieldEnum = parseEnum(enumElement);
ccLicenseFieldEnumList.add(ccLicenseFieldEnum);
}
return new CCLicenseField(id, label, description, ccLicenseFieldEnumList);
}
private CCLicenseFieldEnum parseEnum(final Element enumElement) throws JaxenException {
String id = getSingleNodeValue(enumElement, "@id");
String label = getSingleNodeValue(enumElement, "label");
String description = getSingleNodeValue(enumElement, "description");
return new CCLicenseFieldEnum(id, label, description);
}
private String getNodeValue(final Object el) {
if (el instanceof Element) {
return ((Element) el).getValue();
} else if (el instanceof Attribute) {
return ((Attribute) el).getValue();
} else if (el instanceof String) {
return (String) el;
} else {
return null;
}
}
private String getSingleNodeValue(final Object t, String query) throws JaxenException {
JDOMXPath xpath = new JDOMXPath(query);
Object singleNode = xpath.selectSingleNode(t);
return getNodeValue(singleNode);
}
/**
* Retrieve the CC License URI based on the provided license id, language and answers to the field questions from
* the CC License API
*
* @param licenseId - the ID of the license
* @param language - the language for which to retrieve the full answerMap
* @param answerMap - the answers to the different field questions
* @return the CC License URI
*/
public String retrieveRightsByQuestion(String licenseId,
String language,
Map<String, String> answerMap) {
String ccLicenseUrl = configurationService.getProperty("cc.api.rooturl");
HttpPost httpPost = new HttpPost(ccLicenseUrl + "/license/" + licenseId + "/issue");
String answers = createAnswerString(answerMap);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
String text = MessageFormat.format(postAnswerFormat, licenseId, language, answers);
builder.addTextBody(postArgument, text);
HttpEntity multipart = builder.build();
httpPost.setEntity(multipart);
try (CloseableHttpResponse response = client.execute(httpPost)) {
return retrieveLicenseUri(response);
} catch (JDOMException | JaxenException | IOException e) {
log.error("Error while retrieving the license uri for license : " + licenseId + " with answers "
+ answerMap.toString(), e);
}
return null;
}
/**
* Parse the response for the CC License URI request and return the corresponding CC License URI
*
* @param response for a specific CC License URI response
* @return the corresponding CC License URI as a string
* @throws IOException
* @throws JaxenException
* @throws JDOMException
*/
private String retrieveLicenseUri(final CloseableHttpResponse response)
throws IOException, JaxenException, JDOMException {
String responseString = EntityUtils.toString(response.getEntity());
JDOMXPath licenseClassXpath = new JDOMXPath("//result/license-uri");
try (StringReader stringReader = new StringReader(responseString)) {
InputSource is = new InputSource(stringReader);
org.jdom.Document classDoc = this.parser.build(is);
Object node = licenseClassXpath.selectSingleNode(classDoc);
String nodeValue = getNodeValue(node);
if (StringUtils.isNotBlank(nodeValue)) {
return nodeValue;
}
}
return null;
}
private String createAnswerString(final Map<String, String> parameterMap) {
StringBuilder sb = new StringBuilder();
for (String key : parameterMap.keySet()) {
sb.append("<");
sb.append(key);
sb.append(">");
sb.append(parameterMap.get(key));
sb.append("</");
sb.append(key);
sb.append(">");
}
return sb.toString();
}
/**
* Retrieve the license RDF document based on the license URI
*
* @param licenseURI - The license URI for which to retrieve the license RDF document
* @return the license RDF document
* @throws IOException
*/
@Override
public Document retrieveLicenseRDFDoc(String licenseURI) throws IOException {
String ccLicenseUrl = configurationService.getProperty("cc.api.rooturl");
String issueUrl = ccLicenseUrl + "/details?license-uri=" + licenseURI;
URL request_url;
try {
request_url = new URL(issueUrl);
} catch (MalformedURLException e) {
return null;
}
URLConnection connection = request_url.openConnection();
connection.setDoOutput(true);
try {
// parsing document from input stream
InputStream stream = connection.getInputStream();
Document doc = parser.build(stream);
return doc;
} catch (Exception e) {
log.error("Error while retrieving the license document for URI: " + licenseURI, e);
}
return null;
}
/**
* Retrieve the license Name from the license document
*
* @param doc - The license document from which to retrieve the license name
* @return the license name
*/
public String retrieveLicenseName(final Document doc) {
try {
return getSingleNodeValue(doc, "//result/license-name");
} catch (JaxenException e) {
log.error("Error while retrieving the license name from the license document", e);
}
return null;
}
}

View File

@@ -7,8 +7,7 @@
*/
package org.dspace.license;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
/**
* Wrapper class for representation of a license field declaration.
@@ -22,7 +21,7 @@ public class CCLicenseField {
private String description = "";
private String type = "";
private HashMap fieldEnum = null;
private List<CCLicenseFieldEnum> fieldEnum = null;
/**
* Construct a new LicenseField class. Note that after construction,
@@ -31,13 +30,11 @@ public class CCLicenseField {
* @param id The unique identifier for this field; this value will be used in constructing the answers XML.
* @param label The label to use when generating the user interface.
*/
public CCLicenseField(String id, String label) {
super();
this.fieldEnum = new HashMap();
public CCLicenseField(String id, String label, String description, List<CCLicenseFieldEnum> fieldEnum) {
this.id = id;
this.label = label;
this.description = description;
this.fieldEnum = fieldEnum;
}
/**
@@ -90,16 +87,12 @@ public class CCLicenseField {
}
/**
* @return Returns an instance implementing the Map interface;
* the instance contains a mapping from identifiers to
* labels for the enumeration values.
* @see Map
* Returns the list of enums of this field
* @return the list of enums of this field
*/
public Map<String, String> getEnum() {
return this.fieldEnum;
}
public List<CCLicenseFieldEnum> getFieldEnum() {
return fieldEnum;
}
}

View File

@@ -0,0 +1,82 @@
/**
* 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.license;
import org.apache.commons.lang3.StringUtils;
/**
* Wrapper class for representation of a license field enum declaration.
* A field enum is a single "answer" to the field question
*/
public class CCLicenseFieldEnum {
private String id = "";
private String label = "";
private String description = "";
public CCLicenseFieldEnum(String id, String label, String description) {
if (StringUtils.isNotBlank(id)) {
this.id = id;
}
if (StringUtils.isNotBlank(label)) {
this.label = label;
}
if (StringUtils.isNotBlank(description)) {
this.description = description;
}
}
/**
* Get the id of this enum
* @return the id of this enum
*/
public String getId() {
return id;
}
/**
* Set the id of this enum
* @param id
*/
public void setId(final String id) {
this.id = id;
}
/**
* Get the label of this enum
* @return the label of this enum
*/
public String getLabel() {
return label;
}
/**
* Set the label of this enum
* @param label
*/
public void setLabel(final String label) {
this.label = label;
}
/**
* Get the description of this enum
* @return the description of this enum
*/
public String getDescription() {
return description;
}
/**
* Set the description of this enum
* @param description
*/
public void setDescription(final String description) {
this.description = description;
}
}

View File

@@ -1,435 +0,0 @@
/**
* 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.license;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import org.apache.logging.log4j.Logger;
import org.dspace.license.factory.LicenseServiceFactory;
import org.dspace.license.service.CreativeCommonsService;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.jaxen.JaxenException;
import org.jaxen.jdom.JDOMXPath;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
/**
* A wrapper around Creative Commons REST web services.
*
* @author Wendy Bossons
*/
public class CCLookup {
/**
* log4j logger
*/
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(CCLookup.class);
private String cc_root;
private String jurisdiction;
private List<String> lcFilter = new ArrayList<String>();
private Document license_doc = null;
private String rdfString = null;
private String errorMessage = null;
private boolean success = false;
private SAXBuilder parser = new SAXBuilder();
private List<CCLicense> licenses = new ArrayList<CCLicense>();
private List<CCLicenseField> licenseFields = new ArrayList<CCLicenseField>();
protected CreativeCommonsService creativeCommonsService = LicenseServiceFactory.getInstance()
.getCreativeCommonsService();
/**
* Constructs a new instance with the default web services root.
*/
public CCLookup() {
super();
ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
cc_root = configurationService.getProperty("cc.api.rooturl");
String jurisProp = configurationService.getProperty("cc.license.jurisdiction");
jurisdiction = (jurisProp != null) ? jurisProp : "";
String[] filters = configurationService.getArrayProperty("cc.license.classfilter");
if (filters != null) {
for (String name : filters) {
lcFilter.add(name.trim());
}
}
}
/**
* Returns the id for a particular CCLicense label. Returns an
* empty string if no match is found.
*
* @param class_label The CCLicense label to find.
* @return Returns a String containing the License class ID if the label
* is found; if not found, returns an empty string.
* @see CCLicense
*/
public String getLicenseId(String class_label) {
for (int i = 0; i < this.licenses.size(); i++) {
if (((CCLicense) this.licenses.get(i)).getLicenseName().equals(class_label)) {
return ((CCLicense) this.licenses.get(i)).getLicenseId();
}
}
return "";
}
/**
* Queries the web service for the available licenses.
*
* @param language The language to request labels and description strings in.
* @return Returns a Map of CCLicense objects.
* @see Map
* @see CCLicense
*/
public Collection<CCLicense> getLicenses(String language) {
// create XPath expressions
try {
JDOMXPath xp_Licenses = new JDOMXPath("//licenses/license");
JDOMXPath xp_LicenseID = new JDOMXPath("@id");
URL classUrl = new URL(this.cc_root + "/?locale=" + language);
Document classDoc = this.parser.build(classUrl);
// extract the identifiers and labels using XPath
List<Element> results = xp_Licenses.selectNodes(classDoc);
// populate licenses container
this.licenses.clear();
for (int i = 0; i < results.size(); i++) {
Element license = results.get(i);
// add if not filtered
String liD = ((Attribute) xp_LicenseID.selectSingleNode(license)).getValue();
if (!lcFilter.contains(liD)) {
this.licenses.add(new CCLicense(liD, license.getText(), i));
}
}
} catch (JaxenException jaxen_e) {
return null;
} catch (JDOMException jdom_e) {
return null;
} catch (IOException io_e) {
return null;
} catch (Exception e) {
// do nothing... but we should
return null;
}
return licenses;
}
/**
* Queries the web service for a set of licenseFields for a particular license class.
*
* @param license A String specifying the CCLicense identifier to
* retrieve fields for.
* @param language the locale string
* @return A Collection of LicenseField objects.
* @see CCLicense
*/
public Collection<CCLicenseField> getLicenseFields(String license, String language) {
JDOMXPath xp_LicenseField;
JDOMXPath xp_LicenseID;
JDOMXPath xp_FieldType;
JDOMXPath xp_Description;
JDOMXPath xp_Label;
JDOMXPath xp_Enum;
Document fieldDoc;
URL classUrl;
List results = null;
List enumOptions = null;
// create XPath expressions
try {
xp_LicenseField = new JDOMXPath("//field");
xp_LicenseID = new JDOMXPath("@id");
xp_Description = new JDOMXPath("description");
xp_Label = new JDOMXPath("label");
xp_FieldType = new JDOMXPath("type");
xp_Enum = new JDOMXPath("enum");
} catch (JaxenException e) {
return null;
}
// retrieve and parse the license class document
try {
classUrl = new URL(this.cc_root + "/license/" + license + "?locale=" + language);
} catch (Exception err) {
// do nothing... but we should
return null;
}
// parse the licenses document
try {
fieldDoc = this.parser.build(classUrl);
} catch (JDOMException e) {
return null;
} catch (IOException e) {
return null;
}
// reset the field definition container
this.licenseFields.clear();
// extract the identifiers and labels using XPath
try {
results = xp_LicenseField.selectNodes(fieldDoc);
} catch (JaxenException e) {
return null;
}
for (int i = 0; i < results.size(); i++) {
Element field = (Element) results.get(i);
try {
// create the field object
CCLicenseField cclicensefield = new CCLicenseField(
((Attribute) xp_LicenseID.selectSingleNode(field)).getValue(),
((Element) xp_Label.selectSingleNode(field)).getText());
// extract additional properties
cclicensefield.setDescription(((Element) xp_Description.selectSingleNode(field)).getText());
cclicensefield.setType(((Element) xp_FieldType.selectSingleNode(field)).getText());
enumOptions = xp_Enum.selectNodes(field);
for (int j = 0; j < enumOptions.size(); j++) {
String id = ((Attribute) xp_LicenseID.selectSingleNode(enumOptions.get(j))).getValue();
String label = ((Element) xp_Label.selectSingleNode(enumOptions.get(j))).getText();
cclicensefield.getEnum().put(id, label);
} // for each enum option
this.licenseFields.add(cclicensefield);
} catch (JaxenException e) {
return null;
}
}
return licenseFields;
} // licenseFields
/**
* Passes a set of "answers" to the web service and retrieves a license.
*
* @param licenseId The identifier of the license class being requested.
* @param answers A Map containing the answers to the license fields;
* each key is the identifier of a LicenseField, with the value
* containing the user-supplied answer.
* @param lang The language to request localized elements in.
* @throws IOException if IO error
* @see CCLicense
* @see Map
*/
public void issue(String licenseId, Map answers, String lang)
throws IOException {
// Determine the issue URL
String issueUrl = this.cc_root + "/license/" + licenseId + "/issue";
// Assemble the "answers" document
String answer_doc = "<answers>\n<locale>" + lang + "</locale>\n" + "<license-" + licenseId + ">\n";
Iterator keys = answers.keySet().iterator();
try {
String current = (String) keys.next();
while (true) {
answer_doc += "<" + current + ">" + (String) answers.get(current) + "</" + current + ">\n";
current = (String) keys.next();
}
} catch (NoSuchElementException e) {
// exception indicates we've iterated through the
// entire collection; just swallow and continue
}
// answer_doc += "<jurisdiction></jurisidiction>\n"; FAILS with jurisdiction argument
answer_doc += "</license-" + licenseId + ">\n</answers>\n";
String post_data;
try {
post_data = URLEncoder.encode("answers", "UTF-8") + "=" + URLEncoder.encode(answer_doc, "UTF-8");
} catch (UnsupportedEncodingException e) {
return;
}
URL post_url;
try {
post_url = new URL(issueUrl);
} catch (MalformedURLException e) {
return;
}
URLConnection connection = post_url.openConnection();
// this will not be needed after I'm done TODO: remove
connection.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(post_data);
writer.flush();
// end TODO
try {
// parsing document from input stream
java.io.InputStream stream = connection.getInputStream();
this.license_doc = this.parser.build(stream);
} catch (JDOMException jde) {
log.warn(jde.getMessage());
} catch (Exception e) {
log.warn(e.getCause());
}
return;
} // issue
/**
* Passes a set of "answers" to the web service and retrieves a license.
*
* @param licenseURI The uri of the license.
*
* Note: does not support localization in 1.5 -- not yet
* @throws IOException if IO error
* @see CCLicense
* @see Map
*/
public void issue(String licenseURI)
throws IOException {
// Determine the issue URL
// Example: http://api.creativecommons.org/rest/1.5/details?
// license-uri=http://creativecommons.org/licenses/by-nc-sa/3.0/
String issueUrl = cc_root + "/details?license-uri=" + licenseURI;
URL request_url;
try {
request_url = new URL(issueUrl);
} catch (MalformedURLException e) {
return;
}
URLConnection connection = request_url.openConnection();
// this will not be needed after I'm done TODO: remove
connection.setDoOutput(true);
try {
// parsing document from input stream
java.io.InputStream stream = connection.getInputStream();
license_doc = this.parser.build(stream);
} catch (JDOMException jde) {
log.warn(jde.getMessage());
} catch (Exception e) {
log.warn(e.getCause());
}
return;
} // issue
/**
* Retrieves the URI for the license issued.
*
* @return A String containing the URI for the license issued.
*/
public String getLicenseUrl() {
String text = null;
try {
JDOMXPath xp_LicenseName = new JDOMXPath("//result/license-uri");
text = ((Element) xp_LicenseName.selectSingleNode(this.license_doc)).getText();
} catch (Exception e) {
log.warn(e.getMessage());
setSuccess(false);
text = "An error occurred getting the license - uri.";
} finally {
return text;
}
} // getLicenseUrl
/**
* Retrieves the human readable name for the license issued.
*
* @return A String containing the license name.
*/
public String getLicenseName() {
String text = null;
try {
JDOMXPath xp_LicenseName = new JDOMXPath("//result/license-name");
text = ((Element) xp_LicenseName.selectSingleNode(this.license_doc)).getText();
} catch (Exception e) {
log.warn(e.getMessage());
setSuccess(false);
text = "An error occurred on the license name.";
} finally {
return text;
}
} // getLicenseName
public org.jdom.Document getLicenseDocument() {
return this.license_doc;
}
public String getRdf()
throws IOException {
String result = "";
try {
result = creativeCommonsService.fetchLicenseRDF(license_doc);
} catch (Exception e) {
log.warn("An error occurred getting the rdf . . ." + e.getMessage());
setSuccess(false);
}
return result;
}
public boolean isSuccess() {
setSuccess(false);
JDOMXPath xp_Success;
String text = null;
try {
xp_Success = new JDOMXPath("//message");
text = ((Element) xp_Success.selectSingleNode(this.license_doc)).getText();
setErrorMessage(text);
} catch (Exception e) {
log.warn("There was an issue . . . " + text);
setSuccess(true);
}
return this.success;
}
private void setSuccess(boolean success) {
this.success = success;
}
public String getErrorMessage() {
return this.errorMessage;
}
private void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}

View File

@@ -13,7 +13,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
@@ -82,9 +85,18 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
protected BundleService bundleService;
@Autowired(required = true)
protected ItemService itemService;
@Autowired
protected CCLicenseConnectorService ccLicenseConnectorService;
protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
private String defaultLanguage;
private String jurisdiction;
private static final String JURISDICTION_KEY = "jurisdiction";
private Map<String, Map<String, CCLicense>> ccLicenses;
protected CreativeCommonsServiceImpl() {
}
@@ -101,6 +113,10 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
System.setProperty("http.proxyPort", proxyPort);
}
ccLicenses = new HashMap<>();
defaultLanguage = configurationService.getProperty("cc.license.locale", "en");
jurisdiction = configurationService.getProperty("cc.license.jurisdiction", "");
try {
templates = TransformerFactory.newInstance().newTemplates(
new StreamSource(CreativeCommonsServiceImpl.class
@@ -112,11 +128,6 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
}
@Override
public boolean isEnabled() {
return true;
}
// create the CC bundle if it doesn't exist
// If it does, remove it and create a new one.
protected Bundle getCcBundle(Context context, Item item)
@@ -168,8 +179,17 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
}
/**
* Removes the license file from the item
*
* @param context - The relevant DSpace Context
* @param item - The item from which the license file needs to be removed
* @throws SQLException
* @throws IOException
* @throws AuthorizeException
*/
@Override
public void removeLicense(Context context, Item item)
public void removeLicenseFile(Context context, Item item)
throws SQLException, IOException, AuthorizeException {
// remove CC license bundle if one exists
List<Bundle> bundles = itemService.getBundles(item, CC_BUNDLE_NAME);
@@ -179,34 +199,6 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
}
}
@Override
public boolean hasLicense(Context context, Item item)
throws SQLException, IOException {
// try to find CC license bundle
List<Bundle> bundles = itemService.getBundles(item, CC_BUNDLE_NAME);
if (bundles.size() == 0) {
return false;
}
// verify it has correct contents
try {
if ((getLicenseURL(context, item) == null)) {
return false;
}
} catch (AuthorizeException ae) {
return false;
}
return true;
}
@Override
public String getLicenseRDF(Context context, Item item) throws SQLException,
IOException, AuthorizeException {
return getStringFromBitstream(context, item, BSN_LICENSE_RDF);
}
@Override
public Bitstream getLicenseRdfBitstream(Item item) throws SQLException,
IOException, AuthorizeException {
@@ -222,15 +214,51 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
@Override
public String getLicenseURL(Context context, Item item) throws SQLException, IOException, AuthorizeException {
String licenseUri = getCCField("uri").ccItemValue(item);
String licenseUri = getCCField("uri");
if (StringUtils.isNotBlank(licenseUri)) {
return licenseUri;
return getLicenseURI(item);
}
// JSPUI backward compatibility see https://jira.duraspace.org/browse/DS-2604
return getStringFromBitstream(context, item, BSN_LICENSE_URL);
}
/**
* Returns the stored license uri of the item
*
* @param item - The item for which to retrieve the stored license uri
* @return the stored license uri of the item
*/
@Override
public String getLicenseURI(Item item) {
String licenseUriField = getCCField("uri");
if (StringUtils.isNotBlank(licenseUriField)) {
String metadata = itemService.getMetadata(item, licenseUriField);
if (StringUtils.isNotBlank(metadata)) {
return metadata;
}
}
return null;
}
/**
* Returns the stored license name of the item
*
* @param item - The item for which to retrieve the stored license name
* @return the stored license name of the item
*/
@Override
public String getLicenseName( Item item) {
String licenseNameField = getCCField("name");
if (StringUtils.isNotBlank(licenseNameField)) {
String metadata = itemService.getMetadata(item, licenseNameField);
if (StringUtils.isNotBlank(metadata)) {
return metadata;
}
}
return null;
}
@Override
public String fetchLicenseRDF(Document license) {
StringWriter result = new StringWriter();
@@ -361,26 +389,322 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
* Returns a metadata field handle for given field Id
*/
@Override
public LicenseMetadataValue getCCField(String fieldId) {
return new LicenseMetadataValue(configurationService.getProperty("cc.license." + fieldId));
public String getCCField(String fieldId) {
return configurationService.getProperty("cc.license." + fieldId);
}
/**
* Remove license information, delete also the bitstream
*
* @param context - DSpace Context
* @param item - the item
* @throws AuthorizeException Exception indicating the current user of the context does not have permission
* to perform a particular action.
* @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
* @throws SQLException An exception that provides information on a database access error or other errors.
*/
@Override
public void removeLicense(Context context, LicenseMetadataValue uriField,
LicenseMetadataValue nameField, Item item)
public void removeLicense(Context context, Item item)
throws AuthorizeException, IOException, SQLException {
String uriField = getCCField("uri");
String nameField = getCCField("name");
String licenseUri = itemService.getMetadata(item, uriField);
// only remove any previous licenses
String licenseUri = uriField.ccItemValue(item);
if (licenseUri != null) {
uriField.removeItemValue(context, item, licenseUri);
removeLicenseField(context, item, uriField);
if (configurationService.getBooleanProperty("cc.submit.setname")) {
String licenseName = nameField.keyedItemValue(item, licenseUri);
nameField.removeItemValue(context, item, licenseName);
removeLicenseField(context, item, nameField);
}
if (configurationService.getBooleanProperty("cc.submit.addbitstream")) {
removeLicense(context, item);
removeLicenseFile(context, item);
}
}
}
private void removeLicenseField(Context context, Item item, String field) throws SQLException {
String[] params = splitField(field);
itemService.clearMetadata(context, item, params[0], params[1], params[2], params[3]);
}
private void addLicenseField(Context context, Item item, String field, String value) throws SQLException {
String[] params = splitField(field);
itemService.addMetadata(context, item, params[0], params[1], params[2], params[3], value);
}
/**
* Find all CC Licenses using the default language found in the configuration
*
* @return A list of available CC Licenses
*/
@Override
public List<CCLicense> findAllCCLicenses() {
return findAllCCLicenses(defaultLanguage);
}
/**
* Find all CC Licenses for the provided language
*
* @param language - the language for which to find the CC Licenses
* @return A list of available CC Licenses for the provided language
*/
@Override
public List<CCLicense> findAllCCLicenses(String language) {
if (!ccLicenses.containsKey(language)) {
initLicenses(language);
}
return new LinkedList<>(ccLicenses.get(language).values());
}
/**
* Find the CC License corresponding to the provided ID using the default language found in the configuration
*
* @param id - the ID of the license to be found
* @return the corresponding license if found or null when not found
*/
@Override
public CCLicense findOne(String id) {
return findOne(id, defaultLanguage);
}
/**
* Find the CC License corresponding to the provided ID and provided language
*
* @param id - the ID of the license to be found
* @param language - the language for which to find the CC License
* @return the corresponding license if found or null when not found
*/
@Override
public CCLicense findOne(String id, String language) {
if (!ccLicenses.containsKey(language)) {
initLicenses(language);
}
Map<String, CCLicense> licenseMap = ccLicenses.get(language);
if (licenseMap.containsKey(id)) {
return licenseMap.get(id);
}
return null;
}
/**
* Retrieves the licenses for a specific language and cache them in this service
*
* @param language - the language for which to find the CC Licenses
*/
private void initLicenses(final String language) {
Map<String, CCLicense> licenseMap = ccLicenseConnectorService.retrieveLicenses(language);
ccLicenses.put(language, licenseMap);
}
/**
* Retrieve the CC License URI for the provided license ID, based on the provided answers, using the default
* language found in the configuration
*
* @param licenseId - the ID of the license
* @param answerMap - the answers to the different field questions
* @return the corresponding license URI
*/
@Override
public String retrieveLicenseUri(String licenseId, Map<String, String> answerMap) {
return retrieveLicenseUri(licenseId, defaultLanguage, answerMap);
}
/**
* Retrieve the CC License URI for the provided license ID and language based on the provided answers
*
* @param licenseId - the ID of the license
* @param language - the language for which to find the CC License URI
* @param answerMap - the answers to the different field questions
* @return the corresponding license URI
*/
@Override
public String retrieveLicenseUri(String licenseId, String language, Map<String, String> answerMap) {
return ccLicenseConnectorService.retrieveRightsByQuestion(licenseId, language, answerMap);
}
/**
* Verify whether the answer map contains a valid response to all field questions and no answers that don't have a
* corresponding question in the license, using the default language found in the config to check the license
*
* @param licenseId - the ID of the license
* @param fullAnswerMap - the answers to the different field questions
* @return whether the information is valid
*/
@Override
public boolean verifyLicenseInformation(String licenseId, Map<String, String> fullAnswerMap) {
return verifyLicenseInformation(licenseId, defaultLanguage, fullAnswerMap);
}
/**
* Verify whether the answer map contains a valid response to all field questions and no answers that don't have a
* corresponding question in the license, using the provided language to check the license
*
* @param licenseId - the ID of the license
* @param language - the language for which to retrieve the full answerMap
* @param fullAnswerMap - the answers to the different field questions
* @return whether the information is valid
*/
@Override
public boolean verifyLicenseInformation(String licenseId, String language, Map<String, String> fullAnswerMap) {
CCLicense ccLicense = findOne(licenseId, language);
List<CCLicenseField> ccLicenseFieldList = ccLicense.getCcLicenseFieldList();
for (String field : fullAnswerMap.keySet()) {
CCLicenseField ccLicenseField = findCCLicenseField(field, ccLicenseFieldList);
if (ccLicenseField == null) {
return false;
}
if (!containsAnswerEnum(fullAnswerMap.get(field), ccLicenseField)) {
return false;
}
}
return true;
}
/**
* Retrieve the full answer map containing empty values when an answer for a field was not provided in the
* answerMap, using the default language found in the configuration
*
* @param licenseId - the ID of the license
* @param answerMap - the answers to the different field questions
* @return the answerMap supplemented with all other license fields with a blank answer
*/
@Override
public Map<String, String> retrieveFullAnswerMap(String licenseId, Map<String, String> answerMap) {
return retrieveFullAnswerMap(licenseId, defaultLanguage, answerMap);
}
/**
* Retrieve the full answer map for a provided language, containing empty values when an answer for a field was not
* provided in the answerMap.
*
* @param licenseId - the ID of the license
* @param language - the language for which to retrieve the full answerMap
* @param answerMap - the answers to the different field questions
* @return the answerMap supplemented with all other license fields with a blank answer for the provided language
*/
@Override
public Map<String, String> retrieveFullAnswerMap(String licenseId, String language, Map<String, String> answerMap) {
CCLicense ccLicense = findOne(licenseId, language);
if (ccLicense == null) {
return null;
}
Map<String, String> fullParamMap = new HashMap<>(answerMap);
List<CCLicenseField> ccLicenseFieldList = ccLicense.getCcLicenseFieldList();
for (CCLicenseField ccLicenseField : ccLicenseFieldList) {
if (!fullParamMap.containsKey(ccLicenseField.getId())) {
fullParamMap.put(ccLicenseField.getId(), "");
}
}
updateJurisdiction(fullParamMap);
return fullParamMap;
}
private void updateJurisdiction(final Map<String, String> fullParamMap) {
if (fullParamMap.containsKey(JURISDICTION_KEY)) {
fullParamMap.put(JURISDICTION_KEY, jurisdiction);
}
}
private boolean containsAnswerEnum(final String enumAnswer, final CCLicenseField ccLicenseField) {
List<CCLicenseFieldEnum> fieldEnums = ccLicenseField.getFieldEnum();
for (CCLicenseFieldEnum fieldEnum : fieldEnums) {
if (StringUtils.equals(fieldEnum.getId(), enumAnswer)) {
return true;
}
}
return false;
}
private CCLicenseField findCCLicenseField(final String field, final List<CCLicenseField> ccLicenseFieldList) {
for (CCLicenseField ccLicenseField : ccLicenseFieldList) {
if (StringUtils.equals(ccLicenseField.getId(), field)) {
return ccLicenseField;
}
}
return null;
}
/**
* Update the license of the item with a new one based on the provided license URI
*
* @param context - The relevant DSpace context
* @param licenseUri - The license URI to be used in the update
* @param item - The item for which to update the license
* @return true when the update was successful, false when not
* @throws AuthorizeException
* @throws SQLException
*/
@Override
public boolean updateLicense(final Context context, final String licenseUri, final Item item)
throws AuthorizeException, SQLException {
try {
Document doc = ccLicenseConnectorService.retrieveLicenseRDFDoc(licenseUri);
if (doc == null) {
return false;
}
String licenseName = ccLicenseConnectorService.retrieveLicenseName(doc);
if (StringUtils.isBlank(licenseName)) {
return false;
}
removeLicense(context, item);
addLicense(context, item, licenseUri, licenseName, doc);
return true;
} catch (IOException e) {
log.error("Error while updating the license of item: " + item.getID(), e);
}
return false;
}
/**
* Add a new license to the item
*
* @param context - The relevant Dspace context
* @param item - The item to which the license will be added
* @param licenseUri - The license URI to add
* @param licenseName - The license name to add
* @param doc - The license to document to add
* @throws SQLException
* @throws IOException
* @throws AuthorizeException
*/
@Override
public void addLicense(Context context, Item item, String licenseUri, String licenseName, Document doc)
throws SQLException, IOException, AuthorizeException {
String uriField = getCCField("uri");
String nameField = getCCField("name");
addLicenseField(context, item, uriField, licenseUri);
if (configurationService.getBooleanProperty("cc.submit.addbitstream")) {
setLicenseRDF(context, item, fetchLicenseRDF(doc));
}
if (configurationService.getBooleanProperty("cc.submit.setname")) {
addLicenseField(context, item, nameField, licenseName);
}
}
private String[] splitField(String fieldName) {
String[] params = new String[4];
String[] fParams = fieldName.split("\\.");
for (int i = 0; i < fParams.length; i++) {
params[i] = fParams[i];
}
params[3] = Item.ANY;
return params;
}
}

View File

@@ -1,129 +0,0 @@
/**
* 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.license;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Item;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
/**
* Helper class for using CC-related Metadata fields
*
* @author kevinvandevelde at atmire.com
*/
public class LicenseMetadataValue {
protected final ItemService itemService;
// Shibboleth for Creative Commons license data - i.e. characters that reliably indicate CC in a URI
protected static final String ccShib = "creativecommons";
private String[] params = new String[4];
public LicenseMetadataValue(String fieldName) {
if (fieldName != null && fieldName.length() > 0) {
String[] fParams = fieldName.split("\\.");
for (int i = 0; i < fParams.length; i++) {
params[i] = fParams[i];
}
params[3] = Item.ANY;
}
itemService = ContentServiceFactory.getInstance().getItemService();
}
/**
* Returns first value that matches Creative Commons 'shibboleth',
* or null if no matching values.
* NB: this method will succeed only for metadata fields holding CC URIs
*
* @param item - the item to read
* @return value - the first CC-matched value, or null if no such value
*/
public String ccItemValue(Item item) {
List<MetadataValue> dcvalues = itemService.getMetadata(item, params[0], params[1], params[2], params[3]);
for (MetadataValue dcvalue : dcvalues) {
if ((dcvalue.getValue()).indexOf(ccShib) != -1) {
// return first value that matches the shib
return dcvalue.getValue();
}
}
return null;
}
/**
* Returns the value that matches the value mapped to the passed key if any.
* NB: this only delivers a license name (if present in field) given a license URI
*
* @param item - the item to read
* @param key - the key for desired value
* @return value - the value associated with key or null if no such value
* @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
* @throws SQLException An exception that provides information on a database access error or other errors.
* @throws AuthorizeException Exception indicating the current user of the context does not have permission
* to perform a particular action.
*/
public String keyedItemValue(Item item, String key)
throws AuthorizeException, IOException, SQLException {
CCLookup ccLookup = new CCLookup();
ccLookup.issue(key);
String matchValue = ccLookup.getLicenseName();
List<MetadataValue> dcvalues = itemService.getMetadata(item, params[0], params[1], params[2], params[3]);
for (MetadataValue dcvalue : dcvalues) {
if (dcvalue.getValue().equals(matchValue)) {
return dcvalue.getValue();
}
}
return null;
}
/**
* Removes the passed value from the set of values for the field in passed item.
*
* @param context The relevant DSpace Context.
* @param item - the item to update
* @param value - the value to remove
* @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
* @throws SQLException An exception that provides information on a database access error or other errors.
* @throws AuthorizeException Exception indicating the current user of the context does not have permission
* to perform a particular action.
*/
public void removeItemValue(Context context, Item item, String value)
throws AuthorizeException, IOException, SQLException {
if (value != null) {
List<MetadataValue> dcvalues = itemService.getMetadata(item, params[0], params[1], params[2], params[3]);
ArrayList<String> arrayList = new ArrayList<String>();
for (MetadataValue dcvalue : dcvalues) {
if (!dcvalue.getValue().equals(value)) {
arrayList.add(dcvalue.getValue());
}
}
itemService.clearMetadata(context, item, params[0], params[1], params[2], params[3]);
itemService.addMetadata(context, item, params[0], params[1], params[2], params[3], arrayList);
}
}
/**
* Adds passed value to the set of values for the field in passed item.
*
* @param context The relevant DSpace Context.
* @param item - the item to update
* @param value - the value to add in this field
* @throws SQLException An exception that provides information on a database access error or other errors.
*/
public void addItemValue(Context context, Item item, String value) throws SQLException {
itemService.addMetadata(context, item, params[0], params[1], params[2], params[3], value);
}
}

View File

@@ -10,12 +10,14 @@ package org.dspace.license.service;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.content.Item;
import org.dspace.core.Context;
import org.dspace.license.LicenseMetadataValue;
import org.dspace.license.CCLicense;
import org.jdom.Document;
/**
@@ -29,13 +31,6 @@ public interface CreativeCommonsService {
public static final String CC_BUNDLE_NAME = "CC-LICENSE";
/**
* Simple accessor for enabling of CC
*
* @return is CC enabled?
*/
public boolean isEnabled();
/**
* setLicenseRDF
*
@@ -74,17 +69,38 @@ public interface CreativeCommonsService {
InputStream licenseStm, String mimeType)
throws SQLException, IOException, AuthorizeException;
public void removeLicense(Context context, Item item)
/**
* Removes the license file from the item
*
* @param context - The relevant DSpace Context
* @param item - The item from which the license file needs to be removed
* @throws SQLException
* @throws IOException
* @throws AuthorizeException
*/
public void removeLicenseFile(Context context, Item item)
throws SQLException, IOException, AuthorizeException;
public boolean hasLicense(Context context, Item item)
throws SQLException, IOException;
public String getLicenseURL(Context context, Item item)
throws SQLException, IOException, AuthorizeException;
public String getLicenseRDF(Context context, Item item)
throws SQLException, IOException, AuthorizeException;
/**
* Returns the stored license uri of the item
*
* @param item - The item for which to retrieve the stored license uri
* @return the stored license uri of the item
*/
public String getLicenseURI(Item item);
/**
* Returns the stored license name of the item
*
* @param item - The item for which to retrieve the stored license name
* @return the stored license name of the item
*/
public String getLicenseName(Item item);
/**
* Get Creative Commons license RDF, returning Bitstream object.
@@ -121,7 +137,7 @@ public interface CreativeCommonsService {
* @param fieldId name of the property.
* @return its value.
*/
public LicenseMetadataValue getCCField(String fieldId);
public String getCCField(String fieldId);
/**
* Apply same transformation on the document to retrieve only the most
@@ -138,15 +154,134 @@ public interface CreativeCommonsService {
* Remove license information, delete also the bitstream
*
* @param context - DSpace Context
* @param uriField - the metadata field for license uri
* @param nameField - the metadata field for license name
* @param item - the item
* @throws AuthorizeException Exception indicating the current user of the context does not have permission
* to perform a particular action.
* @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
* @throws SQLException An exception that provides information on a database access error or other errors.
*/
public void removeLicense(Context context, LicenseMetadataValue uriField,
LicenseMetadataValue nameField, Item item)
public void removeLicense(Context context, Item item)
throws AuthorizeException, IOException, SQLException;
/**
* Find all CC Licenses using the default language found in the configuration
*
* @return A list of available CC Licenses
*/
public List<CCLicense> findAllCCLicenses();
/**
* Find all CC Licenses for the provided language
*
* @param language - the language for which to find the CC Licenses
* @return A list of available CC Licenses for the provided language
*/
public List<CCLicense> findAllCCLicenses(String language);
/**
* Find the CC License corresponding to the provided ID using the default language found in the configuration
*
* @param id - the ID of the license to be found
* @return the corresponding license if found or null when not found
*/
public CCLicense findOne(String id);
/**
* Find the CC License corresponding to the provided ID and provided language
*
* @param id - the ID of the license to be found
* @param language - the language for which to find the CC License
* @return the corresponding license if found or null when not found
*/
public CCLicense findOne(String id, String language);
/**
* Retrieve the CC License URI for the provided license ID, based on the provided answers, using the default
* language found in the configuration
*
* @param licenseId - the ID of the license
* @param answerMap - the answers to the different field questions
* @return the corresponding license URI
*/
public String retrieveLicenseUri(String licenseId, Map<String, String> answerMap);
/**
* Retrieve the CC License URI for the provided license ID and language based on the provided answers
*
* @param licenseId - the ID of the license
* @param language - the language for which to find the CC License URI
* @param answerMap - the answers to the different field questions
* @return the corresponding license URI
*/
public String retrieveLicenseUri(String licenseId, String language, Map<String, String> answerMap);
/**
* Retrieve the full answer map containing empty values when an answer for a field was not provided in the
* answerMap, using the default language found in the configuration
*
* @param licenseId - the ID of the license
* @param answerMap - the answers to the different field questions
* @return the answerMap supplemented with all other license fields with a blank answer
*/
public Map<String, String> retrieveFullAnswerMap(String licenseId, Map<String, String> answerMap);
/**
* Retrieve the full answer map for a provided language, containing empty values when an answer for a field was not
* provided in the answerMap.
*
* @param licenseId - the ID of the license
* @param language - the language for which to retrieve the full answerMap
* @param answerMap - the answers to the different field questions
* @return the answerMap supplemented with all other license fields with a blank answer for the provided language
*/
public Map<String, String> retrieveFullAnswerMap(String licenseId, String language, Map<String, String> answerMap);
/**
* Verify whether the answer map contains a valid response to all field questions and no answers that don't have a
* corresponding question in the license, using the default language found in the config to check the license
*
* @param licenseId - the ID of the license
* @param fullAnswerMap - the answers to the different field questions
* @return whether the information is valid
*/
public boolean verifyLicenseInformation(String licenseId, Map<String, String> fullAnswerMap);
/**
* Verify whether the answer map contains a valid response to all field questions and no answers that don't have a
* corresponding question in the license, using the provided language to check the license
*
* @param licenseId - the ID of the license
* @param language - the language for which to retrieve the full answerMap
* @param fullAnswerMap - the answers to the different field questions
* @return whether the information is valid
*/
public boolean verifyLicenseInformation(String licenseId, String language, Map<String, String> fullAnswerMap);
/**
* Update the license of the item with a new one based on the provided license URI
*
* @param context - The relevant DSpace context
* @param licenseUri - The license URI to be used in the update
* @param item - The item for which to update the license
* @return true when the update was successful, false when not
* @throws AuthorizeException
* @throws SQLException
*/
public boolean updateLicense(final Context context, String licenseUri, final Item item)
throws AuthorizeException, SQLException;
/**
* Add a new license to the item
*
* @param context - The relevant Dspace context
* @param item - The item to which the license will be added
* @param licenseUri - The license URI to add
* @param licenseName - The license name to add
* @param doc - The license to document to add
* @throws SQLException
* @throws IOException
* @throws AuthorizeException
*/
public void addLicense(Context context, Item item, String licenseUri, String licenseName, Document doc)
throws SQLException, IOException, AuthorizeException;
}

View File

@@ -7,70 +7,72 @@
*/
package org.dspace.scripts;
import java.sql.SQLException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.core.Context;
import org.apache.commons.lang3.StringUtils;
import org.dspace.eperson.EPerson;
import org.dspace.scripts.configuration.ScriptConfiguration;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
/**
* This abstract class is the class that should be extended by each script.
* it provides the basic variables to be hold by the script as well as the means to initialize, parse and run the script
* Every DSpaceRunnable that is implemented in this way should be defined in the scripts.xml config file as a bean
* This is the class that should be extended for each Script. This class will contain the logic needed to run and it'll
* fetch the information that it needs from the {@link ScriptConfiguration} provided through the diamond operators.
* This will be the dspaceRunnableClass for the {@link ScriptConfiguration} beans. Specifically created for each
* script
* @param <T>
*/
public abstract class DSpaceRunnable implements Runnable {
public abstract class DSpaceRunnable<T extends ScriptConfiguration> implements Runnable {
/**
* The name of the script
*/
private String name;
/**
* The description of the script
*/
private String description;
/**
* The CommandLine object for the script that'll hold the information
*/
protected CommandLine commandLine;
/**
* The possible options for this script
* This EPerson identifier variable is the uuid of the eperson that's running the script
*/
protected Options options;
private UUID epersonIdentifier;
/**
* The handler that deals with this script. This handler can currently either be a RestDSpaceRunnableHandler or
* a CommandlineDSpaceRunnableHandler depending from where the script is called
*/
protected DSpaceRunnableHandler handler;
@Autowired
private AuthorizeService authorizeService;
/**
* This method will return the Configuration that the implementing DSpaceRunnable uses
* @return The {@link ScriptConfiguration} that this implementing DspaceRunnable uses
*/
public abstract T getScriptConfiguration();
public String getName() {
return name;
private void setHandler(DSpaceRunnableHandler dSpaceRunnableHandler) {
this.handler = dSpaceRunnableHandler;
}
@Required
public void setName(String name) {
this.name = name;
/**
* This method sets the appropriate DSpaceRunnableHandler depending on where it was ran from and it parses
* the arguments given to the script
* @param args The arguments given to the script
* @param dSpaceRunnableHandler The DSpaceRunnableHandler object that defines from where the script was ran
* @param currentUser
* @throws ParseException If something goes wrong
*/
public void initialize(String[] args, DSpaceRunnableHandler dSpaceRunnableHandler,
EPerson currentUser) throws ParseException {
if (currentUser != null) {
this.setEpersonIdentifier(currentUser.getID());
}
public String getDescription() {
return description;
}
@Required
public void setDescription(String description) {
this.description = description;
}
public Options getOptions() {
return options;
this.setHandler(dSpaceRunnableHandler);
this.parse(args);
}
/**
@@ -80,18 +82,16 @@ public abstract class DSpaceRunnable implements Runnable {
* @throws ParseException If something goes wrong
*/
private void parse(String[] args) throws ParseException {
commandLine = new DefaultParser().parse(getOptions(), args);
commandLine = new DefaultParser().parse(getScriptConfiguration().getOptions(), args);
setup();
}
/**
* This method will call upon the {@link DSpaceRunnableHandler#printHelp(Options, String)} method with the script's
* options and name
* This method has to be included in every script and handles the setup of the script by parsing the CommandLine
* and setting the variables
* @throws ParseException If something goes wrong
*/
public void printHelp() {
handler.printHelp(options, name);
}
public abstract void setup() throws ParseException;
/**
* This is the run() method from the Runnable interface that we implement. This method will handle the running
@@ -108,22 +108,6 @@ public abstract class DSpaceRunnable implements Runnable {
}
}
private void setHandler(DSpaceRunnableHandler dSpaceRunnableHandler) {
this.handler = dSpaceRunnableHandler;
}
/**
* This method sets the appropriate DSpaceRunnableHandler depending on where it was ran from and it parses
* the arguments given to the script
* @param args The arguments given to the script
* @param dSpaceRunnableHandler The DSpaceRunnableHandler object that defines from where the script was ran
* @throws ParseException If something goes wrong
*/
public void initialize(String[] args, DSpaceRunnableHandler dSpaceRunnableHandler) throws ParseException {
this.setHandler(dSpaceRunnableHandler);
this.parse(args);
}
/**
* This method has to be included in every script and this will be the main execution block for the script that'll
* contain all the logic needed
@@ -132,25 +116,46 @@ public abstract class DSpaceRunnable implements Runnable {
public abstract void internalRun() throws Exception;
/**
* This method has to be included in every script and handles the setup of the script by parsing the CommandLine
* and setting the variables
* @throws ParseException If something goes wrong
* This method will call upon the {@link DSpaceRunnableHandler#printHelp(Options, String)} method with the script's
* options and name
*/
public abstract void setup() throws ParseException;
public void printHelp() {
handler.printHelp(getScriptConfiguration().getOptions(), getScriptConfiguration().getName());
}
/**
* This method will return if the script is allowed to execute in the given context. This is by default set
* to the currentUser in the context being an admin, however this can be overwritten by each script individually
* if different rules apply
* @param context The relevant DSpace context
* @return A boolean indicating whether the script is allowed to execute or not
* This method will traverse all the options and it'll grab options defined as an InputStream type to then save
* the filename specified by that option in a list of Strings that'll be returned in the end
* @return The list of Strings representing filenames from the options given to the script
*/
public boolean isAllowedToExecute(Context context) {
try {
return authorizeService.isAdmin(context);
} catch (SQLException e) {
handler.logError("Error occured when trying to verify permissions for script: " + name);
}
return false;
public List<String> getFileNamesFromInputStreamOptions() {
List<String> fileNames = new LinkedList<>();
for (Option option : getScriptConfiguration().getOptions().getOptions()) {
if (option.getType() == InputStream.class &&
StringUtils.isNotBlank(commandLine.getOptionValue(option.getOpt()))) {
fileNames.add(commandLine.getOptionValue(option.getOpt()));
}
}
return fileNames;
}
/**
* Generic getter for the epersonIdentifier
* This EPerson identifier variable is the uuid of the eperson that's running the script
* @return the epersonIdentifier value of this DSpaceRunnable
*/
public UUID getEpersonIdentifier() {
return epersonIdentifier;
}
/**
* Generic setter for the epersonIdentifier
* This EPerson identifier variable is the uuid of the eperson that's running the script
* @param epersonIdentifier The epersonIdentifier to be set on this DSpaceRunnable
*/
public void setEpersonIdentifier(UUID epersonIdentifier) {
this.epersonIdentifier = epersonIdentifier;
}
}

View File

@@ -8,6 +8,7 @@
package org.dspace.scripts;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
@@ -80,6 +81,8 @@ public class Process implements ReloadableEntity<Integer> {
@Temporal(TemporalType.TIMESTAMP)
private Date creationTime;
public static final String BITSTREAM_TYPE_METADATAFIELD = "dspace.process.filetype";
protected Process() {
}
@@ -174,6 +177,9 @@ public class Process implements ReloadableEntity<Integer> {
* @return The Bitstreams that are used or created by the process
*/
public List<Bitstream> getBitstreams() {
if (bitstreams == null) {
bitstreams = new LinkedList<>();
}
return bitstreams;
}

View File

@@ -7,18 +7,33 @@
*/
package org.dspace.scripts;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Bitstream;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataValue;
import org.dspace.content.ProcessStatus;
import org.dspace.content.dao.ProcessDAO;
import org.dspace.content.service.BitstreamFormatService;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.eperson.EPerson;
@@ -35,6 +50,18 @@ public class ProcessServiceImpl implements ProcessService {
@Autowired
private ProcessDAO processDAO;
@Autowired
private BitstreamService bitstreamService;
@Autowired
private BitstreamFormatService bitstreamFormatService;
@Autowired
private AuthorizeService authorizeService;
@Autowired
private MetadataFieldService metadataFieldService;
@Override
public Process create(Context context, EPerson ePerson, String scriptName,
List<DSpaceCommandLineParameter> parameters) throws SQLException {
@@ -113,11 +140,35 @@ public class ProcessServiceImpl implements ProcessService {
}
@Override
public void delete(Context context, Process process) throws SQLException {
public void appendFile(Context context, Process process, InputStream is, String type, String fileName)
throws IOException, SQLException, AuthorizeException {
Bitstream bitstream = bitstreamService.create(context, is);
if (getBitstream(context, process, type) != null) {
throw new IllegalArgumentException("Cannot create another file of type: " + type + " for this process" +
" with id: " + process.getID());
}
bitstream.setName(context, fileName);
bitstreamService.setFormat(context, bitstream, bitstreamFormatService.guessFormat(context, bitstream));
MetadataField dspaceProcessFileTypeField = metadataFieldService
.findByString(context, Process.BITSTREAM_TYPE_METADATAFIELD, '.');
bitstreamService.addMetadata(context, bitstream, dspaceProcessFileTypeField, null, type);
authorizeService.addPolicy(context, bitstream, Constants.READ, context.getCurrentUser());
authorizeService.addPolicy(context, bitstream, Constants.WRITE, context.getCurrentUser());
authorizeService.addPolicy(context, bitstream, Constants.DELETE, context.getCurrentUser());
bitstreamService.update(context, bitstream);
process.addBitstream(bitstream);
update(context, process);
}
@Override
public void delete(Context context, Process process) throws SQLException, IOException, AuthorizeException {
for (Bitstream bitstream : ListUtils.emptyIfNull(process.getBitstreams())) {
bitstreamService.delete(context, bitstream);
}
processDAO.delete(context, process);
log.info(LogManager.getHeader(context, "process_delete", "Process with ID " + process.getID()
+ " and name " + process.getName() + " has been deleted"));
}
@Override
@@ -141,8 +192,57 @@ public class ProcessServiceImpl implements ProcessService {
return parameterList;
}
@Override
public Bitstream getBitstreamByName(Context context, Process process, String bitstreamName) {
for (Bitstream bitstream : getBitstreams(context, process)) {
if (StringUtils.equals(bitstream.getName(), bitstreamName)) {
return bitstream;
}
}
return null;
}
@Override
public Bitstream getBitstream(Context context, Process process, String type) {
List<Bitstream> allBitstreams = process.getBitstreams();
if (type == null) {
return null;
} else {
if (allBitstreams != null) {
for (Bitstream bitstream : allBitstreams) {
if (StringUtils.equals(bitstreamService.getMetadata(bitstream,
Process.BITSTREAM_TYPE_METADATAFIELD), type)) {
return bitstream;
}
}
}
}
return null;
}
@Override
public List<Bitstream> getBitstreams(Context context, Process process) {
return process.getBitstreams();
}
public int countTotal(Context context) throws SQLException {
return processDAO.countRows(context);
}
@Override
public List<String> getFileTypesForProcessBitstreams(Context context, Process process) {
List<Bitstream> list = getBitstreams(context, process);
Set<String> fileTypesSet = new HashSet<>();
for (Bitstream bitstream : list) {
List<MetadataValue> metadata = bitstreamService.getMetadata(bitstream,
Process.BITSTREAM_TYPE_METADATAFIELD, Item.ANY);
if (metadata != null && !metadata.isEmpty()) {
fileTypesSet.add(metadata.get(0).getValue());
}
}
return new ArrayList<>(fileTypesSet);
}
}

View File

@@ -7,33 +7,46 @@
*/
package org.dspace.scripts;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.dspace.core.Context;
import org.dspace.kernel.ServiceManager;
import org.dspace.scripts.configuration.ScriptConfiguration;
import org.dspace.scripts.service.ScriptService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
/**
* The implementation for the {@link ScriptService}
*/
public class ScriptServiceImpl implements ScriptService {
private static final Logger log = LoggerFactory.getLogger(ScriptServiceImpl.class);
@Autowired
private List<DSpaceRunnable> dSpaceRunnables;
private ServiceManager serviceManager;
@Override
public DSpaceRunnable getScriptForName(String name) {
return dSpaceRunnables.stream()
.filter(dSpaceRunnable -> StringUtils.equalsIgnoreCase(dSpaceRunnable.getName(), name))
.findFirst()
.orElse(null);
public ScriptConfiguration getScriptConfiguration(String name) {
return serviceManager.getServiceByName(name, ScriptConfiguration.class);
}
@Override
public List<DSpaceRunnable> getDSpaceRunnables(Context context) {
return dSpaceRunnables.stream().filter(
dSpaceRunnable -> dSpaceRunnable.isAllowedToExecute(context)).collect(Collectors.toList());
public List<ScriptConfiguration> getScriptConfigurations(Context context) {
return serviceManager.getServicesByType(ScriptConfiguration.class).stream().filter(
scriptConfiguration -> scriptConfiguration.isAllowedToExecute(context)).collect(Collectors.toList());
}
@Override
public DSpaceRunnable createDSpaceRunnableForScriptConfiguration(ScriptConfiguration scriptToExecute)
throws IllegalAccessException, InstantiationException {
try {
return (DSpaceRunnable) scriptToExecute.getDspaceRunnableClass().getDeclaredConstructor().newInstance();
} catch (InvocationTargetException | NoSuchMethodException e) {
log.error(e.getMessage(), e);
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,92 @@
/**
* 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.scripts.configuration;
import org.apache.commons.cli.Options;
import org.dspace.core.Context;
import org.dspace.scripts.DSpaceRunnable;
import org.springframework.beans.factory.BeanNameAware;
/**
* This class represents an Abstract class that a ScriptConfiguration can inherit to further implement this
* and represent a script's configuration
*/
public abstract class ScriptConfiguration<T extends DSpaceRunnable> implements BeanNameAware {
/**
* The possible options for this script
*/
protected Options options;
private String description;
private String name;
/**
* Generic getter for the description
* @return the description value of this ScriptConfiguration
*/
public String getDescription() {
return description;
}
/**
* Generic setter for the description
* @param description The description to be set on this ScriptConfiguration
*/
public void setDescription(String description) {
this.description = description;
}
/**
* Generic getter for the name
* @return the name value of this ScriptConfiguration
*/
public String getName() {
return name;
}
/**
* Generic setter for the name
* @param name The name to be set on this ScriptConfiguration
*/
public void setName(String name) {
this.name = name;
}
/**
* Generic getter for the dspaceRunnableClass
* @return the dspaceRunnableClass value of this ScriptConfiguration
*/
public abstract Class<T> getDspaceRunnableClass();
/**
* Generic setter for the dspaceRunnableClass
* @param dspaceRunnableClass The dspaceRunnableClass to be set on this IndexDiscoveryScriptConfiguration
*/
public abstract void setDspaceRunnableClass(Class<T> dspaceRunnableClass);
/**
* This method will return if the script is allowed to execute in the given context. This is by default set
* to the currentUser in the context being an admin, however this can be overwritten by each script individually
* if different rules apply
* @param context The relevant DSpace context
* @return A boolean indicating whether the script is allowed to execute or not
*/
public abstract boolean isAllowedToExecute(Context context);
/**
* The getter for the options of the Script
* @return the options value of this ScriptConfiguration
*/
public abstract Options getOptions();
@Override
public void setBeanName(String beanName) {
this.name = beanName;
}
}

View File

@@ -7,9 +7,14 @@
*/
package org.dspace.scripts.handler;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Optional;
import org.apache.commons.cli.Options;
import org.dspace.authorize.AuthorizeException;
import org.dspace.core.Context;
/**
* This is an interface meant to be implemented by any DSpaceRunnableHandler to specify specific execution methods
@@ -78,4 +83,28 @@ public interface DSpaceRunnableHandler {
* @param name The name of the script
*/
public void printHelp(Options options, String name);
/**
* This method will grab the InputStream for the file defined by the given file name. The exact implementation will
* differ based on whether it's a REST call or CommandLine call. The REST Call will look for Bitstreams in the
* Database whereas the CommandLine call will look on the filesystem
* @param context The relevant DSpace context
* @param fileName The filename for the file that holds the InputStream
* @return The InputStream for the file defined by the given file name
* @throws IOException If something goes wrong
* @throws AuthorizeException If something goes wrong
*/
public Optional<InputStream> getFileStream(Context context, String fileName) throws IOException, AuthorizeException;
/**
* This method will write the InputStream to either a file on the filesystem or a bitstream in the database
* depending on whether it's coming from a CommandLine call or REST call respectively
* @param context The relevant DSpace context
* @param fileName The filename
* @param inputStream The inputstream to be written
* @param type The type of the file
* @throws IOException If something goes wrong
*/
public void writeFilestream(Context context, String fileName, InputStream inputStream, String type)
throws IOException, SQLException, AuthorizeException;
}

View File

@@ -7,9 +7,16 @@
*/
package org.dspace.scripts.handler.impl;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.core.Context;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
/**
@@ -84,4 +91,20 @@ public class CommandLineDSpaceRunnableHandler implements DSpaceRunnableHandler {
formatter.printHelp(name, options);
}
}
@Override
public Optional<InputStream> getFileStream(Context context, String fileName) throws IOException {
File file = new File(fileName);
if (!(file.exists() && file.isFile())) {
return Optional.empty();
}
return Optional.of(FileUtils.openInputStream(file));
}
@Override
public void writeFilestream(Context context, String fileName, InputStream inputStream, String type)
throws IOException {
File file = new File(fileName);
FileUtils.copyInputStreamToFile(inputStream, file);
}
}

View File

@@ -7,9 +7,13 @@
*/
package org.dspace.scripts.service;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.List;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.scripts.DSpaceCommandLineParameter;
@@ -104,13 +108,28 @@ public interface ProcessService {
*/
public void complete(Context context, Process process) throws SQLException;
/**
* The method will create a bitstream from the given inputstream with the given type as metadata and given name
* as name and attach it to the given process
* @param context The relevant DSpace context
* @param process The process for which the bitstream will be made
* @param is The inputstream for the bitstream
* @param type The type of the bitstream
* @param fileName The name of the bitstream
* @throws IOException If something goes wrong
* @throws SQLException If something goes wrong
* @throws AuthorizeException If something goes wrong
*/
public void appendFile(Context context, Process process, InputStream is, String type, String fileName)
throws IOException, SQLException, AuthorizeException;
/**
* This method will delete the given Process object from the database
* @param context The relevant DSpace context
* @param process The Process object to be deleted
* @throws SQLException If something goes wrong
*/
public void delete(Context context, Process process) throws SQLException;
public void delete(Context context, Process process) throws SQLException, IOException, AuthorizeException;
/**
* This method will be used to update the given Process object in the database
@@ -128,6 +147,32 @@ public interface ProcessService {
*/
public List<DSpaceCommandLineParameter> getParameters(Process process);
/**
* This method will return the Bitstream that matches the given name for the given Process
* @param context The relevant DSpace context
* @param process The process that should hold the requested Bitstream
* @param bitstreamName The name of the requested Bitstream
* @return The Bitstream from the given Process that matches the given bitstream name
*/
public Bitstream getBitstreamByName(Context context, Process process, String bitstreamName);
/**
* This method will return the Bitstream for a given process with a given type
* @param context The relevant DSpace context
* @param process The process that holds the Bitstreams to be searched in
* @param type The type that the Bitstream must have
* @return The Bitstream of the given type for the given Process
*/
public Bitstream getBitstream(Context context, Process process, String type);
/**
* This method will return all the Bitstreams for a given process
* @param context The relevant DSpace context
* @param process The process that holds the Bitstreams to be searched in
* @return The list of Bitstreams
*/
public List<Bitstream> getBitstreams(Context context, Process process);
/**
* Returns the total amount of Process objects in the dataase
* @param context The relevant DSpace context
@@ -136,4 +181,12 @@ public interface ProcessService {
*/
int countTotal(Context context) throws SQLException;
/**
* This will return a list of Strings where each String represents the type of a Bitstream in the Process given
* @param context The DSpace context
* @param process The Process object that we'll use to find the bitstreams
* @return A list of Strings where each String represents a fileType that is in the Process
*/
public List<String> getFileTypesForProcessBitstreams(Context context, Process process);
}

View File

@@ -11,6 +11,7 @@ import java.util.List;
import org.dspace.core.Context;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.scripts.configuration.ScriptConfiguration;
/**
* This service will deal with logic to handle DSpaceRunnable objects
@@ -18,16 +19,29 @@ import org.dspace.scripts.DSpaceRunnable;
public interface ScriptService {
/**
* This method will return the DSpaceRunnable that has the name that's equal to the name given in the parameters
* This method will return the ScriptConfiguration that has the name that's equal to the name given in the
* parameters
* @param name The name that the script has to match
* @return The matching DSpaceRunnable script
* @return The matching ScriptConfiguration
*/
DSpaceRunnable getScriptForName(String name);
ScriptConfiguration getScriptConfiguration(String name);
/**
* This method will return a list of DSpaceRunnable objects for which the given Context is authorized to use them
* This method will return a list of ScriptConfiguration objects for which the given Context is authorized
* @param context The relevant DSpace context
* @return The list of accessible DSpaceRunnable scripts for this context
* @return The list of accessible ScriptConfiguration scripts for this context
*/
List<DSpaceRunnable> getDSpaceRunnables(Context context);
List<ScriptConfiguration> getScriptConfigurations(Context context);
/**
* This method will create a new instance of the DSpaceRunnable that's linked with this Scriptconfiguration
* It'll grab the DSpaceRunnable class from the ScriptConfiguration's variables and create a new instance of it
* to return
* @param scriptToExecute The relevant ScriptConfiguration
* @return The new instance of the DSpaceRunnable class
* @throws IllegalAccessException If something goes wrong
* @throws InstantiationException If something goes wrong
*/
DSpaceRunnable createDSpaceRunnableForScriptConfiguration(ScriptConfiguration scriptToExecute)
throws IllegalAccessException, InstantiationException;
}

View File

@@ -0,0 +1,2 @@
id,collection,dc.contributor.author
+,"123456789/2","Donald, SmithImported"
1 id collection dc.contributor.author
2 + 123456789/2 Donald, SmithImported

View File

@@ -82,9 +82,9 @@
<!--Step will be to select a Creative Commons License -->
<!-- Uncomment this step to allow the user to select a Creative Commons
license -->
<!-- <step id="creative-commons"> <heading>submit.progressbar.CClicense</heading>
<processing-class>org.dspace.submit.step.CCLicenseStep</processing-class>
<type>cclicense</type> </step> -->
<step id="cclicense"> <heading>submit.progressbar.CClicense</heading>
<processing-class>org.dspace.app.rest.submit.step.CCLicenseStep</processing-class>
<type>cclicense</type> </step>
<!--Step will be to Check for potential duplicate -->
<!-- <step id="detect-duplicate"> <heading>submit.progressbar.detect.duplicate</heading>
@@ -145,7 +145,7 @@
<!--Step will be to Sign off on the License -->
<step id="license"/>
<!-- <step id="creative-commons"/> -->
<step id="cclicense"/>
<!-- <step id="verify"/> -->
</submission-process>

View File

@@ -108,3 +108,15 @@ plugin.sequence.java.util.Collection = \
java.util.LinkedList, \
java.util.Stack, \
java.util.TreeSet
###########################################
# PROPERTIES USED TO TEST CONFIGURATION #
# PROPERTY EXPOSURE VIA REST #
###########################################
rest.properties.exposed = configuration.exposed.single.value
rest.properties.exposed = configuration.exposed.array.value
rest.properties.exposed = configuration.not.existing
configuration.not.exposed = secret_value
configuration.exposed.single.value = public_value
configuration.exposed.array.value = public_value_1, public_value_2

View File

@@ -4,13 +4,23 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="indexClient" class="org.dspace.discovery.IndexClient" scope="prototype">
<property name="name" value="index-discovery"/>
<bean id="index-discovery" class="org.dspace.discovery.IndexDiscoveryScriptConfiguration">
<property name="description" value="Update Discovery Solr Search Index"/>
<property name="dspaceRunnableClass" value="org.dspace.discovery.IndexClient"/>
</bean>
<bean id="MockScript" class="org.dspace.scripts.impl.MockDSpaceRunnableScript" scope="prototype">
<property name="name" value="mock-script" />
<bean id="metadata-import" class="org.dspace.app.bulkedit.MetadataImportCliScriptConfiguration">
<property name="description" value="Import metadata after batch editing" />
<property name="dspaceRunnableClass" value="org.dspace.app.bulkedit.MetadataImportCLI"/>
</bean>
<bean id="metadata-export" class="org.dspace.app.bulkedit.MetadataExportScriptConfiguration">
<property name="description" value="Export metadata for batch editing"/>
<property name="dspaceRunnableClass" value="org.dspace.app.bulkedit.MetadataExport"/>
</bean>
<bean id="mock-script" class="org.dspace.scripts.MockDSpaceRunnableScriptConfiguration" scope="prototype">
<property name="description" value="Mocking a script for testing purposes" />
<property name="dspaceRunnableClass" value="org.dspace.scripts.impl.MockDSpaceRunnableScript"/>
</bean>
</beans>

View File

@@ -18,6 +18,7 @@ import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.AbstractUnitTest;
import org.junit.Test;
@@ -67,7 +68,7 @@ public class DSpaceCSVTest extends AbstractUnitTest {
out = null;
// Test the CSV parsing was OK
DSpaceCSV dcsv = new DSpaceCSV(new File(filename), context);
DSpaceCSV dcsv = new DSpaceCSV(FileUtils.openInputStream(new File(filename)), context);
String[] lines = dcsv.getCSVLinesAsStringArray();
assertThat("testDSpaceCSV Good CSV", lines.length, equalTo(8));
@@ -96,7 +97,7 @@ public class DSpaceCSVTest extends AbstractUnitTest {
// Test the CSV parsing was OK
try {
dcsv = new DSpaceCSV(new File(filename), context);
dcsv = new DSpaceCSV(FileUtils.openInputStream(new File(filename)), context);
lines = dcsv.getCSVLinesAsStringArray();
fail("An exception should have been thrown due to bad CSV");
@@ -124,7 +125,7 @@ public class DSpaceCSVTest extends AbstractUnitTest {
// Test the CSV parsing was OK
try {
dcsv = new DSpaceCSV(new File(filename), context);
dcsv = new DSpaceCSV(FileUtils.openInputStream(new File(filename)), context);
lines = dcsv.getCSVLinesAsStringArray();
fail("An exception should have been thrown due to bad CSV");

View File

@@ -0,0 +1,71 @@
/**
* 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.bulkedit;
import static junit.framework.TestCase.assertTrue;
import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.dspace.AbstractIntegrationTest;
import org.dspace.app.launcher.ScriptLauncher;
import org.dspace.app.scripts.handler.impl.TestDSpaceRunnableHandler;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.content.WorkspaceItem;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.content.service.InstallItemService;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.WorkspaceItemService;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.junit.Test;
public class MetadataExportTest extends AbstractIntegrationTest {
private ItemService itemService = ContentServiceFactory.getInstance().getItemService();
private CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
private CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
private WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
private InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService();
private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
@Test
public void metadataExportToCsvTest() throws Exception {
context.turnOffAuthorisationSystem();
Community community = communityService.create(null, context);
Collection collection = collectionService.create(context, community);
WorkspaceItem wi = workspaceItemService.create(context, collection, true);
Item item = wi.getItem();
itemService.addMetadata(context, item, "dc", "contributor", "author", null, "Donald, Smith");
item = installItemService.installItem(context, wi);
context.restoreAuthSystemState();
String fileLocation = configurationService.getProperty("dspace.dir") + testProps.get("test.exportcsv")
.toString();
String[] args = new String[] {"metadata-export", "-i", String.valueOf(item.getHandle()), "-f", fileLocation};
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
File file = new File(fileLocation);
String fileContent = IOUtils.toString(new FileInputStream(file), StandardCharsets.UTF_8);
assertTrue(fileContent.contains("Donald, Smith"));
assertTrue(fileContent.contains(String.valueOf(item.getID())));
context.turnOffAuthorisationSystem();
itemService.delete(context, itemService.find(context, item.getID()));
collectionService.delete(context, collectionService.find(context, collection.getID()));
communityService.delete(context, communityService.find(context, community.getID()));
context.restoreAuthSystemState();
}
}

View File

@@ -0,0 +1,60 @@
/**
* 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.bulkedit;
import static junit.framework.TestCase.assertTrue;
import java.io.File;
import org.apache.commons.lang3.StringUtils;
import org.dspace.AbstractIntegrationTest;
import org.dspace.app.launcher.ScriptLauncher;
import org.dspace.app.scripts.handler.impl.TestDSpaceRunnableHandler;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.content.service.ItemService;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.junit.Test;
public class MetadataImportTest extends AbstractIntegrationTest {
private ItemService itemService = ContentServiceFactory.getInstance().getItemService();
private CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
private CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
@Test
public void metadataImportTest() throws Exception {
context.turnOffAuthorisationSystem();
Community community = communityService.create(null, context);
Collection collection = collectionService.create(context, community);
context.restoreAuthSystemState();
String fileLocation = new File(testProps.get("test.importcsv").toString()).getAbsolutePath();
String[] args = new String[] {"metadata-import", "-f", fileLocation, "-e", eperson.getEmail(), "-s"};
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
Item importedItem = itemService.findAll(context).next();
assertTrue(
StringUtils.equals(
itemService.getMetadata(importedItem, "dc", "contributor", "author", Item.ANY).get(0).getValue(),
"Donald, SmithImported"));
context.turnOffAuthorisationSystem();
itemService.delete(context, itemService.find(context, importedItem.getID()));
collectionService.delete(context, collectionService.find(context, collection.getID()));
communityService.delete(context, communityService.find(context, community.getID()));
context.restoreAuthSystemState();
}
}

View File

@@ -0,0 +1,36 @@
/**
* 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.scripts.handler.impl;
import org.dspace.scripts.handler.impl.CommandLineDSpaceRunnableHandler;
/**
* This class will be used as a DSpaceRunnableHandler for the Tests so that we can stop the handler
* from calling System.exit() when a script would throw an exception
*/
public class TestDSpaceRunnableHandler extends CommandLineDSpaceRunnableHandler {
private Exception exception = null;
/**
* We're overriding this method so that we can stop the script from doing the System.exit() if
* an exception within the script is thrown
*/
@Override
public void handleException(String message, Exception e) {
exception = e;
}
/**
* Generic getter for the exception
* @return the exception value of this TestDSpaceRunnableHandler
*/
public Exception getException() {
return exception;
}
}

View File

@@ -0,0 +1,127 @@
/**
* 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.license;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.jdom.Document;
import org.jdom.JDOMException;
/**
* Mock implementation for the Creative commons license connector service.
* This class will return a structure of CC Licenses similar to the CC License API but without having to contact it
*/
public class MockCCLicenseConnectorServiceImpl extends CCLicenseConnectorServiceImpl {
/**
* Retrieves mock CC Licenses for the provided language
* @param language - the language
* @return a map of mocked licenses with the id and the license
*/
public Map<String, CCLicense> retrieveLicenses(String language) {
Map<String, CCLicense> ccLicenses = new HashMap<>();
CCLicense mockLicense1 = createMockLicense(1, new int[]{3, 2, 3});
CCLicense mockLicense2 = createMockLicense(2, new int[]{2});
CCLicense mockLicense3 = createMockLicense(3, new int[]{});
ccLicenses.put(mockLicense1.getLicenseId(), mockLicense1);
ccLicenses.put(mockLicense2.getLicenseId(), mockLicense2);
ccLicenses.put(mockLicense3.getLicenseId(), mockLicense3);
return ccLicenses;
}
private CCLicense createMockLicense(int count, int[] amountOfFieldsAndEnums) {
String licenseId = "license" + count;
String licenseName = "License " + count + " - Name";
List<CCLicenseField> mockLicenseFields = createMockLicenseFields(count, amountOfFieldsAndEnums);
return new CCLicense(licenseId, licenseName, mockLicenseFields);
}
private List<CCLicenseField> createMockLicenseFields(int count, int[] amountOfFieldsAndEnums) {
List<CCLicenseField> ccLicenseFields = new LinkedList<>();
for (int index = 0; index < amountOfFieldsAndEnums.length; index++) {
String licenseFieldId = "license" + count + "-field" + index;
String licenseFieldLabel = "License " + count + " - Field " + index + " - Label";
String licenseFieldDescription = "License " + count + " - Field " + index + " - Description";
List<CCLicenseFieldEnum> mockLicenseFields = createMockLicenseFields(count,
index,
amountOfFieldsAndEnums[index]);
ccLicenseFields.add(new CCLicenseField(licenseFieldId,
licenseFieldLabel,
licenseFieldDescription,
mockLicenseFields));
}
return ccLicenseFields;
}
private List<CCLicenseFieldEnum> createMockLicenseFields(int count, int index, int amountOfEnums) {
List<CCLicenseFieldEnum> ccLicenseFieldEnumList = new LinkedList<>();
for (int i = 0; i < amountOfEnums; i++) {
String enumId = "license" + count + "-field" + index + "-enum" + i;
String enumLabel = "License " + count + " - Field " + index + " - Enum " + i + " - Label";
String enumDescription = "License " + count + " - Field " + index + " - Enum " + i + " - " +
"Description";
ccLicenseFieldEnumList.add(new CCLicenseFieldEnum(enumId, enumLabel, enumDescription));
}
return ccLicenseFieldEnumList;
}
/**
* Retrieve a mock CC License URI
*
* @param licenseId - the ID of the license
* @param language - the language for which to retrieve the full answerMap
* @param answerMap - the answers to the different field questions
* @return the CC License URI
*/
public String retrieveRightsByQuestion(final String licenseId,
final String language,
final Map<String, String> answerMap) {
return "mock-license-uri";
}
/**
* Retrieve a mock license RDF document.
* When the uri contains "invalid", null will be returned to simulate that no document was found for the provided
* URI
*
* @param licenseURI - The license URI for which to retrieve the license RDF document
* @return a mock license RDF document or null when the URI contains invalid
* @throws IOException
*/
public Document retrieveLicenseRDFDoc(String licenseURI) throws IOException {
if (!StringUtils.contains(licenseURI, "invalid")) {
InputStream cclicense = null;
try {
cclicense = getClass().getResourceAsStream("cc-license-rdf.xml");
Document doc = parser.build(cclicense);
return doc;
} catch (JDOMException e) {
throw new RuntimeException(e);
} finally {
if (cclicense != null) {
cclicense.close();
}
}
}
return null;
}
}

View File

@@ -0,0 +1,68 @@
/**
* 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.scripts;
import java.io.InputStream;
import java.sql.SQLException;
import org.apache.commons.cli.Options;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.core.Context;
import org.dspace.scripts.configuration.ScriptConfiguration;
import org.dspace.scripts.impl.MockDSpaceRunnableScript;
import org.springframework.beans.factory.annotation.Autowired;
public class MockDSpaceRunnableScriptConfiguration<T extends MockDSpaceRunnableScript> extends ScriptConfiguration<T> {
@Autowired
private AuthorizeService authorizeService;
private Class<T> dspaceRunnableClass;
@Override
public Class<T> getDspaceRunnableClass() {
return dspaceRunnableClass;
}
/**
* Generic setter for the dspaceRunnableClass
* @param dspaceRunnableClass The dspaceRunnableClass to be set on this MetadataExportScriptConfiguration
*/
@Override
public void setDspaceRunnableClass(Class<T> dspaceRunnableClass) {
this.dspaceRunnableClass = dspaceRunnableClass;
}
@Override
public boolean isAllowedToExecute(Context context) {
try {
return authorizeService.isAdmin(context);
} catch (SQLException e) {
throw new RuntimeException("SQLException occurred when checking if the current user is an admin", e);
}
}
@Override
public Options getOptions() {
if (options == null) {
Options options = new Options();
options.addOption("r", "remove", true, "description r");
options.getOption("r").setType(String.class);
options.addOption("i", "index", false, "description i");
options.getOption("i").setType(boolean.class);
options.getOption("i").setRequired(true);
options.addOption("f", "file", true, "source file");
options.getOption("f").setType(InputStream.class);
options.getOption("f").setRequired(false);
super.options = options;
}
return options;
}
}

View File

@@ -7,19 +7,20 @@
*/
package org.dspace.scripts.impl;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.scripts.MockDSpaceRunnableScriptConfiguration;
import org.dspace.utils.DSpace;
public class MockDSpaceRunnableScript extends DSpaceRunnable {
private MockDSpaceRunnableScript() {
Options options = constructOptions();
this.options = options;
public class MockDSpaceRunnableScript extends DSpaceRunnable<MockDSpaceRunnableScriptConfiguration> {
@Override
public void internalRun() throws Exception {
}
@Override
public void internalRun() throws Exception {
public MockDSpaceRunnableScriptConfiguration getScriptConfiguration() {
return new DSpace().getServiceManager()
.getServiceByName("mock-script", MockDSpaceRunnableScriptConfiguration.class);
}
@Override
@@ -28,15 +29,4 @@ public class MockDSpaceRunnableScript extends DSpaceRunnable {
throw new ParseException("-i is a mandatory parameter");
}
}
private Options constructOptions() {
Options options = new Options();
options.addOption("r", "remove", true, "description r");
options.getOption("r").setType(String.class);
options.addOption("i", "index", true, "description i");
options.getOption("i").setType(boolean.class);
options.getOption("i").setRequired(true);
return options;
}
}

View File

@@ -11,3 +11,5 @@ test.folder = ./target/testing/
# Path of the test bitstream (to use in BitstreamTest and elsewhere)
test.bitstream = ./target/testing/dspace/assetstore/ConstitutionofIreland.pdf
test.exportcsv = ./target/testing/dspace/assetstore/test.csv
test.importcsv = ./target/testing/dspace/assetstore/testImport.csv

View File

@@ -19,7 +19,7 @@
<properties>
<!-- This is the path to the root [dspace-src] directory. -->
<root.basedir>${basedir}/..</root.basedir>
<spring-security.version>5.3.1.RELEASE</spring-security.version>
<spring-security.version>5.3.3.RELEASE</spring-security.version>
</properties>
<build>
<plugins>

View File

@@ -172,6 +172,21 @@
</execution>
</executions>
</plugin>
<!-- Verify OS license headers for all source code files -->
<plugin>
<groupId>com.mycila</groupId>
<artifactId>license-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/src/test/resources/**</exclude>
<exclude>**/src/test/data/**</exclude>
<!--Skip license check of third party files included/customized from HAL Browser -->
<exclude>src/main/webapp/index.html</exclude>
<exclude>src/main/webapp/login.html</exclude>
<exclude>src/main/webapp/js/hal/**</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
@@ -242,6 +257,23 @@
<version>${spring-hal-browser.version}</version>
</dependency>
<!-- WebJars dependencies used to update/enhance the default HAL Browser -->
<!-- Pull in current version of JQuery via WebJars
Made available at: webjars/jquery/dist/jquery.min.js -->
<dependency>
<groupId>org.webjars.bowergithub.jquery</groupId>
<artifactId>jquery-dist</artifactId>
<version>3.5.1</version>
</dependency>
<!-- Pull in current version of Toastr (toastrjs.com) via WebJars
Made available at: webjars/toastr/build/toastr.min.js -->
<dependency>
<groupId>org.webjars.bowergithub.codeseven</groupId>
<artifactId>toastr</artifactId>
<version>2.1.4</version>
</dependency>
<!-- Add in Spring Security for AuthN and AuthZ -->
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -32,6 +32,7 @@ import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
@@ -149,6 +150,18 @@ public class Application extends SpringBootServletInitializer {
}
}
/**
* Add a new ResourceHandler to allow us to use WebJars.org to pull in web dependencies
* dynamically for HAL Browser, and access them off the /webjars path.
* @param registry ResourceHandlerRegistry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/webjars/**")
.addResourceLocations("/webjars/");
}
@Override
public void addArgumentResolvers(@NonNull List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new SearchFilterResolver());

View File

@@ -81,7 +81,7 @@ public class RelationshipTypeRestController {
List<RelationshipType> list = relationshipTypeService.findByEntityType(context, entityType, -1, -1);
Page<RelationshipTypeRest> relationshipTypeRestPage = converter
.toRestPage(list, pageable, list.size(), utils.obtainProjection());
.toRestPage(list, pageable, utils.obtainProjection());
Page<RelationshipTypeResource> relationshipTypeResources = relationshipTypeRestPage
.map(relationshipTypeRest -> new RelationshipTypeResource(relationshipTypeRest, utils));

View File

@@ -342,7 +342,15 @@ public class RestResourceController implements InitializingBean {
return findRelEntryInternal(request, response, apiCategory, model, id, rel, relid, page, assembler);
}
@RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT +
"/{rel}/{relid}")
public RepresentationModel findRel(HttpServletRequest request, HttpServletResponse response,
@PathVariable String apiCategory,
@PathVariable String model, @PathVariable Integer id, @PathVariable String rel,
@PathVariable String relid,
Pageable page, PagedResourcesAssembler assembler) throws Throwable {
return findRelEntryInternal(request, response, apiCategory, model, id.toString(), rel, relid, page, assembler);
}
/**
* Execute a POST request;
*

View File

@@ -7,6 +7,8 @@
*/
package org.dspace.app.rest;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.converter.ConverterService;
@@ -14,6 +16,9 @@ import org.dspace.app.rest.model.ProcessRest;
import org.dspace.app.rest.model.ScriptRest;
import org.dspace.app.rest.model.hateoas.ProcessResource;
import org.dspace.app.rest.repository.ScriptRestRepository;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.core.Context;
import org.dspace.services.RequestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ControllerUtils;
import org.springframework.hateoas.RepresentationModel;
@@ -24,7 +29,9 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* This controller adds additional subresource methods to allow connecting scripts with processes
@@ -41,6 +48,9 @@ public class ScriptProcessesController {
@Autowired
private ScriptRestRepository scriptRestRepository;
@Autowired
private RequestService requestService;
/**
* This method can be called by sending a POST request to the system/scripts/{name}/processes endpoint
* This will start a process for the script that matches the given name
@@ -50,13 +60,16 @@ public class ScriptProcessesController {
*/
@RequestMapping(method = RequestMethod.POST)
@PreAuthorize("hasAuthority('ADMIN')")
public ResponseEntity<RepresentationModel<?>> startProcess(@PathVariable(name = "name") String scriptName)
public ResponseEntity<RepresentationModel<?>> startProcess(@PathVariable(name = "name") String scriptName,
@RequestParam(name = "file") List<MultipartFile> files)
throws Exception {
if (log.isTraceEnabled()) {
log.trace("Starting Process for Script with name: " + scriptName);
}
ProcessRest processRest = scriptRestRepository.startProcess(scriptName);
Context context = ContextUtil.obtainContext(requestService.getCurrentRequest().getServletRequest());
ProcessRest processRest = scriptRestRepository.startProcess(context, scriptName, files);
ProcessResource processResource = converter.toResource(processRest);
context.complete();
return ControllerUtils.toResponseEntity(HttpStatus.ACCEPTED, new HttpHeaders(), processResource);
}

View File

@@ -0,0 +1,140 @@
/**
* 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.rest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.exception.DSpaceBadRequestException;
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
import org.dspace.app.rest.model.SubmissionCCLicenseUrlRest;
import org.dspace.app.rest.model.wrapper.SubmissionCCLicenseUrl;
import org.dspace.app.rest.repository.DSpaceRestRepository;
import org.dspace.app.rest.utils.Utils;
import org.dspace.core.Context;
import org.dspace.license.service.CreativeCommonsService;
import org.dspace.services.RequestService;
import org.dspace.utils.DSpace;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.hateoas.Link;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
/**
* This Repository is responsible for handling the CC License URIs.
* It only supports a search method
*/
@Component(SubmissionCCLicenseUrlRest.CATEGORY + "." + SubmissionCCLicenseUrlRest.NAME)
public class SubmissionCCLicenseUrlRepository extends DSpaceRestRepository<SubmissionCCLicenseUrlRest, String>
implements InitializingBean {
@Autowired
protected Utils utils;
@Autowired
protected CreativeCommonsService creativeCommonsService;
@Autowired
protected ConverterService converter;
protected RequestService requestService = new DSpace().getRequestService();
@Autowired
DiscoverableEndpointsService discoverableEndpointsService;
/**
* Retrieves the CC License URI based on the license ID and answers in the field questions, provided as parameters
* to this request
*
* @return the CC License URI as a SubmissionCCLicenseUrlRest
*/
@PreAuthorize("hasAuthority('AUTHENTICATED')")
@SearchRestMethod(name = "rightsByQuestions")
public SubmissionCCLicenseUrlRest findByRightsByQuestions() {
ServletRequest servletRequest = requestService.getCurrentRequest()
.getServletRequest();
Map<String, String[]> requestParameterMap = servletRequest
.getParameterMap();
Map<String, String> parameterMap = new HashMap<>();
String licenseId = servletRequest.getParameter("license");
if (StringUtils.isBlank(licenseId)) {
throw new DSpaceBadRequestException(
"A \"license\" parameter needs to be provided.");
}
// Loop through parameters to find answer parameters, adding them to the parameterMap. Zero or more answers
// may exist, as some CC licenses do not require answers
for (String parameter : requestParameterMap.keySet()) {
if (StringUtils.startsWith(parameter, "answer_")) {
String field = StringUtils.substringAfter(parameter, "answer_");
String answer = "";
if (requestParameterMap.get(parameter).length > 0) {
answer = requestParameterMap.get(parameter)[0];
}
parameterMap.put(field, answer);
}
}
Map<String, String> fullParamMap = creativeCommonsService.retrieveFullAnswerMap(licenseId, parameterMap);
if (fullParamMap == null) {
throw new ResourceNotFoundException("No CC License could be matched on the provided ID: " + licenseId);
}
boolean licenseContainsCorrectInfo = creativeCommonsService.verifyLicenseInformation(licenseId, fullParamMap);
if (!licenseContainsCorrectInfo) {
throw new DSpaceBadRequestException(
"The provided answers do not match the required fields for the provided license.");
}
String licenseUri = creativeCommonsService.retrieveLicenseUri(licenseId, fullParamMap);
SubmissionCCLicenseUrl submissionCCLicenseUrl = new SubmissionCCLicenseUrl(licenseUri, licenseUri);
if (StringUtils.isBlank(licenseUri)) {
throw new ResourceNotFoundException("No CC License URI could be found for ID: " + licenseId);
}
return converter.toRest(submissionCCLicenseUrl, utils.obtainProjection());
}
/**
* The findOne method is not supported in this repository
*/
@PreAuthorize("permitAll()")
public SubmissionCCLicenseUrlRest findOne(final Context context, final String s) {
throw new RepositoryMethodNotImplementedException(SubmissionCCLicenseUrlRest.NAME, "findOne");
}
/**
* The findAll method is not supported in this repository
*/
public Page<SubmissionCCLicenseUrlRest> findAll(final Context context, final Pageable pageable) {
throw new RepositoryMethodNotImplementedException(SubmissionCCLicenseUrlRest.NAME, "findAll");
}
public Class<SubmissionCCLicenseUrlRest> getDomainClass() {
return SubmissionCCLicenseUrlRest.class;
}
@Override
public void afterPropertiesSet() {
discoverableEndpointsService.register(this, Arrays.asList(
new Link("/api/" + SubmissionCCLicenseUrlRest.CATEGORY + "/" +
SubmissionCCLicenseUrlRest.NAME + "/search",
SubmissionCCLicenseUrlRest.NAME + "-search")));
}
}

View File

@@ -72,7 +72,7 @@ public class WorkflowDefinitionCollectionsLinkRepository extends AbstractDSpaceR
collectionsMappedToWorkflow.addAll(xmlWorkflowFactory.getCollectionHandlesMappedToWorklow(context,
workflowName));
Pageable pageable = optionalPageable != null ? optionalPageable : PageRequest.of(0, 20);
return converter.toRestPage(utils.getPage(collectionsMappedToWorkflow, pageable),
return converter.toRestPage(collectionsMappedToWorkflow, pageable,
projection);
} else {
throw new ResourceNotFoundException("No workflow with name " + workflowName + " is configured");

View File

@@ -55,7 +55,7 @@ public class WorkflowDefinitionStepsLinkRepository extends AbstractDSpaceRestRep
try {
List<Step> steps = xmlWorkflowFactory.getWorkflowByName(workflowName).getSteps();
Pageable pageable = optionalPageable != null ? optionalPageable : PageRequest.of(0, 20);
return converter.toRestPage(utils.getPage(steps, pageable), projection);
return converter.toRestPage(steps, pageable, projection);
} catch (WorkflowConfigurationException e) {
throw new ResourceNotFoundException("No workflow with name " + workflowName + " is configured");
}

View File

@@ -52,6 +52,6 @@ public class WorkflowStepActionsLinkRepository extends AbstractDSpaceRestReposit
Projection projection) {
List<WorkflowActionConfig> actions = xmlWorkflowFactory.getStepByName(workflowStepName).getActions();
Pageable pageable = optionalPageable != null ? optionalPageable : PageRequest.of(0, 20);
return converter.toRestPage(utils.getPage(actions, pageable), projection);
return converter.toRestPage(actions, pageable, projection);
}
}

View File

@@ -7,33 +7,44 @@
*/
package org.dspace.app.rest.converter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.dspace.app.rest.link.HalLinkFactory;
import org.dspace.app.rest.link.HalLinkService;
import org.dspace.app.rest.model.BaseObjectRest;
import org.dspace.app.rest.model.RestAddressableModel;
import org.dspace.app.rest.model.RestModel;
import org.dspace.app.rest.model.hateoas.HALResource;
import org.dspace.app.rest.projection.DefaultProjection;
import org.dspace.app.rest.projection.Projection;
import org.dspace.app.rest.repository.DSpaceRestRepository;
import org.dspace.app.rest.security.DSpacePermissionEvaluator;
import org.dspace.app.rest.security.WebSecurityExpressionEvaluator;
import org.dspace.app.rest.utils.Utils;
import org.dspace.services.RequestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@@ -64,6 +75,15 @@ public class ConverterService {
@Autowired
private List<Projection> projections;
@Autowired
private DSpacePermissionEvaluator dSpacePermissionEvaluator;
@Autowired
private WebSecurityExpressionEvaluator webSecurityExpressionEvaluator;
@Autowired
private RequestService requestService;
/**
* Converts the given model object to a rest object, using the appropriate {@link DSpaceConverter} and
* the given projection.
@@ -86,18 +106,74 @@ public class ConverterService {
M transformedModel = projection.transformModel(modelObject);
DSpaceConverter<M, R> converter = requireConverter(modelObject.getClass());
R restObject = converter.convert(transformedModel, projection);
if (restObject instanceof BaseObjectRest) {
BaseObjectRest baseObjectRest = (BaseObjectRest) restObject;
// This section will verify whether the current user has permissions to retrieve the
// rest object. It'll only return the REST object if the permission is granted.
// If permission isn't granted, it'll return null
String preAuthorizeValue = getPreAuthorizeAnnotationForBaseObject(baseObjectRest);
if (!webSecurityExpressionEvaluator
.evaluate(preAuthorizeValue, requestService.getCurrentRequest().getHttpServletRequest(),
requestService.getCurrentRequest().getHttpServletResponse(),
String.valueOf(baseObjectRest.getId()))) {
log.debug("Access denied on " + restObject.getClass() + " with id: " +
((BaseObjectRest) restObject).getId());
return null;
}
}
if (restObject instanceof RestModel) {
return (R) projection.transformRest((RestModel) restObject);
}
return restObject;
}
private String getPreAuthorizeAnnotationForBaseObject(BaseObjectRest restObject) {
Annotation preAuthorize = getAnnotationForRestObject(restObject);
if (preAuthorize == null) {
preAuthorize = getDefaultFindOnePreAuthorize();
}
return parseAnnotation(preAuthorize);
}
private String parseAnnotation(Annotation preAuthorize) {
if (preAuthorize != null) {
return (String) AnnotationUtils.getValue(preAuthorize);
}
return null;
}
private Annotation getAnnotationForRestObject(BaseObjectRest restObject) {
BaseObjectRest baseObjectRest = restObject;
DSpaceRestRepository repositoryToUse = utils
.getResourceRepositoryByCategoryAndModel(baseObjectRest.getCategory(), baseObjectRest.getType());
Annotation preAuthorize = null;
for (Method m : repositoryToUse.getClass().getMethods()) {
if (StringUtils.equalsIgnoreCase(m.getName(), "findOne")) {
preAuthorize = AnnotationUtils.findAnnotation(m, PreAuthorize.class);
}
}
return preAuthorize;
}
private Annotation getDefaultFindOnePreAuthorize() {
for (Method m : DSpaceRestRepository.class.getMethods()) {
if (StringUtils.equalsIgnoreCase(m.getName(), "findOne")) {
Annotation annotation = AnnotationUtils.findAnnotation(m, PreAuthorize.class);
if (annotation != null) {
return annotation;
}
}
}
return null;
}
/**
* Converts a list of model objects to a page of rest objects using the given {@link Projection}.
*
* @param modelObjects the list of model objects.
* @param pageable the pageable.
* @param total the total number of items.
* @param projection the projection to use.
* @param <M> the model object class.
* @param <R> the rest object class.
@@ -105,24 +181,47 @@ public class ConverterService {
* @throws IllegalArgumentException if there is no compatible converter.
* @throws ClassCastException if the converter's return type is not compatible with the inferred return type.
*/
public <M, R> Page<R> toRestPage(List<M> modelObjects, Pageable pageable, long total, Projection projection) {
return new PageImpl<>(modelObjects, pageable, total).map((object) -> toRest(object, projection));
public <M, R> Page<R> toRestPage(List<M> modelObjects, Pageable pageable, Projection projection) {
List<R> transformedList = new LinkedList<>();
for (M modelObject : modelObjects) {
R transformedObject = toRest(modelObject, projection);
if (transformedObject != null) {
transformedList.add(transformedObject);
}
}
if (pageable == null) {
pageable = utils.getPageable(pageable);
}
return utils.getPage(transformedList, pageable);
}
/**
* Converts a list of model objects to a page of rest objects using the given {@link Projection}.
*
* @param modelObjects the page of model objects.
* Converts a list of ModelObjects to a page of Rest Objects using the given {@link Projection}
* This method differences in the sense that we define a total here instead of the size of the list because
* this method will be called if the list is limited through a DB call already and thus we need to give the
* total amount of records in the DB; not the size of the given list
* @param modelObjects the list of model objects.
* @param pageable the pageable.
* @param total The total amount of objects
* @param projection the projection to use.
* @param <M> the model object class.
* @param <R> the rest object class.
* @return the page.
* @throws IllegalArgumentException if there is no compatible converter.
* @throws ClassCastException if the converter's return type is not compatible with the inferred return type.
*/
public <M, R> Page<R> toRestPage(Page<M> modelObjects, Projection projection) {
return modelObjects.map((object) -> toRest(object, projection));
public <M, R> Page<R> toRestPage(List<M> modelObjects, Pageable pageable, long total, Projection projection) {
List<R> transformedList = new LinkedList<>();
for (M modelObject : modelObjects) {
R transformedObject = toRest(modelObject, projection);
if (transformedObject != null) {
transformedList.add(transformedObject);
}
}
if (pageable == null) {
pageable = utils.getPageable(pageable);
}
return new PageImpl(transformedList, pageable, total);
}
/**
* Gets the converter supporting the given class as input.
@@ -177,6 +276,9 @@ public class ConverterService {
* @return the fully converted resource, with all automatic links and embeds applied.
*/
public <T extends HALResource> T toResource(RestModel restObject, Link... oldLinks) {
if (restObject == null) {
return null;
}
T halResource = getResource(restObject);
if (restObject instanceof RestAddressableModel) {
utils.embedOrLinkClassLevelRels(halResource, oldLinks);

View File

@@ -24,8 +24,8 @@ public class RootConverter {
public RootRest convert() {
RootRest rootRest = new RootRest();
rootRest.setDspaceName(configurationService.getProperty("dspace.name"));
rootRest.setDspaceURL(configurationService.getProperty("dspace.ui.url"));
rootRest.setDspaceRest(configurationService.getProperty("dspace.server.url"));
rootRest.setDspaceUI(configurationService.getProperty("dspace.ui.url"));
rootRest.setDspaceServer(configurationService.getProperty("dspace.server.url"));
return rootRest;
}
}

View File

@@ -15,7 +15,7 @@ import org.apache.commons.collections4.CollectionUtils;
import org.dspace.app.rest.model.ParameterRest;
import org.dspace.app.rest.model.ScriptRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.scripts.configuration.ScriptConfiguration;
import org.springframework.stereotype.Component;
/**
@@ -23,18 +23,18 @@ import org.springframework.stereotype.Component;
* of {@link ScriptRest}
*/
@Component
public class ScriptConverter implements DSpaceConverter<DSpaceRunnable, ScriptRest> {
public class ScriptConverter implements DSpaceConverter<ScriptConfiguration, ScriptRest> {
@Override
public ScriptRest convert(DSpaceRunnable script, Projection projection) {
public ScriptRest convert(ScriptConfiguration scriptConfiguration, Projection projection) {
ScriptRest scriptRest = new ScriptRest();
scriptRest.setProjection(projection);
scriptRest.setDescription(script.getDescription());
scriptRest.setId(script.getName());
scriptRest.setName(script.getName());
scriptRest.setDescription(scriptConfiguration.getDescription());
scriptRest.setId(scriptConfiguration.getName());
scriptRest.setName(scriptConfiguration.getName());
List<ParameterRest> parameterRestList = new LinkedList<>();
for (Option option : CollectionUtils.emptyIfNull(script.getOptions().getOptions())) {
for (Option option : CollectionUtils.emptyIfNull(scriptConfiguration.getOptions().getOptions())) {
ParameterRest parameterRest = new ParameterRest();
parameterRest.setDescription(option.getDescription());
parameterRest.setName((option.getOpt() != null ? "-" + option.getOpt() : "--" + option.getLongOpt()));
@@ -49,7 +49,7 @@ public class ScriptConverter implements DSpaceConverter<DSpaceRunnable, ScriptRe
}
@Override
public Class<DSpaceRunnable> getModelClass() {
return DSpaceRunnable.class;
public Class<ScriptConfiguration> getModelClass() {
return ScriptConfiguration.class;
}
}

View File

@@ -0,0 +1,60 @@
/**
* 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.rest.converter;
import java.util.LinkedList;
import java.util.List;
import org.dspace.app.rest.model.SubmissionCCLicenseFieldRest;
import org.dspace.app.rest.model.SubmissionCCLicenseRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.license.CCLicense;
import org.dspace.license.CCLicenseField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* This converter is responsible for transforming the model representation of an CCLicense to the REST
* representation of an CCLicense and vice versa
**/
@Component
public class SubmissionCCLicenseConverter implements DSpaceConverter<CCLicense, SubmissionCCLicenseRest> {
@Autowired
private ConverterService converter;
/**
* Convert a CCLicense to its REST representation
* @param modelObject - the CCLicense to convert
* @param projection - the projection
* @return the corresponding SubmissionCCLicenseRest object
*/
@Override
public SubmissionCCLicenseRest convert(final CCLicense modelObject, final Projection projection) {
SubmissionCCLicenseRest submissionCCLicenseRest = new SubmissionCCLicenseRest();
submissionCCLicenseRest.setProjection(projection);
submissionCCLicenseRest.setId(modelObject.getLicenseId());
submissionCCLicenseRest.setName(modelObject.getLicenseName());
List<CCLicenseField> ccLicenseFieldList = modelObject.getCcLicenseFieldList();
List<SubmissionCCLicenseFieldRest> submissionCCLicenseFieldRests = new LinkedList<>();
if (ccLicenseFieldList != null) {
for (CCLicenseField ccLicenseField : ccLicenseFieldList) {
submissionCCLicenseFieldRests.add(converter.toRest(ccLicenseField, projection));
}
}
submissionCCLicenseRest.setFields(submissionCCLicenseFieldRests);
return submissionCCLicenseRest;
}
@Override
public Class<CCLicense> getModelClass() {
return CCLicense.class;
}
}

View File

@@ -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.rest.converter;
import java.util.LinkedList;
import java.util.List;
import org.dspace.app.rest.model.SubmissionCCLicenseFieldEnumRest;
import org.dspace.app.rest.model.SubmissionCCLicenseFieldRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.license.CCLicenseField;
import org.dspace.license.CCLicenseFieldEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* This converter is responsible for transforming the model representation of an CCLicenseField to the REST
* representation of an CCLicenseField and vice versa
* The CCLicenseField is a sub component of the CCLicense object
**/
@Component
public class SubmissionCCLicenseFieldConverter
implements DSpaceConverter<CCLicenseField, SubmissionCCLicenseFieldRest> {
@Autowired
private ConverterService converter;
/**
* Convert a CCLicenseField to its REST representation
* @param modelObject - the CCLicenseField to convert
* @param projection - the projection
* @return the corresponding SubmissionCCLicenseFieldRest object
*/
@Override
public SubmissionCCLicenseFieldRest convert(final CCLicenseField modelObject, final Projection projection) {
SubmissionCCLicenseFieldRest submissionCCLicenseFieldRest = new SubmissionCCLicenseFieldRest();
submissionCCLicenseFieldRest.setId(modelObject.getId());
submissionCCLicenseFieldRest.setLabel(modelObject.getLabel());
submissionCCLicenseFieldRest.setDescription(modelObject.getDescription());
List<CCLicenseFieldEnum> fieldEnum = modelObject.getFieldEnum();
List<SubmissionCCLicenseFieldEnumRest> submissionCCLicenseFieldEnumRests = new LinkedList<>();
if (fieldEnum != null) {
for (CCLicenseFieldEnum ccLicenseFieldEnum : fieldEnum) {
submissionCCLicenseFieldEnumRests.add(converter.toRest(ccLicenseFieldEnum, projection));
}
}
submissionCCLicenseFieldRest.setEnums(submissionCCLicenseFieldEnumRests);
return submissionCCLicenseFieldRest;
}
@Override
public Class<CCLicenseField> getModelClass() {
return CCLicenseField.class;
}
}

View File

@@ -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.rest.converter;
import org.dspace.app.rest.model.SubmissionCCLicenseFieldEnumRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.license.CCLicenseFieldEnum;
import org.springframework.stereotype.Component;
/**
* This converter is responsible for transforming the model representation of an CCLicenseFieldEnum to the REST
* representation of an CCLicenseFieldEnum and vice versa
* The CCLicenseFieldEnum is a sub component of the CCLicenseField object
**/
@Component
public class SubmissionCCLicenseFieldEnumConverter
implements DSpaceConverter<CCLicenseFieldEnum, SubmissionCCLicenseFieldEnumRest> {
/**
* Convert a CCLicenseFieldEnum to its REST representation
*
* @param modelObject - the CCLicenseField to convert
* @param projection - the projection
* @return the corresponding SubmissionCCLicenseFieldEnumRest object
*/
@Override
public SubmissionCCLicenseFieldEnumRest convert(final CCLicenseFieldEnum modelObject, final Projection projection) {
SubmissionCCLicenseFieldEnumRest submissionCCLicenseFieldEnumRest = new SubmissionCCLicenseFieldEnumRest();
submissionCCLicenseFieldEnumRest.setId(modelObject.getId());
submissionCCLicenseFieldEnumRest.setLabel(modelObject.getLabel());
submissionCCLicenseFieldEnumRest.setDescription(modelObject.getDescription());
return submissionCCLicenseFieldEnumRest;
}
@Override
public Class<CCLicenseFieldEnum> getModelClass() {
return CCLicenseFieldEnum.class;
}
}

View File

@@ -0,0 +1,44 @@
/**
* 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.rest.converter;
import org.dspace.app.rest.model.SubmissionCCLicenseUrlRest;
import org.dspace.app.rest.model.wrapper.SubmissionCCLicenseUrl;
import org.dspace.app.rest.projection.Projection;
import org.springframework.stereotype.Component;
/**
* This converter is responsible for transforming a Submission CC License Url String to the REST
* representation SubmissionCCLicenseUrlRest and vice versa
*/
@Component
public class SubmissionCCLicenseUrlConverter
implements DSpaceConverter<SubmissionCCLicenseUrl, SubmissionCCLicenseUrlRest> {
/**
* Convert a Submission CC License Url String to its REST representation
* @param modelObject - the CC License Url object to convert
* @param projection - the projection
* @return the corresponding SubmissionCCLicenseUrlRest object
*/
@Override
public SubmissionCCLicenseUrlRest convert(SubmissionCCLicenseUrl modelObject, Projection projection) {
SubmissionCCLicenseUrlRest submissionCCLicenseUrlRest = new SubmissionCCLicenseUrlRest();
submissionCCLicenseUrlRest.setUrl(modelObject.getUrl());
submissionCCLicenseUrlRest.setId(modelObject.getId());
return submissionCCLicenseUrlRest;
}
@Override
public Class<SubmissionCCLicenseUrl> getModelClass() {
return SubmissionCCLicenseUrl.class;
}
}

View File

@@ -29,6 +29,7 @@ import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
/**
@@ -54,8 +55,8 @@ public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionH
}
}
@ExceptionHandler(IllegalArgumentException.class)
protected void handleIllegalArgumentException(HttpServletRequest request, HttpServletResponse response,
@ExceptionHandler({IllegalArgumentException.class, MultipartException.class})
protected void handleWrongRequestException(HttpServletRequest request, HttpServletResponse response,
Exception ex) throws IOException {
sendErrorResponse(request, response, ex, ex.getMessage(), HttpServletResponse.SC_BAD_REQUEST);
}

View File

@@ -30,7 +30,7 @@ public class RootHalLinkFactory extends HalLinkFactory<RootResource, RootRestRes
for (Link endpointLink : discoverableEndpointsService.getDiscoverableEndpoints()) {
list.add(
buildLink(endpointLink.getRel().value(),
halResource.getContent().getDspaceRest() + endpointLink.getHref()));
halResource.getContent().getDspaceServer() + endpointLink.getHref()));
}
}

View File

@@ -0,0 +1,19 @@
/**
* 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.rest.link.process;
import org.dspace.app.rest.RestResourceController;
import org.dspace.app.rest.link.HalLinkFactory;
/**
* This abstract class offers an easily extendable HalLinkFactory class to use methods on the RestResourceController
* and make it more easy to read or define which methods should be found in the getMethodOn methods when building links
* @param <T> This parameter should be of type {@link org.dspace.app.rest.model.hateoas.HALResource}
*/
public abstract class ProcessHalLinkFactory<T> extends HalLinkFactory<T, RestResourceController> {
}

View File

@@ -10,7 +10,6 @@ package org.dspace.app.rest.link.process;
import java.util.LinkedList;
import org.dspace.app.rest.RestResourceController;
import org.dspace.app.rest.link.HalLinkFactory;
import org.dspace.app.rest.model.hateoas.ProcessResource;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -19,25 +18,28 @@ import org.springframework.hateoas.Link;
import org.springframework.stereotype.Component;
/**
* This class will provide the ProcessResource with links
* This HalLinkFactory provides the {@link ProcessResource} with links
*/
@Component
public class ProcessResourceHalLinkFactory extends HalLinkFactory<ProcessResource, RestResourceController> {
public class ProcessResourceHalLinkFactory extends ProcessHalLinkFactory<ProcessResource> {
@Autowired
private ConfigurationService configurationService;
@Override
protected void addLinks(ProcessResource halResource, Pageable pageable, LinkedList<Link> list) throws Exception {
String dspaceRestUrl = configurationService.getProperty("dspace.server.url");
String dspaceServerUrl = configurationService.getProperty("dspace.server.url");
list.add(
buildLink("script", dspaceRestUrl + "/api/system/scripts/" + halResource.getContent().getScriptName()));
buildLink("script", dspaceServerUrl + "/api/system/scripts/" + halResource.getContent().getScriptName()));
}
@Override
protected Class<RestResourceController> getControllerClass() {
return RestResourceController.class;
}
@Override
protected Class<ProcessResource> getResourceClass() {
return ProcessResource.class;
}

View File

@@ -0,0 +1,73 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.link.process;
import java.util.LinkedList;
import java.util.Map;
import org.dspace.app.rest.RestResourceController;
import org.dspace.app.rest.link.HalLinkFactory;
import org.dspace.app.rest.model.SubmissionCCLicenseUrlRest;
import org.dspace.app.rest.model.hateoas.SubmissionCCLicenseUrlResource;
import org.dspace.services.RequestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.hateoas.Link;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.util.UriComponentsBuilder;
/**
* This class will provide the SubmissionCCLicenseUrlResource with links
*/
@Component
public class SubmissionCCLicenseUrlResourceHalLinkFactory
extends HalLinkFactory<SubmissionCCLicenseUrlResource, RestResourceController> {
@Autowired
RequestService requestService;
/**
* Add a self link based on the search parameters
*
* @param halResource - The halResource
* @param pageable - The page information
* @param list - The list of present links
* @throws Exception
*/
@Override
protected void addLinks(SubmissionCCLicenseUrlResource halResource, final Pageable pageable,
LinkedList<Link> list)
throws Exception {
halResource.removeLinks();
Map<String, String[]> parameterMap = requestService.getCurrentRequest().getHttpServletRequest()
.getParameterMap();
UriComponentsBuilder uriComponentsBuilder = uriBuilder(getMethodOn().executeSearchMethods(
SubmissionCCLicenseUrlRest.CATEGORY, SubmissionCCLicenseUrlRest.PLURAL, "rightsByQuestions", null, null,
null, null, new LinkedMultiValueMap<>()));
for (String key : parameterMap.keySet()) {
uriComponentsBuilder.queryParam(key, parameterMap.get(key));
}
list.add(buildLink("self", uriComponentsBuilder.build().toUriString()));
}
@Override
protected Class<RestResourceController> getControllerClass() {
return RestResourceController.class;
}
@Override
protected Class<SubmissionCCLicenseUrlResource> getResourceClass() {
return SubmissionCCLicenseUrlResource.class;
}
}

View File

@@ -12,7 +12,7 @@ import org.dspace.app.rest.ExternalSourcesRestController;
/**
* This class serves as a REST representation for an entry of external data
*/
public class ExternalSourceEntryRest extends BaseObjectRest<String> {
public class ExternalSourceEntryRest extends RestAddressableModel {
public static final String NAME = "externalSourceEntry";
public static final String PLURAL_NAME = "externalSourceEntries";

View File

@@ -25,16 +25,16 @@ public class ParameterRest {
*/
private String type;
/**
* The long name of the parameter
*/
private String nameLong;
/**
* Boolean indicating whether the parameter is mandatory or not
*/
private boolean mandatory;
/**
* The long name of the parameter
*/
private String nameLong;
public String getName() {
return name;
}

View File

@@ -0,0 +1,68 @@
/**
* 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.rest.model;
import java.util.LinkedList;
import java.util.List;
import org.dspace.app.rest.RestResourceController;
/**
* This class provides a way to list the filetypes present in a given Process by showing them as a list of Strings
* It'll be used by {@link org.dspace.app.rest.repository.ProcessFileTypesLinkRepository}
*/
public class ProcessFileTypesRest extends BaseObjectRest<String> {
public static final String NAME = "filetypes";
public static final String PLURAL_NAME = "filetypes";
public static final String CATEGORY = RestAddressableModel.SYSTEM;
private List<String> values;
/**
* Generic getter for the values
* @return the values value of this ProcessFileTypesRest
*/
public List<String> getValues() {
return values;
}
/**
* Generic setter for the values
* @param values The values to be set on this ProcessFileTypesRest
*/
public void setValues(List<String> values) {
this.values = values;
}
/**
* Adds a value to the list of FileType Strings
* @param value The value to be added
*/
public void addValue(String value) {
if (values == null) {
values = new LinkedList<>();
}
values.add(value);
}
@Override
public String getCategory() {
return CATEGORY;
}
@Override
public Class getController() {
return RestResourceController.class;
}
@Override
public String getType() {
return NAME;
}
}

View File

@@ -20,12 +20,23 @@ import org.dspace.scripts.Process;
/**
* This class serves as a REST representation for the {@link Process} class
*/
@LinksRest(links = {
@LinkRest(
name = ProcessRest.FILES,
method = "getFilesFromProcess"
),
@LinkRest(
name = ProcessRest.FILE_TYPES,
method = "getFileTypesFromProcess"
)
})
public class ProcessRest extends BaseObjectRest<Integer> {
public static final String NAME = "process";
public static final String PLURAL_NAME = "processes";
public static final String CATEGORY = RestAddressableModel.SYSTEM;
public static final String FILES = "files";
public static final String FILE_TYPES = "filetypes";
public String getCategory() {
return CATEGORY;
}

View File

@@ -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.rest.model;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.dspace.app.rest.RestResourceController;
/**
* This class acts as the REST representation of a DSpace configuration property.
* This class acts as a data holder for the PropertyResource
*/
public class PropertyRest extends BaseObjectRest<String> {
public static final String NAME = "property";
public static final String CATEGORY = RestAddressableModel.CONFIGURATION;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getValues() {
return values;
}
public void setValues(List<String> values) {
this.values = values;
}
public String name;
public List<String> values;
@Override
@JsonIgnore
public String getId() {
return this.name;
}
@Override
public String getCategory() {
return CATEGORY;
}
@Override
public Class getController() {
return RestResourceController.class;
}
@Override
public String getType() {
return NAME;
}
}

View File

@@ -17,9 +17,9 @@ import org.dspace.app.rest.RootRestResourceController;
public class RootRest extends RestAddressableModel {
public static final String NAME = "root";
public static final String CATEGORY = RestModel.ROOT;
private String dspaceURL;
private String dspaceUI;
private String dspaceName;
private String dspaceRest;
private String dspaceServer;
public String getCategory() {
return CATEGORY;
@@ -33,13 +33,13 @@ public class RootRest extends RestAddressableModel {
return RootRestResourceController.class;
}
public String getDspaceURL() {
public String getDspaceUI() {
return dspaceURL;
return dspaceUI;
}
public void setDspaceURL(String dspaceURL) {
this.dspaceURL = dspaceURL;
public void setDspaceUI(String dspaceUI) {
this.dspaceUI = dspaceUI;
}
public String getDspaceName() {
@@ -50,12 +50,12 @@ public class RootRest extends RestAddressableModel {
this.dspaceName = dspaceName;
}
public String getDspaceRest() {
return dspaceRest;
public String getDspaceServer() {
return dspaceServer;
}
public void setDspaceRest(String dspaceRest) {
this.dspaceRest = dspaceRest;
public void setDspaceServer(String dspaceServerURL) {
this.dspaceServer = dspaceServerURL;
}
@Override
@@ -64,9 +64,9 @@ public class RootRest extends RestAddressableModel {
new EqualsBuilder().append(this.getCategory(), ((RootRest) object).getCategory())
.append(this.getType(), ((RootRest) object).getType())
.append(this.getController(), ((RootRest) object).getController())
.append(this.getDspaceURL(), ((RootRest) object).getDspaceURL())
.append(this.getDspaceUI(), ((RootRest) object).getDspaceUI())
.append(this.getDspaceName(), ((RootRest) object).getDspaceName())
.append(this.getDspaceRest(), ((RootRest) object).getDspaceRest())
.append(this.getDspaceServer(), ((RootRest) object).getDspaceServer())
.isEquals());
}
@@ -77,8 +77,8 @@ public class RootRest extends RestAddressableModel {
.append(this.getType())
.append(this.getController())
.append(this.getDspaceName())
.append(this.getDspaceURL())
.append(this.getDspaceRest())
.append(this.getDspaceUI())
.append(this.getDspaceServer())
.toHashCode();
}
}

View File

@@ -0,0 +1,44 @@
/**
* 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.rest.model;
/**
* This class is the REST representation of the CCLicenseFieldEnum model object and acts as a data sub object
* for the SubmissionCCLicenseFieldRest class.
* Refer to {@link org.dspace.license.CCLicenseFieldEnum} for explanation of the properties
*/
public class SubmissionCCLicenseFieldEnumRest {
private String id;
private String label;
private String description;
public String getId() {
return id;
}
public void setId(final String id) {
this.id = id;
}
public String getLabel() {
return label;
}
public void setLabel(final String label) {
this.label = label;
}
public String getDescription() {
return description;
}
public void setDescription(final String description) {
this.description = description;
}
}

View File

@@ -0,0 +1,59 @@
/**
* 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.rest.model;
import java.util.List;
/**
* This class is the REST representation of the CCLicenseField model object and acts as a data sub object
* for the SubmissionCCLicenseRest class.
* Refer to {@link org.dspace.license.CCLicenseField} for explanation of the properties
*/
public class SubmissionCCLicenseFieldRest {
private String id;
private String label;
private String description;
private List<SubmissionCCLicenseFieldEnumRest> enums;
public String getId() {
return id;
}
public void setId(final String id) {
this.id = id;
}
public String getLabel() {
return label;
}
public void setLabel(final String label) {
this.label = label;
}
public String getDescription() {
return description;
}
public void setDescription(final String description) {
this.description = description;
}
public List<SubmissionCCLicenseFieldEnumRest> getEnums() {
return enums;
}
public void setEnums(final List<SubmissionCCLicenseFieldEnumRest> enums) {
this.enums = enums;
}
}

View File

@@ -0,0 +1,74 @@
/**
* 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.rest.model;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.dspace.app.rest.RestResourceController;
/**
* This class is the REST representation of the CCLicense model object and acts as a data object
* for the SubmissionCCLicenseResource class.
* Refer to {@link org.dspace.license.CCLicense} for explanation of the properties
*/
public class SubmissionCCLicenseRest extends BaseObjectRest<String> {
public static final String NAME = "submissioncclicense";
public static final String PLURAL = "submissioncclicenses";
public static final String CATEGORY = RestAddressableModel.CONFIGURATION;
private String id;
private String name;
private List<SubmissionCCLicenseFieldRest> fields;
public String getId() {
return id;
}
public void setId(final String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public List<SubmissionCCLicenseFieldRest> getFields() {
return fields;
}
public void setFields(final List<SubmissionCCLicenseFieldRest> fields) {
this.fields = fields;
}
@JsonIgnore
@Override
public String getCategory() {
return CATEGORY;
}
@Override
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public String getType() {
return NAME;
}
@Override
@JsonIgnore
public Class getController() {
return RestResourceController.class;
}
}

View File

@@ -0,0 +1,60 @@
/**
* 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.rest.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.dspace.app.rest.RestResourceController;
/**
* This class is the REST representation of the CCLicense URL String object and acts as a data object
* for the SubmissionCCLicenseUrlRest class.
*/
public class SubmissionCCLicenseUrlRest extends BaseObjectRest<String> {
public static final String NAME = "submissioncclicenseUrl";
public static final String PLURAL = "submissioncclicenseUrls";
public static final String CATEGORY = RestAddressableModel.CONFIGURATION;
private String url;
@JsonIgnore
@Override
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(final String url) {
this.url = url;
}
@Override
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public String getType() {
return NAME;
}
@Override
public String getCategory() {
return SubmissionCCLicenseUrlRest.CATEGORY;
}
@Override
@JsonIgnore
public Class getController() {
return RestResourceController.class;
}
}

View File

@@ -0,0 +1,22 @@
/**
* 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.rest.model.hateoas;
import org.dspace.app.rest.model.ProcessFileTypesRest;
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
/**
* Resource object for {@link ProcessFileTypesRest}
*/
@RelNameDSpaceResource(ProcessFileTypesRest.NAME)
public class ProcessFileTypesResource extends HALResource<ProcessFileTypesRest> {
public ProcessFileTypesResource(ProcessFileTypesRest content) {
super(content);
}
}

View File

@@ -0,0 +1,21 @@
/**
* 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.rest.model.hateoas;
import org.dspace.app.rest.model.PropertyRest;
import org.dspace.app.rest.utils.Utils;
/**
* The purpose of this class is to wrap the information of the PropertyRest into a HAL resource
*/
public class PropertyResource extends DSpaceResource<PropertyRest> {
public PropertyResource(PropertyRest data, Utils utils) {
super(data, utils);
}
}

View File

@@ -0,0 +1,23 @@
/**
* 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.rest.model.hateoas;
import org.dspace.app.rest.model.SubmissionCCLicenseRest;
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
import org.dspace.app.rest.utils.Utils;
/**
* CCLicense HAL Resource. This resource adds the data from the REST object together with embedded objects
* and a set of links if applicable
*/
@RelNameDSpaceResource(SubmissionCCLicenseRest.NAME)
public class SubmissionCCLicenseResource extends DSpaceResource<SubmissionCCLicenseRest> {
public SubmissionCCLicenseResource(SubmissionCCLicenseRest submissionCCLicenseRest, Utils utils) {
super(submissionCCLicenseRest, utils);
}
}

View File

@@ -0,0 +1,23 @@
/**
* 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.rest.model.hateoas;
import org.dspace.app.rest.model.SubmissionCCLicenseUrlRest;
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
import org.dspace.app.rest.utils.Utils;
/**
* SubmissionCCLicenseUrl HAL Resource. This resource adds the data from the REST object together with embedded objects
* and a set of links if applicable
*/
@RelNameDSpaceResource(SubmissionCCLicenseUrlRest.NAME)
public class SubmissionCCLicenseUrlResource extends DSpaceResource<SubmissionCCLicenseUrlRest> {
public SubmissionCCLicenseUrlResource(SubmissionCCLicenseUrlRest submissionCCLicenseUrlRest, Utils utils) {
super(submissionCCLicenseUrlRest, utils);
}
}

View File

@@ -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.rest.model.step;
import org.dspace.app.rest.model.BitstreamRest;
/**
* Java Bean to expose the section creativecommons representing the CC License during in progress submission.
*/
public class DataCCLicense implements SectionData {
private String uri;
private String rights;
private BitstreamRest file;
public String getUri() {
return uri;
}
public void setUri(final String uri) {
this.uri = uri;
}
public String getRights() {
return rights;
}
public void setRights(final String rights) {
this.rights = rights;
}
public BitstreamRest getFile() {
return file;
}
public void setFile(final BitstreamRest file) {
this.file = file;
}
}

View File

@@ -0,0 +1,68 @@
/**
* 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.rest.model.wrapper;
/**
* This class represents a model implementation for {@link org.dspace.app.rest.model.SubmissionCCLicenseUrlRest}
* This will simply store a url and an id. it'll be used to create an object with these variables out of information
* that came from the back-end. This object will then be used in the
* {@link org.dspace.app.rest.converter.SubmissionCCLicenseUrlConverter} to turn it into its REST object
*/
public class SubmissionCCLicenseUrl {
/**
* The url for ths object
*/
private String url;
/**
* The id for this object
*/
private String id;
/**
* Default constructor with two parameters, url and id
* @param url The url of this object
* @param id The id of this object
*/
public SubmissionCCLicenseUrl(String url, String id) {
this.url = url;
this.id = id;
}
/**
* Generic getter for the url
* @return the url value of this SubmissionCCLicenseUrl
*/
public String getUrl() {
return url;
}
/**
* Generic setter for the url
* @param url The url to be set on this SubmissionCCLicenseUrl
*/
public void setUrl(String url) {
this.url = url;
}
/**
* Generic getter for the id
* @return the id value of this SubmissionCCLicenseUrl
*/
public String getId() {
return id;
}
/**
* Generic setter for the id
* @param id The id to be set on this SubmissionCCLicenseUrl
*/
public void setId(String id) {
this.id = id;
}
}

View File

@@ -8,19 +8,24 @@
package org.dspace.app.rest.repository;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import org.dspace.app.rest.DiscoverableEndpointsService;
import org.dspace.app.rest.model.AuthorityRest;
import org.dspace.app.rest.model.AuthorizationRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.app.rest.utils.AuthorityUtils;
import org.dspace.content.authority.ChoiceAuthority;
import org.dspace.content.authority.service.ChoiceAuthorityService;
import org.dspace.core.Context;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.hateoas.Link;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
@@ -30,7 +35,8 @@ import org.springframework.stereotype.Component;
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
*/
@Component(AuthorityRest.CATEGORY + "." + AuthorityRest.NAME)
public class AuthorityRestRepository extends DSpaceRestRepository<AuthorityRest, String> {
public class AuthorityRestRepository extends DSpaceRestRepository<AuthorityRest, String>
implements InitializingBean {
@Autowired
private ChoiceAuthorityService cas;
@@ -38,6 +44,9 @@ public class AuthorityRestRepository extends DSpaceRestRepository<AuthorityRest,
@Autowired
private AuthorityUtils authorityUtils;
@Autowired
DiscoverableEndpointsService discoverableEndpointsService;
@PreAuthorize("hasAuthority('AUTHENTICATED')")
@Override
public AuthorityRest findOne(Context context, String name) {
@@ -63,4 +72,11 @@ public class AuthorityRestRepository extends DSpaceRestRepository<AuthorityRest,
public Class<AuthorityRest> getDomainClass() {
return AuthorityRest.class;
}
@Override
public void afterPropertiesSet() throws Exception {
discoverableEndpointsService.register(this, Arrays.asList(
new Link("/api/" + AuthorizationRest.CATEGORY + "/" + AuthorizationRest.NAME + "/search",
AuthorizationRest.NAME + "-search")));
}
}

View File

@@ -45,11 +45,10 @@ public class AuthorizationFeatureRestRepository extends DSpaceRestRepository<Aut
@PreAuthorize("hasAuthority('ADMIN')")
@Override
public Page<AuthorizationFeatureRest> findAll(Context context, Pageable pageable) {
return converter.toRestPage(utils.getPage(authorizationFeatureService.findAll(),
pageable), utils.obtainProjection());
return converter.toRestPage(authorizationFeatureService.findAll(), pageable, utils.obtainProjection());
}
@PreAuthorize("hasAuthority('ADMIN')")
@PreAuthorize("permitAll()")
@Override
public AuthorizationFeatureRest findOne(Context context, String id) {
AuthorizationFeature authzFeature = authorizationFeatureService.find(id);
@@ -64,6 +63,6 @@ public class AuthorizationFeatureRestRepository extends DSpaceRestRepository<Aut
public Page<AuthorizationFeatureRest> findByResourceType(@Parameter(value = "type", required = true) String type,
Pageable pageable) {
List<AuthorizationFeature> foundFeatures = authorizationFeatureService.findByResourceType(type);
return converter.toRestPage(utils.getPage(foundFeatures, pageable), utils.obtainProjection());
return converter.toRestPage(foundFeatures, pageable, utils.obtainProjection());
}
}

View File

@@ -174,7 +174,7 @@ public class AuthorizationRestRepository extends DSpaceRestRepository<Authorizat
// restore the real current user
context.restoreContextUser();
}
return converter.toRestPage(utils.getPage(authorizations, pageable), utils.obtainProjection());
return converter.toRestPage(authorizations, pageable, utils.obtainProjection());
}
/**

View File

@@ -42,6 +42,7 @@ public class BitstreamFormatRestRepository extends DSpaceRestRepository<Bitstrea
BitstreamFormatService bitstreamFormatService;
@Override
@PreAuthorize("permitAll()")
public BitstreamFormatRest findOne(Context context, Integer id) {
BitstreamFormat bit = null;
try {
@@ -59,7 +60,7 @@ public class BitstreamFormatRestRepository extends DSpaceRestRepository<Bitstrea
public Page<BitstreamFormatRest> findAll(Context context, Pageable pageable) {
try {
List<BitstreamFormat> bit = bitstreamFormatService.findAll(context);
return converter.toRestPage(utils.getPage(bit, pageable), utils.obtainProjection());
return converter.toRestPage(bit, pageable, utils.obtainProjection());
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}

View File

@@ -10,17 +10,14 @@ package org.dspace.app.rest.repository;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.exception.DSpaceBadRequestException;
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.BundleRest;
import org.dspace.app.rest.model.patch.Patch;
import org.dspace.app.rest.projection.Projection;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Bitstream;
@@ -34,7 +31,6 @@ import org.dspace.content.service.CommunityService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -71,7 +67,7 @@ public class BitstreamRestRepository extends DSpaceObjectRestRepository<Bitstrea
}
@Override
@PreAuthorize("hasPermission(#id, 'BITSTREAM', 'READ')")
@PreAuthorize("hasPermission(#id, 'BITSTREAM', 'METADATA_READ')")
public BitstreamRest findOne(Context context, UUID id) {
Bitstream bit = null;
try {
@@ -95,22 +91,7 @@ public class BitstreamRestRepository extends DSpaceObjectRestRepository<Bitstrea
@Override
@PreAuthorize("hasAuthority('ADMIN')")
public Page<BitstreamRest> findAll(Context context, Pageable pageable) {
List<Bitstream> bit = new ArrayList<Bitstream>();
Iterator<Bitstream> it = null;
int total = 0;
try {
total = bs.countTotal(context);
it = bs.findAll(context, pageable.getPageSize(), Math.toIntExact(pageable.getOffset()));
while (it.hasNext()) {
bit.add(it.next());
}
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
Projection projection = utils.obtainProjection();
Page<BitstreamRest> page = new PageImpl<>(bit, pageable, total)
.map((bitstream) -> converter.toRest(bitstream, projection));
return page;
throw new RepositoryMethodNotImplementedException(BitstreamRest.NAME, "findAll");
}
@Override

View File

@@ -16,6 +16,7 @@ import org.dspace.browse.BrowseIndex;
import org.dspace.core.Context;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
/**
@@ -27,6 +28,7 @@ import org.springframework.stereotype.Component;
public class BrowseIndexRestRepository extends DSpaceRestRepository<BrowseIndexRest, String> {
@Override
@PreAuthorize("permitAll()")
public BrowseIndexRest findOne(Context context, String name) {
BrowseIndexRest bi = null;
BrowseIndex bix;

View File

@@ -15,7 +15,6 @@ import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.BundleRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.BundleService;
@@ -52,8 +51,7 @@ public class BundleBitstreamLinkRepository extends AbstractDSpaceRestRepository
throw new ResourceNotFoundException("No such bundle: " + bundleId);
}
Pageable pageable = utils.getPageable(optionalPageable);
Page<Bitstream> page = utils.getPage(bundle.getBitstreams(), pageable);
return converter.toRestPage(page, projection);
return converter.toRestPage(bundle.getBitstreams(), pageable, projection);
} catch (SQLException e) {
throw new RuntimeException(e);
}

View File

@@ -74,11 +74,11 @@ public class BundleRestRepository extends DSpaceObjectRestRepository<Bundle, Bun
this.bundleService = dsoService;
}
@PreAuthorize("hasPermission(#uuid, 'BUNDLE', 'READ')")
public BundleRest findOne(Context context, UUID uuid) {
@PreAuthorize("hasPermission(#id, 'BUNDLE', 'READ')")
public BundleRest findOne(Context context, UUID id) {
Bundle bundle = null;
try {
bundle = bundleService.find(context, uuid);
bundle = bundleService.find(context, id);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}

View File

@@ -9,6 +9,7 @@ package org.dspace.app.rest.repository;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import javax.mail.MessagingException;
@@ -16,6 +17,7 @@ import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.dspace.app.rest.DiscoverableEndpointsService;
import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.exception.RESTAuthorizationException;
@@ -42,10 +44,12 @@ import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig;
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.hateoas.Link;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
@@ -56,7 +60,8 @@ import org.springframework.stereotype.Component;
*/
@Component(PoolTaskRest.CATEGORY + "." + ClaimedTaskRest.NAME)
public class ClaimedTaskRestRepository extends DSpaceRestRepository<ClaimedTaskRest, Integer> {
public class ClaimedTaskRestRepository extends DSpaceRestRepository<ClaimedTaskRest, Integer>
implements InitializingBean {
private static final Logger log = Logger.getLogger(ClaimedTaskRestRepository.class);
@@ -78,6 +83,9 @@ public class ClaimedTaskRestRepository extends DSpaceRestRepository<ClaimedTaskR
@Autowired
AuthorizeService authorizeService;
@Autowired
DiscoverableEndpointsService discoverableEndpointsService;
@Override
@PreAuthorize("hasPermission(#id, 'CLAIMEDTASK', 'READ')")
public ClaimedTaskRest findOne(Context context, Integer id) {
@@ -108,7 +116,7 @@ public class ClaimedTaskRestRepository extends DSpaceRestRepository<ClaimedTaskR
if (authorizeService.isAdmin(context) || userID.equals(currentUser.getID())) {
EPerson ep = epersonService.find(context, userID);
List<ClaimedTask> tasks = claimedTaskService.findByEperson(context, ep);
return converter.toRestPage(utils.getPage(tasks, pageable), utils.obtainProjection());
return converter.toRestPage(tasks, pageable, utils.obtainProjection());
} else {
throw new RESTAuthorizationException("Only administrators can search for claimed tasks of other users");
}
@@ -188,4 +196,11 @@ public class ClaimedTaskRestRepository extends DSpaceRestRepository<ClaimedTaskR
public Page<ClaimedTaskRest> findAll(Context context, Pageable pageable) {
throw new RepositoryMethodNotImplementedException(ClaimedTaskRest.NAME, "findAll");
}
@Override
public void afterPropertiesSet() throws Exception {
discoverableEndpointsService.register(this, Arrays.asList(
new Link("/api/" + ClaimedTaskRest.CATEGORY + "/" + ClaimedTaskRest.NAME + "/search",
ClaimedTaskRest.NAME + "-search")));
}
}

View File

@@ -72,6 +72,9 @@ public class CollectionBitstreamReadGroupLinkRepository extends AbstractDSpaceRe
}
List<Group> bitstreamGroups = authorizeService
.getAuthorizedGroups(context, collection, Constants.DEFAULT_BITSTREAM_READ);
if (bitstreamGroups == null || bitstreamGroups.isEmpty()) {
return null;
}
Group bitstreamReadGroup = bitstreamGroups.get(0);
if (bitstreamReadGroup == null) {

View File

@@ -163,9 +163,10 @@ public class CollectionRestRepository extends DSpaceObjectRestRepository<Collect
}
}
@SearchRestMethod(name = "findAuthorizedByCommunity")
public Page<CollectionRest> findAuthorizedByCommunity(
@Parameter(value = "uuid", required = true) UUID communityUuid, Pageable pageable) {
@SearchRestMethod(name = "findSubmitAuthorizedByCommunity")
public Page<CollectionRest> findSubmitAuthorizedByCommunity(
@Parameter(value = "uuid", required = true) UUID communityUuid, Pageable pageable,
@Parameter(value = "query") String q) {
try {
Context context = obtainContext();
Community com = communityService.find(context, communityUuid);
@@ -174,19 +175,26 @@ public class CollectionRestRepository extends DSpaceObjectRestRepository<Collect
CommunityRest.CATEGORY + "." + CommunityRest.NAME + " with id: " + communityUuid
+ " not found");
}
List<Collection> collections = cs.findAuthorized(context, com, Constants.ADD);
return converter.toRestPage(utils.getPage(collections, pageable), utils.obtainProjection());
} catch (SQLException e) {
List<Collection> collections = cs.findCollectionsWithSubmit(q, context, com,
Math.toIntExact(pageable.getOffset()),
Math.toIntExact(pageable.getOffset() + pageable.getPageSize()));
int tot = cs.countCollectionsWithSubmit(q, context, com);
return converter.toRestPage(collections, pageable, tot , utils.obtainProjection());
} catch (SQLException | SearchServiceException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
@SearchRestMethod(name = "findAuthorized")
public Page<CollectionRest> findAuthorized(Pageable pageable) {
@SearchRestMethod(name = "findSubmitAuthorized")
public Page<CollectionRest> findSubmitAuthorized(@Parameter(value = "query") String q,
Pageable pageable) throws SearchServiceException {
try {
Context context = obtainContext();
List<Collection> collections = cs.findAuthorizedOptimized(context, Constants.ADD);
return converter.toRestPage(utils.getPage(collections, pageable), utils.obtainProjection());
List<Collection> collections = cs.findCollectionsWithSubmit(q, context, null,
Math.toIntExact(pageable.getOffset()),
Math.toIntExact(pageable.getOffset() + pageable.getPageSize()));
int tot = cs.countCollectionsWithSubmit(q, context, null);
return converter.toRestPage(collections, pageable, tot, utils.obtainProjection());
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}

Some files were not shown because too many files have changed in this diff Show More