diff --git a/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml b/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml
index 07aa36fb2b..100eb5e220 100644
--- a/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml
+++ b/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml
@@ -20,6 +20,7 @@
+
@@ -75,6 +76,18 @@
submission
+
+ submit.progressbar.accessCondition
+ org.dspace.app.rest.submit.step.AccessConditionStep
+ accessCondition
+
+
+
+ submit.progressbar.accessCondition
+ org.dspace.app.rest.submit.step.AccessConditionStep
+ accessCondition
+
+
+
@@ -167,6 +181,12 @@
+
+
+
+
+
+
diff --git a/dspace-api/src/test/data/dspaceFolder/config/spring/api/access-conditions.xml b/dspace-api/src/test/data/dspaceFolder/config/spring/api/access-conditions.xml
index 1f500f6a36..a879f1be91 100644
--- a/dspace-api/src/test/data/dspaceFolder/config/spring/api/access-conditions.xml
+++ b/dspace-api/src/test/data/dspaceFolder/config/spring/api/access-conditions.xml
@@ -82,7 +82,7 @@
-
+
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/AccessConditionAddPatchOperation.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/AccessConditionAddPatchOperation.java
new file mode 100644
index 0000000000..364098bb24
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/AccessConditionAddPatchOperation.java
@@ -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 {
+
+ @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 accessConditions = new ArrayList();
+
+ 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 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 accessConditions)
+ throws SQLException {
+ List 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 getArrayClassForEvaluation() {
+ return AccessConditionDTO[].class;
+ }
+
+ @Override
+ protected Class getClassForEvaluation() {
+ return AccessConditionDTO.class;
+ }
+
+}
\ No newline at end of file
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/AccessConditionRemovePatchOperation.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/AccessConditionRemovePatchOperation.java
index 47fd4c384a..114c082000 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/AccessConditionRemovePatchOperation.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/AccessConditionRemovePatchOperation.java
@@ -55,7 +55,7 @@ public class AccessConditionRemovePatchOperation extends RemovePatchOperation 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,"
+ " currently the are " + policies.size() + " access conditions");
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/AccessConditionReplacePatchOperation.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/AccessConditionReplacePatchOperation.java
new file mode 100644
index 0000000000..95c33c5770
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/AccessConditionReplacePatchOperation.java
@@ -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 {
+
+ @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 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 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 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 getArrayClassForEvaluation() {
+ return AccessConditionDTO[].class;
+ }
+
+ @Override
+ protected Class getClassForEvaluation() {
+ return AccessConditionDTO.class;
+ }
+
+}
\ No newline at end of file
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/AccessConditionResourcePolicyUtils.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/AccessConditionResourcePolicyUtils.java
new file mode 100644
index 0000000000..b9c5215063
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/AccessConditionResourcePolicyUtils.java
@@ -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 accessConditionOptions,
+ DSpaceObject obj, List 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 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 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;
+ }
+}
\ No newline at end of file
diff --git a/dspace-server-webapp/src/main/resources/spring/spring-dspace-core-services.xml b/dspace-server-webapp/src/main/resources/spring/spring-dspace-core-services.xml
index 8de0c3b8dc..bb56393d0b 100644
--- a/dspace-server-webapp/src/main/resources/spring/spring-dspace-core-services.xml
+++ b/dspace-server-webapp/src/main/resources/spring/spring-dspace-core-services.xml
@@ -86,7 +86,7 @@
-
+