This is an automated email from the ASF dual-hosted git repository.
josedee pushed a commit to branch main
in repository
https://gitbox.apache.org/repos/asf/incubator-kie-kogito-runtimes.git
The following commit(s) were added to refs/heads/main by this push:
new e847f353db [incubator-kie-issues-2354] Resume transition permission
fix for Suspended Tasks (#4324)
e847f353db is described below
commit e847f353dbe6aed60d8b4c9a9cad5585cde6a779
Author: Deepak Joseph <[email protected]>
AuthorDate: Thu Jun 25 15:10:17 2026 +0530
[incubator-kie-issues-2354] Resume transition permission fix for Suspended
Tasks (#4324)
* Resume transition permission fix for Suspended Tasks
* More tests
* update
* update
---
.../impl/lifecycle/WsHumanTaskLifeCycle.java | 9 +-
.../resources/manager_admin_multiple_users.bpmn | 156 +++++++++++++++++++++
.../usertask/jpa/it/WsHumanTaskLifeCycleIT.java | 139 ++++++++++++++++++
.../resources/manager_admin_multiple_users.bpmn | 156 +++++++++++++++++++++
.../usertask/jpa/it/WsHumanTaskLifeCycleIT.java | 137 ++++++++++++++++++
5 files changed, 594 insertions(+), 3 deletions(-)
diff --git
a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/lifecycle/WsHumanTaskLifeCycle.java
b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/lifecycle/WsHumanTaskLifeCycle.java
index 8159446834..128ca419d4 100644
---
a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/lifecycle/WsHumanTaskLifeCycle.java
+++
b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/lifecycle/WsHumanTaskLifeCycle.java
@@ -443,7 +443,7 @@ public class WsHumanTaskLifeCycle implements
UserTaskLifeCycle {
private static ZonedDateTime parseSimpleDuration(String input) {
try {
- var millis = parseTimeString(input);
+ long millis = parseTimeString(input);
if (millis <= 0) {
throw new IllegalArgumentException("Invalid suspendUntil
duration: " + input);
}
@@ -522,8 +522,11 @@ public class WsHumanTaskLifeCycle implements
UserTaskLifeCycle {
throw new UserTaskInstanceNotAuthorizedException(message);
}
- if (List.of(CREATED, READY,
SUSPENDED).contains(userTaskInstance.getStatus())) {
- // there is no user
+ if (CREATED.equals(userTaskInstance.getStatus())
+ || READY.equals(userTaskInstance.getStatus())
+ || (SUSPENDED.equals(userTaskInstance.getStatus())
+ &&
READY.getName().equals(userTaskInstance.getMetadata().get(PREVIOUS_STATUS)))) {
+
Set<String> users = new
HashSet<>(userTaskInstance.getPotentialUsers());
users.removeAll(userTaskInstance.getExcludedUsers());
if (users.contains(user)) {
diff --git
a/quarkus/integration-tests/integration-tests-quarkus-wshumantasks/src/main/resources/manager_admin_multiple_users.bpmn
b/quarkus/integration-tests/integration-tests-quarkus-wshumantasks/src/main/resources/manager_admin_multiple_users.bpmn
new file mode 100644
index 0000000000..ebced58b76
--- /dev/null
+++
b/quarkus/integration-tests/integration-tests-quarkus-wshumantasks/src/main/resources/manager_admin_multiple_users.bpmn
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:bpsim="http://www.bpsim.org/schemas/1.0"
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
xmlns:drools="http://www.jboss.org/drools" id="_he0oAFJzED-wgK5wjEdlLQ"
xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd
http://www. [...]
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_PriorityInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_CommentInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_DescriptionInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_CreatedByInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_GroupIdInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_ContentInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_NotStartedReassignInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_NotCompletedReassignInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_NotStartedNotifyInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_NotCompletedNotifyInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputXItem"
structureRef="String"/>
+ <bpmn2:collaboration id="_3778CA92-9FE5-4681-907A-076773F7B8A1"
name="Default Collaboration">
+ <bpmn2:participant id="_872C19AB-BF7E-4B86-B5F6-A8773B235325" name="Pool
Participant" processRef="manager_admin_multiple_users"/>
+ </bpmn2:collaboration>
+ <bpmn2:process id="manager_admin_multiple_users"
drools:packageName="com.example" drools:version="1.0" drools:adHoc="false"
name="manager_admin_multiple_users" isExecutable="true" processType="Public">
+ <bpmn2:sequenceFlow id="_E9728BB4-C7C1-4613-8506-61F6E8D54928"
sourceRef="_60F9AB18-9065-48B1-9667-791889027BF8"
targetRef="_9BD7540D-2B9E-4E41-845E-A2BAEEB59717"/>
+ <bpmn2:sequenceFlow id="_8FF3949E-26E7-42C7-818E-17C8AAF127F5"
sourceRef="_F4221219-F8CE-47B1-A637-8452CB0B6A51"
targetRef="_60F9AB18-9065-48B1-9667-791889027BF8"/>
+ <bpmn2:endEvent id="_9BD7540D-2B9E-4E41-845E-A2BAEEB59717">
+ <bpmn2:incoming>_E9728BB4-C7C1-4613-8506-61F6E8D54928</bpmn2:incoming>
+ </bpmn2:endEvent>
+ <bpmn2:userTask id="_60F9AB18-9065-48B1-9667-791889027BF8" name="Manager
Approval">
+ <bpmn2:extensionElements>
+ <drools:metaData name="elementname">
+ <drools:metaValue><![CDATA[Manager Approval]]></drools:metaValue>
+ </drools:metaData>
+ </bpmn2:extensionElements>
+ <bpmn2:incoming>_8FF3949E-26E7-42C7-818E-17C8AAF127F5</bpmn2:incoming>
+ <bpmn2:outgoing>_E9728BB4-C7C1-4613-8506-61F6E8D54928</bpmn2:outgoing>
+ <bpmn2:ioSpecification>
+ <bpmn2:dataInput
id="_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX" drools:dtype="Object"
itemSubjectRef="__60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputXItem"
name="TaskName"/>
+ <bpmn2:dataInput
id="_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX"
drools:dtype="String"
itemSubjectRef="__60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputXItem"
name="BusinessAdministratorId"/>
+ <bpmn2:dataInput
id="_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX"
drools:dtype="Object"
itemSubjectRef="__60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputXItem"
name="Skippable"/>
+ <bpmn2:inputSet>
+
<bpmn2:dataInputRefs>_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX</bpmn2:dataInputRefs>
+
<bpmn2:dataInputRefs>_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX</bpmn2:dataInputRefs>
+
<bpmn2:dataInputRefs>_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX</bpmn2:dataInputRefs>
+ </bpmn2:inputSet>
+ </bpmn2:ioSpecification>
+ <bpmn2:dataInputAssociation>
+
<bpmn2:targetRef>_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX</bpmn2:targetRef>
+ <bpmn2:assignment>
+ <bpmn2:from
xsi:type="bpmn2:tFormalExpression"><![CDATA[Task]]></bpmn2:from>
+ <bpmn2:to
xsi:type="bpmn2:tFormalExpression"><![CDATA[_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX]]></bpmn2:to>
+ </bpmn2:assignment>
+ </bpmn2:dataInputAssociation>
+ <bpmn2:dataInputAssociation>
+
<bpmn2:targetRef>_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX</bpmn2:targetRef>
+ <bpmn2:assignment>
+ <bpmn2:from
xsi:type="bpmn2:tFormalExpression"><![CDATA[carl]]></bpmn2:from>
+ <bpmn2:to
xsi:type="bpmn2:tFormalExpression"><![CDATA[_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX]]></bpmn2:to>
+ </bpmn2:assignment>
+ </bpmn2:dataInputAssociation>
+ <bpmn2:dataInputAssociation>
+
<bpmn2:targetRef>_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX</bpmn2:targetRef>
+ <bpmn2:assignment>
+ <bpmn2:from
xsi:type="bpmn2:tFormalExpression"><![CDATA[true]]></bpmn2:from>
+ <bpmn2:to
xsi:type="bpmn2:tFormalExpression"><![CDATA[_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX]]></bpmn2:to>
+ </bpmn2:assignment>
+ </bpmn2:dataInputAssociation>
+ <bpmn2:potentialOwner id="_he12IFJzED-wgK5wjEdlLQ">
+ <bpmn2:resourceAssignmentExpression id="_he12IVJzED-wgK5wjEdlLQ">
+ <bpmn2:formalExpression>john</bpmn2:formalExpression>
+ </bpmn2:resourceAssignmentExpression>
+ </bpmn2:potentialOwner>
+ <bpmn2:potentialOwner id="_he12IlJzED-wgK5wjEdlLQ">
+ <bpmn2:resourceAssignmentExpression id="_he2dMFJzED-wgK5wjEdlLQ">
+ <bpmn2:formalExpression>dave</bpmn2:formalExpression>
+ </bpmn2:resourceAssignmentExpression>
+ </bpmn2:potentialOwner>
+ </bpmn2:userTask>
+ <bpmn2:startEvent id="_F4221219-F8CE-47B1-A637-8452CB0B6A51">
+ <bpmn2:outgoing>_8FF3949E-26E7-42C7-818E-17C8AAF127F5</bpmn2:outgoing>
+ </bpmn2:startEvent>
+ </bpmn2:process>
+ <bpmndi:BPMNDiagram>
+ <bpmndi:BPMNPlane bpmnElement="manager_admin_multiple_users">
+ <bpmndi:BPMNShape id="shape__F4221219-F8CE-47B1-A637-8452CB0B6A51"
bpmnElement="_F4221219-F8CE-47B1-A637-8452CB0B6A51">
+ <dc:Bounds height="56" width="56" x="210" y="213"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="shape__60F9AB18-9065-48B1-9667-791889027BF8"
bpmnElement="_60F9AB18-9065-48B1-9667-791889027BF8">
+ <dc:Bounds height="102" width="154" x="346" y="190"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="shape__9BD7540D-2B9E-4E41-845E-A2BAEEB59717"
bpmnElement="_9BD7540D-2B9E-4E41-845E-A2BAEEB59717">
+ <dc:Bounds height="56" width="56" x="580" y="213"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNEdge
id="edge_shape__F4221219-F8CE-47B1-A637-8452CB0B6A51_to_shape__60F9AB18-9065-48B1-9667-791889027BF8"
bpmnElement="_8FF3949E-26E7-42C7-818E-17C8AAF127F5">
+ <di:waypoint x="238" y="241"/>
+ <di:waypoint x="423" y="241"/>
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge
id="edge_shape__60F9AB18-9065-48B1-9667-791889027BF8_to_shape__9BD7540D-2B9E-4E41-845E-A2BAEEB59717"
bpmnElement="_E9728BB4-C7C1-4613-8506-61F6E8D54928">
+ <di:waypoint x="423" y="241"/>
+ <di:waypoint x="608" y="241"/>
+ </bpmndi:BPMNEdge>
+ </bpmndi:BPMNPlane>
+ </bpmndi:BPMNDiagram>
+ <bpmn2:relationship type="BPSimData">
+ <bpmn2:extensionElements>
+ <bpsim:BPSimData>
+ <bpsim:Scenario id="default" name="Simulationscenario">
+ <bpsim:ScenarioParameters/>
+ <bpsim:ElementParameters
elementRef="_F4221219-F8CE-47B1-A637-8452CB0B6A51">
+ <bpsim:TimeParameters>
+ <bpsim:ProcessingTime>
+ <bpsim:NormalDistribution mean="0" standardDeviation="0"/>
+ </bpsim:ProcessingTime>
+ </bpsim:TimeParameters>
+ </bpsim:ElementParameters>
+ <bpsim:ElementParameters
elementRef="_60F9AB18-9065-48B1-9667-791889027BF8">
+ <bpsim:TimeParameters>
+ <bpsim:ProcessingTime>
+ <bpsim:NormalDistribution mean="0" standardDeviation="0"/>
+ </bpsim:ProcessingTime>
+ </bpsim:TimeParameters>
+ <bpsim:ResourceParameters>
+ <bpsim:Availability>
+ <bpsim:FloatingParameter value="0"/>
+ </bpsim:Availability>
+ <bpsim:Quantity>
+ <bpsim:FloatingParameter value="0"/>
+ </bpsim:Quantity>
+ </bpsim:ResourceParameters>
+ <bpsim:CostParameters>
+ <bpsim:UnitCost>
+ <bpsim:FloatingParameter value="0"/>
+ </bpsim:UnitCost>
+ </bpsim:CostParameters>
+ </bpsim:ElementParameters>
+ </bpsim:Scenario>
+ </bpsim:BPSimData>
+ </bpmn2:extensionElements>
+ <bpmn2:source>_he0oAFJzED-wgK5wjEdlLQ</bpmn2:source>
+ <bpmn2:target>_he0oAFJzED-wgK5wjEdlLQ</bpmn2:target>
+ </bpmn2:relationship>
+</bpmn2:definitions>
\ No newline at end of file
diff --git
a/quarkus/integration-tests/integration-tests-quarkus-wshumantasks/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java
b/quarkus/integration-tests/integration-tests-quarkus-wshumantasks/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java
index 0994d4a692..9e2cc64605 100644
---
a/quarkus/integration-tests/integration-tests-quarkus-wshumantasks/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java
+++
b/quarkus/integration-tests/integration-tests-quarkus-wshumantasks/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java
@@ -211,6 +211,132 @@ public class WsHumanTaskLifeCycleIT {
isProcessCompleted(processId, pid);
}
+ @Test
+ public void testPotentialUserCanResumeSuspendedToReadyTask() {
+ var owner = "dave";
+ var potentialUser = "john";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ suspend(taskId, owner);
+ resume(taskId, potentialUser, "Ready");
+
+ claim(taskId, owner);
+ start(taskId, owner);
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testActualOwnerCanResumeSuspendedToReservedTask() {
+ var owner = "dave";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, owner, "Reserved");
+
+ start(taskId, owner);
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testActualOwnerCanResumeSuspendedToInProgressTask() {
+ var owner = "dave";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ start(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, owner, "InProgress");
+
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testPotentialUserCannotResumeSuspendedToReservedTask() {
+ var owner = "dave";
+ var potentialUser = "john";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ suspend(taskId, owner);
+ resumeNotAuthorized(taskId, potentialUser);
+ resume(taskId, owner, "Reserved");
+
+ start(taskId, owner);
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testPotentialUserCannotResumeSuspendedToInProgressTask() {
+ var owner = "dave";
+ var potentialUser = "john";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ start(taskId, owner);
+ suspend(taskId, owner);
+ resumeNotAuthorized(taskId, potentialUser);
+ resume(taskId, owner, "InProgress");
+
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testBusinessAdminCanResumeSuspendedTask() {
+ var owner = "dave";
+ var admin = "carl";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_admin_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ suspend(taskId, owner);
+ resume(taskId, admin, "Ready");
+
+ claim(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, admin, "Reserved");
+
+ start(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, admin, "InProgress");
+
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
@Test
public void testSuspendUntilWithDuration() {
var user = "dave";
@@ -626,6 +752,7 @@ public class WsHumanTaskLifeCycleIT {
public void testMultipleGroupsWithVariablesUserTaskLifeCycle() {
// This test verifies the fix for multi-variable expressions in BPMN
// The GroupId is defined as #{group1},#{group2},#{group3} in the BPMN
+ // and we pass the actual group names as process variables
var user = "dave";
var group = "engineering";
var potentialGroups = new String[] { "hr", "engineering", "management"
};
@@ -640,6 +767,7 @@ public class WsHumanTaskLifeCycleIT {
var taskId = getTaskId(user, group, pid);
// Verify all three groups are present in potentialGroups
+ // This would fail with the old implementation which only extracted
the first variable
given()
.contentType(ContentType.JSON)
.when()
@@ -732,6 +860,17 @@ public class WsHumanTaskLifeCycleIT {
.body("metadata.SuspendedJobId", equalTo(null));
}
+ private void resumeNotAuthorized(String taskId, String user) {
+ given()
+ .contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", user)
+ .body(new TransitionInfo("resume"))
+ .post(USER_TASKS_INSTANCE_TRANSITION_ENDPOINT, taskId)
+ .then()
+ .statusCode(403);
+ }
+
private void suspend(String taskId, String user) {
given()
.contentType(ContentType.JSON)
diff --git
a/springboot/integration-tests/integration-tests-springboot-wshumantasks-it/src/main/resources/manager_admin_multiple_users.bpmn
b/springboot/integration-tests/integration-tests-springboot-wshumantasks-it/src/main/resources/manager_admin_multiple_users.bpmn
new file mode 100644
index 0000000000..ebced58b76
--- /dev/null
+++
b/springboot/integration-tests/integration-tests-springboot-wshumantasks-it/src/main/resources/manager_admin_multiple_users.bpmn
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:bpsim="http://www.bpsim.org/schemas/1.0"
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
xmlns:drools="http://www.jboss.org/drools" id="_he0oAFJzED-wgK5wjEdlLQ"
xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd
http://www. [...]
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_PriorityInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_CommentInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_DescriptionInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_CreatedByInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_GroupIdInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_ContentInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_NotStartedReassignInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_NotCompletedReassignInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_NotStartedNotifyInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_NotCompletedNotifyInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputXItem"
structureRef="String"/>
+ <bpmn2:collaboration id="_3778CA92-9FE5-4681-907A-076773F7B8A1"
name="Default Collaboration">
+ <bpmn2:participant id="_872C19AB-BF7E-4B86-B5F6-A8773B235325" name="Pool
Participant" processRef="manager_admin_multiple_users"/>
+ </bpmn2:collaboration>
+ <bpmn2:process id="manager_admin_multiple_users"
drools:packageName="com.example" drools:version="1.0" drools:adHoc="false"
name="manager_admin_multiple_users" isExecutable="true" processType="Public">
+ <bpmn2:sequenceFlow id="_E9728BB4-C7C1-4613-8506-61F6E8D54928"
sourceRef="_60F9AB18-9065-48B1-9667-791889027BF8"
targetRef="_9BD7540D-2B9E-4E41-845E-A2BAEEB59717"/>
+ <bpmn2:sequenceFlow id="_8FF3949E-26E7-42C7-818E-17C8AAF127F5"
sourceRef="_F4221219-F8CE-47B1-A637-8452CB0B6A51"
targetRef="_60F9AB18-9065-48B1-9667-791889027BF8"/>
+ <bpmn2:endEvent id="_9BD7540D-2B9E-4E41-845E-A2BAEEB59717">
+ <bpmn2:incoming>_E9728BB4-C7C1-4613-8506-61F6E8D54928</bpmn2:incoming>
+ </bpmn2:endEvent>
+ <bpmn2:userTask id="_60F9AB18-9065-48B1-9667-791889027BF8" name="Manager
Approval">
+ <bpmn2:extensionElements>
+ <drools:metaData name="elementname">
+ <drools:metaValue><![CDATA[Manager Approval]]></drools:metaValue>
+ </drools:metaData>
+ </bpmn2:extensionElements>
+ <bpmn2:incoming>_8FF3949E-26E7-42C7-818E-17C8AAF127F5</bpmn2:incoming>
+ <bpmn2:outgoing>_E9728BB4-C7C1-4613-8506-61F6E8D54928</bpmn2:outgoing>
+ <bpmn2:ioSpecification>
+ <bpmn2:dataInput
id="_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX" drools:dtype="Object"
itemSubjectRef="__60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputXItem"
name="TaskName"/>
+ <bpmn2:dataInput
id="_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX"
drools:dtype="String"
itemSubjectRef="__60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputXItem"
name="BusinessAdministratorId"/>
+ <bpmn2:dataInput
id="_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX"
drools:dtype="Object"
itemSubjectRef="__60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputXItem"
name="Skippable"/>
+ <bpmn2:inputSet>
+
<bpmn2:dataInputRefs>_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX</bpmn2:dataInputRefs>
+
<bpmn2:dataInputRefs>_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX</bpmn2:dataInputRefs>
+
<bpmn2:dataInputRefs>_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX</bpmn2:dataInputRefs>
+ </bpmn2:inputSet>
+ </bpmn2:ioSpecification>
+ <bpmn2:dataInputAssociation>
+
<bpmn2:targetRef>_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX</bpmn2:targetRef>
+ <bpmn2:assignment>
+ <bpmn2:from
xsi:type="bpmn2:tFormalExpression"><![CDATA[Task]]></bpmn2:from>
+ <bpmn2:to
xsi:type="bpmn2:tFormalExpression"><![CDATA[_60F9AB18-9065-48B1-9667-791889027BF8_TaskNameInputX]]></bpmn2:to>
+ </bpmn2:assignment>
+ </bpmn2:dataInputAssociation>
+ <bpmn2:dataInputAssociation>
+
<bpmn2:targetRef>_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX</bpmn2:targetRef>
+ <bpmn2:assignment>
+ <bpmn2:from
xsi:type="bpmn2:tFormalExpression"><![CDATA[carl]]></bpmn2:from>
+ <bpmn2:to
xsi:type="bpmn2:tFormalExpression"><![CDATA[_60F9AB18-9065-48B1-9667-791889027BF8_BusinessAdministratorIdInputX]]></bpmn2:to>
+ </bpmn2:assignment>
+ </bpmn2:dataInputAssociation>
+ <bpmn2:dataInputAssociation>
+
<bpmn2:targetRef>_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX</bpmn2:targetRef>
+ <bpmn2:assignment>
+ <bpmn2:from
xsi:type="bpmn2:tFormalExpression"><![CDATA[true]]></bpmn2:from>
+ <bpmn2:to
xsi:type="bpmn2:tFormalExpression"><![CDATA[_60F9AB18-9065-48B1-9667-791889027BF8_SkippableInputX]]></bpmn2:to>
+ </bpmn2:assignment>
+ </bpmn2:dataInputAssociation>
+ <bpmn2:potentialOwner id="_he12IFJzED-wgK5wjEdlLQ">
+ <bpmn2:resourceAssignmentExpression id="_he12IVJzED-wgK5wjEdlLQ">
+ <bpmn2:formalExpression>john</bpmn2:formalExpression>
+ </bpmn2:resourceAssignmentExpression>
+ </bpmn2:potentialOwner>
+ <bpmn2:potentialOwner id="_he12IlJzED-wgK5wjEdlLQ">
+ <bpmn2:resourceAssignmentExpression id="_he2dMFJzED-wgK5wjEdlLQ">
+ <bpmn2:formalExpression>dave</bpmn2:formalExpression>
+ </bpmn2:resourceAssignmentExpression>
+ </bpmn2:potentialOwner>
+ </bpmn2:userTask>
+ <bpmn2:startEvent id="_F4221219-F8CE-47B1-A637-8452CB0B6A51">
+ <bpmn2:outgoing>_8FF3949E-26E7-42C7-818E-17C8AAF127F5</bpmn2:outgoing>
+ </bpmn2:startEvent>
+ </bpmn2:process>
+ <bpmndi:BPMNDiagram>
+ <bpmndi:BPMNPlane bpmnElement="manager_admin_multiple_users">
+ <bpmndi:BPMNShape id="shape__F4221219-F8CE-47B1-A637-8452CB0B6A51"
bpmnElement="_F4221219-F8CE-47B1-A637-8452CB0B6A51">
+ <dc:Bounds height="56" width="56" x="210" y="213"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="shape__60F9AB18-9065-48B1-9667-791889027BF8"
bpmnElement="_60F9AB18-9065-48B1-9667-791889027BF8">
+ <dc:Bounds height="102" width="154" x="346" y="190"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="shape__9BD7540D-2B9E-4E41-845E-A2BAEEB59717"
bpmnElement="_9BD7540D-2B9E-4E41-845E-A2BAEEB59717">
+ <dc:Bounds height="56" width="56" x="580" y="213"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNEdge
id="edge_shape__F4221219-F8CE-47B1-A637-8452CB0B6A51_to_shape__60F9AB18-9065-48B1-9667-791889027BF8"
bpmnElement="_8FF3949E-26E7-42C7-818E-17C8AAF127F5">
+ <di:waypoint x="238" y="241"/>
+ <di:waypoint x="423" y="241"/>
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge
id="edge_shape__60F9AB18-9065-48B1-9667-791889027BF8_to_shape__9BD7540D-2B9E-4E41-845E-A2BAEEB59717"
bpmnElement="_E9728BB4-C7C1-4613-8506-61F6E8D54928">
+ <di:waypoint x="423" y="241"/>
+ <di:waypoint x="608" y="241"/>
+ </bpmndi:BPMNEdge>
+ </bpmndi:BPMNPlane>
+ </bpmndi:BPMNDiagram>
+ <bpmn2:relationship type="BPSimData">
+ <bpmn2:extensionElements>
+ <bpsim:BPSimData>
+ <bpsim:Scenario id="default" name="Simulationscenario">
+ <bpsim:ScenarioParameters/>
+ <bpsim:ElementParameters
elementRef="_F4221219-F8CE-47B1-A637-8452CB0B6A51">
+ <bpsim:TimeParameters>
+ <bpsim:ProcessingTime>
+ <bpsim:NormalDistribution mean="0" standardDeviation="0"/>
+ </bpsim:ProcessingTime>
+ </bpsim:TimeParameters>
+ </bpsim:ElementParameters>
+ <bpsim:ElementParameters
elementRef="_60F9AB18-9065-48B1-9667-791889027BF8">
+ <bpsim:TimeParameters>
+ <bpsim:ProcessingTime>
+ <bpsim:NormalDistribution mean="0" standardDeviation="0"/>
+ </bpsim:ProcessingTime>
+ </bpsim:TimeParameters>
+ <bpsim:ResourceParameters>
+ <bpsim:Availability>
+ <bpsim:FloatingParameter value="0"/>
+ </bpsim:Availability>
+ <bpsim:Quantity>
+ <bpsim:FloatingParameter value="0"/>
+ </bpsim:Quantity>
+ </bpsim:ResourceParameters>
+ <bpsim:CostParameters>
+ <bpsim:UnitCost>
+ <bpsim:FloatingParameter value="0"/>
+ </bpsim:UnitCost>
+ </bpsim:CostParameters>
+ </bpsim:ElementParameters>
+ </bpsim:Scenario>
+ </bpsim:BPSimData>
+ </bpmn2:extensionElements>
+ <bpmn2:source>_he0oAFJzED-wgK5wjEdlLQ</bpmn2:source>
+ <bpmn2:target>_he0oAFJzED-wgK5wjEdlLQ</bpmn2:target>
+ </bpmn2:relationship>
+</bpmn2:definitions>
\ No newline at end of file
diff --git
a/springboot/integration-tests/integration-tests-springboot-wshumantasks-it/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java
b/springboot/integration-tests/integration-tests-springboot-wshumantasks-it/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java
index 2f811265a2..e2d069ace2 100644
---
a/springboot/integration-tests/integration-tests-springboot-wshumantasks-it/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java
+++
b/springboot/integration-tests/integration-tests-springboot-wshumantasks-it/src/test/java/org/jbpm/usertask/jpa/it/WsHumanTaskLifeCycleIT.java
@@ -220,6 +220,132 @@ public class WsHumanTaskLifeCycleIT {
isProcessCompleted(processId, pid);
}
+ @Test
+ public void testPotentialUserCanResumeSuspendedToReadyTask() {
+ var owner = "dave";
+ var potentialUser = "john";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ suspend(taskId, owner);
+ resume(taskId, potentialUser, "Ready");
+
+ claim(taskId, owner);
+ start(taskId, owner);
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testActualOwnerCanResumeSuspendedToReservedTask() {
+ var owner = "dave";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, owner, "Reserved");
+
+ start(taskId, owner);
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testActualOwnerCanResumeSuspendedToInProgressTask() {
+ var owner = "dave";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ start(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, owner, "InProgress");
+
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testPotentialUserCannotResumeSuspendedToReservedTask() {
+ var owner = "dave";
+ var potentialUser = "john";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ suspend(taskId, owner);
+ resumeNotAuthorized(taskId, potentialUser);
+ resume(taskId, owner, "Reserved");
+
+ start(taskId, owner);
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testPotentialUserCannotResumeSuspendedToInProgressTask() {
+ var owner = "dave";
+ var potentialUser = "john";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ claim(taskId, owner);
+ start(taskId, owner);
+ suspend(taskId, owner);
+ resumeNotAuthorized(taskId, potentialUser);
+ resume(taskId, owner, "InProgress");
+
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
+ @Test
+ public void testBusinessAdminCanResumeSuspendedTask() {
+ var owner = "dave";
+ var admin = "carl";
+ var potentialUsers = new String[] { "john", "dave" };
+ var processId = "manager_admin_multiple_users";
+ var pid = startProcessInstance(processId);
+ var taskId = getTaskId(owner, pid);
+ verifyTask(processId, pid, taskId, owner, "Ready", potentialUsers);
+
+ suspend(taskId, owner);
+ resume(taskId, admin, "Ready");
+
+ claim(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, admin, "Reserved");
+
+ start(taskId, owner);
+ suspend(taskId, owner);
+ resume(taskId, admin, "InProgress");
+
+ complete(taskId, owner);
+
+ isProcessCompleted(processId, pid);
+ }
+
@Test
public void testSuspendUntilWithDuration() {
var user = "dave";
@@ -743,6 +869,17 @@ public class WsHumanTaskLifeCycleIT {
.body("metadata.SuspendedJobId", equalTo(null));
}
+ private void resumeNotAuthorized(String taskId, String user) {
+ given()
+ .contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", user)
+ .body(new TransitionInfo("resume"))
+ .post(USER_TASKS_INSTANCE_TRANSITION_ENDPOINT, taskId)
+ .then()
+ .statusCode(403);
+ }
+
private void suspend(String taskId, String user) {
given()
.contentType(ContentType.JSON)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]