implemented patch operations for AccessConditions in submission

This commit is contained in:
Mykhaylo
2021-12-14 13:42:15 +01:00
parent 420f661a5b
commit a85f4e69b9
7 changed files with 376 additions and 3 deletions

View File

@@ -20,6 +20,7 @@
<name-map collection-handle="default" submission-name="traditional"/> <name-map collection-handle="default" submission-name="traditional"/>
<name-map collection-handle="123456789/language-test-1" submission-name="languagetestprocess"/> <name-map collection-handle="123456789/language-test-1" submission-name="languagetestprocess"/>
<name-map collection-handle="123456789/extraction-test" submission-name="extractiontestprocess"/> <name-map collection-handle="123456789/extraction-test" submission-name="extractiontestprocess"/>
<name-map collection-handle="123456789/accessCondition-not-discoverable" submission-name="accessConditionNotDiscoverable"/>
</submission-map> </submission-map>
@@ -75,6 +76,18 @@
<scope visibilityOutside="read-only">submission</scope> <scope visibilityOutside="read-only">submission</scope>
</step-definition> </step-definition>
<step-definition id="defaultAC">
<heading>submit.progressbar.accessCondition</heading>
<processing-class>org.dspace.app.rest.submit.step.AccessConditionStep</processing-class>
<type>accessCondition</type>
</step-definition>
<step-definition id="notDiscoverable">
<heading>submit.progressbar.accessCondition</heading>
<processing-class>org.dspace.app.rest.submit.step.AccessConditionStep</processing-class>
<type>accessCondition</type>
</step-definition>
<!-- Step Upload Item with Embargo Features to enable this step, please <!-- Step Upload Item with Embargo Features to enable this step, please
make sure to comment-out the previous step "UploadStep" <step-definition id="upload-with-embargo"> make sure to comment-out the previous step "UploadStep" <step-definition id="upload-with-embargo">
<heading>submit.progressbar.upload</heading> <processing-class>org.dspace.submit.step.UploadWithEmbargoStep</processing-class> <heading>submit.progressbar.upload</heading> <processing-class>org.dspace.submit.step.UploadWithEmbargoStep</processing-class>
@@ -146,6 +159,7 @@
<step id="upload"/> <step id="upload"/>
<!-- <step id="upload-with-embargo"/> --> <!-- <step id="upload-with-embargo"/> -->
<!-- <step id="extractionstep"/> --> <!-- <step id="extractionstep"/> -->
<step id="defaultAC"/>
<!--Step will be to Sign off on the License --> <!--Step will be to Sign off on the License -->
<step id="license"/> <step id="license"/>
@@ -167,6 +181,12 @@
<step id="cclicense"/> <step id="cclicense"/>
</submission-process> </submission-process>
<submission-process name="accessConditionNotDiscoverable">
<step id="collection"/>
<step id="traditionalpageone"/>
<step id="notDiscoverable"/>
</submission-process>
</submission-definitions> </submission-definitions>
</item-submission> </item-submission>

View File

@@ -82,7 +82,7 @@
</bean> </bean>
<bean id="accessConditionConfigurationNotDiscoverable" class="org.dspace.submit.model.AccessConditionConfiguration"> <bean id="accessConditionConfigurationNotDiscoverable" class="org.dspace.submit.model.AccessConditionConfiguration">
<property name="name" value="defaultAC"></property> <property name="name" value="notDiscoverable"></property>
<property name="discoverable" value="false"></property> <property name="discoverable" value="false"></property>
<property name="options"> <property name="options">
<list> <list>

View File

@@ -0,0 +1,105 @@
/**
* 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.submit.factory.impl;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.AccessConditionDTO;
import org.dspace.app.rest.model.patch.LateObjectEvaluator;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.authorize.service.ResourcePolicyService;
import org.dspace.content.InProgressSubmission;
import org.dspace.content.Item;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.submit.model.AccessConditionConfiguration;
import org.dspace.submit.model.AccessConditionConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Submission "add" operation to add custom resource policies.
*
* @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.com)
*/
public class AccessConditionAddPatchOperation extends AddPatchOperation<AccessConditionDTO> {
@Autowired
private AuthorizeService authorizeService;
@Autowired
private ResourcePolicyService resourcePolicyService;
@Autowired
private AccessConditionConfigurationService accessConditionConfigurationService;
@Override
void add(Context context, HttpServletRequest currentRequest, InProgressSubmission source, String path, Object value)
throws Exception {
String stepId = (String) currentRequest.getAttribute("accessConditionSectionId");
AccessConditionConfiguration configuration = accessConditionConfigurationService.getMap().get(stepId);
//"path": "/sections/<:name-of-the-form>/accessConditions/-"
String[] split = getAbsolutePath(path).split("/");
Item item = source.getItem();
List<AccessConditionDTO> accessConditions = new ArrayList<AccessConditionDTO>();
if (split.length == 1) {
// to replace completely the access conditions
authorizeService.removePoliciesActionFilter(context, item, Constants.READ);
accessConditions = evaluateArrayObject((LateObjectEvaluator) value);
} else if (split.length == 2) {
// to add an access condition
// contains "-", call index-based accessConditions it make not sense
accessConditions.add(evaluateSingleObject((LateObjectEvaluator) value));
}
verifyAccessConditions(context, configuration, accessConditions);
// check duplicate policy
checkDuplication(context, item, accessConditions);
// apply policies
AccessConditionResourcePolicyUtils.findApplyResourcePolicy(context, configuration.getOptions(), item,
accessConditions);
}
private void verifyAccessConditions(Context context, AccessConditionConfiguration configuration,
List<AccessConditionDTO> accessConditions) throws SQLException, AuthorizeException, ParseException {
for (AccessConditionDTO dto : accessConditions) {
AccessConditionResourcePolicyUtils.canApplyResourcePolicy(context, configuration.getOptions(),
dto.getName(), dto.getStartDate(), dto.getEndDate());
}
}
private void checkDuplication(Context context, Item item, List<AccessConditionDTO> accessConditions)
throws SQLException {
List<ResourcePolicy> policies = resourcePolicyService.find(context, item, ResourcePolicy.TYPE_CUSTOM);
for (ResourcePolicy resourcePolicy : policies) {
for (AccessConditionDTO dto : accessConditions) {
if (dto.getName().equals(resourcePolicy.getRpName())) {
throw new UnprocessableEntityException("A policy of the same type already exists!");
}
}
}
}
@Override
protected Class<AccessConditionDTO[]> getArrayClassForEvaluation() {
return AccessConditionDTO[].class;
}
@Override
protected Class<AccessConditionDTO> getClassForEvaluation() {
return AccessConditionDTO.class;
}
}

View File

@@ -55,7 +55,7 @@ public class AccessConditionRemovePatchOperation extends RemovePatchOperation<Ac
} }
List<ResourcePolicy> policies = resourcePolicyService.find(context, item, ResourcePolicy.TYPE_CUSTOM); List<ResourcePolicy> policies = resourcePolicyService.find(context, item, ResourcePolicy.TYPE_CUSTOM);
if ((idxToDelete < 0 || idxToDelete >= policies.size()) && policies.isEmpty()) { if (idxToDelete < 0 || idxToDelete >= policies.size()) {
throw new UnprocessableEntityException("The provided index:" + idxToDelete + " is not supported," throw new UnprocessableEntityException("The provided index:" + idxToDelete + " is not supported,"
+ " currently the are " + policies.size() + " access conditions"); + " currently the are " + policies.size() + " access conditions");
} }

View File

@@ -0,0 +1,178 @@
/**
* 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.submit.factory.impl;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.AccessConditionDTO;
import org.dspace.app.rest.model.patch.JsonValueEvaluator;
import org.dspace.app.rest.model.patch.LateObjectEvaluator;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.ResourcePolicyService;
import org.dspace.content.InProgressSubmission;
import org.dspace.content.Item;
import org.dspace.core.Context;
import org.dspace.submit.model.AccessConditionConfiguration;
import org.dspace.submit.model.AccessConditionConfigurationService;
import org.dspace.submit.model.AccessConditionOption;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Submission "replace" operation to replace custom resource policies.
*
* @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.com)
*/
public class AccessConditionReplacePatchOperation extends ReplacePatchOperation<AccessConditionDTO> {
@Autowired
private ResourcePolicyService resourcePolicyService;
@Autowired
private AccessConditionConfigurationService accessConditionConfigurationService;
@Override
void replace(Context context, HttpServletRequest currentRequest, InProgressSubmission source, String path,
Object value) throws Exception {
String stepId = (String) currentRequest.getAttribute("accessConditionSectionId");
AccessConditionConfiguration configuration = accessConditionConfigurationService.getMap().get(stepId);
// "path" : "/sections/<:name-of-the-form>/accessConditions/0"
String[] split = getAbsolutePath(path).split("/");
Item item = source.getItem();
if (split.length == 2) {
int toReplace = Integer.parseInt(split[1]);
AccessConditionDTO accessConditionDTO = evaluateSingleObject((LateObjectEvaluator) value);
if (Objects.nonNull(accessConditionDTO) && Objects.nonNull(getOption(configuration, accessConditionDTO))) {
List<ResourcePolicy> policies = resourcePolicyService.find(context, item, ResourcePolicy.TYPE_CUSTOM);
if ((toReplace < 0 || toReplace >= policies.size()) && policies.isEmpty()) {
throw new UnprocessableEntityException("The provided index:" + toReplace + " is not supported,"
+ " currently the are " + policies.size() + " access conditions");
}
if (checkDubblication(context, configuration, policies, accessConditionDTO, toReplace, item)) {
context.commit();
resourcePolicyService.delete(context, policies.get(toReplace));
getOption(configuration, accessConditionDTO).createPolicy(context, item,
accessConditionDTO.getName(), null, accessConditionDTO.getStartDate(),
accessConditionDTO.getEndDate());
}
}
} else if (split.length == 3) {
String valueToReplare = getValue(value);
int toReplace = Integer.parseInt(split[1]);
String attributeReplace = split[2];
List<ResourcePolicy> policies = resourcePolicyService.find(context, item, ResourcePolicy.TYPE_CUSTOM);
if ((toReplace < 0 || toReplace >= policies.size()) && policies.isEmpty()) {
throw new UnprocessableEntityException("The provided index:" + toReplace + " is not supported,"
+ " currently the are " + policies.size() + " access conditions");
}
ResourcePolicy rpToReplace = policies.get(toReplace);
AccessConditionDTO accessConditionDTO = createDTO(rpToReplace, attributeReplace, valueToReplare);
boolean canApplay = AccessConditionResourcePolicyUtils.canApplyResourcePolicy(context,
configuration.getOptions(), accessConditionDTO.getName(), accessConditionDTO.getStartDate(),
accessConditionDTO.getEndDate());
if (canApplay) {
switch (attributeReplace) {
case "name":
rpToReplace.setRpName(valueToReplare);
break;
case "startDate":
rpToReplace.setStartDate(new Date(valueToReplare));
break;
case "endDate":
rpToReplace.setEndDate(new Date(valueToReplare));
break;
default:
}
}
resourcePolicyService.update(context, rpToReplace);
}
}
private AccessConditionDTO createDTO(ResourcePolicy rpToReplace, String attributeReplace, String valueToReplare) {
AccessConditionDTO accessCondition = new AccessConditionDTO();
switch (attributeReplace) {
case "name":
accessCondition.setName(valueToReplare);
accessCondition.setStartDate(rpToReplace.getStartDate());
accessCondition.setEndDate(rpToReplace.getEndDate());
return accessCondition;
case "startDate":
accessCondition.setName(rpToReplace.getRpName());
accessCondition.setStartDate(new Date(valueToReplare));
accessCondition.setEndDate(rpToReplace.getEndDate());
return accessCondition;
case "endDate":
accessCondition.setName(rpToReplace.getRpName());
accessCondition.setStartDate(rpToReplace.getStartDate());
accessCondition.setEndDate(new Date(valueToReplare));
return accessCondition;
default:
throw new UnprocessableEntityException("The provided attribute: "
+ attributeReplace + " is not supported");
}
}
private String getValue(Object value) {
if (value instanceof JsonValueEvaluator) {
JsonValueEvaluator jsonValue = (JsonValueEvaluator) value;
if (jsonValue.getValueNode().fields().hasNext()) {
return jsonValue.getValueNode().fields().next().getValue().asText();
}
}
return StringUtils.EMPTY;
}
private AccessConditionOption getOption(AccessConditionConfiguration configuration,
AccessConditionDTO accessConditionDTO) {
for (AccessConditionOption option :configuration.getOptions()) {
if (option.getName().equals(accessConditionDTO.getName())) {
return option;
}
}
return null;
}
private boolean checkDubblication(Context context, AccessConditionConfiguration configuration,
List<ResourcePolicy> policies, AccessConditionDTO accessConditionDTO, int toReplace, Item item)
throws SQLException, AuthorizeException, ParseException {
ResourcePolicy rp = policies.get(toReplace);
if (rp.getRpName().equals(accessConditionDTO.getName())) {
boolean canApplay = AccessConditionResourcePolicyUtils.canApplyResourcePolicy(context,
configuration.getOptions(), accessConditionDTO.getName(),
accessConditionDTO.getStartDate(), accessConditionDTO.getEndDate());
if (canApplay) {
item.getResourcePolicies().remove(rp);
return true;
}
}
for (ResourcePolicy resourcePolicy : policies) {
if (resourcePolicy.getRpName().equals(accessConditionDTO.getName())) {
return false;
}
}
item.getResourcePolicies().remove(rp);
return true;
}
@Override
protected Class<AccessConditionDTO[]> getArrayClassForEvaluation() {
return AccessConditionDTO[].class;
}
@Override
protected Class<AccessConditionDTO> getClassForEvaluation() {
return AccessConditionDTO.class;
}
}

View File

@@ -0,0 +1,70 @@
/**
* 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.submit.factory.impl;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.AccessConditionDTO;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject;
import org.dspace.core.Context;
import org.dspace.submit.model.AccessConditionOption;
/**
* Utility class to reuse methods related to resource-policies
*
* @author Mykhaylo Boychuk (mykhaylo.boychuk@4science.com)
*/
public class AccessConditionResourcePolicyUtils {
private AccessConditionResourcePolicyUtils() {}
public static void findApplyResourcePolicy(Context context, List<AccessConditionOption> accessConditionOptions,
DSpaceObject obj, List<AccessConditionDTO> newAccessConditions)
throws SQLException, AuthorizeException, ParseException {
for (AccessConditionDTO newAccessCondition : newAccessConditions) {
String name = newAccessCondition.getName();
String description = newAccessCondition.getDescription();
Date startDate = newAccessCondition.getStartDate();
Date endDate = newAccessCondition.getEndDate();
findApplyResourcePolicy(context, accessConditionOptions, obj, name, description, startDate, endDate);
}
}
public static void findApplyResourcePolicy(Context context,
List<AccessConditionOption> accessConditionOptions, DSpaceObject obj, String name,
String description, Date startDate, Date endDate) throws SQLException, AuthorizeException, ParseException {
boolean found = false;
for (AccessConditionOption accessConditionOption : accessConditionOptions) {
if (!found && accessConditionOption.getName().equalsIgnoreCase(name)) {
accessConditionOption.createResourcePolicy(context, obj, name, description, startDate, endDate);
found = true;
}
}
if (!found) {
throw new UnprocessableEntityException("The provided policy: " + name + " is not supported!");
}
}
public static boolean canApplyResourcePolicy(Context context,
List<AccessConditionOption> accessConditionOptions, String name, Date startDate, Date endDate)
throws SQLException, AuthorizeException, ParseException {
for (AccessConditionOption accessConditionOption : accessConditionOptions) {
if (accessConditionOption.getName().equalsIgnoreCase(name)) {
return accessConditionOption.canCreateResourcePolicy(context, name, startDate, endDate);
}
}
return false;
}
}

View File

@@ -86,7 +86,7 @@
<bean <bean
class="org.dspace.app.rest.submit.factory.impl.BitstreamRemovePatchOperation" /> class="org.dspace.app.rest.submit.factory.impl.BitstreamRemovePatchOperation" />
</entry> </entry>
<entry key="accessConditions"> <entry key="upload.accessConditions">
<bean <bean
class="org.dspace.app.rest.submit.factory.impl.BitstreamResourcePolicyRemovePatchOperation"/> class="org.dspace.app.rest.submit.factory.impl.BitstreamResourcePolicyRemovePatchOperation"/>
</entry> </entry>