- Added isTaskEditable, isTaskReassignable, isTaskClaimable and isTaskReleasable to WorkflowService

- Added isEditable, isReassignable, isClaimable and isReleasable flags to task model in REST API
- Added outcome property to task model in REST API (label instead of raw value)
- Change "definitionTypeTitle" property to "type" and fixed up fallout
- Changed UI to use the isXXX flags above rather than copious amount of repeated checks
- Updated workflow details page to use outcome label, isEditable flag and some changes following discussion with Linton
- Added tests

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21890 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Gavin Cornwell
2010-08-20 09:07:02 +00:00
parent 127100a4a1
commit 93a7f84624
4 changed files with 248 additions and 0 deletions

View File

@@ -30,6 +30,8 @@ inwf_invite-workflow-model.property.inwf_inviteeRole.title=Invitee Role
# Invite Process Definitions
inwf_invitation-nominated.node.start.title=Start
inwf_invitation-nominated.node.start.description=Send an invitation
inwf_invitation-nominated.node.start.transition.sendInvite.title=Send Invite
inwf_invitation-nominated.node.start.transition.sendInvite.description=Send Invite
inwf_invitation-nominated.node.invitePending.title=Invite Pending
inwf_invitation-nominated.node.invitePending.description=Invite Pending

View File

@@ -57,6 +57,7 @@ public interface WorkflowModel
static final QName PROP_PACKAGE_ACTION_GROUP = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "packageActionGroup");
static final QName PROP_PACKAGE_ITEM_ACTION_GROUP = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "packageItemActionGroup");
static final QName PROP_HIDDEN_TRANSITIONS = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "hiddenTransitions");
static final QName PROP_REASSIGNABLE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "reassignable");
static final QName ASSOC_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "package");
// workflow task contstants

View File

@@ -22,6 +22,7 @@ package org.alfresco.repo.workflow;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -647,6 +648,121 @@ public class WorkflowServiceImpl implements WorkflowService
return component.endTask(taskId, transition);
}
/*
* @see org.alfresco.service.cmr.workflow.WorkflowService#isTaskEditable(org.alfresco.service.cmr.workflow.WorkflowTask, java.lang.String)
*/
public boolean isTaskEditable(WorkflowTask task, String username)
{
// if the task is complete it is not editable
if (task.getState() == WorkflowTaskState.COMPLETED)
{
return false;
}
if (isUserOwnerOrInitiator(task, username))
{
// editable if the current user is the task owner or initiator
return true;
}
// if the current user is not the owner or initiator check whether they are
// a member of the pooled actors for the task (if it has any)
return isUserInPooledActors(task, username);
}
/*
* @see org.alfresco.service.cmr.workflow.WorkflowService#isTaskReassignable(org.alfresco.service.cmr.workflow.WorkflowTask, java.lang.String)
*/
public boolean isTaskReassignable(WorkflowTask task, String username)
{
// if the task is complete it is not reassignable
if (task.getState() == WorkflowTaskState.COMPLETED)
{
return false;
}
// if the task has the 'reassignable' property set to false it can not be reassigned
Map<QName, Serializable> properties = task.getProperties();
Boolean reassignable = (Boolean)properties.get(WorkflowModel.PROP_REASSIGNABLE);
if (reassignable != null && reassignable.booleanValue() == false)
{
return false;
}
// if the task has pooled actors and an owner it can not be reassigned (it must be released)
Collection<?> actors = (Collection<?>) properties.get(WorkflowModel.ASSOC_POOLED_ACTORS);
String owner = (String)properties.get(ContentModel.PROP_OWNER);
if (actors != null && !actors.isEmpty() && owner != null)
{
return false;
}
if (isUserOwnerOrInitiator(task, username))
{
// reassignable if the current user is the task owner or initiator
return true;
}
return false;
}
/*
* @see org.alfresco.service.cmr.workflow.WorkflowService#isTaskClaimable(org.alfresco.service.cmr.workflow.WorkflowTask, java.lang.String)
*/
public boolean isTaskClaimable(WorkflowTask task, String username)
{
// if the task is complete it is not claimable
if (task.getState() == WorkflowTaskState.COMPLETED)
{
return false;
}
// if the task has an owner it can not be claimed
if (task.getProperties().get(ContentModel.PROP_OWNER) != null)
{
return false;
}
// a task can only be claimed if the user is a member of
// of the pooled actors for the task
return isUserInPooledActors(task, username);
}
/*
* @see org.alfresco.service.cmr.workflow.WorkflowService#isTaskReleasable(org.alfresco.service.cmr.workflow.WorkflowTask, java.lang.String)
*/
public boolean isTaskReleasable(WorkflowTask task, String username)
{
// if the task is complete it is not releasable
if (task.getState() == WorkflowTaskState.COMPLETED)
{
return false;
}
// if the task doesn't have pooled actors it is not releasable
Map<QName, Serializable> properties = task.getProperties();
Collection<?> actors = (Collection<?>) properties.get(WorkflowModel.ASSOC_POOLED_ACTORS);
if (actors == null || actors.isEmpty())
{
return false;
}
// if the task does not have an owner it is not releasable
String owner = (String)properties.get(ContentModel.PROP_OWNER);
if (owner == null)
{
return false;
}
if (isUserOwnerOrInitiator(task, username))
{
// releasable if the current user is the task owner or initiator
return true;
}
return false;
}
/*
* (non-Javadoc)
* @see
@@ -837,4 +953,88 @@ public class WorkflowServiceImpl implements WorkflowService
}
return contents;
}
/**
* Determines if the given user is a member of the pooled actors assigned to the task
*
* @param task The task instance to check
* @param username The username to check
* @return true if the user is a pooled actor, false otherwise
*/
private boolean isUserInPooledActors(WorkflowTask task, String username)
{
// get groups that the current user has to belong (at least one of them)
final Collection<?> actors = (Collection<?>)task.getProperties().get(WorkflowModel.ASSOC_POOLED_ACTORS);
if (actors != null && !actors.isEmpty())
{
for (Object actor : actors)
{
// retrieve the name of the group
Map<QName, Serializable> props = nodeService.getProperties((NodeRef)actor);
String name = (String)props.get(ContentModel.PROP_AUTHORITY_NAME);
// retrieve the users of the group
Set<String> users = this.authorityService.getContainedAuthorities(AuthorityType.USER, name, true);
// see if the user is one of the users in the group
if (users != null && !users.isEmpty() && users.contains(username))
{
// they are a member of the group so stop looking!
return true;
}
}
}
return false;
}
/**
* Determines if the given user is the owner of the given task or
* the initiator of the workflow the task is part of
*
* @param task The task to check
* @param username The username to check
* @return true if the user is the owner or the workflow initiator
*/
private boolean isUserOwnerOrInitiator(WorkflowTask task, String username)
{
boolean result = false;
String owner = (String)task.getProperties().get(ContentModel.PROP_OWNER);
if (username.equals(owner))
{
// user owns the task
result = true;
}
else if (username.equals(getWorkflowInitiatorUsername(task)))
{
// user is the workflow initiator
result = true;
}
return result;
}
/**
* Returns the username of the user that initiated the workflow the
* given task is part of.
*
* @param task The task to get the workflow initiator for
* @return Username or null if the initiator could not be found
*/
private String getWorkflowInitiatorUsername(WorkflowTask task)
{
String initiator = null;
NodeRef initiatorRef = task.getPath().getInstance().getInitiator();
if (initiator != null)
{
// TODO: deal with missing users!
initiator = (String)this.nodeService.getProperty(initiatorRef, ContentModel.PROP_USERNAME);
}
return initiator;
}
}

View File

@@ -207,6 +207,7 @@ public interface WorkflowService
*
* @param workflowDefinitionId the workflow definition id
* @return the list of "in-flight" workflow instances
* @since 3.4
*/
@Auditable(parameters = {"workflowDefinitionId"})
public List<WorkflowInstance> getCompletedWorkflows(String workflowDefinitionId);
@@ -216,6 +217,7 @@ public interface WorkflowService
*
* @param workflowDefinitionId the workflow definition id
* @return the list of "in-flight" workflow instances
* @since 3.4
*/
@Auditable(parameters = {"workflowDefinitionId"})
public List<WorkflowInstance> getWorkflows(String workflowDefinitionId);
@@ -374,6 +376,49 @@ public interface WorkflowService
@Auditable(parameters = {"taskId", "transitionId"})
public WorkflowTask endTask(String taskId, String transitionId);
/**
* Determines if the given user can edit the given task
*
* @param task The task to check
* @param username The user to check
* @return true if the user can edit the task
* @since 3.4
*/
@Auditable(parameters = {"task", "username"})
public boolean isTaskEditable(WorkflowTask task, String username);
/**
* Determines if the given user can reassign the given task
*
* @param task The task to check
* @param username The user to check
* @return true if the user can reassign the task
* @since 3.4
*/
@Auditable(parameters = {"task", "username"})
public boolean isTaskReassignable(WorkflowTask task, String username);
/**
* Determines if the given user can claim the given task
*
* @param task The task to check
* @param username The user to check
* @return true if the user can claim the task
* @since 3.4
*/
@Auditable(parameters = {"task", "username"})
public boolean isTaskClaimable(WorkflowTask task, String username);
/**
* Determines if the given user can release the given task
*
* @param task The task to check
* @param username The user to check
* @return true if the user can release the task
* @since 3.4
*/
@Auditable(parameters = {"task", "username"})
public boolean isTaskReleasable(WorkflowTask task, String username);
//
// Package Management