diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/invite/invites.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/invite/invites.get.desc.xml index c0b9ff02e1..b4ee8e36d5 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/invite/invites.get.desc.xml +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/invite/invites.get.desc.xml @@ -1,6 +1,6 @@ Invites - Returns pending invites filtered by Inviter user name, Invitee user name & Site short name + Returns pending invites filtered by Inviter user name, Invitee user name & Site short name /api/invites?inviterUserName={inviterUserName}&inviteeUserName={inviteeUserName?}&siteShortName={siteShortName?} /api/invites?inviterUserName={inviterUserName?}&inviteeUserName={inviteeUserName}&siteShortName={siteShortName?} /api/invites?inviterUserName={inviterUserName?}&inviteeUserName={inviteeUserName?}&siteShortName={siteShortName} diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/invite/invite.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/invite/scripts/invite.get.js similarity index 100% rename from config/alfresco/templates/webscripts/org/alfresco/repository/invite/invite.get.js rename to config/alfresco/templates/webscripts/org/alfresco/repository/invite/scripts/invite.get.js diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/invite/inviteresponse.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/invite/scripts/inviteresponse.get.js similarity index 100% rename from config/alfresco/templates/webscripts/org/alfresco/repository/invite/inviteresponse.get.js rename to config/alfresco/templates/webscripts/org/alfresco/repository/invite/scripts/inviteresponse.get.js diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 4d8b4d2622..42fd588ba6 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -277,9 +277,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/source/java/org/alfresco/repo/web/scripts/invite/Invite.java b/source/java/org/alfresco/repo/web/scripts/invite/Invite.java index 007ca2cf3b..b11565906a 100644 --- a/source/java/org/alfresco/repo/web/scripts/invite/Invite.java +++ b/source/java/org/alfresco/repo/web/scripts/invite/Invite.java @@ -26,17 +26,23 @@ package org.alfresco.repo.web.scripts.invite; import java.io.Serializable; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.MutableAuthenticationDao; import org.alfresco.repo.security.authentication.PasswordGenerator; import org.alfresco.repo.security.authentication.UserNameGenerator; +import org.alfresco.repo.workflow.WorkflowModel; +import org.alfresco.service.cmr.repository.NodeRef; 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.WorkflowPath; import org.alfresco.service.cmr.workflow.WorkflowService; +import org.alfresco.service.cmr.workflow.WorkflowTask; +import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.web.scripts.DeclarativeWebScript; import org.alfresco.web.scripts.Status; @@ -72,6 +78,8 @@ public class Invite extends DeclarativeWebScript private PersonService personService; private AuthenticationService authenticationService; private MutableAuthenticationDao mutableAuthenticationDao; + private NamespaceService namespaceService; + private AuthenticationComponent authenticationComponent; // user name and password generation beans private UserNameGenerator usernameGenerator; @@ -83,6 +91,7 @@ public class Invite extends DeclarativeWebScript public static final String WF_PROP_SITE_SHORT_NAME = "wf:siteShortName"; private static final String WF_PROP_INVITEE_GEN_PASSWORD = "wf:inviteeGenPassword"; + public static final String WF_INVITE_TASK_INVITE_TO_SITE = "wf:inviteToSiteTask"; public static final String WORKFLOW_DEFINITION_NAME = "jbpm$wf:invite"; /** @@ -130,6 +139,27 @@ public class Invite extends DeclarativeWebScript { this.mutableAuthenticationDao = mutableAuthenticationDao; } + + /** + * Set the namespace service + * + * @param namespaceService the namespace service to set + */ + public void setNamespaceService( + NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + /** + * Set the authentication component + * + * @param authenticationComponent the authentication component to set + */ + public void setAuthenticationComponent(AuthenticationComponent authenticationComponent) + { + this.authenticationComponent = authenticationComponent; + } /** * Set the user name generator service @@ -266,9 +296,14 @@ public class Invite extends DeclarativeWebScript private void startInvite(Map model, String inviteeEmail, String siteShortName) { + // get the inviter user name (the name of user web script is executed under) + // - needs to be assigned here because various system calls further on + // - in this method set the current user to the system user + String inviterUserName = this.authenticationService.getCurrentUserName(); + WorkflowDefinition wfDefinition = this.workflowService .getDefinitionByName(WORKFLOW_DEFINITION_NAME); - + // handle workflow definition does not exist if (wfDefinition == null) { @@ -314,21 +349,55 @@ public class Invite extends DeclarativeWebScript // create workflow properties Map workflowProps = new HashMap( 4); - workflowProps.put(QName.createQName(WF_PROP_INVITER_USER_NAME), - this.authenticationService.getCurrentUserName()); - workflowProps.put(QName.createQName(WF_PROP_INVITEE_USER_NAME), + workflowProps.put(QName.createQName(WF_PROP_INVITER_USER_NAME, this.namespaceService), + inviterUserName); + workflowProps.put(QName.createQName(WF_PROP_INVITEE_USER_NAME, this.namespaceService), inviteeUserName); - workflowProps.put(QName.createQName(WF_PROP_INVITEE_GEN_PASSWORD), - generatedPassword); - workflowProps.put(QName.createQName(WF_PROP_SITE_SHORT_NAME), siteShortName); + workflowProps.put(QName.createQName(WF_PROP_INVITEE_GEN_PASSWORD, this.namespaceService), + String.valueOf(generatedPassword)); + workflowProps.put(QName.createQName(WF_PROP_SITE_SHORT_NAME, this.namespaceService), + siteShortName); // start the workflow WorkflowPath wfPath = this.workflowService.startWorkflow(wfDefinition .getId(), workflowProps); + + // get the workflow instance and path IDs String workflowId = wfPath.instance.id; - + String wfPathId = wfPath.id; + + // complete the start task + List wfTasks = this.workflowService.getTasksForWorkflowPath(wfPathId); + + // throw an exception if no tasks where found on the workflow path + if (wfTasks.size() == 0) + { + throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, + "No workflow tasks where found on workflow path ID: " + wfPathId); + } + + // first task in workflow task list associated with the workflow path id above + // should be "wf:inviteToSiteTask", otherwise throw web script exception + String wfTaskTitle = wfTasks.get(0).title; + if (!wfTaskTitle.equals(WF_INVITE_TASK_INVITE_TO_SITE)) + { + throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, + "First workflow task found on workflow path ID: " + wfPathId + + " should be " + WF_INVITE_TASK_INVITE_TO_SITE); + } + + // complete invite workflow start task + WorkflowTask wfStartTask = wfTasks.get(0); + // send out the invite - this.workflowService.signal(wfPath.id, TRANSITION_SEND_INVITE); + + // attach empty package to start task, end it and follow transition + // thats sends out invite + NodeRef wfPackage = this.workflowService.createPackage(null); + Map wfTaskProps = new HashMap(1, 1.0f); + wfTaskProps.put(WorkflowModel.ASSOC_PACKAGE, wfPackage); + this.workflowService.updateTask(wfStartTask.id, wfTaskProps, null, null); + this.workflowService.endTask(wfStartTask.id, TRANSITION_SEND_INVITE); // add model properties for template to render model.put(MODEL_PROP_KEY_ACTION, ACTION_START); diff --git a/source/java/org/alfresco/repo/web/scripts/invite/InviteResponse.java b/source/java/org/alfresco/repo/web/scripts/invite/InviteResponse.java index 7a10a8eace..18bf9a1d89 100644 --- a/source/java/org/alfresco/repo/web/scripts/invite/InviteResponse.java +++ b/source/java/org/alfresco/repo/web/scripts/invite/InviteResponse.java @@ -28,7 +28,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.SiteModel; import org.alfresco.repo.site.SiteService; import org.alfresco.service.cmr.security.PersonService; @@ -42,19 +44,52 @@ import org.alfresco.web.scripts.WebScriptRequest; /** * Web Script invoked by Invitee to either accept (response='accept') an * invitation from a Site Manager (Inviter) to join a Site as a Site - * Collaborator, or to reject (response='reject') an invitation that has - * already been sent out + * Collaborator, or to reject (response='reject') an invitation that has already + * been sent out * * @author glen dot johnson at alfresco dot com */ public class InviteResponse extends DeclarativeWebScript { + /** + * Inner class providing functionality (which needs to run under admin + * rights) to set membership of invitee (given as invitee user name) to site + * (given as site short name) as given site role + */ + private class SetSiteMembershipWorker implements + AuthenticationUtil.RunAsWork + { + private String siteShortName; + private String inviteeUserName; + private String siteRole; + + private SetSiteMembershipWorker(String siteShortName, + String inviteeUserName, String siteRole) + { + this.siteShortName = siteShortName; + this.inviteeUserName = inviteeUserName; + this.siteRole = siteRole; + } + + /** + * Does the work to set the site membership + */ + public Boolean doWork() throws Exception + { + InviteResponse.this.siteService.setMembership(this.siteShortName, + this.inviteeUserName, this.siteRole); + + return Boolean.TRUE; + } + } + private static final String RESPONSE_ACCEPT = "accept"; private static final String RESPONSE_REJECT = "reject"; private static final String TRANSITION_ACCEPT = "accept"; private static final String TRANSITION_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; @@ -196,21 +231,22 @@ public class InviteResponse extends DeclarativeWebScript String inviteeUserName, String siteShortName) { // get workflow paths associated with given workflow ID - List wfPaths = this.workflowService.getWorkflowPaths(workflowId); - - // throw web script exception if there is not at least one workflow path + List wfPaths = this.workflowService + .getWorkflowPaths(workflowId); + + // throw web script exception if there is not at least one workflow path // associated with this workflow ID if ((wfPaths == null) || (wfPaths.size() == 0)) { throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, "There are no workflow paths associated with workflow ID: " - + workflowId); + + workflowId); } - + // get workflow path ID for path matching workflow ID WorkflowPath wfPath = wfPaths.get(0); String wfPathID = wfPath.id; - + this.workflowService.signal(wfPathID, TRANSITION_ACCEPT); // enable invitee person's user account because he/she has accepted the @@ -218,8 +254,9 @@ public class InviteResponse extends DeclarativeWebScript this.mutableAuthenticationDao.setEnabled(inviteeUserName, true); // Add Invitee to Site as "Site Collaborator" role - this.siteService.setMembership(siteShortName, inviteeUserName, - SiteModel.SITE_COLLABORATOR); + RunAsWork setSiteMembershipWorker = new InviteResponse.SetSiteMembershipWorker( + siteShortName, inviteeUserName, SiteModel.SITE_COLLABORATOR); + AuthenticationUtil.runAs(setSiteMembershipWorker, USER_ADMIN); // add model properties for template to render model.put(MODEL_PROP_KEY_RESPONSE, RESPONSE_ACCEPT); @@ -244,21 +281,22 @@ public class InviteResponse extends DeclarativeWebScript String inviteeUserName, String siteShortName) { // get workflow paths associated with given workflow ID - List wfPaths = this.workflowService.getWorkflowPaths(workflowId); - - // throw web script exception if there is not at least one workflow path + List wfPaths = this.workflowService + .getWorkflowPaths(workflowId); + + // throw web script exception if there is not at least one workflow path // associated with this workflow ID if ((wfPaths == null) || (wfPaths.size() == 0)) { throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, "There are no workflow paths associated with workflow ID: " - + workflowId); + + workflowId); } - + // get workflow path ID for path matching workflow ID WorkflowPath wfPath = wfPaths.get(0); String wfPathID = wfPath.id; - + this.workflowService.signal(wfPathID, TRANSITION_REJECT); // delete the person created for invitee diff --git a/source/java/org/alfresco/repo/web/scripts/invite/InviteServiceTest.java b/source/java/org/alfresco/repo/web/scripts/invite/InviteServiceTest.java index 785158edb7..e3aafca4ce 100644 --- a/source/java/org/alfresco/repo/web/scripts/invite/InviteServiceTest.java +++ b/source/java/org/alfresco/repo/web/scripts/invite/InviteServiceTest.java @@ -33,6 +33,7 @@ import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.util.PropertyMap; import org.alfresco.web.scripts.Status; +import org.json.JSONArray; import org.json.JSONObject; import org.springframework.mock.web.MockHttpServletResponse; @@ -47,161 +48,324 @@ public class InviteServiceTest extends BaseWebScriptTest private AuthenticationComponent authenticationComponent; private PersonService personService; private SiteService siteService; - + private static final String USER_ADMIN = "admin"; private static final String USER_INVITER = "InviteeUser"; private static final String INVITEE_EMAIL = "inviter123@email.com"; private static final String SITE_SHORT_NAME_INVITE = "InviteSiteShortName"; - + 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 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 { super.setUp(); + + this.authenticationService = (AuthenticationService) getServer() + .getApplicationContext().getBean("AuthenticationService"); + this.authenticationComponent = (AuthenticationComponent) getServer() + .getApplicationContext().getBean("authenticationComponent"); + this.personService = (PersonService) getServer() + .getApplicationContext().getBean("PersonService"); + this.siteService = (SiteService) getServer().getApplicationContext() + .getBean("siteService"); + + // set current user as admin for person and site creation + this.authenticationComponent.setCurrentUser(USER_ADMIN); - this.authenticationService = (AuthenticationService)getServer().getApplicationContext().getBean("AuthenticationService"); - this.authenticationComponent = (AuthenticationComponent)getServer().getApplicationContext().getBean("authenticationComponent"); - this.personService = (PersonService)getServer().getApplicationContext().getBean("PersonService"); - this.siteService = (SiteService)getServer().getApplicationContext().getBean("siteService"); - - // Create inviter user - createUser(USER_INVITER); - + // Create inviter person + createPerson(USER_INVITER); + // Create site for Inviter to invite Invitee to // - only create the site if it doesn't already exist SiteInfo siteInfo = this.siteService.getSite(SITE_SHORT_NAME_INVITE); if (siteInfo == null) { - this.siteService.createSite("InviteSitePreset", SITE_SHORT_NAME_INVITE, "InviteSiteTitle", - "InviteSiteDescription", true); + this.siteService.createSite("InviteSitePreset", + SITE_SHORT_NAME_INVITE, "InviteSiteTitle", + "InviteSiteDescription", true); } - + // Do tests as inviter user this.authenticationComponent.setCurrentUser(USER_INVITER); } - + @Override protected void tearDown() throws Exception { super.tearDown(); - + // admin user required to delete user this.authenticationComponent.setCurrentUser(USER_ADMIN); - + // delete the inviter user personService.deletePerson(USER_INVITER); - + // delete invite site siteService.deleteSite(SITE_SHORT_NAME_INVITE); + + // return back to inviter user + this.authenticationComponent.setCurrentUser(USER_INVITER); } - - private void createUser(String userName) + + private void createPerson(String userName) { // if user with given user name doesn't already exist then create user if (this.authenticationService.authenticationExists(userName) == false) { // create user - this.authenticationService.createAuthentication(userName, "password".toCharArray()); - + this.authenticationService.createAuthentication(userName, + "password".toCharArray()); + } + + // if person with given user name doesn't already exist then create + // person + if (this.personService.personExists(userName) == false) + { // create person properties PropertyMap personProps = new PropertyMap(); personProps.put(ContentModel.PROP_USERNAME, userName); personProps.put(ContentModel.PROP_FIRSTNAME, "FirstName123"); personProps.put(ContentModel.PROP_LASTNAME, "LastName123"); - personProps.put(ContentModel.PROP_EMAIL, "FirstName123.LastName123@email.com"); + personProps.put(ContentModel.PROP_EMAIL, + "FirstName123.LastName123@email.com"); personProps.put(ContentModel.PROP_JOBTITLE, "JobTitle123"); personProps.put(ContentModel.PROP_JOBTITLE, "Organisation123"); - + // create person node for user this.personService.createPerson(personProps); - } + } } - - private JSONObject startInvite(String inviteeEmail, String siteShortName, int expectedStatus) - throws Exception + + private JSONObject startInvite(String inviteeEmail, String siteShortName, + int expectedStatus) throws Exception { // Inviter sends invitation to Invitee to join a Site - String startInviteUrl = URL_INVITE_SERVICE + "/" + INVITE_ACTION_START + "?inviteeEmail=" + inviteeEmail - + "&siteShortName=" + siteShortName; - MockHttpServletResponse response = getRequest(startInviteUrl, expectedStatus); + String startInviteUrl = URL_INVITE_SERVICE + "/" + INVITE_ACTION_START + + "?inviteeEmail=" + inviteeEmail + "&siteShortName=" + + siteShortName; + MockHttpServletResponse response = getRequest(startInviteUrl, + expectedStatus); + + JSONObject result = new JSONObject(response.getContentAsString()); + + return result; + } + + private JSONArray getInvitesByInviteId(String inviteId, int expectedStatus) + throws Exception + { + // construct get invites URL + String getInvitesUrl = URL_INVITES_SERVICE + "?inviteId=" + inviteId; + + // invoke get invites web script + MockHttpServletResponse response = getRequest(getInvitesUrl, + expectedStatus); + + JSONArray result = new JSONArray(response.getContentAsString()); + + return result; + } + + private JSONArray getInvitesByInviterUserName(String inviterUserName, int expectedStatus) + throws Exception + { + // construct get invites URL + String getInvitesUrl = URL_INVITES_SERVICE + "?inviterUserName=" + inviterUserName; - JSONObject result = new JSONObject(response.getContentAsString()); + // invoke get invites web script + MockHttpServletResponse response = getRequest(getInvitesUrl, + expectedStatus); + + JSONArray result = new JSONArray(response.getContentAsString()); return result; } - + + private JSONArray getInvitesByInviteeUserName(String inviteeUserName, int expectedStatus) + throws Exception + { + // construct get invites URL + String getInvitesUrl = URL_INVITES_SERVICE + "?inviteeUserName=" + inviteeUserName; + + // invoke get invites web script + MockHttpServletResponse response = getRequest(getInvitesUrl, + expectedStatus); + + JSONArray result = new JSONArray(response.getContentAsString()); + + return result; + } + + private JSONArray getInvitesBySiteShortName(String siteShortName, int expectedStatus) + throws Exception + { + // construct get invites URL + String getInvitesUrl = URL_INVITES_SERVICE + "?siteShortName=" + siteShortName; + + // invoke get invites web script + MockHttpServletResponse response = getRequest(getInvitesUrl, + expectedStatus); + + JSONArray result = new JSONArray(response.getContentAsString()); + + return result; + } + public void testStartInvite() throws Exception { - // admin user required to delete user - this.authenticationComponent.setCurrentUser(USER_ADMIN); - - JSONObject result = startInvite(INVITEE_EMAIL, SITE_SHORT_NAME_INVITE, Status.STATUS_OK); - + JSONObject result = startInvite(INVITEE_EMAIL, SITE_SHORT_NAME_INVITE, + Status.STATUS_OK); + assertEquals(INVITE_ACTION_START, result.get("action")); assertEquals(SITE_SHORT_NAME_INVITE, result.get("siteShortName")); } - + public void testCancelInvite() throws Exception { - // admin user required to delete user - this.authenticationComponent.setCurrentUser(USER_ADMIN); - // inviter starts invite workflow - JSONObject result = startInvite(INVITEE_EMAIL, SITE_SHORT_NAME_INVITE, Status.STATUS_OK); - + JSONObject result = startInvite(INVITEE_EMAIL, SITE_SHORT_NAME_INVITE, + Status.STATUS_OK); + // get hold of workflow ID of started invite workflow instance String workflowId = result.getString("workflowId"); - + // Inviter cancels pending invitation - String cancelInviteUrl = URL_INVITE_SERVICE + "/" + INVITE_ACTION_CANCEL + "?workflowId=" + workflowId; - MockHttpServletResponse response = getRequest(cancelInviteUrl, Status.STATUS_OK); + String cancelInviteUrl = URL_INVITE_SERVICE + "/" + + INVITE_ACTION_CANCEL + "?workflowId=" + workflowId; + MockHttpServletResponse response = getRequest(cancelInviteUrl, + Status.STATUS_OK); } - + public void testAcceptInvite() throws Exception { - // admin user required to delete user - this.authenticationComponent.setCurrentUser(USER_ADMIN); - // inviter starts invite workflow - JSONObject result = startInvite(INVITEE_EMAIL, SITE_SHORT_NAME_INVITE, Status.STATUS_OK); - + JSONObject result = startInvite(INVITEE_EMAIL, SITE_SHORT_NAME_INVITE, + Status.STATUS_OK); + // get hold of workflow ID of started invite workflow instance String workflowId = result.getString("workflowId"); - - // get hold of invitee user name that was generated as part of starting the invite + + // 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_INVITERSP_SERVICE + "/" + INVITE_RSP_ACCEPT + "?workflowId=" + workflowId - + "&inviteeUserName=" + inviteeUserName + "&siteShortName=" + SITE_SHORT_NAME_INVITE; - MockHttpServletResponse response = getRequest(acceptInviteUrl, Status.STATUS_OK); + String acceptInviteUrl = URL_INVITERSP_SERVICE + "/" + + INVITE_RSP_ACCEPT + "?workflowId=" + workflowId + + "&inviteeUserName=" + inviteeUserName + "&siteShortName=" + + SITE_SHORT_NAME_INVITE; + MockHttpServletResponse response = getRequest(acceptInviteUrl, + Status.STATUS_OK); } - + public void testRejectInvite() throws Exception { - // admin user required to delete user - this.authenticationComponent.setCurrentUser(USER_ADMIN); - // inviter starts invite workflow - JSONObject result = startInvite(INVITEE_EMAIL, SITE_SHORT_NAME_INVITE, Status.STATUS_OK); - + JSONObject result = startInvite(INVITEE_EMAIL, SITE_SHORT_NAME_INVITE, + Status.STATUS_OK); + // get hold of workflow ID of started invite workflow instance String workflowId = result.getString("workflowId"); - - // get hold of invitee user name that was generated as part of starting the invite + + // 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_INVITERSP_SERVICE + "/" + INVITE_RSP_REJECT + "?workflowId=" + workflowId - + "&inviteeUserName=" + inviteeUserName + "&siteShortName=" + SITE_SHORT_NAME_INVITE; - MockHttpServletResponse response = getRequest(rejectInviteUrl, Status.STATUS_OK); + String rejectInviteUrl = URL_INVITERSP_SERVICE + "/" + + INVITE_RSP_REJECT + "?workflowId=" + workflowId + + "&inviteeUserName=" + inviteeUserName + "&siteShortName=" + + SITE_SHORT_NAME_INVITE; + MockHttpServletResponse response = getRequest(rejectInviteUrl, + Status.STATUS_OK); + } + + public void testGetInvitesByInviteId() throws Exception + { + // inviter starts invite workflow + JSONObject startInviteResult = startInvite(INVITEE_EMAIL, SITE_SHORT_NAME_INVITE, + Status.STATUS_OK); + + // get hold of workflow ID of started invite workflow instance + + String inviteId = startInviteResult.getString("workflowId"); + + assertEquals(true, ((inviteId != null) && (inviteId.length() != 0))); + + // get pending invite matching inviteId from invite started above + JSONArray getInvitesResult = getInvitesByInviteId(inviteId, Status.STATUS_OK); + + assertEquals(getInvitesResult.length(), 1); + + JSONObject inviteJSONObj = getInvitesResult.getJSONObject(0); + + assertEquals(inviteId, inviteJSONObj.get("inviteId")); + } + + public void testGetInvitesByInviterUserName() throws Exception + { + // inviter starts invite workflow + JSONObject startInviteResult = startInvite(INVITEE_EMAIL, SITE_SHORT_NAME_INVITE, + Status.STATUS_OK); + + // get pending invites matching inviter user name used in invite started above + JSONArray getInvitesResult = getInvitesByInviterUserName(USER_INVITER, Status.STATUS_OK); + + assertEquals(true, getInvitesResult.length() > 0); + + JSONObject inviteJSONObj = getInvitesResult.getJSONObject(0); + + assertEquals(USER_INVITER, inviteJSONObj.get("inviterUserName")); + } + + public void testGetInvitesByInviteeUserName() throws Exception + { + // inviter starts invite workflow + JSONObject startInviteResult = startInvite(INVITEE_EMAIL, SITE_SHORT_NAME_INVITE, + Status.STATUS_OK); + + // get hold of invitee user name property of started invite workflow instance + String inviteeUserName = startInviteResult.getString("inviteeUserName"); + + assertEquals(true, ((inviteeUserName != null) && (inviteeUserName.length() != 0))); + + // get pending invites matching invitee user name from invite started above + JSONArray getInvitesResult = getInvitesByInviteeUserName(inviteeUserName, Status.STATUS_OK); + + assertEquals(true, getInvitesResult.length() > 0); + + JSONObject inviteJSONObj = getInvitesResult.getJSONObject(0); + + assertEquals(inviteeUserName, inviteJSONObj.get("inviteeUserName")); + } + + public void testGetInvitesBySiteShortName() throws Exception + { + // inviter starts invite workflow + JSONObject startInviteResult = startInvite(INVITEE_EMAIL, SITE_SHORT_NAME_INVITE, + Status.STATUS_OK); + + // get hold of site short name property of started invite workflow instance + String siteShortName = startInviteResult.getString("siteShortName"); + + assertEquals(true, ((siteShortName != null) && (siteShortName.length() != 0))); + + // get pending invites matching site short name from invite started above + JSONArray getInvitesResult = getInvitesBySiteShortName(siteShortName, Status.STATUS_OK); + + assertEquals(true, getInvitesResult.length() > 0); + + JSONObject inviteJSONObj = getInvitesResult.getJSONObject(0); + + assertEquals(siteShortName, inviteJSONObj.get("siteShortName")); } } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/invite/Invites.java b/source/java/org/alfresco/repo/web/scripts/invite/Invites.java index 9e0ef50ad3..5e41ce348a 100644 --- a/source/java/org/alfresco/repo/web/scripts/invite/Invites.java +++ b/source/java/org/alfresco/repo/web/scripts/invite/Invites.java @@ -24,7 +24,6 @@ */ package org.alfresco.repo.web.scripts.invite; -import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -33,6 +32,8 @@ 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.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.web.scripts.DeclarativeWebScript; import org.alfresco.web.scripts.Status; @@ -41,19 +42,19 @@ import org.alfresco.web.scripts.WebScriptRequest; /** * Web Script which returns pending Site invitations matching at least one of - * - * (1a) inviter (inviter user name). i.e. pending invitations which have been sent - * by that inviter, but which have not been responded to (accepted or rejected) - * by the invitee, and have not been cancelled by that inviter * - * (1b) invitee (invitee user name), i.e. pending invitations which have not been accepted or - * rejected yet by that inviter - * - * (1c) site (site short name), i.e. pending invitations sent out to join that Site. - * If only the site is given, then all pending invites are returned, irrespective of who - * the inviters or invitees are - * - * or + * (1a) inviter (inviter user name). i.e. pending invitations which have been + * sent by that inviter, but which have not been responded to (accepted or + * rejected) by the invitee, and have not been cancelled by that inviter + * + * (1b) invitee (invitee user name), i.e. pending invitations which have not + * been accepted or rejected yet by that inviter + * + * (1c) site (site short name), i.e. pending invitations sent out to join that + * Site. If only the site is given, then all pending invites are returned, + * irrespective of who the inviters or invitees are + * + * or * * (2) matching the given invite ID * @@ -67,23 +68,36 @@ public class Invites extends DeclarativeWebScript private static final String PARAM_INVITEE_USER_NAME = "inviteeUserName"; private static final String PARAM_SITE_SHORT_NAME = "siteShortName"; private static final String PARAM_INVITE_ID = "inviteId"; - + // model key names private static final String MODEL_KEY_NAME_INVITES = "invites"; - + // service instances private WorkflowService workflowService; - + private NamespaceService namespaceService; + /** * Set the workflow service property * - * @param workflowService the workflow service to set + * @param workflowService + * the workflow service to set */ public void setWorkflowService(WorkflowService workflowService) { this.workflowService = workflowService; } - + + /** + * Set the namespace service + * + * @param namespaceService the namespace service to set + */ + public void setNamespaceService( + NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + /* * (non-Javadoc) * @@ -98,7 +112,7 @@ public class Invites extends DeclarativeWebScript { // initialise model to pass on for template to render Map model = new HashMap(); - + // Get parameter names String[] paramNames = req.getParameterNames(); @@ -108,110 +122,134 @@ public class Invites extends DeclarativeWebScript throw new WebScriptException(Status.STATUS_BAD_REQUEST, "No parameters have been provided on URL"); } - + // get URL request parameters, checking if they have been provided - + // check if 'inviterUserName' parameter provided String inviterUserName = req.getParameter(PARAM_INVITER_USER_NAME); - boolean inviterUserNameProvided = (inviterUserName != null) && (inviterUserName.length() != 0); + boolean inviterUserNameProvided = (inviterUserName != null) + && (inviterUserName.length() != 0); // check if 'inviteeUserName' parameter provided String inviteeUserName = req.getParameter(PARAM_INVITEE_USER_NAME); - boolean inviteeUserNameProvided = (inviteeUserName != null) && (inviteeUserName.length() != 0); + boolean inviteeUserNameProvided = (inviteeUserName != null) + && (inviteeUserName.length() != 0); // check if 'siteShortName' parameter provided String siteShortName = req.getParameter(PARAM_SITE_SHORT_NAME); - boolean siteShortNameProvided = (siteShortName != null) && (siteShortName.length() != 0); - + boolean siteShortNameProvided = (siteShortName != null) + && (siteShortName.length() != 0); + // check if 'inviteId' parameter provided String inviteId = req.getParameter(PARAM_INVITE_ID); - boolean inviteIdProvided = (inviteId != null) && (inviteId.length() != 0); + boolean inviteIdProvided = (inviteId != null) + && (inviteId.length() != 0); - // throw web script exception if at least one of 'inviterUserName', 'inviteeUserName', 'siteShortName', + // throw web script exception if at least one of 'inviterUserName', + // 'inviteeUserName', 'siteShortName', // 'inviteId' URL request parameters has not been provided - if (!(inviterUserNameProvided || inviteeUserNameProvided || siteShortNameProvided || inviteIdProvided)) + if (!(inviterUserNameProvided || inviteeUserNameProvided + || siteShortNameProvided || inviteIdProvided)) { - throw new WebScriptException(Status.STATUS_BAD_REQUEST, + throw new WebScriptException( + Status.STATUS_BAD_REQUEST, "At least one of the following URL request parameters must be provided in URL " - + "'inviterUserName', 'inviteeUserName', 'siteShortName' or 'inviteId'"); + + "'inviterUserName', 'inviteeUserName', 'siteShortName' or 'inviteId'"); } - + // query for workflow tasks by given parameters // create workflow task query WorkflowTaskQuery wfTaskQuery = new WorkflowTaskQuery(); - - // query only active workflows - wfTaskQuery.setActive(Boolean.TRUE); - - // workflow query properties - HashMap wfQueryProps = null; - - // 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 + + // 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 if (inviteIdProvided) { wfTaskQuery.setProcessId(inviteId); - } - else - // 'inviteId' has not been provided, so create the query properties from the invite URL request - // parameters - // - because this web script class will terminate with a web script exception if none of the required - // request parameters are provided, at least one of these query properties will be set - // at this point + } else + // 'inviteId' has not been provided, so create the query properties from + // the invite URL request + // parameters + // - because this web script class will terminate with a web script + // exception if none of the required + // request parameters are provided, at least one of these query + // properties will be set + // at this point { - wfQueryProps = new HashMap(3, 1.0f); + // workflow query properties + HashMap wfQueryProps = new HashMap(3, + 1.0f); if (inviterUserName != null) { - wfQueryProps.put(QName.createQName(Invite.WF_PROP_INVITER_USER_NAME), inviterUserName); + wfQueryProps.put(QName.createQName(Invite.WF_PROP_INVITER_USER_NAME, this.namespaceService), + inviterUserName); } if (inviteeUserName != null) { - wfQueryProps.put(QName.createQName(Invite.WF_PROP_INVITEE_USER_NAME), inviteeUserName); + wfQueryProps.put(QName.createQName(Invite.WF_PROP_INVITEE_USER_NAME, this.namespaceService), + inviteeUserName); } if (siteShortName != null) { - wfQueryProps.put(QName.createQName(Invite.WF_PROP_SITE_SHORT_NAME), siteShortName); + wfQueryProps.put(QName.createQName(Invite.WF_PROP_SITE_SHORT_NAME, this.namespaceService), + siteShortName); } - + // set workflow task query parameters - wfTaskQuery.setProcessCustomProps(wfQueryProps); + wfTaskQuery.setTaskCustomProps(wfQueryProps); } - - // set process name to "wf:invite" so that only tasks associated with invite workflow instances + + // query only active workflows + wfTaskQuery.setActive(Boolean.TRUE); + + // pick up the start task + wfTaskQuery.setTaskState(WorkflowTaskState.COMPLETED); + wfTaskQuery.setTaskName(QName.createQName(Invite.WF_INVITE_TASK_INVITE_TO_SITE, this.namespaceService)); + + // set process name to "wf:invite" so that only tasks associated with + // invite workflow instances // are returned by query - wfTaskQuery.setProcessName(QName.createQName(Invite.WORKFLOW_DEFINITION_NAME)); - + wfTaskQuery.setProcessName(QName.createQName("wf:invite", this.namespaceService)); + // query for invite workflow tasks - List wf_invite_tasks = this.workflowService.queryTasks(wfTaskQuery); - + List wf_invite_tasks = this.workflowService + .queryTasks(wfTaskQuery); + // InviteInfo List to place onto model List inviteInfoList = new ArrayList(); - + // Put InviteInfo objects (containing workflow path properties - // wf:inviterUserName, wf:inviteeUserName, wf:siteShortName, - // and invite id property (from workflow instance id)) + // wf:inviterUserName, wf:inviteeUserName, wf:siteShortName, + // and invite id property (from workflow instance id)) // onto model for each invite workflow task returned by the query for (WorkflowTask workflowTask : wf_invite_tasks) { // get wf:inviterUserName, wf:inviteeUserName, wf:siteShortName // properties from workflow path associated with workflow task - Map pathProperties = this.workflowService.getPathProperties(workflowTask.path.id); - String inviterUserNameProp = (String)pathProperties.get(Invite.WF_PROP_INVITER_USER_NAME); - String inviteeUserNameProp = (String)pathProperties.get(Invite.WF_PROP_INVITEE_USER_NAME); - String siteShortNameProp = (String)pathProperties.get(Invite.WF_PROP_SITE_SHORT_NAME); - - // get workflow instance id (associated with workflow task) to place as "inviteId" onto model + String inviterUserNameProp = (String) workflowTask.properties.get( + QName.createQName(Invite.WF_PROP_INVITER_USER_NAME, this.namespaceService)); + String inviteeUserNameProp = (String) workflowTask.properties.get( + QName.createQName(Invite.WF_PROP_INVITEE_USER_NAME, this.namespaceService)); + String siteShortNameProp = (String) workflowTask.properties.get( + QName.createQName(Invite.WF_PROP_SITE_SHORT_NAME, this.namespaceService)); + + // get workflow instance id (associated with workflow task) to place + // as "inviteId" onto model String workflowId = workflowTask.path.instance.id; - + // create and add InviteInfo to inviteInfoList - InviteInfo inviteInfo = new InviteInfo(inviterUserNameProp, inviteeUserNameProp, siteShortNameProp, workflowId); + InviteInfo inviteInfo = new InviteInfo(inviterUserNameProp, + inviteeUserNameProp, siteShortNameProp, workflowId); inviteInfoList.add(inviteInfo); } - - // put the list of invite infos onto model to be passed onto template for rendering + + // put the list of invite infos onto model to be passed onto template + // for rendering model.put(MODEL_KEY_NAME_INVITES, inviteInfoList); - + return model; } }