mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
Merged BRANCHES/DEV/BELARUS/HEAD_2010_07_19 to HEAD:
21326: ALF-3894 : F81 REST API to update properties for a particular task instance 21376: ALF-3894 : F81 REST API to update properties for a particular task instance git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21404 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -20,7 +20,9 @@ package org.alfresco.repo.web.scripts.workflow;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
@@ -31,14 +33,16 @@ import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
/**
|
||||
* @author Nick Smith
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
public abstract class AbstractWorkflowWebscript extends DeclarativeWebScript
|
||||
{
|
||||
|
||||
private NamespaceService namespaceService;
|
||||
private NodeService nodeService;
|
||||
private PersonService personService;
|
||||
protected NamespaceService namespaceService;
|
||||
protected NodeService nodeService;
|
||||
protected PersonService personService;
|
||||
protected DictionaryService dictionaryService;
|
||||
protected AuthenticationService authenticationService;
|
||||
protected WorkflowService workflowService;
|
||||
|
||||
@Override
|
||||
@@ -63,6 +67,16 @@ public abstract class AbstractWorkflowWebscript extends DeclarativeWebScript
|
||||
this.personService = personService;
|
||||
}
|
||||
|
||||
public void setDictionaryService(DictionaryService dictionaryService)
|
||||
{
|
||||
this.dictionaryService = dictionaryService;
|
||||
}
|
||||
|
||||
public void setAuthenticationService(AuthenticationService authenticationService)
|
||||
{
|
||||
this.authenticationService = authenticationService;
|
||||
}
|
||||
|
||||
public void setWorkflowService(WorkflowService workflowService)
|
||||
{
|
||||
this.workflowService = workflowService;
|
||||
@@ -80,4 +94,4 @@ public abstract class AbstractWorkflowWebscript extends DeclarativeWebScript
|
||||
WorkflowModelBuilder modelBuilder,
|
||||
WebScriptRequest req,
|
||||
Status status, Cache cache);
|
||||
}
|
||||
}
|
@@ -31,7 +31,7 @@ import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
/**
|
||||
* @author unknown
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
public class TaskInstanceGet extends AbstractWorkflowWebscript
|
||||
{
|
||||
@@ -41,19 +41,23 @@ public class TaskInstanceGet extends AbstractWorkflowWebscript
|
||||
{
|
||||
Map<String, String> params = req.getServiceMatch().getTemplateVars();
|
||||
|
||||
// getting task id from request parameters
|
||||
String taskId = params.get("task_instance_id");
|
||||
|
||||
// searching for task in repository
|
||||
WorkflowTask workflowTask = workflowService.getTaskById(taskId);
|
||||
|
||||
// task was not found -> return 404
|
||||
if (workflowTask == null)
|
||||
{
|
||||
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find workflow task with id: " + taskId);
|
||||
}
|
||||
|
||||
Map<String, Object> model = new HashMap<String, Object>();
|
||||
// build the model for ftl
|
||||
model.put("workflowTask", modelBuilder.buildDetailed(workflowTask));
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.repo.web.scripts.workflow;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTask;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONTokener;
|
||||
import org.springframework.extensions.webscripts.Cache;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
/**
|
||||
* @author unknown
|
||||
* @since 3.4
|
||||
*/
|
||||
public class TaskInstancePut extends AbstractWorkflowWebscript
|
||||
{
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> buildModel(WorkflowModelBuilder modelBuilder, WebScriptRequest req, Status status, Cache cache)
|
||||
{
|
||||
Map<String, String> params = req.getServiceMatch().getTemplateVars();
|
||||
|
||||
// getting task id from request parameters
|
||||
String taskId = params.get("task_instance_id");
|
||||
|
||||
JSONObject json = null;
|
||||
|
||||
try
|
||||
{
|
||||
WorkflowTask workflowTask = workflowService.getTaskById(taskId);
|
||||
|
||||
String currentUser = authenticationService.getCurrentUserName();
|
||||
|
||||
Serializable owner = workflowTask.properties.get(ContentModel.PROP_OWNER);
|
||||
|
||||
Serializable initiator = getWorkflowInitiator(workflowTask);
|
||||
|
||||
if (!(owner != null && currentUser.equals(owner) || initiator != null && currentUser.equals(initiator)))
|
||||
{
|
||||
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Failed to update workflow task with id: " + taskId);
|
||||
}
|
||||
|
||||
// read request json
|
||||
json = new JSONObject(new JSONTokener(req.getContent().getContent()));
|
||||
|
||||
// update task properties
|
||||
workflowTask = workflowService.updateTask(taskId, parseTaskProperties(json), null, null);
|
||||
|
||||
// task was not founded -> return 404
|
||||
if (workflowTask == null)
|
||||
{
|
||||
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Failed to find workflow task with id: " + taskId);
|
||||
}
|
||||
|
||||
Map<String, Object> model = new HashMap<String, Object>();
|
||||
// build the model for ftl
|
||||
model.put("workflowTask", modelBuilder.buildDetailed(workflowTask));
|
||||
|
||||
return model;
|
||||
}
|
||||
catch (IOException iox)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not read content from request.", iox);
|
||||
}
|
||||
catch (JSONException je)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not parse JSON from request.", je);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<QName, Serializable> parseTaskProperties(JSONObject json) throws JSONException
|
||||
{
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||
|
||||
// gets the array of properties names
|
||||
String[] names = JSONObject.getNames(json);
|
||||
|
||||
if (names != null)
|
||||
{
|
||||
// array is not empty
|
||||
for (String name : names)
|
||||
{
|
||||
// build the qname of property
|
||||
QName key = QName.createQName(name.replaceFirst("_", ":"), namespaceService);
|
||||
Object jsonValue = json.get(name);
|
||||
|
||||
Serializable value = null;
|
||||
|
||||
// process null values
|
||||
if (jsonValue.equals(JSONObject.NULL))
|
||||
{
|
||||
props.put(key, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
// gets the property definition from dictionary
|
||||
PropertyDefinition prop = dictionaryService.getProperty(key);
|
||||
|
||||
if (prop != null)
|
||||
{
|
||||
// convert property using its data type specified in model
|
||||
value = (Serializable) DefaultTypeConverter.INSTANCE.convert(prop.getDataType(), json.get(name));
|
||||
}
|
||||
else
|
||||
{
|
||||
// property definition was not founded in dictionary
|
||||
if (jsonValue instanceof JSONArray)
|
||||
{
|
||||
value = new ArrayList<String>();
|
||||
|
||||
for (int i = 0; i < ((JSONArray)jsonValue).length(); i++)
|
||||
{
|
||||
((List<String>)value).add(((JSONArray)jsonValue).getString(i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = (Serializable) DefaultTypeConverter.INSTANCE.convert(NodeRef.class, jsonValue.toString().replaceAll("\\\\", ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
props.put(key, value);
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the workflow initiator for the given workflow task.
|
||||
*
|
||||
* @param workflowTask The task to get the initiator for
|
||||
* @return The user name of the initiator or null if there isn't one
|
||||
*/
|
||||
private Serializable getWorkflowInitiator(WorkflowTask workflowTask)
|
||||
{
|
||||
Serializable initiatorUserName = null;
|
||||
|
||||
NodeRef initiator = workflowTask.path.instance.initiator;
|
||||
|
||||
if (initiator != null)
|
||||
{
|
||||
initiatorUserName = this.nodeService.getProperty(initiator, ContentModel.PROP_USERNAME);
|
||||
}
|
||||
|
||||
return initiatorUserName;
|
||||
}
|
||||
}
|
@@ -39,6 +39,7 @@ import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowNode;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowPath;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTask;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTransition;
|
||||
@@ -144,7 +145,7 @@ public class WorkflowModelBuilder
|
||||
{
|
||||
Map<String, Object> model = buildSimple(workflowTask, null);
|
||||
|
||||
model.put(TASK_PATH, getUrl(workflowTask) + "/paths/" + workflowTask.path.id);
|
||||
model.put(TASK_PATH, getUrl(workflowTask, workflowTask.path));
|
||||
|
||||
// definition part
|
||||
model.put(TASK_DEFINITION, buildTaskDefinition(workflowTask.definition, workflowTask));
|
||||
@@ -348,4 +349,9 @@ public class WorkflowModelBuilder
|
||||
return "api/classes/" + typeDefinition.getName().toPrefixString().replace(PREFIX_SEPARATOR, "_");
|
||||
}
|
||||
|
||||
private String getUrl(WorkflowTask task, WorkflowPath path)
|
||||
{
|
||||
return getUrl(task) + "/paths/" + path.id;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -40,13 +40,17 @@ import org.alfresco.service.cmr.workflow.WorkflowTask;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTaskState;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTransition;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.extensions.surf.util.ISO8601DateFormat;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.TestWebScriptServer.GetRequest;
|
||||
import org.springframework.extensions.webscripts.TestWebScriptServer.PutRequest;
|
||||
import org.springframework.extensions.webscripts.TestWebScriptServer.Response;
|
||||
|
||||
/**
|
||||
@@ -57,11 +61,13 @@ public class WorkflowRestApiTest extends BaseWebScriptTest
|
||||
{
|
||||
private final static String USER1 = "Bob" + GUID.generate();
|
||||
private final static String USER2 = "Jane" + GUID.generate();
|
||||
private final static String USER3 = "Nick" + GUID.generate();
|
||||
private static final String URL_TASKS = "api/task-instances";
|
||||
private static final String URL_WORKFLOW_DEFINITIONS = "api/workflow-definitions";
|
||||
|
||||
private TestPersonManager personManager;
|
||||
private WorkflowService workflowService;
|
||||
private NamespaceService namespaceService;
|
||||
private NodeRef packageRef;
|
||||
|
||||
public void testTaskInstancesGet() throws Exception
|
||||
@@ -213,6 +219,49 @@ public class WorkflowRestApiTest extends BaseWebScriptTest
|
||||
|
||||
}
|
||||
|
||||
public void testTaskInstancePut() throws Exception
|
||||
{
|
||||
//Start workflow as USER1 and assign task to USER2.
|
||||
personManager.setUser(USER1);
|
||||
WorkflowDefinition adhocDef = workflowService.getDefinitionByName("jbpm$wf:adhoc");
|
||||
Map<QName, Serializable> params = new HashMap<QName, Serializable>();
|
||||
params.put(WorkflowModel.ASSOC_ASSIGNEE, personManager.get(USER2));
|
||||
params.put(WorkflowModel.PROP_DUE_DATE, new Date());
|
||||
params.put(WorkflowModel.PROP_PRIORITY, 1);
|
||||
params.put(WorkflowModel.ASSOC_PACKAGE, packageRef);
|
||||
|
||||
WorkflowPath adhocPath = workflowService.startWorkflow(adhocDef.id, params);
|
||||
WorkflowTask startTask = workflowService.getTasksForWorkflowPath(adhocPath.id).get(0);
|
||||
|
||||
Response getResponse = sendRequest(new GetRequest(URL_TASKS + "/" + startTask.id), 200);
|
||||
|
||||
JSONObject jsonProperties = new JSONObject(getResponse.getContentAsString()).getJSONObject("data").getJSONObject("properties");
|
||||
|
||||
// make some changes
|
||||
jsonProperties.remove(qnameToString(WorkflowModel.ASSOC_PACKAGE));
|
||||
jsonProperties.put(qnameToString(WorkflowModel.PROP_COMMENT), "Edited comment");
|
||||
jsonProperties.put(qnameToString(WorkflowModel.PROP_DUE_DATE), ISO8601DateFormat.format(new Date()));
|
||||
jsonProperties.put(qnameToString(WorkflowModel.PROP_DESCRIPTION), "Edited description");
|
||||
jsonProperties.put(qnameToString(WorkflowModel.PROP_PRIORITY), 1);
|
||||
|
||||
personManager.setUser(USER3);
|
||||
Response unauthResponse = sendRequest(new PutRequest(URL_TASKS + "/" + startTask.id, jsonProperties.toString(), "application/json"), 401);
|
||||
assertEquals(Status.STATUS_UNAUTHORIZED, unauthResponse.getStatus());
|
||||
|
||||
personManager.setUser(USER1);
|
||||
Response putResponse = sendRequest(new PutRequest(URL_TASKS + "/" + startTask.id, jsonProperties.toString(), "application/json"), 200);
|
||||
|
||||
assertEquals(Status.STATUS_OK, putResponse.getStatus());
|
||||
String jsonStr = putResponse.getContentAsString();
|
||||
JSONObject json = new JSONObject(jsonStr);
|
||||
JSONObject result = json.getJSONObject("data");
|
||||
assertNotNull(result);
|
||||
|
||||
JSONObject editedJsonProperties = result.getJSONObject("properties");
|
||||
|
||||
compareProperties(jsonProperties, editedJsonProperties);
|
||||
}
|
||||
|
||||
public void testWorkflowDefinitionsGet() throws Exception
|
||||
{
|
||||
Response response = sendRequest(new GetRequest(URL_WORKFLOW_DEFINITIONS), 200);
|
||||
@@ -250,6 +299,7 @@ public class WorkflowRestApiTest extends BaseWebScriptTest
|
||||
super.setUp();
|
||||
ApplicationContext appContext = getServer().getApplicationContext();
|
||||
|
||||
namespaceService = (NamespaceService)appContext.getBean("NamespaceService");
|
||||
workflowService = (WorkflowService)appContext.getBean("WorkflowService");
|
||||
MutableAuthenticationService authenticationService = (MutableAuthenticationService)appContext.getBean("AuthenticationService");
|
||||
PersonService personService = (PersonService)appContext.getBean("PersonService");
|
||||
@@ -258,6 +308,7 @@ public class WorkflowRestApiTest extends BaseWebScriptTest
|
||||
|
||||
personManager.createPerson(USER1);
|
||||
personManager.createPerson(USER2);
|
||||
personManager.createPerson(USER3);
|
||||
|
||||
packageRef = workflowService.createPackage(null);
|
||||
}
|
||||
@@ -271,4 +322,32 @@ public class WorkflowRestApiTest extends BaseWebScriptTest
|
||||
super.tearDown();
|
||||
personManager.clearPeople();
|
||||
}
|
||||
|
||||
private String qnameToString(QName qName)
|
||||
{
|
||||
String separator = Character.toString(QName.NAMESPACE_PREFIX);
|
||||
|
||||
return qName.toPrefixString(namespaceService).replaceFirst(separator, "_");
|
||||
}
|
||||
|
||||
private void compareProperties(JSONObject before, JSONObject after) throws JSONException
|
||||
{
|
||||
for (String name : JSONObject.getNames(after))
|
||||
{
|
||||
if (before.has(name))
|
||||
{
|
||||
if (before.get(name) instanceof JSONArray)
|
||||
{
|
||||
for (int i = 0; i < before.getJSONArray(name).length(); i++)
|
||||
{
|
||||
assertEquals(before.getJSONArray(name).get(i), after.getJSONArray(name).get(i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assertEquals(before.get(name), after.get(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user