mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-08 02:24:18 +00:00
Merge branch 'main' into CST-7754
This commit is contained in:
@@ -303,6 +303,10 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini
|
|||||||
commitCounter++;
|
commitCounter++;
|
||||||
if (commitCounter % 100 == 0) {
|
if (commitCounter % 100 == 0) {
|
||||||
context.dispatchEvents();
|
context.dispatchEvents();
|
||||||
|
// Commit actual changes to DB after dispatch events
|
||||||
|
System.out.print("Performing incremental commit to the database...");
|
||||||
|
context.commit();
|
||||||
|
System.out.println(" Incremental commit done!");
|
||||||
}
|
}
|
||||||
|
|
||||||
context.uncacheEntity(bitstream);
|
context.uncacheEntity(bitstream);
|
||||||
|
@@ -18,6 +18,7 @@ import org.dspace.core.Context;
|
|||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.eperson.Group;
|
import org.dspace.eperson.Group;
|
||||||
import org.dspace.xmlworkflow.WorkflowConfigurationException;
|
import org.dspace.xmlworkflow.WorkflowConfigurationException;
|
||||||
|
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service interface class for the WorkflowService framework.
|
* Service interface class for the WorkflowService framework.
|
||||||
@@ -100,6 +101,9 @@ public interface WorkflowService<T extends WorkflowItem> {
|
|||||||
String rejection_message)
|
String rejection_message)
|
||||||
throws SQLException, AuthorizeException, IOException;
|
throws SQLException, AuthorizeException, IOException;
|
||||||
|
|
||||||
|
public void restartWorkflow(Context context, XmlWorkflowItem wi, EPerson decliner, String provenance)
|
||||||
|
throws SQLException, AuthorizeException, IOException, WorkflowException;
|
||||||
|
|
||||||
public String getMyDSpaceLink();
|
public String getMyDSpaceLink();
|
||||||
|
|
||||||
public void deleteCollection(Context context, Collection collection)
|
public void deleteCollection(Context context, Collection collection)
|
||||||
|
@@ -41,6 +41,9 @@ public class Role implements BeanNameAware {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private WorkflowItemRoleService workflowItemRoleService;
|
private WorkflowItemRoleService workflowItemRoleService;
|
||||||
|
|
||||||
|
// Whether or not to delete temporary group made attached to the WorkflowItemRole for this role in AutoAssignAction
|
||||||
|
private boolean deleteTemporaryGroup = false;
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
private String name;
|
private String name;
|
||||||
private String description;
|
private String description;
|
||||||
@@ -153,4 +156,17 @@ public class Role implements BeanNameAware {
|
|||||||
public void setInternal(boolean internal) {
|
public void setInternal(boolean internal) {
|
||||||
isInternal = internal;
|
isInternal = internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDeleteTemporaryGroup() {
|
||||||
|
return deleteTemporaryGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter for config that indicated whether or not to delete temporary group made attached to the
|
||||||
|
* WorkflowItemRole for this role in AutoAssignAction
|
||||||
|
* @param deleteTemporaryGroup
|
||||||
|
*/
|
||||||
|
public void setDeleteTemporaryGroup(boolean deleteTemporaryGroup) {
|
||||||
|
this.deleteTemporaryGroup = deleteTemporaryGroup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1076,6 +1076,53 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService {
|
|||||||
return wsi;
|
return wsi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restartWorkflow(Context context, XmlWorkflowItem wi, EPerson decliner, String provenance)
|
||||||
|
throws SQLException, AuthorizeException, IOException, WorkflowException {
|
||||||
|
if (!authorizeService.isAdmin(context)) {
|
||||||
|
throw new AuthorizeException("You must be an admin to restart a workflow");
|
||||||
|
}
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
// rejection provenance
|
||||||
|
Item myitem = wi.getItem();
|
||||||
|
|
||||||
|
// Here's what happened
|
||||||
|
String provDescription =
|
||||||
|
provenance + " Declined by " + getEPersonName(decliner) + " on " + DCDate.getCurrent().toString() +
|
||||||
|
" (GMT) ";
|
||||||
|
|
||||||
|
// Add to item as a DC field
|
||||||
|
itemService
|
||||||
|
.addMetadata(context, myitem, MetadataSchemaEnum.DC.getName(),
|
||||||
|
"description", "provenance", "en", provDescription);
|
||||||
|
|
||||||
|
//Clear any workflow schema related metadata
|
||||||
|
itemService
|
||||||
|
.clearMetadata(context, myitem, WorkflowRequirementsService.WORKFLOW_SCHEMA, Item.ANY, Item.ANY, Item.ANY);
|
||||||
|
|
||||||
|
itemService.update(context, myitem);
|
||||||
|
|
||||||
|
// remove policy for controller
|
||||||
|
removeUserItemPolicies(context, myitem, decliner);
|
||||||
|
revokeReviewerPolicies(context, myitem);
|
||||||
|
|
||||||
|
// convert into personal workspace
|
||||||
|
WorkspaceItem wsi = returnToWorkspace(context, wi);
|
||||||
|
|
||||||
|
// Because of issue of xmlWorkflowItemService not realising wfi wrapper has been deleted
|
||||||
|
context.commit();
|
||||||
|
wsi = context.reloadEntity(wsi);
|
||||||
|
|
||||||
|
log.info(LogHelper.getHeader(context, "decline_workflow", "workflow_item_id="
|
||||||
|
+ wi.getID() + "item_id=" + wi.getItem().getID() + "collection_id=" + wi.getCollection().getID() +
|
||||||
|
"eperson_id=" + decliner.getID()));
|
||||||
|
|
||||||
|
// Restart workflow
|
||||||
|
this.startWithoutNotify(context, wsi);
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the workflow item to the workspace of the submitter. The workflow
|
* Return the workflow item to the workspace of the submitter. The workflow
|
||||||
* item is removed, and a workspace item created.
|
* item is removed, and a workspace item created.
|
||||||
|
@@ -14,10 +14,15 @@ import java.util.List;
|
|||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
|
import org.dspace.content.DCDate;
|
||||||
|
import org.dspace.content.MetadataSchemaEnum;
|
||||||
|
import org.dspace.content.factory.ContentServiceFactory;
|
||||||
|
import org.dspace.content.service.ItemService;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.workflow.WorkflowException;
|
import org.dspace.workflow.WorkflowException;
|
||||||
import org.dspace.xmlworkflow.RoleMembers;
|
import org.dspace.xmlworkflow.RoleMembers;
|
||||||
import org.dspace.xmlworkflow.WorkflowConfigurationException;
|
import org.dspace.xmlworkflow.WorkflowConfigurationException;
|
||||||
|
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
||||||
import org.dspace.xmlworkflow.state.Step;
|
import org.dspace.xmlworkflow.state.Step;
|
||||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||||
|
|
||||||
@@ -37,6 +42,8 @@ public abstract class Action {
|
|||||||
|
|
||||||
private WorkflowActionConfig parent;
|
private WorkflowActionConfig parent;
|
||||||
private static final String ERROR_FIELDS_ATTRIBUTE = "dspace.workflow.error_fields";
|
private static final String ERROR_FIELDS_ATTRIBUTE = "dspace.workflow.error_fields";
|
||||||
|
private List<String> advancedOptions = new ArrayList<>();
|
||||||
|
private List<ActionAdvancedInfo> advancedInfo = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a workflow item becomes eligible for this Action.
|
* Called when a workflow item becomes eligible for this Action.
|
||||||
@@ -192,4 +199,58 @@ public abstract class Action {
|
|||||||
//save updated list
|
//save updated list
|
||||||
setErrorFields(request, errorFields);
|
setErrorFields(request, errorFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of advanced options that the user can select at this action
|
||||||
|
* @return A list of advanced options of this action, resulting in the next step of the workflow
|
||||||
|
*/
|
||||||
|
protected List<String> getAdvancedOptions() {
|
||||||
|
return advancedOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this Action has advanced options, false if it doesn't
|
||||||
|
* @return true if there are advanced options, false otherwise
|
||||||
|
*/
|
||||||
|
protected boolean isAdvanced() {
|
||||||
|
return !getAdvancedOptions().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of advanced info required by the advanced options
|
||||||
|
* @return A list of advanced info required by the advanced options
|
||||||
|
*/
|
||||||
|
protected List<ActionAdvancedInfo> getAdvancedInfo() {
|
||||||
|
return advancedInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds info in the metadata field dc.description.provenance about item being approved containing in which step
|
||||||
|
* it was approved, which user approved it and the time
|
||||||
|
*
|
||||||
|
* @param c DSpace contect
|
||||||
|
* @param wfi Workflow item we're adding workflow accept provenance on
|
||||||
|
*/
|
||||||
|
public void addApprovedProvenance(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
||||||
|
ItemService itemService = ContentServiceFactory.getInstance().getItemService();
|
||||||
|
|
||||||
|
//Add the provenance for the accept
|
||||||
|
String now = DCDate.getCurrent().toString();
|
||||||
|
|
||||||
|
// Get user's name + email address
|
||||||
|
String usersName =
|
||||||
|
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().getEPersonName(c.getCurrentUser());
|
||||||
|
|
||||||
|
String provDescription = getProvenanceStartId() + " Approved for entry into archive by " + usersName + " on "
|
||||||
|
+ now + " (GMT) ";
|
||||||
|
|
||||||
|
// Add to item as a DC field
|
||||||
|
c.turnOffAuthorisationSystem();
|
||||||
|
itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), "description", "provenance", "en",
|
||||||
|
provDescription);
|
||||||
|
itemService.update(c, wfi.getItem());
|
||||||
|
c.restoreAuthSystemState();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* 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.xmlworkflow.state.actions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for the shared properties of an 'advancedInfo' section of an advanced workflow {@link Action}
|
||||||
|
* Implementations of this class will define the specific fields per action that will need to be defined/configured
|
||||||
|
* to pass along this info to REST endpoint
|
||||||
|
*/
|
||||||
|
public abstract class ActionAdvancedInfo {
|
||||||
|
|
||||||
|
protected String type;
|
||||||
|
protected String id;
|
||||||
|
|
||||||
|
protected final static String TYPE_PREFIX = "action_info_";
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = TYPE_PREFIX + type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter for the Action id to be set.
|
||||||
|
* This is an MD5 hash of the type and the stringified properties of the advanced info
|
||||||
|
*
|
||||||
|
* @param type The type of this Action to be included in the MD5 hash
|
||||||
|
*/
|
||||||
|
protected abstract void generateId(String type);
|
||||||
|
|
||||||
|
}
|
@@ -69,4 +69,28 @@ public class WorkflowActionConfig {
|
|||||||
return this.processingAction.getOptions();
|
return this.processingAction.getOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of advanced options this user has on this action, resulting in the next step of the workflow
|
||||||
|
* @return A list of advanced options of this action, resulting in the next step of the workflow
|
||||||
|
*/
|
||||||
|
public List<String> getAdvancedOptions() {
|
||||||
|
return this.processingAction.getAdvancedOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a boolean depending on whether this action has advanced options
|
||||||
|
* @return The boolean indicating whether this action has advanced options
|
||||||
|
*/
|
||||||
|
public boolean isAdvanced() {
|
||||||
|
return this.processingAction.isAdvanced();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Map of info for the advanced options this user has on this action
|
||||||
|
* @return a Map of info for the advanced options this user has on this action
|
||||||
|
*/
|
||||||
|
public List<ActionAdvancedInfo> getAdvancedInfo() {
|
||||||
|
return this.processingAction.getAdvancedInfo();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -15,8 +15,6 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
|
|
||||||
import org.dspace.app.util.Util;
|
import org.dspace.app.util.Util;
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.content.DCDate;
|
|
||||||
import org.dspace.content.MetadataSchemaEnum;
|
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
||||||
import org.dspace.xmlworkflow.state.Step;
|
import org.dspace.xmlworkflow.state.Step;
|
||||||
@@ -34,8 +32,6 @@ import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
|||||||
*/
|
*/
|
||||||
public class AcceptEditRejectAction extends ProcessingAction {
|
public class AcceptEditRejectAction extends ProcessingAction {
|
||||||
|
|
||||||
private static final String SUBMIT_APPROVE = "submit_approve";
|
|
||||||
private static final String SUBMIT_REJECT = "submit_reject";
|
|
||||||
private static final String SUBMITTER_IS_DELETED_PAGE = "submitter_deleted";
|
private static final String SUBMITTER_IS_DELETED_PAGE = "submitter_deleted";
|
||||||
|
|
||||||
//TODO: rename to AcceptAndEditMetadataAction
|
//TODO: rename to AcceptAndEditMetadataAction
|
||||||
@@ -53,7 +49,7 @@ public class AcceptEditRejectAction extends ProcessingAction {
|
|||||||
case SUBMIT_APPROVE:
|
case SUBMIT_APPROVE:
|
||||||
return processAccept(c, wfi);
|
return processAccept(c, wfi);
|
||||||
case SUBMIT_REJECT:
|
case SUBMIT_REJECT:
|
||||||
return processRejectPage(c, wfi, request);
|
return super.processRejectPage(c, wfi, request);
|
||||||
case SUBMITTER_IS_DELETED_PAGE:
|
case SUBMITTER_IS_DELETED_PAGE:
|
||||||
return processSubmitterIsDeletedPage(c, wfi, request);
|
return processSubmitterIsDeletedPage(c, wfi, request);
|
||||||
default:
|
default:
|
||||||
@@ -69,33 +65,18 @@ public class AcceptEditRejectAction extends ProcessingAction {
|
|||||||
options.add(SUBMIT_APPROVE);
|
options.add(SUBMIT_APPROVE);
|
||||||
options.add(SUBMIT_REJECT);
|
options.add(SUBMIT_REJECT);
|
||||||
options.add(ProcessingAction.SUBMIT_EDIT_METADATA);
|
options.add(ProcessingAction.SUBMIT_EDIT_METADATA);
|
||||||
|
options.add(RETURN_TO_POOL);
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionResult processAccept(Context c, XmlWorkflowItem wfi)
|
public ActionResult processAccept(Context c, XmlWorkflowItem wfi)
|
||||||
throws SQLException, AuthorizeException {
|
throws SQLException, AuthorizeException {
|
||||||
//Delete the tasks
|
//Delete the tasks
|
||||||
addApprovedProvenance(c, wfi);
|
super.addApprovedProvenance(c, wfi);
|
||||||
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionResult processRejectPage(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
|
||||||
throws SQLException, AuthorizeException, IOException {
|
|
||||||
String reason = request.getParameter("reason");
|
|
||||||
if (reason == null || 0 == reason.trim().length()) {
|
|
||||||
addErrorField(request, "reason");
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have pressed reject, so remove the task the user has & put it back
|
|
||||||
// to a workspace item
|
|
||||||
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().sendWorkflowItemBackSubmission(c, wfi,
|
|
||||||
c.getCurrentUser(), this.getProvenanceStartId(), reason);
|
|
||||||
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionResult processSubmitterIsDeletedPage(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
public ActionResult processSubmitterIsDeletedPage(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
||||||
throws SQLException, AuthorizeException, IOException {
|
throws SQLException, AuthorizeException, IOException {
|
||||||
if (request.getParameter("submit_delete") != null) {
|
if (request.getParameter("submit_delete") != null) {
|
||||||
@@ -111,21 +92,4 @@ public class AcceptEditRejectAction extends ProcessingAction {
|
|||||||
return new ActionResult(ActionResult.TYPE.TYPE_PAGE);
|
return new ActionResult(ActionResult.TYPE.TYPE_PAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addApprovedProvenance(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
|
||||||
//Add the provenance for the accept
|
|
||||||
String now = DCDate.getCurrent().toString();
|
|
||||||
|
|
||||||
// Get user's name + email address
|
|
||||||
String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
|
||||||
.getEPersonName(c.getCurrentUser());
|
|
||||||
|
|
||||||
String provDescription = getProvenanceStartId() + " Approved for entry into archive by "
|
|
||||||
+ usersName + " on " + now + " (GMT) ";
|
|
||||||
|
|
||||||
// Add to item as a DC field
|
|
||||||
itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), "description", "provenance", "en",
|
|
||||||
provDescription);
|
|
||||||
itemService.update(c, wfi.getItem());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -14,10 +14,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
|
|
||||||
import org.dspace.app.util.Util;
|
import org.dspace.app.util.Util;
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.content.DCDate;
|
|
||||||
import org.dspace.content.MetadataSchemaEnum;
|
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
|
||||||
import org.dspace.xmlworkflow.state.Step;
|
import org.dspace.xmlworkflow.state.Step;
|
||||||
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
||||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||||
@@ -52,7 +49,7 @@ public class FinalEditAction extends ProcessingAction {
|
|||||||
switch (Util.getSubmitButton(request, SUBMIT_CANCEL)) {
|
switch (Util.getSubmitButton(request, SUBMIT_CANCEL)) {
|
||||||
case SUBMIT_APPROVE:
|
case SUBMIT_APPROVE:
|
||||||
//Delete the tasks
|
//Delete the tasks
|
||||||
addApprovedProvenance(c, wfi);
|
super.addApprovedProvenance(c, wfi);
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||||
default:
|
default:
|
||||||
//We pressed the leave button so return to our submissions page
|
//We pressed the leave button so return to our submissions page
|
||||||
@@ -67,25 +64,8 @@ public class FinalEditAction extends ProcessingAction {
|
|||||||
List<String> options = new ArrayList<>();
|
List<String> options = new ArrayList<>();
|
||||||
options.add(SUBMIT_APPROVE);
|
options.add(SUBMIT_APPROVE);
|
||||||
options.add(ProcessingAction.SUBMIT_EDIT_METADATA);
|
options.add(ProcessingAction.SUBMIT_EDIT_METADATA);
|
||||||
|
options.add(RETURN_TO_POOL);
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addApprovedProvenance(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
|
||||||
//Add the provenance for the accept
|
|
||||||
String now = DCDate.getCurrent().toString();
|
|
||||||
|
|
||||||
// Get user's name + email address
|
|
||||||
String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
|
||||||
.getEPersonName(c.getCurrentUser());
|
|
||||||
|
|
||||||
String provDescription = getProvenanceStartId() + " Approved for entry into archive by "
|
|
||||||
+ usersName + " on " + now + " (GMT) ";
|
|
||||||
|
|
||||||
// Add to item as a DC field
|
|
||||||
itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), "description", "provenance", "en",
|
|
||||||
provDescription);
|
|
||||||
itemService.update(c, wfi.getItem());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -7,12 +7,16 @@
|
|||||||
*/
|
*/
|
||||||
package org.dspace.xmlworkflow.state.actions.processingaction;
|
package org.dspace.xmlworkflow.state.actions.processingaction;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.content.service.ItemService;
|
import org.dspace.content.service.ItemService;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.xmlworkflow.service.XmlWorkflowService;
|
||||||
import org.dspace.xmlworkflow.state.actions.Action;
|
import org.dspace.xmlworkflow.state.actions.Action;
|
||||||
|
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
||||||
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.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService;
|
import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService;
|
||||||
@@ -32,9 +36,15 @@ public abstract class ProcessingAction extends Action {
|
|||||||
protected ClaimedTaskService claimedTaskService;
|
protected ClaimedTaskService claimedTaskService;
|
||||||
@Autowired(required = true)
|
@Autowired(required = true)
|
||||||
protected ItemService itemService;
|
protected ItemService itemService;
|
||||||
|
@Autowired
|
||||||
|
protected XmlWorkflowService xmlWorkflowService;
|
||||||
|
|
||||||
public static final String SUBMIT_EDIT_METADATA = "submit_edit_metadata";
|
public static final String SUBMIT_EDIT_METADATA = "submit_edit_metadata";
|
||||||
public static final String SUBMIT_CANCEL = "submit_cancel";
|
public static final String SUBMIT_CANCEL = "submit_cancel";
|
||||||
|
protected static final String SUBMIT_APPROVE = "submit_approve";
|
||||||
|
protected static final String SUBMIT_REJECT = "submit_reject";
|
||||||
|
protected static final String RETURN_TO_POOL = "return_to_pool";
|
||||||
|
protected static final String REJECT_REASON = "reason";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAuthorized(Context context, HttpServletRequest request, XmlWorkflowItem wfi) throws SQLException {
|
public boolean isAuthorized(Context context, HttpServletRequest request, XmlWorkflowItem wfi) throws SQLException {
|
||||||
@@ -48,4 +58,31 @@ public abstract class ProcessingAction extends Action {
|
|||||||
task.getStepID().equals(getParent().getStep().getId()) &&
|
task.getStepID().equals(getParent().getStep().getId()) &&
|
||||||
task.getActionID().equals(getParent().getId());
|
task.getActionID().equals(getParent().getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process result when option {@link this#SUBMIT_REJECT} is selected.
|
||||||
|
* - Sets the reason and workflow step responsible on item in dc.description.provenance
|
||||||
|
* - Send workflow back to the submission
|
||||||
|
* If reason is not given => error
|
||||||
|
*/
|
||||||
|
public ActionResult processRejectPage(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
||||||
|
throws SQLException, AuthorizeException, IOException {
|
||||||
|
String reason = request.getParameter(REJECT_REASON);
|
||||||
|
if (reason == null || 0 == reason.trim().length()) {
|
||||||
|
addErrorField(request, REJECT_REASON);
|
||||||
|
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have pressed reject, so remove the task the user has & put it back
|
||||||
|
// to a workspace item
|
||||||
|
xmlWorkflowService.sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(), this.getProvenanceStartId(),
|
||||||
|
reason);
|
||||||
|
|
||||||
|
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isAdvanced() {
|
||||||
|
return !getAdvancedOptions().isEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,8 +15,6 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
|
|
||||||
import org.dspace.app.util.Util;
|
import org.dspace.app.util.Util;
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.content.DCDate;
|
|
||||||
import org.dspace.content.MetadataSchemaEnum;
|
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
||||||
import org.dspace.xmlworkflow.state.Step;
|
import org.dspace.xmlworkflow.state.Step;
|
||||||
@@ -36,11 +34,8 @@ public class ReviewAction extends ProcessingAction {
|
|||||||
public static final int MAIN_PAGE = 0;
|
public static final int MAIN_PAGE = 0;
|
||||||
public static final int REJECT_PAGE = 1;
|
public static final int REJECT_PAGE = 1;
|
||||||
|
|
||||||
private static final String SUBMIT_APPROVE = "submit_approve";
|
|
||||||
private static final String SUBMIT_REJECT = "submit_reject";
|
|
||||||
private static final String SUBMITTER_IS_DELETED_PAGE = "submitter_deleted";
|
private static final String SUBMITTER_IS_DELETED_PAGE = "submitter_deleted";
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activate(Context c, XmlWorkflowItem wfItem) {
|
public void activate(Context c, XmlWorkflowItem wfItem) {
|
||||||
|
|
||||||
@@ -54,7 +49,7 @@ public class ReviewAction extends ProcessingAction {
|
|||||||
case SUBMIT_APPROVE:
|
case SUBMIT_APPROVE:
|
||||||
return processAccept(c, wfi);
|
return processAccept(c, wfi);
|
||||||
case SUBMIT_REJECT:
|
case SUBMIT_REJECT:
|
||||||
return processRejectPage(c, wfi, step, request);
|
return super.processRejectPage(c, wfi, request);
|
||||||
case SUBMITTER_IS_DELETED_PAGE:
|
case SUBMITTER_IS_DELETED_PAGE:
|
||||||
return processSubmitterIsDeletedPage(c, wfi, request);
|
return processSubmitterIsDeletedPage(c, wfi, request);
|
||||||
default:
|
default:
|
||||||
@@ -69,50 +64,15 @@ public class ReviewAction extends ProcessingAction {
|
|||||||
List<String> options = new ArrayList<>();
|
List<String> options = new ArrayList<>();
|
||||||
options.add(SUBMIT_APPROVE);
|
options.add(SUBMIT_APPROVE);
|
||||||
options.add(SUBMIT_REJECT);
|
options.add(SUBMIT_REJECT);
|
||||||
|
options.add(RETURN_TO_POOL);
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionResult processAccept(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
public ActionResult processAccept(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
||||||
//Delete the tasks
|
super.addApprovedProvenance(c, wfi);
|
||||||
addApprovedProvenance(c, wfi);
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addApprovedProvenance(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
|
||||||
//Add the provenance for the accept
|
|
||||||
String now = DCDate.getCurrent().toString();
|
|
||||||
|
|
||||||
// Get user's name + email address
|
|
||||||
String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
|
||||||
.getEPersonName(c.getCurrentUser());
|
|
||||||
|
|
||||||
String provDescription = getProvenanceStartId() + " Approved for entry into archive by "
|
|
||||||
+ usersName + " on " + now + " (GMT) ";
|
|
||||||
|
|
||||||
// Add to item as a DC field
|
|
||||||
itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), "description", "provenance", "en",
|
|
||||||
provDescription);
|
|
||||||
itemService.update(c, wfi.getItem());
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionResult processRejectPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
|
||||||
throws SQLException, AuthorizeException, IOException {
|
|
||||||
String reason = request.getParameter("reason");
|
|
||||||
if (reason == null || 0 == reason.trim().length()) {
|
|
||||||
request.setAttribute("page", REJECT_PAGE);
|
|
||||||
addErrorField(request, "reason");
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
//We have pressed reject, so remove the task the user has & put it back to a workspace item
|
|
||||||
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
|
||||||
.sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(),
|
|
||||||
this.getProvenanceStartId(), reason);
|
|
||||||
|
|
||||||
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionResult processSubmitterIsDeletedPage(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
public ActionResult processSubmitterIsDeletedPage(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
||||||
throws SQLException, AuthorizeException, IOException {
|
throws SQLException, AuthorizeException, IOException {
|
||||||
if (request.getParameter("submit_delete") != null) {
|
if (request.getParameter("submit_delete") != null) {
|
||||||
|
@@ -7,6 +7,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.dspace.xmlworkflow.state.actions.processingaction;
|
package org.dspace.xmlworkflow.state.actions.processingaction;
|
||||||
|
|
||||||
|
import static org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewAction.REVIEW_FIELD;
|
||||||
|
import static org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewAction.SCORE_FIELD;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -19,7 +22,6 @@ import org.dspace.content.MetadataSchemaEnum;
|
|||||||
import org.dspace.content.MetadataValue;
|
import org.dspace.content.MetadataValue;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
||||||
import org.dspace.xmlworkflow.service.WorkflowRequirementsService;
|
|
||||||
import org.dspace.xmlworkflow.state.Step;
|
import org.dspace.xmlworkflow.state.Step;
|
||||||
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
||||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||||
@@ -37,6 +39,7 @@ import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
|||||||
*/
|
*/
|
||||||
public class ScoreEvaluationAction extends ProcessingAction {
|
public class ScoreEvaluationAction extends ProcessingAction {
|
||||||
|
|
||||||
|
// Minimum aggregate of scores
|
||||||
private int minimumAcceptanceScore;
|
private int minimumAcceptanceScore;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -47,43 +50,64 @@ public class ScoreEvaluationAction extends ProcessingAction {
|
|||||||
@Override
|
@Override
|
||||||
public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
||||||
throws SQLException, AuthorizeException, IOException {
|
throws SQLException, AuthorizeException, IOException {
|
||||||
boolean hasPassed = false;
|
// Retrieve all our scores from the metadata & add em up
|
||||||
//Retrieve all our scores from the metadata & add em up
|
int scoreMean = getMeanScore(wfi);
|
||||||
List<MetadataValue> scores = itemService
|
|
||||||
.getMetadata(wfi.getItem(), WorkflowRequirementsService.WORKFLOW_SCHEMA, "score", null, Item.ANY);
|
|
||||||
if (0 < scores.size()) {
|
|
||||||
int totalScoreCount = 0;
|
|
||||||
for (MetadataValue score : scores) {
|
|
||||||
totalScoreCount += Integer.parseInt(score.getValue());
|
|
||||||
}
|
|
||||||
int scoreMean = totalScoreCount / scores.size();
|
|
||||||
//We have passed if we have at least gained our minimum score
|
//We have passed if we have at least gained our minimum score
|
||||||
hasPassed = getMinimumAcceptanceScore() <= scoreMean;
|
boolean hasPassed = getMinimumAcceptanceScore() <= scoreMean;
|
||||||
//Wether or not we have passed, clear our score information
|
//Whether or not we have passed, clear our score information
|
||||||
itemService
|
itemService.clearMetadata(c, wfi.getItem(), SCORE_FIELD.schema, SCORE_FIELD.element, SCORE_FIELD.qualifier,
|
||||||
.clearMetadata(c, wfi.getItem(), WorkflowRequirementsService.WORKFLOW_SCHEMA, "score", null, Item.ANY);
|
Item.ANY);
|
||||||
|
|
||||||
String provDescription = getProvenanceStartId() + " Approved for entry into archive with a score of: " +
|
|
||||||
scoreMean;
|
|
||||||
itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(),
|
|
||||||
"description", "provenance", "en", provDescription);
|
|
||||||
itemService.update(c, wfi.getItem());
|
|
||||||
}
|
|
||||||
if (hasPassed) {
|
if (hasPassed) {
|
||||||
|
this.addRatingInfoToProv(c, wfi, scoreMean);
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||||
} else {
|
} else {
|
||||||
//We haven't passed, reject our item
|
//We haven't passed, reject our item
|
||||||
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||||
.sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(),
|
.sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(), this.getProvenanceStartId(),
|
||||||
this.getProvenanceStartId(),
|
|
||||||
"The item was reject due to a bad review score.");
|
"The item was reject due to a bad review score.");
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getMeanScore(XmlWorkflowItem wfi) {
|
||||||
|
List<MetadataValue> scores = itemService
|
||||||
|
.getMetadata(wfi.getItem(), SCORE_FIELD.schema, SCORE_FIELD.element, SCORE_FIELD.qualifier, Item.ANY);
|
||||||
|
int scoreMean = 0;
|
||||||
|
if (0 < scores.size()) {
|
||||||
|
int totalScoreCount = 0;
|
||||||
|
for (MetadataValue score : scores) {
|
||||||
|
totalScoreCount += Integer.parseInt(score.getValue());
|
||||||
|
}
|
||||||
|
scoreMean = totalScoreCount / scores.size();
|
||||||
|
}
|
||||||
|
return scoreMean;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addRatingInfoToProv(Context c, XmlWorkflowItem wfi, int scoreMean)
|
||||||
|
throws SQLException, AuthorizeException {
|
||||||
|
StringBuilder provDescription = new StringBuilder();
|
||||||
|
provDescription.append(String.format("%s Approved for entry into archive with a score of: %s",
|
||||||
|
getProvenanceStartId(), scoreMean));
|
||||||
|
List<MetadataValue> reviews = itemService
|
||||||
|
.getMetadata(wfi.getItem(), REVIEW_FIELD.schema, REVIEW_FIELD.element, REVIEW_FIELD.qualifier, Item.ANY);
|
||||||
|
if (!reviews.isEmpty()) {
|
||||||
|
provDescription.append(" | Reviews: ");
|
||||||
|
}
|
||||||
|
for (MetadataValue review : reviews) {
|
||||||
|
provDescription.append(String.format("; %s", review.getValue()));
|
||||||
|
}
|
||||||
|
c.turnOffAuthorisationSystem();
|
||||||
|
itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(),
|
||||||
|
"description", "provenance", "en", provDescription.toString());
|
||||||
|
itemService.update(c, wfi.getItem());
|
||||||
|
c.restoreAuthSystemState();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getOptions() {
|
public List<String> getOptions() {
|
||||||
return new ArrayList<>();
|
List<String> options = new ArrayList<>();
|
||||||
|
options.add(RETURN_TO_POOL);
|
||||||
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMinimumAcceptanceScore() {
|
public int getMinimumAcceptanceScore() {
|
||||||
|
@@ -9,14 +9,20 @@ package org.dspace.xmlworkflow.state.actions.processingaction;
|
|||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.dspace.app.util.Util;
|
import org.dspace.app.util.Util;
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
|
import org.dspace.content.MetadataFieldName;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.xmlworkflow.service.WorkflowRequirementsService;
|
import org.dspace.xmlworkflow.service.WorkflowRequirementsService;
|
||||||
import org.dspace.xmlworkflow.state.Step;
|
import org.dspace.xmlworkflow.state.Step;
|
||||||
|
import org.dspace.xmlworkflow.state.actions.ActionAdvancedInfo;
|
||||||
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
||||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||||
|
|
||||||
@@ -24,40 +30,121 @@ import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
|||||||
* This action will allow multiple users to rate a certain item
|
* This action will allow multiple users to rate a certain item
|
||||||
* if the mean of this score is higher then the minimum score the
|
* if the mean of this score is higher then the minimum score the
|
||||||
* item will be sent to the next action/step else it will be rejected
|
* item will be sent to the next action/step else it will be rejected
|
||||||
*
|
|
||||||
* @author Bram De Schouwer (bram.deschouwer at dot com)
|
|
||||||
* @author Kevin Van de Velde (kevin at atmire dot com)
|
|
||||||
* @author Ben Bosman (ben at atmire dot com)
|
|
||||||
* @author Mark Diggory (markd at atmire dot com)
|
|
||||||
*/
|
*/
|
||||||
public class ScoreReviewAction extends ProcessingAction {
|
public class ScoreReviewAction extends ProcessingAction {
|
||||||
|
private static final Logger log = LogManager.getLogger(ScoreReviewAction.class);
|
||||||
|
|
||||||
private static final String SUBMIT_SCORE = "submit_score";
|
// Option(s)
|
||||||
|
public static final String SUBMIT_SCORE = "submit_score";
|
||||||
|
|
||||||
|
// Response param(s)
|
||||||
|
private static final String SCORE = "score";
|
||||||
|
private static final String REVIEW = "review";
|
||||||
|
|
||||||
|
// Metadata fields to save params in
|
||||||
|
public static final MetadataFieldName SCORE_FIELD =
|
||||||
|
new MetadataFieldName(WorkflowRequirementsService.WORKFLOW_SCHEMA, SCORE, null);
|
||||||
|
public static final MetadataFieldName REVIEW_FIELD =
|
||||||
|
new MetadataFieldName(WorkflowRequirementsService.WORKFLOW_SCHEMA, REVIEW, null);
|
||||||
|
|
||||||
|
// Whether or not it is required that a text review is added to the rating
|
||||||
|
private boolean descriptionRequired;
|
||||||
|
// Maximum value rating is allowed to be
|
||||||
|
private int maxValue;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activate(Context c, XmlWorkflowItem wf) {
|
public void activate(Context c, XmlWorkflowItem wf) {
|
||||||
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
||||||
throws SQLException, AuthorizeException {
|
throws SQLException, AuthorizeException {
|
||||||
if (request.getParameter(SUBMIT_SCORE) != null) {
|
if (super.isOptionInParam(request) &&
|
||||||
int score = Util.getIntParameter(request, "score");
|
StringUtils.equalsIgnoreCase(Util.getSubmitButton(request, SUBMIT_CANCEL), SUBMIT_SCORE)) {
|
||||||
//Add our score to the metadata
|
return processSetRating(c, wfi, request);
|
||||||
itemService.addMetadata(c, wfi.getItem(), WorkflowRequirementsService.WORKFLOW_SCHEMA, "score", null, null,
|
}
|
||||||
|
return new ActionResult(ActionResult.TYPE.TYPE_CANCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ActionResult processSetRating(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
||||||
|
throws SQLException, AuthorizeException {
|
||||||
|
|
||||||
|
int score = Util.getIntParameter(request, SCORE);
|
||||||
|
String review = request.getParameter(REVIEW);
|
||||||
|
if (!this.checkRequestValid(score, review)) {
|
||||||
|
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
||||||
|
}
|
||||||
|
//Add our rating and review to the metadata
|
||||||
|
itemService.addMetadata(c, wfi.getItem(), SCORE_FIELD.schema, SCORE_FIELD.element, SCORE_FIELD.qualifier, null,
|
||||||
String.valueOf(score));
|
String.valueOf(score));
|
||||||
|
if (StringUtils.isNotBlank(review)) {
|
||||||
|
itemService.addMetadata(c, wfi.getItem(), REVIEW_FIELD.schema, REVIEW_FIELD.element,
|
||||||
|
REVIEW_FIELD.qualifier, null, String.format("%s - %s", score, review));
|
||||||
|
}
|
||||||
itemService.update(c, wfi.getItem());
|
itemService.update(c, wfi.getItem());
|
||||||
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||||
} else {
|
|
||||||
//We have pressed the leave button so return to our submission page
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request is not valid if:
|
||||||
|
* - Given score is higher than configured maxValue
|
||||||
|
* - There is no review given and description is configured to be required
|
||||||
|
* Config in workflow-actions.xml
|
||||||
|
*
|
||||||
|
* @param score Given score rating from request
|
||||||
|
* @param review Given review/description from request
|
||||||
|
* @return True if valid request params with config, otherwise false
|
||||||
|
*/
|
||||||
|
private boolean checkRequestValid(int score, String review) {
|
||||||
|
if (score > this.maxValue) {
|
||||||
|
log.error("{} only allows max rating {} (config workflow-actions.xml), given rating of " +
|
||||||
|
"{} not allowed.", this.getClass().toString(), this.maxValue, score);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(review) && this.descriptionRequired) {
|
||||||
|
log.error("{} has config descriptionRequired=true (workflow-actions.xml), so rating " +
|
||||||
|
"requests without 'review' query param containing description are not allowed",
|
||||||
|
this.getClass().toString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getOptions() {
|
public List<String> getOptions() {
|
||||||
|
return List.of(SUBMIT_SCORE, RETURN_TO_POOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getAdvancedOptions() {
|
||||||
return Arrays.asList(SUBMIT_SCORE);
|
return Arrays.asList(SUBMIT_SCORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<ActionAdvancedInfo> getAdvancedInfo() {
|
||||||
|
ScoreReviewActionAdvancedInfo scoreReviewActionAdvancedInfo = new ScoreReviewActionAdvancedInfo();
|
||||||
|
scoreReviewActionAdvancedInfo.setDescriptionRequired(descriptionRequired);
|
||||||
|
scoreReviewActionAdvancedInfo.setMaxValue(maxValue);
|
||||||
|
scoreReviewActionAdvancedInfo.setType(SUBMIT_SCORE);
|
||||||
|
scoreReviewActionAdvancedInfo.generateId(SUBMIT_SCORE);
|
||||||
|
return Collections.singletonList(scoreReviewActionAdvancedInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter that sets the descriptionRequired property from workflow-actions.xml
|
||||||
|
* @param descriptionRequired boolean whether a description is required
|
||||||
|
*/
|
||||||
|
public void setDescriptionRequired(boolean descriptionRequired) {
|
||||||
|
this.descriptionRequired = descriptionRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter that sets the maxValue property from workflow-actions.xml
|
||||||
|
* @param maxValue integer of the maximum allowed value
|
||||||
|
*/
|
||||||
|
public void setMaxValue(int maxValue) {
|
||||||
|
this.maxValue = maxValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* 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.xmlworkflow.state.actions.processingaction;
|
||||||
|
|
||||||
|
import org.dspace.xmlworkflow.state.actions.ActionAdvancedInfo;
|
||||||
|
import org.springframework.util.DigestUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that holds the advanced information needed for the
|
||||||
|
* {@link org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewAction}
|
||||||
|
* See config {@code workflow-actions.cfg}
|
||||||
|
*/
|
||||||
|
public class ScoreReviewActionAdvancedInfo extends ActionAdvancedInfo {
|
||||||
|
private boolean descriptionRequired;
|
||||||
|
private int maxValue;
|
||||||
|
|
||||||
|
public boolean isDescriptionRequired() {
|
||||||
|
return descriptionRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescriptionRequired(boolean descriptionRequired) {
|
||||||
|
this.descriptionRequired = descriptionRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxValue() {
|
||||||
|
return maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxValue(int maxValue) {
|
||||||
|
this.maxValue = maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateId(String type) {
|
||||||
|
String idString = type
|
||||||
|
+ ";descriptionRequired," + descriptionRequired
|
||||||
|
+ ";maxValue," + maxValue;
|
||||||
|
super.id = DigestUtils.md5DigestAsHex(idString.getBytes());
|
||||||
|
}
|
||||||
|
}
|
@@ -9,17 +9,27 @@ package org.dspace.xmlworkflow.state.actions.processingaction;
|
|||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.ArrayUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.dspace.app.util.Util;
|
import org.dspace.app.util.Util;
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
|
import org.dspace.eperson.Group;
|
||||||
import org.dspace.eperson.service.EPersonService;
|
import org.dspace.eperson.service.EPersonService;
|
||||||
|
import org.dspace.eperson.service.GroupService;
|
||||||
|
import org.dspace.services.ConfigurationService;
|
||||||
import org.dspace.xmlworkflow.Role;
|
import org.dspace.xmlworkflow.Role;
|
||||||
import org.dspace.xmlworkflow.state.Step;
|
import org.dspace.xmlworkflow.state.Step;
|
||||||
|
import org.dspace.xmlworkflow.state.actions.ActionAdvancedInfo;
|
||||||
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
||||||
import org.dspace.xmlworkflow.storedcomponents.WorkflowItemRole;
|
import org.dspace.xmlworkflow.storedcomponents.WorkflowItemRole;
|
||||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||||
@@ -37,13 +47,13 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
*/
|
*/
|
||||||
public class SelectReviewerAction extends ProcessingAction {
|
public class SelectReviewerAction extends ProcessingAction {
|
||||||
|
|
||||||
public static final int SEARCH_RESULTS_PAGE = 1;
|
private static final Logger log = LogManager.getLogger(SelectReviewerAction.class);
|
||||||
|
|
||||||
public static final int RESULTS_PER_PAGE = 5;
|
|
||||||
|
|
||||||
private static final String SUBMIT_CANCEL = "submit_cancel";
|
private static final String SUBMIT_CANCEL = "submit_cancel";
|
||||||
private static final String SUBMIT_SEARCH = "submit_search";
|
private static final String SUBMIT_SELECT_REVIEWER = "submit_select_reviewer";
|
||||||
private static final String SUBMIT_SELECT_REVIEWER = "submit_select_reviewer_";
|
private static final String PARAM_REVIEWER = "eperson";
|
||||||
|
|
||||||
|
private static final String CONFIG_REVIEWER_GROUP = "action.selectrevieweraction.group";
|
||||||
|
|
||||||
private Role role;
|
private Role role;
|
||||||
|
|
||||||
@@ -53,6 +63,15 @@ public class SelectReviewerAction extends ProcessingAction {
|
|||||||
@Autowired(required = true)
|
@Autowired(required = true)
|
||||||
private WorkflowItemRoleService workflowItemRoleService;
|
private WorkflowItemRoleService workflowItemRoleService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ConfigurationService configurationService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GroupService groupService;
|
||||||
|
|
||||||
|
private static Group selectFromReviewsGroup;
|
||||||
|
private static boolean selectFromReviewsGroupInitialised = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activate(Context c, XmlWorkflowItem wf) {
|
public void activate(Context c, XmlWorkflowItem wf) {
|
||||||
|
|
||||||
@@ -67,49 +86,121 @@ public class SelectReviewerAction extends ProcessingAction {
|
|||||||
if (submitButton.equals(SUBMIT_CANCEL)) {
|
if (submitButton.equals(SUBMIT_CANCEL)) {
|
||||||
//Send us back to the submissions page
|
//Send us back to the submissions page
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_CANCEL);
|
return new ActionResult(ActionResult.TYPE.TYPE_CANCEL);
|
||||||
|
|
||||||
} else if (submitButton.equals(SUBMIT_SEARCH)) {
|
|
||||||
//Perform the search
|
|
||||||
String query = request.getParameter("query");
|
|
||||||
int page = Util.getIntParameter(request, "result-page");
|
|
||||||
if (page == -1) {
|
|
||||||
page = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int resultCount = ePersonService.searchResultCount(c, query);
|
|
||||||
List<EPerson> epeople = ePersonService.search(c, query, page * RESULTS_PER_PAGE, RESULTS_PER_PAGE);
|
|
||||||
|
|
||||||
|
|
||||||
request.setAttribute("eperson-result-count", resultCount);
|
|
||||||
request.setAttribute("eperson-results", epeople);
|
|
||||||
request.setAttribute("result-page", page);
|
|
||||||
request.setAttribute("page", SEARCH_RESULTS_PAGE);
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_PAGE, SEARCH_RESULTS_PAGE);
|
|
||||||
} else if (submitButton.startsWith(SUBMIT_SELECT_REVIEWER)) {
|
} else if (submitButton.startsWith(SUBMIT_SELECT_REVIEWER)) {
|
||||||
//Retrieve the identifier of the eperson which will do the reviewing
|
return processSelectReviewers(c, wfi, request);
|
||||||
UUID reviewerId = UUID.fromString(submitButton.substring(submitButton.lastIndexOf("_") + 1));
|
|
||||||
EPerson reviewer = ePersonService.find(c, reviewerId);
|
|
||||||
//Assign the reviewer. The workflowitemrole will be translated into a task in the autoassign
|
|
||||||
WorkflowItemRole workflowItemRole = workflowItemRoleService.create(c);
|
|
||||||
workflowItemRole.setEPerson(reviewer);
|
|
||||||
workflowItemRole.setRoleId(getRole().getId());
|
|
||||||
workflowItemRole.setWorkflowItem(wfi);
|
|
||||||
workflowItemRoleService.update(c, workflowItemRole);
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//There are only 2 active buttons on this page, so if anything else happens just return an error
|
//There are only 2 active buttons on this page, so if anything else happens just return an error
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to handle the {@link this#SUBMIT_SELECT_REVIEWER} action:
|
||||||
|
* - will retrieve the reviewer(s) uuid from request (param {@link this#PARAM_REVIEWER})
|
||||||
|
* - assign them to a {@link WorkflowItemRole}
|
||||||
|
* - In {@link org.dspace.xmlworkflow.state.actions.userassignment.AutoAssignAction} these reviewer(s) will get
|
||||||
|
* claimed task for this {@link XmlWorkflowItem}
|
||||||
|
* Will result in error if:
|
||||||
|
* - No reviewer(s) uuid in request (param {@link this#PARAM_REVIEWER})
|
||||||
|
* - If none of the reviewer(s) uuid passed along result in valid EPerson
|
||||||
|
* - If the reviewer(s) passed along are not in {@link this#selectFromReviewsGroup} when it is set
|
||||||
|
*
|
||||||
|
* @param c current DSpace session
|
||||||
|
* @param wfi the item on which the action is to be performed
|
||||||
|
* @param request the current client request
|
||||||
|
* @return the result of performing the action
|
||||||
|
*/
|
||||||
|
private ActionResult processSelectReviewers(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
||||||
|
throws SQLException, AuthorizeException {
|
||||||
|
//Retrieve the identifier of the eperson which will do the reviewing
|
||||||
|
String[] reviewerIds = request.getParameterValues(PARAM_REVIEWER);
|
||||||
|
if (ArrayUtils.isEmpty(reviewerIds)) {
|
||||||
|
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
||||||
|
}
|
||||||
|
List<EPerson> reviewers = new ArrayList<>();
|
||||||
|
for (String reviewerId : reviewerIds) {
|
||||||
|
EPerson reviewer = ePersonService.find(c, UUID.fromString(reviewerId));
|
||||||
|
if (reviewer == null) {
|
||||||
|
log.warn("No EPerson found with uuid {}", reviewerId);
|
||||||
|
} else {
|
||||||
|
reviewers.add(reviewer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.checkReviewersValid(c, reviewers)) {
|
||||||
|
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
createWorkflowItemRole(c, wfi, reviewers);
|
||||||
|
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkReviewersValid(Context c, List<EPerson> reviewers) throws SQLException {
|
||||||
|
if (reviewers.size() == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Group group = this.getGroup(c);
|
||||||
|
if (group != null) {
|
||||||
|
for (EPerson reviewer: reviewers) {
|
||||||
|
if (!groupService.isMember(c, reviewer, group)) {
|
||||||
|
log.error("Reviewers selected must be member of group {}", group.getID());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private WorkflowItemRole createWorkflowItemRole(Context c, XmlWorkflowItem wfi, List<EPerson> reviewers)
|
||||||
|
throws SQLException, AuthorizeException {
|
||||||
|
WorkflowItemRole workflowItemRole = workflowItemRoleService.create(c);
|
||||||
|
workflowItemRole.setRoleId(getRole().getId());
|
||||||
|
workflowItemRole.setWorkflowItem(wfi);
|
||||||
|
if (reviewers.size() == 1) {
|
||||||
|
// 1 reviewer in workflowitemrole => will be translated into a claimed task in the autoassign
|
||||||
|
workflowItemRole.setEPerson(reviewers.get(0));
|
||||||
|
} else {
|
||||||
|
// multiple reviewers, create a temporary group and assign this group, the workflowitemrole will be
|
||||||
|
// translated into a claimed task for reviewers in the autoassign, where group will be deleted
|
||||||
|
c.turnOffAuthorisationSystem();
|
||||||
|
Group selectedReviewsGroup = groupService.create(c);
|
||||||
|
groupService.setName(selectedReviewsGroup, "selectedReviewsGroup_" + wfi.getID());
|
||||||
|
for (EPerson reviewer : reviewers) {
|
||||||
|
groupService.addMember(c, selectedReviewsGroup, reviewer);
|
||||||
|
}
|
||||||
|
workflowItemRole.setGroup(selectedReviewsGroup);
|
||||||
|
c.restoreAuthSystemState();
|
||||||
|
}
|
||||||
|
workflowItemRoleService.update(c, workflowItemRole);
|
||||||
|
return workflowItemRole;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getOptions() {
|
public List<String> getOptions() {
|
||||||
List<String> options = new ArrayList<>();
|
List<String> options = new ArrayList<>();
|
||||||
options.add(SUBMIT_SEARCH);
|
|
||||||
options.add(SUBMIT_SELECT_REVIEWER);
|
options.add(SUBMIT_SELECT_REVIEWER);
|
||||||
|
options.add(RETURN_TO_POOL);
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getAdvancedOptions() {
|
||||||
|
return Arrays.asList(SUBMIT_SELECT_REVIEWER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<ActionAdvancedInfo> getAdvancedInfo() {
|
||||||
|
List<ActionAdvancedInfo> advancedInfo = new ArrayList<>();
|
||||||
|
SelectReviewerActionAdvancedInfo selectReviewerActionAdvancedInfo = new SelectReviewerActionAdvancedInfo();
|
||||||
|
if (getGroup(null) != null) {
|
||||||
|
selectReviewerActionAdvancedInfo.setGroup(getGroup(null).getID().toString());
|
||||||
|
}
|
||||||
|
selectReviewerActionAdvancedInfo.setType(SUBMIT_SELECT_REVIEWER);
|
||||||
|
selectReviewerActionAdvancedInfo.generateId(SUBMIT_SELECT_REVIEWER);
|
||||||
|
advancedInfo.add(selectReviewerActionAdvancedInfo);
|
||||||
|
return advancedInfo;
|
||||||
|
}
|
||||||
|
|
||||||
public Role getRole() {
|
public Role getRole() {
|
||||||
return role;
|
return role;
|
||||||
}
|
}
|
||||||
@@ -118,4 +209,49 @@ public class SelectReviewerAction extends ProcessingAction {
|
|||||||
public void setRole(Role role) {
|
public void setRole(Role role) {
|
||||||
this.role = role;
|
this.role = role;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Reviewer group from the "action.selectrevieweraction.group" property in actions.cfg by its UUID or name
|
||||||
|
* Returns null if no (valid) group configured
|
||||||
|
*
|
||||||
|
* @return configured reviewers Group from property or null if none
|
||||||
|
*/
|
||||||
|
private Group getGroup(@Nullable Context context) {
|
||||||
|
if (selectFromReviewsGroupInitialised) {
|
||||||
|
return this.selectFromReviewsGroup;
|
||||||
|
}
|
||||||
|
if (context == null) {
|
||||||
|
context = new Context();
|
||||||
|
}
|
||||||
|
String groupIdOrName = configurationService.getProperty(CONFIG_REVIEWER_GROUP);
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(groupIdOrName)) {
|
||||||
|
Group group = null;
|
||||||
|
try {
|
||||||
|
// try to get group by name
|
||||||
|
group = groupService.findByName(context, groupIdOrName);
|
||||||
|
if (group == null) {
|
||||||
|
// try to get group by uuid if not a name
|
||||||
|
group = groupService.find(context, UUID.fromString(groupIdOrName));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// There is an issue with the reviewer group that is set; if it is not set then can be chosen
|
||||||
|
// from all epeople
|
||||||
|
log.error("Issue with determining matching group for config {}={} for reviewer group of " +
|
||||||
|
"select reviewers workflow", CONFIG_REVIEWER_GROUP, groupIdOrName);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectFromReviewsGroup = group;
|
||||||
|
}
|
||||||
|
selectFromReviewsGroupInitialised = true;
|
||||||
|
return this.selectFromReviewsGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To be used by IT, e.g. {@code XmlWorkflowServiceIT}, when defining new 'Reviewers' group
|
||||||
|
*/
|
||||||
|
static public void resetGroup() {
|
||||||
|
selectFromReviewsGroup = null;
|
||||||
|
selectFromReviewsGroupInitialised = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* 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.xmlworkflow.state.actions.processingaction;
|
||||||
|
|
||||||
|
import org.dspace.xmlworkflow.state.actions.ActionAdvancedInfo;
|
||||||
|
import org.springframework.util.DigestUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that holds the advanced information needed for the
|
||||||
|
* {@link org.dspace.xmlworkflow.state.actions.processingaction.SelectReviewerAction}
|
||||||
|
* See config {@code workflow-actions.cfg}
|
||||||
|
*/
|
||||||
|
public class SelectReviewerActionAdvancedInfo extends ActionAdvancedInfo {
|
||||||
|
private String group;
|
||||||
|
|
||||||
|
public String getGroup() {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroup(String group) {
|
||||||
|
this.group = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateId(String type) {
|
||||||
|
String idString = type
|
||||||
|
+ ";group," + group;
|
||||||
|
super.id = DigestUtils.md5DigestAsHex(idString.getBytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -13,11 +13,15 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.dspace.app.util.Util;
|
import org.dspace.app.util.Util;
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.content.DCDate;
|
import org.dspace.content.WorkspaceItem;
|
||||||
import org.dspace.content.MetadataSchemaEnum;
|
import org.dspace.content.factory.ContentServiceFactory;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.eperson.EPerson;
|
||||||
|
import org.dspace.workflow.WorkflowException;
|
||||||
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
||||||
import org.dspace.xmlworkflow.state.Step;
|
import org.dspace.xmlworkflow.state.Step;
|
||||||
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
||||||
@@ -34,39 +38,59 @@ import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
|||||||
* @author Mark Diggory (markd at atmire dot com)
|
* @author Mark Diggory (markd at atmire dot com)
|
||||||
*/
|
*/
|
||||||
public class SingleUserReviewAction extends ProcessingAction {
|
public class SingleUserReviewAction extends ProcessingAction {
|
||||||
|
private static final Logger log = LogManager.getLogger(SingleUserReviewAction.class);
|
||||||
public static final int MAIN_PAGE = 0;
|
|
||||||
public static final int REJECT_PAGE = 1;
|
|
||||||
public static final int SUBMITTER_IS_DELETED_PAGE = 2;
|
|
||||||
|
|
||||||
public static final int OUTCOME_REJECT = 1;
|
public static final int OUTCOME_REJECT = 1;
|
||||||
|
|
||||||
protected static final String SUBMIT_APPROVE = "submit_approve";
|
|
||||||
protected static final String SUBMIT_REJECT = "submit_reject";
|
|
||||||
protected static final String SUBMIT_DECLINE_TASK = "submit_decline_task";
|
protected static final String SUBMIT_DECLINE_TASK = "submit_decline_task";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activate(Context c, XmlWorkflowItem wfItem) {
|
public void activate(Context c, XmlWorkflowItem wfItem) {
|
||||||
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
||||||
throws SQLException, AuthorizeException, IOException {
|
throws SQLException, AuthorizeException, IOException, WorkflowException {
|
||||||
int page = Util.getIntParameter(request, "page");
|
if (!super.isOptionInParam(request)) {
|
||||||
|
return new ActionResult(ActionResult.TYPE.TYPE_CANCEL);
|
||||||
switch (page) {
|
}
|
||||||
case MAIN_PAGE:
|
switch (Util.getSubmitButton(request, SUBMIT_CANCEL)) {
|
||||||
return processMainPage(c, wfi, step, request);
|
case SUBMIT_APPROVE:
|
||||||
case REJECT_PAGE:
|
return processAccept(c, wfi);
|
||||||
return processRejectPage(c, wfi, step, request);
|
case SUBMIT_REJECT:
|
||||||
case SUBMITTER_IS_DELETED_PAGE:
|
return processReject(c, wfi, request);
|
||||||
return processSubmitterIsDeletedPage(c, wfi, request);
|
case SUBMIT_DECLINE_TASK:
|
||||||
|
return processDecline(c, wfi);
|
||||||
default:
|
default:
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_CANCEL);
|
return new ActionResult(ActionResult.TYPE.TYPE_CANCEL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process {@link super#SUBMIT_REJECT} on this action, will either:
|
||||||
|
* - If submitter of item no longer exists => Permanently delete corresponding item (no wfi/wsi remaining)
|
||||||
|
* - Otherwise: reject item back to submission => becomes wsi of submitter again
|
||||||
|
*/
|
||||||
|
private ActionResult processReject(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
||||||
|
throws SQLException, IOException, AuthorizeException {
|
||||||
|
if (wfi.getSubmitter() == null) {
|
||||||
|
// If the original submitter is no longer there, delete the task
|
||||||
|
return processDelete(c, wfi);
|
||||||
|
} else {
|
||||||
|
return super.processRejectPage(c, wfi, request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accept the workflow item => last step in workflow so will be archived
|
||||||
|
* Info on step & reviewer will be added on metadata dc.description.provenance of resulting item
|
||||||
|
*/
|
||||||
|
public ActionResult processAccept(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
||||||
|
super.addApprovedProvenance(c, wfi);
|
||||||
|
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getOptions() {
|
public List<String> getOptions() {
|
||||||
List<String> options = new ArrayList<>();
|
List<String> options = new ArrayList<>();
|
||||||
@@ -76,87 +100,29 @@ public class SingleUserReviewAction extends ProcessingAction {
|
|||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionResult processMainPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
/**
|
||||||
throws SQLException, AuthorizeException {
|
* Since original submitter no longer exists, workflow item is permanently deleted
|
||||||
if (request.getParameter(SUBMIT_APPROVE) != null) {
|
*/
|
||||||
//Delete the tasks
|
private ActionResult processDelete(Context c, XmlWorkflowItem wfi)
|
||||||
addApprovedProvenance(c, wfi);
|
|
||||||
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
|
||||||
} else if (request.getParameter(SUBMIT_REJECT) != null) {
|
|
||||||
// Make sure we indicate which page we want to process
|
|
||||||
if (wfi.getSubmitter() == null) {
|
|
||||||
request.setAttribute("page", SUBMITTER_IS_DELETED_PAGE);
|
|
||||||
} else {
|
|
||||||
request.setAttribute("page", REJECT_PAGE);
|
|
||||||
}
|
|
||||||
// We have pressed reject item, so take the user to a page where they can reject
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_PAGE);
|
|
||||||
} else if (request.getParameter(SUBMIT_DECLINE_TASK) != null) {
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, OUTCOME_REJECT);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
//We pressed the leave button so return to our submissions page
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addApprovedProvenance(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
|
||||||
//Add the provenance for the accept
|
|
||||||
String now = DCDate.getCurrent().toString();
|
|
||||||
|
|
||||||
// Get user's name + email address
|
|
||||||
String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
|
||||||
.getEPersonName(c.getCurrentUser());
|
|
||||||
|
|
||||||
String provDescription = getProvenanceStartId() + " Approved for entry into archive by "
|
|
||||||
+ usersName + " on " + now + " (GMT) ";
|
|
||||||
|
|
||||||
// Add to item as a DC field
|
|
||||||
itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), "description", "provenance", "en",
|
|
||||||
provDescription);
|
|
||||||
itemService.update(c, wfi.getItem());
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionResult processRejectPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
|
||||||
throws SQLException, AuthorizeException, IOException {
|
throws SQLException, AuthorizeException, IOException {
|
||||||
if (request.getParameter("submit_reject") != null) {
|
EPerson user = c.getCurrentUser();
|
||||||
String reason = request.getParameter("reason");
|
c.turnOffAuthorisationSystem();
|
||||||
if (reason == null || 0 == reason.trim().length()) {
|
WorkspaceItem workspaceItem = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||||
request.setAttribute("page", REJECT_PAGE);
|
.abort(c, wfi, user);
|
||||||
addErrorField(request, "reason");
|
ContentServiceFactory.getInstance().getWorkspaceItemService().deleteAll(c, workspaceItem);
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
c.restoreAuthSystemState();
|
||||||
}
|
|
||||||
|
|
||||||
//We have pressed reject, so remove the task the user has & put it back to a workspace item
|
|
||||||
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
|
||||||
.sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(),
|
|
||||||
this.getProvenanceStartId(), reason);
|
|
||||||
|
|
||||||
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||||
} else {
|
|
||||||
//Cancel, go back to the main task page
|
|
||||||
request.setAttribute("page", MAIN_PAGE);
|
|
||||||
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_PAGE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionResult processSubmitterIsDeletedPage(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
/**
|
||||||
throws SQLException, AuthorizeException, IOException {
|
* Selected reviewer declines to review task, then the workflow is aborted and restarted
|
||||||
if (request.getParameter("submit_delete") != null) {
|
*/
|
||||||
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
private ActionResult processDecline(Context c, XmlWorkflowItem wfi)
|
||||||
.deleteWorkflowByWorkflowItem(c, wfi, c.getCurrentUser());
|
throws SQLException, IOException, AuthorizeException, WorkflowException {
|
||||||
// Delete and send user back to myDspace page
|
c.turnOffAuthorisationSystem();
|
||||||
|
xmlWorkflowService.restartWorkflow(c, wfi, c.getCurrentUser(), this.getProvenanceStartId());
|
||||||
|
c.restoreAuthSystemState();
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||||
} else if (request.getParameter("submit_keep_it") != null) {
|
|
||||||
// Do nothing, just send it back to myDspace page
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
|
||||||
} else {
|
|
||||||
//Cancel, go back to the main task page
|
|
||||||
request.setAttribute("page", MAIN_PAGE);
|
|
||||||
return new ActionResult(ActionResult.TYPE.TYPE_PAGE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -80,6 +80,10 @@ public class AutoAssignAction extends UserSelectionAction {
|
|||||||
}
|
}
|
||||||
//Delete our workflow item role since the users have been assigned
|
//Delete our workflow item role since the users have been assigned
|
||||||
workflowItemRoleService.delete(c, workflowItemRole);
|
workflowItemRoleService.delete(c, workflowItemRole);
|
||||||
|
if (role.isDeleteTemporaryGroup() && workflowItemRole.getGroup() != null) {
|
||||||
|
// Delete temporary groups created after members have workflow task assigned
|
||||||
|
groupService.delete(c, workflowItemRole.getGroup());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.warn(LogHelper.getHeader(c, "Error while executing auto assign action",
|
log.warn(LogHelper.getHeader(c, "Error while executing auto assign action",
|
||||||
@@ -127,7 +131,7 @@ public class AutoAssignAction extends UserSelectionAction {
|
|||||||
protected void createTaskForEPerson(Context c, XmlWorkflowItem wfi, Step step, WorkflowActionConfig actionConfig,
|
protected void createTaskForEPerson(Context c, XmlWorkflowItem wfi, Step step, WorkflowActionConfig actionConfig,
|
||||||
EPerson user) throws SQLException, AuthorizeException, IOException {
|
EPerson user) throws SQLException, AuthorizeException, IOException {
|
||||||
if (claimedTaskService.find(c, wfi, step.getId(), actionConfig.getId()) != null) {
|
if (claimedTaskService.find(c, wfi, step.getId(), actionConfig.getId()) != null) {
|
||||||
workflowRequirementsService.addClaimedUser(c, wfi, step, c.getCurrentUser());
|
workflowRequirementsService.addClaimedUser(c, wfi, step, user);
|
||||||
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||||
.createOwnedTask(c, wfi, step, actionConfig, user);
|
.createOwnedTask(c, wfi, step, actionConfig, user);
|
||||||
}
|
}
|
||||||
|
@@ -138,6 +138,10 @@ public class ClaimAction extends UserSelectionAction {
|
|||||||
RoleMembers roleMembers = role.getMembers(context, wfi);
|
RoleMembers roleMembers = role.getMembers(context, wfi);
|
||||||
|
|
||||||
ArrayList<EPerson> epersons = roleMembers.getAllUniqueMembers(context);
|
ArrayList<EPerson> epersons = roleMembers.getAllUniqueMembers(context);
|
||||||
|
if (epersons.isEmpty() || step.getRequiredUsers() > epersons.size()) {
|
||||||
|
log.warn(String.format("There must be at least %s ePerson(s) in the group",
|
||||||
|
step.getRequiredUsers()));
|
||||||
|
}
|
||||||
return !(epersons.isEmpty() || step.getRequiredUsers() > epersons.size());
|
return !(epersons.isEmpty() || step.getRequiredUsers() > epersons.size());
|
||||||
} else {
|
} else {
|
||||||
// We don't have a role and do have a UI so throw a workflow exception
|
// We don't have a role and do have a UI so throw a workflow exception
|
||||||
|
@@ -15,9 +15,12 @@
|
|||||||
<bean id="selectrevieweractionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.SelectReviewerAction" scope="prototype">
|
<bean id="selectrevieweractionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.SelectReviewerAction" scope="prototype">
|
||||||
<property name="role" ref="scoreassignedreviewer"/>
|
<property name="role" ref="scoreassignedreviewer"/>
|
||||||
</bean>
|
</bean>
|
||||||
<bean id="scorereviewactionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewAction" scope="prototype"/>
|
<bean id="scorereviewactionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewAction" scope="prototype">
|
||||||
|
<property name="descriptionRequired" value="true"/>
|
||||||
|
<property name="maxValue" value="5"/>
|
||||||
|
</bean>
|
||||||
<bean id="evaluationactionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.ScoreEvaluationAction" scope="prototype">
|
<bean id="evaluationactionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.ScoreEvaluationAction" scope="prototype">
|
||||||
<property name="minimumAcceptanceScore" value="50" />
|
<property name="minimumAcceptanceScore" value="3" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
|
||||||
@@ -63,6 +66,12 @@
|
|||||||
<property name="requiresUI" value="true"/>
|
<property name="requiresUI" value="true"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="ratingreviewaction" class="org.dspace.xmlworkflow.state.actions.WorkflowActionConfig" scope="prototype">
|
||||||
|
<constructor-arg type="java.lang.String" value="ratingreviewaction"/>
|
||||||
|
<property name="processingAction" ref="ratingreviewactionAPI" />
|
||||||
|
<property name="requiresUI" value="true"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
<!--Autmatic step that evaluates scores (workflow.score) and checks if they match the configured minimum for archiving -->
|
<!--Autmatic step that evaluates scores (workflow.score) and checks if they match the configured minimum for archiving -->
|
||||||
<bean id="evaluationaction" class="org.dspace.xmlworkflow.state.actions.WorkflowActionConfig" scope="prototype">
|
<bean id="evaluationaction" class="org.dspace.xmlworkflow.state.actions.WorkflowActionConfig" scope="prototype">
|
||||||
<constructor-arg type="java.lang.String" value="evaluationaction"/>
|
<constructor-arg type="java.lang.String" value="evaluationaction"/>
|
||||||
|
@@ -153,6 +153,7 @@
|
|||||||
<bean id="scoreassignedreviewer" class="org.dspace.xmlworkflow.Role">
|
<bean id="scoreassignedreviewer" class="org.dspace.xmlworkflow.Role">
|
||||||
<property name="scope" value="#{ T(org.dspace.xmlworkflow.Role.Scope).ITEM}"/>
|
<property name="scope" value="#{ T(org.dspace.xmlworkflow.Role.Scope).ITEM}"/>
|
||||||
<property name="name" value="Reviewer"/>
|
<property name="name" value="Reviewer"/>
|
||||||
|
<property name="deleteTemporaryGroup" value="true"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
|
||||||
|
@@ -9,11 +9,13 @@ package org.dspace.xmlworkflow;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.dspace.AbstractIntegrationTestWithDatabase;
|
import org.dspace.AbstractIntegrationTestWithDatabase;
|
||||||
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.authorize.ResourcePolicy;
|
import org.dspace.authorize.ResourcePolicy;
|
||||||
import org.dspace.authorize.factory.AuthorizeServiceFactory;
|
import org.dspace.authorize.factory.AuthorizeServiceFactory;
|
||||||
import org.dspace.authorize.service.AuthorizeService;
|
import org.dspace.authorize.service.AuthorizeService;
|
||||||
@@ -21,17 +23,24 @@ import org.dspace.builder.ClaimedTaskBuilder;
|
|||||||
import org.dspace.builder.CollectionBuilder;
|
import org.dspace.builder.CollectionBuilder;
|
||||||
import org.dspace.builder.CommunityBuilder;
|
import org.dspace.builder.CommunityBuilder;
|
||||||
import org.dspace.builder.EPersonBuilder;
|
import org.dspace.builder.EPersonBuilder;
|
||||||
|
import org.dspace.builder.GroupBuilder;
|
||||||
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.core.Constants;
|
import org.dspace.core.Constants;
|
||||||
import org.dspace.discovery.IndexingService;
|
import org.dspace.discovery.IndexingService;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
|
import org.dspace.eperson.Group;
|
||||||
|
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||||
|
import org.dspace.eperson.service.GroupService;
|
||||||
|
import org.dspace.services.ConfigurationService;
|
||||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||||
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
||||||
import org.dspace.xmlworkflow.service.XmlWorkflowService;
|
import org.dspace.xmlworkflow.service.XmlWorkflowService;
|
||||||
import org.dspace.xmlworkflow.state.Workflow;
|
import org.dspace.xmlworkflow.state.Workflow;
|
||||||
|
import org.dspace.xmlworkflow.state.actions.processingaction.SelectReviewerAction;
|
||||||
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
|
|
||||||
@@ -47,6 +56,22 @@ public class XmlWorkflowServiceIT extends AbstractIntegrationTestWithDatabase {
|
|||||||
.getServiceByName(IndexingService.class.getName(),
|
.getServiceByName(IndexingService.class.getName(),
|
||||||
IndexingService.class);
|
IndexingService.class);
|
||||||
protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
|
protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
|
||||||
|
protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService();
|
||||||
|
protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up the created workflow role groups after each test
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws AuthorizeException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
@After
|
||||||
|
public void cleanup() throws SQLException, AuthorizeException, IOException {
|
||||||
|
Group reviewManagers = groupService.findByName(context, "ReviewManagers");
|
||||||
|
if (reviewManagers != null) {
|
||||||
|
groupService.delete(context, reviewManagers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test to verify that if a user submits an item into the workflow, then it gets rejected that the submitter gets
|
* Test to verify that if a user submits an item into the workflow, then it gets rejected that the submitter gets
|
||||||
@@ -85,6 +110,93 @@ public class XmlWorkflowServiceIT extends AbstractIntegrationTestWithDatabase {
|
|||||||
assertTrue(this.containsRPForUser(taskToReject.getWorkflowItem().getItem(), submitter, Constants.WRITE));
|
assertTrue(this.containsRPForUser(taskToReject.getWorkflowItem().getItem(), submitter, Constants.WRITE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test to verify that if a user submits an item into the workflow, a reviewmanager can select a single reviewer
|
||||||
|
* eperson
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void workflowUserSingleSelectedReviewer_ItemShouldBeEditable() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
EPerson submitter = EPersonBuilder.createEPerson(context).withEmail("submitter@example.org").build();
|
||||||
|
context.setCurrentUser(submitter);
|
||||||
|
EPerson reviewManager =
|
||||||
|
EPersonBuilder.createEPerson(context).withEmail("reviewmanager-test@example.org").build();
|
||||||
|
Community community = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.build();
|
||||||
|
Collection colWithWorkflow = CollectionBuilder.createCollection(context, community, "123456789/workflow-test-1")
|
||||||
|
.withName("Collection WITH workflow")
|
||||||
|
.withWorkflowGroup("reviewmanagers", reviewManager)
|
||||||
|
.build();
|
||||||
|
Workflow workflow = XmlWorkflowServiceFactory.getInstance().getWorkflowFactory().getWorkflow(colWithWorkflow);
|
||||||
|
ClaimedTask task = ClaimedTaskBuilder.createClaimedTask(context, colWithWorkflow, reviewManager)
|
||||||
|
.withTitle("Test workflow item to reject").build();
|
||||||
|
// Set reviewer group property and add reviewer to group
|
||||||
|
SelectReviewerAction.resetGroup();
|
||||||
|
configurationService.setProperty("action.selectrevieweraction.group", "Reviewers");
|
||||||
|
Group reviewerGroup = GroupBuilder.createGroup(context).withName("Reviewers").build();
|
||||||
|
EPerson reviewer = EPersonBuilder.createEPerson(context).withEmail("reviewer@example.org").build();
|
||||||
|
groupService.addMember(context, reviewerGroup, reviewer);
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
// Review Manager should have access to workflow item
|
||||||
|
assertTrue(this.containsRPForUser(task.getWorkflowItem().getItem(), reviewManager, Constants.WRITE));
|
||||||
|
|
||||||
|
// select 1 reviewer
|
||||||
|
MockHttpServletRequest httpSelectReviewerRequest = new MockHttpServletRequest();
|
||||||
|
httpSelectReviewerRequest.setParameter("submit_select_reviewer", "true");
|
||||||
|
httpSelectReviewerRequest.setParameter("eperson", reviewer.getID().toString());
|
||||||
|
executeWorkflowAction(httpSelectReviewerRequest, workflow, task);
|
||||||
|
|
||||||
|
// Reviewer should have access to workflow item
|
||||||
|
assertTrue(this.containsRPForUser(task.getWorkflowItem().getItem(), reviewer, Constants.WRITE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test to verify that if a user submits an item into the workflow, a reviewmanager can select a multiple reviewer
|
||||||
|
* epersons
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void workflowUserMultipleSelectedReviewer_ItemShouldBeEditable() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
EPerson submitter = EPersonBuilder.createEPerson(context).withEmail("submitter@example.org").build();
|
||||||
|
context.setCurrentUser(submitter);
|
||||||
|
EPerson reviewManager =
|
||||||
|
EPersonBuilder.createEPerson(context).withEmail("reviewmanager-test@example.org").build();
|
||||||
|
Community community = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.build();
|
||||||
|
Collection colWithWorkflow = CollectionBuilder.createCollection(context, community, "123456789/workflow-test-1")
|
||||||
|
.withName("Collection WITH workflow")
|
||||||
|
.withWorkflowGroup("reviewmanagers", reviewManager)
|
||||||
|
.build();
|
||||||
|
Workflow workflow = XmlWorkflowServiceFactory.getInstance().getWorkflowFactory().getWorkflow(colWithWorkflow);
|
||||||
|
ClaimedTask task = ClaimedTaskBuilder.createClaimedTask(context, colWithWorkflow, reviewManager)
|
||||||
|
.withTitle("Test workflow item to reject").build();
|
||||||
|
// Set reviewer group property and add reviewer to group
|
||||||
|
SelectReviewerAction.resetGroup();
|
||||||
|
configurationService.setProperty("action.selectrevieweraction.group", "Reviewers");
|
||||||
|
Group reviewerGroup = GroupBuilder.createGroup(context).withName("Reviewers").build();
|
||||||
|
EPerson reviewer1 = EPersonBuilder.createEPerson(context).withEmail("reviewer1@example.org").build();
|
||||||
|
EPerson reviewer2 = EPersonBuilder.createEPerson(context).withEmail("reviewer2@example.org").build();
|
||||||
|
groupService.addMember(context, reviewerGroup, reviewer1);
|
||||||
|
groupService.addMember(context, reviewerGroup, reviewer2);
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
// Review Manager should have access to workflow item
|
||||||
|
assertTrue(this.containsRPForUser(task.getWorkflowItem().getItem(), reviewManager, Constants.WRITE));
|
||||||
|
|
||||||
|
// Select multiple reviewers
|
||||||
|
MockHttpServletRequest httpSelectMultipleReviewers = new MockHttpServletRequest();
|
||||||
|
httpSelectMultipleReviewers.setParameter("submit_select_reviewer", "true");
|
||||||
|
httpSelectMultipleReviewers.setParameter("eperson", reviewer1.getID().toString(), reviewer2.getID().toString());
|
||||||
|
executeWorkflowAction(httpSelectMultipleReviewers, workflow, task);
|
||||||
|
|
||||||
|
// Reviewers should have access to workflow item
|
||||||
|
assertTrue(this.containsRPForUser(task.getWorkflowItem().getItem(), reviewer1, Constants.WRITE));
|
||||||
|
assertTrue(this.containsRPForUser(task.getWorkflowItem().getItem(), reviewer2, Constants.WRITE));
|
||||||
|
}
|
||||||
|
|
||||||
private boolean containsRPForUser(Item item, EPerson user, int action) throws SQLException {
|
private boolean containsRPForUser(Item item, EPerson user, int action) throws SQLException {
|
||||||
List<ResourcePolicy> rps = authorizeService.getPolicies(context, item);
|
List<ResourcePolicy> rps = authorizeService.getPolicies(context, item);
|
||||||
for (ResourcePolicy rp : rps) {
|
for (ResourcePolicy rp : rps) {
|
||||||
|
@@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* 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.converter;
|
||||||
|
|
||||||
|
import org.dspace.app.rest.model.ScoreReviewActionAdvancedInfoRest;
|
||||||
|
import org.dspace.app.rest.projection.Projection;
|
||||||
|
import org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewActionAdvancedInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This converter is responsible for transforming the model representation of a ScoreReviewActionAdvancedInfo to
|
||||||
|
* the REST representation of a ScoreReviewActionAdvancedInfo
|
||||||
|
*/
|
||||||
|
public class ScoreReviewActionAdvancedInfoConverter
|
||||||
|
implements DSpaceConverter<ScoreReviewActionAdvancedInfo, ScoreReviewActionAdvancedInfoRest> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScoreReviewActionAdvancedInfoRest convert(ScoreReviewActionAdvancedInfo modelObject,
|
||||||
|
Projection projection) {
|
||||||
|
ScoreReviewActionAdvancedInfoRest restModel = new ScoreReviewActionAdvancedInfoRest();
|
||||||
|
restModel.setDescriptionRequired(modelObject.isDescriptionRequired());
|
||||||
|
restModel.setMaxValue(modelObject.getMaxValue());
|
||||||
|
restModel.setType(modelObject.getType());
|
||||||
|
restModel.setId(modelObject.getId());
|
||||||
|
return restModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<ScoreReviewActionAdvancedInfo> getModelClass() {
|
||||||
|
return ScoreReviewActionAdvancedInfo.class;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* 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.converter;
|
||||||
|
|
||||||
|
import org.dspace.app.rest.model.SelectReviewerActionAdvancedInfoRest;
|
||||||
|
import org.dspace.app.rest.projection.Projection;
|
||||||
|
import org.dspace.xmlworkflow.state.actions.processingaction.SelectReviewerActionAdvancedInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This converter is responsible for transforming the model representation of a SelectReviewerActionAdvancedInfo to
|
||||||
|
* the REST representation of a SelectReviewerActionAdvancedInfo
|
||||||
|
*/
|
||||||
|
public class SelectReviewerActionAdvancedInfoConverter
|
||||||
|
implements DSpaceConverter<SelectReviewerActionAdvancedInfo, SelectReviewerActionAdvancedInfoRest> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SelectReviewerActionAdvancedInfoRest convert(SelectReviewerActionAdvancedInfo modelObject,
|
||||||
|
Projection projection) {
|
||||||
|
SelectReviewerActionAdvancedInfoRest restModel = new SelectReviewerActionAdvancedInfoRest();
|
||||||
|
restModel.setGroup(modelObject.getGroup());
|
||||||
|
restModel.setType(modelObject.getType());
|
||||||
|
restModel.setId(modelObject.getId());
|
||||||
|
return restModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<SelectReviewerActionAdvancedInfo> getModelClass() {
|
||||||
|
return SelectReviewerActionAdvancedInfo.class;
|
||||||
|
}
|
||||||
|
}
|
@@ -26,6 +26,10 @@ public class WorkflowActionConverter implements DSpaceConverter<WorkflowActionCo
|
|||||||
restModel.setProjection(projection);
|
restModel.setProjection(projection);
|
||||||
restModel.setId(modelObject.getId());
|
restModel.setId(modelObject.getId());
|
||||||
restModel.setOptions(modelObject.getOptions());
|
restModel.setOptions(modelObject.getOptions());
|
||||||
|
if (modelObject.isAdvanced()) {
|
||||||
|
restModel.setAdvancedOptions(modelObject.getAdvancedOptions());
|
||||||
|
restModel.setAdvancedInfo(modelObject.getAdvancedInfo());
|
||||||
|
}
|
||||||
return restModel;
|
return restModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* 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 org.dspace.xmlworkflow.state.actions.ActionAdvancedInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class for {@link ActionAdvancedInfo}
|
||||||
|
*
|
||||||
|
* @author Marie Verdonck (Atmire) on 03/02/23
|
||||||
|
*/
|
||||||
|
public abstract class AdvancedInfoRest {
|
||||||
|
|
||||||
|
String id;
|
||||||
|
String type;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ScoreReviewActionAdvancedInfo REST Resource,
|
||||||
|
* see {@link org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewActionAdvancedInfo}
|
||||||
|
*/
|
||||||
|
public class ScoreReviewActionAdvancedInfoRest extends AdvancedInfoRest {
|
||||||
|
|
||||||
|
private boolean descriptionRequired;
|
||||||
|
private int maxValue;
|
||||||
|
|
||||||
|
public boolean isDescriptionRequired() {
|
||||||
|
return descriptionRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescriptionRequired(boolean descriptionRequired) {
|
||||||
|
this.descriptionRequired = descriptionRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxValue() {
|
||||||
|
return maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxValue(int maxValue) {
|
||||||
|
this.maxValue = maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SelectReviewerActionAdvancedInfoRest REST Resource,
|
||||||
|
* see {@link org.dspace.xmlworkflow.state.actions.processingaction.SelectReviewerActionAdvancedInfo}
|
||||||
|
*/
|
||||||
|
public class SelectReviewerActionAdvancedInfoRest extends AdvancedInfoRest {
|
||||||
|
|
||||||
|
private String groupId;
|
||||||
|
|
||||||
|
public String getGroup() {
|
||||||
|
return groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroup(String groupId) {
|
||||||
|
this.groupId = groupId;
|
||||||
|
}
|
||||||
|
}
|
@@ -9,7 +9,10 @@ package org.dspace.app.rest.model;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.dspace.app.rest.RestResourceController;
|
import org.dspace.app.rest.RestResourceController;
|
||||||
|
import org.dspace.xmlworkflow.state.actions.ActionAdvancedInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The rest resource used for workflow actions
|
* The rest resource used for workflow actions
|
||||||
@@ -23,6 +26,8 @@ public class WorkflowActionRest extends BaseObjectRest<String> {
|
|||||||
public static final String NAME_PLURAL = "workflowactions";
|
public static final String NAME_PLURAL = "workflowactions";
|
||||||
|
|
||||||
private List<String> options;
|
private List<String> options;
|
||||||
|
private List<String> advancedOptions;
|
||||||
|
private List<ActionAdvancedInfo> advancedInfo;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCategory() {
|
public String getCategory() {
|
||||||
@@ -39,21 +44,33 @@ public class WorkflowActionRest extends BaseObjectRest<String> {
|
|||||||
return NAME;
|
return NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generic getter for the options
|
|
||||||
*
|
|
||||||
* @return the options value of this WorkflowActionRest
|
|
||||||
*/
|
|
||||||
public List<String> getOptions() {
|
public List<String> getOptions() {
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generic setter for the options
|
|
||||||
*
|
|
||||||
* @param options The options to be set on this WorkflowActionRest
|
|
||||||
*/
|
|
||||||
public void setOptions(List<String> options) {
|
public void setOptions(List<String> options) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public List<String> getAdvancedOptions() {
|
||||||
|
return advancedOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdvancedOptions(List<String> advancedOptions) {
|
||||||
|
this.advancedOptions = advancedOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getAdvanced() {
|
||||||
|
return CollectionUtils.isNotEmpty(getAdvancedOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public List<ActionAdvancedInfo> getAdvancedInfo() {
|
||||||
|
return advancedInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdvancedInfo(List<ActionAdvancedInfo> advancedInfo) {
|
||||||
|
this.advancedInfo = advancedInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -44,6 +44,7 @@ import org.dspace.builder.ClaimedTaskBuilder;
|
|||||||
import org.dspace.builder.CollectionBuilder;
|
import org.dspace.builder.CollectionBuilder;
|
||||||
import org.dspace.builder.CommunityBuilder;
|
import org.dspace.builder.CommunityBuilder;
|
||||||
import org.dspace.builder.EPersonBuilder;
|
import org.dspace.builder.EPersonBuilder;
|
||||||
|
import org.dspace.builder.GroupBuilder;
|
||||||
import org.dspace.builder.ItemBuilder;
|
import org.dspace.builder.ItemBuilder;
|
||||||
import org.dspace.builder.PoolTaskBuilder;
|
import org.dspace.builder.PoolTaskBuilder;
|
||||||
import org.dspace.builder.WorkflowItemBuilder;
|
import org.dspace.builder.WorkflowItemBuilder;
|
||||||
@@ -52,11 +53,11 @@ 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.eperson.Group;
|
import org.dspace.eperson.Group;
|
||||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
|
||||||
import org.dspace.eperson.service.GroupService;
|
import org.dspace.eperson.service.GroupService;
|
||||||
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
||||||
import org.dspace.xmlworkflow.state.Step;
|
import org.dspace.xmlworkflow.state.Step;
|
||||||
import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig;
|
import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig;
|
||||||
|
import org.dspace.xmlworkflow.state.actions.processingaction.SelectReviewerAction;
|
||||||
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;
|
||||||
@@ -78,6 +79,9 @@ public class TaskRestRepositoriesIT extends AbstractControllerIntegrationTest {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private XmlWorkflowFactory xmlWorkflowFactory;
|
private XmlWorkflowFactory xmlWorkflowFactory;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
GroupService groupService;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
/**
|
/**
|
||||||
* Retrieve a specific pooltask
|
* Retrieve a specific pooltask
|
||||||
@@ -4174,9 +4178,6 @@ public class TaskRestRepositoriesIT extends AbstractControllerIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void addReviewerToRunningWorkflowTest() throws Exception {
|
public void addReviewerToRunningWorkflowTest() throws Exception {
|
||||||
|
|
||||||
GroupService groupService = EPersonServiceFactory.getInstance().getGroupService();
|
|
||||||
|
|
||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
EPerson reviewer1 = EPersonBuilder.createEPerson(context)
|
EPerson reviewer1 = EPersonBuilder.createEPerson(context)
|
||||||
@@ -4329,4 +4330,384 @@ public class TaskRestRepositoriesIT extends AbstractControllerIntegrationTest {
|
|||||||
.andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
|
.andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the run of the selectSingleReviewer workflow
|
||||||
|
* - Creates ‘ReviewManagers’ and ‘Reviewers’, each with some members
|
||||||
|
* - Creates a normal user, not member of either group, this user is set on context
|
||||||
|
* - Tests selecting a single reviewer, multiple reviewers and selecting a non-reviewer
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void selectReviewerWorkflowTest() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
// Create normal user, not member of "ReviewManagers" or "Reviewers" and set as current user
|
||||||
|
EPerson user = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("user@example.com")
|
||||||
|
.withPassword(password).build();
|
||||||
|
context.setCurrentUser(user);
|
||||||
|
|
||||||
|
// Create creator as this user is member of "ReviewManagers" for this item
|
||||||
|
EPerson creator = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("creator@example.com")
|
||||||
|
.withPassword(password).build();
|
||||||
|
|
||||||
|
// Create with some members to be added to "ReviewManagers"
|
||||||
|
EPerson reviewManager1 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("reviewManager1@example.com")
|
||||||
|
.withPassword(password).build();
|
||||||
|
|
||||||
|
EPerson reviewManager2 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("reviewManager2@example.com")
|
||||||
|
.withPassword(password).build();
|
||||||
|
|
||||||
|
EPerson reviewManager3 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("reviewManager3@example.com")
|
||||||
|
.withPassword(password).build();
|
||||||
|
|
||||||
|
// The "selectSingleReviewer" requires the "ReviewManagers" repository group to be present with at least 1
|
||||||
|
// member
|
||||||
|
GroupBuilder.createGroup(context)
|
||||||
|
.withName("ReviewManagers")
|
||||||
|
.addMember(reviewManager1)
|
||||||
|
.addMember(reviewManager2)
|
||||||
|
.addMember(reviewManager3)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Create "Reviewers" with some members
|
||||||
|
Group reviewerGroup = GroupBuilder.createGroup(context).withName("Reviewers").build();
|
||||||
|
|
||||||
|
EPerson reviewer1 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("reviewer1@example.com")
|
||||||
|
.withPassword(password)
|
||||||
|
.withGroupMembership(reviewerGroup).build();
|
||||||
|
|
||||||
|
EPerson reviewer2 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("reviewer2@example.com")
|
||||||
|
.withPassword(password)
|
||||||
|
.withGroupMembership(reviewerGroup).build();
|
||||||
|
|
||||||
|
EPerson reviewer3 = EPersonBuilder.createEPerson(context)
|
||||||
|
.withEmail("reviewer3@example.com")
|
||||||
|
.withPassword(password)
|
||||||
|
.withGroupMembership(reviewerGroup).build();
|
||||||
|
|
||||||
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community").build();
|
||||||
|
|
||||||
|
// Create collection with handle "123456789/workflow-test-1" to use "selectSingleReviewer"
|
||||||
|
Collection collection =
|
||||||
|
CollectionBuilder.createCollection(context, parentCommunity, "123456789/workflow-test-1")
|
||||||
|
.withName("Collection 1")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Create 3 pool tasks
|
||||||
|
// First one for selecting a single reviewer
|
||||||
|
PoolTask poolTask1 = PoolTaskBuilder.createPoolTask(context, collection, reviewManager1)
|
||||||
|
.withTitle("Workflow Item 1")
|
||||||
|
.withIssueDate("2017-10-17")
|
||||||
|
.withAuthor("Smith, Donald")
|
||||||
|
.withAuthor("Doe, John")
|
||||||
|
.withSubject("ExtraEntry").build();
|
||||||
|
XmlWorkflowItem witem1 = poolTask1.getWorkflowItem();
|
||||||
|
// Second one for selecting multiple reviewers
|
||||||
|
PoolTask poolTask2 = PoolTaskBuilder.createPoolTask(context, collection, reviewManager2)
|
||||||
|
.withTitle("Workflow Item 2")
|
||||||
|
.withIssueDate("2017-10-17")
|
||||||
|
.withAuthor("Smith, Donald")
|
||||||
|
.withAuthor("Doe, John")
|
||||||
|
.withSubject("ExtraEntry").build();
|
||||||
|
XmlWorkflowItem witem2 = poolTask2.getWorkflowItem();
|
||||||
|
// Third one for trying to add user not in "Reviewers" group
|
||||||
|
PoolTask poolTask3 = PoolTaskBuilder.createPoolTask(context, collection, reviewManager3)
|
||||||
|
.withTitle("Workflow Item 3")
|
||||||
|
.withIssueDate("2017-10-17")
|
||||||
|
.withAuthor("Smith, Donald")
|
||||||
|
.withAuthor("Doe, John")
|
||||||
|
.withSubject("ExtraEntry").build();
|
||||||
|
XmlWorkflowItem witem3 = poolTask3.getWorkflowItem();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
String reviewManager1Token = getAuthToken(reviewManager1.getEmail(), password);
|
||||||
|
String reviewManager2Token = getAuthToken(reviewManager2.getEmail(), password);
|
||||||
|
String reviewManager3Token = getAuthToken(reviewManager3.getEmail(), password);
|
||||||
|
|
||||||
|
String reviewer1Token = getAuthToken(reviewer1.getEmail(), password);
|
||||||
|
String reviewer2Token = getAuthToken(reviewer2.getEmail(), password);
|
||||||
|
String reviewer3Token = getAuthToken(reviewer3.getEmail(), password);
|
||||||
|
|
||||||
|
String adminToken = getAuthToken(admin.getEmail(), password);
|
||||||
|
String userToken = getAuthToken(user.getEmail(), password);
|
||||||
|
|
||||||
|
AtomicReference<Integer> idRef = new AtomicReference<>();
|
||||||
|
|
||||||
|
// Verify as member of "ReviewManagers" you can find these pool tasks
|
||||||
|
getClient(reviewManager1Token).perform(get("/api/workflow/pooltasks/" + poolTask1.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", Matchers.is(PoolTaskMatcher.matchPoolTask(poolTask1, "selectReviewerStep"))));
|
||||||
|
|
||||||
|
// Verify as member of "Reviewers" you can not find these pool tasks
|
||||||
|
getClient(reviewer1Token).perform(get("/api/workflow/pooltasks/" + poolTask1.getID()))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
// Verify as member of "ReviewManagers" you can claim in this tasks
|
||||||
|
getClient(reviewManager1Token).perform(post("/api/workflow/claimedtasks")
|
||||||
|
.contentType(
|
||||||
|
MediaType.parseMediaType(RestMediaTypes.TEXT_URI_LIST_VALUE))
|
||||||
|
.content("/api/workflow/pooltasks/" + poolTask1.getID()))
|
||||||
|
.andExpect(status().isCreated())
|
||||||
|
.andExpect(jsonPath("$", Matchers.allOf(hasJsonPath("$.type", is("claimedtask")))))
|
||||||
|
.andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
|
||||||
|
|
||||||
|
// Verify that pool task 1 no longer exists
|
||||||
|
getClient(reviewManager1Token).perform(get("/api/workflow/pooltasks/" + poolTask1.getID()))
|
||||||
|
.andExpect(status().isNotFound());
|
||||||
|
|
||||||
|
// Verify items now in claimed tasks /api/workflow/claimedtasks for user reviewManager1
|
||||||
|
getClient(reviewManager1Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", reviewManager1.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._embedded.claimedtasks", Matchers.contains(
|
||||||
|
Matchers.allOf(
|
||||||
|
hasJsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks/")),
|
||||||
|
hasJsonPath("$.type", Matchers.is("claimedtask")),
|
||||||
|
hasJsonPath("$._embedded.owner",
|
||||||
|
Matchers.is(EPersonMatcher.matchEPersonOnEmail(reviewManager1.getEmail()))),
|
||||||
|
hasJsonPath("$._embedded.action.id", Matchers.is("selectrevieweraction")),
|
||||||
|
hasJsonPath("$._embedded.workflowitem",
|
||||||
|
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
||||||
|
witem1, "Workflow Item 1", "2017-10-17", "ExtraEntry")))
|
||||||
|
))))
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(1)));
|
||||||
|
|
||||||
|
// Verify items now not in claimed tasks /api/workflow/claimedtasks for user reviewer1
|
||||||
|
getClient(reviewer1Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", reviewer1.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(0)));
|
||||||
|
|
||||||
|
// Test for single reviewer
|
||||||
|
SelectReviewerAction.resetGroup();
|
||||||
|
// Select reviewer1 as a reviewer, wf step 1
|
||||||
|
getClient(reviewManager1Token).perform(post("/api/workflow/claimedtasks/" + idRef.get())
|
||||||
|
.param("submit_select_reviewer", "true")
|
||||||
|
.param("eperson", reviewer1.getID().toString())
|
||||||
|
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
|
||||||
|
.andExpect(status().isNoContent());
|
||||||
|
|
||||||
|
// Verify reviewer1 has the claimed task
|
||||||
|
getClient(reviewer1Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", reviewer1.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._embedded.claimedtasks", Matchers.contains(
|
||||||
|
Matchers.allOf(
|
||||||
|
hasJsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks/")),
|
||||||
|
hasJsonPath("$.type", Matchers.is("claimedtask")),
|
||||||
|
hasJsonPath("$._embedded.owner",
|
||||||
|
Matchers.is(EPersonMatcher.matchEPersonOnEmail(reviewer1.getEmail()))),
|
||||||
|
hasJsonPath("$._embedded.action.id", Matchers.is("singleuserreviewaction")),
|
||||||
|
hasJsonPath("$._embedded.workflowitem",
|
||||||
|
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
||||||
|
witem1, "Workflow Item 1", "2017-10-17", "ExtraEntry")))
|
||||||
|
))))
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(1)));
|
||||||
|
|
||||||
|
// Verify other members of "Reviewers" don't have this task claimed
|
||||||
|
getClient(reviewer2Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", reviewer2.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(0)));
|
||||||
|
getClient(reviewer3Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", reviewer3.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(0)));
|
||||||
|
// Verify members of "ReviewManagers" don't have this task claimed
|
||||||
|
getClient(reviewManager1Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", reviewManager1.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(0)));
|
||||||
|
getClient(reviewManager2Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", reviewManager2.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(0)));
|
||||||
|
getClient(reviewManager3Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", reviewManager3.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(0)));
|
||||||
|
// Verify other users don't have this task claimed
|
||||||
|
getClient(userToken).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", user.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(0)));
|
||||||
|
|
||||||
|
// Test for multiple reviewers
|
||||||
|
|
||||||
|
// Claim pooltask2 as member of "ReviewManagers"
|
||||||
|
getClient(reviewManager2Token).perform(post("/api/workflow/claimedtasks")
|
||||||
|
.contentType(
|
||||||
|
MediaType.parseMediaType(RestMediaTypes.TEXT_URI_LIST_VALUE))
|
||||||
|
.content("/api/workflow/pooltasks/" + poolTask2.getID()))
|
||||||
|
.andExpect(status().isCreated())
|
||||||
|
.andExpect(jsonPath("$", Matchers.allOf(hasJsonPath("$.type", is("claimedtask")))))
|
||||||
|
.andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
|
||||||
|
|
||||||
|
// Select reviewer2 and reviewer3 as reviewers, wf step 1
|
||||||
|
getClient(reviewManager2Token).perform(post("/api/workflow/claimedtasks/" + idRef.get())
|
||||||
|
.param("submit_select_reviewer", "true")
|
||||||
|
.param("eperson", reviewer2.getID().toString())
|
||||||
|
.param("eperson", reviewer3.getID().toString())
|
||||||
|
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
|
||||||
|
.andExpect(status().isNoContent());
|
||||||
|
|
||||||
|
// Verify reviewer2 has the claimed task
|
||||||
|
getClient(reviewer2Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", reviewer2.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._embedded.claimedtasks", Matchers.contains(
|
||||||
|
Matchers.allOf(
|
||||||
|
hasJsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks/")),
|
||||||
|
hasJsonPath("$.type", Matchers.is("claimedtask")),
|
||||||
|
hasJsonPath("$._embedded.owner",
|
||||||
|
Matchers.is(EPersonMatcher.matchEPersonOnEmail(reviewer2.getEmail()))),
|
||||||
|
hasJsonPath("$._embedded.action.id", Matchers.is("singleuserreviewaction")),
|
||||||
|
hasJsonPath("$._embedded.workflowitem",
|
||||||
|
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
||||||
|
witem2, "Workflow Item 2", "2017-10-17", "ExtraEntry")))
|
||||||
|
))))
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(1)));
|
||||||
|
|
||||||
|
// Verify reviewer3 has the claimed task too
|
||||||
|
getClient(reviewer3Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", reviewer3.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._embedded.claimedtasks", Matchers.contains(
|
||||||
|
Matchers.allOf(
|
||||||
|
hasJsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks/")),
|
||||||
|
hasJsonPath("$.type", Matchers.is("claimedtask")),
|
||||||
|
hasJsonPath("$._embedded.owner",
|
||||||
|
Matchers.is(EPersonMatcher.matchEPersonOnEmail(reviewer3.getEmail()))),
|
||||||
|
hasJsonPath("$._embedded.action.id", Matchers.is("singleuserreviewaction")),
|
||||||
|
hasJsonPath("$._embedded.workflowitem",
|
||||||
|
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
||||||
|
witem2, "Workflow Item 2", "2017-10-17", "ExtraEntry")))
|
||||||
|
))))
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(1)));
|
||||||
|
|
||||||
|
// Verify reviewer1 of "Reviewers" doesn't have this task claimed, only the first task
|
||||||
|
getClient(reviewer1Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", reviewer1.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._embedded.claimedtasks", Matchers.contains(
|
||||||
|
Matchers.allOf(
|
||||||
|
hasJsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks/")),
|
||||||
|
hasJsonPath("$.type", Matchers.is("claimedtask")),
|
||||||
|
hasJsonPath("$._embedded.owner",
|
||||||
|
Matchers.is(EPersonMatcher.matchEPersonOnEmail(reviewer1.getEmail()))),
|
||||||
|
hasJsonPath("$._embedded.action.id", Matchers.is("singleuserreviewaction")),
|
||||||
|
hasJsonPath("$._embedded.workflowitem",
|
||||||
|
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
||||||
|
witem1, "Workflow Item 1", "2017-10-17", "ExtraEntry"))),
|
||||||
|
hasJsonPath("$._embedded.workflowitem",
|
||||||
|
Matchers.not(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
||||||
|
witem2, "Workflow Item 2", "2017-10-17", "ExtraEntry")))
|
||||||
|
))))
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(1)));
|
||||||
|
// Verify members of "ReviewManagers" don't have this task claimed
|
||||||
|
getClient(reviewManager1Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", reviewManager1.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(0)));
|
||||||
|
getClient(reviewManager2Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", reviewManager2.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(0)));
|
||||||
|
getClient(reviewManager3Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", reviewManager3.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(0)));
|
||||||
|
// Verify other users don't have this task claimed
|
||||||
|
getClient(userToken).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", user.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(0)));
|
||||||
|
|
||||||
|
// Test to assign non-reviewer
|
||||||
|
|
||||||
|
// Claim pooltask3 as member of "ReviewManagers"
|
||||||
|
getClient(reviewManager3Token).perform(post("/api/workflow/claimedtasks")
|
||||||
|
.contentType(
|
||||||
|
MediaType.parseMediaType(RestMediaTypes.TEXT_URI_LIST_VALUE))
|
||||||
|
.content("/api/workflow/pooltasks/" + poolTask3.getID()))
|
||||||
|
.andExpect(status().isCreated())
|
||||||
|
.andExpect(jsonPath("$", Matchers.allOf(hasJsonPath("$.type", is("claimedtask")))))
|
||||||
|
.andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
|
||||||
|
|
||||||
|
// Select (non-reviewer) user as a reviewer, wf step 1
|
||||||
|
getClient(reviewManager3Token).perform(post("/api/workflow/claimedtasks/" + idRef.get())
|
||||||
|
.param("submit_select_reviewer", "true")
|
||||||
|
.param("eperson", user.getID().toString())
|
||||||
|
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
|
||||||
|
.andExpect(status().isNoContent());
|
||||||
|
|
||||||
|
// Verify user does not have this task claimed
|
||||||
|
getClient(userToken).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", user.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(0)));
|
||||||
|
|
||||||
|
// Verify item still in claimed tasks for user reviewManager3 on step "selectrevieweraction"
|
||||||
|
getClient(reviewManager3Token).perform(get("/api/workflow/claimedtasks/search/findByUser")
|
||||||
|
.param("uuid", reviewManager3.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._embedded.claimedtasks", Matchers.contains(
|
||||||
|
Matchers.allOf(
|
||||||
|
hasJsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks/")),
|
||||||
|
hasJsonPath("$.type", Matchers.is("claimedtask")),
|
||||||
|
hasJsonPath("$._embedded.owner",
|
||||||
|
Matchers.is(EPersonMatcher.matchEPersonOnEmail(reviewManager3.getEmail()))),
|
||||||
|
hasJsonPath("$._embedded.action.id", Matchers.is("selectrevieweraction")),
|
||||||
|
hasJsonPath("$._embedded.workflowitem",
|
||||||
|
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(
|
||||||
|
witem3, "Workflow Item 3", "2017-10-17", "ExtraEntry")))
|
||||||
|
))))
|
||||||
|
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks")))
|
||||||
|
.andExpect(jsonPath("$.page.size", is(20)))
|
||||||
|
.andExpect(jsonPath("$.page.totalElements", is(1)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.dspace.app.rest;
|
package org.dspace.app.rest;
|
||||||
|
|
||||||
|
import static org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewAction.SUBMIT_SCORE;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
@@ -17,9 +19,18 @@ import org.dspace.app.rest.matcher.WorkflowActionMatcher;
|
|||||||
import org.dspace.app.rest.model.WorkflowActionRest;
|
import org.dspace.app.rest.model.WorkflowActionRest;
|
||||||
import org.dspace.app.rest.repository.WorkflowActionRestRepository;
|
import org.dspace.app.rest.repository.WorkflowActionRestRepository;
|
||||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||||
|
import org.dspace.builder.GroupBuilder;
|
||||||
|
import org.dspace.eperson.Group;
|
||||||
|
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||||
|
import org.dspace.eperson.service.GroupService;
|
||||||
|
import org.dspace.services.ConfigurationService;
|
||||||
|
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||||
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
||||||
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
||||||
import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig;
|
import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig;
|
||||||
|
import org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewActionAdvancedInfo;
|
||||||
|
import org.dspace.xmlworkflow.state.actions.processingaction.SelectReviewerAction;
|
||||||
|
import org.dspace.xmlworkflow.state.actions.processingaction.SelectReviewerActionAdvancedInfo;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -31,6 +42,8 @@ import org.junit.Test;
|
|||||||
public class WorkflowActionRestRepositoryIT extends AbstractControllerIntegrationTest {
|
public class WorkflowActionRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||||
|
|
||||||
private XmlWorkflowFactory xmlWorkflowFactory = XmlWorkflowServiceFactory.getInstance().getWorkflowFactory();
|
private XmlWorkflowFactory xmlWorkflowFactory = XmlWorkflowServiceFactory.getInstance().getWorkflowFactory();
|
||||||
|
private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||||
|
private GroupService groupService = EPersonServiceFactory.getInstance().getGroupService();
|
||||||
|
|
||||||
private static final String WORKFLOW_ACTIONS_ENDPOINT
|
private static final String WORKFLOW_ACTIONS_ENDPOINT
|
||||||
= "/api/" + WorkflowActionRest.CATEGORY + "/" + WorkflowActionRest.NAME_PLURAL;
|
= "/api/" + WorkflowActionRest.CATEGORY + "/" + WorkflowActionRest.NAME_PLURAL;
|
||||||
@@ -82,6 +95,7 @@ public class WorkflowActionRestRepositoryIT extends AbstractControllerIntegratio
|
|||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
// has options
|
// has options
|
||||||
.andExpect(jsonPath("$.options", not(empty())))
|
.andExpect(jsonPath("$.options", not(empty())))
|
||||||
|
.andExpect(jsonPath("$.advanced", is(false)))
|
||||||
//Matches expected corresponding rest action values
|
//Matches expected corresponding rest action values
|
||||||
.andExpect(jsonPath("$", Matchers.is(
|
.andExpect(jsonPath("$", Matchers.is(
|
||||||
WorkflowActionMatcher.matchWorkflowActionEntry(existentWorkflow)
|
WorkflowActionMatcher.matchWorkflowActionEntry(existentWorkflow)
|
||||||
@@ -99,6 +113,7 @@ public class WorkflowActionRestRepositoryIT extends AbstractControllerIntegratio
|
|||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
// has no options
|
// has no options
|
||||||
.andExpect(jsonPath("$.options", empty()))
|
.andExpect(jsonPath("$.options", empty()))
|
||||||
|
.andExpect(jsonPath("$.advanced", is(false)))
|
||||||
//Matches expected corresponding rest action values
|
//Matches expected corresponding rest action values
|
||||||
.andExpect(jsonPath("$", Matchers.is(
|
.andExpect(jsonPath("$", Matchers.is(
|
||||||
WorkflowActionMatcher.matchWorkflowActionEntry(existentWorkflowNoOptions)
|
WorkflowActionMatcher.matchWorkflowActionEntry(existentWorkflowNoOptions)
|
||||||
@@ -125,4 +140,68 @@ public class WorkflowActionRestRepositoryIT extends AbstractControllerIntegratio
|
|||||||
//We expect a 401 Unauthorized
|
//We expect a 401 Unauthorized
|
||||||
.andExpect(status().isUnauthorized());
|
.andExpect(status().isUnauthorized());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getWorkflowActionByName_ExistentWithOptions_ratingreviewaction() throws Exception {
|
||||||
|
String token = getAuthToken(eperson.getEmail(), password);
|
||||||
|
String nameActionWithOptions = "scorereviewaction";
|
||||||
|
WorkflowActionConfig existentWorkflow = xmlWorkflowFactory.getActionByName(nameActionWithOptions);
|
||||||
|
|
||||||
|
// create ScoreReviewActionAdvancedInfo to compare with output
|
||||||
|
ScoreReviewActionAdvancedInfo scoreReviewActionAdvancedInfo = new ScoreReviewActionAdvancedInfo();
|
||||||
|
scoreReviewActionAdvancedInfo.setDescriptionRequired(true);
|
||||||
|
scoreReviewActionAdvancedInfo.setMaxValue(5);
|
||||||
|
scoreReviewActionAdvancedInfo.setType(SUBMIT_SCORE);
|
||||||
|
scoreReviewActionAdvancedInfo.generateId(SUBMIT_SCORE);
|
||||||
|
|
||||||
|
//When we call this facets endpoint
|
||||||
|
getClient(token).perform(get(WORKFLOW_ACTIONS_ENDPOINT + "/" + nameActionWithOptions))
|
||||||
|
//We expect a 200 is ok status
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
// has options
|
||||||
|
.andExpect(jsonPath("$.options", not(empty())))
|
||||||
|
.andExpect(jsonPath("$.advancedOptions", not(empty())))
|
||||||
|
.andExpect(jsonPath("$.advanced", is(true)))
|
||||||
|
.andExpect(jsonPath("$.advancedInfo", Matchers.contains(
|
||||||
|
WorkflowActionMatcher.matchScoreReviewActionAdvancedInfo(scoreReviewActionAdvancedInfo))))
|
||||||
|
//Matches expected corresponding rest action values
|
||||||
|
.andExpect(jsonPath("$", Matchers.is(
|
||||||
|
WorkflowActionMatcher.matchWorkflowActionEntry(existentWorkflow)
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getWorkflowActionByName_ExistentWithOptions_selectrevieweraction() throws Exception {
|
||||||
|
String token = getAuthToken(eperson.getEmail(), password);
|
||||||
|
String nameActionWithOptions = "selectrevieweraction";
|
||||||
|
// create reviewers group
|
||||||
|
SelectReviewerAction.resetGroup();
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
Group group = GroupBuilder.createGroup(context).withName("ReviewersUUIDConfig").build();
|
||||||
|
configurationService.setProperty("action.selectrevieweraction.group", group.getID());
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
// create SelectReviewerActionAdvancedInfo to compare with output
|
||||||
|
SelectReviewerActionAdvancedInfo selectReviewerActionAdvancedInfo = new SelectReviewerActionAdvancedInfo();
|
||||||
|
selectReviewerActionAdvancedInfo.setGroup(group.getID().toString());
|
||||||
|
selectReviewerActionAdvancedInfo.setType("submit_select_reviewer");
|
||||||
|
selectReviewerActionAdvancedInfo.generateId("submit_select_reviewer");
|
||||||
|
|
||||||
|
WorkflowActionConfig existentWorkflow = xmlWorkflowFactory.getActionByName(nameActionWithOptions);
|
||||||
|
//When we call this facets endpoint
|
||||||
|
getClient(token).perform(get(WORKFLOW_ACTIONS_ENDPOINT + "/" + nameActionWithOptions))
|
||||||
|
//We expect a 200 is ok status
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
// has options
|
||||||
|
.andExpect(jsonPath("$.options", not(empty())))
|
||||||
|
.andExpect(jsonPath("$.advancedOptions", not(empty())))
|
||||||
|
.andExpect(jsonPath("$.advanced", is(true)))
|
||||||
|
.andExpect(jsonPath("$.advancedInfo", Matchers.contains(
|
||||||
|
WorkflowActionMatcher.matchSelectReviewerActionAdvancedInfo(selectReviewerActionAdvancedInfo))))
|
||||||
|
//Matches expected corresponding rest action values
|
||||||
|
.andExpect(jsonPath("$", Matchers.is(
|
||||||
|
WorkflowActionMatcher.matchWorkflowActionEntry(existentWorkflow)
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,10 @@ import static org.hamcrest.Matchers.is;
|
|||||||
|
|
||||||
import org.dspace.app.rest.model.WorkflowActionRest;
|
import org.dspace.app.rest.model.WorkflowActionRest;
|
||||||
import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig;
|
import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig;
|
||||||
|
import org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewActionAdvancedInfo;
|
||||||
|
import org.dspace.xmlworkflow.state.actions.processingaction.SelectReviewerActionAdvancedInfo;
|
||||||
import org.hamcrest.Matcher;
|
import org.hamcrest.Matcher;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Maria Verdonck (Atmire) on 06/01/2020
|
* @author Maria Verdonck (Atmire) on 06/01/2020
|
||||||
@@ -32,7 +35,35 @@ public class WorkflowActionMatcher {
|
|||||||
return allOf(
|
return allOf(
|
||||||
hasJsonPath("$.id", is(workflowAction.getId())),
|
hasJsonPath("$.id", is(workflowAction.getId())),
|
||||||
hasJsonPath("$.options", is(workflowAction.getOptions())),
|
hasJsonPath("$.options", is(workflowAction.getOptions())),
|
||||||
|
hasJsonPath("$.advanced", is(workflowAction.isAdvanced())),
|
||||||
hasJsonPath("$._links.self.href", containsString(WORKFLOW_ACTIONS_ENDPOINT + workflowAction.getId()))
|
hasJsonPath("$._links.self.href", containsString(WORKFLOW_ACTIONS_ENDPOINT + workflowAction.getId()))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matcher to check the contents of the advancedInfo for "ratingreviewaction"
|
||||||
|
* @param scoreReviewActionAdvancedInfo identical ScoreReviewActionAdvancedInfo object
|
||||||
|
*/
|
||||||
|
public static Matcher<? super Object> matchScoreReviewActionAdvancedInfo(
|
||||||
|
ScoreReviewActionAdvancedInfo scoreReviewActionAdvancedInfo) {
|
||||||
|
return Matchers.allOf(
|
||||||
|
hasJsonPath("$.descriptionRequired", is(scoreReviewActionAdvancedInfo.isDescriptionRequired())),
|
||||||
|
hasJsonPath("$.maxValue", is(scoreReviewActionAdvancedInfo.getMaxValue())),
|
||||||
|
hasJsonPath("$.type", is(scoreReviewActionAdvancedInfo.getType())),
|
||||||
|
hasJsonPath("$.id", is(scoreReviewActionAdvancedInfo.getId()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matcher to check the contents of the advancedInfo for "selectrevieweraction"
|
||||||
|
* @param selectReviewerActionAdvancedInfo identical SelectReviewerActionAdvancedInfo object
|
||||||
|
*/
|
||||||
|
public static Matcher<? super Object> matchSelectReviewerActionAdvancedInfo(
|
||||||
|
SelectReviewerActionAdvancedInfo selectReviewerActionAdvancedInfo) {
|
||||||
|
return Matchers.allOf(
|
||||||
|
hasJsonPath("$.group", is(selectReviewerActionAdvancedInfo.getGroup())),
|
||||||
|
hasJsonPath("$.type", is(selectReviewerActionAdvancedInfo.getType())),
|
||||||
|
hasJsonPath("$.id", is(selectReviewerActionAdvancedInfo.getId()))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,3 +17,8 @@ workflow.reviewer.file-edit=false
|
|||||||
|
|
||||||
# Notify reviewers about tasks returned to the pool
|
# Notify reviewers about tasks returned to the pool
|
||||||
#workflow.notify.returned.tasks = true
|
#workflow.notify.returned.tasks = true
|
||||||
|
|
||||||
|
# Reviewer group for the select reviewer workflow (can be UUID or group name)
|
||||||
|
# This determines the group from which reviewers can be chosen
|
||||||
|
# If this is not set, the review manager can choose reviewers from all e-people instead of this selected group
|
||||||
|
action.selectrevieweraction.group = Reviewers
|
||||||
|
@@ -17,7 +17,13 @@
|
|||||||
<dc-type>
|
<dc-type>
|
||||||
<schema>workflow</schema>
|
<schema>workflow</schema>
|
||||||
<element>score</element>
|
<element>score</element>
|
||||||
<scope_note>Metadata field used for the score review</scope_note>
|
<scope_note>Metadata field used for the score review rating</scope_note>
|
||||||
|
</dc-type>
|
||||||
|
|
||||||
|
<dc-type>
|
||||||
|
<schema>workflow</schema>
|
||||||
|
<element>review</element>
|
||||||
|
<scope_note>Metadata field used for the score review description</scope_note>
|
||||||
</dc-type>
|
</dc-type>
|
||||||
|
|
||||||
</dspace-dc-types>
|
</dspace-dc-types>
|
||||||
|
@@ -13,9 +13,12 @@
|
|||||||
<bean id="selectrevieweractionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.SelectReviewerAction" scope="prototype">
|
<bean id="selectrevieweractionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.SelectReviewerAction" scope="prototype">
|
||||||
<property name="role" ref="scoreassignedreviewer"/>
|
<property name="role" ref="scoreassignedreviewer"/>
|
||||||
</bean>
|
</bean>
|
||||||
<bean id="scorereviewactionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewAction" scope="prototype"/>
|
<bean id="scorereviewactionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewAction" scope="prototype">
|
||||||
|
<property name="descriptionRequired" value="true"/>
|
||||||
|
<property name="maxValue" value="5"/>
|
||||||
|
</bean>
|
||||||
<bean id="evaluationactionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.ScoreEvaluationAction" scope="prototype">
|
<bean id="evaluationactionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.ScoreEvaluationAction" scope="prototype">
|
||||||
<property name="minimumAcceptanceScore" value="50" />
|
<property name="minimumAcceptanceScore" value="3" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
|
||||||
@@ -61,6 +64,12 @@
|
|||||||
<property name="requiresUI" value="true"/>
|
<property name="requiresUI" value="true"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="ratingreviewaction" class="org.dspace.xmlworkflow.state.actions.WorkflowActionConfig" scope="prototype">
|
||||||
|
<constructor-arg type="java.lang.String" value="ratingreviewaction"/>
|
||||||
|
<property name="processingAction" ref="ratingreviewactionAPI" />
|
||||||
|
<property name="requiresUI" value="true"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
<!--Autmatic step that evaluates scores (workflow.score) and checks if they match the configured minimum for archiving -->
|
<!--Autmatic step that evaluates scores (workflow.score) and checks if they match the configured minimum for archiving -->
|
||||||
<bean id="evaluationaction" class="org.dspace.xmlworkflow.state.actions.WorkflowActionConfig" scope="prototype">
|
<bean id="evaluationaction" class="org.dspace.xmlworkflow.state.actions.WorkflowActionConfig" scope="prototype">
|
||||||
<constructor-arg type="java.lang.String" value="evaluationaction"/>
|
<constructor-arg type="java.lang.String" value="evaluationaction"/>
|
||||||
|
@@ -151,6 +151,7 @@
|
|||||||
<bean id="scoreassignedreviewer" class="org.dspace.xmlworkflow.Role">
|
<bean id="scoreassignedreviewer" class="org.dspace.xmlworkflow.Role">
|
||||||
<property name="scope" value="#{ T(org.dspace.xmlworkflow.Role.Scope).ITEM}"/>
|
<property name="scope" value="#{ T(org.dspace.xmlworkflow.Role.Scope).ITEM}"/>
|
||||||
<property name="name" value="Reviewer"/>
|
<property name="name" value="Reviewer"/>
|
||||||
|
<property name="deleteTemporaryGroup" value="true"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user