diff --git a/config/alfresco/public-rest-context.xml b/config/alfresco/public-rest-context.xml index 1fc9454e3a..fe564240b3 100644 --- a/config/alfresco/public-rest-context.xml +++ b/config/alfresco/public-rest-context.xml @@ -830,7 +830,7 @@ - + @@ -874,7 +874,6 @@ - @@ -899,7 +898,6 @@ - diff --git a/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java index f329f39cf1..e942db9d68 100644 --- a/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java +++ b/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java @@ -61,7 +61,6 @@ import org.alfresco.repo.workflow.WorkflowPropertyHandlerRegistry; import org.alfresco.repo.workflow.WorkflowQNameConverter; import org.alfresco.repo.workflow.activiti.ActivitiConstants; import org.alfresco.repo.workflow.activiti.ActivitiNodeConverter; -import org.alfresco.repo.workflow.activiti.ActivitiScriptNode; import org.alfresco.repo.workflow.activiti.ActivitiTypeConverter; import org.alfresco.repo.workflow.activiti.ActivitiUtil; import org.alfresco.repo.workflow.activiti.properties.ActivitiPropertyConverter; @@ -85,11 +84,7 @@ import org.alfresco.service.cmr.dictionary.AssociationDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.dictionary.TypeDefinition; -import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.ContentData; -import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.namespace.InvalidQNameException; @@ -101,8 +96,6 @@ import org.apache.commons.io.IOUtils; public class ProcessesImpl extends WorkflowRestImpl implements Processes { - protected static final String BPM_PACKAGE = "bpm_package"; - protected static String PROCESS_STATUS_ANY = "any"; protected static String PROCESS_STATUS_ACTIVE = "active"; protected static String PROCESS_STATUS_COMPLETED = "completed"; @@ -130,7 +123,6 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes protected WorkflowPackageImpl workflowPackageComponent; protected ServiceRegistry serviceRegistry; protected AuthorityDAO authorityDAO; - protected NodeService nodeService; protected PersonService personService; protected MessageService messageService; protected String engineId; @@ -163,11 +155,6 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes this.workflowPackageComponent = workflowPackageComponent; } - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - public void setPersonService(PersonService personService) { this.personService = personService; @@ -754,42 +741,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes } validateIfUserAllowedToWorkWithProcess(processId); - - ActivitiScriptNode packageScriptNode = null; - try - { - HistoricVariableInstance variableInstance = activitiProcessEngine.getHistoryService() - .createHistoricVariableInstanceQuery() - .processInstanceId(processId) - .variableName(BPM_PACKAGE) - .singleResult(); - - if (variableInstance != null) - { - packageScriptNode = (ActivitiScriptNode) variableInstance.getValue(); - } - else - { - throw new EntityNotFoundException(processId); - } - } - catch (ActivitiObjectNotFoundException e) - { - throw new EntityNotFoundException(processId); - } - - List page = new ArrayList(); - if (packageScriptNode != null) - { - List documentList = nodeService.getChildAssocs(packageScriptNode.getNodeRef()); - for (ChildAssociationRef childAssociationRef : documentList) - { - Item item = createItemForNodeRef(childAssociationRef.getChildRef()); - page.add(item); - } - } - - return CollectionWithPagingInfo.asPaged(paging, page, false, page.size()); + return getItemsFromProcess(processId, paging); } @Override @@ -805,52 +757,8 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes throw new InvalidArgumentException("itemId is required to get an attached item"); } - NodeRef nodeRef = getNodeRef(itemId); - validateIfUserAllowedToWorkWithProcess(processId); - - ActivitiScriptNode packageScriptNode = null; - try - { - HistoricVariableInstance variableInstance = activitiProcessEngine.getHistoryService() - .createHistoricVariableInstanceQuery() - .processInstanceId(processId) - .variableName(BPM_PACKAGE) - .singleResult(); - - if (variableInstance != null) - { - packageScriptNode = (ActivitiScriptNode) variableInstance.getValue(); - } - else - { - throw new EntityNotFoundException(processId); - } - } - catch (ActivitiObjectNotFoundException e) - { - throw new EntityNotFoundException(processId); - } - - Item item = null; - if (packageScriptNode != null) - { - List documentList = nodeService.getChildAssocs(packageScriptNode.getNodeRef()); - for (ChildAssociationRef childAssociationRef : documentList) - { - if (childAssociationRef.getChildRef().equals(nodeRef)) - { - item = createItemForNodeRef(childAssociationRef.getChildRef()); - break; - } - } - } - - if (item == null) { - throw new EntityNotFoundException(itemId); - } - - return item; + return getItemFromProcess(itemId, processId); } @Override @@ -867,46 +775,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes } validateIfUserAllowedToWorkWithProcess(processId); - - NodeRef nodeRef = getNodeRef(item.getId()); - - ActivitiScriptNode packageScriptNode = null; - try - { - packageScriptNode = (ActivitiScriptNode) activitiProcessEngine.getRuntimeService().getVariable(processId, BPM_PACKAGE); - } - catch (ActivitiObjectNotFoundException e) - { - throw new EntityNotFoundException(processId); - } - - if (packageScriptNode == null) - { - throw new InvalidArgumentException("process doesn't contain a workflow package variable"); - } - - // check if noderef exists - try - { - nodeService.getProperties(nodeRef); - } - catch (Exception e) - { - throw new EntityNotFoundException("item with id " + nodeRef.toString() + " not found"); - } - - try - { - QName workflowPackageItemId = QName.createQName("wpi", nodeRef.toString()); - nodeService.addChild(packageScriptNode.getNodeRef(), nodeRef, - WorkflowModel.ASSOC_PACKAGE_CONTAINS, workflowPackageItemId); - } - catch (Exception e) - { - throw new ApiException("could not add item to process " + e.getMessage(), e); - } - - return item; + return createItemInProcess(item.getId(), processId); } @Override @@ -922,49 +791,8 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes throw new InvalidArgumentException("itemId is required to delete an attached item"); } - NodeRef nodeRef = getNodeRef(itemId); - validateIfUserAllowedToWorkWithProcess(processId); - - ActivitiScriptNode packageScriptNode = null; - try - { - packageScriptNode = (ActivitiScriptNode) activitiProcessEngine.getRuntimeService().getVariable(processId, BPM_PACKAGE); - } - catch (ActivitiObjectNotFoundException e) - { - throw new EntityNotFoundException(processId); - } - - if (packageScriptNode == null) - { - throw new InvalidArgumentException("process doesn't contain a workflow package variable"); - } - - boolean itemIdFoundInPackage = false; - List documentList = nodeService.getChildAssocs(packageScriptNode.getNodeRef()); - for (ChildAssociationRef childAssociationRef : documentList) - { - if (childAssociationRef.getChildRef().equals(nodeRef)) - { - itemIdFoundInPackage = true; - break; - } - } - - if (itemIdFoundInPackage == false) - { - throw new EntityNotFoundException("Item " + itemId + " not found in the process package variable"); - } - - try - { - nodeService.removeChild(packageScriptNode.getNodeRef(), nodeRef); - } - catch (InvalidNodeRefException e) - { - throw new EntityNotFoundException("Item " + itemId + " not found"); - } + deleteItemFromProcess(itemId, processId); } @Override @@ -1233,33 +1061,4 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes processInfo.setProcessDefinitionKey(getLocalProcessDefinitionKey(definitionEntity.getKey())); return processInfo; } - - protected Item createItemForNodeRef(NodeRef nodeRef) { - Map properties = nodeService.getProperties(nodeRef); - Item item = new Item(); - String name = (String) properties.get(ContentModel.PROP_NAME); - String title = (String) properties.get(ContentModel.PROP_TITLE); - String description = (String) properties.get(ContentModel.PROP_DESCRIPTION); - Date createdAt = (Date) properties.get(ContentModel.PROP_CREATED); - String createdBy = (String) properties.get(ContentModel.PROP_CREATOR); - Date modifiedAt = (Date) properties.get(ContentModel.PROP_MODIFIED); - String modifiedBy = (String) properties.get(ContentModel.PROP_MODIFIER); - - ContentData contentData = (ContentData) nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); - - item.setId(nodeRef.getId()); - item.setName(name); - item.setTitle(title); - item.setDescription(description); - item.setCreatedAt(createdAt); - item.setCreatedBy(createdBy); - item.setModifiedAt(modifiedAt); - item.setModifiedBy(modifiedBy); - if (contentData != null) - { - item.setMimeType(contentData.getMimetype()); - item.setSize(contentData.getSize()); - } - return item; - } } \ No newline at end of file diff --git a/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java index 8a4b3a8297..89cff81b40 100644 --- a/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java +++ b/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java @@ -54,7 +54,6 @@ import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.Paging; import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.rest.framework.resource.parameters.where.QueryHelper; -import org.alfresco.rest.workflow.api.Processes; import org.alfresco.rest.workflow.api.Tasks; import org.alfresco.rest.workflow.api.impl.MapBasedQueryWalker.QueryVariableHolder; import org.alfresco.rest.workflow.api.model.FormModelElement; @@ -123,7 +122,6 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks private WorkflowObjectFactory workflowFactory; private WorkflowQNameConverter qNameConverter; private MessageService messageService; - private Processes processes; public void setRestVariableHelper(RestVariableHelper restVariableHelper) { @@ -135,11 +133,6 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks this.messageService = messageService; } - public void setProcesses(Processes processes) - { - this.processes = processes; - } - @Override public CollectionWithPagingInfo getTasks(Parameters parameters) { @@ -634,7 +627,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks throw new InvalidArgumentException("Task id is required"); } - HistoricTaskInstance taskInstance = getValidHistoricTask(taskId, true); + HistoricTaskInstance taskInstance = getValidHistoricTask(taskId); return new Task(taskInstance); } @@ -818,7 +811,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks public CollectionWithPagingInfo getTaskFormModel(String taskId, Paging paging) { // Check if task can be accessed by the current user - HistoricTaskInstance task = getValidHistoricTask(taskId, true); + HistoricTaskInstance task = getValidHistoricTask(taskId); String formKey = task.getFormKey(); // Lookup type definition for the task @@ -830,7 +823,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks public CollectionWithPagingInfo getTaskVariables(String taskId, Paging paging, VariableScope scope) { // Ensure the user is allowed to get variables for the task involved. - HistoricTaskInstance taskInstance = getValidHistoricTask(taskId, true); + HistoricTaskInstance taskInstance = getValidHistoricTask(taskId); String formKey = taskInstance.getFormKey(); // Based on the scope, right variables are queried @@ -878,13 +871,13 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks @Override public TaskVariable updateTaskVariable(String taskId, TaskVariable taskVariable) { - org.activiti.engine.task.Task taskInstance = getValidTask(taskId, true); + org.activiti.engine.task.Task taskInstance = getValidTask(taskId); return updateVariableInTask(taskId, taskInstance, taskVariable); } public List updateTaskVariables(String taskId, List variables) { - org.activiti.engine.task.Task taskInstance = getValidTask(taskId, true); + org.activiti.engine.task.Task taskInstance = getValidTask(taskId); List updatedVariables = new ArrayList(); if (variables != null) { @@ -1003,7 +996,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks } // Fetch task to check if user is authorized to perform the delete - getValidTask(taskId, true); + getValidTask(taskId); // Check if variable is present on the scope if (activitiProcessEngine.getTaskService().hasVariableLocal(taskId, variableName) == false) @@ -1017,7 +1010,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks public CollectionWithPagingInfo getTaskCandidates(String taskId, Paging paging) { // Fetch task to check if user is authorized to perform the delete - getValidTask(taskId, true); + getValidTask(taskId); List links = activitiProcessEngine.getTaskService().getIdentityLinksForTask(taskId); List page = new ArrayList(); @@ -1038,49 +1031,49 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks @Override public Item createItem(String taskId, Item item) { - org.activiti.engine.task.Task task = getValidTask(taskId, false); + org.activiti.engine.task.Task task = getValidTask(taskId); if (task.getProcessInstanceId() == null) { throw new UnsupportedResourceOperationException("Task is not part of process, no items available."); } - return processes.createItem(task.getProcessInstanceId(), item); + return createItemInProcess(item.getId(), task.getProcessInstanceId()); } @Override public void deleteItem(String taskId, String itemId) { - org.activiti.engine.task.Task task = getValidTask(taskId, false); - - if(task.getProcessInstanceId() == null) - { - throw new UnsupportedResourceOperationException("Task is not part of process, no items available."); - } - processes.deleteItem(task.getProcessInstanceId(), itemId); - } - - @Override - public Item getItem(String taskId, String itemId) - { - HistoricTaskInstance task = getValidHistoricTask(taskId, true); + org.activiti.engine.task.Task task = getValidTask(taskId); if (task.getProcessInstanceId() == null) { throw new UnsupportedResourceOperationException("Task is not part of process, no items available."); } - return processes.getItem(task.getProcessInstanceId(), itemId); + deleteItemFromProcess(itemId, task.getProcessInstanceId()); + } + + @Override + public Item getItem(String taskId, String itemId) + { + HistoricTaskInstance task = getValidHistoricTask(taskId); + + if (task.getProcessInstanceId() == null) + { + throw new UnsupportedResourceOperationException("Task is not part of process, no items available."); + } + return getItemFromProcess(itemId, task.getProcessInstanceId()); } @Override public CollectionWithPagingInfo getItems(String taskId, Paging paging) { - HistoricTaskInstance task = getValidHistoricTask(taskId, true); + HistoricTaskInstance task = getValidHistoricTask(taskId); - if(task.getProcessInstanceId() == null) + if (task.getProcessInstanceId() == null) { throw new UnsupportedResourceOperationException("Task is not part of process, no items available."); } - return processes.getItems(task.getProcessInstanceId(), paging); + return getItemsFromProcess(task.getProcessInstanceId(), paging); } protected String getFormResourceKey(final org.activiti.engine.task.Task task) @@ -1175,7 +1168,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks * @throws EntityNotFoundException when the task was not found * @throws PermissionDeniedException when the current logged in user isn't allowed to access task. */ - protected HistoricTaskInstance getValidHistoricTask(String taskId, boolean validIfClaimable) + protected HistoricTaskInstance getValidHistoricTask(String taskId) { HistoricTaskInstanceQuery query = activitiProcessEngine.getHistoryService() .createHistoricTaskInstanceQuery() @@ -1214,19 +1207,15 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks else { boolean isTaskClaimable = false; - - if (validIfClaimable) + if (taskInstance.getEndTime() == null) { - if (taskInstance.getEndTime() == null) - { - // Task is not yet finished, so potentially claimable. If user is part of a "candidateGroup", the task is accessible to the - // user regardless of not being involved/owner/assignee - isTaskClaimable = activitiProcessEngine.getTaskService() - .createTaskQuery() - .taskCandidateGroupIn(new ArrayList(authorityService.getAuthoritiesForUser(AuthenticationUtil.getRunAsUser()))) - .taskId(taskId) - .count() == 1; - } + // Task is not yet finished, so potentially claimable. If user is part of a "candidateGroup", the task is accessible to the + // user regardless of not being involved/owner/assignee + isTaskClaimable = activitiProcessEngine.getTaskService() + .createTaskQuery() + .taskCandidateGroupIn(new ArrayList(authorityService.getAuthoritiesForUser(AuthenticationUtil.getRunAsUser()))) + .taskId(taskId) + .count() == 1; } if (isTaskClaimable == false) @@ -1246,7 +1235,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks * @throws EntityNotFoundException when the task was not found * @throws PermissionDeniedException when the current logged in user isn't allowed to access task. */ - protected org.activiti.engine.task.Task getValidTask(String taskId, boolean validIfClaimable) + protected org.activiti.engine.task.Task getValidTask(String taskId) { if (taskId == null) { @@ -1289,18 +1278,13 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks } else { - boolean isTaskClaimable = false; - - if (validIfClaimable) - { - // Task is not yet finished, so potentially claimable. If user is part of a "candidateGroup", the task is accessible to the - // user regardless of not being involved/owner/assignee - isTaskClaimable = activitiProcessEngine.getTaskService() - .createTaskQuery() - .taskCandidateGroupIn(new ArrayList(authorityService.getAuthoritiesForUser(AuthenticationUtil.getRunAsUser()))) - .taskId(taskId) - .count() == 1; - } + // Task is not yet finished, so potentially claimable. If user is part of a "candidateGroup", the task is accessible to the + // user regardless of not being involved/owner/assignee + boolean isTaskClaimable = activitiProcessEngine.getTaskService() + .createTaskQuery() + .taskCandidateGroupIn(new ArrayList(authorityService.getAuthoritiesForUser(AuthenticationUtil.getRunAsUser()))) + .taskId(taskId) + .count() == 1; if (isTaskClaimable == false) { diff --git a/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java index 9a0c6c47f3..620610a16b 100644 --- a/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java +++ b/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java @@ -1,5 +1,6 @@ package org.alfresco.rest.workflow.api.impl; +import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -11,6 +12,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import org.activiti.engine.ActivitiObjectNotFoundException; import org.activiti.engine.ProcessEngine; import org.activiti.engine.history.HistoricTaskInstance; import org.activiti.engine.history.HistoricTaskInstanceQuery; @@ -28,8 +30,10 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.tenant.TenantUtil; import org.alfresco.repo.workflow.WorkflowConstants; +import org.alfresco.repo.workflow.WorkflowModel; import org.alfresco.repo.workflow.activiti.ActivitiConstants; import org.alfresco.repo.workflow.activiti.ActivitiScriptNode; +import org.alfresco.rest.framework.core.exceptions.ApiException; import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException; @@ -37,6 +41,7 @@ import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.Paging; import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.rest.workflow.api.model.FormModelElement; +import org.alfresco.rest.workflow.api.model.Item; import org.alfresco.service.cmr.dictionary.AssociationDefinition; import org.alfresco.service.cmr.dictionary.ClassDefinition; import org.alfresco.service.cmr.dictionary.Constraint; @@ -44,7 +49,11 @@ import org.alfresco.service.cmr.dictionary.ConstraintDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.dictionary.TypeDefinition; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.namespace.NamespaceService; @@ -60,10 +69,13 @@ import org.apache.commons.beanutils.ConvertUtils; */ public class WorkflowRestImpl { + protected static final String BPM_PACKAGE = "bpm_package"; + protected TenantService tenantService; protected AuthorityService authorityService; protected NamespaceService namespaceService; protected DictionaryService dictionaryService; + protected NodeService nodeService; protected ProcessEngine activitiProcessEngine; protected boolean deployWorkflowsInTenant; protected List excludeModelTypes = new ArrayList(Arrays.asList("bpm_priority", "bpm_description", "bpm_dueDate")); @@ -96,6 +108,11 @@ public class WorkflowRestImpl this.dictionaryService = dictionaryService; } + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + public void setActivitiProcessEngine(ProcessEngine activitiProcessEngine) { this.activitiProcessEngine = activitiProcessEngine; @@ -123,6 +140,192 @@ public class WorkflowRestImpl return nodeRef; } + /** + * Get all items from the process package variable + */ + public CollectionWithPagingInfo getItemsFromProcess(String processId, Paging paging) + { + ActivitiScriptNode packageScriptNode = null; + try + { + HistoricVariableInstance variableInstance = activitiProcessEngine.getHistoryService() + .createHistoricVariableInstanceQuery() + .processInstanceId(processId) + .variableName(BPM_PACKAGE) + .singleResult(); + + if (variableInstance != null) + { + packageScriptNode = (ActivitiScriptNode) variableInstance.getValue(); + } + else + { + throw new EntityNotFoundException(processId); + } + } + catch (ActivitiObjectNotFoundException e) + { + throw new EntityNotFoundException(processId); + } + + List page = new ArrayList(); + if (packageScriptNode != null) + { + List documentList = nodeService.getChildAssocs(packageScriptNode.getNodeRef()); + for (ChildAssociationRef childAssociationRef : documentList) + { + Item item = createItemForNodeRef(childAssociationRef.getChildRef()); + page.add(item); + } + } + + return CollectionWithPagingInfo.asPaged(paging, page, false, page.size()); + } + + /** + * Get an item from the process package variable + */ + public Item getItemFromProcess(String itemId, String processId) + { + NodeRef nodeRef = getNodeRef(itemId); + ActivitiScriptNode packageScriptNode = null; + try + { + HistoricVariableInstance variableInstance = activitiProcessEngine.getHistoryService() + .createHistoricVariableInstanceQuery() + .processInstanceId(processId) + .variableName(BPM_PACKAGE) + .singleResult(); + + if (variableInstance != null) + { + packageScriptNode = (ActivitiScriptNode) variableInstance.getValue(); + } + else + { + throw new EntityNotFoundException(processId); + } + } + catch (ActivitiObjectNotFoundException e) + { + throw new EntityNotFoundException(processId); + } + + Item item = null; + if (packageScriptNode != null) + { + List documentList = nodeService.getChildAssocs(packageScriptNode.getNodeRef()); + for (ChildAssociationRef childAssociationRef : documentList) + { + if (childAssociationRef.getChildRef().equals(nodeRef)) + { + item = createItemForNodeRef(childAssociationRef.getChildRef()); + break; + } + } + } + + if (item == null) { + throw new EntityNotFoundException(itemId); + } + + return item; + } + + /** + * Create a new item in the process package variable + */ + public Item createItemInProcess(String itemId, String processId) + { + NodeRef nodeRef = getNodeRef(itemId); + + ActivitiScriptNode packageScriptNode = null; + try + { + packageScriptNode = (ActivitiScriptNode) activitiProcessEngine.getRuntimeService().getVariable(processId, BPM_PACKAGE); + } + catch (ActivitiObjectNotFoundException e) + { + throw new EntityNotFoundException(processId); + } + + if (packageScriptNode == null) + { + throw new InvalidArgumentException("process doesn't contain a workflow package variable"); + } + + // check if noderef exists + try + { + nodeService.getProperties(nodeRef); + } + catch (Exception e) + { + throw new EntityNotFoundException("item with id " + nodeRef.toString() + " not found"); + } + + try + { + QName workflowPackageItemId = QName.createQName("wpi", nodeRef.toString()); + nodeService.addChild(packageScriptNode.getNodeRef(), nodeRef, + WorkflowModel.ASSOC_PACKAGE_CONTAINS, workflowPackageItemId); + } + catch (Exception e) + { + throw new ApiException("could not add item to process " + e.getMessage(), e); + } + + Item responseItem = createItemForNodeRef(nodeRef); + return responseItem; + } + + /** + * Delete an item from the process package variable + */ + public void deleteItemFromProcess(String itemId, String processId) + { + NodeRef nodeRef = getNodeRef(itemId); + ActivitiScriptNode packageScriptNode = null; + try + { + packageScriptNode = (ActivitiScriptNode) activitiProcessEngine.getRuntimeService().getVariable(processId, BPM_PACKAGE); + } + catch (ActivitiObjectNotFoundException e) + { + throw new EntityNotFoundException(processId); + } + + if (packageScriptNode == null) + { + throw new InvalidArgumentException("process doesn't contain a workflow package variable"); + } + + boolean itemIdFoundInPackage = false; + List documentList = nodeService.getChildAssocs(packageScriptNode.getNodeRef()); + for (ChildAssociationRef childAssociationRef : documentList) + { + if (childAssociationRef.getChildRef().equals(nodeRef)) + { + itemIdFoundInPackage = true; + break; + } + } + + if (itemIdFoundInPackage == false) + { + throw new EntityNotFoundException("Item " + itemId + " not found in the process package variable"); + } + + try + { + nodeService.removeChild(packageScriptNode.getNodeRef(), nodeRef); + } + catch (InvalidNodeRefException e) + { + throw new EntityNotFoundException("Item " + itemId + " not found"); + } + } + /** * Get the process definition from the cache if available * @@ -342,4 +545,33 @@ public class WorkflowRestImpl return variableInstances; } + + protected Item createItemForNodeRef(NodeRef nodeRef) { + Map properties = nodeService.getProperties(nodeRef); + Item item = new Item(); + String name = (String) properties.get(ContentModel.PROP_NAME); + String title = (String) properties.get(ContentModel.PROP_TITLE); + String description = (String) properties.get(ContentModel.PROP_DESCRIPTION); + Date createdAt = (Date) properties.get(ContentModel.PROP_CREATED); + String createdBy = (String) properties.get(ContentModel.PROP_CREATOR); + Date modifiedAt = (Date) properties.get(ContentModel.PROP_MODIFIED); + String modifiedBy = (String) properties.get(ContentModel.PROP_MODIFIER); + + ContentData contentData = (ContentData) nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); + + item.setId(nodeRef.getId()); + item.setName(name); + item.setTitle(title); + item.setDescription(description); + item.setCreatedAt(createdAt); + item.setCreatedBy(createdBy); + item.setModifiedAt(modifiedAt); + item.setModifiedBy(modifiedBy); + if (contentData != null) + { + item.setMimeType(contentData.getMimetype()); + item.setSize(contentData.getSize()); + } + return item; + } } diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/DeploymentWorkflowApiTest.java b/source/test-java/org/alfresco/rest/workflow/api/tests/DeploymentWorkflowApiTest.java index 6000aad3eb..3bfaa44125 100644 --- a/source/test-java/org/alfresco/rest/workflow/api/tests/DeploymentWorkflowApiTest.java +++ b/source/test-java/org/alfresco/rest/workflow/api/tests/DeploymentWorkflowApiTest.java @@ -25,10 +25,14 @@ import static org.junit.Assert.fail; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.tenant.TenantUtil; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.rest.api.tests.AbstractTestFixture; +import org.alfresco.rest.api.tests.RepoService.TestNetwork; import org.alfresco.rest.api.tests.client.PublicApiClient.ListResponse; import org.alfresco.rest.api.tests.client.PublicApiException; import org.alfresco.rest.api.tests.client.RequestContext; @@ -118,40 +122,53 @@ public class DeploymentWorkflowApiTest extends EnterpriseWorkflowTestApi assertEquals(activitiDeployment.getDeploymentTime(), adhocDeployment.getDeployedAt()); } -// @Test -// public void testGetDeploymentsEmpty() throws Exception -// { -// // Create a new test-network, not added to the test-fixture to prevent being used -// // in other tests -// String networkName = AbstractTestFixture.TEST_DOMAIN_PREFIX + UUID.randomUUID(); -// TestNetwork testNetwork = repoService.createNetworkWithAlias(networkName, true); -// testNetwork.create(); -// -// // Delete all deployments in the network -// List deployments = activitiProcessEngine.getRepositoryService() -// .createDeploymentQuery() -// .processDefinitionKeyLike("@" + networkName + "@") -// .list(); -// -// for(org.activiti.engine.repository.Deployment deployment : deployments) { -// activitiProcessEngine.getRepositoryService().deleteDeployment(deployment.getId(), true); -// } -// -// // Fetch deployments using tenant-admin -// String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + networkName; -// publicApiClient.setRequestContext(new RequestContext(TenantUtil.DEFAULT_TENANT, tenantAdmin)); -// -// DeploymentsClient deploymentsClient = publicApiClient.deploymentsClient(); -// -// ListResponse deploymentResponse = deploymentsClient.getDeployments(); -// assertEquals(0, deploymentResponse.getList().size()); -// } + @Test + public void testGetDeploymentsEmpty() throws Exception + { + // Create a new test-network, not added to the test-fixture to prevent being used + // in other tests + String networkName = AbstractTestFixture.TEST_DOMAIN_PREFIX + "999"; + final TestNetwork testNetwork = repoService.createNetworkWithAlias(networkName, true); + transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @SuppressWarnings("synthetic-access") + public Void execute() throws Throwable + { + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); + + testNetwork.create(); + + return null; + } + }, false, true); + + // Delete all deployments in the network + List deployments = activitiProcessEngine.getRepositoryService() + .createDeploymentQuery() + .processDefinitionKeyLike("@" + testNetwork.getId() + "@%") + .list(); + + for(org.activiti.engine.repository.Deployment deployment : deployments) + { + activitiProcessEngine.getRepositoryService().deleteDeployment(deployment.getId(), true); + } + + // Fetch deployments using tenant-admin + String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + testNetwork.getId(); + publicApiClient.setRequestContext(new RequestContext(testNetwork.getId(), tenantAdmin)); + + DeploymentsClient deploymentsClient = publicApiClient.deploymentsClient(); + + ListResponse deploymentResponse = deploymentsClient.getDeployments(); + assertEquals(0, deploymentResponse.getList().size()); + } @Test public void testGetDeploymentById() throws Exception { // Use admin-user for tenant RequestContext requestContext = initApiClientWithTestUser(); + String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + requestContext.getNetworkId(); publicApiClient.setRequestContext(new RequestContext(TenantUtil.DEFAULT_TENANT, tenantAdmin)); @@ -174,6 +191,28 @@ public class DeploymentWorkflowApiTest extends EnterpriseWorkflowTestApi assertEquals(activitiDeployment.getCategory(), deployment.getCategory()); assertEquals(activitiDeployment.getName(), deployment.getName()); assertEquals(activitiDeployment.getDeploymentTime(), deployment.getDeployedAt()); + + try + { + deploymentsClient.findDeploymentById("fakeid"); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(404, e.getHttpResponse().getStatusCode()); + } + + // get deployment with default user + try + { + publicApiClient.setRequestContext(requestContext); + deploymentsClient.findDeploymentById(activitiDeployment.getId()); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(403, e.getHttpResponse().getStatusCode()); + } } protected String createProcessDefinitionKey(String key, RequestContext requestContext) { diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessDefinitionWorkflowApiTest.java b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessDefinitionWorkflowApiTest.java index 79c7dadeed..a62a30a42f 100644 --- a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessDefinitionWorkflowApiTest.java +++ b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessDefinitionWorkflowApiTest.java @@ -175,12 +175,30 @@ public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi assertTrue(processDefinitionMap.containsKey("activitiAdhoc")); assertEquals(1, processDefinitionMap.size()); + // Use AND operator + processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(category = 'http://alfresco.org' AND name = 'Adhoc Activiti Process')"); + assertTrue(processDefinitionMap.containsKey("activitiAdhoc")); + assertEquals(1, processDefinitionMap.size()); + + // Use OR operator + try + { + processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(category = 'http://alfresco.org' OR name = 'Adhoc Activiti Process')"); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(400, e.getHttpResponse().getStatusCode()); + } } @Test public void testGetProcessDefinitionById() throws Exception { RequestContext requestContext = initApiClientWithTestUser(); + + String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + requestContext.getNetworkId(); + RequestContext adminContext = new RequestContext(requestContext.getNetworkId(), tenantAdmin); String adhocKey = createProcessDefinitionKey("activitiAdhoc", requestContext); org.activiti.engine.repository.ProcessDefinition activitiDefinition = activitiProcessEngine.getRepositoryService() @@ -204,6 +222,15 @@ public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi assertEquals(activitiDefinition.getVersion(), adhocDefinition.getVersion()); assertEquals(((ProcessDefinitionEntity) activitiDefinition).isGraphicalNotationDefined(), adhocDefinition.isGraphicNotationDefined()); assertEquals("wf:submitAdhocTask", adhocDefinition.getStartFormResourceKey()); + + // get process definition with admin + publicApiClient.setRequestContext(adminContext); + adhocDefinition = processDefinitionsClient.findProcessDefinitionById(activitiDefinition.getId()); + assertNotNull(adhocDefinition); + + // Check fields of a resulting process-definition + assertEquals(activitiDefinition.getId(), adhocDefinition.getId()); + assertEquals("activitiAdhoc", adhocDefinition.getKey()); } @Test @@ -227,6 +254,10 @@ public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi public void testGetProcessDefinitionStartModel() throws Exception { RequestContext requestContext = initApiClientWithTestUser(); + + String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + requestContext.getNetworkId(); + RequestContext adminContext = new RequestContext(requestContext.getNetworkId(), tenantAdmin); + ProcessDefinitionsClient processDefinitionsClient = publicApiClient.processDefinitionsClient(); String adhocKey = createProcessDefinitionKey("activitiAdhoc", requestContext); @@ -322,6 +353,43 @@ public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi assertTrue(allowedValues.contains("On Hold")); assertTrue(allowedValues.contains("Cancelled")); assertTrue(allowedValues.contains("Completed")); + + // get start form model with admin + publicApiClient.setRequestContext(adminContext); + model = processDefinitionsClient.findStartFormModel(activitiDefinition.getId()); + assertNotNull(model); + + entries = (JSONArray) model.get("entries"); + assertNotNull(entries); + + // Add all entries to a map, to make lookup easier + modelFieldsByName = new HashMap(); + for(int i=0; i() + try { - @Override - public Void doWork() throws Exception + // Complete the adhoc task + final Task completedTask = activitiProcessEngine.getTaskService().createTaskQuery() + .processInstanceId(processInstance.getId()).singleResult(); + + assertNotNull(completedTask); + + String anotherUserId = UUID.randomUUID().toString(); + + Calendar completedTaskDue = Calendar.getInstance(); + completedTaskDue.add(Calendar.HOUR, 1); + completedTaskDue.set(Calendar.MILLISECOND, 0); + completedTask.setOwner(requestContext.getRunAsUser()); + completedTask.setPriority(3); + completedTask.setDueDate(completedTaskDue.getTime()); + completedTask.setAssignee(anotherUserId); + completedTask.setName("Another task name"); + completedTask.setDescription("This is another test description"); + activitiProcessEngine.getTaskService().saveTask(completedTask); + + // Complete task in correct tenant + TenantUtil.runAsUserTenant(new TenantRunAsWork() { - activitiProcessEngine.getTaskService().complete(completedTask.getId()); - return null; + @Override + public Void doWork() throws Exception + { + activitiProcessEngine.getTaskService().complete(completedTask.getId()); + return null; + } + }, requestContext.getRunAsUser(), requestContext.getNetworkId()); + + // Active task is the second task in the adhoc-process (Verify task completed) + Task activeTask = activitiProcessEngine.getTaskService().createTaskQuery() + .processInstanceId(processInstance.getId()).singleResult(); + assertNotNull(activeTask); + + Calendar activeTaskDue = Calendar.getInstance(); + + activeTaskDue.set(Calendar.MILLISECOND, 0); + activeTask.setDueDate(activeTaskDue.getTime()); + activeTask.setName("Task name"); + activeTask.setDescription("This is a test description"); + activeTask.setOwner(requestContext.getRunAsUser()); + activeTask.setPriority(2); + activeTask.setAssignee(requestContext.getRunAsUser()); + activitiProcessEngine.getTaskService().saveTask(activeTask); + activitiProcessEngine.getTaskService().addCandidateUser(activeTask.getId(), anotherUserId); + activitiProcessEngine.getTaskService().addCandidateGroup(activeTask.getId(), "sales"); + activitiProcessEngine.getTaskService().setVariableLocal(activeTask.getId(), "numberVar", 10); + + TasksClient tasksClient = publicApiClient.tasksClient(); + + // Test status filtering - active + Map params = new HashMap(); + params.put("where", "(status = 'active' AND processId = '" + processInstance.getId() + "')"); + assertTasksPresentInTaskQuery(params, tasksClient, false, activeTask.getId()); + + // Test status filtering - completed + params.clear(); + params.put("where", "(status = 'completed' AND processId = '" + processInstance.getId() + "')"); + assertTasksPresentInTaskQuery(params, tasksClient, false, completedTask.getId()); + + // Test status filtering - any + params.clear(); + params.put("where", "(status = 'any' AND processId = '" + processInstance.getId() + "')"); + assertTasksPresentInTaskQuery(params, tasksClient, false, activeTask.getId(), completedTask.getId()); + + // Test status filtering - no value should default to 'active' + params.clear(); + params.put("where", "(processId = '" + processInstance.getId() + "')"); + assertTasksPresentInTaskQuery(params, tasksClient, false, activeTask.getId()); + + // Test status filtering - illegal status + params.clear(); + params.put("where", "(status = 'alfrescorocks')"); + try + { + tasksClient.findTasks(params); + fail("Exception expected"); } - }, requestContext.getRunAsUser(), requestContext.getNetworkId()); - - // Active task is the second task in the adhoc-process (Verify task completed) - Task activeTask = activitiProcessEngine.getTaskService().createTaskQuery() - .processInstanceId(processInstance.getId()).singleResult(); - assertNotNull(activeTask); - - Calendar activeTaskDue = Calendar.getInstance(); - - activeTaskDue.set(Calendar.MILLISECOND, 0); - activeTask.setDueDate(activeTaskDue.getTime()); - activeTask.setName("Task name"); - activeTask.setDescription("This is a test description"); - activeTask.setOwner(requestContext.getRunAsUser()); - activeTask.setPriority(2); - activeTask.setAssignee(requestContext.getRunAsUser()); - activitiProcessEngine.getTaskService().saveTask(activeTask); - activitiProcessEngine.getTaskService().addCandidateUser(activeTask.getId(), anotherUserId); - activitiProcessEngine.getTaskService().addCandidateGroup(activeTask.getId(), "sales"); - activitiProcessEngine.getTaskService().setVariableLocal(activeTask.getId(), "numberVar", 10); - - TasksClient tasksClient = publicApiClient.tasksClient(); - - // Test status filtering - active - Map params = new HashMap(); - params.put("where", "(status = 'active' AND processId = '" + processInstance.getId() + "')"); - assertTasksPresentInTaskQuery(params, tasksClient, false, activeTask.getId()); - - // Test status filtering - completed - params.clear(); - params.put("where", "(status = 'completed' AND processId = '" + processInstance.getId() + "')"); - assertTasksPresentInTaskQuery(params, tasksClient, false, completedTask.getId()); - - // Test status filtering - any - params.clear(); - params.put("where", "(status = 'any' AND processId = '" + processInstance.getId() + "')"); - assertTasksPresentInTaskQuery(params, tasksClient, false, activeTask.getId(), completedTask.getId()); - - // Test status filtering - no value should default to 'active' - params.clear(); - params.put("where", "(processId = '" + processInstance.getId() + "')"); - assertTasksPresentInTaskQuery(params, tasksClient, false, activeTask.getId()); - - // Test status filtering - illegal status - params.clear(); - params.put("where", "(status = 'alfrescorocks')"); - try - { - tasksClient.findTasks(params); - fail("Exception expected"); + catch(PublicApiException expected) + { + assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode()); + assertErrorSummary("Invalid status parameter: alfrescorocks", expected.getHttpResponse()); + } + + // Next, we test all filtering for active, complete and any tasks + + // Assignee filtering + params.clear(); + params.put("where", "(status = 'active' AND assignee = '" + requestContext.getRunAsUser() + "')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.put("where", "(status = 'completed' AND assignee = '" + anotherUserId + "')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + params.put("where", "(status = 'any' AND assignee = '" + anotherUserId + "')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + // Owner filtering + params.clear(); + params.put("where", "(status = 'active' AND owner = '" + requestContext.getRunAsUser() + "')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.put("where", "(status = 'completed' AND owner = '" + requestContext.getRunAsUser() + "')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + params.put("where", "(status = 'any' AND owner = '" + requestContext.getRunAsUser() + "')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId(), completedTask.getId()); + + // Candidate user filtering, only available for active tasks. When used with completed/any 400 is returned + params.clear(); + params.put("where", "(status = 'active' AND candidateUser = '" + anotherUserId + "')"); + // No tasks expected since assignee is set + assertEquals(0L, getResultSizeForTaskQuery(params, tasksClient)); + + // Clear assignee + activitiProcessEngine.getTaskService().setAssignee(activeTask.getId(), null); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.clear(); + params.put("where", "(status = 'completed' AND candidateUser = '" + anotherUserId + "')"); + try + { + tasksClient.findTasks(params); + fail("Exception expected"); + } + catch(PublicApiException expected) + { + assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode()); + assertErrorSummary("Filtering on candidateUser is only allowed in combination with status-parameter 'active'", expected.getHttpResponse()); + } + + params.clear(); + params.put("where", "(status = 'any' AND candidateUser = '" + anotherUserId + "')"); + try + { + tasksClient.findTasks(params); + fail("Exception expected"); + } + catch(PublicApiException expected) + { + assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode()); + assertErrorSummary("Filtering on candidateUser is only allowed in combination with status-parameter 'active'", expected.getHttpResponse()); + } + + // Candidate group filtering, only available for active tasks. When used with completed/any 400 is returned + params.clear(); + params.put("where", "(status = 'active' AND candidateGroup = 'sales' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.clear(); + params.put("where", "(status = 'completed' AND candidateGroup = 'sales' AND processId='" + processInstance.getId() +"')"); + try + { + tasksClient.findTasks(params); + fail("Exception expected"); + } + catch (PublicApiException expected) + { + assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode()); + assertErrorSummary("Filtering on candidateGroup is only allowed in combination with status-parameter 'active'", expected.getHttpResponse()); + } + + params.clear(); + params.put("where", "(status = 'any' AND candidateGroup = 'sales' AND processId='" + processInstance.getId() +"')"); + try + { + tasksClient.findTasks(params); + fail("Exception expected"); + } + catch (PublicApiException expected) + { + assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode()); + assertErrorSummary("Filtering on candidateGroup is only allowed in combination with status-parameter 'active'", expected.getHttpResponse()); + } + + // Name filtering + params.clear(); + params.put("where", "(status = 'active' AND name = 'Task name' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.clear(); + params.put("where", "(status = 'completed' AND name = 'Another task name' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + params.clear(); + params.put("where", "(status = 'any' AND name = 'Another task name' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + // Description filtering + params.clear(); + params.put("where", "(status = 'active' AND description = 'This is a test description' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.clear(); + params.put("where", "(status = 'completed' AND description = 'This is another test description' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + params.clear(); + params.put("where", "(status = 'any' AND description = 'This is another test description' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + // Priority filtering + params.clear(); + params.put("where", "(status = 'active' AND priority = 2 AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.put("where", "(status = 'completed' AND priority = 3 AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + params.put("where", "(status = 'any' AND priority = 3 AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + // Process instance business-key filtering + params.clear(); + params.put("where", "(status = 'active' AND processBusinessKey = '" + businessKey + "')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.clear(); + params.put("where", "(status = 'completed' AND processBusinessKey = '" + businessKey + "')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + params.clear(); + params.put("where", "(status = 'any' AND processBusinessKey = '" + businessKey + "')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId(), activeTask.getId()); + + // Activity definition id filtering + params.clear(); + params.put("where", "(status = 'active' AND activityDefinitionId = 'verifyTaskDone' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.clear(); + params.put("where", "(status = 'completed' AND activityDefinitionId = 'adhocTask' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + params.clear(); + params.put("where", "(status = 'any' AND activityDefinitionId = 'adhocTask' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + // Process definition id filtering + params.clear(); + params.put("where", "(status = 'active' AND processDefinitionId = '" + processInstance.getProcessDefinitionId() + + "' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.clear(); + params.put("where", "(status = 'completed' AND processDefinitionId = '" + processInstance.getProcessDefinitionId() + + "' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + params.clear(); + params.put("where", "(status = 'any' AND processDefinitionId = '" + processInstance.getProcessDefinitionId() + + "' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId(), completedTask.getId()); + + // Process definition name filerting + params.clear(); + params.put("where", "(status = 'active' AND processDefinitionName = 'Adhoc Activiti Process' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.clear(); + params.put("where", "(status = 'completed' AND processDefinitionName = 'Adhoc Activiti Process' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + params.clear(); + params.put("where", "(status = 'any' AND processDefinitionName = 'Adhoc Activiti Process' AND processId='" + processInstance.getId() +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId(), completedTask.getId()); + + // Due date filtering + params.clear(); + params.put("where", "(status = 'active' AND dueAt = '" + ISO8601DateFormat.format(activeTaskDue.getTime()) +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.clear(); + params.put("where", "(status = 'completed' AND dueAt = '" + ISO8601DateFormat.format(completedTaskDue.getTime()) +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + params.clear(); + params.put("where", "(status = 'any' AND dueAt = '" + ISO8601DateFormat.format(completedTaskDue.getTime()) +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + // Started filtering + params.clear(); + params.put("where", "(status = 'active' AND startedAt = '" + ISO8601DateFormat.format(taskCreated.getTime()) +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.clear(); + params.put("where", "(status = 'completed' AND startedAt = '" + ISO8601DateFormat.format(taskCreated.getTime()) +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); + + params.clear(); + params.put("where", "(status = 'any' AND startedAt = '" + ISO8601DateFormat.format(taskCreated.getTime()) +"')"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId(), activeTask.getId()); + + params.clear(); + params.put("where", "(variables/numberVar > 'd:int 5')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.clear(); + params.put("where", "(variables/numberVar > 'd:int 10')"); + assertEquals(0, getResultSizeForTaskQuery(params, tasksClient)); + + params.clear(); + params.put("where", "(variables/numberVar >= 'd_int 10')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.clear(); + params.put("where", "(variables/numberVar >= 'd:int 11')"); + assertEquals(0, getResultSizeForTaskQuery(params, tasksClient)); + + params.clear(); + params.put("where", "(variables/numberVar <= 'd:int 10')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.clear(); + params.put("where", "(variables/numberVar <= 'd:int 9')"); + assertEquals(0, getResultSizeForTaskQuery(params, tasksClient)); + + params.clear(); + params.put("where", "(variables/numberVar < 'd_int 15')"); + assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); + + params.clear(); + params.put("where", "(variables/numberVar < 'd:int 10')"); + assertEquals(0, getResultSizeForTaskQuery(params, tasksClient)); } - catch(PublicApiException expected) + finally { - assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode()); - assertErrorSummary("Invalid status parameter: alfrescorocks", expected.getHttpResponse()); + cleanupProcessInstance(processInstance); } - - // Next, we test all filtering for active, complete and any tasks - - // Assignee filtering - params.clear(); - params.put("where", "(status = 'active' AND assignee = '" + requestContext.getRunAsUser() + "')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.put("where", "(status = 'completed' AND assignee = '" + anotherUserId + "')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - params.put("where", "(status = 'any' AND assignee = '" + anotherUserId + "')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - // Owner filtering - params.clear(); - params.put("where", "(status = 'active' AND owner = '" + requestContext.getRunAsUser() + "')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.put("where", "(status = 'completed' AND owner = '" + requestContext.getRunAsUser() + "')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - params.put("where", "(status = 'any' AND owner = '" + requestContext.getRunAsUser() + "')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId(), completedTask.getId()); - - // Candidate user filtering, only available for active tasks. When used with completed/any 400 is returned - params.clear(); - params.put("where", "(status = 'active' AND candidateUser = '" + anotherUserId + "')"); - // No tasks expected since assignee is set - assertEquals(0L, getResultSizeForTaskQuery(params, tasksClient)); - - // Clear assignee - activitiProcessEngine.getTaskService().setAssignee(activeTask.getId(), null); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.clear(); - params.put("where", "(status = 'completed' AND candidateUser = '" + anotherUserId + "')"); - try - { - tasksClient.findTasks(params); - fail("Exception expected"); - } - catch(PublicApiException expected) - { - assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode()); - assertErrorSummary("Filtering on candidateUser is only allowed in combination with status-parameter 'active'", expected.getHttpResponse()); - } - - params.clear(); - params.put("where", "(status = 'any' AND candidateUser = '" + anotherUserId + "')"); - try - { - tasksClient.findTasks(params); - fail("Exception expected"); - } - catch(PublicApiException expected) - { - assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode()); - assertErrorSummary("Filtering on candidateUser is only allowed in combination with status-parameter 'active'", expected.getHttpResponse()); - } - - // Candidate group filtering, only available for active tasks. When used with completed/any 400 is returned - params.clear(); - params.put("where", "(status = 'active' AND candidateGroup = 'sales' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.clear(); - params.put("where", "(status = 'completed' AND candidateGroup = 'sales' AND processId='" + processInstance.getId() +"')"); - try - { - tasksClient.findTasks(params); - fail("Exception expected"); - } - catch(PublicApiException expected) - { - assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode()); - assertErrorSummary("Filtering on candidateGroup is only allowed in combination with status-parameter 'active'", expected.getHttpResponse()); - } - - params.clear(); - params.put("where", "(status = 'any' AND candidateGroup = 'sales' AND processId='" + processInstance.getId() +"')"); - try - { - tasksClient.findTasks(params); - fail("Exception expected"); - } - catch(PublicApiException expected) - { - assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode()); - assertErrorSummary("Filtering on candidateGroup is only allowed in combination with status-parameter 'active'", expected.getHttpResponse()); - } - - // Name filtering - params.clear(); - params.put("where", "(status = 'active' AND name = 'Task name' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.clear(); - params.put("where", "(status = 'completed' AND name = 'Another task name' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - params.clear(); - params.put("where", "(status = 'any' AND name = 'Another task name' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - // Description filtering - params.clear(); - params.put("where", "(status = 'active' AND description = 'This is a test description' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.clear(); - params.put("where", "(status = 'completed' AND description = 'This is another test description' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - params.clear(); - params.put("where", "(status = 'any' AND description = 'This is another test description' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - // Priority filtering - params.clear(); - params.put("where", "(status = 'active' AND priority = 2 AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.put("where", "(status = 'completed' AND priority = 3 AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - params.put("where", "(status = 'any' AND priority = 3 AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - // Process instance business-key filtering - params.clear(); - params.put("where", "(status = 'active' AND processBusinessKey = '" + businessKey + "')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.clear(); - params.put("where", "(status = 'completed' AND processBusinessKey = '" + businessKey + "')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - params.clear(); - params.put("where", "(status = 'any' AND processBusinessKey = '" + businessKey + "')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId(), activeTask.getId()); - - // Activity definition id filtering - params.clear(); - params.put("where", "(status = 'active' AND activityDefinitionId = 'verifyTaskDone' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.clear(); - params.put("where", "(status = 'completed' AND activityDefinitionId = 'adhocTask' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - params.clear(); - params.put("where", "(status = 'any' AND activityDefinitionId = 'adhocTask' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - // Process definition id filtering - params.clear(); - params.put("where", "(status = 'active' AND processDefinitionId = '" + processInstance.getProcessDefinitionId() + - "' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.clear(); - params.put("where", "(status = 'completed' AND processDefinitionId = '" + processInstance.getProcessDefinitionId() + - "' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - params.clear(); - params.put("where", "(status = 'any' AND processDefinitionId = '" + processInstance.getProcessDefinitionId() + - "' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId(), completedTask.getId()); - - // Process definition name filerting - params.clear(); - params.put("where", "(status = 'active' AND processDefinitionName = 'Adhoc Activiti Process' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.clear(); - params.put("where", "(status = 'completed' AND processDefinitionName = 'Adhoc Activiti Process' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - params.clear(); - params.put("where", "(status = 'any' AND processDefinitionName = 'Adhoc Activiti Process' AND processId='" + processInstance.getId() +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId(), completedTask.getId()); - - // Due date filtering - params.clear(); - params.put("where", "(status = 'active' AND dueAt = '" + ISO8601DateFormat.format(activeTaskDue.getTime()) +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.clear(); - params.put("where", "(status = 'completed' AND dueAt = '" + ISO8601DateFormat.format(completedTaskDue.getTime()) +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - params.clear(); - params.put("where", "(status = 'any' AND dueAt = '" + ISO8601DateFormat.format(completedTaskDue.getTime()) +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - // Started filtering - params.clear(); - params.put("where", "(status = 'active' AND startedAt = '" + ISO8601DateFormat.format(taskCreated.getTime()) +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.clear(); - params.put("where", "(status = 'completed' AND startedAt = '" + ISO8601DateFormat.format(taskCreated.getTime()) +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId()); - - params.clear(); - params.put("where", "(status = 'any' AND startedAt = '" + ISO8601DateFormat.format(taskCreated.getTime()) +"')"); - assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId(), activeTask.getId()); - - params.clear(); - params.put("where", "(variables/numberVar > 'd:int 5')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.clear(); - params.put("where", "(variables/numberVar > 'd:int 10')"); - assertEquals(0, getResultSizeForTaskQuery(params, tasksClient)); - - params.clear(); - params.put("where", "(variables/numberVar >= 'd_int 10')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.clear(); - params.put("where", "(variables/numberVar >= 'd:int 11')"); - assertEquals(0, getResultSizeForTaskQuery(params, tasksClient)); - - params.clear(); - params.put("where", "(variables/numberVar <= 'd:int 10')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.clear(); - params.put("where", "(variables/numberVar <= 'd:int 9')"); - assertEquals(0, getResultSizeForTaskQuery(params, tasksClient)); - - params.clear(); - params.put("where", "(variables/numberVar < 'd_int 15')"); - assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId()); - - params.clear(); - params.put("where", "(variables/numberVar < 'd:int 10')"); - assertEquals(0, getResultSizeForTaskQuery(params, tasksClient)); } @Test @@ -2463,20 +2469,26 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi { final RequestContext requestContext = initApiClientWithTestUser(); + String otherPerson = getOtherPersonInNetwork(requestContext.getRunAsUser(), requestContext.getNetworkId()).getId(); + RequestContext otherContext = new RequestContext(requestContext.getNetworkId(), otherPerson); + + String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + requestContext.getNetworkId(); + RequestContext adminContext = new RequestContext(requestContext.getNetworkId(), tenantAdmin); + // Create test-document and add to package NodeRef[] docNodeRefs = createTestDocuments(requestContext); ProcessInfo processInfo = startAdhocProcess(requestContext, docNodeRefs); - ProcessInstance processInstance = activitiProcessEngine.getRuntimeService().createProcessInstanceQuery() + Task task = activitiProcessEngine.getTaskService().createTaskQuery() .processInstanceId(processInfo.getId()).singleResult(); - assertNotNull(processInstance); + assertNotNull(task); + activitiProcessEngine.getTaskService().setAssignee(task.getId(), null); try { - final String newProcessInstanceId = processInstance.getId(); - ProcessesClient processesClient = publicApiClient.processesClient(); - JSONObject itemsJSON = processesClient.findProcessItems(newProcessInstanceId); + TasksClient tasksClient = publicApiClient.tasksClient(); + JSONObject itemsJSON = tasksClient.findTaskItems(task.getId()); assertNotNull(itemsJSON); JSONArray entriesJSON = (JSONArray) itemsJSON.get("entries"); assertNotNull(entriesJSON); @@ -2515,10 +2527,398 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi } assertTrue(doc1Found); assertTrue(doc2Found); + + // get with admin + publicApiClient.setRequestContext(adminContext); + itemsJSON = tasksClient.findTaskItems(task.getId()); + assertNotNull(itemsJSON); + entriesJSON = (JSONArray) itemsJSON.get("entries"); + assertNotNull(entriesJSON); + assertTrue(entriesJSON.size() == 2); + + // get with non involved user + publicApiClient.setRequestContext(otherContext); + try + { + tasksClient.findTaskItems(task.getId()); + } + catch (PublicApiException e) + { + assertEquals(403, e.getHttpResponse().getStatusCode()); + } + + // get with candidate user + activitiProcessEngine.getTaskService().addCandidateUser(task.getId(), otherContext.getRunAsUser()); + publicApiClient.setRequestContext(otherContext); + itemsJSON = tasksClient.findTaskItems(task.getId()); + assertNotNull(itemsJSON); + entriesJSON = (JSONArray) itemsJSON.get("entries"); + assertNotNull(entriesJSON); + assertTrue(entriesJSON.size() == 2); + + // get with user from candidate group + List memberships = getTestFixture().getNetwork(otherContext.getNetworkId()).getSiteMemberships(otherContext.getRunAsUser()); + assertTrue(memberships.size() > 0); + MemberOfSite memberOfSite = memberships.get(0); + String group = "GROUP_site_" + memberOfSite.getSiteId() + "_" + memberOfSite.getRole().name(); + + activitiProcessEngine.getTaskService().deleteCandidateUser(task.getId(), otherContext.getRunAsUser()); + activitiProcessEngine.getTaskService().addCandidateGroup(task.getId(), group); + publicApiClient.setRequestContext(otherContext); + itemsJSON = tasksClient.findTaskItems(task.getId()); + assertNotNull(itemsJSON); + entriesJSON = (JSONArray) itemsJSON.get("entries"); + assertNotNull(entriesJSON); + assertTrue(entriesJSON.size() == 2); + + // invalid task id + publicApiClient.setRequestContext(requestContext); + try + { + tasksClient.findTaskItems("fakeid"); + } + catch (PublicApiException e) + { + assertEquals(404, e.getHttpResponse().getStatusCode()); + } } finally { - cleanupProcessInstance(processInstance); + cleanupProcessInstance(processInfo.getId()); + } + } + + @Test + @SuppressWarnings("unchecked") + public void testAddTaskItem() throws Exception + { + final RequestContext requestContext = initApiClientWithTestUser(); + + String otherPerson = getOtherPersonInNetwork(requestContext.getRunAsUser(), requestContext.getNetworkId()).getId(); + RequestContext otherContext = new RequestContext(requestContext.getNetworkId(), otherPerson); + + String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + requestContext.getNetworkId(); + RequestContext adminContext = new RequestContext(requestContext.getNetworkId(), tenantAdmin); + + // Create test-document and add to package + NodeRef[] docNodeRefs = createTestDocuments(requestContext); + ProcessInfo processInfo = startAdhocProcess(requestContext, null); + + final Task task = activitiProcessEngine.getTaskService() + .createTaskQuery() + .processInstanceId(processInfo.getId()) + .singleResult(); + + assertNotNull(task); + + try + { + TasksClient tasksClient = publicApiClient.tasksClient(); + JSONObject createItemObject = new JSONObject(); + createItemObject.put("id", docNodeRefs[0].getId()); + JSONObject result = tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString()); + + assertNotNull(result); + assertEquals(docNodeRefs[0].getId(), result.get("id")); + assertEquals("Test Doc1", result.get("name")); + assertEquals("Test Doc1 Title", result.get("title")); + assertEquals("Test Doc1 Description", result.get("description")); + assertNotNull(result.get("createdAt")); + assertEquals(requestContext.getRunAsUser(), result.get("createdBy")); + assertNotNull(result.get("modifiedAt")); + assertEquals(requestContext.getRunAsUser(), result.get("modifiedBy")); + assertNotNull(result.get("size")); + assertNotNull(result.get("mimeType")); + + JSONObject itemJSON = tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId()); + assertEquals(docNodeRefs[0].getId(), itemJSON.get("id")); + + tasksClient.deleteTaskItem(task.getId(), docNodeRefs[0].getId()); + try + { + tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId()); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(404, e.getHttpResponse().getStatusCode()); + } + + // add item as admin + publicApiClient.setRequestContext(adminContext); + result = tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString()); + assertNotNull(result); + assertEquals(docNodeRefs[0].getId(), result.get("id")); + assertEquals("Test Doc1", result.get("name")); + + itemJSON = tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId()); + assertEquals(docNodeRefs[0].getId(), itemJSON.get("id")); + + tasksClient.deleteTaskItem(task.getId(), docNodeRefs[0].getId()); + try + { + tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId()); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(404, e.getHttpResponse().getStatusCode()); + } + + // add item with candidate user + activitiProcessEngine.getTaskService().addCandidateUser(task.getId(), otherPerson); + publicApiClient.setRequestContext(otherContext); + result = tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString()); + assertNotNull(result); + assertEquals(docNodeRefs[0].getId(), result.get("id")); + assertEquals("Test Doc1", result.get("name")); + + itemJSON = tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId()); + assertEquals(docNodeRefs[0].getId(), itemJSON.get("id")); + + tasksClient.deleteTaskItem(task.getId(), docNodeRefs[0].getId()); + try + { + tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId()); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(404, e.getHttpResponse().getStatusCode()); + } + + // add item with not involved user + activitiProcessEngine.getTaskService().deleteCandidateUser(task.getId(), otherPerson); + publicApiClient.setRequestContext(otherContext); + try + { + tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString()); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(403, e.getHttpResponse().getStatusCode()); + } + + // invalid task id + publicApiClient.setRequestContext(requestContext); + try + { + tasksClient.addTaskItem("fakeid", createItemObject.toJSONString()); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(404, e.getHttpResponse().getStatusCode()); + } + + // invalid item id + createItemObject = new JSONObject(); + createItemObject.put("id", "fakeid"); + try + { + tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString()); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(404, e.getHttpResponse().getStatusCode()); + } + + // add item to completed task + TenantUtil.runAsUserTenant(new TenantRunAsWork() + { + @Override + public Void doWork() throws Exception + { + activitiProcessEngine.getTaskService().complete(task.getId()); + return null; + } + }, requestContext.getRunAsUser(), requestContext.getNetworkId()); + + createItemObject = new JSONObject(); + createItemObject.put("id", docNodeRefs[0].getId()); + try + { + tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString()); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(404, e.getHttpResponse().getStatusCode()); + } + } + finally + { + cleanupProcessInstance(processInfo.getId()); + } + } + + @Test + @SuppressWarnings("unchecked") + public void testDeleteTaskItem() throws Exception + { + final RequestContext requestContext = initApiClientWithTestUser(); + + String otherPerson = getOtherPersonInNetwork(requestContext.getRunAsUser(), requestContext.getNetworkId()).getId(); + RequestContext otherContext = new RequestContext(requestContext.getNetworkId(), otherPerson); + + String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + requestContext.getNetworkId(); + RequestContext adminContext = new RequestContext(requestContext.getNetworkId(), tenantAdmin); + + // Create test-document and add to package + NodeRef[] docNodeRefs = createTestDocuments(requestContext); + ProcessInfo processInfo = startAdhocProcess(requestContext, docNodeRefs); + + final Task task = activitiProcessEngine.getTaskService() + .createTaskQuery() + .processInstanceId(processInfo.getId()) + .singleResult(); + + assertNotNull(task); + + try + { + TasksClient tasksClient = publicApiClient.tasksClient(); + tasksClient.deleteTaskItem(task.getId(), docNodeRefs[0].getId()); + + try + { + tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId()); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(404, e.getHttpResponse().getStatusCode()); + } + + // delete item as admin + JSONObject createItemObject = new JSONObject(); + createItemObject.put("id", docNodeRefs[0].getId()); + JSONObject result = tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString()); + + assertNotNull(result); + assertEquals(docNodeRefs[0].getId(), result.get("id")); + + JSONObject itemJSON = tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId()); + assertEquals(docNodeRefs[0].getId(), itemJSON.get("id")); + + publicApiClient.setRequestContext(adminContext); + tasksClient.deleteTaskItem(task.getId(), docNodeRefs[0].getId()); + try + { + tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId()); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(404, e.getHttpResponse().getStatusCode()); + } + + // delete item with candidate user + createItemObject = new JSONObject(); + createItemObject.put("id", docNodeRefs[0].getId()); + result = tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString()); + + assertNotNull(result); + assertEquals(docNodeRefs[0].getId(), result.get("id")); + + itemJSON = tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId()); + assertEquals(docNodeRefs[0].getId(), itemJSON.get("id")); + + activitiProcessEngine.getTaskService().addCandidateUser(task.getId(), otherPerson); + publicApiClient.setRequestContext(otherContext); + tasksClient.deleteTaskItem(task.getId(), docNodeRefs[0].getId()); + try + { + tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId()); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(404, e.getHttpResponse().getStatusCode()); + } + + // delete item with not involved user + createItemObject = new JSONObject(); + createItemObject.put("id", docNodeRefs[0].getId()); + result = tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString()); + + assertNotNull(result); + assertEquals(docNodeRefs[0].getId(), result.get("id")); + + itemJSON = tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId()); + assertEquals(docNodeRefs[0].getId(), itemJSON.get("id")); + + activitiProcessEngine.getTaskService().deleteCandidateUser(task.getId(), otherPerson); + publicApiClient.setRequestContext(otherContext); + try + { + tasksClient.deleteTaskItem(task.getId(), docNodeRefs[0].getId()); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(403, e.getHttpResponse().getStatusCode()); + } + + // invalid task id + publicApiClient.setRequestContext(requestContext); + try + { + tasksClient.deleteTaskItem("fakeid", docNodeRefs[0].getId()); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(404, e.getHttpResponse().getStatusCode()); + } + + // invalid item id + try + { + tasksClient.deleteTaskItem(task.getId(), "fakeid"); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(404, e.getHttpResponse().getStatusCode()); + } + + // delete item from completed task + createItemObject = new JSONObject(); + createItemObject.put("id", docNodeRefs[0].getId()); + result = tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString()); + + assertNotNull(result); + assertEquals(docNodeRefs[0].getId(), result.get("id")); + + itemJSON = tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId()); + assertEquals(docNodeRefs[0].getId(), itemJSON.get("id")); + + TenantUtil.runAsUserTenant(new TenantRunAsWork() + { + @Override + public Void doWork() throws Exception + { + activitiProcessEngine.getTaskService().complete(task.getId()); + return null; + } + }, requestContext.getRunAsUser(), requestContext.getNetworkId()); + + try + { + tasksClient.deleteTaskItem(task.getId(), docNodeRefs[0].getId()); + fail("Expected exception"); + } + catch (PublicApiException e) + { + assertEquals(404, e.getHttpResponse().getStatusCode()); + } + } + finally + { + cleanupProcessInstance(processInfo.getId()); } } @@ -2597,4 +2997,22 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi log("Error while cleaning up process instance"); } } + + protected void cleanupProcessInstance(String... processInstances) + { + // Clean up process-instance regardless of test success/failure + try + { + for (String instanceId : processInstances) + { + activitiProcessEngine.getRuntimeService().deleteProcessInstance(instanceId, null); + activitiProcessEngine.getHistoryService().deleteHistoricProcessInstance(instanceId); + } + } + catch(Throwable t) + { + // Ignore error during cleanup to prevent swallowing potential assetion-exception + log("Error while cleaning up process instance"); + } + } } diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/WorkflowApiClient.java b/source/test-java/org/alfresco/rest/workflow/api/tests/WorkflowApiClient.java index 6e2e558aec..26f5d71848 100644 --- a/source/test-java/org/alfresco/rest/workflow/api/tests/WorkflowApiClient.java +++ b/source/test-java/org/alfresco/rest/workflow/api/tests/WorkflowApiClient.java @@ -158,6 +158,12 @@ public class WorkflowApiClient extends PublicApiClient return list; } + public HttpResponse getImage(String processInstanceId) throws PublicApiException + { + HttpResponse response = getSingle("processes", processInstanceId, "image", null, "Failed to get image of processInstanceId " + processInstanceId); + return response; + } + public JSONObject findProcessItems(String processInstanceId) throws PublicApiException { HttpResponse response = getAll("processes", processInstanceId, "items", null, null, @@ -283,6 +289,34 @@ public class WorkflowApiClient extends PublicApiClient JSONObject list = (JSONObject) response.getJsonResponse().get("list"); return list; } + + public JSONObject findTaskItems(String taskId) throws PublicApiException + { + HttpResponse response = getAll("tasks", taskId, "items", null, null, + "Failed to get the items of the task"); + JSONObject list = (JSONObject) response.getJsonResponse().get("list"); + return list; + } + + public JSONObject addTaskItem(String taskId, String body) throws PublicApiException + { + HttpResponse response = create("tasks", taskId, "items", null, body, "Failed to add item"); + JSONObject entry = (JSONObject) response.getJsonResponse().get("entry"); + return entry; + } + + public void deleteTaskItem(String taskId, String itemId) throws PublicApiException + { + remove("tasks", taskId, "items", itemId, "Failed to delete item"); + } + + public JSONObject findTaskItem(String taskId, String itemId) throws PublicApiException + { + HttpResponse response = getAll("tasks", taskId, "items", itemId, null, + "Failed to get the item of the task"); + JSONObject entry = (JSONObject) response.getJsonResponse().get("entry"); + return entry; + } } public static Date parseDate(JSONObject entry, String fieldName) {