mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-18 15:33:09 +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.RestRepositoryUtils;
|
||||||
import org.dspace.app.rest.utils.Utils;
|
import org.dspace.app.rest.utils.Utils;
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
|
import org.dspace.util.UUIDUtils;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
@@ -441,7 +442,15 @@ public class RestResourceController implements InitializingBean {
|
|||||||
throws HttpRequestMethodNotSupportedException {
|
throws HttpRequestMethodNotSupportedException {
|
||||||
checkModelPluralForm(apiCategory, model);
|
checkModelPluralForm(apiCategory, model);
|
||||||
DSpaceRestRepository<RestAddressableModel, ID> repository = utils.getResourceRepository(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) {
|
if (modelObject == null) {
|
||||||
return ControllerUtils.toEmptyResponse(HttpStatus.CREATED);
|
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.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.dspace.app.rest.Parameter;
|
import org.dspace.app.rest.Parameter;
|
||||||
import org.dspace.app.rest.SearchRestMethod;
|
import org.dspace.app.rest.SearchRestMethod;
|
||||||
import org.dspace.app.rest.converter.CollectionConverter;
|
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.content.service.CommunityService;
|
||||||
import org.dspace.core.Constants;
|
import org.dspace.core.Constants;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.util.UUIDUtils;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageImpl;
|
import org.springframework.data.domain.PageImpl;
|
||||||
@@ -169,8 +167,19 @@ public class CollectionRestRepository extends DSpaceObjectRestRepository<Collect
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@PreAuthorize("hasAuthority('ADMIN')")
|
|
||||||
protected CollectionRest createAndReturn(Context context) throws AuthorizeException {
|
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();
|
HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest();
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
CollectionRest collectionRest;
|
CollectionRest collectionRest;
|
||||||
@@ -180,36 +189,19 @@ public class CollectionRestRepository extends DSpaceObjectRestRepository<Collect
|
|||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
throw new UnprocessableEntityException("Error parsing request body: " + e1.toString());
|
throw new UnprocessableEntityException("Error parsing request body: " + e1.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection collection;
|
Collection collection;
|
||||||
|
|
||||||
|
|
||||||
String parentCommunityString = req.getParameter("parent");
|
|
||||||
try {
|
try {
|
||||||
Community parent = null;
|
Community parent = communityService.find(context, id);
|
||||||
if (StringUtils.isNotBlank(parentCommunityString)) {
|
if (parent == null) {
|
||||||
|
throw new UnprocessableEntityException("Parent community for id: "
|
||||||
UUID parentCommunityUuid = UUIDUtils.fromString(parentCommunityString);
|
+ id + " not found");
|
||||||
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.");
|
|
||||||
}
|
}
|
||||||
collection = cs.create(context, parent);
|
collection = cs.create(context, parent);
|
||||||
cs.update(context, collection);
|
cs.update(context, collection);
|
||||||
metadataConverter.setMetadata(context, collection, collectionRest.getMetadata());
|
metadataConverter.setMetadata(context, collection, collectionRest.getMetadata());
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException("Unable to create new Collection under parent Community " +
|
throw new RuntimeException("Unable to create new Collection under parent Community " +
|
||||||
parentCommunityString, e);
|
id, e);
|
||||||
}
|
}
|
||||||
return converter.convert(collection);
|
return converter.convert(collection);
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,6 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.dspace.app.rest.Parameter;
|
import org.dspace.app.rest.Parameter;
|
||||||
import org.dspace.app.rest.SearchRestMethod;
|
import org.dspace.app.rest.SearchRestMethod;
|
||||||
import org.dspace.app.rest.converter.CommunityConverter;
|
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.Community;
|
||||||
import org.dspace.content.service.CommunityService;
|
import org.dspace.content.service.CommunityService;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.util.UUIDUtils;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageImpl;
|
import org.springframework.data.domain.PageImpl;
|
||||||
@@ -83,25 +81,45 @@ public class CommunityRestRepository extends DSpaceObjectRestRepository<Communit
|
|||||||
}
|
}
|
||||||
|
|
||||||
Community community;
|
Community community;
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Community parent = null;
|
// top-level community
|
||||||
String parentCommunityString = req.getParameter("parent");
|
community = cs.create(null, context);
|
||||||
if (StringUtils.isNotBlank(parentCommunityString)) {
|
cs.update(context, community);
|
||||||
|
metadataConverter.setMetadata(context, community, communityRest.getMetadata());
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
UUID parentCommunityUuid = UUIDUtils.fromString(parentCommunityString);
|
return dsoConverter.convert(community);
|
||||||
if (parentCommunityUuid == null) {
|
}
|
||||||
throw new DSpaceBadRequestException("The given parent parameter was invalid: "
|
|
||||||
+ parentCommunityString);
|
|
||||||
}
|
|
||||||
|
|
||||||
parent = cs.find(context, parentCommunityUuid);
|
@Override
|
||||||
if (parent == null) {
|
@PreAuthorize("hasPermission(#id, 'COMMUNITY', 'ADD')")
|
||||||
throw new UnprocessableEntityException("Parent community for id: "
|
protected CommunityRest createAndReturn(Context context, UUID id) throws AuthorizeException {
|
||||||
+ parentCommunityUuid + " not found");
|
|
||||||
}
|
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);
|
community = cs.create(parent, context);
|
||||||
cs.update(context, community);
|
cs.update(context, community);
|
||||||
metadataConverter.setMetadata(context, community, communityRest.getMetadata());
|
metadataConverter.setMetadata(context, community, communityRest.getMetadata());
|
||||||
|
@@ -12,6 +12,7 @@ import java.io.IOException;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
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);
|
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
|
* 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
|
* 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
|
* @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() {
|
protected T createAndReturn(Context context, UUID uuid)
|
||||||
Context context = null;
|
throws AuthorizeException, SQLException, RepositoryMethodNotImplementedException {
|
||||||
try {
|
throw new RepositoryMethodNotImplementedException("No implementation found; Method not allowed!", "");
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -132,7 +132,7 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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
|
//We turn off the authorization system in order to create the structure as defined below
|
||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
@@ -140,6 +140,7 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
|
|||||||
parentCommunity = CommunityBuilder.createCommunity(context)
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
.withName("Parent Community")
|
.withName("Parent Community")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
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
|
// We send a name but the created community should set this to the title
|
||||||
comm.setName("Test Sub-Level Community");
|
comm.setName("Test Sub-Level Community");
|
||||||
|
|
||||||
comm.setMetadata(new MetadataRest()
|
// Anonymous user tries to create a community.
|
||||||
.put("dc.description",
|
// Should fail because user is not authenticated. Error 401.
|
||||||
new MetadataValueRest("<p>Some cool HTML code here</p>"))
|
getClient().perform(post("/api/core/communities")
|
||||||
.put("dc.description.abstract",
|
.content(mapper.writeValueAsBytes(comm))
|
||||||
new MetadataValueRest("Sample top-level community created via the REST API"))
|
.param("parent", parentCommunity.getID().toString())
|
||||||
.put("dc.description.tableofcontents",
|
.contentType(contentType))
|
||||||
new MetadataValueRest("<p>HTML News</p>"))
|
.andExpect(status().isUnauthorized());
|
||||||
.put("dc.rights",
|
|
||||||
new MetadataValueRest("Custom Copyright Text"))
|
|
||||||
.put("dc.title",
|
|
||||||
new MetadataValueRest("Title Text")));
|
|
||||||
|
|
||||||
String authToken = getAuthToken(admin.getEmail(), password);
|
// Non-admin Eperson tries to create a community.
|
||||||
// Capture the UUID of the created Community (see andDo() below)
|
// 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>();
|
AtomicReference<UUID> idRef = new AtomicReference<UUID>();
|
||||||
try {
|
try {
|
||||||
getClient(authToken).perform(post("/api/core/communities")
|
getClient(authToken).perform(post("/api/core/communities")
|
||||||
.content(mapper.writeValueAsBytes(comm))
|
.content(mapper.writeValueAsBytes(comm))
|
||||||
.param("parent", parentCommunity.getID().toString())
|
.param("parent", parentCommunity.getID().toString())
|
||||||
.contentType(contentType))
|
.contentType(contentType))
|
||||||
.andExpect(status().isCreated())
|
.andExpect(status().isCreated())
|
||||||
.andExpect(content().contentType(contentType))
|
.andExpect(content().contentType(contentType))
|
||||||
.andExpect(jsonPath("$", Matchers.allOf(
|
.andExpect(jsonPath("$", Matchers.allOf(
|
||||||
@@ -181,15 +222,15 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
|
|||||||
hasJsonPath("$._links.self.href", not(empty())),
|
hasJsonPath("$._links.self.href", not(empty())),
|
||||||
hasJsonPath("$.metadata", Matchers.allOf(
|
hasJsonPath("$.metadata", Matchers.allOf(
|
||||||
MetadataMatcher.matchMetadata("dc.description",
|
MetadataMatcher.matchMetadata("dc.description",
|
||||||
"<p>Some cool HTML code here</p>"),
|
"<p>Some cool HTML code here</p>"),
|
||||||
MetadataMatcher.matchMetadata("dc.description.abstract",
|
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",
|
MetadataMatcher.matchMetadata("dc.description.tableofcontents",
|
||||||
"<p>HTML News</p>"),
|
"<p>HTML News</p>"),
|
||||||
MetadataMatcher.matchMetadata("dc.rights",
|
MetadataMatcher.matchMetadata("dc.rights",
|
||||||
"Custom Copyright Text"),
|
"Custom Copyright Text"),
|
||||||
MetadataMatcher.matchMetadata("dc.title",
|
MetadataMatcher.matchMetadata("dc.title",
|
||||||
"Title Text")
|
"Title Text")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)))
|
)))
|
||||||
|
Reference in New Issue
Block a user