mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-16 22:43:12 +00:00
Merge remote-tracking branch 'dspace/master' into w2p-68732_list-version-history
Conflicts: dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkflowItemRestRepositoryIT.java dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java
This commit is contained in:
6
.gitattributes
vendored
6
.gitattributes
vendored
@@ -1,6 +1,12 @@
|
|||||||
# Auto detect text files and perform LF normalization
|
# Auto detect text files and perform LF normalization
|
||||||
* text=auto
|
* text=auto
|
||||||
|
|
||||||
|
# Ensure Unix files always keep Unix line endings
|
||||||
|
*.sh text eol=lf
|
||||||
|
|
||||||
|
# Ensure Windows files always keep Windows line endings
|
||||||
|
*.bat text eol=crlf
|
||||||
|
|
||||||
# Standard to msysgit
|
# Standard to msysgit
|
||||||
*.doc diff=astextplain
|
*.doc diff=astextplain
|
||||||
*.DOC diff=astextplain
|
*.DOC diff=astextplain
|
||||||
|
@@ -153,7 +153,7 @@ public class AuthorityValueServiceImpl implements AuthorityValueService {
|
|||||||
public List<AuthorityValue> findByValue(Context context, String schema, String element, String qualifier,
|
public List<AuthorityValue> findByValue(Context context, String schema, String element, String qualifier,
|
||||||
String value) {
|
String value) {
|
||||||
String field = fieldParameter(schema, element, qualifier);
|
String field = fieldParameter(schema, element, qualifier);
|
||||||
return findByValue(context, field, qualifier);
|
return findByValue(context, field, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -8,22 +8,59 @@
|
|||||||
package org.dspace.submit.model;
|
package org.dspace.submit.model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* This class represents an option available in the submission upload section to
|
||||||
|
* set permission on a file. An option is defined by a name such as "open
|
||||||
|
* access", "embargo", "restricted access", etc. and some optional attributes to
|
||||||
|
* better clarify the constraints and input available to the user. For instance
|
||||||
|
* an embargo option could allow to set a start date not longer than 3 years,
|
||||||
|
* etc
|
||||||
|
*
|
||||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
*/
|
*/
|
||||||
public class AccessConditionOption {
|
public class AccessConditionOption {
|
||||||
|
/** An unique name identifying the access contion option **/
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the name of the group that will be bound to the resource policy created if
|
||||||
|
* such option is used
|
||||||
|
*/
|
||||||
private String groupName;
|
private String groupName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this is in alternative to the {@link #groupName}. The sub-groups listed in
|
||||||
|
* the DSpace group identified by the name here specified will be available to
|
||||||
|
* the user to personalize the access condition. They can be for instance
|
||||||
|
* University Staff, University Students, etc. so that a "restricted access"
|
||||||
|
* option can be further specified without the need to create separate access
|
||||||
|
* condition options for each group
|
||||||
|
*/
|
||||||
private String selectGroupName;
|
private String selectGroupName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set to <code>true</code> if this option requires a start date to be indicated
|
||||||
|
* for the underlying resource policy to create
|
||||||
|
*/
|
||||||
private Boolean hasStartDate;
|
private Boolean hasStartDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set to <code>true</code> if this option requires an end date to be indicated
|
||||||
|
* for the underlying resource policy to create
|
||||||
|
*/
|
||||||
private Boolean hasEndDate;
|
private Boolean hasEndDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It contains, if applicable, the maximum start date (i.e. when the "embargo
|
||||||
|
* expires") that can be selected. It accepts date math via joda library (such as
|
||||||
|
* +3years)
|
||||||
|
*/
|
||||||
private String startDateLimit;
|
private String startDateLimit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It contains, if applicable, the maximum end date (i.e. when the "lease
|
||||||
|
* expires") that can be selected. It accepts date math via joda library (such as
|
||||||
|
* +3years)
|
||||||
|
*/
|
||||||
private String endDateLimit;
|
private String endDateLimit;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@@ -81,6 +118,4 @@ public class AccessConditionOption {
|
|||||||
public void setSelectGroupName(String selectGroupName) {
|
public void setSelectGroupName(String selectGroupName) {
|
||||||
this.selectGroupName = selectGroupName;
|
this.selectGroupName = selectGroupName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,82 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||||
|
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||||
|
|
||||||
|
<bean id="uploadConfigurationDefault" class="org.dspace.submit.model.UploadConfiguration">
|
||||||
|
<property name="name" value="upload"></property>
|
||||||
|
<property name="configurationService" ref="org.dspace.services.ConfigurationService"/>
|
||||||
|
<property name="metadata" value="bitstream-metadata" />
|
||||||
|
<property name="options">
|
||||||
|
<list>
|
||||||
|
<ref bean="openAccess"/>
|
||||||
|
<ref bean="lease"/>
|
||||||
|
<ref bean="embargoed" />
|
||||||
|
<ref bean="embargoedWithGroupSelect" />
|
||||||
|
<ref bean="administrator"/>
|
||||||
|
<!-- <ref bean="networkAdministration"/> -->
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openAccess" class="org.dspace.submit.model.AccessConditionOption">
|
||||||
|
<property name="groupName" value="Anonymous"/>
|
||||||
|
<property name="name" value="openaccess"/>
|
||||||
|
<property name="hasStartDate" value="false"/>
|
||||||
|
<property name="hasEndDate" value="false"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="lease" class="org.dspace.submit.model.AccessConditionOption">
|
||||||
|
<property name="groupName" value="Anonymous"/>
|
||||||
|
<!--
|
||||||
|
use the selectGroupName to specify the group containing the subgroups
|
||||||
|
that can be used for the policy
|
||||||
|
<property name="selectGroupName" value="Lease Groups"/>
|
||||||
|
-->
|
||||||
|
<property name="name" value="lease"/>
|
||||||
|
<property name="hasStartDate" value="false"/>
|
||||||
|
<property name="hasEndDate" value="true"/>
|
||||||
|
<property name="endDateLimit" value="+6MONTHS"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="embargoed" class="org.dspace.submit.model.AccessConditionOption">
|
||||||
|
<property name="groupName" value="Anonymous"/>
|
||||||
|
<!--
|
||||||
|
use the selectGroupName to specify the group containing the subgroups
|
||||||
|
that can be used for the policy
|
||||||
|
<property name="selectGroupName" value="Embargoed Groups"/>
|
||||||
|
-->
|
||||||
|
<property name="name" value="embargo"/>
|
||||||
|
<property name="hasStartDate" value="true"/>
|
||||||
|
<property name="startDateLimit" value="+36MONTHS"/>
|
||||||
|
<property name="hasEndDate" value="false"/>
|
||||||
|
|
||||||
|
</bean>
|
||||||
|
<bean id="embargoedWithGroupSelect" class="org.dspace.submit.model.AccessConditionOption">
|
||||||
|
<property name="selectGroupName" value="Embargoed Groups"/>
|
||||||
|
<property name="name" value="embargo"/>
|
||||||
|
<property name="hasStartDate" value="true"/>
|
||||||
|
<property name="startDateLimit" value="+36MONTHS"/>
|
||||||
|
<property name="hasEndDate" value="false"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="administrator" class="org.dspace.submit.model.AccessConditionOption">
|
||||||
|
<property name="groupName" value="Administrator"/>
|
||||||
|
<property name="name" value="administrator"/>
|
||||||
|
<property name="hasStartDate" value="false"/>
|
||||||
|
<property name="hasEndDate" value="false"/>
|
||||||
|
</bean>
|
||||||
|
<!-- <bean id="networkAdministration" class="org.dspace.submit.model.AccessConditionOption">
|
||||||
|
<property name="groupName" value="INSTITUTIONAL_NETWORK"/>
|
||||||
|
<property name="name" value="networkAdministration"/>
|
||||||
|
<property name="hasStartDate" value="false"/>
|
||||||
|
<property name="hasEndDate" value="false"/>
|
||||||
|
</bean> -->
|
||||||
|
|
||||||
|
<bean id="uploadConfigurationService" class="org.dspace.submit.model.UploadConfigurationService">
|
||||||
|
<property name="map">
|
||||||
|
<map>
|
||||||
|
<entry key="upload" value-ref="uploadConfigurationDefault" />
|
||||||
|
</map>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
</beans>
|
@@ -22,7 +22,7 @@ import org.dspace.core.ConfigurationManager;
|
|||||||
|
|
||||||
public class DSpaceResourceResolver implements ResourceResolver {
|
public class DSpaceResourceResolver implements ResourceResolver {
|
||||||
private static final TransformerFactory transformerFactory = TransformerFactory
|
private static final TransformerFactory transformerFactory = TransformerFactory
|
||||||
.newInstance();
|
.newInstance("net.sf.saxon.TransformerFactoryImpl", null);
|
||||||
|
|
||||||
private final String basePath = ConfigurationManager.getProperty("oai",
|
private final String basePath = ConfigurationManager.getProperty("oai",
|
||||||
"config.dir");
|
"config.dir");
|
||||||
|
@@ -19,7 +19,8 @@ import javax.xml.transform.stream.StreamSource;
|
|||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
public abstract class AbstractXSLTest {
|
public abstract class AbstractXSLTest {
|
||||||
private static final TransformerFactory factory = TransformerFactory.newInstance();
|
private static final TransformerFactory factory = TransformerFactory
|
||||||
|
.newInstance("net.sf.saxon.TransformerFactoryImpl", null);
|
||||||
|
|
||||||
protected TransformBuilder apply(String xslLocation) throws Exception {
|
protected TransformBuilder apply(String xslLocation) throws Exception {
|
||||||
return new TransformBuilder(xslLocation);
|
return new TransformBuilder(xslLocation);
|
||||||
|
@@ -10,6 +10,7 @@ package org.dspace.app.rest.converter;
|
|||||||
import org.dspace.app.rest.model.ClaimedTaskRest;
|
import org.dspace.app.rest.model.ClaimedTaskRest;
|
||||||
import org.dspace.app.rest.projection.Projection;
|
import org.dspace.app.rest.projection.Projection;
|
||||||
import org.dspace.discovery.IndexableObject;
|
import org.dspace.discovery.IndexableObject;
|
||||||
|
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
||||||
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
||||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -28,6 +29,9 @@ public class ClaimedTaskConverter
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ConverterService converter;
|
private ConverterService converter;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected XmlWorkflowFactory xmlWorkflowFactory;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClaimedTaskRest convert(ClaimedTask obj, Projection projection) {
|
public ClaimedTaskRest convert(ClaimedTask obj, Projection projection) {
|
||||||
ClaimedTaskRest taskRest = new ClaimedTaskRest();
|
ClaimedTaskRest taskRest = new ClaimedTaskRest();
|
||||||
@@ -35,8 +39,7 @@ public class ClaimedTaskConverter
|
|||||||
XmlWorkflowItem witem = obj.getWorkflowItem();
|
XmlWorkflowItem witem = obj.getWorkflowItem();
|
||||||
taskRest.setId(obj.getID());
|
taskRest.setId(obj.getID());
|
||||||
taskRest.setWorkflowitem(converter.toRest(witem, projection));
|
taskRest.setWorkflowitem(converter.toRest(witem, projection));
|
||||||
taskRest.setAction(obj.getActionID());
|
taskRest.setAction(converter.toRest(xmlWorkflowFactory.getActionByName(obj.getActionID()), projection));
|
||||||
taskRest.setStep(obj.getStepID());
|
|
||||||
taskRest.setOwner(converter.toRest(obj.getOwner(), projection));
|
taskRest.setOwner(converter.toRest(obj.getOwner(), projection));
|
||||||
return taskRest;
|
return taskRest;
|
||||||
}
|
}
|
||||||
|
@@ -32,6 +32,7 @@ import org.springframework.core.type.filter.AssignableTypeFilter;
|
|||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageImpl;
|
import org.springframework.data.domain.PageImpl;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.hateoas.Link;
|
||||||
import org.springframework.hateoas.Resource;
|
import org.springframework.hateoas.Resource;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -155,9 +156,30 @@ public class ConverterService {
|
|||||||
* @throws ClassCastException if the resource type is not compatible with the inferred return type.
|
* @throws ClassCastException if the resource type is not compatible with the inferred return type.
|
||||||
*/
|
*/
|
||||||
public <T extends HALResource> T toResource(RestModel restObject) {
|
public <T extends HALResource> T toResource(RestModel restObject) {
|
||||||
|
return toResource(restObject, new Link[] {});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given rest object to a {@link HALResource} object.
|
||||||
|
* <p>
|
||||||
|
* If the rest object is a {@link RestAddressableModel}, the projection returned by
|
||||||
|
* {@link RestAddressableModel#getProjection()} will be used to determine which optional
|
||||||
|
* embeds and links will be added, and {@link Projection#transformResource(HALResource)}
|
||||||
|
* will be automatically called before returning the final, fully converted resource.
|
||||||
|
* </p><p>
|
||||||
|
* In all cases, the {@link HalLinkService} will be used immediately after the resource is constructed,
|
||||||
|
* to ensure all {@link HalLinkFactory}s have had a chance to add links as needed.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param restObject the input rest object.
|
||||||
|
* @param oldLinks The old links fo the Resource Object
|
||||||
|
* @param <T> the return type, a subclass of {@link HALResource}.
|
||||||
|
* @return the fully converted resource, with all automatic links and embeds applied.
|
||||||
|
*/
|
||||||
|
public <T extends HALResource> T toResource(RestModel restObject, Link... oldLinks) {
|
||||||
T halResource = getResource(restObject);
|
T halResource = getResource(restObject);
|
||||||
if (restObject instanceof RestAddressableModel) {
|
if (restObject instanceof RestAddressableModel) {
|
||||||
utils.embedOrLinkClassLevelRels(halResource);
|
utils.embedOrLinkClassLevelRels(halResource, oldLinks);
|
||||||
halLinkService.addLinks(halResource);
|
halLinkService.addLinks(halResource);
|
||||||
Projection projection = ((RestAddressableModel) restObject).getProjection();
|
Projection projection = ((RestAddressableModel) restObject).getProjection();
|
||||||
return projection.transformResource(halResource);
|
return projection.transformResource(halResource);
|
||||||
|
@@ -43,7 +43,6 @@ public class PoolTaskConverter
|
|||||||
taskRest.setGroup(converter.toRest(obj.getGroup(), projection));
|
taskRest.setGroup(converter.toRest(obj.getGroup(), projection));
|
||||||
}
|
}
|
||||||
taskRest.setAction(obj.getActionID());
|
taskRest.setAction(obj.getActionID());
|
||||||
taskRest.setStep(obj.getStepID());
|
|
||||||
return taskRest;
|
return taskRest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -26,12 +26,6 @@ public class ResourcePolicyConverter implements DSpaceConverter<ResourcePolicy,
|
|||||||
@Autowired
|
@Autowired
|
||||||
ResourcePolicyService resourcePolicyService;
|
ResourcePolicyService resourcePolicyService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
EPersonConverter epersonConverter;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
GroupConverter groupConverter;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
ConverterService converterService;
|
ConverterService converterService;
|
||||||
|
|
||||||
@@ -53,13 +47,11 @@ public class ResourcePolicyConverter implements DSpaceConverter<ResourcePolicy,
|
|||||||
model.setEndDate(obj.getEndDate());
|
model.setEndDate(obj.getEndDate());
|
||||||
|
|
||||||
if (obj.getGroup() != null) {
|
if (obj.getGroup() != null) {
|
||||||
model.setGroupUUID(obj.getGroup().getID());
|
model.setGroup(converterService.toRest(obj.getGroup(), projection));
|
||||||
model.setGroup(groupConverter.convert(obj.getGroup(), projection));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.getEPerson() != null) {
|
if (obj.getEPerson() != null) {
|
||||||
model.setEpersonUUID(obj.getEPerson().getID());
|
model.setEperson(converterService.toRest(obj.getEPerson(), projection));
|
||||||
model.setEperson(epersonConverter.convert(obj.getEPerson(), projection));
|
|
||||||
}
|
}
|
||||||
if (obj.getdSpaceObject() != null) {
|
if (obj.getdSpaceObject() != null) {
|
||||||
model.setResource(converterService.toRest(obj.getdSpaceObject(), projection));
|
model.setResource(converterService.toRest(obj.getdSpaceObject(), projection));
|
||||||
|
@@ -9,20 +9,26 @@ package org.dspace.app.rest.model;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import org.dspace.app.rest.RestResourceController;
|
import org.dspace.app.rest.RestResourceController;
|
||||||
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ClaimedTask REST Resource
|
* The ClaimedTask REST Resource
|
||||||
*
|
*
|
||||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||||
*/
|
*/
|
||||||
|
@LinksRest(links = {
|
||||||
|
@LinkRest(
|
||||||
|
name = ClaimedTaskRest.STEP,
|
||||||
|
method = "getStep"
|
||||||
|
)
|
||||||
|
})
|
||||||
public class ClaimedTaskRest extends BaseObjectRest<Integer> {
|
public class ClaimedTaskRest extends BaseObjectRest<Integer> {
|
||||||
public static final String NAME = "claimedtask";
|
public static final String NAME = "claimedtask";
|
||||||
public static final String CATEGORY = RestAddressableModel.WORKFLOW;
|
public static final String CATEGORY = RestAddressableModel.WORKFLOW;
|
||||||
|
|
||||||
private String step;
|
public static final String STEP = "step";
|
||||||
|
|
||||||
private String action;
|
@JsonIgnore
|
||||||
|
private WorkflowActionRest action;
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private EPersonRest owner;
|
private EPersonRest owner;
|
||||||
@@ -45,27 +51,15 @@ public class ClaimedTaskRest extends BaseObjectRest<Integer> {
|
|||||||
return RestResourceController.class;
|
return RestResourceController.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ClaimedTask#getStepID()
|
|
||||||
* @return the step
|
|
||||||
*/
|
|
||||||
public String getStep() {
|
|
||||||
return step;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStep(String step) {
|
|
||||||
this.step = step;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ClaimedTaskRest#getAction()
|
* @see ClaimedTaskRest#getAction()
|
||||||
* @return the action
|
* @return the action
|
||||||
*/
|
*/
|
||||||
public String getAction() {
|
public WorkflowActionRest getAction() {
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAction(String action) {
|
public void setAction(WorkflowActionRest action) {
|
||||||
this.action = action;
|
this.action = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +76,7 @@ public class ClaimedTaskRest extends BaseObjectRest<Integer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return the WorkflowItemRest that belong to this claimed task
|
* @return the WorkflowItemRest that belong to this claimed task
|
||||||
*/
|
*/
|
||||||
public WorkflowItemRest getWorkflowitem() {
|
public WorkflowItemRest getWorkflowitem() {
|
||||||
|
@@ -16,11 +16,17 @@ import org.dspace.xmlworkflow.storedcomponents.PoolTask;
|
|||||||
*
|
*
|
||||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||||
*/
|
*/
|
||||||
|
@LinksRest(links = {
|
||||||
|
@LinkRest(
|
||||||
|
name = PoolTaskRest.STEP,
|
||||||
|
method = "getStep"
|
||||||
|
)
|
||||||
|
})
|
||||||
public class PoolTaskRest extends BaseObjectRest<Integer> {
|
public class PoolTaskRest extends BaseObjectRest<Integer> {
|
||||||
public static final String NAME = "pooltask";
|
public static final String NAME = "pooltask";
|
||||||
public static final String CATEGORY = RestAddressableModel.WORKFLOW;
|
public static final String CATEGORY = RestAddressableModel.WORKFLOW;
|
||||||
|
|
||||||
private String step;
|
public static final String STEP = "step";
|
||||||
|
|
||||||
private String action;
|
private String action;
|
||||||
|
|
||||||
@@ -48,18 +54,6 @@ public class PoolTaskRest extends BaseObjectRest<Integer> {
|
|||||||
return RestResourceController.class;
|
return RestResourceController.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see PoolTask#getStepID()
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getStep() {
|
|
||||||
return step;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStep(String step) {
|
|
||||||
this.step = step;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see PoolTask#getActionID()
|
* @see PoolTask#getActionID()
|
||||||
* @return
|
* @return
|
||||||
|
@@ -8,7 +8,6 @@
|
|||||||
package org.dspace.app.rest.model;
|
package org.dspace.app.rest.model;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
@@ -34,12 +33,6 @@ public class ResourcePolicyRest extends BaseObjectRest<Integer> {
|
|||||||
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
@JsonInclude(Include.NON_NULL)
|
|
||||||
private UUID groupUUID;
|
|
||||||
|
|
||||||
@JsonInclude(Include.NON_NULL)
|
|
||||||
private UUID epersonUUID;
|
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private EPersonRest eperson;
|
private EPersonRest eperson;
|
||||||
|
|
||||||
@@ -55,14 +48,6 @@ public class ResourcePolicyRest extends BaseObjectRest<Integer> {
|
|||||||
|
|
||||||
private Date endDate;
|
private Date endDate;
|
||||||
|
|
||||||
public UUID getGroupUUID() {
|
|
||||||
return groupUUID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setGroupUUID(UUID groupUuid) {
|
|
||||||
this.groupUUID = groupUuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getEndDate() {
|
public Date getEndDate() {
|
||||||
return endDate;
|
return endDate;
|
||||||
}
|
}
|
||||||
@@ -111,14 +96,6 @@ public class ResourcePolicyRest extends BaseObjectRest<Integer> {
|
|||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getEpersonUUID() {
|
|
||||||
return epersonUUID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEpersonUUID(UUID epersonUUID) {
|
|
||||||
this.epersonUUID = epersonUUID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EPersonRest getEperson() {
|
public EPersonRest getEperson() {
|
||||||
return eperson;
|
return eperson;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,101 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.rest.model;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.dspace.app.rest.model.step.UploadBitstreamRest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The UploadAccessConditionDTO is a partial representation of the DSpace
|
||||||
|
* {@link ResourcePolicyRest} as used in the patch payload for the upload
|
||||||
|
* submission section (see {@link UploadBitstreamRest}. The main reason for this
|
||||||
|
* class is to have a DTO to use serialize/deserialize the REST model, that
|
||||||
|
* include reference to the GroupRest and EPersonRest object, in the upload
|
||||||
|
* section data in a simpler way where such reference are just UUID. Indeed, due
|
||||||
|
* to the fact that the RestModel class are serialized according to the HAL
|
||||||
|
* format and the reference are only exposed in the _links section of the
|
||||||
|
* RestResource it was not possible to use the {@link ResourcePolicyRest} class
|
||||||
|
* directly in the upload section
|
||||||
|
*
|
||||||
|
* @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.it)
|
||||||
|
*/
|
||||||
|
public class UploadBitstreamAccessConditionDTO {
|
||||||
|
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private UUID groupUUID;
|
||||||
|
|
||||||
|
private UUID epersonUUID;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private Date startDate;
|
||||||
|
|
||||||
|
private Date endDate;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getGroupUUID() {
|
||||||
|
return groupUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupUUID(UUID groupUUID) {
|
||||||
|
this.groupUUID = groupUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getEpersonUUID() {
|
||||||
|
return epersonUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEpersonUUID(UUID epersonUUID) {
|
||||||
|
this.epersonUUID = epersonUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getStartDate() {
|
||||||
|
return startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartDate(Date startDate) {
|
||||||
|
this.startDate = startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getEndDate() {
|
||||||
|
return endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndDate(Date endDate) {
|
||||||
|
this.endDate = endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -14,10 +14,18 @@ import org.dspace.app.rest.RestResourceController;
|
|||||||
*
|
*
|
||||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||||
*/
|
*/
|
||||||
|
@LinksRest(links = {
|
||||||
|
@LinkRest(
|
||||||
|
name = WorkflowItemRest.STEP,
|
||||||
|
method = "getStep"
|
||||||
|
)
|
||||||
|
})
|
||||||
public class WorkflowItemRest extends AInprogressSubmissionRest {
|
public class WorkflowItemRest extends AInprogressSubmissionRest {
|
||||||
public static final String NAME = "workflowitem";
|
public static final String NAME = "workflowitem";
|
||||||
public static final String CATEGORY = RestAddressableModel.WORKFLOW;
|
public static final String CATEGORY = RestAddressableModel.WORKFLOW;
|
||||||
|
|
||||||
|
public static final String STEP = "step";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCategory() {
|
public String getCategory() {
|
||||||
return CATEGORY;
|
return CATEGORY;
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
package org.dspace.app.rest.model.step;
|
package org.dspace.app.rest.model.step;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -16,13 +17,19 @@ import java.util.UUID;
|
|||||||
import org.dspace.app.rest.model.BitstreamFormatRest;
|
import org.dspace.app.rest.model.BitstreamFormatRest;
|
||||||
import org.dspace.app.rest.model.CheckSumRest;
|
import org.dspace.app.rest.model.CheckSumRest;
|
||||||
import org.dspace.app.rest.model.MetadataValueRest;
|
import org.dspace.app.rest.model.MetadataValueRest;
|
||||||
import org.dspace.app.rest.model.ResourcePolicyRest;
|
import org.dspace.app.rest.model.UploadBitstreamAccessConditionDTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This Java Bean is used to represent a single bitstream with all its metadata
|
||||||
|
* and access conditions ({@link UploadBitstreamAccessConditionDTO}) inside an
|
||||||
|
* upload submission section ({@link DataUpload}
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class UploadBitstreamRest extends UploadStatusResponse {
|
public class UploadBitstreamRest extends UploadStatusResponse {
|
||||||
|
|
||||||
private UUID uuid;
|
private UUID uuid;
|
||||||
private Map<String, List<MetadataValueRest>> metadata = new HashMap<>();
|
private Map<String, List<MetadataValueRest>> metadata = new HashMap<>();
|
||||||
private List<ResourcePolicyRest> accessConditions;
|
private List<UploadBitstreamAccessConditionDTO> accessConditions;
|
||||||
private BitstreamFormatRest format;
|
private BitstreamFormatRest format;
|
||||||
private Long sizeBytes;
|
private Long sizeBytes;
|
||||||
private CheckSumRest checkSum;
|
private CheckSumRest checkSum;
|
||||||
@@ -68,14 +75,14 @@ public class UploadBitstreamRest extends UploadStatusResponse {
|
|||||||
this.metadata = metadata;
|
this.metadata = metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ResourcePolicyRest> getAccessConditions() {
|
public List<UploadBitstreamAccessConditionDTO> getAccessConditions() {
|
||||||
if (accessConditions == null) {
|
if (accessConditions == null) {
|
||||||
accessConditions = new ArrayList<>();
|
accessConditions = new ArrayList<>();
|
||||||
}
|
}
|
||||||
return accessConditions;
|
return accessConditions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAccessConditions(List<ResourcePolicyRest> accessConditions) {
|
public void setAccessConditions(List<UploadBitstreamAccessConditionDTO> accessConditions) {
|
||||||
this.accessConditions = accessConditions;
|
this.accessConditions = accessConditions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,8 +8,10 @@
|
|||||||
package org.dspace.app.rest.projection;
|
package org.dspace.app.rest.projection;
|
||||||
|
|
||||||
import org.dspace.app.rest.model.LinkRest;
|
import org.dspace.app.rest.model.LinkRest;
|
||||||
|
import org.dspace.app.rest.model.RestAddressableModel;
|
||||||
import org.dspace.app.rest.model.RestModel;
|
import org.dspace.app.rest.model.RestModel;
|
||||||
import org.dspace.app.rest.model.hateoas.HALResource;
|
import org.dspace.app.rest.model.hateoas.HALResource;
|
||||||
|
import org.springframework.hateoas.Link;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for projections.
|
* Abstract base class for projections.
|
||||||
@@ -34,7 +36,8 @@ public abstract class AbstractProjection implements Projection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean allowEmbedding(HALResource halResource, LinkRest linkRest) {
|
public boolean allowEmbedding(HALResource<? extends RestAddressableModel> halResource, LinkRest linkRest,
|
||||||
|
Link... oldLinks) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.rest.projection;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.dspace.app.rest.model.LinkRest;
|
||||||
|
import org.dspace.app.rest.model.RestAddressableModel;
|
||||||
|
import org.dspace.app.rest.model.RestModel;
|
||||||
|
import org.dspace.app.rest.model.hateoas.HALResource;
|
||||||
|
import org.springframework.hateoas.Link;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A projection that combines the behavior of multiple projections.
|
||||||
|
*
|
||||||
|
* Model, rest, and resource transformations will be performed in the order of the projections given in
|
||||||
|
* the constructor. Embedding will be allowed if any of the given projections allow them. Linking will
|
||||||
|
* be allowed if all of the given projections allow them.
|
||||||
|
*/
|
||||||
|
public class CompositeProjection implements Projection {
|
||||||
|
|
||||||
|
public final static String NAME = "composite";
|
||||||
|
|
||||||
|
private final List<Projection> projections;
|
||||||
|
|
||||||
|
public CompositeProjection(List<Projection> projections) {
|
||||||
|
this.projections = projections;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T transformModel(T modelObject) {
|
||||||
|
for (Projection projection : projections) {
|
||||||
|
modelObject = projection.transformModel(modelObject);
|
||||||
|
}
|
||||||
|
return modelObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends RestModel> T transformRest(T restObject) {
|
||||||
|
for (Projection projection : projections) {
|
||||||
|
restObject = projection.transformRest(restObject);
|
||||||
|
}
|
||||||
|
return restObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends HALResource> T transformResource(T halResource) {
|
||||||
|
for (Projection projection : projections) {
|
||||||
|
halResource = projection.transformResource(halResource);
|
||||||
|
}
|
||||||
|
return halResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean allowEmbedding(HALResource<? extends RestAddressableModel> halResource, LinkRest linkRest,
|
||||||
|
Link... oldLinks) {
|
||||||
|
for (Projection projection : projections) {
|
||||||
|
if (projection.allowEmbedding(halResource, linkRest, oldLinks)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean allowLinking(HALResource halResource, LinkRest linkRest) {
|
||||||
|
for (Projection projection : projections) {
|
||||||
|
if (!projection.allowLinking(halResource, linkRest)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* 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.projection;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.dspace.app.rest.model.LinkRest;
|
||||||
|
import org.dspace.app.rest.model.RestAddressableModel;
|
||||||
|
import org.dspace.app.rest.model.hateoas.HALResource;
|
||||||
|
import org.springframework.hateoas.Link;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Projection that allows a given set of rels to be embedded.
|
||||||
|
* A Rel refers to a Link Relation, this is an Embedded Object of the HalResource and the HalResource contains
|
||||||
|
* a link to this
|
||||||
|
*/
|
||||||
|
public class EmbedRelsProjection extends AbstractProjection {
|
||||||
|
|
||||||
|
public final static String NAME = "embedrels";
|
||||||
|
|
||||||
|
private final Set<String> embedRels;
|
||||||
|
|
||||||
|
public EmbedRelsProjection(Set<String> embedRels) {
|
||||||
|
this.embedRels = embedRels;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean allowEmbedding(HALResource<? extends RestAddressableModel> halResource, LinkRest linkRest,
|
||||||
|
Link... oldLinks) {
|
||||||
|
// If level 0, and the name is present, the link can be embedded (e.g. the logo on a collection page)
|
||||||
|
if (halResource.getContent().getEmbedLevel() == 0 && embedRels.contains(linkRest.name())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder fullName = new StringBuilder();
|
||||||
|
for (Link oldLink : oldLinks) {
|
||||||
|
fullName.append(oldLink.getRel()).append("/");
|
||||||
|
}
|
||||||
|
fullName.append(linkRest.name());
|
||||||
|
// If the full name matches, the link can be embedded (e.g. mappedItems/owningCollection on a collection page)
|
||||||
|
if (embedRels.contains(fullName.toString())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fullName.append("/");
|
||||||
|
// If the full name starts with the allowed embed, but the embed goes deeper, the link can be embedded
|
||||||
|
// (e.g. making sure mappedItems/owningCollection also embeds mappedItems on a collection page)
|
||||||
|
for (String embedRel : embedRels) {
|
||||||
|
if (embedRel.startsWith(fullName.toString())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@@ -8,7 +8,10 @@
|
|||||||
package org.dspace.app.rest.projection;
|
package org.dspace.app.rest.projection;
|
||||||
|
|
||||||
import org.dspace.app.rest.model.LinkRest;
|
import org.dspace.app.rest.model.LinkRest;
|
||||||
|
import org.dspace.app.rest.model.RestAddressableModel;
|
||||||
import org.dspace.app.rest.model.hateoas.HALResource;
|
import org.dspace.app.rest.model.hateoas.HALResource;
|
||||||
|
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||||
|
import org.springframework.hateoas.Link;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,14 +21,17 @@ import org.springframework.stereotype.Component;
|
|||||||
public class FullProjection extends AbstractProjection {
|
public class FullProjection extends AbstractProjection {
|
||||||
|
|
||||||
public final static String NAME = "full";
|
public final static String NAME = "full";
|
||||||
|
private final int maxEmbed = DSpaceServicesFactory.getInstance().getConfigurationService()
|
||||||
|
.getIntProperty("rest.projections.full.max", 2);
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return NAME;
|
return NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean allowEmbedding(HALResource halResource, LinkRest linkRest) {
|
public boolean allowEmbedding(HALResource<? extends RestAddressableModel> halResource, LinkRest linkRest,
|
||||||
return true;
|
Link... oldLinks) {
|
||||||
|
return halResource.getContent().getEmbedLevel() < maxEmbed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -10,9 +10,12 @@ package org.dspace.app.rest.projection;
|
|||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
|
||||||
import org.dspace.app.rest.model.LinkRest;
|
import org.dspace.app.rest.model.LinkRest;
|
||||||
|
import org.dspace.app.rest.model.RestAddressableModel;
|
||||||
import org.dspace.app.rest.model.RestModel;
|
import org.dspace.app.rest.model.RestModel;
|
||||||
import org.dspace.app.rest.model.hateoas.HALResource;
|
import org.dspace.app.rest.model.hateoas.HALResource;
|
||||||
import org.dspace.app.rest.repository.DSpaceRestRepository;
|
import org.dspace.app.rest.repository.DSpaceRestRepository;
|
||||||
|
import org.dspace.app.rest.utils.Utils;
|
||||||
|
import org.springframework.hateoas.Link;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@@ -44,7 +47,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
* <li> After it is converted to a {@link RestModel}, the projection may modify it
|
* <li> After it is converted to a {@link RestModel}, the projection may modify it
|
||||||
* via {@link #transformRest(RestModel)}.</li>
|
* via {@link #transformRest(RestModel)}.</li>
|
||||||
* <li> During conversion to a {@link HALResource}, the projection may opt in to certain annotation-discovered
|
* <li> During conversion to a {@link HALResource}, the projection may opt in to certain annotation-discovered
|
||||||
* HAL embeds and links via {@link #allowEmbedding(HALResource, LinkRest)}
|
* HAL embeds and links via {@link #allowEmbedding(HALResource, LinkRest, Link...)}
|
||||||
* and {@link #allowLinking(HALResource, LinkRest)}</li>
|
* and {@link #allowLinking(HALResource, LinkRest)}</li>
|
||||||
* <li> After conversion to a {@link HALResource}, the projection may modify it
|
* <li> After conversion to a {@link HALResource}, the projection may modify it
|
||||||
* via {@link #transformResource(HALResource)}.</li>
|
* via {@link #transformResource(HALResource)}.</li>
|
||||||
@@ -52,8 +55,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
*
|
*
|
||||||
* <h2>How a projection is chosen</h2>
|
* <h2>How a projection is chosen</h2>
|
||||||
*
|
*
|
||||||
* When a REST request is made, the projection argument, if present, is used to look up the projection to use,
|
* See {@link Utils#obtainProjection()}.
|
||||||
* by name. If no argument is present, {@link DefaultProjection} will be used.
|
|
||||||
*/
|
*/
|
||||||
public interface Projection {
|
public interface Projection {
|
||||||
|
|
||||||
@@ -115,16 +117,18 @@ public interface Projection {
|
|||||||
*
|
*
|
||||||
* @param halResource the resource from which the embed may or may not be made.
|
* @param halResource the resource from which the embed may or may not be made.
|
||||||
* @param linkRest the LinkRest annotation through which the related resource was discovered on the rest object.
|
* @param linkRest the LinkRest annotation through which the related resource was discovered on the rest object.
|
||||||
|
* @param oldLinks The previously traversed links
|
||||||
* @return true if allowed, false otherwise.
|
* @return true if allowed, false otherwise.
|
||||||
*/
|
*/
|
||||||
boolean allowEmbedding(HALResource halResource, LinkRest linkRest);
|
boolean allowEmbedding(HALResource<? extends RestAddressableModel> halResource, LinkRest linkRest,
|
||||||
|
Link... oldLinks);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells whether this projection permits the linking of a particular linkable subresource.
|
* Tells whether this projection permits the linking of a particular linkable subresource.
|
||||||
*
|
*
|
||||||
* This gives the projection an opportunity to opt in to to certain links, by returning {@code true}.
|
* This gives the projection an opportunity to opt in to to certain links, by returning {@code true}.
|
||||||
*
|
*
|
||||||
* Note: If {@link #allowEmbedding(HALResource, LinkRest)} returns {@code true} for a given subresource,
|
* Note: If {@link #allowEmbedding(HALResource, LinkRest, Link...)} returns {@code true} for a given subresource,
|
||||||
* it will be automatically linked regardless of what this method returns.
|
* it will be automatically linked regardless of what this method returns.
|
||||||
*
|
*
|
||||||
* @param halResource the resource from which the link may or may not be made.
|
* @param halResource the resource from which the link may or may not be made.
|
||||||
|
@@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* 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.projection;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.dspace.app.rest.exception.MissingParameterException;
|
||||||
|
import org.dspace.app.rest.model.LinkRest;
|
||||||
|
import org.dspace.app.rest.model.RestAddressableModel;
|
||||||
|
import org.dspace.app.rest.model.hateoas.HALResource;
|
||||||
|
import org.dspace.services.RequestService;
|
||||||
|
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.hateoas.Link;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This Projection will allow us to specify how many levels deep we're going to embed resources onto the requested
|
||||||
|
* HalResource.
|
||||||
|
* The projection is used by using the name combined with the embedLevelDepth parameter to specify how deep the embeds
|
||||||
|
* have to go. There is an upperlimit in place for this, which is specified on the bean through the maxEmbed property
|
||||||
|
*/
|
||||||
|
public class SpecificLevelProjection extends AbstractProjection {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RequestService requestService;
|
||||||
|
|
||||||
|
public final static String NAME = "level";
|
||||||
|
|
||||||
|
private int maxEmbed = DSpaceServicesFactory.getInstance().getConfigurationService()
|
||||||
|
.getIntProperty("rest.projections.full.max", 2);
|
||||||
|
|
||||||
|
public int getMaxEmbed() {
|
||||||
|
return maxEmbed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxEmbed(int maxEmbed) {
|
||||||
|
this.maxEmbed = maxEmbed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean allowEmbedding(HALResource<? extends RestAddressableModel> halResource, LinkRest linkRest,
|
||||||
|
Link... oldLinks) {
|
||||||
|
String embedLevelDepthString = requestService.getCurrentRequest().getHttpServletRequest()
|
||||||
|
.getParameter("embedLevelDepth");
|
||||||
|
if (StringUtils.isBlank(embedLevelDepthString)) {
|
||||||
|
throw new MissingParameterException("The embedLevelDepth parameter needs to be specified" +
|
||||||
|
" for this Projection");
|
||||||
|
}
|
||||||
|
Integer embedLevelDepth = Integer.parseInt(embedLevelDepthString);
|
||||||
|
if (embedLevelDepth > maxEmbed) {
|
||||||
|
throw new IllegalArgumentException("The embedLevelDepth may not exceed the configured max: " + maxEmbed);
|
||||||
|
}
|
||||||
|
return halResource.getContent().getEmbedLevel() < embedLevelDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean allowLinking(HALResource halResource, LinkRest linkRest) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* 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.repository;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.dspace.app.rest.model.ClaimedTaskRest;
|
||||||
|
import org.dspace.app.rest.model.WorkflowStepRest;
|
||||||
|
import org.dspace.app.rest.projection.Projection;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
||||||
|
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
||||||
|
import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link repository for the Steps subresources for an individual ClaimedTask
|
||||||
|
*/
|
||||||
|
@Component(ClaimedTaskRest.CATEGORY + "." + ClaimedTaskRest.NAME + "." + ClaimedTaskRest.STEP)
|
||||||
|
public class ClaimedTaskStepLinkRepository extends AbstractDSpaceRestRepository implements LinkRestRepository {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ClaimedTaskService claimedTaskService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private XmlWorkflowFactory xmlWorkflowFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will retrieve the {@link WorkflowStepRest} object for the {@link ClaimedTask} with the given id
|
||||||
|
* @param request The current request
|
||||||
|
* @param claimedTaskId The id for the ClaimedTask to be used
|
||||||
|
* @param optionalPageable The pageable if relevant
|
||||||
|
* @param projection The Projection
|
||||||
|
* @return The {@link WorkflowStepRest} object related to the {@link ClaimedTask} specified by
|
||||||
|
* the given ID
|
||||||
|
*/
|
||||||
|
public WorkflowStepRest getStep(@Nullable HttpServletRequest request,
|
||||||
|
Integer claimedTaskId,
|
||||||
|
@Nullable Pageable optionalPageable,
|
||||||
|
Projection projection) {
|
||||||
|
|
||||||
|
Context context = obtainContext();
|
||||||
|
try {
|
||||||
|
ClaimedTask claimedTask = claimedTaskService.find(context, claimedTaskId);
|
||||||
|
if (claimedTask == null) {
|
||||||
|
throw new ResourceNotFoundException("ClaimedTask with id: " + claimedTaskId + " wasn't found");
|
||||||
|
}
|
||||||
|
return converter.toRest(xmlWorkflowFactory.getStepByName(claimedTask.getStepID()), projection);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* 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.repository;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.dspace.app.rest.model.PoolTaskRest;
|
||||||
|
import org.dspace.app.rest.model.WorkflowStepRest;
|
||||||
|
import org.dspace.app.rest.projection.Projection;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
||||||
|
import org.dspace.xmlworkflow.storedcomponents.PoolTask;
|
||||||
|
import org.dspace.xmlworkflow.storedcomponents.service.PoolTaskService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link repositoy for the Steps subresources of an individual PoolTask
|
||||||
|
*/
|
||||||
|
@Component(PoolTaskRest.CATEGORY + "." + PoolTaskRest.NAME + "." + PoolTaskRest.STEP)
|
||||||
|
public class PoolTaskStepLinkRepository extends AbstractDSpaceRestRepository implements LinkRestRepository {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PoolTaskService poolTaskService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private XmlWorkflowFactory xmlWorkflowFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will retrieve the {@link WorkflowStepRest} object for the {@link PoolTask} with the given id
|
||||||
|
* @param request The current request
|
||||||
|
* @param poolTaskId The id for the PoolTask to be used
|
||||||
|
* @param optionalPageable The pageable if relevant
|
||||||
|
* @param projection The Projection
|
||||||
|
* @return The {@link WorkflowStepRest} object related to the {@link PoolTask} specified by
|
||||||
|
* the given ID
|
||||||
|
*/
|
||||||
|
public WorkflowStepRest getStep(@Nullable HttpServletRequest request,
|
||||||
|
Integer poolTaskId,
|
||||||
|
@Nullable Pageable optionalPageable,
|
||||||
|
Projection projection) {
|
||||||
|
|
||||||
|
Context context = obtainContext();
|
||||||
|
try {
|
||||||
|
PoolTask poolTask = poolTaskService.find(context, poolTaskId);
|
||||||
|
if (poolTask == null) {
|
||||||
|
throw new ResourceNotFoundException("ClaimedTask with id: " + poolTaskId + " wasn't found");
|
||||||
|
}
|
||||||
|
return converter.toRest(xmlWorkflowFactory.getStepByName(poolTask.getStepID()), projection);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,86 @@
|
|||||||
|
/**
|
||||||
|
* 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.repository;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.dspace.app.rest.model.WorkflowItemRest;
|
||||||
|
import org.dspace.app.rest.model.WorkflowStepRest;
|
||||||
|
import org.dspace.app.rest.projection.Projection;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
||||||
|
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
||||||
|
import org.dspace.xmlworkflow.storedcomponents.PoolTask;
|
||||||
|
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||||
|
import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService;
|
||||||
|
import org.dspace.xmlworkflow.storedcomponents.service.PoolTaskService;
|
||||||
|
import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link Repository for the Steps subresources of an individual WorkflowItem
|
||||||
|
*/
|
||||||
|
@Component(WorkflowItemRest.CATEGORY + "." + WorkflowItemRest.NAME + "." + WorkflowItemRest.STEP)
|
||||||
|
public class WorkflowItemStepLinkRepository extends AbstractDSpaceRestRepository implements LinkRestRepository {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private XmlWorkflowItemService xmlWorkflowItemService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PoolTaskService poolTaskService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ClaimedTaskService claimedTaskService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private XmlWorkflowFactory xmlWorkflowFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will retrieve the {@link WorkflowStepRest} object for the {@link org.dspace.workflow.WorkflowItem}
|
||||||
|
* with the given id
|
||||||
|
* @param request The current request
|
||||||
|
* @param workflowItemId The id for the WorkflowItem to be used
|
||||||
|
* @param optionalPageable The pageable if relevant
|
||||||
|
* @param projection The Projection
|
||||||
|
* @return The {@link WorkflowStepRest} object related to the
|
||||||
|
* {@link org.dspace.workflow.WorkflowItem} specified by the given ID
|
||||||
|
*/
|
||||||
|
public WorkflowStepRest getStep(@Nullable HttpServletRequest request,
|
||||||
|
Integer workflowItemId,
|
||||||
|
@Nullable Pageable optionalPageable,
|
||||||
|
Projection projection) {
|
||||||
|
|
||||||
|
Context context = obtainContext();
|
||||||
|
try {
|
||||||
|
XmlWorkflowItem xmlWorkflowItem = xmlWorkflowItemService.find(context, workflowItemId);
|
||||||
|
if (xmlWorkflowItem == null) {
|
||||||
|
throw new ResourceNotFoundException("XmlWorkflowItem with id: " + workflowItemId + " wasn't found");
|
||||||
|
}
|
||||||
|
List<PoolTask> poolTasks = poolTaskService.find(context, xmlWorkflowItem);
|
||||||
|
List<ClaimedTask> claimedTasks = claimedTaskService.find(context, xmlWorkflowItem);
|
||||||
|
for (PoolTask poolTask : poolTasks) {
|
||||||
|
return converter.toRest(xmlWorkflowFactory.getStepByName(poolTask.getStepID()), projection);
|
||||||
|
}
|
||||||
|
for (ClaimedTask claimedTask : claimedTasks) {
|
||||||
|
return converter.toRest(xmlWorkflowFactory.getStepByName(claimedTask.getStepID()), projection);
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
throw new ResourceNotFoundException("No workflowStep for this workflowItem with id: " + workflowItemId +
|
||||||
|
" was found");
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -85,7 +85,7 @@ public class AuthorizeServicePermissionEvaluatorPlugin extends RestObjectPermiss
|
|||||||
}
|
}
|
||||||
|
|
||||||
return authorizeService.authorizeActionBoolean(context, ePerson, dSpaceObject,
|
return authorizeService.authorizeActionBoolean(context, ePerson, dSpaceObject,
|
||||||
restPermission.getDspaceApiActionId(), false);
|
restPermission.getDspaceApiActionId(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
package org.dspace.app.rest.submit;
|
package org.dspace.app.rest.submit;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -23,8 +24,9 @@ import org.dspace.app.rest.exception.UnprocessableEntityException;
|
|||||||
import org.dspace.app.rest.model.BitstreamRest;
|
import org.dspace.app.rest.model.BitstreamRest;
|
||||||
import org.dspace.app.rest.model.CheckSumRest;
|
import org.dspace.app.rest.model.CheckSumRest;
|
||||||
import org.dspace.app.rest.model.MetadataValueRest;
|
import org.dspace.app.rest.model.MetadataValueRest;
|
||||||
import org.dspace.app.rest.model.ResourcePolicyRest;
|
import org.dspace.app.rest.model.UploadBitstreamAccessConditionDTO;
|
||||||
import org.dspace.app.rest.model.WorkspaceItemRest;
|
import org.dspace.app.rest.model.WorkspaceItemRest;
|
||||||
|
import org.dspace.app.rest.model.step.DataUpload;
|
||||||
import org.dspace.app.rest.model.step.UploadBitstreamRest;
|
import org.dspace.app.rest.model.step.UploadBitstreamRest;
|
||||||
import org.dspace.app.rest.projection.Projection;
|
import org.dspace.app.rest.projection.Projection;
|
||||||
import org.dspace.app.rest.utils.ContextUtil;
|
import org.dspace.app.rest.utils.ContextUtil;
|
||||||
@@ -81,7 +83,7 @@ public class SubmissionService {
|
|||||||
private org.dspace.app.rest.utils.Utils utils;
|
private org.dspace.app.rest.utils.Utils utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a workspaceitem using the information in the reqest
|
* Create a workspaceitem using the information in the request
|
||||||
*
|
*
|
||||||
* @param context
|
* @param context
|
||||||
* the dspace context
|
* the dspace context
|
||||||
@@ -135,7 +137,17 @@ public class SubmissionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the rest representation of a bitstream as used in the upload section
|
||||||
|
* ({@link DataUpload}. It contains all its metadata and the list of applied
|
||||||
|
* access conditions (@link {@link UploadBitstreamAccessConditionDTO}
|
||||||
|
*
|
||||||
|
* @param configurationService the DSpace ConfigurationService
|
||||||
|
* @param source the bitstream to translate in its rest submission
|
||||||
|
* representation
|
||||||
|
* @return
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
public UploadBitstreamRest buildUploadBitstream(ConfigurationService configurationService, Bitstream source)
|
public UploadBitstreamRest buildUploadBitstream(ConfigurationService configurationService, Bitstream source)
|
||||||
throws SQLException {
|
throws SQLException {
|
||||||
UploadBitstreamRest data = new UploadBitstreamRest();
|
UploadBitstreamRest data = new UploadBitstreamRest();
|
||||||
@@ -170,8 +182,8 @@ public class SubmissionService {
|
|||||||
|
|
||||||
for (ResourcePolicy rp : source.getResourcePolicies()) {
|
for (ResourcePolicy rp : source.getResourcePolicies()) {
|
||||||
if (ResourcePolicy.TYPE_CUSTOM.equals(rp.getRpType())) {
|
if (ResourcePolicy.TYPE_CUSTOM.equals(rp.getRpType())) {
|
||||||
ResourcePolicyRest resourcePolicyRest = converter.toRest(rp, projection);
|
UploadBitstreamAccessConditionDTO uploadAccessCondition = createAccessConditionFromResourcePolicy(rp);
|
||||||
data.getAccessConditions().add(resourcePolicyRest);
|
data.getAccessConditions().add(uploadAccessCondition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +199,7 @@ public class SubmissionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a workflowitem using the information in the reqest
|
* Create a workflowitem using the information in the request
|
||||||
*
|
*
|
||||||
* @param context
|
* @param context
|
||||||
* the dspace context
|
* the dspace context
|
||||||
@@ -237,6 +249,23 @@ public class SubmissionService {
|
|||||||
return wi;
|
return wi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private UploadBitstreamAccessConditionDTO createAccessConditionFromResourcePolicy(ResourcePolicy rp) {
|
||||||
|
UploadBitstreamAccessConditionDTO accessCondition = new UploadBitstreamAccessConditionDTO();
|
||||||
|
|
||||||
|
accessCondition.setId(rp.getID());
|
||||||
|
accessCondition.setName(rp.getRpName());
|
||||||
|
accessCondition.setDescription(rp.getRpDescription());
|
||||||
|
accessCondition.setStartDate(rp.getStartDate());
|
||||||
|
accessCondition.setEndDate(rp.getEndDate());
|
||||||
|
if (rp.getGroup() != null) {
|
||||||
|
accessCondition.setGroupUUID(rp.getGroup().getID());
|
||||||
|
}
|
||||||
|
if (rp.getEPerson() != null) {
|
||||||
|
accessCondition.setEpersonUUID(rp.getEPerson().getID());
|
||||||
|
}
|
||||||
|
return accessCondition;
|
||||||
|
}
|
||||||
|
|
||||||
public void saveWorkflowItem(Context context, XmlWorkflowItem source) throws SQLException, AuthorizeException {
|
public void saveWorkflowItem(Context context, XmlWorkflowItem source) throws SQLException, AuthorizeException {
|
||||||
workflowItemService.update(context, source);
|
workflowItemService.update(context, source);
|
||||||
}
|
}
|
||||||
|
@@ -8,10 +8,11 @@
|
|||||||
package org.dspace.app.rest.submit.factory.impl;
|
package org.dspace.app.rest.submit.factory.impl;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.dspace.app.rest.model.ResourcePolicyRest;
|
import org.dspace.app.rest.model.UploadBitstreamAccessConditionDTO;
|
||||||
import org.dspace.app.rest.model.patch.LateObjectEvaluator;
|
import org.dspace.app.rest.model.patch.LateObjectEvaluator;
|
||||||
import org.dspace.authorize.ResourcePolicy;
|
import org.dspace.authorize.ResourcePolicy;
|
||||||
import org.dspace.authorize.service.AuthorizeService;
|
import org.dspace.authorize.service.AuthorizeService;
|
||||||
@@ -35,7 +36,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
*
|
*
|
||||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
*/
|
*/
|
||||||
public class ResourcePolicyAddPatchOperation extends AddPatchOperation<ResourcePolicyRest> {
|
public class BitstreamResourcePolicyAddPatchOperation extends AddPatchOperation<UploadBitstreamAccessConditionDTO> {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
BitstreamService bitstreamService;
|
BitstreamService bitstreamService;
|
||||||
@@ -48,6 +49,7 @@ public class ResourcePolicyAddPatchOperation extends AddPatchOperation<ResourceP
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
GroupService groupService;
|
GroupService groupService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
EPersonService epersonService;
|
EPersonService epersonService;
|
||||||
|
|
||||||
@@ -65,7 +67,8 @@ public class ResourcePolicyAddPatchOperation extends AddPatchOperation<ResourceP
|
|||||||
for (Bitstream b : bb.getBitstreams()) {
|
for (Bitstream b : bb.getBitstreams()) {
|
||||||
if (idx == Integer.parseInt(split[1])) {
|
if (idx == Integer.parseInt(split[1])) {
|
||||||
|
|
||||||
List<ResourcePolicyRest> newAccessConditions = new ArrayList<ResourcePolicyRest>();
|
List<UploadBitstreamAccessConditionDTO> newAccessConditions =
|
||||||
|
new ArrayList<UploadBitstreamAccessConditionDTO>();
|
||||||
if (split.length == 3) {
|
if (split.length == 3) {
|
||||||
authorizeService.removePoliciesActionFilter(context, b, Constants.READ);
|
authorizeService.removePoliciesActionFilter(context, b, Constants.READ);
|
||||||
newAccessConditions = evaluateArrayObject((LateObjectEvaluator) value);
|
newAccessConditions = evaluateArrayObject((LateObjectEvaluator) value);
|
||||||
@@ -74,7 +77,7 @@ public class ResourcePolicyAddPatchOperation extends AddPatchOperation<ResourceP
|
|||||||
newAccessConditions.add(evaluateSingleObject((LateObjectEvaluator) value));
|
newAccessConditions.add(evaluateSingleObject((LateObjectEvaluator) value));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ResourcePolicyRest newAccessCondition : newAccessConditions) {
|
for (UploadBitstreamAccessConditionDTO newAccessCondition : newAccessConditions) {
|
||||||
String name = newAccessCondition.getName();
|
String name = newAccessCondition.getName();
|
||||||
String description = newAccessCondition.getDescription();
|
String description = newAccessCondition.getDescription();
|
||||||
|
|
||||||
@@ -102,12 +105,12 @@ public class ResourcePolicyAddPatchOperation extends AddPatchOperation<ResourceP
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<ResourcePolicyRest[]> getArrayClassForEvaluation() {
|
protected Class<UploadBitstreamAccessConditionDTO[]> getArrayClassForEvaluation() {
|
||||||
return ResourcePolicyRest[].class;
|
return UploadBitstreamAccessConditionDTO[].class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<ResourcePolicyRest> getClassForEvaluation() {
|
protected Class<UploadBitstreamAccessConditionDTO> getClassForEvaluation() {
|
||||||
return ResourcePolicyRest.class;
|
return UploadBitstreamAccessConditionDTO.class;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -9,7 +9,7 @@ package org.dspace.app.rest.submit.factory.impl;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.dspace.app.rest.model.ResourcePolicyRest;
|
import org.dspace.app.rest.model.UploadBitstreamAccessConditionDTO;
|
||||||
import org.dspace.authorize.ResourcePolicy;
|
import org.dspace.authorize.ResourcePolicy;
|
||||||
import org.dspace.authorize.service.ResourcePolicyService;
|
import org.dspace.authorize.service.ResourcePolicyService;
|
||||||
import org.dspace.content.Bitstream;
|
import org.dspace.content.Bitstream;
|
||||||
@@ -28,7 +28,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
*
|
*
|
||||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
*/
|
*/
|
||||||
public class ResourcePolicyRemovePatchOperation extends RemovePatchOperation<ResourcePolicyRest> {
|
public class BitstreamResourcePolicyRemovePatchOperation
|
||||||
|
extends RemovePatchOperation<UploadBitstreamAccessConditionDTO> {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
ItemService itemService;
|
ItemService itemService;
|
||||||
@@ -83,12 +84,12 @@ public class ResourcePolicyRemovePatchOperation extends RemovePatchOperation<Res
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<ResourcePolicyRest[]> getArrayClassForEvaluation() {
|
protected Class<UploadBitstreamAccessConditionDTO[]> getArrayClassForEvaluation() {
|
||||||
return ResourcePolicyRest[].class;
|
return UploadBitstreamAccessConditionDTO[].class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<ResourcePolicyRest> getClassForEvaluation() {
|
protected Class<UploadBitstreamAccessConditionDTO> getClassForEvaluation() {
|
||||||
return ResourcePolicyRest.class;
|
return UploadBitstreamAccessConditionDTO.class;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -9,6 +9,7 @@ package org.dspace.app.rest.submit.factory.impl;
|
|||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.dspace.app.rest.model.ResourcePolicyRest;
|
import org.dspace.app.rest.model.ResourcePolicyRest;
|
||||||
import org.dspace.app.rest.model.patch.LateObjectEvaluator;
|
import org.dspace.app.rest.model.patch.LateObjectEvaluator;
|
||||||
@@ -35,7 +36,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
*
|
*
|
||||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
*/
|
*/
|
||||||
public class ResourcePolicyReplacePatchOperation extends ReplacePatchOperation<ResourcePolicyRest> {
|
public class BitstreamResourcePolicyReplacePatchOperation extends ReplacePatchOperation<ResourcePolicyRest> {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
BitstreamService bitstreamService;
|
BitstreamService bitstreamService;
|
||||||
@@ -89,12 +90,14 @@ public class ResourcePolicyReplacePatchOperation extends ReplacePatchOperation<R
|
|||||||
|
|
||||||
//TODO manage error on select group and eperson
|
//TODO manage error on select group and eperson
|
||||||
Group group = null;
|
Group group = null;
|
||||||
if (newAccessCondition.getGroupUUID() != null) {
|
if (newAccessCondition.getGroup().getUuid() != null) {
|
||||||
group = groupService.find(context, newAccessCondition.getGroupUUID());
|
UUID uuidGroup = UUID.fromString(newAccessCondition.getGroup().getUuid());
|
||||||
|
group = groupService.find(context, uuidGroup);
|
||||||
}
|
}
|
||||||
EPerson eperson = null;
|
EPerson eperson = null;
|
||||||
if (newAccessCondition.getEpersonUUID() != null) {
|
if (newAccessCondition.getEperson().getUuid() != null) {
|
||||||
eperson = epersonService.find(context, newAccessCondition.getEpersonUUID());
|
UUID uuidEPerson = UUID.fromString(newAccessCondition.getEperson().getUuid());
|
||||||
|
eperson = epersonService.find(context, uuidEPerson);
|
||||||
}
|
}
|
||||||
|
|
||||||
Date startDate = newAccessCondition.getStartDate();
|
Date startDate = newAccessCondition.getStartDate();
|
@@ -27,6 +27,7 @@ import java.sql.SQLException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -37,6 +38,7 @@ import java.util.Set;
|
|||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@@ -57,7 +59,9 @@ import org.dspace.app.rest.model.VersionHistoryRest;
|
|||||||
import org.dspace.app.rest.model.hateoas.DSpaceResource;
|
import org.dspace.app.rest.model.hateoas.DSpaceResource;
|
||||||
import org.dspace.app.rest.model.hateoas.EmbeddedPage;
|
import org.dspace.app.rest.model.hateoas.EmbeddedPage;
|
||||||
import org.dspace.app.rest.model.hateoas.HALResource;
|
import org.dspace.app.rest.model.hateoas.HALResource;
|
||||||
|
import org.dspace.app.rest.projection.CompositeProjection;
|
||||||
import org.dspace.app.rest.projection.DefaultProjection;
|
import org.dspace.app.rest.projection.DefaultProjection;
|
||||||
|
import org.dspace.app.rest.projection.EmbedRelsProjection;
|
||||||
import org.dspace.app.rest.projection.Projection;
|
import org.dspace.app.rest.projection.Projection;
|
||||||
import org.dspace.app.rest.repository.DSpaceRestRepository;
|
import org.dspace.app.rest.repository.DSpaceRestRepository;
|
||||||
import org.dspace.app.rest.repository.LinkRestRepository;
|
import org.dspace.app.rest.repository.LinkRestRepository;
|
||||||
@@ -99,7 +103,7 @@ public class Utils {
|
|||||||
/**
|
/**
|
||||||
* The maximum number of embed levels to allow.
|
* The maximum number of embed levels to allow.
|
||||||
*/
|
*/
|
||||||
private static final int EMBED_MAX_LEVELS = 2;
|
private static final int EMBED_MAX_LEVELS = 10;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
ApplicationContext applicationContext;
|
ApplicationContext applicationContext;
|
||||||
@@ -443,28 +447,87 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the projection requested by the current servlet request, or {@link DefaultProjection} if none
|
* Gets the effective projection requested by the current servlet request, or {@link DefaultProjection} if none
|
||||||
* is specified.
|
* is specified.
|
||||||
|
* <p>
|
||||||
|
* Any number of individual {@code Projections} that are spring-registered {@link Component}s may be specified
|
||||||
|
* by name via the {@code projection} parameter. If multiple projections are specified, they will be wrapped in a
|
||||||
|
* {@link CompositeProjection} and applied in order as described there.
|
||||||
|
* </p><p>
|
||||||
|
* In addition, any number of embeds may be specified by rel name via the {@code embed} parameter.
|
||||||
|
* When provided, these act as a whitelist of embeds that may be included in the response, as described
|
||||||
|
* and implemented by {@link EmbedRelsProjection}.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @return the requested or default projection, never {@code null}.
|
* @return the requested or default projection, never {@code null}.
|
||||||
* @throws IllegalArgumentException if the request specifies an unknown projection name.
|
* @throws IllegalArgumentException if the request specifies an unknown projection name.
|
||||||
*/
|
*/
|
||||||
public Projection obtainProjection() {
|
public Projection obtainProjection() {
|
||||||
String projectionName = requestService.getCurrentRequest().getServletRequest().getParameter("projection");
|
ServletRequest servletRequest = requestService.getCurrentRequest().getServletRequest();
|
||||||
return converter.getProjection(projectionName);
|
List<String> projectionNames = getValues(servletRequest, "projection");
|
||||||
|
Set<String> embedRels = new HashSet<>(getValues(servletRequest, "embed"));
|
||||||
|
|
||||||
|
List<Projection> projections = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String projectionName : projectionNames) {
|
||||||
|
projections.add(converter.getProjection(projectionName));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!embedRels.isEmpty()) {
|
||||||
|
projections.add(new EmbedRelsProjection(embedRels));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (projections.isEmpty()) {
|
||||||
|
return Projection.DEFAULT;
|
||||||
|
} else if (projections.size() == 1) {
|
||||||
|
return projections.get(0);
|
||||||
|
} else {
|
||||||
|
return new CompositeProjection(projections);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets zero or more values for the given servlet request parameter.
|
||||||
|
* <p>
|
||||||
|
* This convenience method reads multiple values that have been specified as request parameter in multiple ways:
|
||||||
|
* via * {@code ?paramName=value1¶mName=value2}, via {@code ?paramName=value1,value2},
|
||||||
|
* or a combination.
|
||||||
|
* </p><p>
|
||||||
|
* It provides the values in the order they were given in the request, and automatically de-dupes them.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param servletRequest the servlet request.
|
||||||
|
* @param parameterName the parameter name.
|
||||||
|
* @return the ordered, de-duped values, possibly empty, never {@code null}.
|
||||||
|
*/
|
||||||
|
private List<String> getValues(ServletRequest servletRequest, String parameterName) {
|
||||||
|
String[] rawValues = servletRequest.getParameterValues(parameterName);
|
||||||
|
List<String> values = new ArrayList<>();
|
||||||
|
if (rawValues != null) {
|
||||||
|
for (String rawValue : rawValues) {
|
||||||
|
for (String value : rawValue.split(",")) {
|
||||||
|
String trimmedValue = value.trim();
|
||||||
|
if (trimmedValue.length() > 0 && !values.contains(trimmedValue)) {
|
||||||
|
values.add(trimmedValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds embeds or links for all class-level LinkRel annotations for which embeds or links are allowed.
|
* Adds embeds or links for all class-level LinkRel annotations for which embeds or links are allowed.
|
||||||
*
|
*
|
||||||
* @param halResource the resource.
|
* @param halResource the resource.
|
||||||
|
* @param oldLinks previously traversed links
|
||||||
*/
|
*/
|
||||||
public void embedOrLinkClassLevelRels(HALResource<RestAddressableModel> halResource) {
|
public void embedOrLinkClassLevelRels(HALResource<RestAddressableModel> halResource, Link... oldLinks) {
|
||||||
Projection projection = halResource.getContent().getProjection();
|
Projection projection = halResource.getContent().getProjection();
|
||||||
getLinkRests(halResource.getContent().getClass()).stream().forEach((linkRest) -> {
|
getLinkRests(halResource.getContent().getClass()).stream().forEach((linkRest) -> {
|
||||||
Link link = linkToSubResource(halResource.getContent(), linkRest.name());
|
Link link = linkToSubResource(halResource.getContent(), linkRest.name());
|
||||||
if (projection.allowEmbedding(halResource, linkRest)) {
|
if (projection.allowEmbedding(halResource, linkRest, oldLinks)) {
|
||||||
embedRelFromRepository(halResource, linkRest.name(), link, linkRest);
|
embedRelFromRepository(halResource, linkRest.name(), link, linkRest, oldLinks);
|
||||||
halResource.add(link); // unconditionally link if embedding was allowed
|
halResource.add(link); // unconditionally link if embedding was allowed
|
||||||
} else if (projection.allowLinking(halResource, linkRest)) {
|
} else if (projection.allowLinking(halResource, linkRest)) {
|
||||||
halResource.add(link);
|
halResource.add(link);
|
||||||
@@ -503,6 +566,32 @@ public class Utils {
|
|||||||
*/
|
*/
|
||||||
void embedRelFromRepository(HALResource<? extends RestAddressableModel> resource,
|
void embedRelFromRepository(HALResource<? extends RestAddressableModel> resource,
|
||||||
String rel, Link link, LinkRest linkRest) {
|
String rel, Link link, LinkRest linkRest) {
|
||||||
|
embedRelFromRepository(resource, rel, link, linkRest, new Link[] {});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Embeds a rel whose value comes from a {@link LinkRestRepository}, if the maximum embed level has not
|
||||||
|
* been exceeded yet.
|
||||||
|
* <p>
|
||||||
|
* The embed will be skipped if 1) the link repository reports that it is not embeddable or 2) the returned
|
||||||
|
* value is null and the LinkRest annotation has embedOptional = true.
|
||||||
|
* </p><p>
|
||||||
|
* Implementation note: The caller is responsible for ensuring that the projection allows the embed
|
||||||
|
* before calling this method.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param resource the resource from which the embed will be made.
|
||||||
|
* @param rel the name of the rel.
|
||||||
|
* @param link the link.
|
||||||
|
* @param linkRest the LinkRest annotation (must have method defined).
|
||||||
|
* @param oldLinks The previously traversed links
|
||||||
|
* @throws RepositoryNotFoundException if the link repository could not be found.
|
||||||
|
* @throws IllegalArgumentException if the method specified by the LinkRest could not be found in the
|
||||||
|
* link repository.
|
||||||
|
* @throws RuntimeException if any other problem occurs when trying to invoke the method.
|
||||||
|
*/
|
||||||
|
void embedRelFromRepository(HALResource<? extends RestAddressableModel> resource,
|
||||||
|
String rel, Link link, LinkRest linkRest, Link... oldLinks) {
|
||||||
if (resource.getContent().getEmbedLevel() == EMBED_MAX_LEVELS) {
|
if (resource.getContent().getEmbedLevel() == EMBED_MAX_LEVELS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -514,7 +603,7 @@ public class Utils {
|
|||||||
Object contentId = getContentIdForLinkMethod(resource.getContent(), method);
|
Object contentId = getContentIdForLinkMethod(resource.getContent(), method);
|
||||||
try {
|
try {
|
||||||
Object linkedObject = method.invoke(linkRepository, null, contentId, null, projection);
|
Object linkedObject = method.invoke(linkRepository, null, contentId, null, projection);
|
||||||
resource.embedResource(rel, wrapForEmbedding(resource, linkedObject, link));
|
resource.embedResource(rel, wrapForEmbedding(resource, linkedObject, link, oldLinks));
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
if (e.getTargetException() instanceof RuntimeException) {
|
if (e.getTargetException() instanceof RuntimeException) {
|
||||||
throw (RuntimeException) e.getTargetException();
|
throw (RuntimeException) e.getTargetException();
|
||||||
@@ -619,17 +708,37 @@ public class Utils {
|
|||||||
*/
|
*/
|
||||||
private Object wrapForEmbedding(HALResource<? extends RestAddressableModel> resource,
|
private Object wrapForEmbedding(HALResource<? extends RestAddressableModel> resource,
|
||||||
Object linkedObject, Link link) {
|
Object linkedObject, Link link) {
|
||||||
|
return wrapForEmbedding(resource, linkedObject, link, new Link[] {});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the given linked object (retrieved from a link repository or link method on the rest item)
|
||||||
|
* in an object that is appropriate for embedding, if needed. Does not perform the actual embed; the
|
||||||
|
* caller is responsible for that.
|
||||||
|
*
|
||||||
|
* @param resource the resource from which the embed will be made.
|
||||||
|
* @param linkedObject the linked object.
|
||||||
|
* @param link the link, which is used if the linked object is a list or page, to determine the self link
|
||||||
|
* and embed property name to use for the subresource.
|
||||||
|
* @param oldLinks The previously traversed links
|
||||||
|
* @return the wrapped object, which will have an "embed level" one greater than the given parent resource.
|
||||||
|
*/
|
||||||
|
private Object wrapForEmbedding(HALResource<? extends RestAddressableModel> resource,
|
||||||
|
Object linkedObject, Link link, Link... oldLinks) {
|
||||||
int childEmbedLevel = resource.getContent().getEmbedLevel() + 1;
|
int childEmbedLevel = resource.getContent().getEmbedLevel() + 1;
|
||||||
|
//Add the latest link to the list
|
||||||
|
Link[] newList = Arrays.copyOf(oldLinks, oldLinks.length + 1);
|
||||||
|
newList[oldLinks.length] = link;
|
||||||
if (linkedObject instanceof RestAddressableModel) {
|
if (linkedObject instanceof RestAddressableModel) {
|
||||||
RestAddressableModel restObject = (RestAddressableModel) linkedObject;
|
RestAddressableModel restObject = (RestAddressableModel) linkedObject;
|
||||||
restObject.setEmbedLevel(childEmbedLevel);
|
restObject.setEmbedLevel(childEmbedLevel);
|
||||||
return converter.toResource(restObject);
|
return converter.toResource(restObject, newList);
|
||||||
} else if (linkedObject instanceof Page) {
|
} else if (linkedObject instanceof Page) {
|
||||||
// The first page has already been constructed by a link repository and we only need to wrap it
|
// The first page has already been constructed by a link repository and we only need to wrap it
|
||||||
Page<RestAddressableModel> page = (Page<RestAddressableModel>) linkedObject;
|
Page<RestAddressableModel> page = (Page<RestAddressableModel>) linkedObject;
|
||||||
return new EmbeddedPage(link.getHref(), page.map((restObject) -> {
|
return new EmbeddedPage(link.getHref(), page.map((restObject) -> {
|
||||||
restObject.setEmbedLevel(childEmbedLevel);
|
restObject.setEmbedLevel(childEmbedLevel);
|
||||||
return converter.toResource(restObject);
|
return converter.toResource(restObject, newList);
|
||||||
}), null, link.getRel());
|
}), null, link.getRel());
|
||||||
} else if (linkedObject instanceof List) {
|
} else if (linkedObject instanceof List) {
|
||||||
// The full list has been retrieved and we need to provide the first page for embedding
|
// The full list has been retrieved and we need to provide the first page for embedding
|
||||||
@@ -641,7 +750,7 @@ public class Utils {
|
|||||||
return new EmbeddedPage(link.getHref(),
|
return new EmbeddedPage(link.getHref(),
|
||||||
page.map((restObject) -> {
|
page.map((restObject) -> {
|
||||||
restObject.setEmbedLevel(childEmbedLevel);
|
restObject.setEmbedLevel(childEmbedLevel);
|
||||||
return converter.toResource(restObject);
|
return converter.toResource(restObject, newList);
|
||||||
}),
|
}),
|
||||||
list, link.getRel());
|
list, link.getRel());
|
||||||
} else {
|
} else {
|
||||||
|
@@ -50,7 +50,7 @@
|
|||||||
</entry>
|
</entry>
|
||||||
<entry key="accessConditions">
|
<entry key="accessConditions">
|
||||||
<bean
|
<bean
|
||||||
class="org.dspace.app.rest.submit.factory.impl.ResourcePolicyAddPatchOperation"/>
|
class="org.dspace.app.rest.submit.factory.impl.BitstreamResourcePolicyAddPatchOperation"/>
|
||||||
</entry>
|
</entry>
|
||||||
</map>
|
</map>
|
||||||
</entry>
|
</entry>
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
</entry>
|
</entry>
|
||||||
<entry key="accessConditions">
|
<entry key="accessConditions">
|
||||||
<bean
|
<bean
|
||||||
class="org.dspace.app.rest.submit.factory.impl.ResourcePolicyRemovePatchOperation"/>
|
class="org.dspace.app.rest.submit.factory.impl.BitstreamResourcePolicyRemovePatchOperation"/>
|
||||||
</entry>
|
</entry>
|
||||||
</map>
|
</map>
|
||||||
</entry>
|
</entry>
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
</entry>
|
</entry>
|
||||||
<entry key="accessConditions">
|
<entry key="accessConditions">
|
||||||
<bean
|
<bean
|
||||||
class="org.dspace.app.rest.submit.factory.impl.ResourcePolicyReplacePatchOperation"/>
|
class="org.dspace.app.rest.submit.factory.impl.BitstreamResourcePolicyReplacePatchOperation"/>
|
||||||
</entry>
|
</entry>
|
||||||
<entry key="collection">
|
<entry key="collection">
|
||||||
<bean
|
<bean
|
||||||
|
@@ -57,6 +57,7 @@ import org.apache.solr.client.solrj.SolrServerException;
|
|||||||
import org.dspace.app.rest.builder.BitstreamBuilder;
|
import org.dspace.app.rest.builder.BitstreamBuilder;
|
||||||
import org.dspace.app.rest.builder.CollectionBuilder;
|
import org.dspace.app.rest.builder.CollectionBuilder;
|
||||||
import org.dspace.app.rest.builder.CommunityBuilder;
|
import org.dspace.app.rest.builder.CommunityBuilder;
|
||||||
|
import org.dspace.app.rest.builder.EPersonBuilder;
|
||||||
import org.dspace.app.rest.builder.GroupBuilder;
|
import org.dspace.app.rest.builder.GroupBuilder;
|
||||||
import org.dspace.app.rest.builder.ItemBuilder;
|
import org.dspace.app.rest.builder.ItemBuilder;
|
||||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||||
@@ -70,6 +71,7 @@ import org.dspace.content.service.BitstreamFormatService;
|
|||||||
import org.dspace.content.service.BitstreamService;
|
import org.dspace.content.service.BitstreamService;
|
||||||
import org.dspace.core.Constants;
|
import org.dspace.core.Constants;
|
||||||
import org.dspace.disseminate.CitationDocumentServiceImpl;
|
import org.dspace.disseminate.CitationDocumentServiceImpl;
|
||||||
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.eperson.Group;
|
import org.dspace.eperson.Group;
|
||||||
import org.dspace.services.ConfigurationService;
|
import org.dspace.services.ConfigurationService;
|
||||||
import org.dspace.statistics.ObjectCount;
|
import org.dspace.statistics.ObjectCount;
|
||||||
@@ -341,6 +343,184 @@ public class BitstreamRestControllerIT extends AbstractControllerIntegrationTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void embargoedBitstreamForbiddenTest() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity)
|
||||||
|
.withName("Collection 1")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// a public item with an embargoed bitstream
|
||||||
|
String bitstreamContent = "Embargoed!";
|
||||||
|
|
||||||
|
try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) {
|
||||||
|
|
||||||
|
Item publicItem1 = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("Public item 1")
|
||||||
|
.withIssueDate("2017-10-17")
|
||||||
|
.withAuthor("Smith, Donald")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
bitstream = BitstreamBuilder
|
||||||
|
.createBitstream(context, publicItem1, is)
|
||||||
|
.withName("Test Embargoed Bitstream")
|
||||||
|
.withDescription("This bitstream is embargoed")
|
||||||
|
.withMimeType("text/plain")
|
||||||
|
.withEmbargoPeriod("3 months")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
String authToken = getAuthToken(eperson.getEmail(), password);
|
||||||
|
getClient(authToken).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isUnauthorized());
|
||||||
|
|
||||||
|
checkNumberOfStatsRecords(bitstream, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void expiredEmbargoedBitstreamTest() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity)
|
||||||
|
.withName("Collection 1")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
String bitstreamContent = "Embargoed!";
|
||||||
|
|
||||||
|
try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) {
|
||||||
|
|
||||||
|
Item publicItem1 = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("Public item 1")
|
||||||
|
.withIssueDate("2015-10-17")
|
||||||
|
.withAuthor("Smith, Donald")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Bitstream bitstream = BitstreamBuilder
|
||||||
|
.createBitstream(context, publicItem1, is)
|
||||||
|
.withName("Test Embargoed Bitstream")
|
||||||
|
.withDescription("This bitstream is embargoed")
|
||||||
|
.withMimeType("text/plain")
|
||||||
|
.withEmbargoPeriod("-3 months")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
// all are allowed access to item with embargoed expired
|
||||||
|
|
||||||
|
String authToken = getAuthToken(eperson.getEmail(), password);
|
||||||
|
getClient(authToken).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
checkNumberOfStatsRecords(bitstream, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void embargoedBitstreamAccessGrantByAdminsTest() throws Exception {
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson adminParentCommunity = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("adminCommunity@mail.com")
|
||||||
|
.withPassword("qwerty02")
|
||||||
|
.build();
|
||||||
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.withAdminGroup(adminParentCommunity)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
|
||||||
|
.withName("Sub Community")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
EPerson adminChild2 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("adminChil2@mail.com")
|
||||||
|
.withPassword("qwerty05")
|
||||||
|
.build();
|
||||||
|
Community child2 = CommunityBuilder.createSubCommunity(context, parentCommunity)
|
||||||
|
.withName("Sub Community 2")
|
||||||
|
.withAdminGroup(adminChild2)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
EPerson adminCollection1 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("adminCollection1@mail.com")
|
||||||
|
.withPassword("qwerty03")
|
||||||
|
.build();
|
||||||
|
Collection col1 = CollectionBuilder.createCollection(context, child1)
|
||||||
|
.withName("Collection 1")
|
||||||
|
.withAdminGroup(adminCollection1)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
EPerson adminCollection2 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("adminCol2@mail.com")
|
||||||
|
.withPassword("qwerty01")
|
||||||
|
.build();
|
||||||
|
Collection col2 = CollectionBuilder.createCollection(context, child1)
|
||||||
|
.withName("Collection 2")
|
||||||
|
.withAdminGroup(adminCollection2)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
String bitstreamContent = "Embargoed!";
|
||||||
|
Bitstream bitstream = null;
|
||||||
|
try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) {
|
||||||
|
|
||||||
|
Item item = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("Test")
|
||||||
|
.withIssueDate("2018-10-18")
|
||||||
|
.withAuthor("Smith, Donald")
|
||||||
|
.withSubject("ExtraEntry")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
bitstream = BitstreamBuilder.createBitstream(context, item, is)
|
||||||
|
.withName("Bitstream")
|
||||||
|
.withDescription("Description")
|
||||||
|
.withMimeType("text/plain")
|
||||||
|
.withEmbargoPeriod("2 week")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
// parent community's admin user is allowed access to embargoed item
|
||||||
|
String tokenAdminParentCommunity = getAuthToken(adminParentCommunity.getEmail(), "qwerty02");
|
||||||
|
getClient(tokenAdminParentCommunity).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
// collection1's admin user is allowed access to embargoed item
|
||||||
|
String tokenAdminCollection1 = getAuthToken(adminCollection1.getEmail(), "qwerty03");
|
||||||
|
getClient(tokenAdminCollection1).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
checkNumberOfStatsRecords(bitstream, 2);
|
||||||
|
|
||||||
|
// admin of second collection is NOT allowed access to embargoed item of first collection
|
||||||
|
String tokenAdminCollection2 = getAuthToken(adminCollection2.getEmail(), "qwerty01");
|
||||||
|
getClient(tokenAdminCollection2).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
// admin of child2 community is NOT allowed access to embargoed item of first collection
|
||||||
|
String tokenAdminChild2 = getAuthToken(adminChild2.getEmail(), "qwerty05");
|
||||||
|
getClient(tokenAdminCollection2).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
checkNumberOfStatsRecords(bitstream, 2);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPrivateBitstream() throws Exception {
|
public void testPrivateBitstream() throws Exception {
|
||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
@@ -388,6 +568,153 @@ public class BitstreamRestControllerIT extends AbstractControllerIntegrationTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void restrictedGroupBitstreamForbiddenTest() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson eperson2 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("eperson2@mail.com")
|
||||||
|
.withPassword("qwerty02")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity)
|
||||||
|
.withName("Collection 1")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Group restrictedGroup = GroupBuilder.createGroup(context)
|
||||||
|
.withName("Restricted Group")
|
||||||
|
.addMember(eperson)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
String bitstreamContent = "Private!";
|
||||||
|
try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) {
|
||||||
|
|
||||||
|
Item item = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("item 1")
|
||||||
|
.withIssueDate("2013-01-17")
|
||||||
|
.withAuthor("Doe, John")
|
||||||
|
.build();
|
||||||
|
bitstream = BitstreamBuilder
|
||||||
|
.createBitstream(context, item, is)
|
||||||
|
.withName("Test Embargoed Bitstream")
|
||||||
|
.withDescription("This bitstream is embargoed")
|
||||||
|
.withMimeType("text/plain")
|
||||||
|
.withReaderGroup(restrictedGroup)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
// download the bitstream
|
||||||
|
// eperson that belong to restricted group is allowed access to the item
|
||||||
|
String authToken = getAuthToken(eperson.getEmail(), password);
|
||||||
|
getClient(authToken).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
checkNumberOfStatsRecords(bitstream, 1);
|
||||||
|
|
||||||
|
String tokenEPerson2 = getAuthToken(eperson2.getEmail(), "qwerty02");
|
||||||
|
getClient(tokenEPerson2).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
// Anonymous users CANNOT access/download Bitstreams that are restricted
|
||||||
|
getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isUnauthorized());
|
||||||
|
|
||||||
|
checkNumberOfStatsRecords(bitstream, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void restrictedGroupBitstreamAccessGrantByAdminsTest() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson adminParentCommunity = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("adminCommunity@mail.com")
|
||||||
|
.withPassword("qwerty00")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.withAdminGroup(adminParentCommunity)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
EPerson adminChild1 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("adminChild1@mail.com")
|
||||||
|
.withPassword("qwerty05")
|
||||||
|
.build();
|
||||||
|
Community child1 = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Sub Community")
|
||||||
|
.withAdminGroup(adminChild1)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
EPerson adminCol1 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("admin1@mail.com")
|
||||||
|
.withPassword("qwerty01")
|
||||||
|
.build();
|
||||||
|
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity)
|
||||||
|
.withName("Collection 1")
|
||||||
|
.withAdminGroup(adminCol1)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
EPerson adminCol2 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("admin2@mail.com")
|
||||||
|
.withPassword("qwerty02")
|
||||||
|
.build();
|
||||||
|
Collection col2 = CollectionBuilder.createCollection(context, parentCommunity)
|
||||||
|
.withName("Collection 2")
|
||||||
|
.withAdminGroup(adminCol2)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Group restrictedGroup = GroupBuilder.createGroup(context)
|
||||||
|
.withName("Restricted Group")
|
||||||
|
.addMember(eperson)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
String bitstreamContent = "Private!";
|
||||||
|
try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) {
|
||||||
|
|
||||||
|
Item item = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("item")
|
||||||
|
.withIssueDate("2018-10-17")
|
||||||
|
.withAuthor("Doe, John")
|
||||||
|
.build();
|
||||||
|
bitstream = BitstreamBuilder
|
||||||
|
.createBitstream(context, item, is)
|
||||||
|
.withName("Test Embargoed Bitstream")
|
||||||
|
.withDescription("This bitstream is embargoed")
|
||||||
|
.withMimeType("text/plain")
|
||||||
|
.withReaderGroup(restrictedGroup)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
// download the bitstream
|
||||||
|
// parent community's admin user is allowed access to the item belong restricted group
|
||||||
|
String tokenAdminParentCommuity = getAuthToken(adminParentCommunity.getEmail(), "qwerty00");
|
||||||
|
getClient(tokenAdminParentCommuity).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
// collection1's admin user is allowed access to the item belong restricted group
|
||||||
|
String tokenAdminCol1 = getAuthToken(adminCol1.getEmail(), "qwerty01");
|
||||||
|
getClient(tokenAdminCol1).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
checkNumberOfStatsRecords(bitstream, 2);
|
||||||
|
|
||||||
|
// collection2's admin user is NOT allowed access to the item belong collection1
|
||||||
|
String tokenAdminCol2 = getAuthToken(adminCol2.getEmail(), "qwerty02");
|
||||||
|
getClient(tokenAdminCol2).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
// child1's admin user is NOT allowed access to the item belong collection1
|
||||||
|
String tokenAdminChild1 = getAuthToken(adminChild1.getEmail(), "qwerty05");
|
||||||
|
getClient(tokenAdminCol2).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
checkNumberOfStatsRecords(bitstream, 2);
|
||||||
|
}
|
||||||
|
|
||||||
// Verify number of hits/views of Bitstream is as expected
|
// Verify number of hits/views of Bitstream is as expected
|
||||||
private void checkNumberOfStatsRecords(Bitstream bitstream, int expectedNumberOfStatsRecords)
|
private void checkNumberOfStatsRecords(Bitstream bitstream, int expectedNumberOfStatsRecords)
|
||||||
throws SolrServerException, IOException {
|
throws SolrServerException, IOException {
|
||||||
|
@@ -26,6 +26,7 @@ import org.dspace.app.rest.builder.CollectionBuilder;
|
|||||||
import org.dspace.app.rest.builder.CommunityBuilder;
|
import org.dspace.app.rest.builder.CommunityBuilder;
|
||||||
import org.dspace.app.rest.converter.ConverterService;
|
import org.dspace.app.rest.converter.ConverterService;
|
||||||
import org.dspace.app.rest.matcher.CollectionMatcher;
|
import org.dspace.app.rest.matcher.CollectionMatcher;
|
||||||
|
import org.dspace.app.rest.matcher.CommunityMatcher;
|
||||||
import org.dspace.app.rest.matcher.HalMatcher;
|
import org.dspace.app.rest.matcher.HalMatcher;
|
||||||
import org.dspace.app.rest.matcher.MetadataMatcher;
|
import org.dspace.app.rest.matcher.MetadataMatcher;
|
||||||
import org.dspace.app.rest.matcher.PageMatcher;
|
import org.dspace.app.rest.matcher.PageMatcher;
|
||||||
@@ -940,4 +941,132 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
|
|||||||
.andExpect(jsonPath("$.page", PageMatcher.pageEntryWithTotalPagesAndElements(0, 20,
|
.andExpect(jsonPath("$.page", PageMatcher.pageEntryWithTotalPagesAndElements(0, 20,
|
||||||
1, 2)));
|
1, 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void projectonLevelTest() 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();
|
||||||
|
Community child1child = CommunityBuilder.createSubCommunity(context, child1)
|
||||||
|
.withName("Sub Community Two")
|
||||||
|
.build();
|
||||||
|
Collection col1 = CollectionBuilder.createCollection(context, child1)
|
||||||
|
.withName("Collection 1")
|
||||||
|
.withLogo("TestingContentForLogo")
|
||||||
|
.build();
|
||||||
|
Collection col2 = CollectionBuilder.createCollection(context, child1child).withName("Collection 2").build();
|
||||||
|
|
||||||
|
getClient().perform(get("/api/core/collections/" + col1.getID())
|
||||||
|
.param("projection", "level")
|
||||||
|
.param("embedLevelDepth", "1"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", CollectionMatcher.matchCollectionEntry(col1.getName(),
|
||||||
|
col1.getID(),
|
||||||
|
col1.getHandle())))
|
||||||
|
// .exists() makes sure that the embed is there, but it could be empty
|
||||||
|
.andExpect(jsonPath("$._embedded.mappedItems").exists())
|
||||||
|
// .isEmpty() makes sure that the embed is there, but that there's no actual data
|
||||||
|
.andExpect(jsonPath("$._embedded.mappedItems._embedded.mappedItems").isEmpty())
|
||||||
|
.andExpect(jsonPath("$._embedded.parentCommunity",
|
||||||
|
CommunityMatcher.matchCommunityEntry(child1.getName(),
|
||||||
|
child1.getID(),
|
||||||
|
child1.getHandle())))
|
||||||
|
// .doesNotExist() makes sure that this section is not embedded, it's not there at all
|
||||||
|
.andExpect(jsonPath("$._embedded.parentCommunity._embedded.subcommunities").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$._embedded.logo", Matchers.not(Matchers.empty())))
|
||||||
|
// .doesNotExist() makes sure that this section is not embedded, it's not there at all
|
||||||
|
.andExpect(jsonPath("$._embedded.logo._embedded.format").doesNotExist());
|
||||||
|
|
||||||
|
getClient().perform(get("/api/core/collections/" + col1.getID())
|
||||||
|
.param("projection", "level")
|
||||||
|
.param("embedLevelDepth", "3"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", CollectionMatcher.matchCollectionEntry(col1.getName(),
|
||||||
|
col1.getID(),
|
||||||
|
col1.getHandle())))
|
||||||
|
// .exists() makes sure that the embed is there, but it could be empty
|
||||||
|
.andExpect(jsonPath("$._embedded.mappedItems").exists())
|
||||||
|
// .isEmpty() makes sure that the embed is there, but that there's no actual data
|
||||||
|
.andExpect(jsonPath("$._embedded.mappedItems._embedded.mappedItems").isEmpty())
|
||||||
|
.andExpect(jsonPath("$._embedded.parentCommunity",
|
||||||
|
CommunityMatcher.matchCommunityEntry(child1.getName(),
|
||||||
|
child1.getID(),
|
||||||
|
child1.getHandle())))
|
||||||
|
// .exists() makes sure that the embed is there, but it could be empty
|
||||||
|
.andExpect(jsonPath("$._embedded.parentCommunity._embedded.subcommunities").exists())
|
||||||
|
.andExpect(jsonPath("$._embedded.parentCommunity._embedded.subcommunities._embedded.subcommunities",
|
||||||
|
Matchers.contains(CommunityMatcher.matchCommunityEntry(child1child.getID(),
|
||||||
|
child1child.getHandle())
|
||||||
|
)))
|
||||||
|
.andExpect(jsonPath("$._embedded.parentCommunity._embedded.subcommunities" +
|
||||||
|
"._embedded.subcommunities[0]._embedded.collections._embedded.collections",
|
||||||
|
Matchers.contains(CollectionMatcher.matchCollectionEntry(col2.getName(),
|
||||||
|
col2.getID(),
|
||||||
|
col2.getHandle())
|
||||||
|
)))
|
||||||
|
// .doesNotExist() makes sure that this section is not embedded, it's not there at all
|
||||||
|
.andExpect(jsonPath("$._embedded.parentCommunity._embedded.subcommunities" +
|
||||||
|
"._embedded.subcommunities[0]._embedded.collections._embedded" +
|
||||||
|
".collections[0]._embedded.logo").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$._embedded.logo", Matchers.not(Matchers.empty())))
|
||||||
|
// .exists() makes sure that the embed is there, but it could be empty
|
||||||
|
.andExpect(jsonPath("$._embedded.logo._embedded.format").exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void projectonLevelEmbedLevelDepthHigherThanEmbedMaxBadRequestTest() 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();
|
||||||
|
Community child1child = CommunityBuilder.createSubCommunity(context, child1)
|
||||||
|
.withName("Sub Community Two")
|
||||||
|
.build();
|
||||||
|
Collection col1 = CollectionBuilder.createCollection(context, child1)
|
||||||
|
.withName("Collection 1")
|
||||||
|
.withLogo("TestingContentForLogo")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
getClient().perform(get("/api/core/collections/" + col1.getID())
|
||||||
|
.param("projection", "level")
|
||||||
|
.param("embedLevelDepth", "100"))
|
||||||
|
.andExpect(status().isBadRequest());
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void projectonLevelEmbedLevelDepthNotPresentBadRequestTest() 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();
|
||||||
|
Community child1child = CommunityBuilder.createSubCommunity(context, child1)
|
||||||
|
.withName("Sub Community Two")
|
||||||
|
.build();
|
||||||
|
Collection col1 = CollectionBuilder.createCollection(context, child1)
|
||||||
|
.withName("Collection 1")
|
||||||
|
.withLogo("TestingContentForLogo")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
getClient().perform(get("/api/core/collections/" + col1.getID())
|
||||||
|
.param("projection", "level"))
|
||||||
|
.andExpect(status().isBadRequest());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -277,8 +277,9 @@ public class ItemOwningCollectionUpdateRestControllerIT extends AbstractControll
|
|||||||
"https://localhost:8080/spring-rest/api/core/collections/" + col2.getID()
|
"https://localhost:8080/spring-rest/api/core/collections/" + col2.getID()
|
||||||
))
|
))
|
||||||
|
|
||||||
//We expect a 401 Unauthorized status when performed by anonymous
|
// we expect a 200 here as the user has ADMIN permission on the source collection and
|
||||||
.andExpect(status().isForbidden());
|
// ADD permission on the target one. This is the normal behavior also in DSpace 6
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
package org.dspace.app.rest;
|
package org.dspace.app.rest;
|
||||||
|
|
||||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
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.request.MockMvcRequestBuilders.get;
|
||||||
@@ -35,6 +36,8 @@ import org.dspace.app.rest.builder.EPersonBuilder;
|
|||||||
import org.dspace.app.rest.builder.GroupBuilder;
|
import org.dspace.app.rest.builder.GroupBuilder;
|
||||||
import org.dspace.app.rest.builder.ItemBuilder;
|
import org.dspace.app.rest.builder.ItemBuilder;
|
||||||
import org.dspace.app.rest.builder.WorkspaceItemBuilder;
|
import org.dspace.app.rest.builder.WorkspaceItemBuilder;
|
||||||
|
import org.dspace.app.rest.matcher.BitstreamMatcher;
|
||||||
|
import org.dspace.app.rest.matcher.CollectionMatcher;
|
||||||
import org.dspace.app.rest.matcher.HalMatcher;
|
import org.dspace.app.rest.matcher.HalMatcher;
|
||||||
import org.dspace.app.rest.matcher.ItemMatcher;
|
import org.dspace.app.rest.matcher.ItemMatcher;
|
||||||
import org.dspace.app.rest.matcher.MetadataMatcher;
|
import org.dspace.app.rest.matcher.MetadataMatcher;
|
||||||
@@ -50,15 +53,20 @@ import org.dspace.content.Collection;
|
|||||||
import org.dspace.content.Community;
|
import org.dspace.content.Community;
|
||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
import org.dspace.content.WorkspaceItem;
|
import org.dspace.content.WorkspaceItem;
|
||||||
|
import org.dspace.content.service.CollectionService;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.eperson.Group;
|
import org.dspace.eperson.Group;
|
||||||
import org.hamcrest.Matcher;
|
import org.hamcrest.Matcher;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.test.web.servlet.MvcResult;
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
|
|
||||||
public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
|
public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CollectionService collectionService;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void findAllTest() throws Exception {
|
public void findAllTest() throws Exception {
|
||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
@@ -251,6 +259,16 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$", HalMatcher.matchNoEmbeds()))
|
.andExpect(jsonPath("$", HalMatcher.matchNoEmbeds()))
|
||||||
.andExpect(jsonPath("$", publicItem1Matcher));
|
.andExpect(jsonPath("$", publicItem1Matcher));
|
||||||
|
|
||||||
|
// When exact embeds are requested, response should include expected properties, links, and exact embeds.
|
||||||
|
getClient().perform(get("/api/core/items/" + publicItem1.getID())
|
||||||
|
.param("embed", "bundles,owningCollection"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", HalMatcher.matchEmbeds(
|
||||||
|
"bundles[]",
|
||||||
|
"owningCollection"
|
||||||
|
)))
|
||||||
|
.andExpect(jsonPath("$", publicItem1Matcher));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1294,6 +1312,122 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void embargoAccessGrantAdminsTest() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson adminParentCommunity = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("adminCommunity@mail.com")
|
||||||
|
.withPassword("qwerty01")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.withAdminGroup(adminParentCommunity)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
|
||||||
|
.withName("Sub Community")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
EPerson adminChild2 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("adminChild2@mail.com")
|
||||||
|
.withPassword("qwerty05")
|
||||||
|
.build();
|
||||||
|
Community child2 = CommunityBuilder.createSubCommunity(context, parentCommunity)
|
||||||
|
.withName("Sub Community 2")
|
||||||
|
.withAdminGroup(adminChild2)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
EPerson adminCollection1 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("adminCollection1@mail.com")
|
||||||
|
.withPassword("qwerty02")
|
||||||
|
.build();
|
||||||
|
Collection col1 = CollectionBuilder.createCollection(context, child1)
|
||||||
|
.withName("Collection 1")
|
||||||
|
.withAdminGroup(adminCollection1)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
EPerson adminCollection2 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("adminCollection2@mail.com")
|
||||||
|
.withPassword("qwerty03")
|
||||||
|
.build();
|
||||||
|
Collection col2 = CollectionBuilder.createCollection(context, child1)
|
||||||
|
.withName("Collection 2")
|
||||||
|
.withAdminGroup(adminCollection2)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item embargoedItem = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("Public item 1")
|
||||||
|
.withIssueDate("2015-10-21")
|
||||||
|
.withAuthor("Smith, Donald")
|
||||||
|
.withSubject("ExtraEntry")
|
||||||
|
.withEmbargoPeriod("1 week")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
// parent community's admin user is allowed access to embargoed item
|
||||||
|
String tokenAdminParentCommunity = getAuthToken(adminParentCommunity.getEmail(), "qwerty01");
|
||||||
|
getClient(tokenAdminParentCommunity).perform(get("/api/core/items/" + embargoedItem.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", is(ItemMatcher.matchItemProperties(embargoedItem))));
|
||||||
|
|
||||||
|
// collection1's admin user is allowed access to embargoed item
|
||||||
|
String tokenAdminCollection1 = getAuthToken(adminCollection1.getEmail(), "qwerty02");
|
||||||
|
getClient(tokenAdminCollection1).perform(get("/api/core/items/" + embargoedItem.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", is(ItemMatcher.matchItemProperties(embargoedItem))));
|
||||||
|
|
||||||
|
// collection2's admin user is NOT allowed access to embargoed item of collection1
|
||||||
|
String tokenAdminCollection2 = getAuthToken(adminCollection2.getEmail(), "qwerty03");
|
||||||
|
getClient(tokenAdminCollection2).perform(get("/api/core/items/" + embargoedItem.getID()))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
// full admin user is allowed access to embargoed item
|
||||||
|
String tokenAdmin = getAuthToken(admin.getEmail(), password);
|
||||||
|
getClient(tokenAdmin).perform(get("/api/core/items/" + embargoedItem.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", is(ItemMatcher.matchItemProperties(embargoedItem))));
|
||||||
|
|
||||||
|
// child2's admin user is NOT allowed access to embargoed item of collection1
|
||||||
|
String tokenAdminChild2 = getAuthToken(adminChild2.getEmail(), "qwerty05");
|
||||||
|
getClient(tokenAdminChild2).perform(get("/api/core/items/" + embargoedItem.getID()))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void expiredEmbargoTest() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity)
|
||||||
|
.withName("Collection 1")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item embargoedItem = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("embargoed item 1")
|
||||||
|
.withIssueDate("2017-11-18")
|
||||||
|
.withAuthor("Smith, Donald")
|
||||||
|
.withEmbargoPeriod("-2 week")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
// all are allowed access to item with embargoed expired
|
||||||
|
|
||||||
|
String tokenEperson = getAuthToken(eperson.getEmail(), password);
|
||||||
|
getClient(tokenEperson).perform(get("/api/core/items/" + embargoedItem.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", Matchers.is(ItemMatcher.matchItemProperties(embargoedItem))));
|
||||||
|
|
||||||
|
getClient().perform(get("/api/core/items/" + embargoedItem.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", Matchers.is(ItemMatcher.matchItemProperties(embargoedItem))));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void undiscoverableAccessTest() throws Exception {
|
public void undiscoverableAccessTest() throws Exception {
|
||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
@@ -1422,6 +1556,134 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
Matchers.containsString("/api/core/items")));
|
Matchers.containsString("/api/core/items")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void restrictedGroupAccessForbiddenTest() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson memberRestrictGroup = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("eperson1@mail.com")
|
||||||
|
.withPassword("qwerty01")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Group restrictGroup = GroupBuilder.createGroup(context)
|
||||||
|
.addMember(memberRestrictGroup)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
Item itemRestrictedByGroup = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("Public item 1")
|
||||||
|
.withIssueDate("2011-11-13")
|
||||||
|
.withAuthor("Smith, Donald")
|
||||||
|
.withReaderGroup(restrictGroup)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
//A member of the restricted group is also allowed access to restricted item
|
||||||
|
String tokenMemberRestrictedGroup = getAuthToken(memberRestrictGroup.getEmail(), "qwerty01");
|
||||||
|
getClient(tokenMemberRestrictedGroup).perform(get("/api/core/items/" + itemRestrictedByGroup.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", is(ItemMatcher.matchItemProperties(itemRestrictedByGroup))));
|
||||||
|
|
||||||
|
//members who are not part of the restricted group, have no access to the item
|
||||||
|
String tokenEPerson = getAuthToken(eperson.getEmail(), password);
|
||||||
|
getClient(tokenEPerson).perform(get("/api/core/items/" + itemRestrictedByGroup.getID()))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
getClient().perform(get("/api/core/items/" + itemRestrictedByGroup.getID()))
|
||||||
|
.andExpect(status().isUnauthorized());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void restrictedGroupAccessGrantAdminsTest() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson adminParentCommunity = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("adminCommunity@mail.com")
|
||||||
|
.withPassword("qwerty01")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Group restrictedGroup = GroupBuilder.createGroup(context)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.withAdminGroup(adminParentCommunity)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
|
||||||
|
.withName("Sub Community")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
EPerson adminChild2 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("adminChild2@mail.com")
|
||||||
|
.withPassword("qwerty05")
|
||||||
|
.build();
|
||||||
|
Community child2 = CommunityBuilder.createSubCommunity(context, parentCommunity)
|
||||||
|
.withName("Sub Community 2")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
EPerson adminCollection1 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("adminCollection1@mail.com")
|
||||||
|
.withPassword("qwerty02")
|
||||||
|
.build();
|
||||||
|
Collection col1 = CollectionBuilder.createCollection(context, child1)
|
||||||
|
.withName("Collection 1")
|
||||||
|
.withAdminGroup(adminCollection1)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
EPerson adminCollection2 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("adminCollection2@mail.com")
|
||||||
|
.withPassword("qwerty03")
|
||||||
|
.build();
|
||||||
|
Collection col2 = CollectionBuilder.createCollection(context, child1)
|
||||||
|
.withName("Collection 2")
|
||||||
|
.withAdminGroup(adminCollection2)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item itemRestrictedByGroup = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("Public item 1")
|
||||||
|
.withIssueDate("2015-10-21")
|
||||||
|
.withAuthor("Smith, Donald")
|
||||||
|
.withSubject("ExtraEntry")
|
||||||
|
.withReaderGroup(restrictedGroup)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
// parent community's admin user is allowed access to restricted item
|
||||||
|
String tokenAdminParentCommunity = getAuthToken(adminParentCommunity.getEmail(), "qwerty01");
|
||||||
|
getClient(tokenAdminParentCommunity).perform(get("/api/core/items/" + itemRestrictedByGroup.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", is(ItemMatcher.matchItemProperties(itemRestrictedByGroup))));
|
||||||
|
|
||||||
|
// collection1's admin user is allowed access to restricted item
|
||||||
|
String tokenAdminCollection1 = getAuthToken(adminCollection1.getEmail(), "qwerty02");
|
||||||
|
getClient(tokenAdminCollection1).perform(get("/api/core/items/" + itemRestrictedByGroup.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", is(ItemMatcher.matchItemProperties(itemRestrictedByGroup))));
|
||||||
|
|
||||||
|
// collection2's admin user is NOT allowed access to restricted item of collection1
|
||||||
|
String tokenAdminCollection2 = getAuthToken(adminCollection2.getEmail(), "qwerty03");
|
||||||
|
getClient(tokenAdminCollection2).perform(get("/api/core/items/" + itemRestrictedByGroup.getID()))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
// child2's admin user is NOT allowed access to restricted item of collection1
|
||||||
|
String tokenAdminChild2 = getAuthToken(adminChild2.getEmail(), "qwerty05");
|
||||||
|
getClient(tokenAdminCollection2).perform(get("/api/core/items/" + itemRestrictedByGroup.getID()))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateItem() throws Exception {
|
public void testCreateItem() throws Exception {
|
||||||
|
|
||||||
@@ -2110,4 +2372,178 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
.content("https://localhost:8080/server/api/integration/externalsources/" +
|
.content("https://localhost:8080/server/api/integration/externalsources/" +
|
||||||
"mock/entryValues/one")).andExpect(status().isUnauthorized());
|
"mock/entryValues/one")).andExpect(status().isUnauthorized());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void specificEmbedTestMultipleLevelOfLinks() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
//** GIVEN **
|
||||||
|
//1. A community-collection structure with one parent community with sub-community and two collections.
|
||||||
|
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();
|
||||||
|
Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build();
|
||||||
|
|
||||||
|
//2. Three public items that are readable by Anonymous with different subjects
|
||||||
|
Item publicItem1 = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("Public item 1")
|
||||||
|
.withIssueDate("2017-10-17")
|
||||||
|
.withAuthor("Smith, Donald").withAuthor("Doe, John")
|
||||||
|
.withSubject("ExtraEntry")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item publicItem2 = ItemBuilder.createItem(context, col2)
|
||||||
|
.withTitle("Public item 2")
|
||||||
|
.withIssueDate("2016-02-13")
|
||||||
|
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||||
|
.withSubject("TestingForMore").withSubject("ExtraEntry")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item publicItem3 = ItemBuilder.createItem(context, col2)
|
||||||
|
.withTitle("Public item 3")
|
||||||
|
.withIssueDate("2016-02-13")
|
||||||
|
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||||
|
.withSubject("AnotherTest").withSubject("TestingForMore")
|
||||||
|
.withSubject("ExtraEntry")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
//Add a bitstream to an item
|
||||||
|
String bitstreamContent = "ThisIsSomeDummyText";
|
||||||
|
Bitstream bitstream1 = null;
|
||||||
|
try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) {
|
||||||
|
bitstream1 = BitstreamBuilder.
|
||||||
|
createBitstream(context, publicItem1, is)
|
||||||
|
.withName("Bitstream1")
|
||||||
|
.withMimeType("text/plain")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
getClient().perform(get("/api/core/items/" + publicItem1.getID() +
|
||||||
|
"?embed=owningCollection/mappedItems/bundles/" +
|
||||||
|
"bitstreams&embed=owningCollection/logo"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", ItemMatcher.matchItemProperties(publicItem1)))
|
||||||
|
.andExpect(jsonPath("$._embedded.owningCollection",
|
||||||
|
CollectionMatcher.matchCollectionEntry(col1.getName(),
|
||||||
|
col1.getID(),
|
||||||
|
col1.getHandle())))
|
||||||
|
// .doesNotExist() makes sure that this section is not embedded, it's not there at all
|
||||||
|
.andExpect(jsonPath("$._embedded.bundles").doesNotExist())
|
||||||
|
// .doesNotExist() makes sure that this section is not embedded, it's not there at all
|
||||||
|
.andExpect(jsonPath("$._embedded.relationships").doesNotExist())
|
||||||
|
// .doesNotExist() makes sure that this section is not embedded, it's not there at all
|
||||||
|
.andExpect(jsonPath("$._embedded.owningCollection._embedded.defaultAccessConditions")
|
||||||
|
.doesNotExist())
|
||||||
|
// .nullValue() makes sure that it could be embedded, it's just null in this case
|
||||||
|
.andExpect(jsonPath("$._embedded.owningCollection._embedded.logo", Matchers.nullValue()))
|
||||||
|
// .empty() makes sure that the embed is there, but that there's no actual data
|
||||||
|
.andExpect(jsonPath("$._embedded.owningCollection._embedded.mappedItems._embedded.mappedItems",
|
||||||
|
Matchers.empty()))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void specificEmbedTestMultipleLevelOfLinksWithData() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
//** GIVEN **
|
||||||
|
//1. A community-collection structure with one parent community with sub-community and two collections.
|
||||||
|
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")
|
||||||
|
.withLogo("TestingContentForLogo").build();
|
||||||
|
Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build();
|
||||||
|
|
||||||
|
//2. Three public items that are readable by Anonymous with different subjects
|
||||||
|
Item publicItem1 = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("Public item 1")
|
||||||
|
.withIssueDate("2017-10-17")
|
||||||
|
.withAuthor("Smith, Donald").withAuthor("Doe, John")
|
||||||
|
.withSubject("ExtraEntry")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item publicItem2 = ItemBuilder.createItem(context, col2)
|
||||||
|
.withTitle("Public item 2")
|
||||||
|
.withIssueDate("2016-02-13")
|
||||||
|
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||||
|
.withSubject("TestingForMore").withSubject("ExtraEntry")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item publicItem3 = ItemBuilder.createItem(context, col2)
|
||||||
|
.withTitle("Public item 3")
|
||||||
|
.withIssueDate("2016-02-13")
|
||||||
|
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||||
|
.withSubject("AnotherTest").withSubject("TestingForMore")
|
||||||
|
.withSubject("ExtraEntry")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
collectionService.addItem(context, col1, publicItem2);
|
||||||
|
|
||||||
|
//Add a bitstream to an item
|
||||||
|
String bitstreamContent = "ThisIsSomeDummyText";
|
||||||
|
Bitstream bitstream1 = null;
|
||||||
|
try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) {
|
||||||
|
bitstream1 = BitstreamBuilder.
|
||||||
|
createBitstream(context, publicItem1, is)
|
||||||
|
.withName("Bitstream1")
|
||||||
|
.withMimeType("text/plain")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
String bitstreamContent2 = "ThisIsSomeDummyText";
|
||||||
|
Bitstream bitstream2 = null;
|
||||||
|
try (InputStream is = IOUtils.toInputStream(bitstreamContent2, CharEncoding.UTF_8)) {
|
||||||
|
bitstream2 = BitstreamBuilder.
|
||||||
|
createBitstream(context, publicItem2, is)
|
||||||
|
.withName("Bitstream2")
|
||||||
|
.withMimeType("text/plain")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
getClient().perform(get("/api/core/items/" + publicItem1.getID() +
|
||||||
|
"?embed=owningCollection/mappedItems/bundles/" +
|
||||||
|
"bitstreams&embed=owningCollection/logo"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", ItemMatcher.matchItemProperties(publicItem1)))
|
||||||
|
.andExpect(jsonPath("$._embedded.owningCollection",
|
||||||
|
CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(),
|
||||||
|
col1.getHandle())))
|
||||||
|
// .doesNotExist() makes sure that this section is not embedded, it's not there at all
|
||||||
|
.andExpect(jsonPath("$._embedded.bundles").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$._embedded.relationships").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$._embedded.owningCollection._embedded.defaultAccessConditions")
|
||||||
|
.doesNotExist())
|
||||||
|
// .notNullValue() makes sure that it's there and that it does actually contain a value, but not null
|
||||||
|
.andExpect(jsonPath("$._embedded.owningCollection._embedded.logo", Matchers.notNullValue()))
|
||||||
|
.andExpect(jsonPath("$._embedded.owningCollection._embedded.logo._embedded").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$._embedded.owningCollection._embedded.mappedItems._embedded.mappedItems",
|
||||||
|
Matchers.contains(ItemMatcher.matchItemProperties(publicItem2))))
|
||||||
|
.andExpect(jsonPath("$._embedded.owningCollection._embedded.mappedItems._embedded" +
|
||||||
|
".mappedItems[0]._embedded.bundles._embedded.bundles[0]._embedded" +
|
||||||
|
".bitstreams._embedded.bitstreams", Matchers.contains(
|
||||||
|
BitstreamMatcher.matchBitstreamEntryWithoutEmbed(bitstream2.getID(), bitstream2.getSizeBytes())
|
||||||
|
)))
|
||||||
|
.andExpect(jsonPath("$._embedded.owningCollection._embedded.mappedItems." +
|
||||||
|
"_embedded.mappedItems[0]_embedded.relationships").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$._embedded.owningCollection._embedded.mappedItems" +
|
||||||
|
"._embedded.mappedItems[0]._embedded.bundles._embedded.bundles[0]." +
|
||||||
|
"_embedded.primaryBitstream").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$._embedded.owningCollection._embedded.mappedItems." +
|
||||||
|
"_embedded.mappedItems[0]._embedded.bundles._embedded.bundles[0]." +
|
||||||
|
"_embedded.bitstreams._embedded.bitstreams[0]._embedded.format")
|
||||||
|
.doesNotExist())
|
||||||
|
;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,18 +27,24 @@ import org.dspace.app.rest.builder.WorkflowItemBuilder;
|
|||||||
import org.dspace.app.rest.matcher.ClaimedTaskMatcher;
|
import org.dspace.app.rest.matcher.ClaimedTaskMatcher;
|
||||||
import org.dspace.app.rest.matcher.EPersonMatcher;
|
import org.dspace.app.rest.matcher.EPersonMatcher;
|
||||||
import org.dspace.app.rest.matcher.PoolTaskMatcher;
|
import org.dspace.app.rest.matcher.PoolTaskMatcher;
|
||||||
|
import org.dspace.app.rest.matcher.WorkflowActionMatcher;
|
||||||
import org.dspace.app.rest.matcher.WorkflowItemMatcher;
|
import org.dspace.app.rest.matcher.WorkflowItemMatcher;
|
||||||
|
import org.dspace.app.rest.matcher.WorkflowStepMatcher;
|
||||||
import org.dspace.app.rest.matcher.WorkspaceItemMatcher;
|
import org.dspace.app.rest.matcher.WorkspaceItemMatcher;
|
||||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||||
import org.dspace.content.Collection;
|
import org.dspace.content.Collection;
|
||||||
import org.dspace.content.Community;
|
import org.dspace.content.Community;
|
||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
|
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
||||||
|
import org.dspace.xmlworkflow.state.Step;
|
||||||
|
import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig;
|
||||||
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
||||||
import org.dspace.xmlworkflow.storedcomponents.PoolTask;
|
import org.dspace.xmlworkflow.storedcomponents.PoolTask;
|
||||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,6 +55,10 @@ import org.springframework.http.MediaType;
|
|||||||
*/
|
*/
|
||||||
public class TaskRestRepositoriesIT extends AbstractControllerIntegrationTest {
|
public class TaskRestRepositoriesIT extends AbstractControllerIntegrationTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private XmlWorkflowFactory xmlWorkflowFactory;
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
/**
|
/**
|
||||||
* Retrieve a specific pooltask
|
* Retrieve a specific pooltask
|
||||||
@@ -1799,13 +1809,15 @@ public class TaskRestRepositoriesIT extends AbstractControllerIntegrationTest {
|
|||||||
|
|
||||||
AtomicReference<Integer> idRef = new AtomicReference<Integer>();
|
AtomicReference<Integer> idRef = new AtomicReference<Integer>();
|
||||||
|
|
||||||
|
Step step = xmlWorkflowFactory.getStepByName("reviewstep");
|
||||||
// step 1
|
// step 1
|
||||||
getClient(reviewer1Token).perform(get("/api/workflow/pooltasks/search/findByUser")
|
getClient(reviewer1Token).perform(get("/api/workflow/pooltasks/search/findByUser")
|
||||||
.param("uuid", reviewer1.getID().toString()))
|
.param("uuid", reviewer1.getID().toString()).param("projection", "full"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains(
|
.andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains(
|
||||||
Matchers.allOf(
|
Matchers.allOf(
|
||||||
Matchers.is(PoolTaskMatcher.matchPoolTask(null, "reviewstep")),
|
Matchers.is(PoolTaskMatcher.matchPoolTask(null, "reviewstep")),
|
||||||
|
hasJsonPath("$._embedded.step", WorkflowStepMatcher.matchWorkflowStepEntry(step)),
|
||||||
hasJsonPath("$._embedded.workflowitem",
|
hasJsonPath("$._embedded.workflowitem",
|
||||||
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
||||||
witem, "Test item full workflow", "2019-03-06", "ExtraEntry")))
|
witem, "Test item full workflow", "2019-03-06", "ExtraEntry")))
|
||||||
@@ -1821,17 +1833,22 @@ public class TaskRestRepositoriesIT extends AbstractControllerIntegrationTest {
|
|||||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
|
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
|
||||||
.andExpect(status().isNoContent());
|
.andExpect(status().isNoContent());
|
||||||
|
|
||||||
|
WorkflowActionConfig workflowAction = xmlWorkflowFactory.getActionByName("reviewaction");
|
||||||
|
|
||||||
// get the id of the claimed task
|
// get the id of the claimed task
|
||||||
getClient(reviewer1Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
getClient(reviewer1Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
.param("uuid", reviewer1.getID().toString()))
|
.param("uuid", reviewer1.getID().toString()).param("projection", "full"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$._embedded.claimedtasks", Matchers.contains(
|
.andExpect(jsonPath("$._embedded.claimedtasks", Matchers.contains(
|
||||||
Matchers.allOf(
|
Matchers.allOf(
|
||||||
hasJsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks/")),
|
hasJsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks/")),
|
||||||
hasJsonPath("$.type", Matchers.is("claimedtask")),
|
hasJsonPath("$.type", Matchers.is("claimedtask")),
|
||||||
|
hasJsonPath("$._embedded.step", WorkflowStepMatcher.matchWorkflowStepEntry(step)),
|
||||||
hasJsonPath("$._embedded.workflowitem",
|
hasJsonPath("$._embedded.workflowitem",
|
||||||
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
||||||
witem, "Test item full workflow", "2019-03-06", "ExtraEntry")))
|
witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))),
|
||||||
|
hasJsonPath("$._embedded.action",
|
||||||
|
WorkflowActionMatcher.matchWorkflowActionEntry(workflowAction))
|
||||||
))))
|
))))
|
||||||
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
.andExpect(jsonPath("$.page.size", is(20)))
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
@@ -1850,13 +1867,16 @@ public class TaskRestRepositoriesIT extends AbstractControllerIntegrationTest {
|
|||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$.inArchive", is(false)));
|
.andExpect(jsonPath("$.inArchive", is(false)));
|
||||||
|
|
||||||
|
step = xmlWorkflowFactory.getStepByName("editstep");
|
||||||
|
|
||||||
// step 2
|
// step 2
|
||||||
getClient(reviewer2Token).perform(get("/api/workflow/pooltasks/search/findByUser")
|
getClient(reviewer2Token).perform(get("/api/workflow/pooltasks/search/findByUser")
|
||||||
.param("uuid", reviewer2.getID().toString()))
|
.param("uuid", reviewer2.getID().toString()).param("projection", "full"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains(
|
.andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains(
|
||||||
Matchers.allOf(
|
Matchers.allOf(
|
||||||
Matchers.is(PoolTaskMatcher.matchPoolTask(null, "editstep")),
|
Matchers.is(PoolTaskMatcher.matchPoolTask(null, "editstep")),
|
||||||
|
hasJsonPath("$._embedded.step", WorkflowStepMatcher.matchWorkflowStepEntry(step)),
|
||||||
hasJsonPath("$._embedded.workflowitem",
|
hasJsonPath("$._embedded.workflowitem",
|
||||||
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
||||||
witem, "Test item full workflow", "2019-03-06", "ExtraEntry")))
|
witem, "Test item full workflow", "2019-03-06", "ExtraEntry")))
|
||||||
@@ -1872,17 +1892,22 @@ public class TaskRestRepositoriesIT extends AbstractControllerIntegrationTest {
|
|||||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
|
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
|
||||||
.andExpect(status().isNoContent());
|
.andExpect(status().isNoContent());
|
||||||
|
|
||||||
|
workflowAction = xmlWorkflowFactory.getActionByName("editaction");
|
||||||
|
|
||||||
// get the id of the claimed task
|
// get the id of the claimed task
|
||||||
getClient(reviewer2Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
getClient(reviewer2Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
.param("uuid", reviewer2.getID().toString()))
|
.param("uuid", reviewer2.getID().toString()).param("projection", "full"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$._embedded.claimedtasks", Matchers.contains(
|
.andExpect(jsonPath("$._embedded.claimedtasks", Matchers.contains(
|
||||||
Matchers.allOf(
|
Matchers.allOf(
|
||||||
hasJsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks/")),
|
hasJsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks/")),
|
||||||
hasJsonPath("$.type", Matchers.is("claimedtask")),
|
hasJsonPath("$.type", Matchers.is("claimedtask")),
|
||||||
|
hasJsonPath("$._embedded.step", WorkflowStepMatcher.matchWorkflowStepEntry(step)),
|
||||||
hasJsonPath("$._embedded.workflowitem",
|
hasJsonPath("$._embedded.workflowitem",
|
||||||
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
||||||
witem, "Test item full workflow", "2019-03-06", "ExtraEntry")))
|
witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))),
|
||||||
|
hasJsonPath("$._embedded.action",
|
||||||
|
WorkflowActionMatcher.matchWorkflowActionEntry(workflowAction))
|
||||||
))))
|
))))
|
||||||
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
.andExpect(jsonPath("$.page.size", is(20)))
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
@@ -1901,17 +1926,20 @@ public class TaskRestRepositoriesIT extends AbstractControllerIntegrationTest {
|
|||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$.inArchive", is(false)));
|
.andExpect(jsonPath("$.inArchive", is(false)));
|
||||||
|
|
||||||
|
step = xmlWorkflowFactory.getStepByName("finaleditstep");
|
||||||
|
|
||||||
// step 3
|
// step 3
|
||||||
getClient(reviewer3Token).perform(get("/api/workflow/pooltasks/search/findByUser")
|
getClient(reviewer3Token).perform(get("/api/workflow/pooltasks/search/findByUser")
|
||||||
.param("uuid", reviewer3.getID().toString()))
|
.param("uuid", reviewer3.getID().toString()).param("projection", "full"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains(
|
.andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains(
|
||||||
Matchers.allOf(
|
Matchers.allOf(
|
||||||
Matchers.is(PoolTaskMatcher.matchPoolTask(null, "finaleditstep")),
|
Matchers.is(PoolTaskMatcher.matchPoolTask(null, "finaleditstep")),
|
||||||
|
hasJsonPath("$._embedded.step", WorkflowStepMatcher.matchWorkflowStepEntry(step)),
|
||||||
hasJsonPath("$._embedded.workflowitem",
|
hasJsonPath("$._embedded.workflowitem",
|
||||||
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
||||||
witem, "Test item full workflow", "2019-03-06", "ExtraEntry")))
|
witem, "Test item full workflow", "2019-03-06", "ExtraEntry")))
|
||||||
))))
|
))))
|
||||||
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/pooltasks")))
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/pooltasks")))
|
||||||
.andExpect(jsonPath("$.page.size", is(20)))
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
.andExpect(jsonPath("$.page.totalElements", is(1)))
|
.andExpect(jsonPath("$.page.totalElements", is(1)))
|
||||||
@@ -1923,17 +1951,21 @@ public class TaskRestRepositoriesIT extends AbstractControllerIntegrationTest {
|
|||||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
|
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
|
||||||
.andExpect(status().isNoContent());
|
.andExpect(status().isNoContent());
|
||||||
|
|
||||||
|
workflowAction = xmlWorkflowFactory.getActionByName("finaleditaction");
|
||||||
// get the id of the claimed task
|
// get the id of the claimed task
|
||||||
getClient(reviewer3Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
getClient(reviewer3Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
.param("uuid", reviewer3.getID().toString()))
|
.param("uuid", reviewer3.getID().toString()).param("projection", "full"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$._embedded.claimedtasks", Matchers.contains(
|
.andExpect(jsonPath("$._embedded.claimedtasks", Matchers.contains(
|
||||||
Matchers.allOf(
|
Matchers.allOf(
|
||||||
hasJsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks/")),
|
hasJsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks/")),
|
||||||
hasJsonPath("$.type", Matchers.is("claimedtask")),
|
hasJsonPath("$.type", Matchers.is("claimedtask")),
|
||||||
|
hasJsonPath("$._embedded.step", WorkflowStepMatcher.matchWorkflowStepEntry(step)),
|
||||||
hasJsonPath("$._embedded.workflowitem",
|
hasJsonPath("$._embedded.workflowitem",
|
||||||
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
||||||
witem, "Test item full workflow", "2019-03-06", "ExtraEntry")))
|
witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))),
|
||||||
|
hasJsonPath("$._embedded.action",
|
||||||
|
WorkflowActionMatcher.matchWorkflowActionEntry(workflowAction))
|
||||||
))))
|
))))
|
||||||
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
.andExpect(jsonPath("$.page.size", is(20)))
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
@@ -40,6 +40,7 @@ import org.dspace.app.rest.builder.WorkspaceItemBuilder;
|
|||||||
import org.dspace.app.rest.matcher.CollectionMatcher;
|
import org.dspace.app.rest.matcher.CollectionMatcher;
|
||||||
import org.dspace.app.rest.matcher.ItemMatcher;
|
import org.dspace.app.rest.matcher.ItemMatcher;
|
||||||
import org.dspace.app.rest.matcher.WorkflowItemMatcher;
|
import org.dspace.app.rest.matcher.WorkflowItemMatcher;
|
||||||
|
import org.dspace.app.rest.matcher.WorkflowStepMatcher;
|
||||||
import org.dspace.app.rest.matcher.WorkspaceItemMatcher;
|
import org.dspace.app.rest.matcher.WorkspaceItemMatcher;
|
||||||
import org.dspace.app.rest.model.patch.AddOperation;
|
import org.dspace.app.rest.model.patch.AddOperation;
|
||||||
import org.dspace.app.rest.model.patch.Operation;
|
import org.dspace.app.rest.model.patch.Operation;
|
||||||
@@ -53,6 +54,8 @@ import org.dspace.content.Item;
|
|||||||
import org.dspace.content.WorkspaceItem;
|
import org.dspace.content.WorkspaceItem;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.services.ConfigurationService;
|
import org.dspace.services.ConfigurationService;
|
||||||
|
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
||||||
|
import org.dspace.xmlworkflow.state.Step;
|
||||||
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
||||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
@@ -71,6 +74,8 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ConfigurationService configurationService;
|
private ConfigurationService configurationService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private XmlWorkflowFactory xmlWorkflowFactory;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@Override
|
@Override
|
||||||
@@ -85,7 +90,7 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
|||||||
@Test
|
@Test
|
||||||
/**
|
/**
|
||||||
* All the workflowitems should be returned regardless of the collection where they were created
|
* All the workflowitems should be returned regardless of the collection where they were created
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public void findAllTest() throws Exception {
|
public void findAllTest() throws Exception {
|
||||||
@@ -140,7 +145,7 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
|||||||
@Test
|
@Test
|
||||||
/**
|
/**
|
||||||
* The workflowitem endpoint must provide proper pagination
|
* The workflowitem endpoint must provide proper pagination
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public void findAllWithPaginationTest() throws Exception {
|
public void findAllWithPaginationTest() throws Exception {
|
||||||
@@ -208,7 +213,7 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
|||||||
@Test
|
@Test
|
||||||
/**
|
/**
|
||||||
* The findAll should be available only to admins regardless to having or less a role in the workflow
|
* The findAll should be available only to admins regardless to having or less a role in the workflow
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public void findAllForbiddenTest() throws Exception {
|
public void findAllForbiddenTest() throws Exception {
|
||||||
@@ -259,7 +264,7 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
|||||||
@Test
|
@Test
|
||||||
/**
|
/**
|
||||||
* The workflowitem resource endpoint must expose the proper structure
|
* The workflowitem resource endpoint must expose the proper structure
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public void findOneTest() throws Exception {
|
public void findOneTest() throws Exception {
|
||||||
@@ -297,7 +302,7 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
|||||||
@Test
|
@Test
|
||||||
/**
|
/**
|
||||||
* The workflowitem resource endpoint should be visible only to member of the corresponding workflow step
|
* The workflowitem resource endpoint should be visible only to member of the corresponding workflow step
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public void findOneForbiddenTest() throws Exception {
|
public void findOneForbiddenTest() throws Exception {
|
||||||
@@ -430,7 +435,7 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
|||||||
@Test
|
@Test
|
||||||
/**
|
/**
|
||||||
* The workflowitem resource endpoint must expose the proper structure
|
* The workflowitem resource endpoint must expose the proper structure
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public void findOneRelsTest() throws Exception {
|
public void findOneRelsTest() throws Exception {
|
||||||
@@ -478,7 +483,7 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
|||||||
@Test
|
@Test
|
||||||
/**
|
/**
|
||||||
* Check the response code for unexistent workflowitem
|
* Check the response code for unexistent workflowitem
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public void findOneWrongIDTest() throws Exception {
|
public void findOneWrongIDTest() throws Exception {
|
||||||
@@ -495,7 +500,7 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
|||||||
/**
|
/**
|
||||||
* Create three workflowitem with two different submitter and verify that the findBySubmitter return the proper
|
* Create three workflowitem with two different submitter and verify that the findBySubmitter return the proper
|
||||||
* list of workflowitem for each submitter also paginating
|
* list of workflowitem for each submitter also paginating
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public void findBySubmitterTest() throws Exception {
|
public void findBySubmitterTest() throws Exception {
|
||||||
@@ -602,7 +607,7 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
|||||||
/**
|
/**
|
||||||
* A delete request over a workflowitem should result in abort the workflow sending the item back to the submitter
|
* A delete request over a workflowitem should result in abort the workflow sending the item back to the submitter
|
||||||
* workspace
|
* workspace
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public void deleteOneTest() throws Exception {
|
public void deleteOneTest() throws Exception {
|
||||||
@@ -1682,4 +1687,84 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
|||||||
.param("uuid", String.valueOf(witem.getItem().getID())))
|
.param("uuid", String.valueOf(witem.getItem().getID())))
|
||||||
.andExpect(status().isUnauthorized());
|
.andExpect(status().isUnauthorized());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void stepEmbedTest() throws Exception {
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
//** GIVEN **
|
||||||
|
// 1. A community-collection structure with one parent community with sub-community and three collections
|
||||||
|
// (different workflow steps and reviewers).
|
||||||
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.build();
|
||||||
|
Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
|
||||||
|
.withName("Sub Community")
|
||||||
|
.build();
|
||||||
|
EPerson reviewer1 = EPersonBuilder.createEPerson(context).withEmail("reviewer1@example.com")
|
||||||
|
.withPassword(password).build();
|
||||||
|
|
||||||
|
Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1")
|
||||||
|
.withWorkflowGroup(1, reviewer1).build();
|
||||||
|
|
||||||
|
EPerson reviewer2 = EPersonBuilder.createEPerson(context).withEmail("reviewer2@example.com")
|
||||||
|
.withPassword(password).build();
|
||||||
|
|
||||||
|
Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2")
|
||||||
|
.withWorkflowGroup(2, reviewer2).build();
|
||||||
|
|
||||||
|
EPerson reviewer3 = EPersonBuilder.createEPerson(context).withEmail("reviewer3@example.com")
|
||||||
|
.withPassword(password).build();
|
||||||
|
|
||||||
|
Collection col3 = CollectionBuilder.createCollection(context, child1).withName("Collection 3")
|
||||||
|
.withWorkflowGroup(3, reviewer3).build();
|
||||||
|
|
||||||
|
//2. three workflow items in the three collections (this will lead to pool task)
|
||||||
|
XmlWorkflowItem witem1 = WorkflowItemBuilder.createWorkflowItem(context, col1)
|
||||||
|
.withTitle("Workflow Item 1")
|
||||||
|
.withIssueDate("2016-02-13")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
XmlWorkflowItem witem2 = WorkflowItemBuilder.createWorkflowItem(context, col2)
|
||||||
|
.withTitle("Workflow Item 2")
|
||||||
|
.withIssueDate("2016-02-13")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
XmlWorkflowItem witem3 = WorkflowItemBuilder.createWorkflowItem(context, col3)
|
||||||
|
.withTitle("Workflow Item 3")
|
||||||
|
.withIssueDate("2016-02-13")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Step step = xmlWorkflowFactory.getStepByName("reviewstep");
|
||||||
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
getClient(token).perform(get("/api/workflow/workflowitems/" + witem1.getID())
|
||||||
|
.param("projection", "full"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$",
|
||||||
|
WorkflowItemMatcher.matchItemWithTitleAndDateIssued(witem1,
|
||||||
|
"Workflow Item 1", "2016-02-13")))
|
||||||
|
.andExpect(jsonPath("$._embedded.step", WorkflowStepMatcher.matchWorkflowStepEntry(step)));
|
||||||
|
|
||||||
|
step = xmlWorkflowFactory.getStepByName("editstep");
|
||||||
|
|
||||||
|
getClient(token).perform(get("/api/workflow/workflowitems/" + witem2.getID())
|
||||||
|
.param("projection", "full"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$",
|
||||||
|
WorkflowItemMatcher.matchItemWithTitleAndDateIssued(witem2,
|
||||||
|
"Workflow Item 2", "2016-02-13")))
|
||||||
|
.andExpect(jsonPath("$._embedded.step", WorkflowStepMatcher.matchWorkflowStepEntry(step)));
|
||||||
|
|
||||||
|
step = xmlWorkflowFactory.getStepByName("finaleditstep");
|
||||||
|
|
||||||
|
getClient(token).perform(get("/api/workflow/workflowitems/" + witem3.getID())
|
||||||
|
.param("projection", "full"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$",
|
||||||
|
WorkflowItemMatcher.matchItemWithTitleAndDateIssued(witem3,
|
||||||
|
"Workflow Item 3", "2016-02-13")))
|
||||||
|
.andExpect(jsonPath("$._embedded.step", WorkflowStepMatcher.matchWorkflowStepEntry(step)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
package org.dspace.app.rest;
|
package org.dspace.app.rest;
|
||||||
|
|
||||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.springframework.data.rest.webmvc.RestMediaTypes.TEXT_URI_LIST_VALUE;
|
import static org.springframework.data.rest.webmvc.RestMediaTypes.TEXT_URI_LIST_VALUE;
|
||||||
import static org.springframework.http.MediaType.parseMediaType;
|
import static org.springframework.http.MediaType.parseMediaType;
|
||||||
@@ -35,6 +36,7 @@ import org.dspace.app.rest.builder.BitstreamBuilder;
|
|||||||
import org.dspace.app.rest.builder.CollectionBuilder;
|
import org.dspace.app.rest.builder.CollectionBuilder;
|
||||||
import org.dspace.app.rest.builder.CommunityBuilder;
|
import org.dspace.app.rest.builder.CommunityBuilder;
|
||||||
import org.dspace.app.rest.builder.EPersonBuilder;
|
import org.dspace.app.rest.builder.EPersonBuilder;
|
||||||
|
import org.dspace.app.rest.builder.GroupBuilder;
|
||||||
import org.dspace.app.rest.builder.ItemBuilder;
|
import org.dspace.app.rest.builder.ItemBuilder;
|
||||||
import org.dspace.app.rest.builder.WorkspaceItemBuilder;
|
import org.dspace.app.rest.builder.WorkspaceItemBuilder;
|
||||||
import org.dspace.app.rest.matcher.CollectionMatcher;
|
import org.dspace.app.rest.matcher.CollectionMatcher;
|
||||||
@@ -52,6 +54,8 @@ import org.dspace.content.Community;
|
|||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
import org.dspace.content.WorkspaceItem;
|
import org.dspace.content.WorkspaceItem;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
|
import org.dspace.eperson.Group;
|
||||||
|
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||||
import org.dspace.services.ConfigurationService;
|
import org.dspace.services.ConfigurationService;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -70,14 +74,34 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ConfigurationService configurationService;
|
private ConfigurationService configurationService;
|
||||||
|
|
||||||
|
private Group embargoedGroups;
|
||||||
|
private Group embargoedGroup1;
|
||||||
|
private Group embargoedGroup2;
|
||||||
|
private Group anonymousGroup;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@Override
|
@Override
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
|
|
||||||
super.setUp();
|
super.setUp();
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
//disable file upload mandatory
|
embargoedGroups = GroupBuilder.createGroup(context)
|
||||||
configurationService.setProperty("webui.submit.upload.required", false);
|
.withName("Embargoed Groups")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
embargoedGroup1 = GroupBuilder.createGroup(context)
|
||||||
|
.withName("Embargoed Group 1")
|
||||||
|
.withParent(embargoedGroups)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
embargoedGroup2 = GroupBuilder.createGroup(context)
|
||||||
|
.withName("Embargoed Group 2")
|
||||||
|
.withParent(embargoedGroups)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
anonymousGroup = EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS);
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -637,6 +661,9 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
.withIssueDate("2017-10-17")
|
.withIssueDate("2017-10-17")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
//disable file upload mandatory
|
||||||
|
configurationService.setProperty("webui.submit.upload.required", false);
|
||||||
|
|
||||||
getClient(authToken).perform(get("/api/submission/workspaceitems/" + workspaceItem1.getID()))
|
getClient(authToken).perform(get("/api/submission/workspaceitems/" + workspaceItem1.getID()))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$.errors").doesNotExist())
|
.andExpect(jsonPath("$.errors").doesNotExist())
|
||||||
@@ -697,6 +724,9 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
.withSubject("ExtraEntry")
|
.withSubject("ExtraEntry")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
//disable file upload mandatory
|
||||||
|
configurationService.setProperty("webui.submit.upload.required", false);
|
||||||
|
|
||||||
// a simple patch to update an existent metadata
|
// a simple patch to update an existent metadata
|
||||||
List<Operation> updateTitle = new ArrayList<Operation>();
|
List<Operation> updateTitle = new ArrayList<Operation>();
|
||||||
Map<String, String> value = new HashMap<String, String>();
|
Map<String, String> value = new HashMap<String, String>();
|
||||||
@@ -803,6 +833,9 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
null, "2017-10-17", "ExtraEntry"))))
|
null, "2017-10-17", "ExtraEntry"))))
|
||||||
;
|
;
|
||||||
|
|
||||||
|
//disable file upload mandatory
|
||||||
|
configurationService.setProperty("webui.submit.upload.required", false);
|
||||||
|
|
||||||
// try to remove a metadata in a specific position
|
// try to remove a metadata in a specific position
|
||||||
List<Operation> removeMidSubject = new ArrayList<Operation>();
|
List<Operation> removeMidSubject = new ArrayList<Operation>();
|
||||||
removeMidSubject.add(new RemoveOperation("/sections/traditionalpagetwo/dc.subject/1"));
|
removeMidSubject.add(new RemoveOperation("/sections/traditionalpagetwo/dc.subject/1"));
|
||||||
@@ -932,6 +965,8 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
.withSubject("ExtraEntry")
|
.withSubject("ExtraEntry")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
//disable file upload mandatory
|
||||||
|
configurationService.setProperty("webui.submit.upload.required", false);
|
||||||
|
|
||||||
// try to add the title
|
// try to add the title
|
||||||
List<Operation> addTitle = new ArrayList<Operation>();
|
List<Operation> addTitle = new ArrayList<Operation>();
|
||||||
@@ -989,6 +1024,9 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
.withIssueDate("2017-10-17")
|
.withIssueDate("2017-10-17")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
//disable file upload mandatory
|
||||||
|
configurationService.setProperty("webui.submit.upload.required", false);
|
||||||
|
|
||||||
// try to add multiple subjects at once
|
// try to add multiple subjects at once
|
||||||
List<Operation> addSubjects = new ArrayList<Operation>();
|
List<Operation> addSubjects = new ArrayList<Operation>();
|
||||||
// create a list of values to use in add operation
|
// create a list of values to use in add operation
|
||||||
@@ -1210,6 +1248,9 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
.andExpect(jsonPath("$.sections.license.url").isEmpty())
|
.andExpect(jsonPath("$.sections.license.url").isEmpty())
|
||||||
;
|
;
|
||||||
|
|
||||||
|
//disable file upload mandatory
|
||||||
|
configurationService.setProperty("webui.submit.upload.required", false);
|
||||||
|
|
||||||
// try to grant the license with an add operation
|
// try to grant the license with an add operation
|
||||||
List<Operation> addGrant = new ArrayList<Operation>();
|
List<Operation> addGrant = new ArrayList<Operation>();
|
||||||
addGrant.add(new AddOperation("/sections/license/granted", true));
|
addGrant.add(new AddOperation("/sections/license/granted", true));
|
||||||
@@ -1359,6 +1400,9 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
.grantLicense()
|
.grantLicense()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
//disable file upload mandatory
|
||||||
|
configurationService.setProperty("webui.submit.upload.required", false);
|
||||||
|
|
||||||
// check that our workspaceitems come with a license (all are build in the same way, just check the first)
|
// check that our workspaceitems come with a license (all are build in the same way, just check the first)
|
||||||
getClient().perform(get("/api/submission/workspaceitems/" + witem.getID()))
|
getClient().perform(get("/api/submission/workspaceitems/" + witem.getID()))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
@@ -1601,6 +1645,147 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void patchUploadAddAccessConditionTest() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
|
||||||
|
.withName("Sub Community")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Collection collection1 = CollectionBuilder.createCollection(context, child1)
|
||||||
|
.withName("Collection 1")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
InputStream pdf = getClass().getResourceAsStream("simple-article.pdf");
|
||||||
|
|
||||||
|
WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, collection1)
|
||||||
|
.withTitle("Test WorkspaceItem")
|
||||||
|
.withIssueDate("2019-10-01")
|
||||||
|
.withFulltext("simple-article.pdf", "/local/path/simple-article.pdf", pdf)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
// create a list of values to use in add accessCondition
|
||||||
|
List<Operation> addAccessCondition = new ArrayList<Operation>();
|
||||||
|
Map<String, String> value = new HashMap<String, String>();
|
||||||
|
value.put("name", "embargoedWithGroupSelect");
|
||||||
|
value.put("groupUUID", embargoedGroup1.getID().toString());
|
||||||
|
value.put("endDate", "2030-10-02");
|
||||||
|
addAccessCondition.add(new AddOperation("/sections/upload/files/0/accessConditions/-", value));
|
||||||
|
|
||||||
|
String patchBody = getPatchContent(addAccessCondition);
|
||||||
|
String authToken = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID())
|
||||||
|
.content(patchBody)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$",Matchers.allOf(
|
||||||
|
hasJsonPath("$.sections.upload.files[0].accessConditions[0].name",
|
||||||
|
is("embargoedWithGroupSelect")),
|
||||||
|
hasJsonPath("$.sections.upload.files[0].accessConditions[0].groupUUID",
|
||||||
|
is(embargoedGroup1.getID().toString()))
|
||||||
|
)));
|
||||||
|
|
||||||
|
// verify that the patch changes have been persisted
|
||||||
|
getClient(authToken).perform(get("/api/submission/workspaceitems/" + witem.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$",Matchers.allOf(
|
||||||
|
hasJsonPath("$.sections.upload.files[0].accessConditions[0].name",
|
||||||
|
is("embargoedWithGroupSelect")),
|
||||||
|
hasJsonPath("$.sections.upload.files[0].accessConditions[0].groupUUID",
|
||||||
|
is(embargoedGroup1.getID().toString()))
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void patchUploadRemoveAccessConditionTest() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
|
||||||
|
.withName("Sub Community")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Collection collection1 = CollectionBuilder.createCollection(context, child1)
|
||||||
|
.withName("Collection 1")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
InputStream pdf = getClass().getResourceAsStream("simple-article.pdf");
|
||||||
|
|
||||||
|
WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, collection1)
|
||||||
|
.withTitle("Test WorkspaceItem")
|
||||||
|
.withIssueDate("2019-10-01")
|
||||||
|
.withFulltext("simple-article.pdf", "/local/path/simple-article.pdf", pdf)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
// create a list of values to use in add operation
|
||||||
|
List<Operation> addAccessCondition = new ArrayList<Operation>();
|
||||||
|
Map<String, String> value = new HashMap<String, String>();
|
||||||
|
value.put("name", "embargoedWithGroupSelect");
|
||||||
|
value.put("groupUUID", embargoedGroup1.getID().toString());
|
||||||
|
value.put("endDate", "2020-01-01");
|
||||||
|
addAccessCondition.add(new AddOperation("/sections/upload/files/0/accessConditions/-", value));
|
||||||
|
|
||||||
|
String patchBody = getPatchContent(addAccessCondition);
|
||||||
|
String authToken = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID())
|
||||||
|
.content(patchBody)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$",Matchers.allOf(
|
||||||
|
hasJsonPath("$.sections.upload.files[0].accessConditions[0].name",
|
||||||
|
is("embargoedWithGroupSelect")),
|
||||||
|
hasJsonPath("$.sections.upload.files[0].accessConditions[0].endDate",
|
||||||
|
is("2020-01-01")),
|
||||||
|
hasJsonPath("$.sections.upload.files[0].accessConditions[0].groupUUID",
|
||||||
|
is(embargoedGroup1.getID().toString()))
|
||||||
|
)));
|
||||||
|
|
||||||
|
// verify that the patch changes have been persisted
|
||||||
|
getClient(authToken).perform(get("/api/submission/workspaceitems/" + witem.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$",Matchers.allOf(
|
||||||
|
hasJsonPath("$.sections.upload.files[0].accessConditions[0].name",
|
||||||
|
is("embargoedWithGroupSelect")),
|
||||||
|
hasJsonPath("$.sections.upload.files[0].accessConditions[0].endDate",
|
||||||
|
is("2020-01-01")),
|
||||||
|
hasJsonPath("$.sections.upload.files[0].accessConditions[0].groupUUID",
|
||||||
|
is(embargoedGroup1.getID().toString()))
|
||||||
|
)));
|
||||||
|
|
||||||
|
// create a list of values to use in remove operation
|
||||||
|
List<Operation> removeAccessCondition = new ArrayList<Operation>();
|
||||||
|
removeAccessCondition.add(new RemoveOperation("/sections/upload/files/0/accessConditions"));
|
||||||
|
|
||||||
|
String patchReplaceBody = getPatchContent(removeAccessCondition);
|
||||||
|
getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID())
|
||||||
|
.content(patchReplaceBody)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$",Matchers.allOf(
|
||||||
|
hasJsonPath("$.sections.upload.files[0].accessConditions",hasSize(0)))));
|
||||||
|
|
||||||
|
// verify that the patch changes have been persisted
|
||||||
|
getClient(authToken).perform(get("/api/submission/workspaceitems/" + witem.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$",Matchers.allOf(
|
||||||
|
hasJsonPath("$.sections.upload.files[0].accessConditions", hasSize(0))
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
/**
|
/**
|
||||||
* Test the upload of files in the upload over section
|
* Test the upload of files in the upload over section
|
||||||
@@ -1672,8 +1857,6 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
.withIssueDate("2017-10-17")
|
.withIssueDate("2017-10-17")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
configurationService.setProperty("webui.submit.upload.required", true);
|
|
||||||
|
|
||||||
InputStream pdf = getClass().getResourceAsStream("simple-article.pdf");
|
InputStream pdf = getClass().getResourceAsStream("simple-article.pdf");
|
||||||
final MockMultipartFile pdfFile = new MockMultipartFile("file", "/local/path/simple-article.pdf",
|
final MockMultipartFile pdfFile = new MockMultipartFile("file", "/local/path/simple-article.pdf",
|
||||||
"application/pdf", pdf);
|
"application/pdf", pdf);
|
||||||
@@ -1715,8 +1898,6 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
.withIssueDate("2017-10-17")
|
.withIssueDate("2017-10-17")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
configurationService.setProperty("webui.submit.upload.required", true);
|
|
||||||
|
|
||||||
//Verify there is an error since no file was uploaded (with upload required set to true)
|
//Verify there is an error since no file was uploaded (with upload required set to true)
|
||||||
getClient(authToken).perform(get("/api/submission/workspaceitems/" + witem.getID()))
|
getClient(authToken).perform(get("/api/submission/workspaceitems/" + witem.getID()))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
|
@@ -19,6 +19,8 @@ import org.dspace.content.Community;
|
|||||||
import org.dspace.content.MetadataSchemaEnum;
|
import org.dspace.content.MetadataSchemaEnum;
|
||||||
import org.dspace.content.service.DSpaceObjectService;
|
import org.dspace.content.service.DSpaceObjectService;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.eperson.EPerson;
|
||||||
|
import org.dspace.eperson.Group;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder to construct Community objects
|
* Builder to construct Community objects
|
||||||
@@ -74,6 +76,23 @@ public class CommunityBuilder extends AbstractDSpaceObjectBuilder<Community> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an admin group for the community with the specified members
|
||||||
|
*
|
||||||
|
* @param members epersons to add to the admin group
|
||||||
|
* @return this builder
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws AuthorizeException
|
||||||
|
*/
|
||||||
|
public CommunityBuilder withAdminGroup(EPerson... members) throws SQLException, AuthorizeException {
|
||||||
|
Group g = communityService.createAdministrators(context, community);
|
||||||
|
for (EPerson e : members) {
|
||||||
|
groupService.addMember(context, g, e);
|
||||||
|
}
|
||||||
|
groupService.update(context, g);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public CommunityBuilder addParentCommunity(final Context context, final Community parent)
|
public CommunityBuilder addParentCommunity(final Context context, final Community parent)
|
||||||
throws SQLException, AuthorizeException {
|
throws SQLException, AuthorizeException {
|
||||||
communityService.addSubcommunity(context, parent, community);
|
communityService.addSubcommunity(context, parent, community);
|
||||||
|
@@ -66,6 +66,19 @@ public class BitstreamMatcher {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Matcher<? super Object> matchBitstreamEntryWithoutEmbed(UUID uuid, long size) {
|
||||||
|
return allOf(
|
||||||
|
//Check ID and size
|
||||||
|
hasJsonPath("$.uuid", is(uuid.toString())),
|
||||||
|
hasJsonPath("$.sizeBytes", is((int) size)),
|
||||||
|
//Make sure we have a checksum
|
||||||
|
hasJsonPath("$.checkSum", matchChecksum()),
|
||||||
|
//Make sure we have a valid format
|
||||||
|
//Check links
|
||||||
|
matchLinks(uuid)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private static Matcher<? super Object> matchChecksum() {
|
private static Matcher<? super Object> matchChecksum() {
|
||||||
return allOf(
|
return allOf(
|
||||||
hasJsonPath("$.checkSumAlgorithm", not(empty())),
|
hasJsonPath("$.checkSumAlgorithm", not(empty())),
|
||||||
|
@@ -36,7 +36,6 @@ public class ClaimedTaskMatcher {
|
|||||||
*/
|
*/
|
||||||
public static Matcher matchClaimedTask(ClaimedTask cTask, String step) {
|
public static Matcher matchClaimedTask(ClaimedTask cTask, String step) {
|
||||||
return allOf(
|
return allOf(
|
||||||
hasJsonPath("$.step", is(step)),
|
|
||||||
// Check workflowitem properties
|
// Check workflowitem properties
|
||||||
matchProperties(cTask),
|
matchProperties(cTask),
|
||||||
// Check links
|
// Check links
|
||||||
|
@@ -36,7 +36,6 @@ public class PoolTaskMatcher {
|
|||||||
*/
|
*/
|
||||||
public static Matcher matchPoolTask(PoolTask pTask, String step) {
|
public static Matcher matchPoolTask(PoolTask pTask, String step) {
|
||||||
return allOf(
|
return allOf(
|
||||||
hasJsonPath("$.step", is(step)),
|
|
||||||
// Check workflowitem properties
|
// Check workflowitem properties
|
||||||
matchProperties(pTask),
|
matchProperties(pTask),
|
||||||
// Check links
|
// Check links
|
||||||
|
@@ -12,6 +12,7 @@ import javax.annotation.Nullable;
|
|||||||
import org.dspace.app.rest.model.LinkRest;
|
import org.dspace.app.rest.model.LinkRest;
|
||||||
import org.dspace.app.rest.model.MockObject;
|
import org.dspace.app.rest.model.MockObject;
|
||||||
import org.dspace.app.rest.model.MockObjectRest;
|
import org.dspace.app.rest.model.MockObjectRest;
|
||||||
|
import org.dspace.app.rest.model.RestAddressableModel;
|
||||||
import org.dspace.app.rest.model.RestModel;
|
import org.dspace.app.rest.model.RestModel;
|
||||||
import org.dspace.app.rest.model.hateoas.HALResource;
|
import org.dspace.app.rest.model.hateoas.HALResource;
|
||||||
import org.springframework.hateoas.Link;
|
import org.springframework.hateoas.Link;
|
||||||
@@ -87,8 +88,9 @@ public class MockProjection implements Projection {
|
|||||||
return halResource;
|
return halResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean allowEmbedding(HALResource halResource, LinkRest linkRest) {
|
public boolean allowEmbedding(HALResource<? extends RestAddressableModel> halResource, LinkRest linkRest,
|
||||||
return true;
|
Link... oldLinks) {
|
||||||
|
return halResource.getContent().getEmbedLevel() < 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean allowLinking(HALResource halResource, LinkRest linkRest) {
|
public boolean allowLinking(HALResource halResource, LinkRest linkRest) {
|
||||||
|
@@ -1,9 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<!-- http://www.loc.gov/standards/mets/mets.xsd -->
|
<!-- http://www.loc.gov/standards/mets/mets.xsd -->
|
||||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
xmlns:doc="http://www.lyncode.com/xoai"
|
xmlns:doc="http://www.lyncode.com/xoai" version="2.0">
|
||||||
xmlns:date="http://exslt.org/dates-and-times"
|
|
||||||
extension-element-prefixes="date" version="1.0">
|
|
||||||
|
|
||||||
<xsl:output omit-xml-declaration="yes" method="xml" indent="yes" />
|
<xsl:output omit-xml-declaration="yes" method="xml" indent="yes" />
|
||||||
|
|
||||||
@@ -20,7 +18,7 @@
|
|||||||
</xsl:attribute>
|
</xsl:attribute>
|
||||||
<metsHdr>
|
<metsHdr>
|
||||||
<xsl:attribute name="CREATEDATE">
|
<xsl:attribute name="CREATEDATE">
|
||||||
<xsl:value-of select="concat(date:format-date(date:date(), 'yyyy-MM-dd'), 'T' , date:format-date(date:time(), 'HH:mm:ss'), 'Z')"/>
|
<xsl:value-of select="concat(format-date(current-date(), 'yyyy-MM-dd'), 'T' , format-time(current-time(), 'HH:mm:ss'), 'Z')"/>
|
||||||
</xsl:attribute>
|
</xsl:attribute>
|
||||||
<agent ROLE="CUSTODIAN" TYPE="ORGANIZATION">
|
<agent ROLE="CUSTODIAN" TYPE="ORGANIZATION">
|
||||||
<name><xsl:value-of select="doc:metadata/doc:element[@name='repository']/doc:field[@name='name']/text()" /></name>
|
<name><xsl:value-of select="doc:metadata/doc:element[@name='repository']/doc:field[@name='name']/text()" /></name>
|
||||||
|
@@ -8,6 +8,12 @@
|
|||||||
# (Requires reboot of servlet container, e.g. Tomcat, to reload)
|
# (Requires reboot of servlet container, e.g. Tomcat, to reload)
|
||||||
rest.cors.allowed-origins = *
|
rest.cors.allowed-origins = *
|
||||||
|
|
||||||
|
# This property determines the max embeddepth for a FullProjection. This is also used by the SpecificLevelProjection
|
||||||
|
# as a fallback incase the property is defined on the bean
|
||||||
|
rest.projections.full.max = 2
|
||||||
|
|
||||||
|
# This property determines the max embed depth for a SpecificLevelProjection
|
||||||
|
rest.projection.specificLevel.maxEmbed = 5
|
||||||
|
|
||||||
#---------------------------------------------------------------#
|
#---------------------------------------------------------------#
|
||||||
# These configs are used by the deprecated REST (v4-6) module #
|
# These configs are used by the deprecated REST (v4-6) module #
|
||||||
|
9
dspace/config/spring/rest/projections.xml
Normal file
9
dspace/config/spring/rest/projections.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||||
|
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||||
|
|
||||||
|
<bean class="org.dspace.app.rest.projection.SpecificLevelProjection">
|
||||||
|
<property name="maxEmbed" value="${rest.projection.specificLevel.maxEmbed}" />
|
||||||
|
</bean>
|
||||||
|
</beans>
|
Reference in New Issue
Block a user