diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/invite/invites.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/invite/invites.get.desc.xml index b4ee8e36d5..7156f04a46 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/invite/invites.get.desc.xml +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/invite/invites.get.desc.xml @@ -1,9 +1,7 @@ Invites Returns pending invites filtered by Inviter user name, Invitee user name & Site short name - /api/invites?inviterUserName={inviterUserName}&inviteeUserName={inviteeUserName?}&siteShortName={siteShortName?} - /api/invites?inviterUserName={inviterUserName?}&inviteeUserName={inviteeUserName}&siteShortName={siteShortName?} - /api/invites?inviterUserName={inviterUserName?}&inviteeUserName={inviteeUserName?}&siteShortName={siteShortName} + /api/invites?inviterUserName={inviterUserName?}&inviteeUserName={inviteeUserName?}&siteShortName={siteShortName?} /api/invites?inviteId={inviteId} user diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 3e98c14093..f9a0c3ec5f 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -348,10 +348,7 @@ - - - - + diff --git a/config/alfresco/workflow/invite-workflow-model.xml b/config/alfresco/workflow/invite-workflow-model.xml index c34fefe7a1..0e1a559c58 100644 --- a/config/alfresco/workflow/invite-workflow-model.xml +++ b/config/alfresco/workflow/invite-workflow-model.xml @@ -1,17 +1,16 @@ - + - + - + bpm:startTask @@ -49,6 +48,9 @@ d:text + + bpm:assignee + diff --git a/config/alfresco/workflow/invite_processdefinition.xml b/config/alfresco/workflow/invite_processdefinition.xml index 7f69cc8821..e84ef28b25 100644 --- a/config/alfresco/workflow/invite_processdefinition.xml +++ b/config/alfresco/workflow/invite_processdefinition.xml @@ -4,8 +4,6 @@ - - @@ -50,24 +48,30 @@ + + + #{bpm_assignee.properties['cm:userName']} + + + - - + + + + + + - - - - + + - - - - + + diff --git a/source/java/org/alfresco/repo/web/scripts/invite/AcceptInviteAction.java b/source/java/org/alfresco/repo/web/scripts/invite/AcceptInviteAction.java new file mode 100644 index 0000000000..97ff8c537e --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/invite/AcceptInviteAction.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.invite; + +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.MutableAuthenticationDao; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.site.SiteService; +import org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler; +import org.alfresco.service.ServiceRegistry; +import org.jbpm.graph.exe.ExecutionContext; +import org.springframework.beans.factory.BeanFactory; + +/** + * This class contains logic that gets executed when + * the wf:invitePendingTask in the invite workflow gets completed + * along the "accept" transition + * + * @author glen johnson at alfresco com + */ +public class AcceptInviteAction extends JBPMSpringActionHandler +{ + private static final long serialVersionUID = 8133039174866049136L; + + /** + * Inner class providing functionality (which needs to run under admin + * rights) to set membership of invitee (given as invitee user name) to site + * (given as site short name) as given site role + */ + private class SetSiteMembershipWorker implements + AuthenticationUtil.RunAsWork + { + private String siteShortName; + private String inviteeUserName; + private String siteRole; + + private SetSiteMembershipWorker(String siteShortName, + String inviteeUserName, String siteRole) + { + this.siteShortName = siteShortName; + this.inviteeUserName = inviteeUserName; + this.siteRole = siteRole; + } + + /** + * Does the work to set the site membership + */ + public Boolean doWork() throws Exception + { + AcceptInviteAction.this.siteService.setMembership(this.siteShortName, + this.inviteeUserName, this.siteRole); + + return Boolean.TRUE; + } + } + + private static final String USER_ADMIN = "admin"; + + private SiteService siteService; + private MutableAuthenticationDao mutableAuthenticationDao; + + /* (non-Javadoc) + * @see org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler#initialiseHandler(org.springframework.beans.factory.BeanFactory) + */ + @Override + protected void initialiseHandler(BeanFactory factory) + { + ServiceRegistry services = (ServiceRegistry)factory.getBean(ServiceRegistry.SERVICE_REGISTRY); + mutableAuthenticationDao = (MutableAuthenticationDao) factory.getBean("authenticationDao"); + siteService = services.getSiteService(); + } + + /* (non-Javadoc) + * @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext) + */ + @SuppressWarnings("unchecked") + public void execute(final ExecutionContext executionContext) throws Exception + { + String inviteeUserName = (String) executionContext.getVariable("wf_inviteeUserName"); + String siteShortName = (String) executionContext.getVariable("wf_siteShortName"); + String inviteeSiteRole = (String) executionContext.getVariable("wf_inviteeSiteRole"); + + // if there is already a user account for the invitee and that account + // is disabled, then enable the account because he/she has accepted the + // site invitation + if ((this.mutableAuthenticationDao.userExists(inviteeUserName)) + && (this.mutableAuthenticationDao.getEnabled(inviteeUserName) == false)) + { + this.mutableAuthenticationDao.setEnabled(inviteeUserName, true); + } + + // add Invitee to Site with the site role that the inviter "started" the invite process with + RunAsWork setSiteMembershipWorker = new SetSiteMembershipWorker( + siteShortName, inviteeUserName, inviteeSiteRole); + AuthenticationUtil.runAs(setSiteMembershipWorker, USER_ADMIN); + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/invite/Invite.java b/source/java/org/alfresco/repo/web/scripts/invite/Invite.java index 0b0e873e7d..c0239db1e8 100644 --- a/source/java/org/alfresco/repo/web/scripts/invite/Invite.java +++ b/source/java/org/alfresco/repo/web/scripts/invite/Invite.java @@ -190,7 +190,7 @@ public class Invite extends DeclarativeWebScript { this.nodeService = nodeService; } - + /* * (non-Javadoc) * @@ -562,13 +562,17 @@ public class Invite extends DeclarativeWebScript + InviteWorkflowModel.WORKFLOW_DEFINITION_NAME + " does not exist"); } + // Get invitee person NodeRef to add as assignee + NodeRef inviteeNodeRef = this.personService.getPerson(inviteeUserName); + // create workflow properties Map workflowProps = new HashMap( - 7); + 10); workflowProps.put(InviteWorkflowModel.WF_PROP_INVITER_USER_NAME, inviterUserName); workflowProps.put(InviteWorkflowModel.WF_PROP_INVITEE_USER_NAME, inviteeUserName); + workflowProps.put(WorkflowModel.ASSOC_ASSIGNEE, inviteeNodeRef); workflowProps.put(InviteWorkflowModel.WF_PROP_INVITEE_FIRSTNAME, inviteeFirstName); workflowProps.put(InviteWorkflowModel.WF_PROP_INVITEE_LASTNAME, diff --git a/source/java/org/alfresco/repo/web/scripts/invite/InviteHelper.java b/source/java/org/alfresco/repo/web/scripts/invite/InviteHelper.java index 8c78e559ad..355c3fca49 100644 --- a/source/java/org/alfresco/repo/web/scripts/invite/InviteHelper.java +++ b/source/java/org/alfresco/repo/web/scripts/invite/InviteHelper.java @@ -25,7 +25,9 @@ package org.alfresco.repo.web.scripts.invite; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.alfresco.repo.jscript.ScriptNode; import org.alfresco.repo.site.SiteInfo; @@ -47,7 +49,7 @@ import org.alfresco.service.namespace.QName; public class InviteHelper { /** - * Find an invite start task given the task id. + * Find an invite start task by the given task id. * * @return a WorkflowTask or null if not found. */ @@ -62,8 +64,7 @@ public class InviteHelper // invite workflow instances are returned by query wfTaskQuery.setProcessName(QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "invite")); - // pick up the start task because it has the "wf:inviteeSiteRole" property set with the - // site role value that we want to retrieve + // filter to find only the invite start task wfTaskQuery.setTaskState(WorkflowTaskState.COMPLETED); wfTaskQuery.setTaskName(InviteWorkflowModel.WF_INVITE_TASK_INVITE_TO_SITE); @@ -83,35 +84,71 @@ public class InviteHelper } /** - * Returns an InviteInfo object usable for rendering the response. + * Find invitePending tasks (in-progress) by the given invitee user name * - * @return object containing invite information + * @return a list of workflow tasks */ - public static InviteInfo getPendingInviteInfo(WorkflowTask workflowTask, - ServiceRegistry serviceRegistry, SiteService siteService) + public static List findInvitePendingTasks(String inviteeUserName, WorkflowService workflowService) { - PersonService personService = serviceRegistry.getPersonService(); + // create workflow task query + WorkflowTaskQuery wfTaskQuery = new WorkflowTaskQuery(); + + // set process name to "wf:invite" so that only tasks associated with + // invite workflow instances are returned by query + wfTaskQuery.setProcessName(QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "invite")); + + // set query to only pick up invite workflow instances + // associated with the given invitee user name + Map processCustomProps = new HashMap(1, 1.0f); + processCustomProps.put(InviteWorkflowModel.WF_PROP_INVITEE_USER_NAME, inviteeUserName); + wfTaskQuery.setProcessCustomProps(processCustomProps); + + // set query to only pick up in-progress invite pending tasks + wfTaskQuery.setTaskState(WorkflowTaskState.IN_PROGRESS); + wfTaskQuery.setTaskName(InviteWorkflowModel.WF_TASK_INVITE_PENDING); + + // query for invite workflow task associate + List inviteStartTasks = workflowService + .queryTasks(wfTaskQuery); + + return inviteStartTasks; + } + + /** + * Returns an InviteInfo instance for the given startInvite task + * (used for rendering the response). + * + * @param startInviteTask startInvite task to get invite info properties from + * @param serviceRegistry service registry instance + * @param siteService site service instance + * + * @return InviteInfo instance containing invite information + */ + public static InviteInfo getPendingInviteInfo(final WorkflowTask startInviteTask, + final ServiceRegistry serviceRegistry, final SiteService siteService) + { + final PersonService personService = serviceRegistry.getPersonService(); // get the inviter, invitee, role and site short name - String inviterUserNameProp = (String) workflowTask.properties.get( + final String inviterUserNameProp = (String) startInviteTask.properties.get( InviteWorkflowModel.WF_PROP_INVITER_USER_NAME); - String inviteeUserNameProp = (String) workflowTask.properties.get( + final String inviteeUserNameProp = (String) startInviteTask.properties.get( InviteWorkflowModel.WF_PROP_INVITEE_USER_NAME); - String role = (String) workflowTask.properties.get( + final String role = (String) startInviteTask.properties.get( InviteWorkflowModel.WF_PROP_INVITEE_SITE_ROLE); - String siteShortNameProp = (String) workflowTask.properties.get( + final String siteShortNameProp = (String) startInviteTask.properties.get( InviteWorkflowModel.WF_PROP_SITE_SHORT_NAME); - // fetch the site object + // get the site info SiteInfo siteInfo = siteService.getSite(siteShortNameProp); // get workflow instance id (associated with workflow task) to place // as "inviteId" onto model - String workflowId = workflowTask.path.instance.id; + String workflowId = startInviteTask.path.instance.id; // set the invite start date to the time the workflow instance // (associated with the task) was started - Date sentInviteDate = workflowTask.path.instance.startDate; + Date sentInviteDate = startInviteTask.path.instance.startDate; // TODO: glen johnson at alfresco com - as this web script only returns // pending invites, this is hard coded to "pending" for now @@ -133,7 +170,7 @@ public class InviteHelper inviteePerson = new ScriptNode(inviteeRef, serviceRegistry); } - // create and add InviteInfo to inviteInfoList + // create and return a invite info InviteInfo inviteInfo = new InviteInfo(invitationStatus, inviterUserNameProp, inviterPerson, inviteeUserNameProp, inviteePerson, role, siteShortNameProp, siteInfo, sentInviteDate, workflowId); 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 dca6952151..02f2edd16b 100644 --- a/source/java/org/alfresco/repo/web/scripts/invite/InviteResponse.java +++ b/source/java/org/alfresco/repo/web/scripts/invite/InviteResponse.java @@ -28,11 +28,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.authentication.MutableAuthenticationDao; -import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; -import org.alfresco.repo.site.SiteService; -import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.cmr.workflow.WorkflowTask; import org.alfresco.service.cmr.workflow.WorkflowTaskQuery; @@ -53,49 +48,13 @@ import org.alfresco.web.scripts.WebScriptRequest; */ public class InviteResponse extends DeclarativeWebScript { - /** - * Inner class providing functionality (which needs to run under admin - * rights) to set membership of invitee (given as invitee user name) to site - * (given as site short name) as given site role - */ - private class SetSiteMembershipWorker implements - AuthenticationUtil.RunAsWork - { - private String siteShortName; - private String inviteeUserName; - private String siteRole; - - private SetSiteMembershipWorker(String siteShortName, - String inviteeUserName, String siteRole) - { - this.siteShortName = siteShortName; - this.inviteeUserName = inviteeUserName; - this.siteRole = siteRole; - } - - /** - * Does the work to set the site membership - */ - public Boolean doWork() throws Exception - { - InviteResponse.this.siteService.setMembership(this.siteShortName, - this.inviteeUserName, this.siteRole); - - return Boolean.TRUE; - } - } - private static final String RESPONSE_ACCEPT = "accept"; private static final String RESPONSE_REJECT = "reject"; 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"; // properties for services private WorkflowService workflowService; - private MutableAuthenticationDao mutableAuthenticationDao; - private SiteService siteService; - private PersonService personService; /** * Sets the workflow service property @@ -108,40 +67,6 @@ public class InviteResponse extends DeclarativeWebScript this.workflowService = workflowService; } - /** - * Sets the mutableAuthenticationDao service property - * - * @param mutableAuthenticationDao - * the MutableAuthenticationDao service to set - */ - public void setMutableAuthenticationDao( - MutableAuthenticationDao mutableAuthenticationDao) - { - this.mutableAuthenticationDao = mutableAuthenticationDao; - } - - /** - * Sets the siteService property - * - * @param siteService - * the siteService to set - */ - public void setSiteService(SiteService siteService) - { - this.siteService = siteService; - } - - /** - * Sets the personService property - * - * @param personService - * the person service to set - */ - public void setPersonService(PersonService personService) - { - this.personService = personService; - } - /* * (non-Javadoc) * @@ -160,7 +85,7 @@ public class InviteResponse extends DeclarativeWebScript String inviteId = req.getServiceMatch().getTemplateVars().get("inviteId"); String inviteTicket = req.getServiceMatch().getTemplateVars().get("inviteTicket"); - // fetch the start task - it might not exist if the workflow has been finished/canceled already + // fetch the start task - it might not exist if the workflow has been finished/cancelled already WorkflowTask inviteStartTask = InviteHelper.findInviteStartTask(inviteId, workflowService); if (inviteStartTask == null) { @@ -173,7 +98,8 @@ public class InviteResponse extends DeclarativeWebScript if (ticket == null || (! ticket.equals(inviteTicket))) { throw new WebScriptException(Status.STATUS_NOT_FOUND, - "Invalid ticket"); + "Response to invite has supplied an invalid ticket. The response to the " + + "invitation could thus not be processed"); } // process response @@ -197,7 +123,7 @@ public class InviteResponse extends DeclarativeWebScript } /** - * Processes 'accept' response from invitee + * Processes 'accept invite' response from invitee * * @param model * model to add objects to, which will be passed to the template @@ -205,44 +131,17 @@ public class InviteResponse extends DeclarativeWebScript * @param inviteId * ID of invite * @param inviteStartTask + * wf:inviteToSiteTask instance containing the invite parameters the + * invite workflow instance (it belongs to) was started with */ private void acceptInvite(Map model, String inviteId, WorkflowTask inviteStartTask) { - String inviteeUserName = (String) inviteStartTask.properties.get( - InviteWorkflowModel.WF_PROP_INVITEE_USER_NAME); String siteShortName = (String) inviteStartTask.properties.get( InviteWorkflowModel.WF_PROP_SITE_SHORT_NAME); - String inviteeSiteRole = (String) inviteStartTask.properties.get( - InviteWorkflowModel.WF_PROP_INVITEE_SITE_ROLE); - // complete the wf:invitePendingTask task because the invitation has been accepted + // complete the wf:invitePendingTask along the 'accept' transition because the invitation has been accepted completeInviteTask(inviteId, InviteWorkflowModel.WF_TASK_INVITE_PENDING, InviteWorkflowModel.WF_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 - - // if there is already a user account for the invitee and that account - // is disabled, then enable the account because he/she has accepted the - // site invitation - if ((this.mutableAuthenticationDao.userExists(inviteeUserName)) - && (this.mutableAuthenticationDao.getEnabled(inviteeUserName) == false)) - { - this.mutableAuthenticationDao.setEnabled(inviteeUserName, true); - } - - // add Invitee to Site with the site role that the inviter "started" the invite process with - RunAsWork setSiteMembershipWorker = new InviteResponse.SetSiteMembershipWorker( - siteShortName, inviteeUserName, inviteeSiteRole); - 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 - // starting from above where wf:invitePendingTask is completed, up to here). This code - // block will soon be farmed out into a workflow action which gets executed when - // wf:acceptInviteTask gets completed - completeInviteTask(inviteId, InviteWorkflowModel.WF_TASK_ACCEPT_INVITE, InviteWorkflowModel.WF_TRANSITION_ACCEPT_INVITE_END); - // add model properties for template to render model.put(MODEL_PROP_KEY_RESPONSE, RESPONSE_ACCEPT); model.put(MODEL_PROP_KEY_SITE_SHORT_NAME, siteShortName); @@ -264,40 +163,12 @@ public class InviteResponse extends DeclarativeWebScript */ private void rejectInvite(Map model, String inviteId, WorkflowTask inviteStartTask) { - String inviteeUserName = (String) inviteStartTask.properties.get( - InviteWorkflowModel.WF_PROP_INVITEE_USER_NAME); String siteShortName = (String) inviteStartTask.properties.get( InviteWorkflowModel.WF_PROP_SITE_SHORT_NAME); - // complete the wf:invitePendingTask task because the invitation has been accepted + // complete the wf:invitePendingTask task along the 'reject' transition because the invitation has been rejected completeInviteTask(inviteId, InviteWorkflowModel.WF_TASK_INVITE_PENDING, InviteWorkflowModel.WF_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 - - // if invitee's user account is still disabled then remove the account and - // delete the invitee's person node - if ((this.mutableAuthenticationDao.userExists(inviteeUserName)) - && (this.mutableAuthenticationDao.getEnabled(inviteeUserName) == false)) - { - // delete the invitee's user account - this.mutableAuthenticationDao.deleteUser(inviteeUserName); - - // delete the invitee's person node if one exists - if (this.personService.personExists(inviteeUserName)) - { - 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 - // starting from above where wf:invitePendingTask is completed, up to here). This code - // block will soon be farmed out into a workflow action which gets executed when - // wf:rejectInviteTask gets completed - completeInviteTask(inviteId, InviteWorkflowModel.WF_TASK_REJECT_INVITE, InviteWorkflowModel.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); 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 c4ee48853b..920d442f03 100644 --- a/source/java/org/alfresco/repo/web/scripts/invite/InviteServiceTest.java +++ b/source/java/org/alfresco/repo/web/scripts/invite/InviteServiceTest.java @@ -91,16 +91,12 @@ public class InviteServiceTest extends BaseWebScriptTest private static final String SITE_SHORT_NAME_INVITE_1 = "BananaMilkshakeSite"; private static final String SITE_SHORT_NAME_INVITE_2 = "DoubleScoopSite"; - private static final String URL_INVITE_SERVICE = "/api/invite"; - private static final String URL_INVITERSP_SERVICE = "/api/inviteresponse"; - private static final String URL_INVITES_SERVICE = "/api/invites"; + private static final String URL_INVITE = "/api/invite"; + private static final String URL_INVITES = "/api/invites"; private static final String INVITE_ACTION_START = "start"; private static final String INVITE_ACTION_CANCEL = "cancel"; - private static final String INVITE_RSP_ACCEPT = "accept"; - private static final String INVITE_RSP_REJECT = "reject"; - @Override protected void setUp() throws Exception { @@ -145,6 +141,9 @@ public class InviteServiceTest extends BaseWebScriptTest InviteServiceTest.this.siteService.createSite( "InviteSitePreset", SITE_SHORT_NAME_INVITE_1, "InviteSiteTitle", "InviteSiteDescription", true); + + InviteServiceTest.this.siteService.setMembership( + SITE_SHORT_NAME_INVITE_1, USER_INVITER, SiteModel.SITE_MANAGER); } SiteInfo siteInfo2 = InviteServiceTest.this.siteService @@ -154,6 +153,9 @@ public class InviteServiceTest extends BaseWebScriptTest InviteServiceTest.this.siteService.createSite( "InviteSitePreset", SITE_SHORT_NAME_INVITE_2, "InviteSiteTitle", "InviteSiteDescription", true); + + InviteServiceTest.this.siteService.setMembership( + SITE_SHORT_NAME_INVITE_2, USER_INVITER, SiteModel.SITE_MANAGER); } return null; @@ -308,7 +310,7 @@ public class InviteServiceTest extends BaseWebScriptTest this.inviteeEmailAddrs.add(inviteeEmail); // Inviter sends invitation to Invitee to join a Site - String startInviteUrl = URL_INVITE_SERVICE + "/" + INVITE_ACTION_START + String startInviteUrl = URL_INVITE + "/" + INVITE_ACTION_START + "?inviteeFirstName=" + inviteeFirstName + "&inviteeLastName=" + inviteeLastName + "&inviteeEmail=" + URLEncoder.encode(inviteeEmail) + "&siteShortName=" @@ -341,7 +343,7 @@ public class InviteServiceTest extends BaseWebScriptTest throws Exception { // construct get invites URL - String getInvitesUrl = URL_INVITES_SERVICE + "?inviteId=" + inviteId; + String getInvitesUrl = URL_INVITES + "?inviteId=" + inviteId; // invoke get invites web script Response response = sendRequest(new GetRequest(getInvitesUrl), expectedStatus); @@ -355,7 +357,7 @@ public class InviteServiceTest extends BaseWebScriptTest int expectedStatus) throws Exception { // construct get invites URL - String getInvitesUrl = URL_INVITES_SERVICE + "?inviterUserName=" + String getInvitesUrl = URL_INVITES + "?inviterUserName=" + inviterUserName; // invoke get invites web script @@ -370,7 +372,7 @@ public class InviteServiceTest extends BaseWebScriptTest int expectedStatus) throws Exception { // construct get invites URL - String getInvitesUrl = URL_INVITES_SERVICE + "?inviteeUserName=" + String getInvitesUrl = URL_INVITES + "?inviteeUserName=" + inviteeUserName; // invoke get invites web script @@ -385,7 +387,7 @@ public class InviteServiceTest extends BaseWebScriptTest int expectedStatus) throws Exception { // construct get invites URL - String getInvitesUrl = URL_INVITES_SERVICE + "?siteShortName=" + String getInvitesUrl = URL_INVITES + "?siteShortName=" + siteShortName; // invoke get invites web script @@ -477,7 +479,8 @@ public class InviteServiceTest extends BaseWebScriptTest String inviteId = result.getString("inviteId"); // Inviter cancels pending invitation - String cancelInviteUrl = URL_INVITE_SERVICE + "/" + INVITE_ACTION_CANCEL + "?inviteId=" + inviteId; + String cancelInviteUrl = URL_INVITE + "/" + + INVITE_ACTION_CANCEL + "?inviteId=" + inviteId; Response response = sendRequest(new GetRequest(cancelInviteUrl), Status.STATUS_OK); } @@ -487,16 +490,12 @@ public class InviteServiceTest extends BaseWebScriptTest JSONObject result = startInvite(INVITEE_FIRSTNAME, INVITEE_LASTNAME, INVITEE_SITE_ROLE, SITE_SHORT_NAME_INVITE_1, Status.STATUS_OK); - // get hold of invite ID of started invite + // get hold of invite ID and invite ticket of started invite String inviteId = result.getString("inviteId"); String inviteTicket = result.getString("inviteTicket"); - // get hold of invitee user name that was generated as part of starting - // the invite - String inviteeUserName = result.getString("inviteeUserName"); - // Invitee accepts invitation to a Site from Inviter - String acceptInviteUrl = URL_INVITE_SERVICE + "/" + inviteId + "/" + inviteTicket + "/accept"; + String acceptInviteUrl = URL_INVITE + "/" + inviteId + "/" + inviteTicket + "/accept"; Response response = sendRequest(new PutRequest(acceptInviteUrl, (byte[])null, null), Status.STATUS_OK); // @@ -506,12 +505,13 @@ public class InviteServiceTest extends BaseWebScriptTest // accepted) // - // get pending invite matching inviteId from invite started above + // get pending invite matching inviteId from invite started above (run as inviter user) + this.authenticationComponent.setCurrentUser(USER_INVITER); JSONObject getInvitesResult = getInvitesByInviteId(inviteId, Status.STATUS_OK); // there should no longer be any invites identified by invite ID pending - assertEquals(getInvitesResult.getJSONArray("invites").length(), 0); + assertEquals(0, getInvitesResult.getJSONArray("invites").length()); } public void testRejectInvite() throws Exception @@ -524,12 +524,8 @@ public class InviteServiceTest extends BaseWebScriptTest String inviteId = result.getString("inviteId"); String inviteTicket = result.getString("inviteTicket"); - // get hold of invitee user name that was generated as part of starting - // the invite - String inviteeUserName = result.getString("inviteeUserName"); - // Invitee rejects invitation to a Site from Inviter - String rejectInviteUrl = URL_INVITE_SERVICE + "/" + inviteId + "/" + inviteTicket + "/reject"; + String rejectInviteUrl = URL_INVITE + "/" + inviteId + "/" + inviteTicket + "/reject"; Response response = sendRequest(new PutRequest(rejectInviteUrl, (byte[])null, null), Status.STATUS_OK); // @@ -539,11 +535,12 @@ public class InviteServiceTest extends BaseWebScriptTest // rejected) // - // get pending invite matching inviteId from invite started above + // get pending invite matching inviteId from invite started above (run as inviter user) + this.authenticationComponent.setCurrentUser(USER_INVITER); JSONObject getInvitesResult = getInvitesByInviteId(inviteId, Status.STATUS_OK); // there should no longer be any invites identified by invite ID pending - assertEquals(getInvitesResult.getJSONArray("invites").length(), 0); + assertEquals(0, getInvitesResult.getJSONArray("invites").length()); } public void testGetInvitesByInviteId() throws Exception @@ -636,4 +633,4 @@ public class InviteServiceTest extends BaseWebScriptTest assertEquals(siteShortName, inviteJSONObj.getJSONObject("site").get("shortName")); } -} \ No newline at end of file +} diff --git a/source/java/org/alfresco/repo/web/scripts/invite/InviteWorkflowModel.java b/source/java/org/alfresco/repo/web/scripts/invite/InviteWorkflowModel.java index dadaadd289..47363579eb 100644 --- a/source/java/org/alfresco/repo/web/scripts/invite/InviteWorkflowModel.java +++ b/source/java/org/alfresco/repo/web/scripts/invite/InviteWorkflowModel.java @@ -13,6 +13,7 @@ public interface InviteWorkflowModel { // tasks public static final QName WF_INVITE_TASK_INVITE_TO_SITE = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "inviteToSiteTask"); + public static final QName WF_INVITE_TASK_INVITE_PENDING = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "invitePendingTask"); public static final QName WF_TASK_ACCEPT_INVITE = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "acceptInviteTask"); public static final QName WF_TASK_REJECT_INVITE = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "rejectInviteTask"); public static final QName WF_TASK_INVITE_PENDING = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "invitePendingTask"); diff --git a/source/java/org/alfresco/repo/web/scripts/invite/Invites.java b/source/java/org/alfresco/repo/web/scripts/invite/Invites.java index 3d5cbfbf35..94a263c933 100644 --- a/source/java/org/alfresco/repo/web/scripts/invite/Invites.java +++ b/source/java/org/alfresco/repo/web/scripts/invite/Invites.java @@ -122,7 +122,7 @@ public class Invites extends DeclarativeWebScript "No parameters have been provided on URL"); } - // get URL request parameters, checking if they have been provided + // get URL request parameters, checking if at least one has been provided // check if 'inviterUserName' parameter provided String inviterUserName = req.getParameter(PARAM_INVITER_USER_NAME); @@ -163,12 +163,12 @@ public class Invites extends DeclarativeWebScript // if 'inviteId' has been provided then set that as the workflow query // process ID // - since this is unique don't bother about setting the other workflow - // query - // - properties + // query properties if (inviteIdProvided) { wfTaskQuery.setProcessId(inviteId); - } else + } + else // 'inviteId' has not been provided, so create the query properties from // the invite URL request // parameters @@ -181,32 +181,32 @@ public class Invites extends DeclarativeWebScript // workflow query properties HashMap wfQueryProps = new HashMap(3, 1.0f); - if (inviterUserName != null) + if (inviterUserNameProvided) { wfQueryProps.put(InviteWorkflowModel.WF_PROP_INVITER_USER_NAME, inviterUserName); } - if (inviteeUserName != null) + if (inviteeUserNameProvided) { wfQueryProps.put(InviteWorkflowModel.WF_PROP_INVITEE_USER_NAME, inviteeUserName); } - if (siteShortName != null) + if (siteShortNameProvided) { wfQueryProps.put(InviteWorkflowModel.WF_PROP_SITE_SHORT_NAME, siteShortName); } // set workflow task query parameters - wfTaskQuery.setTaskCustomProps(wfQueryProps); + wfTaskQuery.setProcessCustomProps(wfQueryProps); } // query only active workflows wfTaskQuery.setActive(Boolean.TRUE); // pick up the start task - wfTaskQuery.setTaskState(WorkflowTaskState.COMPLETED); - wfTaskQuery.setTaskName(InviteWorkflowModel.WF_INVITE_TASK_INVITE_TO_SITE); + wfTaskQuery.setTaskState(WorkflowTaskState.IN_PROGRESS); + wfTaskQuery.setTaskName(InviteWorkflowModel.WF_INVITE_TASK_INVITE_PENDING); // set process name to "wf:invite" so that only tasks associated with // invite workflow instances @@ -226,7 +226,13 @@ public class Invites extends DeclarativeWebScript // onto model for each invite workflow task returned by the query for (WorkflowTask workflowTask : wf_invite_tasks) { - InviteInfo inviteInfo = InviteHelper.getPendingInviteInfo(workflowTask, serviceRegistry, siteService); + // get workflow instance (ID) that pendingInvite task (in query result set) + // belongs to, and get startTask associated with the same workflow instance - + // to create a InviteInfo instance from that startTask's properties + + String workflowId = workflowTask.path.instance.id; + WorkflowTask startInvite = InviteHelper.findInviteStartTask(workflowId, workflowService); + InviteInfo inviteInfo = InviteHelper.getPendingInviteInfo(startInvite, serviceRegistry, siteService); inviteInfoList.add(inviteInfo); } diff --git a/source/java/org/alfresco/repo/web/scripts/invite/RejectInviteAction.java b/source/java/org/alfresco/repo/web/scripts/invite/RejectInviteAction.java new file mode 100644 index 0000000000..c80bb74c08 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/invite/RejectInviteAction.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.invite; + +import java.util.List; + +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.MutableAuthenticationDao; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.cmr.workflow.WorkflowService; +import org.alfresco.service.cmr.workflow.WorkflowTask; +import org.jbpm.graph.exe.ExecutionContext; +import org.springframework.beans.factory.BeanFactory; + +/** + * This class contains logic that gets executed when + * the wf:invitePendingTask in the invite workflow gets completed + * along the "reject" transition + * + * @author glen johnson at alfresco com + */ +public class RejectInviteAction extends JBPMSpringActionHandler +{ + private static final long serialVersionUID = 4377660284993206875L; + + private MutableAuthenticationDao mutableAuthenticationDao; + private PersonService personService; + private WorkflowService workflowService; + + /* (non-Javadoc) + * @see org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler#initialiseHandler(org.springframework.beans.factory.BeanFactory) + */ + @Override + protected void initialiseHandler(BeanFactory factory) + { + ServiceRegistry services = (ServiceRegistry)factory.getBean(ServiceRegistry.SERVICE_REGISTRY); + mutableAuthenticationDao = (MutableAuthenticationDao) factory.getBean("authenticationDao"); + personService = (PersonService) services.getPersonService(); + workflowService = (WorkflowService) services.getWorkflowService(); + } + + /* (non-Javadoc) + * @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext) + */ + @SuppressWarnings("unchecked") + public void execute(final ExecutionContext executionContext) throws Exception + { + // get the invitee user name + final String inviteeUserName = (String) executionContext.getVariable("wf_inviteeUserName"); + + AuthenticationUtil.runAs(new RunAsWork() + { + public Object doWork() throws Exception + { + // see if there are any pending invites (invite workflow instances with invitePending task in-progress) + // outstanding for invitee who has responded here with an invite rejection + List pendingTasks = InviteHelper.findInvitePendingTasks(inviteeUserName, workflowService); + boolean invitesPending = (pendingTasks != null) && (pendingTasks.size() > 0); + + // if invitee's user account is still disabled and there are no pending invites outstanding + // for the invitee, then remove the account and delete the invitee's person node + if ((RejectInviteAction.this.mutableAuthenticationDao.userExists(inviteeUserName)) + && (RejectInviteAction.this.mutableAuthenticationDao.getEnabled(inviteeUserName) == false) + && (invitesPending == false)) + { + // delete the invitee's user account + mutableAuthenticationDao.deleteUser(inviteeUserName); + + // delete the invitee's person node if one exists + if (personService.personExists(inviteeUserName)) + { + personService.deletePerson(inviteeUserName); + } + } + + return null; + } + }, AuthenticationUtil.getSystemUserName()); + } +}