From 6079c6fdfb9da5cdd4d5969b974d9989a8e9b369 Mon Sep 17 00:00:00 2001 From: Glen Johnson Date: Tue, 29 Jul 2008 15:50:42 +0000 Subject: [PATCH] Fix for inviteresponse web script - when an invitation is either accepted or rejected, the respective tasks in the invite workflow are now getting ended properly, thus ending the workflow git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@10105 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../web-scripts-application-context.xml | 1 + .../workflow/invite_processdefinition.xml | 4 +- .../web/scripts/invite/InviteResponse.java | 128 +++++++++++------- .../web/scripts/invite/InviteServiceTest.java | 31 ++++- 4 files changed, 110 insertions(+), 54 deletions(-) diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 8be2838ff3..2106206bfa 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -310,6 +310,7 @@ + diff --git a/config/alfresco/workflow/invite_processdefinition.xml b/config/alfresco/workflow/invite_processdefinition.xml index 045c38803f..670e00f7c5 100644 --- a/config/alfresco/workflow/invite_processdefinition.xml +++ b/config/alfresco/workflow/invite_processdefinition.xml @@ -58,12 +58,12 @@ - + - + diff --git a/source/java/org/alfresco/repo/web/scripts/invite/InviteResponse.java b/source/java/org/alfresco/repo/web/scripts/invite/InviteResponse.java index f4b5a543b0..1c9daad8fd 100644 --- a/source/java/org/alfresco/repo/web/scripts/invite/InviteResponse.java +++ b/source/java/org/alfresco/repo/web/scripts/invite/InviteResponse.java @@ -34,8 +34,12 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.site.SiteModel; import org.alfresco.repo.site.SiteService; import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.cmr.workflow.WorkflowPath; import org.alfresco.service.cmr.workflow.WorkflowService; +import org.alfresco.service.cmr.workflow.WorkflowTask; +import org.alfresco.service.cmr.workflow.WorkflowTaskQuery; +import org.alfresco.service.cmr.workflow.WorkflowTaskState; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; import org.alfresco.web.scripts.DeclarativeWebScript; import org.alfresco.web.scripts.Status; import org.alfresco.web.scripts.WebScriptException; @@ -85,8 +89,13 @@ public class InviteResponse extends DeclarativeWebScript private static final String RESPONSE_ACCEPT = "accept"; private static final String RESPONSE_REJECT = "reject"; - private static final String TRANSITION_ACCEPT = "accept"; - private static final String TRANSITION_REJECT = "reject"; + private static final String WF_TASK_ACCEPT_INVITE = "wf:acceptInviteTask"; + private static final String WF_TASK_REJECT_INVITE = "wf:rejectInviteTask"; + private static final String WF_TASK_INVITE_PENDING = "wf:invitePendingTask"; + private static final String WF_TRANSITION_ACCEPT = "accept"; + private static final String WF_TRANSITION_REJECT = "reject"; + private static final String WF_TRANSITION_ACCEPT_INVITE_END = "end"; + private static final String WF_TRANSITION_REJECT_INVITE_END = "end"; private static final String MODEL_PROP_KEY_RESPONSE = "response"; private static final String MODEL_PROP_KEY_SITE_SHORT_NAME = "siteShortName"; private static final String USER_ADMIN = "admin"; @@ -96,6 +105,7 @@ public class InviteResponse extends DeclarativeWebScript private MutableAuthenticationDao mutableAuthenticationDao; private SiteService siteService; private PersonService personService; + private NamespaceService namespaceService; /** * Sets the workflow service property @@ -141,6 +151,17 @@ public class InviteResponse extends DeclarativeWebScript { this.personService = personService; } + + /** + * Sets the namespaceService property + * + * @param namespaceService + * the namespace service to set + */ + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } /* * (non-Javadoc) @@ -230,37 +251,28 @@ public class InviteResponse extends DeclarativeWebScript private void acceptInvite(Map model, String inviteId, String inviteeUserName, String siteShortName) { - // get workflow ID from invite ID (of which the value is actually - // just the ID of the invite workflow instance) - String workflowId = inviteId; + // complete the wf:invitePendingTask task because the invitation has been accepted + completeInviteTask(QName.createQName(WF_TASK_INVITE_PENDING, this.namespaceService), WF_TRANSITION_ACCEPT); - // get workflow paths associated with workflow ID - List wfPaths = this.workflowService - .getWorkflowPaths(workflowId); - - // throw web script exception if there is not at least one workflow path - // associated with this workflow ID - if ((wfPaths == null) || (wfPaths.size() == 0)) - { - throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, - "There are no workflow paths associated with workflow ID: " - + workflowId); - } - - // get workflow path ID for path matching workflow ID - WorkflowPath wfPath = wfPaths.get(0); - String wfPathID = wfPath.id; - - this.workflowService.signal(wfPathID, TRANSITION_ACCEPT); + // TODO glen dot johnson at alfresco dot com - farm the code that follows (up until adding properties onto + // the model) out into workflow action class that gets run when task wf:acceptInviteTask + // is completed by this web script // enable invitee person's user account because he/she has accepted the // site invitation this.mutableAuthenticationDao.setEnabled(inviteeUserName, true); - + // Add Invitee to Site as "Site Collaborator" role RunAsWork setSiteMembershipWorker = new InviteResponse.SetSiteMembershipWorker( siteShortName, inviteeUserName, SiteModel.SITE_COLLABORATOR); AuthenticationUtil.runAs(setSiteMembershipWorker, USER_ADMIN); + + // complete the wf:acceptInviteTask because the operations that need to be performed + // when the invitee has accepted the invitation have now been performed (code block + // above up to where wf:invitePendingTask is completed). This code block will soon + // be farmed out into a workflow action which gets executed when wf:acceptInviteTask + // gets completed + completeInviteTask(QName.createQName(WF_TASK_ACCEPT_INVITE, this.namespaceService), WF_TRANSITION_ACCEPT_INVITE_END); // add model properties for template to render model.put(MODEL_PROP_KEY_RESPONSE, RESPONSE_ACCEPT); @@ -284,34 +296,58 @@ public class InviteResponse extends DeclarativeWebScript private void rejectInvite(Map model, String inviteId, String inviteeUserName, String siteShortName) { - // get workflow ID from invite ID (of which the value is actually - // just the ID of the invite workflow instance) - String workflowId = inviteId; + // complete the wf:invitePendingTask task because the invitation has been accepted + completeInviteTask(QName.createQName(WF_TASK_INVITE_PENDING, this.namespaceService), WF_TRANSITION_REJECT); - // get workflow paths associated with workflow ID - List wfPaths = this.workflowService - .getWorkflowPaths(workflowId); - - // throw web script exception if there is not at least one workflow path - // associated with this workflow ID - if ((wfPaths == null) || (wfPaths.size() == 0)) - { - throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, - "There are no workflow paths associated with workflow ID: " - + workflowId); - } - - // get workflow path ID for path matching workflow ID - WorkflowPath wfPath = wfPaths.get(0); - String wfPathID = wfPath.id; - - this.workflowService.signal(wfPathID, TRANSITION_REJECT); + // TODO glen dot johnson at alfresco dot com - farm the code that follows (up until adding properties onto + // the model) out into workflow action class that gets run when task wf:rejectInviteTask + // is completed by this web script // delete the person created for invitee this.personService.deletePerson(inviteeUserName); + // complete the wf:rejectInviteTask because the operations that need to be performed + // when the invitee has rejected the invitation have now been performed (code block + // above up to where wf:invitePendingTask is completed). This code block will soon + // be farmed out into a workflow action which gets executed when wf:rejectInviteTask + // gets completed + completeInviteTask(QName.createQName(WF_TASK_REJECT_INVITE, this.namespaceService), WF_TRANSITION_REJECT_INVITE_END); + // add model properties for template to render model.put(MODEL_PROP_KEY_RESPONSE, RESPONSE_REJECT); model.put(MODEL_PROP_KEY_SITE_SHORT_NAME, siteShortName); } + + /** + * Complete the specified Invite Workflow Task and follow the given + * transition upon completing the task + * + * @param fullTaskName qualified name of invite workflow task to complete + * @param transitionId the task transition to take on completion of + * the task (or null, for the default transition) + */ + private void completeInviteTask(QName fullTaskName, String transitionId) + { + // create workflow task query + WorkflowTaskQuery wfTaskQuery = new WorkflowTaskQuery(); + + // find incomplete invite workflow tasks with given task name + wfTaskQuery.setActive(Boolean.TRUE); + wfTaskQuery.setTaskState(WorkflowTaskState.IN_PROGRESS); + wfTaskQuery.setTaskName(fullTaskName); + + // set process name to "wf:invite" so that only + // invite workflow instances are considered by this query + wfTaskQuery.setProcessName(QName.createQName("wf:invite", this.namespaceService)); + + // query for invite workflow tasks with the constructed query + List wf_invite_tasks = this.workflowService + .queryTasks(wfTaskQuery); + + // end all tasks found with this name + for (WorkflowTask workflowTask : wf_invite_tasks) + { + this.workflowService.endTask(workflowTask.id, transitionId); + } + } } diff --git a/source/java/org/alfresco/repo/web/scripts/invite/InviteServiceTest.java b/source/java/org/alfresco/repo/web/scripts/invite/InviteServiceTest.java index ad9167863c..3353778423 100644 --- a/source/java/org/alfresco/repo/web/scripts/invite/InviteServiceTest.java +++ b/source/java/org/alfresco/repo/web/scripts/invite/InviteServiceTest.java @@ -33,8 +33,8 @@ import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.PropertyMap; +import org.alfresco.util.URLEncoder; import org.alfresco.web.scripts.Status; import org.json.JSONArray; import org.json.JSONObject; @@ -52,7 +52,6 @@ public class InviteServiceTest extends BaseWebScriptTest private AuthenticationComponent authenticationComponent; private PersonService personService; private SiteService siteService; - private TransactionService transactionService; private static final String USER_ADMIN = "admin"; private static final String USER_INVITER = "InviterUser"; @@ -60,7 +59,6 @@ public class InviteServiceTest extends BaseWebScriptTest private static final String INVITEE_LASTNAME = "InviteeLastName"; private static final String INVITEE_EMAIL = "inviteeFN.inviteeLN@email123.com"; private static final String SITE_SHORT_NAME_INVITE = "InviteSiteShortName"; - private static final String GROUP_EMAIL_CONTRIBUTORS = "EMAIL_CONTRIBUTORS"; private static final String URL_INVITE_SERVICE = "/api/invite"; private static final String URL_INVITERSP_SERVICE = "/api/inviteresponse"; @@ -88,8 +86,6 @@ public class InviteServiceTest extends BaseWebScriptTest .getApplicationContext().getBean("PersonService"); this.siteService = (SiteService) getServer().getApplicationContext() .getBean("siteService"); - this.transactionService = (TransactionService) getServer().getApplicationContext() - .getBean("transactionService"); // set current user as admin for various setup operations needing admin rights this.authenticationComponent.setCurrentUser(USER_ADMIN); @@ -197,7 +193,8 @@ public class InviteServiceTest extends BaseWebScriptTest // Inviter sends invitation to Invitee to join a Site String startInviteUrl = URL_INVITE_SERVICE + "/" + INVITE_ACTION_START + "?inviteeFirstName=" + inviteeFirstName + "&inviteeLastName=" + inviteeLastName - + "&inviteeEmail=" + inviteeEmail + "&siteShortName=" + siteShortName; + + "&inviteeEmail=" + URLEncoder.encode(inviteeEmail) + "&siteShortName=" + siteShortName; + MockHttpServletResponse response = getRequest(startInviteUrl, expectedStatus); JSONObject result = new JSONObject(response.getContentAsString()); @@ -313,6 +310,17 @@ public class InviteServiceTest extends BaseWebScriptTest + SITE_SHORT_NAME_INVITE; MockHttpServletResponse response = getRequest(acceptInviteUrl, Status.STATUS_OK); + + // + // test that invitation represented by invite ID (of invitation started above) + // is no longer pending (as a result of the invitation having being accepted) + // + + // get pending invite matching inviteId from invite started above + JSONArray getInvitesResult = getInvitesByInviteId(inviteId, Status.STATUS_OK); + + // there should no longer be any invites identified by invite ID pending + assertEquals(getInvitesResult.length(), 0); } public void testRejectInvite() throws Exception @@ -335,6 +343,17 @@ public class InviteServiceTest extends BaseWebScriptTest + SITE_SHORT_NAME_INVITE; MockHttpServletResponse response = getRequest(rejectInviteUrl, Status.STATUS_OK); + + // + // test that invite represented by invite ID (of invitation started above) + // is no longer pending (as a result of the invitation having being rejected) + // + + // get pending invite matching inviteId from invite started above + JSONArray getInvitesResult = getInvitesByInviteId(inviteId, Status.STATUS_OK); + + // there should no longer be any invites identified by invite ID pending + assertEquals(getInvitesResult.length(), 0); } public void testGetInvitesByInviteId() throws Exception