Merge branch 'master' into DS-4317_bundles-in-REST

# Conflicts:
#	dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java
This commit is contained in:
Marie Verdonck
2019-11-14 18:37:30 +01:00
19 changed files with 1230 additions and 35 deletions

View File

@@ -27,8 +27,6 @@
<resource.delimiter>@</resource.delimiter>
<!-- Define our starting class for our Spring Boot Application -->
<start-class>org.dspace.app.rest.Application</start-class>
<!-- Library for reading JSON documents: https://github.com/json-path/JsonPath -->
<json-path.version>2.4.0</json-path.version>
<!-- Library for managing JSON Web Tokens (JWT): https://bitbucket.org/connect2id/nimbus-jose-jwt/wiki/Home -->
<nimbus-jose-jwt.version>6.2</nimbus-jose-jwt.version>
</properties>
@@ -150,6 +148,37 @@
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<attachClasses>true</attachClasses>
<!-- Filter the web.xml (needed for IDE compatibility/debugging) -->
<filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
</configuration>
<executions>
<execution>
<phase>prepare-package</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<!-- Builds a *-tests.jar of all test classes -->
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
@@ -299,7 +328,6 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<scope>test</scope>
<exclusions>
<!-- Temporary exclusion to avoid dependency conflict with version of org.json:json used by dspace-api.
@@ -325,7 +353,6 @@
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path-assert</artifactId>
<version>${json-path.version}</version>
<scope>test</scope>
</dependency>
<dependency> <!-- Keep jmockit before junit -->
@@ -418,7 +445,6 @@
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-cell</artifactId>
<version>${solr.client.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
@@ -480,7 +506,6 @@
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-icu</artifactId>
<version>${solr.client.version}</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@@ -0,0 +1,112 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import java.io.IOException;
import java.sql.SQLException;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.CollectionRest;
import org.dspace.app.rest.model.hateoas.BitstreamResource;
import org.dspace.app.rest.repository.CollectionRestRepository;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.service.CollectionService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ControllerUtils;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* This RestController takes care of the creation and deletion of Collection's nested objects
* This class will typically receive the UUID of a Collection and it'll perform logic on its nested objects
*/
@RestController
@RequestMapping("/api/" + CollectionRest.CATEGORY + "/" + CollectionRest.PLURAL_NAME
+ CollectionLogoController.REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID + "/logo")
public class CollectionLogoController {
/**
* Regular expression in the request mapping to accept UUID as identifier
*/
protected static final String REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID =
"/{uuid:[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12}}";
@Autowired
protected Utils utils;
@Autowired
private CollectionRestRepository collectionRestRepository;
@Autowired
private CollectionService collectionService;
/**
* This method will add a logo to the collection.
*
* curl -X POST http://<dspace.restUrl>/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo' \
* -XPOST -H 'Content-Type: multipart/form-data' \
* -H 'Authorization: Bearer eyJhbGciOiJI...' \
* -F "file=@Downloads/test.png"
*
* Example:
* <pre>
* {@code
* curl -X POST http://<dspace.restUrl>/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo' \
* -XPOST -H 'Content-Type: multipart/form-data' \
* -H 'Authorization: Bearer eyJhbGciOiJI...' \
* -F "file=@Downloads/test.png"
* }
* </pre>
* @param request The StandardMultipartHttpServletRequest that will contain the logo in its body
* @param uuid The UUID of the collection
* @return The created bitstream
* @throws SQLException If something goes wrong
* @throws IOException If something goes wrong
* @throws AuthorizeException If the user doesn't have the correct rights
*/
@PreAuthorize("hasPermission(#uuid, 'COLLECTION', 'WRITE')")
@RequestMapping(method = RequestMethod.POST,
headers = "content-type=multipart/form-data")
public ResponseEntity<ResourceSupport> createLogo(HttpServletRequest request, @PathVariable UUID uuid,
@RequestParam(value = "file", required = false) MultipartFile uploadfile)
throws SQLException, IOException, AuthorizeException {
if (uploadfile == null) {
throw new UnprocessableEntityException("No file was given");
}
Context context = ContextUtil.obtainContext(request);
Collection collection = collectionService.find(context, uuid);
if (collection == null) {
throw new ResourceNotFoundException(
"The given uuid did not resolve to a collection on the server: " + uuid);
}
BitstreamRest bitstream = collectionRestRepository.setLogo(context, collection, uploadfile);
BitstreamResource bitstreamResource = new BitstreamResource(bitstream, utils);
context.complete();
return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, bitstreamResource);
}
}

View File

@@ -0,0 +1,114 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import java.io.IOException;
import java.sql.SQLException;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.CommunityRest;
import org.dspace.app.rest.model.hateoas.BitstreamResource;
import org.dspace.app.rest.repository.CommunityRestRepository;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Community;
import org.dspace.content.service.CommunityService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ControllerUtils;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* This RestController takes care of the creation and deletion of Communities' nested objects
* This class will typically receive the UUID of a Community and it'll perform logic on its nested objects
*/
@RestController
@RequestMapping("/api/" + CommunityRest.CATEGORY + "/" + CommunityRest.PLURAL_NAME
+ CommunityLogoController.REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID + "/logo")
public class CommunityLogoController {
/**
* Regular expression in the request mapping to accept UUID as identifier
*/
protected static final String REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID =
"/{uuid:[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12}}";
@Autowired
protected Utils utils;
@Autowired
private CommunityRestRepository communityRestRepository;
@Autowired
private CommunityService communityService;
/**
* This method will add a logo to the community.
*
* curl -X POST http://<dspace.restUrl>/api/core/communities/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo' \
* -XPOST -H 'Content-Type: multipart/form-data' \
* -H 'Authorization: Bearer eyJhbGciOiJI...' \
* -F "file=@Downloads/test.png"
*
* Example:
* <pre>
* {@code
* curl -X POST http://<dspace.restUrl>/api/core/communities/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo' \
* -XPOST -H 'Content-Type: multipart/form-data' \
* -H 'Authorization: Bearer eyJhbGciOiJI...' \
* -F "file=@Downloads/test.png"
* }
* </pre>
* @param request The StandardMultipartHttpServletRequest that will contain the logo in its body
* @param uuid The UUID of the community
* @return The created bitstream
* @throws SQLException If something goes wrong
* @throws IOException If something goes wrong
* @throws AuthorizeException If the user doesn't have the correct rights
*/
@PreAuthorize("hasPermission(#uuid, 'COMMUNITY', 'WRITE')")
@RequestMapping(method = RequestMethod.POST,
headers = "content-type=multipart/form-data")
public ResponseEntity<ResourceSupport> createLogo(HttpServletRequest request, @PathVariable UUID uuid,
@RequestParam(value = "file", required = false) MultipartFile uploadfile)
throws SQLException, IOException, AuthorizeException {
if (uploadfile == null) {
throw new UnprocessableEntityException("No file was given");
}
Context context = ContextUtil.obtainContext(request);
Community community = communityService.find(context, uuid);
if (community == null) {
throw new ResourceNotFoundException(
"The given uuid did not resolve to a community on the server: " + uuid);
}
BitstreamRest bitstream = communityRestRepository.setLogo(context, community, uploadfile);
BitstreamResource bitstreamResource = new BitstreamResource(bitstream, utils);
context.complete();
return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, bitstreamResource);
}
}

View File

@@ -23,6 +23,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
})
public class CollectionRest extends DSpaceObjectRest {
public static final String NAME = "collection";
public static final String PLURAL_NAME = "collections";
public static final String CATEGORY = RestAddressableModel.CORE;
public static final String LICENSE = "license";
public static final String HARVEST = "harvester";

View File

@@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
*/
public class CommunityRest extends DSpaceObjectRest {
public static final String NAME = "community";
public static final String PLURAL_NAME = "communities";
public static final String CATEGORY = RestAddressableModel.CORE;
@JsonIgnore

View File

@@ -18,7 +18,6 @@ import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.converter.BitstreamConverter;
import org.dspace.app.rest.exception.DSpaceBadRequestException;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.hateoas.BitstreamResource;
import org.dspace.app.rest.model.patch.Patch;
@@ -27,8 +26,12 @@ import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.BundleService;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
@@ -56,6 +59,12 @@ public class BitstreamRestRepository extends DSpaceObjectRestRepository<Bitstrea
@Autowired
AuthorizeService authorizeService;
@Autowired
private CollectionService collectionService;
@Autowired
private CommunityService communityService;
@Autowired
public BitstreamRestRepository(BitstreamService dsoService,
BitstreamConverter dsoConverter) {
@@ -126,10 +135,21 @@ public class BitstreamRestRepository extends DSpaceObjectRestRepository<Bitstrea
Bitstream bit = null;
try {
bit = bs.find(context, id);
if (bit.getCommunity() != null | bit.getCollection() != null) {
throw new UnprocessableEntityException("The bitstream cannot be deleted it is a logo");
if (bit == null) {
throw new ResourceNotFoundException("The bitstream with uuid " + id + " could not be found");
}
} catch (SQLException e) {
if (bit.isDeleted()) {
throw new ResourceNotFoundException("The bitstream with uuid " + id + " was already deleted");
}
Community community = bit.getCommunity();
if (community != null) {
communityService.setLogo(context, community, null);
}
Collection collection = bit.getCollection();
if (collection != null) {
collectionService.setLogo(context, collection, null);
}
} catch (SQLException | IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
try {

View File

@@ -17,13 +17,16 @@ import javax.servlet.http.HttpServletRequest;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.converter.BitstreamConverter;
import org.dspace.app.rest.converter.CollectionConverter;
import org.dspace.app.rest.converter.MetadataConverter;
import org.dspace.app.rest.exception.DSpaceBadRequestException;
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.CollectionRest;
import org.dspace.app.rest.model.CommunityRest;
import org.dspace.app.rest.model.hateoas.CollectionResource;
@@ -31,8 +34,10 @@ import org.dspace.app.rest.model.patch.Patch;
import org.dspace.app.rest.repository.patch.DSpaceObjectPatch;
import org.dspace.app.rest.utils.CollectionRestEqualityUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.core.Constants;
@@ -44,6 +49,7 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
/**
* This is the repository responsible to manage Item Rest object
@@ -54,7 +60,8 @@ import org.springframework.stereotype.Component;
@Component(CollectionRest.CATEGORY + "." + CollectionRest.NAME)
public class CollectionRestRepository extends DSpaceObjectRestRepository<Collection, CollectionRest> {
private final CollectionService cs;
private static final Logger log = org.apache.logging.log4j.LogManager
.getLogger(CollectionRestRepository.class);
@Autowired
CommunityService communityService;
@@ -62,17 +69,24 @@ public class CollectionRestRepository extends DSpaceObjectRestRepository<Collect
@Autowired
CollectionConverter converter;
@Autowired
BitstreamConverter bitstreamConverter;
@Autowired
MetadataConverter metadataConverter;
@Autowired
CollectionRestEqualityUtils collectionRestEqualityUtils;
@Autowired
private CollectionService cs;
@Autowired
private BitstreamService bitstreamService;
public CollectionRestRepository(CollectionService dsoService,
CollectionConverter dsoConverter) {
super(dsoService, dsoConverter, new DSpaceObjectPatch<CollectionRest>() {});
this.cs = dsoService;
}
@Override
@@ -253,4 +267,28 @@ public class CollectionRestRepository extends DSpaceObjectRestRepository<Collect
throw new RuntimeException("Unable to delete collection because the logo couldn't be deleted", e);
}
}
}
/**
* Method to install a logo on a Collection which doesn't have a logo
* Called by request mappings in CollectionLogoController
* @param context
* @param collection The collection on which to install the logo
* @param uploadfile The new logo
* @return The created bitstream containing the new logo
* @throws IOException
* @throws AuthorizeException
* @throws SQLException
*/
public BitstreamRest setLogo(Context context, Collection collection, MultipartFile uploadfile)
throws IOException, AuthorizeException, SQLException {
if (collection.getLogo() != null) {
throw new UnprocessableEntityException(
"The collection with the given uuid already has a logo: " + collection.getID());
}
Bitstream bitstream = cs.setLogo(context, collection, uploadfile.getInputStream());
cs.update(context, collection);
bitstreamService.update(context, bitstream);
return bitstreamConverter.fromModel(context.reloadEntity(bitstream));
}
}

View File

@@ -17,20 +17,25 @@ import javax.servlet.http.HttpServletRequest;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.converter.BitstreamConverter;
import org.dspace.app.rest.converter.CommunityConverter;
import org.dspace.app.rest.converter.MetadataConverter;
import org.dspace.app.rest.exception.DSpaceBadRequestException;
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.CommunityRest;
import org.dspace.app.rest.model.hateoas.CommunityResource;
import org.dspace.app.rest.model.patch.Patch;
import org.dspace.app.rest.repository.patch.DSpaceObjectPatch;
import org.dspace.app.rest.utils.CommunityRestEqualityUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.content.Community;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.CommunityService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
@@ -40,6 +45,7 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
/**
* This is the repository responsible to manage Community Rest object
@@ -50,21 +56,30 @@ import org.springframework.stereotype.Component;
@Component(CommunityRest.CATEGORY + "." + CommunityRest.NAME)
public class CommunityRestRepository extends DSpaceObjectRestRepository<Community, CommunityRest> {
private final CommunityService cs;
private static final Logger log = org.apache.logging.log4j.LogManager
.getLogger(CommunityRestRepository.class);
@Autowired
CommunityConverter converter;
@Autowired
BitstreamConverter bitstreamConverter;
@Autowired
MetadataConverter metadataConverter;
@Autowired
CommunityRestEqualityUtils communityRestEqualityUtils;
@Autowired
private CommunityService cs;
@Autowired
private BitstreamService bitstreamService;
public CommunityRestRepository(CommunityService dsoService,
CommunityConverter dsoConverter) {
super(dsoService, dsoConverter, new DSpaceObjectPatch<CommunityRest>() {});
this.cs = dsoService;
}
@Override
@@ -260,4 +275,28 @@ public class CommunityRestRepository extends DSpaceObjectRestRepository<Communit
throw new RuntimeException("Unable to delete community because the logo couldn't be deleted", e);
}
}
}
/**
* Method to install a logo on a Community which doesn't have a logo
* Called by request mappings in CommunityLogoController
* @param context
* @param community The community on which to install the logo
* @param uploadfile The new logo
* @return The created bitstream containing the new logo
* @throws IOException
* @throws AuthorizeException
* @throws SQLException
*/
public BitstreamRest setLogo(Context context, Community community, MultipartFile uploadfile)
throws IOException, AuthorizeException, SQLException {
if (community.getLogo() != null) {
throw new UnprocessableEntityException(
"The community with the given uuid already has a logo: " + community.getID());
}
Bitstream bitstream = cs.setLogo(context, community, uploadfile.getInputStream());
cs.update(context, community);
bitstreamService.update(context, bitstream);
return bitstreamConverter.fromModel(context.reloadEntity(bitstream));
}
}

View File

@@ -474,7 +474,7 @@ public class BitstreamRestRepositoryIT extends AbstractControllerIntegrationTest
}
@Test
public void deleteUnauthorized() throws Exception {
public void deleteForbidden() throws Exception {
//We turn off the authorization system in order to create the structure as defined below
context.turnOffAuthorisationSystem();
@@ -521,7 +521,7 @@ public class BitstreamRestRepositoryIT extends AbstractControllerIntegrationTest
}
@Test
public void deleteForbidden() throws Exception {
public void deleteUnauthorized() throws Exception {
//We turn off the authorization system in order to create the structure as defined below
context.turnOffAuthorisationSystem();
@@ -581,13 +581,72 @@ public class BitstreamRestRepositoryIT extends AbstractControllerIntegrationTest
String token = getAuthToken(admin.getEmail(), password);
// 422 error when trying to DELETE parentCommunity logo
// trying to DELETE parentCommunity logo should work
getClient(token).perform(delete("/api/core/bitstreams/" + parentCommunity.getLogo().getID()))
.andExpect(status().is(422));
.andExpect(status().is(204));
// 422 error when trying to DELETE collection logo
// trying to DELETE collection logo should work
getClient(token).perform(delete("/api/core/bitstreams/" + col.getLogo().getID()))
.andExpect(status().is(422));
.andExpect(status().is(204));
}
@Test
public void deleteMissing() throws Exception {
String token = getAuthToken(admin.getEmail(), password);
// Delete
getClient(token).perform(delete("/api/core/bitstreams/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb"))
.andExpect(status().isNotFound());
// Verify 404 after failed delete
getClient(token).perform(delete("/api/core/bitstreams/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb"))
.andExpect(status().isNotFound());
}
@Test
public void deleteDeleted() throws Exception {
//We turn off the authorization system in order to create the structure as defined below
context.turnOffAuthorisationSystem();
//** GIVEN **
//1. A community-collection structure with one parent community with sub-community and one collection.
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
.withName("Sub Community")
.build();
Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build();
//2. One public items that is readable by Anonymous
Item publicItem1 = ItemBuilder.createItem(context, col1)
.withTitle("Test")
.withIssueDate("2010-10-17")
.withAuthor("Smith, Donald")
.withSubject("ExtraEntry")
.build();
String bitstreamContent = "ThisIsSomeDummyText";
//Add a bitstream to an item
Bitstream bitstream = null;
try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) {
bitstream = BitstreamBuilder.
createBitstream(context, publicItem1, is)
.withName("Bitstream")
.withDescription("Description")
.withMimeType("text/plain")
.build();
}
String token = getAuthToken(admin.getEmail(), password);
// Delete
getClient(token).perform(delete("/api/core/bitstreams/" + bitstream.getID()))
.andExpect(status().is(204));
// Verify 404 when trying to delete a non-existing bitstream
getClient(token).perform(delete("/api/core/bitstreams/" + bitstream.getID()))
.andExpect(status().isNotFound());
}
@Test

View File

@@ -0,0 +1,152 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.dspace.app.rest.builder.CollectionBuilder;
import org.dspace.app.rest.builder.CommunityBuilder;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.dspace.content.Collection;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
public class CollectionLogoControllerIT extends AbstractControllerIntegrationTest {
private ObjectMapper mapper;
private String adminAuthToken;
private String bitstreamContent;
private MockMultipartFile bitstreamFile;
private Collection childCollection;
@Before
public void createStructure() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
childCollection = CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1").build();
adminAuthToken = getAuthToken(admin.getEmail(), password);
bitstreamContent = "Hello, World!";
bitstreamFile = new MockMultipartFile("file",
"hello.txt", MediaType.TEXT_PLAIN_VALUE,
bitstreamContent.getBytes());
mapper = new ObjectMapper();
}
private String createLogoInternal() throws Exception {
MvcResult mvcPostResult = getClient(adminAuthToken).perform(
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(childCollection.getID().toString()))
.file(bitstreamFile))
.andExpect(status().isCreated())
.andReturn();
String postContent = mvcPostResult.getResponse().getContentAsString();
Map<String, Object> mapPostResult = mapper.readValue(postContent, Map.class);
return String.valueOf(mapPostResult.get("uuid"));
}
@Test
public void createLogoNotLoggedIn() throws Exception {
getClient().perform(
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(childCollection.getID().toString()))
.file(bitstreamFile))
.andExpect(status().isUnauthorized());
}
@Test
public void createLogo() throws Exception {
String postUuid = createLogoInternal();
assert (postUuid != null);
MvcResult mvcGetResult = getClient().perform(get(getLogoUrlTemplate(childCollection.getID().toString())))
.andExpect(status().is2xxSuccessful())
.andReturn();
String getContent = mvcGetResult.getResponse().getContentAsString();
Map<String, Object> mapGetResult = mapper.readValue(getContent, Map.class);
String getUuid = String.valueOf(mapGetResult.get("uuid"));
assert (postUuid.equals(getUuid));
}
@Test
public void createLogoNoRights() throws Exception {
String userToken = getAuthToken(eperson.getEmail(), password);
getClient(userToken).perform(
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(childCollection.getID().toString()))
.file(bitstreamFile))
.andExpect(status().isForbidden());
}
@Test
public void createDuplicateLogo() throws Exception {
getClient(adminAuthToken).perform(
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(childCollection.getID().toString()))
.file(bitstreamFile))
.andExpect(status().isCreated());
getClient(adminAuthToken).perform(
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(childCollection.getID().toString()))
.file(bitstreamFile))
.andExpect(status().isUnprocessableEntity());
}
@Test
public void createLogoForNonexisting() throws Exception {
getClient(adminAuthToken).perform(
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate("16a4b65b-3b3f-4ef5-8058-ef6f5a653ef9"))
.file(bitstreamFile))
.andExpect(status().isNotFound());
}
@Test
public void deleteLogoNotLoggedIn() throws Exception {
String postUuid = createLogoInternal();
getClient().perform(delete(getBitstreamUrlTemplate(postUuid)))
.andExpect(status().isUnauthorized());
}
@Test
public void deleteLogo() throws Exception {
String postUuid = createLogoInternal();
getClient(adminAuthToken).perform(delete(getBitstreamUrlTemplate(postUuid)))
.andExpect(status().isNoContent());
getClient(adminAuthToken).perform(get(getLogoUrlTemplate(childCollection.getID().toString())))
.andExpect(status().isNoContent());
}
@Test
public void deleteLogoNoRights() throws Exception {
String postUuid = createLogoInternal();
String userToken = getAuthToken(eperson.getEmail(), password);
getClient(userToken).perform(delete(getBitstreamUrlTemplate(postUuid)))
.andExpect(status().isForbidden());
}
private String getLogoUrlTemplate(String uuid) {
return "/api/core/collections/" + uuid + "/logo";
}
private String getBitstreamUrlTemplate(String uuid) {
return "/api/core/bitstreams/" + uuid;
}
}

View File

@@ -0,0 +1,147 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.dspace.app.rest.builder.CommunityBuilder;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
public class CommunityLogoControllerIT extends AbstractControllerIntegrationTest {
private ObjectMapper mapper;
private String adminAuthToken;
private String bitstreamContent;
private MockMultipartFile bitstreamFile;
@Before
public void createStructure() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
adminAuthToken = getAuthToken(admin.getEmail(), password);
bitstreamContent = "Hello, World!";
bitstreamFile = new MockMultipartFile("file",
"hello.txt", MediaType.TEXT_PLAIN_VALUE,
bitstreamContent.getBytes());
mapper = new ObjectMapper();
}
private String createLogoInternal() throws Exception {
MvcResult mvcPostResult = getClient(adminAuthToken).perform(
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(parentCommunity.getID().toString()))
.file(bitstreamFile))
.andExpect(status().isCreated())
.andReturn();
String postContent = mvcPostResult.getResponse().getContentAsString();
Map<String, Object> mapPostResult = mapper.readValue(postContent, Map.class);
return String.valueOf(mapPostResult.get("uuid"));
}
@Test
public void createLogoNotLoggedIn() throws Exception {
getClient().perform(
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(parentCommunity.getID().toString()))
.file(bitstreamFile))
.andExpect(status().isUnauthorized());
}
@Test
public void createLogo() throws Exception {
String postUuid = createLogoInternal();
assert (postUuid != null);
MvcResult mvcGetResult = getClient().perform(get(getLogoUrlTemplate(parentCommunity.getID().toString())))
.andExpect(status().is2xxSuccessful())
.andReturn();
String getContent = mvcGetResult.getResponse().getContentAsString();
Map<String, Object> mapGetResult = mapper.readValue(getContent, Map.class);
String getUuid = String.valueOf(mapGetResult.get("uuid"));
assert (postUuid.equals(getUuid));
}
@Test
public void createLogoNoRights() throws Exception {
String userToken = getAuthToken(eperson.getEmail(), password);
getClient(userToken).perform(
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(parentCommunity.getID().toString()))
.file(bitstreamFile))
.andExpect(status().isForbidden());
}
@Test
public void createDuplicateLogo() throws Exception {
getClient(adminAuthToken).perform(
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(parentCommunity.getID().toString()))
.file(bitstreamFile))
.andExpect(status().isCreated());
getClient(adminAuthToken).perform(
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate(parentCommunity.getID().toString()))
.file(bitstreamFile))
.andExpect(status().isUnprocessableEntity());
}
@Test
public void createLogoForNonexisting() throws Exception {
getClient(adminAuthToken).perform(
MockMvcRequestBuilders.fileUpload(getLogoUrlTemplate("16a4b65b-3b3f-4ef5-8058-ef6f5a653ef9"))
.file(bitstreamFile))
.andExpect(status().isNotFound());
}
@Test
public void deleteLogoNotLoggedIn() throws Exception {
String postUuid = createLogoInternal();
getClient().perform(delete(getBitstreamUrlTemplate(postUuid)))
.andExpect(status().isUnauthorized());
}
@Test
public void deleteLogo() throws Exception {
String postUuid = createLogoInternal();
getClient(adminAuthToken).perform(delete(getBitstreamUrlTemplate(postUuid)))
.andExpect(status().isNoContent());
getClient(adminAuthToken).perform(get(getLogoUrlTemplate(parentCommunity.getID().toString())))
.andExpect(status().isNoContent());
}
@Test
public void deleteLogoNoRights() throws Exception {
String postUuid = createLogoInternal();
String userToken = getAuthToken(eperson.getEmail(), password);
getClient(userToken).perform(delete(getBitstreamUrlTemplate(postUuid)))
.andExpect(status().isForbidden());
}
private String getLogoUrlTemplate(String uuid) {
return "/api/core/communities/" + uuid + "/logo";
}
private String getBitstreamUrlTemplate(String uuid) {
return "/api/core/bitstreams/" + uuid;
}
}

View File

@@ -42,6 +42,130 @@
</dependency>
</dependencies>
</profile>
<!-- If Unit Testing is enabled, then setup the Unit Test Environment.
See also the 'skiptests' profile in Parent POM. -->
<profile>
<id>test-environment</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>maven.test.skip</name>
<value>false</value>
</property>
</activation>
<build>
<plugins>
<!-- Unit/Integration Testing setup: This plugin unzips the
'testEnvironment.zip' file (created by dspace-parent POM), into
the 'target/testing/' folder, to essentially create a test
install of DSpace, against which Tests can be run. -->
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<configuration>
<outputDirectory>${project.build.directory}/testing</outputDirectory>
<artifactItems>
<artifactItem>
<groupId>org.dspace</groupId>
<artifactId>dspace-parent</artifactId>
<version>${project.version}</version>
<type>zip</type>
<classifier>testEnvironment</classifier>
</artifactItem>
</artifactItems>
</configuration>
<executions>
<execution>
<id>setupTestEnvironment</id>
<phase>generate-test-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
</execution>
<execution>
<id>setupIntegrationTestEnvironment</id>
<phase>pre-integration-test</phase>
<goals>
<goal>unpack</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- This plugin allows us to run a Groovy script in our Maven POM
(see: http://gmaven.codehaus.org/Executing+Groovy+Code )
We are generating a OS-agnostic version (agnostic.build.dir) of
the ${project.build.directory} property (full path of target dir).
This is needed by the FileWeaver & Surefire plugins (see below)
to initialize the Unit Test environment's dspace.cfg file.
Otherwise, the Unit Test Framework will not work on Windows OS.
This Groovy code was mostly borrowed from:
http://stackoverflow.com/questions/3872355/how-to-convert-file-separator-in-maven
-->
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>groovy-maven-plugin</artifactId>
<version>2.0</version>
<executions>
<execution>
<id>setproperty</id>
<phase>generate-test-resources
</phase> <!-- XXX I think this should be 'initialize' - MHW -->
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
project.properties['agnostic.build.dir'] = project.build.directory.replace(File.separator, '/');
println("Initializing Maven property 'agnostic.build.dir' to: " + project.properties['agnostic.build.dir']);
</source>
</configuration>
</execution>
</executions>
</plugin>
<!-- Run Unit Testing! This plugin just kicks off the tests (when enabled). -->
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<!-- Specify the dspace.dir to use for test environment -->
<!-- This system property is loaded by AbstractDSpaceTest to initialize the test environment -->
<dspace.dir>${agnostic.build.dir}/testing/dspace/</dspace.dir>
<!-- Turn off any DSpace logging -->
<dspace.log.init.disable>true</dspace.log.init.disable>
<solr.install.dir>${agnostic.build.dir}/testing/dspace/solr/</solr.install.dir>
</systemPropertyVariables>
</configuration>
</plugin>
<!-- Run Integration Testing! This plugin just kicks off the tests (when enabled). -->
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<!-- Specify the dspace.dir to use for test environment -->
<dspace.dir>${agnostic.build.dir}/testing/dspace/</dspace.dir>
<!-- Turn off any DSpace logging -->
<dspace.log.init.disable>true</dspace.log.init.disable>
<solr.install.dir>${agnostic.build.dir}/testing/dspace/solr/</solr.install.dir>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- When running tests, also include test classes from dspace-api
(this test-jar is only built when tests are enabled). -->
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-api</artifactId>
<version>7.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
</profiles>
<!--
@@ -73,6 +197,33 @@
</exclusions>
</dependency>
<!-- Keep jmockit before junit -->
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -8,9 +8,7 @@
package org.dspace.example;
/**
* TODO: Add Description
*
* @author mdiggory @ atmire.com
* This interface serves as an example of how & where to add local customizations to the DSpace REST API.
*/
public interface Example {
}

View File

@@ -10,9 +10,7 @@ package org.dspace.example.impl;
import org.dspace.example.Example;
/**
* TODO: Add Description
*
* @author mdiggory @ atmire.com
* This class serves as an example of how & where to add local customizations to the DSpace REST API.
*/
public class ExampleImpl implements Example {
}

View File

@@ -0,0 +1,27 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.example;
import static org.junit.Assert.assertTrue;
import org.dspace.AbstractIntegrationTest;
import org.dspace.example.impl.ExampleImpl;
import org.dspace.utils.DSpace;
import org.junit.Test;
/**
* This IT serves as an an example of how & where to add integration tests for local customizations to the DSpace API.
* See {@link Example} and {@link ExampleImpl} for the class of which the functionality is tested.
*/
public class ExampleIT extends AbstractIntegrationTest {
@Test
public void testExampleImpl() {
assertTrue(new DSpace().getSingletonService(Example.class) instanceof ExampleImpl);
}
}

View File

@@ -77,6 +77,128 @@ just adding new jar in the classloader</description>
</build>
<profiles>
<!-- If Unit Testing is enabled, then setup the Unit Test Environment.
See also the 'skiptests' profile in Parent POM. -->
<profile>
<id>test-environment</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>maven.test.skip</name>
<value>false</value>
</property>
</activation>
<build>
<plugins>
<!-- Unit/Integration Testing setup: This plugin unzips the
'testEnvironment.zip' file (created by dspace-parent POM), into
the 'target/testing/' folder, to essentially create a test
install of DSpace, against which Tests can be run. -->
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<configuration>
<outputDirectory>${project.build.directory}/testing</outputDirectory>
<artifactItems>
<artifactItem>
<groupId>org.dspace</groupId>
<artifactId>dspace-parent</artifactId>
<version>${project.version}</version>
<type>zip</type>
<classifier>testEnvironment</classifier>
</artifactItem>
</artifactItems>
</configuration>
<executions>
<execution>
<id>setupTestEnvironment</id>
<phase>generate-test-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
</execution>
<execution>
<id>setupIntegrationTestEnvironment</id>
<phase>pre-integration-test</phase>
<goals>
<goal>unpack</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- This plugin allows us to run a Groovy script in our Maven POM
(see: http://gmaven.codehaus.org/Executing+Groovy+Code )
We are generating a OS-agnostic version (agnostic.build.dir) of
the ${project.build.directory} property (full path of target dir).
This is needed by the FileWeaver & Surefire plugins (see below)
to initialize the Unit Test environment's dspace.cfg file.
Otherwise, the Unit Test Framework will not work on Windows OS.
This Groovy code was mostly borrowed from:
http://stackoverflow.com/questions/3872355/how-to-convert-file-separator-in-maven
-->
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>groovy-maven-plugin</artifactId>
<executions>
<execution>
<id>setproperty</id>
<phase>generate-test-resources
</phase> <!-- XXX I think this should be 'initialize' - MHW -->
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
project.properties['agnostic.build.dir'] = project.build.directory.replace(File.separator, '/');
println("Initializing Maven property 'agnostic.build.dir' to: " + project.properties['agnostic.build.dir']);
</source>
</configuration>
</execution>
</executions>
</plugin>
<!-- Run Unit Testing! This plugin just kicks off the tests (when enabled). -->
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<!-- Specify the dspace.dir to use for test environment -->
<!-- This system property is loaded by AbstractDSpaceTest to initialize the test environment -->
<dspace.dir>${agnostic.build.dir}/testing/dspace/</dspace.dir>
<!-- Turn off any DSpace logging -->
<dspace.log.init.disable>true</dspace.log.init.disable>
<solr.install.dir>${agnostic.build.dir}/testing/dspace/solr/</solr.install.dir>
</systemPropertyVariables>
</configuration>
</plugin>
<!-- Run Integration Testing! This plugin just kicks off the tests (when enabled). -->
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<!-- Specify the dspace.dir to use for test environment -->
<dspace.dir>${agnostic.build.dir}/testing/dspace/</dspace.dir>
<!-- Turn off any DSpace logging -->
<dspace.log.init.disable>true</dspace.log.init.disable>
<solr.install.dir>${agnostic.build.dir}/testing/dspace/solr/</solr.install.dir>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- When running tests, also include test classes from dspace-server-webapp
(this test-jar is only built when tests are enabled). -->
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-server-webapp</artifactId>
<version>7.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
<profile>
<id>oracle-support</id>
<activation>
@@ -95,15 +217,85 @@ just adding new jar in the classloader</description>
</profiles>
<dependencies>
<dependency>
<groupId>org.dspace.modules</groupId>
<artifactId>additions</artifactId>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-server-webapp</artifactId>
<classifier>classes</classifier>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-server-webapp</artifactId>
<type>war</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<exclusions>
<!-- Temporary exclusion to avoid dependency conflict with version of org.json:json used by dspace-api.
NOTE: THIS CAN BE REMOVED ONCE WE UPGRADE TO SPRING-BOOT v1.5 (or above), see DS-3802
As of Spring-Boot 1.5, org.json:json is no longer used by spring-boot-starter-test -->
<exclusion>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
</exclusion>
<!-- More recent version used for testing below -->
<exclusion>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path-assert</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-cell</artifactId>
<scope>test</scope>
</dependency>
<!-- Reminder: Keep icu4j (in Parent POM) synced with version used by lucene-analyzers-icu below,
otherwise ICUFoldingFilterFactory may throw errors in tests. -->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-icu</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,25 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.example;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* This Controller serves as an example of how & where to add local customizations to the DSpace REST API.
* See {@link ExampleControllerIT} for the integration tests for this controller.
*/
@RestController
@RequestMapping("example")
public class ExampleController {
@RequestMapping("")
public String test() {
return "Hello world";
}
}

View File

@@ -0,0 +1,31 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.example;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.junit.Test;
/**
* This IT serves as an example of how & where to add integration tests for local customizations to the DSpace REST API.
* See {@link ExampleController} for the Controller of which the functionality is tested.
*/
public class ExampleControllerIT extends AbstractControllerIntegrationTest {
@Test
public void testTest() throws Exception {
getClient()
.perform(get("/example"))
.andExpect(status().isOk())
.andExpect(content().string("Hello world"));
}
}

79
pom.xml
View File

@@ -42,6 +42,9 @@
<solr.client.version>7.3.1</solr.client.version>
<spring.version>4.3.24.RELEASE</spring.version>
<spring-boot.version>1.4.4.RELEASE</spring-boot.version>
<!-- Library for reading JSON documents: https://github.com/json-path/JsonPath -->
<json-path.version>2.4.0</json-path.version>
<!-- 'root.basedir' is the path to the root [dspace-src] dir. It must be redefined by each child POM,
as it is used to reference the LICENSE_HEADER and *.properties file(s) in that directory. -->
<root.basedir>${basedir}</root.basedir>
@@ -978,24 +981,25 @@
<version>7.0-SNAPSHOT</version>
<type>war</type>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-server-webapp</artifactId>
<version>7.0-SNAPSHOT</version>
<type>jar</type>
<classifier>classes</classifier>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-server-webapp</artifactId>
<version>7.0-SNAPSHOT</version>
<type>war</type>
</dependency>
<!-- DSpace Localization Packages -->
<!-- DSpace API Localization Packages -->
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-api-lang</artifactId>
<version>[6.0.0,7.0.0)</version>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-xmlui-lang</artifactId>
<version>[6.0.0,7.0.0)</version>
<type>war</type>
</dependency>
<!-- DSpace third Party Dependencies -->
@@ -1105,6 +1109,67 @@
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<exclusions>
<!-- Temporary exclusion to avoid dependency conflict with version of org.json:json used by dspace-api.
NOTE: THIS CAN BE REMOVED ONCE WE UPGRADE TO SPRING-BOOT v1.5 (or above), see DS-3802
As of Spring-Boot 1.5, org.json:json is no longer used by spring-boot-starter-test -->
<exclusion>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
</exclusion>
<!-- More recent version used for testing below -->
<exclusion>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-cell</artifactId>
<version>${solr.client.version}</version>
</dependency>
<!-- Reminder: Keep icu4j (in Parent POM) synced with version used by lucene-analyzers-icu below,
otherwise ICUFoldingFilterFactory may throw errors in tests. -->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-icu</artifactId>
<version>${solr.client.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>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>${json-path.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>