mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-17 23:13:10 +00:00
[DS-4153] Added repository create method that takes a parameter for the parent object.
Implementions are added to the collection and community repository classes.
This commit is contained in:
@@ -51,6 +51,7 @@ import org.dspace.app.rest.repository.LinkRestRepository;
|
||||
import org.dspace.app.rest.utils.RestRepositoryUtils;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.util.UUIDUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -441,7 +442,15 @@ public class RestResourceController implements InitializingBean {
|
||||
throws HttpRequestMethodNotSupportedException {
|
||||
checkModelPluralForm(apiCategory, model);
|
||||
DSpaceRestRepository<RestAddressableModel, ID> repository = utils.getResourceRepository(apiCategory, model);
|
||||
RestAddressableModel modelObject = repository.createAndReturn();
|
||||
|
||||
String parentCommunityString = request.getParameter("parent");
|
||||
RestAddressableModel modelObject;
|
||||
if (parentCommunityString != null) {
|
||||
UUID parentCommunityUuid = UUIDUtils.fromString(parentCommunityString);
|
||||
modelObject = repository.createAndReturn(parentCommunityUuid);
|
||||
} else {
|
||||
modelObject = repository.createAndReturn();
|
||||
}
|
||||
if (modelObject == null) {
|
||||
return ControllerUtils.toEmptyResponse(HttpStatus.CREATED);
|
||||
}
|
||||
|
@@ -17,7 +17,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.rest.Parameter;
|
||||
import org.dspace.app.rest.SearchRestMethod;
|
||||
import org.dspace.app.rest.converter.CollectionConverter;
|
||||
@@ -38,7 +37,6 @@ import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.CommunityService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.util.UUIDUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
@@ -169,8 +167,19 @@ public class CollectionRestRepository extends DSpaceObjectRestRepository<Collect
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('ADMIN')")
|
||||
protected CollectionRest createAndReturn(Context context) throws AuthorizeException {
|
||||
throw new DSpaceBadRequestException("Missing parent parameter.");
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasPermission(#id, 'COMMUNITY', 'ADD')")
|
||||
protected CollectionRest createAndReturn(Context context, UUID id) throws AuthorizeException {
|
||||
|
||||
if (id == null) {
|
||||
throw new DSpaceBadRequestException("The given parent parameter was invalid: "
|
||||
+ id);
|
||||
}
|
||||
|
||||
HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
CollectionRest collectionRest;
|
||||
@@ -180,36 +189,19 @@ public class CollectionRestRepository extends DSpaceObjectRestRepository<Collect
|
||||
} catch (IOException e1) {
|
||||
throw new UnprocessableEntityException("Error parsing request body: " + e1.toString());
|
||||
}
|
||||
|
||||
Collection collection;
|
||||
|
||||
|
||||
String parentCommunityString = req.getParameter("parent");
|
||||
try {
|
||||
Community parent = null;
|
||||
if (StringUtils.isNotBlank(parentCommunityString)) {
|
||||
|
||||
UUID parentCommunityUuid = UUIDUtils.fromString(parentCommunityString);
|
||||
if (parentCommunityUuid == null) {
|
||||
throw new DSpaceBadRequestException("The given parent was invalid: "
|
||||
+ parentCommunityString);
|
||||
}
|
||||
|
||||
parent = communityService.find(context, parentCommunityUuid);
|
||||
if (parent == null) {
|
||||
throw new UnprocessableEntityException("Parent community for id: "
|
||||
+ parentCommunityUuid + " not found");
|
||||
}
|
||||
} else {
|
||||
throw new DSpaceBadRequestException("The parent parameter cannot be left empty," +
|
||||
"collections require a parent community.");
|
||||
Community parent = communityService.find(context, id);
|
||||
if (parent == null) {
|
||||
throw new UnprocessableEntityException("Parent community for id: "
|
||||
+ id + " not found");
|
||||
}
|
||||
collection = cs.create(context, parent);
|
||||
cs.update(context, collection);
|
||||
metadataConverter.setMetadata(context, collection, collectionRest.getMetadata());
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("Unable to create new Collection under parent Community " +
|
||||
parentCommunityString, e);
|
||||
id, e);
|
||||
}
|
||||
return converter.convert(collection);
|
||||
}
|
||||
|
@@ -17,7 +17,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.rest.Parameter;
|
||||
import org.dspace.app.rest.SearchRestMethod;
|
||||
import org.dspace.app.rest.converter.CommunityConverter;
|
||||
@@ -34,7 +33,6 @@ import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.service.CommunityService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.util.UUIDUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
@@ -83,25 +81,45 @@ public class CommunityRestRepository extends DSpaceObjectRestRepository<Communit
|
||||
}
|
||||
|
||||
Community community;
|
||||
|
||||
|
||||
try {
|
||||
Community parent = null;
|
||||
String parentCommunityString = req.getParameter("parent");
|
||||
if (StringUtils.isNotBlank(parentCommunityString)) {
|
||||
// top-level community
|
||||
community = cs.create(null, context);
|
||||
cs.update(context, community);
|
||||
metadataConverter.setMetadata(context, community, communityRest.getMetadata());
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
UUID parentCommunityUuid = UUIDUtils.fromString(parentCommunityString);
|
||||
if (parentCommunityUuid == null) {
|
||||
throw new DSpaceBadRequestException("The given parent parameter was invalid: "
|
||||
+ parentCommunityString);
|
||||
}
|
||||
return dsoConverter.convert(community);
|
||||
}
|
||||
|
||||
parent = cs.find(context, parentCommunityUuid);
|
||||
if (parent == null) {
|
||||
throw new UnprocessableEntityException("Parent community for id: "
|
||||
+ parentCommunityUuid + " not found");
|
||||
}
|
||||
@Override
|
||||
@PreAuthorize("hasPermission(#id, 'COMMUNITY', 'ADD')")
|
||||
protected CommunityRest createAndReturn(Context context, UUID id) throws AuthorizeException {
|
||||
|
||||
if (id == null) {
|
||||
throw new DSpaceBadRequestException("The given parent parameter was invalid: "
|
||||
+ id);
|
||||
}
|
||||
|
||||
HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
CommunityRest communityRest;
|
||||
try {
|
||||
ServletInputStream input = req.getInputStream();
|
||||
communityRest = mapper.readValue(input, CommunityRest.class);
|
||||
} catch (IOException e1) {
|
||||
throw new UnprocessableEntityException("Error parsing request body: " + e1.toString());
|
||||
}
|
||||
|
||||
Community community;
|
||||
try {
|
||||
Community parent = cs.find(context, id);
|
||||
if (parent == null) {
|
||||
throw new UnprocessableEntityException("Parent community for id: "
|
||||
+ id + " not found");
|
||||
}
|
||||
// sub-community
|
||||
community = cs.create(parent, context);
|
||||
cs.update(context, community);
|
||||
metadataConverter.setMetadata(context, community, communityRest.getMetadata());
|
||||
|
@@ -12,6 +12,7 @@ import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@@ -259,6 +260,46 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
*/
|
||||
public abstract DSpaceResource<T> wrapResource(T model, String... rels);
|
||||
|
||||
/**
|
||||
* Create and return a new instance. Data are usually retrieved from the thread bound http request
|
||||
*
|
||||
* @return the created REST object
|
||||
*/
|
||||
public T createAndReturn() {
|
||||
Context context = null;
|
||||
try {
|
||||
context = obtainContext();
|
||||
T entity = thisRepository.createAndReturn(context);
|
||||
context.commit();
|
||||
return entity;
|
||||
} catch (AuthorizeException e) {
|
||||
throw new RESTAuthorizationException(e);
|
||||
} catch (SQLException ex) {
|
||||
throw new RuntimeException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new instance after adding to the parent. Data are usually retrieved from
|
||||
* the thread bound http request.
|
||||
*
|
||||
* @param uuid the id of the parent object
|
||||
* @return the created REST object
|
||||
*/
|
||||
public T createAndReturn(UUID uuid) {
|
||||
Context context = null;
|
||||
try {
|
||||
context = obtainContext();
|
||||
T entity = thisRepository.createAndReturn(context, uuid);
|
||||
context.commit();
|
||||
return entity;
|
||||
} catch (AuthorizeException e) {
|
||||
throw new RESTAuthorizationException(e);
|
||||
} catch (SQLException ex) {
|
||||
throw new RuntimeException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new instance. Data is recovered from the thread bound HTTP request and the list
|
||||
* of DSpaceObjects provided in the uri-list body
|
||||
@@ -281,22 +322,22 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new instance. Data are usually retrieved from the thread bound http request
|
||||
* Method to implement to support the creation of a new instance. Usually require to retrieve the http request from
|
||||
* the thread bound attribute
|
||||
*
|
||||
* @param context
|
||||
* the dspace context
|
||||
* @param uuid
|
||||
* The uuid of the parent object retrieved from the query param.
|
||||
* @return the created REST object
|
||||
* @throws AuthorizeException
|
||||
* @throws SQLException
|
||||
* @throws RepositoryMethodNotImplementedException
|
||||
* returned by the default implementation when the operation is not supported for the entity
|
||||
*/
|
||||
public T createAndReturn() {
|
||||
Context context = null;
|
||||
try {
|
||||
context = obtainContext();
|
||||
T entity = thisRepository.createAndReturn(context);
|
||||
context.commit();
|
||||
return entity;
|
||||
} catch (AuthorizeException e) {
|
||||
throw new RESTAuthorizationException(e);
|
||||
} catch (SQLException ex) {
|
||||
throw new RuntimeException(ex.getMessage(), ex);
|
||||
}
|
||||
protected T createAndReturn(Context context, UUID uuid)
|
||||
throws AuthorizeException, SQLException, RepositoryMethodNotImplementedException {
|
||||
throw new RepositoryMethodNotImplementedException("No implementation found; Method not allowed!", "");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -132,7 +132,7 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithParentTest() throws Exception {
|
||||
public void createSubCommunityUnAuthorizedTest() throws Exception {
|
||||
//We turn off the authorization system in order to create the structure as defined below
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
@@ -140,6 +140,7 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
|
||||
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||
.withName("Parent Community")
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
@@ -147,26 +148,66 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
|
||||
// We send a name but the created community should set this to the title
|
||||
comm.setName("Test Sub-Level Community");
|
||||
|
||||
comm.setMetadata(new MetadataRest()
|
||||
.put("dc.description",
|
||||
new MetadataValueRest("<p>Some cool HTML code here</p>"))
|
||||
.put("dc.description.abstract",
|
||||
new MetadataValueRest("Sample top-level community created via the REST API"))
|
||||
.put("dc.description.tableofcontents",
|
||||
new MetadataValueRest("<p>HTML News</p>"))
|
||||
.put("dc.rights",
|
||||
new MetadataValueRest("Custom Copyright Text"))
|
||||
.put("dc.title",
|
||||
new MetadataValueRest("Title Text")));
|
||||
// Anonymous user tries to create a community.
|
||||
// Should fail because user is not authenticated. Error 401.
|
||||
getClient().perform(post("/api/core/communities")
|
||||
.content(mapper.writeValueAsBytes(comm))
|
||||
.param("parent", parentCommunity.getID().toString())
|
||||
.contentType(contentType))
|
||||
.andExpect(status().isUnauthorized());
|
||||
|
||||
String authToken = getAuthToken(admin.getEmail(), password);
|
||||
// Capture the UUID of the created Community (see andDo() below)
|
||||
// Non-admin Eperson tries to create a community.
|
||||
// Should fail because user doesn't have permissions. Error 403.
|
||||
String authToken = getAuthToken(eperson.getEmail(), password);
|
||||
getClient(authToken).perform(post("/api/core/communities")
|
||||
.content(mapper.writeValueAsBytes(comm))
|
||||
.param("parent", parentCommunity.getID().toString())
|
||||
.contentType(contentType))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSubCommunityAuthorizedTest() throws Exception {
|
||||
//We turn off the authorization system in order to create the structure as defined below
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
// Create a parent community to POST a new sub-community to
|
||||
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||
.withName("Parent Community")
|
||||
.build();
|
||||
|
||||
// ADD authorization on parent community
|
||||
context.setCurrentUser(eperson);
|
||||
authorizeService.addPolicy(context, parentCommunity, Constants.ADD, eperson);
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
String authToken = getAuthToken(eperson.getEmail(), password);
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
CommunityRest comm = new CommunityRest();
|
||||
// We send a name but the created community should set this to the title
|
||||
comm.setName("Test Sub-Level Community");
|
||||
|
||||
comm.setMetadata(new MetadataRest()
|
||||
.put("dc.description",
|
||||
new MetadataValueRest("<p>Some cool HTML code here</p>"))
|
||||
.put("dc.description.abstract",
|
||||
new MetadataValueRest("Sample top-level community created via the REST API"))
|
||||
.put("dc.description.tableofcontents",
|
||||
new MetadataValueRest("<p>HTML News</p>"))
|
||||
.put("dc.rights",
|
||||
new MetadataValueRest("Custom Copyright Text"))
|
||||
.put("dc.title",
|
||||
new MetadataValueRest("Title Text")));
|
||||
|
||||
// Capture the UUID of the created Community (see andDo() below)
|
||||
AtomicReference<UUID> idRef = new AtomicReference<UUID>();
|
||||
try {
|
||||
getClient(authToken).perform(post("/api/core/communities")
|
||||
.content(mapper.writeValueAsBytes(comm))
|
||||
.param("parent", parentCommunity.getID().toString())
|
||||
.contentType(contentType))
|
||||
.content(mapper.writeValueAsBytes(comm))
|
||||
.param("parent", parentCommunity.getID().toString())
|
||||
.contentType(contentType))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$", Matchers.allOf(
|
||||
@@ -181,15 +222,15 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
|
||||
hasJsonPath("$._links.self.href", not(empty())),
|
||||
hasJsonPath("$.metadata", Matchers.allOf(
|
||||
MetadataMatcher.matchMetadata("dc.description",
|
||||
"<p>Some cool HTML code here</p>"),
|
||||
"<p>Some cool HTML code here</p>"),
|
||||
MetadataMatcher.matchMetadata("dc.description.abstract",
|
||||
"Sample top-level community created via the REST API"),
|
||||
"Sample top-level community created via the REST API"),
|
||||
MetadataMatcher.matchMetadata("dc.description.tableofcontents",
|
||||
"<p>HTML News</p>"),
|
||||
"<p>HTML News</p>"),
|
||||
MetadataMatcher.matchMetadata("dc.rights",
|
||||
"Custom Copyright Text"),
|
||||
"Custom Copyright Text"),
|
||||
MetadataMatcher.matchMetadata("dc.title",
|
||||
"Title Text")
|
||||
"Title Text")
|
||||
)
|
||||
)
|
||||
)))
|
||||
|
Reference in New Issue
Block a user