mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Various changes to Invite Service
- added functionality to forbid a user from cancelling a pending invite, if he/she is not a Site Manager for the site associated with that invite - added CancelInviteAction workflow action class, with functionality to clean up disabled invitee account and invitee person node when (upon cancellation) there are no outstanding invites for that invitee. - added various unit tests to InviteServiceTest for above functionality - added automatic redeployment of invite process definition in setup(...) method of InviteServiceTest class - other minor refinements to InviteServiceTest - some minor refactoring to Invite Service to prevent code duplication amongst various invite web scripts and workflow action classes git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@10894 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.site.SiteModel;
|
||||
import org.alfresco.repo.site.SiteService;
|
||||
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.web.scripts.Status;
|
||||
import org.alfresco.web.scripts.WebScriptException;
|
||||
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 cancelled
|
||||
* along the "cancel" transition
|
||||
*
|
||||
* @author glen johnson at alfresco com
|
||||
*/
|
||||
public class CancelInviteAction extends JBPMSpringActionHandler
|
||||
{
|
||||
private static final long serialVersionUID = 776961141883350908L;
|
||||
|
||||
private MutableAuthenticationDao mutableAuthenticationDao;
|
||||
private PersonService personService;
|
||||
private WorkflowService workflowService;
|
||||
private SiteService siteService;
|
||||
|
||||
/* (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();
|
||||
siteService = (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
|
||||
{
|
||||
// get the invitee user name and site short name variables off the execution context
|
||||
final String inviteeUserName = (String) executionContext.getVariable(
|
||||
InviteWorkflowModel.wfVarInviteeUserName);
|
||||
final String siteShortName = (String) executionContext.getVariable(
|
||||
InviteWorkflowModel.wfVarSiteShortName);
|
||||
final String inviteId = (String) executionContext.getVariable(
|
||||
InviteWorkflowModel.wfVarWorkflowInstanceId);
|
||||
|
||||
// throw http status 'forbidden' Web Script Exception if current user is not a Site Manager of the site
|
||||
// associated with the invite (identified by inviteID)
|
||||
String currentUserName = AuthenticationUtil.getCurrentUserName();
|
||||
String currentUserSiteRole = this.siteService.getMembersRole(siteShortName, currentUserName);
|
||||
if ((currentUserSiteRole == null) || (currentUserSiteRole.equals(SiteModel.SITE_MANAGER) == false))
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_FORBIDDEN,
|
||||
"Current user '" + currentUserName + "' cannot cancel invite having ID '" + inviteId
|
||||
+ "' because he\\she is not a Site Manager of the site with short name:'" + siteShortName
|
||||
+ "'");
|
||||
}
|
||||
|
||||
// clean up invitee's user account and person node if they are not in use i.e.
|
||||
// account is still disabled and there are no pending invites outstanding for the
|
||||
// invitee
|
||||
InviteHelper.cleanUpStaleInviteeResources(inviteeUserName, mutableAuthenticationDao, personService,
|
||||
workflowService);
|
||||
}
|
||||
}
|
@@ -31,6 +31,8 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.security.authentication.MutableAuthenticationDao;
|
||||
import org.alfresco.repo.security.authentication.PasswordGenerator;
|
||||
import org.alfresco.repo.security.authentication.UserNameGenerator;
|
||||
@@ -43,10 +45,10 @@ import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowException;
|
||||
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.namespace.NamespacePrefixResolver;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.GUID;
|
||||
@@ -400,13 +402,23 @@ public class Invite extends DeclarativeWebScript
|
||||
|
||||
// create a person node for the invitee with generated invitee user name
|
||||
// and other provided person property values
|
||||
Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
|
||||
final Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
|
||||
properties.put(ContentModel.PROP_USERNAME, inviteeUserName);
|
||||
properties.put(ContentModel.PROP_FIRSTNAME, inviteeFirstName);
|
||||
properties.put(ContentModel.PROP_LASTNAME, inviteeLastName);
|
||||
properties.put(ContentModel.PROP_EMAIL, inviteeEmail);
|
||||
this.personService.createPerson(properties);
|
||||
|
||||
AuthenticationUtil.runAs(new RunAsWork<Object>()
|
||||
{
|
||||
public Object doWork() throws Exception
|
||||
{
|
||||
personService.createPerson(properties);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
|
||||
return inviteeUserName;
|
||||
}
|
||||
|
||||
@@ -676,8 +688,9 @@ public class Invite extends DeclarativeWebScript
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels pending invite. Note that only the Inviter should cancel the
|
||||
* pending invite.
|
||||
* Cancels pending invite. Note that only a Site Manager of the
|
||||
* site associated with the pending invite should be able to cancel that
|
||||
* invite
|
||||
*
|
||||
* @param model
|
||||
* model to add objects to, which will be passed to the template
|
||||
@@ -695,10 +708,31 @@ public class Invite extends DeclarativeWebScript
|
||||
"Given invite ID " + inviteId + " null or empty");
|
||||
}
|
||||
|
||||
// cancel the workflow with the given invite ID
|
||||
// which is actually the workflow ID
|
||||
this.workflowService.cancelWorkflow(inviteId);
|
||||
|
||||
try
|
||||
{
|
||||
// complete the wf:invitePendingTask along the 'cancel' transition because the invitation has been cancelled
|
||||
InviteHelper.completeInviteTask(inviteId, InviteWorkflowModel.WF_INVITE_TASK_INVITE_PENDING,
|
||||
InviteWorkflowModel.WF_TRANSITION_CANCEL, this.workflowService);
|
||||
}
|
||||
catch (WorkflowException wfe)
|
||||
{
|
||||
//
|
||||
// If the indirect cause of workflow exception is a WebScriptException object
|
||||
// then throw this directly, otherwise it will not be picked up by unit tests
|
||||
//
|
||||
|
||||
Throwable indirectCause = wfe.getCause().getCause();
|
||||
if (indirectCause instanceof WebScriptException)
|
||||
{
|
||||
WebScriptException wse = (WebScriptException) indirectCause;
|
||||
throw wse;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw wfe;
|
||||
}
|
||||
}
|
||||
|
||||
// add model properties for template to render
|
||||
model.put(MODEL_PROP_KEY_ACTION, ACTION_CANCEL);
|
||||
model.put(MODEL_PROP_KEY_INVITE_ID, inviteId);
|
||||
|
@@ -29,6 +29,9 @@ 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.SiteInfo;
|
||||
import org.alfresco.repo.site.SiteService;
|
||||
import org.alfresco.repo.template.TemplateNode;
|
||||
@@ -95,7 +98,7 @@ public class InviteHelper
|
||||
|
||||
// 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"));
|
||||
wfTaskQuery.setProcessName(InviteWorkflowModel.WF_PROCESS_INVITE);
|
||||
|
||||
// set query to only pick up invite workflow instances
|
||||
// associated with the given invitee user name
|
||||
@@ -105,7 +108,7 @@ public class InviteHelper
|
||||
|
||||
// set query to only pick up in-progress invite pending tasks
|
||||
wfTaskQuery.setTaskState(WorkflowTaskState.IN_PROGRESS);
|
||||
wfTaskQuery.setTaskName(InviteWorkflowModel.WF_TASK_INVITE_PENDING);
|
||||
wfTaskQuery.setTaskName(InviteWorkflowModel.WF_INVITE_TASK_INVITE_PENDING);
|
||||
|
||||
// query for invite workflow task associate
|
||||
List<WorkflowTask> inviteStartTasks = workflowService
|
||||
@@ -178,4 +181,88 @@ public class InviteHelper
|
||||
|
||||
return inviteInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up invitee user account and person node when no longer in use.
|
||||
* They are deemed to no longer be in use when the invitee user account
|
||||
* is still disabled and there are no outstanding pending invites for that invitee.
|
||||
*
|
||||
* @param inviteeUserName
|
||||
* @param authenticationDao
|
||||
* @param personService
|
||||
* @param workflowService
|
||||
*/
|
||||
public static void cleanUpStaleInviteeResources(final String inviteeUserName,
|
||||
final MutableAuthenticationDao authenticationDao, final PersonService personService,
|
||||
final WorkflowService workflowService)
|
||||
{
|
||||
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 given invitee user name
|
||||
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 ((authenticationDao.userExists(inviteeUserName))
|
||||
&& (authenticationDao.getEnabled(inviteeUserName) == false)
|
||||
&& (invitesPending == false))
|
||||
{
|
||||
// delete the invitee's user account
|
||||
authenticationDao.deleteUser(inviteeUserName);
|
||||
|
||||
// delete the invitee's person node if one exists
|
||||
if (personService.personExists(inviteeUserName))
|
||||
{
|
||||
personService.deletePerson(inviteeUserName);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the specified Invite Workflow Task for the invite workflow
|
||||
* instance associated with the given invite ID, and follow the given
|
||||
* transition upon completing the task
|
||||
*
|
||||
* @param inviteId the invite ID of the invite workflow instance for which
|
||||
* we want to complete the given 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)
|
||||
*/
|
||||
public static void completeInviteTask(String inviteId, QName fullTaskName, String transitionId,
|
||||
final WorkflowService workflowService)
|
||||
{
|
||||
// create workflow task query
|
||||
WorkflowTaskQuery wfTaskQuery = new WorkflowTaskQuery();
|
||||
|
||||
// set the given invite ID as the workflow process ID in the workflow query
|
||||
wfTaskQuery.setProcessId(inviteId);
|
||||
|
||||
// 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(InviteWorkflowModel.WF_PROCESS_INVITE);
|
||||
|
||||
// query for invite workflow tasks with the constructed query
|
||||
List<WorkflowTask> wf_invite_tasks = workflowService
|
||||
.queryTasks(wfTaskQuery);
|
||||
|
||||
// end all tasks found with this name
|
||||
for (WorkflowTask workflowTask : wf_invite_tasks)
|
||||
{
|
||||
workflowService.endTask(workflowTask.id, transitionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -25,14 +25,10 @@
|
||||
package org.alfresco.repo.web.scripts.invite;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
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.QName;
|
||||
import org.alfresco.web.scripts.DeclarativeWebScript;
|
||||
import org.alfresco.web.scripts.Status;
|
||||
import org.alfresco.web.scripts.WebScriptException;
|
||||
@@ -140,7 +136,8 @@ public class InviteResponse extends DeclarativeWebScript
|
||||
InviteWorkflowModel.WF_PROP_SITE_SHORT_NAME);
|
||||
|
||||
// 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);
|
||||
InviteHelper.completeInviteTask(inviteId, InviteWorkflowModel.WF_INVITE_TASK_INVITE_PENDING,
|
||||
InviteWorkflowModel.WF_TRANSITION_ACCEPT, this.workflowService);
|
||||
|
||||
// add model properties for template to render
|
||||
model.put(MODEL_PROP_KEY_RESPONSE, RESPONSE_ACCEPT);
|
||||
@@ -167,49 +164,11 @@ public class InviteResponse extends DeclarativeWebScript
|
||||
InviteWorkflowModel.WF_PROP_SITE_SHORT_NAME);
|
||||
|
||||
// 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);
|
||||
InviteHelper.completeInviteTask(inviteId, InviteWorkflowModel.WF_INVITE_TASK_INVITE_PENDING,
|
||||
InviteWorkflowModel.WF_TRANSITION_REJECT, this.workflowService);
|
||||
|
||||
// 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 for the invite workflow
|
||||
* instance associated with the given invite ID, and follow the given
|
||||
* transition upon completing the task
|
||||
*
|
||||
* @param inviteId the invite ID of the invite workflow instance for which
|
||||
* we want to complete the given 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(String inviteId, QName fullTaskName, String transitionId)
|
||||
{
|
||||
// create workflow task query
|
||||
WorkflowTaskQuery wfTaskQuery = new WorkflowTaskQuery();
|
||||
|
||||
// set the given invite ID as the workflow process ID in the workflow query
|
||||
wfTaskQuery.setProcessId(inviteId);
|
||||
|
||||
// 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(InviteWorkflowModel.WF_PROCESS_INVITE);
|
||||
|
||||
// query for invite workflow tasks with the constructed query
|
||||
List<WorkflowTask> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.MutableAuthenticationDao;
|
||||
@@ -36,6 +37,8 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.site.SiteInfo;
|
||||
import org.alfresco.repo.site.SiteModel;
|
||||
import org.alfresco.repo.site.SiteService;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.repo.web.scripts.BaseWebScriptTest;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
@@ -47,6 +50,8 @@ import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowInstance;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.PropertyMap;
|
||||
import org.alfresco.util.URLEncoder;
|
||||
import org.alfresco.web.scripts.Status;
|
||||
@@ -55,6 +60,7 @@ import org.alfresco.web.scripts.TestWebScriptServer.PutRequest;
|
||||
import org.alfresco.web.scripts.TestWebScriptServer.Response;
|
||||
import org.apache.commons.lang.RandomStringUtils;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
/**
|
||||
* Unit Test to test Invite Web Script API
|
||||
@@ -72,6 +78,8 @@ public class InviteServiceTest extends BaseWebScriptTest
|
||||
private NodeService nodeService;
|
||||
private WorkflowService workflowService;
|
||||
private MutableAuthenticationDao mutableAuthenticationDao;
|
||||
private NamespaceService namespaceService;
|
||||
private TransactionService transactionService;
|
||||
|
||||
// stores invitee email addresses, one entry for each "start invite" operation
|
||||
// invoked, so that resources created for each invitee for each test
|
||||
@@ -116,7 +124,19 @@ public class InviteServiceTest extends BaseWebScriptTest
|
||||
this.workflowService = (WorkflowService) getServer().getApplicationContext().getBean("WorkflowService");
|
||||
this.mutableAuthenticationDao = (MutableAuthenticationDao) getServer().getApplicationContext()
|
||||
.getBean("authenticationDao");
|
||||
this.namespaceService = (NamespaceService) getServer().getApplicationContext().getBean("NamespaceService");
|
||||
this.transactionService = (TransactionService) getServer().getApplicationContext()
|
||||
.getBean("TransactionService");
|
||||
|
||||
// redeploy invite process definition in case it has been modified
|
||||
WorkflowDefinition inviteWfDefinition = this.workflowService.getDefinitionByName(
|
||||
"jbpm$" + InviteWorkflowModel.WF_PROCESS_INVITE.toPrefixString(this.namespaceService));
|
||||
this.workflowService.undeployDefinition(inviteWfDefinition.id);
|
||||
ClassPathResource inviteWfResource = new ClassPathResource(
|
||||
"alfresco/workflow/invite_processdefinition.xml");
|
||||
workflowService.deployDefinition(
|
||||
"jbpm", inviteWfResource.getInputStream(), MimetypeMap.MIMETYPE_XML);
|
||||
|
||||
// Create new invitee email address list
|
||||
this.inviteeEmailAddrs = new ArrayList<String>();
|
||||
|
||||
@@ -354,6 +374,26 @@ public class InviteServiceTest extends BaseWebScriptTest
|
||||
return startInvite(inviteeFirstName, inviteeLastName, inviteeEmail, inviteeSiteRole, siteShortName,
|
||||
expectedStatus);
|
||||
}
|
||||
|
||||
private JSONObject cancelInvite(String inviteId, int expectedStatus) throws Exception
|
||||
{
|
||||
String cancelInviteUrl = URL_INVITE + "/"
|
||||
+ INVITE_ACTION_CANCEL + "?inviteId=" + inviteId;
|
||||
|
||||
Response response = sendRequest(new GetRequest(cancelInviteUrl), expectedStatus);;
|
||||
JSONObject result = new JSONObject(response.getContentAsString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private JSONObject rejectInvite(String inviteId, String inviteTicket, int expectedStatus) throws Exception
|
||||
{
|
||||
// Invitee rejects invitation to a Site from Inviter
|
||||
String rejectInviteUrl = URL_INVITE + "/" + inviteId + "/" + inviteTicket + "/reject";
|
||||
Response response = sendRequest(new PutRequest(rejectInviteUrl, (byte[])null, null), expectedStatus);
|
||||
JSONObject result = new JSONObject(response.getContentAsString());
|
||||
return result;
|
||||
}
|
||||
|
||||
private JSONObject getInvitesByInviteId(String inviteId, int expectedStatus)
|
||||
throws Exception
|
||||
@@ -465,7 +505,7 @@ public class InviteServiceTest extends BaseWebScriptTest
|
||||
|
||||
}, USER_INVITER);
|
||||
|
||||
JSONObject result = startInvite(INVITEE_FIRSTNAME, INVITEE_LASTNAME, inviteeEmailAddr, INVITEE_SITE_ROLE,
|
||||
startInvite(INVITEE_FIRSTNAME, INVITEE_LASTNAME, inviteeEmailAddr, INVITEE_SITE_ROLE,
|
||||
SITE_SHORT_NAME_INVITE_1, Status.STATUS_CONFLICT);
|
||||
}
|
||||
|
||||
@@ -503,9 +543,7 @@ public class InviteServiceTest extends BaseWebScriptTest
|
||||
String inviteId = result.getString("inviteId");
|
||||
|
||||
// Inviter cancels pending invitation
|
||||
String cancelInviteUrl = URL_INVITE + "/"
|
||||
+ INVITE_ACTION_CANCEL + "?inviteId=" + inviteId;
|
||||
Response response = sendRequest(new GetRequest(cancelInviteUrl), Status.STATUS_OK);
|
||||
cancelInvite(inviteId, Status.STATUS_OK);
|
||||
}
|
||||
|
||||
public void testAcceptInvite() throws Exception
|
||||
@@ -520,7 +558,7 @@ public class InviteServiceTest extends BaseWebScriptTest
|
||||
|
||||
// Invitee accepts invitation to a Site from Inviter
|
||||
String acceptInviteUrl = URL_INVITE + "/" + inviteId + "/" + inviteTicket + "/accept";
|
||||
Response response = sendRequest(new PutRequest(acceptInviteUrl, (byte[])null, null), Status.STATUS_OK);
|
||||
sendRequest(new PutRequest(acceptInviteUrl, (byte[])null, null), Status.STATUS_OK);
|
||||
|
||||
//
|
||||
// test that invitation represented by invite ID (of invitation started
|
||||
@@ -548,9 +586,7 @@ public class InviteServiceTest extends BaseWebScriptTest
|
||||
String inviteId = result.getString("inviteId");
|
||||
String inviteTicket = result.getString("inviteTicket");
|
||||
|
||||
// Invitee rejects invitation to a Site from Inviter
|
||||
String rejectInviteUrl = URL_INVITE + "/" + inviteId + "/" + inviteTicket + "/reject";
|
||||
Response response = sendRequest(new PutRequest(rejectInviteUrl, (byte[])null, null), Status.STATUS_OK);
|
||||
rejectInvite(inviteId, inviteTicket, Status.STATUS_OK);
|
||||
|
||||
//
|
||||
// test that invite represented by invite ID (of invitation started
|
||||
@@ -593,7 +629,7 @@ public class InviteServiceTest extends BaseWebScriptTest
|
||||
public void testGetInvitesByInviterUserName() throws Exception
|
||||
{
|
||||
// inviter starts invite workflow
|
||||
JSONObject startInviteResult = startInvite(INVITEE_FIRSTNAME,
|
||||
startInvite(INVITEE_FIRSTNAME,
|
||||
INVITEE_LASTNAME, INVITEE_SITE_ROLE, SITE_SHORT_NAME_INVITE_1, Status.STATUS_OK);
|
||||
|
||||
// get pending invites matching inviter user name used in invite started
|
||||
@@ -658,11 +694,104 @@ public class InviteServiceTest extends BaseWebScriptTest
|
||||
assertEquals(siteShortName, inviteJSONObj.getJSONObject("site").get("shortName"));
|
||||
}
|
||||
|
||||
public void testInviteForbiddenWhenInviterNotSiteManager() throws Exception
|
||||
public void testStartInviteForbiddenWhenInviterNotSiteManager() throws Exception
|
||||
{
|
||||
// inviter2 starts invite workflow, but he/she is not the site manager of the given site
|
||||
AuthenticationUtil.setCurrentUser(USER_INVITER_2);
|
||||
startInvite(INVITEE_FIRSTNAME,
|
||||
INVITEE_LASTNAME, INVITEE_SITE_ROLE, SITE_SHORT_NAME_INVITE_3, Status.STATUS_FORBIDDEN);
|
||||
}
|
||||
|
||||
public void testCancelInviteForbiddenWhenInviterNotSiteManager() throws Exception
|
||||
{
|
||||
// inviter (who is Site Manager of the given site) starts invite workflow
|
||||
JSONObject result = startInvite(INVITEE_FIRSTNAME,
|
||||
INVITEE_LASTNAME, INVITEE_SITE_ROLE, SITE_SHORT_NAME_INVITE_3, Status.STATUS_OK);
|
||||
|
||||
// get hold of invite ID of started invite
|
||||
String inviteId = result.getString("inviteId");
|
||||
|
||||
// when inviter 2 (who is not Site Manager of the given site) tries to cancel invite
|
||||
// http status FORBIDDEN must be returned
|
||||
AuthenticationUtil.setCurrentUser(USER_INVITER_2);
|
||||
cancelInvite(inviteId, Status.STATUS_FORBIDDEN);
|
||||
}
|
||||
|
||||
public void testInviteeResourcesDeletedUponRejectWhenNoInvitePending() throws Exception
|
||||
{
|
||||
// inviter starts invite workflow
|
||||
JSONObject result = startInvite(INVITEE_FIRSTNAME,
|
||||
INVITEE_LASTNAME, INVITEE_SITE_ROLE, SITE_SHORT_NAME_INVITE_1, Status.STATUS_OK);
|
||||
|
||||
// get hold of properties of started invite
|
||||
String inviteId = result.getString("inviteId");
|
||||
String inviteTicket = result.getString("inviteTicket");
|
||||
final String inviteeUserName = result.getString("inviteeUserName");
|
||||
|
||||
rejectInvite(inviteId, inviteTicket, Status.STATUS_OK);
|
||||
|
||||
AuthenticationUtil.runAs(new RunAsWork<Object>()
|
||||
{
|
||||
public Object doWork() throws Exception
|
||||
{
|
||||
assertEquals(false, mutableAuthenticationDao.userExists(inviteeUserName));
|
||||
assertEquals(false, personService.personExists(inviteeUserName));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
|
||||
public void testInviteeResourcesNotDeletedUponRejectWhenInvitesPending() throws Exception
|
||||
{
|
||||
// inviter invites invitee to site 1
|
||||
JSONObject result = startInvite(INVITEE_FIRSTNAME,
|
||||
INVITEE_LASTNAME, INVITEE_SITE_ROLE, SITE_SHORT_NAME_INVITE_1, Status.STATUS_OK);
|
||||
|
||||
// get hold of properties of started invite
|
||||
String invite1Id = result.getString("inviteId");
|
||||
String invite1Ticket = result.getString("inviteTicket");
|
||||
String inviteeEmail = result.getString("inviteeEmail");
|
||||
final String inviteeUserName = result.getString("inviteeUserName");
|
||||
|
||||
// inviter invites invitee to site 2
|
||||
startInvite(INVITEE_FIRSTNAME,
|
||||
INVITEE_LASTNAME, inviteeEmail, INVITEE_SITE_ROLE, SITE_SHORT_NAME_INVITE_2, Status.STATUS_OK);
|
||||
|
||||
rejectInvite(invite1Id, invite1Ticket, Status.STATUS_OK);
|
||||
|
||||
boolean inviteeUserExists = AuthenticationUtil.runAs(new RunAsWork<Boolean>()
|
||||
{
|
||||
public Boolean doWork() throws Exception
|
||||
{
|
||||
RetryingTransactionHelper tranHelper = transactionService.getRetryingTransactionHelper();
|
||||
Boolean result = tranHelper.doInTransaction(new RetryingTransactionCallback<Boolean>()
|
||||
{
|
||||
public Boolean execute() throws Throwable
|
||||
{
|
||||
Boolean result = mutableAuthenticationDao.userExists(inviteeUserName);
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
|
||||
// test that the invitee's user account still exists (has not been deleted
|
||||
assertEquals(true, inviteeUserExists);
|
||||
|
||||
boolean inviteePersonExists = AuthenticationUtil.runAs(new RunAsWork<Boolean>()
|
||||
{
|
||||
public Boolean doWork() throws Exception
|
||||
{
|
||||
Boolean result = personService.personExists(inviteeUserName);
|
||||
|
||||
return result;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
|
||||
assertEquals(true, inviteePersonExists);
|
||||
}
|
||||
}
|
||||
|
@@ -16,13 +16,12 @@ public interface InviteWorkflowModel {
|
||||
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");
|
||||
|
||||
|
||||
// transition names
|
||||
public static final String WF_TRANSITION_SEND_INVITE = "sendInvite";
|
||||
public static final String WF_TRANSITION_ACCEPT = "accept";
|
||||
public static final String WF_TRANSITION_REJECT = "reject";
|
||||
public static final String WF_TRANSITION_CANCEL = "cancel";
|
||||
public static final String WF_TRANSITION_ACCEPT_INVITE_END = "end";
|
||||
public static final String WF_TRANSITION_REJECT_INVITE_END = "end";
|
||||
|
||||
@@ -40,4 +39,8 @@ public interface InviteWorkflowModel {
|
||||
public static final QName WF_PROP_SENT_INVITE_DATE = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "sentInviteDate");
|
||||
public static final QName WF_PROP_INVITEE_GEN_PASSWORD = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "inviteeGenPassword");
|
||||
|
||||
// workflow execution context variable names
|
||||
public static final String wfVarInviteeUserName = "wf_inviteeUserName";
|
||||
public static final String wfVarSiteShortName = "wf_siteShortName";
|
||||
public static final String wfVarWorkflowInstanceId = "workflowinstanceid";
|
||||
}
|
||||
|
@@ -24,16 +24,11 @@
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -71,35 +66,12 @@ public class RejectInviteAction extends JBPMSpringActionHandler
|
||||
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);
|
||||
}
|
||||
}
|
||||
final String inviteeUserName = (String) executionContext.getVariable(InviteWorkflowModel.wfVarInviteeUserName);
|
||||
|
||||
return null;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
// clean up invitee's user account and person node if they are not in use i.e.
|
||||
// account is still disabled and there are no pending invites outstanding for the
|
||||
// invitee
|
||||
InviteHelper.cleanUpStaleInviteeResources(inviteeUserName, mutableAuthenticationDao, personService,
|
||||
workflowService);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user