1. Added code and config to assign invitee person as assignee on invite workflow

2. Various changes to invite service arising from moving accept and reject logic and operations out of invite web scripts, and into workflow actions on respective "accept" and "reject" transitions of invitePending task
- in web-scripts-application-context removed services no longer needed for invitereponse web script (only needs WorkflowService)
- moved logic and operations for accept and reject invite out of inviteresponse web script and into AcceptInviteAction and RejectInviteAction actions for invitePending task in workflow definition
- refine house keeping work that cleans up invitee person node and disabled account if they are no longer being used (no outstanding pending invites for invitee) when invitee rejects invite
- changed pending invites query to cater for when inviteAccepted and inviteRejected tasks left incomplete in inviter's dashboard "tasklist"
- a few minor code cleanups
- added SiteService to ServiceRegistry for use in accept and reject workflow action classes
 

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@10755 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Glen Johnson
2008-09-04 15:44:56 +00:00
parent 3de5ef8f5c
commit 12a855d511
12 changed files with 358 additions and 217 deletions

View File

@@ -1,9 +1,7 @@
<webscript>
<shortname>Invites</shortname>
<description>Returns pending invites filtered by Inviter user name, Invitee user name &amp; Site short name</description>
<url>/api/invites?inviterUserName={inviterUserName}&amp;inviteeUserName={inviteeUserName?}&amp;siteShortName={siteShortName?}</url>
<url>/api/invites?inviterUserName={inviterUserName?}&amp;inviteeUserName={inviteeUserName}&amp;siteShortName={siteShortName?}</url>
<url>/api/invites?inviterUserName={inviterUserName?}&amp;inviteeUserName={inviteeUserName?}&amp;siteShortName={siteShortName}</url>
<url>/api/invites?inviterUserName={inviterUserName?}&amp;inviteeUserName={inviteeUserName?}&amp;siteShortName={siteShortName?}</url>
<url>/api/invites?inviteId={inviteId}</url>
<format default="json"/>
<authentication>user</authentication>

View File

@@ -348,10 +348,7 @@
<bean id="webscript.org.alfresco.repository.invite.inviteresponse.put"
class="org.alfresco.repo.web.scripts.invite.InviteResponse"
parent="webscript">
<property name="workflowService" ref="workflowServiceImpl"/>
<property name="mutableAuthenticationDao" ref="authenticationDao"/>
<property name="siteService" ref="siteService"/>
<property name="personService" ref="personService"/>
<property name="workflowService" ref="WorkflowService"/>
</bean>
<!-- -->

View File

@@ -1,17 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<model name="wf:invite-workflow-model"
xmlns="http://www.alfresco.org/model/dictionary/1.0">
<model name="wf:invite-workflow-model" xmlns="http://www.alfresco.org/model/dictionary/1.0">
<imports>
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d" />
<import uri="http://www.alfresco.org/model/bpm/1.0" prefix="bpm" />
<import uri="http://www.alfresco.org/model/workflow/1.0" prefix="wf"/>
<import uri="http://www.alfresco.org/model/workflow/1.0" prefix="wf" />
</imports>
<types>
<!-- Custom Tasks -->
<type name="wf:inviteToSiteTask">
<parent>bpm:startTask</parent>
<properties>
@@ -49,6 +48,9 @@
<type>d:text</type>
</property>
</properties>
<mandatory-aspects>
<aspect>bpm:assignee</aspect>
</mandatory-aspects>
</type>
<type name="wf:invitePendingTask">

View File

@@ -4,8 +4,6 @@
<swimlane name="initiator"/>
<swimlane name="assignee"/>
<start-state name="start">
<task name="wf:inviteToSiteTask" swimlane="initiator" />
<transition name="sendInvite" to="invitePending">
@@ -50,24 +48,30 @@
</transition>
</start-state>
<swimlane name="assignee">
<assignment class="org.alfresco.repo.workflow.jbpm.AlfrescoAssignment">
<actor>#{bpm_assignee.properties['cm:userName']}</actor>
</assignment>
</swimlane>
<task-node name="invitePending">
<task name="wf:invitePendingTask" swimlane="assignee" />
<transition name="accept" to="inviteAccepted" />
<transition name="reject" to="inviteRejected" />
<transition name="accept" to="inviteAccepted">
<action class="org.alfresco.repo.web.scripts.invite.AcceptInviteAction"/>
</transition>
<transition name="reject" to="inviteRejected">
<action class="org.alfresco.repo.web.scripts.invite.RejectInviteAction"/>
</transition>
</task-node>
<task-node name="inviteAccepted">
<task name="wf:acceptInviteTask" swimlane="assignee" />
<!-- TODO glen.johnson - code in acceptInvite(...) method of inviteresponse web script -->
<!-- needs to be moved into action for transition "end" below. -->
<transition name="end" to="end" />
<task name="wf:acceptInviteTask" swimlane="initiator" />
<transition name="end" to="end"/>
</task-node>
<task-node name="inviteRejected">
<task name="wf:rejectInviteTask" swimlane="assignee" />
<!-- TODO glen.johnson - code in rejectInvite(...) method of inviteresponse web script -->
<!-- needs to be moved into action for transition "end" below. -->
<transition name="end" to="end" />
<task name="wf:rejectInviteTask" swimlane="initiator" />
<transition name="end" to="end"/>
</task-node>
<end-state name="end" />

View File

@@ -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<Boolean>
{
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<Boolean> setSiteMembershipWorker = new SetSiteMembershipWorker(
siteShortName, inviteeUserName, inviteeSiteRole);
AuthenticationUtil.runAs(setSiteMembershipWorker, USER_ADMIN);
}
}

View File

@@ -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<QName, Serializable> workflowProps = new HashMap<QName, Serializable>(
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,

View File

@@ -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<WorkflowTask> 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<QName, Object> processCustomProps = new HashMap<QName, Object>(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<WorkflowTask> 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);

View File

@@ -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<Boolean>
{
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<String, Object> 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<Boolean> 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<String, Object> 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);

View File

@@ -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"));
}
}
}

View File

@@ -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");

View File

@@ -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<QName, Object> wfQueryProps = new HashMap<QName, Object>(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);
}

View File

@@ -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<Object>()
{
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<WorkflowTask> 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());
}
}