mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
Merge branch 'main' into CST-5340-OpenAIREFundingDataProvider
This commit is contained in:
@@ -63,56 +63,11 @@
|
||||
<groupId>org.glassfish.jersey.media</groupId>
|
||||
<artifactId>jersey-media-json-jackson</artifactId>
|
||||
<version>${jersey.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-module-jaxb-annotations</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.jaxrs</groupId>
|
||||
<artifactId>jackson-jaxrs-base</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.jaxrs</groupId>
|
||||
<artifactId>jackson-jaxrs-json-provider</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.module</groupId>
|
||||
<artifactId>jackson-module-jaxb-annotations</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.jaxrs</groupId>
|
||||
<artifactId>jackson-jaxrs-base</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.jaxrs</groupId>
|
||||
<artifactId>jackson-jaxrs-json-provider</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.module</groupId>
|
||||
<artifactId>jackson-module-jaxb-annotations</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<exclusions>
|
||||
<!-- Use versions provided by Solr / Tika -->
|
||||
<exclusion>
|
||||
<groupId>jakarta.activation</groupId>
|
||||
<artifactId>jakarta.activation-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<groupId>org.glassfish.jersey.media</groupId>
|
||||
<artifactId>jersey-media-jaxb</artifactId>
|
||||
<version>${jersey.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring dependencies -->
|
||||
@@ -167,11 +122,6 @@
|
||||
<groupId>jakarta.annotation</groupId>
|
||||
<artifactId>jakarta.annotation-api</artifactId>
|
||||
</exclusion>
|
||||
<!-- Newer version provided by solr-cell -->
|
||||
<exclusion>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-commons</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -204,30 +154,9 @@
|
||||
<version>${spring-security.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib</artifactId>
|
||||
<version>2.2.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Use DSpace, for now, an older version to minimize spring generated dependency on Discovery -->
|
||||
<dependency>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-api</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Connecting to DSpace datasource sets a dependency on Postgres DB-->
|
||||
|
@@ -22,7 +22,10 @@ The only tested way right now is to run this webapp inside your IDE (Eclipse). J
|
||||
> dspace.dir = d:/install/dspace7
|
||||
|
||||
## HAL Browser
|
||||
The modified version of the HAL Browser from the Spring Data REST project is included, the index.html file is overriden locally to support the /api baseURL (see [DATAREST-971](https://jira.spring.io/browse/DATAREST-971))
|
||||
|
||||
The modified version of the HAL Browser from https://github.com/mikekelly/hal-browser
|
||||
|
||||
We've updated/customized the HAL Browser to integrate better with our authentication system, provide CSRF support, and use a more recent version of its dependencies.
|
||||
|
||||
## Packages and main classes
|
||||
*[org.dspace.app.rest.Application](src/main/java/org/dspace/app/rest/Application.java)* is the spring boot main class it initializes
|
||||
|
@@ -68,7 +68,9 @@
|
||||
<!--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/styles.css</exclude>
|
||||
<exclude>src/main/webapp/js/hal/**</exclude>
|
||||
<exclude>src/main/webapp/js/vendor/**</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
@@ -238,24 +240,7 @@
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- These next two dependencies build a WAR that is BOTH executable
|
||||
AND deployable into an external container (Tomcat).
|
||||
See: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#build-tool-plugins-maven-packaging -->
|
||||
<!-- NOTE: For rapid development (if you don't need Solr or other webapps),
|
||||
you can temporarily comment these out, and switch <packaging> to "jar".
|
||||
This lets you develop in a standalone, runnable JAR application. -->
|
||||
<!--<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>-->
|
||||
<!-- Ensure embedded servlet container doesn't interfere when this
|
||||
WAR is deployed to an external Tomcat (i.e. provided). -->
|
||||
<!--<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>-->
|
||||
|
||||
<!-- Spring Boot dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
@@ -293,20 +278,24 @@
|
||||
<version>0.4.6</version>
|
||||
</dependency>
|
||||
|
||||
<!-- The HAL Browser -->
|
||||
<!-- HAL Browser (via WebJars) : https://github.com/mikekelly/hal-browser -->
|
||||
<!-- This is primarily used to pull in the HAL Browser core Javascript code ('js' folder), as we've overridden
|
||||
many dependencies below and the HTML pages in src/main/webapp/ -->
|
||||
<!-- NOTE: Eventually this should be replaced by the HAL Explorer included in Spring Data REST,
|
||||
see https://github.com/DSpace/DSpace/issues/3017 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-rest-hal-browser</artifactId>
|
||||
<version>${spring-hal-browser.version}</version>
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>hal-browser</artifactId>
|
||||
<version>ad9b865</version>
|
||||
</dependency>
|
||||
|
||||
<!-- WebJars dependencies used to update/enhance the default HAL Browser -->
|
||||
<!-- Pull in several 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>
|
||||
<version>3.6.0</version>
|
||||
</dependency>
|
||||
<!-- Pull in current version of Toastr (toastrjs.com) via WebJars
|
||||
Made available at: webjars/toastr/build/toastr.min.js -->
|
||||
@@ -315,17 +304,46 @@
|
||||
<artifactId>toastr</artifactId>
|
||||
<version>2.1.4</version>
|
||||
</dependency>
|
||||
<!-- Also pull in current version of Bootstrap via WebJars. This is currently ONLY used by our OAI-PMH
|
||||
interface. But, it is include here so that it's accessible to all interfaces enabled in server webapp.
|
||||
<!-- Pull in current version of URI.js (https://medialize.github.io/URI.js/) via WebJars
|
||||
Made available at: webjars/urijs/src/URI.min.js -->
|
||||
<dependency>
|
||||
<groupId>org.webjars.bowergithub.medialize</groupId>
|
||||
<artifactId>uri.js</artifactId>
|
||||
<version>1.19.10</version>
|
||||
</dependency>
|
||||
<!-- Pull in current version of Underscore.js (https://underscorejs.org/) via WebJars
|
||||
Made available at: webjars/underscore/underscore-min.js -->
|
||||
<dependency>
|
||||
<groupId>org.webjars.bowergithub.jashkenas</groupId>
|
||||
<artifactId>underscore</artifactId>
|
||||
<version>1.13.2</version>
|
||||
</dependency>
|
||||
<!-- Pull in current version of Backbone.js (http://backbonejs.org/) via WebJars
|
||||
Made available at: webjars/backbone/backbone-min.js -->
|
||||
<dependency>
|
||||
<groupId>org.webjars.bowergithub.jashkenas</groupId>
|
||||
<artifactId>backbone</artifactId>
|
||||
<version>1.4.1</version>
|
||||
</dependency>
|
||||
<!-- Pull in current version of json-editor.js (https://github.com/json-editor/json-editor) via WebJars
|
||||
Made available at: webjars/json-editor__json-editor/2.6.1/dist/jsoneditor.js
|
||||
(Required by js/vendor/CustomPostForm.js)
|
||||
NOTE: Because the path contains the version, you MUST update index.html when updating this dependency -->
|
||||
<dependency>
|
||||
<groupId>org.webjars.npm</groupId>
|
||||
<artifactId>json-editor__json-editor</artifactId>
|
||||
<version>2.6.1</version>
|
||||
</dependency>
|
||||
<!-- Also pull in current version of Bootstrap via WebJars.
|
||||
This is used by BOTH our HAL Browser and our OAI-PMH interface.
|
||||
Made available at: webjars/bootstrap/dist/js/bootstrap.min.js and
|
||||
webjars/bootstrap/dist/css/bootstrap.min.css -->
|
||||
<dependency>
|
||||
<groupId>org.webjars.bowergithub.twbs</groupId>
|
||||
<artifactId>bootstrap</artifactId>
|
||||
<version>4.5.2</version>
|
||||
<version>4.6.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Add in Spring Security for AuthN and AuthZ -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@@ -463,13 +481,11 @@
|
||||
<dependency>
|
||||
<groupId>com.jayway.jsonpath</groupId>
|
||||
<artifactId>json-path</artifactId>
|
||||
<version>${json-path.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jayway.jsonpath</groupId>
|
||||
<artifactId>json-path-assert</artifactId>
|
||||
<version>${json-path.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@@ -40,6 +40,7 @@ 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.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
@@ -192,13 +193,31 @@ public class Application extends SpringBootServletInitializer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a ViewController for the root path, to load HAL Browser
|
||||
* @param registry ViewControllerRegistry
|
||||
*/
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
// Ensure accessing the root path will load the index.html of the HAL Browser
|
||||
registry.addViewController("/").setViewName("forward:/index.html");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* dynamically for HAL Browser, etc.
|
||||
* @param registry ResourceHandlerRegistry
|
||||
*/
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
// First, "mount" the Hal Browser resources at the /browser path
|
||||
// NOTE: the hal-browser directory uses the version of the Hal browser, so this needs to be synced
|
||||
// with the org.webjars.hal-browser version in the POM
|
||||
registry
|
||||
.addResourceHandler("/browser/**")
|
||||
.addResourceLocations("/webjars/hal-browser/ad9b865/");
|
||||
|
||||
// Make all other Webjars available off the /webjars path
|
||||
registry
|
||||
.addResourceHandler("/webjars/**")
|
||||
.addResourceLocations("/webjars/");
|
||||
|
@@ -80,7 +80,7 @@ public class AuthenticationRestController implements InitializingBean {
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
discoverableEndpointsService
|
||||
.register(this, Arrays.asList(new Link("/api/" + AuthnRest.CATEGORY, AuthnRest.NAME)));
|
||||
.register(this, Arrays.asList(Link.of("/api/" + AuthnRest.CATEGORY, AuthnRest.NAME)));
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
|
@@ -59,7 +59,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
* </pre>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/" + BundleRest.CATEGORY + "/" + BundleRest.PLURAL_NAME + "/"
|
||||
@RequestMapping("/api/" + BundleRest.CATEGORY + "/" + BundleRest.PLURAL_NAME
|
||||
+ REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID + "/" + BitstreamRest.PLURAL_NAME)
|
||||
public class BundleUploadBitstreamController {
|
||||
|
||||
|
@@ -73,7 +73,7 @@ public class DiscoveryRestController implements InitializingBean {
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
discoverableEndpointsService
|
||||
.register(this, Arrays.asList(new Link("/api/" + SearchResultsRest.CATEGORY, SearchResultsRest.CATEGORY)));
|
||||
.register(this, Arrays.asList(Link.of("/api/" + SearchResultsRest.CATEGORY, SearchResultsRest.CATEGORY)));
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
|
@@ -66,8 +66,8 @@ public class IdentifierRestController implements InitializingBean {
|
||||
discoverableEndpointsService
|
||||
.register(this,
|
||||
Arrays.asList(
|
||||
new Link(
|
||||
new UriTemplate("/api/" + CATEGORY + "/" + ACTION,
|
||||
Link.of(
|
||||
UriTemplate.of("/api/" + CATEGORY + "/" + ACTION,
|
||||
new TemplateVariables(
|
||||
new TemplateVariable(PARAM, VariableType.REQUEST_PARAM))),
|
||||
CATEGORY)));
|
||||
|
@@ -45,7 +45,7 @@ public class OidcRestController {
|
||||
|
||||
@PostConstruct
|
||||
public void afterPropertiesSet() {
|
||||
discoverableEndpointsService.register(this, List.of(new Link("/api/" + AuthnRest.CATEGORY, "oidc")));
|
||||
discoverableEndpointsService.register(this, List.of(Link.of("/api/" + AuthnRest.CATEGORY, "oidc")));
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
|
@@ -127,7 +127,7 @@ public class RestResourceController implements InitializingBean {
|
||||
// Link l = linkTo(this.getClass(), r).withRel(r);
|
||||
String[] split = r.split("\\.", 2);
|
||||
String plural = English.plural(split[1]);
|
||||
Link l = new Link("/api/" + split[0] + "/" + plural, plural);
|
||||
Link l = Link.of("/api/" + split[0] + "/" + plural, plural);
|
||||
links.add(l);
|
||||
log.debug(l.getRel().value() + " " + l.getHref());
|
||||
}
|
||||
@@ -821,7 +821,7 @@ public class RestResourceController implements InitializingBean {
|
||||
link = linkTo(this.getClass(), apiCategory, model).slash(uuid).slash(subpath).withSelfRel();
|
||||
}
|
||||
|
||||
return new EntityModel(new EmbeddedPage(link.getHref(),
|
||||
return EntityModel.of(new EmbeddedPage(link.getHref(),
|
||||
pageResult.map(converter::toResource), null, subpath));
|
||||
} else {
|
||||
RestModel object = (RestModel) linkMethod.invoke(linkRepository, request,
|
||||
|
@@ -55,13 +55,15 @@ public class ScriptProcessesController {
|
||||
* 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
|
||||
* @param scriptName The name of the script that we want to start a process for
|
||||
* @param files (Optional) any files that need to be passed to the script for it to run
|
||||
* @return The ProcessResource object for the created process
|
||||
* @throws Exception If something goes wrong
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
@PreAuthorize("hasAuthority('ADMIN')")
|
||||
public ResponseEntity<RepresentationModel<?>> startProcess(@PathVariable(name = "name") String scriptName,
|
||||
@RequestParam(name = "file") List<MultipartFile> files)
|
||||
public ResponseEntity<RepresentationModel<?>> startProcess(
|
||||
@PathVariable(name = "name") String scriptName,
|
||||
@RequestParam(name = "file", required = false) List<MultipartFile> files)
|
||||
throws Exception {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Starting Process for Script with name: " + scriptName);
|
||||
|
@@ -57,7 +57,7 @@ public class StatisticsRestController implements InitializingBean {
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
discoverableEndpointsService
|
||||
.register(this, Arrays
|
||||
.asList(new Link("/api/" + RestAddressableModel.STATISTICS, RestAddressableModel.STATISTICS)));
|
||||
.asList(Link.of("/api/" + RestAddressableModel.STATISTICS, RestAddressableModel.STATISTICS)));
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
|
@@ -132,7 +132,7 @@ public class SubmissionCCLicenseUrlRepository extends DSpaceRestRepository<Submi
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
discoverableEndpointsService.register(this, Arrays.asList(
|
||||
new Link("/api/" + SubmissionCCLicenseUrlRest.CATEGORY + "/" +
|
||||
Link.of("/api/" + SubmissionCCLicenseUrlRest.CATEGORY + "/" +
|
||||
SubmissionCCLicenseUrlRest.PLURAL + "/search",
|
||||
SubmissionCCLicenseUrlRest.PLURAL + "-search")));
|
||||
}
|
||||
|
@@ -73,8 +73,8 @@ public class UUIDLookupRestController implements InitializingBean {
|
||||
discoverableEndpointsService
|
||||
.register(this,
|
||||
Arrays.asList(
|
||||
new Link(
|
||||
new UriTemplate("/api/" + CATEGORY + "/" + ACTION,
|
||||
Link.of(
|
||||
UriTemplate.of("/api/" + CATEGORY + "/" + ACTION,
|
||||
new TemplateVariables(
|
||||
new TemplateVariable(PARAM, VariableType.REQUEST_PARAM))),
|
||||
CATEGORY)));
|
||||
|
@@ -27,6 +27,7 @@ import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
||||
/**
|
||||
* Abstract implementation providing the common functionalities for all the inprogressSubmission Converter
|
||||
@@ -44,6 +45,8 @@ public abstract class AInprogressItemConverter<T extends InProgressSubmission,
|
||||
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(AInprogressItemConverter.class);
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
|
@@ -15,7 +15,6 @@ import org.dspace.app.rest.model.CheckSumRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.Bundle;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
@@ -27,9 +26,6 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class BitstreamConverter extends DSpaceObjectConverter<Bitstream, BitstreamRest> {
|
||||
|
||||
@Autowired
|
||||
ConverterService converter;
|
||||
|
||||
@Override
|
||||
public BitstreamRest convert(org.dspace.content.Bitstream obj, Projection projection) {
|
||||
BitstreamRest b = super.convert(obj, projection);
|
||||
|
@@ -14,6 +14,7 @@ import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
||||
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -26,6 +27,8 @@ import org.springframework.stereotype.Component;
|
||||
public class ClaimedTaskConverter
|
||||
implements IndexableObjectConverter<ClaimedTask, ClaimedTaskRest> {
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
|
@@ -38,6 +38,7 @@ import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -52,9 +53,12 @@ import org.springframework.stereotype.Service;
|
||||
/**
|
||||
* Converts domain objects from the DSpace service layer to rest objects, and from rest objects to resource
|
||||
* objects, applying {@link Projection}s where applicable.
|
||||
*
|
||||
* <P>
|
||||
* MUST be loaded @Lazy, as this service requires other services to be preloaded (especially DSpaceConverter components)
|
||||
* and that can result in circular references if those services need this ConverterService (and many do).
|
||||
* @author Luca Giamminonni (luca.giamminonni at 4science dot it)
|
||||
*/
|
||||
@Lazy
|
||||
@Service
|
||||
public class ConverterService {
|
||||
|
||||
|
@@ -24,6 +24,7 @@ import org.dspace.content.MetadataValue;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.RequestService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
||||
/**
|
||||
* This is the base converter from/to objects in the DSpace API data model and
|
||||
@@ -38,6 +39,8 @@ public abstract class DSpaceObjectConverter<M extends DSpaceObject, R extends or
|
||||
|
||||
private static final Logger log = LogManager.getLogger(DSpaceObjectConverter.class);
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
ConverterService converter;
|
||||
|
||||
|
@@ -18,6 +18,7 @@ import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.harvest.HarvestedCollection;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -28,6 +29,8 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class HarvestedCollectionConverter implements DSpaceConverter<HarvestedCollection, HarvestedCollectionRest> {
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
|
@@ -28,6 +28,7 @@ import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.DSpaceObjectService;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -39,6 +40,8 @@ public class MetadataConverter implements DSpaceConverter<MetadataValueList, Met
|
||||
@Autowired
|
||||
private ContentServiceFactory contentServiceFactory;
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
|
@@ -11,6 +11,7 @@ import org.dspace.app.rest.model.MetadataFieldRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.content.MetadataField;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -21,6 +22,8 @@ import org.springframework.stereotype.Component;
|
||||
*/
|
||||
@Component
|
||||
public class MetadataFieldConverter implements DSpaceConverter<MetadataField, MetadataFieldRest> {
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
|
@@ -13,6 +13,7 @@ import org.dspace.discovery.IndexableObject;
|
||||
import org.dspace.xmlworkflow.storedcomponents.PoolTask;
|
||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -25,6 +26,8 @@ import org.springframework.stereotype.Component;
|
||||
public class PoolTaskConverter
|
||||
implements IndexableObjectConverter<PoolTask, org.dspace.app.rest.model.PoolTaskRest> {
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
|
@@ -15,6 +15,7 @@ import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.scripts.Process;
|
||||
import org.dspace.scripts.service.ProcessService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -23,6 +24,8 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class ProcessConverter implements DSpaceConverter<Process, ProcessRest> {
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
|
@@ -11,6 +11,7 @@ import org.dspace.app.rest.model.RelationshipRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.content.Relationship;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -20,6 +21,8 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class RelationshipConverter implements DSpaceConverter<Relationship, RelationshipRest> {
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
|
@@ -11,6 +11,7 @@ import org.dspace.app.rest.model.RelationshipTypeRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.content.RelationshipType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -20,6 +21,8 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class RelationshipTypeConverter implements DSpaceConverter<RelationshipType, RelationshipTypeRest> {
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
|
@@ -12,6 +12,7 @@ import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.authorize.ResourcePolicy;
|
||||
import org.dspace.authorize.service.ResourcePolicyService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -26,6 +27,8 @@ public class ResourcePolicyConverter implements DSpaceConverter<ResourcePolicy,
|
||||
@Autowired
|
||||
ResourcePolicyService resourcePolicyService;
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
ConverterService converterService;
|
||||
|
||||
|
@@ -16,6 +16,7 @@ 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.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -25,6 +26,8 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class SubmissionCCLicenseConverter implements DSpaceConverter<CCLicense, SubmissionCCLicenseRest> {
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
|
@@ -16,6 +16,7 @@ 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.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -27,6 +28,8 @@ import org.springframework.stereotype.Component;
|
||||
public class SubmissionCCLicenseFieldConverter
|
||||
implements DSpaceConverter<CCLicenseField, SubmissionCCLicenseFieldRest> {
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
|
@@ -27,6 +27,7 @@ import org.dspace.content.Collection;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.RequestService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -47,6 +48,8 @@ public class SubmissionDefinitionConverter implements DSpaceConverter<Submission
|
||||
@Autowired
|
||||
private RequestService requestService;
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
|
@@ -18,6 +18,7 @@ import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -28,6 +29,8 @@ import org.springframework.stereotype.Component;
|
||||
public class TemplateItemConverter
|
||||
implements DSpaceConverter<TemplateItem, TemplateItemRest> {
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
ConverterService converter;
|
||||
|
||||
|
@@ -15,6 +15,7 @@ import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
||||
import org.dspace.xmlworkflow.state.Workflow;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -28,6 +29,8 @@ public class WorkflowDefinitionConverter implements DSpaceConverter<Workflow, Wo
|
||||
@Autowired
|
||||
protected XmlWorkflowFactory xmlWorkflowFactory;
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
ConverterService converter;
|
||||
|
||||
|
@@ -14,6 +14,7 @@ import org.dspace.app.rest.model.WorkflowStepRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.xmlworkflow.state.Step;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -24,6 +25,8 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class WorkflowStepConverter implements DSpaceConverter<Step, WorkflowStepRest> {
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components
|
||||
@Lazy
|
||||
@Autowired
|
||||
ConverterService converter;
|
||||
|
||||
|
@@ -12,9 +12,9 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.dspace.app.rest.security.WebSecurityConfiguration;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.csrf.CsrfToken;
|
||||
@@ -40,8 +40,9 @@ import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
@Component
|
||||
public class DSpaceAccessDeniedHandler implements AccessDeniedHandler {
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private WebSecurityConfiguration webSecurityConfiguration;
|
||||
private CsrfTokenRepository csrfTokenRepository;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("handlerExceptionResolver")
|
||||
@@ -69,9 +70,6 @@ public class DSpaceAccessDeniedHandler implements AccessDeniedHandler {
|
||||
// switched clients (from HAL Browser to UI or visa versa) and has an out-of-sync token.
|
||||
// NOTE: this logic is tested in AuthenticationRestControllerIT.testRefreshTokenWithInvalidCSRF()
|
||||
if (ex instanceof InvalidCsrfTokenException) {
|
||||
// Get access to our enabled CSRF token repository
|
||||
CsrfTokenRepository csrfTokenRepository = webSecurityConfiguration.getCsrfTokenRepository();
|
||||
|
||||
// Remove current token & generate a new one
|
||||
csrfTokenRepository.saveToken(null, request, response);
|
||||
CsrfToken newToken = csrfTokenRepository.generateToken(request);
|
||||
|
@@ -56,9 +56,7 @@ public abstract class HalLinkFactory<RESOURCE, CONTROLLER> {
|
||||
}
|
||||
|
||||
protected Link buildLink(String rel, String href) {
|
||||
Link link = new Link(href, rel);
|
||||
|
||||
return link;
|
||||
return Link.of(href, rel);
|
||||
}
|
||||
|
||||
protected CONTROLLER getMethodOn(Object... parameters) {
|
||||
|
@@ -14,6 +14,7 @@ import org.dspace.core.Context;
|
||||
import org.dspace.services.RequestService;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
||||
/**
|
||||
* This is the base class for any Rest Repository. It provides utility method to
|
||||
@@ -26,6 +27,7 @@ public abstract class AbstractDSpaceRestRepository {
|
||||
@Autowired
|
||||
protected Utils utils;
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
protected ConverterService converter;
|
||||
|
||||
|
@@ -287,7 +287,7 @@ public class ClaimedTaskRestRepository extends DSpaceRestRepository<ClaimedTaskR
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
discoverableEndpointsService.register(this, Arrays.asList(
|
||||
new Link("/api/" + ClaimedTaskRest.CATEGORY + "/" + ClaimedTaskRest.PLURAL_NAME + "/search",
|
||||
Link.of("/api/" + ClaimedTaskRest.CATEGORY + "/" + ClaimedTaskRest.PLURAL_NAME + "/search",
|
||||
ClaimedTaskRest.PLURAL_NAME + "-search")));
|
||||
}
|
||||
}
|
||||
|
@@ -22,12 +22,15 @@ import org.dspace.app.rest.exception.DSpaceBadRequestException;
|
||||
import org.dspace.app.rest.exception.RESTAuthorizationException;
|
||||
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.ItemRest;
|
||||
import org.dspace.app.rest.model.RestAddressableModel;
|
||||
import org.dspace.app.rest.model.patch.Patch;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.service.MetadataFieldService;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
@@ -45,20 +48,44 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
*/
|
||||
public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID extends Serializable>
|
||||
extends AbstractDSpaceRestRepository
|
||||
implements PagingAndSortingRepository<T, ID> {
|
||||
implements PagingAndSortingRepository<T, ID>, BeanNameAware {
|
||||
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(DSpaceRestRepository.class);
|
||||
|
||||
//Trick to make inner-calls to ourselves that are checked by Spring security
|
||||
//See:
|
||||
// https://stackoverflow.com/questions/13564627/spring-aop-not-working-for-method-call-inside-another-method
|
||||
// https://docs.spring.io/spring/docs/4.3.18.RELEASE/spring-framework-reference/htmlsingle/#aop-understanding-aop-proxies
|
||||
@Autowired
|
||||
private String thisRepositoryBeanName;
|
||||
private DSpaceRestRepository<T, ID> thisRepository;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private MetadataFieldService metadataFieldService;
|
||||
|
||||
/**
|
||||
* From BeanNameAware. Allows us to capture the name of the bean, so we can load it into thisRepository.
|
||||
* See getThisRepository() method.
|
||||
* @param beanName name of ourselves
|
||||
*/
|
||||
@Override
|
||||
public void setBeanName(String beanName) {
|
||||
this.thisRepositoryBeanName = beanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get access to our current DSpaceRestRepository bean. This is a trick to make inner-calls to ourselves that are
|
||||
* checked by Spring Security
|
||||
* See:
|
||||
* https://stackoverflow.com/questions/13564627/spring-aop-not-working-for-method-call-inside-another-method
|
||||
* https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-understanding-aop-proxies
|
||||
* @return current DSpaceRestRepository
|
||||
*/
|
||||
private DSpaceRestRepository<T, ID> getThisRepository() {
|
||||
if (thisRepository == null) {
|
||||
thisRepository = (DSpaceRestRepository<T, ID>) applicationContext.getBean(thisRepositoryBeanName);
|
||||
}
|
||||
return thisRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends T> S save(S entity) {
|
||||
Context context = null;
|
||||
@@ -108,7 +135,7 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
*/
|
||||
public Optional<T> findById(ID id) {
|
||||
Context context = obtainContext();
|
||||
final T object = thisRepository.findOne(context, id);
|
||||
final T object = getThisRepository().findOne(context, id);
|
||||
if (object == null) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
@@ -171,7 +198,7 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
public void deleteById(ID id) {
|
||||
Context context = obtainContext();
|
||||
try {
|
||||
thisRepository.delete(context, id);
|
||||
getThisRepository().delete(context, id);
|
||||
context.commit();
|
||||
} catch (AuthorizeException e) {
|
||||
throw new RESTAuthorizationException(e);
|
||||
@@ -212,6 +239,14 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Deletes all instances of the type T with the given IDs.
|
||||
*/
|
||||
public void deleteAllById(Iterable<? extends ID> ids) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Method to implement to support bulk delete of ALL entity instances
|
||||
@@ -235,7 +270,7 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
*/
|
||||
public Page<T> findAll(Pageable pageable) {
|
||||
Context context = obtainContext();
|
||||
return thisRepository.findAll(context, pageable);
|
||||
return getThisRepository().findAll(context, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,7 +298,7 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
Context context = null;
|
||||
try {
|
||||
context = obtainContext();
|
||||
T entity = thisRepository.createAndReturn(context);
|
||||
T entity = getThisRepository().createAndReturn(context);
|
||||
context.commit();
|
||||
return entity;
|
||||
} catch (AuthorizeException e) {
|
||||
@@ -284,7 +319,7 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
Context context = null;
|
||||
try {
|
||||
context = obtainContext();
|
||||
T entity = thisRepository.createAndReturn(context, uuid);
|
||||
T entity = getThisRepository().createAndReturn(context, uuid);
|
||||
context.commit();
|
||||
return entity;
|
||||
} catch (AuthorizeException e) {
|
||||
@@ -305,7 +340,7 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
Context context = null;
|
||||
try {
|
||||
context = obtainContext();
|
||||
T entity = thisRepository.createAndReturn(context, list);
|
||||
T entity = getThisRepository().createAndReturn(context, list);
|
||||
context.commit();
|
||||
return entity;
|
||||
} catch (AuthorizeException e) {
|
||||
@@ -406,7 +441,7 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
throws UnprocessableEntityException, DSpaceBadRequestException {
|
||||
Context context = obtainContext();
|
||||
try {
|
||||
thisRepository.patch(context, request, apiCategory, model, id, patch);
|
||||
getThisRepository().patch(context, request, apiCategory, model, id, patch);
|
||||
context.commit();
|
||||
} catch (AuthorizeException ae) {
|
||||
throw new RESTAuthorizationException(ae);
|
||||
@@ -507,7 +542,7 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
public T put(HttpServletRequest request, String apiCategory, String model, ID uuid, JsonNode jsonNode) {
|
||||
Context context = obtainContext();
|
||||
try {
|
||||
thisRepository.put(context, request, apiCategory, model, uuid, jsonNode);
|
||||
getThisRepository().put(context, request, apiCategory, model, uuid, jsonNode);
|
||||
context.commit();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("Unable to update DSpace object " + model + " with id=" + uuid, e);
|
||||
@@ -532,7 +567,7 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
List<String> stringList) {
|
||||
Context context = obtainContext();
|
||||
try {
|
||||
thisRepository.put(context, request, apiCategory, model, id, stringList);
|
||||
getThisRepository().put(context, request, apiCategory, model, id, stringList);
|
||||
context.commit();
|
||||
} catch (SQLException | AuthorizeException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
|
@@ -336,6 +336,6 @@ public class EPersonRestRepository extends DSpaceObjectRestRepository<EPerson, E
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
discoverableEndpointsService.register(this, Arrays.asList(
|
||||
new Link("/api/" + EPersonRest.CATEGORY + "/registrations", EPersonRest.NAME + "-registration")));
|
||||
Link.of("/api/" + EPersonRest.CATEGORY + "/registrations", EPersonRest.NAME + "-registration")));
|
||||
}
|
||||
}
|
||||
|
@@ -131,7 +131,7 @@ public class PoolTaskRestRepository extends DSpaceRestRepository<PoolTaskRest, I
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
discoverableEndpointsService.register(this, Arrays.asList(
|
||||
new Link("/api/" + PoolTaskRest.CATEGORY + "/" + PoolTaskRest.PLURAL_NAME + "/search",
|
||||
Link.of("/api/" + PoolTaskRest.CATEGORY + "/" + PoolTaskRest.PLURAL_NAME + "/search",
|
||||
PoolTaskRest.PLURAL_NAME + "-search")));
|
||||
}
|
||||
|
||||
|
@@ -324,7 +324,7 @@ public class ResourcePolicyRestRepository extends DSpaceRestRepository<ResourceP
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
discoverableEndpointsService.register(this, Arrays.asList(
|
||||
new Link("/api/" + ResourcePolicyRest.CATEGORY + "/" + ResourcePolicyRest.PLURAL_NAME + "/search",
|
||||
Link.of("/api/" + ResourcePolicyRest.CATEGORY + "/" + ResourcePolicyRest.PLURAL_NAME + "/search",
|
||||
ResourcePolicyRest.PLURAL_NAME + "-search")));
|
||||
}
|
||||
}
|
||||
|
@@ -147,8 +147,10 @@ public class ScriptRestRepository extends DSpaceRestRepository<ScriptRest, Strin
|
||||
DSpaceRunnable dSpaceRunnable = scriptService.createDSpaceRunnableForScriptConfiguration(scriptToExecute);
|
||||
try {
|
||||
dSpaceRunnable.initialize(args.toArray(new String[0]), restDSpaceRunnableHandler, context.getCurrentUser());
|
||||
checkFileNames(dSpaceRunnable, files);
|
||||
processFiles(context, restDSpaceRunnableHandler, files);
|
||||
if (files != null && !files.isEmpty()) {
|
||||
checkFileNames(dSpaceRunnable, files);
|
||||
processFiles(context, restDSpaceRunnableHandler, files);
|
||||
}
|
||||
restDSpaceRunnableHandler.schedule(dSpaceRunnable);
|
||||
} catch (ParseException e) {
|
||||
dSpaceRunnable.printHelp();
|
||||
|
@@ -56,7 +56,7 @@ public class VocabularyEntryDetailsRestRepository extends DSpaceRestRepository<V
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
discoverableEndpointsService.register(this, Arrays.asList(
|
||||
new Link("/api/" + VocabularyRest.CATEGORY + "/" + VocabularyEntryDetailsRest.PLURAL_NAME + "/search",
|
||||
Link.of("/api/" + VocabularyRest.CATEGORY + "/" + VocabularyEntryDetailsRest.PLURAL_NAME + "/search",
|
||||
VocabularyEntryDetailsRest.PLURAL_NAME + "-search")));
|
||||
}
|
||||
|
||||
|
@@ -13,7 +13,9 @@ import org.dspace.services.RequestService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
@@ -102,7 +104,7 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
// (both are defined below as methods).
|
||||
// While we primarily use JWT in headers, CSRF protection is needed because we also support JWT via Cookies
|
||||
.csrf()
|
||||
.csrfTokenRepository(this.getCsrfTokenRepository())
|
||||
.csrfTokenRepository(this.csrfTokenRepository())
|
||||
.sessionAuthenticationStrategy(this.sessionAuthenticationStrategy())
|
||||
.and()
|
||||
.exceptionHandling()
|
||||
@@ -168,7 +170,9 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
*
|
||||
* @return CsrfTokenRepository as described above
|
||||
*/
|
||||
public CsrfTokenRepository getCsrfTokenRepository() {
|
||||
@Lazy
|
||||
@Bean
|
||||
public CsrfTokenRepository csrfTokenRepository() {
|
||||
return new DSpaceCsrfTokenRepository();
|
||||
}
|
||||
|
||||
@@ -177,7 +181,7 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
* is only refreshed when it is used (or attempted to be used) by the client.
|
||||
*/
|
||||
private SessionAuthenticationStrategy sessionAuthenticationStrategy() {
|
||||
return new DSpaceCsrfAuthenticationStrategy(getCsrfTokenRepository());
|
||||
return new DSpaceCsrfAuthenticationStrategy(csrfTokenRepository());
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -21,7 +21,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.rest.model.wrapper.AuthenticationToken;
|
||||
import org.dspace.app.rest.security.DSpaceAuthentication;
|
||||
import org.dspace.app.rest.security.RestAuthenticationService;
|
||||
import org.dspace.app.rest.security.WebSecurityConfiguration;
|
||||
import org.dspace.app.rest.utils.ContextUtil;
|
||||
import org.dspace.authenticate.AuthenticationMethod;
|
||||
import org.dspace.authenticate.service.AuthenticationService;
|
||||
@@ -32,6 +31,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.http.ResponseCookie;
|
||||
import org.springframework.security.web.csrf.CsrfToken;
|
||||
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
||||
@@ -65,8 +65,9 @@ public class JWTTokenRestAuthenticationServiceImpl implements RestAuthentication
|
||||
@Autowired
|
||||
private AuthenticationService authenticationService;
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private WebSecurityConfiguration webSecurityConfiguration;
|
||||
private CsrfTokenRepository csrfTokenRepository;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
@@ -331,9 +332,6 @@ public class JWTTokenRestAuthenticationServiceImpl implements RestAuthentication
|
||||
* @param response current response
|
||||
*/
|
||||
private void resetCSRFToken(HttpServletRequest request, HttpServletResponse response) {
|
||||
// Get access to our enabled CSRF token repository
|
||||
CsrfTokenRepository csrfTokenRepository = webSecurityConfiguration.getCsrfTokenRepository();
|
||||
|
||||
// Remove current CSRF token & generate a new one
|
||||
// We do this as we want the token to change anytime you login or logout
|
||||
csrfTokenRepository.saveToken(null, request, response);
|
||||
|
@@ -63,6 +63,7 @@ import org.dspace.workflow.WorkflowItemService;
|
||||
import org.dspace.workflow.WorkflowService;
|
||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.data.rest.webmvc.json.patch.PatchException;
|
||||
import org.springframework.jdbc.datasource.init.UncategorizedScriptException;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -94,6 +95,7 @@ public class SubmissionService {
|
||||
protected CreativeCommonsService creativeCommonsService;
|
||||
@Autowired
|
||||
private RequestService requestService;
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
@Autowired
|
||||
|
@@ -11,7 +11,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.web.config.EnableSpringDataWebSupport;
|
||||
|
||||
/**
|
||||
* This class provides extra configuration for our Spring Boot Application
|
||||
@@ -23,7 +22,6 @@ import org.springframework.data.web.config.EnableSpringDataWebSupport;
|
||||
* @author Tim Donohue
|
||||
*/
|
||||
@Configuration
|
||||
@EnableSpringDataWebSupport
|
||||
@ComponentScan( {"org.dspace.app.rest.converter", "org.dspace.app.rest.repository", "org.dspace.app.rest.utils",
|
||||
"org.dspace.app.configuration", "org.dspace.iiif", "org.dspace.app.iiif"})
|
||||
public class ApplicationConfig {
|
||||
|
@@ -17,6 +17,7 @@ import org.dspace.content.authority.Choice;
|
||||
import org.dspace.content.authority.ChoiceAuthority;
|
||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -38,6 +39,9 @@ public class AuthorityUtils {
|
||||
@Autowired
|
||||
private ChoiceAuthorityService cas;
|
||||
|
||||
// Lazy load required so that AuthorityUtils can be used from DSpaceConverter components
|
||||
// (because ConverterService autowires all DSpaceConverter components)
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
|
@@ -84,6 +84,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -131,6 +132,8 @@ public class Utils {
|
||||
@Autowired
|
||||
private BitstreamFormatService bitstreamFormatService;
|
||||
|
||||
// Must be loaded @Lazy, as ConverterService also autowires Utils
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
|
@@ -38,11 +38,6 @@
|
||||
# interact with or read its configuration from dspace.cfg.
|
||||
dspace.dir=${dspace.dir}
|
||||
|
||||
########################
|
||||
# Spring DATA Rest settings
|
||||
#
|
||||
spring.data.rest.basePath=
|
||||
|
||||
########################
|
||||
# Jackson serialization settings
|
||||
#
|
||||
@@ -60,11 +55,9 @@ spring.messages.encoding=UTF-8
|
||||
#
|
||||
#
|
||||
# Charset of HTTP requests and responses. Added to the "Content-Type" header if not set explicitly.
|
||||
spring.http.encoding.charset=UTF-8
|
||||
# Enable http encoding support.
|
||||
spring.http.encoding.enabled=true
|
||||
server.servlet.encoding.charset=UTF-8
|
||||
# Force the encoding to the configured charset on HTTP requests and responses.
|
||||
spring.http.encoding.force=true
|
||||
server.servlet.encoding.force=true
|
||||
|
||||
###########################
|
||||
# Server Properties
|
||||
|
@@ -6,51 +6,54 @@
|
||||
* This DSpace version has be customized to include:
|
||||
* * Download file functionality (see new downloadFile() method)
|
||||
* * Improved AuthorizationHeader parsing (see new getAuthorizationHeader() method)
|
||||
* * Upgraded third party dependencies (JQuery)
|
||||
* * Upgraded third party dependencies via WebJars
|
||||
* * Updated to use Bootstrap 4, based loosely on this PR to HAL Browser:
|
||||
https://github.com/mikekelly/hal-browser/pull/102
|
||||
-->
|
||||
<!doctype html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>The HAL Browser (customized for DSpace Server Webapp)</title>
|
||||
<link rel="stylesheet" media="screen" href="browser/vendor/css/bootstrap.css" />
|
||||
<title>The HAL Browser (customized for DSpace)</title>
|
||||
<link rel="stylesheet" media="screen" href="webjars/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<style type="text/css">
|
||||
body {
|
||||
padding-top: 60px;
|
||||
padding-bottom: 40px;
|
||||
height: 100vh;
|
||||
}
|
||||
.sidebar-nav {
|
||||
padding: 9px 0;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" media="screen" href="browser/vendor/css/bootstrap-responsive.css" />
|
||||
<link rel="stylesheet" media="screen" href="browser/styles.css" />
|
||||
<link rel="stylesheet" media="screen" href="styles.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="brand">The HAL Browser</a>
|
||||
<div class="nav-collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="#/" id="entryPointLink">Go To Entry Point</a></li>
|
||||
<li><a href="https://github.com/mikekelly/hal-browser">About The HAL Browser</a></li>
|
||||
<li><a href="login.html">Login</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="navbar sticky-top navbar-expand-md navbar-light bg-light">
|
||||
<a class="navbar-brand" href="#">The HAL Browser</a>
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#/" id="entryPointLink">Go To Entry Point</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://github.com/mikekelly/hal-browser">About The HAL Browser</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="login.html">Login</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="browser" class="container-fluid"></div>
|
||||
|
||||
<script id="location-bar-template" type="text/template">
|
||||
<form>
|
||||
<div class="input-append span12 location-bar-container">
|
||||
<input class="span11" id="appendedInputButton" type="text" value="<%= _.escape(url) %>">
|
||||
<button class="btn" type="submit">Go!</button>
|
||||
<span class="ajax-loader"></span>
|
||||
<div class="input-group mb-3">
|
||||
<input type="text" class="form-control" id="appendedInputButton" type="text" value="<%= _.escape(url) %>">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-outline-secondary input-group-text" type="submit">Go!</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
@@ -60,12 +63,12 @@
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>rel</th>
|
||||
<th>title</th>
|
||||
<th>name / index</th>
|
||||
<th>docs</th>
|
||||
<th>GET</th>
|
||||
<th>NON-GET</th>
|
||||
<th scope="col">rel</th>
|
||||
<th scope="col">title</th>
|
||||
<th scope="col">name / index</th>
|
||||
<th scope="col">docs</th>
|
||||
<th scope="col">GET</th>
|
||||
<th scope="col">NON-GET</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -78,14 +81,14 @@
|
||||
<td><%= link.name ? 'name: ' + link.name : 'index: ' + i %></td>
|
||||
<td>
|
||||
<% if (HAL.isUrl(rel)) { %>
|
||||
<a class="dox" href="<%= HAL.normalizeUrl(HAL.buildUrl(rel)) %>"><i class="icon-book"></i></a>
|
||||
<a class="dox" href="<%= HAL.normalizeUrl(HAL.buildUrl(rel)) %>">🕮</a>
|
||||
<% } %>
|
||||
</td>
|
||||
<td>
|
||||
<% if (link.templated === true) { %>
|
||||
<a class="query btn btn-success" href="<%= HAL.normalizeUrl(link.href) %>" title="Query URI template"><i class="icon-question-sign"></i></a>
|
||||
<a class="query btn btn-success" href="<%= HAL.normalizeUrl(link.href) %>" title="Query URI template">?</a>
|
||||
<% } else { %>
|
||||
<a class="follow btn btn-success" href="<%= HAL.normalizeUrl(link.href) %>" title="Follow link"><i class="icon-arrow-right"></i></a>
|
||||
<a class="follow btn btn-success" href="<%= HAL.normalizeUrl(link.href) %>" title="Follow link">➜</a>
|
||||
<% } %>
|
||||
</td>
|
||||
<td>
|
||||
@@ -100,14 +103,14 @@
|
||||
<td><%= obj.name || '' %></td>
|
||||
<td>
|
||||
<% if (HAL.isUrl(rel)) { %>
|
||||
<a class="dox" href="<%= HAL.normalizeUrl(HAL.buildUrl(rel)) %>"><i class="icon-book"></i></a>
|
||||
<a class="dox btn btn-success" href="<%= HAL.normalizeUrl(HAL.buildUrl(rel)) %>">🕮</a>
|
||||
<% } %>
|
||||
</td>
|
||||
<td>
|
||||
<% if (obj.templated === true) { %>
|
||||
<a class="query btn btn-success" href="<%= HAL.normalizeUrl(obj.href) %>" title="Query URI template"><i class="icon-question-sign"></i></a>
|
||||
<a class="query btn btn-success" href="<%= HAL.normalizeUrl(obj.href) %>" title="Query URI template">?</a>
|
||||
<% } else { %>
|
||||
<a class="follow btn btn-success" href="<%= HAL.normalizeUrl(obj.href) %>" title="Follow link"><i class="icon-arrow-right"></i></a>
|
||||
<a class="follow btn btn-success" href="<%= HAL.normalizeUrl(obj.href) %>" title="Follow link">➜</a>
|
||||
<% } %>
|
||||
</td>
|
||||
<td>
|
||||
@@ -122,17 +125,25 @@
|
||||
|
||||
<script id="properties-template" type="text/template">
|
||||
<h2>Properties</h2>
|
||||
<pre><%= properties %></pre>
|
||||
<div class="card read-only">
|
||||
<div class="card-body">
|
||||
<pre><%= properties %></pre>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script id="request-headers-template" type="text/template">
|
||||
<h2>Custom Request Headers</h2>
|
||||
<textarea class="span12"></textarea>
|
||||
<div class="input-group">
|
||||
<textarea class="form-control"></textarea>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script id="response-headers-template" type="text/template">
|
||||
<h2>Response Headers</h2>
|
||||
<pre><%= status.code %> <%= status.text %>
|
||||
<div class="card read-only">
|
||||
<div class="card-body">
|
||||
<pre><%= status.code %> <%= status.text %>
|
||||
|
||||
<% _.each(headers, function(value, name) {
|
||||
%><%= _.escape(name) %>: <%
|
||||
@@ -143,97 +154,119 @@
|
||||
%><% if(HAL.isFollowableHeader(name)) {
|
||||
%></a><%
|
||||
} %>
|
||||
<% }) %></pre>
|
||||
<% }) %>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script id="response-body-template" type="text/template">
|
||||
<h2>Response Body</h2>
|
||||
<pre><%= _.escape(body) %></pre>
|
||||
<div class="card read-only">
|
||||
<div class="card-body">
|
||||
<pre><%= _.escape(body) %></pre>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script id="query-uri-template" type="text/template">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>Expand URI Template</h3>
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5>Expand URI Template</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
</div>
|
||||
<form id="query" action="<%= href %>">
|
||||
<div class="modal-body">
|
||||
<label for="uri">URI Template:</label>
|
||||
<div class="card read-only" id="uri">
|
||||
<div class="card-body">
|
||||
<pre><%- href %></pre>
|
||||
</div>
|
||||
</div>
|
||||
<label for="input">Input (JSON):</label>
|
||||
<textarea class="form-control" id="input"><%= input %></textarea>
|
||||
<label for="preview">Expanded URI:</label>
|
||||
<div class="card read-only" id="preview">
|
||||
<div class="card-body">
|
||||
<pre class="preview"> </pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Follow URI</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="query" action="<%= href %>">
|
||||
<div class="modal-body">
|
||||
<p>URI Template:</p>
|
||||
<pre><%- href %></pre>
|
||||
<p>Input (JSON):</p>
|
||||
<textarea><%= input %></textarea>
|
||||
<p>Expanded URI:</p>
|
||||
<pre class="preview"> </pre>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Follow URI</button>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
|
||||
<script id="non-safe-request-template" type="text/template">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>Make a non-GET request</h3>
|
||||
</div>
|
||||
|
||||
<form class="non-safe" action="<%= _.escape(href) %>">
|
||||
<div class="modal-body">
|
||||
<p>Target URI</p>
|
||||
<input name="url" type="text" class="url" value="<%= _.escape(href) %>" />
|
||||
<p>Method:</p>
|
||||
<input name="method" type="text" class="method" value="POST" />
|
||||
<p>Headers:</p>
|
||||
<textarea name="headers" class="headers" style="height: 100px">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Make a NON-GET request</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
</div>
|
||||
<form class="non-safe" action="<%= href %>">
|
||||
<div class="modal-body">
|
||||
<label for="url">Target URI</label>
|
||||
<input name="url" type="text" class="url form-control" id="url" value="<%= href %>" />
|
||||
<label for="method">Method:</label>
|
||||
<input name="method" type="text" class="method form-control" id="method" value="POST" />
|
||||
<label for="headers">Headers:</label>
|
||||
<textarea name="headers" class="headers form-control" style="height: 100px" id="headers">
|
||||
Content-Type: application/json
|
||||
<%= user_defined_headers %>
|
||||
</textarea>
|
||||
<p>Body:</p>
|
||||
<textarea name="body" class="body" style="height: 200px">
|
||||
</textarea>
|
||||
<label for="body">Body:</label>
|
||||
<textarea name="body" class="body form-control" style="height: 200px" id="body">
|
||||
{
|
||||
|
||||
}
|
||||
</textarea>
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Make Request</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Make Request</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script id="dynamic-request-template" type="text/template">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>Create/Update</h3>
|
||||
</div>
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">Create/Update</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
</div>
|
||||
|
||||
<form class="non-safe" action="<%= href %>">
|
||||
<div class="modal-body" style="padding-top: 0px">
|
||||
<div id="jsoneditor"></div>
|
||||
<form class="non-safe" action="<%= href %>">
|
||||
<div class="modal-body">
|
||||
<div id="jsoneditor"></div>
|
||||
|
||||
<div class="well well-small" style="padding-bottom: 0px;">
|
||||
<div class="container-fluid">
|
||||
<div class="row-fluid">
|
||||
<div class="control-group">
|
||||
<label class="control-label" style="display: inline-block; font-weight: bold;">Action:</label>
|
||||
<input name="method" type="text" class="method controls" style="width: 98%" value="POST" />
|
||||
<input name="url" type="text" class="url controls" style="width: 98%" value="<%= href %>" />
|
||||
<div class="card card-body bg-light">
|
||||
<div class="container-fluid">
|
||||
<div class="row-fluid">
|
||||
<div class="form-group">
|
||||
<label class="col-form-label" style="display: inline-block; font-weight: bold;">Action:</label>
|
||||
<input name="method" type="text" class="method form-control" style="width: 98%" value="POST" />
|
||||
<input name="url" type="text" class="url form-control" style="width: 98%" value="<%= href %>" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Make Request</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Make Request</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
<script id="embedded-resources-template" type="text/template">
|
||||
<h2>Embedded Resources</h2>
|
||||
</script>
|
||||
@@ -250,13 +283,13 @@ Content-Type: application/json
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- Customized (to use WebJars) for DSpace -->
|
||||
<!-- Pull in updated versions of "vendor" libraries using WebJars -->
|
||||
<script src="webjars/jquery/dist/jquery.min.js"></script>
|
||||
<script src="browser/vendor/js/underscore.js"></script>
|
||||
<script src="browser/vendor/js/backbone.js"></script>
|
||||
<script src="webjars/underscore/underscore-min.js"></script>
|
||||
<script src="webjars/backbone/backbone-min.js"></script>
|
||||
<script src="browser/vendor/js/uritemplates.js"></script>
|
||||
<script src="browser/vendor/js/URI.min.js"></script>
|
||||
<script src="browser/vendor/js/bootstrap.js"></script>
|
||||
<script src="webjars/urijs/src/URI.min.js"></script>
|
||||
<script src="webjars/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||
|
||||
<script src="browser/js/hal.js"></script>
|
||||
<script src="browser/js/hal/browser.js"></script>
|
||||
@@ -288,8 +321,8 @@ Content-Type: application/json
|
||||
|
||||
<script src="browser/js/hal/views/documentation.js"></script>
|
||||
|
||||
<script src="browser/vendor/js/jsoneditor.js"></script>
|
||||
<script src="browser/js/CustomPostForm.js"></script>
|
||||
<script src="webjars/json-editor__json-editor/2.6.1/dist/jsoneditor.js"></script>
|
||||
<script src="js/vendor/CustomPostForm.js"></script>
|
||||
|
||||
<script>
|
||||
var browser = new HAL.Browser({
|
||||
|
208
dspace-server-webapp/src/main/webapp/js/vendor/CustomPostForm.js
vendored
Normal file
208
dspace-server-webapp/src/main/webapp/js/vendor/CustomPostForm.js
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
* Custom Backbone view that uses JSON Schema metadata to create pop-up dialog with actual field names instead of
|
||||
* asking user to input raw JSON.
|
||||
*
|
||||
* NOTE: Because JSON Schema lists all properties, including those that are links, they have to be filtered out.
|
||||
* Links have to be set via a PUT operation with the proper media type.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Gregory Frank
|
||||
* @since 2.4
|
||||
* @see DATAREST-627, DATAREST-1077
|
||||
*
|
||||
* This code was copied/borrowed from Spring Data REST version 3.3.x:
|
||||
* https://github.com/spring-projects/spring-data-rest/blob/3.3.x/spring-data-rest-hal-browser/src/main/resources/META-INF/spring-data-rest/hal-browser/js/CustomPostForm.js
|
||||
* NOTE: For DSpace, we made minor style/theme updates to align with Bootstrap 4.
|
||||
* This script requires json-editor (https://github.com/json-editor/json-editor) which we pull in via WebJars
|
||||
*/
|
||||
/* jshint strict: true */
|
||||
/* globals HAL, Backbone, _, $, window, jqxhr */
|
||||
|
||||
'use strict';
|
||||
|
||||
var CustomPostForm = Backbone.View.extend({
|
||||
initialize: function (opts) {
|
||||
this.href = opts.href.split('{')[0];
|
||||
this.vent = opts.vent;
|
||||
_.bindAll(this, 'createNewResource');
|
||||
},
|
||||
|
||||
events: {
|
||||
'submit form': 'createNewResource'
|
||||
},
|
||||
|
||||
className: 'modal fade',
|
||||
|
||||
/**
|
||||
* Perform a POST/PUT operation on the resource.
|
||||
*
|
||||
* @param e
|
||||
*/
|
||||
createNewResource: function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var self = this;
|
||||
|
||||
var opts = {
|
||||
url: this.$('.url').val(),
|
||||
headers: _.defaults({'Content-Type': 'application/json'}, HAL.client.getHeaders()),
|
||||
method: this.$('.method').val(),
|
||||
data: this.getNewResourceData()
|
||||
};
|
||||
|
||||
HAL.client.request(opts).done(function (response) {
|
||||
self.vent.trigger('response', {resource: response, jqxhr: jqxhr});
|
||||
}).fail(function (e) {
|
||||
self.vent.trigger('fail-response', {jqxhr: jqxhr});
|
||||
}).always(function (e) {
|
||||
self.vent.trigger('response-headers', {jqxhr: jqxhr});
|
||||
window.location.hash = 'NON-GET:' + opts.url;
|
||||
});
|
||||
|
||||
this.$el.modal('hide');
|
||||
},
|
||||
|
||||
/**
|
||||
* Draw the dialog after fetching the resource's JSON Schema metadata. If no metadata is available, use the
|
||||
* fallback editor.
|
||||
*
|
||||
* @param opts
|
||||
* @returns {CustomPostForm}
|
||||
*/
|
||||
render: function (opts) {
|
||||
var self = this;
|
||||
|
||||
try {
|
||||
HAL.client.request({
|
||||
method: 'HEAD',
|
||||
headers: HAL.client.getHeaders(),
|
||||
url: this.href
|
||||
}).done(function (message, text, jqXHR) {
|
||||
self.$el.html(self.template({href: self.href}));
|
||||
|
||||
try {
|
||||
var hal = self.w3cLinksToHalLinks(jqXHR.getResponseHeader('Link'));
|
||||
|
||||
HAL.client.request({
|
||||
method: 'GET',
|
||||
url: hal._links.profile.href,
|
||||
headers: _.defaults({'Accept': 'application/schema+json'}, HAL.client.getHeaders())
|
||||
}).done(function (schema) {
|
||||
self.loadJsonEditor(schema);
|
||||
});
|
||||
} catch (e) {
|
||||
self.loadFallbackEditor();
|
||||
}
|
||||
|
||||
self.$el.modal();
|
||||
});
|
||||
} catch (e) {
|
||||
self.loadFallbackEditor();
|
||||
self.$el.modal();
|
||||
}
|
||||
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Load the JSON Schema-driven editor.
|
||||
*
|
||||
* @see https://github.com/jdorn/json-editor
|
||||
*/
|
||||
loadJsonEditor: function (schema) {
|
||||
var self = this;
|
||||
|
||||
/**
|
||||
* Remove URI-based fields since this dialog doesn't handle relationships.
|
||||
*/
|
||||
Object.keys(schema.properties).forEach(function (property) {
|
||||
if (schema.properties[property].hasOwnProperty('format') &&
|
||||
schema.properties[property].format === 'uri') {
|
||||
delete schema.properties[property];
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* See https://github.com/jdorn/json-editor#options for more customizing options.
|
||||
*/
|
||||
this.editor = new window.JSONEditor(this.$('#jsoneditor')[0], {
|
||||
theme: 'bootstrap4',
|
||||
schema: schema,
|
||||
disable_collapse: true,
|
||||
disable_edit_json: true,
|
||||
disable_properties: true
|
||||
});
|
||||
|
||||
this.getNewResourceData = function() {
|
||||
return JSON.stringify(self.editor.getValue());
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Load fallback editor that doesn't depend on any form of metadata.
|
||||
*/
|
||||
loadFallbackEditor: function () {
|
||||
var editor = this.$('#jsoneditor');
|
||||
|
||||
editor.append($('<h5>' + this.href + '</h5>'));
|
||||
|
||||
var inputBox = $('<textarea name="body" class="body" style="height: 200px">{\n}</textarea>');
|
||||
editor.append(inputBox);
|
||||
|
||||
this.getNewResourceData = function() {
|
||||
return inputBox.val();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert a W3C link header into a HAL-based set of _links.
|
||||
*
|
||||
* e.g.
|
||||
* <http://localhost:8080/persons>; rel="persons",<http://localhost:8080/profile/persons>; rel="profile"
|
||||
* to
|
||||
* {
|
||||
* _links: {
|
||||
* persons: {
|
||||
* href: http://localhost:8080/persons
|
||||
* },
|
||||
* profile: {
|
||||
* href: http://localhost:8080/profile/persons
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @param linkHeader - HTTP Response header containing a list of W3C compliant links with rels.
|
||||
* @see https://www.w3.org/wiki/LinkHeader
|
||||
*/
|
||||
w3cLinksToHalLinks: function (linkHeader) {
|
||||
var w3cLinks = linkHeader.split(',');
|
||||
|
||||
var halLinks = {_links: {}};
|
||||
|
||||
w3cLinks.forEach(function (w3cLink) {
|
||||
var parts = w3cLink.split(';');
|
||||
|
||||
var hrefWrappedWithBrackets = parts[0];
|
||||
var href = hrefWrappedWithBrackets.slice(1, parts[0].length - 1);
|
||||
|
||||
var w3cRel = parts[1];
|
||||
var relWrappedWithQuotes = w3cRel.split('=')[1];
|
||||
var rel = relWrappedWithQuotes.slice(1, relWrappedWithQuotes.length - 1);
|
||||
|
||||
halLinks._links[rel] = { "href": href };
|
||||
});
|
||||
|
||||
return halLinks;
|
||||
},
|
||||
|
||||
/**
|
||||
* Look up the HTML template.
|
||||
*/
|
||||
template: _.template($('#dynamic-request-template').html())
|
||||
});
|
||||
|
||||
/**
|
||||
* Inject the form into the HAL Browser.
|
||||
*/
|
||||
HAL.customPostForm = CustomPostForm;
|
@@ -6,7 +6,7 @@
|
||||
* This DSpace version has be customized to include:
|
||||
* * Shibboleth login functionality
|
||||
* * Other customization to use DSpace's login endpoint
|
||||
* * Upgraded third party dependencies (JQuery)
|
||||
* * Upgraded third party dependencies (Bootstrap, JQuery, Toastr) using webjars
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@@ -14,9 +14,9 @@
|
||||
<meta charset="utf-8">
|
||||
<title>Sign in - HAL Browser</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="webjars/toastr/build/toastr.min.css" rel="stylesheet"/>
|
||||
<link href="browser/vendor/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="browser/vendor/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link rel="stylesheet" media="screen" href="webjars/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<!-- Toastr CSS must be loaded after Bootstrap -->
|
||||
<link rel="stylesheet" href="webjars/toastr/build/toastr.min.css"/>
|
||||
<style type="text/css">
|
||||
body {
|
||||
padding-top: 40px;
|
||||
@@ -24,16 +24,12 @@
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.form-signin {
|
||||
max-width: 300px;
|
||||
max-width: 350px;
|
||||
padding: 19px 29px 29px;
|
||||
margin: 0 auto 20px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #e5e5e5;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
|
||||
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
|
||||
}
|
||||
.form-signin .form-signin-heading, .form-signin .checkbox {
|
||||
@@ -51,17 +47,17 @@
|
||||
}
|
||||
</style>
|
||||
<script src="webjars/jquery/dist/jquery.min.js"></script>
|
||||
<script src="browser/vendor/js/bootstrap.js"></script>
|
||||
<script src="webjars/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||
<script src="webjars/toastr/build/toastr.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<form id="login-form" class="form-signin">
|
||||
<h2 class="form-signin-heading">HAL Browser</h2>
|
||||
<input type="text" class="input-block-level" placeholder="Username" id="username">
|
||||
<input type="password" class="input-block-level" placeholder="Password" id="password">
|
||||
<button type="submit" class="btn btn-large btn-primary" id="login">Sign in</button>
|
||||
<div class="other-login-methods hidden">
|
||||
<input type="text" class="form-control" placeholder="Username" id="username">
|
||||
<input type="password" class="form-control" placeholder="Password" id="password">
|
||||
<button type="submit" class="btn btn-large btn-primary form-signin-btn" id="login">Sign in</button>
|
||||
<div class="other-login-methods d-none">
|
||||
<h3>Other login methods:</h3>
|
||||
|
||||
</div>
|
||||
@@ -158,7 +154,7 @@
|
||||
});
|
||||
|
||||
function addLocationButton(realm, element){
|
||||
element.removeClass("hidden");
|
||||
element.removeClass("d-none");
|
||||
var loc = /location="([^,]*)"/.exec(realm);
|
||||
var name = /(\w+) (\w+=((".*?")|[^,]*)(, )?)*/.exec(realm);
|
||||
if (loc !== null && loc.length === 2) {
|
||||
|
104
dspace-server-webapp/src/main/webapp/styles.css
Normal file
104
dspace-server-webapp/src/main/webapp/styles.css
Normal file
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Customized version of the HAL Browser styles.css provided from https://github.com/mikekelly/hal-browser
|
||||
* Copyright (c) 2012 Mike Kelly, http://stateless.co/
|
||||
* MIT LICENSE: https://github.com/mikekelly/hal-browser/blob/master/MIT-LICENSE.txt
|
||||
*
|
||||
* This DSpace version has be customized to include:
|
||||
* * Updates to align with Bootstrap 4.
|
||||
**/
|
||||
html, body, #browser, .hal-browser { height: 100%; }
|
||||
|
||||
#browser #location-bar { margin: 10px 0; }
|
||||
|
||||
#browser #location-bar .address {
|
||||
border: 1px solid #999;
|
||||
padding: 4px; margin: 0;
|
||||
}
|
||||
|
||||
#browser #headers-bar {
|
||||
border: 1px solid #888;
|
||||
padding: 5px
|
||||
}
|
||||
|
||||
#request-headers {
|
||||
border: 0;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
resize: vertical;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
margin-bottom: 0px;
|
||||
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Updated to roughly match Bootstrap 4 'row' class */
|
||||
.hal-browser {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* Updated to roughly match Bootstrap 4 'col-6' class */
|
||||
.inspector { height: 100%;
|
||||
flex: 0 0 49%;
|
||||
max-width: 49%;
|
||||
margin-left: 2%}
|
||||
|
||||
/* Updated to roughly match Bootstrap 4 'col-6' class */
|
||||
.explorer { flex: 0 0 49%;
|
||||
max-width: 49%;}
|
||||
|
||||
.documentation { height: 100%; }
|
||||
.documentation iframe { width: 100%; height: 100%; border-color: transparent;}
|
||||
|
||||
.modal input, .modal textarea {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.modal textarea {
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.read-only {
|
||||
background-color: #f5f5f5 !important;
|
||||
}
|
||||
|
||||
.links .btn {
|
||||
padding: 2px 5px 2px;
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
body table.table {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.location-bar-container {
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.ajax-loader {
|
||||
vertical-align: middle;
|
||||
background-image: url("./vendor/img/ajax-loader.gif");
|
||||
background-repeat: no-repeat;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-left: 6px;
|
||||
opacity: 0;
|
||||
display: inline-block;
|
||||
transition: opacity 1s;
|
||||
}
|
||||
.ajax-loader.visible {
|
||||
opacity: 1;
|
||||
}
|
||||
.embedded-resource-title {
|
||||
font-style: italic;
|
||||
}
|
||||
.embedded-resource-title:before {
|
||||
content: "\"";
|
||||
}
|
||||
.embedded-resource-title:after {
|
||||
content: "\"";
|
||||
}
|
@@ -153,8 +153,8 @@ public class OAIpmhIT extends AbstractControllerIntegrationTest {
|
||||
getClient().perform(get(DEFAULT_CONTEXT).param("verb", "Identify"))
|
||||
// Expect a 200 response code
|
||||
.andExpect(status().isOk())
|
||||
// Expect the content type to be "text/xml"
|
||||
.andExpect(content().contentType("text/xml"))
|
||||
// Expect the content type to be "text/xml;charset=UTF-8"
|
||||
.andExpect(content().contentType("text/xml;charset=UTF-8"))
|
||||
// Expect <scheme>oai</scheme>
|
||||
.andExpect(xpath("OAI-PMH/Identify/description/oai-identifier/scheme").string("oai"))
|
||||
// Expect protocol version 2.0
|
||||
|
@@ -40,8 +40,8 @@ public class OpenSearchControllerDisabledIT extends AbstractControllerIntegratio
|
||||
.param("query", "dog"))
|
||||
//The status has to be 404 Not Found
|
||||
.andExpect(status().isNotFound())
|
||||
//We expect the content type to be "application/html"
|
||||
.andExpect(content().contentType("text/html"))
|
||||
//We expect the content type to be "text/html"
|
||||
.andExpect(content().contentType("text/html;charset=UTF-8"))
|
||||
.andExpect(content().string("OpenSearch Service is disabled"))
|
||||
;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ public class OpenSearchControllerDisabledIT extends AbstractControllerIntegratio
|
||||
getClient().perform(get("/opensearch/service"))
|
||||
//The status has to be 404 Not Found
|
||||
.andExpect(status().isNotFound())
|
||||
.andExpect(content().contentType("text/html"))
|
||||
.andExpect(content().contentType("text/html;charset=UTF-8"))
|
||||
.andExpect(content().string("OpenSearch Service is disabled"))
|
||||
;
|
||||
}
|
||||
|
@@ -203,7 +203,7 @@ public class BitstreamRestControllerIT extends AbstractControllerIntegrationTest
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
|
||||
.andExpect(header().string("ETag", "\"" + bitstream.getChecksum() + "\""))
|
||||
//We expect the content type to match the bitstream mime type
|
||||
.andExpect(content().contentType("text/plain"))
|
||||
.andExpect(content().contentType("text/plain;charset=UTF-8"))
|
||||
//THe bytes of the content must match the original content
|
||||
.andExpect(content().bytes(bitstreamContent.getBytes()));
|
||||
|
||||
@@ -265,7 +265,7 @@ public class BitstreamRestControllerIT extends AbstractControllerIntegrationTest
|
||||
//The response should give us details about the range
|
||||
.andExpect(header().string("Content-Range", "bytes 1-3/10"))
|
||||
//We expect the content type to match the bitstream mime type
|
||||
.andExpect(content().contentType("text/plain"))
|
||||
.andExpect(content().contentType("text/plain;charset=UTF-8"))
|
||||
//We only expect the bytes 1, 2 and 3
|
||||
.andExpect(content().bytes("123".getBytes()));
|
||||
|
||||
@@ -286,7 +286,7 @@ public class BitstreamRestControllerIT extends AbstractControllerIntegrationTest
|
||||
//The response should give us details about the range
|
||||
.andExpect(header().string("Content-Range", "bytes 4-9/10"))
|
||||
//We expect the content type to match the bitstream mime type
|
||||
.andExpect(content().contentType("text/plain"))
|
||||
.andExpect(content().contentType("text/plain;charset=UTF-8"))
|
||||
//We all remaining bytes, starting at byte 4
|
||||
.andExpect(content().bytes("456789".getBytes()));
|
||||
|
||||
@@ -827,7 +827,7 @@ public class BitstreamRestControllerIT extends AbstractControllerIntegrationTest
|
||||
//The ETag has to be based on the checksum
|
||||
.andExpect(header().string("ETag", "\"" + bitstream.getChecksum() + "\""))
|
||||
//We expect the content type to match the bitstream mime type
|
||||
.andExpect(content().contentType("application/pdf"))
|
||||
.andExpect(content().contentType("application/pdf;charset=UTF-8"))
|
||||
//THe bytes of the content must match the original content
|
||||
.andReturn().getResponse().getContentAsByteArray();
|
||||
|
||||
|
@@ -103,7 +103,7 @@ public class BundleUploadBitstreamControllerIT extends AbstractEntityIntegration
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
MvcResult mvcResult = getClient(token).perform(
|
||||
MockMvcRequestBuilders.fileUpload("/api/core/bundles/" + bundle.getID() + "/bitstreams")
|
||||
MockMvcRequestBuilders.multipart("/api/core/bundles/" + bundle.getID() + "/bitstreams")
|
||||
.file(file)
|
||||
.param("properties", mapper
|
||||
.writeValueAsString(bitstreamRest)))
|
||||
@@ -167,7 +167,7 @@ public class BundleUploadBitstreamControllerIT extends AbstractEntityIntegration
|
||||
input.getBytes());
|
||||
context.restoreAuthSystemState();
|
||||
MvcResult mvcResult = getClient(token)
|
||||
.perform(MockMvcRequestBuilders.fileUpload("/api/core/bundles/" + bundle.getID() + "/bitstreams")
|
||||
.perform(MockMvcRequestBuilders.multipart("/api/core/bundles/" + bundle.getID() + "/bitstreams")
|
||||
.file(file))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$.bundleName", is("TESTINGBUNDLE")))
|
||||
@@ -223,7 +223,7 @@ public class BundleUploadBitstreamControllerIT extends AbstractEntityIntegration
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
MvcResult mvcResult = getClient(token)
|
||||
.perform(MockMvcRequestBuilders.fileUpload("/api/core/bundles/" + bundle.getID() + "/bitstreams")
|
||||
.perform(MockMvcRequestBuilders.multipart("/api/core/bundles/" + bundle.getID() + "/bitstreams")
|
||||
.file(file))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$.uuid", notNullValue())).andReturn();
|
||||
@@ -273,7 +273,7 @@ public class BundleUploadBitstreamControllerIT extends AbstractEntityIntegration
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
getClient(token).perform(MockMvcRequestBuilders
|
||||
.fileUpload("/api/core/bundles/" + bundle.getID() + "/bitstreams")
|
||||
.multipart("/api/core/bundles/" + bundle.getID() + "/bitstreams")
|
||||
.file(file))
|
||||
.andExpect(status().isForbidden());
|
||||
|
||||
@@ -315,7 +315,7 @@ public class BundleUploadBitstreamControllerIT extends AbstractEntityIntegration
|
||||
input.getBytes());
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
getClient().perform(MockMvcRequestBuilders.fileUpload("/api/core/bundles/" + bundle.getID() + "/bitstreams")
|
||||
getClient().perform(MockMvcRequestBuilders.multipart("/api/core/bundles/" + bundle.getID() + "/bitstreams")
|
||||
.file(file))
|
||||
.andExpect(status().isUnauthorized());
|
||||
|
||||
@@ -367,7 +367,7 @@ public class BundleUploadBitstreamControllerIT extends AbstractEntityIntegration
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
MvcResult mvcResult = getClient(token)
|
||||
.perform(MockMvcRequestBuilders.fileUpload("/api/core/bundles/" + bundle.getID() + "/bitstreams")
|
||||
.perform(MockMvcRequestBuilders.multipart("/api/core/bundles/" + bundle.getID() + "/bitstreams")
|
||||
.file(file)
|
||||
.param("properties", mapper
|
||||
.writeValueAsString(bitstreamRest)))
|
||||
@@ -422,7 +422,7 @@ public class BundleUploadBitstreamControllerIT extends AbstractEntityIntegration
|
||||
input.getBytes());
|
||||
context.restoreAuthSystemState();
|
||||
getClient(token)
|
||||
.perform(MockMvcRequestBuilders.fileUpload("/api/core/bundles/" + bundle.getID() + "/bitstreams")
|
||||
.perform(MockMvcRequestBuilders.multipart("/api/core/bundles/" + bundle.getID() + "/bitstreams")
|
||||
.file(file).file(file2))
|
||||
.andExpect(status().isUnprocessableEntity());
|
||||
}
|
||||
|
@@ -51,7 +51,7 @@ public class CollectionLogoControllerIT extends AbstractControllerIntegrationTes
|
||||
|
||||
private String createLogoInternal() throws Exception {
|
||||
MvcResult mvcPostResult = getClient(adminAuthToken).perform(
|
||||
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(childCollection.getID().toString()))
|
||||
MockMvcRequestBuilders.multipart(getLogoUrlTemplate(childCollection.getID().toString()))
|
||||
.file(bitstreamFile))
|
||||
.andExpect(status().isCreated())
|
||||
.andReturn();
|
||||
@@ -64,7 +64,7 @@ public class CollectionLogoControllerIT extends AbstractControllerIntegrationTes
|
||||
@Test
|
||||
public void createLogoNotLoggedIn() throws Exception {
|
||||
getClient().perform(
|
||||
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(childCollection.getID().toString()))
|
||||
MockMvcRequestBuilders.multipart(getLogoUrlTemplate(childCollection.getID().toString()))
|
||||
.file(bitstreamFile))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
@@ -88,7 +88,7 @@ public class CollectionLogoControllerIT extends AbstractControllerIntegrationTes
|
||||
public void createLogoNoRights() throws Exception {
|
||||
String userToken = getAuthToken(eperson.getEmail(), password);
|
||||
getClient(userToken).perform(
|
||||
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(childCollection.getID().toString()))
|
||||
MockMvcRequestBuilders.multipart(getLogoUrlTemplate(childCollection.getID().toString()))
|
||||
.file(bitstreamFile))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
@@ -96,12 +96,12 @@ public class CollectionLogoControllerIT extends AbstractControllerIntegrationTes
|
||||
@Test
|
||||
public void createDuplicateLogo() throws Exception {
|
||||
getClient(adminAuthToken).perform(
|
||||
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(childCollection.getID().toString()))
|
||||
MockMvcRequestBuilders.multipart(getLogoUrlTemplate(childCollection.getID().toString()))
|
||||
.file(bitstreamFile))
|
||||
.andExpect(status().isCreated());
|
||||
|
||||
getClient(adminAuthToken).perform(
|
||||
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(childCollection.getID().toString()))
|
||||
MockMvcRequestBuilders.multipart(getLogoUrlTemplate(childCollection.getID().toString()))
|
||||
.file(bitstreamFile))
|
||||
.andExpect(status().isUnprocessableEntity());
|
||||
}
|
||||
@@ -109,7 +109,7 @@ public class CollectionLogoControllerIT extends AbstractControllerIntegrationTes
|
||||
@Test
|
||||
public void createLogoForNonexisting() throws Exception {
|
||||
getClient(adminAuthToken).perform(
|
||||
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate("16a4b65b-3b3f-4ef5-8058-ef6f5a653ef9"))
|
||||
MockMvcRequestBuilders.multipart(getLogoUrlTemplate("16a4b65b-3b3f-4ef5-8058-ef6f5a653ef9"))
|
||||
.file(bitstreamFile))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
@@ -46,7 +46,7 @@ public class CommunityLogoControllerIT extends AbstractControllerIntegrationTest
|
||||
|
||||
private String createLogoInternal() throws Exception {
|
||||
MvcResult mvcPostResult = getClient(adminAuthToken).perform(
|
||||
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(parentCommunity.getID().toString()))
|
||||
MockMvcRequestBuilders.multipart(getLogoUrlTemplate(parentCommunity.getID().toString()))
|
||||
.file(bitstreamFile))
|
||||
.andExpect(status().isCreated())
|
||||
.andReturn();
|
||||
@@ -59,7 +59,7 @@ public class CommunityLogoControllerIT extends AbstractControllerIntegrationTest
|
||||
@Test
|
||||
public void createLogoNotLoggedIn() throws Exception {
|
||||
getClient().perform(
|
||||
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(parentCommunity.getID().toString()))
|
||||
MockMvcRequestBuilders.multipart(getLogoUrlTemplate(parentCommunity.getID().toString()))
|
||||
.file(bitstreamFile))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
@@ -83,7 +83,7 @@ public class CommunityLogoControllerIT extends AbstractControllerIntegrationTest
|
||||
public void createLogoNoRights() throws Exception {
|
||||
String userToken = getAuthToken(eperson.getEmail(), password);
|
||||
getClient(userToken).perform(
|
||||
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(parentCommunity.getID().toString()))
|
||||
MockMvcRequestBuilders.multipart(getLogoUrlTemplate(parentCommunity.getID().toString()))
|
||||
.file(bitstreamFile))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
@@ -91,12 +91,12 @@ public class CommunityLogoControllerIT extends AbstractControllerIntegrationTest
|
||||
@Test
|
||||
public void createDuplicateLogo() throws Exception {
|
||||
getClient(adminAuthToken).perform(
|
||||
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(parentCommunity.getID().toString()))
|
||||
MockMvcRequestBuilders.multipart(getLogoUrlTemplate(parentCommunity.getID().toString()))
|
||||
.file(bitstreamFile))
|
||||
.andExpect(status().isCreated());
|
||||
|
||||
getClient(adminAuthToken).perform(
|
||||
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(parentCommunity.getID().toString()))
|
||||
MockMvcRequestBuilders.multipart(getLogoUrlTemplate(parentCommunity.getID().toString()))
|
||||
.file(bitstreamFile))
|
||||
.andExpect(status().isUnprocessableEntity());
|
||||
}
|
||||
@@ -104,7 +104,7 @@ public class CommunityLogoControllerIT extends AbstractControllerIntegrationTest
|
||||
@Test
|
||||
public void createLogoForNonexisting() throws Exception {
|
||||
getClient(adminAuthToken).perform(
|
||||
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate("16a4b65b-3b3f-4ef5-8058-ef6f5a653ef9"))
|
||||
MockMvcRequestBuilders.multipart(getLogoUrlTemplate("16a4b65b-3b3f-4ef5-8058-ef6f5a653ef9"))
|
||||
.file(bitstreamFile))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
@@ -12,8 +12,8 @@ import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
@@ -211,29 +211,26 @@ public class ScriptRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void postProcessNonAdminAuthorizeException() throws Exception {
|
||||
|
||||
String token = getAuthToken(eperson.getEmail(), password);
|
||||
|
||||
getClient(token).perform(post("/api/system/scripts/mock-script/processes").contentType("multipart/form-data"))
|
||||
getClient(token).perform(multipart("/api/system/scripts/mock-script/processes"))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessAnonymousAuthorizeException() throws Exception {
|
||||
getClient().perform(post("/api/system/scripts/mock-script/processes").contentType("multipart/form-data"))
|
||||
getClient().perform(multipart("/api/system/scripts/mock-script/processes"))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessAdminWrongOptionsException() throws Exception {
|
||||
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
AtomicReference<Integer> idRef = new AtomicReference<>();
|
||||
|
||||
try {
|
||||
getClient(token)
|
||||
.perform(post("/api/system/scripts/mock-script/processes").contentType("multipart/form-data"))
|
||||
.perform(multipart("/api/system/scripts/mock-script/processes"))
|
||||
.andExpect(status().isAccepted())
|
||||
.andExpect(jsonPath("$", is(
|
||||
ProcessMatcher.matchProcess("mock-script",
|
||||
@@ -277,9 +274,8 @@ public class ScriptRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
try {
|
||||
getClient(token)
|
||||
.perform(post("/api/system/scripts/mock-script/processes").contentType("multipart/form-data")
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.perform(multipart("/api/system/scripts/mock-script/processes")
|
||||
.param("properties", new Gson().toJson(list)))
|
||||
.andExpect(status().isAccepted())
|
||||
.andExpect(jsonPath("$", is(
|
||||
ProcessMatcher.matchProcess("mock-script",
|
||||
@@ -296,8 +292,7 @@ public class ScriptRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
public void postProcessNonExistingScriptNameException() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(post("/api/system/scripts/mock-script-invalid/processes")
|
||||
.contentType("multipart/form-data"))
|
||||
getClient(token).perform(multipart("/api/system/scripts/mock-script-invalid/processes"))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@@ -323,9 +318,8 @@ public class ScriptRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
try {
|
||||
getClient(token)
|
||||
.perform(post("/api/system/scripts/mock-script/processes").contentType("multipart/form-data")
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.perform(multipart("/api/system/scripts/mock-script/processes")
|
||||
.param("properties", new Gson().toJson(list)))
|
||||
.andExpect(status().isAccepted())
|
||||
.andExpect(jsonPath("$", is(
|
||||
ProcessMatcher.matchProcess("mock-script",
|
||||
@@ -361,9 +355,8 @@ public class ScriptRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
try {
|
||||
getClient(token)
|
||||
.perform(post("/api/system/scripts/mock-script/processes").contentType("multipart/form-data")
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.perform(multipart("/api/system/scripts/mock-script/processes")
|
||||
.param("properties", new Gson().toJson(list)))
|
||||
.andExpect(status().isAccepted())
|
||||
.andExpect(jsonPath("$", is(
|
||||
ProcessMatcher.matchProcess("mock-script",
|
||||
@@ -468,9 +461,10 @@ public class ScriptRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
try {
|
||||
getClient(token)
|
||||
.perform(fileUpload("/api/system/scripts/mock-script/processes").file(bitstreamFile)
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.perform(multipart("/api/system/scripts/mock-script/processes")
|
||||
.file(bitstreamFile)
|
||||
.characterEncoding("UTF-8")
|
||||
.param("properties", new Gson().toJson(list)))
|
||||
.andExpect(status().isAccepted())
|
||||
.andExpect(jsonPath("$", is(
|
||||
ProcessMatcher.matchProcess("mock-script",
|
||||
|
@@ -107,7 +107,7 @@ public class SitemapRestControllerIT extends AbstractControllerIntegrationTest {
|
||||
//** THEN **
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to match
|
||||
.andExpect(content().contentType("text/html"))
|
||||
.andExpect(content().contentType("text/html;charset=UTF-8"))
|
||||
.andReturn();
|
||||
|
||||
String response = result.getResponse().getContentAsString();
|
||||
@@ -123,7 +123,7 @@ public class SitemapRestControllerIT extends AbstractControllerIntegrationTest {
|
||||
//** THEN **
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to match
|
||||
.andExpect(content().contentType("text/html"))
|
||||
.andExpect(content().contentType("text/html;charset=UTF-8"))
|
||||
.andReturn();
|
||||
|
||||
String response = result.getResponse().getContentAsString();
|
||||
@@ -140,7 +140,7 @@ public class SitemapRestControllerIT extends AbstractControllerIntegrationTest {
|
||||
//** THEN **
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to match
|
||||
.andExpect(content().contentType("application/xml"))
|
||||
.andExpect(content().contentType("application/xml;charset=UTF-8"))
|
||||
.andReturn();
|
||||
|
||||
String response = result.getResponse().getContentAsString();
|
||||
@@ -156,7 +156,7 @@ public class SitemapRestControllerIT extends AbstractControllerIntegrationTest {
|
||||
//** THEN **
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to match
|
||||
.andExpect(content().contentType("application/xml"))
|
||||
.andExpect(content().contentType("application/xml;charset=UTF-8"))
|
||||
.andReturn();
|
||||
|
||||
String response = result.getResponse().getContentAsString();
|
||||
|
@@ -15,8 +15,8 @@ import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.data.rest.webmvc.RestMediaTypes.TEXT_URI_LIST_VALUE;
|
||||
import static org.springframework.http.MediaType.parseMediaType;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
@@ -2650,7 +2650,7 @@ public class TaskRestRepositoriesIT extends AbstractControllerIntegrationTest {
|
||||
InputStream bibtex = getClass().getResourceAsStream("bibtex-test.bib");
|
||||
final MockMultipartFile bibtexFile = new MockMultipartFile("file", "bibtex-test.bib", "application/x-bibtex",
|
||||
bibtex);
|
||||
getClient(reviewer1Token).perform(fileUpload("/api/workflow/workflowitems/" + witem.getID())
|
||||
getClient(reviewer1Token).perform(multipart("/api/workflow/workflowitems/" + witem.getID())
|
||||
.file(bibtexFile))
|
||||
.andExpect(status().isUnprocessableEntity());
|
||||
|
||||
@@ -2791,7 +2791,7 @@ public class TaskRestRepositoriesIT extends AbstractControllerIntegrationTest {
|
||||
InputStream bibtex = getClass().getResourceAsStream("bibtex-test.bib");
|
||||
final MockMultipartFile bibtexFile = new MockMultipartFile("file", "bibtex-test.bib", "application/x-bibtex",
|
||||
bibtex);
|
||||
getClient(authToken).perform(fileUpload("/api/workflow/workflowitems/" + witem.getID())
|
||||
getClient(authToken).perform(multipart("/api/workflow/workflowitems/" + witem.getID())
|
||||
.file(bibtexFile))
|
||||
.andExpect(status().isUnprocessableEntity());
|
||||
|
||||
@@ -2944,7 +2944,7 @@ public class TaskRestRepositoriesIT extends AbstractControllerIntegrationTest {
|
||||
InputStream bibtex = getClass().getResourceAsStream("bibtex-test.bib");
|
||||
final MockMultipartFile bibtexFile = new MockMultipartFile("file", "bibtex-test.bib", "application/x-bibtex",
|
||||
bibtex);
|
||||
getClient(reviewer1Token).perform(fileUpload("/api/workflow/workflowitems/" + witem.getID())
|
||||
getClient(reviewer1Token).perform(multipart("/api/workflow/workflowitems/" + witem.getID())
|
||||
.file(bibtexFile))
|
||||
.andExpect(status().isCreated());
|
||||
|
||||
|
@@ -1862,7 +1862,7 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenWorkspaceitemBecomeWorkflowitemWithAccessConditionsTheBitstremMustBeDownloableTest()
|
||||
public void whenWorkspaceitemBecomeWorkflowitemWithAccessConditionsTheBitstreamMustBeDownloableTest()
|
||||
throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
@@ -1890,8 +1890,6 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
||||
|
||||
String bitstreamContent = "0123456789";
|
||||
|
||||
AtomicReference<Integer> idRef = new AtomicReference<Integer>();
|
||||
|
||||
try (InputStream is = IOUtils.toInputStream(bitstreamContent, Charset.defaultCharset())) {
|
||||
|
||||
context.setCurrentUser(submitter);
|
||||
@@ -1905,56 +1903,60 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
||||
.withDescription("This is a bitstream to test range requests")
|
||||
.withMimeType("text/plain")
|
||||
.build();
|
||||
}
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
String tokenEPerson = getAuthToken(eperson.getEmail(), password);
|
||||
String tokenSubmitter = getAuthToken(submitter.getEmail(), password);
|
||||
String tokenReviewer1 = getAuthToken(reviewer1.getEmail(), password);
|
||||
String tokenEPerson = getAuthToken(eperson.getEmail(), password);
|
||||
String tokenSubmitter = getAuthToken(submitter.getEmail(), password);
|
||||
String tokenReviewer1 = getAuthToken(reviewer1.getEmail(), password);
|
||||
|
||||
// submitter can download the bitstream
|
||||
getClient(tokenSubmitter).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string("Accept-Ranges", "bytes"))
|
||||
.andExpect(header().string("ETag", "\"" + bitstream.getChecksum() + "\""))
|
||||
.andExpect(content().contentType("text/plain"))
|
||||
.andExpect(content().bytes(bitstreamContent.getBytes()));
|
||||
// submitter can download the bitstream
|
||||
getClient(tokenSubmitter).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string("Accept-Ranges", "bytes"))
|
||||
.andExpect(header().string("ETag", "\"" + bitstream.getChecksum() + "\""))
|
||||
.andExpect(content().contentType("text/plain;charset=UTF-8"))
|
||||
.andExpect(content().bytes(bitstreamContent.getBytes()));
|
||||
|
||||
// reviewer can't still download the bitstream
|
||||
getClient(tokenReviewer1).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||
.andExpect(status().isForbidden());
|
||||
// reviewer can't still download the bitstream
|
||||
getClient(tokenReviewer1).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||
.andExpect(status().isForbidden());
|
||||
|
||||
// others can't download the bitstream
|
||||
getClient(tokenEPerson).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||
.andExpect(status().isForbidden());
|
||||
// others can't download the bitstream
|
||||
getClient(tokenEPerson).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||
.andExpect(status().isForbidden());
|
||||
|
||||
// create a list of values to use in add operation
|
||||
List<Operation> addAccessCondition = new ArrayList<>();
|
||||
List<Map<String, String>> accessConditions = new ArrayList<Map<String,String>>();
|
||||
// create a list of values to use in add operation
|
||||
List<Operation> addAccessCondition = new ArrayList<>();
|
||||
List<Map<String, String>> accessConditions = new ArrayList<Map<String,String>>();
|
||||
|
||||
Map<String, String> value = new HashMap<>();
|
||||
value.put("name", "administrator");
|
||||
Map<String, String> value = new HashMap<>();
|
||||
value.put("name", "administrator");
|
||||
|
||||
accessConditions.add(value);
|
||||
accessConditions.add(value);
|
||||
|
||||
addAccessCondition.add(new AddOperation("/sections/upload/files/0/accessConditions", accessConditions));
|
||||
addAccessCondition.add(new AddOperation("/sections/upload/files/0/accessConditions", accessConditions));
|
||||
|
||||
String patchBody = getPatchContent(addAccessCondition);
|
||||
getClient(tokenSubmitter).perform(patch("/api/submission/workspaceitems/" + witem.getID())
|
||||
.content(patchBody)
|
||||
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.sections.upload.files[0].accessConditions[0].name",is("administrator")))
|
||||
.andExpect(jsonPath("$.sections.upload.files[0].accessConditions[0].startDate",nullValue()))
|
||||
.andExpect(jsonPath("$.sections.upload.files[0].accessConditions[0].endDate", nullValue()));
|
||||
String patchBody = getPatchContent(addAccessCondition);
|
||||
getClient(tokenSubmitter).perform(patch("/api/submission/workspaceitems/" + witem.getID())
|
||||
.content(patchBody)
|
||||
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.sections.upload.files[0].accessConditions[0].name",is("administrator")))
|
||||
.andExpect(jsonPath("$.sections.upload.files[0].accessConditions[0].startDate",nullValue()))
|
||||
.andExpect(jsonPath("$.sections.upload.files[0].accessConditions[0].endDate", nullValue()));
|
||||
|
||||
// verify that the patch changes have been persisted
|
||||
getClient(tokenSubmitter).perform(get("/api/submission/workspaceitems/" + witem.getID()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.sections.upload.files[0].accessConditions[0].name",is("administrator")))
|
||||
.andExpect(jsonPath("$.sections.upload.files[0].accessConditions[0].startDate",nullValue()))
|
||||
.andExpect(jsonPath("$.sections.upload.files[0].accessConditions[0].endDate", nullValue()));
|
||||
// verify that the patch changes have been persisted
|
||||
getClient(tokenSubmitter).perform(get("/api/submission/workspaceitems/" + witem.getID()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.sections.upload.files[0].accessConditions[0].name",is("administrator")))
|
||||
.andExpect(jsonPath("$.sections.upload.files[0].accessConditions[0].startDate",nullValue()))
|
||||
.andExpect(jsonPath("$.sections.upload.files[0].accessConditions[0].endDate", nullValue()));
|
||||
|
||||
AtomicReference<Integer> idRef = new AtomicReference<Integer>();
|
||||
|
||||
try {
|
||||
// submit the workspaceitem to start the workflow
|
||||
getClient(tokenSubmitter).perform(post(BASE_REST_SERVER_URL + "/api/workflow/workflowitems")
|
||||
.content("/api/submission/workspaceitems/" + witem.getID())
|
||||
@@ -1976,7 +1978,7 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string("Accept-Ranges", "bytes"))
|
||||
.andExpect(header().string("ETag", "\"" + bitstream.getChecksum() + "\""))
|
||||
.andExpect(content().contentType("text/plain"))
|
||||
.andExpect(content().contentType("text/plain;charset=UTF-8"))
|
||||
.andExpect(content().bytes(bitstreamContent.getBytes()));
|
||||
|
||||
// submitter can download the bitstream
|
||||
@@ -1984,7 +1986,7 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string("Accept-Ranges", "bytes"))
|
||||
.andExpect(header().string("ETag", "\"" + bitstream.getChecksum() + "\""))
|
||||
.andExpect(content().contentType("text/plain"))
|
||||
.andExpect(content().contentType("text/plain;charset=UTF-8"))
|
||||
.andExpect(content().bytes(bitstreamContent.getBytes()));
|
||||
|
||||
// others can't download the bitstream
|
||||
|
@@ -19,8 +19,8 @@ import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.springframework.data.rest.webmvc.RestMediaTypes.TEXT_URI_LIST_VALUE;
|
||||
import static org.springframework.http.MediaType.parseMediaType;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
@@ -934,7 +934,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
String authToken = getAuthToken(eperson.getEmail(), password);
|
||||
try {
|
||||
// create a workspaceitem from a single bibliographic entry file explicitly in the default collection (col1)
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(bibtexFile))
|
||||
// create should return 200, 201 (created) is better for single resource
|
||||
.andExpect(status().isOk())
|
||||
@@ -962,7 +962,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
|
||||
// create a workspaceitem from a single bibliographic entry file explicitly in the col2
|
||||
try {
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(bibtexFile)
|
||||
.param("owningCollection", col2.getID().toString()))
|
||||
.andExpect(status().isOk())
|
||||
@@ -1026,7 +1026,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
// create workspaceitems in the default collection (col1)
|
||||
AtomicReference<List<Integer>> idRef = new AtomicReference<>();
|
||||
try {
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(csvFile))
|
||||
// create should return 200, 201 (created) is better for single resource
|
||||
.andExpect(status().isOk())
|
||||
@@ -1065,7 +1065,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
|
||||
// create workspaceitems explicitly in the col2
|
||||
try {
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(csvFile)
|
||||
.param("owningCollection", col2.getID().toString()))
|
||||
.andExpect(status().isOk())
|
||||
@@ -1143,7 +1143,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
// create workspaceitems in the default collection (col1)
|
||||
|
||||
try {
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(csvFile))
|
||||
// create should return 200, 201 (created) is better for single resource
|
||||
.andExpect(status().isOk())
|
||||
@@ -1221,7 +1221,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
|
||||
// create workspaceitems in the default collection (col1)
|
||||
try {
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(tsvFile))
|
||||
// create should return 200, 201 (created) is better for single resource
|
||||
.andExpect(status().isOk())
|
||||
@@ -1297,7 +1297,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
|
||||
// create workspaceitems in the default collection (col1)
|
||||
try {
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(tsvFile))
|
||||
// create should return 200, 201 (created) is better for single resource
|
||||
.andExpect(status().isOk())
|
||||
@@ -1374,7 +1374,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
AtomicReference<List<Integer>> idRef = new AtomicReference<>();
|
||||
// create workspaceitems in the default collection (col1)
|
||||
try {
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(endnoteFile))
|
||||
// create should return 200, 201 (created) is better for single resource
|
||||
.andExpect(status().isOk())
|
||||
@@ -1453,7 +1453,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
|
||||
// create workspaceitems in the default collection (col1)
|
||||
try {
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(csvFile))
|
||||
// create should return 200, 201 (created) is better for single resource
|
||||
.andExpect(status().isOk())
|
||||
@@ -1534,7 +1534,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
|
||||
// create a workspaceitem from a single bibliographic entry file explicitly in the default collection (col1)
|
||||
try {
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(bibtexFile).file(pubmedFile))
|
||||
// create should return 200, 201 (created) is better for single resource
|
||||
.andExpect(status().isOk())
|
||||
@@ -1568,7 +1568,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
|
||||
// create a workspaceitem from a single bibliographic entry file explicitly in the col2
|
||||
try {
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(bibtexFile).file(pubmedFile)
|
||||
.param("owningCollection", col2.getID().toString()))
|
||||
.andExpect(status().isOk())
|
||||
@@ -1640,7 +1640,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
String authToken = getAuthToken(eperson.getEmail(), password);
|
||||
|
||||
// create a workspaceitem from a single bibliographic entry file explicitly in the default collection (col1)
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(bibtexFile))
|
||||
// create should return return a 422 because we don't allow/support bibliographic files
|
||||
// that have multiple metadata records
|
||||
@@ -1685,7 +1685,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
|
||||
// create a workspaceitem from a single bibliographic entry file explicitly in the default collection (col1)
|
||||
try {
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(pubmedFile))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value",
|
||||
@@ -1716,7 +1716,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
|
||||
// create a workspaceitem from a single bibliographic entry file explicitly in the col2
|
||||
try {
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(pubmedFile)
|
||||
.param("owningCollection", col2.getID().toString()))
|
||||
.andExpect(status().isOk())
|
||||
@@ -1776,7 +1776,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
// create a workspaceitem
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(pdfFile))
|
||||
// create should return 200, 201 (created) is better for single resource
|
||||
.andExpect(status().isOk())
|
||||
@@ -3491,7 +3491,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
// upload the file in our workspaceitem
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems/" + witem.getID())
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems/" + witem.getID())
|
||||
.file(pdfFile))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value",
|
||||
@@ -3534,7 +3534,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
// upload the file in our workspaceitem
|
||||
getClient().perform(fileUpload("/api/submission/workspaceitems/" + witem.getID())
|
||||
getClient().perform(multipart("/api/submission/workspaceitems/" + witem.getID())
|
||||
.file(pdfFile))
|
||||
.andExpect(status().isUnauthorized());
|
||||
|
||||
@@ -3580,7 +3580,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
|
||||
// upload the file in our workspaceitem
|
||||
String authToken = getAuthToken(eperson2.getEmail(), "qwerty02");
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems/" + witem.getID())
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems/" + witem.getID())
|
||||
.file(pdfFile))
|
||||
.andExpect(status().isForbidden());
|
||||
|
||||
@@ -3617,7 +3617,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
// upload the file in our workspaceitem
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems/" + witem.getID())
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems/" + witem.getID())
|
||||
.file(pdfFile))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value",
|
||||
@@ -4386,7 +4386,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
try {
|
||||
// adding a bibtex file with a single entry should automatically put the metadata in the bibtex file into
|
||||
// the item
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems/" + witem.getID())
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems/" + witem.getID())
|
||||
.file(bibtexFile))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$.sections.traditionalpageone['dc.title'][0].value",
|
||||
@@ -4403,7 +4403,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
is("bibtex-test.bib")));
|
||||
|
||||
// do again over a submission that already has a title, the manual input should be preserved
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems/" + witem2.getID())
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems/" + witem2.getID())
|
||||
.file(bibtexFile))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$.sections.traditionalpageone['dc.title'][0].value",
|
||||
@@ -4944,7 +4944,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
|
||||
// upload file and verify response
|
||||
getClient(authToken)
|
||||
.perform(fileUpload("/api/submission/workspaceitems/" + wItem.getID()).file(pdfFile))
|
||||
.perform(multipart("/api/submission/workspaceitems/" + wItem.getID()).file(pdfFile))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$.sections.upload.files[0].accessConditions", empty()));
|
||||
|
||||
@@ -5415,7 +5415,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
try {
|
||||
getClient(authToken).perform(fileUpload("/api/submission/workspaceitems")
|
||||
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||
.file(pdfFile))
|
||||
.andExpect(status().is(500));
|
||||
} finally {
|
||||
@@ -6976,7 +6976,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string("Accept-Ranges", "bytes"))
|
||||
.andExpect(header().string("ETag", "\"" + bitstream.getChecksum() + "\""))
|
||||
.andExpect(content().contentType("text/plain"))
|
||||
.andExpect(content().contentType("text/plain;charset=UTF-8"))
|
||||
.andExpect(content().bytes(bitstreamContent.getBytes()));
|
||||
|
||||
// others can't download the bitstream
|
||||
@@ -7014,7 +7014,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string("Accept-Ranges", "bytes"))
|
||||
.andExpect(header().string("ETag", "\"" + bitstream.getChecksum() + "\""))
|
||||
.andExpect(content().contentType("text/plain"))
|
||||
.andExpect(content().contentType("text/plain;charset=UTF-8"))
|
||||
.andExpect(content().bytes(bitstreamContent.getBytes()));
|
||||
|
||||
// others can't download the bitstream
|
||||
@@ -7171,7 +7171,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
||||
.andExpect(jsonPath("$.sections.upload.files[1]").doesNotExist());
|
||||
|
||||
// upload second file
|
||||
getClient(tokenEPerson).perform(fileUpload("/api/submission/workspaceitems/" + wItem.getID())
|
||||
getClient(tokenEPerson).perform(multipart("/api/submission/workspaceitems/" + wItem.getID())
|
||||
.file(xmlFile))
|
||||
.andExpect(status().isCreated());
|
||||
|
||||
|
@@ -9,7 +9,7 @@ package org.dspace.app.rest.csv;
|
||||
|
||||
import static com.jayway.jsonpath.JsonPath.read;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@@ -76,9 +76,8 @@ public class CsvExportIT extends AbstractControllerIntegrationTest {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token)
|
||||
.perform(fileUpload("/api/system/scripts/metadata-export/processes")
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.perform(multipart("/api/system/scripts/metadata-export/processes")
|
||||
.param("properties", new Gson().toJson(list)))
|
||||
.andExpect(status().isAccepted())
|
||||
.andExpect(jsonPath("$", is(
|
||||
ProcessMatcher.matchProcess("metadata-export",
|
||||
@@ -128,9 +127,8 @@ public class CsvExportIT extends AbstractControllerIntegrationTest {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token)
|
||||
.perform(fileUpload("/api/system/scripts/metadata-export/processes")
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.perform(multipart("/api/system/scripts/metadata-export/processes")
|
||||
.param("properties", new Gson().toJson(list)))
|
||||
.andExpect(status().isAccepted())
|
||||
.andExpect(jsonPath("$", is(
|
||||
ProcessMatcher.matchProcess("metadata-export",
|
||||
|
@@ -13,8 +13,8 @@ import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@@ -284,8 +284,8 @@ public class CsvImportIT extends AbstractEntityIntegrationTest {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token)
|
||||
.perform(fileUpload("/api/system/scripts/metadata-import/processes").file(bitstreamFile)
|
||||
.param("properties",
|
||||
.perform(multipart("/api/system/scripts/metadata-import/processes").file(bitstreamFile)
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.andExpect(status().isAccepted())
|
||||
.andDo(result -> idRef
|
||||
@@ -344,7 +344,7 @@ public class CsvImportIT extends AbstractEntityIntegrationTest {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token)
|
||||
.perform(fileUpload("/api/system/scripts/metadata-import/processes").file(bitstreamFile)
|
||||
.perform(multipart("/api/system/scripts/metadata-import/processes").file(bitstreamFile)
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.andExpect(status().isAccepted())
|
||||
|
@@ -13,6 +13,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -89,8 +90,9 @@ public class AbstractControllerIntegrationTest extends AbstractIntegrationTestWi
|
||||
public static final String REST_SERVER_URL = "http://localhost/api/";
|
||||
public static final String BASE_REST_SERVER_URL = "http://localhost";
|
||||
|
||||
// Our standard/expected content type
|
||||
protected MediaType contentType = new MediaType(MediaTypes.HAL_JSON.getType(),
|
||||
MediaTypes.HAL_JSON.getSubtype());
|
||||
MediaTypes.HAL_JSON.getSubtype(), StandardCharsets.UTF_8);
|
||||
|
||||
protected MediaType textUriContentType = RestMediaTypes.TEXT_URI_LIST;
|
||||
|
||||
|
@@ -9,7 +9,7 @@ package org.dspace.curate;
|
||||
|
||||
import static com.jayway.jsonpath.JsonPath.read;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@@ -87,9 +87,8 @@ public class CurationScriptIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
// Request with -t <invalidTaskOption>
|
||||
getClient(token)
|
||||
.perform(post(CURATE_SCRIPT_ENDPOINT).contentType("multipart/form-data")
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.perform(multipart(CURATE_SCRIPT_ENDPOINT)
|
||||
.param("properties", new Gson().toJson(list)))
|
||||
// Illegal Argument Exception
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
@@ -109,9 +108,8 @@ public class CurationScriptIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
// Request with missing required -i <handle>
|
||||
getClient(token)
|
||||
.perform(post(CURATE_SCRIPT_ENDPOINT).contentType("multipart/form-data")
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.perform(multipart(CURATE_SCRIPT_ENDPOINT)
|
||||
.param("properties", new Gson().toJson(list)))
|
||||
// Illegal Argument Exception
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
@@ -132,9 +130,8 @@ public class CurationScriptIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
// Request with missing required -i <handle>
|
||||
getClient(token)
|
||||
.perform(post(CURATE_SCRIPT_ENDPOINT).contentType("multipart/form-data")
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.perform(multipart(CURATE_SCRIPT_ENDPOINT)
|
||||
.param("properties", new Gson().toJson(list)))
|
||||
// Illegal Argument Exception
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
@@ -173,9 +170,8 @@ public class CurationScriptIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
// Request without -t <task> or -T <taskFile> (and no -q <queue>)
|
||||
getClient(token)
|
||||
.perform(post(CURATE_SCRIPT_ENDPOINT).contentType("multipart/form-data")
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.perform(multipart(CURATE_SCRIPT_ENDPOINT)
|
||||
.param("properties", new Gson().toJson(list)))
|
||||
// Illegal Argument Exception
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
@@ -196,9 +192,8 @@ public class CurationScriptIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
// Request with invalid -s <scope>; must be object, curation or open
|
||||
getClient(token)
|
||||
.perform(post(CURATE_SCRIPT_ENDPOINT).contentType("multipart/form-data")
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.perform(multipart(CURATE_SCRIPT_ENDPOINT)
|
||||
.param("properties", new Gson().toJson(list)))
|
||||
// Illegal Argument Exception
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
@@ -219,9 +214,8 @@ public class CurationScriptIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
// Request with invalid -s <scope>; must be object, curation or open
|
||||
getClient(token)
|
||||
.perform(post(CURATE_SCRIPT_ENDPOINT).contentType("multipart/form-data")
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.perform(multipart(CURATE_SCRIPT_ENDPOINT)
|
||||
.param("properties", new Gson().toJson(list)))
|
||||
// Illegal Argument Exception
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
@@ -262,9 +256,8 @@ public class CurationScriptIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
try {
|
||||
getClient(token)
|
||||
.perform(post(CURATE_SCRIPT_ENDPOINT).contentType("multipart/form-data")
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.perform(multipart(CURATE_SCRIPT_ENDPOINT)
|
||||
.param("properties", new Gson().toJson(list)))
|
||||
.andExpect(status().isAccepted())
|
||||
.andExpect(jsonPath("$", is(
|
||||
ProcessMatcher.matchProcess("curate",
|
||||
@@ -314,9 +307,8 @@ public class CurationScriptIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
try {
|
||||
getClient(token)
|
||||
.perform(post(CURATE_SCRIPT_ENDPOINT).contentType("multipart/form-data")
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.perform(multipart(CURATE_SCRIPT_ENDPOINT)
|
||||
.param("properties", new Gson().toJson(list)))
|
||||
.andExpect(status().isAccepted())
|
||||
.andExpect(jsonPath("$", is(
|
||||
ProcessMatcher.matchProcess("curate",
|
||||
@@ -366,9 +358,8 @@ public class CurationScriptIT extends AbstractControllerIntegrationTest {
|
||||
try {
|
||||
|
||||
getClient(token)
|
||||
.perform(post(CURATE_SCRIPT_ENDPOINT).contentType("multipart/form-data")
|
||||
.param("properties",
|
||||
new Gson().toJson(list)))
|
||||
.perform(multipart(CURATE_SCRIPT_ENDPOINT)
|
||||
.param("properties", new Gson().toJson(list)))
|
||||
.andExpect(jsonPath("$", is(
|
||||
ProcessMatcher.matchProcess("curate",
|
||||
String.valueOf(admin.getID()), parameters,
|
||||
|
@@ -113,20 +113,6 @@
|
||||
<dependency>
|
||||
<groupId>org.dspace.modules</groupId>
|
||||
<artifactId>additions</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- DSpace REST Webapp -->
|
||||
|
38
pom.xml
38
pom.xml
@@ -13,15 +13,15 @@
|
||||
|
||||
<organization>
|
||||
<name>LYRASIS</name>
|
||||
<url>http://www.dspace.org</url>
|
||||
<url>https://dspace.org</url>
|
||||
</organization>
|
||||
|
||||
<properties>
|
||||
<!--=== GENERAL / DSPACE-API DEPENDENCIES ===-->
|
||||
<java.version>11</java.version>
|
||||
<spring.version>5.2.5.RELEASE</spring.version>
|
||||
<spring-boot.version>2.2.6.RELEASE</spring-boot.version>
|
||||
<spring-security.version>5.2.2.RELEASE</spring-security.version> <!-- sync with version used by spring-boot-->
|
||||
<spring.version>5.3.18</spring.version>
|
||||
<spring-boot.version>2.6.6</spring-boot.version>
|
||||
<spring-security.version>5.6.2</spring-security.version> <!-- sync with version used by spring-boot-->
|
||||
<hibernate.version>5.6.5.Final</hibernate.version>
|
||||
<hibernate-validator.version>6.0.23.Final</hibernate-validator.version>
|
||||
<postgresql.driver.version>42.3.3</postgresql.driver.version>
|
||||
@@ -46,10 +46,8 @@
|
||||
<bouncycastle.version>1.70</bouncycastle.version>
|
||||
|
||||
<!--=== SERVER WEBAPP DEPENDENCIES ===-->
|
||||
<!-- Spring Data REST HAL Browser (used by Server webapp) -->
|
||||
<spring-hal-browser.version>3.2.6.RELEASE</spring-hal-browser.version>
|
||||
<!-- Library for reading JSON documents: https://github.com/json-path/JsonPath (used by Server webapp) -->
|
||||
<json-path.version>2.4.0</json-path.version>
|
||||
<json-path.version>2.6.0</json-path.version>
|
||||
<!-- Library for managing JSON Web Tokens (JWT): https://bitbucket.org/connect2id/nimbus-jose-jwt/wiki/Home
|
||||
(used by Server webapp) -->
|
||||
<nimbus-jose-jwt.version>7.9</nimbus-jose-jwt.version>
|
||||
@@ -1108,13 +1106,6 @@
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>${postgresql.driver.version}</version>
|
||||
<exclusions>
|
||||
<!-- Use version provided by Solr -->
|
||||
<exclusion>
|
||||
<groupId>org.checkerframework</groupId>
|
||||
<artifactId>checker-qual</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -1738,9 +1729,9 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>30.1.1-jre</version>
|
||||
<version>31.0.1-jre</version>
|
||||
<exclusions>
|
||||
<!-- Use version provided by Solr -->
|
||||
<!-- Use version provided by Solr / Postgres -->
|
||||
<exclusion>
|
||||
<groupId>org.checkerframework</groupId>
|
||||
<artifactId>checker-qual</artifactId>
|
||||
@@ -1752,6 +1743,21 @@
|
||||
<artifactId>xom</artifactId>
|
||||
<version>1.2.5</version>
|
||||
</dependency>
|
||||
|
||||
<!-- json-path is needed by Spring HATEOAS -->
|
||||
<dependency>
|
||||
<groupId>com.jayway.jsonpath</groupId>
|
||||
<artifactId>json-path</artifactId>
|
||||
<version>${json-path.version}</version>
|
||||
</dependency>
|
||||
<!-- json-path-assert is just needed by tests -->
|
||||
<dependency>
|
||||
<groupId>com.jayway.jsonpath</groupId>
|
||||
<artifactId>json-path-assert</artifactId>
|
||||
<version>${json-path.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- JAXB API and implementation (no longer bundled as of Java 11) -->
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
|
Reference in New Issue
Block a user