diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml index 217b5bf06b..f3f7df4c55 100644 --- a/config/alfresco/bootstrap-context.xml +++ b/config/alfresco/bootstrap-context.xml @@ -201,6 +201,14 @@ text/xml false + + + + activiti + alfresco/workflow/invitation-add-direct.bpmn20.xml + text/xml + false + diff --git a/config/alfresco/invitation-service-context.xml b/config/alfresco/invitation-service-context.xml index 972b790fb6..41efd39634 100644 --- a/config/alfresco/invitation-service-context.xml +++ b/config/alfresco/invitation-service-context.xml @@ -21,6 +21,9 @@ + + + diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties index 7a027a7d6a..9a541da82d 100644 --- a/config/alfresco/repository.properties +++ b/config/alfresco/repository.properties @@ -769,6 +769,12 @@ deployment.service.targetLockTimeout=3600000 #Invitation Service # Should send emails as part of invitation process. notification.email.siteinvite=true +# Moderated invite Activiti workflow +site.invite.moderated.workflowId=activiti$activitiInvitationModerated +# Add intneral users Activiti workflow (use activiti$activitiInvitationNominated to revert to requiring accept of invite for internal users) +site.invite.nominated.workflowId=activiti$activitiInvitationNominatedAddDirect +# Add external users Activiti workflow +site.invite.nominatedExternal.workflowId=activiti$activitiInvitationNominated # Replication Service replication.enabled=false diff --git a/config/alfresco/workflow/invitation-add-direct.bpmn20.xml b/config/alfresco/workflow/invitation-add-direct.bpmn20.xml new file mode 100644 index 0000000000..bdcac57aa3 --- /dev/null +++ b/config/alfresco/workflow/invitation-add-direct.bpmn20.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + if (typeof bpm_workflowPriority != 'undefined') task.priority = bpm_workflowPriority; + + + + + + + ${initiator.exists() ? initiator.properties.userName : 'admin'} + + + + + + + + + + \ No newline at end of file diff --git a/source/java/org/alfresco/repo/invitation/InvitationServiceImpl.java b/source/java/org/alfresco/repo/invitation/InvitationServiceImpl.java index 87fb7fad3e..4bc4968e72 100644 --- a/source/java/org/alfresco/repo/invitation/InvitationServiceImpl.java +++ b/source/java/org/alfresco/repo/invitation/InvitationServiceImpl.java @@ -126,6 +126,19 @@ public class InvitationServiceImpl implements InvitationService, NodeServicePoli // Property determining whether emails should be sent. private boolean sendEmails = true; + + private enum InvitationWorkflowType { NOMINATED, NOMINATED_EXTERNAL, MODERATED }; + + // The nominated invite workflow definition to use for internal users + private String nominatedInvitationWorkflowId = + WorkflowModelNominatedInvitation.WORKFLOW_DEFINITION_NAME_ACTIVITI_ADD_DIRECT; + // The nominated invite workflow definition to use for external users + private String nominatedInvitationExternalWorkflowId = + WorkflowModelNominatedInvitation.WORKFLOW_DEFINITION_NAME_ACTIVITI_INVITE; + // The nominated invite workflow definition to use for internal users + private String moderatedInvitationWorkflowId = + WorkflowModelModeratedInvitation.WORKFLOW_DEFINITION_NAME_ACTIVITI; + /** * Set the policy component * @@ -136,6 +149,36 @@ public class InvitationServiceImpl implements InvitationService, NodeServicePoli this.policyComponent = policyComponent; } + /** + * Sets the nominated invite activiti workflow definition for internal users + * + * @param nominatedInvitationWorkflowId + */ + public void setNominatedInvitationWorkflowId(String nominatedInvitationWorkflowId) + { + this.nominatedInvitationWorkflowId = nominatedInvitationWorkflowId; + } + + /** + * Sets the nominated invite activiti workflow definition for external users + * + * @param nominatedInvitationExternalWorkflowId + */ + public void setNominatedInvitationExternalWorkflowId(String nominatedInvitationExternalWorkflowId) + { + this.nominatedInvitationExternalWorkflowId = nominatedInvitationExternalWorkflowId; + } + + /** + * Sets the moderated invite activiti workflow definition + * + * @param moderatedInvitationWorkflowId + */ + public void setModeratedInvitationWorkflowId(String moderatedInvitationWorkflowId) + { + this.moderatedInvitationWorkflowId = moderatedInvitationWorkflowId; + } + /** * Checks that all necessary properties and services have been provided. */ @@ -170,7 +213,8 @@ public class InvitationServiceImpl implements InvitationService, NodeServicePoli { List ret = new ArrayList(3); ret.add(WorkflowModelNominatedInvitation.WORKFLOW_DEFINITION_NAME); - ret.add(WorkflowModelNominatedInvitation.WORKFLOW_DEFINITION_NAME_ACTIVITI); + ret.add(WorkflowModelNominatedInvitation.WORKFLOW_DEFINITION_NAME_ACTIVITI_ADD_DIRECT); + ret.add(WorkflowModelNominatedInvitation.WORKFLOW_DEFINITION_NAME_ACTIVITI_INVITE); ret.add(WorkflowModelModeratedInvitation.WORKFLOW_DEFINITION_NAME); ret.add(WorkflowModelModeratedInvitation.WORKFLOW_DEFINITION_NAME_ACTIVITI); // old deprecated invitation workflow. @@ -1214,7 +1258,7 @@ public class InvitationServiceImpl implements InvitationService, NodeServicePoli // get the moderated workflow - WorkflowDefinition wfDefinition = getWorkflowDefinition(false); + WorkflowDefinition wfDefinition = getWorkflowDefinition(InvitationWorkflowType.MODERATED); return (ModeratedInvitation) startWorkflow(wfDefinition, workflowProps); } @@ -1375,8 +1419,10 @@ public class InvitationServiceImpl implements InvitationService, NodeServicePoli // // Start the invite workflow with inviter, invitee and site properties // - - WorkflowDefinition wfDefinition = getWorkflowDefinition(true); + + InvitationWorkflowType type = + created ? InvitationWorkflowType.NOMINATED_EXTERNAL : InvitationWorkflowType.NOMINATED; + WorkflowDefinition wfDefinition = getWorkflowDefinition(type); // Get invitee person NodeRef to add as assignee NodeRef inviteeNodeRef = personService.getPerson(inviteeUserName); @@ -1489,12 +1535,24 @@ public class InvitationServiceImpl implements InvitationService, NodeServicePoli /** * Return Activiti workflow definition unless Activiti engine is disabled. - * @param isNominated TODO + * @param type the workflow type * @return WorkflowDefinition */ - private WorkflowDefinition getWorkflowDefinition(boolean isNominated) + private WorkflowDefinition getWorkflowDefinition(InvitationWorkflowType type) { - String workflowName = isNominated ? getNominatedDefinitionName() : getModeratedDefinitionName(); + String workflowName = null; + if (type == InvitationWorkflowType.MODERATED) + { + workflowName = getModeratedDefinitionName(); + } + else if (type == InvitationWorkflowType.NOMINATED_EXTERNAL) + { + workflowName = getNominatedExternalDefinitionName(); + } + else + { + workflowName = getNominatedDefinitionName(); + } WorkflowDefinition definition = workflowService.getDefinitionByName(workflowName); if (definition == null) { @@ -1509,26 +1567,39 @@ public class InvitationServiceImpl implements InvitationService, NodeServicePoli { if(workflowAdminService.isEngineEnabled(ActivitiConstants.ENGINE_ID)) { - return WorkflowModelNominatedInvitation.WORKFLOW_DEFINITION_NAME_ACTIVITI; + return nominatedInvitationWorkflowId; } else if(workflowAdminService.isEngineEnabled(JBPMEngine.ENGINE_ID)) { return WorkflowModelNominatedInvitation.WORKFLOW_DEFINITION_NAME; } - throw new IllegalStateException("None of the Workflow engines supported by teh InvitationService are currently enabled!"); + throw new IllegalStateException("None of the Workflow engines supported by the InvitationService are currently enabled!"); + } + + private String getNominatedExternalDefinitionName() + { + if(workflowAdminService.isEngineEnabled(ActivitiConstants.ENGINE_ID)) + { + return nominatedInvitationExternalWorkflowId; + } + else if(workflowAdminService.isEngineEnabled(JBPMEngine.ENGINE_ID)) + { + return WorkflowModelNominatedInvitation.WORKFLOW_DEFINITION_NAME; + } + throw new IllegalStateException("None of the Workflow engines supported by the InvitationService are currently enabled!"); } private String getModeratedDefinitionName() { if(workflowAdminService.isEngineEnabled(ActivitiConstants.ENGINE_ID)) { - return WorkflowModelModeratedInvitation.WORKFLOW_DEFINITION_NAME_ACTIVITI; + return moderatedInvitationWorkflowId; } else if(workflowAdminService.isEngineEnabled(JBPMEngine.ENGINE_ID)) { return WorkflowModelModeratedInvitation.WORKFLOW_DEFINITION_NAME; } - throw new IllegalStateException("None of the Workflow engines supported by teh InvitationService are currently enabled!"); + throw new IllegalStateException("None of the Workflow engines supported by the InvitationService are currently enabled!"); } /** diff --git a/source/java/org/alfresco/repo/invitation/WorkflowModelNominatedInvitation.java b/source/java/org/alfresco/repo/invitation/WorkflowModelNominatedInvitation.java index 62059a6271..e308a3db9b 100644 --- a/source/java/org/alfresco/repo/invitation/WorkflowModelNominatedInvitation.java +++ b/source/java/org/alfresco/repo/invitation/WorkflowModelNominatedInvitation.java @@ -34,7 +34,8 @@ public interface WorkflowModelNominatedInvitation // workflow definition name public static final String WORKFLOW_DEFINITION_NAME = "jbpm$inwf:invitation-nominated"; - public static final String WORKFLOW_DEFINITION_NAME_ACTIVITI = "activiti$activitiInvitationNominated"; + public static final String WORKFLOW_DEFINITION_NAME_ACTIVITI_INVITE = "activiti$activitiInvitationNominated"; + public static final String WORKFLOW_DEFINITION_NAME_ACTIVITI_ADD_DIRECT = "activiti$activitiInvitationNominatedAddDirect"; // tasks public static final QName WF_TASK_INVITE_TO_SITE = QName.createQName(NAMESPACE_URI, "inviteToSiteTask"); diff --git a/source/test-java/org/alfresco/repo/invitation/AbstractInvitationServiceImplTest.java b/source/test-java/org/alfresco/repo/invitation/AbstractInvitationServiceImplTest.java index 1c75902ed8..7f690b629d 100644 --- a/source/test-java/org/alfresco/repo/invitation/AbstractInvitationServiceImplTest.java +++ b/source/test-java/org/alfresco/repo/invitation/AbstractInvitationServiceImplTest.java @@ -704,12 +704,28 @@ public abstract class AbstractInvitationServiceImplTest extends BaseAlfrescoSpri } /** - * Create a Nominated Invitation (for existing user, USER_ONE) read it. - * search for it cancel it search for it again (and fail to find it) Create - * a Nominated Invitation read it. search for it reject it Create a - * Nominated Invitation read it. accept it + * If requireAcceptance=true skip to C1 + * + * A1. Create a Nominated Invitation (for existing user, USER_ONE) + * A2. Read it + * A3. Search for it. + * A4. Cancel it + * A5. Search for it again (and fail to find it) + * + * B1. Create a Nominated Invitation + * B2. Read it + * B3. Search for it + * B4. Reject it + * + * C1. Create a Nominated Invitation + * C2. Read it + * C3. Accept it + * C4. Verify ACL + * + * @param requireAcceptance true if a workflow requiring acceptance is being used + * @throws Exception */ - public void testNominatedInvitationExistingUser() throws Exception + protected void testNominatedInvitationExistingUser(boolean requireAcceptance) throws Exception { String inviteeUserName = USER_ONE; String inviteeEmail = USER_ONE_EMAIL; @@ -725,98 +741,103 @@ public abstract class AbstractInvitationServiceImplTest extends BaseAlfrescoSpri authenticationComponent.setCurrentUser(USER_MANAGER); - NominatedInvitation nominatedInvitation = invitationService.inviteNominated(inviteeUserName, resourceType, - resourceName, inviteeRole, serverPath, acceptUrl, rejectUrl); - - assertNotNull("nominated invitation is null", nominatedInvitation); - String inviteId = nominatedInvitation.getInviteId(); - assertEquals("user name wrong", inviteeUserName, nominatedInvitation.getInviteeUserName()); - assertEquals("resource type name wrong", resourceType, nominatedInvitation.getResourceType()); - assertEquals("resource name wrong", resourceName, nominatedInvitation.getResourceName()); - assertEquals("role name wrong", inviteeRole, nominatedInvitation.getRoleName()); - assertEquals("server path wrong", serverPath, nominatedInvitation.getServerPath()); - assertEquals("accept URL wrong", acceptUrl, nominatedInvitation.getAcceptUrl()); - assertEquals("reject URL wrong", rejectUrl, nominatedInvitation.getRejectUrl()); - - // These values should be read from the person record - assertEquals("first name wrong", inviteeFirstName, nominatedInvitation.getInviteeFirstName()); - assertEquals("last name wrong", inviteeLastName, nominatedInvitation.getInviteeLastName()); - assertEquals("email name wrong", inviteeEmail, nominatedInvitation.getInviteeEmail()); - - /** - * Now we have an invitation get it and check the details have been - * returned correctly. - */ - NominatedInvitation invitation = (NominatedInvitation) invitationService.getInvitation(inviteId); - - assertNotNull("invitation is null", invitation); - assertEquals("invite id wrong", inviteId, invitation.getInviteId()); - assertEquals("user name wrong", inviteeUserName, nominatedInvitation.getInviteeUserName()); - assertEquals("resource type name wrong", resourceType, invitation.getResourceType()); - assertEquals("resource name wrong", resourceName, invitation.getResourceName()); - assertEquals("role name wrong", inviteeRole, invitation.getRoleName()); - assertEquals("server path wrong", serverPath, invitation.getServerPath()); - assertEquals("accept URL wrong", acceptUrl, invitation.getAcceptUrl()); - assertEquals("reject URL wrong", rejectUrl, invitation.getRejectUrl()); - - // These values should have been read from the DB - assertEquals("first name wrong", inviteeFirstName, invitation.getInviteeFirstName()); - assertEquals("last name wrong", inviteeLastName, invitation.getInviteeLastName()); - assertEquals("email name wrong", inviteeEmail, invitation.getInviteeEmail()); - - /** - * Search for the new invitation - */ - List invitations = invitationService.listPendingInvitationsForResource(resourceType, resourceName); - assertTrue("invitations is empty", !invitations.isEmpty()); - - NominatedInvitation firstInvite = (NominatedInvitation) invitations.get(0); - assertEquals("invite id wrong", inviteId, firstInvite.getInviteId()); - assertEquals("first name wrong", inviteeFirstName, firstInvite.getInviteeFirstName()); - assertEquals("last name wrong", inviteeLastName, firstInvite.getInviteeLastName()); - assertEquals("user name wrong", inviteeUserName, firstInvite.getInviteeUserName()); - - /** - * Now cancel the invitation - */ - NominatedInvitation canceledInvitation = (NominatedInvitation) invitationService.cancel(inviteId); - assertEquals("invite id wrong", inviteId, canceledInvitation.getInviteId()); - assertEquals("first name wrong", inviteeFirstName, canceledInvitation.getInviteeFirstName()); - assertEquals("last name wrong", inviteeLastName, canceledInvitation.getInviteeLastName()); - assertEquals("user name wrong", inviteeUserName, canceledInvitation.getInviteeUserName()); - - /** - * Do the query again - should no longer find anything - */ - List it2 = invitationService.listPendingInvitationsForResource(resourceType, resourceName); - assertTrue("invitations is not empty", it2.isEmpty()); - - /** - * Now invite and reject - */ - NominatedInvitation secondInvite = invitationService.inviteNominated(inviteeUserName, resourceType, - resourceName, inviteeRole, serverPath, acceptUrl, rejectUrl); - - NominatedInvitation rejectedInvitation = (NominatedInvitation) invitationService.cancel(secondInvite - .getInviteId()); - assertEquals("invite id wrong", secondInvite.getInviteId(), rejectedInvitation.getInviteId()); - assertEquals("user name wrong", inviteeUserName, rejectedInvitation.getInviteeUserName()); - - List it3 = invitationService.listPendingInvitationsForResource(resourceType, resourceName); - assertTrue("invitations is not empty", it3.isEmpty()); + if (requireAcceptance) + { + NominatedInvitation nominatedInvitation = invitationService.inviteNominated(inviteeUserName, resourceType, + resourceName, inviteeRole, serverPath, acceptUrl, rejectUrl); + + assertNotNull("nominated invitation is null", nominatedInvitation); + String inviteId = nominatedInvitation.getInviteId(); + assertEquals("user name wrong", inviteeUserName, nominatedInvitation.getInviteeUserName()); + assertEquals("resource type name wrong", resourceType, nominatedInvitation.getResourceType()); + assertEquals("resource name wrong", resourceName, nominatedInvitation.getResourceName()); + assertEquals("role name wrong", inviteeRole, nominatedInvitation.getRoleName()); + assertEquals("server path wrong", serverPath, nominatedInvitation.getServerPath()); + assertEquals("accept URL wrong", acceptUrl, nominatedInvitation.getAcceptUrl()); + assertEquals("reject URL wrong", rejectUrl, nominatedInvitation.getRejectUrl()); + + // These values should be read from the person record + assertEquals("first name wrong", inviteeFirstName, nominatedInvitation.getInviteeFirstName()); + assertEquals("last name wrong", inviteeLastName, nominatedInvitation.getInviteeLastName()); + assertEquals("email name wrong", inviteeEmail, nominatedInvitation.getInviteeEmail()); + + /** + * Now we have an invitation get it and check the details have been + * returned correctly. + */ + NominatedInvitation invitation = (NominatedInvitation) invitationService.getInvitation(inviteId); + + assertNotNull("invitation is null", invitation); + assertEquals("invite id wrong", inviteId, invitation.getInviteId()); + assertEquals("user name wrong", inviteeUserName, nominatedInvitation.getInviteeUserName()); + assertEquals("resource type name wrong", resourceType, invitation.getResourceType()); + assertEquals("resource name wrong", resourceName, invitation.getResourceName()); + assertEquals("role name wrong", inviteeRole, invitation.getRoleName()); + assertEquals("server path wrong", serverPath, invitation.getServerPath()); + assertEquals("accept URL wrong", acceptUrl, invitation.getAcceptUrl()); + assertEquals("reject URL wrong", rejectUrl, invitation.getRejectUrl()); + + // These values should have been read from the DB + assertEquals("first name wrong", inviteeFirstName, invitation.getInviteeFirstName()); + assertEquals("last name wrong", inviteeLastName, invitation.getInviteeLastName()); + assertEquals("email name wrong", inviteeEmail, invitation.getInviteeEmail()); + + /** + * Search for the new invitation + */ + List invitations = invitationService.listPendingInvitationsForResource(resourceType, resourceName); + assertTrue("invitations is empty", !invitations.isEmpty()); + + NominatedInvitation firstInvite = (NominatedInvitation) invitations.get(0); + assertEquals("invite id wrong", inviteId, firstInvite.getInviteId()); + assertEquals("first name wrong", inviteeFirstName, firstInvite.getInviteeFirstName()); + assertEquals("last name wrong", inviteeLastName, firstInvite.getInviteeLastName()); + assertEquals("user name wrong", inviteeUserName, firstInvite.getInviteeUserName()); + + /** + * Now cancel the invitation + */ + NominatedInvitation canceledInvitation = (NominatedInvitation) invitationService.cancel(inviteId); + assertEquals("invite id wrong", inviteId, canceledInvitation.getInviteId()); + assertEquals("first name wrong", inviteeFirstName, canceledInvitation.getInviteeFirstName()); + assertEquals("last name wrong", inviteeLastName, canceledInvitation.getInviteeLastName()); + assertEquals("user name wrong", inviteeUserName, canceledInvitation.getInviteeUserName()); + + /** + * Do the query again - should no longer find anything + */ + List it2 = invitationService.listPendingInvitationsForResource(resourceType, resourceName); + assertTrue("invitations is not empty", it2.isEmpty()); + + /** + * Now invite and reject + */ + NominatedInvitation secondInvite = invitationService.inviteNominated(inviteeUserName, resourceType, + resourceName, inviteeRole, serverPath, acceptUrl, rejectUrl); + + NominatedInvitation rejectedInvitation = (NominatedInvitation) invitationService.cancel(secondInvite + .getInviteId()); + assertEquals("invite id wrong", secondInvite.getInviteId(), rejectedInvitation.getInviteId()); + assertEquals("user name wrong", inviteeUserName, rejectedInvitation.getInviteeUserName()); + + List it3 = invitationService.listPendingInvitationsForResource(resourceType, resourceName); + assertTrue("invitations is not empty", it3.isEmpty()); + } /** * Now invite and accept */ NominatedInvitation thirdInvite = invitationService.inviteNominated(inviteeUserName, resourceType, resourceName, inviteeRole, serverPath, acceptUrl, rejectUrl); - - NominatedInvitation acceptedInvitation = (NominatedInvitation) invitationService.accept(thirdInvite - .getInviteId(), thirdInvite.getTicket()); - assertEquals("invite id wrong", thirdInvite.getInviteId(), acceptedInvitation.getInviteId()); - assertEquals("first name wrong", inviteeFirstName, acceptedInvitation.getInviteeFirstName()); - assertEquals("last name wrong", inviteeLastName, acceptedInvitation.getInviteeLastName()); - assertEquals("user name wrong", inviteeUserName, acceptedInvitation.getInviteeUserName()); + if (requireAcceptance) + { + NominatedInvitation acceptedInvitation = (NominatedInvitation) invitationService.accept(thirdInvite + .getInviteId(), thirdInvite.getTicket()); + assertEquals("invite id wrong", thirdInvite.getInviteId(), acceptedInvitation.getInviteId()); + assertEquals("first name wrong", inviteeFirstName, acceptedInvitation.getInviteeFirstName()); + assertEquals("last name wrong", inviteeLastName, acceptedInvitation.getInviteeLastName()); + assertEquals("user name wrong", inviteeUserName, acceptedInvitation.getInviteeUserName()); + } List it4 = invitationService.listPendingInvitationsForResource(resourceType, resourceName); assertTrue("invitations is not empty", it4.isEmpty()); @@ -828,6 +849,13 @@ public abstract class AbstractInvitationServiceImplTest extends BaseAlfrescoSpri assertEquals("role name wrong", inviteeRole, roleName); siteService.removeMembership(resourceName, inviteeUserName); } + + public void testNominatedInvitationExistingUser() throws Exception + { + this.invitationServiceImpl.setNominatedInvitationWorkflowId( + WorkflowModelNominatedInvitation.WORKFLOW_DEFINITION_NAME_ACTIVITI_INVITE); + testNominatedInvitationExistingUser(true); + } /** * Create a moderated invitation Get it Search for it Cancel it Create a diff --git a/source/test-java/org/alfresco/repo/invitation/ActivitiInvitationServiceImplTests.java b/source/test-java/org/alfresco/repo/invitation/ActivitiInvitationServiceImplTests.java index fd16a799a8..d1dedf3969 100644 --- a/source/test-java/org/alfresco/repo/invitation/ActivitiInvitationServiceImplTests.java +++ b/source/test-java/org/alfresco/repo/invitation/ActivitiInvitationServiceImplTests.java @@ -116,4 +116,11 @@ public class ActivitiInvitationServiceImplTests extends AbstractInvitationServic // Disable Jbpm and enable Activiti workflowAdminService.setEnabledEngines(Arrays.asList(ActivitiConstants.ENGINE_ID)); } + + public void testAddExistingUser() throws Exception + { + this.invitationServiceImpl.setNominatedInvitationWorkflowId( + WorkflowModelNominatedInvitation.WORKFLOW_DEFINITION_NAME_ACTIVITI_ADD_DIRECT); + testNominatedInvitationExistingUser(false); + } }