From 743d35f098c2a03edab7acd995f615cfd4fa3a53 Mon Sep 17 00:00:00 2001 From: Marie Verdonck Date: Tue, 18 Feb 2020 11:33:48 +0100 Subject: [PATCH] 68821: check if submit button is in valid options for current action in workflow + previously @ignore tests now work as expected --- .../xmlworkflow/state/actions/Action.java | 14 + .../AcceptEditRejectAction.java | 15 +- .../processingaction/FinalEditAction.java | 24 +- .../processingaction/ProcessingAction.java | 1 + .../processingaction/ReviewAction.java | 27 +- .../repository/ClaimedTaskRestRepository.java | 5 + .../app/rest/TaskRestRepositoriesIT.java | 813 ++++++++++++++++++ 7 files changed, 870 insertions(+), 29 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/Action.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/Action.java index 9cf202f12d..b8273ebf9b 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/Action.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/Action.java @@ -50,6 +50,20 @@ public abstract class Action { */ public abstract List getOptions(); + /** + * Returns true if one of the options is a parameter of the request + * @param request Action request + * @return true if one of the options is a parameter of the request; false if none was found + */ + protected boolean isInOptions(HttpServletRequest request) { + for (String option: this.getOptions()) { + if (request.getParameter(option) != null) { + return true; + } + } + return false; + } + public WorkflowActionConfig getParent() { return parent; } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/AcceptEditRejectAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/AcceptEditRejectAction.java index 3c595b7545..5065753b0a 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/AcceptEditRejectAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/AcceptEditRejectAction.java @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.List; import javax.servlet.http.HttpServletRequest; +import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCDate; import org.dspace.content.MetadataSchemaEnum; @@ -46,12 +47,14 @@ public class AcceptEditRejectAction extends ProcessingAction { @Override public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException { - - if (request.getParameter(SUBMIT_APPROVE) != null) { - return processAccept(c, wfi); - } else { - if (request.getParameter(SUBMIT_REJECT) != null) { - return processRejectPage(c, wfi, request); + if (super.isInOptions(request)) { + switch (Util.getSubmitButton(request, SUBMIT_CANCEL)) { + case SUBMIT_APPROVE: + return processAccept(c, wfi); + case SUBMIT_REJECT: + return processRejectPage(c, wfi, request); + default: + return new ActionResult(ActionResult.TYPE.TYPE_CANCEL); } } return new ActionResult(ActionResult.TYPE.TYPE_CANCEL); diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/FinalEditAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/FinalEditAction.java index fe73bf6a5d..31bb8712d3 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/FinalEditAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/FinalEditAction.java @@ -12,6 +12,7 @@ import java.util.ArrayList; import java.util.List; import javax.servlet.http.HttpServletRequest; +import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCDate; import org.dspace.content.MetadataSchemaEnum; @@ -42,20 +43,23 @@ public class FinalEditAction extends ProcessingAction { @Override public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException { - return processMainPage(c, wfi, step, request); + return processMainPage(c, wfi, request); } - public ActionResult processMainPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + public ActionResult processMainPage(Context c, XmlWorkflowItem wfi, HttpServletRequest request) throws SQLException, AuthorizeException { - if (request.getParameter(SUBMIT_APPROVE) != null) { - //Delete the tasks - addApprovedProvenance(c, wfi); - - return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE); - } else { - //We pressed the leave button so return to our submissions page - return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE); + if (super.isInOptions(request)) { + switch (Util.getSubmitButton(request, SUBMIT_CANCEL)) { + case SUBMIT_APPROVE: + //Delete the tasks + addApprovedProvenance(c, wfi); + return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE); + default: + //We pressed the leave button so return to our submissions page + return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE); + } } + return new ActionResult(ActionResult.TYPE.TYPE_CANCEL); } @Override diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ProcessingAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ProcessingAction.java index 98af6facf3..76f834887d 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ProcessingAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ProcessingAction.java @@ -35,6 +35,7 @@ public abstract class ProcessingAction extends Action { protected ItemService itemService; protected static final String SUBMIT_EDIT_METADATA = "submit_edit_metadata"; + protected static final String SUBMIT_CANCEL = "submit_cancel"; @Override public boolean isAuthorized(Context context, HttpServletRequest request, XmlWorkflowItem wfi) throws SQLException { diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ReviewAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ReviewAction.java index 5284874572..ec86a13ef3 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ReviewAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ReviewAction.java @@ -14,6 +14,7 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; +import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCDate; import org.dspace.content.MetadataSchemaEnum; @@ -47,14 +48,16 @@ public class ReviewAction extends ProcessingAction { @Override public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException { - if (request.getParameter(SUBMIT_APPROVE) != null) { - return processAccept(c, wfi, step, request); - } else { - if (request.getParameter(SUBMIT_REJECT) != null) { - return processRejectPage(c, wfi, step, request); + if (super.isInOptions(request)) { + switch (Util.getSubmitButton(request, SUBMIT_CANCEL)) { + case SUBMIT_APPROVE: + return processAccept(c, wfi); + case SUBMIT_REJECT: + return processRejectPage(c, wfi, step, request); + default: + return new ActionResult(ActionResult.TYPE.TYPE_CANCEL); } } - return new ActionResult(ActionResult.TYPE.TYPE_CANCEL); } @@ -66,11 +69,9 @@ public class ReviewAction extends ProcessingAction { return options; } - public ActionResult processAccept(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) - throws SQLException, AuthorizeException { + public ActionResult processAccept(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException { //Delete the tasks addApprovedProvenance(c, wfi); - return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE); } @@ -80,14 +81,14 @@ public class ReviewAction extends ProcessingAction { // Get user's name + email address String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService() - .getEPersonName(c.getCurrentUser()); + .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); + provDescription); itemService.update(c, wfi.getItem()); } @@ -102,8 +103,8 @@ public class ReviewAction extends ProcessingAction { //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); + .sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(), + this.getProvenanceStartId(), reason); return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClaimedTaskRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClaimedTaskRestRepository.java index f0e1beff3c..354bceb949 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClaimedTaskRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClaimedTaskRestRepository.java @@ -23,6 +23,7 @@ import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException; import org.dspace.app.rest.exception.UnprocessableEntityException; import org.dspace.app.rest.model.ClaimedTaskRest; import org.dspace.app.rest.model.PoolTaskRest; +import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.service.AuthorizeService; import org.dspace.content.service.ItemService; @@ -137,6 +138,10 @@ public class ClaimedTaskRestRepository extends DSpaceRestRepository idRef = new AtomicReference(); + + // step 1 + getClient(reviewer1Token).perform(get("/api/workflow/pooltasks/search/findByUser") + .param("uuid", reviewer1.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains( + Matchers.allOf( + Matchers.is(PoolTaskMatcher.matchPoolTask(null, "reviewstep")), + hasJsonPath("$._embedded.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/pooltasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.pooltasks[0].id")))); + + // claim the task + getClient(reviewer1Token).perform(post("/api/workflow/pooltasks/" + idRef.get()) + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // get the id of 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.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.claimedtasks[0].id")))); + + // approve the claimedTask, wf step 1 + getClient(reviewer1Token).perform(post("/api/workflow/claimedtasks/" + idRef.get()) + .param("submit_approve", "true") + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // verify that the underline item is still unpublished + getClient(adminToken).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.inArchive", is(false))); + + // step 2 + getClient(reviewer2Token).perform(get("/api/workflow/pooltasks/search/findByUser") + .param("uuid", reviewer2.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains( + Matchers.allOf( + Matchers.is(PoolTaskMatcher.matchPoolTask(null, "editstep")), + hasJsonPath("$._embedded.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/pooltasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.pooltasks[0].id")))); + + // claim the task + getClient(reviewer2Token).perform(post("/api/workflow/pooltasks/" + idRef.get()) + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // get the id of 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.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.claimedtasks[0].id")))); + + // try submit_edit_metadata option, default wf step 2 (edit step) + getClient(reviewer2Token).perform(post("/api/workflow/claimedtasks/" + idRef.get()) + .param("submit_edit_metadata", "true") + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + } + @Test /** * Test the run of the default workflow where the reviewer attempts a non-valid option in the 2d step (edit step) @@ -2505,4 +2660,662 @@ public class TaskRestRepositoriesIT extends AbstractControllerIntegrationTest { .andExpect(jsonPath("$.inArchive", is(false))); } + @Test + /** + * Test the run of the default workflow where the reviewer attempts a reject option in the 3rd step (final edit step) + * + * @throws Exception + */ + public void defaultWorkflowTest_UntilFinalEditStep_Reject() throws Exception { + context.turnOffAuthorisationSystem(); + //** GIVEN ** + //1. three reviewers + EPerson reviewer1 = EPersonBuilder.createEPerson(context) + .withEmail("reviewer1@example.com") + .withPassword(password) + .build(); + + EPerson reviewer2 = EPersonBuilder.createEPerson(context) + .withEmail("reviewer2@example.com") + .withPassword(password) + .build(); + + EPerson reviewer3 = EPersonBuilder.createEPerson(context) + .withEmail("reviewer3@example.com") + .withPassword(password) + .build(); + + //2. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1") + .withWorkflowGroup(1, reviewer1) + .withWorkflowGroup(2, reviewer2) + .withWorkflowGroup(3, reviewer3) + .build(); + + //3. create a normal user to use as submitter + EPerson submitter = EPersonBuilder.createEPerson(context) + .withEmail("submitter@example.com") + .withPassword(password) + .build(); + + context.setCurrentUser(submitter); + + //3. create a workflowitem (so a pool task in step1) + XmlWorkflowItem witem = WorkflowItemBuilder.createWorkflowItem(context, col1) + .withTitle("Test item full workflow") + .withIssueDate("2019-03-06") + .withSubject("ExtraEntry") + .build(); + + Item item = witem.getItem(); + + context.restoreAuthSystemState(); + + String reviewer1Token = getAuthToken(reviewer1.getEmail(), password); + String reviewer2Token = getAuthToken(reviewer2.getEmail(), password); + String reviewer3Token = getAuthToken(reviewer3.getEmail(), password); + String adminToken = getAuthToken(admin.getEmail(), password); + + AtomicReference idRef = new AtomicReference(); + + // step 1 + getClient(reviewer1Token).perform(get("/api/workflow/pooltasks/search/findByUser") + .param("uuid", reviewer1.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains( + Matchers.allOf( + Matchers.is(PoolTaskMatcher.matchPoolTask(null, "reviewstep")), + hasJsonPath("$._embedded.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/pooltasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.pooltasks[0].id")))); + + // claim the task + getClient(reviewer1Token).perform(post("/api/workflow/pooltasks/" + idRef.get()) + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // get the id of 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.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.claimedtasks[0].id")))); + + // approve the claimedTask, wf step 1 + getClient(reviewer1Token).perform(post("/api/workflow/claimedtasks/" + idRef.get()) + .param("submit_approve", "true") + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // verify that the underline item is still unpublished + getClient(adminToken).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.inArchive", is(false))); + + // step 2 + getClient(reviewer2Token).perform(get("/api/workflow/pooltasks/search/findByUser") + .param("uuid", reviewer2.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains( + Matchers.allOf( + Matchers.is(PoolTaskMatcher.matchPoolTask(null, "editstep")), + hasJsonPath("$._embedded.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/pooltasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.pooltasks[0].id")))); + + // claim the task + getClient(reviewer2Token).perform(post("/api/workflow/pooltasks/" + idRef.get()) + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // get the id of 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.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.claimedtasks[0].id")))); + + // approve the claimedTask, wf step 2 + getClient(reviewer2Token).perform(post("/api/workflow/claimedtasks/" + idRef.get()) + .param("submit_approve", "true") + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // verify that the underline item is still unpublished + getClient(adminToken).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.inArchive", is(false))); + + // step 3 + getClient(reviewer3Token).perform(get("/api/workflow/pooltasks/search/findByUser") + .param("uuid", reviewer3.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains( + Matchers.allOf( + Matchers.is(PoolTaskMatcher.matchPoolTask(null, "finaleditstep")), + hasJsonPath("$._embedded.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/pooltasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.pooltasks[0].id")))); + + // claim the task + getClient(reviewer3Token).perform(post("/api/workflow/pooltasks/" + idRef.get()) + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // get the id of the claimed task + 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.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.claimedtasks[0].id")))); + + // reject the claimedTask, default wf step 3 (final edit step) + getClient(reviewer3Token).perform(post("/api/workflow/claimedtasks/" + idRef.get()) + .param("submit_reject", "true") + .param("reason", "I need to test reject in fina edit step") + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isUnprocessableEntity()); + + // verify that the task has not been processed and is still available + getClient(reviewer3Token).perform(get("/api/workflow/claimedtasks/" + idRef.get())) + .andExpect(status().isOk()); + + // verify that the underline item is still unpublished + getClient(adminToken).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.inArchive", is(false))); + } + + @Test + /** + * Test the run of the default workflow where the reviewer attempts an edit metadata in the 3rd step (final edit step) + * + * @throws Exception + */ + public void defaultWorkflowTest_UntilFinalEditStep_EditMetadata() throws Exception { + context.turnOffAuthorisationSystem(); + //** GIVEN ** + //1. three reviewers + EPerson reviewer1 = EPersonBuilder.createEPerson(context) + .withEmail("reviewer1@example.com") + .withPassword(password) + .build(); + + EPerson reviewer2 = EPersonBuilder.createEPerson(context) + .withEmail("reviewer2@example.com") + .withPassword(password) + .build(); + + EPerson reviewer3 = EPersonBuilder.createEPerson(context) + .withEmail("reviewer3@example.com") + .withPassword(password) + .build(); + + //2. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1") + .withWorkflowGroup(1, reviewer1) + .withWorkflowGroup(2, reviewer2) + .withWorkflowGroup(3, reviewer3) + .build(); + + //3. create a normal user to use as submitter + EPerson submitter = EPersonBuilder.createEPerson(context) + .withEmail("submitter@example.com") + .withPassword(password) + .build(); + + context.setCurrentUser(submitter); + + //3. create a workflowitem (so a pool task in step1) + XmlWorkflowItem witem = WorkflowItemBuilder.createWorkflowItem(context, col1) + .withTitle("Test item full workflow") + .withIssueDate("2019-03-06") + .withSubject("ExtraEntry") + .build(); + + Item item = witem.getItem(); + + context.restoreAuthSystemState(); + + String reviewer1Token = getAuthToken(reviewer1.getEmail(), password); + String reviewer2Token = getAuthToken(reviewer2.getEmail(), password); + String reviewer3Token = getAuthToken(reviewer3.getEmail(), password); + String adminToken = getAuthToken(admin.getEmail(), password); + + AtomicReference idRef = new AtomicReference(); + + // step 1 + getClient(reviewer1Token).perform(get("/api/workflow/pooltasks/search/findByUser") + .param("uuid", reviewer1.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains( + Matchers.allOf( + Matchers.is(PoolTaskMatcher.matchPoolTask(null, "reviewstep")), + hasJsonPath("$._embedded.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/pooltasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.pooltasks[0].id")))); + + // claim the task + getClient(reviewer1Token).perform(post("/api/workflow/pooltasks/" + idRef.get()) + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // get the id of 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.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.claimedtasks[0].id")))); + + // approve the claimedTask, wf step 1 + getClient(reviewer1Token).perform(post("/api/workflow/claimedtasks/" + idRef.get()) + .param("submit_approve", "true") + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // verify that the underline item is still unpublished + getClient(adminToken).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.inArchive", is(false))); + + // step 2 + getClient(reviewer2Token).perform(get("/api/workflow/pooltasks/search/findByUser") + .param("uuid", reviewer2.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains( + Matchers.allOf( + Matchers.is(PoolTaskMatcher.matchPoolTask(null, "editstep")), + hasJsonPath("$._embedded.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/pooltasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.pooltasks[0].id")))); + + // claim the task + getClient(reviewer2Token).perform(post("/api/workflow/pooltasks/" + idRef.get()) + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // get the id of 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.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.claimedtasks[0].id")))); + + // approve the claimedTask, wf step 2 + getClient(reviewer2Token).perform(post("/api/workflow/claimedtasks/" + idRef.get()) + .param("submit_approve", "true") + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // verify that the underline item is still unpublished + getClient(adminToken).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.inArchive", is(false))); + + // step 3 + getClient(reviewer3Token).perform(get("/api/workflow/pooltasks/search/findByUser") + .param("uuid", reviewer3.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains( + Matchers.allOf( + Matchers.is(PoolTaskMatcher.matchPoolTask(null, "finaleditstep")), + hasJsonPath("$._embedded.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/pooltasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.pooltasks[0].id")))); + + // claim the task + getClient(reviewer3Token).perform(post("/api/workflow/pooltasks/" + idRef.get()) + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // get the id of the claimed task + 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.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.claimedtasks[0].id")))); + + // edit metadata of the claimedTask, default wf step 3 (final edit step) + getClient(reviewer3Token).perform(post("/api/workflow/claimedtasks/" + idRef.get()) + .param("submit_edit_metadata", "true") + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + } + + @Test + /** + * Test the run of the default workflow where the reviewer attempts a non-valid option in the 3rd step (final edit step) + * + * @throws Exception + */ + public void defaultWorkflowTest_UntilFinalEditStep_NonValidOption() throws Exception { + context.turnOffAuthorisationSystem(); + //** GIVEN ** + //1. three reviewers + EPerson reviewer1 = EPersonBuilder.createEPerson(context) + .withEmail("reviewer1@example.com") + .withPassword(password) + .build(); + + EPerson reviewer2 = EPersonBuilder.createEPerson(context) + .withEmail("reviewer2@example.com") + .withPassword(password) + .build(); + + EPerson reviewer3 = EPersonBuilder.createEPerson(context) + .withEmail("reviewer3@example.com") + .withPassword(password) + .build(); + + //2. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1") + .withWorkflowGroup(1, reviewer1) + .withWorkflowGroup(2, reviewer2) + .withWorkflowGroup(3, reviewer3) + .build(); + + //3. create a normal user to use as submitter + EPerson submitter = EPersonBuilder.createEPerson(context) + .withEmail("submitter@example.com") + .withPassword(password) + .build(); + + context.setCurrentUser(submitter); + + //3. create a workflowitem (so a pool task in step1) + XmlWorkflowItem witem = WorkflowItemBuilder.createWorkflowItem(context, col1) + .withTitle("Test item full workflow") + .withIssueDate("2019-03-06") + .withSubject("ExtraEntry") + .build(); + + Item item = witem.getItem(); + + context.restoreAuthSystemState(); + + String reviewer1Token = getAuthToken(reviewer1.getEmail(), password); + String reviewer2Token = getAuthToken(reviewer2.getEmail(), password); + String reviewer3Token = getAuthToken(reviewer3.getEmail(), password); + String adminToken = getAuthToken(admin.getEmail(), password); + + AtomicReference idRef = new AtomicReference(); + + // step 1 + getClient(reviewer1Token).perform(get("/api/workflow/pooltasks/search/findByUser") + .param("uuid", reviewer1.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains( + Matchers.allOf( + Matchers.is(PoolTaskMatcher.matchPoolTask(null, "reviewstep")), + hasJsonPath("$._embedded.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/pooltasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.pooltasks[0].id")))); + + // claim the task + getClient(reviewer1Token).perform(post("/api/workflow/pooltasks/" + idRef.get()) + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // get the id of 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.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.claimedtasks[0].id")))); + + // approve the claimedTask, wf step 1 + getClient(reviewer1Token).perform(post("/api/workflow/claimedtasks/" + idRef.get()) + .param("submit_approve", "true") + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // verify that the underline item is still unpublished + getClient(adminToken).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.inArchive", is(false))); + + // step 2 + getClient(reviewer2Token).perform(get("/api/workflow/pooltasks/search/findByUser") + .param("uuid", reviewer2.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains( + Matchers.allOf( + Matchers.is(PoolTaskMatcher.matchPoolTask(null, "editstep")), + hasJsonPath("$._embedded.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/pooltasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.pooltasks[0].id")))); + + // claim the task + getClient(reviewer2Token).perform(post("/api/workflow/pooltasks/" + idRef.get()) + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // get the id of 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.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.claimedtasks[0].id")))); + + // approve the claimedTask, wf step 2 + getClient(reviewer2Token).perform(post("/api/workflow/claimedtasks/" + idRef.get()) + .param("submit_approve", "true") + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // verify that the underline item is still unpublished + getClient(adminToken).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.inArchive", is(false))); + + // step 3 + getClient(reviewer3Token).perform(get("/api/workflow/pooltasks/search/findByUser") + .param("uuid", reviewer3.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.pooltasks", Matchers.contains( + Matchers.allOf( + Matchers.is(PoolTaskMatcher.matchPoolTask(null, "finaleditstep")), + hasJsonPath("$._embedded.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/pooltasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.pooltasks[0].id")))); + + // claim the task + getClient(reviewer3Token).perform(post("/api/workflow/pooltasks/" + idRef.get()) + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + + // get the id of the claimed task + 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.workflowitem", + Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject( + witem, "Test item full workflow", "2019-03-06", "ExtraEntry"))) + )))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/workflow/claimedtasks"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andDo((result -> idRef + .set(read(result.getResponse().getContentAsString(), "$._embedded.claimedtasks[0].id")))); + + // non valid option in the default wf step 3 (final edit step) + getClient(reviewer3Token).perform(post("/api/workflow/claimedtasks/" + idRef.get()) + .param("submit_non_valid_option", "true") + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isUnprocessableEntity()); + + // verify that the task has not been processed and is still available + getClient(reviewer3Token).perform(get("/api/workflow/claimedtasks/" + idRef.get())) + .andExpect(status().isOk()); + + // verify that the underline item is still unpublished + getClient(adminToken).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.inArchive", is(false))); + } + }