You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2019/12/17 15:43:01 UTC

[syncope] branch master updated: [SYNCOPE-1530] Provide the possibility to start a User Request with custom variables. (#150)

This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/master by this push:
     new 475d6ca  [SYNCOPE-1530] Provide the possibility to start a User Request with custom variables. (#150)
475d6ca is described below

commit 475d6ca6de6f2c521ad07d983b0861c949c73756
Author: Federico Palmitesta <fe...@gmail.com>
AuthorDate: Tue Dec 17 16:24:30 2019 +0100

    [SYNCOPE-1530] Provide the possibility to start a User Request with custom variables. (#150)
---
 .../client/enduser/rest/UserRequestRestClient.java |  2 +-
 .../core/flowable/api/UserRequestHandler.java      |  4 +-
 .../flowable/impl/FlowableUserRequestHandler.java  |  7 ++-
 .../syncope/core/logic/UserRequestLogic.java       | 19 +++++--
 .../rest/api/service/UserRequestService.java       |  5 +-
 .../rest/cxf/service/UserRequestServiceImpl.java   |  7 ++-
 .../main/resources/verifyAddedVariables.bpmn20.xml | 64 ++++++++++++++++++++++
 .../apache/syncope/fit/core/UserRequestITCase.java | 57 +++++++++++++++++--
 8 files changed, 146 insertions(+), 19 deletions(-)

diff --git a/ext/flowable/client-enduser/src/main/java/org/apache/syncope/client/enduser/rest/UserRequestRestClient.java b/ext/flowable/client-enduser/src/main/java/org/apache/syncope/client/enduser/rest/UserRequestRestClient.java
index 86335e5..3d449af 100644
--- a/ext/flowable/client-enduser/src/main/java/org/apache/syncope/client/enduser/rest/UserRequestRestClient.java
+++ b/ext/flowable/client-enduser/src/main/java/org/apache/syncope/client/enduser/rest/UserRequestRestClient.java
@@ -82,7 +82,7 @@ public class UserRequestRestClient extends BaseRestClient {
     }
 
     public static void start(final String bpmnProcess, final String user) {
-        getService(UserRequestService.class).start(bpmnProcess, user);
+        getService(UserRequestService.class).start(bpmnProcess, user, null);
     }
 
     public static UserRequestForm claimForm(final String taskKey) {
diff --git a/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/api/UserRequestHandler.java b/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/api/UserRequestHandler.java
index 4b47edd..105278e 100644
--- a/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/api/UserRequestHandler.java
+++ b/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/api/UserRequestHandler.java
@@ -23,6 +23,7 @@ import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.request.UserUR;
 import org.apache.syncope.common.lib.to.UserRequest;
 import org.apache.syncope.common.lib.to.UserRequestForm;
+import org.apache.syncope.common.lib.to.WorkflowTaskExecInput;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.UserWorkflowResult;
@@ -49,9 +50,10 @@ public interface UserRequestHandler {
      *
      * @param bpmnProcess BPMN process
      * @param user user
+     * @param inputVariables variables
      * @return data about the started request service, including execution id
      */
-    UserRequest start(String bpmnProcess, User user);
+    UserRequest start(String bpmnProcess, User user, WorkflowTaskExecInput inputVariables);
 
     /**
      * Parses the given execution id to find matching user request and owner.
diff --git a/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/impl/FlowableUserRequestHandler.java b/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/impl/FlowableUserRequestHandler.java
index 5a12062..233b3f2 100644
--- a/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/impl/FlowableUserRequestHandler.java
+++ b/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/impl/FlowableUserRequestHandler.java
@@ -35,6 +35,7 @@ import org.apache.syncope.common.lib.to.UserRequest;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.to.UserRequestFormProperty;
 import org.apache.syncope.common.lib.to.UserRequestForm;
+import org.apache.syncope.common.lib.to.WorkflowTaskExecInput;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ResourceOperation;
 import org.apache.syncope.common.lib.types.UserRequestFormPropertyType;
@@ -195,12 +196,14 @@ public class FlowableUserRequestHandler implements UserRequestHandler {
     }
 
     @Override
-    public UserRequest start(final String bpmnProcess, final User user) {
+    public UserRequest start(final String bpmnProcess, final User user, final WorkflowTaskExecInput inputVariables) {
         Map<String, Object> variables = new HashMap<>();
         variables.put(FlowableRuntimeUtils.WF_EXECUTOR, AuthContextUtils.getUsername());
         variables.put(FlowableRuntimeUtils.USER, lazyLoad(user));
         variables.put(FlowableRuntimeUtils.USER_TO, dataBinder.getUserTO(user, true));
-
+        if (inputVariables != null) {
+            variables.putAll(inputVariables.getVariables());
+        }
         ProcessInstance procInst = null;
         try {
             procInst = engine.getRuntimeService().startProcessInstanceByKey(bpmnProcess, variables);
diff --git a/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserRequestLogic.java b/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserRequestLogic.java
index a0b4a3a..65ed365 100644
--- a/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserRequestLogic.java
+++ b/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserRequestLogic.java
@@ -28,6 +28,7 @@ import org.apache.syncope.common.lib.to.EntityTO;
 import org.apache.syncope.common.lib.to.UserRequest;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.to.UserRequestForm;
+import org.apache.syncope.common.lib.to.WorkflowTaskExecInput;
 import org.apache.syncope.common.lib.types.BpmnProcessFormat;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.FlowableEntitlement;
@@ -95,21 +96,27 @@ public class UserRequestLogic extends AbstractTransactionalLogic<EntityTO> {
         return userRequestHandler.getUserRequests(userKey, page, size, orderByClauses);
     }
 
-    protected UserRequest doStart(final String bpmnProcess, final User user) {
+    protected UserRequest doStart(
+            final String bpmnProcess,
+            final User user,
+            final WorkflowTaskExecInput inputVariables) {
         // check if BPMN process exists
         bpmnProcessManager.exportProcess(bpmnProcess, BpmnProcessFormat.XML, new NullOutputStream());
 
-        return userRequestHandler.start(bpmnProcess, user);
+        return userRequestHandler.start(bpmnProcess, user, inputVariables);
     }
 
     @PreAuthorize("isAuthenticated()")
-    public UserRequest start(final String bpmnProcess) {
-        return doStart(bpmnProcess, userDAO.findByUsername(AuthContextUtils.getUsername()));
+    public UserRequest start(final String bpmnProcess, final WorkflowTaskExecInput inputVariables) {
+        return doStart(bpmnProcess, userDAO.findByUsername(AuthContextUtils.getUsername()), inputVariables);
     }
 
     @PreAuthorize("hasRole('" + FlowableEntitlement.USER_REQUEST_START + "')")
-    public UserRequest start(final String bpmnProcess, final String userKey) {
-        return doStart(bpmnProcess, userDAO.authFind(userKey));
+    public UserRequest start(
+            final String bpmnProcess,
+            final String userKey,
+            final WorkflowTaskExecInput inputVariables) {
+        return doStart(bpmnProcess, userDAO.authFind(userKey), inputVariables);
     }
 
     protected static void securityChecks(final String username, final String entitlement, final String errorMessage) {
diff --git a/ext/flowable/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserRequestService.java b/ext/flowable/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserRequestService.java
index b38cd61..d9bcd53 100644
--- a/ext/flowable/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserRequestService.java
+++ b/ext/flowable/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserRequestService.java
@@ -38,6 +38,7 @@ import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.UserRequest;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.to.UserRequestForm;
+import org.apache.syncope.common.lib.to.WorkflowTaskExecInput;
 import org.apache.syncope.common.rest.api.RESTHeaders;
 import org.apache.syncope.common.rest.api.beans.UserRequestFormQuery;
 import org.apache.syncope.common.rest.api.beans.UserRequestQuery;
@@ -67,6 +68,7 @@ public interface UserRequestService extends JAXRSService {
      *
      * @param bpmnProcess BPMN process
      * @param user if value looks like a UUID then it is interpreted as key otherwise as a username
+     * @param inputVariables initial request variables
      * @return data about the started request service, including execution id
      */
     @POST
@@ -74,7 +76,8 @@ public interface UserRequestService extends JAXRSService {
     @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     UserRequest start(
             @NotNull @PathParam("bpmnProcess") String bpmnProcess,
-            @QueryParam(JAXRSService.PARAM_USER) String user);
+            @QueryParam(JAXRSService.PARAM_USER) String user,
+            WorkflowTaskExecInput inputVariables);
 
     /**
      * Cancel a running user request.
diff --git a/ext/flowable/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserRequestServiceImpl.java b/ext/flowable/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserRequestServiceImpl.java
index d339ac8..4f939c4 100644
--- a/ext/flowable/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserRequestServiceImpl.java
+++ b/ext/flowable/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserRequestServiceImpl.java
@@ -24,6 +24,7 @@ import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.UserRequest;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.to.UserRequestForm;
+import org.apache.syncope.common.lib.to.WorkflowTaskExecInput;
 import org.apache.syncope.common.rest.api.beans.UserRequestFormQuery;
 import org.apache.syncope.common.rest.api.beans.UserRequestQuery;
 import org.apache.syncope.core.logic.UserRequestLogic;
@@ -53,10 +54,10 @@ public class UserRequestServiceImpl extends AbstractServiceImpl implements UserR
     }
 
     @Override
-    public UserRequest start(final String bpmnProcess, final String user) {
+    public UserRequest start(final String bpmnProcess, final String user, final WorkflowTaskExecInput inputVariables) {
         return user == null
-                ? logic.start(bpmnProcess)
-                : logic.start(bpmnProcess, getActualKey(userDAO, user));
+                ? logic.start(bpmnProcess, inputVariables)
+                : logic.start(bpmnProcess, getActualKey(userDAO, user), inputVariables);
     }
 
     @Override
diff --git a/fit/core-reference/src/main/resources/verifyAddedVariables.bpmn20.xml b/fit/core-reference/src/main/resources/verifyAddedVariables.bpmn20.xml
new file mode 100644
index 0000000..0528e22
--- /dev/null
+++ b/fit/core-reference/src/main/resources/verifyAddedVariables.bpmn20.xml
@@ -0,0 +1,64 @@
+<?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.
+-->
+<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 
+             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+             xmlns:flowable="http://flowable.org/bpmn"
+             xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" 
+             xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" 
+             xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" 
+             typeLanguage="http://www.w3.org/2001/XMLSchema" 
+             expressionLanguage="http://www.w3.org/1999/XPath" 
+             targetNamespace="http://www.flowable.org/processdef">
+
+  <process id="verifyAddedVariables" name="Verify Added Variables" isExecutable="true">
+    <startEvent id="startevent1" name="Start" flowable:formFieldValidation="true"/>
+    <userTask id="testForm" name="Test Form" flowable:formKey="approval" flowable:formFieldValidation="true">
+      <extensionElements>
+        <flowable:formProperty id="approve" name="Approve?" type="boolean" variable="approve" required="true"/>
+        <flowable:formProperty id="providedVariable" name="Provided Variable" type="string" expression="${providedVariable}" writable="false"/>
+        <flowable:formProperty id="username" name="Username" type="string" expression="${userTO.username}" writable="false"/>
+      </extensionElements>
+    </userTask>
+    <sequenceFlow id="sid-27C1484D-96E9-4B39-A129-F4AB14ABDF13" sourceRef="testForm" targetRef="endevent1"/>
+    <sequenceFlow id="sid-A9FEC01B-768E-4C07-B025-6D019D72015F" sourceRef="startevent1" targetRef="testForm"/>
+    <endEvent id="endevent1" name="End"/>
+  </process>
+  <bpmndi:BPMNDiagram id="BPMNDiagram_userWorkflow">
+    <bpmndi:BPMNPlane bpmnElement="userWorkflow" id="BPMNPlane_userWorkflow">
+      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
+        <omgdc:Bounds height="30.0" width="30.0" x="150.0" y="115.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="testForm" id="BPMNShape_testForm">
+        <omgdc:Bounds height="80.0" width="100.0" x="345.0" y="90.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
+        <omgdc:Bounds height="28.0" width="28.0" x="615.0" y="116.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge bpmnElement="sid-27C1484D-96E9-4B39-A129-F4AB14ABDF13" id="BPMNEdge_sid-27C1484D-96E9-4B39-A129-F4AB14ABDF13">
+        <omgdi:waypoint x="444.94999999992734" y="130.0"/>
+        <omgdi:waypoint x="615.0" y="130.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-A9FEC01B-768E-4C07-B025-6D019D72015F" id="BPMNEdge_sid-A9FEC01B-768E-4C07-B025-6D019D72015F">
+        <omgdi:waypoint x="179.94999965443563" y="130.0"/>
+        <omgdi:waypoint x="345.0" y="130.0"/>
+      </bpmndi:BPMNEdge>
+    </bpmndi:BPMNPlane>
+  </bpmndi:BPMNDiagram>
+</definitions>
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserRequestITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserRequestITCase.java
index dd5b907..e1a89ad 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserRequestITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserRequestITCase.java
@@ -35,6 +35,7 @@ import org.apache.syncope.common.lib.to.RelationshipTO;
 import org.apache.syncope.common.lib.to.UserRequestForm;
 import org.apache.syncope.common.lib.to.UserRequest;
 import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.to.WorkflowTaskExecInput;
 import org.apache.syncope.common.rest.api.beans.UserRequestFormQuery;
 import org.apache.syncope.common.rest.api.beans.UserRequestQuery;
 import org.apache.syncope.common.rest.api.service.UserRequestService;
@@ -54,6 +55,8 @@ public class UserRequestITCase extends AbstractITCase {
                 IOUtils.toString(UserRequestITCase.class.getResourceAsStream("/directorGroupRequest.bpmn20.xml")));
         bpmnProcessService.set("assignPrinterRequest",
                 IOUtils.toString(UserRequestITCase.class.getResourceAsStream("/assignPrinterRequest.bpmn20.xml")));
+        bpmnProcessService.set("verifyAddedVariables",
+                IOUtils.toString(UserRequestITCase.class.getResourceAsStream("/verifyAddedVariables.bpmn20.xml")));
     }
 
     @Test
@@ -65,7 +68,7 @@ public class UserRequestITCase extends AbstractITCase {
         assertFalse(user.getMembership("ebf97068-aa4b-4a85-9f01-680e8c4cf227").isPresent());
 
         // start request
-        UserRequest req = userRequestService.start("directorGroupRequest", user.getKey());
+        UserRequest req = userRequestService.start("directorGroupRequest", user.getKey(), null);
         assertNotNull(req);
         assertEquals("directorGroupRequest", req.getBpmnProcess());
         assertNotNull(req.getExecutionId());
@@ -91,7 +94,7 @@ public class UserRequestITCase extends AbstractITCase {
         assertFalse(userService.read(user.getKey()).getMembership("ebf97068-aa4b-4a85-9f01-680e8c4cf227").isPresent());
 
         // start request again
-        req = userRequestService.start("directorGroupRequest", user.getKey());
+        req = userRequestService.start("directorGroupRequest", user.getKey(), null);
         assertNotNull(req);
 
         // 1st approval -> accept
@@ -114,7 +117,7 @@ public class UserRequestITCase extends AbstractITCase {
         assertFalse(userService.read(user.getKey()).getMembership("ebf97068-aa4b-4a85-9f01-680e8c4cf227").isPresent());
 
         // start request again
-        req = userRequestService.start("directorGroupRequest", user.getKey());
+        req = userRequestService.start("directorGroupRequest", user.getKey(), null);
         assertNotNull(req);
 
         // 1st approval -> accept
@@ -149,7 +152,7 @@ public class UserRequestITCase extends AbstractITCase {
         assertFalse(user.getMembership("ebf97068-aa4b-4a85-9f01-680e8c4cf227").isPresent());
 
         // start request
-        UserRequest req = userRequestService.start("directorGroupRequest", user.getKey());
+        UserRequest req = userRequestService.start("directorGroupRequest", user.getKey(), null);
         assertNotNull(req);
 
         // check that form was generated
@@ -186,7 +189,7 @@ public class UserRequestITCase extends AbstractITCase {
         SyncopeClient client = clientFactory.create(user.getUsername(), "password123");
 
         // start request as user
-        UserRequest req = client.getService(UserRequestService.class).start("assignPrinterRequest", null);
+        UserRequest req = client.getService(UserRequestService.class).start("assignPrinterRequest", null, null);
         assertNotNull(req);
 
         // check (as admin) that a new form is available
@@ -244,4 +247,48 @@ public class UserRequestITCase extends AbstractITCase {
         assertTrue(relationships.stream().
                 anyMatch(relationship -> "8559d14d-58c2-46eb-a2d4-a7d35161e8f8".equals(relationship.getOtherEndKey())));
     }
+    
+    @Test
+    public void addVariablesToUserRequestAtStart() {
+        assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(syncopeService));
+
+        PagedResult<UserRequestForm> forms =
+                userRequestService.getForms(new UserRequestFormQuery.Builder().build());
+        int preForms = forms.getTotalCount();
+
+        UserTO user = createUser(UserITCase.getUniqueSample("addVariables@tirasa.net")).getEntity();
+        assertNotNull(user);
+
+        SyncopeClient client = clientFactory.create(user.getUsername(), "password123");
+
+        WorkflowTaskExecInput testInput = new WorkflowTaskExecInput();
+        testInput.getVariables().put("providedVariable", "test");
+        
+        // start request as user
+        UserRequest req = client.getService(UserRequestService.class).start("verifyAddedVariables", null, testInput);
+        assertNotNull(req);
+
+        // check that a new form is available
+        forms = userRequestService.getForms(new UserRequestFormQuery.Builder().build());
+        assertEquals(preForms + 1, forms.getTotalCount());
+
+        // get the form and verify the property value
+        PagedResult<UserRequestForm> userForms = userRequestService.
+                getForms(new UserRequestFormQuery.Builder().user(user.getKey()).build());
+        assertEquals(1, userForms.getTotalCount());
+
+        UserRequestForm form = userForms.getResult().get(0);
+        form = userRequestService.claimForm(form.getTaskId());
+        assertEquals(form.getProperty("providedVariable").get().getValue(), "test");
+        
+        // cancel request
+        userRequestService.cancel(req.getExecutionId(), "nothing in particular");
+       
+        // no more forms available
+        forms = userRequestService.getForms(new UserRequestFormQuery.Builder().build());
+        assertEquals(preForms, forms.getTotalCount());
+
+        assertTrue(client.getService(UserRequestService.class).
+                list(new UserRequestQuery.Builder().user(user.getKey()).build()).getResult().isEmpty());
+    }
 }